状态机的写法可以分为以下几种:
一段式:最主要的特征是只有一个always块。在这个always块内既描述状态转移,又含有组合逻辑输入/输出,当前状态用寄存器输出;在这种状态机的写法中,组合逻辑电路和时序逻辑电路都在一起,没有分开;因此这种写法增加了代码的复杂度且不利于代码的维护和修改,同时也不利于后期约束;
两段式:最主要的特征是有两个always块,将组合逻辑和时序逻辑分开。其中一个always块采用同步时序描述状态转移,而另一个always块采用组合逻辑来判断状态转移的条件,描述状态转移规律及输出;在这种写法下,需要定义两个状态,分别是现态和次态,通过现态和次态的转换来实现状态转移;两段式状态机可以清晰完整的显示出状态机的结构,有利于代码的维护和后期修改,同时也降低编写复杂度;
三段式:最主要的特征是有三个always块。区别于两段式状态机的关键在于两段式状态机直接采用组合逻辑输出,而三段式状态机则通过在组合逻辑后再增加一级寄存器实现逻辑输出——即一个always块采用同步时序描述状态转移,一个always块采用组合逻辑判断转移条件、转移状态规律,最后一个always块采用同步时序描述状态的输出;这种三段式状态机的写法代码非常清晰,极大降低了编写维护代码的复杂度,最大程度清晰完整的显示出状态机的结构。同时可以有效地滤除两段式状态机组合逻辑输出可能产生的毛刺信号;另外对于总线形式的输出来说,容易使总线数据对齐,从而减小总线数据间的偏移,减小接收端数据采样出错的频率;但是代码量会长一些哦OvO
下面是以上介绍的三种状态机在下面这种状态转移图下的代码
module simple(
input clk,
input rst_n,
input w,
output reg[1:0] z
);
localparam A = 2'b00;
localparam B = 2'b01;
localparam C = 2'b10;
reg [1:0] state;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state <= A;
z <= 0;
end
else
case (state)
A:
begin
if (w) begin
state <= B;
z <= 2'd1;
end
else begin
state <= A;
z <= 2'd0;
end
end
B:
begin
if (w) begin
state <= C;
z <= 2'd2;
end
else begin
state <= A;
z <= 2'd1;
end
end
C:
begin
if (w) begin
state <= C;
z <= 2'd2;
end
else begin
state <= A;
z <= 2'd0;
end
end
default:
begin
state <= A;
z <= 2'd0;
end
endcase
end
endmodule
两段式状态机代码:
module simple(
input clk,
input rst_n,
input w,
output reg[1:0] z
);
localparam A = 2'b00;
localparam B = 2'b01;
localparam C = 2'b10;
reg [1:0] current_state;
reg [1:0] next_state;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
current_state <= A;
end
else
current_state <= next_state;
end
always @(*) begin
case (current_state)
A:
begin
if (w) begin
next_state = B;
z = 2'd1;
end
else begin
next_state = A;
z = 2'd0;
end
end
B:
begin
if (w) begin
next_state = C;
z = 2'd2;
end
else begin
next_state <= A;
z = 2'd1;
end
end
C:
begin
if (w) begin
next_state = C;
z = 2'd2;
end
else begin
next_state = A;
z = 2'd0;
end
end
default:
begin
next_state = A;
z = 2'd0;
end
endcase
end
endmodule
三段式状态机代码:
module simple(
input clk,
input rst_n,
input w,
output reg[1:0] z
);
localparam A = 2'b00;
localparam B = 2'b01;
localparam C = 2'b10;
reg [1:0] current_state;
reg [1:0] next_state;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
current_state <= A;
end
else
current_state <= next_state;
end
always @(*) begin
case (current_state)
A:
begin
if (w) begin
next_state = B;
end
else begin
next_state = A;
end
end
B:
begin
if (w) begin
next_state = C;
end
else begin
next_state <= A;
end
end
C:
begin
if (w) begin
next_state = C;
end
else begin
next_state = A;
end
end
default:
begin
next_state = A;
end
endcase
end
always @(posedge clk or negedge rst_n) begin
if (rst_n) begin
z <= 2'd0;
end
else begin
case (next_state)
A: z <= 2'd0;
B: z <= 2'd1;
C: z <= 2'd2;
default: z <= 2'd0;
endcase
end
end
endmodule
转自:https://zhuanlan.zhihu.com/p/431143109
标签:区别,always,状态机,localparam,三种,rst,input,reg
From: https://www.cnblogs.com/amxiang/p/16646484.html