From Nand to Tetris(Nand2tetris) Project 5

  1. Instruction. CPU can take address instruction and computing instruction, so how do we distinguish them? Remember all the instructions, data, or label are all represented by a 16 bit binary number. Noam and Shimon decided to use the first bit from left to right to represent the type of instruction. If the first bit is zero then it’s an address instruction, otherwise it’s a computing instruction. For example:
0000 0000 0000 0001 will be translated into @1, this is an A-instruction.
1000 0000 0000 0001 will be translated into D&A;JGT, and this is a C-instruction.
  1. outM: the result of the previous cycle of computation.
  2. writeM: the load bit deciding whether we write to RAM or not.
  3. addressM: the location of the the RAM slot that we want to write to.
  4. PC: program counter, it could take a 16 bit data as input, and it has 3 load bits: inc, reset, load. this PC register is deciding which line of code to process, and if we reset the PC, all the program will be terminated and we are back to line 0.
a more detailed version of CPU
CHIP CPU {     IN  inM[16],         // M value input  (M = contents of RAM[A])
instruction[16], // Instruction for execution
reset; // Signals whether to re-start
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: //ARegister Not(in=instruction[15], out=aload); And(a=instruction[15], b=instruction[5], out=instructionloadA); /** the first bit(instruction[15] and d1(instruction[5] is deciding whether we save the value to A-Regis, if the first bit is 1 and instruction[5] is 1, we are going to save the output to A-Register, because in the instruction, d1(instruction[5]) is deciding where to store value's when it is a C-Instruction. if the first bit is 0, no matter what, we will save the input to A-Register.*/ Or(a=aload, b=instructionloadA, out=aregload); ARegister(in=mux1out, load=aregload, out=aregisterout, out[0..14]=addressM); //DRegister And(a=instruction[15], b=instruction[4], out=dregload);
/** only if the first bit is 1, and d2(instruction[4] is 1, then we save to D register */
DRegister(in=aluOut, load=dregload, out=alux); //Mux1: the reason why we need this is for situations like A=A+1, to make it simple I'm testing to see if aload decide the output of Mux1, if Aload=1 means this is an A-instruction, then we will save this value into our a-register, if it is a c instruction, we will use our previous alu output. //*************** REMEMBER: if it's not an A-instruction, we should never let the Mux's sel to take in the value of the instruction.*/ Mux16(a=aluOut, b=instruction, sel=aload, out=mux1out); //Mux2 And(a=instruction[15], b=instruction[12], out=mux2load);
/** only if both of the first bit and the "a" bit is 1, then we start to use the value we get from M, otherwise we will work on A */
Mux16(a=aregisterout, b=inM, sel=mux2load, out=aluy); //ALU /** the load bit of the ALU is decided by instruction[6..11] */
/** I have to say that this design is really elegant, we have two numbers, how could the ALU output 1? well, first, it turns both input into 0, and negate them on the bit level, so both of them will be 1111 1111 1111 1111, and then add them up, we will get a 1111 1111 1111 1110, then we negate it again on the bit level, then we get 0000 0000 0000 0001, which is 1, this is awesome*/
ALU(x=alux, y=aluy, zx=instruction[11], nx=instruction[10], zy=instruction[9], ny=instruction[8], f=instruction[7], no=instruction[6], out=aluOut, out=outM, zr=zr, ng=ng); //PC /** Program Counter is deciding where to jump to */
/** if the j bits(instruction[0..2]) are not 000, we should start to manipulate the PC's load bits */
Jmp(in=instruction, ng=ng, zr=zr, load=pcload, inc=inc); PC(in=aregisterout, load=pcload, inc=inc, reset=reset, out[0..14]=pc); //WriteM And(a=instruction[3], b=instruction[15], out=writeM);}CHIP Jmp { IN in[16], zr, ng; OUT load, inc; PARTS: Not(in=ng, out=notng); Not(in=zr, out=notzr); //remember notng is not equal to pos!!! And(a=notng, b=notzr, out=pos); And(a=in[0], b=pos, out=checkpositive); And(a=in[1], b=zr, out=checkzero); And(a=in[2], b=ng, out=checknegative); Or(a=checkpositive, b=checkzero, out=positiveorzero); Or(a=positiveorzero, b=checknegative, out=preload); And(a=in[15], b=preload, out=notinc, out=load); Not(in=notinc, out=inc);
/** if the load bit is zero, then inc is 1, else, inc is 0 */
}After we understand the CPU, let's look at the full picture.




Designer transforming into a developer

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Apache Kafka® on Kubernetes®

Model IoT Application For Tracking Kitchen Inventory


Configure Elastic, Enterprise search and Kibana on premise /ubuntu/

My journey into Web3 education

GitHub Alternative with Self Hosted Painless Git-Service

How Much Does Software Testing Cost? 9 Proven Ways to Optimize it.

Hey Docker run EKS, with Auto Fleet Spotting Support, please!

Introduction to DevOps: A beginner’s perspective

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Yizhe Wang

Yizhe Wang

Designer transforming into a developer

More from Medium

𝔠𝔯𝔶𝔭𝔱0ᗯ1ᘔᗩᖇᗪ ’𝓶.𝓣’’ — My 10 Rules for Success:

How to configure IPTV on Enigma2 Easier ?-In 2022

start of LS blog

Activity 02: Drop Cap Love