def compile_cmp(self, instr, src, dest): """`instr` is only for reporting purposes""" if isinstance(src, LocationRef) and self.get_type(src) == TYPE_WORD: src_label = self.get_label(src.name) dest_label = self.get_label(dest.name) self.emitter.emit(LDA(Absolute(dest_label))) self.emitter.emit(CMP(Absolute(src_label))) end_label = Label('end_label') self.emitter.emit(BNE(Relative(end_label))) self.emitter.emit(LDA(Absolute(Offset(dest_label, 1)))) self.emitter.emit(CMP(Absolute(Offset(src_label, 1)))) self.emitter.resolve_label(end_label) return if isinstance(src, ConstantRef) and self.get_type(src) == TYPE_WORD: dest_label = self.get_label(dest.name) self.emitter.emit(LDA(Absolute(dest_label))) self.emitter.emit(CMP(Immediate(Byte(src.low_byte())))) end_label = Label('end_label') self.emitter.emit(BNE(Relative(end_label))) self.emitter.emit(LDA(Absolute(Offset(dest_label, 1)))) self.emitter.emit(CMP(Immediate(Byte(src.high_byte())))) self.emitter.resolve_label(end_label) return cls = { 'a': CMP, 'x': CPX, 'y': CPY, }.get(dest.name) if cls is None: raise UnsupportedOpcodeError(instr) if isinstance(src, ConstantRef): self.emitter.emit(cls(Immediate(Byte(src.value)))) elif isinstance(src, IndexedRef): # FIXME might not work for some dest's (that is, cls's) mode = self.addressing_mode_for_index(src.index) self.emitter.emit( cls( mode(Offset(self.get_label(src.ref.name), src.offset.value)))) else: self.emitter.emit(cls(Absolute(self.get_label(src.name))))
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 compile_single_op(self, instr): opcode = instr.opcode dest = instr.dest src = instr.src if opcode == 'ld': if dest == REG_A: if src == REG_X: self.emitter.emit(TXA()) elif src == REG_Y: self.emitter.emit(TYA()) elif isinstance(src, ConstantRef): self.emitter.emit(LDA(Immediate(Byte(src.value)))) elif isinstance(src, IndexedRef) and src.index == REG_X: self.emitter.emit( LDA( AbsoluteX( Offset(self.get_label(src.ref.name), src.offset.value)))) elif isinstance(src, IndexedRef) and src.index == REG_Y: self.emitter.emit( LDA( AbsoluteY( Offset(self.get_label(src.ref.name), src.offset.value)))) elif isinstance(src, IndirectRef) and isinstance( self.get_type(src.ref), PointerType): self.emitter.emit( LDA(IndirectY(self.get_label(src.ref.name)))) else: self.emitter.emit( LDA( self.absolute_or_zero_page(self.get_label( src.name)))) elif dest == REG_X: if src == REG_A: self.emitter.emit(TAX()) elif isinstance(src, ConstantRef): self.emitter.emit(LDX(Immediate(Byte(src.value)))) elif isinstance(src, IndexedRef) and src.index == REG_Y: self.emitter.emit( LDX( AbsoluteY( Offset(self.get_label(src.ref.name), src.offset.value)))) else: self.emitter.emit( LDX( self.absolute_or_zero_page(self.get_label( src.name)))) elif dest == REG_Y: if src == REG_A: self.emitter.emit(TAY()) elif isinstance(src, ConstantRef): self.emitter.emit(LDY(Immediate(Byte(src.value)))) elif isinstance(src, IndexedRef) and src.index == REG_X: self.emitter.emit( LDY( AbsoluteX( Offset(self.get_label(src.ref.name), src.offset.value)))) else: self.emitter.emit( LDY( self.absolute_or_zero_page(self.get_label( src.name)))) else: raise UnsupportedOpcodeError(instr) elif opcode == 'st': if dest == FLAG_C and src == ConstantRef(TYPE_BIT, 0): self.emitter.emit(CLC()) elif dest == FLAG_C and src == ConstantRef(TYPE_BIT, 1): self.emitter.emit(SEC()) else: op_cls = {REG_A: STA, REG_X: STX, REG_Y: STY}.get(src, None) if isinstance(dest, IndexedRef): mode_cls = { REG_X: AbsoluteX, REG_Y: AbsoluteY, }[dest.index] operand = mode_cls( Offset(self.get_label(dest.ref.name), dest.offset.value)) elif isinstance(dest, IndirectRef) and isinstance( self.get_type(dest.ref), PointerType): operand = IndirectY(self.get_label(dest.ref.name)) else: operand = self.absolute_or_zero_page( self.get_label(dest.name)) if op_cls is None: raise UnsupportedOpcodeError(instr) self.emitter.emit(op_cls(operand)) elif opcode == 'add': if dest == REG_X or dest == REG_Y: raise UnsupportedOpcodeError(instr) if dest == REG_A: if isinstance(src, ConstantRef): self.emitter.emit(ADC(Immediate(Byte(src.value)))) elif isinstance(src, IndexedRef): mode = self.addressing_mode_for_index(src.index) self.emitter.emit( ADC( mode( Offset(self.get_label(src.ref.name), src.offset.value)))) else: self.emitter.emit(ADC(Absolute(self.get_label(src.name)))) elif isinstance(dest, LocationRef) and self.get_type( src) == TYPE_BYTE and self.get_type(dest) == TYPE_BYTE: if isinstance(src, ConstantRef): dest_label = self.get_label(dest.name) self.emitter.emit(LDA(Absolute(dest_label))) self.emitter.emit(ADC(Immediate(Byte(src.low_byte())))) self.emitter.emit(STA(Absolute(dest_label))) elif isinstance(src, LocationRef): src_label = self.get_label(src.name) dest_label = self.get_label(dest.name) self.emitter.emit(LDA(Absolute(dest_label))) self.emitter.emit(ADC(Absolute(src_label))) self.emitter.emit(STA(Absolute(dest_label))) else: raise UnsupportedOpcodeError(instr) elif isinstance(dest, LocationRef) and self.get_type( src) == TYPE_WORD and self.get_type(dest) == TYPE_WORD: if isinstance(src, ConstantRef): dest_label = self.get_label(dest.name) self.emitter.emit(LDA(Absolute(dest_label))) self.emitter.emit(ADC(Immediate(Byte(src.low_byte())))) self.emitter.emit(STA(Absolute(dest_label))) self.emitter.emit(LDA(Absolute(Offset(dest_label, 1)))) self.emitter.emit(ADC(Immediate(Byte(src.high_byte())))) self.emitter.emit(STA(Absolute(Offset(dest_label, 1)))) elif isinstance(src, LocationRef): src_label = self.get_label(src.name) dest_label = self.get_label(dest.name) self.emitter.emit(LDA(Absolute(dest_label))) self.emitter.emit(ADC(Absolute(src_label))) self.emitter.emit(STA(Absolute(dest_label))) self.emitter.emit(LDA(Absolute(Offset(dest_label, 1)))) self.emitter.emit(ADC(Absolute(Offset(src_label, 1)))) self.emitter.emit(STA(Absolute(Offset(dest_label, 1)))) else: raise UnsupportedOpcodeError(instr) elif isinstance(dest, LocationRef) and self.get_type( src) == TYPE_WORD and isinstance(self.get_type(dest), PointerType): if isinstance(src, ConstantRef): dest_label = self.get_label(dest.name) self.emitter.emit(LDA(ZeroPage(dest_label))) self.emitter.emit(ADC(Immediate(Byte(src.low_byte())))) self.emitter.emit(STA(ZeroPage(dest_label))) self.emitter.emit(LDA(ZeroPage(Offset(dest_label, 1)))) self.emitter.emit(ADC(Immediate(Byte(src.high_byte())))) self.emitter.emit(STA(ZeroPage(Offset(dest_label, 1)))) elif isinstance(src, LocationRef): src_label = self.get_label(src.name) dest_label = self.get_label(dest.name) self.emitter.emit(LDA(ZeroPage(dest_label))) self.emitter.emit(ADC(Absolute(src_label))) self.emitter.emit(STA(ZeroPage(dest_label))) self.emitter.emit(LDA(ZeroPage(Offset(dest_label, 1)))) self.emitter.emit(ADC(Absolute(Offset(src_label, 1)))) self.emitter.emit(STA(ZeroPage(Offset(dest_label, 1)))) else: raise UnsupportedOpcodeError(instr) else: raise UnsupportedOpcodeError(instr) elif opcode == 'sub': if dest == REG_X or dest == REG_Y: raise UnsupportedOpcodeError(instr) if dest == REG_A: if isinstance(src, ConstantRef): self.emitter.emit(SBC(Immediate(Byte(src.value)))) elif isinstance(src, IndexedRef): mode = self.addressing_mode_for_index(src.index) self.emitter.emit( SBC( mode( Offset(self.get_label(src.ref.name), src.offset.value)))) else: self.emitter.emit(SBC(Absolute(self.get_label(src.name)))) elif isinstance(dest, LocationRef) and self.get_type( src) == TYPE_BYTE and self.get_type(dest) == TYPE_BYTE: if isinstance(src, ConstantRef): dest_label = self.get_label(dest.name) self.emitter.emit(LDA(Absolute(dest_label))) self.emitter.emit(SBC(Immediate(Byte(src.low_byte())))) self.emitter.emit(STA(Absolute(dest_label))) elif isinstance(src, LocationRef): src_label = self.get_label(src.name) dest_label = self.get_label(dest.name) self.emitter.emit(LDA(Absolute(dest_label))) self.emitter.emit(SBC(Absolute(src_label))) self.emitter.emit(STA(Absolute(dest_label))) else: raise UnsupportedOpcodeError(instr) elif isinstance(dest, LocationRef) and self.get_type( src) == TYPE_WORD and self.get_type(dest) == TYPE_WORD: if isinstance(src, ConstantRef): dest_label = self.get_label(dest.name) self.emitter.emit(LDA(Absolute(dest_label))) self.emitter.emit(SBC(Immediate(Byte(src.low_byte())))) self.emitter.emit(STA(Absolute(dest_label))) self.emitter.emit(LDA(Absolute(Offset(dest_label, 1)))) self.emitter.emit(SBC(Immediate(Byte(src.high_byte())))) self.emitter.emit(STA(Absolute(Offset(dest_label, 1)))) elif isinstance(src, LocationRef): src_label = self.get_label(src.name) dest_label = self.get_label(dest.name) self.emitter.emit(LDA(Absolute(dest_label))) self.emitter.emit(SBC(Absolute(src_label))) self.emitter.emit(STA(Absolute(dest_label))) self.emitter.emit(LDA(Absolute(Offset(dest_label, 1)))) self.emitter.emit(SBC(Absolute(Offset(src_label, 1)))) self.emitter.emit(STA(Absolute(Offset(dest_label, 1)))) else: raise UnsupportedOpcodeError(instr) else: raise UnsupportedOpcodeError(instr) elif opcode == 'cmp': self.compile_cmp(instr, instr.src, instr.dest) elif opcode in ( 'and', 'or', 'xor', ): cls = { 'and': AND, 'or': ORA, 'xor': EOR, }[opcode] if dest == REG_A: if isinstance(src, ConstantRef): self.emitter.emit(cls(Immediate(Byte(src.value)))) elif isinstance(src, IndexedRef): mode = self.addressing_mode_for_index(src.index) self.emitter.emit( cls( mode( Offset(self.get_label(src.ref.name), src.offset.value)))) else: self.emitter.emit( cls( self.absolute_or_zero_page(self.get_label( src.name)))) else: raise UnsupportedOpcodeError(instr) elif opcode == 'inc': self.compile_inc(instr, instr.dest) elif opcode == 'dec': self.compile_dec(instr, instr.dest) elif opcode in ('shl', 'shr'): cls = { 'shl': ROL, 'shr': ROR, }[opcode] if dest == REG_A: self.emitter.emit(cls()) elif isinstance(dest, IndexedRef): mode = self.addressing_mode_for_index(dest.index) self.emitter.emit( cls( mode( Offset(self.get_label(dest.ref.name), dest.offset.value)))) else: self.emitter.emit( cls(self.absolute_or_zero_page(self.get_label(dest.name)))) elif opcode == 'copy': self.compile_copy(instr, instr.src, instr.dest) elif opcode == 'trash': pass elif opcode == 'nop': self.emitter.emit(NOP()) else: raise NotImplementedError(opcode)
def write_prelude(self): self.write_header() for byte in self.prelude: self.emitter.emit(Byte(byte))