The case statement in Verilog is a powerful tool that helps to make decisions based on an expression’s value. It’s often used in designs like multiplexers, where different inputs are routed based on a selection signal. In this guide, we will explore how the Verilog case statement works, its syntax, and how it compares to if-else statements.

What is a Verilog Case Statement?

The case statement checks if a given expression matches one of the predefined values or alternatives and performs actions accordingly. It’s ideal for situations where you need to handle many different conditions in a clean and efficient way.

This statement is commonly used for creating multiplexers. When you have many possible conditions to check, the if-else construct might not be as efficient and could lead to priority encoders, not multiplexers.

Syntax of the Case Statement

In Verilog, the case statement begins with the keyword case and ends with endcase. Here’s the basic syntax:

case (<expression>)
  case_item1 :  <single statement>;
  case_item2, case_item3 :  <single statement>;
  case_item4 :  begin
                   <multiple statements>;
                 end;
  default : <statement>;
endcase
  • The expression inside the case is evaluated once and compared to each case_item.
  • If there’s a match, the corresponding statement or block of statements is executed.
  • If no match occurs, the default block is executed (if provided). If the default block is not specified, no action is taken if no match is found.

Key Points:

  1. Matching Expressions: The case checks each bit of the expression against the alternatives (e.g., 0, 1, x, z).
  2. Default Block: The default statement is optional but helps handle unexpected cases.
  3. Nested Cases: Case statements can be nested within other case statements.

Example: Simple Multiplexer Using Case Statement

Let’s look at an example of how the case statement is used to implement a 4-to-1 multiplexer. We have three 3-bit inputs, and we use a 2-bit select signal (sel) to choose which input gets routed to the output (out).

module my_mux (
  input [2:0] a, b, c,      // Three 3-bit inputs
  input [1:0] sel,           // 2-bit select signal
  output reg [2:0] out       // 3-bit output signal
);

  always @ (a, b, c, sel) begin
    case(sel)
      2'b00 : out = a;        // If sel=00, output is a
      2'b01 : out = b;        // If sel=01, output is b
      2'b10 : out = c;        // If sel=10, output is c
      default : out = 3'b000; // If sel is 11 or invalid, output is 0
    endcase
  end

endmodule

Hardware Schematic

This code generates a 4-to-1 multiplexer. It ensures that the output is 0 when the select signal (sel) is 3. For other values, the output corresponds to the selected input (a, b, or c).

Hardware Schematic

Simulation Log:

Here is what the simulation log might look like for various values of sel:

[0]  a=0x4 b=0x1 c=0x1 sel=0b11 out=0x0
[10] a=0x5 b=0x5 c=0x5 sel=0b10 out=0x5
[20] a=0x1 b=0x5 c=0x6 sel=0b01 out=0x5
[30] a=0x5 b=0x4 c=0x1 sel=0b10 out=0x1
[40] a=0x5 b=0x2 c=0x5 sel=0b11 out=0x0

Handling x and z Values in Case Statements

In Verilog, the case statement compares each bit of the expression with the alternatives, including x (unknown) and z (high impedance). If the expression contains x or z, and no case_item matches, the default statement will be executed.

Example:

If sel contains x or z, the output will default to zero since none of the case items will match.

ncsim> run
[0] a=0x4 b=0x1 c=0x1 sel=0bxx out=0x0
[10] a=0x3 b=0x5 c=0x5 sel=0bzx out=0x0
[20] a=0x5 b=0x2 c=0x1 sel=0bxx out=0x0

Case with x and z in Case Items

You can also include x and z in the case items themselves. This can be useful for matching unknown or high-impedance values. For example:

module my_mux (
  input [2:0] a, b, c,
  input [1:0] sel,
  output reg [2:0] out
);

  always @ (a, b, c, sel) begin
    case(sel)
      2'bxz : out = a;       // Match if sel is x or z
      2'bzx : out = b;       // Match if sel is zx
      2'bxx : out = c;       // Match if sel is xx
      default : out = 0;     // Default to zero
    endcase
  end

endmodule
Simulation Log:
[0] a=0x4 b=0x1 c=0x1 sel=0bxx out=0x1
[10] a=0x3 b=0x5 c=0x5 sel=0bzx out=0x5
[20] a=0x5 b=0x2 c=0x1 sel=0bxx out=0x1
[30] a=0x5 b=0x6 c=0x5 sel=0bzx out=0x6

Case vs. If-Else: What’s the Difference?

The main difference between a case statement and an if-else block lies in how they match conditions:

  1. Case Statement:
  • A single expression is compared to a list of possible alternatives.
  • It provides precise results, especially when dealing with x and z values.
  1. If-Else:
  • It can check multiple expressions and is more flexible but may be less efficient when handling many conditions.
  • If-else might be synthesized into a priority encoder instead of a multiplexer in some cases.

Conclusion

The Verilog case statement is an essential tool for handling multiple conditions efficiently. Whether you’re building a simple multiplexer or handling unknown values (x and z), the case statement ensures clean, readable, and predictable logic. By understanding how to use the case statement, you can design more complex digital circuits with ease.

Scroll to Top