John M
John M

Reputation: 1496

The number '0' not working how I expect in Verilog

I had some strange behavior when synthesizing some code with the expression:

logic [7:0] x;
//...
if ((~x) == 0)

In a situation where x is 8'hff), the above boolean evaluates to false. I saw this behavior in synthesized hardware and double-checked it in simulation.

Of course, changing the expression to

if ((~x) == '0)

Gives me the behavior I expect; It evaluates to true when x is 8'hff.

My question: Why does adding the tick mark fix this problem? 0 by itself should give me an unsigned integer with width 32, and (~x) should give me an 8-bit unsigned number. Whether or not I specify the width of my 0, the result ought to be the same.

I assume that I'm missing something about signedness or type promotion in the Verilog spec.

Example code: You can see this behavior across all Commercial simulators at this EDA playground link.

In case you have trouble accessing it, the code at the link is

module tb;
  logic [7:0] x;
  logic [7:0] y;
  
  initial begin
    x <= 8'hff; 
    y <= 8'h00;
    
    #1;
    $display("((~x) == 0) evaluates to %b", (~x) == 0); #1;
    $display("((~x) == '0) evaluates to %b", (~x) == '0); #1;
    
    
    $display("((y) == 0) evaluates to %b", (y) == 0); #1;
    $display("((y) == 0) evaluates to %b", (y) == '0); #1;
    $display("((~y) == ~0) evaluates to %b", (~y) == ~0); #1;
    
    $finish;
  end
endmodule

Upvotes: 0

Views: 220

Answers (1)

dave_59
dave_59

Reputation: 42698

This is because operands get extended before apply any operations within the same context.

Since the width of the unsized decimal literal 0 is 32, the equality operator extends the width of the smaller operand to the width of the larger operand. So 8'hFF becomes 32'h0000_00FF. Then the bitwise-negation operator ~ gets applied.

The width of fill literal '0 depends on its context. When self-determined, its width is 1 bit. However, when in the context of the equality operator, its width gets extended to the width of x, which is 8-bits.

You can get the behavior you want by using the fill literal, or making sure there is no operand extension either by:

if ((~x) == 8'b0) // No extension -- both sides are 8-bits

or use a concatenation:

if ({~x} == 8'b0)

The concatenation works because each operand of a concatenation is self-determined. Only the result of the concatenation is the context of the equality expression.

Upvotes: 1

Related Questions