1
0
mirror of https://github.com/catseye/SixtyPical.git synced 2025-02-20 13:29:09 +00:00

6502 opcodes are Emittables. Can compile simple programs now!

This commit is contained in:
Chris Pressey 2015-10-17 11:08:25 +01:00
parent c0243ee6ba
commit 5b429adfd9
4 changed files with 264 additions and 98 deletions

View File

@ -33,6 +33,9 @@ if __name__ == '__main__':
optparser.add_option("--compile", optparser.add_option("--compile",
action="store_true", dest="compile", default=False, action="store_true", dest="compile", default=False,
help="") help="")
optparser.add_option("--debug",
action="store_true", dest="debug", default=False,
help="")
optparser.add_option("--traceback", optparser.add_option("--traceback",
action="store_true", dest="traceback", default=False, action="store_true", dest="traceback", default=False,
help="") help="")
@ -61,6 +64,9 @@ if __name__ == '__main__':
if options.compile: if options.compile:
emitter = Emitter(41952) emitter = Emitter(41952)
compile_program(program, emitter) compile_program(program, emitter)
if options.debug:
print repr(emitter.accum)
else:
emitter.serialize(sys.stdout) emitter.serialize(sys.stdout)
if options.execute: if options.execute:

View File

@ -5,33 +5,41 @@ 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.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): def compile_program(program, emitter):
assert isinstance(program, Program) assert isinstance(program, Program)
generator = Generator(emitter)
routines = {r.name: r for r in program.routines} routines = {r.name: r for r in program.routines}
for routine 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) assert isinstance(routine, Routine)
label = generator.emitter.make_label(routine.name) label = emitter.make_label(routine.name)
compile_block(routine.block, generator, routines) compile_block(routine.block, emitter, routines)
emitter.emit(RTS())
return label return label
def compile_block(block, generator, routines): def compile_block(block, emitter, routines):
assert isinstance(block, Block) assert isinstance(block, Block)
label = generator.emitter.make_label() label = emitter.make_label()
for instr in block.instrs: for instr in block.instrs:
compile_instr(instr, generator, routines) compile_instr(instr, emitter, routines)
return label return label
def compile_instr(instr, generator, routines): 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
@ -40,26 +48,36 @@ def compile_instr(instr, generator, routines):
if opcode == 'ld': if opcode == 'ld':
if dest == REG_A: if dest == REG_A:
if isinstance(src, ConstantRef): if isinstance(src, ConstantRef):
# LDA #... emitter.emit(LDA(Immediate(Byte(src.value))))
pass
else: else:
# LDA abs emitter.emit(LDA(Absolute(src.label)))
pass
elif dest == REG_X: elif dest == REG_X:
pass pass
elif dest == REG_Y: elif dest == REG_Y:
pass pass
else: else:
raise KeyError raise UnsupportedOpcodeError(instr)
elif opcode == 'st': elif opcode == 'st':
if src == REG_A: if dest == FLAG_C and src == ConstantRef(0):
# assert isinstance(dest, MemoryRef) emitter.emit(CLC())
# generate STA elif dest == FLAG_C and src == ConstantRef(1):
pass 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: else:
raise KeyError raise UnsupportedOpcodeError(instr)
elif opcode == 'add': 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': elif opcode == 'sub':
raise NotImplementedError raise NotImplementedError
elif opcode == 'inc': elif opcode == 'inc':

View File

