4
\$\begingroup\$

I am trying to code a state machine for the given state diagram:

State DiagramI

module mealy(input x_in,rst_n,clk, output reg y_out);

parameter s0 = 2'b00, s1 = 2'b01 , s2 = 2'b10,s3 = 2'b11;
reg [1:0] p_state,n_state;

always@(posedge clk,negedge rst_n) begin
    if(!rst_n) p_state = s0;
    else
    if(clk)
    p_state <= n_state;
end

always@(x_in,p_state) begin
    case (p_state)
        s0:
            n_state = x_in ? s2 : s1;
        s1: 
            n_state = x_in ? s2 : s1;
        s2:
            n_state = x_in ? s2 : s1;
        s3:
            n_state = s3;
    endcase
end

always@(x_in,p_state) begin
    case (p_state)
        s0:
            y_out = 1'b0;
        s1:
            y_out = x_in ? 1'b1 : 1'b0;
        s2:
            y_out = !x_in ? 1'b1 : 1'b0;
        s3:
            y_out = 1'b0;
    endcase
end

endmodule
module mealy_tb;

reg x_in,rst_n,clk;
wire y_out;

mealy dut(x_in,rst_n,clk,y_out);

initial begin
    clk = 1'b0;
    repeat(7) #10 clk = ~clk;
end

initial begin
        rst_n = 1'b0;
        #20;
        rst_n = 1'b1;
        x_in = 1'b0;
        #10;
        x_in = 1'b1;
        #10;
        x_in = 1'b0;
        #10;
        x_in = 1'b1;
        #10;
        x_in = 1'b1;
end

always@(posedge clk,negedge rst_n)
$monitor($time," rst_n = %b clk = %b x_in = %b y_out = %b ",rst_n,clk,x_in,y_out); 

endmodule

If rst_n is low, then I reset my state machine to its origin state s0, else make the present state to the next state. Then I followed the diagram. I use case statements to show the present state and next state. Finally, I setup output according to the state and input.

In the testbench, I tried a small sample case.

This is my first time writing a state machine, so I need some guidance on the errors that I have made and the things that I can improve upon.

\$\endgroup\$
0

1 Answer 1

4
\$\begingroup\$

You have done an excellent job of partitioning your design code from your testbench code into different modules. Similarly, you used good partioning between your sequential logic and combinational logic into separate always blocks. You made good use of parameters for constants, and on the whole, the code layout is good (indentation, etc.).

In the sequential logic block, you should not use the following line:

if(clk)

While the code may simulate as desired, it is not needed, and it is not a common way to code sequential logic. It may cause a problem if you want to synthesize the code.

You should use nonblocking assignments (<=) to p_state in the sequential logic block.

For the combinational logic blocks, it is preferable to use the implicit sensitivity list instead of explicitly listing each signal by name. This is less error-prone:

always @*

This avoids problems with synthesis (having to maintain an explicit list).

In the testbench, it is preferable to make connections to the dut instance ports by name instead of by port order:

mealy dut (
    .clk    (clk),
    .rst_n  (rst_n),
    .x_in   (x_in),
    .y_out  (y_out)
);

While it is more verbose, it avoids another common Verilog error of connecting signals up in the wrong order.

The $monitor statement is intended to be called once in an initial block, instead of every time an event occurs in an always block.

You should drive the synchronous x_in input signal using nonblocking assignments (<=) and at the posedge clk to avoid simulation race conditions.

Here is the code with the recommended changes:

module mealy (
    input x_in, rst_n, clk, 
    output reg y_out
);

parameter s0 = 2'b00, s1 = 2'b01, s2 = 2'b10, s3 = 2'b11;
reg [1:0] p_state, n_state;

always @(posedge clk, negedge rst_n) begin
    if (!rst_n)
        p_state <= s0;
    else
        p_state <= n_state;
end

always @* begin
    case (p_state)
        s0: n_state = x_in ? s2 : s1;
        s1: n_state = x_in ? s2 : s1;
        s2: n_state = x_in ? s2 : s1;
        s3: n_state = s3;
    endcase
end

always @* begin
    case (p_state)
        s0: y_out = 1'b0;
        s1: y_out =  x_in ? 1'b1 : 1'b0;
        s2: y_out = !x_in ? 1'b1 : 1'b0;
        s3: y_out = 1'b0;
    endcase
end

endmodule

module mealy_tb;

reg x_in, rst_n, clk;
wire y_out;

mealy dut (
    .clk    (clk),
    .rst_n  (rst_n),
    .x_in   (x_in),
    .y_out  (y_out)
);

initial begin
    clk = 1'b0;
    repeat (7) #10 clk = ~clk;
end

initial begin
    $monitor($time," rst_n = %b clk = %b x_in = %b y_out = %b ", rst_n, clk, x_in, y_out); 
    rst_n = 0;
    #20;
    rst_n = 1;
    @(posedge clk);
    x_in <= 0;
    @(posedge clk);
    x_in <= 1;
    @(posedge clk);
    x_in <= 0;
    @(posedge clk);
    x_in <= 1;
    @(posedge clk);
    x_in <= 1;
    @(posedge clk);
end

endmodule
\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.