4 minute read

Signed Arithmetic

When working with Verilog or SystemVerilog, it’s crucial to understand the distinction between the bitwise NOT operator (~) and the logical NOT operator (!). While they might seem similar, they behave differently and are intended for distinct purposes. Using them incorrectly can lead to subtle bugs that are hard to track down.

Video Tutorial

Watch this comprehensive video explanation of Difference between Bitwise NOT (~) and Logical NOT (!):

Quick Reference

Operator Name Purpose Input Output Use Case
~ Bitwise NOT Inverts each bit Any width Same width as input Bit manipulation
! Logical NOT Logical negation Any width 1-bit (0 or 1) Boolean conditions

Detailed Explanation

Bitwise NOT (~) - Invert Operator

The bitwise NOT operator, also known as the “invert” operator, performs a bit-by-bit inversion of its operand. This means each 0 becomes a 1, and each 1 becomes a 0. The result will have the same bit width as the operand. This is also referred to as taking the one’s complement.

Key Characteristics:

  • Inverts each individual bit of the operand.
  • Returns a value with the same bit width as the operand.

When to Use ~:

  • Use ~ only when you need to invert the individual bits of a vector or a scalar value.

When NOT to Use ~:

  • Do not use ~ for evaluating logical true/false conditions, especially with multi-bit vectors, as it can lead to unexpected behavior. If any bit in the inverted vector is 1, the condition will evaluate to true.

Example:

logic [3:0] data = 4'b1100;
logic [3:0] result = ~data;  // result = 4'b0011

Logical NOT (!) - Negate Operator

The logical NOT operator, also known as the “negate” operator, is used for logical negation. It first performs a “reduction OR” on all bits of its operand. If any bit in the operand is 1 (true), the reduction OR results in 1. If all bits are 0 (false), the result is 0. If there’s an X or Z and no 1, the result is X. The logical NOT operator then inverts this single-bit result.

Key Characteristics:

  • Performs a reduction OR on the operand to get a single 1-bit value (0 for false, 1 for true, X for unknown).
  • Inverts this 1-bit result.
  • Always returns a 1-bit value: 1'b1 (true), 1'b0 (false), or 1'bx (unknown).

When to Use !:

  • Use ! only to negate the result of a logical expression or a value that represents a true/false condition.

When NOT to Use !:

  • Do not use ! if your intention is to invert all bits of a multi-bit vector. It will reduce the vector to a single bit before negation.

Example:

logic [3:0] data = 4'b1100;
logic result = !data;  // result = 1'b0 (because data is not all zeros)

Best Practices

Correct Usage

Use ~ for bit manipulation:

logic [7:0] mask = 8'b11110000;
logic [7:0] inverted_mask = ~mask;  // 8'b00001111

Use ! for logical conditions:

logic enable;
if (!enable) begin
    // Execute when enable is false
end

Common Mistakes

Don’t use ~ for logical conditions on multi-bit values:

logic [3:0] count = 4'b0001;
if (~count) begin  // BUG: ~count = 4'b1110, which evaluates to true!
    // This will execute unexpectedly
end

Don’t use ! for bit inversion:

logic [3:0] data = 4'b1100;
logic [3:0] result = !data;  // BUG: result = 1'b0, not 4'b0011

Complete Code Example

module not_operators_example;
    logic       a, r1;
    logic [3:0] b, r2;
    
    initial begin
        // Initialize values
        a = 1'b1;
        b = 4'b1100;
        
        // Bitwise NOT on 1-bit value
        r1 = ~a;        // r1 = 1'b0 OK
        r1 = !a;        // r1 = 1'b0 OK (both work for 1-bit)
        
        // Conditional checks on 1-bit value
        if (~a) $display("~a is true");   // false OK
        if (!a) $display("!a is true");   // false OK
        
        // Operations on multi-bit value
        r2 = ~b;        // r2 = 4'b0011 OK (bitwise invert)
        r1 = !b;        // r1 = 1'b0     OK (logical negate)
        
        // Conditional checks on multi-bit value
        if (~b) $display("~b is true");   // true  BUG!
        if (!b) $display("!b is true");   // false OK
        
        // Correct way to check if all bits are zero
        if (b == 4'b0000) $display("b is all zeros");
        
        // Correct way to check if any bit is set
        if (|b) $display("b has at least one bit set");
    end
endmodule

Guidelines Summary

When to use ~ (Bitwise NOT):

  • Inverting individual bits in a vector
  • Creating bit masks
  • One’s complement operations
  • Never use for logical true/false conditions on multi-bit values

When to use ! (Logical NOT):

  • Negating boolean results in conditional statements
  • Converting any value to a single-bit true/false result
  • Never use for bit inversion of multi-bit values

For Vector Comparisons:

  • Use equality operators: ==, !=
  • Use relational operators: <, >, <=, >=
  • Use reduction operators: |, &, ^ for specific bit operations

Memory Aid

Think of it this way:

  • ~ = “Flip bits” (bitwise operation)
  • ! = “Is false?” (logical operation)

Following these guidelines will help you avoid common pitfalls and write more reliable SystemVerilog code.