diff --git a/projects/08/FunctionCalls/SimpleFunction/SimpleFunction.asm b/projects/08/FunctionCalls/SimpleFunction/SimpleFunction.asm new file mode 100644 index 0000000..5edfdad --- /dev/null +++ b/projects/08/FunctionCalls/SimpleFunction/SimpleFunction.asm @@ -0,0 +1,98 @@ +(SimpleFunction.test) // function SimpleFunction.test 2 +@SP +A=M +M=D +@SP +M=M+1 +@SP +A=M +M=D +@SP +M=M+1 +@LCL +A=M +D=M +@SP +A=M +M=D +@SP +M=M+1 // end push local 0 (L1) +@LCL // local 1 +D=M +@1 // write 1 to A +D=D+A // D = segment+index +@R13 // save it to R13 +M=D // write @LCL+1 to R13 +@R13 +A=M +D=M +@SP +A=M +M=D +@SP +M=M+1 // end push local 1 (L2) +@SP // ==== add ==== +A=M-1 +D=M +A=A-1 +M=D+M +@SP +M=M-1 // end add (L3) +@SP // ==== not ==== +A=M-1 +D=M +M=!M // end not (L4) +@ARG +A=M +D=M +@SP +A=M +M=D +@SP +M=M+1 // end push argument 0 (L5) +@SP // ==== add ==== +A=M-1 +D=M +A=A-1 +M=D+M +@SP +M=M-1 // end add (L6) +@ARG // argument 1 +D=M +@1 // write 1 to A +D=D+A // D = segment+index +@R13 // save it to R13 +M=D // write @ARG+1 to R13 +@R13 +A=M +D=M +@SP +A=M +M=D +@SP +M=M+1 // end push argument 1 (L7) +@SP // ==== sub ==== +A=M-1 +D=M +A=A-1 +M=M-D +@SP +M=M-1 // end sub (L8) +@ARG +D=M+1 +@SP +M=D // @SP = ARG+1 +@LCL +D=M // D=@LCL +@THAT +MD=D-1 // THAT = LCL-1 +@THIS +MD=D-1 // THIS = LCL-2 +@ARG +MD=D-1 // ARG = LCL-3 +@LCL +MD=D-1 // LCL = LCL-4 +A=D-1 // A = LCL-5 +0;JMP // Jump to *(LCL-5) +@97 +0;JMP diff --git a/projects/08/FunctionCalls/SimpleFunction/SimpleFunction.out b/projects/08/FunctionCalls/SimpleFunction/SimpleFunction.out new file mode 100644 index 0000000..7b5e4c9 --- /dev/null +++ b/projects/08/FunctionCalls/SimpleFunction/SimpleFunction.out @@ -0,0 +1 @@ +| RAM[0] | RAM[1] | RAM[2] | RAM[3] | RAM[4] |RAM[310]| diff --git a/projects/08/ProgramFlow/FibonacciSeries/FibonacciSeries.out b/projects/08/ProgramFlow/FibonacciSeries/FibonacciSeries.out index 304e7c1..e69de29 100644 --- a/projects/08/ProgramFlow/FibonacciSeries/FibonacciSeries.out +++ b/projects/08/ProgramFlow/FibonacciSeries/FibonacciSeries.out @@ -1,2 +0,0 @@ -|RAM[3000]|RAM[3001]|RAM[3002]|RAM[3003]|RAM[3004]|RAM[3005]| -| 0 | 1 | 1 | 2 | 3 | 5 | diff --git a/vm/CodeWriter.php b/vm/CodeWriter.php index 7cc3b21..1ebe311 100644 --- a/vm/CodeWriter.php +++ b/vm/CodeWriter.php @@ -12,6 +12,68 @@ class CodeWriter { $this->fn = null; } + public function writeReturn() { + $this->write([ + // SP=ARG+1 + "@ARG", + "D=M+1", + "@SP", + "M=D // @SP = ARG+1", + // THAT = LCL-1 + "@LCL", + "D=M // D=@LCL", + "@THAT", + "MD=D-1 // THAT = LCL-1", + // THIS = LCL-2 + "@THIS", + "MD=D-1 // THIS = LCL-2", + // ARG = LCL-3 + "@ARG", + "MD=D-1 // ARG = LCL-3", + // LCL = LCL-4 + "@LCL", + "MD=D-1 // LCL = LCL-4", + "A=D-1 // A = LCL-5", + "0;JMP // Jump to *(LCL-5)", + ]); + } + + public function writeFunction($name, $numArgs) { + $this->fn = $name; + $this->write([ + "($name) // function $name $numArgs", + ]); + for($i=0;$i<$numArgs;$i++) { + $this->write([ + "@SP", + "A=M", + "M=D", + "@SP", + "M=M+1" + ]); + } + } + + /** + * Writes the preable to initialize the VM + */ + private function writeInit() { + $this->write([ + "@256", + "D=A", + "@SP", + "M=D // initialized SP to 256", + "@16000", + "D=A", + "@LCL", + "M=D // initialized @LCL to 16000", + "@16500", + "D=A", + "@ARG", + "M=D // initialized @ARG to 16500", + ]); + } + function setInputFileName($inputFileName) { $this->vm = basename($inputFileName, ".vm"); } diff --git a/vm/CommandType.php b/vm/CommandType.php index 5e6178c..6a8b3b4 100644 --- a/vm/CommandType.php +++ b/vm/CommandType.php @@ -5,10 +5,12 @@ namespace captn3m0\NandToTetris; class CommandType { const PUSH = 1; const POP = 2; + // Program Flow Commands const LABEL= 3; const GOTO= 4; const IF= 5; + // Function Calling Commands const FUNC= 6; const RETURN= 7; diff --git a/vm/VMTranslator.php b/vm/VMTranslator.php index 0e79539..5f1c2d8 100644 --- a/vm/VMTranslator.php +++ b/vm/VMTranslator.php @@ -21,6 +21,10 @@ class VMTranslator { $this->writer = new CodeWriter($outputFile); } + /** + * This is the main entry point for the VM Translator + * and starts the translate sequence + */ function translate() { foreach ($this->files as $file) { $parser = new Parser($file); @@ -55,6 +59,16 @@ class VMTranslator { $this->writer->writeGoto($label); break; + case CommandType::FUNC: + $functionName = $parser->arg1(); + $numberOfArgs = $parser->arg2(); + $this->writer->writeFunction($functionName, $numberOfArgs); + break; + + case CommandType::RETURN: + $this->writer->writeReturn(); + break; + default: throw new \Exception("Not Implemented $command", 1); break; @@ -66,6 +80,10 @@ class VMTranslator { $this->writer->close(); } + /** + * Generates an output file name + * for the VM. Same as the Directory.asm + */ private function outputFile() { $dir = dirname($this->files[0]); $name = basename($dir);