From 90362d4baff3172511db16a78136d642a98c92be Mon Sep 17 00:00:00 2001 From: Olivier Galibert Date: Wed, 20 Mar 2013 16:14:39 +0000 Subject: [PATCH] m6502: Seriously untested multi-dispatch-table support [O. Galibert] --- docs/m6502.txt | 16 ++++++++++++++-- src/emu/cpu/m6502/m6502.c | 7 +++++-- src/emu/cpu/m6502/m6502.h | 3 ++- src/emu/cpu/m6502/m6502make.py | 22 ++++++++++++---------- 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/docs/m6502.txt b/docs/m6502.txt index 6b010e64ab0..56e761ebf5a 100644 --- a/docs/m6502.txt +++ b/docs/m6502.txt @@ -252,7 +252,7 @@ A code generator is used to support interrupting and restarting an instruction in the middle. This is done through a two-level state machine with updates only at the boundaries. More precisely, inst_state tells you which main state you're in. It's equal to the -opcode byte when 0-255, and 256 means reset. It's always valid and +opcode byte when 0-255, and 0xff00 means reset. It's always valid and used by instructions like rmb. inst_substate indicates at which step we are in an instruction, but it set only when an instruction has been interrupted. Let's go back to the asl code: @@ -458,7 +458,19 @@ to note that the exception path only happens when the contention/wait state goes further than the scheduling slice of the cpu. That should not usually be the case, so the cost should be minimal. - 10. Current TODO + 10. Multi-dispatch variants + +Some variants currently in the process of being supported change +instruction set depending on an internal flag, either switching to a +16-bits mode or changing some register accesses to memory accesses. +This is handled by having multiple dispatch tables for the cpu, the +d.lst not being 257 entries anymore but 256*n+1. The variable +inst_state_base must select which instruction table to use at a given +time. It must be a multiple of 256, and is in fact simply or-ed to +the first instruction byte to get the dispatch table index (aka +inst_state). + + 11. Current TODO - Implement the bus contention/wait states stuff, but that requires support on the memory map side first. diff --git a/src/emu/cpu/m6502/m6502.c b/src/emu/cpu/m6502/m6502.c index d944a433415..2d15dadd967 100644 --- a/src/emu/cpu/m6502/m6502.c +++ b/src/emu/cpu/m6502/m6502.c @@ -100,6 +100,7 @@ void m6502_device::init() save_item(NAME(v_state)); save_item(NAME(inst_state)); save_item(NAME(inst_substate)); + save_item(NAME(inst_state_base)); save_item(NAME(irq_taken)); save_item(NAME(inhibit_interrupts)); @@ -122,6 +123,7 @@ void m6502_device::init() v_state = false; inst_state = STATE_RESET; inst_substate = 0; + inst_state_base = 0; sync = false; end_cycles = 0; inhibit_interrupts = false; @@ -131,6 +133,7 @@ void m6502_device::device_reset() { inst_state = STATE_RESET; inst_substate = 0; + inst_state_base = 0; nmi_state = false; irq_state = false; apu_irq_state = false; @@ -406,7 +409,7 @@ void m6502_device::execute_run() while(icount > 0) { if(inst_state < 0x100) { PPC = NPC; - inst_state = IR; + inst_state = IR | inst_state_base; if(machine().debug_flags & DEBUG_FLAG_ENABLED) debugger_instruction_hook(this, NPC); } @@ -479,7 +482,7 @@ UINT32 m6502_device::disasm_max_opcode_bytes() const offs_t m6502_device::disassemble_generic(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options, const disasm_entry *table) { - const disasm_entry &e = table[oprom[0]]; + const disasm_entry &e = table[oprom[0] | inst_state_base]; UINT32 flags = e.flags | DASMFLAG_SUPPORTED; buffer += sprintf(buffer, "%s", e.opcode); diff --git a/src/emu/cpu/m6502/m6502.h b/src/emu/cpu/m6502/m6502.h index 766f30a1fe3..0588442e9bd 100644 --- a/src/emu/cpu/m6502/m6502.h +++ b/src/emu/cpu/m6502/m6502.h @@ -97,7 +97,7 @@ protected: }; enum { - STATE_RESET = 0x100, + STATE_RESET = 0xff00, }; enum { @@ -182,6 +182,7 @@ protected: UINT8 Y; /* Y index register */ UINT8 P; /* Processor status */ UINT8 IR; /* Prefetched instruction register */ + int inst_state_base; /* Current instruction bank */ memory_interface *mintf; int inst_state, inst_substate; diff --git a/src/emu/cpu/m6502/m6502make.py b/src/emu/cpu/m6502/m6502make.py index e6da2f2e992..38ac41841d9 100755 --- a/src/emu/cpu/m6502/m6502make.py +++ b/src/emu/cpu/m6502/m6502make.py @@ -7,7 +7,7 @@ Usage: import sys import logging -MAX_STATES = 0x101 +MAX_STATES = 0 def load_opcodes(fname): """Load opcodes from .lst file""" @@ -174,7 +174,7 @@ DO_EXEC_PARTIAL_EPILOG="""\ """ DISASM_PROLOG="""\ -const %(device)s::disasm_entry %(device)s::disasm_entries[0x100] = { +const %(device)s::disasm_entry %(device)s::disasm_entries[0x%(disasm_count)x] = { """ DISASM_EPILOG="""\ @@ -182,15 +182,17 @@ DISASM_EPILOG="""\ """ def save_tables(f, device, states): + total_states = len(states) + d = { "device": device, + "disasm_count": total_states-1 } - - assert len(states) == MAX_STATES - + + emit(f, DO_EXEC_FULL_PROLOG % d) for n, state in enumerate(states): if state == ".": continue - if n < MAX_STATES - 1: + 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)) @@ -199,16 +201,16 @@ def save_tables(f, device, states): emit(f, DO_EXEC_PARTIAL_PROLOG % d) for n, state in enumerate(states): if state == ".": continue - if n < MAX_STATES - 1: + 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) + emit(f, DISASM_PROLOG % d ) for n, state in enumerate(states): if state == ".": continue - if n == MAX_STATES - 1: break + if n == total_states - 1: break tokens = state.split("_") opc = tokens[0] mode = tokens[-1] @@ -262,8 +264,8 @@ def main(argv): states = load_disp(argv[3]) logging.info("loaded %s states", len(states)) - assert len(states) == MAX_STATES + assert (len(states) & 0xff) == 1 save(argv[4], device_name, opcodes, states)