mirror of
https://github.com/catseye/SixtyPical.git
synced 2024-11-25 23:49:17 +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",
|
||||
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)
|
||||
|
@ -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':
|
||||
|
@ -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:
|
||||
|
@ -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,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user