1
0
mirror of https://github.com/mnaberez/py65.git synced 2024-10-01 04:55:47 +00:00

finish basic support for 65Org16, all tests passing

This commit is contained in:
BigEd 2011-08-20 21:50:26 +01:00
parent 0eb140d6c1
commit c264bd6707
5 changed files with 92 additions and 44 deletions

View File

@ -7,7 +7,7 @@ class Assembler:
r'\(?\s*)([^,\s\)]+)(\s*[,xXyY\s]*\)?'
r'[,xXyY\s]*)$')
Addressing = [
Addressing8 = [
['zpi', re.compile(r'^\(\$00([0-9A-F]{2})\)$')], # "($0012)"
['zpx', re.compile(r'^\$00([0-9A-F]{2}),X$')], # "$0012,X"
['zpy', re.compile(r'^\$00([0-9A-F]{2}),Y$')], # "$0012,Y"
@ -24,7 +24,25 @@ class Assembler:
['acc', re.compile(r'^A$')], # "A"
['imm', re.compile(r'^#\$([0-9A-F]{2})$')] # "#$12"
]
Addressing16 = [
['zpi', re.compile(r'^\(\$0000([0-9A-F]{4})\)$')], # "($00001234)"
['zpx', re.compile(r'^\$0000([0-9A-F]{4}),X$')], # "$00001234,X"
['zpy', re.compile(r'^\$0000([0-9A-F]{4}),Y$')], # "$00001234,Y"
['zpg', re.compile(r'^\$0000([0-9A-F]{4})$')], # "$00001234"
['inx', re.compile(r'^\(\$0000([0-9A-F]{4}),X\)$')], # "($00001234,X)"
['iny', re.compile(r'^\(\$0000([0-9A-F]{4})\),Y$')], # "($00001234),Y"
['ind', re.compile(r'^\(\$([0-9A-F]{4})([0-9A-F]{4})\)$')], # "($12345678)"
['abx', re.compile(r'^\$([0-9A-F]{4})([0-9A-F]{4}),X$')], # "$12345678,X"
['aby', re.compile(r'^\$([0-9A-F]{4})([0-9A-F]{4}),Y$')], # "$12345678,Y"
['abs', re.compile(r'^\$([0-9A-F]{4})([0-9A-F]{4})$')], # "$12345678"
['rel', re.compile(r'^\$([0-9A-F]{4})([0-9A-F]{4})$')], # "$12345678"
['imp', re.compile(r'^$')], # ""
['acc', re.compile(r'^$')], # ""
['acc', re.compile(r'^A$')], # "A"
['imm', re.compile(r'^#\$([0-9A-F]{4})$')] # "#$1234"
]
Addressing = Addressing8
def __init__(self, mpu, address_parser=None):
""" If a configured AddressParser is passed, symbolic addresses
may be used in the assembly statements.
@ -35,6 +53,18 @@ class Assembler:
self._mpu = mpu
self._address_parser = address_parser
self.addrWidth = mpu.addrWidth
self.byteWidth = mpu.byteWidth
self.addrFmt = mpu.addrFmt
self.byteFmt = mpu.byteFmt
self.addrMask = mpu.addrMask
self.byteMask = mpu.byteMask
if self.byteWidth == 8:
self.Addressing = self.Addressing8
else:
self.Addressing = self.Addressing16
def assemble(self, statement, pc=0000):
""" Assemble the given assembly language statement. If the statement
uses relative addressing, the program counter (pc) must also be given.
@ -58,8 +88,8 @@ class Assembler:
absolute = int(''.join(operands), 16)
relative = (absolute - pc) - 2
if (relative < 1):
relative = (relative ^ 0xFF) + 1
operands = [ ('%02x' % relative) ]
relative = (relative ^ self.byteMask) + 1
operands = [ (self.byteFmt % relative) ]
elif len(operands) == 2:
# swap bytes
@ -87,9 +117,9 @@ class Assembler:
# target is an immediate number
if target.startswith('#'):
number = self._address_parser.number(target[1:])
if (number < 0x00) or (number > 0xFF):
if (number < 0x00) or (number > self.byteMask):
raise OverflowError
statement = '%s#$%02x' % (before, number)
statement = before + '#$' + self.byteFmt % number
# target is the accumulator
elif target in ('a', 'A'):
@ -98,7 +128,7 @@ class Assembler:
# target is an address or label
else:
address = self._address_parser.number(target)
statement = '%s$%04x%s' % (before, address, after)
statement = before + '$' + self.addrFmt % address + after
# strip unnecessary whitespace
opcode = statement[:3].upper()

View File

@ -17,7 +17,7 @@ class MPU:
ZERO = 2
CARRY = 1
def __init__(self, memory=None, pc=0x0000, debug=False, byteWidth=8, addrWidth=16):
def __init__(self, memory=None, pc=0x0000, debug=False, byteWidth=8, addrWidth=16, addrFmt="%04x", byteFmt="%02x"):
# config
self.debug = debug
self.name = '6502'
@ -26,6 +26,8 @@ class MPU:
self.addrWidth = addrWidth
self.addrMask = ((1<<addrWidth)-1)
self.addrHighMask = (self.byteMask<<byteWidth)
self.addrFmt=addrFmt
self.byteFmt=byteFmt
self.spBase = 1<<byteWidth
# vm status

View File

@ -3,8 +3,8 @@ from py65.utils.devices import make_instruction_decorator
class MPU(mpu6502.MPU):
def __init__(self, byteWidth=16, addrWidth=32, *args, **kwargs):
mpu6502.MPU.__init__(self, byteWidth=byteWidth, addrWidth=addrWidth, *args, **kwargs)
def __init__(self, byteWidth=16, addrWidth=32, addrFmt="%08x", byteFmt="%04x", *args, **kwargs):
mpu6502.MPU.__init__(self, byteWidth=byteWidth, addrWidth=addrWidth, addrFmt=addrFmt, byteFmt=byteFmt, *args, **kwargs)
self.name = '65Org16'
self.waiting = False
self.IrqTo = (1<<self.addrWidth)-2

View File

@ -8,6 +8,13 @@ class Disassembler:
self._mpu = mpu
self._address_parser = address_parser
self.addrWidth = mpu.addrWidth
self.byteWidth = mpu.byteWidth
self.addrFmt = mpu.addrFmt
self.byteFmt = mpu.byteFmt
self.addrMask = mpu.addrMask
self.byteMask = mpu.byteMask
def instruction_at(self, pc):
""" Disassemble the instruction at PC and return a tuple
containing (instruction byte count, human readable text)
@ -23,27 +30,27 @@ class Disassembler:
elif addressing == 'abs':
address = self._mpu.WordAt(pc + 1)
address_or_label = self._address_parser.label_for(address,
'$%04x' % address)
'$' + self.addrFmt % address)
disasm += ' ' + address_or_label
length = 3
elif addressing == 'abx':
address = self._mpu.WordAt(pc + 1)
address_or_label = self._address_parser.label_for(address,
'$%04x' % address)
'$' + self.addrFmt % address)
disasm += ' %s,X' % address_or_label
length = 3
elif addressing == 'aby':
address = self._mpu.WordAt(pc + 1)
address_or_label = self._address_parser.label_for(address,
'$%04x' % address)
'$' + self.addrFmt % address)
disasm += ' %s,Y' % address_or_label
length = 3
elif addressing == 'imm':
byte = self._mpu.ByteAt(pc + 1)
disasm += ' #$%02x' % byte
disasm += ' #$' + self.byteFmt % byte
length = 2
elif addressing == 'imp':
@ -52,63 +59,63 @@ class Disassembler:
elif addressing == 'ind':
address = self._mpu.WordAt(pc + 1)
address_or_label = self._address_parser.label_for(address,
'$%04x' % address)
'$' + self.addrFmt % address)
disasm += ' (%s)' % address_or_label
length = 3
elif addressing == 'iny':
zp_address = self._mpu.ByteAt(pc + 1)
address_or_label = self._address_parser.label_for(zp_address,
'$%02x' % zp_address)
'$' + self.byteFmt % zp_address)
disasm += ' (%s),Y' % address_or_label
length = 2
elif addressing == 'inx':
zp_address = self._mpu.ByteAt(pc + 1)
address_or_label = self._address_parser.label_for(zp_address,
'$%02x' % zp_address)
'$' + self.byteFmt % zp_address)
disasm += ' (%s,X)' % address_or_label
length = 2
elif addressing == 'rel':
opv = self._mpu.ByteAt(pc + 1)
targ = pc + 2
if opv & 128:
targ -= (opv ^ 255) + 1
if opv & (1<<self.byteWidth):
targ -= (opv ^ self.byteMask) + 1
else:
targ += opv
targ &= 0xffff
targ &= self.addrMask
address_or_label = self._address_parser.label_for(targ,
'$%04x' % targ)
'$' + self.addrFmt % targ)
disasm += ' ' + address_or_label
length = 2
elif addressing == 'zpi':
zp_address = self._mpu.ByteAt(pc + 1)
address_or_label = self._address_parser.label_for(zp_address,
'($%02x)' % zp_address)
'($' + self.byteFmt % zp_address + ')' )
disasm += ' %s' % address_or_label
length = 2
elif addressing == 'zpg':
zp_address = self._mpu.ByteAt(pc + 1)
address_or_label = self._address_parser.label_for(zp_address,
'$%02x' % zp_address)
'$' + self.byteFmt % zp_address)
disasm += ' %s' % address_or_label
length = 2
elif addressing == 'zpx':
zp_address = self._mpu.ByteAt(pc + 1)
address_or_label = self._address_parser.label_for(zp_address,
'$%02x' % zp_address)
'$' + self.byteFmt % zp_address)
disasm += ' %s,X' % address_or_label
length = 2
elif addressing == 'zpy':
zp_address = self._mpu.ByteAt(pc + 1)
address_or_label = self._address_parser.label_for(zp_address,
'$%02x' % zp_address)
'$' + self.byteFmt % zp_address)
disasm += ' %s,Y' % address_or_label
length = 2

View File

@ -43,6 +43,12 @@ class Monitor(cmd.Cmd):
def _reset(self, mpu_type):
self._mpu = mpu_type()
self.addrWidth = self._mpu.addrWidth
self.byteWidth = self._mpu.byteWidth
self.addrFmt = self._mpu.addrFmt
self.byteFmt = self._mpu.byteFmt
self.addrMask = self._mpu.addrMask
self.byteMask = self._mpu.byteMask
self._install_mpu_observers()
self._address_parser = AddressParser()
self._disassembler = Disassembler(self._mpu, self._address_parser)
@ -113,7 +119,7 @@ class Monitor(cmd.Cmd):
byte = 0
return byte
m = ObservableMemory(addrWidth=self._mpu.addrWidth)
m = ObservableMemory(addrWidth=self.addrWidth)
m.subscribe_to_write([0xF001], putc)
m.subscribe_to_read([0xF004], getc)
@ -202,7 +208,7 @@ class Monitor(cmd.Cmd):
else:
end = start + len(bytes)
self._mpu.memory[start:end] = bytes
self.do_disassemble('%04x:%04x' % (start, end))
self.do_disassemble((self.addrFmt+":"+self.addrFmt) % (start, end))
def help_assemble(self):
self._output("assemble <address> <statement>")
@ -221,7 +227,7 @@ class Monitor(cmd.Cmd):
assembling = True
while assembling:
prompt = "\r$%04x " % (start)
prompt = "\r$" + ( self.addrFmt % start ) + " " + (" " * (1 + self.byteWidth/4) * 3)
line = console.line_input(prompt,
stdin=self.stdin, stdout=self.stdout)
@ -232,7 +238,7 @@ class Monitor(cmd.Cmd):
# assemble into memory
bytes = self._assembler.assemble(line)
if bytes is None:
self.stdout.write("\r$%04x ???\n" % start)
self.stdout.write("\r$" + (self.addrFmt % start) + " ???\n")
continue
end = start + len(bytes)
self._mpu.memory[start:end] = bytes
@ -259,9 +265,11 @@ class Monitor(cmd.Cmd):
def _format_disassembly(self, address, bytes, disasm):
mem = ''
for byte in self._mpu.memory[address:address+bytes]:
mem += '%02x ' % byte
mem += self.byteFmt % byte + " "
return "$%04x %-10s%s" % (address, mem, disasm)
fieldwidth = 1 + (1 + self.byteWidth/4) * 3
fieldfmt = "%%-%ds" % fieldwidth
return "$" + self.addrFmt % address + " " + fieldfmt % mem + disasm
def help_disassemble(self):
self._output("disassemble <address_range>")
@ -273,7 +281,7 @@ class Monitor(cmd.Cmd):
def do_step(self, args):
self._mpu.step()
self.do_disassemble('%04x' % self._mpu.pc)
self.do_disassemble(self.addrFmt % self._mpu.pc)
def help_return(self):
self._output("return")
@ -339,7 +347,7 @@ class Monitor(cmd.Cmd):
return
self._output("+%u" % num)
self._output("$%02x" % num)
self._output("$" + self.byteFmt % num)
self._output("%04o" % num)
self._output(itoa(num, 2).zfill(8))
@ -361,9 +369,9 @@ class Monitor(cmd.Cmd):
self._output("Invalid register: %s" % register)
else:
try:
intval = self._address_parser.number(value) & 0xFFFF
intval = self._address_parser.number(value) & self.addrMask
if len(register) == 1:
intval &= 0xFF
intval &= self.byteMask
setattr(self._mpu, register, intval)
except KeyError, why:
self._output(why[0])
@ -466,19 +474,20 @@ class Monitor(cmd.Cmd):
if start == end:
end = start + length - 1
if (end > 0xFFFF):
end = 0xFFFF
if (end > self.addrMask):
end = self.addrMask
while address <= end:
address &= 0xFFFF
self._mpu.memory[address] = (filler[index] & 0xFF)
address &= self.addrMask
self._mpu.memory[address] = (filler[index] & self.byteMask)
index += 1
if index == length:
index = 0
address += 1
fmt = (end - start + 1, start, end)
self._output("Wrote +%d bytes from $%04x to $%04x" % fmt)
starttoend = "$" + self.addrFmt + " to $" + self.addrFmt
self._output(("Wrote +%d bytes from " + starttoend) % fmt)
def help_mem(self):
self._output("mem <address_range>")
@ -487,15 +496,15 @@ class Monitor(cmd.Cmd):
def do_mem(self, args):
start, end = self._address_parser.range(args)
line = "%04x:" % start
line = self.addrFmt % start + ":"
for address in range(start, end+1):
byte = self._mpu.memory[address]
more = " %02x" % byte
more = " " + self.byteFmt % byte
exceeded = len(line) + len(more) > self._width
if exceeded:
self._output(line)
line = "%04x:" % address
line = self.addrFmt % address + ":"
line += more
self._output(line)
@ -525,7 +534,7 @@ class Monitor(cmd.Cmd):
byaddress = zip(values, keys)
byaddress.sort()
for address, label in byaddress:
self._output("%04x: %s" % (address, label))
self._output(self.addrFmt % address + ": " + label)
def help_delete_label(self):
self._output("delete_label <label>")