1
0
mirror of https://github.com/catseye/SixtyPical.git synced 2024-11-25 23:49:17 +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,90 +16,97 @@ class UnsupportedOpcodeError(KeyError):
pass pass
def compile_program(program, emitter): class Compiler(object):
assert isinstance(program, Program) def __init__(self, emitter):
routines = {r.name: r for r in program.routines} self.emitter = emitter
for routine in program.routines: self.routines = {}
compile_routine(routine, emitter, 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): def compile_routine(self, routine):
assert isinstance(routine, Routine) assert isinstance(routine, Routine)
label = emitter.make_label(routine.name) if routine.block:
if routine.block: self.compile_block(routine.block)
compile_block(routine.block, emitter, routines) self.emitter.emit(RTS())
emitter.emit(RTS())
return label
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): def compile_instr(self, instr):
assert isinstance(block, Block) assert isinstance(instr, Instr)
label = emitter.make_label() opcode = instr.opcode
for instr in block.instrs: dest = instr.dest
compile_instr(instr, emitter, routines) src = instr.src
return label
if opcode == 'ld':
if dest == REG_A:
def compile_instr(instr, emitter, routines): if isinstance(src, ConstantRef):
assert isinstance(instr, Instr) self.emitter.emit(LDA(Immediate(Byte(src.value))))
opcode = instr.opcode else:
dest = instr.dest self.emitter.emit(LDA(Absolute(src.label)))
src = instr.src elif dest == REG_X:
pass
if opcode == 'ld': elif dest == REG_Y:
if dest == REG_A: pass
if isinstance(src, ConstantRef):
emitter.emit(LDA(Immediate(Byte(src.value))))
else: else:
emitter.emit(LDA(Absolute(src.label))) raise UnsupportedOpcodeError(instr)
elif dest == REG_X: elif opcode == 'st':
pass if dest == FLAG_C and src == ConstantRef(0):
elif dest == REG_Y: self.emitter.emit(CLC())
pass elif dest == FLAG_C and src == ConstantRef(1):
else: self.emitter.emit(SEC())
raise UnsupportedOpcodeError(instr) elif src == REG_A:
elif opcode == 'st': self.emitter.emit(STA(Absolute(dest.label)))
if dest == FLAG_C and src == ConstantRef(0): elif src == REG_X:
emitter.emit(CLC()) self.emitter.emit(STX(Absolute(dest.label)))
elif dest == FLAG_C and src == ConstantRef(1): elif src == REG_Y:
emitter.emit(SEC()) self.emitter.emit(STY(Absolute(dest.label)))
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))))
else: 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: else:
raise UnsupportedOpcodeError(instr) raise NotImplementedError
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

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