Lesson 0. Logic: 0 and 1, gates from transistors, an adder

In pictures

The foundation before the watch. What 0 and 1 are, the three operations on them (Boolean algebra), how a logic gate is made of transistors, and how gates make something useful — a circuit that adds two 4-bit numbers. Everything later in the kit is the same gates, just more of them.

Result: NOT (2 transistors), NAND and NOR (4 each), AND and OR (6 each), XOR (16), the full adder FA (50), the 4-bit adder ADD4 (200) — all 256 sums from 0+0 to 15+15 are correct.


0.1. The simulator

Everything is built in the browser: cs.khanin.info. No install, no sign-up; a computer with a mouse is the most comfortable.

This is a learning simulator, not a tool for designing real electronics. A transistor in it is an ideal switch (open or closed), and a signal is only 0 or 1. There are no voltages, currents, wire delays, heat or noise. That is more than enough to understand how logic, memory and a processor work; you can't design a real board with it — that needs resistors, power calculations and timing margins.

How to place parts, labels and chips is in "The simulator in five minutes" before the lessons. The key points: labels with the same name are connected, Ctrl+G turns a selection into a chip, Export saves your work.


0.2. Boolean algebra: 0, 1 and three operations

A signal is 0 or 1 (no/yes, false/true, off/on). Boolean algebra (George Boole, 1847) is the arithmetic of such values. There are only three operations:

  • NOT — flips: NOT 0 = 1, NOT 1 = 0. In the kit we write it with an n prefix: nA = NOT A.
  • AND — A·B is 1 only when both inputs are 1.
  • OR — A + B is 1 when at least one input is 1.

Their combinations got names of their own because they come up all the time:

