Verilog’s Casex Issue

Verilog also has some academic constructs.  Things that make sense for people who don’t want to design a structure.  Casex is one example from Verilog. The issue with casex is that it treats x’s as wildcards on both sides of the evaluation.  This is shown below:

module tb ();
  reg [2:0] y;
  reg [1:0] sel;

  always begin
    #100 sel <= 2'b00;
    #100 sel <= 2'b01;
    #100 sel <= 2'b10;
    #100 sel <= 2'b11;
    #100 sel <= 2'b0x;
    #100 sel <= 2'b1x;
    #100 sel <= 2'bx0;
    #100 sel <= 2'bx1;
    #100 sel <= 2'bxx;
  end

  always@(sel) begin
    casex (sel)
    2'b01   : y = 3'b001;
    2'b00   : y = 3'b010;
    2'b1?   : y = 3'b100;
    default : y = 3'bxxx;
    endcase
  end

endmodule

The above is  a simple testbench for a casex statement.  Here is the result:

This may seem very odd, so I’ll explain each step:

  1. sel = 2’bxx.  y = 3’bxxx.  This occurs because this is time=0.  Neither sel nor y have initial statement.  The casex has not been evaluated as sel has not yet changed.
  2. sel = 2’b00. y = 3’b010.  This is a direct match in the casex.
  3. sel = 2’b01. y = 3’b001.  Another direct match.
  4. sel = 2’b10.  y = 3’b100.  This matches the 2’b1? case.
  5. sel = 2’b11.  y = 3’b100.  This also matches the 2’b1? case.
  6. sel = 2’b0x.  y= 3’b001.  This is the issue — the x in sel will resolve to either the 2’b00 or 2’b01 case.  Verilog will choose 2’b01, as it it the first matched case.
  7. sel = 2’b1x.  y = 3’b100.  This will also match a valid case, the 2’b1? case.
  8. sel = 2’bx0. y = 3’b010.  This could have matched either 2’b10 or 2’b00.  The 2’b00 case is the first match.
  9. sel = 2’bx1. y = 3’b001.  This could have matched either 2’b11 or 2’b01.  The 2’b01 case is the first match.
  10. sel = 2’bxx.  y= 3’b001.  This can match any case, so 2’b01 is chosen as it is first

The issue above is that unknowns on the input, sel, are also treated as wildcards.  The default case is not reached when an input is unknown.  If an input is unknown for any reason, the simulator will be able to select a known value for y.

Really, it would be more practical if there were a “casewithdontcare” structure, where unknowns on the inputs would not match 0/1/? on the cases, but where a ? in a case would match a 0 or 1 in the input.  This is how the casex is often used, but not how it actually works.  Casez can be used, but it will still treat z’s as wildcards.  This is fairly rare for FPGA design, so it is less risky.  However, things like unconnected ports can result in values of z.

It should be noted that either wrapping casex with an if (^signal) !== 1’bx statement, or in some cases, adding this as a post-check, the behavior can be mostly corrected.  Basically, the (^signal) performs an xor-reduce.  While or-reduce and and-reduce can return a 1’b1 and 1’b0 even with x’s in the signal, xor-reduce cannot.  As a result, any x’s or z’s will result in a 1 bit unknown.  The !== operator can then be used to compare to 1’bx.

always@(*) begin
  // Wrapping the casex
  if (^sel !== 1'bx) begin
    //casex not shown for brevity.
  end else begin
    outputs <= (SIZE){1'bx};
  end

  // _alternatively_ a post-check (can be hidden from synth)
  //synthesis translate off
  if (^sel === 1'bx) begin
    outputs <= (SIZE){1'bx};
  end
  //synthesis translate on
end

Either can be done, with a lower chance of making mistakes when you wrap the casex in an if-else structure.  The key is that you must assign all affected outputs to x’s yourself.  Forgetting to do this will again lead to simulation mismatches.  The latter method is easy to wrap in a //synthesis translate off/on block, in the event the synthesizer has issues with the comparisons to x.

This entry was posted in Verilog. Bookmark the permalink.

Comments are closed.