[08] Adds support for label and if-goto commands

master
Nemo 3 years ago
parent 91dd0bb102
commit b61d4c4339
  1. 2
      README.md
  2. 94
      projects/08/ProgramFlow/BasicLoop/BasicLoop.asm
  3. 2
      projects/08/ProgramFlow/BasicLoop/BasicLoop.out
  4. 65
      vm/CodeWriter.php
  5. 10
      vm/VMTranslator.php

@ -115,7 +115,7 @@ wc -l file.hack
### Program Flow Commands
- [ ] `BasicLoop.vm`
- [x] `BasicLoop.vm` (93)
- [ ] `Fibonacci.vm`
## Function Calling Commands

@ -0,0 +1,94 @@
@0 // push constant 0
D=A
@SP
A=M
M=D
@SP
M=M+1 // end push constant 0 (L0)
@SP // pop
AM=M-1
D=M
@LCL
A=M // Read @LCL to A (for local 0)
M=D // end pop local 0 (L1)
(__GLOBAL__.LOOP_START) // end label LOOP_START (L2)
@ARG
A=M
D=M
@SP
A=M
M=D
@SP
M=M+1 // end push argument 0 (L3)
@LCL
A=M
D=M
@SP
A=M
M=D
@SP
M=M+1 // end push local 0 (L4)
@SP // ==== add ====
A=M-1
D=M
A=A-1
M=D+M
@SP
M=M-1 // end add (L5)
@SP // pop
AM=M-1
D=M
@LCL
A=M // Read @LCL to A (for local 0)
M=D // end pop local 0 (L6)
@ARG
A=M
D=M
@SP
A=M
M=D
@SP
M=M+1 // end push argument 0 (L7)
@1 // push constant 1
D=A
@SP
A=M
M=D
@SP
M=M+1 // end push constant 1 (L8)
@SP // ==== sub ====
A=M-1
D=M
A=A-1
M=M-D
@SP
M=M-1 // end sub (L9)
@SP // pop
AM=M-1
D=M
@ARG
A=M // Read @ARG to A (for argument 0)
M=D // end pop argument 0 (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__.LOOP_START
D;JNE // end if-goto LOOP_START (L12)
@LCL
A=M
D=M
@SP
A=M
M=D
@SP
M=M+1 // end push local 0 (L13)
@93
0;JMP

@ -0,0 +1,2 @@
| RAM[0] |RAM[256]|
| 257 | 6 |

@ -7,6 +7,9 @@ class CodeWriter {
$this->ic = 0;
$this->sourceLine = 0;
$this->file = fopen($outputFile, "w");
// We aren't inside a function by default
$this->fn = null;
}
function setInputFileName($inputFileName) {
@ -21,6 +24,10 @@ class CodeWriter {
fclose($this->file);
}
/**
* Puts the closing non-terminating
* loop
*/
function close() {
$endJump = $this->ic+1;
$this->write([
@ -29,6 +36,43 @@ class CodeWriter {
]);
}
/**
* Writes label X as (fnlabel)
*/
function writeLabel(String $label) {
$globalLabel = $this->resolveLabel($label);
$this->write([
"($globalLabel) // end label $label (L{$this->sourceLine})",
]);
}
/**
* Generates a unique global label
* by using the current function name
*/
private function resolveLabel(String $label) {
if($this->fn === null)
return "__GLOBAL__.$label";
return $this->fn . $label;
}
/**
* Writes corresponding code for if-goto
* if value == true, goto X
* else keep executing
*/
function writeIf(String $label) {
$globalLabel = $this->resolveLabel($label);
$this->write([
// Read top of the stack to D
'@SP',
'AM=M-1',
'D=M',
"@$globalLabel",
"D;JNE // end if-goto $label (L{$this->sourceLine})",
]);
}
function writeArithmetic(String $command) {
$stackDecrease=true;
// Read top of stack to D
@ -177,7 +221,7 @@ class CodeWriter {
case 'local':
case 'this':
case 'that':
$register = $this->segmentToRegister($segment);
$register = $this->resolveSegmentToRegister($segment);
if ($index !== 0) {
$this->resolveSegmentToR13($segment, $index);
$register = "@R13";
@ -230,7 +274,10 @@ class CodeWriter {
]);
}
private function segmentToRegister(String $segment) {
/**
* Resolves a given segment to a register
*/
private function resolveSegmentToRegister(String $segment) {
return [
'local' => '@LCL',
'argument' => '@ARG',
@ -239,8 +286,13 @@ class CodeWriter {
][$segment];
}
/**
* For cases where we need calculations on both LHS and RHS, we temporarily
* store the resolved address of the memory segment to R13. This is the code
* that does that
*/
private function resolveSegmentToR13(string $segment, Int $index) {
$register = $this->segmentToRegister($segment);
$register = $this->resolveSegmentToRegister($segment);
$this->write([
"$register // $segment $index" ,
"D=M",
@ -251,6 +303,10 @@ class CodeWriter {
]);
}
/**
* Static variables are just the same labels repeated again
* They are unique across a file
*/
private function resolveStatic(Int $index) {
return "@{$this->vm}.$index";
}
@ -266,7 +322,7 @@ class CodeWriter {
$this->resolveSegmentToR13($segment, $index);
$lookupRegister = '@R13';
} else{
$lookupRegister = $this->segmentToRegister($segment);
$lookupRegister = $this->resolveSegmentToRegister($segment);
}
$this->write([
@ -312,6 +368,7 @@ class CodeWriter {
"M=D // end pop temp $index (L{$this->sourceLine})"
]);
break;
default:
throw new \Exception("Not implemented pop $segment");
break;

@ -40,6 +40,16 @@ class VMTranslator {
$this->writer->writePushPop($commandType, $segment, $index);
break;
case CommandType::LABEL:
$label = $parser->arg1();
$this->writer->writeLabel($label);
break;
case CommandType::IF:
$label = $parser->arg1();
$this->writer->writeIf($label);
break;
default:
throw new \Exception("Not Implemented $command", 1);
break;

Loading…
Cancel
Save