casez and casex


In addition to the regular case statements, verilog provides two variations casez and casex. Before we try to understand casex and casez, we need to understand that there are 4 types of logic levels and in verilog

0 - logic zero
1 - logic one,
z - high impedance state.
x - unknown logic value - can be 0,1,z or transition.

In normal case statement, the case expression needs to EXACTLY match, for one of the case statements to execute. There is no provision of Don't cares.

casez solves this problem by allowing dont cares. If there is a z or ? in the case expression, then it means that the expression can match to 0, 1 or z.

A very good example is the priority encoder. A common use of priority encoders is for interrupt controllers, where we select the most critical out of multiple interrupt requests.

Here is the truth table and block diagram of a 4 input and 3 output priority encodr.



  1. // Referencedesigner.com
  2. // Priority Encoder Example - Usage of casez
  3. // Verilog Tutorial
  4.  
  5. module priory_encoder_casez
  6. (
  7. input wire [4:1] A,
  8. output reg [2:0] pcode
  9. );
  10. always @ *
  11.  
  12. casez (A)
  13. 4'b1zzz :
  14. pcode = 3'b100;
  15. 4'b01zz :
  16. pcode = 3'b011 ;
  17. 4'b001z :
  18. pcode = 3'b010;
  19. 4'b0001 :
  20. pcode = 3'b001;
  21. 4'b0000 :
  22. pcode = 3'b000;
  23. endcase
  24.  
  25. endmodule


Note the statement

4'b1zzz :
pcode  = 3'b100;


It means that we don't care if the bits [2:0] are 0, 1 or z. The above statement could also be written as

4'b1??? :
pcode  = 3'b100;


We now suggest that you write a test bench for this code and verify that it works. If you have difficulty, you can check it with following test bench

  1.  
  2. `timescale 1ns / 1ps
  3. module stimulus;
  4. reg [4:1] A;
  5. wire [2:0] pcode;
  6. // Instantiate the Unit Under Test (UUT)
  7. priory_encoder_casez uut (
  8. .A(A),
  9. .pcode(pcode)
  10. );
  11.  
  12. initial begin
  13. // Initialize Inputs
  14. A = 4'b0000;
  15.  
  16. #20 A = 4'b0001;
  17. #20 A = 4'b0010;
  18. #20 A = 4'b0011;
  19. #20 A = 4'b0100;
  20. #20 A = 4'b0101;
  21. #20 A = 4'b0110;
  22. #20 A = 4'b0111;
  23. #20 A = 4'b1000;
  24. #20 A = 4'b1001;
  25. #20 A = 4'b1010;
  26. #20 A = 4'b1011;
  27. #20 A = 4'b1100;
  28. #20 A = 4'b1101;
  29. #20 A = 4'b1110;
  30. #20 A = 4'b1111;
  31. #40 ;
  32.  
  33. end
  34.  
  35. initial begin
  36. $monitor("t=%3d A=%4b,pcode=%3b",$time,A,pcode );
  37. end
  38.  
  39. endmodule
  40.  
  41.  


As another example consider a multiplexer, that has 4 input bits and one output bit. The output is connected to one of the inputs depending upon the value of the input bits. Normally you will need only 2 select bits but we have used 3 select bits. Why ?

  1. // Reference Designer.com mux example
  2. // usage of casez don't care
  3.  
  4. module mux4to1(sel, a0, a1, a2, a3, out);
  5. input [2:0] sel;
  6. input [3:0] a0, a1, a2, a3;
  7. output reg[3:0] c;
  8.  
  9. always @(sel or a0 or a1 or a2 or a3) begin
  10. casez(sel)
  11. 3'b000: out = a0;
  12. 3'b001: out = a1;
  13. 3'b010: out = a2;
  14. 3'b011: out = a3;
  15. 3'b1??: out = 4'b0000;
  16. endcase
  17. end
  18. endmodule

If the MSB select bit is 1, the output is forced to 0 no matter what.

Another thing to notice is that, when more there is more than one match, the first match takes effect. Let us say we have the code.
  1. module casez_priority1;
  2.  
  3. reg select;
  4.  
  5. always @ (select)
  6. casez (select)
  7. 1'bz : $display("CASEZ : Logic z on select");
  8. 1'b1 : $display("CASEZ : Logic 1 on select");
  9. 1'b0 : $display("CASEZ : Logic 0 on select");
  10.  
  11. endcase
  12.  
  13.  
  14. initial begin
  15. #1 $display ("\nDriving 0");
  16. select = 1'b0;
  17. #1 $display ("\nDriving 1");
  18. select = 1'b1;
  19. #1 $display ("\nDriving z");
  20. select = 1'bz;
  21. #1
  22. #1 $finish;
  23. end
  24.  
  25.  
  26. endmodule

It gives the following output

Driving 0
CASEZ  : Logic z on select

Driving 1
CASEZ  : Logic z on select

Driving z
CASEZ  : Logic z on select


The reason is that the first case statement

1'bz : $display("CASEZ  : Logic z on select");


which is equivalent to

1'b? : $display("CASEZ  : Logic z on select");


gets selected no matter what the dont care input is - 0,1 or z

However, if we change the order of the case assignment statement as in

  1. module casez_priority1;
  2.  
  3. reg select;
  4.  
  5. always @ (select)
  6. casez (select)
  7. 1'b1 : $display("CASEZ : Logic 1 on select");
  8. 1'b0 : $display("CASEZ : Logic 0 on select");
  9. 1'bz : $display("CASEZ : Logic z on select");
  10.  
  11. endcase
  12.  
  13.  
  14. initial begin
  15. #1 $display ("\nDriving 0");
  16. select = 1'b0;
  17. #1 $display ("\nDriving 1");
  18. select = 1'b1;
  19. #1 $display ("\nDriving z");
  20. select = 1'bz;
  21. #1
  22. #1 $finish;
  23. end
  24.  
  25.  
  26. endmodule

The output changes to

Driving 0
CASEZ  : Logic 0 on select

Driving 1
CASEZ  : Logic 1 on select

Driving z
CASEZ  : Logic 1 on select


The casex is same as the casez execpt that the don't care also include x in addition to 0,1 and z. This is usually helpful in simulation, when we can give out value x to the module and test for the output.



Exercise

1. .