@ -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): 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 self.value = value
def size(self): def size(self):
@ -11,8 +39,11 @@ class Word(object):
high = (word >> 8) & 255 high = (word >> 8) & 255
return chr(low) + chr(high) 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): def __init__(self, name, addr=None):
self.name = name self.name = name
self.addr = addr self.addr = addr
@ -24,8 +55,7 @@ class Label(object):
return 2 return 2
def serialize(self): def serialize(self):
if self.addr is None: assert self.addr is not None, "unresolved label: %s" % self.name
raise ValueError(self.addr)
return Word(self.addr).serialize() return Word(self.addr).serialize()
@ -35,25 +65,16 @@ class Emitter(object):
self.addr = addr self.addr = addr
self.name_counter = 0 self.name_counter = 0
def gen(self, *things): def emit(self, *things):
for thing in things: for thing in things:
if isinstance(thing, int): if isinstance(thing, int):
if thing < -127 or thing > 255: thing = Byte(thing)
raise ValueError(thing)
if thing < 0:
thing += 256
self.accum.append(thing)
self.addr += 1
else:
self.accum.append(thing) self.accum.append(thing)
self.addr += thing.size() self.addr += thing.size()
def serialize(self, stream): def serialize(self, stream):
for thing in self.accum: for emittable in self.accum:
if isintance(thing, int): stream.write(emittable.serialize())
stream.write(chr(thing))
else:
stream.write(thing.serialize())
def make_label(self, name=None): def make_label(self, name=None):
if name is None: if name is None:

View File

@ -1,91 +1,212 @@
"""This is just a sketch for now.""" """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): class AddressingMode(object):
def __init__(self, emitter): def size(self):
self.emitter = emitter """Size of the operand for the mode (not including the opcode)"""
raise NotImplementedError
### ld ###
def gen_lda_imm(self, b): class Implied(AddressingMode):
self.emitter.emit(0xa9, b) def size(self):
return 0
def gen_lda_abs(self, addr): def serialize(self):
self.emitter.emit(0xad, addr) return ''
def gen_ldx_imm(self, b): def __repr__(self):
self.emitter.emit(0xa2, b) return "%s()" % (self.__class__.__name__)
def gen_ldx_abs(self, addr):
self.emitter.emit(0xae, addr)
def gen_tax(self): class Immediate(AddressingMode):
self.emitter.emit(0xaa) def __init__(self, value):
assert isinstance(value, Byte)
self.value = value
def gen_tay(self): def size(self):
self.emitter.emit(0xa8) return 1
def gen_txa(self): def serialize(self):
self.emitter.emit(0x8a) return self.value.serialize()
def gen_tya(self): def __repr__(self):
self.emitter.emit(0x98) return "%s(%r)" % (self.__class__.__name__, self.value)
### st ###
def gen_sta_abs(self, addr): class Absolute(AddressingMode):
self.emitter.emit(0x8d, addr) def __init__(self, value):
assert isinstance(value, (Word, Label))
self.value = value
def gen_stx_abs(self, addr): def size(self):
self.emitter.emit(0x8e, addr) return 2
def gen_sty_abs(self, addr): def serialize(self):
self.emitter.emit(0x8c, addr) 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): class Opcode(Emittable):
self.emitter.emit(0x6d, addr) 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): def serialize(self):
self.emitter.emit(0xe9, b) return (
chr(self.opcodes[self.operand.__class__]) +
self.operand.serialize()
)
def gen_sbc_abs(self, addr): def __repr__(self):
self.emitter.emit(0xed, addr) return "%s(%r)" % (self.__class__.__name__, self.operand)
### inc ###
def gen_inc_abs(self, addr): class ADC(Opcode):
self.emitter.emit(0xee, addr) opcodes = {
Immediate: 0x69,
Absolute: 0x6d,
}
def gen_inx(self):
self.emitter.emit(0xe8)
def gen_iny(self): class ADD(Opcode):
self.emitter.emit(0xc8) opcodes = {
Immediate: 0x29,
Absolute: 0x2d,
}
### dec ###
def gen_dec_abs(self, addr): class CLC(Opcode):
self.emitter.emit(0xce, addr) opcodes = {
Implied: 0x18
}
def gen_dex(self):
self.emitter.emit(0xca)
def gen_dey(self): class DEC(Opcode):
self.emitter.emit(0x88) opcodes = {
Absolute: 0xce,
}
### and ###
def gen_and_imm(self, b): class DEX(Opcode):
self.emitter.emit(0x29, b) 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,
}