Multiple Items Matching in Verilog Case Statement

Multiple Items Matching in Verilog Case Statement

I have a state machine with several states that are very similar. I could write it for each state, like in the following example:

module CHECK_FSM (
GO,
DONE,
CLK, RESETN );

input       GO;
output reg  DONE;
input       CLK,RESETN;

reg[7:0]    state;

reg[7:0]    next_state; 

    //the actual registers
    always @(posedge CLK or negedge RESETN)
        if (!RESETN)    state <= 8'd0;
        else            state <= next_state;

    //next state logic
    always @(*)
        begin
        //defaults
        next_state = state;
        DONE = 1'b0; //low by default

        case(state)
            0: //S_INIT
                if(GO==1'b1)
                    next_state = 8'd1;
                else
                    next_state = 8'd0;
            1: //S_WAIT_1:
                if(GO==1'b1)
                    next_state = state+1; //continue
                else
                    next_state = 8'd0; //go back to S_INIT
            2: //S_WAIT_2:
                if(GO==1'b1)
                    next_state = state+1; //continue
                else
                    next_state = 8'd0; //go back to S_INIT
            3: //S_WAIT_3:
                if(GO==1'b1)
                    next_state = state+1; //continue
                else
                    next_state = 8'd0; //go back to S_INIT
            //...
            127: //S_FINISH
                begin
                DONE = 1'b1;
                next_state = state; //stay put
                end

            default: next_state= 8'd0;
            endcase
        end

endmodule

I am wondering if there is a way to specify the case statement for multiple states. Something like:

        case(state)
            0: //S_INIT
                if(GO==1'b1)
                    next_state = 8'd1;
                else
                    next_state = 8'd0;
            [1-->126]:
                if(GO==1'b1)
                    next_state = state+1; //continue
                else
                    next_state = 8'd0; //go back to S_INIT
            127: //S_FINISH
                begin
                DONE = 1'b1;
                next_state = state; //stay put
                end

            default: next_state= 8'd0;
            endcase

I want to avoid repeating the statements (that are all the same) to be more clear and to avoid errors if I need to modify it afterwards (my actual FSM is more complicated than this...). Any ideas ?

PS: The code is meant to be synthesized. In my case, the synthesis tool does not support SystemVerilog statements, so I am hoping for a Verilog solution.

2 Answers

The case inside statement in SystemVerilog would do exactly what you want. But since you have constrained yourself to Verilog,it might be more practical to use an if/else chain than a case statement for the example given

if (state==0) begin : S_INIT
                if(GO==1'b1)
                    next_state = 8'd1;
                else
                    next_state = 8'd0;
              end
 else if (state >0 && state < 127) begin
                if(GO==1'b1)
                    next_state = state+1; //continue
                else
                    next_state = 8'd0; //go back to S_INIT
            end
else if (state == 127) begin : S_FINISH
                DONE = 1'b1;
                next_state = state; //stay put
                end
else begin : S_DEFUALT
            default: next_state= 8'd0;
end

or you can still use a case statement in this form

case(1)
  state==0: //S_INIT
                if(GO==1'b1)
                    next_state = 8'd1;
                else
                    next_state = 8'd0;
  (state>0&&state<127):
                if(GO==1'b1)
                    next_state = state+1; //continue
                else
                    next_state = 8'd0; //go back to S_INIT
  state==127: //S_FINISH
                begin
                DONE = 1'b1;
                next_state = state; //stay put
                end
  default: next_state= 8'd0;
endcase

case statement syntax allows for specifying multiple case item values separated by commas:

1, 2, 3, 4,
5, 6, 7, 8: begin
    // your code
end

That will be quite cumbersome for 126 values.

In your case, since you are only using values 0 to 127, you don't need 8 bits for your state variables. You could change them to be 7-bit ([6:0]), and then your case would be full. Then, you could use the default for your states 1-126 without having the long comma-separated list.

case (state)
    0       : //...
    127     : //...
    default : //1-126 ...
endcase

For the benefit of tools which do support SystemVerilog syntax, IEEE Std 1800-2017, section 12.5.4 Set membership case statement describes the case inside construct:

case (state) inside
    0       : //...
    [1:126] : //...
    default : //...
endcase

Your synthesis tool may or may not support it, but it is worth a quick try.

0

Your Answer

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

Sarah Jenkins
Author

Sarah Jenkins

Sarah Jenkins is a veteran tech journalist with over 12 years of experience covering artificial intelligence, mobile innovations, and digital ethics. Her insights have appeared in leading technology publications worldwide.