Ophis/tools/opcodes/gensets.py

170 lines
5.2 KiB
Python

#!/usr/bin/python
import sys
verbose = 0
prologue = '"""' + """Opcodes file.
Tables for the assembly of 6502-family instructions, mapping
opcodes and addressing modes to binary instructions.""" + '"""' + """
# Copyright 2002-2012 Michael C. Martin and additional contributors.
# You may use, modify, and distribute this file under the MIT
# license: See README for details.
# DO NOT EDIT THIS FILE DIRECTLY.
# This file was automatically generated by gensets.py based on the
# the tables in tools/opcodes. Edit those tables, not these.
# Names of addressing modes
modes = ["Implied", # 0
"Immediate", # 1
"Zero Page", # 2
"Zero Page, X", # 3
"Zero Page, Y", # 4
"Absolute", # 5
"Absolute, X", # 6
"Absolute, Y", # 7
"(Absolute)", # 8
"(Absolute, X)", # 9
"(Absolute), Y", # 10
"(Zero Page)", # 11
"(Zero Page, X)", # 12
"(Zero Page), Y", # 13
"Relative"] # 14
# Lengths of the argument
lengths = [0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1]
"""
# These values should match the ones in the prologue string.
modes = ["Implied", # 0
"Immediate", # 1
"Zero Page", # 2
"Zero Page, X", # 3
"Zero Page, Y", # 4
"Absolute", # 5
"Absolute, X", # 6
"Absolute, Y", # 7
"(Absolute)", # 8
"(Absolute, X)", # 9
"(Absolute), Y", # 10
"(Zero Page)", # 11
"(Zero Page, X)", # 12
"(Zero Page), Y", # 13
"Relative"] # 14
flatmodes = [x.lower() for x in modes]
# WARNING: This decommenter assumes that # never appears anywhere else
# in a line.
def decomment(l):
if '#' in l:
l = l[:l.index('#')]
return l.strip()
def decomment_readlines(fname):
result = [decomment(x) for x in file(fname).readlines()]
return [x for x in result if len(x) > 0]
def parse_chipset_file(fname):
result = [None] * 256
ls = [[x.strip() for x in y]
for y in [z.split(':', 1) for z in decomment_readlines(fname)]]
for l in ls:
if len(l) == 2:
try:
op = int(l[0], 16)
syns = l[1].split(';')
for s in syns:
s_p = s.split('-')
if len(s_p) == 2:
mnem = s_p[0].lower().strip()
mode = s_p[1].lower().strip()
if mode in flatmodes:
if result[op] is None:
result[op] = []
result[op].append((mnem, flatmodes.index(mode)))
else:
print "Unknown mode '%s'" % s_p[1]
except ValueError:
print "Illegal opcode '%s'" % l[0]
return result
def collate_chipset_map(cs_list, base):
result = {}
for (opcode, insts) in zip(range(256), cs_list):
if insts is not None:
for inst in insts:
(mnem, mode) = inst
if mnem not in result:
result[mnem] = [None] * len(modes)
if result[mnem][mode] is not None:
print "Warning: Reassigning %s - %s" % (mnem, modes[mode])
result[mnem][mode] = opcode
if base is not None:
todel = []
for x in result:
if x in base:
if result[x] == base[x]:
todel.append(x)
elif verbose != 0:
print "# Opcode %s changed" % x
elif verbose != 0:
print "# Opcode %s added" % x
for x in todel:
del result[x]
return result
def mapval(x):
if x is None:
return "None"
else:
return "0x%02X" % x
def dump_map(m, prologue=''):
mnems = m.keys()
mnems.sort()
for mnem in mnems:
codes = [mapval(x) for x in m[mnem]]
print "%s'%s': [%s,\n%s %s]," % (prologue, mnem,
', '.join(codes[:8]),
prologue + " " * len(mnem),
', '.join(codes[8:]))
if __name__ == '__main__':
if len(sys.argv) > 1:
chipsets = argv[1:]
else:
chipsets = ['chipsets.txt']
archs = []
for x in chipsets:
try:
ls = [[x.strip() for x in y]
for y in [z.split(':', 1) for z in decomment_readlines(x)]]
for l in ls:
if len(l) != 2:
print "Could not parse the chipset line '%s'" % ":".join(l)
else:
archs.append((l[0], l[1]))
except IOError:
print "Could not read file %s" % x
print prologue
baseset = None
for (field, fname) in archs:
chipset_list = parse_chipset_file(fname)
instruction_map = collate_chipset_map(chipset_list, baseset)
if baseset is None:
baseset = instruction_map
print "%s = {" % field
dump_map(instruction_map, ' ' * (len(field) + 4))
print "%s}" % (' ' * (len(field) + 3))