Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • RTL Foundations36
    • Digital Logic for RTL Engineers
    • Number Systems for RTL Engineers
      • Representation Drives Behavior
      • Binary and Hexadecimal Conversion Habits
      • Two's Complement Intuition
      • Sign Extension, Zero Extension and Casting
      • SystemVerilog Signed Arithmetic Pattern
      • Overflow Detection Patterns
    • Verilog Fundamentals
    • Verilog Operators and Types
    • SystemVerilog for RTL
    • Simulation and Testbenches
  • Combinational Design25
  • Sequential Design27
  • FSM & Control27
  • Timing & Clocking39
  • Reset & CDC34
  • Memory & Buses57
  • Advanced RTL28
  • Senior & Interview76
  • Glossary and Notation
Loading lesson

‹Number Systems for RTL Engineers
  1. Topics
  2. RTL Design
  3. RTL Foundations
  4. Number Systems for RTL Engineers
  5. Two's Complement Intuition

Part 1 · Foundations · Beginner

Two's Complement Intuition

Negative top-bit weight, range, invert-and-add-one negation, and the most negative value.

On this page

    Why this matters

    Two's complement lets one adder do signed and unsigned arithmetic. It also has one more negative value than positive, so negating -8 in four bits, or abs of -128 in eight, returns the same value.

    After this lesson you can: decode a two's complement value from its weights and explain why carry and signed overflow are different questions.

    Make the top bit negative

    Two's complement is ordinary binary with one change: the most significant bit has a negative weight. For an N-bit value:

    v=−bN−1​2N−1+i=0∑N−2​bi​2i

    For 4 bits the weights are −8, +4, +2, +1. So 1011 is −8 + 2 + 1 = −5, and 0111 is 4 + 2 + 1 = 7.

    Bits

    Unsigned

    Signed

    Bits

    Unsigned

    Signed

    0000

    0

    0

    1000

    8

    −8

    0001

    1

    1

    1001

    9

    −7

    0010

    2

    2

    1010

    10

    −6

    0011

    3

    3

    1011

    11

    −5

    0100

    4

    4

    1100

    12

    −4

    0101

    5

    5

    1101

    13

    −3

    0110

    6

    6

    1110

    14

    −2

    0111

    7

    7

    1111

    15

    −1

    An N-bit value covers −2ᴺ⁻¹ to 2ᴺ⁻¹ − 1. For 8 bits that is −128 to +127, with one more negative value than positive.

    The bits move around a wheel

    Move clockwise to add one. The outer labels are the stored bits, U is their unsigned value, and S is their signed value. Both interpretations use the same sixteen positions; they disagree only about the values assigned to codes 1000 through 1111.

    A four-bit result keeps only the low four bits: arithmetic is modulo 16. Signedness does not change that stored result. It changes whether the mathematical answer fits the range assigned to those bits. The two highlighted boundaries therefore mean different things.

    For codes 0 through 7, both interpretations agree. For codes 8 through 15, the signed value is the unsigned value minus 16. Replacing the top-bit weight +8 with −8 subtracts exactly 16, which explains the labels on the negative half of the wheel.

    Example 1: 7 + 1 crosses the signed limit

    Diagram
      0111     unsigned 7, signed +7
    + 0001     unsigned 1, signed +1
    ------
    0 1000     carry out 0; stored result 1000

    Unsigned 8 fits in four bits, so there is no unsigned overflow. Signed +8 does not fit in −8 through +7: the stored code reads as −8, so there is signed overflow. On the wheel this is the bottom boundary, not the return to code zero.

    Example 2: -1 + 1 crosses the unsigned boundary

    Diagram
      1111     unsigned 15, signed -1
    + 0001     unsigned  1, signed +1
    ------
    1 0000     carry out 1; stored result 0000

    Unsigned 15 + 1 = 16 needs five bits, so the four-bit result wraps to zero and carry is set. Signed −1 + 1 = 0 fits exactly, so there is no signed overflow. On the wheel this crosses the top boundary. Carry and signed overflow answer different questions.

    Four-bit operation

    Stored bits

    Unsigned carry

    Signed overflow

    0111 + 0001

    1000

    0: unsigned 8 fits

    1: signed +8 does not fit

    1111 + 0001

    0000

    1: unsigned 16 does not fit

    0: signed 0 fits

    Negation reuses the adder

    To negate a value, invert every bit and add 1. The reason: x + ~x is all ones, which is −1, so ~x + 1 is −x.

    The payoff is large: the same adder performs signed and unsigned addition. Subtraction just adds the negated operand.

    Example 3: why negating -8 returns -8 in four bits

    Diagram
    input       1000    signed -8
    invert      0111
    add one   + 0001
               -----
    result      1000    still signed -8, not representable +8

    The modular negation rule still works: code 8 is its own additive inverse because 8 + 8 = 16, which is zero modulo 16. But a four-bit signed result cannot represent the mathematical answer +8. This is the extra negative value in the range, not a failure of the invert-and-add-one circuit.

    To preserve the mathematical result, sign-extend before negating. Widening the already wrapped result afterward is too late:

    Diagram
    Correct: widen the input first
      1000 (-8 in 4 bits) -> 11000 (-8 in 5 bits)
      invert 11000 -> 00111; add 1 -> 01000 (+8)
    
    Too late: negate in 4 bits, then widen
      1000 -> 1000 (-8); sign-extend -> 11000 (-8)

    If the interface must remain four bits, the specification must instead choose what to do: report overflow, reject the input, or saturate to +7. None of those policies makes exact +8 representable in four signed bits.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    module tb_negate;
      int errors = 0;
      logic [7:0] x;
      logic signed [7:0] m = -8'sd128;
      logic signed [7:0] neg_m;
      logic signed [8:0] wide_m, wide_neg;
    
      initial begin
        // invert-and-add-one equals 0 - x for every 8-bit value
        for (int i = 0; i < 256; i++) begin
          x = i[7:0];
          if ((~x + 8'd1) !== (8'd0 - x)) errors++;
        end
    
        // the asymmetric corner: -(-128) does not fit in 8 bits
        neg_m = -m;
        if (neg_m !== -8'sd128) errors++;
        wide_m = m;                              // sign-extend the input before negation
        wide_neg = -wide_m;
        if (wide_neg !== 9'sd128) errors++;
    
        if (errors == 0) $display("PASS: modular negation holds; widening before negation preserves +128");
        else $fatal(1, "FAIL: negation errors=%0d", errors);
        $finish;
      end
    endmodule

    Common mistakes

    Warning

    The most negative value, −128 for 8 bits, has no positive counterpart. Negating it, taking its absolute value, or computing abs(x) returns −128 again. Any abs, negate or saturate block must handle this case explicitly.

    Check yourself What is the 8-bit two's complement encoding of −1, and of −128?

    −1 is 8'hFF (all ones). −128 is 8'h80 (only the top bit set).

    Check yourself Why does 7 + 1 have signed overflow without carry, while -1 + 1 has carry without signed overflow in four bits?

    The bits obey modulo-16 addition in both cases. The first answer, +8, exceeds the signed maximum +7 but fits unsigned. The second unsigned sum, 16, exceeds unsigned maximum 15, while the signed sum is exactly zero.

    Check yourself You need the exact positive result when negating four-bit -8. Do you widen before or after negation?

    Before. Sign-extend 1000 to 11000, then negate to 01000 (+8). Negating first wraps to four-bit 1000 (-8), and widening that result cannot recover the lost mathematical answer.

    Check yourself Why is two's complement preferred over sign-magnitude in hardware?

    One adder handles signed and unsigned addition, subtraction reuses the adder by negating the second operand, and there is only one zero (sign-magnitude has +0 and −0). That keeps the datapath small and the comparison logic simple.

    Remember

    • The top bit has negative weight. N bits cover -2^(N-1) to 2^(N-1) - 1.

    • Arithmetic is modulo 2^N: carry marks the unsigned boundary, signed overflow marks the signed one.

    • The most negative value has no positive counterpart. Negate, abs and saturate blocks must handle it.

    Rule of thumb: negate by inverting every bit and adding one, but sign-extend first if you need the exact result.

    Keep going

    • Interview: run a mock interview on this topic

    Related topics

    • Overflow detection

    • Sign and zero extension

    Previous

    9 / 350

    Next: Sign Extension, Zero Extension and Casting

    Up next

    Up nextSign Extension, Zero Extension and Casting

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Representation Drives Behavior
    • SystemVerilog Signed Arithmetic Pattern
    • Overflow Detection Patterns