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:
parent
c0243ee6ba
commit
5b429adfd9
@ -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:
|
||||||
|
@ -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':
|
||||||
|
@ -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:
|
||||||
|
@ -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,
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user