def write_return(): # endFrame = LCL # retAddr = *(endFrame-5) # *ARG = pop(), sets return value to arg[0] # SP = ARG+1 # endFrame -=1, THAT = *(endFrame) # endFrame -=1, THIS = *(endFrame) # endFrame -=1, ARG = *(endFrame) # endFrame -=1, LCL = *(endFrame) # goto retAddr # ---- implementation ---- # endFrame = LCL output = [at("LCL"), "D=M", at("endFrame"), "M=D"] # retAddr = *(endFrame-5) output += __write_save_retAddr() # *ARG = pop() output += (["// *ARG = pop()"] + pop() + ["D=M", "@ARG", "A=M", "M=D"]) # SP = ARG+1 output += ["// SP = ARG+1", "@ARG", "D=M+1", "@SP", "M=D"] # endFrame -=1, segm_var = *(endFrame) output += __write_restore("THAT") output += __write_restore("THIS") output += __write_restore("ARG") output += __write_restore("LCL") # goto retAddr output += ["// goto retAddr", "@retAddr", "A=M", "0;JMP"] return output
def __write_cmp(jump_type): """Pop 2 items off the stack, compare them, push the result back on""" # pop an item off the stack # D = M # pop another item off the stack # D = D - M # @TRUE_0 # D; JEQ # (FALSE_0) # D = 0 # @END_0 # 0; jump_type # (TRUE_0) # D = 1 # (END_0) # push() if jump_type not in ['EQ', 'GT', 'LT', 'GE', 'LE', 'NE']: raise Exception("Unexpected Jump Type: {0}".format(jump_type)) true_label = unique("TRUE") false_label = unique("FALSE") end_label = unique("END") return (pop() + ['D=M'] + pop() + ['D=M-D', at(true_label), 'D;J{0}'.format(jump_type), '({0})'.format(false_label), 'D=0', at(end_label), '0;JMP', '({0})'.format(true_label), 'D=-1', # -1 == 11111...11 in 2's complement '({0})'.format(end_label)] + push())
def write_pop(segment, i, ftitle=None): """Pop a value from the stack and store it at position i in segment""" # local, argument, this, and that are implemented the same way standard_segs = { "local": "LCL", "argument": "ARG", "this": "THIS", "that": "THAT", } if segment in standard_segs: segname = standard_segs[segment] return ([ at(segname), # addr=segname+i "D=M", at(i), "D=D+A", at('addr'), "M=D" ] + pop() + [ "D=M", at('addr'), # *addr=*SP "A=M", "M=D" ]) elif segment == "temp": return ([ at(5), # temp base address is 5 "D=A", at(i), "D=D+A", at('addr'), "M=D" ] + pop() + [ "D=M", at('addr'), # *addr=*SP "A=M", "M=D" ]) elif segment == "static": label = "{0}.{1}".format(ftitle, i) return pop() + ["D=M", at(label), "M=D"] elif segment == "pointer": if int(i) not in [0, 1]: raise Exception('Invalid i for pop pointer: ' + str(i)) target = "THAT" if int(i) else "THIS" return [ "@SP", # SP-- "M=M-1", "A=M", # THIS/THAT = *SP "D=M", at(target), "M=D" ] raise Exception("{0} segment type not implemented yet".format(segment))
def write_call(func_name, num_args, curr_func, num_calls): return_label = "{0}$ret.{1}".format(curr_func, num_calls) # push returnLabel output = [at(return_label), "D=A"] + push() # push LCL output += [at("LCL"), "D=M"] + push() # push ARG output += [at("ARG"), "D=M"] + push() # push THIS output += [at("THIS"), "D=M"] + push() # push THAT output += [at("THAT"), "D=M"] + push() # ARG=SP-5-nArgs output += [at("SP"), "D=M-1"] for i in range(3 + int(num_args)): output.append("D=D-1") output += [at("ARG"), "M=D-1"] # LCL=SP output += [at("SP"), "D=M", at("LCL"), "M=D"] # goto functionName output += [at(func_name), "0;JMP"] # (returnLabel) output.append("({0})".format(return_label)) return output
def write_push(segment, i, ftitle=None): """Push value i from a segment onto the stack""" # local, argument, this, and that are implemented the same way standard_segs = { "local": "LCL", "argument": "ARG", "this": "THIS", "that": "THAT", } if segment in standard_segs: segname = standard_segs[segment] return ([ at(segname), # addr=segname+i "D=M", at(i), "D=D+A", "A=D", "D=M" ] + push()) elif segment == "temp": return ([ at(5), # temp base address is 5 "D=A", at(i), "D=D+A", "A=D", "D=M" ] + push()) elif segment == "static": label = "{0}.{1}".format(ftitle, i) return [at(label), "D=M"] + push() elif segment == "pointer": if int(i) not in [0, 1]: raise Exception('Invalid i for push pointer: ' + str(i)) target = "THAT" if int(i) else "THIS" return [ at(target), # *SP = THIS/THAT "D=M", "@SP", "A=M", "M=D", "@SP", # SP++ "M=M+1" ] elif segment == "constant": return [at(i), "D=A"] + push() raise Exception("{0} segment type not implemented yet".format(segment))
def write_goto(label, func): return [at(func + '$' + label), "0; JMP"]
def write_if_goto(label, func): return pop() + ["D=M", at(func + '$' + label), "D; JNE"]
def __write_restore(var): """Decrement endframe by 1, then set var to that value""" return ([ "// endFrame-=1, {0} = *(endFrame)".format(var), at("endFrame"), "M=M-1" ] + ["A=M", "D=M", at(var), "M=D"])
def __write_save_retAddr(): """Saves the return address in a local variable. """ return (["// retAddr = *(endFrame - 5)", at("endFrame"), "D=M"] + push() + [at(5), "D=A", "// push"] + push() + ["// write_sub"] + write_sub() + ["// pop"] + pop() + ["A=M", "D=M", at("retAddr"), "M=D"])