Search code examples
verilogsystem-verilog

Result of single bit bitwise vs logical inversion is interpreted differently in arithmetic expression


Consider the following code:

module test;
  reg signed [3:0] signed_reg3 = 4;
  reg ubit = 0;
  
  initial begin
    $display("! => typename: %s, size: %d, %d", $typename(!ubit), $bits(!ubit), signed_reg3 - !ubit);
    $display("~ => typename: %s, size: %d, %d", $typename(~ubit), $bits(~ubit), signed_reg3 - ~ubit );
  end
endmodule

The result in the simulator of the two prints is:

 ! => typename: reg, size:           1,  3
 ~ => typename: reg, size:           1,  5

(Here is the Demo ) As we can see, there is a difference in the result of evaluation of the following two arithmetic expressions:

signed_reg3 - !ubit
signed_reg3 - ~ubit

In the first case the !ubit result is interpreted as unsigned value, while in the second, ~ubit seem to be interpreted as signed. This is something I do not understand, as the same print is showing that both type and size of either result is the same (reg of size 1 bit). Please explain what is happening here.


Solution

  • You are displaying the result of $bits in a different context from when used within an arithmetic expression.

    Table 11-21 shows the logical-not ! returning a 1-bit result and its operand is self-determined. Whereas the bitwise-not ~ returns a bit width of its context determined operand. The fact that ! always returns a 1-bit value is something that was further clarified in the next revision of the IEEE 1800-2017 SystemVerilog LRM.

    Section 11.8.2 Steps for evaluating an expression explains how the bit-widths get propagated through context determined expressions.

    To summarize

    signed_reg3 - !ubit
    

    The logical negation applies to the 1-bit value ubit before it gets extended to 4-bits because its operand is self-determined.

    signed_reg3 - ~ubit
    

    Since ~ubit is part of the context of the subtraction operator, its operand gets extended before bitwise-negation and subtraction.