verilog实现状态机
- 背景
- 问题:计数状态机的实现
- Verilog实现此状态机
- 1. 代码如下
- 2. 代码的说明
- 3. 代码的仿真
背景
在学习spinalHDL的时候对他的状态机的实现有很多不懂的地方,特地使用了verilog编写了一个相同的状态机来学习其中的时序。
问题:计数状态机的实现
状态转移图如下图所示
- stateA:直接跳转到stateB,同时赋值cnt = 2
- stateB:判断cnt的值是否为6,若是则跳转到stateC,没有则继续执行stateB,同时cnt <= cnt + 1’b1
- stateC:什么也不做直接跳转到stateA
Verilog实现此状态机
1. 代码如下
这里的非阻塞赋值后加了 #1,方便后续的仿真
`timescale 1ns/1ns
module test(
input clk,
input rst,
output reg signal_out
);
parameter stateA = 2'b01, stateB = 2'b10, stateC = 2'b11;
reg [1:0] state;
reg [2:0] cnt;
always @(posedge clk or posedge rst) begin
if(rst) begin
state <= #1 stateA;
cnt <= #1 'h0;
end else begin
case(state)
stateA: begin
state <= #1 stateB;
cnt <= #1 'h2;
end
stateB: begin
cnt <= #1 cnt + 1'b1;
if(cnt == 'h6) begin
state <= #1 stateC;
end else begin
state <= #1 stateB;
end
end
stateC: state <= #1 stateA;
default: begin
state <= #1 stateA;
cnt <= #1 'h0;
end
endcase
end
end
always @(*) begin
if(state == stateB && cnt == 'h6) begin
signal_out = 'h1;
end else begin
signal_out = 'h0;
end
end
endmodule
2. 代码的说明
对上面的代码进行一个解释说明:
首先状态机有三个状态分别是stataA, stateB, stateC。
- 代码13、14行对信号进行复位操作此时state的状态为stateA,cnt值为0。
- 复位操作完成之后在时钟的上升沿进行代码16行的状态判断,由于之前的复位状态state为stateA,所以执行分支stateA里的代码块即18,19行代码,将状态转移到stateB, cnt赋值为2,如图所示。==需要注意的是虽然这里的cnt <= 2是在stateA里面的但是由于非阻塞赋值的并行性,state <= stateB语句和cnt <= 2语句都在同一个时钟上升沿作用,所以在图中可以看到状态为stateB时cnt的值才为2。
- 在下一个时钟上升沿的时候判断执行stateB分支中的代码块,22行代码执行cnt加1操作, 同时判断cnt是否等于6,注意这里判断cnt是否等于6中的cnt其实是还没有加1之前的cnt。如果cnt的值不等于6则继续执行stateB中的代码,直到cnt等于6。从图中我们可以看出当在时钟上升沿的时候判断出了cnt的值等于6了,那为什么在stateC状态下cnt还可以继续加1呢,这是因为cnt和state的赋值是并行的,当state从stateB状态跳转到stateC时,cnt的赋值也是同步进行的即cnt <= cnt + 1也是要执行的,所以才有了cnt = 7
- 状态跳转到了stateC时, 其中的代码块直接跳转到了stateA, 此时cnt的值保持不变还为7。
- 图二、
3. 代码的仿真
testbench如下所示
`timescale 1ns/1ns
`define clock_period 20
module test_tb;
reg clk ;
reg reset ;
wire io_signal_out;
test u_test(
.clk ( clk ),
.rst ( reset ),
.signal_out ( io_signal_out )
);
initial begin
clk = 1;
forever begin
#(`clock_period/2) clk = ~clk;
end
end
initial begin
reset = 1;
#(`clock_period*10-1);
reset = 0;
#(`clock_period*30);
$stop;
end
endmodule
仿真波形如下图所示