两段式状态机写法
三段式状态机

三段式状态机时序电路的状态是一个状态变量集合,这些状态变量在任意时刻的值都包含了为确定电路的未来行为而必需考虑的所有历史信息。
状态机采用VerilogHDL语言编码,建议分为三个always段完成。
三段式建模描述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:out1 <= 1'b1; //注意是非阻塞逻辑S2:out2 <= 1'b1;default:... //default的作用是免除综合工具综合出锁存器。
第五讲 状态机设计及其指导原则

第五讲状态机设计及其指导原则 11/ 38
带流水线的Mealy 状态机
下一个状态 = F(当前状态,输入信号); 输出信号 = G(当前状态,输入信号);
组合逻辑
时序逻辑 当前状态
组合逻辑 输出 译码器 G
时序逻辑
输出流 水线寄 存器 clk 输入
输入
状态 激励信号 状态 寄存器 译码器 F
第五讲状态机设计及其指导原则 3/ 38
原语描述
module noconditional (clk,nrst,state,event); input clk,nrst input state; output event; reg event;
reg reg [2:0] CS; //CurrentState [2:0] NS; //NextState
制作人:梁瑞宇 单位:河海大学
第五讲状态机设计及其指导原则 5/ 38
制作人:梁瑞宇 单位:河海大学
第五讲状态机设计及其指导原则 6/ 38
状态机的本质--对具有逻辑顺序或
时序规律事件的一种描述方法
状态机的两个应用思路: - 从状态变量入手
- 明确电路的输出的关系
制作人:梁瑞宇 单位:河海大学
制作人:梁瑞宇 单位:河海大学
第五讲状态机设计及其指导原则 17/ 38
case……endcase 语法格式: case (case_expression) case_item1:case_item_statement1; case_item2:case_item_statement2; case_item3:case_item_statement3; case_item4:case_item_statement4; default:case_item_statement5; endcase 使用default关键字来描述FSM所需状态的补集状态 下的操作,避免FSM进入死循环。 建议初学者使用完整的case 结构,而不使用casex 或casez。
关于使用FPGA三段式状态机的三点好处,你有什么看法?

关于使用FPGA三段式状态机的三点好处,你有什么看法?用三段式描述状态机的好处,国内外各位大牛都已经说的很多了,大致可归为以下三点:1.将组合逻辑和时序逻辑分开,利于综合器分析优化和程序维护;2.更符合设计的思维习惯;3.代码少,比一段式状态机更简洁。
对于第一点,我非常认可,后两点在Clifford E. Cummings著的(Synthesizable Finite State Machine Design Techniques Using theNew SystemVerilog 3.0 Enhancements和The Fundamentals ofEfficient Synthesizable Finite State Machine Design using NC-Verilog andBuildGates)中多次提到,我并不完全赞同,下面谈谈我的一些看法。
先谈谈第二点关于思维习惯。
我发现有些人会有这样一种习惯,先用一段式状态机实现功能,仿真ok后,再将其转成三段式,他们对这种开发方式的解释是一段式更直观,可以更便捷的构建功能框架,但是大家都说三段式性能会更好,所以最后又在搭好的逻辑框架下,将一段式转化为了三段式。
这从一个侧面说明了,对一部人来说一段式更符合他们的思维习惯,但当已经习惯了一段式的思维方式后,再要换用三段式时,可就不这么容易了,一段式和三段式的写法之间存在着思维陷阱,特权同学也曾经不小心在此失足过。
举一个例子,初始状态是wr_st,q和p输出都为0,当计数器count计数到指定的数值10后,输出结束信号end,状态机接收到end有效后跳转为rd_st,同时输出q变为1,在rd_st 状态,如jump有效则跳转到erase_st,如end有效p输出0否则输出1,用一段式实现起来很简单,如下所示。
assign end = (count == 10);always @(posedge clk)begincase(state)wr_st:if(end)begin。
verilog有限状态机实验报告范文(附源代码)

