133 lines
4.9 KiB
Plaintext
133 lines
4.9 KiB
Plaintext
// 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/5/CPU.hdl
|
|
/**
|
|
* The Hack Central Processing unit (CPU).
|
|
* Parses the binary code in the instruction input and executes it according to the
|
|
* Hack machine language specification. In the case of a C-instruction, computes the
|
|
* function specified by the instruction. If the instruction specifies to read a memory
|
|
* value, the inM input is expected to contain this value. If the instruction specifies
|
|
* to write a value to the memory, sets the outM output to this value, sets the addressM
|
|
* output to the target address, and asserts the writeM output (when writeM = 0, any
|
|
* value may appear in outM).
|
|
* If the reset input is 0, computes the address of the next instruction and sets the
|
|
* pc output to that value. If the reset input is 1, sets pc to 0.
|
|
* Note: The outM and writeM outputs are combinational: they are affected by the
|
|
* instruction's execution during the current cycle. The addressM and pc outputs are
|
|
* clocked: although they are affected by the instruction's execution, they commit to
|
|
* their new values only in the next cycle.
|
|
*/
|
|
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:
|
|
|
|
|
|
// Instructions.
|
|
// Decode the instruction bit.
|
|
// i xx a cccccc ddd jjj
|
|
// For C-Instruction the byte is stored as i(opcode) xx(notUsed) a cccccc(a/c = comp) ddd(destination) jjj(jump)
|
|
// i xxxxxxxxxxxxxxx
|
|
// For A-Instruction the i(opcode) is 0 and the rest is the 16(15)-bit value that is stored there.
|
|
|
|
// Decode Instruction
|
|
Not(in=instruction[15], out=isAInstruction); // Flip it and if 1 it's an A Instruction
|
|
And(a=instruction[15], b=true, out=isCInstruction); // Check it with an And static true to check if both 1 then it's C instruction.
|
|
// Don't need decoding for the rest when A instruction.
|
|
// Just use instruction because instruction[15] will always be 0
|
|
// Decode C & Create Wires
|
|
// 1xA
|
|
And(a=instruction[12], b=true , out=a1);
|
|
// 6xC
|
|
And(a=instruction[11], b=true , out=c1);
|
|
And(a=instruction[10], b=true , out=c2);
|
|
And(a=instruction[9], b=true , out=c3);
|
|
And(a=instruction[8], b=true , out=c4);
|
|
And(a=instruction[7], b=true , out=c5);
|
|
And(a=instruction[6], b=true , out=c6);
|
|
// 3xD
|
|
And(a=instruction[5], b=true , out=d1);
|
|
And(a=instruction[4], b=true , out=d2);
|
|
And(a=instruction[3], b=true , out=d3);
|
|
// 3xJ
|
|
And(a=instruction[2], b=true , out=j1);
|
|
And(a=instruction[1], b=true , out=j2);
|
|
And(a=instruction[0], b=true , out=j3);
|
|
|
|
// aluOut is not made yet
|
|
// A Register
|
|
// Should Load from ALU if
|
|
And(a=isCInstruction, b=d1, out=loadAFromALU);
|
|
Mux16(a=instruction, b=aluOut, sel=loadAFromALU,out=aRegIn);
|
|
Or(a=isAInstruction, b=loadAFromALU, out=loadA);
|
|
Register(in=aRegIn,
|
|
load=loadA,
|
|
// Out
|
|
out=aRegOut,
|
|
out[0..14]=addressM
|
|
);
|
|
|
|
// D Register
|
|
And(a=isCInstruction, b=d2, out=loadD);
|
|
Register(in=aluOut, load=loadD, out=dRegOut);
|
|
// a - instruction12 - a1
|
|
// a=0 → use A register
|
|
// a=1 → use M (inM from memory)
|
|
// ALU
|
|
Mux16(a=aRegOut, b=inM , sel=a1 , out=aluYin);
|
|
ALU(x=dRegOut,
|
|
y=aluYin,
|
|
zx=c1, nx=c2, zy=c3, ny=c4 , f=c5 , no=c6 ,
|
|
zr=aluZrOut,
|
|
ng=aluNgOut,
|
|
// Out
|
|
out=aluOut,
|
|
out=outM
|
|
);
|
|
|
|
// IN in[16], reset, load, inc;
|
|
// OUT out[16];
|
|
// inc almost all the time.
|
|
// only when not load. load = jump
|
|
|
|
// JGT
|
|
// not negative and not zero
|
|
Not(in=aluNgOut, out=notAluNgOut);
|
|
Not(in=aluZrOut, out=notAluZrOut);
|
|
And(a=notAluZrOut, b=notAluNgOut , out=isPositive);
|
|
And(a=isPositive, b=j3, out=shouldJumpJGT);
|
|
// JEQ
|
|
// Jump if zero can be checked it zr
|
|
And(a=aluZrOut, b=j2 , out=shouldJumpJEQ);
|
|
// JLT
|
|
// Jump if less than 0
|
|
And(a=aluNgOut, b=j1, out=shouldJumpJLT);
|
|
|
|
// Should Jump
|
|
Or(a=shouldJumpJGT, b=shouldJumpJEQ , out=shouldJumpJGTJEQ);
|
|
Or(a=shouldJumpJGTJEQ , b= shouldJumpJLT, out=hasJumpInstruction );
|
|
|
|
// And C instruction
|
|
And(a=hasJumpInstruction, b=isCInstruction , out=shouldJump);
|
|
|
|
//Inc
|
|
Not(in=shouldJump, out=shouldIncrement);
|
|
|
|
|
|
PC(in=aRegOut, load=shouldJump, inc=shouldIncrement, reset=reset , out[0..14]=pc);
|
|
|
|
// Out
|
|
And(a=isCInstruction, b=d3 , out=writeM);
|
|
}
|