When you are debugging a microcontroller on the bench, reading raw hex dumps or logic analyzer traces requires instant mental translation between decimal and binary. While floating-point math is handled by dedicated FPUs, the core Arithmetic Logic Unit (ALU) in almost every modern microcontroller—from the ATmega328P in an Arduino Uno to the Xtensa cores in an ESP32—relies on integer binary math. Understanding how the hardware handles negative numbers is non-negotiable for embedded systems work.
Below is a complete walkthrough of an exam-style problem. This provides a rigorous, practical example of binary number system arithmetic, specifically focusing on two's complement addition and the status flags that dictate conditional branching in assembly and C code.
The Practice Problem: 8-Bit Two's Complement Addition
An 8-bit microcontroller ALU is instructed to add two signed integers. Register A holds decimal -54, and Register B holds decimal +117.
- Convert both values to 8-bit two's complement binary.
- Perform the binary addition, tracking all carries.
- Determine the final 8-bit result in decimal.
- Identify the state of the Carry (C) and Overflow (V) status flags in the ALU status register.
Before solving, we must establish the positional weights of an 8-bit register. The method applied here is the Radix-2 positional numeral system combined with two's complement encoding. We use two's complement because it allows the ALU to use the exact same hardware adder circuit for both addition and subtraction, eliminating the need for a separate subtractor.
| Bit Position | Power of 2 | Unsigned Weight | Signed Weight (Two's Complement) |
|---|---|---|---|
| 7 (MSB) | 2^7 | 128 | -128 |
| 6 | 2^6 | 64 | 64 |
| 5 | 2^5 | 32 | 32 |
| 4 | 2^4 | 16 | 16 |
| 3 | 2^3 | 8 | 8 |
| 2 | 2^2 | 4 | 4 |
| 1 | 2^1 | 2 | 2 |
| 0 (LSB) | 2^0 | 1 | 1 |
Step-by-Step Solution: Algebra, Bitwise Math, and Flag Logic
We will break this down into the exact algebraic and bitwise steps the ALU performs. For deeper background on binary addition rules, refer to the All About Circuits digital textbook.
Step 1: Convert +117 to 8-Bit Binary
Since 117 is positive, its two's complement representation is identical to its standard unsigned binary form. We subtract the largest powers of 2 that fit into 117:
- 117 - 64 = 53 (Bit 6 = 1)
- 53 - 32 = 21 (Bit 5 = 1)
- 21 - 16 = 5 (Bit 4 = 1)
- 5 - 4 = 1 (Bit 2 = 1)
- 1 - 1 = 0 (Bit 0 = 1)
Result for +117: 01110101
Step 2: Convert -54 to 8-Bit Two's Complement
To represent a negative number, we follow a strict three-step algebraic process:
- Find the absolute value in binary: +54 = 32 + 16 + 4 + 2 →
00110110 - Calculate the One's Complement (invert all bits):
11001001 - Calculate the Two's Complement (add 1 to the LSB):
11001001 + 00000001 = 11001010
Result for -54: 11001010
Step 3: Perform Binary Addition
Now we feed both 8-bit registers into the ALU adder. We must track the carry bit moving from right (LSB) to left (MSB).
Carries: 11000000
--------
01110101 (+117)
+ 11001010 (-54)
----------
1 00111111 (9-bit raw result)
The ALU discards the 9th bit (the carry out of the MSB) because it is an 8-bit register, leaving the final 8-bit result: 00111111.
Step 4: Determine the Status Flags
Microcontrollers like the AVR (used in Arduino) store arithmetic metadata in the Status Register (SREG). We need to evaluate two specific flags:
- Carry Flag (C): This is the carry-out from the MSB (Bit 7). Looking at our addition, Bit 7 generated a carry of
1. Therefore, C = 1. - Overflow Flag (V): This indicates if a signed operation exceeded the valid range (-128 to +127). The hardware calculates this by XORing the carry into the MSB with the carry out of the MSB. Here, the carry into Bit 7 was
1, and the carry out was1. Since 1 XOR 1 = 0, V = 0.
The Trap: Carry vs. Overflow in Signed Binary Arithmetic
The most common mistake students and junior firmware engineers make is confusing the Carry (C) flag with the Overflow (V) flag.
The Carry flag is strictly for unsigned math. It tells you if your result exceeded 255. The Overflow flag is strictly for signed math. It tells you if your result exceeded +127 or dropped below -128.
In our problem, C=1 but V=0. If you are writing assembly or optimizing C code for a motor controller and you use a "Branch if Carry Set" (
BRCS) instruction to check for a signed math error, your code will falsely trigger an error routine. You must use "Branch if Overflow Set" (BRVS) when dealing with signed two's complement variables. For a deeper dive into CPU flag logic, review the Kansas State University binary math module.
Independent Verification and Sanity Checks
Never trust a binary conversion on an exam or in a critical firmware routine without an independent sanity check. Here is how we verify our answer.
1. Decimal Equivalence Check
Let's convert our final 8-bit binary result (00111111) back to decimal using the unsigned weights (since the MSB is 0, it is a positive number):
32 + 16 + 8 + 4 + 2 + 1 = 63
Does this match our original decimal algebra?
(+117) + (-54) = 117 - 54 = 63.
The math holds up perfectly.
2. Order of Magnitude and Units Sanity Check
- Order of Magnitude: 117 is roughly 10^2. 54 is roughly 10^1. The difference should be in the 10^1 range (tens). Our answer, 63, is exactly in the 10^1 range. If we had missed a bit and gotten 191 or 3, the order of magnitude would immediately flag an error.
- Units: Dimensionless integer counts. No scaling factors were applied.
- Range Check: The result (+63) easily fits within the 8-bit signed range of -128 to +127, confirming our V=0 flag calculation is physically logical.
Frequently Asked Questions
Why not just use a sign-magnitude system instead of two's complement?
Sign-magnitude (where the MSB is just a negative sign) creates two representations for zero (+0 and -0) and requires complex, separate hardware for addition and subtraction. Two's complement guarantees a single zero and allows the ALU to simply add the binary strings together regardless of sign, vastly simplifying silicon design.
What happens to the 9th bit (the Carry out) in actual hardware?
It isn't deleted; it is latched into the Carry (C) flag in the status register. In multi-byte addition (like adding two 32-bit integers on an 8-bit AVR), the next instruction uses an "Add with Carry" (ADC) opcode to pull that 9th bit into the next byte's LSB, chaining the math across registers.






