●什么是有限状态机(FSM)?
FSM= 输入 + 状态 + 输出
更详细的介绍请参考https://en.wikipedia.org/wiki/Finite-state_machine
●状态机的类型
●写法:
组合逻辑:下一状态逻辑+输出逻辑;
时序逻辑:当前状态逻辑;
●复位:
★异步复位:在时钟跑起来之前(开机阶段)就可以控制状态机的状态,保证状态机处于正常工作的状态中,因此不用考虑尚未使用的状态。
异步复位可以写在当前状态逻辑或下一状态逻辑中。
★同步复位:不能控制状态机的初始状态,除非开机后强行复位,因此需要考虑状态机未使用的状态,让它能够转入正常工作状态中,这意味着更复杂的状态转移逻辑,和较大的面积(通常也不是好大,因为同步复位的触发器面积本身比异步复位的触发器面积小)。
同步复位只能写在当前状态逻辑中。
●状态编码
常见的状态编码的方法如下图所示
Gray编码和Johnson编码在状态转移的时候只有一个比特发生变化,这是为了减少在触发器建立时间里异步输入造成的状态转移错误的概率(因为每次状态转移只有一个比特发生变化,错误概率大大降低)。
Johnson编码有很多未使用的编码,因此要使用异步复位,否则就要对所有2^n个状态进行编码,让状态机能从未使用的状态转入正常工作状态。
●交互式状态机:一个状态机的当前状态或者输出影响到其它的状态机。
★单向
★双向
●不好的状态机:
★首先,这个状态机有三个正常工作状态,因此需要两个D触发器,所以会有一个未使用的状态。但是,这个状态机没有复位信号,又没有给未使用的那个状态进行编码,让它转入正常工作状态。这样,这个状态机可能出现在开机阶段陷入未使用的状态里“出不来”的情况。
★再者,下一状态逻辑、当前状态逻辑、和输出逻辑都写入到了同一个always里面,这样会综合出不必要的触发器来。
●好的状态机:
★首先,有复位信号,避免了状态机陷入未使用状态出不来的问题。
★组合逻辑和时序逻辑分开写,避免生成不必要的D触发器
小结:一般用三段式来写就不会有什么问题。
~翻译得怪怪的
●输入分支指示:inputs primary branch directive;
●状态分支指示:state value primary branch directive;
小结:
目前还看不出inputs primarybranch directive 有什么好处,还是先用比较简单常用的statevalue primary branch directive吧。
~实在是不想进行奇怪的翻译动作了。。。
●Angular Position FSM:
●亚稳态:
★建立时间(SetupTime):器件输入端在时钟有效沿到来以前,要求输入信号保持稳定不变的时间。
★保持时间(HoldTime):器件输入端在时钟有效沿到来以后,要求输入信号保持稳定不变的时间。
★延迟时间 = 输出响应时间(tffpd) + 组合逻辑延迟(tcomb)
▼输出响应时间(tffpd):在时钟有效沿到来之后,触发器输出从变化到稳定的时间。
▼组合逻辑延迟:触发器输出经过组合逻辑电路需要的时间。
★建立时间容限:器件允许的安全的建立时间的长度范围。
建立时间容限 = 时钟周期 - 输出响应时间(max) - 组合逻辑延迟(max) - 建立时间 >= 0;
★保持时间容限:器件允许的安全的保持时间的长度范围。
也就是说,在HoldTime内,触发器输入信号必须保持稳定,在此期间,上一级触发器的输出信号不能到来。
保持时间容限 = 输出响应时间(min) + 组合逻辑延迟(min) - 保持时间 >= 0;
亚稳态:如果输入信号在建立时间或者保持时间内变化,输出将不可预判,触发器便进入亚稳态。
为什么格雷编码和Johnson编码可以减小状态转移错误的概率?
因为每次时钟上升沿到来的时候,至多只有一个触发器在发生变化,相比于其它编码方式,整体电路进入亚稳态的概率大大降低。
●代码分析:
小结:如果使用johnson编码,就要使用异步复位,以防止开机的时候电路进入未使用的状态。可以使用`include或者`define来实现对状态的不同编码方式。
注意:parameter不允许指定参数的位宽,比如“parameter [2:0] police = 3'b 110;”是错误的用法。
`define 的用法:
`define police 110
然后用的时候,用的是"`police"而不是"police";
`define和parameter的区别:parameter只是对该模块有效,而`define对整个工程都有效。即作用域不一样。
●三段式状态机的好处:
★符合思维习惯
★可消除组合逻辑毛刺和不稳定的隐患(可使FSM做到同步寄存器输出)
★更利于时序路径分组
小结:
代码中都使用的是阻塞赋值。但是,一般情况下,跟时钟上升沿有关系的赋值应采用非阻塞赋值。
阻塞赋值和非阻塞赋值的使用原则:
(1) 时序电路建模时,用非阻塞赋值。
(2) 锁存器电路建模时,用非阻塞赋值。
(3) 用always块建立组合逻辑模型时,用阻塞赋值。
(4) 在同一个always块中建立时序和组合逻辑电路时,用非阻塞赋值。
(5) 在同一个always块中不要既用非阻塞赋值又用阻塞赋值。
(6) 不要在一个以上的always块中为同一个变量赋值。
(7) 用$strobe系统任务来显示用非阻塞赋值的变量值。
(8) 在赋值时不要使用#0延时。
在编写时牢记这八个要点可以为绝大多数的Verilog用户解决在综合后仿真中出现的90-100% 的冒险竞争问题。
冒险竞争:组合电路中,同一个器件的不同引脚的信号在不同的时间到达,叫竞争,竞争导致的毛刺,叫冒险。
●补充:verilog中case、casex、和casez的区别:
★casex的分支表达式某些位的值可以为x(或z),当这些位的值是x(或z)时,这些位在比较过程中将被忽略。
比如,
★casez的分支表达式某些位的值可以为z,当这些位的值是z时,这些位在比较过程中将被忽略。
参考资料:Douglas J Smith. HDL Chip design: a practical guide for designing, synthesizing, and simulating ASICs and FPGAs using VHDL or Verilog