同步状态机——三段式状态机

三段式状态机

下图分别为时钟同步的Moore状态机(左)和时钟同步的Mearly状态机(右),二者都由产生下一状态的组合逻辑、当前状态寄存器和产生输出的组合逻辑三个部分组成。

三段式状态机正如其名字一样,每个部分采用一个always过程块进行描述,可以清晰地显示出状态机的结构。

在调试多输出状态机时,还可以根据输出的数量把产生输出的组合逻辑按输出写成彼此独立的always组合块,以方便调试,在设计复杂的多输出状态机时推荐采用这种风格。

 同步状态机——三段式状态机同步状态机——三段式状态机

 

别人的总结:

  1. 使用三段式状态机需要声明内部信号,一般需要定义state和nextstate;
  2. 三个always语句块分别代表:
    1. 当前状态转换到下一状态的时序逻辑;
    2. 在当前状态在当前输出下转换为下一状态的组合逻辑;
    3. 当前状态(和当前输入)产生当前输出的组合逻辑;

 样例:

  下图为样例的状态转移图,并使用三段式状态机对其进行描述。由于该状态机包含两个输出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

相关推荐