def operate_on_content_of_ptr(ptr_addr, offset): if offset == 0: return ASM(f''' // load the pointer value @{ptr_addr} // dereference the pointer A=M // operate on content-of pointer M=%COMP% ''') else: return ASM(f''' // load the pointer value into D @{ptr_addr} D=M // load the offset into A @{offset} // calculate the new pointer value // and save into D A=A+D // dereference the pointer A=M // operate on content-of pointer M=%COMP% ''')
def resolve(self, known_symbols=None): if int(self.args[1]) > 0: function_init = f''' ({self.label_in_namespace}) $load_sp ''' local_init = ''' // set the current top of stack to 0 M=0 // increment top of stack A=A+1 ''' * int(self.args[1]) sp_prep = ''' // need this so SP now points to the next available // slot after local vars $save_sp ''' return ASM(function_init + local_init + sp_prep) else: # when we use no local vars we don't need any init, just a label return ASM(f''' ({self.label_in_namespace}) ''')
def set_ram(addr, value): asm = ASM(f''' // setup {addr} @{value} D=A @{addr} M=D ''') self.asm_output += asm.to_list(indent=4)
def pop_into_ptr(ptr_addr, offset): if offset == 0: return ASM(f''' $load_sp A=A-1 // load top-of-stack value into D D=M // load the pointer value @{ptr_addr} // dereference the pointer A=M // write D into destination M=D $dec_sp ''') else: return ASM(f''' // load the pointer value into D @{ptr_addr} D=M // load the offset into A @{offset} // calculate the new pointer value // and save into D D=A+D // save the value into T0 @T0 M=D $load_sp A=A-1 // load top-of-stack value into D D=M // load pointer value @T0 // dereference the pointer A=M // write D into destination M=D $dec_sp ''')
def test_compat(): ASM.set_compat(True) asm = EQ_Operation(compat=True).resolve() Assembler(compat=True).assemble(str(asm)) try: ASM.set_compat(False) asm = EQ_Operation().resolve() Assembler(compat=True).assemble(str(asm)) except: pass else: assert False, 'Should have failed'
def test_add(): asm = ADD_Operation().resolve() print(asm) expected = ASM(''' // MACRO=LOAD_SP @SP A=M // MACRO_END // pop y into D A=A-1 D=M // pop x into M A=A-1 // do the operation M=M+D // MACRO=DEC_SP @SP M=M-1 // MACRO_END ''') assert str(asm) == str(expected) # make sure it output valid assembly assembler = Assembler() assembler.assemble(str(asm))
def operate_on_memory(mem_addr): return ASM(f''' // load the memory address @{mem_addr} // write D into destination M=%COMP% ''')
def resolve(self, known_symbols=None): # see comment in LABEL_Operation.resolve return ASM(f''' // load jump destination into A @{self.label_in_namespace} // unconditional jump 0;JEQ ''')
def push_content_of_ptr(ptr_addr, offset): if offset == 0: return ASM(f''' // load the pointer value @{ptr_addr} // dereference the pointer A=M // save the value into D D=M $load_sp // write value to top of stack M=D $inc_sp ''') else: return ASM(f''' // load the pointer value into D @{ptr_addr} D=M // load the offset into A @{offset} // calculate the new pointer value // and dereference A=A+D // save the value into D D=M $load_sp // write value to top of stack M=D $inc_sp ''')
def resolve(self, known_symbols=None): return ASM(''' $load_sp // pop y into inM A=A-1 // neg M=-M // no need to update SP b/c // the top of the stack is not // changed by a pop and push ''')
def push_content_of_memory(mem_addr): return ASM(f''' // load memory address @{mem_addr} // save the value into D D=M $load_sp // write value to top of stack M=D $inc_sp ''')
def resolve(self, known_symbols=None): return ASM(''' $load_sp // pop y into D A=A-1 D=M // invert and write result to stack M=!D // no need to update SP b/c // the top of the stack is not // changed by a pop and push ''')
def resolve(self, known_symbols=None): return ASM(''' $load_sp // pop y into D A=A-1 D=M // pop x into M A=A-1 // do the operation M=M%OP%D $dec_sp ''')
def pop_into_memory(mem_addr): return ASM(f''' $load_sp A=A-1 // load top-of-stack value into D D=M // load the memory address @{mem_addr} // write D into destination M=D $dec_sp ''')
def resolve(self, known_symbols=None): # see comment in LABEL_Operation.resolve return ASM(f''' $load_sp // pop value into D A=A-1 D=M // we have to do this now b/c once // the jump executes it is too late $dec_sp // load jump destination @{self.label_in_namespace} // take a leaf from most languages: true // means !0 D;JNE ''')
def resolve(self, known_symbols=None): return ASM(''' $load_sp // pop y into D A=A-1 D=M // pop x into M A=A-1 // sub D=M-D // write -1 (=0xFFFF) into M assuming // are EQ M=-1 // update stack pointer to point to top // of stack $dec_sp @$_END D;%JMP% // if we didn't jump then the comparison // fail and we write 0 into the top // of the stack $load_sp A=A-1 // write 0 M=0 ($_END) ''')
def resolve(self, known_symbols=None): self.namespace = NAMESPACE_FILE segment, index = self.args segment, index = Operation.validate_segment_index( segment, index, known_symbols) def push_content_of_ptr(ptr_addr, offset): if offset == 0: return ASM(f''' // load the pointer value @{ptr_addr} // dereference the pointer A=M // save the value into D D=M $load_sp // write value to top of stack M=D $inc_sp ''') else: return ASM(f''' // load the pointer value into D @{ptr_addr} D=M // load the offset into A @{offset} // calculate the new pointer value // and dereference A=A+D // save the value into D D=M $load_sp // write value to top of stack M=D $inc_sp ''') # this is the sme as push_content_of_ptr but # minus the deference step for those segments # with fixed addresses def push_content_of_memory(mem_addr): return ASM(f''' // load memory address @{mem_addr} // save the value into D D=M $load_sp // write value to top of stack M=D $inc_sp ''') if segment in VM2ASM.SEGMENT_BASE_ADDR_TABLE: ptr_addr = VM2ASM.SEGMENT_BASE_ADDR_TABLE[segment] return push_content_of_ptr(ptr_addr, index) elif segment == 'temp': # b/c temp is fixed we can calculate the pointer address # directly mem_addr = VM2ASM.TEMP_BASE_ADDRESS + index return push_content_of_memory(mem_addr) elif segment == 'static': # static is special where we don't actually index into anything but auto-allocate into # the variable memory address. We leave that job to the assembler mem_addr = f'{self.label_in_namespace}.STATIC{index}' return push_content_of_memory(mem_addr) elif segment == 'pointer': # set the addr of this (0) or that (1) ptr_name = ['this', 'that'][index] mem_addr = VM2ASM.SEGMENT_BASE_ADDR_TABLE[ptr_name] return push_content_of_memory(mem_addr) elif segment == 'constant': return ASM(f''' // load {index} into D @{index} D=A // load the stack pointer $load_sp // write the constant to the top // of the stack M=D $inc_sp ''') else: raise NameError(f'Unknown segment {segment}')
def test_unique_labels(): asm1 = ASM('$_LABEL') # we should generate unique asm every time assert str(asm1) != str(asm1)
def resolve(self, known_symbols=None): # we don't use $ID_ macro here b/c these labels # originate from the user and could have scope beyond the # assembly emitted for this operation return ASM(f'({self.label_in_namespace})')
def __init__(self, input_vm=None, compat=False, annotate=False, no_init=False, ram_specs=None, LCL=None, ARG=None, THIS=None, THAT=None): self._input_vm = input_vm self._compat = compat self._annotate = annotate self._known_symbols = dict(VM2ASM.PREDEFINED_CONSTANTS) self._operations = None ASM.set_compat(self._compat) self.asm_output = [] if annotate: self.asm_output.append(f'// SOURCE FILE={input_vm}') if not no_init: def set_ram(addr, value): asm = ASM(f''' // setup {addr} @{value} D=A @{addr} M=D ''') self.asm_output += asm.to_list(indent=4) self.asm_output.append('// INIT BEGIN') set_ram('SP', VM2ASM.STACK_BASE_ADDRESS) if not self._compat: asm = ASM(''' // setup the W register as SP replacement @{VM2ASM.STACK_BASE_ADDRESS} W=A ''') self.asm_output += asm.to_list(indent=4) # if any of the runtime segment base address were given we set them. This is # needed to run the test programs supplied by the course if LCL: set_ram('LCL', LCL) if ARG: set_ram('ARG', ARG) if THIS: set_ram('THIS', THIS) if THAT: set_ram('THAT', THAT) if ram_specs and len(ram_specs): for spec in ram_specs: addr, val = spec.split('=') addr = int(addr) val = int(val) set_ram(addr, val) # set all temp variables to 0 set_ram('T0', 0) set_ram('T1', 0) set_ram('T2', 0) if annotate: self.asm_output.append('// INIT END')
def resolve(self, known_symbols=None): return ASM(''' // save the return address at LCL-5 into FRAME b/c we will be updating LCL soon and also // if number of arguments is 0 ARG and LCL-5 are pointing to the same place and we will // end up overwriting the return address when we store the return value into ARG @5 D=A @LCL A=M-D D=M @RET M=D // store the return value where ARG is pointing to, i.e. *ARG=*SP $load_sp A=A-1 D=M @ARG A=M M=D // set A to 1 past ARG and save as SP @ARG A=M+1 $save_sp // restore THAT at LCL-1 @LCL A=M-1 D=M @THAT M=D // restore THIS at LCL-2 @2 D=A @LCL A=M-D D=M @THIS M=D // restore ARG at LCL-3 @3 D=A @LCL A=M-D D=M @ARG M=D // restore LCL at LCL-4 @4 D=A @LCL A=M-D D=M @LCL M=D // load *RET into A and do an unconditional jump to that address @RET A=M 0;JEQ ''')
#for shape in shapes: # cshape,_=centerShape(shape) # cshapes.append(cshape) #plotShapes(cshapes) #ashape,_=alignAtoBProcrustes(cshapes[6],cshapes[1]) #plotShapes([cshapes[6],cshapes[1]]) #plotShapes([ashape,cshapes[1]]) #newshapes,meanShape,t=gpa(shapes) #plotShapes([meanShape]) #plotShapes(newshapes) #ashapemat=[] #ashapemean=[] for i in range(8): shapes=extractLandmarksForIncisorByIndex(landmarks,i) #newshapes,meanShape,t=gpa(shapes) #print 'Completed gpa of incisor ' + str(i) + ' in ' + str(t) + ' iterations ' #plotShapes([meanShape]) #ashapemat.append(newshapes) #ashapemean.append(meanShape) #X=prePCA(shapes) #l,W,mu=pcaV(X,0.9) #print W.shape #print l model = ASM(shapes,0.9) print model.getLambdas() modes=model.getModes() for j in range(len(model.getLambdas())): plotShapes(modes[j])
f = z[0] * sin(z[1]) gradzf = ((sin(z[1]), z[0] * cos(z[1]))) gradf = dot(gradzf, A) return f, gradf # number of Monte Carlo samples to estimate Jacobian covariance Nsamples = 1000 # input space dimension m = 10 # construct dimension reduction object asm = ASM(f, m, Nsamples) W = asm.W lamb = asm.lamb # plot the eigenvalues plt.semilogy(range(len(lamb)), lamb, '*') plt.grid(True) plt.xlabel('Index') plt.ylabel('Eigenvalue') # choose reduced dimension based on eigenvalue decay n = 2 # number of design sites per reduced dimension Nd = 6 # construct the kriging surface kr = Kriging(asm, m, n, Nd)
def resolve(self, known_symbols=None): """ Note that we use the $_ macro to ensure a unique label b/c self.label_in_namespace is the same for calls to the same function in the same file """ return ASM(f''' // push return addr onto the stack // load the return addr into D via A @$_{self.label_in_namespace} D=A $load_sp M=D $inc_sp // push LCL onto the stack // point M to LCL @LCL D=M $load_sp M=D $inc_sp // push ARG onto the stack @ARG D=M $load_sp M=D $inc_sp // push THIS onto the stack @THIS D=M $load_sp M=D $inc_sp // push THAT onto the stack @THAT D=M $load_sp M=D $inc_sp // recalculate ARG: ARG = SP - n - 5 // note that to be backward compat with HACK platform we can't manipulate the W // register directly // SP - n @{self.args[1]} D=A $load_sp // use D for destination b/c we are about to use A for a constant D=A-D // ... -5 @5 D=D-A // D now contains the new ARG value which we need to save into the ARG register @ARG M=D // write current SP into LCL register $load_sp D=A @LCL M=D // jump to the function entry point @{self.f_op.label_in_namespace} 0;JEQ ($_{self.label_in_namespace}) ''')