Using case statement and if-else at the same time?

Eric Na picture Eric Na · Dec 2, 2013 · Viewed 28.4k times · Source

I am trying to write Verilog HDL behavioral description of the machine specified in the state diagram below.

enter image description here

I am using if-else statements inside a case statement, and this gives me syntax errors regarding those lines. Do you see what the problem is?

My code is attached below:

module foo(y_out, state, x_in, clk, reset);

    input x_in, clk, reset;
    output reg y_out;
    parameter s0 = 3'b000, s1 = 3'b001, s2 = 3'b010, s3 = 3'b011, s4 = 3'b100;
    output reg[2:0] state;
    reg[2:0] next_state;

    always @(posedge clk) begin
        if(reset == 1'b0) state <= s0;
        else state <= next_state;
    end
    always @(state, x_in) begin
        y_out = 0;
        next_state = s0;
        case(state, x_in)
        s0:
            if (!x_in) begin
                next_state = s3;
                y_out = 1'b0;
            end
            else begin
                next_state = s4;
                y_out =1'b1;
            end
        s1:
            if (!x_in) begin
                next_state = s1;
                y_out = 1'b0;
            end
            else begin
                next_state = s4;
                y_out =1'b1;
            end
        s2: if (!x_in) begin
                next_state = s2;
                y_out = 1'b0;
            end
            else begin
                next_state = s0;
                y_out =1'b1;
            end
        s3: if (!x_in) begin
                next_state = s1;
                y_out = 1'b0;
            end
            else begin
                next_state = s2;
                y_out =1'b1;
            end
        s4: if (!x_in) begin
                next_state = s2;
                y_out = 1'b0;
            end
            else begin
                next_state = s3;
                y_out =1'b0;
            end
        default begin
            next_state = s0;
            y_out = 1'b0;
        end
        endcase
    end
endmodule

module t_foo;

    wire t_y_out, t_state;
    reg t_x_in, t_clock, t_reset;

    foo M1(t_y_out, t_state, t_x_in, t_clock, t_reset);

    initial #200 $finish;
    initial begin
        t_reset = 0;
        t_clock = 0;
        #5 t_reset = 1;
      repeat (16)
        #5 t_clock = ~t_clock;
    end

    initial begin
        t_x_in = 0;
        #15 t_x_in = 1;
      repeat (8)
        #10 t_x_in = ~t_x_in;
    end
    initial begin
       $monitor("ABC: %d, x_in: %d, Clock: %d, Reset: %d", state, t_x_in, t_clock, t_reset);
       $dumpfile("5_41_wv.vcd");
       $dumpvars;
    end
endmodule

Answer

Morgan picture Morgan · Dec 2, 2013

case statements expect a single item if this is to be based on multiple wire/regs then they need to be concatenated using {}.

I would avoid using things like always @(state, x_in) begin and just write always @* begin. The @* will take care of the sensitivity list.

Using the concatenation operator would allow you to remove the if statements:

 always @* begin
   y_out = 0;
   next_state = s0;
   case({state, x_in}) //Added {}
    {s0, 1'b0}: 
      begin
        next_state = s3;
        y_out      = 1'b0;
      end
    {s0, 1'b1}:
      begin 
        next_state = s4;
        y_out      = 1'b1;
      end
    {s1, 1'b0}: 
      begin
        next_state = s1;
        y_out      = 1'b0;
      end
    {s1, 1'b1}:
      begin
        next_state = s4;
        y_out      = 1'b1;
      end

Using a casez would allow you to add do not cares to the next_state logic:

 always @* begin
   y_out = 0;
   next_state = s0;
   casez({state, x_in}) //Added {}
    {s0, 1'bx}: //Do not care about the state of x_in
      begin
        next_state = s3;
        y_out      = 1'b0;
      end
    {s1, 1'b0}: 
      begin
        next_state = s1;
        y_out      = 1'b0;
      end
    {s1, 1'b1}:
      begin
        next_state = s4;
        y_out      = 1'b1;
      end