The Element of Computing Systems (Nand2tetris)
Nand2Tetris reference book

The article covers project1 ~ project2 or chapter 1 ~ chapter 6, which are fundamentals of computer architectures based on HDL (an hardware description language defined in the book). Course materials could refer to https://www.nand2tetris.org/course, and videos on Coursera. The goal for this article is to build a Hack computer based on simple combinational and sequential logic elements composed in HDL.
HACK computer overview:
HACK computer overviewCPU interface:
CPU interfaceCPU control/data path:
CPU control/data path
The code below is HDL implementation of project 1, 2, 3 and 5.
Project 1: boolean logic
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/01/And.hdl
/**
* And gate:
* out = 1 if (a == 1 and b == 1)
* 0 otherwise
*/
CHIP And {
IN a, b;
OUT out;
PARTS:
// Put your code here:
Nand (a=a, b=b, out=outNand1);
Nand (a=outNand1, b=true, out=out);
}
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/01/And16.hdl
/**
* 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:
// Put your code here:
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]);
}
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/01/DMux.hdl
/**
* Demultiplexor:
* {a, b} = {in, 0} if sel == 0
* {0, in} if sel == 1
*/
CHIP DMux {
IN in, sel;
OUT a, b;
PARTS:
// Put your code here:
Not (in=sel, out=out1);
And (a=in, b=out1, out=a);
And (a=in, b=sel, out=b);
}
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/01/DMux4Way.hdl
/**
* 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:
// Put your code here:
DMux (in=in, sel=sel[1], a=out1, b=out2);
DMux (in=out1, sel=sel[0], a=a, b=b);
DMux (in=out2, sel=sel[0], a=c, b=d);
}
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/01/DMux8Way.hdl
/**
* 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:
// Put your code here:
DMux (in=in, sel=sel[2], a=out1, b=out2);
DMux (in=out1, sel=sel[1], a=out3, b=out4);
DMux (in=out2, sel=sel[1], a=out5, b=out6);
DMux (in=out3, sel=sel[0], a=a, b=b);
DMux (in=out4, sel=sel[0], a=c, b=d);
DMux (in=out5, sel=sel[0], a=e, b=f);
DMux (in=out6, sel=sel[0], a=g, b=h);
}
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/01/Mux.hdl
/**
* Multiplexor:
* out = a if sel == 0
* b otherwise
*/
CHIP Mux {
IN a, b, sel;
OUT out;
PARTS:
// Put your code here:
Not (in=sel, out=outNot);
And (a=a, b=outNot, out=outAnd1);
And (a=sel, b=b, out=outAnd2);
Or (a=outAnd1, b=outAnd2, out=out);
}
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/01/Mux4Way16.hdl
/**
* 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:
// Put your code here:
Mux16 (a=a, b=b, sel=sel[0], out=out1);
Mux16 (a=c, b=d, sel=sel[0], out=out2);
Mux16 (a=out1, b=out2, sel=sel[1], out=out);
}
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/01/Mux8Way16.hdl
/**
* 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:
// Put your code here:
Mux16 (a=a, b=b, sel=sel[0], out=out1);
Mux16 (a=c, b=d, sel=sel[0], out=out2);
Mux16 (a=e, b=f, sel=sel[0], out=out3);
Mux16 (a=g, b=h, sel=sel[0], out=out4);
Mux16 (a=out1, b=out2, sel=sel[1], out=out5);
Mux16 (a=out3, b=out4, sel=sel[1], out=out6);
Mux16 (a=out5, b=out6, sel=sel[2], out=out);
}
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/01/Mux16.hdl
/**
* 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:
// Put your code here:
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]);
}
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/01/Not.hdl
/**
* Not gate:
* out = not in
*/
CHIP Not {
IN in;
OUT out;
PARTS:
// Put your code here:
Nand (a=in, b=true, out=out);
}
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/01/Not16.hdl
/**
* 16-bit Not:
* for i=0..15: out[i] = not in[i]
*/
CHIP Not16 {
IN in[16];
OUT out[16];
PARTS:
// Put your code here:
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]);
}
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/01/Or.hdl
/**
* Or gate:
* out = 1 if (a == 1 or b == 1)
* 0 otherwise
*/
CHIP Or {
IN a, b;
OUT out;
PARTS:
// Put your code here:
Nand (a=a, b=true, out=outNot1);
Nand (a=true, b=b, out=outNot2);
Nand (a=outNot1, b=outNot2, out=out);
}
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/01/Or8Way.hdl
/**
* 8-way Or:
* out = (in[0] or in[1] or ... or in[7])
*/
CHIP Or8Way {
IN in[8];
OUT out;
PARTS:
// Put your code here:
Or (a=in[0], b=in[1], out=outOr1);
Or (a=in[2], b=outOr1, out=outOr2);
Or (a=in[3], b=outOr2, out=outOr3);
Or (a=in[4], b=outOr3, out=outOr4);
Or (a=in[5], b=outOr4, out=outOr5);
Or (a=in[6], b=outOr5, out=outOr6);
Or (a=in[7], b=outOr6, out=out);
}
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/01/Or16.hdl
/**
* 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:
// Put your code here:
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]);
}
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/01/Xor.hdl
/**
* Exclusive-or gate:
* out = not (a == b)
*/
CHIP Xor {
IN a, b;
OUT out;
PARTS:
// Put your code here:
Not (in=a, out=nota);
Not (in=b, out=notb);
And (a=a, b=notb, out=w1);
And (a=nota, b=b, out=w2);
Or (a=w1, b=w2, out=out);
}
Project 2: boolean arithmetic
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/02/Adder16.hdl
/**
* Adds two 16-bit values.
* The most significant carry bit is ignored.
*/
CHIP Add16 {
IN a[16], b[16];
OUT out[16];
PARTS:
// Put you code here:
FullAdder (a=a[0], b=b[0], c=false, sum=out[0], carry=carry15);
FullAdder (a=a[1], b=b[1], c=carry15, sum=out[1], carry=carry14);
FullAdder (a=a[2], b=b[2], c=carry14, sum=out[2], carry=carry13);
FullAdder (a=a[3], b=b[3], c=carry13, sum=out[3], carry=carry12);
FullAdder (a=a[4], b=b[4], c=carry12, sum=out[4], carry=carry11);
FullAdder (a=a[5], b=b[5], c=carry11, sum=out[5], carry=carry10);
FullAdder (a=a[6], b=b[6], c=carry10, sum=out[6], carry=carry9);
FullAdder (a=a[7], b=b[7], c=carry9, sum=out[7], carry=carry8);
FullAdder (a=a[8], b=b[8], c=carry8, sum=out[8], carry=carry7);
FullAdder (a=a[9], b=b[9], c=carry7, sum=out[9], carry=carry6);
FullAdder (a=a[10], b=b[10], c=carry6, sum=out[10], carry=carry5);
FullAdder (a=a[11], b=b[11], c=carry5, sum=out[11], carry=carry4);
FullAdder (a=a[12], b=b[12], c=carry4, sum=out[12], carry=carry3);
FullAdder (a=a[13], b=b[13], c=carry3, sum=out[13], carry=carry2);
FullAdder (a=a[14], b=b[14], c=carry2, sum=out[14], carry=carry1);
FullAdder (a=a[15], b=b[15], c=carry1, sum=out[15], carry=carry0);
}
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/02/ALU.hdl
/**
* The ALU (Arithmetic Logic Unit).
* Computes one of the following functions:
* x+y, x-y, y-x, 0, 1, -1, x, y, -x, -y, !x, !y,
* x+1, y+1, x-1, y-1, x&y, x|y on two 16-bit inputs,
* according to 6 input bits denoted zx,nx,zy,ny,f,no.
* In addition, the ALU computes two 1-bit outputs:
* if the ALU output == 0, zr is set to 1; otherwise zr is set to 0;
* if the ALU output < 0, ng is set to 1; otherwise ng is set to 0.
*/
// Implementation: the ALU logic manipulates the x and y inputs
// and operates on the resulting values, as follows:
// if (zx == 1) set x = 0 // 16-bit constant
// if (nx == 1) set x = !x // bitwise not
// if (zy == 1) set y = 0 // 16-bit constant
// if (ny == 1) set y = !y // bitwise not
// if (f == 1) set out = x + y // integer 2's complement addition
// if (f == 0) set out = x & y // bitwise and
// if (no == 1) set out = !out // bitwise not
// if (out == 0) set zr = 1
// if (out < 0) set ng = 1
CHIP ALU {
IN
x[16], y[16], // 16-bit inputs
zx, // zero the x input?
nx, // negate the x input?
zy, // zero the y input?
ny, // negate the y input?
f, // compute out = x + y (if 1) or x & y (if 0)
no; // negate the out output?
OUT
out[16], // 16-bit output
zr, // 1 if (out == 0), 0 otherwise
ng; // 1 if (out < 0), 0 otherwise
PARTS:
// Put you code here:
Not16 (in=x, out=notx);
Mux4Way16 (a=x, b=notx, c=false, d=true, sel[1]=zx, sel[0]=nx, out=outx);
Not16 (in=y, out=noty);
Mux4Way16 (a=y, b=noty, c=false, d=true, sel[1]=zy, sel[0]=ny, out=outy);
And16 (a=outx, b=outy, out=outAnd);
Add16 (a=outx, b=outy, out=outAdd);
Mux16 (a=outAnd, b=outAdd, sel=f, out=outsel1);
Not16 (in=outsel1, out=outsel2);
Mux16 (a=outsel1, b=outsel2, sel=no, out=out, out[15]=sign, out[15]=out15, out[14]=out14,
out[13]=out13, out[12]=out12, out[11]=out11, out[10]=out10, out[9]=out9, out[8]=out8,
out[7]=out7, out[6]=out6, out[5]=out5, out[4]=out4, out[3]=out3, out[2]=out2, out[1]=out1,
out[0]=out0);
Or (a=sign, b=false, out=ng);
Or (a=out0, b=out1, out=and1);
Or (a=and1, b=out2, out=and2);
Or (a=and2, b=out3, out=and3);
Or (a=and3, b=out4, out=and4);
Or (a=and4, b=out5, out=and5);
Or (a=and5, b=out6, out=and6);
Or (a=and6, b=out7, out=and7);
Or (a=and7, b=out8, out=and8);
Or (a=and8, b=out9, out=and9);
Or (a=and9, b=out10, out=and10);
Or (a=and10, b=out11, out=and11);
Or (a=and11, b=out12, out=and12);
Or (a=and12, b=out13, out=and13);
Or (a=and13, b=out14, out=and14);
Or (a=and14, b=out15, out=and15);
Not (in=and15, out=zr);
}
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/02/FullAdder.hdl
/**
* Computes the sum of three bits.
*/
CHIP FullAdder {
IN a, b, c; // 1-bit inputs
OUT sum, // Right bit of a + b + c
carry; // Left bit of a + b + c
PARTS:
// Put you code here:
HalfAdder (a=a, b=b, carry=carry1, sum=sum1);
HalfAdder (a=sum1, b=c, carry=carry2, sum=sum);
Or (a=carry1, b=carry2, out=carry);
}
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/02/FullAdder.hdl
/**
* Computes the sum of three bits.
*/
CHIP FullAdder {
IN a, b, c; // 1-bit inputs
OUT sum, // Right bit of a + b + c
carry; // Left bit of a + b + c
PARTS:
// Put you code here:
HalfAdder (a=a, b=b, carry=carry1, sum=sum1);
HalfAdder (a=sum1, b=c, carry=carry2, sum=sum);
Or (a=carry1, b=carry2, out=carry);
}
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/02/Inc16.hdl
/**
* 16-bit incrementer:
* out = in + 1 (arithmetic addition)
*/
CHIP Inc16 {
IN in[16];
OUT out[16];
PARTS:
// Put you code here:
Add16 (a=in, b[0]=true, out=out);
}
Project 3: sequential logic
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/03/a/Bit.hdl
/**
* 1-bit register:
* If load[t] == 1 then out[t+1] = in[t]
* else out does not change (out[t+1] = out[t])
*/
CHIP Bit {
IN in, load;
OUT out;
PARTS:
// Put your code here:
Mux (a=dffOut, b=in, sel=load, out=muxOut);
DFF (in=muxOut, out=out, out=dffOut);
}
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/03/a/PC.hdl
/**
* A 16-bit counter with load and reset control bits.
* if (reset[t] == 1) out[t+1] = 0
* else if (load[t] == 1) out[t+1] = in[t]
* else if (inc[t] == 1) out[t+1] = out[t] + 1 (integer addition)
* else out[t+1] = out[t]
*/
CHIP PC {
IN in[16],load,inc,reset;
OUT out[16];
PARTS:
// Put your code here:
Inc16 (in=rOut, out=incOut);
Mux16 (a=in, b=incOut, sel=inc, out=muxOut1);
Mux16 (a=muxOut1, b=in, sel=load, out=muxOut2);
And16 (a=in, b=false, out=andOut);
Mux16 (a=muxOut2, b=andOut, sel=reset, out=muxOut3);
Register (in=muxOut3, load=true, out=out, out=rOut);
}
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/03/b/RAM4K.hdl
/**
* Memory of 4K registers, each 16 bit-wide. Out holds the value
* stored at the memory location specified by address. If load==1, then
* the in value is loaded into the memory location specified by address
* (the loaded value will be emitted to out from the next time step onward).
*/
CHIP RAM4K {
IN in[16], load, address[12];
OUT out[16];
PARTS:
// Put your code here:
DMux8Way (in=load, sel[2]=address[11], sel[1]=address[10], sel[0]=address[9],
a=out1, b=out2, c=out3, d=out4, e=out5, f=out6, g=out7, h=out8);
RAM512 (in=in, load=out1, address[8]=address[8], address[7]=address[7], address[6]=address[6],
address[5]=address[5], address[4]=address[4], address[3]=address[3], address[2]=address[2],
address[1]=address[1], address[0]=address[0], out=outR1);
RAM512 (in=in, load=out2, address[8]=address[8], address[7]=address[7], address[6]=address[6],
address[5]=address[5], address[4]=address[4], address[3]=address[3], address[2]=address[2],
address[1]=address[1], address[0]=address[0], out=outR2);
RAM512 (in=in, load=out3, address[8]=address[8], address[7]=address[7], address[6]=address[6],
address[5]=address[5], address[4]=address[4], address[3]=address[3], address[2]=address[2],
address[1]=address[1], address[0]=address[0], out=outR3);
RAM512 (in=in, load=out4, address[8]=address[8], address[7]=address[7], address[6]=address[6],
address[5]=address[5], address[4]=address[4], address[3]=address[3], address[2]=address[2],
address[1]=address[1], address[0]=address[0], out=outR4);
RAM512 (in=in, load=out5, address[8]=address[8], address[7]=address[7], address[6]=address[6],
address[5]=address[5], address[4]=address[4], address[3]=address[3], address[2]=address[2],
address[1]=address[1], address[0]=address[0], out=outR5);
RAM512 (in=in, load=out6, address[8]=address[8], address[7]=address[7], address[6]=address[6],
address[5]=address[5], address[4]=address[4], address[3]=address[3], address[2]=address[2],
address[1]=address[1], address[0]=address[0], out=outR6);
RAM512 (in=in, load=out7, address[8]=address[8], address[7]=address[7], address[6]=address[6],
address[5]=address[5], address[4]=address[4], address[3]=address[3], address[2]=address[2],
address[1]=address[1], address[0]=address[0], out=outR7);
RAM512 (in=in, load=out8, address[8]=address[8], address[7]=address[7], address[6]=address[6],
address[5]=address[5], address[4]=address[4], address[3]=address[3], address[2]=address[2],
address[1]=address[1], address[0]=address[0], out=outR8);
Mux8Way16 (a=outR1, b=outR2, c=outR3, d=outR4, e=outR5, f=outR6, g=outR7, h=outR8,
sel[2]=address[11], sel[1]=address[10], sel[0]=address[9], out=out);
}
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/03/a/RAM8.hdl
/**
* Memory of 8 registers, each 16 bit-wide. Out holds the value
* stored at the memory location specified by address. If load==1, then
* the in value is loaded into the memory location specified by address
* (the loaded value will be emitted to out from the next time step onward).
*/
CHIP RAM8 {
IN in[16], load, address[3];
OUT out[16];
PARTS:
// Put your code here:
DMux8Way (in=load, sel=address, a=out1, b=out2, c=out3, d=out4, e=out5, f=out6, g=out7, h=out8);
Register (in=in, load=out1, out=outR1);
Register (in=in, load=out2, out=outR2);
Register (in=in, load=out3, out=outR3);
Register (in=in, load=out4, out=outR4);
Register (in=in, load=out5, out=outR5);
Register (in=in, load=out6, out=outR6);
Register (in=in, load=out7, out=outR7);
Register (in=in, load=out8, out=outR8);
Mux8Way16 (a=outR1, b=outR2, c=outR3, d=outR4, e=outR5, f=outR6, g=outR7, h=outR8, sel=address, out=out);
}
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/03/b/RAM16K.hdl
/**
* Memory of 16K registers, each 16 bit-wide. Out holds the value
* stored at the memory location specified by address. If load==1, then
* the in value is loaded into the memory location specified by address
* (the loaded value will be emitted to out from the next time step onward).
*/
CHIP RAM16K {
IN in[16], load, address[14];
OUT out[16];
PARTS:
// Put your code here:
DMux4Way (in=load, sel[1]=address[13], sel[0]=address[12], a=out1, b=out2, c=out3, d=out4);
RAM4K (in=in, load=out1, address[11]=address[11], address[10]=address[10], address[9]=address[9],
address[8]=address[8], address[7]=address[7], address[6]=address[6], address[5]=address[5],
address[4]=address[4], address[3]=address[3], address[2]=address[2], address[1]=address[1],
address[0]=address[0], out=outR1);
RAM4K (in=in, load=out2, address[11]=address[11], address[10]=address[10], address[9]=address[9],
address[8]=address[8], address[7]=address[7], address[6]=address[6], address[5]=address[5],
address[4]=address[4], address[3]=address[3], address[2]=address[2], address[1]=address[1],
address[0]=address[0], out=outR2);
RAM4K (in=in, load=out3, address[11]=address[11], address[10]=address[10], address[9]=address[9],
address[8]=address[8], address[7]=address[7], address[6]=address[6], address[5]=address[5],
address[4]=address[4], address[3]=address[3], address[2]=address[2], address[1]=address[1],
address[0]=address[0], out=outR3);
RAM4K (in=in, load=out4, address[11]=address[11], address[10]=address[10], address[9]=address[9],
address[8]=address[8], address[7]=address[7], address[6]=address[6], address[5]=address[5],
address[4]=address[4], address[3]=address[3], address[2]=address[2], address[1]=address[1],
address[0]=address[0], out=outR4);
Mux4Way16 (a=outR1, b=outR2, c=outR3, d=outR4, sel[1]=address[13], sel[0]=address[12], out=out);
}
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/03/a/RAM64.hdl
/**
* Memory of 64 registers, each 16 bit-wide. Out holds the value
* stored at the memory location specified by address. If load==1, then
* the in value is loaded into the memory location specified by address
* (the loaded value will be emitted to out from the next time step onward).
*/
CHIP RAM64 {
IN in[16], load, address[6];
OUT out[16];
PARTS:
// Put your code here:
DMux8Way (in=load, sel[2]=address[5], sel[1]=address[4], sel[0]=address[3], a=out1, b=out2, c=out3,
d=out4, e=out5, f=out6, g=out7, h=out8);
RAM8 (in=in, load=out1, address[2]=address[2], address[1]=address[1], address[0]=address[0], out=outR1);
RAM8 (in=in, load=out2, address[2]=address[2], address[1]=address[1], address[0]=address[0], out=outR2);
RAM8 (in=in, load=out3, address[2]=address[2], address[1]=address[1], address[0]=address[0], out=outR3);
RAM8 (in=in, load=out4, address[2]=address[2], address[1]=address[1], address[0]=address[0], out=outR4);
RAM8 (in=in, load=out5, address[2]=address[2], address[1]=address[1], address[0]=address[0], out=outR5);
RAM8 (in=in, load=out6, address[2]=address[2], address[1]=address[1], address[0]=address[0], out=outR6);
RAM8 (in=in, load=out7, address[2]=address[2], address[1]=address[1], address[0]=address[0], out=outR7);
RAM8 (in=in, load=out8, address[2]=address[2], address[1]=address[1], address[0]=address[0], out=outR8);
Mux8Way16 (a=outR1, b=outR2, c=outR3, d=outR4, e=outR5, f=outR6, g=outR7, h=outR8, sel[2]=address[5],
sel[1]=address[4], sel[0]=address[3], out=out);
}
// This file is part of the materials accompanying the book
// "The Elements of Computing Systems" by Nisan and Schocken,
// MIT Press. Book site: www.idc.ac.il/tecs
// File name: projects/03/b/RAM512.hdl
/**
* Memory of 512 registers, each 16 bit-wide. Out holds the value
* stored at the memory location specified by address. If load==1, then
* the in value is loaded into the memory location specified by address
* (the loaded value will be emitted to out from the next time step onward).
*/
CHIP RAM512 {
IN in[16], load, address[9];
OUT out[16];
PARTS:
// Put your code here:
DMux8Way (in=load, sel[2]=address[8], sel[1]=address[7], sel[0]=address[6], a=out1, b=out2, c=out3,
d=out4, e=out5, f=out6, g=out7, h=out8);
RAM64 (in=in, load=out1, address[5]=address[5], address[4]=address[4], address[3]=address[3],
address[2]=address[2], address[1]=address[1], address[0]=address[0], out=outR1);
RAM64 (in=in, load=out2, address[5]=address[5], address[4]=address[4], address[3]=address[3],
address[2]=address[2], address[1]=address[1], address[0]=address[0], out=outR2);
RAM64 (in=in, load=out3, address[5]=address[5], address[4]=address[4], address[3]=address[3],
address[2]=address[2], address[1]=address[1], address[0]=address[0], out=outR3);
RAM64 (in=in, load=out4, address[5]=address[5], address[4]=address[4], address[3]=address[3],
address[2]=address[2], address[1]=address[1], address[0]=address[0], out=outR4);
RAM64 (in=in, load=out5, address[5]=address[5], address[4]=address[4], address[3]=address[3],
address[2]=address[2], address[1]=address[1], address[0]=address[0], out=outR5);
RAM64 (in=in, load=out6, address[5]=address[5], address[4]=address[4], address[3]=address[3],
address[2]=address[2], address[1]=address[1], address[0]=address[0], out=outR6);
RAM64 (in=in, load=out7, address[5]=address[5], address[4]=address[4], address[3]=address[3],
address[2]=address[2], address[1]=address[1], address[0]=address[0], out=outR7);
RAM64 (in=in, load=out8, address[5]=address[5], address[4]=address[4], address[3]=address[3],
address[2]=address[2], address[1]=address[1], address[0]=address[0], out=outR8);
Mux8Way16 (a=outR1, b=outR2, c=outR3, d=outR4, e=outR5, f=outR6, g=outR7, h=outR8, sel[2]=address[8],
sel[1]=address[7], sel[0]=address[6], out=out);
}
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/03/a/Register.hdl
/**
* 16-bit register:
* If load[t] == 1 then out[t+1] = in[t]
* else out does not change
*/
CHIP Register {
IN in[16], load;
OUT out[16];
PARTS:
// Put your code here:
Bit (in=in[0], load=load, out=out[0]);
Bit (in=in[1], load=load, out=out[1]);
Bit (in=in[2], load=load, out=out[2]);
Bit (in=in[3], load=load, out=out[3]);
Bit (in=in[4], load=load, out=out[4]);
Bit (in=in[5], load=load, out=out[5]);
Bit (in=in[6], load=load, out=out[6]);
Bit (in=in[7], load=load, out=out[7]);
Bit (in=in[8], load=load, out=out[8]);
Bit (in=in[9], load=load, out=out[9]);
Bit (in=in[10], load=load, out=out[10]);
Bit (in=in[11], load=load, out=out[11]);
Bit (in=in[12], load=load, out=out[12]);
Bit (in=in[13], load=load, out=out[13]);
Bit (in=in[14], load=load, out=out[14]);
Bit (in=in[15], load=load, out=out[15]);
}
Project 5: computer architecture
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/05/CPU.hdl
/**
* The Hack CPU (Central Processing unit), consisting of an ALU,
* two registers named A and D, and a program counter named PC.
* The CPU is designed to fetch and execute instructions written in
* the Hack machine language. In particular, functions as follows:
* Executes the inputted instruction according to the Hack machine
* language specification. The D and A in the language specification
* refer to CPU-resident registers, while M refers to the external
* memory location addressed by A, i.e. to Memory[A]. The inM input
* holds the value of this location. If the current instruction needs
* to write a value to M, the value is placed in outM, the address
* of the target location is placed in the addressM output, and the
* writeM control bit is asserted. (When writeM==0, any value may
* appear in outM). The outM and writeM outputs are combinational:
* they are affected instantaneously by the execution of the current
* instruction. The addressM and pc outputs are clocked: although they
* are affected by the execution of the current instruction, they commit
* to their new values only in the next time step. If reset==1 then the
* CPU jumps to address 0 (i.e. pc is set to 0 in next time step) rather
* than to the address resulting from executing the current instruction.
*/
CHIP CPU {
IN inM[16], // M value input (M = contents of RAM[A])
instruction[16], // Instruction for execution
reset; // Signals whether to re-start the current
// program (reset==1) or continue executing
// the current program (reset==0).
OUT outM[16], // M value output
writeM, // Write to M?
addressM[15], // Address in data memory (of M)
pc[15]; // address of next instruction
PARTS:
// Put your code here:
// PC block.
And (a=instruction[2], b=aluNg, out=pcAndOut1);
And (a=instruction[1], b=aluZr, out=pcAndOut2);
Not (in=aluNg, out=pcNotOut1);
Not (in=aluZr, out=pcNotOut2);
And (a=instruction[0], b=pcNotOut1, out=pcAndOut3);
And (a=pcAndOut3, b=pcNotOut2, out=pcAndOut4);
Or (a=pcAndOut1, b=pcAndOut2, out=pcOrOut1);
Or (a=pcOrOut1, b=pcAndOut4, out=pcOrOut2);
And (a=instruction[15], b=pcOrOut2, out=pcLoad);
PC (in=aRegOut, load= pcLoad, inc=true, reset= reset, out[0..14]=pc);
// Mux16_1 block.
Mux16 (a=instruction, b=aluOut, sel=instruction[15], out=mux16Out1);
// A register block.
Not (in=instruction[15], out=aRegNotOut1);
And (a=instruction[15], b=instruction[5], out=aRegAndOut1);
Or (a=aRegNotOut1, b=aRegAndOut1, out=aRegLoad);
ARegister (in=mux16Out1, load=aRegLoad, out=aRegOut, out[0..14]=addressM);
// D register block.
And (a=instruction[15], b=instruction[4], out=dRegLoad);
DRegister (in=aluOut, load=dRegLoad, out=dRegOut);
// Mux16_2 block.
Mux16 (a=aRegOut, b=inM, sel=instruction[12], out=mux16Out2);
// ALU block.
ALU(x=dRegOut, y=mux16Out2, zx=instruction[11], nx=instruction[10], zy=instruction[9], ny=instruction[8],
f=instruction[7], no=instruction[6], out=aluOut, zr=aluZr, ng=aluNg, out=outM);
// writeM output block.
Not (in=instruction[9], out=wmNotOut1);
And (a=instruction[12], b=instruction[3], out=wmAndOut1);
Not (in=instruction[12], out=wmNotOut2);
Or (a=wmNotOut2, b=wmAndOut1, out=wmOrOut1);
And (a=wmOrOut1, b=instruction[3], out=wmAndOut2);
And (a=wmAndOut2, b=instruction[15], out=writeM);
}
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/05/Memory.hdl
/**
* The complete address space of the Hack computer's memory,
* including RAM and memory-mapped I/O.
* The chip facilitates read and write operations, as follows:
* Read: out(t) = Memory[address(t)](t)
* Write: if load(t-1) then Memory[address(t-1)](t) = in(t-1)
* In words: the chip always outputs the value stored at the memory
* location specified by address. If load==1, the in value is loaded
* into the memory location specified by address. This value becomes
* available through the out output from the next time step onward.
* Address space rules:
* Only the upper 16K+8K+1 words of the Memory chip are used.
* Access to address>0x6000 is invalid. Access to any address in
* the range 0x4000-0x5FFF results in accessing the screen memory
* map. Access to address 0x6000 results in accessing the keyboard
* memory map. The behavior in these addresses is described in the
* Screen and Keyboard chip specifications given in the book.
*/
CHIP Memory {
IN in[16], load, address[15];
OUT out[16];
PARTS:
// Put your code here:
And (a=address[13], b=true, out=andOut1);
And (a=address[14], b=true, out=andOut2);
Not (in=andOut1, out=notOut1);
Not (in=andOut2, out=notOut2);
// RAM
And (a=true, b=notOut2, out=ramAnd1);
And (a=load, b=ramAnd1, out=ramLoad);
RAM16K (in=in, load=ramLoad, address=address[0..13], out=ramOut);
And16 (a[0]=ramAnd1, a[1]=ramAnd1, a[2]=ramAnd1, a[3]=ramAnd1, a[4]=ramAnd1, a[5]=ramAnd1, a[6]=ramAnd1,
a[7]=ramAnd1, a[8]=ramAnd1, a[9]=ramAnd1, a[10]=ramAnd1, a[11]=ramAnd1, a[12]=ramAnd1, a[13]=ramAnd1,
a[14]=ramAnd1, a[15]=ramAnd1, b=ramOut, out=ramFinal);
// SCREEN
And (a=notOut1, b=andOut2, out=scAnd1);
And (a=load, b=scAnd1, out=scLoad);
And16 (a[0]=scAnd1, a[1]=scAnd1, a[2]=scAnd1, a[3]=scAnd1, a[4]=scAnd1, a[5]=scAnd1, a[6]=scAnd1,
a[7]=scAnd1, a[8]=scAnd1, a[9]=scAnd1, a[10]=scAnd1, a[11]=scAnd1, a[12]=scAnd1, a[13]=scAnd1,
a[14]=scAnd1, a[15]=scAnd1, b=scOut, out=scFinal);
Screen (in=in, load=scLoad, address=address[0..12], out=scOut);
// KEYBOARD
Keyboard (out=kbOut);
And (a=andOut1, b=andOut2, out=kbAnd1);
And16 (a[0]=kbAnd1, a[1]=kbAnd1, a[2]=kbAnd1, a[3]=kbAnd1, a[4]=kbAnd1, a[5]=kbAnd1, a[6]=kbAnd1,
a[7]=kbAnd1, a[8]=kbAnd1, a[9]=kbAnd1, a[10]=kbAnd1, a[11]=kbAnd1, a[12]=kbAnd1, a[13]=kbAnd1,
a[14]=kbAnd1, a[15]=kbAnd1, b=kbOut, out=kbFinal);
// OUTPUT
Or16 (a=ramFinal, b=scFinal, out=outFinal1);
Or16 (a=outFinal1, b=kbFinal, out=out);
}
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/05/Computer.hdl
/**
* The HACK computer, including CPU, ROM and RAM.
* When reset is 0, the program stored in the computer's ROM executes.
* When reset is 1, the execution of the program restarts.
* Thus, to start a program's execution, reset must be pushed "up" (1)
* and "down" (0). From this point onward the user is at the mercy of
* the software. In particular, depending on the program's code, the
* screen may show some output and the user may be able to interact
* with the computer via the keyboard.
*/
CHIP Computer {
IN reset;
PARTS:
// Put your code here:
ROM32K (address=pcOut, out=insOut);
CPU (inM=memOut, instruction=insOut, reset=reset, outM=cpuOutM, writeM=cpuWm, addressM=cpuAm, pc=pcOut);
Memory (in=cpuOutM, load=cpuWm, address=cpuAm, out=memOut);
}