同步状态机——三段式状态机
三段式状态机
下图分别为时钟同步的Moore状态机(左)和时钟同步的Mearly状态机(右),二者都由产生下一状态的组合逻辑、当前状态寄存器和产生输出的组合逻辑三个部分组成。
三段式状态机正如其名字一样,每个部分采用一个always过程块进行描述,可以清晰地显示出状态机的结构。
在调试多输出状态机时,还可以根据输出的数量把产生输出的组合逻辑按输出写成彼此独立的always组合块,以方便调试,在设计复杂的多输出状态机时推荐采用这种风格。
别人的总结:
- 使用三段式状态机需要声明内部信号,一般需要定义state和nextstate;
- 三个always语句块分别代表:
- 当前状态转换到下一状态的时序逻辑;
- 在当前状态在当前输出下转换为下一状态的组合逻辑;
- 当前状态(和当前输入)产生当前输出的组合逻辑;
样例:
下图为样例的状态转移图,并使用三段式状态机对其进行描述。由于该状态机包含两个输出G、F,所以代码中包含两个输出组合逻辑。
// 三段式状态机
module fsm_mult_out(
output reg K2, K1,
input clk, Reset, A
);
reg [1:0] state, nextstate;
parameter
Idle = 2'b00,
Start = 2'b01,
Stop = 2'b10,
Clear = 2'b11;
// -----------------当前状态寄存器-------------------------
always @(posedge clk) // 为什么这里要用非阻塞赋值,后面用阻塞赋值?
if(!Reset)
state <= Idle;
else
state <= nextstate;
// ----------------产生下一状态的组合逻辑--------------------
always @(state, A)
case(state)
Idle: if(A) nextstate = Start;
else nextstate = state;
Start: if(!A) nextstate = Stop;
else nextstate = state;
Stop: if(A) nextstate = Clear;
else nextstate = state;
Clear: if(!A) nextstate = Idle;
else nextstate = Clear;
default: nextstate = 2'bxx;
endcase
// --------------产生输出的组合逻辑--------------------------
// assignment for K1
always @(state, Reset, A)
if(!Reset) K1 = 0;
else
if(state==Clear && !A) K1 = 1;
else K1 = 0;
// assginment for K2
always @(state, Reset, A)
if(!Reset) K2 = 0;
else
if(state==Stop && A) K2 = 1;
else K2 = 0;
endmodule
相应的testbench
// testbench
module t_fsm();
reg a;
reg clk, rst;
wire k1, k2;
// reg [1:0] state;
fsm_mult_out m(.K2(k2), .K1(k1), .A(a), .clk(clk), .Reset(rst));
initial
begin
// state = 2'b00;
a = 0;
rst = 1;
clk = 0;
#22 rst = 0;
#133 rst = 1;
end
always #50 clk = ~clk;
always @(posedge clk)
begin
#30 a = {$random}%2;
#(3*50 + 12);
end
initial
begin
#100000 $stop;
end
endmodule