The ALU
Arithmetic logic unit
The ALU is not a new part: it is an adder and a bitwise AND placed side by side, with a few control bits choosing which one runs. It has two 16-bit inputs, one 16-bit output, six 1-bit controls and two flags.
00What the ALU looks like
01The six control bits
| Bit | Controls | When 1 |
|---|---|---|
| zx | x | zero x |
| nx | x | invert x (after zx) |
| zy | y | zero y |
| ny | y | invert y (after zy) |
| f | operation | 1 = add, 0 = bitwise AND |
| no | output | invert the result |
The order matters: zero first, then invert, so zx=1, nx=1 gives all ones (−1), not 0.
x − y?By two’s complement, inversion is
~A = −A − 1. Set nx=1 (invert x), f=1 (add) and no=1 (invert the output):· add inside:
~x + y = (−x − 1) + y = (y − x) − 1;· invert the output:
~((y − x) − 1) = −((y − x) − 1) − 1 = x − y!No dedicated subtract line is needed: invert, add, invert again — subtraction falls out of parts that were already there.
All six bits are 1 bit wide — narrow control, wide data. They carry no information; they only decide.
02The two flags
zr (zero): 1 when the output is all zeros. The CPU uses it for “the values are equal”.
ng (negative): the top bit of the output, that is the sign bit. The CPU uses it for “less than zero”.
Note that ng is just out[15], no extra logic; zr must look at all 16 bits — which is why reduction gates exist.
03Eighteen functions, eighteen switch combinations
0000 0000 0000 0101
| Function | zx nx zy ny f no | Result | Hex | Flags |
|---|---|---|---|---|
| 0 | 101010 | 0 | 0x0000 | zr |
| 1 | 111111 | 1 | 0x0001 | |
| -1 | 111010 | -1 | 0xFFFF | ng |
| x | 001100 | 2 | 0x0002 | |
| y | 110000 | 3 | 0x0003 | |
| !x | 001101 | -3 | 0xFFFD | ng |
| !y | 110001 | -4 | 0xFFFC | ng |
| -x | 001111 | -2 | 0xFFFE | ng |
| -y | 110011 | -3 | 0xFFFD | ng |
| x+1 | 011111 | 3 | 0x0003 | |
| y+1 | 110111 | 4 | 0x0004 | |
| x-1 | 001110 | 1 | 0x0001 | |
| y-1 | 110010 | 2 | 0x0002 | |
| x+y | 000010 | 5 | 0x0005 | |
| x-y | 010011 | -1 | 0xFFFF | ng |
| y-x | 000111 | 1 | 0x0001 | |
| x&y | 000000 | 2 | 0x0002 | |
| x|y | 010101 | 3 | 0x0003 |
Click any row and the control bits set themselves — the 18 functions are 18 combinations of six switches.
CHIP ALU { IN x[16], y[16], zx, nx, zy, ny, f, no; OUT out[16], zr, ng; PARTS: Mux16(a=x, b=false, sel=zx, out=x1); // zx: zero x Not16(in=x1, out=nx1); Mux16(a=x1, b=nx1, sel=nx, out=x2); // nx: invert x Mux16(a=y, b=false, sel=zy, out=y1); // zy Not16(in=y1, out=ny1); Mux16(a=y1, b=ny1, sel=ny, out=y2); // ny And16(a=x2, b=y2, out=andxy); Add16(a=x2, b=y2, out=addxy); Mux16(a=andxy, b=addxy, sel=f, out=o1); // f: 0 = AND, 1 = add Not16(in=o1, out=no1); Mux16(a=o1, b=no1, sel=no, out=out, out[0..7]=lo, out[8..15]=hi, out[15]=msb); // no: invert the result Or8Way(in=lo, out=z1); // zr: all-zero test (reads internal nets, not out) Or8Way(in=hi, out=z2); Or(a=z1, b=z2, out=z); Not(in=z, out=zr); And(a=msb, b=true, out=ng); // ng: sign bit }
All six control bits go to Mux16 selectors. Since out is an output pin, it cannot be read back, so it is also wired to the internal nets lo / hi / msb, and the flags read those nets.