Home · part 5 of 9

Bit Lab: the ALU and its flags

A hands-on lab on bitwise operations, binary arithmetic and the N Z C V condition flags, built from gates you can see.

Level: beginner digital designTime: 45–60 minNeeds: nothing to install

Prerequisites

You should already be comfortable with:

This is part 5 of From gates to a compiled if. Three other parts build the pieces this lab uses from those gates, with inputs you can tap: From gates to an ALU (a full adder, then four of them chained), From adding to subtracting (wrap-around, NOT then add 1, and the borrow as a carry) and From gates to a register (a latch, a clock, a 4-bit register). Read them first if you want the ground under your feet; the background below only summarises them.

Notation. Gate equations on this page use the usual Boolean shorthand: A ⊕ B is XOR (1 exactly when the inputs differ), A·B or AB is AND, A + B is OR when it appears inside a gate equation, and ¬A is NOT. So the full adder's carry-out, A·B + cin·(A ⊕ B), reads "A and B, or cin and (A xor B)". Everywhere else on the page, + is ordinary addition.

Self-check — if you can answer these without the lab, you're ready:

  1. What is 0b0110 AND 0b1010?
  2. What is the largest unsigned value an 8-bit register can hold?
  3. What does 1 XOR 1 give?
Answers

1. 0b0010.  2. 255 (0xFF).  3. 0.

You do not need to know what an ALU is, what a flag is, what a clock does, or anything about two's complement. The background section introduces all of them.

Learning goals

By the end of this lab you will be able to:

  1. Explain why bitwise logic ops need no communication between bit positions (columns), while addition does.
  2. Trace a carry rippling through a chain of full adders and predict the result.
  3. Show how subtraction and negation are built from addition using invert-and-add-one.
  4. State what each of the N, Z, C and V flags means and which gates produce it.
  5. Distinguish unsigned overflow (C) from signed overflow (V), and predict both for a given addition.
  6. Describe what the three kinds of shift do to the bits and to the carry flag.

Background

What an ALU is. Inside every CPU there is one circuit whose whole job is to take one or two numbers and produce a new number from them: add, subtract, AND, shift and so on. It's called the arithmetic logic unit, or ALU. It has no memory and no clock of its own — it is pure combinational logic, a web of gates, so its output changes the moment its inputs do. Everything else in a CPU is plumbing to get numbers into the ALU and results out of it.

register Aregister B ALU result flagsN Z C V instruction registerADD R0, R1, R2 control unitdecodes the opcode operation

A register is just a row of bits the CPU holds on to — in this lab, A and B are 4 or 8 bits wide. An instruction like add selects which operation the ALU performs, the ALU computes, and the result is written back to a register. Alongside the result the ALU also outputs a few single bits of information about the result: was it zero, was it negative, did it overflow. These are the flags. They are what makes if statements and loops possible: a conditional branch simply tests a flag left by the previous ALU operation.

Where the operation comes from. The instruction is itself a number, fetched from memory into the instruction register. A few of its bits, the opcode, go to the control unit, which decodes them into the wires that tell the ALU what to do and which registers to use. So "add" never reaches the ALU as a word: it arrives as a pattern on the operation lines, and the ALU is wired so that pattern selects the adder. Some example instructions, in a generic assembly notation:

InstructionWhat the ALU computesResult goes toFlags
ADD R0, R1, R2R1 + R2register R0N Z C V
SUB R0, R1, R2R1 − R2, done as R1 + NOT R2 + 1register R0N Z C V
AND R0, R1, R2R1 AND R2, one gate per bit positionregister R0N Z
LSL R0, R1, #1R1 shifted left one placeregister R0N Z C
CMP R1, R2R1 − R2, result thrown awaynowhere, only the flagsN Z C V
BEQ labelnothing: the branch unit tests Zthe program counter, if Z = 1reads Z

CMP followed by BEQ is how if (a == b) runs: the subtraction leaves Z set exactly when the two values were equal, and the branch reads it. In the lab below there is no control unit; you are it. The operation buttons are its output wires.

