diff --git a/README.markdown b/README.markdown index 55877a5..9ffcd27 100644 --- a/README.markdown +++ b/README.markdown @@ -33,9 +33,7 @@ TODO For 0.3: -* extern routines. * generate 6502 code for all SixtyPical instructions. -* a little demo that actually compiles and does something on a C64 emulator. For 0.4: diff --git a/bin/sixtypical b/bin/sixtypical index 3ff56bb..03013b5 100755 --- a/bin/sixtypical +++ b/bin/sixtypical @@ -21,7 +21,7 @@ from sixtypical.parser import Parser from sixtypical.evaluator import eval_program from sixtypical.analyzer import analyze_program from sixtypical.emitter import Emitter, Byte, Word -from sixtypical.compiler import compile_program +from sixtypical.compiler import Compiler if __name__ == '__main__': @@ -75,7 +75,8 @@ if __name__ == '__main__': emitter.emit(Word(start_addr)) for byte in header: emitter.emit(Byte(byte)) - compile_program(program, emitter) + compiler = Compiler(emitter) + compiler.compile_program(program) if options.debug: print repr(emitter.accum) else: diff --git a/eg/print.60p b/eg/print.60p new file mode 100644 index 0000000..c1c29c3 --- /dev/null +++ b/eg/print.60p @@ -0,0 +1,12 @@ +routine chrout + inputs a + trashes a + @ 65490 + +routine main + inputs a + trashes a, z, n +{ + ld a, 65 + call chrout +} diff --git a/src/sixtypical/compiler.py b/src/sixtypical/compiler.py index 240fdcf..df83c54 100644 --- a/src/sixtypical/compiler.py +++ b/src/sixtypical/compiler.py @@ -5,10 +5,10 @@ from sixtypical.model import ( ConstantRef, LocationRef, REG_A, REG_X, REG_Y, FLAG_Z, FLAG_N, FLAG_V, FLAG_C ) -from sixtypical.emitter import Byte +from sixtypical.emitter import Label, Byte from sixtypical.gen6502 import ( Immediate, Absolute, - LDA, LDX, LDY, STA, STX, STY, CLC, SEC, ADC, RTS + LDA, LDX, LDY, STA, STX, STY, CLC, SEC, ADC, RTS, JSR ) @@ -16,90 +16,97 @@ class UnsupportedOpcodeError(KeyError): pass -def compile_program(program, emitter): - assert isinstance(program, Program) - routines = {r.name: r for r in program.routines} - for routine in program.routines: - compile_routine(routine, emitter, routines) +class Compiler(object): + def __init__(self, emitter): + self.emitter = emitter + self.routines = {} + self.labels = {} + def compile_program(self, program): + assert isinstance(program, Program) + 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 + for routine in program.routines: + self.compile_routine(routine) -def compile_routine(routine, emitter, routines): - assert isinstance(routine, Routine) - label = emitter.make_label(routine.name) - if routine.block: - compile_block(routine.block, emitter, routines) - emitter.emit(RTS()) - return label + def compile_routine(self, routine): + assert isinstance(routine, Routine) + if routine.block: + self.compile_block(routine.block) + self.emitter.emit(RTS()) + def compile_block(self, block): + assert isinstance(block, Block) + label = self.emitter.make_label() + for instr in block.instrs: + self.compile_instr(instr) + return label -def compile_block(block, emitter, routines): - assert isinstance(block, Block) - label = emitter.make_label() - for instr in block.instrs: - compile_instr(instr, emitter, routines) - return label - - -def compile_instr(instr, emitter, routines): - assert isinstance(instr, Instr) - opcode = instr.opcode - dest = instr.dest - src = instr.src - - if opcode == 'ld': - if dest == REG_A: - if isinstance(src, ConstantRef): - emitter.emit(LDA(Immediate(Byte(src.value)))) + def compile_instr(self, instr): + assert isinstance(instr, Instr) + opcode = instr.opcode + dest = instr.dest + src = instr.src + + if opcode == 'ld': + if dest == REG_A: + if isinstance(src, ConstantRef): + self.emitter.emit(LDA(Immediate(Byte(src.value)))) + else: + self.emitter.emit(LDA(Absolute(src.label))) + elif dest == REG_X: + pass + elif dest == REG_Y: + pass else: - emitter.emit(LDA(Absolute(src.label))) - elif dest == REG_X: - pass - elif dest == REG_Y: - pass - else: - raise UnsupportedOpcodeError(instr) - elif opcode == 'st': - 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 UnsupportedOpcodeError(instr) - elif opcode == 'add': - if dest == REG_A: - if isinstance(src, ConstantRef): - emitter.emit(ADC(Immediate(Byte(src.value)))) + raise UnsupportedOpcodeError(instr) + elif opcode == 'st': + if dest == FLAG_C and src == ConstantRef(0): + self.emitter.emit(CLC()) + elif dest == FLAG_C and src == ConstantRef(1): + self.emitter.emit(SEC()) + elif src == REG_A: + self.emitter.emit(STA(Absolute(dest.label))) + elif src == REG_X: + self.emitter.emit(STX(Absolute(dest.label))) + elif src == REG_Y: + self.emitter.emit(STY(Absolute(dest.label))) else: - emitter.emit(ADC(Absolute(src.label))) + raise UnsupportedOpcodeError(instr) + elif opcode == 'add': + if dest == REG_A: + if isinstance(src, ConstantRef): + self.emitter.emit(ADC(Immediate(Byte(src.value)))) + else: + self.emitter.emit(ADC(Absolute(src.label))) + else: + raise UnsupportedOpcodeError(instr) + elif opcode == 'sub': + raise NotImplementedError + elif opcode == 'inc': + raise NotImplementedError + elif opcode == 'dec': + raise NotImplementedError + elif opcode == 'cmp': + raise NotImplementedError + elif opcode == 'and': + raise NotImplementedError + elif opcode == 'or': + raise NotImplementedError + elif opcode == 'xor': + raise NotImplementedError + elif opcode == 'shl': + raise NotImplementedError + elif opcode == 'shr': + raise NotImplementedError + elif opcode == 'call': + label = self.labels[instr.name] + self.emitter.emit(JSR(Absolute(label))) + elif opcode == 'if': + raise NotImplementedError else: - raise UnsupportedOpcodeError(instr) - elif opcode == 'sub': - raise NotImplementedError - elif opcode == 'inc': - raise NotImplementedError - elif opcode == 'dec': - raise NotImplementedError - elif opcode == 'cmp': - raise NotImplementedError - elif opcode == 'and': - raise NotImplementedError - elif opcode == 'or': - raise NotImplementedError - elif opcode == 'xor': - raise NotImplementedError - elif opcode == 'shl': - raise NotImplementedError - elif opcode == 'shr': - raise NotImplementedError - elif opcode == 'call': - raise NotImplementedError(instr.name) - elif opcode == 'if': - raise NotImplementedError - else: - raise NotImplementedError + raise NotImplementedError diff --git a/src/sixtypical/emitter.py b/src/sixtypical/emitter.py index f4dc0eb..e50ef7b 100644 --- a/src/sixtypical/emitter.py +++ b/src/sixtypical/emitter.py @@ -58,6 +58,10 @@ class Label(Emittable): assert self.addr is not None, "unresolved label: %s" % self.name return Word(self.addr).serialize() + def __repr__(self): + addrs = ', addr=%r' % self.addr if self.addr is not None else '' + return "%s(%r%s)" % (self.__class__.__name__, self.name, addrs) + class Emitter(object): def __init__(self, addr): diff --git a/src/sixtypical/gen6502.py b/src/sixtypical/gen6502.py index fc9b5cd..381d6f1 100644 --- a/src/sixtypical/gen6502.py +++ b/src/sixtypical/gen6502.py @@ -123,6 +123,12 @@ class INY(Opcode): } +class JSR(Opcode): + opcodes = { + Absolute: 0x20, + } + + class LDA(Opcode): opcodes = { Immediate: 0xa9, diff --git a/tests/SixtyPical Compilation.md b/tests/SixtyPical Compilation.md index 09327c7..5d5c26b 100644 --- a/tests/SixtyPical Compilation.md +++ b/tests/SixtyPical Compilation.md @@ -44,4 +44,4 @@ Call extern. | ld a, 65 | call chrout | } - = 00c018690460 + = 00c0a94120d2ff60