------------------------------------------------------------------ push constant [number] ------------------------------------------------------------------ RAM[SP] = [number] SP += 1 @[number] D=A @SP M=M+1 A=M-1 M=D ------------------------------------------------------------------ push [argument/local/this/that] [number] ------------------------------------------------------------------ RAM[SP] = RAM[ARG/LCL/THIS/THAT + number] SP += 1 @[number] D=A @[ARG for argument, LCL for local, THIS for this, THAT for that] A=M+D D=M @SP M=M+1 A=M-1 M=D ------------------------------------------------------------------ push [static/pointer/temp] [number ------------------------------------------------------------------ RAM[SP] = RAM[16/3/5 + number] SP += 1 @[number] D=A @[16 for static, 3 for pointer, 5 for temp] A=A+D D=M @SP M=M+1 A=M-1 M=D ------------------------------------------------------------------ pop [argument/local/this/that] [number] ------------------------------------------------------------------ SP -= 1 RAM[ARG/LCL/THIS/THAT + number] = RAM[SP] @[number] D=A @[ARG for argument, LCL for local, THIS for this, THAT for that] A=M+D D=A @R13 M=D // Now R13 contains the address we want to pop into @SP M=M-1 A=M D=M // Now we have decremented SP and stored the value we want to pop in D @R13 A=M M=D ------------------------------------------------------------------ pop [static/pointer/temp] [number] ------------------------------------------------------------------ SP -= 1 RAM[256/3/8 + number] = RAM[SP] @[number] D=A @[256 for static, 3 for pointer, 8 for temp] A=A+D D=A @R13 M=D // Now R13 contains the address we want to pop into @SP M=M-1 A=M D=M // Now we have decremented SP and stored the value we want to pop in D @R13 A=M M=D ------------------------------------------------------------------ add/sub/and/or ------------------------------------------------------------------ SP -= 1 RAM[SP-1] = RAM[SP-1] [+/-/&/|] RAM[SP] @SP M=M-1 A=M D=M @SP A=M-1 [M=M+D for add, M=M-D for sub, M=M&D for and, M=M|D for or] ------------------------------------------------------------------ neg/not ------------------------------------------------------------------ RAM[SP-1] = [- or !] RAM[SP-1] @SP A=M-1 [D=-M for neg, D=!M for not] M=D ------------------------------------------------------------------ eq/lt/gt ------------------------------------------------------------------ SP -= 1 If RAM[SP-1] [< or == or >] RAM[SP] then RAM[SP-1] = -1, else RAM[SP-1] = 0. @SP M=M-1 A=M D=M @SP A=M-1 D=D-M // D now contains RAM[SP-1] - RAM[SP-2], and SP has been decremented @[unused label 1] [D;JEQ for ==, D;JGT for <, D;JLT for >] @SP // If we are here then RAM[SP-2] != RAM[SP-1], so write 0x0000 to RAM[SP-2] A=M-1 M=0 @[unused label 2] 0;JMP ([unused label 1]) @SP A=M-1 M=-1 // If we are here then RAM[SP-2] == RAM[SP-1], so write 0xFFFF to RAM[SP-2] ([unused label 2]) ------------------------------------------------------------------ label [label name] ------------------------------------------------------------------ (manual$[filename]$[label name]) [Here we can pick basically any format we like, the point is just to make sure that a) two Hack VM labels in different files with the same name get mapped to two different Hack assembly labels and b) none of the Hack assembly labels we create in compiling other statements clash have the same name as this label and c) label uses the same format as goto and if-goto.) ------------------------------------------------------------------ goto [label name] ------------------------------------------------------------------ @manual$[filename]$[label name] 0;JMP ------------------------------------------------------------------ if-goto [label name] ------------------------------------------------------------------ SP -= 1 If RAM[SP] != 0, jump to the label @SP M=M-1 A=M D=M @manual$[filename]$[label name] D;JNE ------------------------------------------------------------------ call [function name] [number] ------------------------------------------------------------------ RAM[SP] = Return address RAM[SP+1] = LCL RAM[SP+2] = ARG RAM[SP+3] = THIS RAM[SP+4] = THAT ARG = SP-[number] LCL = SP+5 Jump to function Return label @[Unused label] // Push call frame to stack D=A @SP A=M M=D @LCL D=M @SP A=M+1 M=D @ARG D=M @SP A=M+1 A=A+1 M=D @THIS D=M @SP A=M+1 A=A+1 A=A+1 M=D @THAT D=M @SP A=M+1 A=A+1 A=A+1 A=A+1 M=D D=A+1 // Update LCL @LCL M=D @SP // Update ARG D=M @[number] D=D-A @ARG M=D @(call$[function name]) // Jump to function 0;JMP ([Same unused label]) // Return label [Again we can use any format we like for the (call$[function name]) label as long as a) no two functions get the same name, b) they don't clash with any of the other labels we make and c) call and function use the same format.] ------------------------------------------------------------------ function [function name] [number] ------------------------------------------------------------------ Function label RAM[SP]=0 RAM[SP+1]=0 ... RAM[SP+[number-1]]=0 SP += number + 1 (call$[function name]) // Function label @R13 // Initialise local segment via loop M=0 // (NB this is horribly slow, especially for small local segments!) ([unused label 1]) // Here R13 stores the i for which we're initialising local i @R13 D=M @[number] D=D-A @[unused label 2] D;JEQ @R13 D=M M=M+1 @LCL A=M+D M=0 @[unused label 1] 0;JMP ([unused label 2]) @[number] // Set SP D=A @LCL D=M+D @SP M=D ------------------------------------------------------------------ return ------------------------------------------------------------------ R13 = RAM[LCL-5] RAM[ARG] = RAM[SP] THAT = RAM[LCL-1] THIS = RAM[LCL-2] ARG = RAM[LCL-3] LCL = RAM[LCL-4] Jump to R13 @5 // Store return address in R13 D=A @LCL A=M-D D=M @R13 M=D @SP // Copy return value to argument 0, NB this may overwrite A=M-1 // return address if argument has length 0 D=M @ARG A=M M=D D=A+1 // Update SP @SP M=D @LCL // Restore THAT A=M-1 D=M @THAT M=D @LCL // Restore THIS A=M-1 A=A-1 D=M @THIS M=D @3 // Restore ARG D=A @LCL A=M-D D=M @ARG M=D @4 // Restore LCL D=A @LCL A=M-D D=M @LCL M=D @R13 // Jump to return address A=M 0;JMP