状态机设计(共7页).doc

上传人:飞****2 文档编号:13448812 上传时间:2022-04-29 格式:DOC 页数:7 大小:85.50KB
返回 下载 相关 举报
状态机设计(共7页).doc_第1页
第1页 / 共7页
状态机设计(共7页).doc_第2页
第2页 / 共7页
点击查看更多>>
资源描述

《状态机设计(共7页).doc》由会员分享,可在线阅读,更多相关《状态机设计(共7页).doc(7页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。

1、精选优质文档-倾情为你奉上状态机设计 FSM简介: FSM 分两大类:米里型和摩尔型,组成要素有输入(包括复位),状态(包括当前状态的操作),状态转移条件,状态的输出条件,图1为状态机结构图。设计FSM 的方法和技巧多种多样,但是总结起来有两大类:第一种,将状态转移和状态的操作和判断等写到一个模块(process、block)中。另一种是将状态转移单独写成一个模块,将状态的操作和判断等写到另一个模块中(在Verilog代码中,相当于使用两个“always” block)。其中较好的方式是后者。其原因如下: 首先FSM 和其他设计一样,最好使用同步时序方式设计,好处不再赘述。而状态机实现后,状态

2、转移是用寄存器实现的,是同步时序部分。状态的转移条件的判断是通过组合逻辑判断实现的,之所以第二种比第一种编码方式合理,就在于第二种编码将同步时序和组合逻辑分别放到不同的程序块(process,block)中实现。这样做的好处不仅仅是便于阅读、理解、维护,更重要的是利于综合器优化代码,利于用户添加合适的时序约束条件,利于布局布线器实现设计。图1为状态机结构图 显式的FSM 描述方法可以描述任意的FSM(参考Verilog 第四版P181 有限状态机的说明)。两个always 模块。其中一个是时序模块,一个为组合逻辑。时序模块设计与书上完全一致,表示状态转移,可分为同步与异步复位。 同步: alw

3、ays (posedge clk) if (!reset) 异步: always (posedge clk or negedge reset) if (!reset) 专心-专注-专业组合逻辑用case 语句,sensitive list 包括当然状态(current state)和输入(a,b,c)。 编者注:以下是编者从“State Machine Coding Styles for Synthesis”一文中摘取的程序代码,是一个简单状态机的示例,采用两个always块的方法: module bm1_s (err, n_o1, o2, o3, o4,i1, i2, i3, i4, clk

4、, rst); output err, n_o1, o2, o3, o4; input i1, i2, i3, i4, clk, rst; reg err, n_o1, o2, o3, o4; parameter 2:0 /可以在此处添加综合约束属性来限定状态机的编码:binary,one-hot,gray,etc IDLE = 3d0, S1 = 3d1, S2 = 3d2, S3 = 3d3, ERROR = 3d4; reg 2:0 state, next; always (posedge clk or posedge rst)/异步复位,时序逻辑 if (rst) state = ID

5、LE; else state = next; always (state or i1 or i2 or i3 or i4) begin /组合逻辑,敏感列表包含当前状态以及所有的状态机输入 next = 3bx;/设置默认值,以便防止因为if或者case语句不完整综合生成锁存器 err = 0; n_o1 = 1; o2 = 0; o3 = 0; o4 = 0; case (state) IDLE: begin next = ERROR;/如果下面所有的if条件都不符合,则对next赋该默认值 if (!i1) next = IDLE; if (i1 & i2) next = S1; if (

6、i1 & !i2 & i3) next = S2; end S1: begin next = ERROR; if (!i2) next = S1; if (i2 & i3) next = S2; if (i2 & !i3 & i4) next = S3; n_o1 = 0; o2 = 1; end S2: begin next = ERROR; if (i3) next = S2; if (!i3 & i4) next = S3; o2 = 1; o3 = 1; end S3: begin next = S3; if (!i1) next = IDLE; if (i1 & i2) next =

7、 ERROR; o4 = 1; end endmodule 对于状态机的输出可以通过寄存器寄存一下,消除毛刺,这将另外需要一个always块,也就是状态机三个always块的写法。 编码风格: 1. 避免生成锁存器 一个完备的状态机(健壮性强)应该具备初始化(reset)状态和默认(default)状态。当芯片加电或者复位后,状态机应该能够自动将所有判断条件复位,并进入初始化状态。需要注 明的一点是,大多数FPGA 有GSR(Global Set/Reset)信号,当FPGA 加电后,GSR 信号拉高,对所有的寄存器,RAM 等单元复位/置位,这时配置于FPGA 的逻辑并未生效,所以不能保证正

8、确的进入初始化状态。所以使用GSR 进入FPGA 的初始化状态,常常会产生种种不必一定的麻烦。一般简单方便的方法是采用异步复位信号,当然也可以使用同步复位,但是要注意同步复位的逻辑设计。状态机也应该有一个默认(default)状态,当转移条件不满足,或者状态发生了突变时,要能保证逻辑不会陷入“死循环”。这是对状态机健壮性的一个重要要求,也就是常说的要具备“自恢复”功能。对应于编码就是对case,ifelse 语句要特别注意,要写完备的条件判断语句。VHDL 中,当使用CASE 语句的时候,要使用“When Others”建立默认状态。使用“IF.THEN.ELSE”语句的时候,要在“ELSE”

9、指定默认状态。Verilog 中,使用“case”语句的时候要用“default”建立默认状态,使用“if.else”语句的注意事项相似。 另外有一个技巧:大多数综合器都支持Verilog 编码状态机的完备状态属性“full case”。这个属性用于指定将状态机综合成完备的状态,如Synplicity 的综合工具(Synplify/Synplify Pro)支持的命令格式如下: case (current_state) / synthesis full_case 2b00 : next_state = 2b01; 2b01 : next_state = 2b11; 2b11 : next_st

10、ate = 2b00; /这两段代码等效 case (current_state) 2b00 : next_state = 2b01; 2b01 : next_state = 2b11; 2b11 : next_state = 2b00; default : next_state = 2bx; Synplicity 还有一个关于状态机的综合属性,叫“/ synthesis parallel_case”其功能是检查所有的状态是“并行的”(parallel),也就是说在同一时间只有一个状态能够成立。 编者注:使用上述两个综合约束属性会造成综合前后仿真结果的不一致,请慎重使用。 2. 参数定义用pa

11、rameter 状态的定义用parameter 定义,不推荐使用define 宏定义的方式,因为define 宏定义在编译时自动替换整个设计中所定义的宏,而parameter 仅仅定义模块内部的参数,定义的参数不会与模块外的其他状态机混淆。 3. 时序电路中一定要使用”=”非阻塞赋值方式 Verilog的非阻塞行赋值模拟的是实际硬件中串行寄存器的行为,排除了很多潜在的竞争冒险。在使用非阻塞赋值的时候,很多设计者采用intra-assignment timing delay(在非阻塞赋值前人为加入一个很小单位的延时)。如下例: always (posedge clk or posedge rst

12、) if (rst) state = #1 IDLE; else state = #1 nextstate; 关于这种写法的阐释有下面几点: I. 首先,这种描述是行为级描述方式,仅仅在仿真时起作用,在综合时会自动被综合器忽略。也就是通常所说的延时描述是不可综合的。 II. 这种描述的好处之一是:它简单模拟了赋值过程寄存器内部的clock-to-output 的延时,在做行为级功能仿真的时候,也可以发现一些由于寄存器固有延迟造成的时序和功能问题。 III. 避免了由RTL 级代码向门级描述转变过程中的一些潜在错误,如保持时间带来的问题。 4 不论是二进制编码的FSM,还是独热码FSM,复位时状

13、态寄存器应该赋值为IDLE状态,如下: always( posedge clk or posedge rst ) if( rst ) state = #1 IDLE; else state = #1 next; 如果实现简化的独热码FSM,复位时状态寄存器首先赋值为全零,然后再立即置位状态寄存器的IDLE位。注意:两个非阻塞性赋值作用在同一位上。这完全符合Verilog标准 规定,在此情况下,最后的非阻塞性赋值会代替前面所有的非阻塞性赋值,即更新状态机的IDLE位,如下所示: always( posedge clk or posedge rst ) if( rst ) begin state

14、= 5b0; stateIDLE = 1b1; end else state = next; 5 状态机中组合逻辑块的赋值 在组合always块中只能使用阻塞性赋值。来自同步always块的状态寄存器和状态机的所有输入触发组合always块,该块更新下一状态。应该在组合always块的最前面为下一状态赋一个默认值,块内的case语句会更新该默认值。通常下一状态有三种默认值:全x;预定的恢复状态,如IDLE;状态寄存器的当前值。如果默认值为全x,那么前仿真模型会使状态机在没有任何明确的状态转移时,输出未知。这不仅有利于状态机的调试,还有利于综合,因为综合工具将x作为无关。一些设计(如卫星应用,媒

15、体应用,需要使用FSM触发器作为检测扫描链的设计和使用正规验证工具做等价检测的设计)要求下一状态是已知的,而不是全x。通常这些设计下一状态的默认值应该是IDLE或全零,才能满足设计的要求。将下一状态初始化为默认值,可能比在每个case语句中指定明确的状态转移更简单。 6 Synplify中状态机设计: 可以在Synplify中添加在state定义时添加如下约束属性来限定状态机的编码: reg 2:0 state /* synthesis syn_encoding = onehot */; Synplify中包含一个强大的FSM编辑器,可以产生在时间和面积上均得到优化的状态机设计,但这将忽略一些

16、状态机中未定义的状态(invalid state),如果必须在状态机进入了未定义的状态后能自动回到有效状态,可以在状态机生成时添加一个安全属性(safe),使得到达无效状态时能回到初始状态,这对电路的时间和面积产生很小的影响:reg 2:0 state /* synthesis syn_encoding = safe,onehot */; 这种方法可能与源代码中实际描述的不一致,对于大多数设计来说这不会产生问题,但如果必须与源代码中描述的状态机流程图相吻合,可以通过约束属性关掉FSM编辑器:reg 4:0 state /* synthesis syn_preserve=1 */;但这将严重影响

17、电路的时间和面积特性,下表是将三种方法应用在Altera Flex10k 和 Xilinx Virtex上的比较:编者注:对第5条和第6条在Synplicity公司的Application Note ”Designing Safe Verilog State Machines with Synplify”中有更详细的说明。 7 几种状态机编码比较: 状态机编码有gray、binary、onehot 等,其中Binary、gray-code 编码使用最少的触发器,较多的组合逻辑。而one-hot 编码反之。由于CPLD 更多的提供组合逻辑资源,而FPGA 更多的提供触发器资源,所以CPLD 多使

18、用gray-code,而FPGA 多使用one-hot 编码。另一方面,对于小型设计使用gray-code 和binary 编码更有效,而大型状态机使用one-hot更高效。看synplicity 的文档,推荐在24 个状态以上会用格雷码,在524 个状态会用独热码,在4 个状态以内用二进制码,肯定独热码比二进制码在实现FSM 部分会占更多资源,但是译码输出控制简单,所以如果状态不是太多,独热码较好。状态太少译码不会太复杂,二进制就可以了。状态太多,前面独热码所占资源太多,综合考虑就用格雷码了。在代码中添加综合器的综合约束属性或者在图形界面下设置综合约束属性可以比较方便的改变状态的编码。在sy

19、nplify 综合时,把FSM compile 勾上,就算用binary 表示,综合器会自动综合成one-hot 模式。 也可在coding 时直接添加描述:VHDL attribute TYPE_ENCODING_style of : type is ONEHOT; Verilog Reg2:0 state; / synthesis syn_encoding = value(onehot) 其中onehot编码又分为几种:verbose one-hot 、simplified one-hot、one-hot with zero-idle,关于其具体区别请参考“State Machine Co

20、ding Styles for Synthesis“一文。 8 同步状态机输入变量的处理 所有的输入变量都必须与状态机时钟同步,否则,状态机的实际运行可能出现奇怪的现 象,会莫名其妙地出现非法状态。所有的状态机都不可避免地可能死锁,在运行中间歇地中止。为什么呢?这是因为,实际上所有的物理状态机是用物理门实现的,而物理门的传播延时不为0。输入信号经过不同的物理门组合到不同的状态触发器输入端D的传播延时有细微的差别。如果输入信号正好在错误的时间改变,那么较快的通路会探测到变化,而较慢的通路则不会。时钟是不变的,所以必定有一个触发器会出现错误的电平。这样就导致状态转移错 误,整个状态机电路就会误动作

21、。这种设计错误通常不被人注意,因为误动作的几率很小。所以,一定要注意异步输入。解决异步输入的办法是同步器,通常二级同步器能够预防错误的状态入口。虽然可能性很小,还是必须注意一个统计问题,即异步输入还是有可能传播通过同步器。因为两个同步阶段的出现,这种可能性被大大地减小了。一些空间或军事设计需要使用三级同步器,但是对于商业和工业级设计,二级同步器已经足够了。为了最大的减小延迟,第一级使用下降沿触发,第二级使用上升沿触发。 9 FSM输出产生 FSM的输出逻辑可以编码为一个独立的连续赋值块,也可以编码为一个组合逻辑always块。如果输出赋值编码到组合always块中,那么输出赋值就可以放到Ver

22、ilog的task中,每 个case语句调用task。将输出赋值与组合always块分开,不仅有利于在需要更改时改变输出逻辑,还可以避免综合工具产生意外的锁存器。双always块状态机中,如果将输出赋值放在组合always块内,那么应该在always块的顶部初始化输出为默认值,任何case语句将输出改变为合适值。通常,这种方法使用的代码比在每个case语句中为输出赋值更少,并且可以突出输出的变化。Mealy和寄存输出使用连续赋值或在组合always块中,很容易添加Mealy输出,具体如下: assign rd_out = ( state = READ ) & !rd_strobe_n; cas

23、e( state ) . READ: if( ! rd_strobe_n ) rd_out = 1b1; 需要注意的是经过状态转移组合输出会出现很窄的毛刺。由于时钟的倾斜,不等的时钟到输出延时Tco和不等的组合逻辑传播延时,毛刺会不断出现。这种毛刺可能很窄,也可能在大多数逻辑分析仪和一些示波器上看见。被这些输出驱动的电路的敏感沿肯定有毛刺,并且可能导致电路错误。更糟糕的是,毛刺的宽度随着温度和功耗变化。为此我们可以在时序always块内使用非阻塞性赋值实现寄存输出。FSM可以使用一个时序always块,也可以在第二个时序always块添加相应的代码。此外如果状态比较简单,还可以定义这样一种状态机,它的输出就是状态位:assign OUT3, OUT2, OUT1, OUT0 = state3:0; 这样每个输出的时序都可预测,并且传播延时最小。这样的输出是没有毛刺的,因为假设输入的建立时间Ts和保持时间Th是可观测的,那么每个时钟最多只有一个触发器变化。如果一个输出对于两个连续的状态都是逻辑1,并且输入采取同步方法,那么就可以保证输出的下降沿不会出现毛刺。

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 教育专区 > 教案示例

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号© 2020-2023 www.taowenge.com 淘文阁