状态机是什么?
Finite State Machine
有限状态机(FSM)
状态机的写法
一段式:
只有一个always块,把所有的逻辑(输入、输出、状态)都在一个always块
的时序逻辑中实现。这种写法看起来很简洁,但是不利于维护,如果状态复杂一些
容易出错。
二段式:
有两个always 块,把时序逻辑和组合逻辑分隔开来。时序逻辑里进行当前状态
和下一状态的切换,组合逻辑实现各个输入、输出以及状态判断。这种写法不仅便于
阅读、理解、维护,而且利于综合器优化代码,利于用户添加合适的时序约束条件,
利于布局布线器实现设计。在两段式描述中,当前状态的输出用组合逻辑实现,可能
存在竞争和冒险,产生毛刺。
三段式:
有三个always块,一个采用同步时序的方式描述状态转移,
一个采用组合逻辑的方式判断状态转移条件、描述状态转移规律,
第三个always使用同步时序的方式描述每个状态的输出。
代码容易维护,时序逻辑的输出解决了两段式组合逻辑的毛
刺问题,但是从资源消耗的角度上看,三段式的资源消耗多一些。
一段式状态机参考代码:
module fsm_led(
input wire clk_50M,//输入时钟信号
input wire rst_n, //输入复位信号
output reg [3:0] led //输出4个led
);
//设置参数
parameter T = 26'd9_999_999;
//状态机
//状态空间划分
localparam S_led0_on = 0;//第1个led亮
localparam S_led1_on = 1;//第2个led亮
localparam S_led2_on = 2;//第3个led亮
localparam S_led3_on = 3;//第4个led亮
//状态寄存器
reg [1:0] cstate; //current当前,state状态,4个状态需要2个位宽的二进制数来存储
//定义1s计数器,50_000_000次,需要26个位宽
reg [25:0] cnt;
//1s钟计数器模块
always@(posedge clk_50M or negedge rst_n)begin
if(!rst_n) //如果按下复位键
cnt <= 1'b0; //计数器清零
else if(cnt == T) //如果计数达到1S
cnt <= 1'b0; //计数器清零
else
cnt <= cnt + 1'b1; //否则,计数器自增1
end
//一段式状态机
//状态的判断和转移,根据状态输出
always@(posedge clk_50M or negedge rst_n)begin
if(!rst_n)begin
led <= 4'b0000;
cstate <= S_led0_on;
end
else
case(cstate)
S_led0_on : begin
led <= 4'b0001;
if(cnt == T)
cstate <= S_led1_on;
else
cstate <= cstate;
end
S_led1_on : begin
led <= 4'b0010;
if(cnt == T)
cstate <= S_led2_on;
else
cstate <= cstate;
end
S_led2_on : begin
led <= 4'b0100;
if(cnt == T)
cstate <= S_led3_on;
else
cstate <= cstate;
end
S_led3_on : begin
led <= 4'b1000;
if(cnt == T)
cstate <= S_led0_on;
else
cstate <= cstate;
end
default: begin
led <= 4'b0001;
if(cnt == T)
cstate <= S_led1_on;
else
cstate <= cstate;
end
endcase
end
endmodule
好的状态机标准
好的状态机的标准很多,最重要的几个方面如下:
第一,状态机要安全,是指FSM不会进入死循环,特别是不会进入非预知的状态,而且由于某些扰动进入非设计状态,也能很快的恢复到正常的状态循环中来。这里面有两层含义:其一要求该FSM的综合实现结果无毛刺等异常扰动;其二要求FSM要完备,即使受到异常扰动进入非设计状态,也能很快恢复到正常状态。
第二,状态机的设计要满足设计的面积和速度的要求。
第三,状态机的设计要清晰易懂、易维护。
二段式、三段式以及激励文件,后续补上。
二段式、三段式代码