This is a note for Nand2Tetris Unit 1.
Unit 1.2 We can transform any boolean function to its disjunctive normal formula (析取范式) , which means we can represent any boolean function only with NOT
, AND
and OR
.
Can we go further and use only two operations? The answer is YES! Since we can represent OR
with NOT
and AND
:
1 (x OR y) = NOT(NOT(x) AND NOT(y))
Can we go even further? The answer is also YES! Introducing NAND
:
Def.
1 (x NAND y) = NOT(x AND y)
We can represent NOT
only with NAND
:
And then we can represent AND
with NAND
and NOT
:
1 (x AND y) = NOT(x NAND y)
Unit 1.3 Categories of logic gates Logic gates:
Elementary (Nand, And, Or, Not, ...)
Composite (复合的) (Mux, Adder, ...)
Gate diagrams
Gate interfaces and implements
Unit 1.4 HDL: Hardware Description Language
Common HDLs:
Unit 1.6 bus (总线)
Buses can be composed from (and broken into) sub-buses.
1 2 3 4 5 ... IN lsb[8], msb[8], ... ... Add16(a[0..7]=lsb, a[8..15]=msb, b=..., out=...); Add16(..., out[0...3]=t1, out[4..15]=t2);
Attention that [x..x]
can only appear in the left of the equal sign. Something wrong like in=a[0..7]
raises sub bus of an internal node may not be used
error!
a[0]
: right-most bit (the least significant bit, LSB)a[15]
: left-most bit (the most significant bit, MSB)
Attention! The index is FROM RIGHT TO LEFT !
true
: each bit gets onefalse
: each bit gets zero
Unit 1.7
Multiplexor (Mux, 复用器) 1 2 3 4 if sel == 0 : out = a else : out = b
Demultiplexor (DMux, 解复用器) 1 2 3 4 if sel == 0 : a, b = in , 0 else : a, b = 0 , in
Project 1 Not.hdl Note that NOT(x) = x NAND x
.
1 2 3 4 5 6 7 8 9 10 11 12 /** * Not gate: * out = not in */ CHIP Not { IN in; OUT out; PARTS: Nand(a=in, b=in, out=out); }
Not16.hdl Just repeat Not
for 16 times. I wrote a Python script to generate this:
1 2 for i in range (16 ): print (f"Not(in=in[{i} ], out=out[{i} ]);" )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 /** * 16-bit Not: * for i=0..15: out[i] = not in[i] */ CHIP Not16 { IN in[16]; OUT out[16]; PARTS: Not(in=in[0], out=out[0]); Not(in=in[1], out=out[1]); Not(in=in[2], out=out[2]); Not(in=in[3], out=out[3]); Not(in=in[4], out=out[4]); Not(in=in[5], out=out[5]); Not(in=in[6], out=out[6]); Not(in=in[7], out=out[7]); Not(in=in[8], out=out[8]); Not(in=in[9], out=out[9]); Not(in=in[10], out=out[10]); Not(in=in[11], out=out[11]); Not(in=in[12], out=out[12]); Not(in=in[13], out=out[13]); Not(in=in[14], out=out[14]); Not(in=in[15], out=out[15]); }
And.hdl Note that (x AND y) = NOT(x NAND y)
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 /** * And gate: * out = 1 if (a == 1 and b == 1) * 0 otherwise */ CHIP And { IN a, b; OUT out; PARTS: Nand(a=a, b=b, out=aNandb); Not(in=aNandb, out=out); }
And16.hdl Similarly, repeat And
for 16 times.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 /** * 16-bit bitwise And: * for i = 0..15: out[i] = (a[i] and b[i]) */ CHIP And16 { IN a[16], b[16]; OUT out[16]; PARTS: And(a=a[0], b=b[0], out=out[0]); And(a=a[1], b=b[1], out=out[1]); And(a=a[2], b=b[2], out=out[2]); And(a=a[3], b=b[3], out=out[3]); And(a=a[4], b=b[4], out=out[4]); And(a=a[5], b=b[5], out=out[5]); And(a=a[6], b=b[6], out=out[6]); And(a=a[7], b=b[7], out=out[7]); And(a=a[8], b=b[8], out=out[8]); And(a=a[9], b=b[9], out=out[9]); And(a=a[10], b=b[10], out=out[10]); And(a=a[11], b=b[11], out=out[11]); And(a=a[12], b=b[12], out=out[12]); And(a=a[13], b=b[13], out=out[13]); And(a=a[14], b=b[14], out=out[14]); And(a=a[15], b=b[15], out=out[15]); }
Or.hdl Note that (x Or y) = NOT(NOT(x) AND NOT(y))
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 /** * Or gate: * out = 1 if (a == 1 or b == 1) * 0 otherwise */ CHIP Or { IN a, b; OUT out; PARTS: Not(in=a, out=Nota); Not(in=b, out=Notb); And(a=Nota, b=Notb, out=NotaAndNotb); Not(in=NotaAndNotb, out=out); }
Or16.hdl 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 /** * 16-bit bitwise Or: * for i = 0..15 out[i] = (a[i] or b[i]) */ CHIP Or16 { IN a[16], b[16]; OUT out[16]; PARTS: Or(a=a[0], b=b[0], out=out[0]); Or(a=a[1], b=b[1], out=out[1]); Or(a=a[2], b=b[2], out=out[2]); Or(a=a[3], b=b[3], out=out[3]); Or(a=a[4], b=b[4], out=out[4]); Or(a=a[5], b=b[5], out=out[5]); Or(a=a[6], b=b[6], out=out[6]); Or(a=a[7], b=b[7], out=out[7]); Or(a=a[8], b=b[8], out=out[8]); Or(a=a[9], b=b[9], out=out[9]); Or(a=a[10], b=b[10], out=out[10]); Or(a=a[11], b=b[11], out=out[11]); Or(a=a[12], b=b[12], out=out[12]); Or(a=a[13], b=b[13], out=out[13]); Or(a=a[14], b=b[14], out=out[14]); Or(a=a[15], b=b[15], out=out[15]); }
Or8Way.hdl Connect all the eight inputs together end to end with Or
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 /** * 8-way Or: * out = (in[0] or in[1] or ... or in[7]) */ CHIP Or8Way { IN in[8]; OUT out; PARTS: Or(a=in[0], b=in[1], out=or1); Or(a=or1, b=in[2], out=or2); Or(a=or2, b=in[3], out=or3); Or(a=or3, b=in[4], out=or4); Or(a=or4, b=in[5], out=or5); Or(a=or5, b=in[6], out=or6); Or(a=or6, b=in[7], out=out); }
Xor.hdl List the truth table of XOR
, and then you will find that (x XOR y) = (NOT(x) AND y) OR (x AND NOT(y))
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 /** * Exclusive-or gate: * out = not (a == b) */ CHIP Xor { IN a, b; OUT out; PARTS: Not(in=a, out=Nota); Not(in=b, out=Notb); And(a=Nota, b=b, out=NotaAndb); And(a=a, b=Notb, out=aAndNotb); Or(a=NotaAndb, b=aAndNotb, out=out); }
Mux.hdl List the truth table, and find the disjunctive normal formula:
1 2 3 4 MUX(a, b, sel) = (NOT(a) AND b AND sel) OR (a AND NOT(b) AND NOT(sel)) OR (a AND b AND NOT(sel)) OR (a AND b AND sel)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 /** * Multiplexor: * out = a if sel == 0 * b otherwise */ CHIP Mux { IN a, b, sel; OUT out; PARTS: Not(in=a, out=Nota); Not(in=b, out=Notb); Not(in=sel, out=Notsel); And(a=Nota, b=b, out=p1p); And(a=p1p, b=sel, out=p1); And(a=a, b=Notb, out=p2p); And(a=p2p, b=Notsel, out=p2); And(a=a, b=b, out=p34p); And(a=p34p, b=Notsel, out=p3); And(a=p34p, b=sel, out=p4); Or(a=p1, b=p2, out=o1); Or(a=o1, b=p3, out=o2); Or(a=o2, b=p4, out=out); }
Mux16.hdl 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 /** * 16-bit multiplexor: * for i = 0..15 out[i] = a[i] if sel == 0 * b[i] if sel == 1 */ CHIP Mux16 { IN a[16], b[16], sel; OUT out[16]; PARTS: Mux(a=a[0], b=b[0], sel=sel, out=out[0]); Mux(a=a[1], b=b[1], sel=sel, out=out[1]); Mux(a=a[2], b=b[2], sel=sel, out=out[2]); Mux(a=a[3], b=b[3], sel=sel, out=out[3]); Mux(a=a[4], b=b[4], sel=sel, out=out[4]); Mux(a=a[5], b=b[5], sel=sel, out=out[5]); Mux(a=a[6], b=b[6], sel=sel, out=out[6]); Mux(a=a[7], b=b[7], sel=sel, out=out[7]); Mux(a=a[8], b=b[8], sel=sel, out=out[8]); Mux(a=a[9], b=b[9], sel=sel, out=out[9]); Mux(a=a[10], b=b[10], sel=sel, out=out[10]); Mux(a=a[11], b=b[11], sel=sel, out=out[11]); Mux(a=a[12], b=b[12], sel=sel, out=out[12]); Mux(a=a[13], b=b[13], sel=sel, out=out[13]); Mux(a=a[14], b=b[14], sel=sel, out=out[14]); Mux(a=a[15], b=b[15], sel=sel, out=out[15]); }
Mux4Way16.hdl The idea of the implementation is classify the four inputs into two groups, and use two layers of Mux16
;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 /** * 4-way 16-bit multiplexor: * out = a if sel == 00 * b if sel == 01 * c if sel == 10 * d if sel == 11 */ CHIP Mux4Way16 { IN a[16], b[16], c[16], d[16], sel[2]; OUT out[16]; PARTS: Mux16(a=a, b=b, sel=sel[0], out=ab); Mux16(a=c, b=d, sel=sel[0], out=cd); Mux16(a=ab, b=cd, sel=sel[1], out=out); }
Mux8Way16.hdl 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 /** * 8-way 16-bit multiplexor: * out = a if sel == 000 * b if sel == 001 * etc. * h if sel == 111 */ CHIP Mux8Way16 { IN a[16], b[16], c[16], d[16], e[16], f[16], g[16], h[16], sel[3]; OUT out[16]; PARTS: Mux4Way16(a=a, b=b, c=c, d=d, sel=sel[0..1], out=abcd); Mux4Way16(a=e, b=f, c=g, d=h, sel=sel[0..1], out=efgh); Mux16(a=abcd, b=efgh, sel=sel[2], out=out); }
DMux.hdl 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 /** * Demultiplexor: * {a, b} = {in, 0} if sel == 0 * {0, in} if sel == 1 */ CHIP DMux { IN in, sel; OUT a, b; PARTS: Not(in=sel, out=Notsel); And(a=in, b=Notsel, out=a); And(a=in, b=sel, out=b); }
DMux4Way.hdl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 /** * 4-way demultiplexor: * {a, b, c, d} = {in, 0, 0, 0} if sel == 00 * {0, in, 0, 0} if sel == 01 * {0, 0, in, 0} if sel == 10 * {0, 0, 0, in} if sel == 11 */ CHIP DMux4Way { IN in, sel[2]; OUT a, b, c, d; PARTS: DMux(in=in, sel=sel[1], a=ab, b=cd); DMux(in=ab, sel=sel[0], a=a, b=b); DMux(in=cd, sel=sel[0], a=c, b=d); }
DMux8Way.hdl 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 /** * 8-way demultiplexor: * {a, b, c, d, e, f, g, h} = {in, 0, 0, 0, 0, 0, 0, 0} if sel == 000 * {0, in, 0, 0, 0, 0, 0, 0} if sel == 001 * etc. * {0, 0, 0, 0, 0, 0, 0, in} if sel == 111 */ CHIP DMux8Way { IN in, sel[3]; OUT a, b, c, d, e, f, g, h; PARTS: DMux(in=in, sel=sel[2], a=abcd, b=efgh); DMux4Way(in=abcd, sel=sel[0..1], a=a, b=b, c=c, d=d); DMux4Way(in=efgh, sel=sel[0..1], a=e, b=f, c=g, d=h); }