The lab below is a miniature ALU: two input registers, the gate network for one operation at a time, a result, and the four flags.

Two readings of the same bits. An 8-bit pattern has no intrinsic sign. Read as unsigned, 0xFF is 255. Read as two's complement signed, the top bit counts as −128, so 0xFF is −1 and the range is −128…127. The hardware adds the same way regardless; the flags let software decide whether the answer is trustworthy under the reading it cares about.

The companion pages, in brief

From gates to an ALU. Bitwise ops use one gate per bit position. Addition uses one full adder per bit position, and a full adder is only five gates: sum = A ⊕ B ⊕ cin and carry-out = A·B + cin·(A ⊕ B). Four of them, each carry-out wired to the next carry-in, add two 4-bit numbers the way you add on paper, and the carry ripples from bit 0 upward. The lab draws each full adder as a box marked FA (short for full adder). To see inside the box, with inputs you can tap and a ripple you can watch, read the companion page From gates to an ALU.

From adding to subtracting. A register with 8 bits holds 256 patterns and wraps round: count down past 0 and you are at 255. So 3 − 5 lands on 254, which is 0xFE, and 0xFE is also the pattern for −2. That is what the lab shows when you pick A − B, and it is not a mistake: the same bits are 254 to one reading and −2 to the other. The adder does it without a subtractor. Inverting every bit of B gives 255 − B, so adding NOT B and then 1 adds 256 − B, which modulo 256 is subtracting B. In the drawing, A − B is the adder with an inverter under every B bit and the first carry-in set to 1. The carry out of the top adder then reports whether a borrow was needed: C = 1 means no borrow. The companion page From adding to subtracting shows this on a 16-position wheel and in bits you can tap.

Shifts. The last three operations move bits sideways and need no gates at all, only wiring: each bit's wire is connected one column over. Shifting left moves every bit up a column, which doubles the number, and the bit that falls off the top lands in C. Shifting right halves the number, but there are two right shifts, because the column that empties at the top has to be filled with something. One fills it with 0, which is right for an unsigned number; its traditional name is the logical shift. The other fills it with a copy of the old top bit, so a negative number stays negative, which is right for a signed one; that is the arithmetic shift. The lab's buttons say what each does rather than its name. This is one of the pairs of instructions that exist only because the same bits have two readings; the two kinds of branch, on the next page, are another. In C, >> on an unsigned variable is the logical shift and on a signed variable is, in practice, the arithmetic one, so again the declaration chooses. Java and JavaScript spell them the other way round from what you might guess: >> is arithmetic and >>> is logical. One more thing to expect: the arithmetic shift rounds toward minus infinity, so −3 shifted right once is −2, not −1.

From gates to a register. The ALU needs no memory: a gate's output depends only on its present inputs. The registers on either side of it do, and they are made of the same kinds of gates wired with feedback, an output led back round to an input, so a pair of NOR gates can hold a bit for as long as the power is on. A clock, a signal that swings between 0 and 1 billions of times a second, decides the one instant at which registers take in a new value. The companion page From gates to a register builds a latch from five gates and a 4-bit register you can clock.

The flags

The flags. After an operation the ALU records four one-bit facts, which conditional branches then test. They are four separate stored bits, not one four-way value: each flag has its own flip-flop (the memory cell built on the From gates to a register page), loaded at the same clock edge as the result, and any combination can be set at once. 0x80 + 0x80 sets C and V together, and 0xFF + 1 sets Z and C. Real CPUs keep these four bits inside a wider status register next to things like interrupt and mode bits; on ARM it is 32 bits wide with N, Z, C and V as its top four.

FlagMeaningBuilt from
Nresult is negative when read as signedresult's top bit, straight through
Zresult is zeroNOR of every result bit
Cunsigned result didn't fit (or a bit was shifted out)carry out of the top adder
Vsigned result didn't fitcarry into the top bit XOR carry out of it

