参考
状态机顺序化描述------串口与 AXI4 协议流程建模.csdn
目标
| 时钟 | 状态 | LED |
|---|---|---|
| Reset | S0 | 0 灭 |
| 第1拍 | S1 | 1 亮 |
| 第2拍 | S2 | 0 灭 |
| 第3拍 | S3 | 1 亮 |
| 第4拍 | S0 | 0 灭 |
| 第5拍 | S1 | 1 亮 |
| 第6拍 | S2 | 0 灭 |
| 第7拍 | S3 | 1 亮 |
一段式
verilog
`timescale 1ns/1ps
module fsm_one_block (
input wire i_clk,
input wire i_rst_n,
output reg o_led
);
// 状态定义
localparam S0 = 2'd0;
localparam S1 = 2'd1;
localparam S2 = 2'd2;
localparam S3 = 2'd3;
reg [1:0] r_state;
// 一段式状态机
// 状态跳转和输出逻辑全部写在一个 always 块中
always @(posedge i_clk or negedge i_rst_n) begin
if (!i_rst_n) begin
r_state <= S0;
o_led <= 1'b0;
end
else begin
case (r_state)
S0: begin
o_led <= 1'b0;
r_state <= S1;
end
S1: begin
o_led <= 1'b1;
r_state <= S2;
end
S2: begin
o_led <= 1'b0;
r_state <= S3;
end
S3: begin
o_led <= 1'b1;
r_state <= S0;
end
default: begin
o_led <= 1'b0;
r_state <= S0;
end
endcase
end
end
endmodule
三段式
verilog
`timescale 1ns/1ps
module fsm_three_block (
input wire i_clk,
input wire i_rst_n,
output reg o_led
);
//============================================================
// 状态定义
//============================================================
localparam S0 = 2'd0;
localparam S1 = 2'd1;
localparam S2 = 2'd2;
localparam S3 = 2'd3;
//============================================================
// 状态寄存器
//============================================================
reg [1:0] r_state;
reg [1:0] r_next_state;
//============================================================
// 第一段:状态寄存器
//============================================================
always @(posedge i_clk or negedge i_rst_n) begin
if (!i_rst_n)
r_state <= S0;
else
r_state <= r_next_state;
end
//============================================================
// 第二段:次态逻辑
//============================================================
always @(*) begin
// 默认保持当前状态
r_next_state = r_state;
case (r_state)
S0: begin
r_next_state = S1;
end
S1: begin
r_next_state = S2;
end
S2: begin
r_next_state = S3;
end
S3: begin
r_next_state = S0;
end
default: begin
r_next_state = S0;
end
endcase
end
//============================================================
// 第三段:输出逻辑
//============================================================
always @(*) begin
// 默认灭
o_led = 1'b0;
case (r_state)
S0: begin
o_led = 1'b0;
end
S1: begin
o_led = 1'b1;
end
S2: begin
o_led = 1'b0;
end
S3: begin
o_led = 1'b1;
end
default: begin
o_led = 1'b0;
end
endcase
end
endmodule
tb.v
verilog
`timescale 1ns/1ps
module tb;
//============================================================
// Clock
//============================================================
reg i_clk;
initial begin
i_clk = 1'b0;
forever #5 i_clk = ~i_clk;
end
//============================================================
// Reset
//============================================================
reg i_rst_n;
initial begin
// 初始复位
i_rst_n = 1'b0;
// 保持复位 20ns
#20;
// 释放复位
i_rst_n = 1'b1;
end
//============================================================
// DUT 输出
//============================================================
wire w_led_one;
wire w_led_three;
//============================================================
// 一段式状态机
//============================================================
fsm_one_block u_fsm_one_block (
.i_clk (i_clk),
.i_rst_n (i_rst_n),
.o_led (w_led_one)
);
//============================================================
// 三段式状态机
//============================================================
fsm_three_block u_fsm_three_block (
.i_clk (i_clk),
.i_rst_n (i_rst_n),
.o_led (w_led_three)
);
//============================================================
// 仿真监视
//============================================================
initial begin
$display("================================================");
$display(" Time Reset OneBlock ThreeBlock");
$display("================================================");
$monitor(
"%5t %b %b %b",
$time,
i_rst_n,
w_led_one,
w_led_three
);
end
//============================================================
// 自动检查两个状态机输出
//============================================================
always @(posedge i_clk) begin
if (i_rst_n) begin
if (w_led_one !== w_led_three) begin
$display(
"ERROR: time=%0t, one_block=%b, three_block=%b",
$time,
w_led_one,
w_led_three
);
end
end
end
//============================================================
// 仿真结束
//============================================================
initial begin
#120;
$display("================================================");
$display("Simulation finished.");
$display("================================================");
$finish;
end
endmodule
测试

bash
一段式:
STATE : S0 S1 S2 S3 S0 S1 S2
LED :____________|‾‾‾‾|____|‾‾‾‾|____|‾‾‾‾
三段式:
STATE : S0 S1 S2 S3 S0 S1 S2 S3
STATE': S1 S2 S3 S0 S1 S2 S3 S0
LED : ________|‾‾‾‾|____|‾‾‾‾|____|‾‾‾‾|____|‾‾‾‾|____