1
0
mirror of https://github.com/catseye/SixtyPical.git synced 2024-06-18 03:29:32 +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",
action="store_true", dest="compile", default=False,
help="")
optparser.add_option("--debug",
action="store_true", dest="debug", default=False,
help="")
optparser.add_option("--traceback",
action="store_true", dest="traceback", default=False,
help="")
@ -61,7 +64,10 @@ if __name__ == '__main__':
if options.compile:
emitter = Emitter(41952)
compile_program(program, emitter)
emitter.serialize(sys.stdout)
if options.debug:
print repr(emitter.accum)
else:
emitter.serialize(sys.stdout)
if options.execute:
context = eval_program(program)

View File

@ -5,33 +5,41 @@ from sixtypical.model import (
ConstantRef, LocationRef,
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):
assert isinstance(program, Program)
generator = Generator(emitter)
routines = {r.name: r for r 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)
label = generator.emitter.make_label(routine.name)
compile_block(routine.block, generator, routines)
label = emitter.make_label(routine.name)
compile_block(routine.block, emitter, routines)
emitter.emit(RTS())
return label
def compile_block(block, generator, routines):
def compile_block(block, emitter, routines):
assert isinstance(block, Block)
label = generator.emitter.make_label()
label = emitter.make_label()
for instr in block.instrs:
compile_instr(instr, generator, routines)
compile_instr(instr, emitter, routines)
return label
def compile_instr(instr, generator, routines):
def compile_instr(instr, emitter, routines):
assert isinstance(instr, Instr)
opcode = instr.opcode
dest = instr.dest
@ -40,26 +48,36 @@ def compile_instr(instr, generator, routines):
if opcode == 'ld':
if dest == REG_A:
if isinstance(src, ConstantRef):
# LDA #...
pass
emitter.emit(LDA(Immediate(Byte(src.value))))
else:
# LDA abs
pass
emitter.emit(LDA(Absolute(src.label)))
elif dest == REG_X:
pass
elif dest == REG_Y:
pass
else:
raise KeyError
raise UnsupportedOpcodeError(instr)
elif opcode == 'st':
if src == REG_A:
# assert isinstance(dest, MemoryRef)
# generate STA
pass
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 KeyError
raise UnsupportedOpcodeError(instr)
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':
raise NotImplementedError
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):
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
def size(self):
@ -11,8 +39,11 @@ class Word(object):
high = (word >> 8) & 255
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):
self.name = name
self.addr = addr
@ -24,8 +55,7 @@ class Label(object):
return 2
def serialize(self):
if self.addr is None:
raise ValueError(self.addr)
assert self.addr is not None, "unresolved label: %s" % self.name
return Word(self.addr).serialize()
@ -35,25 +65,16 @@ class Emitter(object):
self.addr = addr
self.name_counter = 0
def gen(self, *things):
def emit(self, *things):
for thing in things:
if isinstance(thing, int):
if thing < -127 or thing > 255:
raise ValueError(thing)
if thing < 0:
thing += 256
self.accum.append(thing)
self.addr += 1
else:
self.accum.append(thing)
self.addr += thing.size()
thing = Byte(thing)
self.accum.append(thing)
self.addr += thing.size()
def serialize(self, stream):
for thing in self.accum:
if isintance(thing, int):
stream.write(chr(thing))
else:
stream.write(thing.serialize())
for emittable in self.accum:
stream.write(emittable.serialize())
def make_label(self, name=None):
if name is None:

View File

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