From Transistor to Browser

The Machine · Chapter 2
What can gates do?

Updated Oct 12, 2026
Summarize
Transcript

What can gates do? Our two switches made one, NAND. Apollo's Moon computer used one kind, in thousands of copies.

Really? AND gates, OR gates, XOR gates, all different rules. Surely each needs its own part. But turn the answers from NAND upside down, and you get OR.

Upside down means both inputs flipped. And the last chapter showed how to flip: tie the two inputs of a NAND together, and it's a NOT gate. So first, put a NOT gate on each input. Then feed both flipped signals into one more NAND. Now run it. Both inputs off? The flips turn them on, and NAND answers off. Switch either one on, and NAND answers on. That's an OR gate, built from three NAND gates. The trick has a name: De Morgan's law.

So one kind of gate really can do it all! NAND is universal. Any gate you want is just NAND gates, wired differently.

Four NANDs can even tell when two bits disagree, and that's how adding starts. Flip the bits below and find that gate.

The hosts' voices are synthetic, made with Breeze TTS 2 by BreezeBlue.

  1. The browser
  2. The network
  3. Software and languages
  4. The CPU
  5. Memory
  6. Arithmetic
  7. Logic gates
  8. The switch
Figure 2.1: Where we are in the climb from transistor to browser: the logic-gates rung. This chapter turns NAND into the named gates the next circuits reuse.

Chapter 1 closed with one gate and a promissory note: NAND alone is enough. This chapter cashes it. Starting from nothing but NAND calls, the program builds the next useful gates: OR, NOR, XOR, and XNOR. Together with NOT, AND, and NAND from the previous chapter, they form the small toolkit the next circuits reuse. By the end you will have met the short algebra of 0 and 1 that organises the whole family and seen why a four-gate network can detect whether two bits disagree, the seed of the adder in the next chapter.

2.1 NAND is universal, made concrete

Chapter 1 showed two derivations: tie both inputs of a NAND together and you get NOT; feed the output of a NAND through that NOT and you recover AND. Those two gates, together with NAND, span the full set of Boolean functions. In code the derivation is already done: the switch chapter’s code, collected in switch.py, exports not_ and and_, both written in terms of nand, with no built-in boolean operator in sight. The rest of this chapter is more of the same: each new gate is a short composition of nand calls, and its truth table is produced by running the gate, not by typing the answers in prose.

2.2 OR, NOR, and the De Morgan bridge

OR is the first gate that needs a conceptual lever: De Morgan’s first law. The law says that NOT(NOT a AND NOT b) equals (a OR b). Feed inverted inputs into a NAND and it behaves as OR. In circuit terms: put an inversion bubble on each input of a NAND and you have drawn an OR gate. Figure 2.2 puts the two symbols side by side so the equivalence is visible as geometry.

de-morgande-morgan
Figure 2.2: De Morgan: a NAND and an OR with inverted inputs are the same gate. The bubble on each input of the right-hand symbol stands for the NOT that De Morgan’s law inserts. Both symbols produce identical outputs for every input pair.

The code is as short as the law:

Example 2-1. OR from NAND, via De Morgan

def or_(a: int, b: int) -> int:
    """OR via De Morgan: invert the inputs, then NAND."""
    return nand(not_(a), not_(b))1

NOR adds only an outer inversion. nor_(a,b) calls not_(or_(a,b)) and nothing else. Counted as NANDs, that is two input inverters, the OR NAND, and one final NAND-as-NOT.

2.3 XOR, the odd one out

XOR outputs 1 when its inputs differ. The algebraic identity is a ⊕ b = (a ∨ b) ∧ (a ∧ b), but the compact NAND implementation avoids OR entirely and uses four NANDs in three levels: a shared NAND, two NANDs combining it with each input, then an output NAND.

Example 2-2. XOR from four NANDs

def xor_(a: int, b: int) -> int:
    """XOR from four NANDs across three levels."""
    shared = nand(a, b)1
    return nand(nand(a, shared), nand(b, shared))2

Computing nand(a, b) twice would produce the same value, but it would waste a gate. Sharing it is what keeps the network to four NANDs, which Figure 2.3 makes visible beside the simpler OR construction.

gates-from-nandgates-from-nand
Figure 2.3: OR and XOR, each built from NAND gates. Left: OR as two inverters feeding one NAND, the De Morgan construction. Right: XOR as four NANDs in three levels: a shared NAND, two NANDs combining it with each input, then an output NAND.

The interactive version needs the in-browser runtime.

XNOR inverts XOR, so it outputs 1 when the two inputs are equal. For inputs 00,01,10,11, its outputs are 1,0,0,1.

Example 2-3. XNOR: equality from inverted XOR

def xnor_(a: int, b: int) -> int:
    """XNOR (equality): invert XOR."""
    return not_(xor_(a, b))

Note that XOR foreshadows the adder in Chapter 3: this gate will compute the sum bit, while AND will compute the carry bit. The four-NAND network here is part of the skeleton of every binary adder.

2.4 Boolean algebra: the algebra of 0 and 1

The gates make sense in isolation, but they make even more sense as a system. Boolean algebra is the algebra whose variables take only the values 0 and 1 and whose three operations correspond directly to the gates above:

A handful of identities follow directly from those definitions and are worth memorising because they recur constantly:

a + 0 = a a · 1 = a
a + 1 = 1 a · 0 = 0
a + a = a a · a = a
a + a = 1 a · a = 0

De Morgan’s two laws tie AND and OR together through complementation:

a · b = a + b a + b = a · b

The first law is what made OR possible after the inputs were inverted: a· b = a + b. In code, the two input inversions prepare the arguments and the final NAND supplies the outer bar. The second law lets you read NOR as an AND of inverted inputs in the same way.

The four gates built here, together with NOT, AND, and NAND from Chapter 1, are the working toolkit for the arithmetic and memory circuits ahead.

Exercises