ALU design
How an arithmetic and logic unit is built from one-bit slices: AND, OR, adder, B inversion and a multiplexer, the flags it produces, set-less-than, the zero detector, shifters, and what limits its speed.
Why it exists
Every arithmetic instruction, every comparison, every address calculation and every branch decision passes through the ALU. It is a purely combinational circuit: two operand inputs, a few control inputs that choose the operation, a result and a handful of status bits (flags). It is also the block that sets the clock speed of the simple processor, because its worst-case delay (the carry through the adder) is the longest path in the datapath. GATE asks you to build an ALU from adders and gates, to give the control signals for an operation, to say what the flags mean, to design the comparison, and to estimate its delay and hardware.
Prerequisites
You need the adder, the adder-subtractor and the carry/overflow flags from adders and subtractors and fixed-point arithmetic, and the multiplexer from multiplexers.
Precise definitions
ALU. A combinational circuit with operands and (each bits), a control input that selects the operation, a result bits wide and status outputs. The common operations are add, subtract, AND, OR, (NOR, XOR), set-on-less-than and sometimes shifts. Multiplication and division are usually done by a separate unit or by repeated use of the ALU (Booth multiplication).
The one-bit slice. An -bit ALU is identical slices connected by the carry chain. Each slice contains
- an XOR gate (or multiplexer) that inverts when a control line is 1,
- an AND gate and an OR gate on and the (possibly inverted) ,
- a full adder with carry in and carry out,
- a multiplexer that picks which of AND, OR, the adder's sum or the special "less" input becomes the result bit.
Operations by control setting (this page's design; also feeds the carry in of the lowest slice):
| Operation | multiplexer selects | carry in | |
|---|---|---|---|
| AND | 0 | AND | 0 |
| OR | 0 | OR | 0 |
| ADD | 0 | sum | 0 |
| SUB | 1 | sum | 1 |
| SLT (set on less than) | 1 | "less" | 1 |
Subtraction. : invert every bit of and set the carry in to 1 (two's complement negation).
Flags. (zero): every result bit is 0, computed by a NOR over all result bits (for bits a tree of two-input gates with levels). (negative): the top result bit. (carry): the carry out of the top slice (after a subtraction a carry of 1 means unsigned, i.e. no borrow). (overflow): the carry into the top slice XOR the carry out of it.
Set on less than. The result is 1 if as signed numbers, else 0. It is computed by subtracting and taking (that is ): the sign bit of the difference alone is wrong when the subtraction overflows. The result is placed in bit 0 and all other bits are 0; the top slice produces the "less" value and feeds slice 0's "less" input. For an unsigned comparison use the carry: exactly when after the subtraction.
Equality is after a subtraction.
Shifters. A barrel shifter shifts by any amount in one step: it has stages, stage shifts by or passes the value unchanged under control of bit of the shift amount, each stage being two-input multiplexers: multiplexers in all (160 for 32 bits). A shift register shifts by one position per clock, so shifting by takes cycles.
Control codes. With operations the control field needs bits. The classic textbook MIPS-style design uses a 4-bit ALU control: 0000 AND, 0001 OR, 0010 add, 0110 subtract, 0111 set on less than, 1100 NOR, where, in that design, bit 3 inverts , bit 2 inverts (so 0110 inverts and adds with carry in 1) and the low two bits choose AND, OR, add or the "less" input; NOR is AND of both inverted inputs.
Speed. The critical path is the carry chain of a ripple adder (about gate delays) plus the B-inversion XOR and the output multiplexer. Carry lookahead or a faster adder makes it close to constant; this is why the ALU delay appears in the clock-period calculation of the datapath.
How it works
The animation runs five operations on 8-bit operands with their flags. Look at the two subtractions: with and the true difference 200 does not fit, the result bits read (so ), the overflow flag is 1, and "set on less than" correctly returns 0 because .
An 8-bit ALU: operations and flags: AND
Computed exactly, not typedWorking
result = A AND B, bit by bit
Value, format and bits (changed bits in amber)
Step 1
Each result bit is the AND of the two input bits at the same position. The carry and overflow flags are not defined for a logic operation and are shown as 0.
Worked examples
EX 1The ALU, built from slices, in a program
EasyThe C program builds an 8-bit ALU from eight copies of the slice (B inverter, AND, OR, full adder, output multiplexer), runs it on the animation's operands, then checks it against the C operators for all 65536 operand pairs and five operations, and checks the logarithmic shifter for all inputs and shift amounts.
#include <stdio.h>
#include <stdint.h>
/* a 1-bit ALU slice: AND, OR, add (full adder) and a "less" input, with an optional inverter on B */
typedef struct { int out, cout, sum; } Slice;
static Slice slice(int a, int b, int cin, int binv, int op, int less) {
int bb = b ^ binv;
Slice s;
s.sum = a ^ bb ^ cin;
s.cout = (a & bb) | (cin & (a ^ bb));
int r[4] = { a & bb, a | bb, s.sum, less };
s.out = r[op];
return s;
}
enum { AND, OR, ADD, SUB, SLT };
/* an 8-bit ALU made of 8 slices; returns the result and sets the flags */
static unsigned alu8(unsigned a, unsigned b, int op, int *z, int *n, int *c, int *v) {
int binv = (op == SUB || op == SLT), carry = binv;
int sel = op == AND ? 0 : op == OR ? 1 : 2;
unsigned res = 0;
int carry_into_sign = 0, sign_sum = 0;
for (int i = 0; i < 8; i++) {
if (i == 7) carry_into_sign = carry;
Slice s = slice((a >> i) & 1, (b >> i) & 1, carry, binv, sel, 0);
res |= (unsigned)s.out << i;
if (i == 7) sign_sum = s.sum;
carry = s.cout;
}
*c = carry;
*v = carry_into_sign ^ carry;
*n = (int)((res >> 7) & 1);
*z = res == 0;
if (op == SLT) return (unsigned)(sign_sum ^ *v); /* set-less-than: sign of the difference xor overflow */
return res;
}
/* a logarithmic shifter: stage k shifts by 2^k when bit k of the shift amount is 1 */
static unsigned shl8(unsigned x, int amount) {
for (int k = 0; k < 3; k++)
if ((amount >> k) & 1) x = (x << (1 << k)) & 0xFF;
return x;
}
int main(void) {
int z, n, c, v;
unsigned r = alu8(106, 53, ADD, &z, &n, &c, &v);
printf("106 + 53 = %u N=%d C=%d V=%d\n", r, n, c, v);
r = alu8(106, 53, SUB, &z, &n, &c, &v);
printf("106 - 53 = %u N=%d C=%d V=%d\n", r, n, c, v);
r = alu8(100, (unsigned)(-100) & 0xFF, SUB, &z, &n, &c, &v);
printf("100 - (-100): bits %02X N=%d V=%d, so N xor V = %d\n", r, n, v, n ^ v);
r = alu8(100, (unsigned)(-100) & 0xFF, SLT, &z, &n, &c, &v);
printf("100 < -100 (signed)? %u\n", r);
int bad = 0;
for (unsigned a = 0; a < 256; a++)
for (unsigned b = 0; b < 256; b++) {
bad += alu8(a, b, AND, &z, &n, &c, &v) != (a & b);
bad += alu8(a, b, OR, &z, &n, &c, &v) != (a | b);
bad += alu8(a, b, ADD, &z, &n, &c, &v) != ((a + b) & 0xFF) || c != (int)((a + b) >> 8);
bad += alu8(a, b, SUB, &z, &n, &c, &v) != ((a - b) & 0xFF) || c != (a >= b) || z != (a == b);
bad += alu8(a, b, SLT, &z, &n, &c, &v) != (unsigned)((int8_t)a < (int8_t)b);
}
int bad_shift = 0;
for (unsigned x = 0; x < 256; x++)
for (int k = 0; k < 8; k++) bad_shift += shl8(x, k) != ((x << k) & 0xFF);
printf("slice ALU wrong on %d of 327680 operations; shifter wrong on %d of 2048 cases\n", bad, bad_shift);
return 0;
}106 + 53 = 159 N=1 C=0 V=1
106 - 53 = 53 N=0 C=1 V=0
100 - (-100): bits C8 N=1 V=1, so N xor V = 0
100 < -100 (signed)? 0
slice ALU wrong on 0 of 327680 operations; shifter wrong on 0 of 2048 casesReading it. does not fit in a signed byte: and (as an unsigned sum it is fine, ). has (no borrow). gives the bit pattern C8, , , so the signed comparison and the set-less-than result is 0: 100 is not less than .
EX 2Control settings for each operation
EasyTo subtract, set and carry in , and select the adder output. To AND, set and select the AND output. For the NOR operation invert both inputs (or invert the AND of inverted inputs): , which needs a second inverter on in this slice, so a design that supports NOR adds an line. The number of control lines for 8 operations is (plus the inversion lines if they are separate).
EX 3Why set-less-than uses the overflow flag
MediumTake 8-bit and . , which wraps to (11001000). The sign bit is 1, so a designer who returns the sign of the difference would report , which is wrong. The overflow flag is 1, and gives the right answer. If and : wraps to (sign 0) with , and : correct, .
EX 4Shifter and zero-detector cost
MediumA 32-bit barrel shifter has stages of 32 two-input multiplexers: 160 multiplexers, and the delay is 5 multiplexer delays whatever the shift amount. A 64-bit one has 6 stages and 384 multiplexers. The zero flag of 32 result bits needs a 32-input NOR: 31 two-input gates in 5 levels (OR gates in a tree followed by an inverter).
EX 5Delay of an n-bit ALU
GATE levelSuppose the slice's XOR (B inversion) takes 1 gate delay, each carry stage (AND then OR) takes 2, the sum XOR takes 1 and the output multiplexer takes 1. For a ripple ALU of bits the critical path from to the top result bit is about gate delays; for this is 67. With carry lookahead the carry path becomes a constant (a few gate delays), so the ALU delay hardly depends on . The question normally supplies its own delays: add them along the longest path.
EX 6Which flags decide which branch?
GATE levelAfter SUB: branch-if-equal looks at ; signed branch-if-less looks at ; signed branch-if-greater-or-equal looks at ; unsigned branch-if-lower looks at (borrow); unsigned branch-if-higher-or-same looks at . The same subtraction serves all of them, so the ALU does not need a separate comparator.
Cheat box
Cheat box
- Slice: XOR on B (), AND, OR, full adder, output multiplexer. slices linked by the carry.
- SUB: , carry in . .
- Flags: = NOR of result; = top bit; = carry out (after SUB: 1 means unsigned); = carry into XOR carry out of the top bit.
- Signed : after SUB. Unsigned: . Equal: .
- Barrel shifter: stages two-input multiplexers.
- Control bits for operations: .
- Ripple ALU delay grows with ; lookahead makes it nearly constant.
Traps and GATE patterns
Connections
Builds on
Unlocks
Within this subject
Journeys that pass through here
The adder, subtractor and their flags are built in adders and subtractors and interpreted in fixed-point arithmetic. The result multiplexer is a multiplexer. The ALU is one block of the datapath, where it sits between the registers and the bus, and its delay sets the clock period that pipelining tries to shorten. Multiplication uses it repeatedly.
PYQs
No PYQs attached to this concept yet
Previous year questions are being added section by section from your PYQ book, each with my own re-checked answer. Nothing is shown from memory.
Self-check
Question 1
What control settings make the ALU compute ?
Show answerHide
Invert B (), set the carry in to 1 and select the adder output: .
Question 2
An 8-bit subtraction gives , . Is (signed)?
Show answerHide
, so yes, (the true difference is negative, but it overflowed to a positive-looking pattern).
Question 3
How many 2-input multiplexers are in a barrel shifter for 16-bit words?
Show answerHide
stages of 16 multiplexers: 64.
Question 4
After SUB the carry flag is 0. What does that mean for unsigned operands?
Show answerHide
A borrow occurred: (unsigned).
Revision card
One-screen revision
- Slice: B-invert XOR, AND, OR, full adder, output multiplexer; SUB = invert B + carry in 1.
- = NOR of result, = top bit, = carry out, = carry into XOR carry out of the sign bit.
- Signed less-than ; unsigned less-than ; equal .
- Barrel shifter: stages of multiplexers. Control bits .
References
- ·Hennessy and Patterson, Computer Organization and Design, Chapter 3 Arithmetic for Computers (Appendix: the arithmetic logic unit)
- ·Morris Mano, Computer System Architecture, 3rd ed., Chapter 10 Computer Arithmetic and Chapter 4 Register Transfer and Microoperations (arithmetic logic shift unit)
- ·Hamacher, Vranesic, Zaky, Computer Organization, 5th ed., Chapter 6 Arithmetic
Verification
The slice-based ALU is implemented twice (a Python model with exhaustive checks for 3, 4 and 5 bits, scripts/enum-checks/coa_alu.py, and the C program on the page, which checks all 65536 operand pairs of 8 bits for five operations against the language operators). The animation's values and flags are recomputed independently in tests/coa-traces.test.ts. The barrel-shifter and zero-detector counts are checked in the script. The control-code numbers of the MIPS-style ALU quoted in the text are from memory of the textbook design and not checked against a manual. Textbook chapter titles are from memory. SECOND PASS (2026-11-02, done by the assistant, not a human check): every Self-check question was solved before the printed answer was read and all agreed; the definitions, worked examples, cheat box and traps were read claim by claim and the numbers re-derived by hand (long C programs were not re-read line by line: they are compiled and compared by npm run verify:c, and their printed outputs were checked against the prose). No defect found. Status raised to self-checked; verified needs a textbook or human check.
last verified: never
My notes (saved in this browser)