def analyze_point_into(self, instr, context): if not isinstance(self.get_type(instr.pointer), PointerType): raise TypeMismatchError(instr, instr.pointer) if not TableType.is_a_table_type(self.get_type(instr.table), TYPE_BYTE): raise TypeMismatchError(instr, instr.table) # check that pointer is not yet associated with any table. if context.get_assoc(instr.pointer): raise ForbiddenWriteError(instr, instr.pointer) # associate pointer with table # (do not mark it as meaningful yet - that's reset's job.) context.set_assoc(instr.pointer, instr.table) context.set_unmeaningful(instr.pointer) self.analyze_block(instr.block, context) if context.encountered_gotos(): raise IllegalJumpError(instr, instr) # unassociate pointer with table, mark as unmeaningful. context.set_assoc(instr.pointer, None) context.set_unmeaningful(instr.pointer)
def assert_types_for_update_table(self, context, instr, dest, type_, offset): if not TableType.is_a_table_type(self.get_type(dest.ref), type_): raise TypeMismatchError(instr, '{}'.format(dest.ref.name)) context.assert_meaningful(dest.index) context.assert_in_range(dest.index, dest.ref, offset) context.set_written(dest.ref)
def assert_types_for_read_table(self, context, instr, src, dest, type_, offset): if (not TableType.is_a_table_type(self.get_type( src.ref), type_)) or (not self.get_type(dest) == type_): raise TypeMismatchError( instr, '{} and {}'.format(src.ref.name, dest.name)) context.assert_meaningful(src, src.index) context.assert_in_range(src.index, src.ref, offset)
def defn_type(self): type_ = self.defn_type_term() if self.scanner.consume('table'): size = self.defn_size() if size <= 0 or size > 65536: self.syntax_error("Table size must be > 0 and <= 65536") type_ = TableType(type_, size) return type_
def backpatched_type(type_): if isinstance(type_, TableType): return TableType(backpatched_type(type_.of_type), type_.size) elif isinstance(type_, VectorType): return VectorType(backpatched_type(type_.of_type)) elif isinstance(type_, RoutineType): return RoutineType( frozenset([resolve(w) for w in type_.inputs]), frozenset([resolve(w) for w in type_.outputs]), frozenset([resolve(w) for w in type_.trashes]), ) else: return type_
def analyze_single_op(self, instr, context): opcode = instr.opcode dest = instr.dest src = instr.src if context.has_terminated(): raise TerminatedContextError(instr, instr) if opcode == 'ld': if isinstance(src, IndexedRef): self.assert_types_for_read_table(context, instr, src, dest, TYPE_BYTE, src.offset) elif isinstance(src, IndirectRef): # copying this analysis from the matching branch in `copy`, below if isinstance( self.get_type(src.ref), PointerType) and self.get_type(dest) == TYPE_BYTE: pass else: raise TypeMismatchError(instr, (src, dest)) origin = context.get_assoc(src.ref) if not origin: raise UnmeaningfulReadError(instr, src.ref) context.assert_meaningful(origin) context.assert_meaningful(src.ref, REG_Y) elif self.get_type(src) != self.get_type(dest): raise TypeMismatchError( instr, '{} and {}'.format(src.name, dest.name)) else: context.assert_meaningful(src) context.copy_range(src, dest) context.set_written(dest, FLAG_Z, FLAG_N) elif opcode == 'st': if isinstance(dest, IndexedRef): if self.get_type(src) != TYPE_BYTE: raise TypeMismatchError(instr, (src, dest)) self.assert_types_for_update_table(context, instr, dest, TYPE_BYTE, dest.offset) elif isinstance(dest, IndirectRef): # copying this analysis from the matching branch in `copy`, below if isinstance(self.get_type(dest.ref), PointerType) and self.get_type(src) == TYPE_BYTE: pass else: raise TypeMismatchError(instr, (src, dest)) context.assert_meaningful(dest.ref, REG_Y) target = context.get_assoc(dest.ref) if not target: raise ForbiddenWriteError(instr, dest.ref) context.set_written(target) elif self.get_type(src) != self.get_type(dest): raise TypeMismatchError(instr, '{} and {}'.format(src, dest)) else: context.set_written(dest) # FIXME: context.copy_range(src, dest) ? context.assert_meaningful(src) elif opcode == 'add': context.assert_meaningful(src, dest, FLAG_C) if isinstance(src, IndexedRef): self.assert_types_for_read_table(context, instr, src, dest, TYPE_BYTE, src.offset) elif self.get_type(src) == TYPE_BYTE: self.assert_type(TYPE_BYTE, src, dest) if dest != REG_A: context.set_touched(REG_A) context.set_unmeaningful(REG_A) else: self.assert_type(TYPE_WORD, src) dest_type = self.get_type(dest) if dest_type == TYPE_WORD: context.set_touched(REG_A) context.set_unmeaningful(REG_A) elif isinstance(dest_type, PointerType): context.set_touched(REG_A) context.set_unmeaningful(REG_A) else: self.assert_type(TYPE_WORD, dest) context.set_written(dest, FLAG_Z, FLAG_N, FLAG_C, FLAG_V) context.invalidate_range(dest) elif opcode == 'sub': context.assert_meaningful(src, dest, FLAG_C) if isinstance(src, IndexedRef): self.assert_types_for_read_table(context, instr, src, dest, TYPE_BYTE, src.offset) elif self.get_type(src) == TYPE_BYTE: self.assert_type(TYPE_BYTE, src, dest) if dest != REG_A: context.set_touched(REG_A) context.set_unmeaningful(REG_A) else: self.assert_type(TYPE_WORD, src, dest) context.set_touched(REG_A) context.set_unmeaningful(REG_A) context.set_written(dest, FLAG_Z, FLAG_N, FLAG_C, FLAG_V) context.invalidate_range(dest) elif opcode == 'cmp': context.assert_meaningful(src, dest) if isinstance(src, IndexedRef): self.assert_types_for_read_table(context, instr, src, dest, TYPE_BYTE, src.offset) elif self.get_type(src) == TYPE_BYTE: self.assert_type(TYPE_BYTE, src, dest) else: self.assert_type(TYPE_WORD, src, dest) context.set_touched(REG_A) context.set_unmeaningful(REG_A) context.set_written(FLAG_Z, FLAG_N, FLAG_C) elif opcode == 'and': if isinstance(src, IndexedRef): self.assert_types_for_read_table(context, instr, src, dest, TYPE_BYTE, src.offset) else: self.assert_type(TYPE_BYTE, src, dest) context.assert_meaningful(src, dest) context.set_written(dest, FLAG_Z, FLAG_N) # If you AND the A register with a value V, the resulting value of A # cannot exceed the value of V; i.e. the maximum value of A becomes # the maximum value of V. if not isinstance(src, IndexedRef): context.set_top_of_range(dest, context.get_top_of_range(src)) elif opcode in ('or', 'xor'): if isinstance(src, IndexedRef): self.assert_types_for_read_table(context, instr, src, dest, TYPE_BYTE, src.offset) else: self.assert_type(TYPE_BYTE, src, dest) context.assert_meaningful(src, dest) context.set_written(dest, FLAG_Z, FLAG_N) context.invalidate_range(dest) elif opcode in ('inc', 'dec'): context.assert_meaningful(dest) if isinstance(dest, IndexedRef): self.assert_types_for_update_table(context, instr, dest, TYPE_BYTE, dest.offset) context.set_written(dest.ref, FLAG_Z, FLAG_N) #context.invalidate_range(dest) else: self.assert_type(TYPE_BYTE, dest) context.set_written(dest, FLAG_Z, FLAG_N) bottom = context.get_bottom_of_range(dest) top = context.get_top_of_range(dest) if opcode == 'inc': if bottom == top and top < 255: context.set_range(dest, bottom + 1, top + 1) else: context.invalidate_range(dest) elif opcode == 'dec': if bottom == top and bottom > 0: context.set_range(dest, bottom - 1, top - 1) else: context.invalidate_range(dest) else: raise NotImplementedError elif opcode in ('shl', 'shr'): context.assert_meaningful(dest, FLAG_C) if isinstance(dest, IndexedRef): self.assert_types_for_update_table(context, instr, dest, TYPE_BYTE, dest.offset) context.set_written(dest.ref, FLAG_Z, FLAG_N, FLAG_C) #context.invalidate_range(dest) else: self.assert_type(TYPE_BYTE, dest) context.set_written(dest, FLAG_Z, FLAG_N, FLAG_C) context.invalidate_range(dest) elif opcode == 'copy': if dest == REG_A: raise ForbiddenWriteError( instr, "{} cannot be used as destination for copy".format(dest)) # 1. check that their types are compatible if isinstance(src, (LocationRef, ConstantRef)) and isinstance( dest, IndirectRef): if self.get_type(src) == TYPE_BYTE and isinstance( self.get_type(dest.ref), PointerType): pass else: raise TypeMismatchError(instr, (src, dest)) elif isinstance(src, IndirectRef) and isinstance( dest, LocationRef): if isinstance( self.get_type(src.ref), PointerType) and self.get_type(dest) == TYPE_BYTE: pass else: raise TypeMismatchError(instr, (src, dest)) elif isinstance(src, IndirectRef) and isinstance( dest, IndirectRef): if isinstance(self.get_type(src.ref), PointerType) and isinstance( self.get_type(dest.ref), PointerType): pass else: raise TypeMismatchError(instr, (src, dest)) elif isinstance(src, (LocationRef, ConstantRef)) and isinstance( dest, IndexedRef): if self.get_type( src) == TYPE_WORD and TableType.is_a_table_type( self.get_type(dest.ref), TYPE_WORD): pass elif (isinstance(self.get_type(src), VectorType) and isinstance(self.get_type(dest.ref), TableType) and RoutineType.executable_types_compatible( self.get_type(src).of_type, self.get_type(dest.ref).of_type)): pass elif (isinstance(self.get_type(src), RoutineType) and isinstance(self.get_type(dest.ref), TableType) and RoutineType.executable_types_compatible( self.get_type(src), self.get_type(dest.ref).of_type)): pass else: raise TypeMismatchError(instr, (src, dest)) context.assert_in_range(dest.index, dest.ref, dest.offset) elif isinstance(src, IndexedRef) and isinstance(dest, LocationRef): if TableType.is_a_table_type( self.get_type(src.ref), TYPE_WORD) and self.get_type(dest) == TYPE_WORD: pass elif (isinstance(self.get_type(src.ref), TableType) and isinstance(self.get_type(dest), VectorType) and RoutineType.executable_types_compatible( self.get_type(src.ref).of_type, self.get_type(dest).of_type)): pass else: raise TypeMismatchError(instr, (src, dest)) context.assert_in_range(src.index, src.ref, src.offset) elif isinstance(src, (LocationRef, ConstantRef)) and isinstance( dest, LocationRef): if self.get_type(src) == self.get_type(dest): pass elif isinstance(self.get_type(src), RoutineType) and isinstance( self.get_type(dest), VectorType): self.assert_affected_within('inputs', self.get_type(src), self.get_type(dest).of_type) self.assert_affected_within('outputs', self.get_type(src), self.get_type(dest).of_type) self.assert_affected_within('trashes', self.get_type(src), self.get_type(dest).of_type) else: raise TypeMismatchError(instr, (src, dest)) else: raise TypeMismatchError(instr, (src, dest)) # 2. check that the context is meaningful if isinstance(src, (LocationRef, ConstantRef)) and isinstance( dest, IndirectRef): context.assert_meaningful(src, dest.ref, REG_Y) target = context.get_assoc(dest.ref) if not target: raise ForbiddenWriteError(instr, dest.ref) context.set_written(target) elif isinstance(src, IndirectRef) and isinstance( dest, LocationRef): context.assert_meaningful(src.ref, REG_Y) origin = context.get_assoc(src.ref) if not origin: raise UnmeaningfulReadError(instr, src.ref) context.assert_meaningful(origin) context.set_written(dest) elif isinstance(src, IndirectRef) and isinstance( dest, IndirectRef): context.assert_meaningful(src.ref, dest.ref, REG_Y) origin = context.get_assoc(src.ref) if not origin: raise UnmeaningfulReadError(instr, src.ref) context.assert_meaningful(origin) target = context.get_assoc(dest.ref) if not target: raise ForbiddenWriteError(instr, dest.ref) context.set_written(target) elif isinstance(src, LocationRef) and isinstance(dest, IndexedRef): context.assert_meaningful(src, dest.ref, dest.index) context.set_written(dest.ref) elif isinstance(src, ConstantRef) and isinstance(dest, IndexedRef): context.assert_meaningful(src, dest.ref, dest.index) context.set_written(dest.ref) elif isinstance(src, IndexedRef) and isinstance(dest, LocationRef): context.assert_meaningful(src.ref, src.index) context.set_written(dest) else: context.assert_meaningful(src) context.set_written(dest) context.set_touched(REG_A, FLAG_Z, FLAG_N) context.set_unmeaningful(REG_A, FLAG_Z, FLAG_N) elif opcode == 'trash': context.set_touched(instr.dest) context.set_unmeaningful(instr.dest) elif opcode == 'nop': pass else: raise NotImplementedError(opcode)
def compile_copy(self, instr, src, dest): if isinstance(src, (IndirectRef, IndexedRef)): src_ref_type = self.get_type(src.ref) else: src_type = self.get_type(src) if isinstance(dest, (IndirectRef, IndexedRef)): dest_ref_type = self.get_type(dest.ref) else: dest_type = self.get_type(dest) if isinstance(src, ConstantRef) and isinstance( dest, IndirectRef) and src_type == TYPE_BYTE and isinstance( dest_ref_type, PointerType): ### copy 123, [ptr] + y dest_label = self.get_label(dest.ref.name) self.emitter.emit(LDA(Immediate(Byte(src.value)))) self.emitter.emit(STA(IndirectY(dest_label))) elif isinstance(src, LocationRef) and isinstance( dest, IndirectRef) and src_type == TYPE_BYTE and isinstance( dest_ref_type, PointerType): ### copy b, [ptr] + y src_label = self.get_label(src.name) dest_label = self.get_label(dest.ref.name) self.emitter.emit(LDA(Absolute(src_label))) self.emitter.emit(STA(IndirectY(dest_label))) elif isinstance(src, IndirectRef) and isinstance( dest, LocationRef) and dest_type == TYPE_BYTE and isinstance( src_ref_type, PointerType): ### copy [ptr] + y, b src_label = self.get_label(src.ref.name) dest_label = self.get_label(dest.name) self.emitter.emit(LDA(IndirectY(src_label))) self.emitter.emit(STA(Absolute(dest_label))) elif isinstance(src, IndirectRef) and isinstance( dest, IndirectRef) and isinstance( src_ref_type, PointerType) and isinstance( dest_ref_type, PointerType): ### copy [ptra] + y, [ptrb] + y src_label = self.get_label(src.ref.name) dest_label = self.get_label(dest.ref.name) self.emitter.emit(LDA(IndirectY(src_label))) self.emitter.emit(STA(IndirectY(dest_label))) elif isinstance(src, LocationRef) and isinstance( dest, IndexedRef ) and src_type == TYPE_WORD and TableType.is_a_table_type( dest_ref_type, TYPE_WORD): ### copy w, wtab + y src_label = self.get_label(src.name) dest_label = self.get_label(dest.ref.name) mode = self.addressing_mode_for_index(dest.index) self.emitter.emit(LDA(Absolute(src_label))) self.emitter.emit(STA(mode(Offset(dest_label, dest.offset.value)))) self.emitter.emit(LDA(Absolute(Offset(src_label, 1)))) self.emitter.emit( STA(mode(Offset(dest_label, dest.offset.value + 256)))) elif isinstance(src, LocationRef) and isinstance( dest, IndexedRef) and isinstance( src_type, VectorType) and isinstance( dest_ref_type, TableType) and isinstance( dest_ref_type.of_type, VectorType): ### copy vec, vtab + y # FIXME this is the exact same as above - can this be simplified? src_label = self.get_label(src.name) dest_label = self.get_label(dest.ref.name) mode = self.addressing_mode_for_index(dest.index) self.emitter.emit(LDA(Absolute(src_label))) self.emitter.emit(STA(mode(Offset(dest_label, dest.offset.value)))) self.emitter.emit(LDA(Absolute(Offset(src_label, 1)))) self.emitter.emit( STA(mode(Offset(dest_label, dest.offset.value + 256)))) elif isinstance(src, LocationRef) and isinstance( dest, IndexedRef) and isinstance( src_type, RoutineType) and isinstance( dest_ref_type, TableType) and isinstance( dest_ref_type.of_type, VectorType): ### copy routine, vtab + y src_label = self.get_label(src.name) dest_label = self.get_label(dest.ref.name) mode = self.addressing_mode_for_index(dest.index) self.emitter.emit(LDA(Immediate(HighAddressByte(src_label)))) self.emitter.emit(STA(mode(Offset(dest_label, dest.offset.value)))) self.emitter.emit(LDA(Immediate(LowAddressByte(src_label)))) self.emitter.emit( STA(mode(Offset(dest_label, dest.offset.value + 256)))) elif isinstance(src, ConstantRef) and isinstance( dest, IndexedRef ) and src_type == TYPE_WORD and TableType.is_a_table_type( dest_ref_type, TYPE_WORD): ### copy 9999, wtab + y dest_label = self.get_label(dest.ref.name) mode = self.addressing_mode_for_index(dest.index) self.emitter.emit(LDA(Immediate(Byte(src.low_byte())))) self.emitter.emit(STA(mode(Offset(dest_label, dest.offset.value)))) self.emitter.emit(LDA(Immediate(Byte(src.high_byte())))) self.emitter.emit( STA(mode(Offset(dest_label, dest.offset.value + 256)))) elif isinstance(src, IndexedRef) and isinstance( dest, LocationRef) and TableType.is_a_table_type( src_ref_type, TYPE_WORD) and dest_type == TYPE_WORD: ### copy wtab + y, w src_label = self.get_label(src.ref.name) dest_label = self.get_label(dest.name) mode = self.addressing_mode_for_index(src.index) self.emitter.emit(LDA(mode(Offset(src_label, src.offset.value)))) self.emitter.emit(STA(Absolute(dest_label))) self.emitter.emit( LDA(mode(Offset(src_label, src.offset.value + 256)))) self.emitter.emit(STA(Absolute(Offset(dest_label, 1)))) elif isinstance(src, IndexedRef) and isinstance( dest, LocationRef) and isinstance( dest_type, VectorType) and isinstance( src_ref_type, TableType) and isinstance( src_ref_type.of_type, VectorType): ### copy vtab + y, vec # FIXME this is the exact same as above - can this be simplified? src_label = self.get_label(src.ref.name) dest_label = self.get_label(dest.name) mode = self.addressing_mode_for_index(src.index) self.emitter.emit(LDA(mode(Offset(src_label, src.offset.value)))) self.emitter.emit(STA(Absolute(dest_label))) self.emitter.emit( LDA(mode(Offset(src_label, src.offset.value + 256)))) self.emitter.emit(STA(Absolute(Offset(dest_label, 1)))) elif src_type == TYPE_BYTE and dest_type == TYPE_BYTE and not isinstance( src, ConstantRef): ### copy b1, b2 src_label = self.get_label(src.name) dest_label = self.get_label(dest.name) self.emitter.emit(LDA(Absolute(src_label))) self.emitter.emit(STA(Absolute(dest_label))) elif src_type == TYPE_WORD and dest_type == TYPE_WORD and isinstance( src, ConstantRef): ### copy 9999, w dest_label = self.get_label(dest.name) self.emitter.emit(LDA(Immediate(Byte(src.low_byte())))) self.emitter.emit(STA(Absolute(dest_label))) self.emitter.emit(LDA(Immediate(Byte(src.high_byte())))) self.emitter.emit(STA(Absolute(Offset(dest_label, 1)))) elif src_type == TYPE_WORD and dest_type == TYPE_WORD and not isinstance( src, ConstantRef): ### copy w1, w2 src_label = self.get_label(src.name) dest_label = self.get_label(dest.name) self.emitter.emit(LDA(Absolute(src_label))) self.emitter.emit(STA(Absolute(dest_label))) self.emitter.emit(LDA(Absolute(Offset(src_label, 1)))) self.emitter.emit(STA(Absolute(Offset(dest_label, 1)))) elif isinstance(src_type, VectorType) and isinstance( dest_type, VectorType): ### copy v1, v2 src_label = self.get_label(src.name) dest_label = self.get_label(dest.name) self.emitter.emit(LDA(Absolute(src_label))) self.emitter.emit(STA(Absolute(dest_label))) self.emitter.emit(LDA(Absolute(Offset(src_label, 1)))) self.emitter.emit(STA(Absolute(Offset(dest_label, 1)))) elif isinstance(src_type, RoutineType) and isinstance( dest_type, VectorType): ### copy routine, vec src_label = self.get_label(src.name) dest_label = self.get_label(dest.name) self.emitter.emit(LDA(Immediate(HighAddressByte(src_label)))) self.emitter.emit(STA(Absolute(dest_label))) self.emitter.emit(LDA(Immediate(LowAddressByte(src_label)))) self.emitter.emit(STA(Absolute(Offset(dest_label, 1)))) else: raise NotImplementedError(src_type)
def compile_program(self, program, compilation_roster=None): assert isinstance(program, Program) declarations = [] for defn in program.defns: length = self.compute_length_of_defn(defn) label = Label(defn.name, addr=defn.addr, length=length) self.labels[defn.name] = label declarations.append( (defn, self.symtab.fetch_global_type(defn.name), label)) for routine in program.routines: self.routines[routine.name] = routine label = Label(routine.name) if routine.addr is not None: label.set_addr(routine.addr) self.labels[routine.name] = label self.current_routine = routine local_labels = {} for defn in routine.locals: length = self.compute_length_of_defn(defn) label = Label(defn.name, addr=defn.addr, length=length) local_labels[defn.name] = label declarations.append( (defn, self.symtab.fetch_local_type(routine.name, defn.name), label)) self.routine_locals[routine.name] = local_labels self.current_routine = None if compilation_roster is None: compilation_roster = [['main']] + [[routine.name] for routine in program.routines if routine.name != 'main'] for roster_row in compilation_roster: for routine_name in roster_row[0:-1]: self.compile_routine(self.routines[routine_name], skip_final_goto=True) routine_name = roster_row[-1] self.compile_routine(self.routines[routine_name]) for location, label in self.trampolines.items(): self.emitter.resolve_label(label) self.emitter.emit(JMP(Indirect(self.get_label(location.name)))) self.emitter.emit(RTS()) # initialized data for defn, type_, label in declarations: if defn.initial is not None: initial_data = None if type_ == TYPE_BYTE: initial_data = Byte(defn.initial) elif type_ == TYPE_WORD: initial_data = Word(defn.initial) elif TableType.is_a_table_type(type_, TYPE_BYTE): initial_data = Table([Byte(i) for i in defn.initial], type_.size) elif TableType.is_a_table_type(type_, TYPE_WORD): initial_data = Table([Word(i) for i in defn.initial], type_.size) else: raise NotImplementedError(type_) label.set_length(initial_data.size()) self.emitter.resolve_label(label) self.emitter.emit(initial_data) # uninitialized, "BSS" data for defn, type_, label in declarations: if defn.initial is None and defn.addr is None: self.emitter.resolve_bss_label(label)
def analyze_single_op(self, instr, context): opcode = instr.opcode dest = instr.dest src = instr.src if context.has_terminated(): raise TerminatedContextError(instr, instr) if opcode == 'ld': if isinstance(src, IndexedRef): self.assert_types_for_read_table(context, instr, src, dest, TYPE_BYTE, src.offset) elif isinstance(src, IndirectRef): # copying this analysis from the matching branch in `copy`, below if isinstance(self.get_type(src.ref), PointerType) and self.get_type(dest) == TYPE_BYTE: pass else: raise TypeMismatchError(instr, (src, dest)) origin = context.get_assoc(src.ref) if not origin: raise UnmeaningfulReadError(instr, src.ref) context.assert_meaningful(origin) context.assert_meaningful(src.ref, REG_Y) elif self.get_type(src) != self.get_type(dest): raise TypeMismatchError(instr, '{} and {}'.format(src.name, dest.name)) else: context.assert_meaningful(src) context.copy_range(src, dest) context.set_written(dest, FLAG_Z, FLAG_N) elif opcode == 'st': if isinstance(dest, IndexedRef): if self.get_type(src) != TYPE_BYTE: raise TypeMismatchError(instr, (src, dest)) self.assert_types_for_update_table(context, instr, dest, TYPE_BYTE, dest.offset) elif isinstance(dest, IndirectRef): # copying this analysis from the matching branch in `copy`, below if isinstance(self.get_type(dest.ref), PointerType) and self.get_type(src) == TYPE_BYTE: pass else: raise TypeMismatchError(instr, (src, dest)) context.assert_meaningful(dest.ref, REG_Y) target = context.get_assoc(dest.ref) if not target: raise ForbiddenWriteError(instr, dest.ref) context.set_written(target) elif self.get_type(src) != self.get_type(dest): raise TypeMismatchError(instr, '{} and {}'.format(src, dest)) else: context.set_written(dest) # FIXME: context.copy_range(src, dest) ? context.assert_meaningful(src) elif opcode == 'add': context.assert_meaningful(src, dest, FLAG_C) if isinstance(src, IndexedRef): self.assert_types_for_read_table(context, instr, src, dest, TYPE_BYTE, src.offset) elif self.get_type(src) == TYPE_BYTE: self.assert_type(TYPE_BYTE, src, dest) if dest != REG_A: context.set_touched(REG_A) context.set_unmeaningful(REG_A) else: self.assert_type(TYPE_WORD, src) dest_type = self.get_type(dest) if dest_type == TYPE_WORD: context.set_touched(REG_A) context.set_unmeaningful(REG_A) elif isinstance(dest_type, PointerType): context.set_touched(REG_A) context.set_unmeaningful(REG_A) else: self.assert_type(TYPE_WORD, dest) context.set_written(dest, FLAG_Z, FLAG_N, FLAG_C, FLAG_V) context.invalidate_range(dest) elif opcode == 'sub': context.assert_meaningful(src, dest, FLAG_C) if isinstance(src, IndexedRef): self.assert_types_for_read_table(context, instr, src, dest, TYPE_BYTE, src.offset) elif self.get_type(src) == TYPE_BYTE: self.assert_type(TYPE_BYTE, src, dest) if dest != REG_A: context.set_touched(REG_A) context.set_unmeaningful(REG_A) else: self.assert_type(TYPE_WORD, src, dest) context.set_touched(REG_A) context.set_unmeaningful(REG_A) context.set_written(dest, FLAG_Z, FLAG_N, FLAG_C, FLAG_V) context.invalidate_range(dest) elif opcode == 'cmp': context.assert_meaningful(src, dest) if isinstance(src, IndexedRef): self.assert_types_for_read_table(context, instr, src, dest, TYPE_BYTE, src.offset) elif self.get_type(src) == TYPE_BYTE: self.assert_type(TYPE_BYTE, src, dest) else: self.assert_type(TYPE_WORD, src, dest) context.set_touched(REG_A) context.set_unmeaningful(REG_A) context.set_written(FLAG_Z, FLAG_N, FLAG_C) elif opcode == 'and': if isinstance(src, IndexedRef): self.assert_types_for_read_table(context, instr, src, dest, TYPE_BYTE, src.offset) else: self.assert_type(TYPE_BYTE, src, dest) context.assert_meaningful(src, dest) context.set_written(dest, FLAG_Z, FLAG_N) # If you AND the A register with a value V, the resulting value of A # cannot exceed the value of V; i.e. the maximum value of A becomes # the maximum value of V. if not isinstance(src, IndexedRef): context.set_top_of_range(dest, context.get_top_of_range(src)) elif opcode in ('or', 'xor'): if isinstance(src, IndexedRef): self.assert_types_for_read_table(context, instr, src, dest, TYPE_BYTE, src.offset) else: self.assert_type(TYPE_BYTE, src, dest) context.assert_meaningful(src, dest) context.set_written(dest, FLAG_Z, FLAG_N) context.invalidate_range(dest) elif opcode in ('inc', 'dec'): context.assert_meaningful(dest) if isinstance(dest, IndexedRef): self.assert_types_for_update_table(context, instr, dest, TYPE_BYTE, dest.offset) context.set_written(dest.ref, FLAG_Z, FLAG_N) #context.invalidate_range(dest) else: self.assert_type(TYPE_BYTE, dest) context.set_written(dest, FLAG_Z, FLAG_N) bottom = context.get_bottom_of_range(dest) top = context.get_top_of_range(dest) if opcode == 'inc': if bottom == top and top < 255: context.set_range(dest, bottom + 1, top + 1) else: context.invalidate_range(dest) elif opcode == 'dec': if bottom == top and bottom > 0: context.set_range(dest, bottom - 1, top - 1) else: context.invalidate_range(dest) else: raise NotImplementedError elif opcode in ('shl', 'shr'): context.assert_meaningful(dest, FLAG_C) if isinstance(dest, IndexedRef): self.assert_types_for_update_table(context, instr, dest, TYPE_BYTE, dest.offset) context.set_written(dest.ref, FLAG_Z, FLAG_N, FLAG_C) #context.invalidate_range(dest) else: self.assert_type(TYPE_BYTE, dest) context.set_written(dest, FLAG_Z, FLAG_N, FLAG_C) context.invalidate_range(dest) elif opcode == 'copy': if dest == REG_A: raise ForbiddenWriteError(instr, "{} cannot be used as destination for copy".format(dest)) # 1. check that their types are compatible if isinstance(src, (LocationRef, ConstantRef)) and isinstance(dest, IndirectRef): if self.get_type(src) == TYPE_BYTE and isinstance(self.get_type(dest.ref), PointerType): pass else: raise TypeMismatchError(instr, (src, dest)) elif isinstance(src, IndirectRef) and isinstance(dest, LocationRef): if isinstance(self.get_type(src.ref), PointerType) and self.get_type(dest) == TYPE_BYTE: pass else: raise TypeMismatchError(instr, (src, dest)) elif isinstance(src, IndirectRef) and isinstance(dest, IndirectRef): if isinstance(self.get_type(src.ref), PointerType) and isinstance(self.get_type(dest.ref), PointerType): pass else: raise TypeMismatchError(instr, (src, dest)) elif isinstance(src, (LocationRef, ConstantRef)) and isinstance(dest, IndexedRef): if self.get_type(src) == TYPE_WORD and TableType.is_a_table_type(self.get_type(dest.ref), TYPE_WORD): pass elif (isinstance(self.get_type(src), VectorType) and isinstance(self.get_type(dest.ref), TableType) and RoutineType.executable_types_compatible(self.get_type(src).of_type, self.get_type(dest.ref).of_type)): pass elif (isinstance(self.get_type(src), RoutineType) and isinstance(self.get_type(dest.ref), TableType) and RoutineType.executable_types_compatible(self.get_type(src), self.get_type(dest.ref).of_type)): pass else: raise TypeMismatchError(instr, (src, dest)) context.assert_in_range(dest.index, dest.ref, dest.offset) elif isinstance(src, IndexedRef) and isinstance(dest, LocationRef): if TableType.is_a_table_type(self.get_type(src.ref), TYPE_WORD) and self.get_type(dest) == TYPE_WORD: pass elif (isinstance(self.get_type(src.ref), TableType) and isinstance(self.get_type(dest), VectorType) and RoutineType.executable_types_compatible(self.get_type(src.ref).of_type, self.get_type(dest).of_type)): pass else: raise TypeMismatchError(instr, (src, dest)) context.assert_in_range(src.index, src.ref, src.offset) elif isinstance(src, (LocationRef, ConstantRef)) and isinstance(dest, LocationRef): if self.get_type(src) == self.get_type(dest): pass elif isinstance(self.get_type(src), RoutineType) and isinstance(self.get_type(dest), VectorType): self.assert_affected_within('inputs', self.get_type(src), self.get_type(dest).of_type) self.assert_affected_within('outputs', self.get_type(src), self.get_type(dest).of_type) self.assert_affected_within('trashes', self.get_type(src), self.get_type(dest).of_type) else: raise TypeMismatchError(instr, (src, dest)) else: raise TypeMismatchError(instr, (src, dest)) # 2. check that the context is meaningful if isinstance(src, (LocationRef, ConstantRef)) and isinstance(dest, IndirectRef): context.assert_meaningful(src, dest.ref, REG_Y) target = context.get_assoc(dest.ref) if not target: raise ForbiddenWriteError(instr, dest.ref) context.set_written(target) elif isinstance(src, IndirectRef) and isinstance(dest, LocationRef): context.assert_meaningful(src.ref, REG_Y) origin = context.get_assoc(src.ref) if not origin: raise UnmeaningfulReadError(instr, src.ref) context.assert_meaningful(origin) context.set_written(dest) elif isinstance(src, IndirectRef) and isinstance(dest, IndirectRef): context.assert_meaningful(src.ref, dest.ref, REG_Y) origin = context.get_assoc(src.ref) if not origin: raise UnmeaningfulReadError(instr, src.ref) context.assert_meaningful(origin) target = context.get_assoc(dest.ref) if not target: raise ForbiddenWriteError(instr, dest.ref) context.set_written(target) elif isinstance(src, LocationRef) and isinstance(dest, IndexedRef): context.assert_meaningful(src, dest.ref, dest.index) context.set_written(dest.ref) elif isinstance(src, ConstantRef) and isinstance(dest, IndexedRef): context.assert_meaningful(src, dest.ref, dest.index) context.set_written(dest.ref) elif isinstance(src, IndexedRef) and isinstance(dest, LocationRef): context.assert_meaningful(src.ref, src.index) context.set_written(dest) else: context.assert_meaningful(src) context.set_written(dest) context.set_touched(REG_A, FLAG_Z, FLAG_N) context.set_unmeaningful(REG_A, FLAG_Z, FLAG_N) elif opcode == 'trash': context.set_touched(instr.dest) context.set_unmeaningful(instr.dest) elif opcode == 'nop': pass else: raise NotImplementedError(opcode)
def assert_types_for_read_table(self, context, instr, src, dest, type_, offset): if (not TableType.is_a_table_type(self.get_type(src.ref), type_)) or (not self.get_type(dest) == type_): raise TypeMismatchError(instr, '{} and {}'.format(src.ref.name, dest.name)) context.assert_meaningful(src, src.index) context.assert_in_range(src.index, src.ref, offset)