This lab follows the ARM / Harris & Harris convention: after subtraction, C = 1 means no borrow was needed. x86 stores the opposite sense for subtraction, so if you later read Intel manuals, keep that in mind.

The lab

Below is the miniature ALU from the diagram above, opened up so you can see the gates. The top rows are the input registers A and B; the bottom row is the result R. Between them is a drawing of the circuit for the chosen operation: one gate or adder per bit column, with wires lit amber when they carry a 1 and carries shown in red. The page works out the result in software and lights the drawing to match, so it shows what each gate would do rather than simulating the gates themselves. The four flags are wired into the drawing too: N is a tap off the top result bit, Z is one wide NOR across every result bit, C is the carry out of the top adder, and V is an XOR of the carry into the top adder and the carry out of it. The cards under the circuit repeat each flag's gates with an explanation of its current value.

Tap a bit to flip it. Pick an operation from the buttons. Switch to 4-bit when you want fewer columns to trace by hand.

Width

Tap a bit in A or B to flip it. Amber wires carry a 1; red carries are the ripple between adders.

Both readings are always shown below. The hardware is just bits and does not know which one you mean. Which reading a program uses, and how, is the next page: Signed or unsigned: who decides?

Try these

Guided exercises

For each one, predict the result and flags before you look. Each "Load" button sets the lab up for you.

1. Columns that don't talk

Flip bit 7 of A. Which result bits change? Now flip bit 0 of B. Which change? Why do no other columns react?

Answer

Only the same column changes each time. Each AND gate sees just its own pair of inputs — there is no wire between columns.

2. Masking and setting

Read the result in hex. Then switch to OR with the same inputs. What does AND with 0x0F do to a byte, and what does OR with 0x0F do?

Answer

AND keeps only the low nibble (0x05). OR forces the low nibble to all ones (0xBF). This is how software clears and sets individual bits.

3. Watch the ripple

Trace it by hand first: bit 0 is 1 + 1, which gives sum 0 and carry 1. Continue for each column. How far does the carry travel? Now set A to 15 and repeat.

Answer

7 + 1: the carry travels through bits 0–2 and stops at bit 3, giving 8. 15 + 1: it ripples through every column and out the top, so R = 0, Z = 1, C = 1. The top adder can't produce its answer until every adder to its right has.

4. Same bits, two overflows

Note C and V. Then load 0xFF + 1 from "Try these" and compare. In each case, which reading (signed or unsigned) gave a wrong answer?

Answer

0x7F + 1: unsigned 127 + 1 = 128 fits, C = 0; signed 127 + 1 should be 128 but the result reads −128, V = 1. 0xFF + 1: unsigned 255 + 1 doesn't fit, C = 1; signed −1 + 1 = 0 is correct, V = 0. The flags report on the two readings independently.

5. The V rule

Look at the two red carries feeding the V gate: carry into bit 7 and carry out of bit 7. Find inputs where both are 1 (V = 0), where only the out is 1, and where only the in is 1. State the rule in words.

Answer

V = 1 exactly when the carry into the sign bit differs from the carry out of it. Adding two positives that produce a negative (carry in only), or two negatives that produce a positive (carry out only), is overflow. If both carries agree the sign bit is still telling the truth.

Why that rule is the same as "the true answer is outside the signed range": the carry out of the top bit is the 256 (or 16) that fell off the end, and the carry into it is what the top column needed for its own sum. If both happen they cancel, and if neither happens nothing was lost, so in both cases the top bit shows the true sign. If exactly one happens, the top bit has been given the opposite sign from the true answer, which can only occur when the true answer did not fit. That is the number-line picture on From adding to subtracting, seen from inside the adder.

6. Subtraction is addition in disguise

Find the inverters on the B inputs and the 1 on the first carry-in. Now swap to 3 − 5. What are R, N and C, and what does C mean here?

Answer

5 − 3 = 2 with C = 1 (no borrow). 3 − 5 = 0xFE, which is −2 signed, so N = 1; C = 0 because a borrow was needed. In ARM style C = 1 means "A ≥ B as unsigned".

