BUAA-CO-P1-课下
FSM
T1_饮料机
饮料价格为2元,顾客只能选择投0.5元、1元、退回所有硬币、不投。当投币总额不足2元,
drink
置0,当投币总额超过2元,drink
置1,同时back
置超出的钱币。若选择退回所有硬币,back
置退回钱币。出货的周期仍然可以投币
信号名 方向 描述 clk I 时钟信号 reset I 异步复位信号,回归初始状态,所有输出为0 coin[1:0] I 投入的硬币,2’b00代表未投币,2’b01代表投入5角,2’b10代表投入1元,2’b11代表按下退币按钮 drink O 顾客是否能获得饮料,1代表是,0代表否 back[1:0] O 售货机返还的钱数,2’b00代表不返还,2’b01代表5角,2’b10代表1元,2’b11代表1.5元
根据“出货的周期仍可以投币”得知,这一定是一个Mealy机。如果是Moore机,显然需要到达一个“输出状态”,同时出货,再继续处理投币,即出货周期不接受投币。而Mealy机可以在转移的同时处理投币。
Mealy机可以把输出和状态转移写在一起,不过这样的话需要把输出设置成reg
,并且不要忘记在always
块头部进行初始化。
T2_表达式状态机
表达式定义:单个数字是表达式;如果X是,Y是,那么X+Y和X*Y也是
每个时钟上升沿读入一个ASCII码字符,判断目前已读入的所有字符组成的字符串是否符合表达式定义
有点小坑的一道题。根据定义,12+34
,1++
等包含连续数字或符号的字符串都不是表达式。但是发现,status
只能记录前一个状态,并不能表示出“之前有没有错误”(显然,一个非表达式无论与什么内容拼接,都不能再得到表达式)。
举个例子,输入1
,状态表示“读入数字”,再输入2
,状态依旧表示“读入数字”,这时如果读入+3
,状态将显示“数字、字符、数字”,即“是表达式”,但这其实并不是表达式。
为解决这个问题,只需要加入另一个寄存器error
,记录曾经出现过的错误(例如数字后又输入了一个数字),当error == 1
时无论如何输出“错误”,并且仅在reset
时才清零。
T3_带括号的表达式状态机
只考虑带一层括号的情况,如
(1+2*3)
,不需要识别嵌套括号
我写状态机的原则是除status
以外,其他变量越少越好,这样可以简化输出时的判断条件,避免一堆if...else...
和&&...||...
混杂在一起,导致难以发现的bug。我的舍友为了减少状态数量,多加了一个left
变量,以记录是否有未匹配的左括号,导致了一些两个人都de不出来的bug,非常难受…
我的状态图:
testbench的优雅写法
1 | reg [0:1023] S = "input_string"; |
rofie简直是个天才,完美解决了与字符串相关的testbench太难写的问题。定义了reg[0:1023]
来存储要输入的字符串(个人理解,从小端开始是为了防止取值时不知道引脚的具体数值),由于字符串被放在最右侧,所以要不断左移,直到开始有内容,随后每次读取0:7
位的内容输入到in
的7:0
位
BUAA-CO-P1-课下