Tips

注意,新手写三段式的时候第一次会犯的错误就是,在三段式状态机的第二段没有用always@()always @(*)。记住,always@()always@(*)是用于组合逻辑,组合逻辑只需要根据模块内的变量综合确定触发条件,不需要根据时钟信号来确定触发条件。
另外,如果第三段基于的是statestatenextnext,则输出波形会整体提前一个时钟信号周期,因此必须基于statestatecurcur

Verilog Code

`timescale 1ns/1ns
module fsm1(
	input wire clk  ,
	input wire rst  ,
	input wire data ,
	output reg flag
);
//*************code***********//
    //行为描述
    reg [1:0] state_cur = 2'b00, state_next = 2'b00;
    parameter S0 = 2'b00, S1 = 2'b01, S2 = 2'b10, S3 = 2'b11;
    parameter ZERO = 1'b0, ONE = 1'b1;
    //状态流转
    always @(posedge clk or negedge rst)begin
        if(~rst)begin
            state_cur <= S0;
        end
        else begin
            state_cur <= state_next;
        end
    end
    //状态切换
    always @(*)begin
        if(~rst)begin
            state_next = S0;
        end
        else begin
            case(state_cur)
                S0:begin
                    if(data == ZERO)begin
                        state_next = S0;
                    end
                    else if(data == ONE)begin
                        state_next = S1;
                    end
                end
                S1:begin
                    if(data == ZERO)begin
                        state_next = S1;
                    end
                    else if(data == ONE)begin
                        state_next = S2;
                    end
                end
                S2:begin
                    if(data == ZERO)begin
                        state_next = S2;
                    end
                    else if(data == ONE)begin
                        state_next = S3;
                    end
                end
                S3:begin
                    if(data == ZERO)begin
                        state_next = S3;
                    end
                    else if(data == ONE)begin
                        state_next = S0;
                    end
                end
                default:begin
                    state_next = S0;
                end
            endcase
        end
    end
    //状态输出
    always @(posedge clk or negedge rst)begin
        if(~rst)begin
            flag <= ZERO;
        end
        else begin
            case(state_cur)
                S0:begin
                    if(data == ZERO)begin
                        flag <= ZERO;
                    end
                    else if(data == ONE)begin
                        flag <= ZERO;
                    end
                end
                S1:begin
                    if(data == ZERO)begin
                        flag <= ZERO;
                    end
                    else if(data == ONE)begin
                        flag <= ZERO;
                    end
                end
                S2:begin
                    if(data == ZERO)begin
                        flag <= ZERO;
                    end
                    else if(data == ONE)begin
                        flag <= ZERO;
                    end
                end
                S3:begin
                    if(data == ZERO)begin
                        flag <= ZERO;
                    end
                    else if(data == ONE)begin
                        flag <= ONE;
                    end
                end
                default:begin
                    flag <= ZERO;
                end
            endcase
        end
    end
//*************code***********//
endmodule

Testbench Code

`timescale 1ns/1ns
module testbench();
	reg clk = 1'b1;
	always #5 clk = ~clk;  // Create clock with period=10
// A testbench
    reg rst = 1'b0, data = 1'b0;
    wire flag;
    fsm1 t(.clk(clk),
           .rst(rst),
           .data(data),
           .flag(flag)
          );
    initial begin
        #10 rst = 1'b1;
        #20 data = 1'b1;
        #10 data = 1'b0;
        #10 data = 1'b1;
        #30 data = 1'b0;
        #10 data = 1'b1;
        #50 data = 1'b0;
        #10 data = 1'b1;
        #20 data = 1'b0;
        #20 $finish();
    end
//end    
  initial begin
    $dumpfile("out.vcd");
    // This will dump all signal, which may not be useful
    //$dumpvars;
    // dumping only this module
    //$dumpvars(1, testbench);
    // dumping only these variable
    // the first number (level) is actually useless
    $dumpvars(0, testbench);
end     
endmodule

Wave

alt