Ophis/src/tools/opcodes/gensets.py

183 lines
5.3 KiB
Python
Executable File

#!/usr/bin/env python3
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-2014 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",
"Immediate",
"ImmediateLong",
"Zero Page",
"Zero Page, X",
"Zero Page, Y",
"Absolute",
"Absolute, X",
"Absolute, Y",
"(Absolute)",
"(Absolute, X)",
"(Absolute), Y",
"(Absolute), Z",
"(Zero Page)",
"(Zero Page, X)",
"(Zero Page), Y",
"(Zero Page, SP), Y",
"(Zero Page), Z",
"Relative",
"RelativeLong",
"Zero Page, Relative"]
# Lengths of the argument
lengths = [0, 1, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2]
"""
# These values should match the ones in the prologue string.
modes = ["Implied",
"Immediate",
"Immediate.W",
"Zero Page",
"Zero Page, X",
"Zero Page, Y",
"Absolute",
"Absolute, X",
"Absolute, Y",
"(Absolute)",
"(Absolute, X)",
"(Absolute), Y",
"(Absolute), Z",
"(Zero Page)",
"(Zero Page, X)",
"(Zero Page), Y",
"(Zero Page, SP), Y",
"(Zero Page), Z",
"Relative",
"RelativeLong",
"Zero Page, Relative"]
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 open(fname, "rt").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(list(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 = list(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 = sys.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)))