2015-10-16 22:12:52 +00:00
|
|
|
# encoding: UTF-8
|
|
|
|
|
|
|
|
from sixtypical.ast import Program, Routine, Block, Instr
|
|
|
|
from sixtypical.model import (
|
|
|
|
ConstantRef, LocationRef,
|
|
|
|
REG_A, REG_X, REG_Y, FLAG_Z, FLAG_N, FLAG_V, FLAG_C
|
|
|
|
)
|
2015-10-17 14:06:50 +00:00
|
|
|
from sixtypical.emitter import Label, Byte
|
2015-10-17 10:08:25 +00:00
|
|
|
from sixtypical.gen6502 import (
|
|
|
|
Immediate, Absolute,
|
2015-10-17 14:46:28 +00:00
|
|
|
LDA, LDX, LDY, STA, STX, STY, CLC, SEC, ADC, RTS, JSR,
|
|
|
|
INC, INX, INY, DEC, DEX, DEY,
|
2015-10-17 10:08:25 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class UnsupportedOpcodeError(KeyError):
|
|
|
|
pass
|
2015-10-16 22:12:52 +00:00
|
|
|
|
|
|
|
|
2015-10-17 14:06:50 +00:00
|
|
|
class Compiler(object):
|
|
|
|
def __init__(self, emitter):
|
|
|
|
self.emitter = emitter
|
|
|
|
self.routines = {}
|
|
|
|
self.labels = {}
|
2015-10-16 22:12:52 +00:00
|
|
|
|
2015-10-17 14:06:50 +00:00
|
|
|
def compile_program(self, program):
|
|
|
|
assert isinstance(program, Program)
|
2015-10-17 14:46:28 +00:00
|
|
|
|
|
|
|
for defn in program.defns:
|
|
|
|
label = Label(defn.name)
|
|
|
|
self.labels[defn.name] = label
|
|
|
|
|
2015-10-17 14:06:50 +00:00
|
|
|
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
|
2015-10-17 14:23:00 +00:00
|
|
|
|
|
|
|
self.compile_routine(self.routines['main'])
|
2015-10-17 14:06:50 +00:00
|
|
|
for routine in program.routines:
|
2015-10-17 14:23:00 +00:00
|
|
|
if routine.name != 'main':
|
|
|
|
self.compile_routine(routine)
|
2015-10-16 22:12:52 +00:00
|
|
|
|
2015-10-17 14:46:28 +00:00
|
|
|
for defn in program.defns:
|
|
|
|
label = self.labels[defn.name]
|
|
|
|
self.emitter.resolve_bss_label(label)
|
|
|
|
|
2015-10-17 14:06:50 +00:00
|
|
|
def compile_routine(self, routine):
|
|
|
|
assert isinstance(routine, Routine)
|
|
|
|
if routine.block:
|
2015-10-17 14:23:00 +00:00
|
|
|
self.emitter.resolve_label(self.labels[routine.name])
|
2015-10-17 14:06:50 +00:00
|
|
|
self.compile_block(routine.block)
|
|
|
|
self.emitter.emit(RTS())
|
2015-10-16 22:12:52 +00:00
|
|
|
|
2015-10-17 14:06:50 +00:00
|
|
|
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
|
2015-10-16 22:12:52 +00:00
|
|
|
|
2015-10-17 14:06:50 +00:00
|
|
|
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:
|
2015-10-17 14:23:00 +00:00
|
|
|
self.emitter.emit(LDA(Absolute(self.labels[src.name])))
|
2015-10-17 14:06:50 +00:00
|
|
|
elif dest == REG_X:
|
2015-10-17 14:23:00 +00:00
|
|
|
if isinstance(src, ConstantRef):
|
|
|
|
self.emitter.emit(LDX(Immediate(Byte(src.value))))
|
|
|
|
else:
|
|
|
|
self.emitter.emit(LDX(Absolute(self.labels[src.name])))
|
2015-10-17 14:06:50 +00:00
|
|
|
elif dest == REG_Y:
|
2015-10-17 14:23:00 +00:00
|
|
|
if isinstance(src, ConstantRef):
|
|
|
|
self.emitter.emit(LDY(Immediate(Byte(src.value))))
|
|
|
|
else:
|
|
|
|
self.emitter.emit(LDY(Absolute(self.labels[src.name])))
|
2015-10-17 09:17:44 +00:00
|
|
|
else:
|
2015-10-17 14:06:50 +00:00
|
|
|
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:
|
2015-10-17 14:23:00 +00:00
|
|
|
self.emitter.emit(STA(Absolute(self.labels[dest.name])))
|
2015-10-17 14:06:50 +00:00
|
|
|
elif src == REG_X:
|
2015-10-17 14:23:00 +00:00
|
|
|
self.emitter.emit(STX(Absolute(self.labels[dest.name])))
|
2015-10-17 14:06:50 +00:00
|
|
|
elif src == REG_Y:
|
2015-10-17 14:23:00 +00:00
|
|
|
self.emitter.emit(STY(Absolute(self.labels[dest.name])))
|
2015-10-17 14:06:50 +00:00
|
|
|
else:
|
|
|
|
raise UnsupportedOpcodeError(instr)
|
|
|
|
elif opcode == 'add':
|
|
|
|
if dest == REG_A:
|
|
|
|
if isinstance(src, ConstantRef):
|
|
|
|
self.emitter.emit(ADC(Immediate(Byte(src.value))))
|
|
|
|
else:
|
2015-10-17 14:46:28 +00:00
|
|
|
self.emitter.emit(ADC(Absolute(self.labels[src.name])))
|
2015-10-17 10:08:25 +00:00
|
|
|
else:
|
2015-10-17 14:06:50 +00:00
|
|
|
raise UnsupportedOpcodeError(instr)
|
|
|
|
elif opcode == 'sub':
|
2015-10-17 14:46:28 +00:00
|
|
|
if dest == REG_A:
|
|
|
|
if isinstance(src, ConstantRef):
|
|
|
|
self.emitter.emit(SBC(Immediate(Byte(src.value))))
|
|
|
|
else:
|
|
|
|
self.emitter.emit(SBC(Absolute(self.labels[src.name])))
|
|
|
|
else:
|
|
|
|
raise UnsupportedOpcodeError(instr)
|
2015-10-17 14:06:50 +00:00
|
|
|
elif opcode == 'inc':
|
2015-10-17 14:46:28 +00:00
|
|
|
if dest == REG_X:
|
|
|
|
self.emitter.emit(INX())
|
|
|
|
elif dest == REG_Y:
|
|
|
|
self.emitter.emit(INY())
|
|
|
|
else:
|
|
|
|
self.emitter.emit(INC(Absolute(self.labels[dest.name])))
|
2015-10-17 14:06:50 +00:00
|
|
|
elif opcode == 'dec':
|
2015-10-17 14:46:28 +00:00
|
|
|
if dest == REG_X:
|
|
|
|
self.emitter.emit(DEX())
|
|
|
|
elif dest == REG_Y:
|
|
|
|
self.emitter.emit(DEY())
|
|
|
|
else:
|
|
|
|
self.emitter.emit(DEC(Absolute(self.labels[dest.name])))
|
2015-10-17 14:06:50 +00:00
|
|
|
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
|
2015-10-17 10:08:25 +00:00
|
|
|
else:
|
2015-10-17 14:06:50 +00:00
|
|
|
raise NotImplementedError
|