diff --git a/nand2tetris/projects/7/Mytests/testPush.vm b/nand2tetris/projects/7/Mytests/testPush.vm new file mode 100644 index 0000000..753a3e5 --- /dev/null +++ b/nand2tetris/projects/7/Mytests/testPush.vm @@ -0,0 +1,9 @@ + + +push constant 2 +push local 3 +push argument 4 +push this 0 +push that 0 +push pointer 0 +push static 5 \ No newline at end of file diff --git a/nand2tetris/projects/7/Mytests/testStatic.vm b/nand2tetris/projects/7/Mytests/testStatic.vm new file mode 100644 index 0000000..a14dda1 --- /dev/null +++ b/nand2tetris/projects/7/Mytests/testStatic.vm @@ -0,0 +1,6 @@ +// Testing static + +push static 5 +push static 6 + +add diff --git a/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py b/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py index 0d983fb..c901d81 100644 --- a/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py +++ b/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py @@ -1,5 +1,5 @@ -import sys +import os # import importlib # sys.path.append("C:/Users/Bruger/OneDrive/Dokumenter/GitHub/BuildComputer/nand2tetris/projects/7/VMTranslator") @@ -57,56 +57,122 @@ def writeArithmetic(self, command : str) -> None: return lines - - - def writePushPop(self, command : str, segment : str, index : int): + def writePushPop(self, command : str, segment : str, index : int, filename : str = ""): """ Arguments ---- command : ('C_PUSH' or 'C_POP') segment : constant, local etc. index : pointer number in the segment + filename: Name of file - used for push/pop static i Function ---- Writes to the output file the assembly code that implements the given command, where command is either C_PUSH or C_POP. + + If push/pop static i from filename.vm, convert to push/pop filename.i """ segmentPointer = None ## Initialize - passed to self.processCommands but not always used. + lines = [] ## Initialize lines. - ## First handle 'pointer' logic translation to THIS/THAT - if segment == "pointer": + ## Raise errors: + + ## Wrong command + if command not in ["C_PUSH", "C_POP"]: + raise ValueError(f"command: '{command}' not allowed for writePushPop. Only takes 'C_PUSH' or 'C_POP'.") + ## First handle 'pointer' logic translation to THIS/THAT + ## Also handle temp out of bounds. + ## Also raise error if trying to pop constant + + if segment == "temp" and (not 0 <= index < 7): + raise ValueError(f"'temp' segment only valid for index values 0 to 7. Input: {index}.") + elif command == "C_POP" and segment == "constant": + raise ValueError("Cannot pop constant.") + + ## New if-block + if segment == "static": + if filename == "": + raise ValueError(f"No filename supplied for push/pop static.") + file = os.path.splitext(os.path.basename(filename))[0] + index = file + "." + str(index) + + if command == "C_PUSH": + # addr <- filename.index + # D <- RAM[addr] + lines.extend(self.processAsm("D_eq_RAM_i.asm", index = index)) + else: # command == "C_POP" + # addr <- filename.index + lines.extend(self.processAsm("D_eq_i.asm", index = index)) + + elif segment == "constant": + # D <- addr + lines.extend(self.processAsm("D_eq_i.asm", index = index)) + + elif segment == "temp": + # addr <- 5 + index + # D <- addr + index += dicts.segment[segment] + + if command == "C_PUSH": + lines.extend(self.processAsm("D_eq_RAM_i.asm", index = index)) + else: # command == "C_POP" + lines.extend(self.processAsm("D_eq_i.asm", index = index)) + + elif segment == "pointer": + if index not in [0, 1]: + raise ValueError(f"push/pop pointer only valid for value 0 or 1. Input: {index}.") segment = ["this", "that"][index] ## e.g. 'push pointer 0' means 'push this' + segmentPointer = dicts.segment[segment] index = 0 ## Silently 'push THIS' means 'push THIS 0' + if command == "C_PUSH": + lines.extend(self.processAsm("D_eq_RAM_segmentPointer.asm", segmentPointer = segmentPointer)) + else: # command == "C_POP" + lines.extend(self.processAsm("D_eq_segmentPointer.asm", segmentPointer = segmentPointer)) + + elif segment in dicts.segment.keys(): + ## Used in some of the .asm templates. + ## Contains Hack name convention for segments, e.g. local is "LCL" + segmentPointer = dicts.segment[segment] + + if command == "C_PUSH": + # addr <- segmentPointer + index + # D <- RAM[addr] + lines.extend(self.processAsm("D_eq_RAM_segmentPointer_p_i.asm",index = index, segmentPointer = segmentPointer)) + else: #command == "C_POP": + # D <- addr + lines.extend(self.processAsm("D_eq_segmentPointer_p_i.asm", index = index, segmentPointer = segmentPointer)) + else: + raise ValueError(f"Segment = '{segment}' not handled.") + if command == "C_PUSH": + ## RAM[SP] <- D + ## SP++ + lines.extend(self.processAsm("RAM_SP_eq_D.asm")) + lines.extend(self.processAsm("SPpp.asm")) + elif command == "C_POP": if segment == "constant": - asm_location = "pushConstant.asm" - elif segment in ["local", "argument", "this", "that", "temp"]: - ## Used in some of the .asm templates. - ## Contains Hack name convention for segments, e.g. local is "LCL" - segmentPointer = dicts.segment[segment] - asm_location = "pushSegment.asm" - elif segment == "static": - asm_location = "pushStatic.asm" - # elif segment == "temp": - # ... - # elif segment == "pointer": ## Handled above - # ... - # elif command == "C_POP": - # ... + raise ValueError("Cannot pop constant.") + + ## SP-- + # R13 <- D # R13_eq_D.asm + # RAM[R13] <- RAM[SP] # RAM_R13_eq_RAM_SP.asm + lines.extend(self.processAsm("SPmm.asm")) + lines.extend(self.processAsm("R13_eq_D.asm")) + lines.extend(self.processAsm("RAM_R13_eq_RAM_SP.asm")) + + + else: raise KeyError(f"Unexpected command '{command}' in writePushPop (should be 'C_PUSH' or 'C_POP')") - lines = [] ## Initialize lines. - with open(f"src/utils/asm/{asm_location}", 'r') as asm: - parser = self.Parser(asm) - - lines = self.processCommands(parser, segment = segment, segmentPointer = segmentPointer, index = index) return lines + + def processCommands(self, parser, **kwargs): """ @@ -135,6 +201,10 @@ def processCommands(self, parser, **kwargs): return lines - + def processAsm(self, asm_file : str, **kwargs): + with open(f"src/utils/asm/{asm_file}", 'r') as asm: + parser = self.Parser(asm) + lines = self.processCommands(parser, **kwargs) + return lines \ No newline at end of file diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/asm/add.asm b/nand2tetris/projects/7/VMTranslator/src/utils/asm/Archive/add.asm similarity index 100% rename from nand2tetris/projects/7/VMTranslator/src/utils/asm/add.asm rename to nand2tetris/projects/7/VMTranslator/src/utils/asm/Archive/add.asm diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/asm/popSegment.asm b/nand2tetris/projects/7/VMTranslator/src/utils/asm/Archive/popSegment.asm similarity index 100% rename from nand2tetris/projects/7/VMTranslator/src/utils/asm/popSegment.asm rename to nand2tetris/projects/7/VMTranslator/src/utils/asm/Archive/popSegment.asm diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/asm/pushConstant.asm b/nand2tetris/projects/7/VMTranslator/src/utils/asm/Archive/pushConstant.asm similarity index 86% rename from nand2tetris/projects/7/VMTranslator/src/utils/asm/pushConstant.asm rename to nand2tetris/projects/7/VMTranslator/src/utils/asm/Archive/pushConstant.asm index a1eda4a..c048c09 100644 --- a/nand2tetris/projects/7/VMTranslator/src/utils/asm/pushConstant.asm +++ b/nand2tetris/projects/7/VMTranslator/src/utils/asm/Archive/pushConstant.asm @@ -1,4 +1,4 @@ -// ---- push {segment} {index} ---- +// ---- push constant {index} ---- // addr = segment + i, *SP = *addr, SP++ diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/asm/Archive/pushSegment.asm b/nand2tetris/projects/7/VMTranslator/src/utils/asm/Archive/pushSegment.asm new file mode 100644 index 0000000..0bd9542 --- /dev/null +++ b/nand2tetris/projects/7/VMTranslator/src/utils/asm/Archive/pushSegment.asm @@ -0,0 +1,36 @@ +// ---- push {segment} {index} ---- + +// addr = segment + i, *SP = *addr, SP++ + +// If segment is constant: +// addr <- i +// If segment is static: +// addr <- i +// Else: +// addr <- segmentPointer + i + + +// i or file.i +@{index} + + +// if segment not in ["constant", "static"]: +// D = A +// @{segmentPointer} +// A = D + A + +// if segment == "constant": +// D = A +// else: +// D = RAM[addr] +// D = M + + +// RAM[SP] = RAM[addr] +@SP +A = M +M = D + +// SP++ +@SP +M = M + 1 \ No newline at end of file diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/asm/pushSegment.asm b/nand2tetris/projects/7/VMTranslator/src/utils/asm/Archive/pushStatic.asm similarity index 53% rename from nand2tetris/projects/7/VMTranslator/src/utils/asm/pushSegment.asm rename to nand2tetris/projects/7/VMTranslator/src/utils/asm/Archive/pushStatic.asm index 7caa1a2..aa8501d 100644 --- a/nand2tetris/projects/7/VMTranslator/src/utils/asm/pushSegment.asm +++ b/nand2tetris/projects/7/VMTranslator/src/utils/asm/Archive/pushStatic.asm @@ -1,6 +1,13 @@ -// ---- push {segment} {index} ---- +// ---- push static {index} ---- -// addr = segment + i, *SP = *addr, SP++ +// addr = Foo.i, *SP = *addr, SP++ + +@{index} +D = A + +@{segmentPointer} +A = D + A +D = A // addr <- SegmentPointer + i @@ -8,9 +15,9 @@ D = A // Not used if segment is 'constant' -@{segmentPointer} -A = D + M -D = M +// @{segmentPointer} +// A = D + M +// D = M // RAM[SP] = RAM[addr] @SP diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/asm/D_eq_RAM_i.asm b/nand2tetris/projects/7/VMTranslator/src/utils/asm/D_eq_RAM_i.asm new file mode 100644 index 0000000..1598659 --- /dev/null +++ b/nand2tetris/projects/7/VMTranslator/src/utils/asm/D_eq_RAM_i.asm @@ -0,0 +1,4 @@ +// addr <- i +@{index} +// D <- RAM[addr] +D = M \ No newline at end of file diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/asm/D_eq_RAM_segmentPointer.asm b/nand2tetris/projects/7/VMTranslator/src/utils/asm/D_eq_RAM_segmentPointer.asm new file mode 100644 index 0000000..3f1e048 --- /dev/null +++ b/nand2tetris/projects/7/VMTranslator/src/utils/asm/D_eq_RAM_segmentPointer.asm @@ -0,0 +1,4 @@ +// addr <- segmentPointer +@{segmentPointer} +// D <- RAM[addr] +D = M \ No newline at end of file diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/asm/D_eq_RAM_segmentPointer_p_i.asm b/nand2tetris/projects/7/VMTranslator/src/utils/asm/D_eq_RAM_segmentPointer_p_i.asm new file mode 100644 index 0000000..6a9518c --- /dev/null +++ b/nand2tetris/projects/7/VMTranslator/src/utils/asm/D_eq_RAM_segmentPointer_p_i.asm @@ -0,0 +1,8 @@ +// addr <- segmentPointer + i +@{index} +D = A +@{segmentPointer} +A = M +A = D + A +// D <- RAM[addr] +D = M \ No newline at end of file diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/asm/D_eq_i.asm b/nand2tetris/projects/7/VMTranslator/src/utils/asm/D_eq_i.asm new file mode 100644 index 0000000..0e58833 --- /dev/null +++ b/nand2tetris/projects/7/VMTranslator/src/utils/asm/D_eq_i.asm @@ -0,0 +1,6 @@ +// addr <- i + +// D = addr + +@{index} +D = A \ No newline at end of file diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/asm/D_eq_segmentPointer.asm b/nand2tetris/projects/7/VMTranslator/src/utils/asm/D_eq_segmentPointer.asm new file mode 100644 index 0000000..b872787 --- /dev/null +++ b/nand2tetris/projects/7/VMTranslator/src/utils/asm/D_eq_segmentPointer.asm @@ -0,0 +1,4 @@ +// addr <- segmentPointer +@{segmentPointer} +// D <- addr +D = A \ No newline at end of file diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/asm/D_eq_segmentPointer_p_i.asm b/nand2tetris/projects/7/VMTranslator/src/utils/asm/D_eq_segmentPointer_p_i.asm new file mode 100644 index 0000000..5d92df0 --- /dev/null +++ b/nand2tetris/projects/7/VMTranslator/src/utils/asm/D_eq_segmentPointer_p_i.asm @@ -0,0 +1,7 @@ +// addr <- segmentPointer + i +@{index} +D = A +@{segmentPointer} +// D <- addr +A = M +D = D + A diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/asm/R13_eq_D.asm b/nand2tetris/projects/7/VMTranslator/src/utils/asm/R13_eq_D.asm new file mode 100644 index 0000000..3c4eac3 --- /dev/null +++ b/nand2tetris/projects/7/VMTranslator/src/utils/asm/R13_eq_D.asm @@ -0,0 +1,3 @@ +// R13 <- D +@R13 +M = D \ No newline at end of file diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/asm/RAM_D_eq_RAM_SP.asm b/nand2tetris/projects/7/VMTranslator/src/utils/asm/RAM_D_eq_RAM_SP.asm new file mode 100644 index 0000000..6c68d3f --- /dev/null +++ b/nand2tetris/projects/7/VMTranslator/src/utils/asm/RAM_D_eq_RAM_SP.asm @@ -0,0 +1,15 @@ +// RAM[D] <- RAM[SP] +// Store D in R13 +// i.e. *R13 = D + + +@R13 +M = D +// D = RAM[SP] +@SP +A = M +D = M +// *R13 +@R13 +A = M +M = D \ No newline at end of file diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/asm/RAM_R13_eq_RAM_SP.asm b/nand2tetris/projects/7/VMTranslator/src/utils/asm/RAM_R13_eq_RAM_SP.asm new file mode 100644 index 0000000..ad65028 --- /dev/null +++ b/nand2tetris/projects/7/VMTranslator/src/utils/asm/RAM_R13_eq_RAM_SP.asm @@ -0,0 +1,11 @@ +// RAM[R13] <- RAM[SP] + +// D = RAM[SP] +@SP +A = M +D = M + +// RAM[13] <- D +@R13 +A = M +M = D \ No newline at end of file diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/asm/RAM_SP_eq_D.asm b/nand2tetris/projects/7/VMTranslator/src/utils/asm/RAM_SP_eq_D.asm new file mode 100644 index 0000000..cfd692d --- /dev/null +++ b/nand2tetris/projects/7/VMTranslator/src/utils/asm/RAM_SP_eq_D.asm @@ -0,0 +1,5 @@ +// RAM[SP] = D + +@SP +A = M +M = D \ No newline at end of file diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/asm/SPmm.asm b/nand2tetris/projects/7/VMTranslator/src/utils/asm/SPmm.asm new file mode 100644 index 0000000..d3ac680 --- /dev/null +++ b/nand2tetris/projects/7/VMTranslator/src/utils/asm/SPmm.asm @@ -0,0 +1,3 @@ +// SP-- +@SP +M = M - 1 \ No newline at end of file diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/asm/SPpp.asm b/nand2tetris/projects/7/VMTranslator/src/utils/asm/SPpp.asm new file mode 100644 index 0000000..9bf79cb --- /dev/null +++ b/nand2tetris/projects/7/VMTranslator/src/utils/asm/SPpp.asm @@ -0,0 +1,3 @@ +// SP++ +@SP +M = M + 1 \ No newline at end of file diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/asm/pushStatic.asm b/nand2tetris/projects/7/VMTranslator/src/utils/asm/pushStatic.asm deleted file mode 100644 index e446c63..0000000 --- a/nand2tetris/projects/7/VMTranslator/src/utils/asm/pushStatic.asm +++ /dev/null @@ -1,2 +0,0 @@ -// push static i -