diff --git a/README.md b/README.md index 6a715d5..0020a04 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,7 @@ wc -l file.hack ### Program Flow Commands - [x] `BasicLoop.vm` (93) -- [ ] `Fibonacci.vm` +- [x] `Fibonacci.vm` (193) ## Function Calling Commands diff --git a/projects/08/ProgramFlow/FibonacciSeries/FibonacciSeries.asm b/projects/08/ProgramFlow/FibonacciSeries/FibonacciSeries.asm new file mode 100644 index 0000000..6059cf7 --- /dev/null +++ b/projects/08/ProgramFlow/FibonacciSeries/FibonacciSeries.asm @@ -0,0 +1,196 @@ +@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 (L0) +@SP // pop +AM=M-1 +D=M +@THAT +M=D // (L1) +@0 // push constant 0 +D=A +@SP +A=M +M=D +@SP +M=M+1 // end push constant 0 (L2) +@SP // pop +AM=M-1 +D=M +@THAT +A=M // Read @THAT to A (for that 0) +M=D // end pop that 0 (L3) +@1 // push constant 1 +D=A +@SP +A=M +M=D +@SP +M=M+1 // end push constant 1 (L4) +@THAT // that 1 +D=M +@1 // write 1 to A +D=D+A // D = segment+index +@R13 // save it to R13 +M=D // write @THAT+1 to R13 +@SP // pop +AM=M-1 +D=M +@R13 +A=M // Read @R13 to A (for that 1) +M=D // end pop that 1 (L5) +@ARG +A=M +D=M +@SP +A=M +M=D +@SP +M=M+1 // end push argument 0 (L6) +@2 // push constant 2 +D=A +@SP +A=M +M=D +@SP +M=M+1 // end push constant 2 (L7) +@SP // ==== sub ==== +A=M-1 +D=M +A=A-1 +M=M-D +@SP +M=M-1 // end sub (L8) +@SP // pop +AM=M-1 +D=M +@ARG +A=M // Read @ARG to A (for argument 0) +M=D // end pop argument 0 (L9) +(__GLOBAL__.MAIN_LOOP_START) // end label MAIN_LOOP_START (L10) +@ARG +A=M +D=M +@SP +A=M +M=D +@SP +M=M+1 // end push argument 0 (L11) +@SP +AM=M-1 +D=M +@__GLOBAL__.COMPUTE_ELEMENT +D;JNE // end if-goto COMPUTE_ELEMENT (L12) +@__GLOBAL__.END_PROGRAM +0;JMP // end goto END_PROGRAM (L13) +(__GLOBAL__.COMPUTE_ELEMENT) // end label COMPUTE_ELEMENT (L14) +@THAT +A=M +D=M +@SP +A=M +M=D +@SP +M=M+1 // end push that 0 (L15) +@THAT // that 1 +D=M +@1 // write 1 to A +D=D+A // D = segment+index +@R13 // save it to R13 +M=D // write @THAT+1 to R13 +@R13 +A=M +D=M +@SP +A=M +M=D +@SP +M=M+1 // end push that 1 (L16) +@SP // ==== add ==== +A=M-1 +D=M +A=A-1 +M=D+M +@SP +M=M-1 // end add (L17) +@THAT // that 2 +D=M +@2 // write 2 to A +D=D+A // D = segment+index +@R13 // save it to R13 +M=D // write @THAT+2 to R13 +@SP // pop +AM=M-1 +D=M +@R13 +A=M // Read @R13 to A (for that 2) +M=D // end pop that 2 (L18) +@THAT // pointer 1 +D=M +@SP +A=M +M=D +@SP +M=M+1 // end push pointer 1 (L19) +@1 // push constant 1 +D=A +@SP +A=M +M=D +@SP +M=M+1 // end push constant 1 (L20) +@SP // ==== add ==== +A=M-1 +D=M +A=A-1 +M=D+M +@SP +M=M-1 // end add (L21) +@SP // pop +AM=M-1 +D=M +@THAT +M=D // (L22) +@ARG +A=M +D=M +@SP +A=M +M=D +@SP +M=M+1 // end push argument 0 (L23) +@1 // push constant 1 +D=A +@SP +A=M +M=D +@SP +M=M+1 // end push constant 1 (L24) +@SP // ==== sub ==== +A=M-1 +D=M +A=A-1 +M=M-D +@SP +M=M-1 // end sub (L25) +@SP // pop +AM=M-1 +D=M +@ARG +A=M // Read @ARG to A (for argument 0) +M=D // end pop argument 0 (L26) +@__GLOBAL__.MAIN_LOOP_START +0;JMP // end goto MAIN_LOOP_START (L27) +(__GLOBAL__.END_PROGRAM) // end label END_PROGRAM (L28) +@195 +0;JMP diff --git a/projects/08/ProgramFlow/FibonacciSeries/FibonacciSeries.out b/projects/08/ProgramFlow/FibonacciSeries/FibonacciSeries.out new file mode 100644 index 0000000..304e7c1 --- /dev/null +++ b/projects/08/ProgramFlow/FibonacciSeries/FibonacciSeries.out @@ -0,0 +1,2 @@ +|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 5d3511a..7cc3b21 100644 --- a/vm/CodeWriter.php +++ b/vm/CodeWriter.php @@ -56,6 +56,17 @@ class CodeWriter { return $this->fn . $label; } + /** + * Writes a unconditional jump statement + */ + public function writeGoto(String $label) { + $globalLabel = $this->resolveLabel($label); + $this->write([ + "@$globalLabel", + "0;JMP // end goto $label (L{$this->sourceLine})", + ]); + } + /** * Writes corresponding code for if-goto * if value == true, goto X diff --git a/vm/VMTranslator.php b/vm/VMTranslator.php index 06d0c6d..0e79539 100644 --- a/vm/VMTranslator.php +++ b/vm/VMTranslator.php @@ -50,6 +50,11 @@ class VMTranslator { $this->writer->writeIf($label); break; + case CommandType::GOTO: + $label = $parser->arg1(); + $this->writer->writeGoto($label); + break; + default: throw new \Exception("Not Implemented $command", 1); break;