0%

[CO P0]P0 上机之思考

今天非常惊险地通过了 P0 上机(实话说 P0 挂了就招笑了
但是还是非常难过,在错误的地方浪费了大量时间。


第一题

题干

第一题的大致题意是搭建一个 Moore 机,实现下述功能:

串行输入一个数列,每个 5 位宽,若当前输入的数严格大于前一个数,则称为一次“起”,若严格小于则称为一次“伏”。若最后四个输入满足“起 起 伏 起”的情况,则输出为 1。

识别是循环的,比如一个“起 起 伏 起”的最后一个起可以当作下一个“起 起 伏 起”的第一个“起”,如“起 起 伏 起 起 伏 起”中第 4 个“起”和第 7 个 “起”要输出 1。

初始情况下或者异步复位后,数列的第 0 个元素 a05'd7

感悟

这题的核心在于怎么实现这个初始的 5'd7
很明显我得用一个寄存器去保存上一个输入的数。一开始我选择用寄存器初始化的方法去给这个寄存器初始化一个 5'd7,但是这显然错了,耽误了我很多分钟的时间(。

这个 5'd7 可以说是要以一种“异步初始化”的形式来实现,而我所掌握的是同步初始化。什么意思呢?现有的初始化方法只能当时钟上升沿到来时才给寄存器赋初值。也就是说当第一个时钟周期来时寄存器才变成 5'd7,但是按理说这时候应该存入此时输入的值了,也就是 a1,所以这根本不对。

(补丁)我的老天,发现早已有大佬给出了“异步初始化”的方法,其实只要在同步的基础上略微改动即可。

“异步初始化”

我采用的是笨办法,直接在设计状态的时候把初始状态编了一个状态码,如果下一个输出大于 5'd7 就转到下一个状态——一个“起”,与此同时还设计了一个 invalid 状态接受所有不符合“起 起 伏 起”的输入,比如“伏”完又“伏”,或者只有一个“起”就“伏”之类的,当出现一个“起”时,invalid 也转到一个“起”的状态……
这样状态有点多,也有点混乱,现在想来我觉得并不好。

看群里大佬说可以用一个 MUX 来控制当前数是和寄存器出来的数比大小还是和 5'd7 比大小,我觉得非常好,实在太强了orz。
具体来说,可以搞一个 最大值为 2 的计数器,设置其达到最大值后保持不变,把 carry 端连到 MUX 的选择信号端。第一个上升沿到来时选择 5'd7,之后的上升沿到来时选择寄存器出来的值。

太巧妙了orz…


第二题

题干

搭建一个 Mealy 机,实现下述功能:

通过输入 op(操作符)和 operant(操作数),算出值保存到寄存器中。由于是 Mealy 机,记得要异步输出结果。

2 位宽的输入 op,各种输入含义如下:

  • 00:同步复位

  • 01:将当前值逻辑左移一位,再加上操作数。

  • 10:将当前值逻辑左移一位,再减去操作数。

  • 11:将当前值逻辑左移一位,与操作数按位异或。

感悟

这题较简单,记得是 Mealy 机要异步输出就行。


第三题

题干

题目假设有一个可以无限上人的电梯,运行在 4 层楼间(0,1,2,3),从一个给定的楼层 from 处开始运行。四层楼都有人要乘电梯,人数各不相同。电梯按照从人多到人少的顺序去接客,要设计一个组合电路计算电梯接下所有客人时总共经过了多少层楼。因电梯从 from 处开始运行,故 from 楼的客人立刻上电梯。
从 n 楼运行到 m 楼经过的楼层是 |m - n|。

感悟

因为第一题花费太多时间导致我没能在上机的时候完成这题(悲

隔天来看,这题其实还是有难度的。难点在于如何实现从人多到人少的运行顺序。我采用的方法是冒泡排序,在只有 4 个输入的时候还是非常好用的。接下来一个问题是如何把人数和楼层数绑定,排序肯定只针对于楼层的人数。我又采用了一个笨办法,排完序之后每个值和输入的四个值挨个比较,如果相等就代表楼层号是这个(

最后绝对值的实现可以用 Subtractor 和 Negator 实现。Subtractor 有一个端口用来监控减法是否得到负数,如果为负数,用一个 MUX 选择差的相反数即可。

还有一点要注意就是 Comparator 的比较方法,要依题目选定是无符号比较还是补码比较。

-------------本文结束 感谢您的时间-------------

欢迎关注我的其它发布渠道