@[仅记录FPGA学习过程中的点点滴滴,欢迎交流与指正]
基础知识
状态机全称是有限状态机(Finite State Machine,FSM ),是一种在有限个状态之间按一定规律转换的时序电路,可以认为是组合逻辑和时序逻辑的一种组合。状态机通过控制各个状态的跳转来控制流程,使得整个代码看上去更加清晰易懂,在控制复杂流程的时候,状态机优势明显,因此基本上都会用刀状态机。
状态机功能:
- 描述系统逻辑功能。
- 定义系统的不同状态。
- 描述系统转化的条件及转化过程。
- 刻画系统状态和输入输出之间的关系。
状态机的分类——Mealy型和moore型
根据状态机的输出是否与输入条件相关,可将状态机分为两大类,即米勒(Mealy)型状态机和摩尔(Moore)型状态机。
Mealy型:时序逻辑的输出,不仅仅取决于状态,还取决于信号的输入。
Moore型:时许逻辑的输出只取决于上一时刻的状态,与当前信号的输入无关。
在实际设计中,Mealy型状态机使用最多,Moore型状态机虽然清晰明了,但状态过多,不适合大型状态机。
状态机的设计步骤
状态机的设计步骤主要分为以下四个步骤:
1.逻辑抽象:得出状态转移图,具体的说就是给出一个实际问题表示为时序逻辑函数。可以用状态转换表来描述,也可以用状态转换图来描述。
2.状态化简:化简状态转移图,具体地说就是合并在相同的输入下转换到同一个状态并得到相同输出的状态。
3.状态分配:状态编码,一般使用二进制编码(binary_code)、格雷码(gray_code)、独热码(one_hot_code)等。
4.描述建模
状态机的描述方式
状态机的描述方式有很多种,主要常用的有三种,分别为一段式,二段式和三段式。
1.一段式:单always块把组合逻辑和时序逻辑用同一时序always块描述,其输出是寄存器输出,无毛刺;但这种方式可能会出发多余的粗发起,代码难于修改和调试,不推荐使用。
2.两段式:双always块大多用于描述Mealy型状态机和组合输出的Moore状态机,时序always块描述当前状态逻辑,组合逻辑always块描述次态逻辑并给出输出赋值。这种方式结构清晰,综合后的面积和时间性能好,但组合逻辑输出往往会有毛刺,当输出向量作为时钟信号时,这些毛刺会对电路产生致命的影响。所以两段式很少有人使用。
3.三段式:三always块大多用于同步Mealy状态机,两个时序always块分别用来描述现态逻辑和对输出赋值,组合always块用于产生下一状态。时序电路的状态是一个状态变量集合,这些状态变量在任意时刻的值都包含了为确定电路的未来行为而必须考虑的所有历史信息。
这种三段式的状态机也是寄存器输出,输出无毛刺,并且代码比单always块更加清晰易读,但是面积大于双always块。随着芯片资源和速度的提高,目前这种方式得到了广泛的应用。
一段式状态机的一般结构
总结实例如下:
//一段式状态机示例
// 功能 flag_en信号到来时,实现状态跳转,并输出5位数字信号
`timescale 1ns / 1ps
module fsm_one(
input wire clk,
input wire rst,
input wire flag_en,
output reg [4:0] flag_out
);
reg [2:0] state; //只需要定义状态寄存器
//状态编码
parameter IDLE = 3'b000; //Binary Gray Code
parameter ONE = 3'b001;
parameter TWO = 3'b011;
parameter THREE = 3'b111;
parameter ...................
//一段式状态机
always @ (posedge clk) begin
if (rst) begin
state <= IDLE; //状态寄存器位于IDLE状态
flag_out <= 5'b00000; //输出复位
end
else begin
case (state) //**case语句,以state作为敏感信号
IDLE : begin
if (flag_en) begin
state <= ONE;
flag_out <= 5'b11110;
end
else begin
state <= IDLE;
flag_out <= 5'b00000;
end
end
ONE : begin
if (flag_en) begin
state <= TWO;
flag_out <= 5'b11101;
end
else begin
state <= ONE;
flag_out <= 5'b11110;
end
end
TWO : begin
if (flag_en) begin
state <= THREE;
flag_out <= 5'b11011;
end
else begin
state <= TWO;
flag_out <= 5'b11101;
end
end
THREE : begin
if (flag_en) begin
state <= ....;
flag_out <= 5'b10111;
end
else begin
state <= THREE;
flag_out <= 5'b11011;
end
end
............................
default : begin //默认设置
state <= IDLE;
end
endcase
end
end
endmodule
三段式状态机的一般结构
示例如下:
//三段式状态机示例
//功能 flag_en信号到来时,实现状态跳转,并输出5位数字信号
`timescale 1ns / 1ps
module fsm_three(
input wire clk,
input wire rst,
input wire flag_en,
output reg [4:0] flag_out
);
reg [2:0] current_state; //定义当前时刻状态寄存器
reg [2:0] next_state; //定义下一状态寄存器
// 状态编码
localparam IDLE = 3'b000;
localparam ONE = 3'b001;
localparam TWO = 3'b011;
localparam THREE = 3'b010;
localparam ...................
// *FSM1 用*时序逻辑* -通用-
always @ (posedge clk) begin
if (rst) begin
current_state <= IDLE;
end
else begin
current_state <= next_state;
end
end
// *FSM2 采用*组合逻辑*描述状态转移过程
always @ (*) begin //(*)
case (current_state) //采用current_state作为敏感信号
IDLE : begin
if (flag_en) begin //控制next_state进行跳转
next_state = ONE; //组合逻辑
end
else begin
next_state = IDLE;
end
end
ONE : begin
if (flag_en) begin
next_state = TWO;
end
else begin
next_state = ONE;
end
end
TWO : begin
if (flag_en) begin
next_state = THREE;
end
else begin
next_state = TWO;
end
end
THREE : begin
if (flag_en) begin
next_state = ....;
end
else begin
next_state = THREE;
end
end
..........................
default : begin
next_state = IDLE;
end
endcase
end
// *FSM3 采用*时序逻辑*进行行为描述
always @ (posedge clk) begin
if (rst) begin
flag_out <= 5'b00000; //输出初始化
end
else begin
case (current_state) //使用current_state作为敏感信号
IDLE : begin
if (flag_en) begin
flag_out <= 5'b11110;//时序逻辑
end
else begin
flag_out <= 5'b00000;
end
end
ONE : begin
if (flag_en) begin
flag_out <= 5'b11101;
end
else begin
flag_out <= 5'b11110;
end
end
TWO : begin
if (flag_en) begin
flag_out <= 5'b11011;
end
else begin
flag_out <= 5'b11101;
end
end
THREE : begin
if (flag_en) begin
flag_out <= 5'b10111;
end
else begin
flag_out <= 5'b11011;
end
end
.............................
default : begin
flag_out <= 5'b00000;
end
endcase
end
end
endmodule