From c1cac6ad6f595de52702bee485550f6c1648e291 Mon Sep 17 00:00:00 2001 From: Nemo Date: Mon, 1 Jun 2020 19:49:55 +0530 Subject: [PATCH] [07] Initial work on VM Translator --- NOTES.md | 4 + .../StackArithmetic/SimpleAdd/SimpleAdd.out | 1 + vm/README.md | 37 +++++ vm/VMTranslator.php | 139 ++++++++++++++++++ 4 files changed, 181 insertions(+) create mode 100644 projects/07/StackArithmetic/SimpleAdd/SimpleAdd.out create mode 100644 vm/README.md create mode 100644 vm/VMTranslator.php diff --git a/NOTES.md b/NOTES.md index 3d0f595..7fa5552 100644 --- a/NOTES.md +++ b/NOTES.md @@ -64,3 +64,7 @@ The hardest part about this was deciding what name to give to all the pins ## Assembler I think there are definitely some tricks with reducing lookup table sizes, but I wasn't really aiming for performance (I wrote it in ruby afterall). Also working on a rust implementation, just to learn rust. + +# VM (1) + +See `vm/README.md` for more details. Observations go here, implementation notes are there. diff --git a/projects/07/StackArithmetic/SimpleAdd/SimpleAdd.out b/projects/07/StackArithmetic/SimpleAdd/SimpleAdd.out new file mode 100644 index 0000000..0af1ac8 --- /dev/null +++ b/projects/07/StackArithmetic/SimpleAdd/SimpleAdd.out @@ -0,0 +1 @@ +| RAM[0] | RAM[256] | diff --git a/vm/README.md b/vm/README.md new file mode 100644 index 0000000..5975f86 --- /dev/null +++ b/vm/README.md @@ -0,0 +1,37 @@ +# VM Implementation + +We have 8 segments: + +- `argument` +- `local` +- `this/that` +- `pointer` +- `static` (shared) +- `constant` (shared) +- `temp` (shared) + +RAM Address | Usage +============|================= +0-15 | Virtual Registers +16-255 | Static Variables (shared) +256-2047 | Stack +2048-16384 | Heap +16384-24575 | Memory mapped I/O + +Register | Name | Usage +==========|========|========= +`RAM[0]` | `SP` | Stack Pointer +`RAM[1]` | `LCL` | `local` +`RAM[1]` | `ARG` | `argument` +`RAM[3]` | `THIS` | `this` +`RAM[4]` | `THAT` | `that` +RAM[5-12] | `temp` Segment +RAM[13-15]| General Purpose Registers + + +The implementation is written in Modern PHP with static typing. Uses the following 3 classes + +- `CommandType` as a Enum for using command types as constants +- `Parser`, mostly as defined in the specification +- `CodeWriter`, mostly as defined in the specification +- `VMTranslator` which combines the above diff --git a/vm/VMTranslator.php b/vm/VMTranslator.php new file mode 100644 index 0000000..24bc6f3 --- /dev/null +++ b/vm/VMTranslator.php @@ -0,0 +1,139 @@ +file = fopen($inputFile, "r"); + } + + function arg1() { + assert($this->command !== CommandType::RETURN); + + return $this->pieces[1]; + } + + function arg2() { + assert(in_array($this->command, [CommandType::PUSH, CommandType::POP, CommandType::FUNC, CommandType::CALL])); + return $this->pieces[2]; + } + + private function stripComment(String $line ) { + $index = strpos($line, '//'); + if ($index == 0) { + return ''; + } + if ($index !== false) { + return substr($line, 0, $index-1); + } else { + return $line; + } + } + + function commands() { + while(!feof($this->file)) { + $line = fgets($this->file); + $line = $this->stripComment(trim($line)); + if (empty($line)) continue; + + $this->pieces = explode(" ", $line); + $this->command = $pieces[0]; + yield $this->command; + } + fclose($this->file); + } +} + +class CodeWriter { + function __construct($outputFile) { + $this->file = fopen($outputFile, "w"); + } + + function writeArithmetic(String $command ) { + throw new Exception("Not yet Implemented"); + } + + function writePushPop(Int $command, String $segment , Int $index) { + throw new Exception("Not yet Implemented"); + } + + function close() { + throw new Exception("Not yet Implemented"); + } +} + + +class VMTranslator { + function __construct(String $fileOrDir ) { + if (is_dir($fileOrDir)) { + $this->files = glob("$fileOrDir/*.vm"); + } else { + $this->files = [$fileOrDir]; + } + + foreach ($this->files as $file) { + assert(is_readable($file)); + } + + $outputFile = $this->outputFile(); + $this->writer = new CodeWriter($outputFile); + } + + function translate() { + foreach ($this->files as $file) { + $parser = new Parser($file); + + foreach ($parser->commands() as $command) { + switch ($command) { + case CommandType::ARITHMETIC: + $this->writer->writeArithmetic($command); + break; + + case CommandType::PUSH: + case CommandType::POP: + $segment = $parser->arg1(); + $index = $parser->arg2(); + $this->writer->writePushPop($command, $parser, $index); + break; + + default: + throw new Exception("Not Implemented", 1); + break; + } + } + } + } + + private function outputFile() { + return '/tmp/file.asm'; + } +} + + +if(isset($argv[1])) { + $vmt = new VMTranslator($argv[1]); + $vmt->translate(); +}