祝各位道友念头通达
GitHub Gitee 语雀 打赏

verilog 中的三段式状态机

抄的: https://zhuanlan.zhihu.com/p/431143109

一段式状态机

特点:
最主要的特征是只有一个always块。在这个always块内既描述状态转移,又含有组合逻辑输入/输出,当前状态用寄存器输出;在这种状态机的写法中,组合逻辑电路和时序逻辑电路都在一起,没有分开;因此这种写法增加了代码的复杂度且不利于代码的维护和修改,同时也不利于后期约束;

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

二段式状态机

特点
最主要的特征是有两个always块,将组合逻辑和时序逻辑分开。其中一个always块采用同步时序描述状态转移,而另一个always块采用组合逻辑来判断状态转移的条件,描述状态转移规律及输出;在这种写法下,需要定义两个状态,分别是现态和次态,通过现态和次态的转换来实现状态转移;两段式状态机可以清晰完整的显示出状态机的结构,有利于代码的维护和后期修改,同时也降低编写复杂度;

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

三段式状态机

特点
最主要的特征是有三个always块。区别于两段式状态机的关键在于两段式状态机直接采用组合逻辑输出,而三段式状态机则通过在组合逻辑后再增加一级寄存器实现逻辑输出——即一个always块采用同步时序描述状态转移,一个always块采用组合逻辑判断转移条件、转移状态规律,最后一个always块采用同步时序描述状态的输出;这种三段式状态机的写法代码非常清晰,极大降低了编写维护代码的复杂度,最大程度清晰完整的显示出状态机的结构。同时可以有效地滤除两段式状态机组合逻辑输出可能产生的毛刺信号;另外对于总线形式的输出来说,容易使总线数据对齐,从而减小总线数据间的偏移,减小接收端数据采样出错的频率;但是代码量会长

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
posted @   韩若明瞳  阅读(2017)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示