def compile_pop(cls, segment, offset, vm_command_context): pop_to_d = [ '@SP', 'A=M-1', 'D=M', '@SP', 'M=M-1' ] if is_pointer_type(segment): return lines_of( '@{}'.format(get_base_address(segment)), 'D=M', '@{}'.format(offset), 'D=D+A', '@R15', 'M=D', *pop_to_d, '@R15', 'A=M', 'M=D') elif is_direct_type(segment): return lines_of( *pop_to_d, '@{}'.format(get_base_address(segment) + int(offset)), 'M=D') elif is_static_type(segment): vm_filename, _ = vm_command_context return lines_of( *pop_to_d, '@{}'.format(cls.make_static_variable(vm_filename, offset)), 'M=D') else: raise NotImplementedError('Unsupported segment {}'.format(segment))
def compile_push(cls, segment, offset, vm_command_context): push_from_d = [ '@SP', 'A=M', 'M=D', 'D=A+1', '@SP', 'M=D' ] if is_virtual_type(segment): return lines_of( '@{}'.format(offset), 'D=A', *push_from_d) elif is_static_type(segment): vm_filename, _ = vm_command_context return lines_of( '@{}'.format(cls.make_static_variable(vm_filename, offset)), 'D=M', *push_from_d) elif is_pointer_type(segment): return lines_of( '@{}'.format(get_base_address(segment)), 'D=M', '@{}'.format(offset), 'A=D+A', 'D=M', *push_from_d) elif is_direct_type(segment): return lines_of( '@{}'.format(get_base_address(segment) + int(offset)), 'D=M', *push_from_d) else: raise NotImplementedError('Unknown segment {}'.format(segment))
def compile_if_goto(cls, label, vm_command_context): # note that this pops from the stack return lines_of( '@SP', 'AM=M-1', 'D=M', '@{}'.format(cls.symbol_from_label(vm_command_context, label)), 'D;JNE')
def compile_or(cls): return lines_of( '@SP', 'A=M-1', 'D=M', 'A=A-1', 'M=D|M', 'D=A+1', '@SP', 'M=D')
def compile_sub(cls): return lines_of( '@SP', 'A=M-1', 'D=M', 'A=A-1', 'M=M-D', 'D=A+1', '@SP', 'M=D')
def compile_eq(cls, vm_command_context, callcount): eq_true_symbol = cls.make_order_symbol( vm_command_context, 'EQ_TRUE', callcount) eq_end_symbol = cls.make_order_symbol( vm_command_context, 'EQ_END', callcount) return lines_of( *cls.diff_top2_to_d, '@{}'.format(eq_true_symbol), 'D;JEQ', 'D=0', '@{}'.format(eq_end_symbol), '0;JMP', '({})'.format(eq_true_symbol), 'D=-1', '({})'.format(eq_end_symbol), *cls.push_compare_value)
def compile_lt(cls, vm_command_context, callcount): lt_true_symbol = cls.make_order_symbol( vm_command_context, 'LT_TRUE', callcount) lt_end_symbol = cls.make_order_symbol( vm_command_context, 'LT_END', callcount) return lines_of( *cls.diff_top2_to_d, '@{}'.format(lt_true_symbol), 'D;JLT', 'D=0', '@{}'.format(lt_end_symbol), '0;JMP', '({})'.format(lt_true_symbol), 'D=-1', '({})'.format(lt_end_symbol), *cls.push_compare_value)
def compile_return(cls, vm_command_context): decrement_old_lcl_and_store_value_in_d = ["@R13", "M=M-1", "A=M", "D=M"] return lines_of( # store value of ARG in R15 "@ARG", "D=M", "@R15", "M=D", # revert LCL, THAT, THIS, ARG from # LCL, storing original LCL in R13 "@LCL", "D=M", "@R13", "M=D", *decrement_old_lcl_and_store_value_in_d, "@THAT", "M=D", *decrement_old_lcl_and_store_value_in_d, "@THIS", "M=D", *decrement_old_lcl_and_store_value_in_d, "@ARG", "M=D", *decrement_old_lcl_and_store_value_in_d, "@LCL", "M=D", # store return address in R14 *decrement_old_lcl_and_store_value_in_d, "@R14", "M=D", # push computed value, reset stack pointer "@SP", "A=M-1", "D=M", "@R15", "A=M", "M=D", "@R15", "D=M", "@SP", "M=D+1", # retrieve return value, jump "@R14", "A=M", "0;JMP" )
def compile_call(cls, callee, n_args, vm_command_context, callcount): return_symbol = "{}$RETURN_{}".format(namespace(*vm_command_context), callcount) reposition_arg_loop_symbol = "{}$REPOSITION_ARG_{}".format(namespace(*vm_command_context), callcount) push_from_d = ["@SP", "A=M", "M=D", "D=A+1", "@SP", "M=D"] return lines_of( "@{}".format(return_symbol), "D=A", *push_from_d, "@LCL", "D=M", *push_from_d, "@ARG", "D=M", *push_from_d, "@THIS", "D=M", *push_from_d, "@THAT", "D=M", *push_from_d, # reposition LCL "@SP", "D=M", "@LCL", "M=D", # reposition ARG; ARG = SP - n_args - 5 "@ARG", "M=D", "@{}".format(int(n_args) + 5), "D=A", "({})".format(reposition_arg_loop_symbol), "@ARG", "M=M-1", "@{}".format(reposition_arg_loop_symbol), "D=D-1;JNE", # jump to callee "@{}".format(namespace(vm_command_context[0], callee)), "0;JMP", "({})".format(return_symbol) )
def compile_function(cls, function, n_locals, vm_command_context): init_locals_symbol = "{}$INIT_LOCALS".format(namespace(*vm_command_context)) if int(n_locals): initialize_locals = [ "@{}".format(n_locals), "D=A", "@R13", "M=D", "({})".format(init_locals_symbol), "@SP", "D=M", "M=M+1", "A=D", "M=0", "@R13", "MD=M-1", "@{}".format(init_locals_symbol), "D;JNE", ] else: initialize_locals = [] return lines_of("({})".format(namespace(*vm_command_context)), *initialize_locals)
def bootstrap(cls, file_h): """Sets the stack pointer to 256, calls Sys.init, adds halting loop.""" bootstrap_halt_loop = "BOOTSTRAP_HALT_LOOP" file_h.write(lines_of("@256", "D=A", "@SP", "M=D") + "\n") file_h.write(cls.compile_call("Sys.init", "0", ("", None)) + "\n") file_h.write(lines_of("({})".format(bootstrap_halt_loop), "@{}".format(bootstrap_halt_loop), "0;JMP") + "\n")
def compile_goto(cls, label, vm_command_context): return lines_of( '@{}'.format(cls.symbol_from_label(vm_command_context, label)), '0;JMP')
def compile_label(cls, label, vm_command_context): return lines_of( '({})'.format(cls.symbol_from_label(vm_command_context, label)))
def compile_not(cls): return lines_of( '@SP', 'A=M-1', 'D=M', 'M=!M')
def compile_neg(cls): return lines_of( '@SP', 'A=M-1', 'D=M', 'M=-M')