7. The number that can't be negated

Negate 0x80. What comes out, and which flag tells you something went wrong? Why can this happen?

Answer

The result is 0x80 again, with V = 1. −128 negated should be +128, but the signed range only reaches 127. Two's complement has one more negative value than positive.

8. Three shifts

Compare the two right shifts on 0x92. Which one is "divide by 2" for a signed number, and why does the other give the wrong answer? Then shift 0x81 left and explain where the top bit went.

Answer

0x92 is −110 signed. The arithmetic shift copies the sign bit down and gives 0xC9 = −55 (correct). The logical shift fills with 0 and gives 0x49 = 73, correct only for the unsigned reading (146 ÷ 2). Shifting 0x81 left pushes the 1 at bit 7 out into C.

Check yourself

Answer without the lab, then verify.

  1. Which single gate type, if you had enough of them, could build everything else on this page?
    Answer

    NAND (or NOR). Both are functionally complete.

  2. In 8-bit, what are R, N, Z, C and V after 0x40 + 0x40?
    Answer

    R = 0x80, N = 1, Z = 0, C = 0, V = 1 (64 + 64 = 128 overflows the signed range).

  3. A branch instruction wants "jump if A < B as signed numbers" after computing A − B. Which flags does it test?
    Answer

    N ≠ V. If no overflow happened, N alone says the result was negative; if overflow did happen, the sign is inverted, so N must be flipped. XOR-ing them handles both.

  4. And "jump if A < B as unsigned numbers"?
    Answer

    C = 0 under the ARM convention (a borrow was needed). Under x86 it would be C = 1.

  5. Why is the Z flag computed with a NOR rather than an OR?
    Answer

    OR of all bits is 1 when the result is non-zero. We want 1 when the result is zero, so the OR is inverted.

  6. In an 8-bit ripple-carry adder, which result bit is ready last, and what does that imply about speed?
    Answer

    Bit 7 and the carry flag, because they depend on the carry from every column before them. Adder delay grows with width, which is why real CPUs use carry-lookahead or similar.

Build it for real

If "register" and "ALU" still feel abstract, here is the smallest build that makes them physical, in 4 bits, using the same chips as Ben Eater's breadboard computer. You do not have to build it; reading the five steps is enough to see what the words mean. A bit is one wire sitting at 5 V or 0 V, shown by an LED. A register is a chip that remembers a few such wires. An ALU is a chip with no memory whose output wires are a pure function of its input wires.

