资源描述
时序电路的状态是一个状态变量集合,这些状态变量在任意时刻的值都包含了为 确定电路的未来行为而必需考虑的所有历史信息。状态机采用VerilogHDL语言编码,建议分为三个always段完成。这是为 什么呢?设计FSM的方法和技巧多种多样,但是总结起来有两大类:第一种,将状态 转移和状态的操作和判断等写到一个模块(process、block)中。另一种是将状 态转移单独写成一个模块,将状态的操作和判断等写到另一个模块中(在 Verilog代码中,相当于使用两个“always” block)o其中较好的方式是后者。 其原因如下。首先FSM和其他设计一样,最好使用同步时序方式设计,好处不再累述。 而状态机实现后,状态转移是用寄存器实现的,是同步时序部分。状态的转移条 件的判断是通过组合逻辑判断实现的,之所以第二种比第一种编码方式合理,就 在于第二种编码将同步时序和组合逻辑分别放到不同的程序块(process, block) 中实现。这样做的好处不仅仅是便于阅读、理解、维护,更重要的是利于综合器 优化代码,利于用户添加合适的时序约束条件,利于布局布线器实现设计。三段式建模描述FSM的状态机输出时,只需指定case敏感表为次态寄存器, 然后直接在每个次态的case分支中描述该状态的输出即可,不用考虑状态转移 条件。三段式描述方法虽然代码结构复杂了 一些,但是换来的优势是使FSM做到了 同步寄存器输出,消除了组合逻辑输出的不稳定与毛刺的隐患,而且更利于时序 路径分组,一般来说在FPGA/CPLD等可编程逻辑器件上的综合与布局布线效果更 佳。示例如下:第一个进程,同步时序always模块,格式化描述次态寄存器迁移到现态寄存 器always (posedge clk or negedge rst_n)异步复位if(!rst_n)current_state = IDLE;elsecurrent-state = next_state;/注意,使用的是非阻塞赋值 第二个进程,组合逻辑always模块,描述状态转移条件判断 always (current-state) 电平触发beginnext-state = x;/要初始化,使得系统复位后能进入正确的状态case(current_state)S1: if(.)next-state = S2;/阻塞赋值.endcaseend第三个进程,同步时序always模块,格式化描述次态寄存器输出always (posedge clk or negedge rst_n)./初始化case(next_state)S1:outl = 1b1;注意是非阻塞逻辑S2:out2 = 1b1;default:. /default的作用是免除综合工具综合出锁存器。endcaseend三段式并不是一定要写为3个always块,如果状态机更复杂,就不止3段了。注:=1. 三段always模块中,第一个和第三个always模块是同步时序always模块, 用非阻塞赋值(“ =”);第二个always模块是组合逻辑always模块,用 阻塞赋值(“=”)。2. 第二部分为组合逻辑always模块,为了抑制warning信息,对于always的 敏感列表建议采用always( *)的方式。3. 第二部分,组合逻辑always模块,里面判断条件一定要包含所有情况!可 以用else保证包含完全。4. 第二部分,组合逻辑电平要维持超过一个clock,仿真时注意。5. 需要注意:第二部分case中的条件应该为当前态(current_state),第三 部分case中的条件应该为次态(next_state)。6. 编码原则,binary和gray-code适用于触发器资源较少,组合电路资源丰富 的情况(CPLD),对于FPGA,适用one-hot code。这样不但充分利用FPGA 丰富的触发器资源,还因为只需比较一个bit,速度快,组合电路简单。7. 初始化状态和默认状态。一个完备的状态机(健壮性强)应该具备初始化状态和默认状态。当芯片 加电或者复位后,状态机应该能够自动将所有判断条件复位,并进入初始化状态。 需要注明的一点是,大多数FPGA有GSR(Global Set/Reset)信号,当FPGA加 电后,GSR信号拉高,对所有的寄存器,RAM等单元复位/置位,这时配置于FPGA 的逻辑并未生效,所以不能保证正确的进入初始化状态。所以使用GSR企图进入 FPGA的初始化状态,常常会产生种种不必一定的麻烦。一般的方法是采用异步 复位信号,当然也可以使用同步复位,但是要注意同步复位的逻辑设计。解决这 个问题的另一种方法是将默认的初始状态的编码设为全零,这样GSR复位后,状 态机自动进入初始状态。令一方面状态机也应该有一个默认(default)状态,当转移条件不满足, 或者状态发生了突变时,要能保证逻辑不会陷入“死循环”。这是对状态机健壮 性的一个重要要求,也就是常说的要具备“自恢复,功能。对应于编码就是对 case,if-else语句要特别注意,要写完备的条件判断语句。VHDL中,当使用 CASE语句的时候,要使用“When Others”建立默认状态。使用“IF.THEN.ELSE”语句的时候,要用在“ELSE”指定默认状态。Verilog中, 使用“case”语句的时候要用“default”建立默认状态,使用“if.else”语 句的注意事项相似。8. 另外提一个技巧:大多数综合器都支持Verilog编码状态机的完备状态属性-“full case”。这个属性用于指定将状态机综合成完备的状态,如 Synplicity 的综合工具(Synplify/Synplify Pro,Amplify, etc )支持的 命令格式如下:case (current_state) / synthesis full_case2b00:next_state=2b01;2b01:next_state=2b11;2b11:next_state=2b00;/这两段代码等效case (current_state)2b00:next_state=2b01;2b01:next_state=2b11;2b11:next_state=2b00;default : next_state = 2bx;9. Synplicity还有一个关于状态机的综合属性,叫“synthesisparallel_case,其功能是检查所有的状态是“并行的” (parallel ), 也就是说在同一时间只有一个状态能够成立。10. 状态机的定义可以用parameter定义,但是不推荐使用define宏定义 的方式,因为define宏定义在编译时自动替换整个设计中所定义的宏,而 parameter仅仅定义模块内部的参数,定义的参数不会与模块外的其他状态 机混淆。11. 对于状态比较多的状态机,可以将所有状态分为几个大状态,然后再使 用小状态,可以减少状态译码的时间。12. 在代码中添加综合器的综合约束属性或者在图形界面下设置综合约束 属性可以比较方便的改变状态的编码。如VHDL的示例:Synplicity:attribute syn_encoding : string;attribute syn_encoding of : type is value ;-The syn_encoding attribute has 4 values : sequential, onehot, gray and safe.Exemplar:-Declare TYPE_ENCODING_STYLE. attribute-Not needed if the exemplar_1164 package is usedtype encoding-style. is (BINARY, ONEHOT, GRAY, RANDOM, AUTO); attribute TYPE_ENCODING_STYLE. encoding-style;.attribute TYPE_ENCODING_STYLE. of : type is ONEHOT;Verilog 示例:Synplicity:Reg2:0 state; /* synthesis syn_encoding = value */;/ The syn_encoding attribute has 4 values : sequential, onehot, gray and safe.Exemplar:Parameter /* exemplar enum */ s0 = 0, s1 = 1, s2 = 2, s3 = 3, S4 = 4;Reg 2:0 /* exemplar enum */ present_state, next_state ;13. 小技巧:仔细检查综合器的综合报告,目前大多数的综合器对所综合出的latch都会报“warning”,通过综合报告可以较为方便地找出无意中生 成的latch
展开阅读全文