状态机描述时关键是要描述清楚几个状态机的要素,即如何进行状态转移,每个状态的输出是什么,状态转移的条件等。具体描述时方法各种各样,最常见的有三种描述方式:
(1)一段式:整个状态机写到一个always模块里面,在该模块中既描述状态转移,又描述状态的输入和输出;
(2)二段式:用两个always模块来描述状态机,其中一个always模块采用同步时序描述状态转移;另一个模块采用组合逻辑判断状态转移条件,描述状态转移规律以及输出;
(3)三段式:在两个always模块描述方法基础上,使用三个always模块,一个always模块采用同步时序描述状态转移,一个always采用组合逻辑判断状态转移条件,描述状态转移规律,另一个always模块描述状态输出(可以用组合电路输出,也可以时序电路输出)。
三段式状态机示例模板:
//第一个进程,同步时序always模块,格式化描述次态寄存器迁移到现态寄存器
always @ (posedge clk or negedge rst_n) //异步复位
if(!rst_n)
current_state <= IDLE;
else
current_state <= next_state; //注意,使用的是非阻塞赋值
//第二个进程,组合逻辑always模块,描述状态转移条件判断
always @ (current_state) //电平触发,现存状态为敏感信号
begin
case(current_state)
S1: if(...)
next_state = S2; //阻塞赋值
S2: if(...)
next_state = S3; //阻塞赋值
...
endcase
end
//第三个进程,同步时序always模块,格式化描述次态寄存器输出
always @ (posedge clk or negedge rst_n)
begin
...//初始化
case(next_state)
S1:
out1 <= 1'b1; //注意是非阻塞逻辑
S2:
out2 <= 1'b1;
default:... //default的作用是免除综合工具综合出锁存器
endcase
end
10010序列检测器的三种状态机写法如下
1,一段式
module sn_detector (
rst_n ,
clk ,
sn_i ,
sn_check_o
) ;
input rst_n,clk ;
input sn_i ;
output sn_check_o ;
reg sn_check_o ;
reg [2:0] state ;
parameter st_idle = 3'd0, //对应原始状态
st_1 = 3'd1, //对应起始状态1
st_10 = 3'd2, //对应中间状态10
st_100 = 3'd3, //对应中间状态100
st_1001 = 3'd4, //对应中间状态1001
st_10010 = 3'd5;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
state <= st_idle;
sn_check_o <= 0;
end
else
begin
case(state)
st_idle:begin
if (sn_i==1)
state <=st_1;
sn_check_o <= 1'b0;
end
st_1:begin
if (sn_i==0)
state <=st_10;
sn_check_o <= 1'b0;
end
st_10:begin
if (sn_i==0)
state <=st_100;
else
state <=st_1;
sn_check_o <= 1'b0;
end
st_100:begin
if (sn_i==1)
state <=st_1001;
else
state <=st_idle;
sn_check_o <= 1'b0;
end
st_1001:begin
if (sn_i==1)
state <=st_1;
else
state <=st_10010;
sn_check_o <= 1'b0;
end
st_10010:begin
if (sn_i==1)
state <=st_1;
else
state <=st_100;
sn_check_o <= 1'b1;
end
default:begin
state <=st_idle; //缺省值
sn_check_o <= 1'b0;
end
endcase
end
end
endmodule
2,二段式
module sn_detector (
rst_n ,
clk ,
sn_i ,
sn_check_o
) ;
input rst_n,clk ;
input sn_i ;
output sn_check_o ;
reg sn_check_o ;
reg [2:0] state ;
parameter st_idle = 3'd0, //对应原始状态
st_1 = 3'd1, //对应起始状态1
st_10 = 3'd2, //对应中间状态10
st_100 = 3'd3, //对应中间状态100
st_1001 = 3'd4, //对应中间状态1001
st_10010 = 3'd5;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
state <= st_idle;
else
begin
case(state)
st_idle:
if (sn_i==1)
state <=st_1;
st_1:
if (sn_i==0)
state <=st_10;
st_10:
if (sn_i==0)
state <=st_100;
else
state <=st_1;
st_100:
if (sn_i==1)
state <=st_1001;
else
state <=st_idle;
st_1001:
if (sn_i==1)
state <=st_1;
else
state <=st_10010;
st_10010:
if (sn_i==1)
state <=st_1;
else
state <=st_100;
default:
state <=st_idle; //缺省值
endcase
end
end
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
sn_check_o <= 0;
else if(state==st_10010)
sn_check_o <= 1;
else
sn_check_o <= 0;
end
endmodule
3,三段式
module sn_detector (
rst_n ,
clk ,
sn_i ,
sn_check_o
) ;
input rst_n,clk ;
input sn_i ;
output sn_check_o ;
reg sn_check_o ;
reg [2:0] curr_state ;
reg [2:0] Next_state ;
parameter st_idle = 3'd0, //对应原始状态
st_1 = 3'd1, //对应起始状态1
st_10 = 3'd2, //对应中间状态10
st_100 = 3'd3, //对应中间状态100
st_1001 = 3'd4, //对应中间状态1001
st_10010 = 3'd5;
always @(posedge clk or negedge rst_n)
begin
if (!rst_n)
curr_state <= st_idle;
else
curr_state <= Next_state;
end
always @(*)
begin
case(curr_state)
st_idle:
if (sn_i==1)
Next_state = st_1;
else
Next_state = st_idle;
st_1:
if (sn_i==0)
Next_state = st_10;
else
Next_state = st_1;
st_10:
if (sn_i==0)
Next_state = st_100;
else
Next_state = st_1;
st_100:
if (sn_i==1)
Next_state = st_1001;
else
Next_state = st_idle;
st_1001:
if (sn_i==1)
Next_state = st_1;
else
Next_state = st_10010;
st_10010:
if (sn_i==1)
Next_state = st_1;
else
Next_state = st_100;
default:
Next_state = st_idle; //缺省值
endcase
end
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
sn_check_o <= 1'b0;
else if(curr_state==st_10010)
sn_check_o <= 1'b1;
else
sn_check_o <= 1'b0;
end
endmodule