1
0
mirror of https://github.com/catseye/SixtyPical.git synced 2024-11-29 18:49:22 +00:00

Compiler object, labels, compile 'call'... It prints 'A'!

This commit is contained in:
Chris Pressey 2015-10-17 15:06:50 +01:00
parent 2ffff3bbdb
commit 643a48a2c5
7 changed files with 115 additions and 87 deletions

View File

@ -33,9 +33,7 @@ TODO
For 0.3: For 0.3:
* extern routines.
* generate 6502 code for all SixtyPical instructions. * generate 6502 code for all SixtyPical instructions.
* a little demo that actually compiles and does something on a C64 emulator.
For 0.4: For 0.4:

View File

@ -21,7 +21,7 @@ from sixtypical.parser import Parser
from sixtypical.evaluator import eval_program from sixtypical.evaluator import eval_program
from sixtypical.analyzer import analyze_program from sixtypical.analyzer import analyze_program
from sixtypical.emitter import Emitter, Byte, Word from sixtypical.emitter import Emitter, Byte, Word
from sixtypical.compiler import compile_program from sixtypical.compiler import Compiler
if __name__ == '__main__': if __name__ == '__main__':
@ -75,7 +75,8 @@ if __name__ == '__main__':
emitter.emit(Word(start_addr)) emitter.emit(Word(start_addr))
for byte in header: for byte in header:
emitter.emit(Byte(byte)) emitter.emit(Byte(byte))
compile_program(program, emitter) compiler = Compiler(emitter)
compiler.compile_program(program)
if options.debug: if options.debug:
print repr(emitter.accum) print repr(emitter.accum)
else: else:

12
eg/print.60p Normal file
View File

@ -0,0 +1,12 @@
routine chrout
inputs a
trashes a
@ 65490
routine main
inputs a
trashes a, z, n
{
ld a, 65
call chrout
}

View File

@ -5,10 +5,10 @@ from sixtypical.model import (
ConstantRef, LocationRef, ConstantRef, LocationRef,
REG_A, REG_X, REG_Y, FLAG_Z, FLAG_N, FLAG_V, FLAG_C 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 ( from sixtypical.gen6502 import (
Immediate, Absolute, Immediate, Absolute,
LDA, LDX, LDY, STA, STX, STY, CLC, SEC, ADC, RTS LDA, LDX, LDY, STA, STX, STY, CLC, SEC, ADC, RTS, JSR
) )
@ -16,31 +16,37 @@ class UnsupportedOpcodeError(KeyError):
pass pass
def compile_program(program, emitter): class Compiler(object):
def __init__(self, emitter):
self.emitter = emitter
self.routines = {}
self.labels = {}
def compile_program(self, program):
assert isinstance(program, Program) assert isinstance(program, Program)
routines = {r.name: r for r in program.routines}
for routine in program.routines: for routine in program.routines:
compile_routine(routine, emitter, 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(self, routine):
def compile_routine(routine, emitter, routines):
assert isinstance(routine, Routine) assert isinstance(routine, Routine)
label = emitter.make_label(routine.name)
if routine.block: if routine.block:
compile_block(routine.block, emitter, routines) self.compile_block(routine.block)
emitter.emit(RTS()) self.emitter.emit(RTS())
return label
def compile_block(self, block):
def compile_block(block, emitter, routines):
assert isinstance(block, Block) assert isinstance(block, Block)
label = emitter.make_label() label = self.emitter.make_label()
for instr in block.instrs: for instr in block.instrs:
compile_instr(instr, emitter, routines) self.compile_instr(instr)
return label return label
def compile_instr(self, instr):
def compile_instr(instr, emitter, routines):
assert isinstance(instr, Instr) assert isinstance(instr, Instr)
opcode = instr.opcode opcode = instr.opcode
dest = instr.dest dest = instr.dest
@ -49,9 +55,9 @@ def compile_instr(instr, emitter, routines):
if opcode == 'ld': if opcode == 'ld':
if dest == REG_A: if dest == REG_A:
if isinstance(src, ConstantRef): if isinstance(src, ConstantRef):
emitter.emit(LDA(Immediate(Byte(src.value)))) self.emitter.emit(LDA(Immediate(Byte(src.value))))
else: else:
emitter.emit(LDA(Absolute(src.label))) self.emitter.emit(LDA(Absolute(src.label)))
elif dest == REG_X: elif dest == REG_X:
pass pass
elif dest == REG_Y: elif dest == REG_Y:
@ -60,23 +66,23 @@ def compile_instr(instr, emitter, routines):
raise UnsupportedOpcodeError(instr) raise UnsupportedOpcodeError(instr)
elif opcode == 'st': elif opcode == 'st':
if dest == FLAG_C and src == ConstantRef(0): if dest == FLAG_C and src == ConstantRef(0):
emitter.emit(CLC()) self.emitter.emit(CLC())
elif dest == FLAG_C and src == ConstantRef(1): elif dest == FLAG_C and src == ConstantRef(1):
emitter.emit(SEC()) self.emitter.emit(SEC())
elif src == REG_A: elif src == REG_A:
emitter.emit(STA(Absolute(dest.label))) self.emitter.emit(STA(Absolute(dest.label)))
elif src == REG_X: elif src == REG_X:
emitter.emit(STX(Absolute(dest.label))) self.emitter.emit(STX(Absolute(dest.label)))
elif src == REG_Y: elif src == REG_Y:
emitter.emit(STY(Absolute(dest.label))) self.emitter.emit(STY(Absolute(dest.label)))
else: else:
raise UnsupportedOpcodeError(instr) raise UnsupportedOpcodeError(instr)
elif opcode == 'add': elif opcode == 'add':
if dest == REG_A: if dest == REG_A:
if isinstance(src, ConstantRef): if isinstance(src, ConstantRef):
emitter.emit(ADC(Immediate(Byte(src.value)))) self.emitter.emit(ADC(Immediate(Byte(src.value))))
else: else:
emitter.emit(ADC(Absolute(src.label))) self.emitter.emit(ADC(Absolute(src.label)))
else: else:
raise UnsupportedOpcodeError(instr) raise UnsupportedOpcodeError(instr)
elif opcode == 'sub': elif opcode == 'sub':
@ -98,7 +104,8 @@ def compile_instr(instr, emitter, routines):
elif opcode == 'shr': elif opcode == 'shr':
raise NotImplementedError raise NotImplementedError
elif opcode == 'call': elif opcode == 'call':
raise NotImplementedError(instr.name) label = self.labels[instr.name]
self.emitter.emit(JSR(Absolute(label)))
elif opcode == 'if': elif opcode == 'if':
raise NotImplementedError raise NotImplementedError
else: else:

View File

@ -58,6 +58,10 @@ class Label(Emittable):
assert self.addr is not None, "unresolved label: %s" % self.name assert self.addr is not None, "unresolved label: %s" % self.name
return Word(self.addr).serialize() 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): class Emitter(object):
def __init__(self, addr): def __init__(self, addr):

View File

@ -123,6 +123,12 @@ class INY(Opcode):
} }
class JSR(Opcode):
opcodes = {
Absolute: 0x20,
}
class LDA(Opcode): class LDA(Opcode):
opcodes = { opcodes = {
Immediate: 0xa9, Immediate: 0xa9,

View File

@ -44,4 +44,4 @@ Call extern.
| ld a, 65 | ld a, 65
| call chrout | call chrout
| } | }
= 00c018690460 = 00c0a94120d2ff60