状态机(State Machine)
状态机概念
有限状态机(Finite State Machine,简称FSM):在有限个状态之间按一定规律转换的时序电路。
状态机模型
Mealy 状态机
(图片来自正点原子PPT)
Moore 状态机
(图片来自正点原子PPT)
Mealy状态机产生输出的组合逻辑与输入有关,而Moore状态机参数输出的组合逻辑与输入无关。
状态机设计
要写出完整的三段式状态机,参考四段论方法:
1)状态空间定义
2)状态跳转
3)下个状态判断
4)各个状态下的动作
1)状态空间定义
//define state space
parameter SLEEP = 2'b00;
parameter STYDY = 2'b01;
parameter EAT = 2'b10;
parameter AMUSE = 2'b11;
//internal variable
reg [1:0] current_state; //保存当前状态的寄存器
reg [1:0] next_state; //保存下一个状态的寄存器
采用独热码方式定义,每个状态只有一个寄存器位,生成电路更简单。
//define state space
parameter SLEEP = 4'b1000;
parameter STUDY = 4'b0100;
parameter EAT = 4'b0010;
parameter AMUSE = 4'b0001;
//internal variable
reg [3:0] current_state;
reg [3:0] next_state;
2)状态跳转(时序逻辑)
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
current_state <= SLEEP; //时序逻辑采用非阻塞赋值
else
current_state <= next_state;
end
3)下个状态判断(组合逻辑)
always @(current_state or input_signals) begin
case (current_state)
/*
case/default
if/else
要配对,避免产生latch(锁存器)
*/
SLEEP:begin
if(clock_alarm)
//组合逻辑采用阻塞赋值
next_state = STUDY;
else
next_state = SLEEP;
end
STUDY: begin
if (lunch_time)
next_state = EAT;
else
next_state = STUDY;
end
EAT: ....;
AMUSE: ....;
default:....;
endcase
end
4)各个状态下的动作
简单情况下可使用assign
wire read_book;
assign read_book = (current_state == STUDY) ? 1'b1 : 1'b0;
复杂情况下可使用always
always @ (cuttent_state) begin
if(current_state == STUDY)
read_book = 1;
else
read_book = 0;
end
三段式可以在组合逻辑后再增加一级寄存器(时序逻辑)来实现时序逻辑的输出。
增加寄存器的好处时:
1)可以有效地滤去组合逻辑输出的毛刺;
2)可以有效地进行时序计算与约束
3)对于总线信号来说,容易使总线数据对齐,从而减小总线数据间的便宜,减小接收端数据采样出错的频率。
(图片来自正点原子PPT)
一个完整的三段式状态机
//分频器状态机
module divider7_fsm( //fsm代表该模块是状态机
//input ports
input sys_clk;
input sys_rst_n;
//output ports
output reg clk_divide_7
);
//reg define
reg [6:0] curr_st;
reg [6:0] next_st;
//parameter define
parameter WIDTH = 1
//one hot code design
parameter S0 = 7'b000_0000;
parameter S1 = 7'b000_0010;
parameter S2 = 7'b000_0100;
parameter S3 = 7'b000_1000;
parameter S4 = 7'b001_0000;
parameter S5 = 7'b010_0000;
parameter S6 = 7'b100_0000;
always @(posedge sys_clk or negedge sys_rst_n) begin
if (sys_rst_n == 1'b0)
curr_st <= 7'b0;//时序逻辑采用非阻塞赋值
else
curr_st <= next_st;
end
//FSM state logic
always @(*) begin
case (curr_st)
S0: begin
next_st = S1;
end
S1: begin
next_st = S2;
end
S2: begin
next_st = S3;
end
S3: begin
next_st = S4;
end
S4: begin
next_st = S5;
end
S5: begin
next_st = S6;
end
S6: begin
next_st = S0;
end
endcase
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if (sys_rst_n == 1'b0) begin
clk_divide_7 <= 1'b0;
end
else if ((curr_st == S0) | (curr_st == S1) | (curr_st == S2) | (curr_st == S3))
clk_divide_7 <= 1'b0;
else if ((curr_st == S4) | (curr_st == S5) | (curr_st == S6))
clk_divide_7 <= 1'b1;
else;//补全else防止产生锁存器
end
endmodule
参考链接
https://blog.csdn.net/Pieces_thinking/article/details/84727597###