Schematic of the 4-bit bench build: DIP switches feed registers A and B; register B passes through four XOR gates to a 74HC283 adder whose sum outputs drive four LEDs, a NOR gate for Z and the V logic; the carry-out drives the C LED; a SUB switch controls the XOR gates and the carry-in; a dashed feedback path returns the sums to register A. 4 4 4 clk SUB = 1 inverts B and adds 1 D inputs of register A ← S, instead of the switches DIP switch A4 switches DIP switch B4 switches SUB switch clock button 74HC173register A 74HC173register B 74HC86XOR × 4 74HC2834-bit adder A B cin S C sum LEDs = R S3S2 S1S0 S3 doubles as N C carry-out LED 74HC40024-input NOR Z A3, B′3, S3 V logicXOR × 3 + AND V 1 1 1 1 2 2 2 2 3 3 3 4 1 2 3 4 adder and LEDs subtract and flags registers and clock accumulator feedback
The 4-bit bench build. Thick amber lines are 4-wire buses, dashed grey lines are control signals, red is the carry, and the dashed blue path is the step-5 feedback. The badges show which step adds each part; dashed boxes are the register parts.
  1. One full adder from five gates. Wire the full adder from the From gates to an ALU page with three chips: a 74HC86 (four XOR gates), a 74HC08 (four AND gates) and a 74HC32 (four OR gates). Three switches give A, B and carry-in, each with a 10 kΩ resistor to ground so an open switch reads 0; two LEDs show sum and carry-out. Flick through all eight rows of the truth table. You have built the box the lab draws as FA.
  2. Four of them make the adder. Chain four full adders, each carry-out into the next carry-in and the first carry-in to ground, and you have the ripple-carry adder the lab draws: that is two 74HC86, two 74HC08 and one 74HC32. Or buy the same four adders in one chip, the 74HC283. Either way, two 4-way DIP switches feed A and B, and five LEDs show the sums and the carry-out. Set A to 0111 and B to 0001: the sum LEDs show 1000 the instant the switch closes. There is no clock and no "run"; the outputs just follow the inputs, which is all "ALU" means. Set A to 1111 and B to 0001 and the sums go dark while the carry-out LED lights. That LED is the C flag, and on the 74HC283 it is literally pin 9. The LED on S3 is N. The DIP switches are registers you load by hand.
  3. Subtraction and the other flags. Insert a 74HC86 between the B switches and the adder, with a SUB switch on the second input of every gate and on the adder's carry-in. SUB off passes B through; SUB on inverts B and the carry-in adds the 1, so the adder computes A + NOT B + 1, which is A − B. For Z, feed the four sum lines into one gate of a 74HC4002 (a 4-input NOR) and light an LED from its output. For V, overflow means the two numbers entering the adder had the same top bit and the sum's top bit differs: with spare XOR gates and one AND gate from a 74HC08, compute XNOR(A3, B′3) AND XOR(A3, S3), where B′3 is the bit-3 XOR output, the operand the adder actually sees.
  4. Registers: the numbers stay put. Put a 74HC173, a 4-bit D register, between each DIP switch and the adder: switches into its D inputs, its Q outputs into the adder and four LEDs, and one push button on the clock pin of both chips. Set the switches to 0111 and press the button: the register LEDs show 0111. Now flip the switches to anything else; the register LEDs do not move. The chip is remembering, and that is the whole of what a register is. Its load-enable pins decide whether a press changes it. To see the memory in pure gates first, wire the D latch from the From gates to a register page with a 74HC02 (four NOR gates), a 74HC08 and a 74HC04 inverter; the 74HC173 is four sharper versions of that cell. The adder now works on "registers A and B", the block diagram at the top of this page, and in this build you are the control unit: the SUB switch is an operation line, and each press of the clock executes one instruction.
  5. The payoff: an accumulator. Move four jumpers so the adder's sum outputs feed register A's D inputs instead of the switches. Load B with 0001. Each press of the button now performs A ← A + B and the A LEDs count 0000, 0001, 0010 and so on. Load B with 0011 and it counts in threes; switch SUB on and it counts down. That is one CPU instruction, ADD A, B, per button press, and "the result is written back to a register" stops being a metaphor. Debounce the button first, for instance with a 74HC14 Schmitt inverter and a 10 kΩ resistor with a 1 µF capacitor, or one press adds several times.

74HC283 pins

SignalPins
A0, A1, A2, A35, 3, 14, 12
B0, B1, B2, B36, 2, 15, 11
S0, S1, S2, S34, 1, 13, 10
carry in7
carry out9
5 V, ground16, 8

Worked on the bench

5 − 3   A = 0101  B = 0011  SUB = 1
        B after the XORs = 1100, carry in = 1
        0101 + 1100 + 1 = 1 0010   sum LEDs 0010 (2), carry LED on: no borrow

3 − 5   0011 + 1010 + 1 = 0 1110   sum LEDs 1110 (−2 signed, 14 unsigned)
                                   carry LED off: a borrow happened; N LED on

7 + 1   0111 + 0001     = 0 1000   carry off; V on: both inputs had top bit 0,
                                   the sum has top bit 1

What bites beginners

Mapped onto the lab: the DIP switches are rows A and B, the adder and XOR chips are the drawing, the sum LEDs are row R, and the four flag LEDs are the flag cards. The register step is what the lab leaves out, because the lab has no clock.

What's next