前言
描述状态机的关键要素:
a. 如何进行状态转移;
b. 每个状态的输出是什么;
c. 状态转移是否和输入条件相关。
RTL级好的有限状态机(FSM)描述(优先级由上至下降低):
- FSM要安全,**稳定性高(**要求FSM综合实现结果无毛刺等异常扰动,状态机要完备)
- FSM速度快,满足设计的频率要求;
- FSM面积小,满足设计的面积要求;
- FSM设计要清晰易懂,易维护。
根据建模方式(一段式、二段式、三段式状态机)和输入(摩尔型和米勒型)对状态机进行分类梳理。
一、根据建模方式分类
n段式FSM描述方法强调的是一直建模思路,而不是简单根据always语法块的个数。
一段式状态机
一段式状态机将状态的同步转移、状态输出、输入条件写在一个always模块中。
代码示例:
module state(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;//next_state;
parameter[2:0] IDLE=3'b000, S1=3'b001, S2=3'b010, ERROR=3'b100;
always @(posedge clk, negedge nrst)begin
if(!nrst)begin
NS<=IDLE;
{o1, o2, err}<=3'b000;
end
else begin
NS<=3'bx;
{o1, o2, err}<=3'b000;
end
case(NS)
IDLE:begin
if(~i1) begin {o1, o2, err}<=3'b000; NS<=IDLE; end
if(i1&&i2) begin {o1, o2, err}<=3'b100; NS<=S1; end
if(i1&&~i2) begin {o1, o2, err}<=3'b111; NS<=ERROR; end
end
S1:begin
if(~i2) begin {o1, o2, err}<=3'b100; NS<=S1; end
if(i1&&i2) begin {o1, o2, err}<=3'b010; NS<=S2; end
if(~i1&&i2) begin {o1, o2, err}<=3'b111; NS<=ERROR; end
end
S2:begin
if(i2) begin {o1, o2, err}<=3'b010; NS<=S2; end
if(i1&&~i2) begin {o1, o2, err}<=3'b000; NS<=IDLE; end
if(~i1&&~i2) begin {o1, o2, err}<=3'b111; NS<=ERROR; end
end
ERROR:begin
if(i1) begin {o1, o2, err}<=3'b111; NS<=ERROR; end
if(~i1) begin {o1, o2, err}<=3'b000; NS<=IDLE; end
end
endcase
end
endmodule
从代码可以看出,一段式状态机在描述当前状态时要考虑下个状态的输出,整个代码不清晰,不符合将组合和时序逻辑分开描述的代码风格,应当避免使用。
两段式状态机
两段式状态机中,一个always块采用同步时序描述状态转移,格式化地描述次态到现态的转移(CS<=NS),另一个always块用组合逻辑判断状态转移条件,描述状态转移条件的判断;
最后一个输出的组合逻辑如果时序允许,尽量插入寄存器,可以有效消除毛刺。
always @(posedge clk, negedge nrst)begin//同步时序描述状态转移
if(!nrst)
CS<=IDLE;
else
CS<=NS;
end
always @(*)begin//组合逻辑判断状态转移条件
NS<=3'bx;
ERROR_out;
case(CS)
IDLE:
IDLE_out;
if(~i1) NS<=IDLE;
if(i1&&i2) NS<=S1;
if(i1&&~i2) NS<=ERROR;
S1:
S1_out;
if(~i2) NS<=S1;
if(i1&&i2) NS<=S2;
if(~i1&&i2) NS<=ERROR;
S2:
S2_out;
if(i2) NS<=S2;
if(i1&&~i2) NS<=IDLE;
if(~i1&&~i2) NS<=ERROR;
ERROR:
if(i1) NS<=ERROR;
if(~i1) NS<=IDLE;
endcase
end
//output task
task IDLE_out;
{o1, o2, err}=3'b000;
endtask
task S1_out;
{o1, o2, err}=3'b100;
endtask
task S2_out;
{o1, o2, err}=3'b010;
endtask
task IDLE_out;
{o1, o2, err}=3'b111;
endtask
三段式状态机
一个always块采用同步时序描述状态转移,格式化地描述次态到现态的转移(CS<=NS),另一个always块用组合逻辑判断状态转移条件,描述状态转移条件的判断,第三个同步时序always块格式化描述次态的寄存器输出。
三段式状态机描述方式使得FSM做到了同步寄存器输出,消除了组合逻辑输出的不稳定与毛刺的隐患,更有利于时序路径分组。
代码示例
always @(posedge clk, negedge nrst)begin//同步时序描述状态转移
if(!nrst)
CS<=IDLE;
else
CS<=NS;
end
always @(*)begin//组合逻辑判断状态转移条件
NS<=3'bx;
ERROR_out;
case(CS)
IDLE:
IDLE_out;
if(~i1) NS<=IDLE;
if(i1&&i2) NS<=S1;
if(i1&&~i2) NS<=ERROR;
S1:
S1_out;
if(~i2) NS<=S1;
if(i1&&i2) NS<=S2;
if(~i1&&i2) NS<=ERROR;
S2:
S2_out;
if(i2) NS<=S2;
if(i1&&~i2) NS<=IDLE;
if(~i1&&~i2) NS<=ERROR;
ERROR:
if(i1) NS<=ERROR;
if(~i1) NS<=IDLE;
endcase
end
always @(posedge clk, negedge nrst)//根据次态进行输出
if(!nrst)
{o1, o2, err}<=3'b000;
else begin
{o1, o2, err}<=3'b000;
case(NS)
IDLE:{o1, o2, err}<=3'b000;
S1:{o1, o2, err}<=3'b100;
S2:{o1, o2, err}<=3'b010;
ERROR:{o1, o2, err}<=3'b111;
endcase
end
二、与输入的关系分类
如果要进行序列"110"重叠检测,以两段式状态机来描述两者的区别。
1. moore状态机
moore状态机输出只与现态有关,与输入无关
module seq(
input clk,
input rstn,
input data,
output done);
reg [1:0]state,next_state;
parameter IDLE=2'd0, S1=2'd1, S11=2'd2, S110=2'd3;
always @(posedge clk, negedge rstn)begin
if(!rstn)
state<=IDLE;
else
state<=next_state;
end
always @(*)begin
case(state)
IDLE:next_state<=data?S1:IDLE;
S1:next_state<=DATA?S11:IDLE;
S11:next_state<=!DATA?S110:S11;
S110:next_state<=IDLE;
endcase
end
assign done=(state==S110);//输出只和当前状态有关
endmodule
2. mealy状态机
mealy状态机输入不仅与当前状态有关,还与输入有关;
代码如下(示例):
module seq(
input clk,
input rstn,
input data,
output done);
reg [1:0]state,next_state;
parameter IDLE=2'd0, S1=2'd1, S11=2'd2;
always @(posedge clk, negedge rstn)begin
if(!rstn)
state<=IDLE;
else
state<=next_state;
end
always @(*)begin
case(state)
IDLE:next_state<=data?S1:IDLE;
S1:next_state<=DATA?S11:IDLE;
S11:next_state<=!DATA?IDLE:S11;//比moore状态机少一个状态
endcase
end
assign done=(state==S11&&!DATA);//输出与当前状态和输入有关
endmodule
总结
本文对状态机建模的分类主要是从邸志雄老师的慕课《芯动力——硬件加速设计方法》学习而来的,关于moore和mealy状态机则是因为做题过程中遇到过很多序列检测的题,状态对输出的影响没有进行过梳理,这里一起梳理一下,加油!