summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/m6502/m6502make.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/m6502/m6502make.py')
-rwxr-xr-xsrc/devices/cpu/m6502/m6502make.py280
1 files changed, 280 insertions, 0 deletions
diff --git a/src/devices/cpu/m6502/m6502make.py b/src/devices/cpu/m6502/m6502make.py
new file mode 100755
index 00000000000..4ac62e90ce9
--- /dev/null
+++ b/src/devices/cpu/m6502/m6502make.py
@@ -0,0 +1,280 @@
+#!/usr/bin/python
+
+from __future__ import print_function
+
+USAGE = """
+Usage:
+%s device_name {opc.lst|-} disp.lst device.inc
+"""
+import sys
+import logging
+
+MAX_STATES = 0
+
+def load_opcodes(fname):
+ """Load opcodes from .lst file"""
+ opcodes = []
+ logging.info("load_opcodes: %s", fname)
+ try:
+ f = open(fname, "rU")
+ except Exception:
+ err = sys.exc_info()[1]
+ logging.error("cannot read opcodes file %s [%s]", fname, err)
+ sys.exit(1)
+
+ for line in f:
+ if line.startswith("#"): continue
+ line = line.rstrip()
+ if not line: continue
+ if line.startswith(" ") or line.startswith("\t"):
+ # append instruction to last opcode
+ opcodes[-1][1].append(line)
+ else:
+ # add new opcode
+ opcodes.append((line, []))
+ return opcodes
+
+
+def load_disp(fname):
+ logging.info("load_disp: %s", fname)
+ states = []
+ try:
+ f = open(fname, "rU")
+ except Exception:
+ err = sys.exc_info()[1]
+ logging.error("cannot read display file %s [%s]", fname, err)
+ sys.exit(1)
+ for line in f:
+ if line.startswith("#"): continue
+ line = line.strip()
+ if not line: continue
+ tokens = line.split()
+ states += tokens
+ return states
+
+def emit(f, text):
+ """write string to file"""
+ print(text, file=f)
+
+FULL_PROLOG="""\
+void %(device)s::%(opcode)s_full()
+{
+"""
+
+FULL_EPILOG="""\
+}
+"""
+
+FULL_EAT_ALL="""\
+\ticount=0; inst_substate = %(substate)s; return;
+"""
+
+FULL_MEMORY="""\
+\tif(icount == 0) { inst_substate = %(substate)s; return; }
+%(ins)s
+\ticount--;
+"""
+
+FULL_NONE="""\
+%(ins)s
+"""
+
+PARTIAL_PROLOG="""\
+void %(device)s::%(opcode)s_partial()
+{
+switch(inst_substate) {
+case 0:
+"""
+
+PARTIAL_EPILOG="""\
+}
+\tinst_substate = 0;
+}
+
+"""
+
+PARTIAL_EAT_ALL="""\
+\ticount=0; inst_substate = %(substate)s; return;
+case %(substate)s:;
+"""
+
+PARTIAL_MEMORY="""\
+\tif(icount == 0) { inst_substate = %(substate)s; return; }
+case %(substate)s:
+%(ins)s
+\ticount--;
+"""
+
+PARTIAL_NONE="""\
+%(ins)s
+"""
+def identify_line_type(ins):
+ if "eat-all-cycles" in ins: return "EAT"
+ for s in ["read", "write", "prefetch(", "prefetch_noirq("]:
+ if s in ins:
+ return "MEMORY"
+ return "NONE"
+
+
+def save_opcodes(f, device, opcodes):
+ for name, instructions in opcodes:
+ d = { "device": device,
+ "opcode": name,
+ }
+
+ emit(f, FULL_PROLOG % d)
+ substate = 1
+ for ins in instructions:
+ d["substate"] = str(substate)
+ d["ins"] = ins
+ line_type = identify_line_type(ins)
+ if line_type == "EAT":
+ emit(f, FULL_EAT_ALL % d)
+ substate += 1
+ elif line_type == "MEMORY":
+ emit(f, FULL_MEMORY % d)
+ substate += 1
+ else:
+ emit(f, FULL_NONE %d)
+ emit(f, FULL_EPILOG % d)
+
+ emit(f, PARTIAL_PROLOG % d)
+ substate = 1
+ for ins in instructions:
+ d["substate"] = str(substate)
+ d["ins"] = ins
+ line_type = identify_line_type(ins)
+ if line_type == "EAT":
+ emit(f, PARTIAL_EAT_ALL % d)
+ substate += 1
+ elif line_type == "MEMORY":
+ emit(f, PARTIAL_MEMORY % d)
+ substate += 1
+ else:
+ emit(f, PARTIAL_NONE %d)
+ emit(f, PARTIAL_EPILOG % d)
+
+
+DO_EXEC_FULL_PROLOG="""\
+void %(device)s::do_exec_full()
+{
+\tswitch(inst_state) {
+"""
+
+DO_EXEC_FULL_EPILOG="""\
+\t}
+}
+"""
+
+DO_EXEC_PARTIAL_PROLOG="""\
+void %(device)s::do_exec_partial()
+{
+\tswitch(inst_state) {
+"""
+
+DO_EXEC_PARTIAL_EPILOG="""\
+\t}
+}
+"""
+
+DISASM_PROLOG="""\
+const %(device)s::disasm_entry %(device)s::disasm_entries[0x%(disasm_count)x] = {
+"""
+
+DISASM_EPILOG="""\
+};
+"""
+
+def save_tables(f, device, states):
+ total_states = len(states)
+
+ d = { "device": device,
+ "disasm_count": total_states-1
+ }
+
+
+ emit(f, DO_EXEC_FULL_PROLOG % d)
+ for n, state in enumerate(states):
+ if state == ".": continue
+ if n < total_states - 1:
+ emit(f, "\tcase 0x%02x: %s_full(); break;\n" % (n, state))
+ else:
+ emit(f, "\tcase %s: %s_full(); break;\n" % ("STATE_RESET", state))
+ emit(f, DO_EXEC_FULL_EPILOG % d)
+
+ emit(f, DO_EXEC_PARTIAL_PROLOG % d)
+ for n, state in enumerate(states):
+ if state == ".": continue
+ if n < total_states - 1:
+ emit(f, "\tcase 0x%02x: %s_partial(); break;\n" % (n, state))
+ else:
+ emit(f, "\tcase %s: %s_partial(); break;\n" % ("STATE_RESET", state))
+ emit(f, DO_EXEC_PARTIAL_EPILOG % d)
+
+ emit(f, DISASM_PROLOG % d )
+ for n, state in enumerate(states):
+ if state == ".": continue
+ if n == total_states - 1: break
+ tokens = state.split("_")
+ opc = tokens[0]
+ mode = tokens[-1]
+ extra = "0"
+ if opc in ["jsr", "bsr"]:
+ extra = "DASMFLAG_STEP_OVER"
+ elif opc in ["rts", "rti", "rtn"]:
+ extra = "DASMFLAG_STEP_OUT"
+ emit(f, '\t{ "%s", DASM_%s, %s },\n' % (opc, mode, extra))
+ emit(f, DISASM_EPILOG % d)
+
+def save(fname, device, opcodes, states):
+ logging.info("saving: %s", fname)
+ try:
+ f = open(fname, "w")
+ except Exception:
+ err = sys.exc_info()[1]
+ logging.error("cannot write file %s [%s]", fname, err)
+ sys.exit(1)
+ save_opcodes(f,device, opcodes)
+ emit(f, "\n")
+ save_tables(f, device, states)
+ f.close()
+
+
+def main(argv):
+ debug = False
+ logformat=("%(levelname)s:"
+ "%(module)s:"
+ "%(lineno)d:"
+ "%(threadName)s:"
+ "%(message)s")
+ if debug:
+ logging.basicConfig(level=logging.INFO, format=logformat)
+ else:
+ logging.basicConfig(level=logging.WARNING, format=logformat)
+
+
+ if len(argv) != 5:
+ print(USAGE % argv[0])
+ return 1
+
+ device_name = argv[1]
+
+ opcodes = []
+ if argv[2] != "-":
+ opcodes = load_opcodes(argv[2])
+ logging.info("found %d opcodes", len(opcodes))
+ else:
+ logging.info("skipping opcode reading")
+
+
+ states = load_disp(argv[3])
+ logging.info("loaded %s states", len(states))
+
+ assert (len(states) & 0xff) == 1
+ save(argv[4], device_name, opcodes, states)
+
+
+# ======================================================================
+if __name__ == "__main__":
+ sys.exit(main(sys.argv))
+