ABA·BA + BNANDNORXOR
0000110
0101101
1001101
1111000
  • NAND = NOT(AND), NOR = NOT(OR).
  • XOR ("exclusive OR", A ⊕ B) — 1 when the inputs differ. It is one-bit addition without the carry: 1 + 1 = 0, and the one goes to the carry (we'll need this in 0.5).

⚠ The plus in Boolean algebra is OR, not addition: 1 + 1 = 1.

The laws used to simplify formulas (each one checks out by substituting 0 and 1):

LawExample
with a constantA·1 = A
A·0 = 0
A + 0 = A
A + 1 = 1
with itselfA·A = A
A + A = A
with its oppositeA·nA = 0
A + nA = 1
double NOTNOT(nA) = A
factoring outA·B + A·C = A·(B + C)
mergingA·B + A·nB = A
De MorganNOT(A·B) = nA + nB
NOT(A + B) = nA·nB

De Morgan's law in words: "not (both)" = "at least one is not". It lets you swap AND for OR at the cost of inversions — that's how in lesson 3 the multiplexer is rebuilt from NANDs only and becomes cheaper.


0.3. A transistor is a switch

The palette has a Transistor part. It has three pins: the gate G on the left, top and bottom. The gate controls whether top and bottom are connected. Alt + click on the body (on a Mac — ⌥ or ⌘ + click) switches the type N ↔ P — a plain click leaves it alone:

  • N: gate = 1 → top and bottom connected; gate = 0 → open.
  • P: the other way round — connected when the gate = 0.

The CMOS rule (almost every chip since the 1980s is built this way): P transistors go on top, between VCC (the source of 1) and the output; N ones go at the bottom, between the output and GND (the source of 0). For any input exactly one half conducts — the output is always connected either to 1 or to 0. Never to both at once (a short) and never to nothing (an open, the output "floats").


topNG=0bottomopentopNG=1bottomconnectedtopPG=0bottomconnectedtopPG=1bottomopenN: conducts at G = 1P: conducts at G = 0 (the bubble means "inverted")
A transistor in the simulator is a switch between the "top" and "bottom" pins, controlled by the gate G. N conducts at G = 1, P at G = 0. What is connected is highlighted.

0.4. NOT, NAND, NOR from transistors

NOT — two transistors. Input A goes to both gates: with A = 0 the top P is open and pulls the output to 1, with A = 1 the bottom N pulls it to 0.

INPUT PORTS: A · OUTPUT PORTS: Y

TransistorGateTopBottom
PAVCCY
NAYGND
VCC = 1PA=1NA=1Y = 0GND = 0P closed: no path to VCCN open: Y is tied to GNDone input A —to both gates
NOT from two transistors at A = 1: the bottom N conducts and ties the output to ground, the top P is closed. Y = 0. At A = 0 it is the other way round — P conducts, Y = 1.

Make it a chip: Ctrl+G → NOT.

NAND — four. Two P in parallel on top: a single 0 on an input is enough to make the output 1. Two N in series at the bottom: the output connects to ground only when both inputs are 1. The point between the two N gets the label mid.

INPUT PORTS: A, B · OUTPUT PORTS: Y

TransistorGateTopBottom
PAVCCY
PBVCCY
NAYmid
NBmidGND
VCC = 1VCC = 1PA=1PB=1Y = 0NA=1midNB=1GND = 0two P in parallel:any 0 gives Y = 1two N in series: to GNDonly when both = 1
NAND from four transistors at A = 1, B = 1: both bottom N are open, the path Y → mid → GND is closed, both P are off — Y = 0. As soon as any input becomes 0, its N breaks the chain and its P ties Y to VCC.

Make it a chip: Ctrl+G → NAND.

NOR — the mirror image: two P in series (output 1 only when both inputs are 0), two N in parallel (any 1 pulls the output to 0).

INPUT PORTS: A, B · OUTPUT PORTS: Y

TransistorGateTopBottom
PAVCCmid
PBmidY
NAYGND
NBYGND

Make it a chip: Ctrl+G → NOR.

AND, OR, XOR — from gates. No more transistors needed: the three missing gates are built from the NOT, NAND, NOR you have just made.

AND = NAND + NOT — "NOT-AND", then flip it:

INPUT PORTS: A, B · OUTPUT PORTS: Y

ElementInputsOutput
NANDA, Bn
NOTnY

Make it a chip: Ctrl+G → AND.

OR = NOR + NOT:

INPUT PORTS: A, B · OUTPUT PORTS: Y

ElementInputsOutput
NORA, Bn
NOTnY

Make it a chip: Ctrl+G → OR.

XOR — "at least one, but not both": AND( OR(A, B), NAND(A, B) ):

INPUT PORTS: A, B · OUTPUT PORTS: Y

ElementInputsOutput
ORA, Bo
NANDA, Bn
ANDo, nY

Make it a chip: Ctrl+G → XOR.

Check. Power: V (Power) with the label VCC and G (Ground) with the label GND; two switches X, Y; lamps (LED) on the outputs:

ElementInputsOutput
NOTXnotX
NANDX, YnandXY
NORX, YnorXY
ANDX, YandXY
ORX, YorXY
XORX, YxorXY
LEDnotX
LEDnandXY
LEDnorXY
LEDandXY
LEDorXY
LEDxorXY

Flip the switches — the lamps should follow the table from 0.2. Or select a chip and press T for its truth table.

Cost in transistors: NOT — 2, NAND and NOR — 4 each. But AND = NAND + NOT = 6, OR = NOR + NOT = 6: "AND" costs more than "NAND". That's why NAND and NOR are the native CMOS gates, and it pays to bring formulas down to them. XOR — 16 transistors.

These six chips — NOT, NAND, NOR, AND, OR, XOR — are now in your library on the right, and the whole kit stands on them. From here on we don't place transistors by hand: we use these gates.


0.5. Adding one digit

Binary numbers are added in a column, just like decimal ones: 0 + 0 = 0, 0 + 1 = 1, 1 + 1 = 10 — write 0, carry 1 to the next digit. Each digit adds three bits: A, B and the carry from the lower digit CI. There are two outputs: the sum bit S and the carry onward CO.

ABCISCOones
000000
001101
010101
011012 = 10
100101
101012 = 10
110012 = 10
111113 = 11

How we derived it:

  • S = 1 when the number of ones is odd — that is exactly the XOR of three bits: S = A ⊕ B ⊕ CI.
  • CO = 1 when there are two or three ones. Either both A and B (A·B), or exactly one of them (A ⊕ B) and the carry: CO = A·B + (A ⊕ B)·CI.

A ⊕ B is needed both for S and for CO — compute it once, label p.

INPUT PORTS: A, B, CI · OUTPUT PORTS: S, CO

ElementInputsOutput (→)
XORA, Bp
XORp, CIS
ANDA, Bg
ANDp, CIpc
ORg, pcCO
A=1B=1CI=0XORANDp=0XORS = 0ANDg=1pc=0ORCO = 11 + 1 + 0 = 10: sum 0, carry 1
The full adder FA for A = 1, B = 1, CI = 0. p = A ⊕ B = 0 is needed by both outputs — computed once. S = p ⊕ CI = 0; the carry CO = A·B + p·CI = 1 comes from g = A·B.

Make it a chip: Ctrl+G → FA (full adder), inputs A B CI, outputs S CO, 50 transistors. Check: T — eight rows, as in the table above.


0.6. A 4-bit adder

Four FA in a chain: the carry CO of each digit goes to CI of the next. The lowest digit has no incoming carry — CI = GND (0). The carry out of the highest digit is the fifth bit of the sum S4: 15 + 15 = 30 = 11110 doesn't fit into four bits.

INPUT PORTS: A0 A1 A2 A3, B0 B1 B2 B3 · OUTPUT PORTS: S0 S1 S2 S3 S4

ElementInputsOutput (→)
FAA=A0, B=B0, CI=GNDS→S0, CO→c1
FAA=A1, B=B1, CI=c1S→S1, CO→c2
FAA=A2, B=B2, CI=c2S→S2, CO→c3
FAA=A3, B=B3, CI=c3S→S3, CO→S4
FAA0=1B0=1S0=0c1=1FAA1=1B1=0S1=0c2=1FAA2=1B2=0S2=0c3=1FAA3=0B3=0S3=1GNDS4=00111 + 0001 = 01000 (7 + 1 = 8): the carry runs through every digit
ADD4 — four FA in a chain, the lowest digit on the right, as in column addition. In the 7 + 1 example the carry is born in digit 0 and runs left through every digit: c1 = c2 = c3 = 1, result 01000.

Make it a chip: Ctrl+G → ADD4, 200 transistors.

This is a ripple-carry adder: the carry "ripples" from the lowest digit to the highest, as in column addition. The longest case is 0111 + 0001: the carry passes through all four digits. An adder is the heart of every processor: subtraction, comparison and counters are all made from it.


0.7. The canvas and the check

  1. Power: V (Power) with the label VCC, G (Ground) with the label GND (skip if they are already there from the gate check).
  2. Eight switches (I) → labels A0 A1 A2 A3 and B0 B1 B2 B3.
  3. The ADD4 chip, with labels of the same names on its pins: A0…A3, B0…B3, S0…S4.
  4. Three Display (bus). On each: a click on ⚙ at the top left changes the width (4b / 8b / 16b / 32b), a click on PIN at the bottom left lets you type a bus name, and the display reads the labels name0, name1, … by itself, no wires:
ElementWidthBus
Display (bus)4bA
Display (bus)4bB
Display (bus)8bS

The sum has 5 bits and there is no 5-bit display — use 8b: bits S5…S7 don't exist on the canvas, so the display reads them as zeros.

Check: 3 + 4 = 7, 7 + 1 = 8 (the carry runs through all digits), 15 + 15 = 30 (S4 lights up). Any two 4-bit numbers add correctly — all 256 pairs were checked.


Lesson 0 as a paste (Cmd+I)

In an empty project it creates all the kit's basic gates (NOT, NAND, NOR, AND, OR, XOR), FA, ADD4 and places power, the gate check with lamps and the adder with three displays.

# Lesson 0 — gates from transistors and a 4-bit adder.# Paste: Cmd+I into an empty project: builds all the kit's basic gates (NOT NAND NOR AND OR XOR), FA and ADD4.# Transistor: nmos/pmos(gate, top, bottom). VCC/GND are the shared power rails. # --- gates from transistors ---chip NOT {  portIn(A)  portOut(Y)  pmos(A, VCC, Y)  nmos(A, Y, GND)} # NAND: two P in parallel on top, two N in series belowchip NAND {  portIn(A)  portIn(B)  portOut(Y)  pmos(A, VCC, Y)  pmos(B, VCC, Y)  nmos(A, Y, mid)  nmos(B, mid, GND)} # NOR: two P in series on top, two N in parallel belowchip NOR {  portIn(A)  portIn(B)  portOut(Y)  pmos(A, VCC, mid)  pmos(B, mid, Y)  nmos(A, Y, GND)  nmos(B, Y, GND)} # --- gates from gates ---# AND = NAND + NOT (6 transistors)chip AND {  portIn(A)  portIn(B)  portOut(Y)  NAND(A, B, n)  NOT(n, Y)} # OR = NOR + NOT (6 transistors)chip OR {  portIn(A)  portIn(B)  portOut(Y)  NOR(A, B, n)  NOT(n, Y)} # XOR = "at least one, but not both": AND( OR(A,B), NAND(A,B) ) (16 transistors)chip XOR {  portIn(A)  portIn(B)  portOut(Y)  OR(A, B, o)  NAND(A, B, n)  AND(o, n, Y)} # --- full adder for one bit ---chip FA {  portIn(A)  portIn(B)  portIn(CI)  portOut(S)  portOut(CO)  XOR(A, B, p)  XOR(p, CI, S)  AND(A, B, g)  AND(p, CI, pc)  OR(g, pc, CO)} # --- 4 bits: the carry runs from the lowest bit to the highest ---chip ADD4 {  portIn(A0)  portIn(A1)  portIn(A2)  portIn(A3)  portIn(B0)  portIn(B1)  portIn(B2)  portIn(B3)  portOut(S0)  portOut(S1)  portOut(S2)  portOut(S3)  portOut(S4)  FA(A0, B0, GND, S0, c1)  FA(A1, B1, c1, S1, c2)  FA(A2, B2, c2, S2, c3)  FA(A3, B3, c3, S3, S4)} # --- on the canvas: power, gate check, adder with displays ---power(VCC)ground(GND)input(X)input(Y)NOT(X, notX)NAND(X, Y, nandXY)NOR(X, Y, norXY)AND(X, Y, andXY)OR(X, Y, orXY)XOR(X, Y, xorXY)led(notX)led(nandXY)led(norXY)led(andXY)led(orXY)led(xorXY)input(A0)input(A1)input(A2)input(A3)input(B0)input(B1)input(B2)input(B3)ADD4(A0, A1, A2, A3, B0, B1, B2, B3, S0, S1, S2, S3, S4)display{bits=4, busSource=A}()display{bits=4, busSource=B}()display{bits=8, busSource=S}()

Stuck? Something doesn't work →