-
Notifications
You must be signed in to change notification settings - Fork 0
ALU Flags N, Z, C, V
Every arithmetic operation sets these flags in the CPU status register (CPSR on ARM):
| Flag | Name | Set when |
|---|---|---|
| N | Negative | MSB of result = 1 |
| Z | Zero | result = 0 |
| C | Carry | unsigned overflow (carry out or borrow) |
| V | oVerflow | signed overflow (result mathematically wrong) |
0 + 0 = 0 (no carry)
0 + 1 = 1 (no carry)
1 + 0 = 1 (no carry)
1 + 1 = 10 (result=0, carry=1)
1 + 1 + 1 = 11 (result=1, carry=1)
Example: 1111 + 0001
1111
+ 0001
──────
bit 0: 1+1 = 10 → result=0, carry=1
bit 1: 1+0+1 = 10 → result=0, carry=1
bit 2: 1+0+1 = 10 → result=0, carry=1
bit 3: 1+0+1 = 10 → result=0, carry=1
bit 4: carry out → C=1
result: 10000 → kept: 0000 C=1 N=0 Z=1 V=0
0 - 0 = 0 (no borrow)
1 - 0 = 1 (no borrow)
1 - 1 = 0 (no borrow)
0 - 1 = 1, borrow! (borrow from next bit, add 2 to current)
0 - 1 - 1(borrow) = 0, borrow! (add 2: 2-1-1=0)
💡 When you borrow, the current bit becomes
10(binary) = 2. Then apply the rules above.
Example: 0010 - 0110 (2 - 6)
0010
- 0110
──────
bit 0: 0-0 = 0 result=0, borrow=0
bit 1: 1-1 = 0 result=0, borrow=0
bit 2: 0-1 = borrow! → 2-1=1 result=1, borrow=1
bit 3: 0-0-1(borrow) = borrow! → 2-0-1=1 result=1, borrow=1
bit 4: 0-0-1(borrow) = borrow! → 2-0-1=1 result=1, borrow=1
bit 5: 0-1-1(borrow) = borrow! → 2-1-1=0 result=0, borrow=1
bit 6: 0-0-1(borrow) = borrow! → 2-0-1=1 result=1, borrow=1
bit 7: 0-0-1(borrow) = borrow! → 2-0-1=1 result=1, borrow=1
result: 1111 1100 = 0xFC C=0 (borrow out) N=1 Z=0 V=0
⚠️ On ARM: C=0 after subtraction = borrow occurred (ARM inverts borrow → carry convention)
Addition: C=1 means carry OUT (result wrapped upward past 2ⁿ)
Subtraction: C=0 means borrow (result wrapped downward below 0)
Detect in C code (no direct flag access):
// Unsigned overflow on addition
uint32_t result = a + b;
if (result < a) { /* carry — wrapped */ }
// Unsigned underflow on subtraction
if (b > a) { /* borrow — would wrap */ }
// Safe elapsed time even across wraparound
uint32_t elapsed = tick_now - tick_last; // always correct for uint32_tHardware rule:
V = carry_into_MSB XOR carry_out_of_MSB
If they match → V=0 (carry flowed through cleanly) If they differ → V=1 (carry got trapped in sign bit → sign corrupted)
Intuitive rule — two impossible results:
+ + + = − → V=1 (two positives cannot sum to negative)
− + − = + → V=1 (two negatives cannot sum to positive)
+ + − = any → V=0 (mixed signs can never overflow)
− + + = any → V=0 (result always lands between operands)
Example: 0111 + 0001 (+7 + +1)
0111 (+7)
+ 0001 (+1)
──────
1000 (-8 ← WRONG, should be +8)
carry into bit 3 = 1
carry out of bit 3 = 0
V = 1 XOR 0 = 1 ✓
Example: 1001 + 1001 (-7 + -7)
1001 (-7)
+ 1001 (-7)
──────
0010 (+2 ← WRONG, should be -14)
carry into bit 3 = 0
carry out of bit 3 = 1
V = 0 XOR 1 = 1 ✓
Example 1: 1111 + 0001 (unsigned 15+1 / signed -1+1)
result: 0000 carry out
N=0 MSB=0
Z=1 result=0
C=1 carry out (unsigned 15+1=16 overflowed)
V=0 carry in=1, carry out=1 → 1 XOR 1 = 0 (signed -1+1=0, correct)
Example 2: 0111 + 0001 (unsigned 7+1 / signed +7+1)
result: 1000 no carry out
N=1 MSB=1
Z=0 result≠0
C=0 no carry out (unsigned 7+1=8, fits in 4 bits)
V=1 carry in=1, carry out=0 → 1 XOR 0 = 1 (signed +8 doesn't fit)
Example 3: 0010 - 0110 (2 - 6)
result: 1100 borrow out
N=1 MSB=1
Z=0 result≠0
C=0 borrow (ARM: C=0 = borrow)
V=0 signed 2-6=-4, fits in range
| C flag | V flag | |
|---|---|---|
| Catches | unsigned overflow | signed overflow |
| Addition trigger | result > 2ⁿ-1 | pos+pos=neg or neg+neg=pos |
| Subtraction trigger | b > a (borrow) | pos-neg=neg or neg-pos=pos |
| ARM branch |
BCS / BCC
|
BVS / BVC
|
| C code equivalent |
result < a after add |
no direct equivalent |
| Can fire together? | yes — independently | yes — independently |
| Instruction | Flags checked | Meaning |
|---|---|---|
BEQ |
Z=1 | equal |
BNE |
Z=0 | not equal |
BCS / BHS
|
C=1 | unsigned >= (no borrow) |
BCC / BLO
|
C=0 | unsigned < (borrow) |
BMI |
N=1 | negative |
BPL |
N=0 | positive or zero |
BVS |
V=1 | signed overflow |
BVC |
V=0 | no signed overflow |
BGT |
Z=0 and N=V | signed > |
BLT |
N≠V | signed < |
BGE |
N=V | signed >= |
BLE |
Z=1 or N≠V | signed <= |
0xFF + 0x01 = 0x100 → 0x00, C=1
0x80 - 0x01 = 0x7F (sign bit clears)
0xFFFFFFFF = -1 (signed 32-bit)
0x80000000 = INT_MIN
0x7FFFFFFF = INT_MAX
Two's complement shortcut (negate x):
flip all bits, add 1
0x06 → 0xF9 + 1 = 0xFA (-6 in 8-bit)
Subtraction via two's complement:
a - b = a + (~b + 1)
2 - 6 = 0x02 + 0xFA = 0xFC ✓
Generated during prep session · Swarmer Integration Engineer · 2026