verilog有限状态机实验报告范文(附源代码)有限状态机实验报告一、实验目的进一步学习时序逻辑电路了解有限状态机的工作原理学会使用“三段式”有限状态机设计电路掌握按键去抖动、信号取边沿等处理技巧二、实验内容用三段式有限状态机实现序列检测功能电路a)按从高位到低位逐位串行输入一个序列,输入用拨动开关实现。
b)每当检测到序列“1101”(不重叠)时,LED指示灯亮,否则灭,例如i.ii.输入:1101101101输出:0001000001c)用八段数码管显示最后输入的四个数,每输入一个数,数码管变化一次d)按键按下的瞬间将拨动开关状态锁存i.注意防抖动(按键按下瞬间可能会有多次的电平跳变)三、实验结果1.Rt_n为0时数码管显示0000,led灯不亮,rt_n拨为1,可以开始输入,将输入的开关拨到1,按下按钮,数码管示数变为0001,之后一次类推分别输入1,0,1,按下按钮后,数码管为1101,LED灯亮,再输入1,LED灯灭,之后再输入0,1(即共输入1101101使1101重叠,第二次LED灯不亮),之后单独输入1101,LED灯亮2.仿真图像刚启动时使用rt_n一段时间后其中Y代表输出,即控制led灯的信号,el表示数码管的选择信号,eg表示数码管信号四、实验分析1、实验基本结构其中状态机部分使用三段式结构:2、整体结构为:建立一下模块:Anti_dither.v输入按键信号和时钟信号,输出去除抖动的按键信号生成的脉冲信号op这一模块实现思路是利用按钮按下时会持续10m以上而上下抖动时接触时间不超过10m来给向下接触的时间计时,达到上限时间才产生输出。
Num.v输入op和序列输入信号A,时钟信号clk和复位信号,复位信号将num置零,否则若收到脉冲信号则将num左移一位并将输入存进最后一位。
输出的num即为即将在数码管上显示的值Scan.v输入时钟信号,对其降频以产生1m一次的扫描信号。
Trigger.v这一模块即为状态机模块,按三段式书写。
verilog 状态机写法

verilog 状态机写法在Verilog中,有几种常用的状态机写法,包括Mealy状态机、Moore状态机和通用状态机。
下面简要介绍每种写法的特点:Mealy状态机:输出依赖于当前状态和输入信号。
输出的变化可以与状态的变化同步。
Verilog代码示例:module MealyFSM (input logic clk,input logic reset,input logic input_signal,output logic output_signal);enum logic [2:0] states;logic [2:0] current_state, next_state;always_ff @(posedge clk or posedge reset) beginif (reset)current_state <= states[0];elsecurrent_state <= next_state;endalways_comb begincase (current_state)states[0]: begin // State 0if (input_signal)next_state = states[1];elsenext_state = states[0];output_signal = input_signal & next_state[0]; // Output depends on current state and input signalendstates[1]: begin // State 1if (input_signal)next_state = states[0];elsenext_state = states[1];output_signal = input_signal | next_state[0]; // Output depends on current state and input signalend// Add more states and conditions as neededendcaseendEndmoduleMoore状态机:输出只依赖于当前状态。
状态机编程思路及方法

