From 5b429adfd99a98b96029743c5842d74f1ef2f245 Mon Sep 17 00:00:00 2001 From: Chris Pressey Date: Sat, 17 Oct 2015 11:08:25 +0100 Subject: [PATCH] 6502 opcodes are Emittables. Can compile simple programs now! --- bin/sixtypical | 8 +- src/sixtypical/compiler.py | 60 ++++++---- src/sixtypical/emitter.py | 59 +++++++--- src/sixtypical/gen6502.py | 235 ++++++++++++++++++++++++++++--------- 4 files changed, 264 insertions(+), 98 deletions(-) diff --git a/bin/sixtypical b/bin/sixtypical index bfeb77c..837933f 100755 --- a/bin/sixtypical +++ b/bin/sixtypical @@ -33,6 +33,9 @@ if __name__ == '__main__': optparser.add_option("--compile", action="store_true", dest="compile", default=False, help="") + optparser.add_option("--debug", + action="store_true", dest="debug", default=False, + help="") optparser.add_option("--traceback", action="store_true", dest="traceback", default=False, help="") @@ -61,7 +64,10 @@ if __name__ == '__main__': if options.compile: emitter = Emitter(41952) compile_program(program, emitter) - emitter.serialize(sys.stdout) + if options.debug: + print repr(emitter.accum) + else: + emitter.serialize(sys.stdout) if options.execute: context = eval_program(program) diff --git a/src/sixtypical/compiler.py b/src/sixtypical/compiler.py index 6ef108d..6197281 100644 --- a/src/sixtypical/compiler.py +++ b/src/sixtypical/compiler.py @@ -5,33 +5,41 @@ from sixtypical.model import ( ConstantRef, LocationRef, REG_A, REG_X, REG_Y, FLAG_Z, FLAG_N, FLAG_V, FLAG_C ) -from sixtypical.gen6502 import Generator +from sixtypical.emitter import Byte +from sixtypical.gen6502 import ( + Immediate, Absolute, + LDA, LDX, LDY, STA, STX, STY, CLC, SEC, ADC, RTS +) + + +class UnsupportedOpcodeError(KeyError): + pass def compile_program(program, emitter): assert isinstance(program, Program) - generator = Generator(emitter) routines = {r.name: r for r in program.routines} for routine in program.routines: - compile_routine(routine, generator, routines) + compile_routine(routine, emitter, routines) -def compile_routine(routine, generator, routines): +def compile_routine(routine, emitter, routines): assert isinstance(routine, Routine) - label = generator.emitter.make_label(routine.name) - compile_block(routine.block, generator, routines) + label = emitter.make_label(routine.name) + compile_block(routine.block, emitter, routines) + emitter.emit(RTS()) return label -def compile_block(block, generator, routines): +def compile_block(block, emitter, routines): assert isinstance(block, Block) - label = generator.emitter.make_label() + label = emitter.make_label() for instr in block.instrs: - compile_instr(instr, generator, routines) + compile_instr(instr, emitter, routines) return label -def compile_instr(instr, generator, routines): +def compile_instr(instr, emitter, routines): assert isinstance(instr, Instr) opcode = instr.opcode dest = instr.dest @@ -40,26 +48,36 @@ def compile_instr(instr, generator, routines): if opcode == 'ld': if dest == REG_A: if isinstance(src, ConstantRef): - # LDA #... - pass + emitter.emit(LDA(Immediate(Byte(src.value)))) else: - # LDA abs - pass + emitter.emit(LDA(Absolute(src.label))) elif dest == REG_X: pass elif dest == REG_Y: pass else: - raise KeyError + raise UnsupportedOpcodeError(instr) elif opcode == 'st': - if src == REG_A: - # assert isinstance(dest, MemoryRef) - # generate STA - pass + if dest == FLAG_C and src == ConstantRef(0): + emitter.emit(CLC()) + elif dest == FLAG_C and src == ConstantRef(1): + emitter.emit(SEC()) + elif src == REG_A: + emitter.emit(STA(Absolute(dest.label))) + elif src == REG_X: + emitter.emit(STX(Absolute(dest.label))) + elif src == REG_Y: + emitter.emit(STY(Absolute(dest.label))) else: - raise KeyError + raise UnsupportedOpcodeError(instr) elif opcode == 'add': - raise NotImplementedError + if dest == REG_A: + if isinstance(src, ConstantRef): + emitter.emit(ADC(Immediate(Byte(src.value)))) + else: + emitter.emit(ADC(Absolute(src.label))) + else: + raise UnsupportedOpcodeError(instr) elif opcode == 'sub': raise NotImplementedError elif opcode == 'inc': diff --git a/src/sixtypical/emitter.py b/src/sixtypical/emitter.py index d01ee87..f4dc0eb 100644 --- a/src/sixtypical/emitter.py +++ b/src/sixtypical/emitter.py @@ -1,5 +1,33 @@ -class Word(object): +class Emittable(object): + def size(self): + """Default implementation may not be very efficient.""" + return len(self.serialize()) + + def serialize(self): + raise NotImplementedError + + +class Byte(Emittable): def __init__(self, value): + if value < -127 or value > 255: + raise IndexError(thing) + if value < 0: + value += 256 + self.value = value + + def size(self): + return 1 + + def serialize(self): + return chr(self.value) + + def __repr__(self): + return "%s(%r)" % (self.__class__.__name__, self.value) + + +class Word(Emittable): + def __init__(self, value): + # TODO: range-checking self.value = value def size(self): @@ -11,8 +39,11 @@ class Word(object): high = (word >> 8) & 255 return chr(low) + chr(high) + def __repr__(self): + return "%s(%r)" % (self.__class__.__name__, self.value) -class Label(object): + +class Label(Emittable): def __init__(self, name, addr=None): self.name = name self.addr = addr @@ -24,8 +55,7 @@ class Label(object): return 2 def serialize(self): - if self.addr is None: - raise ValueError(self.addr) + assert self.addr is not None, "unresolved label: %s" % self.name return Word(self.addr).serialize() @@ -35,25 +65,16 @@ class Emitter(object): self.addr = addr self.name_counter = 0 - def gen(self, *things): + def emit(self, *things): for thing in things: if isinstance(thing, int): - if thing < -127 or thing > 255: - raise ValueError(thing) - if thing < 0: - thing += 256 - self.accum.append(thing) - self.addr += 1 - else: - self.accum.append(thing) - self.addr += thing.size() + thing = Byte(thing) + self.accum.append(thing) + self.addr += thing.size() def serialize(self, stream): - for thing in self.accum: - if isintance(thing, int): - stream.write(chr(thing)) - else: - stream.write(thing.serialize()) + for emittable in self.accum: + stream.write(emittable.serialize()) def make_label(self, name=None): if name is None: diff --git a/src/sixtypical/gen6502.py b/src/sixtypical/gen6502.py index ce21e08..fc9b5cd 100644 --- a/src/sixtypical/gen6502.py +++ b/src/sixtypical/gen6502.py @@ -1,91 +1,212 @@ """This is just a sketch for now.""" -from sixtypical.emitter import Emitter, Word, Label +from sixtypical.emitter import Emittable, Byte, Word, Label -class Generator(object): - def __init__(self, emitter): - self.emitter = emitter +class AddressingMode(object): + def size(self): + """Size of the operand for the mode (not including the opcode)""" + raise NotImplementedError - ### ld ### - def gen_lda_imm(self, b): - self.emitter.emit(0xa9, b) +class Implied(AddressingMode): + def size(self): + return 0 - def gen_lda_abs(self, addr): - self.emitter.emit(0xad, addr) + def serialize(self): + return '' - def gen_ldx_imm(self, b): - self.emitter.emit(0xa2, b) + def __repr__(self): + return "%s()" % (self.__class__.__name__) - def gen_ldx_abs(self, addr): - self.emitter.emit(0xae, addr) - def gen_tax(self): - self.emitter.emit(0xaa) +class Immediate(AddressingMode): + def __init__(self, value): + assert isinstance(value, Byte) + self.value = value - def gen_tay(self): - self.emitter.emit(0xa8) + def size(self): + return 1 - def gen_txa(self): - self.emitter.emit(0x8a) + def serialize(self): + return self.value.serialize() - def gen_tya(self): - self.emitter.emit(0x98) + def __repr__(self): + return "%s(%r)" % (self.__class__.__name__, self.value) - ### st ### - def gen_sta_abs(self, addr): - self.emitter.emit(0x8d, addr) +class Absolute(AddressingMode): + def __init__(self, value): + assert isinstance(value, (Word, Label)) + self.value = value - def gen_stx_abs(self, addr): - self.emitter.emit(0x8e, addr) + def size(self): + return 2 - def gen_sty_abs(self, addr): - self.emitter.emit(0x8c, addr) + def serialize(self): + return self.value.serialize() - ### add ### + def __repr__(self): + return "%s(%r)" % (self.__class__.__name__, self.value) - def gen_adc_imm(self, b): - self.emitter.emit(0x69, b) - def gen_adc_abs(self, addr): - self.emitter.emit(0x6d, addr) +class Opcode(Emittable): + def __init__(self, operand=None): + self.operand = operand or Implied() - ### sub ### + def size(self): + return 1 + self.operand.size() if self.operand else 0 - def gen_sbc_imm(self, b): - self.emitter.emit(0xe9, b) + def serialize(self): + return ( + chr(self.opcodes[self.operand.__class__]) + + self.operand.serialize() + ) - def gen_sbc_abs(self, addr): - self.emitter.emit(0xed, addr) + def __repr__(self): + return "%s(%r)" % (self.__class__.__name__, self.operand) - ### inc ### - def gen_inc_abs(self, addr): - self.emitter.emit(0xee, addr) +class ADC(Opcode): + opcodes = { + Immediate: 0x69, + Absolute: 0x6d, + } - def gen_inx(self): - self.emitter.emit(0xe8) - def gen_iny(self): - self.emitter.emit(0xc8) +class ADD(Opcode): + opcodes = { + Immediate: 0x29, + Absolute: 0x2d, + } - ### dec ### - def gen_dec_abs(self, addr): - self.emitter.emit(0xce, addr) +class CLC(Opcode): + opcodes = { + Implied: 0x18 + } - def gen_dex(self): - self.emitter.emit(0xca) - def gen_dey(self): - self.emitter.emit(0x88) +class DEC(Opcode): + opcodes = { + Absolute: 0xce, + } - ### and ### - def gen_and_imm(self, b): - self.emitter.emit(0x29, b) +class DEX(Opcode): + opcodes = { + Implied: 0xca, + } - def gen_and_abs(self, addr): - self.emitter.emit(0x2d, addr) + +class DEY(Opcode): + opcodes = { + Implied: 0x88, + } + + +class INC(Opcode): + opcodes = { + Absolute: 0xee, + } + + +class INX(Opcode): + opcodes = { + Implied: 0xe8, + } + + +class INY(Opcode): + opcodes = { + Implied: 0xc8, + } + + +class LDA(Opcode): + opcodes = { + Immediate: 0xa9, + Absolute: 0xad, + } + + +class LDX(Opcode): + opcodes = { + Immediate: 0xa2, + Absolute: 0xae, + } + + +class LDY(Opcode): + opcodes = { + Immediate: 0xa0, + Absolute: 0xac, + } + + +class ORA(Opcode): + opcodes = { + Immediate: 0x09, + Absolute: 0x0d, + } + + +class RTS(Opcode): + opcodes = { + Implied: 0x60, + } + + +class SBC(Opcode): + opcodes = { + Immediate: 0xe9, + Absolute: 0xed, + } + + +class SEC(Opcode): + opcodes = { + Implied: 0x38, + } + + +class STA(Opcode): + opcodes = { + Absolute: 0x8d, + } + + +class STX(Opcode): + opcodes = { + Absolute: 0x8e, + } + + +class STY(Opcode): + opcodes = { + Absolute: 0x8c, + } + + +class TAX(Opcode): + opcodes = { + Implied: 0xaa, + } + + +class TAY(Opcode): + opcodes = { + Implied: 0xa8, + } + + +class TXA(Opcode): + opcodes = { + Implied: 0x8a, + } + + +class TYA(Opcode): + opcodes = { + Implied: 0x98, + }