Tutorials

Learn More

Case statement in Verilog

The case statement has a given expression and it is checked with the expression (case item) mentioned in the list in the written order and if it matches then the statement or group of statements are executed. If it does not match with any of the written expressions of the list then, the default statement will be executed.

If the ‘default’ statement is not given and the given expression is not matched with any expression in the list, then the case statement evaluation will exit.

Verilog case statement uses case, endcase, and default keywords.

Syntax:


case(<expression>)
  <case_item1>:
  <case_item2>:
  <case_item3>:
  <case_item4>: begin
                  ...
                  ...
                end
   default: 
endcase

Note:

  1. The default statement is not mandatory. There must be only one default statement for the single case statement.
  2. The nested case statement is allowed.
  3. Verilog case statements work similarly as switch statements in C language.
  4. An expression inside a case statement can not use <= (relational operator). 
  5. The === operator is used instead of == operator in case statement comparison. I.e. case statement checks for 0, 1, x and z values in the expression explicitly. (Check example)

Example:

module case_example;  
  reg [2:0] data;
  
  always @(data) begin
    case(data)
      3'h2: $display("value of data is 2");
      3'h4: $display("value of data is 4");
      3'h5: $display("value of data is 5");
      default: $display("default statement is executed for data = %0d", data);
    endcase
  end
  
  initial begin
    repeat(10) begin
      data = $random;
      #1;
    end
  end
endmodule

Output:

value of data is 4
default statement is executed for data = 1
default statement is executed for data = 3
value of data is 5
value of data is 2
default statement is executed for data = 1
value of data is 5

4:1 Mux Verilog implementation

The case statement is also used to design multiplexers. Below 4:1 MUX has two select inputs (sel) and four inputs (i3,i2,i1, and i0) and has one output (y).

module mux_example(
  input [1:0] sel,
  input  i0,i1,i2,i3,
  output reg y);
    
  always @(*) begin
    case(sel)
      2'h0: y = i0;
      2'h1: y = i1;
      2'h2: y = i2;
      2'h3: y = i3;
      default: $display("Invalid sel input");
    endcase
  end
endmodule

Output:

sel = 00 -> i3 = 0, i2 = 1 ,i1 = 0, i0 = 1 -> y = 1
sel = 01 -> i3 = 0, i2 = 1 ,i1 = 0, i0 = 1 -> y = 0
sel = 11 -> i3 = 0, i2 = 1 ,i1 = 0, i0 = 1 -> y = 0
sel = 01 -> i3 = 0, i2 = 1 ,i1 = 0, i0 = 1 -> y = 0

Ambiguous inputs to the case statement

Now, let’s see if the user provides ambiguous values to the case statement (Point 5)

module case_example(
  input  a,
  output reg [3:0] out);
    
  always @(*) begin
    case(a)
      1'h0: out = 4;
      1'h1: out = 5;
      1'hx: out = 6;
      1'hz: out = 7;
      default: $display("Invalid sel input");
    endcase
  end
endmodule

Testbench: User has provided ambiguous values as x and z.

module tb;
  reg a;
  wire [3:0] out;
  
  case_example case_ex(a, out);
  
  initial begin
    $monitor("a = %b -> out = %0h", a, out);
       a = 1'b1;
    #1 a = 1'b0;
    #1 a = 1'bz;
    #1 a = 1'bx;
  end
endmodule

Output:

a = 1 -> out = 5
a = 0 -> out = 4
a = z -> out = 7
a = x -> out = 6

casex and cazez statements

The case statement also has a total of three variations: case, casex and casez. Note the following differences.

  1. case: considers x and z as it is (as shown in above example). If an exact match is not found, the default statement will be executed.
  2. casex: considers all x and z  values as don’t care.
  3. casez: considers all z values as don’t cares. The z can also be specified as ?

casez statement example

module casez_example(
  input  [1:0] data,
  output reg [3:0] out);
    
  always @(*) begin
    casez(data)
      2'b0z: out = 1;
      2'bz0: out = 2;
      2'b1z: out = 3;
      2'bxz: out = 4;
      
      2'b0x: out = 5;
      2'bx0: out = 6;
      2'b1x: out = 7;
      2'bx1: out = 8;

      default: $display("Invalid sel input");
    endcase
  end
endmodule

Output:

data = x1 -> out = 4
data = 0x -> out = 1
data = x0 -> out = 2
data = z1 -> out = 1
data = 0z -> out = 1
data = z0 -> out = 1
data = 1z -> out = 2

casex statement example

module casex_example(
  input  [1:0] data,
  output reg [3:0] out);
    
  always @(*) begin
    casex(data)
      2'b0z: out = 1;
      2'bz0: out = 2;
      2'b1z: out = 3;
      2'bxz: out = 4;
      
      2'b0x: out = 5;
      2'bx0: out = 6;
      2'b1x: out = 7;
      2'bx1: out = 8;

      default: $display("Invalid sel input");
    endcase
  end
endmodule

Output:

data = x1 -> out = 1
data = 0x -> out = 1
data = x0 -> out = 1
data = z1 -> out = 1
data = 0z -> out = 1
data = z0 -> out = 1
data = 1z -> out = 2

Note:

  1. In simple terms, casez ignores bit positions having z value alone and casex ignores bit positions having x or z values.
  2. The ‘casez’ is more likely used as compared to ‘casex’ as the ‘casez’ does not ignore bit positions having x values and ‘casex’ is not synthesizable as well.