The ALU Is Just a Big Multiplexer
Last lesson ended with the control unit's decoder spitting out a handful of signals, one of which was a mysterious "ALU op-select" field. You've probably pictured the ALU as some kind of smart calculator that decides whether to add or subtract based on the instruction. That picture is wrong, and it's wrong in a way that's actually delightful once you see it: the ALU isn't deciding anything. It's computing every operation it knows how to do, all the time, in parallel — and the op-select bits are just choosing which of those already-computed answers gets allowed through to the output. The ALU is a calculator pretending to be a switchboard, or really, a switchboard pretending to be a calculator.
One Circuit, Many Results, Simultaneously
Inside a typical ALU, the same two input operands (call them A and B) feed several independent functional blocks at once:
Every one of those blocks computes its result on every single clock cycle the ALU is active, regardless of whether the instruction actually wants that result. The adder computes A+B even when you asked for an AND. The shifter shifts even when you asked for subtraction. This sounds wasteful — and it costs a little extra silicon area and power — but it buys something enormously valuable: constant, predictable timing. There's no "decide which circuit to route to first" delay; everything is already computed by the time the multiplexer needs to choose, because they all started at the same instant.
Learning Objectives
By the end of this lesson, you should be able to:
- Explain why many ALU subcircuits compute in parallel.
- Describe how function-select bits choose one ALU result through a multiplexer.
- Relate ALU delay to the CPU clock period and critical path.
- Identify where status flags come from during arithmetic and logic operations.
- Predict why adders and shifters often dominate ALU timing.
The Function-Select Field Is the Mux's Address Line
This is where lesson 2's decoder output reappears directly. The control unit's "ALU op-select" signal — typically 3 to 4 bits — is wired straight into the select lines of the output multiplexer. It is, quite literally, an address: just like the opcode addressed a row in the decoder's lookup table, the function-select field addresses one input line of the mux out of 2^n candidates.
| Function-select bits | Operation selected (typical RISC ALU) |
|---|---|
000 |
ADD |
001 |
SUB |
010 |
AND |
011 |
OR |
100 |
XOR |
101 |
Shift Left Logical |
110 |
Shift Right Logical |
111 |
Pass-through / compare |
With 3 bits you get 8 possible operations — note the direct echo of lesson 2's "2^n combinations" idea, just applied one layer deeper in the datapath, inside a single functional unit instead of across the whole control unit.
Where Do the Select Bits Actually Come From?
Often, the function-select field isn't computed by anything fancy — it's lifted directly from a sub-field of the opcode itself, with at most a small amount of extra logic. Look at the AVR opcode map for arithmetic and logic instructions:
| Instruction | Opcode pattern | ALU op-select asserted |
|---|---|---|
ADD Rd, Rr |
0000 11rd dddd rrrr |
ADD |
SUB Rd, Rr |
0001 10rd dddd rrrr |
SUB |
AND Rd, Rr |
0010 00rd dddd rrrr |
AND (bitwise) |
OR Rd, Rr |
0010 10rd dddd rrrr |
OR (bitwise) |
EOR Rd, Rr |
0010 01rd dddd rrrr |
XOR |
Notice the top 6 bits change in a structured way across these — 0000 11, 0001 10, 0010 00, 0010 10, 0010 01. The decoder's match network (from lesson 2) recognizes each unique top-bit pattern and asserts a different, fixed function-select value into the ALU mux. There is no runtime "if opcode equals X then function equals Y" branch happening in software-like fashion — it's a hardwired translation, baked into how the decoder's outputs are physically connected to the mux's select inputs.
Worked Example: Select Bits and Timing
Assume a teaching ALU has these worst-case delays:
| Block | Delay |
|---|---|
| AND/OR/XOR arrays | 1 ns |
| Shifter | 3 ns |
| Adder/subtractor | 5 ns |
| Output mux | 1 ns |
Because all blocks compute in parallel, the selected operation does not change the clock budget. The ALU stage must allow the slowest candidate result to settle before the mux output is trusted:
- Slowest function block:
5 ns. - Output mux delay:
1 ns. - ALU worst-case delay:
5 ns + 1 ns = 6 ns.
Even a simple AND instruction cannot use a 2 ns ALU budget if the same pipeline stage also supports ADD. Synchronous CPU timing is designed around the worst valid path, not the easiest instruction.
Why Design It This Way? Speed Over Elegance
A purist might ask: why not build a single reconfigurable circuit that "becomes" an adder or an AND gate on demand, saving silicon? Because reconfiguring a circuit takes time — and time is the one resource a clocked synchronous design cannot spend carelessly. Computing all results in parallel and selecting at the very last stage means the ALU's worst-case delay is the same no matter which operation you choose. That predictability is what lets a CPU designer say "the ALU stage takes exactly X nanoseconds" and build a clock period around that guarantee.
This constant-delay property is exactly what later allows pipelining to work cleanly — if the ALU stage's timing varied by instruction type, pipeline stage boundaries would become a nightmare to schedule. We'll touch this again in lesson 4 when comparing hardwired vs microcoded control.
Flags Are Just Another Output Tap
While we're inside the ALU, it's worth noting the status flags (Zero, Carry, Negative, Overflow on AVR's SREG, or N/Z/C/V on ARM's APSR) aren't computed by some separate "flag logic" — they're tapped directly off the selected result and its carry/borrow/sign bits, latched into the flag register on the same clock edge the ALU result is captured.
Common Mistakes
- Imagining the ALU reconfigures itself into only one circuit per instruction.
- Forgetting that the clock period must cover the slowest legal ALU path.
- Treating Carry and Overflow as the same flag; carry is unsigned arithmetic, overflow is signed range error.
- Checking flags from an unselected internal result instead of the mux-selected ALU result.
- Assuming a wider ALU is just "more bits"; wider adders increase carry propagation unless special adder structures are used.
Summary
The ALU doesn't "decide" what to compute — it computes everything, every cycle, and a few function-select bits (handed down directly from the decoder you met in lesson 2) simply choose which already-finished answer gets allowed out the door through a multiplexer. This parallel-then-select design trades a little silicon for guaranteed-constant timing, which is the quiet hero behind reliable clock periods. Now that you've seen how opcodes drive both the decoder and the ALU, the natural next question is: how does the chip generate the right control signals for instructions that need multiple clock cycles to finish?
Next: Microcode vs Hardwired Control
Further Reading
- Harris and Harris, Digital Design and Computer Architecture, arithmetic logic unit and datapath chapters.
- Patterson and Hennessy, Computer Organization and Design, single-cycle datapath sections.
- Microchip, AVR Instruction Set Manual, arithmetic/logical instructions and SREG flag definitions.
- Arm, Cortex-M Architecture Reference Manual, APSR condition flags.