状态机编程思路及方法状态机是一种常用的编程思路和方法,用于描述系统或对象在不同状态下的行为和转换。
它可以帮助开发人员更好地理解和设计复杂的系统,并在实际应用中提高代码的可读性和可维护性。
本文将介绍状态机的基本概念、应用场景以及实现方法,并通过示例代码来说明其具体应用。
一、状态机的基本概念状态机,又称有限状态机(Finite State Machine,FSM),是一种计算模型,用于描述系统或对象的状态和状态之间的转换。
它由一组状态、一组转换规则和一个初始状态组成。
1. 状态(State):状态是系统或对象的某种特定情况或属性,可以是一个离散的值或一个更复杂的数据结构。
在状态机中,状态用于描述系统或对象所处的不同状态,例如开机、关机、运行等。
2. 转换(Transition):转换是状态之间的切换过程。
它可以由外部事件触发,也可以由内部条件满足时自动触发。
转换可以是简单的一对一关系,也可以是复杂的多对多关系。
在状态机中,转换规则定义了从一个状态到另一个状态的条件和操作。
3. 初始状态(Initial State):初始状态是系统或对象的初始状态。
在状态机中,初始状态是状态机开始执行时所处的状态。
二、状态机的应用场景状态机广泛应用于各个领域的软件开发中,特别是在需要处理复杂逻辑和状态转换的场景下。
以下是一些常见的应用场景:1. 交通信号灯控制:交通信号灯的状态可以有红灯、黄灯和绿灯,它们之间的转换规则由交通规则和时间控制。
2. 游戏角色行为控制:游戏角色的行为可以有站立、行走、跳跃等,它们之间的转换规则由玩家输入和游戏逻辑控制。
3. 订单状态管理:订单的状态可以有待支付、已支付、待发货、已发货等,它们之间的转换规则由用户行为和系统逻辑控制。
4. 业务流程管理:业务流程的状态可以有开始、进行中、暂停、结束等,它们之间的转换规则由业务规则和用户操作控制。
三、状态机的实现方法状态机的实现方法有多种,可以使用面向对象编程、函数式编程或表驱动等方式来描述和实现状态和转换规则。
Verilog可综合有限状态机的4种写法
Verilog可综合有限状态机的4种写法Verilog可综合有限状态机的4种写法第一种:自然编码1.module fsm1(2.input i_clk,3.input rst_n,4.input A,5.output reg K1,6.output reg K2,7.output reg [1:0] state8.);[/color][/font]9.[font=Times New Roman][color=#000000]parameter Idle=2'b00,10. Start=2'b01,11. Stop=2'b10,12. Clear=2'b11;[/color][/font]13.[font=Times NewRoman][color=#000000][email=always@(posedge]always@ (posedge[/email]i_clk)14.if(!rst_n)15.begin16. state<=Idle;17. K2<=0;18. K1<=0;19.end20.else21.case(state)22. Idle:if(A)23. begin24. state<=Start;25. K1<=0;26. end28. begin29. state<=Idle;30. K2<=0;31. K1<=0;32. end33. Start:if(!A)34. state<=Stop;35. else36. state<=Start;37. Stop:if(A)38. begin39. state<=Clear;40. K2<=1;41. end42. else43. begin44. state<=Stop;45. K2<=0;46. K1<=0;47. end48. Clear:if(!A)49. begin50. state<=Idle;51. K1<=1;52. K2<=0;53. end54. else55. begin56. state<=Clear;57. K2<=0;58. K1<=1;60. default:61. state<=Idle;62. endcase63.endmodule第二种:采用独热编码,据说其可靠性和速度都不错1.module fsm2(2.input i_clk,3.input rst_n,4.input A,5.output reg K1,6.output reg K2,7.output reg [3:0] state8.);9.10.parameter Idle=4'b1000;11.parameter Start=4'b0100;12.parameter Stop=4'b0010;13.parameter Clear=4'b0001;14.15.always@(posedge i_clk)16.begin17. if(!rst_n)18. begin19. state<=Idle;20. K2<=0;21. K1<=0;22. end23. else24. case(state)25. Idle:if(A)26. begin28. K1<=0;29. end30. else31. begin32. state<=Idle;33. K2<=0;34. K1<=0;35. end36. Start:if(!A)37. state<=Stop;38. else39. state<=Start;40. Stop:if(A)41. begin42. state<=Clear;43. K2<=1;44. end45. else46. begin47. state<=Stop;48. K1<=0;49. K2<=0;50. end51. Clear:if(!A)52. begin53. state<=Idle;54. K2<=0;55. K1<=1;56. end57. else58. begin60. K2<=0;61. K1<=0;62. end63. default:state<=Idle;64.endcase65.end66.endmodule第三种:把输出直接指定为状态码,即把状态码的指定和状态机的输出联系起来,状态的变化直接用做输出据说可以提高输出信号的开关速度并节省电路资源(希望了解其机理的高手们能够解说下时怎样提高开关速度的?)1.module fsm3(2.input i_clk,3.input rst_n,4.input A,5.output K1,6.output K2,7.output reg [4:0] state8.);9.10.11.assign K2=state[4];12.assign K1=state[0];13.14.parameter Idle =5'b00000;15.parameter Start =5'b00010;16.parameter Stop =5'b00100;17.parameter StopToClear =5'b11000;18.parameter Clear =5'b01010;19.parameter ClearToIdle =5'b00111;20.21.always@(posedge i_clk)22.if(!rst_n)23.begin24. state<=Idle;25.end26.else27.case(state)28. Idle:if(A)29. state<=Start;30. else31. state<=Idle;32. Start:if(!A)33. state<=Stop;34. else35. state<=Start;36. Stop:if(A)37. state<=StopT oClear;38. else39. state<=Stop;40. StopToClear:state<=Clear;41. Clear:if(!A)42. state<=ClearToIdle;43. else44. state<=Clear;45. ClearToIdle:state<=Idle;46. default:state<=Idle;47.endcase48.endmodule第四:把状态的变化和输出开关的控制分成两部分考虑1.module fsm4(2.input i_clk,3.input rst_n,4.input A,5.output reg K1,6.output reg K2,7.output reg[1:0] state8.);9.10.11.//reg [1:0] state;12.reg [1:0] nextstate;13.parameter Idle=2'b00,14. Start=2'b01,15. Stop=2'b10,16. Clear=2'b11;17.always@(posedge i_clk)18.if(!rst_n)19. state<=Idle;20.else21. state<=nextstate;22.23.always@(state or A)24. case(state)25. Idle:if(A)26. nextstate=Start;27. else28. nextstate=Idle;29. Start:if(!A)30. nextstate=Stop;31. else32. nextstate=Start;33. Stop:if(A)34. nextstate=Clear;35. else36. nextstate=Stop;37. Clear:if(!A)38. nextstate=Idle;39. else40. nextstate=Clear;41. default:nextstate=2'bxx;42. endcase43.always@(state or rst_n or A)44.if(!rst_n)45. K1<=0;46.else47. if(state==Clear&&!A)48. K1<=1;49. else50. K1<=0;51.52.always@(state or rst_n or A)53.if(!rst_n)54. K2<=0;55.else56. if(state==Stop&&A)57. K2<=1;58. else59. K2<=0;60.endmodule。
最新.7-多摩川编码器总结
2013.7 多摩川编码器总结一、摘要 基于CPLD 和DSP 实现CPLD 与多摩川编码器的通讯,通过对编码器发送请求,得到编码器发回的数据并进行解码,得到绝对位置值。
二、学习步骤: 1、熟悉工作环境,掌握Modelsim 以及Quartus 的使用。
2、阅读多摩川编码器的通讯协议。
3、根据协议编写testbench ,并在Modelsim 上进行仿真调试。
4、仿真通过后,通过Quartus 编译后下载到CPLD 上并与编码器通讯,实际情况下运行。
5、完成各项要求的功能。
6、对代码进行优化,尽可能减少资源占用。
7、验收。
三、总体结构双绞线,差分式,串行地址/数据总线接口RO,DI,DIR逻辑信号结构分三部分:多摩川编码器,CPLD ,DSP 。
1、编码器跟CPLD 之间通过MAX485电平转换进行连接。
2、CPLD 与DSP 则通过总线进行连接(这一部分结构编写学长已经完成并且提供了端口连接)3、主要工作是CPLD 的解码部分。
四、通讯协议1、TS5668的技术指标:(物理层)精度:单圈精度: 17位(131 072) 多圈精度: 16位(65 536) 最高转速/ ( r ·min - 1 ): 6 000】 输出:差分NRZ 编码二进制 传输速度/Mbp s : 2. 5发送、接收电路:差分形式 通信方式:主从模式接口:3FG ,4sig+ ,5sig-,7VCC ,8DGND 。
4和5为差分信号接口。
2、通信步骤如下图:(逻辑链路层)1)CPLD 向编码器发送一个控制字CF 2)3us 后编码器返回数据包。
3)CPLD 对数据包进行解码,并将得到的数据放在总线上,等待DSP 获取。
具体流程如下图:3、字的结构:下图分别为CF、DF、CRC字的结构。
1)CF字的开始位为0,再是010的同步位,以及4位的控制位,1位奇偶校验位(对控制位进行奇偶校验),结束位为1,共十位。
verilog标准三段式状态机写法
Verilog标准三段式状态机写法1. 介绍Verilog是一种硬件描述语言,用于对数字电路进行建模和描述。
在Verilog中,状态机是常见的一种数字电路模块,用于描述系统或设备的工作状态和状态之间的转移关系。
Verilog标准三段式状态机是一种常见的状态机设计方法,它由三个部分组成:状态寄存器、状态转移逻辑和输出逻辑。
本文将详细介绍Verilog标准三段式状态机的设计方法和实现步骤。
2. Verilog标准三段式状态机设计方法及实现步骤Verilog标准三段式状态机设计方法主要包括以下几个步骤:2.1 状态寄存器的设计状态寄存器用于存储系统或设备的当前状态。
在Verilog中,状态寄存器通常使用寄存器数组进行描述。
如果系统有n个状态,则可以使用n位的寄存器数组来表示状态寄存器。
在Verilog中,状态寄存器的设计通常需要考虑同步时钟和复位信号的控制。
2.2 状态转移逻辑的设计状态转移逻辑用于描述状态之间的转移关系。
在Verilog中,状态转移逻辑通常使用组合逻辑电路进行描述。
可以使用if-else语句或case 语句来描述各个状态之间的转移关系。
在设计状态转移逻辑时,需要考虑状态转移条件和下一个状态的确定。
2.3 输出逻辑的设计输出逻辑用于描述系统或设备在各个状态下的输出信号。
在Verilog 中,输出逻辑通常也使用组合逻辑电路进行描述。
输出逻辑的设计需要考虑当前状态下的输出信号以及输出信号与状态转移关系之间的逻辑关系。
3. 结论Verilog标准三段式状态机是一种常见的状态机设计方法,它由状态寄存器、状态转移逻辑和输出逻辑三个部分组成。
通过合理的设计和实现,可以有效描述和控制系统或设备的工作状态和状态之间的转移关系。
在Verilog中,状态机的设计是数字电路设计中重要的一部分,掌握好Verilog标准三段式状态机的设计方法对于数字电路设计工程师来说是非常重要的。
希望本文能够对Verilog标准三段式状态机的设计方法有所帮助。
Verilog三段式状态机
Verilog三段式状态机时序电路的状态是一个状态变量集合,这些状态变量在任意时刻的值都包含了为确定电路的未来行为而必需考虑的所有历史信息。
状态机采用VerilogHDL语言编码,建议分为三个always段完成。
这是为什么呢?设计FSM的方法和技巧多种多样,但是总结起来有两大类:第一种,将状态转移和状态的操作和判断等写到一个模块(process、block)中。
另一种是将状态转移单独写成一个模块,将状态的操作和判断等写到另一个模块中(在Verilog代码中,相当于使用两个“always” block)。
其中较好的方式是后者。
其原因如下。
首先FSM和其他设计一样,最好使用同步时序方式设计,好处不再累述。
而状态机实现后,状态转移是用寄存器实现的,是同步时序部分。
状态的转移条件的判断是通过组合逻辑判断实现的,之所以第二种比第一种编码方式合理,就在于第二种编码将同步时序和组合逻辑分别放到不同的程序块(process,block)中实现。
这样做的好处不仅仅是便于阅读、理解、维护,更重要的是利于综合器优化代码,利于用户添加合适的时序约束条件,利于布局布线器实现设计。
三段式建模描述FSM的状态机输出时,只需指定case敏感表为次态寄存器,然后直接在每个次态的case分支中描述该状态的输出即可,不用考虑状态转移条件。
三段式描述方法虽然代码结构复杂了一些,但是换来的优势是使FSM做到了同步寄存器输出,消除了组合逻辑输出的不稳定与毛刺的隐患,而且更利于时序路径分组,一般来说在FPGA/CPLD等可编程逻辑器件上的综合与布局布线效果更佳。
示例如下://第一个进程,同步时序always模块,格式化描述次态寄存器迁移到现态寄存器always @ (posedgeclk or negedgerst_n) //异步复位if(!rst_n)current_state<= IDLE;elsecurrent_state<= next_state;//注意,使用的是非阻塞赋值//第二个进程,组合逻辑always模块,描述状态转移条件判断always @ (posedgeclk) //电平触发beginnext_state = x; //要初始化,使得系统复位后能进入正确的状态case(current_state)S1: if(...)next_state = S2; //阻塞赋值...endcaseend//第三个进程,同步时序always模块,格式化描述次态寄存器输出always @ (posedgeclk or negedgerst_n)...//初始化case(next_state)S1:out1 <= 1'b1; //注意是非阻塞逻辑S2:out2 <= 1'b1;default:... //default的作用是免除综合工具综合出锁存器。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
两段式状态机描述方法(2010-09-17 16:04:06)转载1 状态机描述方法状态机描述时关键是要描述清楚几个状态机的要素,即如何进行状态转移,每个状态的输出是什么,状态转移的条件等。
具体描述时方法各种各样,最常见的有三种描述方式:1、一段式:整个状态机写到一个always模块里面,在该模块中既描述状态转移,又描述状态的输入和输出;2、二段式:用两个always模块来描述状态机,其中一个always模块采用同步时序描述状态转移;另一个模块采用组合逻辑判断状态转移条件,描述状态转移规律以及输出;3、三段式:在两个always模块描述方法基础上,使用三个always模块,一个always模块采用同步时序描述状态转移,一个always采用组合逻辑判断状态转移条件,描述状态转移规律,另一个always模块描述状态输出(可以用组合电路输出,也可以时序电路输出)。
一般而言,推荐的FSM 描述方法是后两种。
这是因为:FSM和其他设计一样,最好使用同步时序方式设计,以提高设计的稳定性,消除毛刺。
状态机实现后,一般来说,状态转移部分是同步时序电路而状态的转移条件的判断是组合逻辑。
第二种描述方法同第一种描述方法相比,将同步时序和组合逻辑分别放到不同的always模块中实现,这样做的好处不仅仅是便于阅读、理解、维护,更重要的是利于综合器优化代码,利于用户添加合适的时序约束条件,利于布局布线器实现设计。
在第二种方式的描述中,描述当前状态的输出用组合逻辑实现,组合逻辑很容易产生毛刺,而且不利于约束,不利于综合器和布局布线器实现高性能的设计。
第三种描述方式与第二种相比,关键在于根据状态转移规律,在上一状态根据输入条件判断出当前状态的输出,从而在不插入额外时钟节拍的前提下,实现了寄存器输出。
2实例为了使FSM 描述清晰简介,易于维护,易于附加时序约束,使综合器和布局布线器更好的优化设计,推荐使用两段式FSM 描述方法。
本例的两段式描述代码如下://2-paragraph method to describe FSM//Describe sequential state transition in 1 sequential always block //State transition conditions in the other combinational always block //Package state output by task. Then register the outputmodule state2 ( nrst,clk,i1,i2,o1,o2,err);input nrst,clk;input i1,i2;output o1,o2,err;reg o1,o2,err;reg [2:0] NS,CS;parameter [2:0] //one hot with zero idleIDLE = 3'b000,S1 = 3’b001,S2 = 3’b010,ERROR = 3’b100;//sequential state transitionalways @ (posedge clk or negedge nrst)if (!nrst)CS <= IDLE;elseCS <=NS;//combinational condition judgmentalways @ (CS or i1 or i2)beginNS = 3'bx;ERROR_out;case (CS)IDLE: beginIDLE_out;if (~i1) NS = IDLE;if (i1 && i2) NS = S1;if (i1 && ~i2) NS = ERROR;endS1: beginS1_out;if (~i2) NS = S1;if (i2 && i1) NS = S2;if (i2 && (~i1)) NS = ERROR;endS2: beginS2_out;if (i2) NS = S2;if (~i2 && i1) NS = IDLE;if (~i2 && (~i1)) NS = ERROR;endERROR: beginERROR_out;if (i1) NS = ERROR;if (~i1) NS = IDLE;endendcaseend//output tasktask IDLE_out;{o1,o2,err} = 3'b000;endtasktask S1_out;{o1,o2,err} = 3'b100;endtasktask S2_out;{o1,o2,err} = 3'b010;endtasktask ERROR_out;{o1,o2,err} = 3'b111;endtaskendmodule两段式写法是推荐的FSM 描述方法之一,在此我们仔细讨论一下代码结构。
两段式FSM 的核心就是:一个always模块采用同步时序描述状态转移;另一个模块采用组合逻辑判断状态转移条件,描述状态转移规律。
本例中,同步时序描述状态转移的always模块代码如下:always @ (posedge clk or negedge nrst)if (!nrst)CS <= IDLE;elseCS <=NS;其实这是一种程式化的描述结构,无论具体到何种FSM 设计,都可以定义两个状态寄存器“CS”和“NS”,分别代表当前状态和下一状态,然后根据所需的复位方式(同步复位或异步复位),在时钟沿到达时将NS 赋给CS。
需要注意的是这个同步时序模块的赋值要采用非阻塞赋值“<=”。
本例中,另一个采用组合逻辑判断状态转移条件的always模块代码如下://combinational condition judgmentalways @ (nrst or CS or i1 or i2)beginNS = 3'bx;ERROR_out;case (CS)IDLE: beginIDLE_out;if (~i1) NS = IDLE;if (i1 && i2) NS = S1;if (i1 && ~i2) NS = ERROR;endS1: beginS1_out;if (~i2) NS = S1;if (i2 && i1) NS = S2;if (i2 && (~i1)) NS = ERROR;endS2: beginS2_out;if (i2) NS = S2;if (~i2 && i1) NS = IDLE;if (~i2 && (~i1)) NS = ERROR;endERROR: beginERROR_out;if (i1) NS = ERROR;if (~i1) NS = IDLE;endendcaseend这个使用组合逻辑判断状态转移条件的always模块也可以看成格式化的书写结构。
其中always的敏感列表为当前状态“CS”,复位信号和输入条件(如果是米勒状态机,则必须有输入条件;如果是摩尔状态机,一般敏感表和后续逻辑判定没有输入),请大家注意电平敏感表必须列完整。
本例中这段电平敏感列表为:always @ (nrst or CS or i1 or i2)一般来说,在这个组合always敏感表下先写一个默认的下一状态“NS”的描述,然后根据实际的状态转移条件由内部的case或者if...else条件判断确定正确的转移。
如本例中下面这段代码,……beginNS = ERROR;ERROR_out;case (CS)……推荐在敏感表下的默认状态为不定状态X,这样描述的好处有两个:第一在仿真时可以很好的考察所设计的FSM 的完备性,如果所设计的FSM 不完备,则会进入任意状态,仿真很容易发现;第二个好处是综合器对不定态X 的处理是“Don’t Care”,即任何没有定义的状态寄存器向量都会被忽略。
这里赋值不定态的效果和使用casez或casex替代case的效果非常相似。
在每个case 模块的内部的结构也非常相似,都是先描述当前状态的组合逻辑输出,然后根据输入条件(米勒FSM)判定下一个状态。
该组合逻辑模块中所有的赋值推荐采用阻塞赋值“=”。
请大家注意,虽然下一状态寄存器NS为寄存器类型,但是在两段式FSM的判断状态转移条件的always模块中,实际上对应的真实硬件电路是纯组合逻辑电路。
对于每个输出,一般用组合逻辑描述,比较简便的方法是用task/endtask将输出封装起来,这样做的好处不仅仅是写法简单,而且利于复用共同的输出。
例如本例中S1 状态的输出被封装为S1_out,在组合逻辑always模块中直接调用即可。
task S1_out;{o1,o2,err} = 3'b100;endtask组合逻辑容易产生毛刺,因此如果时序允许,请尽量对组合逻辑的输出插入一个寄存器节拍,这样可以很好的保证输出信号的稳定性。
/moonlight_bupt/blog/item/2e62746e8f2cd0dc80cb4ac2 .html。