Verilog写状态机的三种描述方式之二段式
Verilog写状态机的二段式描述方式
- 1,门级代码
- 2,门级代码生成的电路原理图
- 3,测试代码
- 4,测试代码生成的波形图,前仿真波形验证
参考文献1:FPGA学习之状态机的多种描述方式
参考文献2:本专栏的Verilog写状态机的三种描述方式(三段式、二段式和一段式)
参考文献3:本专栏的VL-39自动贩卖机
二段式描述:
即二个always。输出使用的是组合逻辑,很容易产生毛刺等不稳定因素。
其中第二个always@(*),此处不受clk的影响。
三段式描述
即三个always。根据下一个状态的判断,利用同步时序逻辑来寄存状态机的输出,从而消除了组合逻辑的不稳定性和毛刺的隐患,有利于时序路径分组。
1,门级代码
// 状态机两段式
// 自动售卖机
module auto_sell2(
input clk,
input rst_n,
input half, // 0.5元
input one, // 1.0元
output reg drink, // 饮料售价2.5元,售出饮料信号
output reg flag, // 找零信号
output c_state,
output n_state
);
reg [2:0] c_state; // 投币信号
reg [2:0] n_state; //
parameter S0 = 3'd0; // 无投币
parameter S1 = 3'd1; // 投币0.5
parameter S2 = 3'd2; // 投币1.0
parameter S3 = 3'd3; // 投币1.5
parameter S4 = 3'd4; // 投币2.0
parameter S5 = 3'd5; // 投币2.5,拉高drink信号
parameter S6 = 3'd6; // 找零
// 第一段
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
c_state <= S0;
else
c_state <= n_state;
end
// 第二段
always@(*) begin
if(!rst_n) begin
drink <= 0;
flag <= 0;
n_state <= S0;
end
else begin
case(c_state)
S0: begin // 起始状态S0时,此时没钱
if(half == 1'b1) // 当0.5元,则进入S1状态
n_state <= S1;
else if(one == 1'b1) // 当1.0元,则进入S2状态
n_state <= S2;
else // 否则就是没有钱进入,停留在S0状态
n_state <= S0;
end
S1: begin // 0.5元
if(half == 1'b1)
n_state <= S2;
else if(one == 1'b1)
n_state <= S3;
else
n_state <= S1;
end
S2: begin // 1.0元
if(half == 1'b1)
n_state <= S3;
else if(one == 1'b1)
n_state <= S4;
else
n_state <= S2;
end
S3: begin // 1.5元
if(half == 1'b1)
n_state <= S4;
else if(one == 1'b1)
n_state <= S5;
else
n_state <= S3;
end
S4: begin
if(half == 1'b1)
n_state <= S5;
else if(one == 1'b1)
n_state <= S6;
else
n_state <= S0;
end
S5: begin
drink <= 1;
n_state <= S0;
end
S6: begin
drink <= 1;
flag <= 1;
n_state <= S0;
end
default:n_state <= S0;
endcase
end
end
endmodule
2,门级代码生成的电路原理图
3,测试代码
// auto_sell3
// tb 测试信号
module tb;
reg clk, rst_n, half, one;
wire [2:0] c_state, n_state;
wire drink, flag;
//-----时钟---------
always #10 clk = ~clk; // T=20
initial begin
rst_n = 0; clk = 1;
#15; rst_n = 1;
end
initial begin
#0; half = 0; one = 0; // 在S0状态
#20; half = 0; one = 0;
#20; half = 1; one = 0; // 进1个状态,S1
#20; half = 1; one = 0; // 进1
#20; half = 0; one = 1; // 进2
#20; half = 0; one = 0;
#20; half = 1; one = 0; // 进1 ,到S5状态,下一个S0状态
#20; half = 0; one = 1; // S2
#20; half = 0; one = 1; // S4
#20; half = 0; one = 1; // S6
#20; half = 0; one = 1;
#60; half = 0; one = 0;
#100; $stop;
end
auto_sell2 uu(
.clk(clk),
.rst_n(rst_n),
.half(half),
.one(one),
.drink(drink),
.flag(flag),
.c_state(c_state),
.n_state(n_state)
);
endmodule