Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions nand2tetris/projects/7/Mytests/testPush.vm
Original file line number Diff line number Diff line change
@@ -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
6 changes: 6 additions & 0 deletions nand2tetris/projects/7/Mytests/testStatic.vm
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Testing static

push static 5
push static 6

add
122 changes: 96 additions & 26 deletions nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

import sys
import os
# import importlib

# sys.path.append("C:/Users/Bruger/OneDrive/Dokumenter/GitHub/BuildComputer/nand2tetris/projects/7/VMTranslator")
Expand Down Expand Up @@ -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):
"""
Expand Down Expand Up @@ -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


Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// ---- push {segment} {index} ----
// ---- push constant {index} ----

// addr = segment + i, *SP = *addr, SP++

Expand Down
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
// ---- 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
@{index}
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
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// addr <- i
@{index}
// D <- RAM[addr]
D = M
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// addr <- segmentPointer
@{segmentPointer}
// D <- RAM[addr]
D = M
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// addr <- segmentPointer + i
@{index}
D = A
@{segmentPointer}
A = M
A = D + A
// D <- RAM[addr]
D = M
6 changes: 6 additions & 0 deletions nand2tetris/projects/7/VMTranslator/src/utils/asm/D_eq_i.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// addr <- i

// D = addr

@{index}
D = A
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// addr <- segmentPointer
@{segmentPointer}
// D <- addr
D = A
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// addr <- segmentPointer + i
@{index}
D = A
@{segmentPointer}
// D <- addr
A = M
D = D + A
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// R13 <- D
@R13
M = D
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// RAM[R13] <- RAM[SP]

// D = RAM[SP]
@SP
A = M
D = M

// RAM[13] <- D
@R13
A = M
M = D
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// RAM[SP] = D

@SP
A = M
M = D
3 changes: 3 additions & 0 deletions nand2tetris/projects/7/VMTranslator/src/utils/asm/SPmm.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// SP--
@SP
M = M - 1
3 changes: 3 additions & 0 deletions nand2tetris/projects/7/VMTranslator/src/utils/asm/SPpp.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// SP++
@SP
M = M + 1

This file was deleted.