定义
状态机能够控制信号按照设定好的状态进行转移,同时完成特定输出。
FPGA是并行运行的,而状态机是用来完成那些需要顺序执行的动作。通俗地说,就是把全部的情况分成几个场景,这些场景的工作方式不同。
结构
基于明德扬的状态机架构,结构清晰,易于修改。
三段式状态机,即三个always块描述状态机.
状态机结构图:(这里图有误,是两段式的)
时序逻辑always块,当前状态的复位,次态赋值给现态。
always@(posedge clk or negedge rst_n)beginif(!rst_n)beginstate_c <= HEAD;endelse beginstate_c <= state_n;endend
组合逻辑always块,描述次态转移的方向。转移条件用信号xx2xx_start命名**,写出转移方向,不用写出具体的转移条件。**状态不变不要写成 state_n = state_n,会产生锁存器。
always@(*)begincase(state_c)HEAD:beginif(hea2typ_start)beginstate_n = TYPE;endelse beginstate_n = state_c;endendTYPE:beginif(typ2len_start)beginstate_n = LEN;endelse if(typ2dat_start)beginstate_n = DATA;endelse beginstate_n = state_c;endend...default:beginstate_n = HEAD;endendcaseend
后面用assign定义具体的转移条件;注意要加上现态,避免因两种不同状态由同一个变化条件发生转移时导致错误;状态的对齐对象是din不是dout,因为是先有din,再分状态,最后得到dout。
assign hea2typ_start = state_c==HEAD && end_cnt;assign typ2len_start = state_c==TYPE && din!=0;
组合or时序always块用来描述输出.(output logic)
always @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)begindout_eop <= 0;endelse if(state_c==FCS && end_fcs_cnt)begindout_eop <= 1;endelse begindout_eop <= 0;endend
注意:
4. Moore和Mealy就在这里产生区别,前者output仅与状态有关,后者output与状态和输入有关。
5. 输出的always块推荐用时序逻辑,用次态做判断。。
判断条件用现态有一拍的延时。
用组合+current_state进行状态判断的话,就成了两段式的。因为组合逻辑产生毛刺,尤其是米利型状态机时;级数过长而引起建立时间违例。
6. 状态机的第二段组合逻辑,它能是时序逻辑吗?
网上没找到解答,我感觉不能。
clk到来,state_c更新,但是此刻D2用作判断的还是上一刻的state_c,所以state_n不变,去更新的state_c也不变。
编码
二进制编码传统二进制序列。少于5种状态。
二进制编码占用的位数少,但其状态跳变需要额外的译码电路,这样的编码方式会对状态机的运行速度有所限制。独热码编码
以n bit表示n个 状态,每个状态分配一个触发器,只要本状态触发器设置为1,其余均设置为0。
5-50种状态
这样编码的译码部分可以做到最简,工作频率可以做到较高,相对于二进制而言,需要更多的位。Gray码
多于50种状态。
示例
module FSM1(i,clk,rst_n,q);input i;input clk,rst_n;output reg q;reg [5:0] cstate;reg [5:0] nstate;//状态编码eparameter s0 = 6'b000001;parameter s1 = 6'b000010;parameter s2 = 6'b000100;parameter s3 = 6'b001000;parameter s4 = 6'b010000;parameter s5 = 6'b100000;//描述对应当前状态的状态寄存器always@ (posedge clk or negedge rst_n)beginif (!rst_n)cstate <= s0; //复位后状态机处于空闲态idleelse cstate <= nstate;end //描述状态的转移always@ (cstate or i)nstate = s0; //要初始化,使得系统复位后能进入正确的状态begincase(cstate)s0: if(i) nstate = s1;else nstate = s0;s1: if(i) nstate = s1;else nstate = s2;s2: if(i) nstate = s1; else nstate = s3;s3: if(i) nstate = s4;else nstate = s0;s4: if(i) nstate = s1;else nstate = s5;s5: if(i) nstate = s1;else nstate = s3;default: nstate = s0;endcaseend//描述输出always@ (*) begin if (!rst_n) q = 1'b0;else begincase(cstate)s0: q = 1'b0;s1: q = 1'b0;s2: q = 1'b0;s3: q = 1'b0;s4: q = 1'b0;s5: q = 1'b1;default: q = 1'b0;//免除综合工具综合出锁存器endcaseendendendmodule
验证:
Quartus编译后,查看State Machine Viewer
步骤
状态转移图
Q是状态编码,X输入,Z输出。下图是mealy型,输出和输入有关。