From a704ed7b1b121c3bcff52d49bff8372360fe907c Mon Sep 17 00:00:00 2001 From: Olivier Galibert Date: Fri, 29 Jun 2018 10:58:19 +0200 Subject: emumem: Backend modernization [O. Galibert] --- scripts/genie.lua | 3 + scripts/src/emu.lua | 27 + src/devices/bus/ti99/internal/998board.cpp | 8 +- src/devices/bus/ti99/internal/998board.h | 4 +- src/devices/bus/ti99/internal/datamux.cpp | 10 +- src/devices/bus/ti99/internal/datamux.h | 2 +- src/devices/bus/ti99/internal/genboard.cpp | 3 +- src/devices/bus/ti99/internal/genboard.h | 2 +- src/devices/cpu/tms32031/tms32031.cpp | 1 - src/devices/cpu/tms9900/tms9900.cpp | 25 +- src/devices/cpu/tms9900/tms9900.h | 4 + src/devices/cpu/tms9900/tms9980a.cpp | 12 +- src/devices/cpu/tms9900/tms9995.cpp | 34 +- src/devices/cpu/tms9900/tms9995.h | 4 + src/devices/cpu/v60/v60.cpp | 2 - src/devices/cpu/v60/v60.h | 1 - src/emu/addrmap.cpp | 21 - src/emu/addrmap.h | 32 - src/emu/debug/debugbuf.cpp | 2 +- src/emu/debug/debugcmd.cpp | 48 +- src/emu/debug/debugcpu.cpp | 569 ++-- src/emu/debug/debugcpu.h | 48 +- src/emu/debug/dvwpoints.cpp | 8 +- src/emu/dimemory.cpp | 28 - src/emu/dimemory.h | 5 +- src/emu/emumem.cpp | 4890 ++++++---------------------- src/emu/emumem.h | 604 +++- src/emu/emumem_hea.h | 40 + src/emu/emumem_hedp.cpp | 144 + src/emu/emumem_hedp.h | 81 + src/emu/emumem_hedr.h | 61 + src/emu/emumem_hedr.ipp | 479 +++ src/emu/emumem_hedr0.cpp | 171 + src/emu/emumem_hedr1.cpp | 192 ++ src/emu/emumem_hedr2.cpp | 192 ++ src/emu/emumem_hedr3.cpp | 193 ++ src/emu/emumem_hedw.h | 61 + src/emu/emumem_hedw.ipp | 479 +++ src/emu/emumem_hedw0.cpp | 171 + src/emu/emumem_hedw1.cpp | 192 ++ src/emu/emumem_hedw2.cpp | 192 ++ src/emu/emumem_hedw3.cpp | 193 ++ src/emu/emumem_hem.cpp | 189 ++ src/emu/emumem_hem.h | 87 + src/emu/emumem_hep.cpp | 97 + src/emu/emumem_hep.h | 48 + src/emu/emumem_het.cpp | 89 + src/emu/emumem_het.h | 50 + src/emu/emumem_heu.cpp | 273 ++ src/emu/emumem_heu.h | 90 + src/emu/emumem_heun.cpp | 158 + src/emu/emumem_heun.h | 68 + src/emu/emumem_mud.cpp | 127 + src/emu/emumem_mud.h | 41 + src/frontend/mame/luaengine.cpp | 30 +- src/lib/util/coretmpl.h | 8 + src/mame/drivers/geneve.cpp | 9 +- src/mame/drivers/m6805evs.cpp | 5 +- src/mame/drivers/ti99_4p.cpp | 17 +- src/mame/drivers/ti99_4x.cpp | 12 +- src/mame/drivers/ti99_8.cpp | 9 +- src/mame/machine/c117.cpp | 8 - src/mame/machine/segaic16.cpp | 1 + 63 files changed, 6206 insertions(+), 4448 deletions(-) create mode 100644 src/emu/emumem_hea.h create mode 100644 src/emu/emumem_hedp.cpp create mode 100644 src/emu/emumem_hedp.h create mode 100644 src/emu/emumem_hedr.h create mode 100644 src/emu/emumem_hedr.ipp create mode 100644 src/emu/emumem_hedr0.cpp create mode 100644 src/emu/emumem_hedr1.cpp create mode 100644 src/emu/emumem_hedr2.cpp create mode 100644 src/emu/emumem_hedr3.cpp create mode 100644 src/emu/emumem_hedw.h create mode 100644 src/emu/emumem_hedw.ipp create mode 100644 src/emu/emumem_hedw0.cpp create mode 100644 src/emu/emumem_hedw1.cpp create mode 100644 src/emu/emumem_hedw2.cpp create mode 100644 src/emu/emumem_hedw3.cpp create mode 100644 src/emu/emumem_hem.cpp create mode 100644 src/emu/emumem_hem.h create mode 100644 src/emu/emumem_hep.cpp create mode 100644 src/emu/emumem_hep.h create mode 100644 src/emu/emumem_het.cpp create mode 100644 src/emu/emumem_het.h create mode 100644 src/emu/emumem_heu.cpp create mode 100644 src/emu/emumem_heu.h create mode 100644 src/emu/emumem_heun.cpp create mode 100644 src/emu/emumem_heun.h create mode 100644 src/emu/emumem_mud.cpp create mode 100644 src/emu/emumem_mud.h diff --git a/scripts/genie.lua b/scripts/genie.lua index ed289f73396..51e80e88562 100644 --- a/scripts/genie.lua +++ b/scripts/genie.lua @@ -1192,6 +1192,9 @@ configuration { "mingw*" } "-static", } end + buildoptions { + "-Wa,-mbig-obj", + } linkoptions { "-Wl,--start-group", } diff --git a/scripts/src/emu.lua b/scripts/src/emu.lua index cc281b6a8c3..c9a8ddeb625 100644 --- a/scripts/src/emu.lua +++ b/scripts/src/emu.lua @@ -116,6 +116,33 @@ files { MAME_DIR .. "src/emu/emucore.h", MAME_DIR .. "src/emu/emumem.cpp", MAME_DIR .. "src/emu/emumem.h", + MAME_DIR .. "src/emu/emumem_mud.cpp", + MAME_DIR .. "src/emu/emumem_mud.h", + MAME_DIR .. "src/emu/emumem_hea.h", + MAME_DIR .. "src/emu/emumem_hem.cpp", + MAME_DIR .. "src/emu/emumem_hem.h", + MAME_DIR .. "src/emu/emumem_hedp.cpp", + MAME_DIR .. "src/emu/emumem_hedp.h", + MAME_DIR .. "src/emu/emumem_heun.cpp", + MAME_DIR .. "src/emu/emumem_heun.h", + MAME_DIR .. "src/emu/emumem_heu.cpp", + MAME_DIR .. "src/emu/emumem_heu.h", + MAME_DIR .. "src/emu/emumem_hedr.ipp", + MAME_DIR .. "src/emu/emumem_hedr.h", + MAME_DIR .. "src/emu/emumem_hedr0.cpp", + MAME_DIR .. "src/emu/emumem_hedr1.cpp", + MAME_DIR .. "src/emu/emumem_hedr2.cpp", + MAME_DIR .. "src/emu/emumem_hedr3.cpp", + MAME_DIR .. "src/emu/emumem_hedw.ipp", + MAME_DIR .. "src/emu/emumem_hedw.h", + MAME_DIR .. "src/emu/emumem_hedw0.cpp", + MAME_DIR .. "src/emu/emumem_hedw1.cpp", + MAME_DIR .. "src/emu/emumem_hedw2.cpp", + MAME_DIR .. "src/emu/emumem_hedw3.cpp", + MAME_DIR .. "src/emu/emumem_hep.cpp", + MAME_DIR .. "src/emu/emumem_hep.h", + MAME_DIR .. "src/emu/emumem_het.cpp", + MAME_DIR .. "src/emu/emumem_het.h", MAME_DIR .. "src/emu/emuopts.cpp", MAME_DIR .. "src/emu/emuopts.h", MAME_DIR .. "src/emu/emupal.cpp", diff --git a/src/devices/bus/ti99/internal/998board.cpp b/src/devices/bus/ti99/internal/998board.cpp index 91bad557d5b..443f5b9312b 100644 --- a/src/devices/bus/ti99/internal/998board.cpp +++ b/src/devices/bus/ti99/internal/998board.cpp @@ -347,7 +347,7 @@ WRITE_LINE_MEMBER( mainboard8_device::dbin_in ) m_dbin_level = (line_state)state; } -SETOFFSET_MEMBER( mainboard8_device::setoffset ) +READ8_MEMBER( mainboard8_device::setoffset ) { LOGMASKED(LOG_ADDRESS, "set %s %04x\n", (m_dbin_level==ASSERT_LINE)? "R" : "W", offset); @@ -386,6 +386,8 @@ SETOFFSET_MEMBER( mainboard8_device::setoffset ) // AMIGO is the one to control the READY line to the CPU // MOFETTA does not contribute to READY m_ready(m_amigo->cpury_out()); + + return 0; } WRITE_LINE_MEMBER( mainboard8_device::reset_console ) @@ -1945,7 +1947,7 @@ WRITE_LINE_MEMBER( amigo_device::lascs_in ) 3. Set the physical address bus with the second 16 bits of the physical address. Clear the MSAST line. Forward any incoming READY=0 to the CPU. */ -SETOFFSET_MEMBER( amigo_device::set_address ) +READ8_MEMBER( amigo_device::set_address ) { // Check whether the mapper itself is accessed int mapaddr = (m_crus==ASSERT_LINE)? 0x8810 : 0xf870; @@ -1991,6 +1993,8 @@ SETOFFSET_MEMBER( amigo_device::set_address ) m_ready_out = m_srdy; LOGMASKED(LOG_CPURY, "Setting CPURY = %d (LAS)\n", m_ready_out); } + + return 0; } /* diff --git a/src/devices/bus/ti99/internal/998board.h b/src/devices/bus/ti99/internal/998board.h index fa161c016db..0f64b551443 100644 --- a/src/devices/bus/ti99/internal/998board.h +++ b/src/devices/bus/ti99/internal/998board.h @@ -337,7 +337,7 @@ public: DECLARE_READ8_MEMBER( read ); DECLARE_WRITE8_MEMBER( write ); - DECLARE_SETOFFSET_MEMBER( set_address ); + DECLARE_READ8_MEMBER( set_address ); // Debugger support int get_physical_address_debug(offs_t offset); @@ -541,7 +541,7 @@ public: // Memory space DECLARE_READ8_MEMBER( read ); DECLARE_WRITE8_MEMBER( write ); - DECLARE_SETOFFSET_MEMBER( setoffset ); + DECLARE_READ8_MEMBER( setoffset ); // Memory space for debugger access DECLARE_READ8_MEMBER( debugger_read ); diff --git a/src/devices/bus/ti99/internal/datamux.cpp b/src/devices/bus/ti99/internal/datamux.cpp index 5fbcb8f3078..da6e870516a 100644 --- a/src/devices/bus/ti99/internal/datamux.cpp +++ b/src/devices/bus/ti99/internal/datamux.cpp @@ -426,21 +426,21 @@ WRITE16_MEMBER( datamux_device::write ) Called when the memory access starts by setting the address bus. From that point on, we suspend the CPU until all operations are done. */ -SETOFFSET_MEMBER( datamux_device::setoffset ) +READ8_MEMBER( datamux_device::setoffset ) { - m_addr_buf = offset << 1; + m_addr_buf = offset; m_waitcount = 0; if (TRACE_ADDRESS) logerror("set address %04x\n", m_addr_buf); if ((m_addr_buf & 0xe000) == 0x0000) { - return; // console ROM + return 0; // console ROM } if ((m_addr_buf & 0xfc00) == 0x8000) { - return; // console RAM + return 0; // console RAM } // Initialize counter @@ -467,6 +467,8 @@ SETOFFSET_MEMBER( datamux_device::setoffset ) ready_join(); } else m_waitcount = 0; + + return 0; } /* diff --git a/src/devices/bus/ti99/internal/datamux.h b/src/devices/bus/ti99/internal/datamux.h index d864ee98c53..b2ec1bff123 100644 --- a/src/devices/bus/ti99/internal/datamux.h +++ b/src/devices/bus/ti99/internal/datamux.h @@ -35,7 +35,7 @@ public: datamux_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); DECLARE_READ16_MEMBER( read ); DECLARE_WRITE16_MEMBER( write ); - DECLARE_SETOFFSET_MEMBER( setoffset ); + DECLARE_READ8_MEMBER( setoffset ); DECLARE_WRITE_LINE_MEMBER( clock_in ); DECLARE_WRITE_LINE_MEMBER( dbin_in ); diff --git a/src/devices/bus/ti99/internal/genboard.cpp b/src/devices/bus/ti99/internal/genboard.cpp index a9ed0e9e1bb..861e0655200 100644 --- a/src/devices/bus/ti99/internal/genboard.cpp +++ b/src/devices/bus/ti99/internal/genboard.cpp @@ -907,7 +907,7 @@ WRITE8_MEMBER( geneve_mapper_device::write_to_pfm ) This decoding will later be used in the READ/WRITE member functions. Also, we initiate wait state creation here. */ -SETOFFSET_MEMBER( geneve_mapper_device::setoffset ) +READ8_MEMBER( geneve_mapper_device::setoffset ) { LOGMASKED(LOG_DETAIL, "setoffset = %04x\n", offset); m_debug_no_ws = false; @@ -928,6 +928,7 @@ SETOFFSET_MEMBER( geneve_mapper_device::setoffset ) m_peribox->memen_in(ASSERT_LINE); m_peribox->setaddress_dbin(space, m_decoded.physaddr, m_read_mode); } + return 0; } /* diff --git a/src/devices/bus/ti99/internal/genboard.h b/src/devices/bus/ti99/internal/genboard.h index baac4db69de..260f02932b1 100644 --- a/src/devices/bus/ti99/internal/genboard.h +++ b/src/devices/bus/ti99/internal/genboard.h @@ -126,7 +126,7 @@ public: DECLARE_READ8_MEMBER( readm ); DECLARE_WRITE8_MEMBER( writem ); - DECLARE_SETOFFSET_MEMBER( setoffset ); + DECLARE_READ8_MEMBER( setoffset ); DECLARE_INPUT_CHANGED_MEMBER( settings_changed ); diff --git a/src/devices/cpu/tms32031/tms32031.cpp b/src/devices/cpu/tms32031/tms32031.cpp index 777097ba85d..fb13fbba9ce 100644 --- a/src/devices/cpu/tms32031/tms32031.cpp +++ b/src/devices/cpu/tms32031/tms32031.cpp @@ -745,7 +745,6 @@ void tms3203x_device::execute_set_input(int inputnum, int state) { // switch between microcomputer/boot loader and microprocessor modes m_mcbl_mode = (state == ASSERT_LINE); - m_cache->force_update(); return; } diff --git a/src/devices/cpu/tms9900/tms9900.cpp b/src/devices/cpu/tms9900/tms9900.cpp index 21760205aff..61ee5644d7f 100644 --- a/src/devices/cpu/tms9900/tms9900.cpp +++ b/src/devices/cpu/tms9900/tms9900.cpp @@ -114,6 +114,8 @@ #define NOPRG -1 +constexpr int tms99xx_device::AS_SETOFFSET; + /* tms9900 ST register bits. */ enum { @@ -179,6 +181,7 @@ enum tms99xx_device::tms99xx_device(const machine_config &mconfig, device_type type, const char *tag, int data_width, int prg_addr_bits, int cru_addr_bits, device_t *owner, uint32_t clock) : cpu_device(mconfig, type, tag, owner, clock), m_program_config("program", ENDIANNESS_BIG, data_width, prg_addr_bits), + m_setoffset_config("setoffset", ENDIANNESS_BIG, data_width, prg_addr_bits), m_io_config("cru", ENDIANNESS_BIG, 8, cru_addr_bits), m_prgspace(nullptr), m_cru(nullptr), @@ -223,6 +226,7 @@ void tms99xx_device::device_start() // TODO: Restore state save feature resolve_lines(); m_prgspace = &space(AS_PROGRAM); + m_sospace = has_space(AS_SETOFFSET) ? &space(AS_SETOFFSET) : nullptr; m_cru = &space(AS_IO); // set our instruction counter @@ -437,10 +441,17 @@ void tms99xx_device::write_workspace_register_debug(int reg, uint16_t data) device_memory_interface::space_config_vector tms99xx_device::memory_space_config() const { - return space_config_vector { - std::make_pair(AS_PROGRAM, &m_program_config), - std::make_pair(AS_IO, &m_io_config) - }; + if (has_configured_map(AS_SETOFFSET)) + return space_config_vector { + std::make_pair(AS_PROGRAM, &m_program_config), + std::make_pair(AS_SETOFFSET, &m_setoffset_config), + std::make_pair(AS_IO, &m_io_config) + }; + else + return space_config_vector { + std::make_pair(AS_PROGRAM, &m_program_config), + std::make_pair(AS_IO, &m_io_config) + }; } /************************************************************************** @@ -1523,7 +1534,8 @@ void tms99xx_device::mem_read() if (m_mem_phase==1) { if (!m_dbin_line.isnull()) m_dbin_line(ASSERT_LINE); - m_prgspace->set_address(m_address & m_prgaddr_mask & 0xfffe); + if (m_sospace) + m_sospace->read_byte(m_address & m_prgaddr_mask & 0xfffe); m_check_ready = true; m_mem_phase = 2; m_pass = 2; @@ -1550,7 +1562,8 @@ void tms99xx_device::mem_write() if (!m_dbin_line.isnull()) m_dbin_line(CLEAR_LINE); // When writing, the data bus is asserted immediately after the address bus if (TRACE_ADDRESSBUS) logerror("set address (w) %04x\n", m_address); - m_prgspace->set_address(m_address & m_prgaddr_mask & 0xfffe); + if (m_sospace) + m_sospace->read_byte(m_address & m_prgaddr_mask & 0xfffe); if (TRACE_MEM) logerror("mem w %04x <- %04x\n", m_address, m_current_value); m_prgspace->write_word(m_address & m_prgaddr_mask & 0xfffe, m_current_value); m_check_ready = true; diff --git a/src/devices/cpu/tms9900/tms9900.h b/src/devices/cpu/tms9900/tms9900.h index 5af536fb54d..c084c190623 100644 --- a/src/devices/cpu/tms9900/tms9900.h +++ b/src/devices/cpu/tms9900/tms9900.h @@ -43,6 +43,8 @@ static const char opname[][5] = class tms99xx_device : public cpu_device { public: + static constexpr int AS_SETOFFSET = 4; + ~tms99xx_device(); // READY input line. When asserted (high), the memory is ready for data exchange. @@ -93,8 +95,10 @@ protected: void decode(uint16_t inst); const address_space_config m_program_config; + const address_space_config m_setoffset_config; const address_space_config m_io_config; address_space* m_prgspace; + address_space* m_sospace; address_space* m_cru; virtual uint16_t read_workspace_register_debug(int reg); diff --git a/src/devices/cpu/tms9900/tms9980a.cpp b/src/devices/cpu/tms9900/tms9980a.cpp index e63b1b76d5b..aebe26f9575 100644 --- a/src/devices/cpu/tms9900/tms9980a.cpp +++ b/src/devices/cpu/tms9900/tms9980a.cpp @@ -183,7 +183,8 @@ void tms9980a_device::mem_read() case 1: m_pass = 4; // make the CPU visit this method more than once if (!m_dbin_line.isnull()) m_dbin_line(ASSERT_LINE); - m_prgspace->set_address(m_address & m_prgaddr_mask & ~1); + if (m_sospace) + m_sospace->read_byte(m_address & m_prgaddr_mask & ~1); if (TRACE_ADDRESSBUS) logerror("tms9980a: set address bus %04x\n", m_address & m_prgaddr_mask & ~1); m_check_ready = true; break; @@ -194,7 +195,8 @@ void tms9980a_device::mem_read() m_current_value = (value << 8) & 0xff00; break; case 3: - m_prgspace->set_address((m_address & m_prgaddr_mask) | 1); + if (m_sospace) + m_sospace->read_byte((m_address & m_prgaddr_mask) | 1); if (TRACE_ADDRESSBUS) logerror("tms9980a: set address bus %04x\n", (m_address & m_prgaddr_mask) | 1); break; case 4: @@ -216,7 +218,8 @@ void tms9980a_device::mem_write() case 1: m_pass = 4; // make the CPU visit this method once more if (!m_dbin_line.isnull()) m_dbin_line(CLEAR_LINE); - m_prgspace->set_address(m_address & m_prgaddr_mask & ~1); + if (m_sospace) + m_sospace->read_byte(m_address & m_prgaddr_mask & ~1); if (TRACE_ADDRESSBUS) logerror("tms9980a: set address bus %04x\n", m_address & m_prgaddr_mask & ~1); m_prgspace->write_byte(m_address & 0x3ffe & ~1, (m_current_value >> 8)&0xff); if (TRACE_MEM) logerror("tms9980a: memory write high byte %04x <- %02x\n", m_address & m_prgaddr_mask & ~1, (m_current_value >> 8)&0xff); @@ -226,7 +229,8 @@ void tms9980a_device::mem_write() // no action here, just wait for READY break; case 3: - m_prgspace->set_address((m_address & m_prgaddr_mask) | 1); + if (m_sospace) + m_sospace->read_byte((m_address & m_prgaddr_mask) | 1); if (TRACE_ADDRESSBUS) logerror("tms9980a: set address bus %04x\n", (m_address & m_prgaddr_mask) | 1); m_prgspace->write_byte((m_address & m_prgaddr_mask) | 1, m_current_value & 0xff); if (TRACE_MEM) logerror("tms9980a: memory write low byte %04x <- %02x\n", (m_address & m_prgaddr_mask) | 1, m_current_value & 0xff); diff --git a/src/devices/cpu/tms9900/tms9995.cpp b/src/devices/cpu/tms9900/tms9995.cpp index ddc80522f68..26d357a8e61 100644 --- a/src/devices/cpu/tms9900/tms9995.cpp +++ b/src/devices/cpu/tms9900/tms9995.cpp @@ -151,6 +151,8 @@ enum #include "logmacro.h" +constexpr int tms9995_device::AS_SETOFFSET; + /**************************************************************************** Constructor ****************************************************************************/ @@ -167,8 +169,10 @@ tms9995_device::tms9995_device(const machine_config &mconfig, device_type type, PC(0), PC_debug(0), m_program_config("program", ENDIANNESS_BIG, 8, 16), + m_setoffset_config("setoffset", ENDIANNESS_BIG, 8, 16), m_io_config("cru", ENDIANNESS_BIG, 8, 16), m_prgspace(nullptr), + m_sospace(nullptr), m_cru(nullptr), m_external_operation(*this), m_iaq_line(*this), @@ -193,7 +197,8 @@ void tms9995_device::device_start() { // TODO: Restore save state suport - m_prgspace = &space(AS_PROGRAM); // dimemory.h + m_prgspace = &space(AS_PROGRAM); + m_sospace = has_space(AS_SETOFFSET) ? &space(AS_SETOFFSET) : nullptr; m_cru = &space(AS_IO); // Resolve our external connections @@ -440,10 +445,17 @@ void tms9995_device::write_workspace_register_debug(int reg, uint16_t data) device_memory_interface::space_config_vector tms9995_device::memory_space_config() const { - return space_config_vector { - std::make_pair(AS_PROGRAM, &m_program_config), - std::make_pair(AS_IO, &m_io_config) - }; + if (has_configured_map(AS_SETOFFSET)) + return space_config_vector { + std::make_pair(AS_PROGRAM, &m_program_config), + std::make_pair(AS_SETOFFSET, &m_setoffset_config), + std::make_pair(AS_IO, &m_io_config) + }; + else + return space_config_vector { + std::make_pair(AS_PROGRAM, &m_program_config), + std::make_pair(AS_IO, &m_io_config) + }; } /************************************************************************** @@ -1838,7 +1850,8 @@ void tms9995_device::mem_read() m_check_hold = false; LOGMASKED(LOG_ADDRESSBUS, "set address bus %04x\n", m_address & ~1); - m_prgspace->set_address(address); + if (m_sospace) + m_sospace->read_byte(address); m_request_auto_wait_state = m_auto_wait; pulse_clock(1); break; @@ -1852,7 +1865,8 @@ void tms9995_device::mem_read() case 3: // Set address + 1 (unless byte command) LOGMASKED(LOG_ADDRESSBUS, "set address bus %04x\n", m_address | 1); - m_prgspace->set_address(m_address | 1); + if (m_sospace) + m_sospace->read_byte(m_address | 1); m_request_auto_wait_state = m_auto_wait; pulse_clock(1); break; @@ -1970,7 +1984,8 @@ void tms9995_device::mem_write() m_check_hold = false; LOGMASKED(LOG_ADDRESSBUS, "set address bus %04x\n", address); - m_prgspace->set_address(address); + if (m_sospace) + m_sospace->read_byte(address); LOGMASKED(LOG_MEM, "memory write byte %04x <- %02x\n", address, (m_current_value >> 8)&0xff); m_prgspace->write_byte(address, (m_current_value >> 8)&0xff); m_request_auto_wait_state = m_auto_wait; @@ -1983,7 +1998,8 @@ void tms9995_device::mem_write() case 3: // Set address + 1 (unless byte command) LOGMASKED(LOG_ADDRESSBUS, "set address bus %04x\n", m_address | 1); - m_prgspace->set_address(m_address | 1); + if (m_sospace) + m_sospace->read_byte(m_address | 1); LOGMASKED(LOG_MEM, "memory write byte %04x <- %02x\n", m_address | 1, m_current_value & 0xff); m_prgspace->write_byte(m_address | 1, m_current_value & 0xff); m_request_auto_wait_state = m_auto_wait; diff --git a/src/devices/cpu/tms9900/tms9995.h b/src/devices/cpu/tms9900/tms9995.h index 1dcc4667176..940ec0f43ee 100644 --- a/src/devices/cpu/tms9900/tms9995.h +++ b/src/devices/cpu/tms9900/tms9995.h @@ -49,6 +49,8 @@ enum class tms9995_device : public cpu_device { public: + static constexpr int AS_SETOFFSET = 4; + tms9995_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); // READY input line. When asserted (high), the memory is ready for data exchange. @@ -125,8 +127,10 @@ private: uint8_t m_onchip_memory[256]; const address_space_config m_program_config; + const address_space_config m_setoffset_config; const address_space_config m_io_config; address_space* m_prgspace; + address_space* m_sospace; address_space* m_cru; // Processor states diff --git a/src/devices/cpu/v60/v60.cpp b/src/devices/cpu/v60/v60.cpp index 0952d1fb189..9fb8374ae1b 100644 --- a/src/devices/cpu/v60/v60.cpp +++ b/src/devices/cpu/v60/v60.cpp @@ -94,7 +94,6 @@ v60_device::v60_device(const machine_config &mconfig, device_type type, const ch : cpu_device(mconfig, type, tag, owner, clock) , m_program_config("program", ENDIANNESS_LITTLE, databits, addrbits, 0) , m_io_config("io", ENDIANNESS_LITTLE, 16, 24, 0) - , m_fetch_xor(BYTE4_XOR_LE(0)) , m_start_pc(0xfffffff0) { m_reg[45] = pir; @@ -428,7 +427,6 @@ void v60_device::device_start() m_io = &space(AS_IO); - save_item(NAME(m_fetch_xor)); save_item(NAME(m_reg)); save_item(NAME(m_irq_line)); save_item(NAME(m_nmi_line)); diff --git a/src/devices/cpu/v60/v60.h b/src/devices/cpu/v60/v60.h index 14a0ca62615..47917aa1c94 100644 --- a/src/devices/cpu/v60/v60.h +++ b/src/devices/cpu/v60/v60.h @@ -151,7 +151,6 @@ private: address_space_config m_program_config; address_space_config m_io_config; - offs_t m_fetch_xor; offs_t m_start_pc; uint32_t m_reg[68]; struct { diff --git a/src/emu/addrmap.cpp b/src/emu/addrmap.cpp index 544bb51011c..3a3fb07c899 100644 --- a/src/emu/addrmap.cpp +++ b/src/emu/addrmap.cpp @@ -294,20 +294,6 @@ address_map_entry &address_map_entry::rw(read64_delegate rfunc, write64_delegate } -//------------------------------------------------- -// set_handler - handler setter for setoffset -//------------------------------------------------- - -address_map_entry &address_map_entry::setoffset(setoffset_delegate func) -{ - assert(!func.isnull()); - m_setoffsethd.m_type = AMH_DEVICE_DELEGATE; - m_setoffsethd.m_bits = 0; - m_setoffsethd.m_name = func.name(); - m_soproto = func; - return *this; -} - //------------------------------------------------- // unitmask_is_appropriate - verify that the // provided unitmask is valid and expected @@ -797,13 +783,6 @@ void address_map::map_validity_check(validity_checker &valid, int spacenum) cons (void)entry.unitmask_is_appropriate(entry.m_write.m_bits, entry.m_mask, entry.m_write.m_name); #endif } - if (entry.m_setoffsethd.m_type == AMH_DEVICE_DELEGATE) - { - // extract the device tag from the proto-delegate - const char *devtag = entry.m_soproto.device_name(); - if (entry.m_devbase.subdevice(devtag) == nullptr) - osd_printf_error("%s space memory map entry references nonexistent device '%s'\n", spaceconfig.m_name, devtag ? devtag : ""); - } // make sure ports exist // if ((entry.m_read.m_type == AMH_PORT && entry.m_read.m_tag != nullptr && portlist.find(entry.m_read.m_tag) == nullptr) || diff --git a/src/emu/addrmap.h b/src/emu/addrmap.h index 1654856dd62..90dd8898533 100644 --- a/src/emu/addrmap.h +++ b/src/emu/addrmap.h @@ -68,17 +68,10 @@ class address_map_entry template struct is_addrmap_method { static constexpr bool value = std::is_constructible::value; }; - template - struct is_setoffset_method { static constexpr bool value = std::is_constructible::value; }; - template static std::enable_if_t::value, address_map_constructor> make_delegate(Ret (T::*func)(Params...), const char *name, T *obj) { return address_map_constructor(func, name, obj); } - template - static std::enable_if_t::value, setoffset_delegate> make_delegate(Ret (T::*func)(Params...), const char *name, const char *tag, T *obj) - { return setoffset_delegate(func, name, tag, obj); } - template static std::enable_if_t, std::add_pointer_t >::value, T *> make_pointer(U &obj) { return &downcast(obj); } @@ -167,9 +160,6 @@ public: return bankrw(target.second); } - // set offset handler (only one version, since there is no data width to consider) - address_map_entry &setoffset(setoffset_delegate func); - // type setters address_map_entry &set_read_type(map_handler_type _type) { m_read.m_type = _type; return *this; } address_map_entry &set_write_type(map_handler_type _type) { m_write.m_type = _type; return *this; } @@ -196,10 +186,6 @@ public: address_map_entry &m(Ret (T::*map)(Params...), const char *map_name) { return m(&m_devbase, make_delegate(map, map_name, make_pointer(m_devbase))); } - template - address_map_entry &setoffset(Ret (T::*so)(Params...), const char *so_name) - { return setoffset(make_delegate(so, so_name, m_devbase.tag(), make_pointer(m_devbase))); } - // device tag -> delegate converter template @@ -218,10 +204,6 @@ public: address_map_entry &m(const char *tag, Ret (T::*map)(Params...), const char *map_name) { return m(tag, make_delegate(map, map_name, static_cast(nullptr))); } - template - address_map_entry &setoffset(const char *tag, Ret (T::*so)(Params...), const char *so_name) - { return setoffset(make_delegate(so, so_name, tag, static_cast(nullptr))); } - // device reference -> delegate converter template @@ -240,10 +222,6 @@ public: address_map_entry &m(T &obj, Ret (U::*map)(Params...), const char *map_name) { return m(make_pointer(obj), make_delegate(map, map_name, make_pointer(obj))); } - template - address_map_entry &setoffset(T &obj, Ret (U::*so)(Params...), const char *so_name) - { return w(make_delegate(so, so_name, get_tag(obj), make_pointer(obj))); } - // device finder -> delegate converter template @@ -278,14 +256,6 @@ public: address_map_entry &m(const device_finder &finder, Ret (U::*map)(Params...), const char *map_name) { const std::pair target(finder.finder_target()); device_t &device(*target.first.subdevice(target.second)); return m(make_delegate(map, map_name, make_pointer(device))); } - template - address_map_entry &setoffset(device_finder &finder, Ret (U::*so)(Params...), const char *so_name) - { const std::pair target(finder.finder_target()); device_t &device(*target.first.subdevice(target.second)); return setoffset(make_delegate(so, so_name, device.tag(), make_pointer(device))); } - - template - address_map_entry &setoffset(const device_finder &finder, Ret (U::*so)(Params...), const char *so_name) - { const std::pair target(finder.finder_target()); device_t &device(*target.first.subdevice(target.second)); return setoffset(make_delegate(so, so_name, device.tag(), make_pointer(device))); } - // lambda -> delegate converter template address_map_entry &lr8(const char *name, _lr &&read) { @@ -351,7 +321,6 @@ public: int m_cswidth; // chip select width override map_handler_data m_read; // data for read handler map_handler_data m_write; // data for write handler - map_handler_data m_setoffsethd; // data for setoffset handler const char * m_share; // tag of a shared memory block const char * m_region; // tag of region containing the memory backing this entry offs_t m_rgnoffs; // offset within the region @@ -366,7 +335,6 @@ public: write32_delegate m_wproto32; // 32-bit write proto-delegate write64_delegate m_wproto64; // 64-bit write proto-delegate - setoffset_delegate m_soproto; // set offset proto-delegate device_t *m_submap_device; address_map_constructor m_submap_delegate; diff --git a/src/emu/debug/debugbuf.cpp b/src/emu/debug/debugbuf.cpp index 26516c62ed6..b61814ef4e5 100644 --- a/src/emu/debug/debugbuf.cpp +++ b/src/emu/debug/debugbuf.cpp @@ -194,7 +194,7 @@ void debug_disasm_buffer::debug_data_buffer::setup_methods() case -1: m_pc_delta_to_bytes = [](offs_t delta) { return delta << 1; }; break; case 0: m_pc_delta_to_bytes = [](offs_t delta) { return delta; }; break; case 3: m_pc_delta_to_bytes = [](offs_t delta) { return delta >> 3; }; break; - default: throw emu_fatalerror("debug_disasm_buffer::debug_data_buffer::setup_methods: Abnormal address buf shift\n"); + default: throw emu_fatalerror("debug_disasm_buffer::debug_data_buffer::setup_methods: Abnormal address bus shift\n"); } // Define the filler diff --git a/src/emu/debug/debugcmd.cpp b/src/emu/debug/debugcmd.cpp index f6f3a876235..4a433017724 100644 --- a/src/emu/debug/debugcmd.cpp +++ b/src/emu/debug/debugcmd.cpp @@ -1400,7 +1400,7 @@ void debugger_commands::execute_wpset(int ref, const std::vector &p address_space *space; const char *action = nullptr; u64 address, length; - int type; + read_or_write type; int wpnum; /* CPU is implicit */ @@ -1417,11 +1417,11 @@ void debugger_commands::execute_wpset(int ref, const std::vector &p /* param 3 is the type */ if (params[2] == "r") - type = WATCHPOINT_READ; + type = read_or_write::READ; else if (params[2] == "w") - type = WATCHPOINT_WRITE; + type = read_or_write::WRITE; else if (params[2] == "rw" || params[2] == "wr") - type = WATCHPOINT_READWRITE; + type = read_or_write::READWRITE; else { m_console.printf("Invalid watchpoint type: expected r, w, or rw\n"); @@ -1527,20 +1527,20 @@ void debugger_commands::execute_wplist(int ref, const std::vector & /* loop over all CPUs */ for (device_t &device : device_iterator(m_machine.root_device())) for (int spacenum = 0; spacenum < device.debug()->watchpoint_space_count(); ++spacenum) - if (device.debug()->watchpoint_first(spacenum) != nullptr) + if (!device.debug()->watchpoint_vector(spacenum).empty()) { static const char *const types[] = { "unkn ", "read ", "write", "r/w " }; m_console.printf("Device '%s' %s space watchpoints:\n", device.tag(), - device.debug()->watchpoint_first(spacenum)->space().name()); + device.debug()->watchpoint_vector(spacenum).front()->space().name()); /* loop over the watchpoints */ - for (device_debug::watchpoint *wp = device.debug()->watchpoint_first(spacenum); wp != nullptr; wp = wp->next()) + for (const auto &wp : device.debug()->watchpoint_vector(spacenum)) { buffer = string_format("%c%4X @ %0*X-%0*X %s", wp->enabled() ? ' ' : 'D', wp->index(), wp->space().addrchars(), wp->address(), wp->space().addrchars(), wp->address() + wp->length() - 1, - types[wp->type() & 3]); + types[int(wp->type())]); if (std::string(wp->condition()).compare("1") != 0) buffer.append(string_format(" if %s", wp->condition())); if (std::string(wp->action()).compare("") != 0) @@ -3001,9 +3001,6 @@ void debugger_commands::execute_trackmem(int ref, const std::vector // Inform the CPU it's time to start tracking memory writes cpu->debug()->set_track_mem(turnOn); - // Use the watchpoint system to catch memory writes - space->enable_write_watchpoints(true); - // Clear out the existing data if requested if (clear) space->device().debug()->track_mem_data_clear(); @@ -3127,7 +3124,7 @@ void debugger_commands::execute_map(int ref, const std::vector &par taddress = address & space->addrmask(); if (space->device().memory().translate(space->spacenum(), intention, taddress)) { - const char *mapname = space->get_handler_string((intention == TRANSLATE_WRITE_DEBUG) ? read_or_write::WRITE : read_or_write::READ, taddress); + std::string mapname = space->get_handler_string((intention == TRANSLATE_WRITE_DEBUG) ? read_or_write::WRITE : read_or_write::READ, taddress); m_console.printf( "%7s: %0*X logical == %0*X physical -> %s\n", intnames[intention & 3], @@ -3158,8 +3155,31 @@ void debugger_commands::execute_memdump(int ref, const std::vector if (file) { memory_interface_iterator iter(m_machine.root_device()); - for (device_memory_interface &memory : iter) - memory.dump(file); + for (device_memory_interface &memory : iter) { + for (int space = 0; space != memory.max_space_count(); space++) + if (memory.has_space(space)) + { + address_space &sp = memory.space(space); + bool octal = sp.is_octal(); + int nc = octal ? (sp.addr_width() + 2) / 3 : (sp.addr_width() + 3) / 4; + + std::vector entries[2]; + sp.dump_maps(entries[0], entries[1]); + for (int mode = 0; mode < 2; mode ++) + { + fprintf(file, " device %s space %s %s:\n", memory.device().tag(), sp.name(), mode ? "write" : "read"); + for (memory_entry &entry : entries[mode]) + { + if (octal) + fprintf(file, "%0*o - %0*o", nc, entry.start, nc, entry.end); + else + fprintf(file, "%0*x - %0*x", nc, entry.start, nc, entry.end); + fprintf(file, ": %s\n", entry.entry->name().c_str()); + } + fprintf(file, "\n"); + } + } + } fclose(file); } } diff --git a/src/emu/debug/debugcpu.cpp b/src/emu/debug/debugcpu.cpp index bbf1170b762..cd130c5e3f0 100644 --- a/src/emu/debug/debugcpu.cpp +++ b/src/emu/debug/debugcpu.cpp @@ -1388,6 +1388,20 @@ device_debug::device_debug(device_t &device) device.interface(m_state); device.interface(m_disasm); + // set up notifiers and clear the passthrough handlers + if (m_memory) { + int count = m_memory->max_space_count(); + m_phr.resize(count, nullptr); + m_phw.resize(count, nullptr); + for (int i=0; i != count; i++) + if (m_memory->has_space(i)) { + address_space &space = m_memory->space(i); + m_notifiers.push_back(space.add_change_notifier([this, &space](read_or_write mode) { reinstall(space, mode); })); + } + else + m_notifiers.push_back(-1); + } + // set up state-related stuff if (m_state != nullptr) { @@ -1470,6 +1484,53 @@ device_debug::~device_debug() registerpoint_clear_all(); } +void device_debug::write_tracking(address_space &space, offs_t address, u64 data) +{ + dasm_memory_access const newAccess(space.spacenum(), address, data, history_pc(0)); + std::pair::iterator, bool> trackedAccess = m_track_mem_set.insert(newAccess); + if (!trackedAccess.second) + trackedAccess.first->m_pc = newAccess.m_pc; +} + +void device_debug::reinstall(address_space &space, read_or_write mode) +{ + int id = space.spacenum(); + if (u32(mode) & u32(read_or_write::READ)) + { + if (m_phr[id]) + m_phr[id]->remove(); + if (!m_hotspots.empty()) + switch (space.data_width()) + { + case 8: m_phr[id] = space.install_read_tap(0, space.addrmask(), "hotspot", [this, &space](offs_t address, u8 &, u8 ) { hotspot_check(space, address); }, m_phr[id]); break; + case 16: m_phr[id] = space.install_read_tap(0, space.addrmask(), "hotspot", [this, &space](offs_t address, u16 &, u16) { hotspot_check(space, address); }, m_phr[id]); break; + case 32: m_phr[id] = space.install_read_tap(0, space.addrmask(), "hotspot", [this, &space](offs_t address, u32 &, u32) { hotspot_check(space, address); }, m_phr[id]); break; + case 64: m_phr[id] = space.install_read_tap(0, space.addrmask(), "hotspot", [this, &space](offs_t address, u64 &, u64) { hotspot_check(space, address); }, m_phr[id]); break; + } + } + if (u32(mode) & u32(read_or_write::WRITE)) + { + if (m_phw[id]) + m_phw[id]->remove(); + if (m_track_mem) + switch (space.data_width()) + { + case 8: m_phw[id] = space.install_read_tap(0, space.addrmask(), "track_mem", [this, &space](offs_t address, u8 &data, u8 ) { write_tracking(space, address, data); }, m_phw[id]); break; + case 16: m_phw[id] = space.install_read_tap(0, space.addrmask(), "track_mem", [this, &space](offs_t address, u16 &data, u16) { write_tracking(space, address, data); }, m_phw[id]); break; + case 32: m_phw[id] = space.install_read_tap(0, space.addrmask(), "track_mem", [this, &space](offs_t address, u32 &data, u32) { write_tracking(space, address, data); }, m_phw[id]); break; + case 64: m_phw[id] = space.install_read_tap(0, space.addrmask(), "track_mem", [this, &space](offs_t address, u64 &data, u64) { write_tracking(space, address, data); }, m_phw[id]); break; + } + } +} + +void device_debug::reinstall_all(read_or_write mode) +{ + int count = m_memory->max_space_count(); + for (int i=0; i < count; i++) + if (m_memory->has_space(i)) + reinstall(m_memory->space(i), mode); +} + //------------------------------------------------- // start_hook - the scheduler calls this hook // before beginning execution for the given device @@ -1678,42 +1739,6 @@ void device_debug::instruction_hook(offs_t curpc) } -//------------------------------------------------- -// memory_read_hook - the memory system calls -// this hook when watchpoints are enabled and a -// memory read happens -//------------------------------------------------- - -void device_debug::memory_read_hook(address_space &space, offs_t address, u64 mem_mask) -{ - // check watchpoints - watchpoint_check(space, WATCHPOINT_READ, address, 0, mem_mask); - - // check hotspots - if (!m_hotspots.empty()) - hotspot_check(space, address); -} - - -//------------------------------------------------- -// memory_write_hook - the memory system calls -// this hook when watchpoints are enabled and a -// memory write happens -//------------------------------------------------- - -void device_debug::memory_write_hook(address_space &space, offs_t address, u64 data, u64 mem_mask) -{ - if (m_track_mem) - { - dasm_memory_access const newAccess(space.spacenum(), address, data, history_pc(0)); - std::pair::iterator, bool> trackedAccess = m_track_mem_set.insert(newAccess); - if (!trackedAccess.second) - trackedAccess.first->m_pc = newAccess.m_pc; - } - watchpoint_check(space, WATCHPOINT_WRITE, address, data, mem_mask); -} - - //------------------------------------------------- // set_instruction_hook - set a hook to be // called on each instruction for a given device @@ -2015,22 +2040,16 @@ void device_debug::breakpoint_enable_all(bool enable) // returning its index //------------------------------------------------- -int device_debug::watchpoint_set(address_space &space, int type, offs_t address, offs_t length, const char *condition, const char *action) +int device_debug::watchpoint_set(address_space &space, read_or_write type, offs_t address, offs_t length, const char *condition, const char *action) { if (space.spacenum() >= int(m_wplist.size())) - m_wplist.resize(space.spacenum()+1, nullptr); + m_wplist.resize(space.spacenum()+1); // allocate a new one u32 id = m_device.machine().debugger().cpu().get_watchpoint_index(); - watchpoint *wp = auto_alloc(m_device.machine(), watchpoint(this, m_symtable, id, space, type, address, length, condition, action)); - - // hook it into our list - wp->m_next = m_wplist[space.spacenum()]; - m_wplist[space.spacenum()] = wp; + m_wplist[space.spacenum()].emplace_back(std::make_unique(this, m_symtable, id, space, type, address, length, condition, action)); - // update the flags and return the index - watchpoint_update_flags(wp->m_space); - return wp->m_index; + return id; } @@ -2042,17 +2061,15 @@ int device_debug::watchpoint_set(address_space &space, int type, offs_t address, bool device_debug::watchpoint_clear(int index) { // scan the list to see if we own this breakpoint - for (int spacenum = 0; spacenum < int(m_wplist.size()); ++spacenum) - for (watchpoint **wp = &m_wplist[spacenum]; *wp != nullptr; wp = &(*wp)->m_next) - if ((*wp)->m_index == index) + for (auto &wpl : m_wplist) + { + for (auto wpi = wpl.begin(); wpi != wpl.end(); wpi++) + if ((*wpi)->index() == index) { - watchpoint *deleteme = *wp; - address_space &space = deleteme->m_space; - *wp = deleteme->m_next; - auto_free(m_device.machine(), deleteme); - watchpoint_update_flags(space); + wpl.erase(wpi); return true; } + } // we don't own it, return false return false; @@ -2065,10 +2082,8 @@ bool device_debug::watchpoint_clear(int index) void device_debug::watchpoint_clear_all() { - // clear the head until we run out - for (int spacenum = 0; spacenum < int(m_wplist.size()); ++spacenum) - while (m_wplist[spacenum] != nullptr) - watchpoint_clear(m_wplist[spacenum]->index()); + for (auto &wpl : m_wplist) + wpl.clear(); } @@ -2080,12 +2095,11 @@ void device_debug::watchpoint_clear_all() bool device_debug::watchpoint_enable(int index, bool enable) { // scan the list to see if we own this watchpoint - for (int spacenum = 0; spacenum < int(m_wplist.size()); ++spacenum) - for (watchpoint *wp = m_wplist[spacenum]; wp != nullptr; wp = wp->next()) - if (wp->m_index == index) + for (auto &wpl : m_wplist) + for (auto &wp : wpl) + if (wp->index() == index) { - wp->m_enabled = enable; - watchpoint_update_flags(wp->m_space); + wp->setEnabled(enable); return true; } @@ -2102,9 +2116,9 @@ bool device_debug::watchpoint_enable(int index, bool enable) void device_debug::watchpoint_enable_all(bool enable) { // apply the enable to all watchpoints we own - for (int spacenum = 0; spacenum < int(m_wplist.size()); ++spacenum) - for (watchpoint *wp = m_wplist[spacenum]; wp != nullptr; wp = wp->next()) - watchpoint_enable(wp->index(), enable); + for (auto &wpl : m_wplist) + for (auto &wp : wpl) + wp->setEnabled(enable); } @@ -2218,10 +2232,7 @@ void device_debug::hotspot_track(int numspots, int threshhold) // fill in the info m_hotspot_threshhold = threshhold; } - - // update the watchpoint flags to include us - if (m_memory != nullptr && m_memory->has_space(AS_PROGRAM)) - watchpoint_update_flags(m_memory->space(AS_PROGRAM)); + reinstall_all(read_or_write::READ); } @@ -2595,140 +2606,11 @@ void device_debug::breakpoint_check(offs_t pc) } -//------------------------------------------------- -// watchpoint_update_flags - update the device's -// watchpoint flags -//------------------------------------------------- - -void device_debug::watchpoint_update_flags(address_space &space) -{ - // if hotspots are enabled, turn on all reads - bool enableread = false; - if (!m_hotspots.empty()) - enableread = true; - - // see if there are any enabled breakpoints - bool enablewrite = false; - if (space.spacenum() < int(m_wplist.size())) - for (watchpoint *wp = m_wplist[space.spacenum()]; wp != nullptr; wp = wp->m_next) - if (wp->m_enabled) - { - if (wp->m_type & WATCHPOINT_READ) - enableread = true; - if (wp->m_type & WATCHPOINT_WRITE) - enablewrite = true; - } - - // push the flags out globally - space.enable_read_watchpoints(enableread); - space.enable_write_watchpoints(enablewrite); -} - - //------------------------------------------------- // watchpoint_check - check the watchpoints // for a given CPU and address space //------------------------------------------------- -void device_debug::watchpoint_check(address_space& space, int type, offs_t address, u64 value_to_write, u64 mem_mask) -{ - m_device.machine().debugger().cpu().watchpoint_check(space, type, address, value_to_write, mem_mask, m_wplist); -} - -void debugger_cpu::watchpoint_check(address_space& space, int type, offs_t address, u64 value_to_write, u64 mem_mask, std::vector &wplist) -{ - // if we're within debugger code, don't stop - if (m_within_instruction_hook || m_machine.side_effects_disabled()) - return; - - m_within_instruction_hook = true; - - // adjust address, size & value_to_write based on mem_mask. - offs_t size = 0; - if (mem_mask != 0) - { - int bus_size = space.data_width() / 8; - int address_offset = 0; - - while (address_offset < bus_size && (mem_mask & 0xff) == 0) - { - address_offset++; - value_to_write >>= 8; - mem_mask >>= 8; - } - - while (mem_mask != 0) - { - size++; - mem_mask >>= 8; - } - - // (1<<(size*8))-1 won't work when size is 8; let's just use a lut - static const u64 masks[] = { - 0x0U, - 0xffU, - 0xffffU, - 0xffffffU, - 0xffffffffU, - 0xffffffffffU, - 0xffffffffffffU, - 0xffffffffffffffU, - 0xffffffffffffffffU}; - value_to_write &= masks[size]; - - if (space.endianness() == ENDIANNESS_LITTLE) - address += address_offset; - else - address += bus_size - size - address_offset; - } - - // if we are a write watchpoint, stash the value that will be written - m_wpaddr = address; - if (type & WATCHPOINT_WRITE) - m_wpdata = value_to_write; - - // see if we match - if (space.spacenum() < int(wplist.size())) - for (device_debug::watchpoint *wp = wplist[space.spacenum()]; wp != nullptr; wp = wp->next()) - if (wp->hit(type, address, size)) - { - // halt in the debugger by default - m_execution_state = exec_state::STOPPED; - - // if we hit, evaluate the action - if (!wp->action().empty()) - m_machine.debugger().console().execute_command(wp->action(), false); - - // print a notification, unless the action made us go again - if (m_execution_state == exec_state::STOPPED) - { - static const char *const sizes[] = - { - "0bytes", "byte", "word", "3bytes", "dword", "5bytes", "6bytes", "7bytes", "qword" - }; - offs_t pc = space.device().state().pcbase(); - std::string buffer; - - if (type & WATCHPOINT_WRITE) - { - buffer = string_format("Stopped at watchpoint %X writing %s to %08X (PC=%X)", wp->index(), sizes[size], address, pc); - if (value_to_write >> 32) - buffer.append(string_format(" (data=%X%08X)", u32(value_to_write >> 32), u32(value_to_write))); - else - buffer.append(string_format(" (data=%X)", u32(value_to_write))); - } - else - buffer = string_format("Stopped at watchpoint %X reading %s from %08X (PC=%X)", wp->index(), sizes[size], address, pc); - m_machine.debugger().console().printf("%s\n", buffer.c_str()); - space.device().debug()->compute_debug_flags(); - } - break; - } - - m_within_instruction_hook = false; -} - - //------------------------------------------------- // hotspot_check - check for hotspots on a // memory read access @@ -2773,7 +2655,6 @@ void device_debug::hotspot_check(address_space &space, offs_t address) } } - //------------------------------------------------- // get_current_pc - getter callback for a device's // current instruction pointer @@ -2917,59 +2798,293 @@ device_debug::watchpoint::watchpoint(device_debug* debugInterface, symbol_table &symbols, int index, address_space &space, - int type, + read_or_write type, offs_t address, offs_t length, const char *condition, const char *action) : m_debugInterface(debugInterface), - m_next(nullptr), - m_space(space), - m_index(index), - m_enabled(true), - m_type(type), - m_address(address & space.addrmask()), - m_length(length), - m_condition(&symbols, (condition != nullptr) ? condition : "1"), - m_action((action != nullptr) ? action : "") + m_phr(nullptr), + m_phw(nullptr), + m_space(space), + m_index(index), + m_enabled(true), + m_type(type), + m_address(address & space.addrmask()), + m_length(length), + m_condition(&symbols, (condition != nullptr) ? condition : "1"), + m_action((action != nullptr) ? action : "") +{ + std::fill(std::begin(m_start_address), std::end(m_start_address), 0); + std::fill(std::begin(m_end_address), std::end(m_end_address), 0); + std::fill(std::begin(m_masks), std::end(m_masks), 0); + + offs_t ashift = m_space.addr_shift(); + endianness_t endian = m_space.endianness(); + offs_t subamask = m_space.alignment() - 1; + offs_t unit_size = ashift <= 0 ? 8 << -ashift : 8 >> ashift; + offs_t start = m_address; + offs_t end = (m_address + m_length - 1) & space.addrmask(); + if (end < start) + end = space.addrmask(); + offs_t rstart = start & ~subamask; + offs_t rend = end | subamask; + u64 smask, mmask, emask; + smask = mmask = emask = make_bitmask(m_space.data_width()); + if (start != rstart) + { + if (endian == ENDIANNESS_LITTLE) + smask &= ~make_bitmask((start - rstart) * unit_size); + else + smask &= make_bitmask((rstart + subamask + 1 - start) * unit_size); + } + if (end != rend) + { + if (endian == ENDIANNESS_LITTLE) + emask &= make_bitmask((rend + subamask + 1 - end) * unit_size); + else + emask &= ~make_bitmask((end - rend) * unit_size); + } + + if (rend == (rstart | subamask) || smask == emask) + { + m_start_address[0] = rstart; + m_end_address[0] = rend; + m_masks[0] = smask & emask; + } + else + { + int idx = 0; + if (smask != mmask) + { + m_start_address[idx] = rstart; + m_end_address[idx] = rstart | subamask; + m_masks[idx] = smask; + idx++; + rstart += subamask + 1; + } + if (mmask == emask) + { + m_start_address[idx] = rstart; + m_end_address[idx] = rend; + m_masks[idx] = emask; + } + else + { + m_start_address[idx] = rstart; + m_end_address[idx] = rend - subamask - 1; + m_masks[idx] = mmask; + idx++; + m_start_address[idx] = rend - subamask; + m_end_address[idx] = rend; + m_masks[idx] = emask; + } + } + + install(read_or_write::READWRITE); + m_notifier = m_space.add_change_notifier([this](read_or_write mode) { + if (m_enabled) + { + if (u32(mode) & u32(read_or_write::READ)) + m_phr->remove(); + if (u32(mode) & u32(read_or_write::WRITE)) + m_phw->remove(); + install(mode); + } + }); +} + +device_debug::watchpoint::~watchpoint() { + m_space.remove_change_notifier(m_notifier); +} + +void device_debug::watchpoint::setEnabled(bool value) +{ + if (m_enabled != value) + { + m_enabled = value; + if (m_enabled) + install(read_or_write::READWRITE); + else + { + m_phr->remove(); + m_phw->remove(); + } + } } +void device_debug::watchpoint::install(read_or_write mode) +{ + std::string name = util::string_format("wp@%x", m_address); + switch (m_space.data_width()) + { + case 8: + if (u32(m_type) & u32(mode) & u32(read_or_write::READ)) + m_phr = m_space.install_read_tap(m_start_address[0], m_end_address[0], name, + [this](offs_t offset, u8 &data, u8 mem_mask) { + triggered(read_or_write::READ, offset, data, mem_mask); + }, m_phr); + if (u32(m_type) & u32(mode) & u32(read_or_write::WRITE)) + m_phw = m_space.install_write_tap(m_start_address[0], m_end_address[0], name, + [this](offs_t offset, u8 &data, u8 mem_mask) { + triggered(read_or_write::WRITE, offset, data, mem_mask); + }, m_phw); + break; -//------------------------------------------------- -// hit - detect a hit -//------------------------------------------------- + case 16: + for (int i=0; i != 3; i++) + if (m_masks[i]) + { + u16 mask = m_masks[i]; + if (u32(m_type) & u32(mode) & u32(read_or_write::READ)) + m_phr = m_space.install_read_tap(m_start_address[i], m_end_address[i], name, + [this, mask](offs_t offset, u16 &data, u16 mem_mask) { + if (mem_mask & mask) + triggered(read_or_write::READ, offset, data, mem_mask); + }, m_phr); + if (u32(m_type) & u32(mode) & u32(read_or_write::WRITE)) + m_phw = m_space.install_write_tap(m_start_address[i], m_end_address[i], name, + [this, mask](offs_t offset, u16 &data, u16 mem_mask) { + if (mem_mask & mask) + triggered(read_or_write::WRITE, offset, data, mem_mask); + }, m_phw); + } + break; + + case 32: + for (int i=0; i != 3; i++) + if (m_masks[i]) + { + u32 mask = m_masks[i]; + if (u32(m_type) & u32(mode) & u32(read_or_write::READ)) + m_phr = m_space.install_read_tap(m_start_address[i], m_end_address[i], name, + [this, mask](offs_t offset, u32 &data, u32 mem_mask) { + if (mem_mask & mask) + triggered(read_or_write::READ, offset, data, mem_mask); + }, m_phr); + if (u32(m_type) & u32(mode) & u32(read_or_write::WRITE)) + m_phw = m_space.install_write_tap(m_start_address[i], m_end_address[i], name, + [this, mask](offs_t offset, u32 &data, u32 mem_mask) { + if (mem_mask & mask) + triggered(read_or_write::WRITE, offset, data, mem_mask); + }, m_phw); + } + break; + + case 64: + for (int i=0; i != 3; i++) + if (m_masks[i]) + { + u64 mask = m_masks[i]; + if (u32(m_type) & u32(mode) & u32(read_or_write::READ)) + m_phr = m_space.install_read_tap(m_start_address[i], m_end_address[i], name, + [this, mask](offs_t offset, u64 &data, u64 mem_mask) { + if (mem_mask & mask) + triggered(read_or_write::READ, offset, data, mem_mask); + }, m_phr); + if (u32(m_type) & u32(mode) & u32(read_or_write::WRITE)) + m_phw = m_space.install_write_tap(m_start_address[i], m_end_address[i], name, + [this, mask](offs_t offset, u64 &data, u64 mem_mask) { + if (mem_mask & mask) + triggered(read_or_write::WRITE, offset, data, mem_mask); + }, m_phw); + } + break; + } +} -bool device_debug::watchpoint::hit(int type, offs_t address, int size) +void device_debug::watchpoint::triggered(read_or_write type, offs_t address, u64 data, u64 mem_mask) { - // don't hit if disabled - if (!m_enabled) - return false; + auto &machine = m_debugInterface->m_device.machine(); + auto &debug = machine.debugger(); - // must match the type - if ((m_type & type) == 0) - return false; + // if we're within debugger code, don't trigger + if (debug.cpu().within_instruction_hook() || machine.side_effects_disabled()) + return; - // must match our address - if (address + size <= m_address || address >= m_address + m_length) - return false; + // adjust address, size & value_to_write based on mem_mask. + offs_t size = 0; + offs_t ashift = m_space.addr_shift(); + offs_t unit_size = ashift <= 0 ? 8 << -ashift : 8 >> ashift; + u64 unit_mask = make_bitmask(unit_size); + + offs_t address_offset = 0; + + if(!mem_mask) + mem_mask = 0xff; + + while (!(mem_mask & unit_mask)) + { + address_offset++; + data >>= unit_size; + mem_mask >>= unit_size; + } + + while (mem_mask) + { + size++; + mem_mask >>= unit_size; + } + + data &= make_bitmask(size * unit_size); + + if (m_space.endianness() == ENDIANNESS_LITTLE) + address += address_offset; + else + address += m_space.alignment() - size - address_offset; + + // stash the value that will be written or has just been read + debug.cpu().set_wpinfo(address, data); + + // protect against recursion + debug.cpu().set_within_instruction(true); // must satisfy the condition if (!m_condition.is_empty()) { try { - return (m_condition.execute() != 0); + if (!m_condition.execute() != 0) + { + debug.cpu().set_within_instruction(false); + return; + } } catch (expression_error &) { - return false; + debug.cpu().set_within_instruction(false); + return; } } - return true; -} + // halt in the debugger by default + debug.cpu().set_execution_stopped(); + + // evaluate the action + if (!m_action.empty()) + debug.console().execute_command(m_action, false); + // print a notification, unless the action made us go again + if (debug.cpu().is_stopped()) + { + offs_t pc = m_space.device().state().pcbase(); + std::string buffer; + + buffer = string_format(type == read_or_write::READ ? + "Stopped at watchpoint %X reading %0*X from %08X (PC=%X)" : + "Stopped at watchpoint %X writing %0*X to %08X (PC=%X)", + m_index, + size * unit_size / 4, + data, + address, + pc); + debug.console().printf("%s\n", buffer); + m_debugInterface->compute_debug_flags(); + } + + debug.cpu().set_within_instruction(false); +} //************************************************************************** // DEBUG REGISTERPOINT diff --git a/src/emu/debug/debugcpu.h b/src/emu/debug/debugcpu.h index 6d54456b913..f3e8f68a408 100644 --- a/src/emu/debug/debugcpu.h +++ b/src/emu/debug/debugcpu.h @@ -22,10 +22,6 @@ // CONSTANTS //************************************************************************** -constexpr u8 WATCHPOINT_READ = 1; -constexpr u8 WATCHPOINT_WRITE = 2; -constexpr u8 WATCHPOINT_READWRITE = WATCHPOINT_READ | WATCHPOINT_WRITE; - constexpr int COMMENT_VERSION = 1; @@ -74,7 +70,6 @@ public: private: // internals bool hit(offs_t pc); - const device_debug * m_debugInterface; // the interface we were created from breakpoint * m_next; // next in the list int m_index; // user reported index @@ -96,18 +91,18 @@ public: symbol_table &symbols, int index, address_space &space, - int type, + read_or_write type, offs_t address, offs_t length, const char *condition = nullptr, const char *action = nullptr); + ~watchpoint(); // getters const device_debug *debugInterface() const { return m_debugInterface; } - watchpoint *next() const { return m_next; } address_space &space() const { return m_space; } int index() const { return m_index; } - int type() const { return m_type; } + read_or_write type() const { return m_type; } bool enabled() const { return m_enabled; } offs_t address() const { return m_address; } offs_t length() const { return m_length; } @@ -115,22 +110,30 @@ public: const std::string &action() const { return m_action; } // setters - void setEnabled(bool value) { m_enabled = value; } + void setEnabled(bool value); // internals bool hit(int type, offs_t address, int size); private: - const device_debug * m_debugInterface; // the interface we were created from - watchpoint * m_next; // next in the list + device_debug * m_debugInterface; // the interface we were created from + memory_passthrough_handler *m_phr; // passthrough handler reference, read access + memory_passthrough_handler *m_phw; // passthrough handler reference, write access address_space & m_space; // address space int m_index; // user reported index bool m_enabled; // enabled? - u8 m_type; // type (read/write) + read_or_write m_type; // type (read/write) offs_t m_address; // start address offs_t m_length; // length of watch area parsed_expression m_condition; // condition std::string m_action; // action + int m_notifier; // address map change notifier id + + offs_t m_start_address[3]; // the start addresses of the checks to install + offs_t m_end_address[3]; // the end addresses + u64 m_masks[3]; // the access masks + void install(read_or_write mode); + void triggered(read_or_write type, offs_t address, u64 data, u64 mem_mask); }; // registerpoint class @@ -179,8 +182,6 @@ public: void interrupt_hook(int irqline); void exception_hook(int exception); void instruction_hook(offs_t curpc); - void memory_read_hook(address_space &space, offs_t address, u64 mem_mask); - void memory_write_hook(address_space &space, offs_t address, u64 data, u64 mem_mask); // hooks into our operations void set_instruction_hook(debug_instruction_hook_func hook); @@ -222,8 +223,8 @@ public: // watchpoints int watchpoint_space_count() const { return m_wplist.size(); } - watchpoint *watchpoint_first(int spacenum) const { return m_wplist[spacenum]; } - int watchpoint_set(address_space &space, int type, offs_t address, offs_t length, const char *condition, const char *action); + const std::vector> &watchpoint_vector(int spacenum) const { return m_wplist[spacenum]; } + int watchpoint_set(address_space &space, read_or_write type, offs_t address, offs_t length, const char *condition, const char *action); bool watchpoint_clear(int wpnum); void watchpoint_clear_all(); bool watchpoint_enable(int index, bool enable = true); @@ -289,9 +290,10 @@ private: // breakpoint and watchpoint helpers void breakpoint_update_flags(); void breakpoint_check(offs_t pc); - void watchpoint_update_flags(address_space &space); - void watchpoint_check(address_space &space, int type, offs_t address, u64 value_to_write, u64 mem_mask); void hotspot_check(address_space &space, offs_t address); + void reinstall_all(read_or_write mode); + void reinstall(address_space &space, read_or_write mode); + void write_tracking(address_space &space, offs_t address, u64 data); // symbol get/set callbacks static u64 get_current_pc(symbol_table &table); @@ -332,7 +334,7 @@ private: // breakpoints and watchpoints breakpoint * m_bplist; // list of breakpoints - std::vector m_wplist; // watchpoint lists for each address space + std::vector>> m_wplist; // watchpoint lists for each address space registerpoint * m_rplist; // list of registerpoints // tracing @@ -373,9 +375,13 @@ private: address_space * m_space; // space where the access occurred u32 m_count; // number of hits }; - std::vector m_hotspots; // hotspot list + std::vector m_hotspots; // hotspot list int m_hotspot_threshhold; // threshhold for the number of hits to print + std::vector m_phr; // passthrough handler reference for each space, read mode + std::vector m_phw; // passthrough handler reference for each space, write mode + std::vector m_notifiers; // notifiers for each space + // pc tracking class dasm_pc_tag { @@ -564,6 +570,7 @@ public: void set_memory_modified(bool memory_modified) { m_memory_modified = memory_modified; } void set_execution_stopped() { m_execution_state = exec_state::STOPPED; } void set_execution_running() { m_execution_state = exec_state::RUNNING; } + void set_wpinfo(offs_t address, u64 data) { m_wpaddr = address; m_wpdata = data; } // device_debug helpers // [TODO] [RH]: Look into this more later, can possibly merge these two classes @@ -575,7 +582,6 @@ public: void ensure_comments_loaded(); void reset_transient_flags(); void process_source_file(); - void watchpoint_check(address_space& space, int type, offs_t address, u64 value_to_write, u64 mem_mask, std::vector &wplist); private: static const size_t NUM_TEMP_VARIABLES; diff --git a/src/emu/debug/dvwpoints.cpp b/src/emu/debug/dvwpoints.cpp index a0e5befe017..2ab1fc6a0bf 100644 --- a/src/emu/debug/dvwpoints.cpp +++ b/src/emu/debug/dvwpoints.cpp @@ -79,7 +79,7 @@ static int cTypeAscending(const void* a, const void* b) { const device_debug::watchpoint* left = *(device_debug::watchpoint**)a; const device_debug::watchpoint* right = *(device_debug::watchpoint**)b; - return left->type() - right->type(); + return int(left->type()) - int(right->type()); } static int cTypeDescending(const void* a, const void* b) @@ -229,8 +229,8 @@ void debug_view_watchpoints::gather_watchpoints() device_debug &debugInterface = *source.device()->debug(); for (int spacenum = 0; spacenum < debugInterface.watchpoint_space_count(); ++spacenum) { - for (device_debug::watchpoint *wp = debugInterface.watchpoint_first(spacenum); wp != nullptr; wp = wp->next()) - m_buffer.push_back(wp); + for (const auto &wp : debugInterface.watchpoint_vector(spacenum)) + m_buffer.push_back(wp.get()); } } @@ -330,7 +330,7 @@ void debug_view_watchpoints::view_update() linebuf.put('-'); util::stream_format(linebuf, "%0*X", wp->space().addrchars(), wp->address() + wp->length() - 1); pad_ostream_to_length(linebuf, tableBreaks[4]); - linebuf << types[wp->type() & 3]; + linebuf << types[int(wp->type())]; pad_ostream_to_length(linebuf, tableBreaks[5]); if (strcmp(wp->condition(), "1")) linebuf << wp->condition(); diff --git a/src/emu/dimemory.cpp b/src/emu/dimemory.cpp index 84b161a5a13..0c1caace023 100644 --- a/src/emu/dimemory.cpp +++ b/src/emu/dimemory.cpp @@ -116,34 +116,6 @@ void device_memory_interface::set_addrmap(int spacenum, address_map_constructor } -//------------------------------------------------- -// dump - dump memory tables to the given file in -// human-readable format -//------------------------------------------------- - -void device_memory_interface::dump(FILE *file) const -{ - for (auto const &space : m_addrspace) - if (space) { - fprintf(file, - "\n\n" - "====================================================\n" - "Device '%s' %s address space read handler dump\n" - "====================================================\n", - device().tag(), space->name()); - space->dump_map(file, read_or_write::READ); - - fprintf(file, - "\n\n" - "====================================================\n" - "Device '%s' %s address space write handler dump\n" - "====================================================\n", - device().tag(), space->name()); - space->dump_map(file, read_or_write::WRITE); - } -} - - //------------------------------------------------- // memory_translate - translate from logical to // phyiscal addresses; designed to be overridden diff --git a/src/emu/dimemory.h b/src/emu/dimemory.h index ec35228edd8..612ff15ae28 100644 --- a/src/emu/dimemory.h +++ b/src/emu/dimemory.h @@ -123,7 +123,7 @@ public: assert((0 <= spacenum) && (max_space_count() > spacenum)); m_addrspace.resize(std::max(m_addrspace.size(), spacenum + 1)); assert(!m_addrspace[spacenum]); - m_addrspace[spacenum] = std::make_unique(manager, *this, spacenum); + m_addrspace[spacenum] = std::make_unique(manager, *this, spacenum, space_config(spacenum)->addr_width()); } void prepare_maps() { for (auto const &space : m_addrspace) { if (space) { space->prepare_map(); } } } void populate_from_maps() { for (auto const &space : m_addrspace) { if (space) { space->populate_from_map(); } } } @@ -131,9 +131,6 @@ public: void locate_memory() { for (auto const &space : m_addrspace) { if (space) { space->locate_memory(); } } } void set_log_unmap(bool log) { for (auto const &space : m_addrspace) { if (space) { space->set_log_unmap(log); } } } - // diagnostic functions - void dump(FILE *file) const; - protected: using space_config_vector = std::vector>; diff --git a/src/emu/emumem.cpp b/src/emu/emumem.cpp index c27fb468287..ae3e95a0b3b 100644 --- a/src/emu/emumem.cpp +++ b/src/emu/emumem.cpp @@ -6,194 +6,173 @@ Functions which handle device memory access. -**************************************************************************** - - Basic theory of memory handling: - - An address with up to 32 bits is passed to a memory handler. First, - an address mask is applied to the address, removing unused bits. - - Next, the address is broken into two halves, an upper half and a - lower half. The number of bits in each half can be controlled via - the macros in LEVEL1_BITS and LEVEL2_BITS, but they default to the - upper 18 bits and the lower 14 bits. - - The upper half is then used as an index into a lookup table of bytes. - If the value pulled from the table is between SUBTABLE_BASE and 255, - then the lower half of the address is needed to resolve the final - handler. In this case, the value from the table is combined with the - lower address bits to form an index into a subtable. - - The final result of the lookup is a value from 0 to SUBTABLE_BASE - 1. - These values correspond to memory handlers. The lower numbered - handlers (from 0 through STATIC_COUNT - 1) are fixed handlers and refer - to either memory banks or other special cases. The remaining handlers - (from STATIC_COUNT through SUBTABLE_BASE - 1) are dynamically - allocated to driver-specified handlers. - - Thus, table entries fall into these categories: - - 0 .. STATIC_COUNT - 1 = fixed handlers - STATIC_COUNT .. SUBTABLE_BASE - 1 = driver-specific handlers - SUBTABLE_BASE .. TOTAL_MEMORY_BANKS - 1 = need to look up lower bits in subtable - - Caveats: - - * If your driver executes an opcode which crosses a bank-switched - boundary, it will pull the wrong data out of memory. Although not - a common case, you may need to revert to memcpy to work around this. - See machine/tnzs.c for an example. - - To do: - - - Add local banks for RAM/ROM to reduce pressure on banking - - Always mirror everything out to 32 bits so we don't have to mask the address? - - Add the ability to start with another memory map and modify it - - Add fourth memory space for encrypted opcodes - - Automatically mirror program space into data space if no data space - - Get rid of opcode/data separation by using address spaces? - - Add support for internal addressing (maybe just accessors - see TMS3202x) - -**************************************************************************** - - Address map fields and restrictions: - - AM_RANGE(start, end) - Specifies a range of consecutive addresses beginning with 'start' and - ending with 'end' inclusive. An address hits in this bucket if the - 'address' >= 'start' and 'address' <= 'end'. - - AM_MASK(mask) - Specifies a mask for the addresses in the current bucket. This mask - is applied after a positive hit in the bucket specified by AM_RANGE - or AM_SPACE, and is computed before accessing the RAM or calling - through to the read/write handler. If you use AM_MIRROR, below, there - should not be any bits in common between mask and mirror. Same for - select. - - AM_MIRROR(mirror) - Specifies mirror addresses for the given bucket. The current bucket - is mapped repeatedly according to the mirror mask, once where each - mirror bit is 0, and once where it is 1. For example, a 'mirror' - value of 0x14000 would map the bucket at 0x00000, 0x04000, 0x10000, - and 0x14000. - - AM_SELECT(select) - Mirrors the addresses for the given bucket and pass the corresponding - address bits to the handler. Very useful for devices with multiple - slots/channels/etc were each slot is on a series of consecutive - addresses regrouping all its registers. - - AM_ROM - Specifies that this bucket contains ROM data by attaching an - internal read handler. If this address space describes the first - address space for a device, and if there is a region whose name - matches the device's name, and if the bucket start/end range is - within the bounds of that region, then this bucket will automatically - map to the memory contained in that region. - - AM_RAM - AM_READONLY - AM_WRITEONLY - Specifies that this bucket contains RAM data by attaching internal - read and/or write handlers. Memory is automatically allocated to back - this area. AM_RAM maps both reads and writes, while AM_READONLY only - maps reads and AM_WRITEONLY only maps writes. - - AM_NOP - AM_READNOP - AM_WRITENOP - Specifies that reads and/or writes in this bucket are unmapped, but - that accesses to them should not be logged. AM_NOP unmaps both reads - and writes, while AM_READNOP only unmaps reads, and AM_WRITENOP only - unmaps writes. - - AM_UNMAP - Specifies that both reads and writes in thus bucket are unmapeed, - and that accesses to them should be logged. There is rarely a need - for this, as the entire address space is initialized to behave this - way by default. - - AM_READ_BANK(tag) - AM_WRITE_BANK(tag) - AM_READWRITE_BANK(tag) - Specifies that reads and/or writes in this bucket map to a memory - bank with the provided 'tag'. The actual memory this bank points to - can be later controlled via the same tag. - - AM_READ(read) - AM_WRITE(write) - AM_READWRITE(read, write) - Specifies read and/or write handler callbacks for this bucket. All - reads and writes in this bucket will trigger a call to the provided - functions. - - AM_DEVREAD(tag, read) - AM_DEVWRITE(tag, read) - AM_DEVREADWRITE(tag, read) - Specifies a device-specific read and/or write handler for this - bucket, automatically bound to the device specified by the provided - 'tag'. - - AM_READ_PORT(tag) - AM_WRITE_PORT(tag) - AM_READWRITE_PORT(tag) - Specifies that read and/or write accesses in this bucket will map - to the I/O port with the provided 'tag'. An internal read/write - handler is set up to handle this mapping. - - AM_REGION(class, tag, offs) - Only useful if used in conjunction with AM_ROM, AM_RAM, or - AM_READ/WRITE_BANK. By default, memory is allocated to back each - bucket. By specifying AM_REGION, you can tell the memory system to - point the base of the memory backing this bucket to a given memory - 'region' at the specified 'offs' instead of allocating it. - - AM_SHARE(tag) - Similar to AM_REGION, this specifies that the memory backing the - current bucket is shared with other buckets. The first bucket to - specify the share 'tag' will use its memory as backing for all - future buckets that specify AM_SHARE with the same 'tag'. - - AM_SETOFFSET(setoffset) - Specifies a handler for a 'set address' operation. The intended use case - for this operation is to emulate a split-phase memory access: The caller - (usually a CPU) sets the address bus lines using set_address. Some - component may then react, for instance, by asserting a control line - like WAIT before delivering the data on the data bus. The data bits are - then sampled on the read operation or delivered on the write operation - that must be called subsequently. - It is not checked whether the address of the set_address operation - matches the address of the subsequent read/write operation. - The address map translates the address to a bucket and an offset, - hence the name of the macro. If no handler is specified for a bucket, - a set_address operation hitting that bucket returns silently. - - AM_DEVSETOFFSET(tag, setoffset) - Specifies a handler for a set_address operation, bound to the device - specified by 'tag'. - - ***************************************************************************/ +#include "emu.h" #include #include - -#include "emu.h" #include "emuopts.h" #include "debug/debugcpu.h" +#include "emumem_mud.h" +#include "emumem_hea.h" +#include "emumem_hem.h" +#include "emumem_hedp.h" +#include "emumem_heun.h" +#include "emumem_heu.h" +#include "emumem_hedr.h" +#include "emumem_hedw.h" +#include "emumem_hep.h" +#include "emumem_het.h" + //************************************************************************** // DEBUGGING //************************************************************************** -#define MEM_DUMP (0) #define VERBOSE (0) -#define TEST_HANDLER (0) #define VPRINTF(x) do { if (VERBOSE) printf x; } while (0) +#define VALIDATE_REFCOUNTS 1 + +void handler_entry::dump_map(std::vector &map) const +{ + fatalerror("dump_map called on non-dispatching class\n"); +} + +void handler_entry::reflist::add(const handler_entry *entry) +{ + refcounts[entry]++; + if(seen.find(entry) == seen.end()) { + seen.insert(entry); + todo.insert(entry); + } +} + +void handler_entry::reflist::propagate() +{ + while(!todo.empty()) { + const handler_entry *entry = *todo.begin(); + todo.erase(todo.begin()); + entry->enumerate_references(*this); + } +} + +void handler_entry::reflist::check() +{ + bool bad = false; + for(const auto &i : refcounts) { + if(i.first->get_refcount() != i.second) { + fprintf(stderr, "Reference count error on handler \"%s\" stored %u real %u.\n", + i.first->name().c_str(), i.first->get_refcount(), i.second); + bad = true; + } + } + if(bad) + abort(); +} + + +// default handler methods + +void handler_entry::enumerate_references(handler_entry::reflist &refs) const +{ +} + +template void handler_entry_read::populate_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read *handler) +{ + fatalerror("populate called on non-dispatching class\n"); +} + +template void handler_entry_read::populate_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_read *handler) +{ + fatalerror("populate called on non-dispatching class\n"); +} + +template void handler_entry_read::populate_mismatched_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, const memory_units_descriptor &descriptor, u8 rkey, std::vector &mappings) +{ + fatalerror("populate_mismatched called on non-dispatching class\n"); +} + +template void handler_entry_read::populate_mismatched_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, const memory_units_descriptor &descriptor, std::vector &mappings) +{ + fatalerror("populate_mismatched called on non-dispatching class\n"); +} + +template void handler_entry_read::populate_passthrough_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read_passthrough *handler, std::vector &mappings) +{ + fatalerror("populate_passthrough called on non-dispatching class\n"); +} + +template void handler_entry_read::populate_passthrough_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_read_passthrough *handler, std::vector &mappings) +{ + fatalerror("populate_passthrough called on non-dispatching class\n"); +} + +template void handler_entry_read::lookup(offs_t address, offs_t &start, offs_t &end, handler_entry_read *&handler) const +{ + fatalerror("lookup called on non-dispatching class\n"); +} + +template void *handler_entry_read::get_ptr(offs_t offset) const +{ + return nullptr; +} + +template void handler_entry_read::detach(const std::unordered_set &handlers) +{ + fatalerror("detach called on non-dispatching class\n"); +} + + +template void handler_entry_write::populate_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_write *handler) +{ + fatalerror("populate called on non-dispatching class\n"); +} + +template void handler_entry_write::populate_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_write *handler) +{ + fatalerror("populate called on non-dispatching class\n"); +} + +template void handler_entry_write::populate_mismatched_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, const memory_units_descriptor &descriptor, u8 rkey, std::vector &mappings) +{ + fatalerror("populate_mismatched called on non-dispatching class\n"); +} + +template void handler_entry_write::populate_mismatched_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, const memory_units_descriptor &descriptor, std::vector &mappings) +{ + fatalerror("populate_mismatched called on non-dispatching class\n"); +} + +template void handler_entry_write::populate_passthrough_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_write_passthrough *handler, std::vector &mappings) +{ + fatalerror("populate_passthrough called on non-dispatching class\n"); +} + +template void handler_entry_write::populate_passthrough_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_write_passthrough *handler, std::vector &mappings) +{ + fatalerror("populate_passthrough called on non-dispatching class\n"); +} + +template void handler_entry_write::lookup(offs_t address, offs_t &start, offs_t &end, handler_entry_write *&handler) const +{ + fatalerror("lookup called on non-dispatching class\n"); +} + +template void *handler_entry_write::get_ptr(offs_t offset) const +{ + return nullptr; +} + +template void handler_entry_write::detach(const std::unordered_set &handlers) +{ + fatalerror("detach called on non-dispatching class\n"); +} + + + /*------------------------------------------------- core_i64_hex_format - i64 format printf helper -------------------------------------------------*/ @@ -235,1099 +214,440 @@ const int BANK_ENTRY_UNSPECIFIED = -1; // other address map constants const int MEMORY_BLOCK_CHUNK = 65536; // minimum chunk size of allocated memory blocks -// static data access handler constants -enum -{ - STATIC_INVALID = 0, // invalid - should never be used - STATIC_BANK1 = 1, // first memory bank - STATIC_BANKMAX = 0xfb, // last memory bank - STATIC_NOP, // NOP - reads = unmapped value; writes = no-op - STATIC_UNMAP, // unmapped - same as NOP except we log errors - STATIC_WATCHPOINT, // watchpoint - used internally - STATIC_COUNT // total number of static handlers -}; - - //************************************************************************** // TYPE DEFINITIONS //************************************************************************** +// ======================> address_space_specific -// ======================> handler_entry - -// a handler entry contains information about a memory handler -class handler_entry +// this is a derived class of address_space with specific width, endianness, and table size +template +class address_space_specific : public address_space { - DISABLE_COPYING(handler_entry); + using uX = typename handler_entry_size::uX; + using NativeType = uX; + using this_type = address_space_specific; -protected: - // construction/destruction - handler_entry(u8 width, endianness_t endianness, u8 **rambaseptr); - virtual ~handler_entry(); + // constants describing the native size + static constexpr u32 NATIVE_BYTES = 1 << Width; + static constexpr u32 NATIVE_STEP = AddrShift >= 0 ? NATIVE_BYTES << iabs(AddrShift) : NATIVE_BYTES >> iabs(AddrShift); + static constexpr u32 NATIVE_MASK = NATIVE_STEP - 1; + static constexpr u32 NATIVE_BITS = 8 * NATIVE_BYTES; + + static constexpr offs_t offset_to_byte(offs_t offset) { return AddrShift < 0 ? offset << iabs(AddrShift) : offset >> iabs(AddrShift); } public: - // getters - bool populated() const { return m_populated; } - offs_t addrstart() const { return m_addrstart; } - offs_t addrend() const { return m_addrend; } - offs_t addrmask() const { return m_addrmask; } - offs_t bytemask() const { return m_bytemask; } - virtual const char *name() const = 0; - virtual const char *subunit_name(int entry) const = 0; - void description(char *buffer) const; - - virtual void copy(handler_entry *entry); - - // return offset within the range referenced by this handler - offs_t offset(offs_t address) const { return (address - m_addrstart) & m_addrmask; } - - // return a pointer to the backing RAM at the given offset - u8 *ramptr(offs_t offset = 0) const { return *m_rambaseptr + offset; } - - // see if we are an exact match to the given parameters - bool matches_exactly(offs_t addrstart, offs_t addrend, offs_t addrmask) const - { - return (m_populated && m_addrstart == addrstart && m_addrend == addrend && m_addrmask == addrmask); - } + std::string get_handler_string(read_or_write readorwrite, offs_t byteaddress) const override; + void dump_maps(std::vector &read_map, std::vector &write_map) const override; + + void unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, bool quiet) override; + void install_ram_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, void *baseptr) override; + void install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, const char *rtag, const char *wtag) override; + void install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_bank *rbank, memory_bank *wbank) override; + void install_readwrite_port(offs_t addrstart, offs_t addrend, offs_t addrmirror, const char *rtag, const char *wtag) override; + void install_device_delegate(offs_t addrstart, offs_t addrend, device_t &device, address_map_constructor &map, u64 unitmask = 0, int cswidth = 0) override; + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override; + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0) override; + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate rhandler, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0) override; + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override; + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0) override; + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate rhandler, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0) override; + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override; + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0) override; + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate rhandler, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0) override; + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override; + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0) override; + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate rhandler, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0) override; + + using address_space::install_read_tap; + using address_space::install_write_tap; + using address_space::install_readwrite_tap; + + virtual memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) override; + virtual memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) override; + virtual memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tapr, std::function tapw, memory_passthrough_handler *mph) override; - // get the start/end address with the given mirror - void mirrored_start_end(offs_t address, offs_t &start, offs_t &end) const - { - offs_t mirrorbits = (address - m_addrstart) & ~m_addrmask; - start = m_addrstart | mirrorbits; - end = m_addrend | mirrorbits; + // construction/destruction + address_space_specific(memory_manager &manager, device_memory_interface &memory, int spacenum, int address_width) + : address_space(manager, memory, spacenum) + { + m_unmap_r = new handler_entry_read_unmapped (this); + m_unmap_w = new handler_entry_write_unmapped(this); + m_nop_r = new handler_entry_read_nop (this); + m_nop_w = new handler_entry_write_nop(this); + + handler_entry::range r{ 0, 0xffffffff >> (32 - address_width) }; + + switch (address_width) { + case 1: m_root_read = new handler_entry_read_dispatch< std::max(1, Width), Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch< std::max(1, Width), Width, AddrShift, Endian>(this, r, nullptr); break; + case 2: m_root_read = new handler_entry_read_dispatch< std::max(2, Width), Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch< std::max(2, Width), Width, AddrShift, Endian>(this, r, nullptr); break; + case 3: m_root_read = new handler_entry_read_dispatch< std::max(3, Width), Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch< std::max(3, Width), Width, AddrShift, Endian>(this, r, nullptr); break; + case 4: m_root_read = new handler_entry_read_dispatch< 4, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch< 4, Width, AddrShift, Endian>(this, r, nullptr); break; + case 5: m_root_read = new handler_entry_read_dispatch< 5, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch< 5, Width, AddrShift, Endian>(this, r, nullptr); break; + case 6: m_root_read = new handler_entry_read_dispatch< 6, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch< 6, Width, AddrShift, Endian>(this, r, nullptr); break; + case 7: m_root_read = new handler_entry_read_dispatch< 7, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch< 7, Width, AddrShift, Endian>(this, r, nullptr); break; + case 8: m_root_read = new handler_entry_read_dispatch< 8, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch< 8, Width, AddrShift, Endian>(this, r, nullptr); break; + case 9: m_root_read = new handler_entry_read_dispatch< 9, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch< 9, Width, AddrShift, Endian>(this, r, nullptr); break; + case 10: m_root_read = new handler_entry_read_dispatch<10, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<10, Width, AddrShift, Endian>(this, r, nullptr); break; + case 11: m_root_read = new handler_entry_read_dispatch<11, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<11, Width, AddrShift, Endian>(this, r, nullptr); break; + case 12: m_root_read = new handler_entry_read_dispatch<12, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<12, Width, AddrShift, Endian>(this, r, nullptr); break; + case 13: m_root_read = new handler_entry_read_dispatch<13, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<13, Width, AddrShift, Endian>(this, r, nullptr); break; + case 14: m_root_read = new handler_entry_read_dispatch<14, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<14, Width, AddrShift, Endian>(this, r, nullptr); break; + case 15: m_root_read = new handler_entry_read_dispatch<15, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<15, Width, AddrShift, Endian>(this, r, nullptr); break; + case 16: m_root_read = new handler_entry_read_dispatch<16, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<16, Width, AddrShift, Endian>(this, r, nullptr); break; + case 17: m_root_read = new handler_entry_read_dispatch<17, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<17, Width, AddrShift, Endian>(this, r, nullptr); break; + case 18: m_root_read = new handler_entry_read_dispatch<18, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<18, Width, AddrShift, Endian>(this, r, nullptr); break; + case 19: m_root_read = new handler_entry_read_dispatch<19, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<19, Width, AddrShift, Endian>(this, r, nullptr); break; + case 20: m_root_read = new handler_entry_read_dispatch<20, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<20, Width, AddrShift, Endian>(this, r, nullptr); break; + case 21: m_root_read = new handler_entry_read_dispatch<21, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<21, Width, AddrShift, Endian>(this, r, nullptr); break; + case 22: m_root_read = new handler_entry_read_dispatch<22, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<22, Width, AddrShift, Endian>(this, r, nullptr); break; + case 23: m_root_read = new handler_entry_read_dispatch<23, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<23, Width, AddrShift, Endian>(this, r, nullptr); break; + case 24: m_root_read = new handler_entry_read_dispatch<24, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<24, Width, AddrShift, Endian>(this, r, nullptr); break; + case 25: m_root_read = new handler_entry_read_dispatch<25, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<25, Width, AddrShift, Endian>(this, r, nullptr); break; + case 26: m_root_read = new handler_entry_read_dispatch<26, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<26, Width, AddrShift, Endian>(this, r, nullptr); break; + case 27: m_root_read = new handler_entry_read_dispatch<27, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<27, Width, AddrShift, Endian>(this, r, nullptr); break; + case 28: m_root_read = new handler_entry_read_dispatch<28, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<28, Width, AddrShift, Endian>(this, r, nullptr); break; + case 29: m_root_read = new handler_entry_read_dispatch<29, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<29, Width, AddrShift, Endian>(this, r, nullptr); break; + case 30: m_root_read = new handler_entry_read_dispatch<30, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<30, Width, AddrShift, Endian>(this, r, nullptr); break; + case 31: m_root_read = new handler_entry_read_dispatch<31, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<31, Width, AddrShift, Endian>(this, r, nullptr); break; + case 32: m_root_read = new handler_entry_read_dispatch<32, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<32, Width, AddrShift, Endian>(this, r, nullptr); break; + default: fatalerror("Unhandled address bus width %d\n", address_width); + } } - // configure the handler addresses, and mark as populated - void configure(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t bytemask) - { - if (m_populated && m_subunits) - reconfigure_subunits(addrstart); - m_populated = true; - m_addrstart = addrstart; - m_addrend = addrend; - m_addrmask = addrmask; - m_bytemask = bytemask; + void *create_cache() override { + return new memory_access_cache(*this, m_root_read, m_root_write); } - // Re-expand the addrmask after subunit fun - void expand_bytemask(offs_t previous_mask) - { - m_bytemask |= previous_mask; + void delayed_ref(handler_entry *e) { + e->ref(); + m_delayed_unrefs.insert(e); } - // reconfigure the subunits on a base address change - void reconfigure_subunits(offs_t addrstart); - - // depopulate an handler - void deconfigure() - { - m_populated = false; - m_subunits = 0; + void delayed_unref(handler_entry *e) { + m_delayed_unrefs.erase(m_delayed_unrefs.find(e)); + e->unref(); } - // apply a global mask - void apply_mask(offs_t addrmask) { m_addrmask &= addrmask; } + void validate_reference_counts() const override { + handler_entry::reflist refs; + refs.add(m_root_read); + refs.add(m_root_write); + refs.add(m_unmap_r); + refs.add(m_unmap_w); + refs.add(m_nop_r); + refs.add(m_nop_w); + for(handler_entry *e : m_delayed_unrefs) + refs.add(e); + refs.propagate(); + refs.check(); + } - void clear_conflicting_subunits(u64 handlermask); - bool overriden_by_mask(u64 handlermask) const; + virtual void remove_passthrough(std::unordered_set &handlers) override { + m_root_read->detach(handlers); + m_root_write->detach(handlers); + } -protected: - // Subunit description information - struct subunit_info + // generate accessor table + virtual void accessors(data_accessors &accessors) const override { - offs_t m_addrmask; // addrmask for this subunit - u64 m_datamask; // datamask for this subunit - u64 m_csmask; // chip select mask for this subunit - s32 m_offset; // offset to add to the address - u32 m_multiplier; // multiplier to the pre-split address - u8 m_size; // size (8, 16 or 32) - u8 m_shift; // shift of the subunit - }; - - // internal helpers - void configure_subunits(u64 handlermask, int handlerbits, int cswidth, int &start_slot, int &end_slot); - virtual void remove_subunit(int entry) = 0; - - // internal state - bool m_populated; // populated? - u8 m_datawidth; - endianness_t m_endianness; - offs_t m_addrstart; // start address for handler - offs_t m_addrend; // end address for handler - offs_t m_addrmask; // mask against the final address - offs_t m_bytemask; // mask against the final address, byte resolution - u8 ** m_rambaseptr; // pointer to the bank base - u8 m_subunits; // for width stubs, the number of subunits - subunit_info m_subunit_infos[8]; // for width stubs, the associated subunit info - u64 m_invsubmask; // inverted mask of the populated subunits -}; - - -// ======================> handler_entry_read + accessors.read_byte = reinterpret_cast(&read_byte_static); + accessors.read_word = reinterpret_cast(&read_word_static); + accessors.read_word_masked = reinterpret_cast(&read_word_masked_static); + accessors.read_dword = reinterpret_cast(&read_dword_static); + accessors.read_dword_masked = reinterpret_cast(&read_dword_masked_static); + accessors.read_qword = reinterpret_cast(&read_qword_static); + accessors.read_qword_masked = reinterpret_cast(&read_qword_masked_static); + accessors.write_byte = reinterpret_cast(&write_byte_static); + accessors.write_word = reinterpret_cast(&write_word_static); + accessors.write_word_masked = reinterpret_cast(&write_word_masked_static); + accessors.write_dword = reinterpret_cast(&write_dword_static); + accessors.write_dword_masked = reinterpret_cast(&write_dword_masked_static); + accessors.write_qword = reinterpret_cast(&write_qword_static); + accessors.write_qword_masked = reinterpret_cast(&write_qword_masked_static); + } -// a read-access-specific extension of handler_entry -class handler_entry_read : public handler_entry -{ -public: - struct access_handler + // return a pointer to the read bank, or nullptr if none + virtual void *get_read_ptr(offs_t address) const override { - // Constructors mean you can't union them - read8_delegate r8; - read16_delegate r16; - read32_delegate r32; - read64_delegate r64; - }; + return m_root_read->get_ptr(address); + } - // construction/destruction - handler_entry_read(u8 width, endianness_t endianness, u8 **rambaseptr) - : handler_entry(width, endianness, rambaseptr), - m_ioport(nullptr) + // return a pointer to the write bank, or nullptr if none + virtual void *get_write_ptr(offs_t address) const override { + return m_root_write->get_ptr(address); } - virtual void copy(handler_entry *entry) override; - - // getters - virtual const char *name() const override; - virtual const char *subunit_name(int entry) const override; - - // configure delegate callbacks - void set_delegate(read8_delegate delegate, u64 umask = 0, int cswidth = 8); - void set_delegate(read16_delegate delegate, u64 umask = 0, int cswidth = 16); - void set_delegate(read32_delegate delegate, u64 umask = 0, int cswidth = 32); - void set_delegate(read64_delegate delegate, u64 umask = 0, int cswidth = 64); - - // configure I/O port access - void set_ioport(ioport_port &ioport); - - // read via the underlying delegates - u8 read8(address_space &space, offs_t offset, u8 mask) const { return m_read.r8(space, offset, mask); } - u16 read16(address_space &space, offs_t offset, u16 mask) const { return m_read.r16(space, offset, mask); } - u32 read32(address_space &space, offs_t offset, u32 mask) const { return m_read.r32(space, offset, mask); } - u64 read64(address_space &space, offs_t offset, u64 mask) const { return m_read.r64(space, offset, mask); } - -private: - // stubs for converting between address sizes - u16 read_stub_16(address_space &space, offs_t offset, u16 mask); - u32 read_stub_32(address_space &space, offs_t offset, u32 mask); - u64 read_stub_64(address_space &space, offs_t offset, u64 mask); - - // stubs for reading I/O ports - template - UintType read_stub_ioport(address_space &space, offs_t offset, UintType mask) { return m_ioport->read(); } - - // internal helper - virtual void remove_subunit(int entry) override; - - // internal state - access_handler m_read; - access_handler m_subread[8]; - ioport_port * m_ioport; -}; + // native read + NativeType read_native(offs_t offset, NativeType mask) + { + g_profiler.start(PROFILER_MEMREAD); + uX result = m_root_read->read(offset, mask); -// ======================> handler_entry_write + g_profiler.stop(); + return result; + } -// a write-access-specific extension of handler_entry -class handler_entry_write : public handler_entry -{ -public: - struct access_handler + // mask-less native read + NativeType read_native(offs_t offset) { - // Constructors mean you can't union them - write8_delegate w8; - write16_delegate w16; - write32_delegate w32; - write64_delegate w64; - }; + g_profiler.start(PROFILER_MEMREAD); - // construction/destruction - handler_entry_write(u8 width, endianness_t endianness, u8 **rambaseptr) - : handler_entry(width, endianness, rambaseptr), - m_ioport(nullptr) - { - } + uX result = m_root_read->read(offset, uX(0xffffffffffffffffU)); - virtual void copy(handler_entry *entry) override; + g_profiler.stop(); + return result; + } - // getters - virtual const char *name() const override; - virtual const char *subunit_name(int entry) const override; + // native write + void write_native(offs_t offset, NativeType data, NativeType mask) + { + g_profiler.start(PROFILER_MEMWRITE); - // configure delegate callbacks - void set_delegate(write8_delegate delegate, u64 umask = 0, int cswidth = 8); - void set_delegate(write16_delegate delegate, u64 umask = 0, int cswidth = 16); - void set_delegate(write32_delegate delegate, u64 umask = 0, int cswidth = 32); - void set_delegate(write64_delegate delegate, u64 umask = 0, int cswidth = 64); + m_root_write->write(offset, data, mask); - // configure I/O port access - void set_ioport(ioport_port &ioport); + g_profiler.stop(); + } - // write via the underlying delegates - void write8(address_space &space, offs_t offset, u8 data, u8 mask) const { m_write.w8(space, offset, data, mask); } - void write16(address_space &space, offs_t offset, u16 data, u16 mask) const { m_write.w16(space, offset, data, mask); } - void write32(address_space &space, offs_t offset, u32 data, u32 mask) const { m_write.w32(space, offset, data, mask); } - void write64(address_space &space, offs_t offset, u64 data, u64 mask) const { m_write.w64(space, offset, data, mask); } + // mask-less native write + void write_native(offs_t offset, NativeType data) + { + g_profiler.start(PROFILER_MEMWRITE); -private: - // stubs for converting between address sizes - void write_stub_16(address_space &space, offs_t offset, u16 data, u16 mask); - void write_stub_32(address_space &space, offs_t offset, u32 data, u32 mask); - void write_stub_64(address_space &space, offs_t offset, u64 data, u64 mask); - - // stubs for writing I/O ports - template - void write_stub_ioport(address_space &space, offs_t offset, UintType data, UintType mask) { m_ioport->write(data, mask); } - - // internal helper - virtual void remove_subunit(int entry) override; - - // internal state - access_handler m_write; - access_handler m_subwrite[8]; - ioport_port * m_ioport; -}; + m_root_write->write(offset, data, uX(0xffffffffffffffffU)); -// ======================> handler_entry_setoffset -// a setoffset-access-specific extension of handler_entry -class handler_entry_setoffset : public handler_entry -{ -public: - // construction/destruction - handler_entry_setoffset() - : handler_entry(0, ENDIANNESS_LITTLE, nullptr) - { + g_profiler.stop(); } - const char *name() const override { return m_setoffset.name(); } - const char *subunit_name(int entry) const override { return "no subunit"; } - - // Call through only if the setoffset handler has been late-bound before - // (i.e. if it was declared in the address map) - void setoffset(address_space &space, offs_t offset) const { if (m_setoffset.has_object()) m_setoffset(space, offset); } + // virtual access to these functions + u8 read_byte(offs_t address) override { address &= m_addrmask; return Width == 0 ? read_native(address & ~NATIVE_MASK) : memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xff); } + u16 read_word(offs_t address) override { address &= m_addrmask; return Width == 1 ? read_native(address & ~NATIVE_MASK) : memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffff); } + u16 read_word(offs_t address, u16 mask) override { address &= m_addrmask; return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } + u16 read_word_unaligned(offs_t address) override { address &= m_addrmask; return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffff); } + u16 read_word_unaligned(offs_t address, u16 mask) override { address &= m_addrmask; return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } + u32 read_dword(offs_t address) override { address &= m_addrmask; return Width == 2 ? read_native(address & ~NATIVE_MASK) : memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffff); } + u32 read_dword(offs_t address, u32 mask) override { address &= m_addrmask; return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } + u32 read_dword_unaligned(offs_t address) override { address &= m_addrmask; return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffff); } + u32 read_dword_unaligned(offs_t address, u32 mask) override { address &= m_addrmask; return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } + u64 read_qword(offs_t address) override { address &= m_addrmask; return Width == 3 ? read_native(address & ~NATIVE_MASK) : memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffffffffffffU); } + u64 read_qword(offs_t address, u64 mask) override { address &= m_addrmask; return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } + u64 read_qword_unaligned(offs_t address) override { address &= m_addrmask; return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffffffffffffU); } + u64 read_qword_unaligned(offs_t address, u64 mask) override { address &= m_addrmask; return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } + + void write_byte(offs_t address, u8 data) override { address &= m_addrmask; if (Width == 0) write_native(address & ~NATIVE_MASK, data); else memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xff); } + void write_word(offs_t address, u16 data) override { address &= m_addrmask; if (Width == 1) write_native(address & ~NATIVE_MASK, data); else memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffff); } + void write_word(offs_t address, u16 data, u16 mask) override { address &= m_addrmask; memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } + void write_word_unaligned(offs_t address, u16 data) override { address &= m_addrmask; memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffff); } + void write_word_unaligned(offs_t address, u16 data, u16 mask) override { address &= m_addrmask; memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } + void write_dword(offs_t address, u32 data) override { address &= m_addrmask; if (Width == 2) write_native(address & ~NATIVE_MASK, data); else memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffff); } + void write_dword(offs_t address, u32 data, u32 mask) override { address &= m_addrmask; memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } + void write_dword_unaligned(offs_t address, u32 data) override { address &= m_addrmask; memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffff); } + void write_dword_unaligned(offs_t address, u32 data, u32 mask) override { address &= m_addrmask; memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } + void write_qword(offs_t address, u64 data) override { address &= m_addrmask; if (Width == 3) write_native(address & ~NATIVE_MASK, data); else memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffffffffffffU); } + void write_qword(offs_t address, u64 data, u64 mask) override { address &= m_addrmask; memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } + void write_qword_unaligned(offs_t address, u64 data) override { address &= m_addrmask; memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffffffffffffU); } + void write_qword_unaligned(offs_t address, u64 data, u64 mask) override {address &= m_addrmask; memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } - // configure delegate callbacks - void set_delegate(setoffset_delegate delegate, u64 umask = 0, int cswidth = 0) { m_setoffset = delegate; } + // static access to these functions + static u8 read_byte_static(this_type &space, offs_t address) { address &= space.m_addrmask; return Width == 0 ? space.read_native(address & ~NATIVE_MASK) : memory_read_generic([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, 0xff); } + static u16 read_word_static(this_type &space, offs_t address) { address &= space.m_addrmask; return Width == 1 ? space.read_native(address & ~NATIVE_MASK) : memory_read_generic([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, 0xffff); } + static u16 read_word_masked_static(this_type &space, offs_t address, u16 mask) { address &= space.m_addrmask; return memory_read_generic([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, mask); } + static u32 read_dword_static(this_type &space, offs_t address) { address &= space.m_addrmask; return Width == 2 ? space.read_native(address & ~NATIVE_MASK) : memory_read_generic([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, 0xffffffff); } + static u32 read_dword_masked_static(this_type &space, offs_t address, u32 mask) { address &= space.m_addrmask; return memory_read_generic([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, mask); } + static u64 read_qword_static(this_type &space, offs_t address) { address &= space.m_addrmask; return Width == 3 ? space.read_native(address & ~NATIVE_MASK) : memory_read_generic([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, 0xffffffffffffffffU); } + static u64 read_qword_masked_static(this_type &space, offs_t address, u64 mask) { address &= space.m_addrmask; return memory_read_generic([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, mask); } + static void write_byte_static(this_type &space, offs_t address, u8 data) { address &= space.m_addrmask; if (Width == 0) space.write_native(address & ~NATIVE_MASK, data); else memory_write_generic([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, 0xff); } + static void write_word_static(this_type &space, offs_t address, u16 data) { address &= space.m_addrmask; if (Width == 1) space.write_native(address & ~NATIVE_MASK, data); else memory_write_generic([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, 0xffff); } + static void write_word_masked_static(this_type &space, offs_t address, u16 data, u16 mask) { address &= space.m_addrmask; memory_write_generic([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, mask); } + static void write_dword_static(this_type &space, offs_t address, u32 data) { address &= space.m_addrmask; if (Width == 2) space.write_native(address & ~NATIVE_MASK, data); else memory_write_generic([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, 0xffffffff); } + static void write_dword_masked_static(this_type &space, offs_t address, u32 data, u32 mask) { address &= space.m_addrmask; memory_write_generic([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, mask); } + static void write_qword_static(this_type &space, offs_t address, u64 data) { address &= space.m_addrmask; if (Width == 3) space.write_native(address & ~NATIVE_MASK, data); else memory_write_generic([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, 0xffffffffffffffffU); } + static void write_qword_masked_static(this_type &space, offs_t address, u64 data, u64 mask) { address &= space.m_addrmask; memory_write_generic([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, mask); } + + handler_entry_read *m_root_read; + handler_entry_write *m_root_write; + + std::unordered_set m_delayed_unrefs; private: - setoffset_delegate m_setoffset; - // We do not have subunits for setoffset - // Accordingly, we need not implement unused functions. - void remove_subunit(int entry) override { } -}; - -// ======================> handler_entry_proxy - -// A proxy class that contains an handler_entry_read or _write and forwards the setter calls - -template -class handler_entry_proxy -{ -public: - handler_entry_proxy(std::list &&_handlers, u64 _umask, int _cswidth) : handlers(std::move(_handlers)), umask(_umask), cswidth(_cswidth) {} - handler_entry_proxy(const handler_entry_proxy &hep) : handlers(hep.handlers), umask(hep.umask), cswidth(hep.cswidth) {} + template std::enable_if_t<(Width == AccessWidth)> + install_read_handler_helper(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, + typename handler_entry_size::READ handler_r) + { + VPRINTF(("address_space::install_read_handler(%s-%s mask=%s mirror=%s, space width=%d, handler width=%d, %s, %s)\n", + core_i64_hex_format(addrstart, m_addrchars), core_i64_hex_format(addrend, m_addrchars), + core_i64_hex_format(addrmask, m_addrchars), core_i64_hex_format(addrmirror, m_addrchars), + 8 << Width, 8 << AccessWidth, + handler_r.name(), core_i64_hex_format(unitmask, data_width() / 4))); - // forward delegate callbacks configuration - template void set_delegate(Delegate delegate) const { - for (const auto & elem : handlers) - (elem)->set_delegate(delegate, umask, cswidth); - } + offs_t nstart, nend, nmask, nmirror; + u64 nunitmask; + int ncswidth; + check_optimize_all("install_read_handler", 8 << AccessWidth, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth); - // forward I/O port access configuration - void set_ioport(ioport_port &ioport) const { - for (const auto & elem : handlers) - (elem)->set_ioport(ioport); + auto hand_r = new handler_entry_read_delegate(this, handler_r); + hand_r->set_address_info(nstart, nmask); + m_root_read->populate(nstart, nend, nmirror, hand_r); + invalidate_caches(read_or_write::READ); } -private: - std::list handlers; - u64 umask; - int cswidth; -}; - - -// ======================> address_table - -// address_table contains information about read/write accesses within an address space -class address_table -{ - // address map lookup table definitions - static const int LEVEL1_BITS = 18; // number of address bits in the level 1 table - static const int LEVEL2_BITS = 32 - LEVEL1_BITS; // number of address bits in the level 2 table - static const int SUBTABLE_COUNT = 64; // number of slots reserved for subtables - static const int SUBTABLE_BASE = TOTAL_MEMORY_BANKS - SUBTABLE_COUNT; // first index of a subtable - static const int ENTRY_COUNT = SUBTABLE_BASE; // number of legitimate (non-subtable) entries - static const int SUBTABLE_ALLOC = 8; // number of subtables to allocate at a time - - inline int level2_bits() const { return m_large ? LEVEL2_BITS : 0; } - -public: - // construction/destruction - address_table(address_space &space, bool large); - virtual ~address_table(); - - // getters - virtual handler_entry &handler(u32 index) const = 0; - bool watchpoints_enabled() const { return (m_live_lookup == s_watchpoint_table); } + template std::enable_if_t<(Width > AccessWidth)> + install_read_handler_helper(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, + typename handler_entry_size::READ handler_r) + { + VPRINTF(("address_space::install_read_handler(%s-%s mask=%s mirror=%s, space width=%d, handler width=%d, %s, %s)\n", + core_i64_hex_format(addrstart, m_addrchars), core_i64_hex_format(addrend, m_addrchars), + core_i64_hex_format(addrmask, m_addrchars), core_i64_hex_format(addrmirror, m_addrchars), + 8 << Width, 8 << AccessWidth, + handler_r.name(), core_i64_hex_format(unitmask, data_width() / 4))); - // address lookups - u32 lookup_live(offs_t address) const { return m_large ? lookup_live_large(address) : lookup_live_small(address); } - u32 lookup_live_small(offs_t address) const { return m_live_lookup[address]; } + offs_t nstart, nend, nmask, nmirror; + u64 nunitmask; + int ncswidth; + check_optimize_all("install_read_handler", 8 << AccessWidth, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth); - u32 lookup_live_large(offs_t address) const - { - u32 entry = m_live_lookup[level1_index_large(address)]; - if (entry >= SUBTABLE_BASE) - entry = m_live_lookup[level2_index_large(entry, address)]; - return entry; + auto hand_r = new handler_entry_read_delegate(this, handler_r); + memory_units_descriptor descriptor(AccessWidth, Endian, hand_r, nstart, nend, nmask, nunitmask, ncswidth); + hand_r->set_address_info(descriptor.get_handler_start(), descriptor.get_handler_mask()); + m_root_read->populate_mismatched(nstart, nend, nmirror, descriptor); + hand_r->unref(); + invalidate_caches(read_or_write::READ); } - u32 lookup_live_nowp(offs_t address) const { return m_large ? lookup_live_large_nowp(address) : lookup_live_small_nowp(address); } - u32 lookup_live_small_nowp(offs_t address) const { return m_table[address]; } - u32 lookup_live_large_nowp(offs_t address) const + template std::enable_if_t<(Width < AccessWidth)> + install_read_handler_helper(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, + typename handler_entry_size::READ handler_r) { - u32 entry = m_table[level1_index_large(address)]; - if (entry >= SUBTABLE_BASE) - entry = m_table[level2_index_large(entry, address)]; - return entry; + fatalerror("install_read_handler: cannot install a %d-wide handler in a %d-wide bus", 8 << AccessWidth, 8 << Width); } - u32 lookup(offs_t address) const + template std::enable_if_t<(Width == AccessWidth)> + install_write_handler_helper(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, + typename handler_entry_size::WRITE handler_w) { - u32 entry = m_live_lookup[level1_index(address)]; - if (entry >= SUBTABLE_BASE) - entry = m_live_lookup[level2_index(entry, address)]; - return entry; - } + VPRINTF(("address_space::install_write_handler(%s-%s mask=%s mirror=%s, space width=%d, handler width=%d, %s, %s)\n", + core_i64_hex_format(addrstart, m_addrchars), core_i64_hex_format(addrend, m_addrchars), + core_i64_hex_format(addrmask, m_addrchars), core_i64_hex_format(addrmirror, m_addrchars), + 8 << Width, 8 << AccessWidth, + handler_w.name(), core_i64_hex_format(unitmask, data_width() / 4))); - // enable watchpoints by swapping in the watchpoint table - void enable_watchpoints(bool enable = true) { m_live_lookup = enable ? s_watchpoint_table : &m_table[0]; } - - // table mapping helpers - void map_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u16 staticentry); - std::list setup_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 umask); - u16 derive_range(offs_t address, offs_t &addrstart, offs_t &addrend) const; - - // misc helpers - void mask_all_handlers(offs_t mask); - const char *handler_name(u16 entry) const; - -protected: - // determine table indexes based on the address - u32 level1_index_large(offs_t address) const { return address >> LEVEL2_BITS; } - u32 level2_index_large(u16 l1entry, offs_t address) const { return (1 << LEVEL1_BITS) + ((l1entry - SUBTABLE_BASE) << LEVEL2_BITS) + (address & ((1 << LEVEL2_BITS) - 1)); } - u32 level1_index(offs_t address) const { return m_large ? level1_index_large(address) : address; } - u32 level2_index(u16 l1entry, offs_t address) const { return m_large ? level2_index_large(l1entry, address) : 0; } - - // table population/depopulation - void populate_range_mirrored(offs_t addrstart, offs_t addrend, offs_t addrmirror, u16 handler); - void populate_range(offs_t addrstart, offs_t addrend, u16 handler); - - // subtable management - u16 subtable_alloc(); - void subtable_realloc(u16 subentry); - int subtable_merge(); - void subtable_release(u16 subentry); - u16 *subtable_open(offs_t l1index); - void subtable_close(offs_t l1index); - u16 *subtable_ptr(u16 entry) { return &m_table[level2_index(entry, 0)]; } - - // internal state - std::vector m_table; // pointer to base of table - u16 * m_live_lookup; // current lookup - address_space & m_space; // pointer back to the space - bool m_large; // large memory model? - - // subtable_data is an internal class with information about each subtable - class subtable_data - { - public: - subtable_data() - : m_checksum_valid(false), - m_checksum(0), - m_usecount(0) { } - - bool m_checksum_valid; // is the checksum valid - u32 m_checksum; // checksum over all the bytes - u32 m_usecount; // number of times this has been used - }; - std::vector m_subtable; // info about each subtable - u16 m_subtable_alloc; // number of subtables allocated - - // static global read-only watchpoint table - static u16 s_watchpoint_table[1 << LEVEL1_BITS]; + offs_t nstart, nend, nmask, nmirror; + u64 nunitmask; + int ncswidth; + check_optimize_all("install_write_handler", 8 << AccessWidth, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth); -private: - int handler_refcount[SUBTABLE_BASE-STATIC_COUNT]; - u16 handler_next_free[SUBTABLE_BASE-STATIC_COUNT]; - u16 handler_free; - u16 get_free_handler(); - void verify_reference_counts(); - bool range_simply_masks(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 umask); - std::list setup_range_solid(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror); - std::list setup_range_masked(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 umask); - - void handler_ref(u16 entry, int count) - { - assert(entry < SUBTABLE_BASE); - if (entry >= STATIC_COUNT) - handler_refcount[entry - STATIC_COUNT] += count; + auto hand_w = new handler_entry_write_delegate(this, handler_w); + hand_w->set_address_info(nstart, nmask); + m_root_write->populate(nstart, nend, nmirror, hand_w); + invalidate_caches(read_or_write::WRITE); } - void handler_unref(u16 entry) + template std::enable_if_t<(Width > AccessWidth)> + install_write_handler_helper(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, + typename handler_entry_size::WRITE handler_w) { - assert(entry < SUBTABLE_BASE); - if (entry >= STATIC_COUNT) - if (! --handler_refcount[entry - STATIC_COUNT]) - { - handler(entry).deconfigure(); - handler_next_free[entry - STATIC_COUNT] = handler_free; - handler_free = entry; - } - } -}; - + VPRINTF(("address_space::install_write_handler(%s-%s mask=%s mirror=%s, space width=%d, handler width=%d, %s, %s)\n", + core_i64_hex_format(addrstart, m_addrchars), core_i64_hex_format(addrend, m_addrchars), + core_i64_hex_format(addrmask, m_addrchars), core_i64_hex_format(addrmirror, m_addrchars), + 8 << Width, 8 << AccessWidth, + handler_w.name(), core_i64_hex_format(unitmask, data_width() / 4))); -// ======================> address_table_read + offs_t nstart, nend, nmask, nmirror; + u64 nunitmask; + int ncswidth; + check_optimize_all("install_write_handler", 8 << AccessWidth, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth); -// read access-specific version of an address table -class address_table_read : public address_table -{ -public: - // construction/destruction - address_table_read(address_space &space, bool large); - virtual ~address_table_read(); - - // getters - virtual handler_entry &handler(u32 index) const override; - handler_entry_read &handler_read(u32 index) const { assert(index < ARRAY_LENGTH(m_handlers)); return *m_handlers[index]; } - - // range getter - handler_entry_proxy handler_map_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 umask = 0, int cswidth = 0) { - std::list entries = setup_range(addrstart, addrend, addrmask, addrmirror, umask); - std::list handlers; - for (std::list::const_iterator i = entries.begin(); i != entries.end(); ++i) - handlers.push_back(&handler_read(*i)); - return handler_entry_proxy(std::move(handlers), umask, cswidth); + auto hand_w = new handler_entry_write_delegate(this, handler_w); + memory_units_descriptor descriptor(AccessWidth, Endian, hand_w, nstart, nend, nmask, nunitmask, ncswidth); + hand_w->set_address_info(descriptor.get_handler_start(), descriptor.get_handler_mask()); + m_root_write->populate_mismatched(nstart, nend, nmirror, descriptor); + hand_w->unref(); + invalidate_caches(read_or_write::WRITE); } -private: - // internal unmapped handler - template - UintType unmap_r(address_space &space, offs_t offset, UintType mask) - { - if (m_space.log_unmap() && !m_space.m_manager.machine().side_effects_disabled()) - { - m_space.device().logerror( - m_space.is_octal() - ? "%s: unmapped %s memory read from %0*o & %0*o\n" - : "%s: unmapped %s memory read from %0*X & %0*X\n", - m_space.m_manager.machine().describe_context(), m_space.name(), - m_space.addrchars(), m_space.byte_to_address(offset * sizeof(UintType)), - 2 * sizeof(UintType), mask); - } - return m_space.unmap(); - } - // internal no-op handler - template - UintType nop_r(address_space &space, offs_t offset, UintType mask) + template std::enable_if_t<(Width < AccessWidth)> + install_write_handler_helper(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, + typename handler_entry_size::WRITE handler_w) { - return m_space.unmap(); + fatalerror("install_write_handler: cannot install a %d-wide handler in a %d-wide bus", 8 << AccessWidth, 8 << Width); } - // internal watchpoint handler - template - UintType watchpoint_r(address_space &space, offs_t offset, UintType mask) - { - int base_shift = sizeof(UintType) == 1 ? 0 : sizeof(UintType) == 2 ? 1 : sizeof(UintType) == 4 ? 2 : 3; - offset = offset << (AddrShift + base_shift); - m_space.device().debug()->memory_read_hook(m_space, offset, mask); - - u16 *oldtable = m_live_lookup; - m_live_lookup = &m_table[0]; - UintType result; - if (sizeof(UintType) == 1) result = m_space.read_byte(offset); - if (sizeof(UintType) == 2) result = m_space.read_word(offset, mask); - if (sizeof(UintType) == 4) result = m_space.read_dword(offset, mask); - if (sizeof(UintType) == 8) result = m_space.read_qword(offset, mask); - m_live_lookup = oldtable; - return result; - } - // internal state - std::unique_ptr m_handlers[TOTAL_MEMORY_BANKS]; // array of user-installed handlers -}; + template std::enable_if_t<(Width == AccessWidth)> + install_readwrite_handler_helper(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, + typename handler_entry_size::READ handler_r, + typename handler_entry_size::WRITE handler_w) + { + VPRINTF(("address_space::install_readwrite_handler(%s-%s mask=%s mirror=%s, space width=%d, handler width=%d, %s, %s, %s)\n", + core_i64_hex_format(addrstart, m_addrchars), core_i64_hex_format(addrend, m_addrchars), + core_i64_hex_format(addrmask, m_addrchars), core_i64_hex_format(addrmirror, m_addrchars), + 8 << Width, 8 << AccessWidth, + handler_r.name(), handler_w.name(), core_i64_hex_format(unitmask, data_width() / 4))); -// ======================> address_table_write + offs_t nstart, nend, nmask, nmirror; + u64 nunitmask; + int ncswidth; + check_optimize_all("install_readwrite_handler", 8 << AccessWidth, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth); -// write access-specific version of an address table -class address_table_write : public address_table -{ -public: - // construction/destruction - address_table_write(address_space &space, bool large); - virtual ~address_table_write(); - - // getters - virtual handler_entry &handler(u32 index) const override; - handler_entry_write &handler_write(u32 index) const { assert(index < ARRAY_LENGTH(m_handlers)); return *m_handlers[index]; } - - // range getter - handler_entry_proxy handler_map_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 umask = 0, int cswidth = 0) { - std::list entries = setup_range(addrstart, addrend, addrmask, addrmirror, umask); - std::list handlers; - for (std::list::const_iterator i = entries.begin(); i != entries.end(); ++i) - handlers.push_back(&handler_write(*i)); - return handler_entry_proxy(std::move(handlers), umask, cswidth); - } + auto hand_r = new handler_entry_read_delegate (this, handler_r); + hand_r->set_address_info(nstart, nmask); + m_root_read ->populate(nstart, nend, nmirror, hand_r); -private: - // internal handlers - template - void unmap_w(address_space &space, offs_t offset, UintType data, UintType mask) - { - if (m_space.log_unmap() && !m_space.m_manager.machine().side_effects_disabled()) - { - m_space.device().logerror( - m_space.is_octal() - ? "%s: unmapped %s memory write to %0*o = %0*o & %0*o\n" - : "%s: unmapped %s memory write to %0*X = %0*X & %0*X\n", - m_space.m_manager.machine().describe_context(), m_space.name(), - m_space.addrchars(), m_space.byte_to_address(offset * sizeof(UintType)), - 2 * sizeof(UintType), data, - 2 * sizeof(UintType), mask); - } - } + auto hand_w = new handler_entry_write_delegate(this, handler_w); + hand_w->set_address_info(nstart, nmask); + m_root_write->populate(nstart, nend, nmirror, hand_w); - template - void nop_w(address_space &space, offs_t offset, UintType data, UintType mask) - { + invalidate_caches(read_or_write::READWRITE); } - - template - void watchpoint_w(address_space &space, offs_t offset, UintType data, UintType mask) + + template std::enable_if_t<(Width > AccessWidth)> + install_readwrite_handler_helper(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, + typename handler_entry_size::READ handler_r, + typename handler_entry_size::WRITE handler_w) { - int base_shift = sizeof(UintType) == 1 ? 0 : sizeof(UintType) == 2 ? 1 : sizeof(UintType) == 4 ? 2 : 3; - offset = offset << (AddrShift + base_shift); - m_space.device().debug()->memory_write_hook(m_space, offset, data, mask); - - u16 *oldtable = m_live_lookup; - m_live_lookup = &m_table[0]; - if (sizeof(UintType) == 1) m_space.write_byte(offset, data); - if (sizeof(UintType) == 2) m_space.write_word(offset, data, mask); - if (sizeof(UintType) == 4) m_space.write_dword(offset, data, mask); - if (sizeof(UintType) == 8) m_space.write_qword(offset, data, mask); - m_live_lookup = oldtable; - } + VPRINTF(("address_space::install_readwrite_handler(%s-%s mask=%s mirror=%s, space width=%d, handler width=%d, %s, %s, %s)\n", + core_i64_hex_format(addrstart, m_addrchars), core_i64_hex_format(addrend, m_addrchars), + core_i64_hex_format(addrmask, m_addrchars), core_i64_hex_format(addrmirror, m_addrchars), + 8 << Width, 8 << AccessWidth, + handler_r.name(), handler_w.name(), core_i64_hex_format(unitmask, data_width() / 4))); - // internal state - std::unique_ptr m_handlers[TOTAL_MEMORY_BANKS]; // array of user-installed handlers -}; + offs_t nstart, nend, nmask, nmirror; + u64 nunitmask; + int ncswidth; + check_optimize_all("install_readwrite_handler", 8 << AccessWidth, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth); -// ======================> address_table_setoffset -// setoffset access-specific version of an address table -class address_table_setoffset : public address_table -{ -public: - // construction/destruction - address_table_setoffset(address_space &space, bool large) - : address_table(space, large) - { - // allocate handlers for each entry, prepopulating the bankptrs for banks - for (auto & elem : m_handlers) - elem = std::make_unique(); + auto hand_r = new handler_entry_read_delegate (this, handler_r); + memory_units_descriptor descriptor(AccessWidth, Endian, hand_r, nstart, nend, nmask, nunitmask, ncswidth); + hand_r->set_address_info(descriptor.get_handler_start(), descriptor.get_handler_mask()); + m_root_read ->populate_mismatched(nstart, nend, nmirror, descriptor); + hand_r->unref(); - // Watchpoints and unmap states do not make sense for setoffset - m_handlers[STATIC_NOP]->set_delegate(setoffset_delegate(FUNC(address_table_setoffset::nop_so), this)); - m_handlers[STATIC_NOP]->configure(0, space.addrmask(), ~0, ~0); - } + auto hand_w = new handler_entry_write_delegate(this, handler_w); + descriptor.set_subunit_handler(hand_w); + hand_w->set_address_info(descriptor.get_handler_start(), descriptor.get_handler_mask()); + m_root_write->populate_mismatched(nstart, nend, nmirror, descriptor); + hand_w->unref(); - ~address_table_setoffset() - { + invalidate_caches(read_or_write::READWRITE); } - handler_entry &handler(u32 index) const override { assert(index < ARRAY_LENGTH(m_handlers)); return *m_handlers[index]; } - handler_entry_setoffset &handler_setoffset(u32 index) const { assert(index < ARRAY_LENGTH(m_handlers)); return *m_handlers[index]; } - - // range getter - handler_entry_proxy handler_map_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 umask = 0, int cswidth = 0) { - std::list entries = setup_range(addrstart, addrend, addrmask, addrmirror, umask); - std::list handlers; - for (std::list::const_iterator i = entries.begin(); i != entries.end(); ++i) - handlers.push_back(&handler_setoffset(*i)); - return handler_entry_proxy(std::move(handlers), umask, cswidth); - } -private: - // internal handlers - // Setoffset does not allow for watchpoints, since we assume that a - // corresponding read/write operation will follow, and the watchpoint will - // apply for that operation - // For the same reason it does not make sense to put a warning into the log - // for unmapped locations, as this will be done by the read/write operation - void nop_so(address_space &space, offs_t offset) + template std::enable_if_t<(Width < AccessWidth)> + install_readwrite_handler_helper(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, + typename handler_entry_size::READ handler_r, + typename handler_entry_size::WRITE handler_w) { + fatalerror("install_readwrite_handler: cannot install a %d-wide handler in a %d-wide bus", 8 << AccessWidth, 8 << Width); } - - // internal state - std::unique_ptr m_handlers[TOTAL_MEMORY_BANKS]; // array of user-installed handlers }; -// ======================> address_space_specific - -// this is a derived class of address_space with specific width, endianness, and table size -template -class address_space_specific : public address_space -{ - typedef address_space_specific this_type; - - // constants describing the native size - static constexpr u32 NATIVE_BYTES = sizeof(NativeType); - static constexpr u32 NATIVE_STEP = AddrShift >= 0 ? NATIVE_BYTES << iabs(AddrShift) : NATIVE_BYTES >> iabs(AddrShift); - static constexpr u32 NATIVE_MASK = NATIVE_STEP - 1; - static constexpr u32 NATIVE_BITS = 8 * NATIVE_BYTES; - static constexpr u32 Width = NATIVE_BYTES == 1 ? 0 : NATIVE_BYTES == 2 ? 1 : NATIVE_BYTES == 4 ? 2 : 3; - - // helpers to simplify core code - u32 read_lookup(offs_t address) const { return Large ? m_read.lookup_live_large(address) : m_read.lookup_live_small(address); } - u32 write_lookup(offs_t address) const { return Large ? m_write.lookup_live_large(address) : m_write.lookup_live_small(address); } - u32 setoffset_lookup(offs_t address) const { return Large ? m_setoffset.lookup_live_large(address) : m_setoffset.lookup_live_small(address); } - - static constexpr offs_t offset_to_byte(offs_t offset) { return AddrShift < 0 ? offset << iabs(AddrShift) : offset >> iabs(AddrShift); } - -public: - // construction/destruction - address_space_specific(memory_manager &manager, device_memory_interface &memory, int spacenum) - : address_space(manager, memory, spacenum, Large), - m_read(*this, Large), - m_write(*this, Large), - m_setoffset(*this, Large) - { -#if (TEST_HANDLER) - // test code to verify the read/write handlers are touching the correct bits - // and returning the correct results - - // install some dummy RAM for the first 16 bytes with well-known values - u8 buffer[16]; - for (int index = 0; index < 16; index++) - buffer[index ^ ((Endian == ENDIANNESS_NATIVE) ? 0 : (data_width()/8 - 1))] = index * 0x11; - install_ram_generic(0x00, 0x0f, 0x0f, 0, read_or_write::READWRITE, buffer); - printf("\n\naddress_space(%d, %s, %s)\n", NATIVE_BITS, (Endian == ENDIANNESS_LITTLE) ? "little" : "big", Large ? "large" : "small"); - - // walk through the first 8 addresses - for (int address = 0; address < 8; address++) - { - // determine expected values - u64 expected64 = (u64((address + ((Endian == ENDIANNESS_LITTLE) ? 7 : 0)) * 0x11) << 56) | - (u64((address + ((Endian == ENDIANNESS_LITTLE) ? 6 : 1)) * 0x11) << 48) | - (u64((address + ((Endian == ENDIANNESS_LITTLE) ? 5 : 2)) * 0x11) << 40) | - (u64((address + ((Endian == ENDIANNESS_LITTLE) ? 4 : 3)) * 0x11) << 32) | - (u64((address + ((Endian == ENDIANNESS_LITTLE) ? 3 : 4)) * 0x11) << 24) | - (u64((address + ((Endian == ENDIANNESS_LITTLE) ? 2 : 5)) * 0x11) << 16) | - (u64((address + ((Endian == ENDIANNESS_LITTLE) ? 1 : 6)) * 0x11) << 8) | - (u64((address + ((Endian == ENDIANNESS_LITTLE) ? 0 : 7)) * 0x11) << 0); - u32 expected32 = (Endian == ENDIANNESS_LITTLE) ? expected64 : (expected64 >> 32); - u16 expected16 = (Endian == ENDIANNESS_LITTLE) ? expected32 : (expected32 >> 16); - u8 expected8 = (Endian == ENDIANNESS_LITTLE) ? expected16 : (expected16 >> 8); - - u64 result64; - u32 result32; - u16 result16; - u8 result8; - - // validate byte accesses - printf("\nAddress %d\n", address); - printf(" read_byte = "); printf("%02X\n", result8 = read_byte(address)); assert(result8 == expected8); - - // validate word accesses (if aligned) - if (WORD_ALIGNED(address)) { printf(" read_word = "); printf("%04X\n", result16 = read_word(address)); assert(result16 == expected16); } - if (WORD_ALIGNED(address)) { printf(" read_word (0xff00) = "); printf("%04X\n", result16 = read_word(address, 0xff00)); assert((result16 & 0xff00) == (expected16 & 0xff00)); } - if (WORD_ALIGNED(address)) { printf(" (0x00ff) = "); printf("%04X\n", result16 = read_word(address, 0x00ff)); assert((result16 & 0x00ff) == (expected16 & 0x00ff)); } - - // validate unaligned word accesses - printf(" read_word_unaligned = "); printf("%04X\n", result16 = read_word_unaligned(address)); assert(result16 == expected16); - printf(" read_word_unaligned (0xff00) = "); printf("%04X\n", result16 = read_word_unaligned(address, 0xff00)); assert((result16 & 0xff00) == (expected16 & 0xff00)); - printf(" (0x00ff) = "); printf("%04X\n", result16 = read_word_unaligned(address, 0x00ff)); assert((result16 & 0x00ff) == (expected16 & 0x00ff)); - - // validate dword acceses (if aligned) - if (DWORD_ALIGNED(address)) { printf(" read_dword = "); printf("%08X\n", result32 = read_dword(address)); assert(result32 == expected32); } - if (DWORD_ALIGNED(address)) { printf(" read_dword (0xff000000) = "); printf("%08X\n", result32 = read_dword(address, 0xff000000)); assert((result32 & 0xff000000) == (expected32 & 0xff000000)); } - if (DWORD_ALIGNED(address)) { printf(" (0x00ff0000) = "); printf("%08X\n", result32 = read_dword(address, 0x00ff0000)); assert((result32 & 0x00ff0000) == (expected32 & 0x00ff0000)); } - if (DWORD_ALIGNED(address)) { printf(" (0x0000ff00) = "); printf("%08X\n", result32 = read_dword(address, 0x0000ff00)); assert((result32 & 0x0000ff00) == (expected32 & 0x0000ff00)); } - if (DWORD_ALIGNED(address)) { printf(" (0x000000ff) = "); printf("%08X\n", result32 = read_dword(address, 0x000000ff)); assert((result32 & 0x000000ff) == (expected32 & 0x000000ff)); } - if (DWORD_ALIGNED(address)) { printf(" (0xffff0000) = "); printf("%08X\n", result32 = read_dword(address, 0xffff0000)); assert((result32 & 0xffff0000) == (expected32 & 0xffff0000)); } - if (DWORD_ALIGNED(address)) { printf(" (0x0000ffff) = "); printf("%08X\n", result32 = read_dword(address, 0x0000ffff)); assert((result32 & 0x0000ffff) == (expected32 & 0x0000ffff)); } - if (DWORD_ALIGNED(address)) { printf(" (0xffffff00) = "); printf("%08X\n", result32 = read_dword(address, 0xffffff00)); assert((result32 & 0xffffff00) == (expected32 & 0xffffff00)); } - if (DWORD_ALIGNED(address)) { printf(" (0x00ffffff) = "); printf("%08X\n", result32 = read_dword(address, 0x00ffffff)); assert((result32 & 0x00ffffff) == (expected32 & 0x00ffffff)); } - - // validate unaligned dword accesses - printf(" read_dword_unaligned = "); printf("%08X\n", result32 = read_dword_unaligned(address)); assert(result32 == expected32); - printf(" read_dword_unaligned (0xff000000) = "); printf("%08X\n", result32 = read_dword_unaligned(address, 0xff000000)); assert((result32 & 0xff000000) == (expected32 & 0xff000000)); - printf(" (0x00ff0000) = "); printf("%08X\n", result32 = read_dword_unaligned(address, 0x00ff0000)); assert((result32 & 0x00ff0000) == (expected32 & 0x00ff0000)); - printf(" (0x0000ff00) = "); printf("%08X\n", result32 = read_dword_unaligned(address, 0x0000ff00)); assert((result32 & 0x0000ff00) == (expected32 & 0x0000ff00)); - printf(" (0x000000ff) = "); printf("%08X\n", result32 = read_dword_unaligned(address, 0x000000ff)); assert((result32 & 0x000000ff) == (expected32 & 0x000000ff)); - printf(" (0xffff0000) = "); printf("%08X\n", result32 = read_dword_unaligned(address, 0xffff0000)); assert((result32 & 0xffff0000) == (expected32 & 0xffff0000)); - printf(" (0x0000ffff) = "); printf("%08X\n", result32 = read_dword_unaligned(address, 0x0000ffff)); assert((result32 & 0x0000ffff) == (expected32 & 0x0000ffff)); - printf(" (0xffffff00) = "); printf("%08X\n", result32 = read_dword_unaligned(address, 0xffffff00)); assert((result32 & 0xffffff00) == (expected32 & 0xffffff00)); - printf(" (0x00ffffff) = "); printf("%08X\n", result32 = read_dword_unaligned(address, 0x00ffffff)); assert((result32 & 0x00ffffff) == (expected32 & 0x00ffffff)); - - // validate qword acceses (if aligned) - if (QWORD_ALIGNED(address)) { printf(" read_qword = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address), 16)); assert(result64 == expected64); } - if (QWORD_ALIGNED(address)) { printf(" read_qword (0xff00000000000000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0xff00000000000000U), 16)); assert((result64 & 0xff00000000000000U) == (expected64 & 0xff00000000000000U)); } - if (QWORD_ALIGNED(address)) { printf(" (0x00ff000000000000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0x00ff000000000000U), 16)); assert((result64 & 0x00ff000000000000U) == (expected64 & 0x00ff000000000000U)); } - if (QWORD_ALIGNED(address)) { printf(" (0x0000ff0000000000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0x0000ff0000000000U), 16)); assert((result64 & 0x0000ff0000000000U) == (expected64 & 0x0000ff0000000000U)); } - if (QWORD_ALIGNED(address)) { printf(" (0x000000ff00000000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0x000000ff00000000U), 16)); assert((result64 & 0x000000ff00000000U) == (expected64 & 0x000000ff00000000U)); } - if (QWORD_ALIGNED(address)) { printf(" (0x00000000ff000000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0x00000000ff000000U), 16)); assert((result64 & 0x00000000ff000000U) == (expected64 & 0x00000000ff000000U)); } - if (QWORD_ALIGNED(address)) { printf(" (0x0000000000ff0000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0x0000000000ff0000U), 16)); assert((result64 & 0x0000000000ff0000U) == (expected64 & 0x0000000000ff0000U)); } - if (QWORD_ALIGNED(address)) { printf(" (0x000000000000ff00) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0x000000000000ff00U), 16)); assert((result64 & 0x000000000000ff00U) == (expected64 & 0x000000000000ff00U)); } - if (QWORD_ALIGNED(address)) { printf(" (0x00000000000000ff) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0x00000000000000ffU), 16)); assert((result64 & 0x00000000000000ffU) == (expected64 & 0x00000000000000ffU)); } - if (QWORD_ALIGNED(address)) { printf(" (0xffff000000000000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0xffff000000000000U), 16)); assert((result64 & 0xffff000000000000U) == (expected64 & 0xffff000000000000U)); } - if (QWORD_ALIGNED(address)) { printf(" (0x0000ffff00000000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0x0000ffff00000000U), 16)); assert((result64 & 0x0000ffff00000000U) == (expected64 & 0x0000ffff00000000U)); } - if (QWORD_ALIGNED(address)) { printf(" (0x00000000ffff0000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0x00000000ffff0000U), 16)); assert((result64 & 0x00000000ffff0000U) == (expected64 & 0x00000000ffff0000U)); } - if (QWORD_ALIGNED(address)) { printf(" (0x000000000000ffff) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0x000000000000ffffU), 16)); assert((result64 & 0x000000000000ffffU) == (expected64 & 0x000000000000ffffU)); } - if (QWORD_ALIGNED(address)) { printf(" (0xffffff0000000000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0xffffff0000000000U), 16)); assert((result64 & 0xffffff0000000000U) == (expected64 & 0xffffff0000000000U)); } - if (QWORD_ALIGNED(address)) { printf(" (0x0000ffffff000000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0x0000ffffff000000U), 16)); assert((result64 & 0x0000ffffff000000U) == (expected64 & 0x0000ffffff000000U)); } - if (QWORD_ALIGNED(address)) { printf(" (0x000000ffffff0000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0x000000ffffff0000U), 16)); assert((result64 & 0x000000ffffff0000U) == (expected64 & 0x000000ffffff0000U)); } - if (QWORD_ALIGNED(address)) { printf(" (0x0000000000ffffff) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0x0000000000ffffffU), 16)); assert((result64 & 0x0000000000ffffffU) == (expected64 & 0x0000000000ffffffU)); } - if (QWORD_ALIGNED(address)) { printf(" (0xffffffff00000000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0xffffffff00000000U), 16)); assert((result64 & 0xffffffff00000000U) == (expected64 & 0xffffffff00000000U)); } - if (QWORD_ALIGNED(address)) { printf(" (0x00ffffffff000000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0x00ffffffff000000U), 16)); assert((result64 & 0x00ffffffff000000U) == (expected64 & 0x00ffffffff000000U)); } - if (QWORD_ALIGNED(address)) { printf(" (0x0000ffffffff0000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0x0000ffffffff0000U), 16)); assert((result64 & 0x0000ffffffff0000U) == (expected64 & 0x0000ffffffff0000U)); } - if (QWORD_ALIGNED(address)) { printf(" (0x000000ffffffff00) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0x000000ffffffff00U), 16)); assert((result64 & 0x000000ffffffff00U) == (expected64 & 0x000000ffffffff00U)); } - if (QWORD_ALIGNED(address)) { printf(" (0x00000000ffffffff) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0x00000000ffffffffU), 16)); assert((result64 & 0x00000000ffffffffU) == (expected64 & 0x00000000ffffffffU)); } - if (QWORD_ALIGNED(address)) { printf(" (0xffffffffff000000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0xffffffffff000000U), 16)); assert((result64 & 0xffffffffff000000U) == (expected64 & 0xffffffffff000000U)); } - if (QWORD_ALIGNED(address)) { printf(" (0x00ffffffffff0000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0x00ffffffffff0000U), 16)); assert((result64 & 0x00ffffffffff0000U) == (expected64 & 0x00ffffffffff0000U)); } - if (QWORD_ALIGNED(address)) { printf(" (0x0000ffffffffff00) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0x0000ffffffffff00U), 16)); assert((result64 & 0x0000ffffffffff00U) == (expected64 & 0x0000ffffffffff00U)); } - if (QWORD_ALIGNED(address)) { printf(" (0x000000ffffffffff) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0x000000ffffffffffU), 16)); assert((result64 & 0x000000ffffffffffU) == (expected64 & 0x000000ffffffffffU)); } - if (QWORD_ALIGNED(address)) { printf(" (0xffffffffffff0000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0xffffffffffff0000U), 16)); assert((result64 & 0xffffffffffff0000U) == (expected64 & 0xffffffffffff0000U)); } - if (QWORD_ALIGNED(address)) { printf(" (0x00ffffffffffff00) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0x00ffffffffffff00U), 16)); assert((result64 & 0x00ffffffffffff00U) == (expected64 & 0x00ffffffffffff00U)); } - if (QWORD_ALIGNED(address)) { printf(" (0x0000ffffffffffff) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0x0000ffffffffffffU), 16)); assert((result64 & 0x0000ffffffffffffU) == (expected64 & 0x0000ffffffffffffU)); } - if (QWORD_ALIGNED(address)) { printf(" (0xffffffffffffff00) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0xffffffffffffff00U), 16)); assert((result64 & 0xffffffffffffff00U) == (expected64 & 0xffffffffffffff00U)); } - if (QWORD_ALIGNED(address)) { printf(" (0x00ffffffffffffff) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword(address, 0x00ffffffffffffffU), 16)); assert((result64 & 0x00ffffffffffffffU) == (expected64 & 0x00ffffffffffffffU)); } - - // validate unaligned qword accesses - printf(" read_qword_unaligned = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address), 16)); assert(result64 == expected64); - printf(" read_qword_unaligned (0xff00000000000000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0xff00000000000000U), 16)); assert((result64 & 0xff00000000000000U) == (expected64 & 0xff00000000000000U)); - printf(" (0x00ff000000000000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0x00ff000000000000U), 16)); assert((result64 & 0x00ff000000000000U) == (expected64 & 0x00ff000000000000U)); - printf(" (0x0000ff0000000000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0x0000ff0000000000U), 16)); assert((result64 & 0x0000ff0000000000U) == (expected64 & 0x0000ff0000000000U)); - printf(" (0x000000ff00000000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0x000000ff00000000U), 16)); assert((result64 & 0x000000ff00000000U) == (expected64 & 0x000000ff00000000U)); - printf(" (0x00000000ff000000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0x00000000ff000000U), 16)); assert((result64 & 0x00000000ff000000U) == (expected64 & 0x00000000ff000000U)); - printf(" (0x0000000000ff0000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0x0000000000ff0000U), 16)); assert((result64 & 0x0000000000ff0000U) == (expected64 & 0x0000000000ff0000U)); - printf(" (0x000000000000ff00) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0x000000000000ff00U), 16)); assert((result64 & 0x000000000000ff00U) == (expected64 & 0x000000000000ff00U)); - printf(" (0x00000000000000ff) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0x00000000000000ffU), 16)); assert((result64 & 0x00000000000000ffU) == (expected64 & 0x00000000000000ffU)); - printf(" (0xffff000000000000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0xffff000000000000U), 16)); assert((result64 & 0xffff000000000000U) == (expected64 & 0xffff000000000000U)); - printf(" (0x0000ffff00000000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0x0000ffff00000000U), 16)); assert((result64 & 0x0000ffff00000000U) == (expected64 & 0x0000ffff00000000U)); - printf(" (0x00000000ffff0000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0x00000000ffff0000U), 16)); assert((result64 & 0x00000000ffff0000U) == (expected64 & 0x00000000ffff0000U)); - printf(" (0x000000000000ffff) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0x000000000000ffffU), 16)); assert((result64 & 0x000000000000ffffU) == (expected64 & 0x000000000000ffffU)); - printf(" (0xffffff0000000000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0xffffff0000000000U), 16)); assert((result64 & 0xffffff0000000000U) == (expected64 & 0xffffff0000000000U)); - printf(" (0x0000ffffff000000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0x0000ffffff000000U), 16)); assert((result64 & 0x0000ffffff000000U) == (expected64 & 0x0000ffffff000000U)); - printf(" (0x000000ffffff0000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0x000000ffffff0000U), 16)); assert((result64 & 0x000000ffffff0000U) == (expected64 & 0x000000ffffff0000U)); - printf(" (0x0000000000ffffff) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0x0000000000ffffffU), 16)); assert((result64 & 0x0000000000ffffffU) == (expected64 & 0x0000000000ffffffU)); - printf(" (0xffffffff00000000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0xffffffff00000000U), 16)); assert((result64 & 0xffffffff00000000U) == (expected64 & 0xffffffff00000000U)); - printf(" (0x00ffffffff000000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0x00ffffffff000000U), 16)); assert((result64 & 0x00ffffffff000000U) == (expected64 & 0x00ffffffff000000U)); - printf(" (0x0000ffffffff0000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0x0000ffffffff0000U), 16)); assert((result64 & 0x0000ffffffff0000U) == (expected64 & 0x0000ffffffff0000U)); - printf(" (0x000000ffffffff00) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0x000000ffffffff00U), 16)); assert((result64 & 0x000000ffffffff00U) == (expected64 & 0x000000ffffffff00U)); - printf(" (0x00000000ffffffff) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0x00000000ffffffffU), 16)); assert((result64 & 0x00000000ffffffffU) == (expected64 & 0x00000000ffffffffU)); - printf(" (0xffffffffff000000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0xffffffffff000000U), 16)); assert((result64 & 0xffffffffff000000U) == (expected64 & 0xffffffffff000000U)); - printf(" (0x00ffffffffff0000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0x00ffffffffff0000U), 16)); assert((result64 & 0x00ffffffffff0000U) == (expected64 & 0x00ffffffffff0000U)); - printf(" (0x0000ffffffffff00) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0x0000ffffffffff00U), 16)); assert((result64 & 0x0000ffffffffff00U) == (expected64 & 0x0000ffffffffff00U)); - printf(" (0x000000ffffffffff) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0x000000ffffffffffU), 16)); assert((result64 & 0x000000ffffffffffU) == (expected64 & 0x000000ffffffffffU)); - printf(" (0xffffffffffff0000) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0xffffffffffff0000U), 16)); assert((result64 & 0xffffffffffff0000U) == (expected64 & 0xffffffffffff0000U)); - printf(" (0x00ffffffffffff00) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0x00ffffffffffff00U), 16)); assert((result64 & 0x00ffffffffffff00U) == (expected64 & 0x00ffffffffffff00U)); - printf(" (0x0000ffffffffffff) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0x0000ffffffffffffU), 16)); assert((result64 & 0x0000ffffffffffffU) == (expected64 & 0x0000ffffffffffffU)); - printf(" (0xffffffffffffff00) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0xffffffffffffff00U), 16)); assert((result64 & 0xffffffffffffff00U) == (expected64 & 0xffffffffffffff00U)); - printf(" (0x00ffffffffffffff) = "); printf("%s\n", core_i64_hex_format(result64 = read_qword_unaligned(address, 0x00ffffffffffffffU), 16)); assert((result64 & 0x00ffffffffffffffU) == (expected64 & 0x00ffffffffffffffU)); - } -#endif - } - - // accessors - virtual address_table_read &read() override { return m_read; } - virtual address_table_write &write() override { return m_write; } - virtual address_table_setoffset &setoffset() override { return m_setoffset; } - - // watchpoint control - virtual void enable_read_watchpoints(bool enable = true) override { m_read.enable_watchpoints(enable); } - virtual void enable_write_watchpoints(bool enable = true) override { m_write.enable_watchpoints(enable); } - - // generate accessor table - virtual void accessors(data_accessors &accessors) const override - { - accessors.read_byte = reinterpret_cast(&read_byte_static); - accessors.read_word = reinterpret_cast(&read_word_static); - accessors.read_word_masked = reinterpret_cast(&read_word_masked_static); - accessors.read_dword = reinterpret_cast(&read_dword_static); - accessors.read_dword_masked = reinterpret_cast(&read_dword_masked_static); - accessors.read_qword = reinterpret_cast(&read_qword_static); - accessors.read_qword_masked = reinterpret_cast(&read_qword_masked_static); - accessors.write_byte = reinterpret_cast(&write_byte_static); - accessors.write_word = reinterpret_cast(&write_word_static); - accessors.write_word_masked = reinterpret_cast(&write_word_masked_static); - accessors.write_dword = reinterpret_cast(&write_dword_static); - accessors.write_dword_masked = reinterpret_cast(&write_dword_masked_static); - accessors.write_qword = reinterpret_cast(&write_qword_static); - accessors.write_qword_masked = reinterpret_cast(&write_qword_masked_static); - } - - // return a pointer to the read bank, or nullptr if none - virtual void *get_read_ptr(offs_t address) override - { - // perform the lookup - address &= m_addrmask; - u32 entry = read_lookup(address); - const handler_entry_read &handler = m_read.handler_read(entry); - - // 8-bit case: RAM/ROM - if (entry > STATIC_BANKMAX) - return nullptr; - return handler.ramptr(handler.offset(address)); - } - - // return a pointer to the write bank, or nullptr if none - virtual void *get_write_ptr(offs_t address) override - { - // perform the lookup - address &= m_addrmask; - u32 entry = write_lookup(address); - const handler_entry_write &handler = m_write.handler_write(entry); - - // 8-bit case: RAM/ROM - if (entry > STATIC_BANKMAX) - return nullptr; - return handler.ramptr(handler.offset(address)); - } - - // native read - NativeType read_native(offs_t offset, NativeType mask) - { - g_profiler.start(PROFILER_MEMREAD); - - if (TEST_HANDLER) printf("[r%X,%s]", offset, core_i64_hex_format(mask, sizeof(NativeType) * 2)); - - // look up the handler - offs_t address = offset & m_addrmask; - u32 entry = read_lookup(address); - const handler_entry_read &handler = m_read.handler_read(entry); - - // either read directly from RAM, or call the delegate - offset = offset_to_byte(handler.offset(address)); - NativeType result; - if (entry <= STATIC_BANKMAX) result = *reinterpret_cast(handler.ramptr(offset)); - else if (sizeof(NativeType) == 1) result = handler.read8(*this, offset, mask); - else if (sizeof(NativeType) == 2) result = handler.read16(*this, offset >> 1, mask); - else if (sizeof(NativeType) == 4) result = handler.read32(*this, offset >> 2, mask); - else if (sizeof(NativeType) == 8) result = handler.read64(*this, offset >> 3, mask); - - g_profiler.stop(); - return result; - } - - // mask-less native read - NativeType read_native(offs_t offset) - { - g_profiler.start(PROFILER_MEMREAD); - - if (TEST_HANDLER) printf("[r%X]", offset); - - // look up the handler - offs_t address = offset & m_addrmask; - u32 entry = read_lookup(address); - const handler_entry_read &handler = m_read.handler_read(entry); - - // either read directly from RAM, or call the delegate - offset = offset_to_byte(handler.offset(address)); - NativeType result; - if (entry <= STATIC_BANKMAX) result = *reinterpret_cast(handler.ramptr(offset)); - else if (sizeof(NativeType) == 1) result = handler.read8(*this, offset, 0xff); - else if (sizeof(NativeType) == 2) result = handler.read16(*this, offset >> 1, 0xffff); - else if (sizeof(NativeType) == 4) result = handler.read32(*this, offset >> 2, 0xffffffff); - else if (sizeof(NativeType) == 8) result = handler.read64(*this, offset >> 3, 0xffffffffffffffffU); - - g_profiler.stop(); - return result; - } - - // native write - void write_native(offs_t offset, NativeType data, NativeType mask) - { - g_profiler.start(PROFILER_MEMWRITE); - - // look up the handler - offs_t address = offset & m_addrmask; - u32 entry = write_lookup(address); - const handler_entry_write &handler = m_write.handler_write(entry); - - // either write directly to RAM, or call the delegate - offset = offset_to_byte(handler.offset(address)); - if (entry <= STATIC_BANKMAX) - { - NativeType *dest = reinterpret_cast(handler.ramptr(offset)); - *dest = (*dest & ~mask) | (data & mask); - } - else if (sizeof(NativeType) == 1) handler.write8(*this, offset, data, mask); - else if (sizeof(NativeType) == 2) handler.write16(*this, offset >> 1, data, mask); - else if (sizeof(NativeType) == 4) handler.write32(*this, offset >> 2, data, mask); - else if (sizeof(NativeType) == 8) handler.write64(*this, offset >> 3, data, mask); - - g_profiler.stop(); - } - - // mask-less native write - void write_native(offs_t offset, NativeType data) - { - g_profiler.start(PROFILER_MEMWRITE); - - // look up the handler - offs_t address = offset & m_addrmask; - u32 entry = write_lookup(address); - const handler_entry_write &handler = m_write.handler_write(entry); - - // either write directly to RAM, or call the delegate - offset = offset_to_byte(handler.offset(address)); - if (entry <= STATIC_BANKMAX) *reinterpret_cast(handler.ramptr(offset)) = data; - else if (sizeof(NativeType) == 1) handler.write8(*this, offset, data, 0xff); - else if (sizeof(NativeType) == 2) handler.write16(*this, offset >> 1, data, 0xffff); - else if (sizeof(NativeType) == 4) handler.write32(*this, offset >> 2, data, 0xffffffff); - else if (sizeof(NativeType) == 8) handler.write64(*this, offset >> 3, data, 0xffffffffffffffffU); - - g_profiler.stop(); - } - - - // Allows to announce a pending read or write operation on this address. - // The user of the address_space calls a set_address operation which leads - // to some particular set_offset operation for an entry in the address map. - void set_address(offs_t address) override - { - address &= m_addrmask; - u32 entry = setoffset_lookup(address); - const handler_entry_setoffset &handler = m_setoffset.handler_setoffset(entry); - - offs_t offset = handler.offset(address); - handler.setoffset(*this, offset / sizeof(NativeType)); - } - - // virtual access to these functions - u8 read_byte(offs_t address) override { return Width == 0 ? read_native(address & ~NATIVE_MASK) : memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xff); } - u16 read_word(offs_t address) override { return Width == 1 ? read_native(address & ~NATIVE_MASK) : memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffff); } - u16 read_word(offs_t address, u16 mask) override { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } - u16 read_word_unaligned(offs_t address) override { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffff); } - u16 read_word_unaligned(offs_t address, u16 mask) override { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } - u32 read_dword(offs_t address) override { return Width == 2 ? read_native(address & ~NATIVE_MASK) : memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffff); } - u32 read_dword(offs_t address, u32 mask) override { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } - u32 read_dword_unaligned(offs_t address) override { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffff); } - u32 read_dword_unaligned(offs_t address, u32 mask) override { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } - u64 read_qword(offs_t address) override { return Width == 3 ? read_native(address & ~NATIVE_MASK) : memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffffffffffffU); } - u64 read_qword(offs_t address, u64 mask) override { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } - u64 read_qword_unaligned(offs_t address) override { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffffffffffffU); } - u64 read_qword_unaligned(offs_t address, u64 mask) override { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } - - void write_byte(offs_t address, u8 data) override { if (Width == 0) write_native(address & ~NATIVE_MASK, data); else memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xff); } - void write_word(offs_t address, u16 data) override { if (Width == 1) write_native(address & ~NATIVE_MASK, data); else memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffff); } - void write_word(offs_t address, u16 data, u16 mask) override { memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } - void write_word_unaligned(offs_t address, u16 data) override { memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffff); } - void write_word_unaligned(offs_t address, u16 data, u16 mask) override { memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } - void write_dword(offs_t address, u32 data) override { if (Width == 2) write_native(address & ~NATIVE_MASK, data); else memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffff); } - void write_dword(offs_t address, u32 data, u32 mask) override { memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } - void write_dword_unaligned(offs_t address, u32 data) override { memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffff); } - void write_dword_unaligned(offs_t address, u32 data, u32 mask) override { memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } - void write_qword(offs_t address, u64 data) override { if (Width == 3) write_native(address & ~NATIVE_MASK, data); else memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffffffffffffU); } - void write_qword(offs_t address, u64 data, u64 mask) override { memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } - void write_qword_unaligned(offs_t address, u64 data) override { memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffffffffffffU); } - void write_qword_unaligned(offs_t address, u64 data, u64 mask) override { memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } - - // static access to these functions - static u8 read_byte_static(this_type &space, offs_t address) { return Width == 0 ? space.read_native(address & ~NATIVE_MASK) : memory_read_generic([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, 0xff); } - static u16 read_word_static(this_type &space, offs_t address) { return Width == 1 ? space.read_native(address & ~NATIVE_MASK) : memory_read_generic([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, 0xffff); } - static u16 read_word_masked_static(this_type &space, offs_t address, u16 mask) { return memory_read_generic([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, mask); } - static u32 read_dword_static(this_type &space, offs_t address) { return Width == 2 ? space.read_native(address & ~NATIVE_MASK) : memory_read_generic([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, 0xffffffff); } - static u32 read_dword_masked_static(this_type &space, offs_t address, u32 mask) { return memory_read_generic([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, mask); } - static u64 read_qword_static(this_type &space, offs_t address) { return Width == 3 ? space.read_native(address & ~NATIVE_MASK) : memory_read_generic([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, 0xffffffffffffffffU); } - static u64 read_qword_masked_static(this_type &space, offs_t address, u64 mask) { return memory_read_generic([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, mask); } - static void write_byte_static(this_type &space, offs_t address, u8 data) { if (Width == 0) space.write_native(address & ~NATIVE_MASK, data); else memory_write_generic([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, 0xff); } - static void write_word_static(this_type &space, offs_t address, u16 data) { if (Width == 1) space.write_native(address & ~NATIVE_MASK, data); else memory_write_generic([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, 0xffff); } - static void write_word_masked_static(this_type &space, offs_t address, u16 data, u16 mask) { memory_write_generic([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, mask); } - static void write_dword_static(this_type &space, offs_t address, u32 data) { if (Width == 2) space.write_native(address & ~NATIVE_MASK, data); else memory_write_generic([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, 0xffffffff); } - static void write_dword_masked_static(this_type &space, offs_t address, u32 data, u32 mask) { memory_write_generic([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, mask); } - static void write_qword_static(this_type &space, offs_t address, u64 data) { if (Width == 3) space.write_native(address & ~NATIVE_MASK, data); else memory_write_generic([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, 0xffffffffffffffffU); } - static void write_qword_masked_static(this_type &space, offs_t address, u64 data, u64 mask) { memory_write_generic([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, mask); } - - address_table_read m_read; // memory read lookup table - address_table_write m_write; // memory write lookup table - address_table_setoffset m_setoffset; // memory setoffset lookup table -}; - -typedef address_space_specific address_space_8_8le_small; -typedef address_space_specific address_space_8_8be_small; -typedef address_space_specific address_space_16_1le_small; -typedef address_space_specific address_space_16_1be_small; -typedef address_space_specific address_space_16_8le_small; -typedef address_space_specific address_space_16_8be_small; -typedef address_space_specific address_space_16_16le_small; -typedef address_space_specific address_space_16_16be_small; -typedef address_space_specific address_space_32_8le_small; -typedef address_space_specific address_space_32_8be_small; -typedef address_space_specific address_space_32_16le_small; -typedef address_space_specific address_space_32_16be_small; -typedef address_space_specific address_space_32_32le_small; -typedef address_space_specific address_space_32_32be_small; -typedef address_space_specific address_space_64_8le_small; -typedef address_space_specific address_space_64_8be_small; -typedef address_space_specific address_space_64_16le_small; -typedef address_space_specific address_space_64_16be_small; -typedef address_space_specific address_space_64_32le_small; -typedef address_space_specific address_space_64_32be_small; -typedef address_space_specific address_space_64_64le_small; -typedef address_space_specific address_space_64_64be_small; - -typedef address_space_specific address_space_8_8le_large; -typedef address_space_specific address_space_8_8be_large; -typedef address_space_specific address_space_16_1le_large; -typedef address_space_specific address_space_16_1be_large; -typedef address_space_specific address_space_16_8le_large; -typedef address_space_specific address_space_16_8be_large; -typedef address_space_specific address_space_16_16le_large; -typedef address_space_specific address_space_16_16be_large; -typedef address_space_specific address_space_32_8le_large; -typedef address_space_specific address_space_32_8be_large; -typedef address_space_specific address_space_32_16le_large; -typedef address_space_specific address_space_32_16be_large; -typedef address_space_specific address_space_32_32le_large; -typedef address_space_specific address_space_32_32be_large; -typedef address_space_specific address_space_64_8le_large; -typedef address_space_specific address_space_64_8be_large; -typedef address_space_specific address_space_64_16le_large; -typedef address_space_specific address_space_64_16be_large; -typedef address_space_specific address_space_64_32le_large; -typedef address_space_specific address_space_64_32be_large; -typedef address_space_specific address_space_64_64le_large; -typedef address_space_specific address_space_64_64be_large; - - - - -//************************************************************************** -// GLOBAL VARIABLES -//************************************************************************** - -// global watchpoint table -u16 address_table::s_watchpoint_table[1 << LEVEL1_BITS]; - - - -//************************************************************************** -// FUNCTION PROTOTYPES -//************************************************************************** - -// debugging -static void generate_memdump(running_machine &machine); - - //************************************************************************** // MEMORY MANAGER @@ -1339,10 +659,8 @@ static void generate_memdump(running_machine &machine); memory_manager::memory_manager(running_machine &machine) : m_machine(machine), - m_initialized(false), - m_banknext(STATIC_BANK1) + m_initialized(false) { - memset(m_bank_ptr, 0, sizeof(m_bank_ptr)); } //------------------------------------------------- @@ -1358,214 +676,87 @@ void memory_manager::allocate(device_memory_interface &memory) if (spaceconfig) { // allocate one of the appropriate type - bool const large(spaceconfig->addr2byte_end(0xffffffffUL >> (32 - spaceconfig->m_addr_width)) >= (1 << 18)); - - switch (spaceconfig->data_width()) + switch (spaceconfig->data_width() | (spaceconfig->addr_shift() + 4)) { - case 8: - if (spaceconfig->endianness() == ENDIANNESS_LITTLE) - { - if (large) - memory.allocate(*this, spacenum); - else - memory.allocate(*this, spacenum); - } - else - { - if (large) - memory.allocate(*this, spacenum); + case 8|(4-0): + if (spaceconfig->endianness() == ENDIANNESS_LITTLE) + memory.allocate>(*this, spacenum); else - memory.allocate(*this, spacenum); - } - break; + memory.allocate>(*this, spacenum); + break; - case 16: - switch (spaceconfig->addr_shift()) - { - case 3: + case 16|(4+3): if (spaceconfig->endianness() == ENDIANNESS_LITTLE) - { - if (large) - memory.allocate(*this, spacenum); - else - memory.allocate(*this, spacenum); - } + memory.allocate>(*this, spacenum); else - { - if (large) - memory.allocate(*this, spacenum); - else - memory.allocate(*this, spacenum); - } + memory.allocate>(*this, spacenum); break; - case 0: + case 16|(4-0): if (spaceconfig->endianness() == ENDIANNESS_LITTLE) - { - if (large) - memory.allocate(*this, spacenum); - else - memory.allocate(*this, spacenum); - } + memory.allocate>(*this, spacenum); else - { - if (large) - memory.allocate(*this, spacenum); - else - memory.allocate(*this, spacenum); - } + memory.allocate>(*this, spacenum); break; - case -1: + case 16|(4-1): if (spaceconfig->endianness() == ENDIANNESS_LITTLE) - { - if (large) - memory.allocate(*this, spacenum); - else - memory.allocate(*this, spacenum); - } + memory.allocate>(*this, spacenum); else - { - if (large) - memory.allocate(*this, spacenum); - else - memory.allocate(*this, spacenum); - } + memory.allocate>(*this, spacenum); break; - } - break; - case 32: - switch (spaceconfig->addr_shift()) - { - case 0: + case 32|(4-0): if (spaceconfig->endianness() == ENDIANNESS_LITTLE) - { - if (large) - memory.allocate(*this, spacenum); - else - memory.allocate(*this, spacenum); - } + memory.allocate>(*this, spacenum); else - { - if (large) - memory.allocate(*this, spacenum); - else - memory.allocate(*this, spacenum); - } + memory.allocate>(*this, spacenum); break; - case -1: + case 32|(4-1): if (spaceconfig->endianness() == ENDIANNESS_LITTLE) - { - if (large) - memory.allocate(*this, spacenum); - else - memory.allocate(*this, spacenum); - } + memory.allocate>(*this, spacenum); else - { - if (large) - memory.allocate(*this, spacenum); - else - memory.allocate(*this, spacenum); - } + memory.allocate>(*this, spacenum); break; - case -2: + case 32|(4-2): if (spaceconfig->endianness() == ENDIANNESS_LITTLE) - { - if (large) - memory.allocate(*this, spacenum); - else - memory.allocate(*this, spacenum); - } + memory.allocate>(*this, spacenum); else - { - if (large) - memory.allocate(*this, spacenum); - else - memory.allocate(*this, spacenum); - } + memory.allocate>(*this, spacenum); break; - } - break; - case 64: - switch (spaceconfig->addr_shift()) - { - case 0: + case 64|(4-0): if (spaceconfig->endianness() == ENDIANNESS_LITTLE) - { - if (large) - memory.allocate(*this, spacenum); - else - memory.allocate(*this, spacenum); - } + memory.allocate>(*this, spacenum); else - { - if (large) - memory.allocate(*this, spacenum); - else - memory.allocate(*this, spacenum); - } + memory.allocate>(*this, spacenum); break; - case -1: + case 64|(4-1): if (spaceconfig->endianness() == ENDIANNESS_LITTLE) - { - if (large) - memory.allocate(*this, spacenum); - else - memory.allocate(*this, spacenum); - } + memory.allocate>(*this, spacenum); else - { - if (large) - memory.allocate(*this, spacenum); - else - memory.allocate(*this, spacenum); - } + memory.allocate>(*this, spacenum); break; - case -2: + case 64|(4-2): if (spaceconfig->endianness() == ENDIANNESS_LITTLE) - { - if (large) - memory.allocate(*this, spacenum); - else - memory.allocate(*this, spacenum); - } + memory.allocate>(*this, spacenum); else - { - if (large) - memory.allocate(*this, spacenum); - else - memory.allocate(*this, spacenum); - } + memory.allocate>(*this, spacenum); break; - case -3: + case 64|(4-3): if (spaceconfig->endianness() == ENDIANNESS_LITTLE) - { - if (large) - memory.allocate(*this, spacenum); - else - memory.allocate(*this, spacenum); - } + memory.allocate>(*this, spacenum); else - { - if (large) - memory.allocate(*this, spacenum); - else - memory.allocate(*this, spacenum); - } + memory.allocate>(*this, spacenum); break; - } - break; - - default: - throw emu_fatalerror("Invalid width %d specified for address_space::allocate", spaceconfig->data_width()); + + default: + throw emu_fatalerror("Invalid width %d/shift %d specified for address_space::allocate", spaceconfig->data_width(), spaceconfig->addr_shift()); } } } @@ -1609,12 +800,6 @@ void memory_manager::initialize() for (auto const memory : memories) memory->set_log_unmap(false); - // register a callback to reset banks when reloading state - machine().save().register_postload(save_prepost_delegate(FUNC(memory_manager::bank_reattach), this)); - - // dump the final memory configuration - generate_memdump(machine()); - // we are now initialized m_initialized = true; } @@ -1665,40 +850,36 @@ memory_region *memory_manager::region_containing(const void *memory, offs_t byte return nullptr; } - -//------------------------------------------------- -// generate_memdump - internal memory dump -//------------------------------------------------- - -static void generate_memdump(running_machine &machine) +memory_bank *memory_manager::find(const char *tag) const { - if (MEM_DUMP) - { - FILE *file = fopen("memdump.log", "w"); - if (file) - { - memory_interface_iterator iter(machine.root_device()); - for (device_memory_interface &memory : iter) - memory.dump(file); - fclose(file); - } - } + auto bank = m_banklist.find(tag); + if (bank != m_banklist.end()) + return bank->second.get(); + return nullptr; } - -//------------------------------------------------- -// bank_reattach - reconnect banks after a load -//------------------------------------------------- - -void memory_manager::bank_reattach() +memory_bank *memory_manager::find(address_space &space, offs_t addrstart, offs_t addrend) const { - // for each non-anonymous bank, explicitly reset its entry + // try to find an exact match for (auto &bank : m_banklist) - if (!bank.second->anonymous() && bank.second->entry() != BANK_ENTRY_UNSPECIFIED) - bank.second->set_entry(bank.second->entry()); -} + if (bank.second->anonymous() && bank.second->references_space(space, read_or_write::READWRITE) && bank.second->matches_exactly(addrstart, addrend)) + return bank.second.get(); + // not found + return nullptr; +} +memory_bank *memory_manager::allocate(address_space &space, offs_t addrstart, offs_t addrend, const char *tag) +{ + auto bank = std::make_unique(space, m_banklist.size(), addrstart, addrend, tag); + std::string temptag; + if (tag == nullptr) { + temptag = string_format("anon_%p", bank.get()); + tag = temptag.c_str(); + } + m_banklist.emplace(tag, std::move(bank)); + return m_banklist.find(tag)->second.get(); +} //************************************************************************** // ADDRESS SPACE @@ -1708,101 +889,21 @@ void memory_manager::bank_reattach() // address_space - constructor //------------------------------------------------- -address_space::address_space(memory_manager &manager, device_memory_interface &memory, int spacenum, bool large) +address_space::address_space(memory_manager &manager, device_memory_interface &memory, int spacenum) : m_config(*memory.space_config(spacenum)), m_device(memory.device()), - m_addrmask(0xffffffffUL >> (32 - m_config.m_addr_width)), - m_logaddrmask(0xffffffffUL >> (32 - m_config.m_logaddr_width)), + m_addrmask(make_bitmask(m_config.m_addr_width)), + m_logaddrmask(make_bitmask(m_config.m_logaddr_width)), m_unmap(0), m_spacenum(spacenum), m_log_unmap(true), m_name(memory.space_config(spacenum)->name()), m_addrchars((m_config.m_addr_width + 3) / 4), m_logaddrchars((m_config.m_logaddr_width + 3) / 4), + m_notifier_id(0), + m_in_notification(0), m_manager(manager) { - switch(m_config.data_width()) { - case 8: - if(m_config.endianness() == ENDIANNESS_LITTLE) - cache_init<0, 0, ENDIANNESS_LITTLE>(); - else - cache_init<0, 0, ENDIANNESS_BIG>(); - break; - case 16: - switch(m_config.addr_shift()) { - case 3: - if(m_config.endianness() == ENDIANNESS_LITTLE) - cache_init<1, 3, ENDIANNESS_LITTLE>(); - else - cache_init<1, 3, ENDIANNESS_BIG>(); - break; - case 0: - if(m_config.endianness() == ENDIANNESS_LITTLE) - cache_init<1, 0, ENDIANNESS_LITTLE>(); - else - cache_init<1, 0, ENDIANNESS_BIG>(); - break; - case -1: - if(m_config.endianness() == ENDIANNESS_LITTLE) - cache_init<1, -1, ENDIANNESS_LITTLE>(); - else - cache_init<1, -1, ENDIANNESS_BIG>(); - break; - } - break; - case 32: - switch(m_config.addr_shift()) { - case 0: - if(m_config.endianness() == ENDIANNESS_LITTLE) - cache_init<2, 0, ENDIANNESS_LITTLE>(); - else - cache_init<2, 0, ENDIANNESS_BIG>(); - break; - case -1: - if(m_config.endianness() == ENDIANNESS_LITTLE) - cache_init<2, -1, ENDIANNESS_LITTLE>(); - else - cache_init<2, -1, ENDIANNESS_BIG>(); - break; - case -2: - if(m_config.endianness() == ENDIANNESS_LITTLE) - cache_init<2, -2, ENDIANNESS_LITTLE>(); - else - cache_init<2, -2, ENDIANNESS_BIG>(); - break; - } - break; - case 64: - switch(m_config.addr_shift()) { - case 0: - if(m_config.endianness() == ENDIANNESS_LITTLE) - cache_init<3, 0, ENDIANNESS_LITTLE>(); - else - cache_init<3, 0, ENDIANNESS_BIG>(); - break; - case -1: - if(m_config.endianness() == ENDIANNESS_LITTLE) - cache_init<3, -1, ENDIANNESS_LITTLE>(); - else - cache_init<3, -1, ENDIANNESS_BIG>(); - break; - case -2: - if(m_config.endianness() == ENDIANNESS_LITTLE) - cache_init<3, -2, ENDIANNESS_LITTLE>(); - else - cache_init<3, -2, ENDIANNESS_BIG>(); - break; - case -3: - if(m_config.endianness() == ENDIANNESS_LITTLE) - cache_init<3, -3, ENDIANNESS_LITTLE>(); - else - cache_init<3, -3, ENDIANNESS_BIG>(); - break; - } - break; - } - - m_cache = m_cache_alloc(nullptr); } @@ -1812,21 +913,12 @@ address_space::address_space(memory_manager &manager, device_memory_interface &m address_space::~address_space() { - m_cache_delete(m_cache); -} - - -template void address_space::cache_init() -{ - using dt = memory_access_cache; - m_cache_alloc = [this](void *cache) -> void * { (void)cache; return static_cast(new dt(*this)); }; - m_cache_delete = [](void *cache) { delete static_cast
(cache); }; - m_cache_invalidate_read_caches = [](void *cache) { static_cast
(cache)->force_update(); }; - m_cache_invalidate_read_cache_entry = [](void *cache, u16 entry) { static_cast
(cache)->force_update(entry); }; - m_cache_invalidate_read_cache_range = [](void *cache, offs_t start, offs_t end) { static_cast
(cache)->remove_intersecting_ranges(start, end); }; + m_unmap_r->unref(); + m_unmap_w->unref(); + m_nop_r->unref(); + m_nop_w->unref(); } - //------------------------------------------------- // adjust_addresses - adjust addresses for a // given address space in a standard fashion @@ -2040,7 +1132,12 @@ void address_space::prepare_map() // extract global parameters specified by the map m_unmap = (m_map->m_unmapval == 0) ? 0 : ~0; if (m_map->m_globalmask != 0) + { + if (m_map->m_globalmask & ~m_addrmask) + fatalerror("Can't set a global address mask of %08x on a %d-bits address width bus.\n", m_map->m_globalmask, addr_width()); + m_addrmask = m_map->m_globalmask; + } // make a pass over the address map, adjusting for the device and getting memory pointers for (address_map_entry &entry : m_map->m_entrylist) @@ -2097,10 +1194,6 @@ void address_space::prepare_map() entry.m_memory = m_manager.machine().root_device().memregion(fulltag.c_str())->base() + entry.m_rgnoffs; } } - - // now loop over all the handlers and enforce the address mask - read().mask_all_handlers(m_addrmask); - write().mask_all_handlers(m_addrmask); } @@ -2121,13 +1214,14 @@ void address_space::populate_from_map(address_map *map) return; // install the handlers, using the original, unadjusted memory map - for (const address_map_entry &entry : map->m_entrylist) - { + for (const address_map_entry &entry : map->m_entrylist) { // map both read and write halves populate_map_entry(entry, read_or_write::READ); populate_map_entry(entry, read_or_write::WRITE); - populate_map_entry_setoffset(entry); } + + if(VALIDATE_REFCOUNTS) + validate_reference_counts(); } @@ -2200,16 +1294,6 @@ void address_space::populate_map_entry(const address_map_entry &entry, read_or_w } } -//------------------------------------------------- -// populate_map_entry_setoffset - special case for setoffset -//------------------------------------------------- - -void address_space::populate_map_entry_setoffset(const address_map_entry &entry) -{ - install_setoffset_handler(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, - entry.m_addrmirror, entry.m_addrselect, setoffset_delegate(entry.m_soproto, entry.m_devbase), entry.m_mask); -} - //------------------------------------------------- // allocate_memory - determine all neighboring // address ranges and allocate memory to back @@ -2301,10 +1385,6 @@ void address_space::locate_memory() VPRINTF(("assigned bank '%s' pointer to memory from range %08X-%08X [%p]\n", bank.second->tag(), entry.m_addrstart, entry.m_addrend, entry.m_memory)); break; } - - // if the entry was set ahead of time, override the automatically found pointer - if (!bank.second->anonymous() && bank.second->entry() != BANK_ENTRY_UNSPECIFIED) - bank.second->set_entry(bank.second->entry()); } } @@ -2367,45 +1447,94 @@ address_map_entry *address_space::block_assign_intersecting(offs_t addrstart, of } -//------------------------------------------------- -// get_handler_string - return a string -// describing the handler at a particular offset -//------------------------------------------------- - -const char *address_space::get_handler_string(read_or_write readorwrite, offs_t address) +memory_passthrough_handler *address_space::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) { - if (readorwrite == read_or_write::READ) - return read().handler_name(read().lookup(address)); - else - return write().handler_name(write().lookup(address)); + fatalerror("Trying to install a 8-bits wide bus read tap in a %d-bits wide bus\n", data_width()); } +memory_passthrough_handler *address_space::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) +{ + fatalerror("Trying to install a 16-bits wide bus read tap in a %d-bits wide bus\n", data_width()); +} -//------------------------------------------------- -// dump_map - dump the contents of a single -// address space -//------------------------------------------------- - -void address_space::dump_map(FILE *file, read_or_write readorwrite) +memory_passthrough_handler *address_space::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) { - const address_table &table = (readorwrite == read_or_write::READ) ? static_cast(read()) : static_cast(write()); + fatalerror("Trying to install a 32-bits wide bus read tap in a %d-bits wide bus\n", data_width()); +} - // dump generic information - fprintf(file, " Address bits = %d\n", m_config.m_addr_width); - fprintf(file, " Data bits = %d\n", m_config.m_data_width); - fprintf(file, " Address mask = %X\n", m_addrmask); - fprintf(file, "\n"); +memory_passthrough_handler *address_space::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) +{ + fatalerror("Trying to install a 64-bits wide bus read tap in a %d-bits wide bus\n", data_width()); +} - // iterate over addresses - offs_t addrstart, addrend; - for (offs_t address = 0; address <= m_addrmask; address = addrend) - { - u16 entry = table.derive_range(address, addrstart, addrend); - fprintf(file, "%08X-%08X = %02X: %s [offset=%08X]\n", - addrstart, addrend, entry, table.handler_name(entry), table.handler(entry).addrstart()); - if (++addrend == 0) - break; - } +memory_passthrough_handler *address_space::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) +{ + fatalerror("Trying to install a 8-bits wide bus write tap in a %d-bits wide bus\n", data_width()); +} + +memory_passthrough_handler *address_space::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) +{ + fatalerror("Trying to install a 16-bits wide bus write tap in a %d-bits wide bus\n", data_width()); +} + +memory_passthrough_handler *address_space::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) +{ + fatalerror("Trying to install a 32-bits wide bus write tap in a %d-bits wide bus\n", data_width()); +} + +memory_passthrough_handler *address_space::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) +{ + fatalerror("Trying to install a 64-bits wide bus write tap in a %d-bits wide bus\n", data_width()); +} + +memory_passthrough_handler *address_space::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tapr, std::function tapw, memory_passthrough_handler *mph) +{ + fatalerror("Trying to install a 8-bits wide bus read/write tap in a %d-bits wide bus\n", data_width()); +} + +memory_passthrough_handler *address_space::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tapr, std::function tapw, memory_passthrough_handler *mph) +{ + fatalerror("Trying to install a 16-bits wide bus read/write tap in a %d-bits wide bus\n", data_width()); +} + +memory_passthrough_handler *address_space::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tapr, std::function tap, memory_passthrough_handler *mph) +{ + fatalerror("Tryingw to install a 32-bits wide bus read/write tap in a %d-bits wide bus\n", data_width()); +} + +memory_passthrough_handler *address_space::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tapr, std::function tapw, memory_passthrough_handler *mph) +{ + fatalerror("Trying to install a 64-bits wide bus read/write tap in a %d-bits wide bus\n", data_width()); +} + + + +//------------------------------------------------- +// get_handler_string - return a string +// describing the handler at a particular offset +//------------------------------------------------- + +template std::string address_space_specific::get_handler_string(read_or_write readorwrite, offs_t address) const +{ + if (readorwrite == read_or_write::READ) { + offs_t start, end; + handler_entry_read *handler; + m_root_read->lookup(address, start, end, handler); + return handler->name(); + } else { + offs_t start, end; + handler_entry_write *handler; + m_root_write->lookup(address, start, end, handler); + return handler->name(); + } +} + +template void address_space_specific::dump_maps(std::vector &read_map, std::vector &write_map) const +{ + read_map.clear(); + write_map.clear(); + m_root_read->dump_map(read_map); + m_root_write->dump_map(write_map); } @@ -2417,7 +1546,7 @@ void address_space::dump_map(FILE *file, read_or_write readorwrite) // unmap - unmap a section of address space //------------------------------------------------- -void address_space::unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, bool quiet) +template void address_space_specific::unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, bool quiet) { VPRINTF(("address_space::unmap(%s-%s mirror=%s, %s, %s)\n", core_i64_hex_format(addrstart, m_addrchars), core_i64_hex_format(addrend, m_addrchars), @@ -2429,13 +1558,93 @@ void address_space::unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrm check_optimize_mirror("unmap_generic", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); // read space - if (readorwrite == read_or_write::READ || readorwrite == read_or_write::READWRITE) - read().map_range(nstart, nend, nmask, nmirror, quiet ? STATIC_NOP : STATIC_UNMAP); + if (readorwrite == read_or_write::READ || readorwrite == read_or_write::READWRITE) { + auto handler = static_cast *>(quiet ? m_nop_r : m_unmap_r); + handler->ref(); + m_root_read->populate(nstart, nend, nmirror, handler); + } // write space - if (readorwrite == read_or_write::WRITE || readorwrite == read_or_write::READWRITE) - write().map_range(nstart, nend, nmask, nmirror, quiet ? STATIC_NOP : STATIC_UNMAP); + if (readorwrite == read_or_write::WRITE || readorwrite == read_or_write::READWRITE) { + auto handler = static_cast *>(quiet ? m_nop_w : m_unmap_w); + handler->ref(); + m_root_write->populate(nstart, nend, nmirror, handler); + } + + invalidate_caches(readorwrite); +} + +//------------------------------------------------- +// install_read_tap - install a read tap on the bus +//------------------------------------------------- + +template memory_passthrough_handler *address_space_specific::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) +{ + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("install_read_tap", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + if(!mph) { + m_mphs.emplace_back(std::make_unique(*this)); + mph = m_mphs.back().get(); + } + + auto handler = new handler_entry_read_tap(this, *mph, name, tap); + m_root_read->populate_passthrough(nstart, nend, nmirror, handler); + handler->unref(); + + invalidate_caches(read_or_write::READ); + + return mph; +} + +//------------------------------------------------- +// install_write_tap - install a write tap on the bus +//------------------------------------------------- + +template memory_passthrough_handler *address_space_specific::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) +{ + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("install_write_tap", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + if(!mph) { + m_mphs.emplace_back(std::make_unique(*this)); + mph = m_mphs.back().get(); + } + + auto handler = new handler_entry_write_tap(this, *mph, name, tap); + m_root_write->populate_passthrough(nstart, nend, nmirror, handler); + handler->unref(); + + invalidate_caches(read_or_write::WRITE); + + return mph; } +//------------------------------------------------- +// install_write_tap - install a read and a write tap on the bus +//------------------------------------------------- + +template memory_passthrough_handler *address_space_specific::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tapr, std::function tapw, memory_passthrough_handler *mph) +{ + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("install_readwrite_tap", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + if(!mph) { + m_mphs.emplace_back(std::make_unique(*this)); + mph = m_mphs.back().get(); + } + + auto rhandler = new handler_entry_read_tap (this, *mph, name, tapr); + m_root_read ->populate_passthrough(nstart, nend, nmirror, rhandler); + rhandler->unref(); + + auto whandler = new handler_entry_write_tap(this, *mph, name, tapw); + m_root_write->populate_passthrough(nstart, nend, nmirror, whandler); + whandler->unref(); + + invalidate_caches(read_or_write::READWRITE); + + return mph; +} + + + //------------------------------------------------- @@ -2443,7 +1652,7 @@ void address_space::unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrm // of a live device into this address space //------------------------------------------------- -void address_space::install_device_delegate(offs_t addrstart, offs_t addrend, device_t &device, address_map_constructor &delegate, u64 unitmask, int cswidth) +template void address_space_specific::install_device_delegate(offs_t addrstart, offs_t addrend, device_t &device, address_map_constructor &delegate, u64 unitmask, int cswidth) { check_address("install_device_delegate", addrstart, addrend); address_map map(*this, addrstart, addrend, unitmask, cswidth, m_device, delegate); @@ -2458,7 +1667,7 @@ void address_space::install_device_delegate(offs_t addrstart, offs_t addrend, de // handler into this address space //------------------------------------------------- -void address_space::install_readwrite_port(offs_t addrstart, offs_t addrend, offs_t addrmirror, const char *rtag, const char *wtag) +template void address_space_specific::install_readwrite_port(offs_t addrstart, offs_t addrend, offs_t addrmirror, const char *rtag, const char *wtag) { VPRINTF(("address_space::install_readwrite_port(%s-%s mirror=%s, read=\"%s\" / write=\"%s\")\n", core_i64_hex_format(addrstart, m_addrchars), core_i64_hex_format(addrend, m_addrchars), @@ -2477,7 +1686,8 @@ void address_space::install_readwrite_port(offs_t addrstart, offs_t addrend, off throw emu_fatalerror("Attempted to map non-existent port '%s' for read in space %s of device '%s'\n", rtag, m_name, m_device.tag()); // map the range and set the ioport - read().handler_map_range(nstart, nend, nmask, nmirror).set_ioport(*port); + auto hand_r = new handler_entry_read_ioport(this, port); + m_root_read->populate(nstart, nend, nmirror, hand_r); } if (wtag != nullptr) @@ -2488,11 +1698,11 @@ void address_space::install_readwrite_port(offs_t addrstart, offs_t addrend, off fatalerror("Attempted to map non-existent port '%s' for write in space %s of device '%s'\n", wtag, m_name, m_device.tag()); // map the range and set the ioport - write().handler_map_range(nstart, nend, nmask, nmirror).set_ioport(*port); + auto hand_w = new handler_entry_write_ioport(this, port); + m_root_write->populate(nstart, nend, nmirror, hand_w); } - // update the memory dump - generate_memdump(m_manager.machine()); + invalidate_caches(rtag ? wtag ? read_or_write::READWRITE : read_or_write::READ : read_or_write::WRITE); } @@ -2501,7 +1711,7 @@ void address_space::install_readwrite_port(offs_t addrstart, offs_t addrend, off // mapping to a particular bank //------------------------------------------------- -void address_space::install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, const char *rtag, const char *wtag) +template void address_space_specific::install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, const char *rtag, const char *wtag) { VPRINTF(("address_space::install_readwrite_bank(%s-%s mirror=%s, read=\"%s\" / write=\"%s\")\n", core_i64_hex_format(addrstart, m_addrchars), core_i64_hex_format(addrend, m_addrchars), @@ -2516,7 +1726,10 @@ void address_space::install_bank_generic(offs_t addrstart, offs_t addrend, offs_ { std::string fulltag = device().siblingtag(rtag); memory_bank &bank = bank_find_or_allocate(fulltag.c_str(), addrstart, addrend, addrmirror, read_or_write::READ); - read().map_range(nstart, nend, nmask, nmirror, bank.index()); + + auto hand_r = new handler_entry_read_memory_bank(this, bank); + hand_r->set_address_info(nstart, nmask); + m_root_read->populate(nstart, nend, nmirror, hand_r); } // map the write bank @@ -2524,15 +1737,17 @@ void address_space::install_bank_generic(offs_t addrstart, offs_t addrend, offs_ { std::string fulltag = device().siblingtag(wtag); memory_bank &bank = bank_find_or_allocate(fulltag.c_str(), addrstart, addrend, addrmirror, read_or_write::WRITE); - write().map_range(nstart, nend, nmask, nmirror, bank.index()); + + auto hand_w = new handler_entry_write_memory_bank(this, bank); + hand_w->set_address_info(nstart, nmask); + m_root_write->populate(nstart, nend, nmirror, hand_w); } - // update the memory dump - generate_memdump(m_manager.machine()); + invalidate_caches(rtag ? wtag ? read_or_write::READWRITE : read_or_write::READ : read_or_write::WRITE); } -void address_space::install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_bank *rbank, memory_bank *wbank) +template void address_space_specific::install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_bank *rbank, memory_bank *wbank) { VPRINTF(("address_space::install_readwrite_bank(%s-%s mirror=%s, read=\"%s\" / write=\"%s\")\n", core_i64_hex_format(addrstart, m_addrchars), core_i64_hex_format(addrend, m_addrchars), @@ -2545,17 +1760,20 @@ void address_space::install_bank_generic(offs_t addrstart, offs_t addrend, offs_ // map the read bank if (rbank != nullptr) { - read().map_range(nstart, nend, nmask, nmirror, rbank->index()); + auto hand_r = new handler_entry_read_memory_bank(this, *rbank); + hand_r->set_address_info(nstart, nmask); + m_root_read->populate(nstart, nend, nmirror, hand_r); } // map the write bank if (wbank != nullptr) { - write().map_range(nstart, nend, nmask, nmirror, wbank->index()); + auto hand_w = new handler_entry_write_memory_bank(this, *wbank); + hand_w->set_address_info(nstart, nmask); + m_root_write->populate(nstart, nend, nmirror, hand_w); } - // update the memory dump - generate_memdump(m_manager.machine()); + invalidate_caches(rbank ? wbank ? read_or_write::READWRITE : read_or_write::READ : read_or_write::WRITE); } @@ -2564,7 +1782,7 @@ void address_space::install_bank_generic(offs_t addrstart, offs_t addrend, offs_ // RAM region into the given address space //------------------------------------------------- -void address_space::install_ram_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, void *baseptr) +template void address_space_specific::install_ram_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, void *baseptr) { VPRINTF(("address_space::install_ram_generic(%s-%s mirror=%s, %s, %p)\n", core_i64_hex_format(addrstart, m_addrchars), core_i64_hex_format(addrend, m_addrchars), @@ -2580,7 +1798,6 @@ void address_space::install_ram_generic(offs_t addrstart, offs_t addrend, offs_t { // find a bank and map it memory_bank &bank = bank_find_or_allocate(nullptr, addrstart, addrend, addrmirror, read_or_write::READ); - read().map_range(nstart, nend, nmask, nmirror, bank.index()); // if we are provided a pointer, set it if (baseptr != nullptr) @@ -2603,6 +1820,17 @@ void address_space::install_ram_generic(offs_t addrstart, offs_t addrend, offs_t bank.set_base(block.get()->data()); m_manager.m_blocklist.push_back(std::move(block)); } + + auto hand_r = new handler_entry_read_memory(this); + if (bank.base()) + hand_r->set_base(static_cast(bank.base())); + else { + delayed_ref(hand_r); + bank.add_notifier([this, hand_r](void *base) { hand_r->set_base(static_cast(base)); delayed_unref(hand_r); }); + } + + hand_r->set_address_info(nstart, nmask); + m_root_read->populate(nstart, nend, nmirror, hand_r); } // map for write @@ -2610,7 +1838,6 @@ void address_space::install_ram_generic(offs_t addrstart, offs_t addrend, offs_t { // find a bank and map it memory_bank &bank = bank_find_or_allocate(nullptr, addrstart, addrend, addrmirror, read_or_write::WRITE); - write().map_range(nstart, nend, nmask, nmirror, bank.index()); // if we are provided a pointer, set it if (baseptr != nullptr) @@ -2633,7 +1860,20 @@ void address_space::install_ram_generic(offs_t addrstart, offs_t addrend, offs_t bank.set_base(block.get()->data()); m_manager.m_blocklist.push_back(std::move(block)); } + + auto hand_w = new handler_entry_write_memory(this); + if (bank.base()) + hand_w->set_base(static_cast(bank.base())); + else { + delayed_ref(hand_w); + bank.add_notifier([this, hand_w](void *base) { hand_w->set_base(static_cast(base)); delayed_unref(hand_w); }); + } + + hand_w->set_address_info(nstart, nmask); + m_root_write->populate(nstart, nend, nmirror, hand_w); } + + invalidate_caches(readorwrite); } @@ -2642,42 +1882,19 @@ void address_space::install_ram_generic(offs_t addrstart, offs_t addrend, offs_t // delegate handlers for the space //------------------------------------------------- -void address_space::install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate handler, u64 unitmask, int cswidth) +template void address_space_specific::install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate handler, u64 unitmask, int cswidth) { - VPRINTF(("address_space::install_read_handler(%s-%s mask=%s mirror=%s, %s, %s)\n", - core_i64_hex_format(addrstart, m_addrchars), core_i64_hex_format(addrend, m_addrchars), - core_i64_hex_format(addrmask, m_addrchars), core_i64_hex_format(addrmirror, m_addrchars), - handler.name(), core_i64_hex_format(unitmask, data_width() / 4))); - - offs_t nstart, nend, nmask, nmirror; - u64 nunitmask; - int ncswidth; - check_optimize_all("install_read_handler", 8, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth); - - read().handler_map_range(nstart, nend, nmask, nmirror, nunitmask, ncswidth).set_delegate(handler); - generate_memdump(m_manager.machine()); + install_read_handler_helper<0>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, handler); } -void address_space::install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8_delegate handler, u64 unitmask, int cswidth) +template void address_space_specific::install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8_delegate handler, u64 unitmask, int cswidth) { - VPRINTF(("address_space::install_write_handler(%s-%s mask=%s mirror=%s, %s, %s)\n", - core_i64_hex_format(addrstart, m_addrchars), core_i64_hex_format(addrend, m_addrchars), - core_i64_hex_format(addrmask, m_addrchars), core_i64_hex_format(addrmirror, m_addrchars), - handler.name(), core_i64_hex_format(unitmask, data_width() / 4))); - - offs_t nstart, nend, nmask, nmirror; - u64 nunitmask; - int ncswidth; - check_optimize_all("install_write_handler", 8, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth); - - write().handler_map_range(nstart, nend, nmask, nmirror, nunitmask, ncswidth).set_delegate(handler); - generate_memdump(m_manager.machine()); + install_write_handler_helper<0>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, handler); } -void address_space::install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate rhandler, write8_delegate whandler, u64 unitmask, int cswidth) +template void address_space_specific::install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate rhandler, write8_delegate whandler, u64 unitmask, int cswidth) { - install_read_handler(addrstart, addrend, addrmask, addrmirror, addrselect, rhandler, unitmask, cswidth); - install_write_handler(addrstart, addrend, addrmask, addrmirror, addrselect, whandler, unitmask, cswidth); + install_readwrite_handler_helper<0>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } @@ -2686,30 +1903,19 @@ void address_space::install_readwrite_handler(offs_t addrstart, offs_t addrend, // delegate handlers for the space //------------------------------------------------- -void address_space::install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate handler, u64 unitmask, int cswidth) +template void address_space_specific::install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate handler, u64 unitmask, int cswidth) { - offs_t nstart, nend, nmask, nmirror; - u64 nunitmask; - int ncswidth; - check_optimize_all("install_read_handler", 16, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth); - read().handler_map_range(nstart, nend, nmask, nmirror, nunitmask, ncswidth).set_delegate(handler); - generate_memdump(m_manager.machine()); + install_read_handler_helper<1>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, handler); } -void address_space::install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16_delegate handler, u64 unitmask, int cswidth) +template void address_space_specific::install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16_delegate handler, u64 unitmask, int cswidth) { - offs_t nstart, nend, nmask, nmirror; - u64 nunitmask; - int ncswidth; - check_optimize_all("install_write_handler", 16, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth); - write().handler_map_range(nstart, nend, nmask, nmirror, nunitmask, ncswidth).set_delegate(handler); - generate_memdump(m_manager.machine()); + install_write_handler_helper<1>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, handler); } -void address_space::install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate rhandler, write16_delegate whandler, u64 unitmask, int cswidth) +template void address_space_specific::install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate rhandler, write16_delegate whandler, u64 unitmask, int cswidth) { - install_read_handler(addrstart, addrend, addrmask, addrmirror, addrselect, rhandler, unitmask, cswidth); - install_write_handler(addrstart, addrend, addrmask, addrmirror, addrselect, whandler, unitmask, cswidth); + install_readwrite_handler_helper<1>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } @@ -2718,30 +1924,19 @@ void address_space::install_readwrite_handler(offs_t addrstart, offs_t addrend, // delegate handlers for the space //------------------------------------------------- -void address_space::install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate handler, u64 unitmask, int cswidth) +template void address_space_specific::install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate handler, u64 unitmask, int cswidth) { - offs_t nstart, nend, nmask, nmirror; - u64 nunitmask; - int ncswidth; - check_optimize_all("install_read_handler", 32, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth); - read().handler_map_range(nstart, nend, nmask, nmirror, nunitmask, ncswidth).set_delegate(handler); - generate_memdump(m_manager.machine()); + install_read_handler_helper<2>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, handler); } -void address_space::install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32_delegate handler, u64 unitmask, int cswidth) +template void address_space_specific::install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32_delegate handler, u64 unitmask, int cswidth) { - offs_t nstart, nend, nmask, nmirror; - u64 nunitmask; - int ncswidth; - check_optimize_all("install_write_handler", 32, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth); - write().handler_map_range(nstart, nend, nmask, nmirror, nunitmask, ncswidth).set_delegate(handler); - generate_memdump(m_manager.machine()); + install_write_handler_helper<2>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, handler); } -void address_space::install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate rhandler, write32_delegate whandler, u64 unitmask, int cswidth) +template void address_space_specific::install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate rhandler, write32_delegate whandler, u64 unitmask, int cswidth) { - install_read_handler(addrstart, addrend, addrmask, addrmirror, addrselect, rhandler, unitmask, cswidth); - install_write_handler(addrstart, addrend, addrmask, addrmirror, addrselect, whandler, unitmask, cswidth); + install_readwrite_handler_helper<2>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } @@ -2750,49 +1945,19 @@ void address_space::install_readwrite_handler(offs_t addrstart, offs_t addrend, // delegate handlers for the space //------------------------------------------------- -void address_space::install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate handler, u64 unitmask, int cswidth) -{ - offs_t nstart, nend, nmask, nmirror; - u64 nunitmask; - int ncswidth; - check_optimize_all("install_read_handler", 64, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth); - read().handler_map_range(nstart, nend, nmask, nmirror, nunitmask, ncswidth).set_delegate(handler); - generate_memdump(m_manager.machine()); -} - -void address_space::install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64_delegate handler, u64 unitmask, int cswidth) +template void address_space_specific::install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate handler, u64 unitmask, int cswidth) { - offs_t nstart, nend, nmask, nmirror; - u64 nunitmask; - int ncswidth; - check_optimize_all("install_write_handler", 64, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth); - write().handler_map_range(nstart, nend, nmask, nmirror, nunitmask, ncswidth).set_delegate(handler); - generate_memdump(m_manager.machine()); + install_read_handler_helper<3>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, handler); } -void address_space::install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate rhandler, write64_delegate whandler, u64 unitmask, int cswidth) +template void address_space_specific::install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64_delegate handler, u64 unitmask, int cswidth) { - install_read_handler(addrstart, addrend, addrmask, addrmirror, addrselect, rhandler, unitmask, cswidth); - install_write_handler(addrstart, addrend, addrmask, addrmirror, addrselect, whandler, unitmask, cswidth); + install_write_handler_helper<3>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, handler); } - -//----------------------------------------------------------------------- -// install_setoffset_handler - install set_offset delegate handlers for the space -//----------------------------------------------------------------------- - -void address_space::install_setoffset_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, setoffset_delegate handler, u64 unitmask, int cswidth) +template void address_space_specific::install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate rhandler, write64_delegate whandler, u64 unitmask, int cswidth) { - VPRINTF(("address_space::install_setoffset_handler(%s-%s mask=%s mirror=%s, %s, %s)\n", - core_i64_hex_format(addrstart, m_addrchars), core_i64_hex_format(addrend, m_addrchars), - core_i64_hex_format(addrmask, m_addrchars), core_i64_hex_format(addrmirror, m_addrchars), - handler.name(), core_i64_hex_format(unitmask, data_width() / 4))); - - offs_t nstart, nend, nmask, nmirror; - u64 nunitmask; - int ncswidth; - check_optimize_all("install_setoffset_handler", 8, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth); - setoffset().handler_map_range(nstart, nend, nmask, nmirror, nunitmask, ncswidth).set_delegate(handler); + install_readwrite_handler_helper<3>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } //************************************************************************** @@ -2869,6 +2034,22 @@ bool address_space::needs_backing_store(const address_map_entry &entry) return false; } +int address_space::add_change_notifier(std::function n) +{ + int id = m_notifier_id++; + m_notifiers.emplace_back(notifier_t{ n, id }); + return id; +} + +void address_space::remove_change_notifier(int id) +{ + for(auto i = m_notifiers.begin(); i != m_notifiers.end(); i++) + if(i->m_id == id) { + m_notifiers.erase(i); + return; + } + fatalerror("Unknown notifier id %d, double remove?\n", id); +} //************************************************************************** @@ -2888,39 +2069,11 @@ memory_bank &address_space::bank_find_or_allocate(const char *tag, offs_t addrst adjust_addresses(addrstart, addrend, addrmask, addrmirror); // look up the bank by name, or else by byte range - memory_bank *membank = nullptr; - if (tag != nullptr) { - auto bank = m_manager.banks().find(tag); - if (bank != m_manager.banks().end()) - membank = bank->second.get(); - } - else { - membank = bank_find_anonymous(addrstart, addrend); - } - - // if we don't have a bank yet, find a free one - if (membank == nullptr) - { - // handle failure - int banknum = m_manager.m_banknext++; - if (banknum > STATIC_BANKMAX) - { - if (tag != nullptr) - throw emu_fatalerror("Unable to allocate new bank '%s'", tag); - else - throw emu_fatalerror("Unable to allocate bank for RAM/ROM area %X-%X\n", addrstart, addrend); - } + memory_bank *membank = tag ? m_manager.find(tag) : m_manager.find(*this, addrstart, addrend); - // if no tag, create a unique one - auto bank = std::make_unique(*this, banknum, addrstart, addrend, tag); - std::string temptag; - if (tag == nullptr) { - temptag = string_format("anon_%p", bank.get()); - tag = temptag.c_str(); - } - m_manager.m_banklist.emplace(tag, std::move(bank)); - membank = m_manager.m_banklist.find(tag)->second.get(); - } + // if we don't have a bank yet, create a new one + if (!membank) + membank = m_manager.allocate(*this, addrstart, addrend, tag); // add a reference for this space membank->add_reference(*this, readorwrite); @@ -2928,2280 +2081,311 @@ memory_bank &address_space::bank_find_or_allocate(const char *tag, offs_t addrst } +//************************************************************************** +// CACHE MEMORY RANGES +//************************************************************************** + //------------------------------------------------- -// bank_find_anonymous - try to find an anonymous -// bank matching the given byte range +// memory_access_cache - constructor //------------------------------------------------- -memory_bank *address_space::bank_find_anonymous(offs_t addrstart, offs_t addrend) const -{ - // try to find an exact match - for (auto &bank : m_manager.banks()) - if (bank.second->anonymous() && bank.second->references_space(*this, read_or_write::READWRITE) && bank.second->matches_exactly(addrstart, addrend)) - return bank.second.get(); - // not found - return nullptr; +template memory_access_cache::memory_access_cache(address_space &space, + handler_entry_read *root_read, + handler_entry_write *root_write) + : m_space(space), + m_addrmask(space.addrmask()), + m_addrstart_r(1), + m_addrend_r(0), + m_addrstart_w(1), + m_addrend_w(0), + m_cache_r(nullptr), + m_cache_w(nullptr), + m_root_read(root_read), + m_root_write(root_write) +{ + m_notifier_id = space.add_change_notifier([this](read_or_write mode) { + if(u32(mode) & u32(read_or_write::READ)) { + m_addrend_r = 0; + m_addrstart_r = 1; + m_cache_r = nullptr; + } + if(u32(mode) & u32(read_or_write::WRITE)) { + m_addrend_w = 0; + m_addrstart_w = 1; + m_cache_w = nullptr; + } + }); } + //------------------------------------------------- -// address_space::invalidate_read_caches -- clear -// the read cache (cache) for a specific entry -// or all of them +// ~memory_access_cache - destructor //------------------------------------------------- -void address_space::invalidate_read_caches() +template memory_access_cache::~memory_access_cache() { - m_cache_invalidate_read_caches(m_cache); + m_space.remove_change_notifier(m_notifier_id); } -void address_space::invalidate_read_caches(u16 entry) -{ - m_cache_invalidate_read_cache_entry(m_cache, entry); -} -void address_space::invalidate_read_caches(offs_t start, offs_t end) -{ - m_cache_invalidate_read_cache_range(m_cache, start, end); -} +template class memory_access_cache<0, 0, ENDIANNESS_LITTLE>; +template class memory_access_cache<0, 0, ENDIANNESS_BIG>; +template class memory_access_cache<1, 3, ENDIANNESS_LITTLE>; +template class memory_access_cache<1, 3, ENDIANNESS_BIG>; +template class memory_access_cache<1, 0, ENDIANNESS_LITTLE>; +template class memory_access_cache<1, 0, ENDIANNESS_BIG>; +template class memory_access_cache<1, -1, ENDIANNESS_LITTLE>; +template class memory_access_cache<1, -1, ENDIANNESS_BIG>; +template class memory_access_cache<2, 0, ENDIANNESS_LITTLE>; +template class memory_access_cache<2, 0, ENDIANNESS_BIG>; +template class memory_access_cache<2, -1, ENDIANNESS_LITTLE>; +template class memory_access_cache<2, -1, ENDIANNESS_BIG>; +template class memory_access_cache<2, -2, ENDIANNESS_LITTLE>; +template class memory_access_cache<2, -2, ENDIANNESS_BIG>; +template class memory_access_cache<3, 0, ENDIANNESS_LITTLE>; +template class memory_access_cache<3, 0, ENDIANNESS_BIG>; +template class memory_access_cache<3, -1, ENDIANNESS_LITTLE>; +template class memory_access_cache<3, -1, ENDIANNESS_BIG>; +template class memory_access_cache<3, -2, ENDIANNESS_LITTLE>; +template class memory_access_cache<3, -2, ENDIANNESS_BIG>; +template class memory_access_cache<3, -3, ENDIANNESS_LITTLE>; +template class memory_access_cache<3, -3, ENDIANNESS_BIG>; + //************************************************************************** -// TABLE MANAGEMENT +// MEMORY BLOCK //************************************************************************** //------------------------------------------------- -// address_table - constructor +// memory_block - constructor //------------------------------------------------- -address_table::address_table(address_space &space, bool large) - : m_table(1 << LEVEL1_BITS), +memory_block::memory_block(address_space &space, offs_t addrstart, offs_t addrend, void *memory) + : m_machine(space.m_manager.machine()), m_space(space), - m_large(large), - m_subtable(SUBTABLE_COUNT), - m_subtable_alloc(0) + m_addrstart(addrstart), + m_addrend(addrend), + m_data(reinterpret_cast(memory)) { - m_live_lookup = &m_table[0]; - - // make our static table all watchpoints - if (s_watchpoint_table[0] != STATIC_WATCHPOINT) - for (unsigned int i=0; i != ARRAY_LENGTH(s_watchpoint_table); i++) - s_watchpoint_table[i] = STATIC_WATCHPOINT; - - // initialize everything to unmapped - for (unsigned int i=0; i != 1 << LEVEL1_BITS; i++) - m_table[i] = STATIC_UNMAP; + offs_t const length = space.address_to_byte(addrend + 1 - addrstart); + VPRINTF(("block_allocate('%s',%s,%08X,%08X,%p)\n", space.device().tag(), space.name(), addrstart, addrend, memory)); - // initialize the handlers freelist - for (int i=0; i != SUBTABLE_BASE-STATIC_COUNT-1; i++) - handler_next_free[i] = i+STATIC_COUNT+1; - handler_next_free[SUBTABLE_BASE-STATIC_COUNT-1] = STATIC_INVALID; - handler_free = STATIC_COUNT; + // allocate a block if needed + if (m_data == nullptr) + { + if (length < 4096) + { + m_allocated.resize(length); + memset(&m_allocated[0], 0, length); + m_data = &m_allocated[0]; + } + else + { + m_allocated.resize(length + 0xfff); + memset(&m_allocated[0], 0, length + 0xfff); + m_data = reinterpret_cast((reinterpret_cast(&m_allocated[0]) + 0xfff) & ~0xfff); + } + } - // initialize the handlers refcounts - memset(handler_refcount, 0, sizeof(handler_refcount)); + // register for saving, but only if we're not part of a memory region + if (space.m_manager.region_containing(m_data, length) != nullptr) + VPRINTF(("skipping save of this memory block as it is covered by a memory region\n")); + else + { + int bytes_per_element = space.data_width() / 8; + std::string name = string_format("%08x-%08x", addrstart, addrend); + machine().save().save_memory(&space.device(), "memory", space.device().tag(), space.spacenum(), name.c_str(), m_data, bytes_per_element, (u32)length / bytes_per_element); + } } //------------------------------------------------- -// ~address_table - destructor +// memory_block - destructor //------------------------------------------------- -address_table::~address_table() +memory_block::~memory_block() { } + +//************************************************************************** +// MEMORY BANK +//************************************************************************** + //------------------------------------------------- -// map_range - map a specific entry in the address -// map +// memory_bank - constructor //------------------------------------------------- -void address_table::map_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u16 entry) +memory_bank::memory_bank(address_space &space, int index, offs_t addrstart, offs_t addrend, const char *tag) + : m_machine(space.m_manager.machine()), + m_baseptr(nullptr), + m_anonymous(tag == nullptr), + m_addrstart(addrstart), + m_addrend(addrend), + m_curentry(0) { - // convert addresses to bytes - m_space.adjust_addresses(addrstart, addrend, addrmask, addrmirror); - - // validity checks - assert_always(addrstart <= addrend, "address_table::map_range called with start greater than end"); - assert_always((addrstart & (m_space.alignment() - 1)) == 0, "address_table::map_range called with misaligned start address"); - assert_always((addrend & (m_space.alignment() - 1)) == (m_space.alignment() - 1), "address_table::map_range called with misaligned end address"); - - // configure the entry to our parameters (but not for static non-banked cases) - handler_entry &curentry = handler(entry); - if (entry <= STATIC_BANKMAX || entry >= STATIC_COUNT) - curentry.configure(addrstart, addrend, addrmask, m_space.address_to_byte_end(addrmask)); + // generate an internal tag if we don't have one + if (tag == nullptr) + { + m_tag = string_format("~%d~", index); + m_name = string_format("Internal bank #%d", index); + } + else + { + m_tag = tag; + m_name = string_format("Bank '%s'", tag); + } - // populate it - populate_range_mirrored(addrstart, addrend, addrmirror, entry); + if (!m_anonymous && machine().save().registration_allowed()) + machine().save().save_item(&space.device(), "memory", m_tag.c_str(), 0, NAME(m_curentry)); +} - // recompute any cache access on this space if it is a read modification - m_space.invalidate_read_caches(entry); - // verify_reference_counts(); -} +//------------------------------------------------- +// memory_bank - destructor +//------------------------------------------------- -u16 address_table::get_free_handler() +memory_bank::~memory_bank() { - if (handler_free == STATIC_INVALID) - throw emu_fatalerror("Out of handler entries in address table"); - - u16 handler = handler_free; - handler_free = handler_next_free[handler - STATIC_COUNT]; - return handler; } //------------------------------------------------- -// setup_range - finds an appropriate handler entry -// and requests to populate the address map with -// it +// references_space - walk the list of references +// to find a match against the provided space +// and read/write //------------------------------------------------- -std::list address_table::setup_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 umask) +bool memory_bank::references_space(const address_space &space, read_or_write readorwrite) const { - // Careful, you can't shift by 64 or more - u64 testmask = (1ULL << (m_space.data_width()-1) << 1) - 1; - - if ((umask & testmask) == 0 || (umask & testmask) == testmask || range_simply_masks(addrstart, addrend, addrmask, addrmirror, umask)) - return setup_range_solid(addrstart, addrend, addrmask, addrmirror); - else - return setup_range_masked(addrstart, addrend, addrmask, addrmirror, umask); + for (auto &ref : m_reflist) + if (ref->matches(space, readorwrite)) + return true; + return false; } + //------------------------------------------------- -// range_simply_masks - determine if a handler -// can fully override part of one existing range -// (speeds up mapping in heavily mirrored cases) +// add_reference - add a new reference to the +// given space //------------------------------------------------- -bool address_table::range_simply_masks(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 umask) +void memory_bank::add_reference(address_space &space, read_or_write readorwrite) { - // convert addresses to bytes - m_space.adjust_addresses(addrstart, addrend, addrmask, addrmirror); - - // Validity checks - assert_always(addrstart <= addrend, "address_table::setup_range called with start greater than end"); - assert_always((addrstart & (m_space.alignment() - 1)) == 0, "address_table::setup_range called with misaligned start address"); - assert_always((addrend & (m_space.alignment() - 1)) == (m_space.alignment() - 1), "address_table::setup_range called with misaligned end address"); - - offs_t range_start, range_end; - u16 entry = derive_range(addrstart, range_start, range_end); - - return range_end >= (addrend | addrmirror) && (entry < STATIC_COUNT || handler(entry).overriden_by_mask(umask)); + // if we already have a reference, skip it + if (references_space(space, readorwrite)) + return; + m_reflist.push_back(std::make_unique(space, readorwrite)); } + //------------------------------------------------- -// setup_range_solid - finds an appropriate handler -// entry and requests to populate the address map with -// it. Replace what's there. -//------------------------------------------------- - -std::list address_table::setup_range_solid(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror) -{ - std::list entries; - - // Grab a free entry - u16 entry = get_free_handler(); - - // Add it in the "to be setup" list - entries.push_back(entry); - - // Configure and map it - map_range(addrstart, addrend, addrmask, addrmirror, entry); - - return entries; -} - -//------------------------------------------------- -// setup_range_masked - finds an appropriate handler -// entry and requests to populate the address map with -// it. Handle non-overlapping subunits. -//------------------------------------------------- - -namespace { - struct subrange { - offs_t start, end; - subrange(offs_t _start, offs_t _end) : start(_start), end(_end) {} - }; -} - -std::list address_table::setup_range_masked(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 umask) -{ - std::list entries; - - // convert addresses to bytes - m_space.adjust_addresses(addrstart, addrend, addrmask, addrmirror); - - // Validity checks - assert_always(addrstart <= addrend, "address_table::setup_range called with start greater than end"); - assert_always((addrstart & (m_space.alignment() - 1)) == 0, "address_table::setup_range called with misaligned start address"); - assert_always((addrend & (m_space.alignment() - 1)) == (m_space.alignment() - 1), "address_table::setup_range called with misaligned end address"); - - offs_t bytemask = m_space.address_to_byte_end(addrmask); - - // Scan the memory to see what has to be done - std::list range_override; - std::map > range_partial; - - offs_t base_mirror = 0; - do - { - offs_t base_address = base_mirror | addrstart; - offs_t end_address = base_mirror | addrend; - - do - { - offs_t range_start, range_end; - u16 entry = derive_range(base_address, range_start, range_end); - u32 stop_address = std::min(range_end, end_address); - - if (entry < STATIC_COUNT || handler(entry).overriden_by_mask(umask)) - range_override.push_back(subrange(base_address, stop_address)); - else - range_partial[entry].push_back(subrange(base_address, stop_address)); - - base_address = stop_address + 1; - } - while (base_address != end_address + 1); - - // Efficient method to go to the next range start given a mirroring mask - base_mirror = (base_mirror + 1 + ~addrmirror) & addrmirror; - } - while (base_mirror); - - // Ranges in range_override must be plain replaced by the new handler - if (!range_override.empty()) - { - // Grab a free entry - u16 entry = get_free_handler(); - - // configure the entry to our parameters - handler_entry &curentry = handler(entry); - curentry.configure(addrstart, addrend, addrmask, bytemask); - - // Populate it wherever needed - for (std::list::const_iterator i = range_override.begin(); i != range_override.end(); ++i) - populate_range(i->start, i->end, entry); - - // Add it in the "to be setup" list - entries.push_back(entry); - - // recompute any cache access on this space if it is a read modification - m_space.invalidate_read_caches(entry); - } - - // Ranges in range_partial must be duplicated then partially changed - if (!range_partial.empty()) - { - for (std::map >::const_iterator i = range_partial.begin(); i != range_partial.end(); ++i) - { - // Theorically, if the handler to change matches the - // characteristics of ours, we can directly change it. In - // practice, it's more complex than that because the - // mirroring is not saved, so we're not sure there aren't - // mappings on the handler outside of the zones we're - // supposed to change. So we won't do the obvious - // optimization at this point. - - // Get the original handler - handler_entry *base_entry = &handler(i->first); - - offs_t previous_bytemask = base_entry->bytemask(); - - // Grab a new handler and copy it there - u16 entry = get_free_handler(); - handler_entry &curentry = handler(entry); - curentry.copy(base_entry); - - // Clear the colliding entries - curentry.clear_conflicting_subunits(umask); - - // Reconfigure the base addresses - curentry.configure(addrstart, addrend, addrmask, bytemask); - - // Populate it wherever needed - for (const auto & elem : i->second) - populate_range(elem.start, elem.end, entry); - - curentry.expand_bytemask(previous_bytemask); - - // Add it in the "to be setup" list - entries.push_back(entry); - - // recompute any cache access on this space if it is a read modification - m_space.invalidate_read_caches(entry); - } - } - - // verify_reference_counts(); - return entries; -} - - -//------------------------------------------------- -// verify_reference_counts - check how much of a -// hash we've made of things -//------------------------------------------------- - -void address_table::verify_reference_counts() -{ - int actual_refcounts[SUBTABLE_BASE-STATIC_COUNT]; - memset(actual_refcounts, 0, sizeof(actual_refcounts)); - - bool subtable_seen[TOTAL_MEMORY_BANKS - SUBTABLE_BASE]; - memset(subtable_seen, 0, sizeof(subtable_seen)); - - for (int level1 = 0; level1 != 1 << LEVEL1_BITS; level1++) - { - u16 l1_entry = m_table[level1]; - if (l1_entry >= SUBTABLE_BASE) - { - assert(m_large); - if (subtable_seen[l1_entry - SUBTABLE_BASE]) - continue; - - subtable_seen[l1_entry - SUBTABLE_BASE] = true; - const u16 *subtable = subtable_ptr(l1_entry); - for (int level2 = 0; level2 != 1 << LEVEL2_BITS; level2++) - { - u16 l2_entry = subtable[level2]; - assert(l2_entry < SUBTABLE_BASE); - if (l2_entry >= STATIC_COUNT) - actual_refcounts[l2_entry - STATIC_COUNT]++; - } - } - else if (l1_entry >= STATIC_COUNT) - actual_refcounts[l1_entry - STATIC_COUNT]++; - } - - if (memcmp(actual_refcounts, handler_refcount, sizeof(handler_refcount))) - { - osd_printf_error("Refcount failure:\n"); - for(int i = STATIC_COUNT; i != SUBTABLE_BASE; i++) - osd_printf_error("%02x: %4x .. %4x\n", i, handler_refcount[i-STATIC_COUNT], actual_refcounts[i-STATIC_COUNT]); - throw emu_fatalerror("memory.c: refcounts are fucked.\n"); - } -} - - -//------------------------------------------------- -// populate_range - assign a memory handler to a -// range of addresses -//------------------------------------------------- - -void address_table::populate_range(offs_t addrstart, offs_t addrend, u16 handlerindex) -{ - offs_t l2mask = (1 << level2_bits()) - 1; - offs_t l1start = addrstart >> level2_bits(); - offs_t l2start = addrstart & l2mask; - offs_t l1stop = addrend >> level2_bits(); - offs_t l2stop = addrend & l2mask; - - // sanity check - if (addrstart > addrend) - return; - - // handle the starting edge if it's not on a block boundary - if (l2start != 0) - { - u16 *subtable = subtable_open(l1start); - - // if the start and stop end within the same block, handle that - if (l1start == l1stop) - { - handler_ref(handlerindex, l2stop-l2start+1); - for (int i = l2start; i <= l2stop; i++) - { - handler_unref(subtable[i]); - subtable[i] = handlerindex; - } - subtable_close(l1start); - return; - } - - // otherwise, fill until the end - handler_ref(handlerindex, l2mask - l2start + 1); - for (int i = l2start; i <= l2mask; i++) - { - handler_unref(subtable[i]); - subtable[i] = handlerindex; - } - subtable_close(l1start); - if (l1start != (offs_t)~0) - l1start++; - } - - // handle the trailing edge if it's not on a block boundary - if (l2stop != l2mask) - { - u16 *subtable = subtable_open(l1stop); - - // fill from the beginning - handler_ref(handlerindex, l2stop+1); - for (int i = 0; i <= l2stop; i++) - { - handler_unref(subtable[i]); - subtable[i] = handlerindex; - } - subtable_close(l1stop); - - // if the start and stop end within the same block, handle that - if (l1start == l1stop) - return; - if (l1stop != 0) - l1stop--; - } - - // now fill in the middle tables - handler_ref(handlerindex, l1stop - l1start + 1); - for (offs_t l1index = l1start; l1index <= l1stop; l1index++) - { - u16 subindex = m_table[l1index]; - - // if we have a subtable here, release it - if (subindex >= SUBTABLE_BASE) - subtable_release(subindex); - else - handler_unref(subindex); - m_table[l1index] = handlerindex; - } -} - - -//------------------------------------------------- -// populate_range_mirrored - assign a memory -// handler to a range of addresses including -// mirrors -//------------------------------------------------- - -void address_table::populate_range_mirrored(offs_t addrstart, offs_t addrend, offs_t addrmirror, u16 handlerindex) -{ - // determine the mirror bits - offs_t lmirrorbits = 0; - offs_t lmirrorbit[32]; - for (int bit = 0; bit < level2_bits(); bit++) - if (addrmirror & (1 << bit)) - lmirrorbit[lmirrorbits++] = 1 << bit; - - offs_t hmirrorbits = 0; - offs_t hmirrorbit[32]; - for (int bit = level2_bits(); bit < 32; bit++) - if (addrmirror & (1 << bit)) - hmirrorbit[hmirrorbits++] = 1 << bit; - - // loop over mirrors in the level 2 table - u16 prev_entry = STATIC_INVALID; - int prev_index = 0; - for (offs_t hmirrorcount = 0; hmirrorcount < (1 << hmirrorbits); hmirrorcount++) - { - // compute the base of this mirror - offs_t hmirrorbase = 0; - for (int bit = 0; bit < hmirrorbits; bit++) - if (hmirrorcount & (1 << bit)) - hmirrorbase |= hmirrorbit[bit]; - - // invalidate any intersecting cached ranges - for (offs_t lmirrorcount = 0; lmirrorcount < (1 << lmirrorbits); lmirrorcount++) - { - // compute the base of this mirror - offs_t lmirrorbase = hmirrorbase; - for (int bit = 0; bit < lmirrorbits; bit++) - if (lmirrorcount & (1 << bit)) - lmirrorbase |= lmirrorbit[bit]; - m_space.invalidate_read_caches(addrstart + lmirrorbase, addrend + lmirrorbase); - } - - // if this is not our first time through, and the level 2 entry matches the previous - // level 2 entry, just do a quick map and get out; note that this only works for entries - // which don't span multiple level 1 table entries - int cur_index = level1_index(addrstart + hmirrorbase); - if (cur_index == level1_index(addrend + hmirrorbase)) - { - if (hmirrorcount != 0 && prev_entry == m_table[cur_index]) - { - VPRINTF(("Quick mapping subtable at %08X to match subtable at %08X\n", cur_index << level2_bits(), prev_index << level2_bits())); - - // release the subtable if the old value was a subtable - if (m_table[cur_index] >= SUBTABLE_BASE) - subtable_release(m_table[cur_index]); - else - handler_unref(m_table[cur_index]); - - // reallocate the subtable if the new value is a subtable - if (m_table[prev_index] >= SUBTABLE_BASE) - subtable_realloc(m_table[prev_index]); - else - handler_ref(m_table[prev_index], 1); - - // set the new value and short-circuit the mapping step - m_table[cur_index] = m_table[prev_index]; - continue; - } - prev_index = cur_index; - prev_entry = m_table[cur_index]; - } - - // loop over mirrors in the level 1 table - for (offs_t lmirrorcount = 0; lmirrorcount < (1 << lmirrorbits); lmirrorcount++) - { - // compute the base of this mirror - offs_t lmirrorbase = hmirrorbase; - for (int bit = 0; bit < lmirrorbits; bit++) - if (lmirrorcount & (1 << bit)) - lmirrorbase |= lmirrorbit[bit]; - - // populate the tables - populate_range(addrstart + lmirrorbase, addrend + lmirrorbase, handlerindex); - } - } -} - - -//------------------------------------------------- -// derive_range - look up the entry for a memory -// range, and then compute the extent of that -// range based on the lookup tables -//------------------------------------------------- - -u16 address_table::derive_range(offs_t address, offs_t &addrstart, offs_t &addrend) const -{ - // look up the initial address to get the entry we care about - u16 l1entry; - u16 entry = l1entry = m_table[level1_index(address)]; - if (l1entry >= SUBTABLE_BASE) - entry = m_table[level2_index(l1entry, address)]; - - // use the addrmask of the entry to set minimum and maximum bounds - offs_t minscan, maxscan; - handler(entry).mirrored_start_end(address, minscan, maxscan); - - // first scan backwards to find the start address - u16 curl1entry = l1entry; - u16 curentry = entry; - addrstart = address; - while (1) - { - // if we need to scan the subtable, do it - if (curentry != curl1entry) - { - u32 minindex = level2_index(curl1entry, 0); - u32 index; - - // scan backwards from the current address, until the previous entry doesn't match - for (index = level2_index(curl1entry, addrstart); index > minindex; index--, addrstart -= 1) - if (m_table[index - 1] != entry) - break; - - // if we didn't hit the beginning, then we're finished scanning - if (index != minindex) - break; - } - - // move to the beginning of this L1 entry; stop at the minimum address - addrstart &= ~((1 << level2_bits()) - 1); - if (addrstart <= minscan) - break; - - // look up the entry of the byte at the end of the previous L1 entry; if it doesn't match, stop - curentry = curl1entry = m_table[level1_index(addrstart - 1)]; - if (curl1entry >= SUBTABLE_BASE) - curentry = m_table[level2_index(curl1entry, addrstart - 1)]; - if (curentry != entry) - break; - - // move into the previous entry and resume searching - addrstart -= 1; - } - - // then scan forwards to find the end address - curl1entry = l1entry; - curentry = entry; - addrend = address; - while (1) - { - // if we need to scan the subtable, do it - if (curentry != curl1entry) - { - u32 maxindex = level2_index(curl1entry, ~0); - u32 index; - - // scan forwards from the current address, until the next entry doesn't match - for (index = level2_index(curl1entry, addrend); index < maxindex; index++, addrend += 1) - if (m_table[index + 1] != entry) - break; - - // if we didn't hit the end, then we're finished scanning - if (index != maxindex) - break; - } - - // move to the end of this L1 entry; stop at the maximum address - addrend |= (1 << level2_bits()) - 1; - if (addrend >= maxscan) - break; - - // look up the entry of the byte at the start of the next L1 entry; if it doesn't match, stop - curentry = curl1entry = m_table[level1_index(addrend + 1)]; - if (curl1entry >= SUBTABLE_BASE) - curentry = m_table[level2_index(curl1entry, addrend + 1)]; - if (curentry != entry) - break; - - // move into the next entry and resume searching - addrend += 1; - } - - return entry; -} - - -//------------------------------------------------- -// mask_all_handlers - apply a mask to all -// address handlers -//------------------------------------------------- - -void address_table::mask_all_handlers(offs_t mask) -{ - // we don't loop over map entries because the mask applies to static handlers as well - for (int entrynum = 0; entrynum < ENTRY_COUNT; entrynum++) - handler(entrynum).apply_mask(mask); -} - - - -//************************************************************************** -// SUBTABLE MANAGEMENT -//************************************************************************** - -//------------------------------------------------- -// subtable_alloc - allocate a fresh subtable -// and set its usecount to 1 -//------------------------------------------------- - -u16 address_table::subtable_alloc() -{ - // loop - while (1) - { - // find a subtable with a usecount of 0 - for (u16 subindex = 0; subindex < SUBTABLE_COUNT; subindex++) - if (m_subtable[subindex].m_usecount == 0) - { - // if this is past our allocation budget, allocate some more - if (subindex >= m_subtable_alloc) - { - m_subtable_alloc += SUBTABLE_ALLOC; - u32 newsize = (1 << LEVEL1_BITS) + (m_subtable_alloc << level2_bits()); - - bool was_live = (m_live_lookup == &m_table[0]); - int oldsize = m_table.size(); - m_table.resize(newsize); - memset(&m_table[oldsize], 0, (newsize-oldsize)*sizeof(m_table[0])); - if (was_live) - m_live_lookup = &m_table[0]; - } - // bump the usecount and return - m_subtable[subindex].m_usecount++; - return subindex + SUBTABLE_BASE; - } - - // merge any subtables we can - if (!subtable_merge()) - fatalerror("Ran out of subtables!\n"); - } -} - - -//------------------------------------------------- -// subtable_realloc - increment the usecount on -// a subtable -//------------------------------------------------- - -void address_table::subtable_realloc(u16 subentry) -{ - u16 subindex = subentry - SUBTABLE_BASE; - - // sanity check - if (m_subtable[subindex].m_usecount <= 0) - fatalerror("Called subtable_realloc on a table with a usecount of 0\n"); - - // increment the usecount - m_subtable[subindex].m_usecount++; -} - - -//------------------------------------------------- -// subtable_merge - merge any duplicate -// subtables -//------------------------------------------------- - -int address_table::subtable_merge() -{ - int merged = 0; - u16 subindex; - - VPRINTF(("Merging subtables....\n")); - - // okay, we failed; update all the checksums and merge tables - for (subindex = 0; subindex < SUBTABLE_COUNT; subindex++) - if (!m_subtable[subindex].m_checksum_valid && m_subtable[subindex].m_usecount != 0) - { - u32 *subtable = reinterpret_cast(subtable_ptr(subindex + SUBTABLE_BASE)); - u32 checksum = 0; - - // update the checksum - for (int l2index = 0; l2index < (1 << level2_bits())/4; l2index++) - checksum += subtable[l2index]; - m_subtable[subindex].m_checksum = checksum; - m_subtable[subindex].m_checksum_valid = true; - } - - // see if there's a matching checksum - for (subindex = 0; subindex < SUBTABLE_COUNT; subindex++) - if (m_subtable[subindex].m_usecount != 0) - { - u16 *subtable = subtable_ptr(subindex + SUBTABLE_BASE); - u32 checksum = m_subtable[subindex].m_checksum; - u16 sumindex; - - for (sumindex = subindex + 1; sumindex < SUBTABLE_COUNT; sumindex++) - if (m_subtable[sumindex].m_usecount != 0 && - m_subtable[sumindex].m_checksum == checksum && - !memcmp(subtable, subtable_ptr(sumindex + SUBTABLE_BASE), 2*(1 << level2_bits()))) - { - int l1index; - - VPRINTF(("Merging subtable %d and %d....\n", subindex, sumindex)); - - // find all the entries in the L1 tables that pointed to the old one, and point them to the merged table - for (l1index = 0; l1index <= (0xffffffffUL >> level2_bits()); l1index++) - if (m_table[l1index] == sumindex + SUBTABLE_BASE) - { - subtable_release(sumindex + SUBTABLE_BASE); - subtable_realloc(subindex + SUBTABLE_BASE); - m_table[l1index] = subindex + SUBTABLE_BASE; - merged++; - } - } - } - - return merged; -} - - -//------------------------------------------------- -// subtable_release - decrement the usecount on -// a subtable and free it if we're done -//------------------------------------------------- - -void address_table::subtable_release(u16 subentry) -{ - u16 subindex = subentry - SUBTABLE_BASE; - // sanity check - if (m_subtable[subindex].m_usecount <= 0) - fatalerror("Called subtable_release on a table with a usecount of 0\n"); - - // decrement the usecount and clear the checksum if we're at 0 - // also unref the subhandlers - m_subtable[subindex].m_usecount--; - if (m_subtable[subindex].m_usecount == 0) - { - m_subtable[subindex].m_checksum = 0; - u16 *subtable = subtable_ptr(subentry); - for (int i = 0; i < (1 << LEVEL2_BITS); i++) - handler_unref(subtable[i]); - } -} - - -//------------------------------------------------- -// subtable_open - gain access to a subtable for -// modification -//------------------------------------------------- - -u16 *address_table::subtable_open(offs_t l1index) -{ - u16 subentry = m_table[l1index]; - - // if we don't have a subtable yet, allocate a new one - if (subentry < SUBTABLE_BASE) - { - int size = 1 << level2_bits(); - u16 newentry = subtable_alloc(); - handler_ref(subentry, size-1); - u16 *subptr = subtable_ptr(newentry); - for (int i=0; i 1) - { - u16 newentry = subtable_alloc(); - - // allocate may cause some additional merging -- look up the subentry again - // when we're done; it should still require a split - subentry = m_table[l1index]; - assert(subentry >= SUBTABLE_BASE); - assert(m_subtable[subentry - SUBTABLE_BASE].m_usecount > 1); - - int size = 1 << level2_bits(); - u16 *src = subtable_ptr(subentry); - for(int i=0; i != size; i++) - handler_ref(src[i], 1); - - memcpy(subtable_ptr(newentry), src, 2*size); - subtable_release(subentry); - m_table[l1index] = newentry; - m_subtable[newentry - SUBTABLE_BASE].m_checksum = m_subtable[subentry - SUBTABLE_BASE].m_checksum; - subentry = newentry; - } - - // mark the table dirty - m_subtable[subentry - SUBTABLE_BASE].m_checksum_valid = false; - - // return the pointer to the subtable - return subtable_ptr(subentry); -} - - -//------------------------------------------------- -// subtable_close - stop access to a subtable -//------------------------------------------------- - -void address_table::subtable_close(offs_t l1index) -{ - // defer any merging until we run out of tables -} - - -//------------------------------------------------- -// handler_name - return friendly string -// description of a handler -//------------------------------------------------- - -const char *address_table::handler_name(u16 entry) const -{ - // banks have names - if (entry >= STATIC_BANK1 && entry <= STATIC_BANKMAX) - for (auto &info : m_space.m_manager.banks()) - if (info.second->index() == entry) - return info.second->name(); - - // constant strings for static entries - if (entry == STATIC_INVALID) return "invalid"; - if (entry == STATIC_NOP) return "nop"; - if (entry == STATIC_UNMAP) return "unmapped"; - if (entry == STATIC_WATCHPOINT) return "watchpoint"; - - static char desc[4096]; - handler(entry).description(desc); - if (desc[0]) - return desc; - return "???"; -} - - -//------------------------------------------------- -// address_table_read - constructor -//------------------------------------------------- - -address_table_read::address_table_read(address_space &space, bool large) - : address_table(space, large) -{ - // allocate handlers for each entry, prepopulating the bankptrs for banks - for (int entrynum = 0; entrynum < ARRAY_LENGTH(m_handlers); entrynum++) - { - u8 **bankptr = (entrynum >= STATIC_BANK1 && entrynum <= STATIC_BANKMAX) ? space.m_manager.bank_pointer_addr(entrynum) : nullptr; - m_handlers[entrynum] = std::make_unique(space.data_width(), space.endianness(), bankptr); - } - - // we have to allocate different object types based on the data bus width - switch (space.data_width()) - { - // 8-bit case - case 8: - m_handlers[STATIC_UNMAP]->set_delegate(read8_delegate(FUNC(address_table_read::unmap_r), this)); - m_handlers[STATIC_NOP]->set_delegate(read8_delegate(FUNC(address_table_read::nop_r), this)); - switch (space.addr_shift()) - { - case 0: m_handlers[STATIC_WATCHPOINT]->set_delegate(read8_delegate (&address_table_read::watchpoint_r, "watchpoint_r", this)); break; - default: abort(); - } - break; - - // 16-bit case - case 16: - m_handlers[STATIC_UNMAP]->set_delegate(read16_delegate(FUNC(address_table_read::unmap_r), this)); - m_handlers[STATIC_NOP]->set_delegate(read16_delegate(FUNC(address_table_read::nop_r), this)); - switch (space.addr_shift()) - { - case -1: m_handlers[STATIC_WATCHPOINT]->set_delegate(read16_delegate(&address_table_read::watchpoint_r, "watchpoint_r", this)); break; - case 0: m_handlers[STATIC_WATCHPOINT]->set_delegate(read16_delegate(&address_table_read::watchpoint_r, "watchpoint_r", this)); break; - case 3: m_handlers[STATIC_WATCHPOINT]->set_delegate(read16_delegate(&address_table_read::watchpoint_r, "watchpoint_r", this)); break; - default: abort(); - } - break; - - // 32-bit case - case 32: - m_handlers[STATIC_UNMAP]->set_delegate(read32_delegate(FUNC(address_table_read::unmap_r), this)); - m_handlers[STATIC_NOP]->set_delegate(read32_delegate(FUNC(address_table_read::nop_r), this)); - switch (space.addr_shift()) - { - case -2: m_handlers[STATIC_WATCHPOINT]->set_delegate(read32_delegate(&address_table_read::watchpoint_r, "watchpoint_r", this)); break; - case -1: m_handlers[STATIC_WATCHPOINT]->set_delegate(read32_delegate(&address_table_read::watchpoint_r, "watchpoint_r", this)); break; - case 0: m_handlers[STATIC_WATCHPOINT]->set_delegate(read32_delegate(&address_table_read::watchpoint_r, "watchpoint_r", this)); break; - default: abort(); - } - break; - - // 64-bit case - case 64: - m_handlers[STATIC_UNMAP]->set_delegate(read64_delegate(FUNC(address_table_read::unmap_r), this)); - m_handlers[STATIC_NOP]->set_delegate(read64_delegate(FUNC(address_table_read::nop_r), this)); - switch (space.addr_shift()) - { - case -3: m_handlers[STATIC_WATCHPOINT]->set_delegate(read64_delegate(&address_table_read::watchpoint_r, "watchpoint_r", this)); break; - case -2: m_handlers[STATIC_WATCHPOINT]->set_delegate(read64_delegate(&address_table_read::watchpoint_r, "watchpoint_r", this)); break; - case -1: m_handlers[STATIC_WATCHPOINT]->set_delegate(read64_delegate(&address_table_read::watchpoint_r, "watchpoint_r", this)); break; - case 0: m_handlers[STATIC_WATCHPOINT]->set_delegate(read64_delegate(&address_table_read::watchpoint_r, "watchpoint_r", this)); break; - default: abort(); - } - break; - } - - // reset the byte masks on the special handlers to open up the full address space for proper reporting - m_handlers[STATIC_UNMAP]->configure(0, space.addrmask(), ~0, ~0); - m_handlers[STATIC_NOP]->configure(0, space.addrmask(), ~0, ~0); - m_handlers[STATIC_WATCHPOINT]->configure(0, space.addrmask(), ~0, ~0); -} - - -//------------------------------------------------- -// address_table_read - destructor -//------------------------------------------------- - -address_table_read::~address_table_read() -{ -} - - -//------------------------------------------------- -// handler - return the generic handler entry for -// this index -//------------------------------------------------- - -handler_entry &address_table_read::handler(u32 index) const -{ - assert(index < ARRAY_LENGTH(m_handlers)); - return *m_handlers[index]; -} - - -//------------------------------------------------- -// address_table_write - constructor -//------------------------------------------------- - -address_table_write::address_table_write(address_space &space, bool large) - : address_table(space, large) -{ - // allocate handlers for each entry, prepopulating the bankptrs for banks - for (int entrynum = 0; entrynum < ARRAY_LENGTH(m_handlers); entrynum++) - { - u8 **bankptr = (entrynum >= STATIC_BANK1 && entrynum <= STATIC_BANKMAX) ? space.m_manager.bank_pointer_addr(entrynum) : nullptr; - m_handlers[entrynum] = std::make_unique(space.data_width(), space.endianness(), bankptr); - } - - // we have to allocate different object types based on the data bus width - switch (space.data_width()) - { - // 8-bit case - case 8: - m_handlers[STATIC_UNMAP]->set_delegate(write8_delegate(FUNC(address_table_write::unmap_w), this)); - m_handlers[STATIC_NOP]->set_delegate(write8_delegate(FUNC(address_table_write::nop_w), this)); - switch (space.addr_shift()) - { - case 0: m_handlers[STATIC_WATCHPOINT]->set_delegate(write8_delegate (&address_table_write::watchpoint_w, "watchpoint_w", this)); break; - default: abort(); - } - break; - - // 16-bit case - case 16: - m_handlers[STATIC_UNMAP]->set_delegate(write16_delegate(FUNC(address_table_write::unmap_w), this)); - m_handlers[STATIC_NOP]->set_delegate(write16_delegate(FUNC(address_table_write::nop_w), this)); - switch (space.addr_shift()) - { - case -1: m_handlers[STATIC_WATCHPOINT]->set_delegate(write16_delegate(&address_table_write::watchpoint_w, "watchpoint_w", this)); break; - case 0: m_handlers[STATIC_WATCHPOINT]->set_delegate(write16_delegate(&address_table_write::watchpoint_w, "watchpoint_w", this)); break; - case 3: m_handlers[STATIC_WATCHPOINT]->set_delegate(write16_delegate(&address_table_write::watchpoint_w, "watchpoint_w", this)); break; - default: abort(); - } - break; - - // 32-bit case - case 32: - m_handlers[STATIC_UNMAP]->set_delegate(write32_delegate(FUNC(address_table_write::unmap_w), this)); - m_handlers[STATIC_NOP]->set_delegate(write32_delegate(FUNC(address_table_write::nop_w), this)); - switch (space.addr_shift()) - { - case -2: m_handlers[STATIC_WATCHPOINT]->set_delegate(write32_delegate(&address_table_write::watchpoint_w, "watchpoint_w", this)); break; - case -1: m_handlers[STATIC_WATCHPOINT]->set_delegate(write32_delegate(&address_table_write::watchpoint_w, "watchpoint_w", this)); break; - case 0: m_handlers[STATIC_WATCHPOINT]->set_delegate(write32_delegate(&address_table_write::watchpoint_w, "watchpoint_w", this)); break; - default: abort(); - } - break; - - // 64-bit case - case 64: - m_handlers[STATIC_UNMAP]->set_delegate(write64_delegate(FUNC(address_table_write::unmap_w), this)); - m_handlers[STATIC_NOP]->set_delegate(write64_delegate(FUNC(address_table_write::nop_w), this)); - switch (space.addr_shift()) - { - case -3: m_handlers[STATIC_WATCHPOINT]->set_delegate(write64_delegate(&address_table_write::watchpoint_w, "watchpoint_w", this)); break; - case -2: m_handlers[STATIC_WATCHPOINT]->set_delegate(write64_delegate(&address_table_write::watchpoint_w, "watchpoint_w", this)); break; - case -1: m_handlers[STATIC_WATCHPOINT]->set_delegate(write64_delegate(&address_table_write::watchpoint_w, "watchpoint_w", this)); break; - case 0: m_handlers[STATIC_WATCHPOINT]->set_delegate(write64_delegate(&address_table_write::watchpoint_w, "watchpoint_w", this)); break; - default: abort(); - } - break; - } - - // reset the byte masks on the special handlers to open up the full address space for proper reporting - m_handlers[STATIC_UNMAP]->configure(0, space.addrmask(), ~0, ~0); - m_handlers[STATIC_NOP]->configure(0, space.addrmask(), ~0, ~0); - m_handlers[STATIC_WATCHPOINT]->configure(0, space.addrmask(), ~0, ~0); -} - - -//------------------------------------------------- -// address_table_write - destructor -//------------------------------------------------- - -address_table_write::~address_table_write() -{ -} - - -//------------------------------------------------- -// handler - return the generic handler entry for -// this index -//------------------------------------------------- - -handler_entry &address_table_write::handler(u32 index) const -{ - assert(index < ARRAY_LENGTH(m_handlers)); - return *m_handlers[index]; -} - - - -//************************************************************************** -// CACHE MEMORY RANGES -//************************************************************************** - -//------------------------------------------------- -// memory_access_cache - constructor -//------------------------------------------------- - -template memory_access_cache::memory_access_cache(address_space &space) - : m_space(space), - m_ptr(nullptr), - m_addrmask(space.addrmask()), - m_addrstart(1), - m_addrend(0), - m_entry(STATIC_UNMAP) -{ -} - - -//------------------------------------------------- -// ~memory_access_cache - destructor -//------------------------------------------------- - -template memory_access_cache::~memory_access_cache() -{ -} - - -//------------------------------------------------- -// set_cache_region - called by device cores to -// update the opcode base for the given address -//------------------------------------------------- - -template bool memory_access_cache::set_cache_region(offs_t address) -{ - // find or allocate a matching range - cache_range *range = find_range(address, m_entry); - - // if we don't map to a bank, return false - if (m_entry < STATIC_BANK1 || m_entry > STATIC_BANKMAX) - { - // ensure future updates to land here as well until we get back into a bank - m_addrend = 0; - m_addrstart = 1; - return false; - } - - u8 *base = *m_space.m_manager.bank_pointer_addr(m_entry); - - // compute the adjusted base - offs_t maskedbits = address & ~m_space.addrmask(); - const handler_entry_read &handler = m_space.read().handler_read(m_entry); - m_addrmask = handler.addrmask(); - u32 delta = handler.addrstart() & m_addrmask; - if(AddrShift < 0) - delta = delta << iabs(AddrShift); - else if(AddrShift > 0) - delta = delta >> iabs(AddrShift); - - m_ptr = base - delta; - m_addrstart = maskedbits | range->m_addrstart; - m_addrend = maskedbits | range->m_addrend; - return true; -} - - -//------------------------------------------------- -// find_range - find a byte address in a range -//------------------------------------------------- - -template typename memory_access_cache::cache_range *memory_access_cache::find_range(offs_t address, u16 &entry) -{ - // determine which entry - address &= m_space.m_addrmask; - entry = m_space.read().lookup_live_nowp(address); - - // scan our table - for (auto &range : m_rangelist[entry]) - if (address >= range.m_addrstart && address <= range.m_addrend) - return ⦥ - - // didn't find out; create a new one - cache_range range; - m_space.read().derive_range(address, range.m_addrstart, range.m_addrend); - m_rangelist[entry].push_front(range); - - return &m_rangelist[entry].front(); -} - - -//------------------------------------------------- -// remove_intersecting_ranges - remove all cached -// ranges that intersect the given address range -//------------------------------------------------- - -template void memory_access_cache::remove_intersecting_ranges(offs_t addrstart, offs_t addrend) -{ - // loop over all entries - for (auto & elem : m_rangelist) - { - // loop over all ranges in this entry's list - for (auto range = elem.begin(); range!=elem.end();) - { - // if we intersect, remove - if (addrstart <= range->m_addrend && addrend >= range->m_addrstart) - range = elem.erase(range); - else - range ++; - } - } -} - -template class memory_access_cache<0, 0, ENDIANNESS_LITTLE>; -template class memory_access_cache<0, 0, ENDIANNESS_BIG>; -template class memory_access_cache<1, 3, ENDIANNESS_LITTLE>; -template class memory_access_cache<1, 3, ENDIANNESS_BIG>; -template class memory_access_cache<1, 0, ENDIANNESS_LITTLE>; -template class memory_access_cache<1, 0, ENDIANNESS_BIG>; -template class memory_access_cache<1, -1, ENDIANNESS_LITTLE>; -template class memory_access_cache<1, -1, ENDIANNESS_BIG>; -template class memory_access_cache<2, 0, ENDIANNESS_LITTLE>; -template class memory_access_cache<2, 0, ENDIANNESS_BIG>; -template class memory_access_cache<2, -1, ENDIANNESS_LITTLE>; -template class memory_access_cache<2, -1, ENDIANNESS_BIG>; -template class memory_access_cache<2, -2, ENDIANNESS_LITTLE>; -template class memory_access_cache<2, -2, ENDIANNESS_BIG>; -template class memory_access_cache<3, 0, ENDIANNESS_LITTLE>; -template class memory_access_cache<3, 0, ENDIANNESS_BIG>; -template class memory_access_cache<3, -1, ENDIANNESS_LITTLE>; -template class memory_access_cache<3, -1, ENDIANNESS_BIG>; -template class memory_access_cache<3, -2, ENDIANNESS_LITTLE>; -template class memory_access_cache<3, -2, ENDIANNESS_BIG>; -template class memory_access_cache<3, -3, ENDIANNESS_LITTLE>; -template class memory_access_cache<3, -3, ENDIANNESS_BIG>; - - - -//************************************************************************** -// MEMORY BLOCK -//************************************************************************** - -//------------------------------------------------- -// memory_block - constructor -//------------------------------------------------- - -memory_block::memory_block(address_space &space, offs_t addrstart, offs_t addrend, void *memory) - : m_machine(space.m_manager.machine()), - m_space(space), - m_addrstart(addrstart), - m_addrend(addrend), - m_data(reinterpret_cast(memory)) -{ - offs_t const length = space.address_to_byte(addrend + 1 - addrstart); - VPRINTF(("block_allocate('%s',%s,%08X,%08X,%p)\n", space.device().tag(), space.name(), addrstart, addrend, memory)); - - // allocate a block if needed - if (m_data == nullptr) - { - if (length < 4096) - { - m_allocated.resize(length); - memset(&m_allocated[0], 0, length); - m_data = &m_allocated[0]; - } - else - { - m_allocated.resize(length + 0xfff); - memset(&m_allocated[0], 0, length + 0xfff); - m_data = reinterpret_cast((reinterpret_cast(&m_allocated[0]) + 0xfff) & ~0xfff); - } - } - - // register for saving, but only if we're not part of a memory region - if (space.m_manager.region_containing(m_data, length) != nullptr) - VPRINTF(("skipping save of this memory block as it is covered by a memory region\n")); - else - { - int bytes_per_element = space.data_width() / 8; - std::string name = string_format("%08x-%08x", addrstart, addrend); - machine().save().save_memory(&space.device(), "memory", space.device().tag(), space.spacenum(), name.c_str(), m_data, bytes_per_element, (u32)length / bytes_per_element); - } -} - - -//------------------------------------------------- -// memory_block - destructor -//------------------------------------------------- - -memory_block::~memory_block() -{ -} - - - -//************************************************************************** -// MEMORY BANK -//************************************************************************** - -//------------------------------------------------- -// memory_bank - constructor -//------------------------------------------------- - -memory_bank::memory_bank(address_space &space, int index, offs_t addrstart, offs_t addrend, const char *tag) - : m_machine(space.m_manager.machine()), - m_baseptr(space.m_manager.bank_pointer_addr(index)), - m_index(index), - m_anonymous(tag == nullptr), - m_addrstart(addrstart), - m_addrend(addrend), - m_curentry(BANK_ENTRY_UNSPECIFIED) -{ - // generate an internal tag if we don't have one - if (tag == nullptr) - { - m_tag = string_format("~%d~", index); - m_name = string_format("Internal bank #%d", index); - } - else - { - m_tag.assign(tag); - m_name = string_format("Bank '%s'", tag); - } - - if (!m_anonymous && machine().save().registration_allowed()) - machine().save().save_item(&space.device(), "memory", m_tag.c_str(), 0, NAME(m_curentry)); -} - - -//------------------------------------------------- -// memory_bank - destructor -//------------------------------------------------- - -memory_bank::~memory_bank() -{ -} - - -//------------------------------------------------- -// references_space - walk the list of references -// to find a match against the provided space -// and read/write -//------------------------------------------------- - -bool memory_bank::references_space(const address_space &space, read_or_write readorwrite) const -{ - for (auto &ref : m_reflist) - if (ref->matches(space, readorwrite)) - return true; - return false; -} - - -//------------------------------------------------- -// add_reference - add a new reference to the -// given space -//------------------------------------------------- - -void memory_bank::add_reference(address_space &space, read_or_write readorwrite) -{ - // if we already have a reference, skip it - if (references_space(space, readorwrite)) - return; - m_reflist.push_back(std::make_unique(space, readorwrite)); -} - - -//------------------------------------------------- -// invalidate_references - force updates on all -// referencing address spaces -//------------------------------------------------- - -void memory_bank::invalidate_references() -{ - // invalidate all the cache references to any referenced address spaces - for (auto &ref : m_reflist) - ref->space().invalidate_read_caches(); -} - - -//------------------------------------------------- -// set_base - set the bank base explicitly -//------------------------------------------------- - -void memory_bank::set_base(void *base) -{ - // nullptr is not an option - if (base == nullptr) - throw emu_fatalerror("memory_bank::set_base called nullptr base"); - - // set the base and invalidate any referencing spaces - *m_baseptr = reinterpret_cast(base); - invalidate_references(); -} - - -//------------------------------------------------- -// set_entry - set the base to a pre-configured -// entry -//------------------------------------------------- - -void memory_bank::set_entry(int entrynum) -{ - // validate - if (m_anonymous) - throw emu_fatalerror("memory_bank::set_entry called for anonymous bank"); - if (entrynum < 0 || entrynum >= int(m_entry.size())) - throw emu_fatalerror("memory_bank::set_entry called with out-of-range entry %d", entrynum); - if (m_entry[entrynum].m_ptr == nullptr) - throw emu_fatalerror("memory_bank::set_entry called for bank '%s' with invalid bank entry %d", m_tag.c_str(), entrynum); - - m_curentry = entrynum; - *m_baseptr = m_entry[entrynum].m_ptr; - - // invalidate referencing spaces - invalidate_references(); -} - - -//------------------------------------------------- -// expand_entries - expand the allocated array -// of entries -//------------------------------------------------- - -void memory_bank::expand_entries(int entrynum) -{ - // allocate a new array and copy from the old one; zero out the new entries - int old_size = m_entry.size(); - m_entry.resize(entrynum + 1); - memset(&m_entry[old_size], 0, (entrynum+1-old_size)*sizeof(m_entry[0])); -} - - -//------------------------------------------------- -// configure_entry - configure an entry -//------------------------------------------------- - -void memory_bank::configure_entry(int entrynum, void *base) -{ - // must be positive - if (entrynum < 0) - throw emu_fatalerror("memory_bank::configure_entry called with out-of-range entry %d", entrynum); - - // if we haven't allocated this many entries yet, expand our array - if (entrynum >= int(m_entry.size())) - expand_entries(entrynum); - - // set the entry - m_entry[entrynum].m_ptr = reinterpret_cast(base); - - // if the bank base is not configured, and we're the first entry, set us up - if (*m_baseptr == nullptr && entrynum == 0) - *m_baseptr = m_entry[entrynum].m_ptr; -} - - -//------------------------------------------------- -// configure_entries - configure multiple entries -//------------------------------------------------- - -void memory_bank::configure_entries(int startentry, int numentries, void *base, offs_t stride) -{ - // fill in the requested bank entries (backwards to improve allocation) - for (int entrynum = startentry + numentries - 1; entrynum >= startentry; entrynum--) - configure_entry(entrynum, reinterpret_cast(base) + (entrynum - startentry) * stride); -} - - -//************************************************************************** -// MEMORY REGIONS -//************************************************************************** - -//------------------------------------------------- -// memory_region - constructor -//------------------------------------------------- - -memory_region::memory_region(running_machine &machine, const char *name, u32 length, u8 width, endianness_t endian) - : m_machine(machine), - m_name(name), - m_buffer(length), - m_endianness(endian), - m_bitwidth(width * 8), - m_bytewidth(width) -{ - assert(width == 1 || width == 2 || width == 4 || width == 8); -} - - - -//************************************************************************** -// HANDLER ENTRY -//************************************************************************** - -//------------------------------------------------- -// handler_entry - constructor -//------------------------------------------------- - -handler_entry::handler_entry(u8 width, endianness_t endianness, u8 **rambaseptr) - : m_populated(false), - m_datawidth(width), - m_endianness(endianness), - m_addrstart(0), - m_addrend(0), - m_addrmask(~0), - m_bytemask(~0), - m_rambaseptr(rambaseptr), - m_subunits(0), - m_invsubmask(0) -{ -} - - -//------------------------------------------------- -// ~handler_entry - destructor -//------------------------------------------------- - -handler_entry::~handler_entry() -{ -} - - -//------------------------------------------------- -// copy - copy another handler_entry, but only -// if it is populated and constitutes of one or -// more subunit handlers -//------------------------------------------------- - -void handler_entry::copy(handler_entry *entry) -{ - assert(entry->m_populated); - assert(entry->m_subunits); - assert(!entry->m_rambaseptr); - assert(!m_populated); - - m_populated = true; - m_datawidth = entry->m_datawidth; - m_endianness = entry->m_endianness; - m_addrstart = entry->m_addrstart; - m_addrend = entry->m_addrend; - m_addrmask = entry->m_addrmask; - m_bytemask = entry->m_bytemask; - m_rambaseptr = nullptr; - m_subunits = entry->m_subunits; - memcpy(m_subunit_infos, entry->m_subunit_infos, m_subunits*sizeof(subunit_info)); - m_invsubmask = entry->m_invsubmask; -} - - -//------------------------------------------------- -// reconfigure_subunits - reconfigure the subunits -// to handle a new base address -//------------------------------------------------- -void handler_entry::reconfigure_subunits(offs_t addrstart) -{ - s32 delta = addrstart - m_addrstart; - for (int i=0; i != m_subunits; i++) - m_subunit_infos[i].m_offset += delta / (m_subunit_infos[i].m_size / 8); -} - - -//------------------------------------------------- -// configure_subunits - configure the subunits -// and subshift array to represent the provided -// mask -//------------------------------------------------- - -void handler_entry::configure_subunits(u64 handlermask, int handlerbits, int cswidth, int &start_slot, int &end_slot) -{ - u64 unitmask = (u64(1) << handlerbits) - 1; - u64 selectmask = (u64(1) << cswidth) - 1; - assert(handlermask != 0); - assert(m_datawidth == 64 || (handlermask >> m_datawidth) == 0); - - // compute the maximum possible subunits - int maxunits = m_datawidth / handlerbits; - assert(maxunits > 1); - assert(maxunits <= ARRAY_LENGTH(m_subunit_infos)); - - int granularity = cswidth / handlerbits; - assert(granularity > 0); - - int shift_xor_mask = m_endianness == ENDIANNESS_LITTLE ? 0 : maxunits - 1; - - // walk the handlermask to find out how many we have - int count = 0; - for (u64 scanmask = handlermask; scanmask != 0; scanmask >>= handlerbits) - { - assert((scanmask & unitmask) == 0 || (scanmask & unitmask) == unitmask); - if ((scanmask & unitmask) != 0) - count++; - } - if (count == 0 || count > maxunits) - throw emu_fatalerror("Invalid subunit mask %s for %d-bit handler in %d-bit space", core_i64_hex_format(handlermask, m_datawidth / 4), handlerbits, m_datawidth); - - // make sure that the multiplier is a power of 2 - int multiplier = count; - while ((multiplier & (multiplier-1)) != 0) - multiplier++; - - // fill in the shifts - int cur_offset = 0; - start_slot = m_subunits; - for (int unitnum = 0; unitnum < maxunits; unitnum++) - { - u32 shift = (unitnum^shift_xor_mask) * handlerbits; - if (((handlermask >> shift) & unitmask) != 0) - { - m_subunit_infos[m_subunits].m_addrmask = m_bytemask / (maxunits / multiplier); - m_subunit_infos[m_subunits].m_datamask = unitmask << shift; - m_subunit_infos[m_subunits].m_csmask = selectmask << (((unitnum^shift_xor_mask) & ~(granularity-1)) * handlerbits); - m_subunit_infos[m_subunits].m_offset = cur_offset++; - m_subunit_infos[m_subunits].m_size = handlerbits; - m_subunit_infos[m_subunits].m_shift = shift; - m_subunit_infos[m_subunits].m_multiplier = multiplier; - m_subunits++; - } - } - end_slot = m_subunits; - - // compute the inverse mask - m_invsubmask = 0; - for (int i = 0; i < m_subunits; i++) - m_invsubmask |= unitmask << m_subunit_infos[i].m_shift; - m_invsubmask = ~m_invsubmask; -} - - -//------------------------------------------------- -// clear_conflicting_subunits - clear the subunits -// conflicting with the provided mask -//------------------------------------------------- - -void handler_entry::clear_conflicting_subunits(u64 handlermask) -{ - // A mask of 0 is in fact an alternative way of saying ~0 - if (!handlermask) - { - m_subunits = 0; - return; - } - - // Start by the end to avoid unnecessary memmoves - for (int i=m_subunits-1; i>=0; i--) - if ((handlermask & m_subunit_infos[i].m_datamask) != 0) - { - if (i != m_subunits-1) - memmove (m_subunit_infos+i, m_subunit_infos+i+1, (m_subunits-i-1)*sizeof(m_subunit_infos[0])); - remove_subunit(i); - } - - // Recompute the inverse mask - m_invsubmask = 0; - for (int i = 0; i < m_subunits; i++) - m_invsubmask |= m_subunit_infos[i].m_datamask; - m_invsubmask = ~m_invsubmask; -} - - -//------------------------------------------------- -// overriden_by_mask - check whether a handler with -// the provided mask fully overrides everything -// that's currently present -//------------------------------------------------- - -bool handler_entry::overriden_by_mask(u64 handlermask) const -{ - // A mask of 0 is in fact an alternative way of saying ~0 - if (!handlermask) - return true; - - // If there are no subunits, it's going to override - if (!m_subunits) - return true; - - // Check whether a subunit would be left - for (int i=0; i != m_subunits; i++) - if ((handlermask & m_subunit_infos[i].m_datamask) == 0) - return false; - - return true; -} - - -//------------------------------------------------- -// description - build a printable description -// of the handler -//------------------------------------------------- - -void handler_entry::description(char *buffer) const -{ - if (m_subunits) - { - for (int i=0; i != m_subunits; i++) - { - if (i) - *buffer++ = ' '; - buffer += sprintf (buffer, "%d:%d:%x:%d:%x:%s:%s:%s", - m_subunit_infos[i].m_size, - m_subunit_infos[i].m_shift, - m_subunit_infos[i].m_offset, - m_subunit_infos[i].m_multiplier, - m_subunit_infos[i].m_addrmask, - core_i64_hex_format(m_subunit_infos[i].m_datamask, m_datawidth), - core_i64_hex_format(m_subunit_infos[i].m_csmask, m_datawidth), - subunit_name(i)); - } - } - else - strcpy (buffer, name()); -} - - -//************************************************************************** -// HANDLER ENTRY READ -//************************************************************************** - -//------------------------------------------------- -// copy - copy another handler_entry, but only -// if it is populated and constitutes of one or -// more subunit handlers -//------------------------------------------------- - -void handler_entry_read::copy(handler_entry *entry) -{ - handler_entry::copy(entry); - handler_entry_read *rentry = static_cast(entry); - m_read = rentry->m_read; - for(int i = 0; i < m_subunits; ++i) - { - switch(m_subunit_infos[i].m_size) - { - case 8: - m_subread[i].r8 = rentry->m_subread[i].r8; - break; - case 16: - m_subread[i].r16 = rentry->m_subread[i].r16; - break; - case 32: - m_subread[i].r32 = rentry->m_subread[i].r32; - break; - } - } -} - -//------------------------------------------------- -// name - return the handler name, from the -// appropriately-sized delegate -//------------------------------------------------- - -const char *handler_entry_read::name() const -{ - switch (m_datawidth) - { - case 8: return m_read.r8.name(); - case 16: return m_read.r16.name(); - case 32: return m_read.r32.name(); - case 64: return m_read.r64.name(); - } - return nullptr; -} - -//------------------------------------------------- -// subunit_name - return the handler name, from the -// appropriately-sized delegate of a subunit -//------------------------------------------------- - -const char *handler_entry_read::subunit_name(int entry) const -{ - switch (m_subunit_infos[entry].m_size) - { - case 8: return m_subread[entry].r8.name(); - case 16: return m_subread[entry].r16.name(); - case 32: return m_subread[entry].r32.name(); - case 64: return m_subread[entry].r64.name(); - } - return nullptr; -} - - -//------------------------------------------------- -// remove_subunit - delete a subunit specific -// information and shift up the following ones -//------------------------------------------------- -void handler_entry_read::remove_subunit(int entry) -{ - int moving = m_subunits - entry - 1; - if (moving) - { - memmove(m_subread+entry, m_subread+entry+1, moving*sizeof(m_subread[0])); - } - m_subunits--; -} - - -//------------------------------------------------- -// set_delegate - set an 8-bit delegate, and -// configure a stub if necessary -//------------------------------------------------- - -void handler_entry_read::set_delegate(read8_delegate delegate, u64 umask, int cswidth) -{ - // error if no object - if (!delegate.has_object()) - throw emu_fatalerror("Attempted to install delegate '%s' without a bound object", delegate.name()); - - // make sure this is a valid size - assert(m_datawidth >= 8); - - // if mismatched bus width, configure a stub - if (m_datawidth != 8) - { - int start_slot, end_slot; - configure_subunits(umask, 8, cswidth, start_slot, end_slot); - for (int i=start_slot; i != end_slot; i++) - { - m_subread[i].r8 = delegate; - } - if (m_datawidth == 16) - set_delegate(read16_delegate(&handler_entry_read::read_stub_16, delegate.name(), this)); - else if (m_datawidth == 32) - set_delegate(read32_delegate(&handler_entry_read::read_stub_32, delegate.name(), this)); - else if (m_datawidth == 64) - set_delegate(read64_delegate(&handler_entry_read::read_stub_64, delegate.name(), this)); - } - else - { - m_read.r8 = delegate; - } -} - - -//------------------------------------------------- -// set_delegate - set a 16-bit delegate, and -// configure a stub if necessary +// set_base - set the bank base explicitly //------------------------------------------------- -void handler_entry_read::set_delegate(read16_delegate delegate, u64 umask, int cswidth) +void memory_bank::set_base(void *base) { - // error if no object - if (!delegate.has_object()) - throw emu_fatalerror("Attempted to install delegate '%s' without a bound object", delegate.name()); - - // make sure this is a valid size - assert(m_datawidth >= 16); + // nullptr is not an option + if (base == nullptr) + throw emu_fatalerror("memory_bank::set_base called nullptr base"); - // if mismatched bus width, configure a stub - if (m_datawidth != 16) - { - int start_slot, end_slot; - configure_subunits(umask, 16, cswidth, start_slot, end_slot); - for (int i=start_slot; i != end_slot; i++) - { - m_subread[i].r16 = delegate; - } - if (m_datawidth == 32) - set_delegate(read32_delegate(&handler_entry_read::read_stub_32, delegate.name(), this)); - else if (m_datawidth == 64) - set_delegate(read64_delegate(&handler_entry_read::read_stub_64, delegate.name(), this)); - } - else - { - m_read.r16 = delegate; + // set the base + if(m_entries.empty()) { + m_entries.resize(1); + m_curentry = 0; } + m_baseptr = m_entries[m_curentry] = reinterpret_cast(base); + for(auto cb : m_alloc_notifier) + cb(base); + m_alloc_notifier.clear(); } //------------------------------------------------- -// set_delegate - set a 32-bit delegate, and -// configure a stub if necessary +// add_notifier - add a function used to notify when the allocation is done //------------------------------------------------- - -void handler_entry_read::set_delegate(read32_delegate delegate, u64 umask, int cswidth) +void memory_bank::add_notifier(std::function cb) { - // error if no object - if (!delegate.has_object()) - throw emu_fatalerror("Attempted to install delegate '%s' without a bound object", delegate.name()); - - // make sure this is a valid size - assert(m_datawidth >= 32); - - // if mismatched bus width, configure a stub - if (m_datawidth != 32) - { - int start_slot, end_slot; - configure_subunits(umask, 32, cswidth, start_slot, end_slot); - for (int i=start_slot; i != end_slot; i++) - { - m_subread[i].r32 = delegate; - } - if (m_datawidth == 64) - set_delegate(read64_delegate(&handler_entry_read::read_stub_64, delegate.name(), this)); - } - else - { - m_read.r32 = delegate; - } + m_alloc_notifier.emplace_back(cb); } - //------------------------------------------------- -// set_delegate - set a 64-bit delegate +// set_entry - set the base to a pre-configured +// entry //------------------------------------------------- -void handler_entry_read::set_delegate(read64_delegate delegate, u64 umask, int cswidth) +void memory_bank::set_entry(int entrynum) { - // error if no object - if (!delegate.has_object()) - throw emu_fatalerror("Attempted to install delegate '%s' without a bound object", delegate.name()); + // validate + if (m_anonymous) + throw emu_fatalerror("memory_bank::set_entry called for anonymous bank"); + if (entrynum < 0 || entrynum >= int(m_entries.size())) + throw emu_fatalerror("memory_bank::set_entry called with out-of-range entry %d", entrynum); + if (m_entries[entrynum] == nullptr) + throw emu_fatalerror("memory_bank::set_entry called for bank '%s' with invalid bank entry %d", m_tag.c_str(), entrynum); - // make sure this is a valid size - assert(m_datawidth >= 64); - m_read.r64 = delegate; + m_curentry = entrynum; + m_baseptr = m_entries[entrynum]; } //------------------------------------------------- -// set_ioport - configure an I/O port read stub -// of the appropriate size +// configure_entry - configure an entry //------------------------------------------------- -void handler_entry_read::set_ioport(ioport_port &ioport) +void memory_bank::configure_entry(int entrynum, void *base) { - m_ioport = &ioport; - if (m_datawidth == 8) - set_delegate(read8_delegate(&handler_entry_read::read_stub_ioport, ioport.tag(), this)); - else if (m_datawidth == 16) - set_delegate(read16_delegate(&handler_entry_read::read_stub_ioport, ioport.tag(), this)); - else if (m_datawidth == 32) - set_delegate(read32_delegate(&handler_entry_read::read_stub_ioport, ioport.tag(), this)); - else if (m_datawidth == 64) - set_delegate(read64_delegate(&handler_entry_read::read_stub_ioport, ioport.tag(), this)); -} + // must be positive + if (entrynum < 0) + throw emu_fatalerror("memory_bank::configure_entry called with out-of-range entry %d", entrynum); + // if we haven't allocated this many entries yet, expand our array + if (entrynum >= int(m_entries.size())) + m_entries.resize(entrynum+1); -//------------------------------------------------- -// read_stub_16 - construct a 16-bit read from -// 8-bit sources -//------------------------------------------------- + // set the entry + m_entries[entrynum] = reinterpret_cast(base); -u16 handler_entry_read::read_stub_16(address_space &space, offs_t offset, u16 mask) -{ - u16 result = space.unmap() & m_invsubmask; - for (int index = 0; index < m_subunits; index++) - { - const subunit_info &si = m_subunit_infos[index]; - if (mask & si.m_csmask) - { - offs_t aoffset = offset * si.m_multiplier + si.m_offset; - u8 val; - val = m_subread[index].r8(space, aoffset & si.m_addrmask, mask >> si.m_shift); - result |= val << si.m_shift; - } - } - return result; + // if the bank base is not configured, and we're the first entry, set us up + if (!m_baseptr && !entrynum) + m_baseptr = m_entries[0]; } //------------------------------------------------- -// read_stub_32 - construct a 32-bit read from -// 8-bit and 16-bit sources +// configure_entries - configure multiple entries //------------------------------------------------- -u32 handler_entry_read::read_stub_32(address_space &space, offs_t offset, u32 mask) +void memory_bank::configure_entries(int startentry, int numentries, void *base, offs_t stride) { - u32 result = space.unmap() & m_invsubmask; - for (int index = 0; index < m_subunits; index++) - { - const subunit_info &si = m_subunit_infos[index]; - if (mask & si.m_csmask) - { - offs_t aoffset = offset * si.m_multiplier + si.m_offset; - u16 val = 0; - switch (si.m_size) - { - case 8: - val = m_subread[index].r8(space, aoffset & si.m_addrmask, mask >> si.m_shift); - break; - case 16: - val = m_subread[index].r16(space, aoffset & si.m_addrmask, mask >> si.m_shift); - break; - } - result |= val << si.m_shift; - } - } - return result; -} - - -//------------------------------------------------- -// read_stub_64 - construct a 64-bit read from -// 8-bit, 16-bit and 32-bit sources -//------------------------------------------------- + if (startentry + numentries >= int(m_entries.size())) + m_entries.resize(startentry + numentries+1); -u64 handler_entry_read::read_stub_64(address_space &space, offs_t offset, u64 mask) -{ - u64 result = space.unmap() & m_invsubmask; - for (int index = 0; index < m_subunits; index++) - { - const subunit_info &si = m_subunit_infos[index]; - if (mask & si.m_csmask) - { - offs_t aoffset = offset * si.m_multiplier + si.m_offset; - u32 val = 0; - switch (si.m_size) - { - case 8: - val = m_subread[index].r8(space, aoffset & si.m_addrmask, mask >> si.m_shift); - break; - case 16: - val = m_subread[index].r16(space, aoffset & si.m_addrmask, mask >> si.m_shift); - break; - case 32: - val = m_subread[index].r32(space, aoffset & si.m_addrmask, mask >> si.m_shift); - break; - } - result |= u64(val) << si.m_shift; - } - } - return result; + // fill in the requested bank entries + for (int entrynum = 0; entrynum < numentries; entrynum ++) + m_entries[entrynum + startentry] = reinterpret_cast(base) + entrynum * stride ; + if(!m_baseptr && !startentry) + m_baseptr = reinterpret_cast(base); } //************************************************************************** -// HANDLER ENTRY WRITE +// MEMORY REGIONS //************************************************************************** //------------------------------------------------- -// copy - copy another handler_entry, but only -// if it is populated and constitutes of one or -// more subunit handlers -//------------------------------------------------- - -void handler_entry_write::copy(handler_entry *entry) -{ - handler_entry::copy(entry); - handler_entry_write *wentry = static_cast(entry); - m_write = wentry->m_write; - for(int i = 0; i < m_subunits; ++i) - { - switch(m_subunit_infos[i].m_size) - { - case 8: - m_subwrite[i].w8 = wentry->m_subwrite[i].w8; - break; - case 16: - m_subwrite[i].w16 = wentry->m_subwrite[i].w16; - break; - case 32: - m_subwrite[i].w32 = wentry->m_subwrite[i].w32; - break; - } - } -} - -//------------------------------------------------- -// name - return the handler name, from the -// appropriately-sized delegate -//------------------------------------------------- - -const char *handler_entry_write::name() const -{ - switch (m_datawidth) - { - case 8: return m_write.w8.name(); - case 16: return m_write.w16.name(); - case 32: return m_write.w32.name(); - case 64: return m_write.w64.name(); - } - return nullptr; -} - - -//------------------------------------------------- -// subunit_name - return the handler name, from the -// appropriately-sized delegate of a subunit -//------------------------------------------------- - -const char *handler_entry_write::subunit_name(int entry) const -{ - switch (m_subunit_infos[entry].m_size) - { - case 8: return m_subwrite[entry].w8.name(); - case 16: return m_subwrite[entry].w16.name(); - case 32: return m_subwrite[entry].w32.name(); - case 64: return m_subwrite[entry].w64.name(); - } - return nullptr; -} - - -//------------------------------------------------- -// remove_subunit - delete a subunit specific -// information and shift up the following ones -//------------------------------------------------- -void handler_entry_write::remove_subunit(int entry) -{ - int moving = m_subunits - entry - 1; - if (moving) - { - memmove(m_subwrite+entry, m_subwrite+entry+1, moving*sizeof(m_subwrite[0])); - } - m_subunits--; -} - - -//------------------------------------------------- -// set_delegate - set an 8-bit delegate, and -// configure a stub if necessary -//------------------------------------------------- - -void handler_entry_write::set_delegate(write8_delegate delegate, u64 umask, int cswidth) -{ - assert(m_datawidth >= 8); - - // if mismatched bus width, configure a stub - if (m_datawidth != 8) - { - int start_slot, end_slot; - configure_subunits(umask, 8, cswidth, start_slot, end_slot); - for (int i=start_slot; i != end_slot; i++) - { - m_subwrite[i].w8 = delegate; - } - if (m_datawidth == 16) - set_delegate(write16_delegate(&handler_entry_write::write_stub_16, delegate.name(), this)); - else if (m_datawidth == 32) - set_delegate(write32_delegate(&handler_entry_write::write_stub_32, delegate.name(), this)); - else if (m_datawidth == 64) - set_delegate(write64_delegate(&handler_entry_write::write_stub_64, delegate.name(), this)); - } - else - { - m_write.w8 = delegate; - } -} - - -//------------------------------------------------- -// set_delegate - set a 16-bit delegate, and -// configure a stub if necessary -//------------------------------------------------- - -void handler_entry_write::set_delegate(write16_delegate delegate, u64 umask, int cswidth) -{ - assert(m_datawidth >= 16); - - // if mismatched bus width, configure a stub - if (m_datawidth != 16) - { - int start_slot, end_slot; - configure_subunits(umask, 16, cswidth, start_slot, end_slot); - for (int i=start_slot; i != end_slot; i++) - { - m_subwrite[i].w16 = delegate; - } - if (m_datawidth == 32) - set_delegate(write32_delegate(&handler_entry_write::write_stub_32, delegate.name(), this)); - else if (m_datawidth == 64) - set_delegate(write64_delegate(&handler_entry_write::write_stub_64, delegate.name(), this)); - } - else - { - m_write.w16 = delegate; - } -} - - -//------------------------------------------------- -// set_delegate - set a 32-bit delegate, and -// configure a stub if necessary -//------------------------------------------------- - -void handler_entry_write::set_delegate(write32_delegate delegate, u64 umask, int cswidth) -{ - assert(m_datawidth >= 32); - - // if mismatched bus width, configure a stub - if (m_datawidth != 32) - { - int start_slot, end_slot; - configure_subunits(umask, 32, cswidth, start_slot, end_slot); - for (int i=start_slot; i != end_slot; i++) - { - m_subwrite[i].w32 = delegate; - } - if (m_datawidth == 64) - set_delegate(write64_delegate(&handler_entry_write::write_stub_64, delegate.name(), this)); - } - else - { - m_write.w32 = delegate; - } -} - - -//------------------------------------------------- -// set_delegate - set a 64-bit delegate -//------------------------------------------------- - -void handler_entry_write::set_delegate(write64_delegate delegate, u64 mask, int cswidth) -{ - assert(m_datawidth >= 64); - m_write.w64 = delegate; -} - - -//------------------------------------------------- -// set_ioport - configure an I/O port read stub -// of the appropriate size -//------------------------------------------------- - -void handler_entry_write::set_ioport(ioport_port &ioport) -{ - m_ioport = &ioport; - if (m_datawidth == 8) - set_delegate(write8_delegate(&handler_entry_write::write_stub_ioport, ioport.tag(), this)); - else if (m_datawidth == 16) - set_delegate(write16_delegate(&handler_entry_write::write_stub_ioport, ioport.tag(), this)); - else if (m_datawidth == 32) - set_delegate(write32_delegate(&handler_entry_write::write_stub_ioport, ioport.tag(), this)); - else if (m_datawidth == 64) - set_delegate(write64_delegate(&handler_entry_write::write_stub_ioport, ioport.tag(), this)); -} - - -//------------------------------------------------- -// write_stub_16 - construct a 16-bit write from -// 8-bit sources -//------------------------------------------------- - -void handler_entry_write::write_stub_16(address_space &space, offs_t offset, u16 data, u16 mask) -{ - for (int index = 0; index < m_subunits; index++) - { - const subunit_info &si = m_subunit_infos[index]; - if (mask & si.m_csmask) - { - offs_t aoffset = offset * si.m_multiplier + si.m_offset; - u8 adata = data >> si.m_shift; - u8 amask = mask >> si.m_shift; - m_subwrite[index].w8(space, aoffset & si.m_addrmask, adata, amask); - } - } -} - - -//------------------------------------------------- -// write_stub_32 - construct a 32-bit write from -// 8-bit and 16-bit sources -//------------------------------------------------- - -void handler_entry_write::write_stub_32(address_space &space, offs_t offset, u32 data, u32 mask) -{ - for (int index = 0; index < m_subunits; index++) - { - const subunit_info &si = m_subunit_infos[index]; - if (mask & si.m_csmask) - { - offs_t aoffset = offset * si.m_multiplier + si.m_offset; - u16 adata = data >> si.m_shift; - u16 amask = mask >> si.m_shift; - switch (si.m_size) - { - case 8: - m_subwrite[index].w8(space, aoffset & si.m_addrmask, adata, amask); - break; - case 16: - m_subwrite[index].w16(space, aoffset & si.m_addrmask, adata, amask); - break; - } - } - } -} - - -//------------------------------------------------- -// write_stub_64 - construct a 64-bit write from -// 8-bit, 16-bit and 32-bit sources +// memory_region - constructor //------------------------------------------------- -void handler_entry_write::write_stub_64(address_space &space, offs_t offset, u64 data, u64 mask) +memory_region::memory_region(running_machine &machine, const char *name, u32 length, u8 width, endianness_t endian) + : m_machine(machine), + m_name(name), + m_buffer(length), + m_endianness(endian), + m_bitwidth(width * 8), + m_bytewidth(width) { - for (int index = 0; index < m_subunits; index++) - { - const subunit_info &si = m_subunit_infos[index]; - if (mask & si.m_csmask) - { - offs_t aoffset = offset * si.m_multiplier + si.m_offset; - u32 adata = data >> si.m_shift; - u32 amask = mask >> si.m_shift; - switch (si.m_size) - { - case 8: - m_subwrite[index].w8(space, aoffset & si.m_addrmask, adata, amask); - break; - case 16: - m_subwrite[index].w16(space, aoffset & si.m_addrmask, adata, amask); - break; - case 32: - m_subwrite[index].w32(space, aoffset & si.m_addrmask, adata, amask); - break; - } - } - } + assert(width == 1 || width == 2 || width == 4 || width == 8); } diff --git a/src/emu/emumem.h b/src/emu/emumem.h index 045e4d33a76..e8b286c6e94 100644 --- a/src/emu/emumem.h +++ b/src/emu/emumem.h @@ -33,8 +33,6 @@ using u64 = std::uint64_t; // CONSTANTS //************************************************************************** -enum { TOTAL_MEMORY_BANKS = 512 }; - // address space names for common use constexpr int AS_PROGRAM = 0; // program address space constexpr int AS_DATA = 1; // data address space @@ -55,14 +53,8 @@ enum class read_or_write // TYPE DEFINITIONS //************************************************************************** -// private classes declared in emumem.cpp -class address_table; -class address_table_read; -class address_table_setoffset; -class address_table_write; - // offsets and addresses are 32-bit (for now...) -typedef u32 offs_t; +using offs_t = u32; // address map constructors are delegates that build up an address_map using address_map_constructor = named_delegate; @@ -87,20 +79,26 @@ struct data_accessors void (*write_qword_masked)(address_space &space, offs_t address, u64 data, u64 mask); }; +// a line in the memory structure dump +struct memory_entry { + offs_t start, end; + class handler_entry *entry; +}; + // ======================> read_delegate // declare delegates for each width -typedef device_delegate read8_delegate; -typedef device_delegate read16_delegate; -typedef device_delegate read32_delegate; -typedef device_delegate read64_delegate; +using read8_delegate = device_delegate; +using read16_delegate = device_delegate; +using read32_delegate = device_delegate; +using read64_delegate = device_delegate; // ======================> write_delegate // declare delegates for each width -typedef device_delegate write8_delegate; +typedef device_delegate write8_delegate; typedef device_delegate write16_delegate; typedef device_delegate write32_delegate; typedef device_delegate write64_delegate; @@ -227,18 +225,251 @@ inline write64_delegate make_delegate(T &&func, const char *name, const char *ta } } // namespace emu::detail +// =====================-> Width -> types + +template struct handler_entry_size {}; +template<> struct handler_entry_size<0> { using uX = u8; using READ = read8_delegate; using WRITE = write8_delegate; }; +template<> struct handler_entry_size<1> { using uX = u16; using READ = read16_delegate; using WRITE = write16_delegate; }; +template<> struct handler_entry_size<2> { using uX = u32; using READ = read32_delegate; using WRITE = write32_delegate; }; +template<> struct handler_entry_size<3> { using uX = u64; using READ = read64_delegate; using WRITE = write64_delegate; }; -// ======================> setoffset_delegate -typedef device_delegate setoffset_delegate; +// ======================> memopry_units_descritor forwards declaration -// =====================-> Width -> types -template struct handler_entry_size {}; -template<> struct handler_entry_size<0> { typedef u8 uX; typedef read8_delegate READ; typedef write8_delegate WRITE; }; -template<> struct handler_entry_size<1> { typedef u16 uX; typedef read16_delegate READ; typedef write16_delegate WRITE; }; -template<> struct handler_entry_size<2> { typedef u32 uX; typedef read32_delegate READ; typedef write32_delegate WRITE; }; -template<> struct handler_entry_size<3> { typedef u64 uX; typedef read64_delegate READ; typedef write64_delegate WRITE; }; +template class memory_units_descriptor; + +// =====================-> Address segmentation for the search tree + +static inline constexpr int handler_entry_dispatch_lowbits(int highbits, int width, int ashift) +{ + if(highbits > 48) + return 48; + if(highbits > 32) + return 32; + if(highbits > 14) + return 14; + return width + ashift; +} + + +// =====================-> The root class of all handlers + +// Handlers the refcounting as part of the interface + +class handler_entry +{ + DISABLE_COPYING(handler_entry); + +public: + // Typing flags + static constexpr u32 F_DISPATCH = 0x00000001; // handler that forwards the access to other handlers + static constexpr u32 F_UNITS = 0x00000002; // handler that merges/splits an access among multiple handlers (unitmask support) + static constexpr u32 F_PASSTHROUGH = 0x00000004; // handler that passes through the request to another handler + + // Start/end of range flags + static constexpr u8 START = 1; + static constexpr u8 END = 2; + + // Intermediary structure for reference count checking + class reflist { + public: + void add(const handler_entry *entry); + + void propagate(); + void check(); + + private: + std::unordered_map refcounts; + std::unordered_set seen; + std::unordered_set todo; + }; + + handler_entry(address_space *space, u32 flags) { m_space = space; m_refcount = 1; m_flags = flags; } + virtual ~handler_entry() {} + + inline void ref(int count = 1) const { m_refcount += count; } + inline void unref(int count = 1) const { m_refcount -= count; if(!m_refcount) delete this; } + inline u32 flags() const { return m_flags; } + + inline bool is_dispatch() const { return m_flags & F_DISPATCH; } + inline bool is_units() const { return m_flags & F_UNITS; } + inline bool is_passthrough() const { return m_flags & F_PASSTHROUGH; } + + virtual void dump_map(std::vector &map) const; + + virtual std::string name() const = 0; + virtual void enumerate_references(handler_entry::reflist &refs) const; + u32 get_refcount() const { return m_refcount; } + +protected: + // Address range storage + struct range { + offs_t start; + offs_t end; + + inline void set(offs_t _start, offs_t _end) { + start = _start; + end = _end; + } + + inline void intersect(offs_t _start, offs_t _end) { + if(_start > start) + start = _start; + if(_end < end) + end = _end; + } + }; + + address_space *m_space; + mutable u32 m_refcount; + u32 m_flags; +}; + + +// =====================-> The parent class of all read handlers + +// Provides the populate/read/get_ptr/lookup API + +template class handler_entry_read_passthrough; + +template class handler_entry_read : public handler_entry +{ +public: + using uX = typename handler_entry_size::uX; + + struct mapping { + handler_entry_read *original; + handler_entry_read *patched; + u8 ukey; + }; + + handler_entry_read(address_space *space, u32 flags) : handler_entry(space, flags) {} + ~handler_entry_read() {} + + virtual uX read(offs_t offset, uX mem_mask) = 0; + virtual void *get_ptr(offs_t offset) const; + virtual void lookup(offs_t address, offs_t &start, offs_t &end, handler_entry_read *&handler) const; + + inline void populate(offs_t start, offs_t end, offs_t mirror, handler_entry_read *handler) { + if(mirror) + populate_mirror(start, end, start, end, mirror, handler); + else + populate_nomirror(start, end, start, end, handler); + } + + virtual void populate_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read *handler); + virtual void populate_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_read *handler); + + inline void populate_mismatched(offs_t start, offs_t end, offs_t mirror, const memory_units_descriptor &descriptor) { + std::vector mappings; + if(mirror) + populate_mismatched_mirror(start, end, start, end, mirror, descriptor, mappings); + else + populate_mismatched_nomirror(start, end, start, end, descriptor, START|END, mappings); + } + + virtual void populate_mismatched_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, const memory_units_descriptor &descriptor, u8 rkey, std::vector &mappings); + virtual void populate_mismatched_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, const memory_units_descriptor &descriptor, std::vector &mappings); + inline void populate_passthrough(offs_t start, offs_t end, offs_t mirror, handler_entry_read_passthrough *handler) { + std::vector mappings; + if(mirror) + populate_passthrough_mirror(start, end, start, end, mirror, handler, mappings); + else + populate_passthrough_nomirror(start, end, start, end, handler, mappings); + } + + virtual void populate_passthrough_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read_passthrough *handler, std::vector &mappings); + virtual void populate_passthrough_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_read_passthrough *handler, std::vector &mappings); + + // Remove a set of passthrough handlers, leaving the lower handler in their place + virtual void detach(const std::unordered_set &handlers); +}; + + +// =====================-> The parent class of all write handlers + +// Provides the populate/write/get_ptr/lookup API + +template class handler_entry_write_passthrough; + +template class handler_entry_write : public handler_entry +{ +public: + using uX = typename handler_entry_size::uX; + + struct mapping { + handler_entry_write *original; + handler_entry_write *patched; + u8 ukey; + }; + + handler_entry_write(address_space *space, u32 flags) : handler_entry(space, flags) {} + virtual ~handler_entry_write() {} + + virtual void write(offs_t offset, uX data, uX mem_mask) = 0; + virtual void *get_ptr(offs_t offset) const; + virtual void lookup(offs_t address, offs_t &start, offs_t &end, handler_entry_write *&handler) const; + + inline void populate(offs_t start, offs_t end, offs_t mirror, handler_entry_write *handler) { + if(mirror) + populate_mirror(start, end, start, end, mirror, handler); + else + populate_nomirror(start, end, start, end, handler); + } + + virtual void populate_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_write *handler); + virtual void populate_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_write *handler); + + inline void populate_mismatched(offs_t start, offs_t end, offs_t mirror, const memory_units_descriptor &descriptor) { + std::vector mappings; + if(mirror) + populate_mismatched_mirror(start, end, start, end, mirror, descriptor, mappings); + else + populate_mismatched_nomirror(start, end, start, end, descriptor, START|END, mappings); + } + + virtual void populate_mismatched_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, const memory_units_descriptor &descriptor, u8 rkey, std::vector &mappings); + virtual void populate_mismatched_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, const memory_units_descriptor &descriptor, std::vector &mappings); + + inline void populate_passthrough(offs_t start, offs_t end, offs_t mirror, handler_entry_write_passthrough *handler) { + std::vector mappings; + if(mirror) + populate_passthrough_mirror(start, end, start, end, mirror, handler, mappings); + else + populate_passthrough_nomirror(start, end, start, end, handler, mappings); + } + + virtual void populate_passthrough_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_write_passthrough *handler, std::vector &mappings); + virtual void populate_passthrough_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_write_passthrough *handler, std::vector &mappings); + + // Remove a set of passthrough handlers, leaving the lower handler in their place + virtual void detach(const std::unordered_set &handlers); +}; + +// =====================-> Passthrough handler management structure +class memory_passthrough_handler +{ + template friend class handler_entry_read_passthrough; + template friend class handler_entry_write_passthrough; + +public: + memory_passthrough_handler(address_space &space) : m_space(space) {} + + inline void remove(); + +private: + address_space &m_space; + std::unordered_set m_handlers; + + void add_handler(handler_entry *handler) { m_handlers.insert(handler); } + void remove_handler(handler_entry *handler) { m_handlers.erase(m_handlers.find(handler)); } +}; + +// =====================-> Forward declaration for address_space + +template class handler_entry_read_unmapped; +template class handler_entry_write_unmapped; // ======================> address offset -> byte offset @@ -510,86 +741,87 @@ template class memory_access_cache { - friend class address_table; using NativeType = typename handler_entry_size::uX; static constexpr u32 NATIVE_BYTES = 1 << Width; static constexpr u32 NATIVE_MASK = Width + AddrShift >= 0 ? (1 << (Width + AddrShift)) - 1 : 0; public: - using cache_update_delegate = delegate &, offs_t)>; - - // cache_range is an internal class that is part of a list of start/end ranges - class cache_range - { - public: - // construction - cache_range(): m_addrstart(0),m_addrend(~0) { } - - inline bool operator==(cache_range val) noexcept - { // return true if _Left and _Right identify the same thread - return (m_addrstart == val.m_addrstart) && (m_addrend == val.m_addrend); - } - - // internal state - offs_t m_addrstart; // starting offset of the range - offs_t m_addrend; // ending offset of the range - }; - // construction/destruction - memory_access_cache(address_space &space); + memory_access_cache(address_space &space, + handler_entry_read *root_read, + handler_entry_write *root_write); + ~memory_access_cache(); // getters address_space &space() const { return m_space; } - u8 *ptr() const { return m_ptr; } - // see if an address is within bounds, or attempt to update it if not - bool address_is_valid(offs_t address) { return EXPECTED(address >= m_addrstart && address <= m_addrend) || set_cache_region(address); } + // see if an address is within bounds, update it if not + void check_address_r(offs_t address) { + if(address >= m_addrstart_r && address <= m_addrend_r) + return; + m_root_read->lookup(address, m_addrstart_r, m_addrend_r, m_cache_r); + } - // force a recomputation on the next read - void force_update() { m_addrend = 0; m_addrstart = 1; } - void force_update(u16 if_match) { if (m_entry == if_match) force_update(); } + void check_address_w(offs_t address) { + if(address >= m_addrstart_w && address <= m_addrend_w) + return; + m_root_write->lookup(address, m_addrstart_w, m_addrend_w, m_cache_w); + } // accessor methods void *read_ptr(offs_t address) { - if (address_is_valid(address)) - return &m_ptr[memory_offset_to_byte(address & m_addrmask, AddrShift)]; - return nullptr; + check_address_r(address); + return m_cache_r->get_ptr(address); } - u8 read_byte(offs_t address) { return Width == 0 ? read_native(address & ~NATIVE_MASK) : memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xff); } - u16 read_word(offs_t address) { return Width == 1 ? read_native(address & ~NATIVE_MASK) : memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffff); } - u16 read_word(offs_t address, u16 mask) { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } - u16 read_word_unaligned(offs_t address) { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffff); } - u16 read_word_unaligned(offs_t address, u16 mask) { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } - u32 read_dword(offs_t address) { return Width == 2 ? read_native(address & ~NATIVE_MASK) : memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffff); } - u32 read_dword(offs_t address, u32 mask) { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } - u32 read_dword_unaligned(offs_t address) { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffff); } - u32 read_dword_unaligned(offs_t address, u32 mask) { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } - u64 read_qword(offs_t address) { return Width == 3 ? read_native(address & ~NATIVE_MASK) : memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffffffffffffU); } - u64 read_qword(offs_t address, u64 mask) { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } - u64 read_qword_unaligned(offs_t address) { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffffffffffffU); } - u64 read_qword_unaligned(offs_t address, u64 mask) { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } - - - void remove_intersecting_ranges(offs_t start, offs_t end); + u8 read_byte(offs_t address) { address &= m_addrmask; return Width == 0 ? read_native(address & ~NATIVE_MASK) : memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xff); } + u16 read_word(offs_t address) { address &= m_addrmask; return Width == 1 ? read_native(address & ~NATIVE_MASK) : memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffff); } + u16 read_word(offs_t address, u16 mask) { address &= m_addrmask; return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } + u16 read_word_unaligned(offs_t address) { address &= m_addrmask; return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffff); } + u16 read_word_unaligned(offs_t address, u16 mask) { address &= m_addrmask; return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } + u32 read_dword(offs_t address) { address &= m_addrmask; return Width == 2 ? read_native(address & ~NATIVE_MASK) : memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffff); } + u32 read_dword(offs_t address, u32 mask) { address &= m_addrmask; return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } + u32 read_dword_unaligned(offs_t address) { address &= m_addrmask; return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffff); } + u32 read_dword_unaligned(offs_t address, u32 mask) { address &= m_addrmask; return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } + u64 read_qword(offs_t address) { address &= m_addrmask; return Width == 3 ? read_native(address & ~NATIVE_MASK) : memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffffffffffffU); } + u64 read_qword(offs_t address, u64 mask) { address &= m_addrmask; return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } + u64 read_qword_unaligned(offs_t address) { address &= m_addrmask; return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffffffffffffU); } + u64 read_qword_unaligned(offs_t address, u64 mask) { address &= m_addrmask; return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } + + void write_byte(offs_t address, u8 data) { address &= m_addrmask; if (Width == 0) write_native(address & ~NATIVE_MASK, data); else memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xff); } + void write_word(offs_t address, u16 data) { address &= m_addrmask; if (Width == 1) write_native(address & ~NATIVE_MASK, data); else memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffff); } + void write_word(offs_t address, u16 data, u16 mask) { address &= m_addrmask; memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } + void write_word_unaligned(offs_t address, u16 data) { address &= m_addrmask; memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffff); } + void write_word_unaligned(offs_t address, u16 data, u16 mask) { address &= m_addrmask; memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } + void write_dword(offs_t address, u32 data) { address &= m_addrmask; if (Width == 2) write_native(address & ~NATIVE_MASK, data); else memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffff); } + void write_dword(offs_t address, u32 data, u32 mask) { address &= m_addrmask; memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } + void write_dword_unaligned(offs_t address, u32 data) { address &= m_addrmask; memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffff); } + void write_dword_unaligned(offs_t address, u32 data, u32 mask) { address &= m_addrmask; memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } + void write_qword(offs_t address, u64 data) { address &= m_addrmask; if (Width == 3) write_native(address & ~NATIVE_MASK, data); else memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffffffffffffU); } + void write_qword(offs_t address, u64 data, u64 mask) { address &= m_addrmask; memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } + void write_qword_unaligned(offs_t address, u64 data) { address &= m_addrmask; memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffffffffffffU); } + void write_qword_unaligned(offs_t address, u64 data, u64 mask) { address &= m_addrmask; memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } private: - // internal helpers - bool set_cache_region(offs_t address); - cache_range *find_range(offs_t address, u16 &entry); - - // internal state address_space & m_space; - u8 * m_ptr; // cache access data pointer - offs_t m_addrmask; // address mask - offs_t m_addrstart; // minimum valid address - offs_t m_addrend; // maximum valid address - u16 m_entry; // live entry - std::list m_rangelist[TOTAL_MEMORY_BANKS]; // list of ranges for each entry + + int m_notifier_id; // id to remove the notifier on destruction + + offs_t m_addrmask; // address mask + offs_t m_addrstart_r; // minimum valid address for reading + offs_t m_addrend_r; // maximum valid address for reading + offs_t m_addrstart_w; // minimum valid address for writing + offs_t m_addrend_w; // maximum valid address for writing + handler_entry_read *m_cache_r; // read cache + handler_entry_write *m_cache_w; // write cache + + handler_entry_read *m_root_read; // decode tree roots + handler_entry_write *m_root_write; NativeType read_native(offs_t address, NativeType mask = ~NativeType(0)); + void write_native(offs_t address, NativeType data, NativeType mask = ~NativeType(0)); }; @@ -642,17 +874,20 @@ public: // address_space holds live information about an address space class address_space { - friend class address_table; - friend class address_table_read; - friend class address_table_write; - friend class address_table_setoffset; - template friend class memory_access_cache; friend class memory_bank; friend class memory_block; + template friend class handler_entry_read_unmapped; + template friend class handler_entry_write_unmapped; + template friend class memory_access_cache; + + struct notifier_t { + std::function m_notifier; + int m_id; + }; protected: // construction/destruction - address_space(memory_manager &manager, device_memory_interface &memory, int spacenum, bool large); + address_space(memory_manager &manager, device_memory_interface &memory, int spacenum); public: virtual ~address_space(); @@ -663,7 +898,7 @@ public: int spacenum() const { return m_spacenum; } address_map *map() const { return m_map.get(); } - template memory_access_cache *cache() const { + template memory_access_cache *cache() { if(AddrShift != m_config.addr_shift()) fatalerror("Requesting cache() with address shift %d while the config says %d\n", AddrShift, m_config.addr_shift()); if(8 << Width != m_config.data_width()) @@ -672,9 +907,26 @@ public: fatalerror("Requesting cache() with endianness %s while the config says %s\n", endianness_names[Endian], endianness_names[m_config.endianness()]); - return static_cast *>(m_cache); + return static_cast *>(create_cache()); + } + + int add_change_notifier(std::function n); + void remove_change_notifier(int id); + + void invalidate_caches(read_or_write mode) { + if(!(u32(mode) & ~m_in_notification)) { + u32 old = m_in_notification; + m_in_notification |= u32(mode); + for(const auto &n : m_notifiers) + n.m_notifier(mode); + m_in_notification = old; + } } + virtual void validate_reference_counts() const = 0; + + virtual void remove_passthrough(std::unordered_set &handlers) = 0; + int data_width() const { return m_config.data_width(); } int addr_width() const { return m_config.addr_width(); } int alignment() const { return m_config.alignment(); } @@ -689,23 +941,17 @@ public: u8 logaddrchars() const { return m_logaddrchars; } // debug helpers - const char *get_handler_string(read_or_write readorwrite, offs_t byteaddress); + virtual std::string get_handler_string(read_or_write readorwrite, offs_t byteaddress) const = 0; + virtual void dump_maps(std::vector &read_map, std::vector &write_map) const = 0; bool log_unmap() const { return m_log_unmap; } void set_log_unmap(bool log) { m_log_unmap = log; } - void dump_map(FILE *file, read_or_write readorwrite); - - // watchpoint enablers - virtual void enable_read_watchpoints(bool enable = true) = 0; - virtual void enable_write_watchpoints(bool enable = true) = 0; // general accessors virtual void accessors(data_accessors &accessors) const = 0; - virtual void *get_read_ptr(offs_t address) = 0; - virtual void *get_write_ptr(offs_t address) = 0; + virtual void *get_read_ptr(offs_t address) const = 0; + virtual void *get_write_ptr(offs_t address) const = 0; // read accessors - template inline typename handler_entry_size::uX read_sized(offs_t address, typename handler_entry_size::uX mask); - virtual u8 read_byte(offs_t address) = 0; virtual u16 read_word(offs_t address) = 0; virtual u16 read_word(offs_t address, u16 mask) = 0; @@ -735,9 +981,6 @@ public: virtual void write_qword_unaligned(offs_t address, u64 data) = 0; virtual void write_qword_unaligned(offs_t address, u64 data, u64 mask) = 0; - // Set address. This will invoke setoffset handlers for the respective entries. - virtual void set_address(offs_t address) = 0; - // address-to-byte conversion helpers offs_t address_to_byte(offs_t address) const { return m_config.addr2byte(address); } offs_t address_to_byte_end(offs_t address) const { return m_config.addr2byte_end(address); } @@ -769,7 +1012,7 @@ public: // install ports, banks, RAM (with mirror/mask) void install_read_port(offs_t addrstart, offs_t addrend, offs_t addrmirror, const char *rtag) { install_readwrite_port(addrstart, addrend, addrmirror, rtag, nullptr); } void install_write_port(offs_t addrstart, offs_t addrend, offs_t addrmirror, const char *wtag) { install_readwrite_port(addrstart, addrend, addrmirror, nullptr, wtag); } - void install_readwrite_port(offs_t addrstart, offs_t addrend, offs_t addrmirror, const char *rtag, const char *wtag); + virtual void install_readwrite_port(offs_t addrstart, offs_t addrend, offs_t addrmirror, const char *rtag, const char *wtag) = 0; void install_read_bank(offs_t addrstart, offs_t addrend, offs_t addrmirror, const char *tag) { install_bank_generic(addrstart, addrend, addrmirror, tag, nullptr); } void install_write_bank(offs_t addrstart, offs_t addrend, offs_t addrmirror, const char *tag) { install_bank_generic(addrstart, addrend, addrmirror, nullptr, tag); } void install_readwrite_bank(offs_t addrstart, offs_t addrend, offs_t addrmirror, const char *tag) { install_bank_generic(addrstart, addrend, addrmirror, tag, tag); } @@ -786,11 +1029,36 @@ public: install_device_delegate(addrstart, addrend, device, delegate, unitmask, cswidth); } - void install_device_delegate(offs_t addrstart, offs_t addrend, device_t &device, address_map_constructor &map, u64 unitmask = 0, int cswidth = 0); + virtual void install_device_delegate(offs_t addrstart, offs_t addrend, device_t &device, address_map_constructor &map, u64 unitmask = 0, int cswidth = 0) = 0; + + // install taps without mirroring + memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, std::string name, std::function tap, memory_passthrough_handler *mph = nullptr) { return install_read_tap(addrstart, addrend, 0, name, tap, mph); } + memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, std::string name, std::function tap, memory_passthrough_handler *mph = nullptr) { return install_read_tap(addrstart, addrend, 0, name, tap, mph); } + memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, std::string name, std::function tap, memory_passthrough_handler *mph = nullptr) { return install_read_tap(addrstart, addrend, 0, name, tap, mph); } + memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, std::string name, std::function tap, memory_passthrough_handler *mph = nullptr) { return install_read_tap(addrstart, addrend, 0, name, tap, mph); } + memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, std::string name, std::function tap, memory_passthrough_handler *mph = nullptr) { return install_write_tap(addrstart, addrend, 0, name, tap, mph); } + memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, std::string name, std::function tap, memory_passthrough_handler *mph = nullptr) { return install_write_tap(addrstart, addrend, 0, name, tap, mph); } + memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, std::string name, std::function tap, memory_passthrough_handler *mph = nullptr) { return install_write_tap(addrstart, addrend, 0, name, tap, mph); } + memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, std::string name, std::function tap, memory_passthrough_handler *mph = nullptr) { return install_write_tap(addrstart, addrend, 0, name, tap, mph); } + memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, std::string name, std::function tapr, std::function tapw, memory_passthrough_handler *mph = nullptr) { return install_readwrite_tap(addrstart, addrend, 0, name, tapr, tapw, mph); } + memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, std::string name, std::function tapr, std::function tapw, memory_passthrough_handler *mph = nullptr) { return install_readwrite_tap(addrstart, addrend, 0, name, tapr, tapw, mph); } + memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, std::string name, std::function tapr, std::function tapw, memory_passthrough_handler *mph = nullptr) { return install_readwrite_tap(addrstart, addrend, 0, name, tapr, tapw, mph); } + memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, std::string name, std::function tapr, std::function tapw, memory_passthrough_handler *mph = nullptr) { return install_readwrite_tap(addrstart, addrend, 0, name, tapr, tapw, mph); } + + // install taps with mirroring + virtual memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph = nullptr); + virtual memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph = nullptr); + virtual memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph = nullptr); + virtual memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph = nullptr); + virtual memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph = nullptr); + virtual memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph = nullptr); + virtual memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph = nullptr); + virtual memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph = nullptr); + virtual memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tapr, std::function tapw, memory_passthrough_handler *mph = nullptr); + virtual memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tapr, std::function tapw, memory_passthrough_handler *mph = nullptr); + virtual memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tapr, std::function tapw, memory_passthrough_handler *mph = nullptr); + virtual memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tapr, std::function tapw, memory_passthrough_handler *mph = nullptr); - // install setoffset handler - void install_setoffset_handler(offs_t addrstart, offs_t addrend, setoffset_delegate sohandler, u64 unitmask = 0, int cswidth = 0) { install_setoffset_handler(addrstart, addrend, 0, 0, 0, sohandler, unitmask, cswidth); } - void install_setoffset_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, setoffset_delegate sohandler, u64 unitmask = 0, int cswidth = 0); // install new-style delegate handlers (short form) void install_read_handler(offs_t addrstart, offs_t addrend, read8_delegate rhandler, u64 unitmask = 0, int cswidth = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth); } @@ -807,18 +1075,18 @@ public: void install_readwrite_handler(offs_t addrstart, offs_t addrend, read64_delegate rhandler, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth); } // install new-style delegate handlers (with mirror/mask) - void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate rhandler, u64 unitmask = 0, int cswidth = 0); - void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0); - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate rhandler, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0); - void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate rhandler, u64 unitmask = 0, int cswidth = 0); - void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0); - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate rhandler, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0); - void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate rhandler, u64 unitmask = 0, int cswidth = 0); - void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0); - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate rhandler, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0); - void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate rhandler, u64 unitmask = 0, int cswidth = 0); - void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0); - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate rhandler, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0); + virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate rhandler, u64 unitmask = 0, int cswidth = 0) = 0; + virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0) = 0; + virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate rhandler, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0) = 0; + virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate rhandler, u64 unitmask = 0, int cswidth = 0) = 0; + virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0) = 0; + virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate rhandler, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0) = 0; + virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate rhandler, u64 unitmask = 0, int cswidth = 0) = 0; + virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0) = 0; + virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate rhandler, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0) = 0; + virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate rhandler, u64 unitmask = 0, int cswidth = 0) = 0; + virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0) = 0; + virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate rhandler, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0) = 0; // setup void prepare_map(); @@ -826,33 +1094,27 @@ public: void allocate_memory(); void locate_memory(); - void invalidate_read_caches(); - void invalidate_read_caches(u16 entry); - void invalidate_read_caches(offs_t start, offs_t end); + template handler_entry_read_unmapped *get_unmap_r() const { return static_cast *>(m_unmap_r); } + template handler_entry_write_unmapped *get_unmap_w() const { return static_cast *>(m_unmap_w); } -private: +protected: // internal helpers - virtual address_table_read &read() = 0; - virtual address_table_write &write() = 0; - virtual address_table_setoffset &setoffset() = 0; + virtual void *create_cache() = 0; void populate_map_entry(const address_map_entry &entry, read_or_write readorwrite); - void populate_map_entry_setoffset(const address_map_entry &entry); - void unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, bool quiet); - void install_ram_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, void *baseptr); - void install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, const char *rtag, const char *wtag); - void install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_bank *rbank, memory_bank *wbank); + virtual void unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, bool quiet) = 0; + virtual void install_ram_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, void *baseptr) = 0; + virtual void install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, const char *rtag, const char *wtag) = 0; + virtual void install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_bank *rbank, memory_bank *wbank) = 0; void adjust_addresses(offs_t &start, offs_t &end, offs_t &mask, offs_t &mirror); void *find_backing_memory(offs_t addrstart, offs_t addrend); bool needs_backing_store(const address_map_entry &entry); memory_bank &bank_find_or_allocate(const char *tag, offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite); - memory_bank *bank_find_anonymous(offs_t bytestart, offs_t byteend) const; address_map_entry *block_assign_intersecting(offs_t bytestart, offs_t byteend, u8 *base); void check_optimize_all(const char *function, int width, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, offs_t &nstart, offs_t &nend, offs_t &nmask, offs_t &nmirror, u64 &nunitmask, int &ncswidth); void check_optimize_mirror(const char *function, offs_t addrstart, offs_t addrend, offs_t addrmirror, offs_t &nstart, offs_t &nend, offs_t &nmask, offs_t &nmirror); void check_address(const char *function, offs_t addrstart, offs_t addrend); -protected: // private state const address_space_config &m_config; // configuration of this space device_t & m_device; // reference to the owning device @@ -862,19 +1124,21 @@ protected: u64 m_unmap; // unmapped value int m_spacenum; // address space index bool m_log_unmap; // log unmapped accesses in this space? - void * m_cache; // fast cache-access read info const char * m_name; // friendly name of the address space u8 m_addrchars; // number of characters to use for physical addresses u8 m_logaddrchars; // number of characters to use for logical addresses - std::function m_cache_alloc; - std::function m_cache_delete; - std::function m_cache_invalidate_read_caches; - std::function m_cache_invalidate_read_cache_entry; - std::function m_cache_invalidate_read_cache_range; - template void cache_init(); + handler_entry *m_unmap_r; + handler_entry *m_unmap_w; -private: + handler_entry *m_nop_r; + handler_entry *m_nop_w; + + std::vector> m_mphs; + + std::vector m_notifiers; // notifier list for address map change + int m_notifier_id; // next notifier id + u32 m_in_notification; // notification(s) currently being done memory_manager & m_manager; // reference to the owning manager }; @@ -940,12 +1204,7 @@ class memory_bank // internal state address_space & m_space; // address space that references us read_or_write m_readorwrite; // used for read or write? - }; - // a bank_entry contains a pointer - struct bank_entry - { - u8 * m_ptr; }; public: @@ -955,11 +1214,10 @@ public: // getters running_machine &machine() const { return m_machine; } - int index() const { return m_index; } int entry() const { return m_curentry; } bool anonymous() const { return m_anonymous; } offs_t addrstart() const { return m_addrstart; } - void *base() const { return *m_baseptr; } + void *base() const { return m_baseptr; } const char *tag() const { return m_tag.c_str(); } const char *name() const { return m_name.c_str(); } @@ -980,24 +1238,21 @@ public: void configure_entry(int entrynum, void *base); void configure_entries(int startentry, int numentries, void *base, offs_t stride); void set_entry(int entrynum); + void add_notifier(std::function cb); private: - // internal helpers - void invalidate_references(); - void expand_entries(int entrynum); - // internal state running_machine & m_machine; // need the machine to free our memory - u8 ** m_baseptr; // pointer to our base pointer in the global array - u16 m_index; // array index for this handler + u8 * m_baseptr; // pointer to our current base pointer + std::vector m_entries; // the entries bool m_anonymous; // are we anonymous or explicit? offs_t m_addrstart; // start offset offs_t m_addrend; // end offset int m_curentry; // current entry - std::vector m_entry; // array of entries (dynamically allocated) std::string m_name; // friendly name for this bank std::string m_tag; // tag for this bank - std::vector> m_reflist; // linked list of address spaces referencing this bank + std::vector> m_reflist; // list of address spaces referencing this bank + std::vector> m_alloc_notifier; // list of notifier targets when allocating }; @@ -1085,6 +1340,7 @@ private: class memory_manager { friend class address_space; + template friend class address_space_specific; friend memory_region::memory_region(running_machine &machine, const char *name, u32 length, u8 width, endianness_t endian); public: // construction/destruction @@ -1097,32 +1353,26 @@ public: const std::unordered_map> ®ions() const { return m_regionlist; } const std::unordered_map> &shares() const { return m_sharelist; } - // pointers to a bank pointer (internal usage only) - u8 **bank_pointer_addr(u8 index) { return &m_bank_ptr[index]; } - // regions memory_region *region_alloc(const char *name, u32 length, u8 width, endianness_t endian); void region_free(const char *name); memory_region *region_containing(const void *memory, offs_t bytes) const; + memory_bank *find(const char *tag) const; + memory_bank *find(address_space &space, offs_t addrstart, offs_t addrend) const; + memory_bank *allocate(address_space &space, offs_t addrstart, offs_t addrend, const char *tag = nullptr); + private: - // internal helpers - void bank_reattach(); void allocate(device_memory_interface &memory); // internal state running_machine & m_machine; // reference to the machine bool m_initialized; // have we completed initialization? - u8 * m_bank_ptr[TOTAL_MEMORY_BANKS]; // array of bank pointers - std::vector> m_blocklist; // head of the list of memory blocks - std::unordered_map> m_banklist; // data gathered for each bank - u16 m_banknext; // next bank to allocate - + std::unordered_map> m_banklist; // data gathered for each bank std::unordered_map> m_sharelist; // map for share lookups - std::unordered_map> m_regionlist; // list of memory regions }; @@ -1151,9 +1401,6 @@ private: #define DECLARE_READ64_MEMBER(name) u64 name(ATTR_UNUSED address_space &space, ATTR_UNUSED offs_t offset, ATTR_UNUSED u64 mem_mask = 0xffffffffffffffffU) #define DECLARE_WRITE64_MEMBER(name) void name(ATTR_UNUSED address_space &space, ATTR_UNUSED offs_t offset, ATTR_UNUSED u64 data, ATTR_UNUSED u64 mem_mask = 0xffffffffffffffffU) -#define SETOFFSET_MEMBER(name) void name(ATTR_UNUSED address_space &space, ATTR_UNUSED offs_t offset) -#define DECLARE_SETOFFSET_MEMBER(name) void name(ATTR_UNUSED address_space &space, ATTR_UNUSED offs_t offset) - // device delegate macros #define READ8_DELEGATE(_class, _member) read8_delegate(FUNC(_class::_member), this) #define WRITE8_DELEGATE(_class, _member) write8_delegate(FUNC(_class::_member), this) @@ -1227,17 +1474,22 @@ private: #define DWORD_ALIGNED(a) (((a) & 3) == 0) #define QWORD_ALIGNED(a) (((a) & 7) == 0) -// inline templates -template<> inline u8 address_space::read_sized<0>(offs_t address, u8 mask) { return read_byte(address); } -template<> inline u16 address_space::read_sized<1>(offs_t address, u16 mask) { return read_word(address, mask); } -template<> inline u32 address_space::read_sized<2>(offs_t address, u32 mask) { return read_dword(address, mask); } -template<> inline u64 address_space::read_sized<3>(offs_t address, u64 mask) { return read_qword(address, mask); } template typename handler_entry_size::uX memory_access_cache::read_native(offs_t address, typename handler_entry_size::uX mask) { - if (address_is_valid(address)) - return *reinterpret_cast(&m_ptr[memory_offset_to_byte(address & m_addrmask, AddrShift)]); - return m_space.read_sized(address, mask); + check_address_r(address); + return m_cache_r->read(address, mask); +} + +template void memory_access_cache::write_native(offs_t address, typename handler_entry_size::uX data, typename handler_entry_size::uX mask) +{ + check_address_w(address); + m_cache_w->write(address, data, mask); +} + +void memory_passthrough_handler::remove() +{ + m_space.remove_passthrough(m_handlers); } #endif /* MAME_EMU_EMUMEM_H */ diff --git a/src/emu/emumem_hea.h b/src/emu/emumem_hea.h new file mode 100644 index 00000000000..7de0d7913a0 --- /dev/null +++ b/src/emu/emumem_hea.h @@ -0,0 +1,40 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +// handler_entry_read_address/handler_entry_write_address + +// parent class for final handlers which want an address base and a mask + +template class handler_entry_read_address : public handler_entry_read +{ +public: + using uX = typename handler_entry_size::uX; + + handler_entry_read_address(address_space *space, u32 flags) : handler_entry_read(space, flags) {} + ~handler_entry_read_address() = default; + + inline void set_address_info(offs_t base, offs_t mask) { + m_address_base = base; + m_address_mask = mask; + } + +protected: + offs_t m_address_base, m_address_mask; +}; + +template class handler_entry_write_address : public handler_entry_write +{ +public: + using uX = typename handler_entry_size::uX; + + handler_entry_write_address(address_space *space, u32 flags) : handler_entry_write(space, flags) {} + ~handler_entry_write_address() = default; + + inline void set_address_info(offs_t base, offs_t mask) { + m_address_base = base; + m_address_mask = mask; + } + +protected: + offs_t m_address_base, m_address_mask; +}; diff --git a/src/emu/emumem_hedp.cpp b/src/emu/emumem_hedp.cpp new file mode 100644 index 00000000000..330117f2637 --- /dev/null +++ b/src/emu/emumem_hedp.cpp @@ -0,0 +1,144 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +#include "emu.h" +#include "emumem_hea.h" +#include "emumem_hedp.h" + +template typename handler_entry_size::uX handler_entry_read_delegate::read(offs_t offset, uX mem_mask) +{ + return m_delegate(*inh::m_space, ((offset - inh::m_address_base) & inh::m_address_mask) >> (Width + AddrShift), mem_mask); +} + +template std::string handler_entry_read_delegate::name() const +{ + return m_delegate.name(); +} + +template void handler_entry_write_delegate::write(offs_t offset, uX data, uX mem_mask) +{ + m_delegate(*inh::m_space, ((offset - inh::m_address_base) & inh::m_address_mask) >> (Width + AddrShift), data, mem_mask); +} + +template std::string handler_entry_write_delegate::name() const +{ + return m_delegate.name(); +} + + + + +template typename handler_entry_size::uX handler_entry_read_ioport::read(offs_t offset, uX mem_mask) +{ + return m_port->read(); +} + +template std::string handler_entry_read_ioport::name() const +{ + return m_port->tag(); +} + +template void handler_entry_write_ioport::write(offs_t offset, uX data, uX mem_mask) +{ + m_port->write(data, mem_mask); +} + +template std::string handler_entry_write_ioport::name() const +{ + return m_port->tag(); +} + + + +template class handler_entry_read_delegate<0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_delegate<0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_delegate<1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_delegate<1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_delegate<1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_delegate<1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_delegate<1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_delegate<1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_delegate<2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_delegate<2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_delegate<2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_delegate<2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_delegate<2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_delegate<2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_delegate<3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_delegate<3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_delegate<3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_delegate<3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_delegate<3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_delegate<3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_delegate<3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_delegate<3, -3, ENDIANNESS_BIG>; + +template class handler_entry_write_delegate<0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_delegate<0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_delegate<1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_delegate<1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_delegate<1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_delegate<1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_delegate<1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_delegate<1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_delegate<2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_delegate<2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_delegate<2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_delegate<2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_delegate<2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_delegate<2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_delegate<3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_delegate<3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_delegate<3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_delegate<3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_delegate<3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_delegate<3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_delegate<3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_delegate<3, -3, ENDIANNESS_BIG>; + + +template class handler_entry_read_ioport<0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_ioport<0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_ioport<1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_ioport<1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_ioport<1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_ioport<1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_ioport<1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_ioport<1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_ioport<2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_ioport<2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_ioport<2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_ioport<2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_ioport<2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_ioport<2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_ioport<3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_ioport<3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_ioport<3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_ioport<3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_ioport<3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_ioport<3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_ioport<3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_ioport<3, -3, ENDIANNESS_BIG>; + +template class handler_entry_write_ioport<0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_ioport<0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_ioport<1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_ioport<1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_ioport<1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_ioport<1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_ioport<1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_ioport<1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_ioport<2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_ioport<2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_ioport<2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_ioport<2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_ioport<2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_ioport<2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_ioport<3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_ioport<3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_ioport<3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_ioport<3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_ioport<3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_ioport<3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_ioport<3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_ioport<3, -3, ENDIANNESS_BIG>; diff --git a/src/emu/emumem_hedp.h b/src/emu/emumem_hedp.h new file mode 100644 index 00000000000..e9539bd21d9 --- /dev/null +++ b/src/emu/emumem_hedp.h @@ -0,0 +1,81 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +// handler_entry_read_delegate/handler_entry_write_delegate + +// Executes an access through called a delegate, usually containing a handler or a lambda + +template class handler_entry_read_delegate : public handler_entry_read_address +{ +public: + using uX = typename handler_entry_size::uX; + using READ = typename handler_entry_size::READ; + using inh = handler_entry_read_address; + + handler_entry_read_delegate(address_space *space, READ delegate) : handler_entry_read_address(space, 0), m_delegate(delegate) {} + ~handler_entry_read_delegate() = default; + + uX read(offs_t offset, uX mem_mask) override; + + std::string name() const override; + +private: + READ m_delegate; +}; + +template class handler_entry_write_delegate : public handler_entry_write_address +{ +public: + using uX = typename handler_entry_size::uX; + using WRITE = typename handler_entry_size::WRITE; + using inh = handler_entry_write_address; + + handler_entry_write_delegate(address_space *space, WRITE delegate) : handler_entry_write_address(space, 0), m_delegate(delegate) {} + ~handler_entry_write_delegate() = default; + + void write(offs_t offset, uX data, uX mem_mask) override; + + std::string name() const override; + +private: + WRITE m_delegate; +}; + + +// handler_entry_read_ioport/handler_entry_write_ioport + +// Accesses an ioport + +template class handler_entry_read_ioport : public handler_entry_read +{ +public: + using uX = typename handler_entry_size::uX; + using inh = handler_entry_read; + + handler_entry_read_ioport(address_space *space, ioport_port *port) : handler_entry_read(space, 0), m_port(port) {} + ~handler_entry_read_ioport() = default; + + uX read(offs_t offset, uX mem_mask) override; + + std::string name() const override; + +private: + ioport_port *m_port; +}; + +template class handler_entry_write_ioport : public handler_entry_write +{ +public: + using uX = typename handler_entry_size::uX; + using inh = handler_entry_write; + + handler_entry_write_ioport(address_space *space, ioport_port *port) : handler_entry_write(space, 0), m_port(port) {} + ~handler_entry_write_ioport() = default; + + void write(offs_t offset, uX data, uX mem_mask) override; + + std::string name() const override; + +private: + ioport_port *m_port; +}; diff --git a/src/emu/emumem_hedr.h b/src/emu/emumem_hedr.h new file mode 100644 index 00000000000..87fff01635e --- /dev/null +++ b/src/emu/emumem_hedr.h @@ -0,0 +1,61 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +// handler_entry_read_dispatch + +// dispatches an access among multiple handlers indexed on part of the address + +template class handler_entry_read_dispatch : public handler_entry_read +{ +public: + using uX = typename handler_entry_size::uX; + using inh = handler_entry_read; + using mapping = typename inh::mapping; + + handler_entry_read_dispatch(address_space *space, const handler_entry::range &init, handler_entry_read *handler); + ~handler_entry_read_dispatch(); + + uX read(offs_t offset, uX mem_mask) override; + void *get_ptr(offs_t offset) const override; + void lookup(offs_t address, offs_t &start, offs_t &end, handler_entry_read *&handler) const override; + + void dump_map(std::vector &map) const override; + + std::string name() const override; + + void populate_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read *handler) override; + void populate_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_read *handler) override; + void populate_mismatched_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, const memory_units_descriptor &descriptor, u8 rkey, std::vector &mappings) override; + void populate_mismatched_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, const memory_units_descriptor &descriptor, std::vector &mappings) override; + void populate_passthrough_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read_passthrough *handler, std::vector &mappings) override; + void populate_passthrough_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_read_passthrough *handler, std::vector &mappings) override; + void detach(const std::unordered_set &handlers) override; + void range_cut_before(offs_t address, int start = COUNT); + void range_cut_after(offs_t address, int start = -1); + + void enumerate_references(handler_entry::reflist &refs) const override; + +protected: + static constexpr u32 LowBits = handler_entry_dispatch_lowbits(HighBits, Width, AddrShift); + static constexpr u32 BITCOUNT = HighBits > LowBits ? HighBits - LowBits : 0; + static constexpr u32 COUNT = 1 << BITCOUNT; + static constexpr offs_t BITMASK = make_bitmask(BITCOUNT); + static constexpr offs_t LOWMASK = make_bitmask(LowBits); + static constexpr offs_t HIGHMASK = make_bitmask(HighBits) ^ LOWMASK; + static constexpr offs_t UPMASK = ~make_bitmask(HighBits); + + handler_entry_read *m_dispatch[COUNT]; + handler_entry::range m_ranges[COUNT]; + +private: + void populate_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read *handler); + void populate_mirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_read *handler); + + void populate_mismatched_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, const memory_units_descriptor &descriptor, u8 rkey, std::vector &mappings); + void populate_mismatched_mirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, const memory_units_descriptor &descriptor, std::vector &mappings); + void mismatched_patch(const memory_units_descriptor &descriptor, u8 rkey, std::vector &mappings, handler_entry_read *&target); + + void populate_passthrough_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read_passthrough *handler, std::vector &mappings); + void populate_passthrough_mirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_read_passthrough *handler, std::vector &mappings); + void passthrough_patch(handler_entry_read_passthrough *handler, std::vector &mappings, handler_entry_read *&target); +}; diff --git a/src/emu/emumem_hedr.ipp b/src/emu/emumem_hedr.ipp new file mode 100644 index 00000000000..5f368b57448 --- /dev/null +++ b/src/emu/emumem_hedr.ipp @@ -0,0 +1,479 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +#include "emu.h" +#include "emumem_mud.h" +#include "emumem_hea.h" +#include "emumem_heu.h" +#include "emumem_heun.h" +#include "emumem_hep.h" +#include "emumem_hedr.h" + +template handler_entry_read_dispatch::handler_entry_read_dispatch(address_space *space, const handler_entry::range &init, handler_entry_read *handler) : handler_entry_read(space, handler_entry::F_DISPATCH) +{ + if (!handler) + handler = space->get_unmap_r(); + handler->ref(COUNT); + for(unsigned int i=0; i != COUNT; i++) { + m_dispatch[i] = handler; + m_ranges[i] = init; + } +} + +template handler_entry_read_dispatch::~handler_entry_read_dispatch() +{ + for(unsigned int i=0; i != COUNT; i++) + m_dispatch[i]->unref(); +} + +template void handler_entry_read_dispatch::enumerate_references(handler_entry::reflist &refs) const +{ + for(unsigned int i=0; i != COUNT; i++) + refs.add(m_dispatch[i]); +} + +template void handler_entry_read_dispatch::dump_map(std::vector &map) const +{ + offs_t cur = map.empty() ? 0 : map.back().end + 1; + offs_t base = cur & UPMASK; + do { + offs_t entry = (cur >> LowBits) & BITMASK; + if(m_dispatch[entry]->is_dispatch()) + m_dispatch[entry]->dump_map(map); + else + map.emplace_back(memory_entry{ m_ranges[entry].start, m_ranges[entry].end, m_dispatch[entry] }); + cur = map.back().end + 1; + } while(cur && !((cur ^ base) & UPMASK)); + +} + +template typename handler_entry_size::uX handler_entry_read_dispatch::read(offs_t offset, uX mem_mask) +{ + return m_dispatch[(offset >> LowBits) & BITMASK]->read(offset, mem_mask); +} + +template void *handler_entry_read_dispatch::get_ptr(offs_t offset) const +{ + return m_dispatch[(offset >> LowBits) & BITMASK]->get_ptr(offset); +} + +template std::string handler_entry_read_dispatch::name() const +{ + return "dispatch"; +} + +template void handler_entry_read_dispatch::lookup(offs_t address, offs_t &start, offs_t &end, handler_entry_read *&handler) const +{ + offs_t slot = (address >> LowBits) & BITMASK; + auto h = m_dispatch[slot]; + if(h->is_dispatch()) + h->lookup(address, start, end, handler); + else { + start = m_ranges[slot].start; + end = m_ranges[slot].end; + handler = h; + } +} + +template void handler_entry_read_dispatch::range_cut_before(offs_t address, int start) +{ + while(--start >= 0) { + if(int(LowBits) > -AddrShift && m_dispatch[start]->is_dispatch()) { + static_cast *>(m_dispatch[start])->range_cut_before(address); + break; + } + if(m_ranges[start].end <= address) + break; + m_ranges[start].end = address; + } +} + +template void handler_entry_read_dispatch::range_cut_after(offs_t address, int start) +{ + while(++start < COUNT) { + if(int(LowBits) > -AddrShift && m_dispatch[start]->is_dispatch()) { + static_cast *>(m_dispatch[start])->range_cut_after(address); + break; + } + if(m_ranges[start].start >= address) + break; + m_ranges[start].start = address; + } +} + +template void handler_entry_read_dispatch::populate_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read *handler) +{ + auto cur = m_dispatch[entry]; + if(cur->is_dispatch()) + cur->populate_nomirror(start, end, ostart, oend, handler); + else { + auto subdispatch = new handler_entry_read_dispatch(handler_entry::m_space, m_ranges[entry], cur); + cur->unref(); + m_dispatch[entry] = subdispatch; + subdispatch->populate_nomirror(start, end, ostart, oend, handler); + } +} + +template void handler_entry_read_dispatch::populate_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read *handler) +{ + offs_t start_entry = start >> LowBits; + offs_t end_entry = end >> LowBits; + range_cut_before(ostart-1, start_entry); + range_cut_after(oend+1, end_entry); + + if(LowBits <= Width + AddrShift) { + handler->ref(end_entry - start_entry); + for(offs_t ent = start_entry; ent <= end_entry; ent++) { + m_dispatch[ent]->unref(); + m_dispatch[ent] = handler; + m_ranges[ent].set(ostart, oend); + } + + } else if(start_entry == end_entry) { + if(!(start & LOWMASK) && (end & LOWMASK) == LOWMASK) { + m_dispatch[start_entry]->unref(); + m_dispatch[start_entry] = handler; + m_ranges[start_entry].set(ostart, oend); + } else + populate_nomirror_subdispatch(start_entry, start & LOWMASK, end & LOWMASK, ostart, oend, handler); + + } else { + if(start & LOWMASK) { + populate_nomirror_subdispatch(start_entry, start & LOWMASK, LOWMASK, ostart, oend, handler); + start_entry++; + if(start_entry <= end_entry) + handler->ref(); + } + if((end & LOWMASK) != LOWMASK) { + populate_nomirror_subdispatch(end_entry, 0, end & LOWMASK, ostart, oend, handler); + end_entry--; + if(start_entry <= end_entry) + handler->ref(); + } + + if(start_entry <= end_entry) { + handler->ref(end_entry - start_entry); + for(offs_t ent = start_entry; ent <= end_entry; ent++) { + m_dispatch[ent]->unref(); + m_dispatch[ent] = handler; + m_ranges[ent].set(ostart, oend); + } + } + } +} +template void handler_entry_read_dispatch::populate_mirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_read *handler) +{ + auto cur = m_dispatch[entry]; + if(cur->is_dispatch()) + cur->populate_mirror(start, end, ostart, oend, mirror, handler); + else { + auto subdispatch = new handler_entry_read_dispatch(handler_entry::m_space, m_ranges[entry], cur); + cur->unref(); + m_dispatch[entry] = subdispatch; + subdispatch->populate_mirror(start, end, ostart, oend, mirror, handler); + } +} + + +template void handler_entry_read_dispatch::populate_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_read *handler) +{ + offs_t hmirror = mirror & HIGHMASK; + offs_t lmirror = mirror & LOWMASK; + + if(lmirror) { + // If lmirror is non-zero, then each mirror instance is a single entry + offs_t add = 1 + ~hmirror; + offs_t offset = 0; + offs_t base_entry = start >> LowBits; + start &= LOWMASK; + end &= LOWMASK; + do { + if(offset) + handler->ref(); + populate_mirror_subdispatch(base_entry | (offset >> LowBits), start, end, ostart | offset, oend | offset, lmirror, handler); + offset = (offset + add) & hmirror; + } while(offset); + } else { + // If lmirror is zero, call the nomirror version as needed + offs_t add = 1 + ~hmirror; + offs_t offset = 0; + do { + if(offset) + handler->ref(); + populate_nomirror(start | offset, end | offset, ostart | offset, oend | offset, handler); + offset = (offset + add) & hmirror; + } while(offset); + } +} + +template void handler_entry_read_dispatch::mismatched_patch(const memory_units_descriptor &descriptor, u8 rkey, std::vector &mappings, handler_entry_read *&target) +{ + u8 ukey = descriptor.rkey_to_ukey(rkey); + handler_entry_read *original = target->is_units() ? target : nullptr; + handler_entry_read *replacement = nullptr; + for(const auto &p : mappings) + if(p.ukey == ukey && p.original == original) { + replacement = p.patched; + break; + } + if(!replacement) { + if(original) + replacement = new handler_entry_read_units(descriptor, ukey, static_cast *>(original)); + else + replacement = new handler_entry_read_units(descriptor, ukey, inh::m_space); + + mappings.emplace_back(mapping{ original, replacement, ukey }); + } else + replacement->ref(); + target->unref(); + target = replacement; +} + +template void handler_entry_read_dispatch::populate_mismatched_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, const memory_units_descriptor &descriptor, u8 rkey, std::vector &mappings) +{ + auto cur = m_dispatch[entry]; + if(cur->is_dispatch()) + cur->populate_mismatched_nomirror(start, end, ostart, oend, descriptor, rkey, mappings); + else { + auto subdispatch = new handler_entry_read_dispatch(handler_entry::m_space, m_ranges[entry], cur); + cur->unref(); + m_dispatch[entry] = subdispatch; + subdispatch->populate_mismatched_nomirror(start, end, ostart, oend, descriptor, rkey, mappings); + } +} + +template void handler_entry_read_dispatch::populate_mismatched_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, const memory_units_descriptor &descriptor, u8 rkey, std::vector &mappings) +{ + offs_t start_entry = start >> LowBits; + offs_t end_entry = end >> LowBits; + range_cut_before(ostart-1, start_entry); + range_cut_after(oend+1, end_entry); + + if(LowBits <= Width + AddrShift) { + for(offs_t ent = start_entry; ent <= end_entry; ent++) { + u8 rkey1 = rkey; + if(ent != start_entry) + rkey1 &= ~handler_entry::START; + if(ent != end_entry) + rkey1 &= ~handler_entry::END; + mismatched_patch(descriptor, rkey1, mappings, m_dispatch[ent]); + m_ranges[ent].set(ostart, oend); + } + + } else if(start_entry == end_entry) { + if(!(start & LOWMASK) && (end & LOWMASK) == LOWMASK) { + if(m_dispatch[start_entry]->is_dispatch()) + m_dispatch[start_entry]->populate_mismatched_nomirror(start & LOWMASK, end & LOWMASK, ostart, oend, descriptor, rkey, mappings); + else { + mismatched_patch(descriptor, rkey, mappings, m_dispatch[start_entry]); + m_ranges[start_entry].set(ostart, oend); + } + } else + populate_mismatched_nomirror_subdispatch(start_entry, start & LOWMASK, end & LOWMASK, ostart, oend, descriptor, rkey, mappings); + + } else { + if(start & LOWMASK) { + populate_mismatched_nomirror_subdispatch(start_entry, start & LOWMASK, LOWMASK, ostart, oend, descriptor, rkey & ~handler_entry::END, mappings); + start_entry++; + rkey &= ~handler_entry::START; + } + if((end & LOWMASK) != LOWMASK) { + populate_mismatched_nomirror_subdispatch(end_entry, 0, end & LOWMASK, ostart, oend, descriptor, rkey & ~handler_entry::START, mappings); + end_entry--; + rkey &= ~handler_entry::END; + } + + if(start_entry <= end_entry) { + for(offs_t ent = start_entry; ent <= end_entry; ent++) { + u8 rkey1 = rkey; + if(ent != start_entry) + rkey1 &= ~handler_entry::START; + if(ent != end_entry) + rkey1 &= ~handler_entry::END; + if(m_dispatch[ent]->is_dispatch()) + m_dispatch[ent]->populate_mismatched_nomirror(start & LOWMASK, end & LOWMASK, ostart, oend, descriptor, rkey1, mappings); + else { + mismatched_patch(descriptor, rkey1, mappings, m_dispatch[ent]); + m_ranges[ent].set(ostart, oend); + } + } + } + } +} + +template void handler_entry_read_dispatch::populate_mismatched_mirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, const memory_units_descriptor &descriptor, std::vector &mappings) +{ + auto cur = m_dispatch[entry]; + if(cur->is_dispatch()) + cur->populate_mismatched_mirror(start, end, ostart, oend, mirror, descriptor, mappings); + else { + auto subdispatch = new handler_entry_read_dispatch(handler_entry::m_space, m_ranges[entry], cur); + cur->unref(); + m_dispatch[entry] = subdispatch; + subdispatch->populate_mismatched_mirror(start, end, ostart, oend, mirror, descriptor, mappings); + } +} + +template void handler_entry_read_dispatch::populate_mismatched_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, const memory_units_descriptor &descriptor, std::vector &mappings) +{ + offs_t hmirror = mirror & HIGHMASK; + offs_t lmirror = mirror & LOWMASK; + + if(lmirror) { + // If lmirror is non-zero, then each mirror instance is a single entry + offs_t add = 1 + ~hmirror; + offs_t offset = 0; + offs_t base_entry = start >> LowBits; + start &= LOWMASK; + end &= LOWMASK; + do { + populate_mismatched_mirror_subdispatch(base_entry | (offset >> LowBits), start, end, ostart | offset, oend | offset, lmirror, descriptor, mappings); + offset = (offset + add) & hmirror; + } while(offset); + } else { + // If lmirror is zero, call the nomirror version as needed + offs_t add = 1 + ~hmirror; + offs_t offset = 0; + do { + populate_mismatched_nomirror(start | offset, end | offset, ostart | offset, oend | offset, descriptor, handler_entry::START|handler_entry::END, mappings); + offset = (offset + add) & hmirror; + } while(offset); + } +} + + +template void handler_entry_read_dispatch::passthrough_patch(handler_entry_read_passthrough *handler, std::vector &mappings, handler_entry_read *&target) +{ + handler_entry_read *original = target; + handler_entry_read *replacement = nullptr; + for(const auto &p : mappings) + if(p.original == original) { + replacement = p.patched; + break; + } + if(!replacement) { + replacement = handler->instantiate(original); + mappings.emplace_back(mapping{ original, replacement }); + } else + replacement->ref(); + target->unref(); + target = replacement; +} + +template void handler_entry_read_dispatch::populate_passthrough_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read_passthrough *handler, std::vector &mappings) +{ + auto cur = m_dispatch[entry]; + if(cur->is_dispatch()) + cur->populate_passthrough_nomirror(start, end, ostart, oend, handler, mappings); + else { + auto subdispatch = new handler_entry_read_dispatch(handler_entry::m_space, m_ranges[entry], cur); + cur->unref(); + m_dispatch[entry] = subdispatch; + subdispatch->populate_passthrough_nomirror(start, end, ostart, oend, handler, mappings); + } +} + +template void handler_entry_read_dispatch::populate_passthrough_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read_passthrough *handler, std::vector &mappings) +{ + offs_t start_entry = (start & HIGHMASK) >> LowBits; + offs_t end_entry = (end & HIGHMASK) >> LowBits; + range_cut_before(ostart-1, start_entry); + range_cut_after(oend+1, end_entry); + + if(LowBits <= Width + AddrShift) { + for(offs_t ent = start_entry; ent <= end_entry; ent++) { + if(m_dispatch[start_entry]->is_dispatch()) + m_dispatch[start_entry]->populate_passthrough_nomirror(start & LOWMASK, end & LOWMASK, ostart, oend, handler, mappings); + else { + passthrough_patch(handler, mappings, m_dispatch[ent]); + m_ranges[ent].intersect(ostart, oend); + } + } + + } else if(start_entry == end_entry) { + if(!(start & LOWMASK) && (end & LOWMASK) == LOWMASK) { + passthrough_patch(handler, mappings, m_dispatch[start_entry]); + m_ranges[start_entry].intersect(ostart, oend); + } else + populate_passthrough_nomirror_subdispatch(start_entry, start & LOWMASK, end & LOWMASK, ostart, oend, handler, mappings); + + } else { + if(start & LOWMASK) { + populate_passthrough_nomirror_subdispatch(start_entry, start & LOWMASK, LOWMASK, ostart, oend, handler, mappings); + start_entry++; + } + if((end & LOWMASK) != LOWMASK) { + populate_passthrough_nomirror_subdispatch(end_entry, 0, end & LOWMASK, ostart, oend, handler, mappings); + end_entry--; + } + + if(start_entry <= end_entry) { + for(offs_t ent = start_entry; ent <= end_entry; ent++) { + if(m_dispatch[ent]->is_dispatch()) + m_dispatch[ent]->populate_passthrough_nomirror(start & LOWMASK, end & LOWMASK, ostart, oend, handler, mappings); + else { + passthrough_patch(handler, mappings, m_dispatch[ent]); + m_ranges[ent].intersect(ostart, oend); + } + } + } + } +} + +template void handler_entry_read_dispatch::populate_passthrough_mirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_read_passthrough *handler, std::vector &mappings) +{ + auto cur = m_dispatch[entry]; + if(cur->is_dispatch()) + cur->populate_passthrough_mirror(start, end, ostart, oend, mirror, handler, mappings); + else { + auto subdispatch = new handler_entry_read_dispatch(handler_entry::m_space, m_ranges[entry], cur); + cur->unref(); + m_dispatch[entry] = subdispatch; + subdispatch->populate_passthrough_mirror(start, end, ostart, oend, mirror, handler, mappings); + } +} + +template void handler_entry_read_dispatch::populate_passthrough_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_read_passthrough *handler, std::vector &mappings) +{ + offs_t hmirror = mirror & HIGHMASK; + offs_t lmirror = mirror & LOWMASK; + + if(lmirror) { + // If lmirror is non-zero, then each mirror instance is a single entry + offs_t add = 1 + ~hmirror; + offs_t offset = 0; + offs_t base_entry = start >> LowBits; + start &= LOWMASK; + end &= LOWMASK; + do { + populate_passthrough_mirror_subdispatch(base_entry | (offset >> LowBits), start, end, ostart | offset, oend | offset, lmirror, handler, mappings); + offset = (offset + add) & hmirror; + } while(offset); + } else { + // If lmirror is zero, call the nomirror version as needed + offs_t add = 1 + ~hmirror; + offs_t offset = 0; + do { + populate_passthrough_nomirror(start | offset, end | offset, ostart | offset, oend | offset, handler, mappings); + offset = (offset + add) & hmirror; + } while(offset); + } +} + +template void handler_entry_read_dispatch::detach(const std::unordered_set &handlers) +{ + for(unsigned int i=0; i != COUNT; i++) { + m_dispatch[i]->unref(); + if(!m_dispatch[i]->is_passthrough()) + continue; + auto np = static_cast *>(m_dispatch[i]); + + if(handlers.find(np) != handlers.end()) { + m_dispatch[i] = np->get_subhandler(); + m_dispatch[i]->ref(); + np->unref(); + + } else + np->detach(handlers); + } +} diff --git a/src/emu/emumem_hedr0.cpp b/src/emu/emumem_hedr0.cpp new file mode 100644 index 00000000000..b39b88263dc --- /dev/null +++ b/src/emu/emumem_hedr0.cpp @@ -0,0 +1,171 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +#include "emu.h" +#include "emumem_hedr.ipp" + + +template class handler_entry_read_dispatch< 1, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 1, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 2, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 2, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 3, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 3, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 4, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 4, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 5, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 5, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 6, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 6, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 7, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 7, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 8, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 8, 0, 0, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch< 1, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 1, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 2, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 2, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 3, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 3, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 4, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 4, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 5, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 5, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 6, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 6, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 7, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 7, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 8, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 8, 1, 3, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch< 1, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 1, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 2, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 2, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 3, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 3, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 4, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 4, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 5, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 5, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 6, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 6, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 7, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 7, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 8, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 8, 1, 0, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch< 1, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 1, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 2, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 2, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 3, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 3, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 4, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 4, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 5, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 5, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 6, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 6, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 7, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 7, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 8, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 8, 1, -1, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch< 2, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 2, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 3, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 3, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 4, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 4, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 5, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 5, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 6, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 6, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 7, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 7, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 8, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 8, 2, 0, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch< 2, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 2, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 3, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 3, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 4, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 4, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 5, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 5, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 6, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 6, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 7, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 7, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 8, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 8, 2, -1, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch< 2, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 2, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 3, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 3, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 4, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 4, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 5, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 5, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 6, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 6, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 7, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 7, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 8, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 8, 2, -2, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch< 3, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 3, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 4, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 4, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 5, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 5, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 6, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 6, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 7, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 7, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 8, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 8, 3, 0, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch< 3, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 3, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 4, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 4, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 5, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 5, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 6, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 6, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 7, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 7, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 8, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 8, 3, -1, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch< 3, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 3, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 4, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 4, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 5, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 5, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 6, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 6, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 7, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 7, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 8, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 8, 3, -2, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch< 3, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 3, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 4, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 4, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 5, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 5, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 6, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 6, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 7, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 7, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 8, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 8, 3, -3, ENDIANNESS_BIG>; diff --git a/src/emu/emumem_hedr1.cpp b/src/emu/emumem_hedr1.cpp new file mode 100644 index 00000000000..5a06dab08c3 --- /dev/null +++ b/src/emu/emumem_hedr1.cpp @@ -0,0 +1,192 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +#include "emu.h" +#include "emumem_hedr.ipp" + +template class handler_entry_read_dispatch< 9, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 9, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<10, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<10, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<11, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<11, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<12, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<12, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<13, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<13, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<14, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<14, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<15, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<15, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<16, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<16, 0, 0, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch< 9, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 9, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<10, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<10, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<11, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<11, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<12, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<12, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<13, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<13, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<14, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<14, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<15, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<15, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<16, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<16, 1, 3, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch< 9, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 9, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<10, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<10, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<11, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<11, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<12, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<12, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<13, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<13, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<14, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<14, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<15, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<15, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<16, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<16, 1, 0, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch< 9, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 9, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<10, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<10, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<11, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<11, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<12, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<12, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<13, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<13, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<14, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<14, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<15, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<15, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<16, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<16, 1, -1, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch< 9, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 9, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<10, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<10, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<11, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<11, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<12, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<12, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<13, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<13, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<14, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<14, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<15, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<15, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<16, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<16, 2, 0, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch< 9, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 9, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<10, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<10, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<11, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<11, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<12, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<12, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<13, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<13, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<14, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<14, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<15, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<15, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<16, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<16, 2, -1, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch< 9, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 9, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<10, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<10, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<11, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<11, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<12, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<12, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<13, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<13, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<14, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<14, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<15, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<15, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<16, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<16, 2, -2, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch< 9, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 9, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<10, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<10, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<11, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<11, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<12, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<12, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<13, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<13, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<14, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<14, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<15, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<15, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<16, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<16, 3, 0, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch< 9, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 9, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<10, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<10, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<11, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<11, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<12, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<12, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<13, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<13, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<14, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<14, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<15, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<15, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<16, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<16, 3, -1, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch< 9, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 9, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<10, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<10, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<11, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<11, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<12, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<12, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<13, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<13, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<14, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<14, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<15, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<15, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<16, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<16, 3, -2, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch< 9, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 9, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<10, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<10, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<11, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<11, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<12, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<12, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<13, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<13, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<14, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<14, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<15, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<15, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<16, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<16, 3, -3, ENDIANNESS_BIG>; diff --git a/src/emu/emumem_hedr2.cpp b/src/emu/emumem_hedr2.cpp new file mode 100644 index 00000000000..4c80f2423c4 --- /dev/null +++ b/src/emu/emumem_hedr2.cpp @@ -0,0 +1,192 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +#include "emu.h" +#include "emumem_hedr.ipp" + +template class handler_entry_read_dispatch<17, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<17, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<18, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<18, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<19, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<19, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<20, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<20, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<21, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<21, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<22, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<22, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<23, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<23, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<24, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<24, 0, 0, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch<17, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<17, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<18, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<18, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<19, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<19, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<20, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<20, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<21, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<21, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<22, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<22, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<23, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<23, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<24, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<24, 1, 3, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch<17, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<17, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<18, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<18, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<19, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<19, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<20, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<20, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<21, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<21, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<22, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<22, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<23, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<23, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<24, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<24, 1, 0, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch<17, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<17, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<18, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<18, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<19, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<19, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<20, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<20, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<21, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<21, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<22, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<22, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<23, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<23, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<24, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<24, 1, -1, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch<17, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<17, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<18, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<18, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<19, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<19, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<20, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<20, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<21, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<21, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<22, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<22, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<23, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<23, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<24, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<24, 2, 0, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch<17, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<17, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<18, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<18, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<19, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<19, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<20, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<20, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<21, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<21, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<22, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<22, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<23, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<23, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<24, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<24, 2, -1, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch<17, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<17, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<18, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<18, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<19, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<19, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<20, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<20, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<21, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<21, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<22, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<22, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<23, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<23, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<24, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<24, 2, -2, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch<17, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<17, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<18, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<18, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<19, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<19, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<20, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<20, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<21, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<21, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<22, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<22, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<23, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<23, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<24, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<24, 3, 0, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch<17, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<17, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<18, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<18, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<19, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<19, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<20, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<20, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<21, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<21, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<22, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<22, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<23, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<23, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<24, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<24, 3, -1, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch<17, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<17, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<18, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<18, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<19, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<19, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<20, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<20, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<21, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<21, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<22, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<22, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<23, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<23, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<24, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<24, 3, -2, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch<17, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<17, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<18, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<18, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<19, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<19, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<20, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<20, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<21, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<21, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<22, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<22, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<23, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<23, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<24, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<24, 3, -3, ENDIANNESS_BIG>; diff --git a/src/emu/emumem_hedr3.cpp b/src/emu/emumem_hedr3.cpp new file mode 100644 index 00000000000..97fa6d1c9e3 --- /dev/null +++ b/src/emu/emumem_hedr3.cpp @@ -0,0 +1,193 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +#include "emu.h" +#include "emumem_hedr.ipp" + + +template class handler_entry_read_dispatch<25, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<25, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<26, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<26, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<27, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<27, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<28, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<28, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<29, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<29, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<30, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<30, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<31, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<31, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<32, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<32, 0, 0, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch<25, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<25, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<26, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<26, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<27, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<27, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<28, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<28, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<29, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<29, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<31, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<31, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<30, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<30, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<32, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<32, 1, 3, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch<25, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<25, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<26, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<26, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<27, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<27, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<28, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<28, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<29, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<29, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<31, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<31, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<30, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<30, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<32, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<32, 1, 0, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch<25, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<25, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<26, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<26, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<27, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<27, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<28, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<28, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<29, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<29, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<31, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<31, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<30, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<30, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<32, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<32, 1, -1, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch<25, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<25, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<26, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<26, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<27, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<27, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<28, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<28, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<29, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<29, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<31, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<31, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<30, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<30, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<32, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<32, 2, 0, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch<25, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<25, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<26, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<26, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<27, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<27, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<28, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<28, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<29, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<29, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<31, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<31, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<30, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<30, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<32, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<32, 2, -1, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch<25, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<25, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<26, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<26, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<27, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<27, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<28, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<28, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<29, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<29, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<31, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<31, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<30, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<30, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<32, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<32, 2, -2, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch<25, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<25, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<26, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<26, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<27, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<27, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<28, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<28, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<29, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<29, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<31, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<31, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<30, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<30, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<32, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<32, 3, 0, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch<25, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<25, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<26, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<26, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<27, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<27, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<28, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<28, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<29, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<29, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<31, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<31, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<30, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<30, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<32, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<32, 3, -1, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch<25, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<25, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<26, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<26, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<27, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<27, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<28, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<28, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<29, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<29, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<31, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<31, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<30, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<30, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<32, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<32, 3, -2, ENDIANNESS_BIG>; + +template class handler_entry_read_dispatch<25, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<25, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<26, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<26, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<27, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<27, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<28, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<28, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<29, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<29, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<31, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<31, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<30, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<30, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch<32, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch<32, 3, -3, ENDIANNESS_BIG>; diff --git a/src/emu/emumem_hedw.h b/src/emu/emumem_hedw.h new file mode 100644 index 00000000000..ed51d826f97 --- /dev/null +++ b/src/emu/emumem_hedw.h @@ -0,0 +1,61 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +// handler_entry_write_dispatch + +// dispatches an access among multiple handlers indexed on part of the address + +template class handler_entry_write_dispatch : public handler_entry_write +{ +public: + using uX = typename handler_entry_size::uX; + using inh = handler_entry_write; + using mapping = typename inh::mapping; + + handler_entry_write_dispatch(address_space *space, const handler_entry::range &init, handler_entry_write *handler); + ~handler_entry_write_dispatch(); + + void write(offs_t offset, uX data, uX mem_mask) override; + void *get_ptr(offs_t offset) const override; + void lookup(offs_t address, offs_t &start, offs_t &end, handler_entry_write *&handler) const override; + + void dump_map(std::vector &map) const override; + + std::string name() const override; + + void populate_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_write *handler) override; + void populate_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_write *handler) override; + void populate_mismatched_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, const memory_units_descriptor &descriptor, u8 rkey, std::vector &mappings) override; + void populate_mismatched_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, const memory_units_descriptor &descriptor, std::vector &mappings) override; + void populate_passthrough_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_write_passthrough *handler, std::vector &mappings) override; + void populate_passthrough_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_write_passthrough *handler, std::vector &mappings) override; + void detach(const std::unordered_set &handlers) override; + void range_cut_before(offs_t address, int start = COUNT); + void range_cut_after(offs_t address, int start = -1); + + void enumerate_references(handler_entry::reflist &refs) const override; + +protected: + static constexpr u32 LowBits = handler_entry_dispatch_lowbits(HighBits, Width, AddrShift); + static constexpr u32 BITCOUNT = HighBits > LowBits ? HighBits - LowBits : 0; + static constexpr u32 COUNT = 1 << BITCOUNT; + static constexpr offs_t BITMASK = make_bitmask(BITCOUNT); + static constexpr offs_t LOWMASK = make_bitmask(LowBits); + static constexpr offs_t HIGHMASK = make_bitmask(HighBits) ^ LOWMASK; + static constexpr offs_t UPMASK = ~make_bitmask(HighBits); + + handler_entry_write *m_dispatch[COUNT]; + handler_entry::range m_ranges[COUNT]; + +private: + void populate_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_write *handler); + void populate_mirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_write *handler); + + void populate_mismatched_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, const memory_units_descriptor &descriptor, u8 rkey, std::vector &mappings); + void populate_mismatched_mirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, const memory_units_descriptor &descriptor, std::vector &mappings); + void mismatched_patch(const memory_units_descriptor &descriptor, u8 rkey, std::vector &mappings, handler_entry_write *&target); + + void populate_passthrough_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_write_passthrough *handler, std::vector &mappings); + void populate_passthrough_mirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_write_passthrough *handler, std::vector &mappings); + void passthrough_patch(handler_entry_write_passthrough *handler, std::vector &mappings, handler_entry_write *&target); +}; diff --git a/src/emu/emumem_hedw.ipp b/src/emu/emumem_hedw.ipp new file mode 100644 index 00000000000..d50de2262be --- /dev/null +++ b/src/emu/emumem_hedw.ipp @@ -0,0 +1,479 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +#include "emu.h" +#include "emumem_mud.h" +#include "emumem_hea.h" +#include "emumem_heu.h" +#include "emumem_heun.h" +#include "emumem_hep.h" +#include "emumem_hedw.h" + + +template handler_entry_write_dispatch::handler_entry_write_dispatch(address_space *space, const handler_entry::range &init, handler_entry_write *handler) : handler_entry_write(space, handler_entry::F_DISPATCH) +{ + if (!handler) + handler = space->get_unmap_w(); + handler->ref(COUNT); + for(unsigned int i=0; i != COUNT; i++) { + m_dispatch[i] = handler; + m_ranges[i] = init; + } +} + +template handler_entry_write_dispatch::~handler_entry_write_dispatch() +{ + for(unsigned int i=0; i != COUNT; i++) + m_dispatch[i]->unref(); +} + +template void handler_entry_write_dispatch::enumerate_references(handler_entry::reflist &refs) const +{ + for(unsigned int i=0; i != COUNT; i++) + refs.add(m_dispatch[i]); +} + +template void handler_entry_write_dispatch::dump_map(std::vector &map) const +{ + offs_t cur = map.empty() ? 0 : map.back().end + 1; + offs_t base = cur & UPMASK; + do { + offs_t entry = (cur >> LowBits) & BITMASK; + if(m_dispatch[entry]->is_dispatch()) + m_dispatch[entry]->dump_map(map); + else + map.emplace_back(memory_entry{ m_ranges[entry].start, m_ranges[entry].end, m_dispatch[entry] }); + cur = map.back().end + 1; + } while(cur && !((cur ^ base) & UPMASK)); +} + +template void handler_entry_write_dispatch::write(offs_t offset, uX data, uX mem_mask) +{ + m_dispatch[(offset >> LowBits) & BITMASK]->write(offset, data, mem_mask); +} + +template void *handler_entry_write_dispatch::get_ptr(offs_t offset) const +{ + return m_dispatch[(offset >> LowBits) & BITMASK]->get_ptr(offset); +} + +template std::string handler_entry_write_dispatch::name() const +{ + return "dispatch"; +} + +template void handler_entry_write_dispatch::lookup(offs_t address, offs_t &start, offs_t &end, handler_entry_write *&handler) const +{ + offs_t slot = (address >> LowBits) & BITMASK; + auto h = m_dispatch[slot]; + if(h->is_dispatch()) + h->lookup(address, start, end, handler); + else { + start = m_ranges[slot].start; + end = m_ranges[slot].end; + handler = h; + } +} + +template void handler_entry_write_dispatch::range_cut_before(offs_t address, int start) +{ + while(--start >= 0) { + if(int(LowBits) > -AddrShift && m_dispatch[start]->is_dispatch()) { + static_cast *>(m_dispatch[start])->range_cut_before(address); + break; + } + if(m_ranges[start].end <= address) + break; + m_ranges[start].end = address; + } +} + +template void handler_entry_write_dispatch::range_cut_after(offs_t address, int start) +{ + while(++start < COUNT) { + if(int(LowBits) > -AddrShift && m_dispatch[start]->is_dispatch()) { + static_cast *>(m_dispatch[start])->range_cut_after(address); + break; + } + if(m_ranges[start].start >= address) + break; + m_ranges[start].start = address; + } +} + +template void handler_entry_write_dispatch::populate_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_write *handler) +{ + auto cur = m_dispatch[entry]; + if(cur->is_dispatch()) + cur->populate_nomirror(start, end, ostart, oend, handler); + else { + auto subdispatch = new handler_entry_write_dispatch(handler_entry::m_space, m_ranges[entry], cur); + cur->unref(); + m_dispatch[entry] = subdispatch; + subdispatch->populate_nomirror(start, end, ostart, oend, handler); + } +} + +template void handler_entry_write_dispatch::populate_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_write *handler) +{ + offs_t start_entry = (start & HIGHMASK) >> LowBits; + offs_t end_entry = (end & HIGHMASK) >> LowBits; + range_cut_before(ostart-1, start_entry); + range_cut_after(oend+1, end_entry); + + if(LowBits <= Width + AddrShift) { + handler->ref(end_entry - start_entry); + for(offs_t ent = start_entry; ent <= end_entry; ent++) { + m_dispatch[ent]->unref(); + m_dispatch[ent] = handler; + m_ranges[ent].set(ostart, oend); + } + + } else if(start_entry == end_entry) { + if(!(start & LOWMASK) && (end & LOWMASK) == LOWMASK) { + m_dispatch[start_entry]->unref(); + m_dispatch[start_entry] = handler; + m_ranges[start_entry].set(ostart, oend); + } else + populate_nomirror_subdispatch(start_entry, start & LOWMASK, end & LOWMASK, ostart, oend, handler); + + } else { + if(start & LOWMASK) { + populate_nomirror_subdispatch(start_entry, start & LOWMASK, LOWMASK, ostart, oend, handler); + start_entry++; + if(start_entry <= end_entry) + handler->ref(); + } + if((end & LOWMASK) != LOWMASK) { + populate_nomirror_subdispatch(end_entry, 0, end & LOWMASK, ostart, oend, handler); + end_entry--; + if(start_entry <= end_entry) + handler->ref(); + } + + if(start_entry <= end_entry) { + handler->ref(end_entry - start_entry); + for(offs_t ent = start_entry; ent <= end_entry; ent++) { + m_dispatch[ent]->unref(); + m_dispatch[ent] = handler; + m_ranges[ent].set(ostart, oend); + } + } + } +} + +template void handler_entry_write_dispatch::populate_mirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_write *handler) +{ + auto cur = m_dispatch[entry]; + if(cur->is_dispatch()) + cur->populate_mirror(start, end, ostart, oend, mirror, handler); + else { + auto subdispatch = new handler_entry_write_dispatch(handler_entry::m_space, m_ranges[entry], cur); + cur->unref(); + m_dispatch[entry] = subdispatch; + subdispatch->populate_mirror(start, end, ostart, oend, mirror, handler); + } +} + +template void handler_entry_write_dispatch::populate_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_write *handler) +{ + offs_t hmirror = mirror & HIGHMASK; + offs_t lmirror = mirror & LOWMASK; + + if(lmirror) { + // If lmirror is non-zero, then each mirror instance is a single entry + offs_t add = 1 + ~hmirror; + offs_t offset = 0; + offs_t base_entry = start >> LowBits; + start &= LOWMASK; + end &= LOWMASK; + do { + if(offset) + handler->ref(); + populate_mirror_subdispatch(base_entry | (offset >> LowBits), start, end, ostart | offset, oend | offset, lmirror, handler); + offset = (offset + add) & hmirror; + } while(offset); + } else { + // If lmirror is zero, call the nomirror version as needed + offs_t add = 1 + ~hmirror; + offs_t offset = 0; + do { + if(offset) + handler->ref(); + populate_nomirror(start | offset, end | offset, ostart | offset, oend | offset, handler); + offset = (offset + add) & hmirror; + } while(offset); + } +} + +template void handler_entry_write_dispatch::mismatched_patch(const memory_units_descriptor &descriptor, u8 rkey, std::vector &mappings, handler_entry_write *&target) +{ + u8 ukey = descriptor.rkey_to_ukey(rkey); + handler_entry_write *original = target->is_units() ? target : nullptr; + handler_entry_write *replacement = nullptr; + for(const auto &p : mappings) + if(p.ukey == ukey && p.original == original) { + replacement = p.patched; + break; + } + if(!replacement) { + if(original) + replacement = new handler_entry_write_units(descriptor, ukey, static_cast *>(original)); + else + replacement = new handler_entry_write_units(descriptor, ukey, inh::m_space); + + mappings.emplace_back(mapping{ original, replacement, ukey }); + } else + replacement->ref(); + target->unref(); + target = replacement; +} + +template void handler_entry_write_dispatch::populate_mismatched_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, const memory_units_descriptor &descriptor, u8 rkey, std::vector &mappings) +{ + auto cur = m_dispatch[entry]; + if(cur->is_dispatch()) + cur->populate_mismatched_nomirror(start, end, ostart, oend, descriptor, rkey, mappings); + else { + auto subdispatch = new handler_entry_write_dispatch(handler_entry::m_space, m_ranges[entry], cur); + cur->unref(); + m_dispatch[entry] = subdispatch; + subdispatch->populate_mismatched_nomirror(start, end, ostart, oend, descriptor, rkey, mappings); + } +} + +template void handler_entry_write_dispatch::populate_mismatched_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, const memory_units_descriptor &descriptor, u8 rkey, std::vector &mappings) +{ + offs_t start_entry = (start & HIGHMASK) >> LowBits; + offs_t end_entry = (end & HIGHMASK) >> LowBits; + range_cut_before(ostart-1, start_entry); + range_cut_after(oend+1, end_entry); + + if(LowBits <= Width + AddrShift) { + for(offs_t ent = start_entry; ent <= end_entry; ent++) { + u8 rkey1 = rkey; + if(ent != start_entry) + rkey1 &= ~handler_entry::START; + if(ent != end_entry) + rkey1 &= ~handler_entry::END; + mismatched_patch(descriptor, rkey1, mappings, m_dispatch[ent]); + m_ranges[ent].intersect(ostart, oend); + } + + } else if(start_entry == end_entry) { + if(!(start & LOWMASK) && (end & LOWMASK) == LOWMASK) { + if(m_dispatch[start_entry]->is_dispatch()) + m_dispatch[start_entry]->populate_mismatched_nomirror(start & LOWMASK, end & LOWMASK, ostart, oend, descriptor, rkey, mappings); + else { + mismatched_patch(descriptor, rkey, mappings, m_dispatch[start_entry]); + m_ranges[start_entry].intersect(ostart, oend); + } + } else + populate_mismatched_nomirror_subdispatch(start_entry, start & LOWMASK, end & LOWMASK, ostart, oend, descriptor, rkey, mappings); + + } else { + if(start & LOWMASK) { + populate_mismatched_nomirror_subdispatch(start_entry, start & LOWMASK, LOWMASK, ostart, oend, descriptor, rkey & ~handler_entry::END, mappings); + start_entry++; + rkey &= ~handler_entry::START; + } + if((end & LOWMASK) != LOWMASK) { + populate_mismatched_nomirror_subdispatch(end_entry, 0, end & LOWMASK, ostart, oend, descriptor, rkey & ~handler_entry::START, mappings); + end_entry--; + rkey &= ~handler_entry::END; + } + + if(start_entry <= end_entry) { + for(offs_t ent = start_entry; ent <= end_entry; ent++) { + u8 rkey1 = rkey; + if(ent != start_entry) + rkey1 &= ~handler_entry::START; + if(ent != end_entry) + rkey1 &= ~handler_entry::END; + if(m_dispatch[ent]->is_dispatch()) + m_dispatch[ent]->populate_mismatched_nomirror(start & LOWMASK, end & LOWMASK, ostart, oend, descriptor, rkey1, mappings); + else { + mismatched_patch(descriptor, rkey1, mappings, m_dispatch[ent]); + m_ranges[ent].intersect(ostart, oend); + } + } + } + } +} + +template void handler_entry_write_dispatch::populate_mismatched_mirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, const memory_units_descriptor &descriptor, std::vector &mappings) +{ + auto cur = m_dispatch[entry]; + if(cur->is_dispatch()) + cur->populate_mismatched_mirror(start, end, ostart, oend, mirror, descriptor, mappings); + else { + auto subdispatch = new handler_entry_write_dispatch(handler_entry::m_space, m_ranges[entry], cur); + cur->unref(); + m_dispatch[entry] = subdispatch; + subdispatch->populate_mismatched_mirror(start, end, ostart, oend, mirror, descriptor, mappings); + } +} + +template void handler_entry_write_dispatch::populate_mismatched_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, const memory_units_descriptor &descriptor, std::vector &mappings) +{ + offs_t hmirror = mirror & HIGHMASK; + offs_t lmirror = mirror & LOWMASK; + + if(lmirror) { + // If lmirror is non-zero, then each mirror instance is a single entry + offs_t add = 1 + ~hmirror; + offs_t offset = 0; + offs_t base_entry = start >> LowBits; + start &= LOWMASK; + end &= LOWMASK; + do { + populate_mismatched_mirror_subdispatch(base_entry | (offset >> LowBits), start, end, ostart | offset, oend | offset, lmirror, descriptor, mappings); + offset = (offset + add) & hmirror; + } while(offset); + } else { + // If lmirror is zero, call the nomirror version as needed + offs_t add = 1 + ~hmirror; + offs_t offset = 0; + do { + populate_mismatched_nomirror(start | offset, end | offset, ostart | offset, oend | offset, descriptor, handler_entry::START|handler_entry::END, mappings); + offset = (offset + add) & hmirror; + } while(offset); + } +} + + +template void handler_entry_write_dispatch::passthrough_patch(handler_entry_write_passthrough *handler, std::vector &mappings, handler_entry_write *&target) +{ + handler_entry_write *original = target; + handler_entry_write *replacement = nullptr; + for(const auto &p : mappings) + if(p.original == original) { + replacement = p.patched; + break; + } + if(!replacement) { + replacement = handler->instantiate(original); + mappings.emplace_back(mapping{ original, replacement }); + } else + replacement->ref(); + target->unref(); + target = replacement; +} + +template void handler_entry_write_dispatch::populate_passthrough_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_write_passthrough *handler, std::vector &mappings) +{ + auto cur = m_dispatch[entry]; + if(cur->is_dispatch()) + cur->populate_passthrough_nomirror(start, end, ostart, oend, handler, mappings); + else { + auto subdispatch = new handler_entry_write_dispatch(handler_entry::m_space, m_ranges[entry], cur); + cur->unref(); + m_dispatch[entry] = subdispatch; + subdispatch->populate_passthrough_nomirror(start, end, ostart, oend, handler, mappings); + } +} + +template void handler_entry_write_dispatch::populate_passthrough_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_write_passthrough *handler, std::vector &mappings) +{ + offs_t start_entry = (start & HIGHMASK) >> LowBits; + offs_t end_entry = (end & HIGHMASK) >> LowBits; + range_cut_before(ostart-1, start_entry); + range_cut_after(oend+1, end_entry); + + if(LowBits <= Width + AddrShift) { + for(offs_t ent = start_entry; ent <= end_entry; ent++) { + passthrough_patch(handler, mappings, m_dispatch[ent]); + m_ranges[ent].intersect(ostart, oend); + } + + } else if(start_entry == end_entry) { + if(!(start & LOWMASK) && (end & LOWMASK) == LOWMASK) { + if(m_dispatch[start_entry]->is_dispatch()) + m_dispatch[start_entry]->populate_passthrough_nomirror(start & LOWMASK, end & LOWMASK, ostart, oend, handler, mappings); + else { + passthrough_patch(handler, mappings, m_dispatch[start_entry]); + m_ranges[start_entry].intersect(ostart, oend); + } + } else + populate_passthrough_nomirror_subdispatch(start_entry, start & LOWMASK, end & LOWMASK, ostart, oend, handler, mappings); + + } else { + if(start & LOWMASK) { + populate_passthrough_nomirror_subdispatch(start_entry, start & LOWMASK, LOWMASK, ostart, oend, handler, mappings); + start_entry++; + } + if((end & LOWMASK) != LOWMASK) { + populate_passthrough_nomirror_subdispatch(end_entry, 0, end & LOWMASK, ostart, oend, handler, mappings); + end_entry--; + } + + if(start_entry <= end_entry) { + for(offs_t ent = start_entry; ent <= end_entry; ent++) { + if(m_dispatch[ent]->is_dispatch()) + m_dispatch[ent]->populate_passthrough_nomirror(start & LOWMASK, end & LOWMASK, ostart, oend, handler, mappings); + else { + passthrough_patch(handler, mappings, m_dispatch[ent]); + m_ranges[ent].intersect(ostart, oend); + } + } + } + } +} + +template void handler_entry_write_dispatch::populate_passthrough_mirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_write_passthrough *handler, std::vector &mappings) +{ + auto cur = m_dispatch[entry]; + if(cur->is_dispatch()) + cur->populate_passthrough_mirror(start, end, ostart, oend, mirror, handler, mappings); + else { + auto subdispatch = new handler_entry_write_dispatch(handler_entry::m_space, m_ranges[entry], cur); + cur->unref(); + m_dispatch[entry] = subdispatch; + subdispatch->populate_passthrough_mirror(start, end, ostart, oend, mirror, handler, mappings); + } +} + +template void handler_entry_write_dispatch::populate_passthrough_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_write_passthrough *handler, std::vector &mappings) +{ + offs_t hmirror = mirror & HIGHMASK; + offs_t lmirror = mirror & LOWMASK; + + if(lmirror) { + // If lmirror is non-zero, then each mirror instance is a single entry + offs_t add = 1 + ~hmirror; + offs_t offset = 0; + offs_t base_entry = start >> LowBits; + start &= LOWMASK; + end &= LOWMASK; + do { + populate_passthrough_mirror_subdispatch(base_entry | (offset >> LowBits), start, end, ostart | offset, oend | offset, lmirror, handler, mappings); + offset = (offset + add) & hmirror; + } while(offset); + } else { + // If lmirror is zero, call the nomirror version as needed + offs_t add = 1 + ~hmirror; + offs_t offset = 0; + do { + populate_passthrough_nomirror(start | offset, end | offset, ostart | offset, oend | offset, handler, mappings); + offset = (offset + add) & hmirror; + } while(offset); + } +} + +template void handler_entry_write_dispatch::detach(const std::unordered_set &handlers) +{ + for(unsigned int i=0; i != COUNT; i++) { + m_dispatch[i]->unref(); + if(!m_dispatch[i]->is_passthrough()) + continue; + auto np = static_cast *>(m_dispatch[i]); + + if(handlers.find(np) != handlers.end()) { + m_dispatch[i] = np->get_subhandler(); + m_dispatch[i]->ref(); + np->unref(); + + } else + np->detach(handlers); + } +} diff --git a/src/emu/emumem_hedw0.cpp b/src/emu/emumem_hedw0.cpp new file mode 100644 index 00000000000..6a1d0b99699 --- /dev/null +++ b/src/emu/emumem_hedw0.cpp @@ -0,0 +1,171 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +#include "emu.h" +#include "emumem_hedw.ipp" + + +template class handler_entry_write_dispatch< 1, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 1, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 2, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 2, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 3, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 3, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 4, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 4, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 5, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 5, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 6, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 6, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 7, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 7, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 8, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 8, 0, 0, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch< 1, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 1, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 2, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 2, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 3, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 3, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 4, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 4, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 5, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 5, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 6, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 6, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 7, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 7, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 8, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 8, 1, 3, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch< 1, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 1, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 2, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 2, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 3, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 3, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 4, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 4, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 5, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 5, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 6, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 6, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 7, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 7, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 8, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 8, 1, 0, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch< 1, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 1, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 2, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 2, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 3, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 3, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 4, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 4, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 5, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 5, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 6, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 6, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 7, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 7, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 8, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 8, 1, -1, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch< 2, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 2, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 3, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 3, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 4, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 4, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 5, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 5, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 6, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 6, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 7, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 7, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 8, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 8, 2, 0, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch< 2, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 2, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 3, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 3, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 4, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 4, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 5, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 5, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 6, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 6, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 7, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 7, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 8, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 8, 2, -1, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch< 2, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 2, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 3, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 3, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 4, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 4, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 5, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 5, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 6, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 6, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 7, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 7, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 8, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 8, 2, -2, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch< 3, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 3, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 4, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 4, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 5, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 5, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 6, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 6, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 7, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 7, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 8, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 8, 3, 0, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch< 3, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 3, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 4, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 4, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 5, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 5, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 6, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 6, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 7, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 7, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 8, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 8, 3, -1, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch< 3, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 3, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 4, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 4, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 5, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 5, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 6, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 6, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 7, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 7, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 8, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 8, 3, -2, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch< 3, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 3, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 4, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 4, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 5, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 5, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 6, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 6, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 7, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 7, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 8, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 8, 3, -3, ENDIANNESS_BIG>; diff --git a/src/emu/emumem_hedw1.cpp b/src/emu/emumem_hedw1.cpp new file mode 100644 index 00000000000..4f62d45de4d --- /dev/null +++ b/src/emu/emumem_hedw1.cpp @@ -0,0 +1,192 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +#include "emu.h" +#include "emumem_hedw.ipp" + +template class handler_entry_write_dispatch< 9, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 9, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<10, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<10, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<11, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<11, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<12, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<12, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<13, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<13, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<14, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<14, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<15, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<15, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<16, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<16, 0, 0, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch< 9, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 9, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<10, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<10, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<11, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<11, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<12, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<12, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<13, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<13, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<14, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<14, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<15, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<15, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<16, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<16, 1, 3, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch< 9, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 9, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<10, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<10, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<11, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<11, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<12, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<12, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<13, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<13, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<14, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<14, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<15, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<15, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<16, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<16, 1, 0, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch< 9, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 9, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<10, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<10, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<11, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<11, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<12, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<12, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<13, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<13, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<14, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<14, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<15, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<15, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<16, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<16, 1, -1, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch< 9, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 9, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<10, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<10, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<11, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<11, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<12, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<12, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<13, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<13, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<14, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<14, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<15, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<15, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<16, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<16, 2, 0, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch< 9, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 9, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<10, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<10, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<11, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<11, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<12, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<12, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<13, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<13, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<14, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<14, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<15, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<15, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<16, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<16, 2, -1, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch< 9, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 9, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<10, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<10, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<11, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<11, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<12, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<12, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<13, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<13, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<14, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<14, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<15, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<15, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<16, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<16, 2, -2, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch< 9, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 9, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<10, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<10, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<11, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<11, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<12, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<12, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<13, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<13, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<14, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<14, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<15, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<15, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<16, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<16, 3, 0, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch< 9, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 9, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<10, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<10, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<11, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<11, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<12, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<12, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<13, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<13, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<14, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<14, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<15, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<15, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<16, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<16, 3, -1, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch< 9, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 9, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<10, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<10, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<11, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<11, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<12, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<12, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<13, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<13, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<14, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<14, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<15, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<15, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<16, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<16, 3, -2, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch< 9, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 9, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<10, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<10, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<11, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<11, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<12, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<12, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<13, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<13, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<14, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<14, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<15, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<15, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<16, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<16, 3, -3, ENDIANNESS_BIG>; diff --git a/src/emu/emumem_hedw2.cpp b/src/emu/emumem_hedw2.cpp new file mode 100644 index 00000000000..b00eb38311d --- /dev/null +++ b/src/emu/emumem_hedw2.cpp @@ -0,0 +1,192 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +#include "emu.h" +#include "emumem_hedw.ipp" + +template class handler_entry_write_dispatch<17, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<17, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<18, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<18, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<19, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<19, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<20, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<20, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<21, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<21, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<22, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<22, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<23, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<23, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<24, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<24, 0, 0, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch<17, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<17, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<18, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<18, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<19, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<19, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<20, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<20, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<21, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<21, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<22, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<22, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<23, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<23, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<24, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<24, 1, 3, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch<17, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<17, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<18, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<18, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<19, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<19, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<20, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<20, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<21, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<21, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<22, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<22, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<23, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<23, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<24, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<24, 1, 0, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch<17, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<17, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<18, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<18, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<19, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<19, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<20, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<20, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<21, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<21, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<22, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<22, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<23, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<23, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<24, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<24, 1, -1, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch<17, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<17, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<18, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<18, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<19, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<19, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<20, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<20, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<21, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<21, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<22, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<22, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<23, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<23, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<24, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<24, 2, 0, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch<17, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<17, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<18, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<18, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<19, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<19, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<20, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<20, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<21, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<21, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<22, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<22, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<23, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<23, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<24, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<24, 2, -1, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch<17, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<17, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<18, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<18, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<19, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<19, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<20, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<20, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<21, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<21, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<22, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<22, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<23, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<23, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<24, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<24, 2, -2, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch<17, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<17, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<18, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<18, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<19, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<19, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<20, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<20, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<21, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<21, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<22, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<22, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<23, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<23, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<24, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<24, 3, 0, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch<17, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<17, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<18, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<18, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<19, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<19, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<20, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<20, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<21, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<21, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<22, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<22, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<23, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<23, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<24, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<24, 3, -1, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch<17, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<17, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<18, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<18, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<19, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<19, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<20, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<20, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<21, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<21, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<22, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<22, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<23, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<23, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<24, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<24, 3, -2, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch<17, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<17, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<18, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<18, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<19, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<19, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<20, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<20, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<21, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<21, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<22, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<22, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<23, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<23, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<24, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<24, 3, -3, ENDIANNESS_BIG>; diff --git a/src/emu/emumem_hedw3.cpp b/src/emu/emumem_hedw3.cpp new file mode 100644 index 00000000000..539736655cc --- /dev/null +++ b/src/emu/emumem_hedw3.cpp @@ -0,0 +1,193 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +#include "emu.h" +#include "emumem_hedw.ipp" + + +template class handler_entry_write_dispatch<25, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<25, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<26, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<26, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<27, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<27, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<28, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<28, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<29, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<29, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<30, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<30, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<31, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<31, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<32, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<32, 0, 0, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch<25, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<25, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<26, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<26, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<27, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<27, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<28, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<28, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<29, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<29, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<31, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<31, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<30, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<30, 1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<32, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<32, 1, 3, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch<25, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<25, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<26, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<26, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<27, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<27, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<28, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<28, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<29, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<29, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<31, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<31, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<30, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<30, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<32, 1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<32, 1, 0, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch<25, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<25, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<26, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<26, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<27, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<27, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<28, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<28, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<29, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<29, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<31, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<31, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<30, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<30, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<32, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<32, 1, -1, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch<25, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<25, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<26, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<26, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<27, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<27, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<28, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<28, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<29, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<29, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<31, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<31, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<30, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<30, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<32, 2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<32, 2, 0, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch<25, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<25, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<26, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<26, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<27, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<27, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<28, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<28, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<29, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<29, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<31, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<31, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<30, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<30, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<32, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<32, 2, -1, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch<25, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<25, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<26, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<26, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<27, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<27, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<28, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<28, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<29, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<29, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<31, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<31, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<30, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<30, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<32, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<32, 2, -2, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch<25, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<25, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<26, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<26, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<27, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<27, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<28, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<28, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<29, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<29, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<31, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<31, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<30, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<30, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<32, 3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<32, 3, 0, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch<25, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<25, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<26, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<26, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<27, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<27, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<28, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<28, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<29, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<29, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<31, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<31, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<30, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<30, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<32, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<32, 3, -1, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch<25, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<25, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<26, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<26, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<27, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<27, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<28, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<28, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<29, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<29, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<31, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<31, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<30, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<30, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<32, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<32, 3, -2, ENDIANNESS_BIG>; + +template class handler_entry_write_dispatch<25, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<25, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<26, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<26, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<27, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<27, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<28, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<28, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<29, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<29, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<31, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<31, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<30, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<30, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch<32, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch<32, 3, -3, ENDIANNESS_BIG>; diff --git a/src/emu/emumem_hem.cpp b/src/emu/emumem_hem.cpp new file mode 100644 index 00000000000..6a897b2c07c --- /dev/null +++ b/src/emu/emumem_hem.cpp @@ -0,0 +1,189 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +#include "emu.h" +#include "emumem_hea.h" +#include "emumem_hem.h" + +template typename handler_entry_size::uX handler_entry_read_memory::read(offs_t offset, uX mem_mask) +{ + return m_base[((offset - inh::m_address_base) & inh::m_address_mask) >> (Width + AddrShift)]; +} + +template void *handler_entry_read_memory::get_ptr(offs_t offset) const +{ + return m_base + (((offset - inh::m_address_base) & inh::m_address_mask) >> (Width + AddrShift)); +} + +template std::string handler_entry_read_memory::name() const +{ + return util::string_format("memory@%x", inh::m_address_base); +} + + +template void handler_entry_write_memory::write(offs_t offset, uX data, uX mem_mask) +{ + offs_t off = ((offset - inh::m_address_base) & inh::m_address_mask) >> (Width + AddrShift); + m_base[off] = (m_base[off] & ~mem_mask) | (data & mem_mask); +} + +template<> void handler_entry_write_memory<0, 0, ENDIANNESS_LITTLE>::write(offs_t offset, u8 data, u8 mem_mask) +{ + m_base[(offset - inh::m_address_base) & inh::m_address_mask] = data; +} + +template<> void handler_entry_write_memory<0, 0, ENDIANNESS_BIG>::write(offs_t offset, u8 data, u8 mem_mask) +{ + m_base[(offset - inh::m_address_base) & inh::m_address_mask] = data; +} + +template void *handler_entry_write_memory::get_ptr(offs_t offset) const +{ + return m_base + (((offset - inh::m_address_base) & inh::m_address_mask) >> (Width + AddrShift)); +} + +template std::string handler_entry_write_memory::name() const +{ + return util::string_format("memory@%x", inh::m_address_base); +} + + + + + +template typename handler_entry_size::uX handler_entry_read_memory_bank::read(offs_t offset, uX mem_mask) +{ + return static_cast(m_bank.base())[((offset - inh::m_address_base) & inh::m_address_mask) >> (Width + AddrShift)]; +} + +template void *handler_entry_read_memory_bank::get_ptr(offs_t offset) const +{ + return static_cast(m_bank.base()) + (((offset - inh::m_address_base) & inh::m_address_mask) >> (Width + AddrShift)); +} + +template std::string handler_entry_read_memory_bank::name() const +{ + return m_bank.name(); +} + + +template void handler_entry_write_memory_bank::write(offs_t offset, uX data, uX mem_mask) +{ + offs_t off = ((offset - inh::m_address_base) & inh::m_address_mask) >> (Width + AddrShift); + static_cast(m_bank.base())[off] = (static_cast(m_bank.base())[off] & ~mem_mask) | (data & mem_mask); +} + +template<> void handler_entry_write_memory_bank<0, 0, ENDIANNESS_LITTLE>::write(offs_t offset, u8 data, u8 mem_mask) +{ + static_cast(m_bank.base())[(offset - inh::m_address_base) & inh::m_address_mask] = data; +} + +template<> void handler_entry_write_memory_bank<0, 0, ENDIANNESS_BIG>::write(offs_t offset, u8 data, u8 mem_mask) +{ + static_cast(m_bank.base())[(offset - inh::m_address_base) & inh::m_address_mask] = data; +} + +template void *handler_entry_write_memory_bank::get_ptr(offs_t offset) const +{ + return static_cast(m_bank.base()) + (((offset - inh::m_address_base) & inh::m_address_mask) >> (Width + AddrShift)); +} + +template std::string handler_entry_write_memory_bank::name() const +{ + return m_bank.name(); +} + + + +template class handler_entry_read_memory<0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_memory<0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_memory<1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_memory<1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_memory<1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_memory<1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_memory<1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_memory<1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_memory<2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_memory<2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_memory<2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_memory<2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_memory<2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_memory<2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_memory<3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_memory<3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_memory<3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_memory<3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_memory<3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_memory<3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_memory<3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_memory<3, -3, ENDIANNESS_BIG>; + +template class handler_entry_write_memory<0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_memory<0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_memory<1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_memory<1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_memory<1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_memory<1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_memory<1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_memory<1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_memory<2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_memory<2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_memory<2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_memory<2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_memory<2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_memory<2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_memory<3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_memory<3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_memory<3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_memory<3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_memory<3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_memory<3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_memory<3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_memory<3, -3, ENDIANNESS_BIG>; + + +template class handler_entry_read_memory_bank<0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_memory_bank<0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_memory_bank<1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_memory_bank<1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_memory_bank<1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_memory_bank<1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_memory_bank<1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_memory_bank<1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_memory_bank<2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_memory_bank<2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_memory_bank<2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_memory_bank<2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_memory_bank<2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_memory_bank<2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_memory_bank<3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_memory_bank<3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_memory_bank<3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_memory_bank<3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_memory_bank<3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_memory_bank<3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_memory_bank<3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_memory_bank<3, -3, ENDIANNESS_BIG>; + +template class handler_entry_write_memory_bank<0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_memory_bank<0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_memory_bank<1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_memory_bank<1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_memory_bank<1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_memory_bank<1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_memory_bank<1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_memory_bank<1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_memory_bank<2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_memory_bank<2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_memory_bank<2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_memory_bank<2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_memory_bank<2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_memory_bank<2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_memory_bank<3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_memory_bank<3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_memory_bank<3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_memory_bank<3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_memory_bank<3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_memory_bank<3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_memory_bank<3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_memory_bank<3, -3, ENDIANNESS_BIG>; diff --git a/src/emu/emumem_hem.h b/src/emu/emumem_hem.h new file mode 100644 index 00000000000..554f6957a18 --- /dev/null +++ b/src/emu/emumem_hem.h @@ -0,0 +1,87 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +// handler_entry_read_memory/handler_entry_write_memory + +// Accesses fixed memory (non-banked rom or ram) + +template class handler_entry_read_memory : public handler_entry_read_address +{ +public: + using uX = typename handler_entry_size::uX; + using inh = handler_entry_read_address; + + handler_entry_read_memory(address_space *space) : handler_entry_read_address(space, 0) {} + ~handler_entry_read_memory() = default; + + uX read(offs_t offset, uX mem_mask) override; + void *get_ptr(offs_t offset) const override; + + inline void set_base(uX *base) { m_base = base; } + + std::string name() const override; + +private: + uX *m_base; +}; + +template class handler_entry_write_memory : public handler_entry_write_address +{ +public: + using uX = typename handler_entry_size::uX; + using inh = handler_entry_write_address; + + handler_entry_write_memory(address_space *space) : handler_entry_write_address(space, 0) {} + ~handler_entry_write_memory() = default; + + void write(offs_t offset, uX data, uX mem_mask) override; + void *get_ptr(offs_t offset) const override; + + inline void set_base(uX *base) { m_base = base; } + + std::string name() const override; + +private: + uX *m_base; +}; + + +// handler_entry_read_memory_bank/handler_entry_write_memory_bank + +// Accesses banked memory, associated to a memory_bank + +template class handler_entry_read_memory_bank : public handler_entry_read_address +{ +public: + using uX = typename handler_entry_size::uX; + using inh = handler_entry_read_address; + + handler_entry_read_memory_bank(address_space *space, memory_bank &bank) : handler_entry_read_address(space, 0), m_bank(bank) {} + ~handler_entry_read_memory_bank() = default; + + uX read(offs_t offset, uX mem_mask) override; + void *get_ptr(offs_t offset) const override; + + std::string name() const override; + +private: + memory_bank &m_bank; +}; + +template class handler_entry_write_memory_bank : public handler_entry_write_address +{ +public: + using uX = typename handler_entry_size::uX; + using inh = handler_entry_write_address; + + handler_entry_write_memory_bank(address_space *space, memory_bank &bank) : handler_entry_write_address(space, 0), m_bank(bank) {} + ~handler_entry_write_memory_bank() = default; + + void write(offs_t offset, uX data, uX mem_mask) override; + void *get_ptr(offs_t offset) const override; + + std::string name() const override; + +private: + memory_bank &m_bank; +}; diff --git a/src/emu/emumem_hep.cpp b/src/emu/emumem_hep.cpp new file mode 100644 index 00000000000..97bdf759a38 --- /dev/null +++ b/src/emu/emumem_hep.cpp @@ -0,0 +1,97 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +#include "emu.h" +#include "emumem_hep.h" + +template handler_entry_read_passthrough::~handler_entry_read_passthrough() +{ + if(m_next) { + m_mph.remove_handler(this); + m_next->unref(); + } +} + +template void handler_entry_read_passthrough::detach(const std::unordered_set &handlers) +{ + if(!m_next->is_passthrough()) + return; + auto np = static_cast *>(m_next); + + if(handlers.find(np) != handlers.end()) { + m_next = np->get_subhandler(); + m_next->ref(); + np->unref(); + + } else + np->detach(handlers); +} + +template handler_entry_write_passthrough::~handler_entry_write_passthrough() +{ + if(m_next) { + m_mph.remove_handler(this); + m_next->unref(); + } +} + +template void handler_entry_write_passthrough::detach(const std::unordered_set &handlers) +{ + if(!m_next->is_passthrough()) + return; + auto np = static_cast *>(m_next); + + if(handlers.find(np) != handlers.end()) { + m_next = np->get_subhandler(); + m_next->ref(); + np->unref(); + + } else + np->detach(handlers); +} + +template class handler_entry_read_passthrough<0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_passthrough<0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_passthrough<1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_passthrough<1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_passthrough<1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_passthrough<1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_passthrough<1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_passthrough<1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_passthrough<2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_passthrough<2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_passthrough<2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_passthrough<2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_passthrough<2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_passthrough<2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_passthrough<3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_passthrough<3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_passthrough<3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_passthrough<3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_passthrough<3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_passthrough<3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_passthrough<3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_passthrough<3, -3, ENDIANNESS_BIG>; + +template class handler_entry_write_passthrough<0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_passthrough<0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_passthrough<1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_passthrough<1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_passthrough<1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_passthrough<1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_passthrough<1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_passthrough<1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_passthrough<2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_passthrough<2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_passthrough<2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_passthrough<2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_passthrough<2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_passthrough<2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_passthrough<3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_passthrough<3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_passthrough<3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_passthrough<3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_passthrough<3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_passthrough<3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_passthrough<3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_passthrough<3, -3, ENDIANNESS_BIG>; diff --git a/src/emu/emumem_hep.h b/src/emu/emumem_hep.h new file mode 100644 index 00000000000..11da1dc2bca --- /dev/null +++ b/src/emu/emumem_hep.h @@ -0,0 +1,48 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +// handler_entry_read_passthrough/handler_entry_write_passthrough + +// parent class for handlers which want to tap the access and usually pass it on to another handler + +template class handler_entry_read_passthrough : public handler_entry_read +{ +public: + using uX = typename handler_entry_size::uX; + + handler_entry_read_passthrough(address_space *space, memory_passthrough_handler &mph) : handler_entry_read(space, handler_entry::F_PASSTHROUGH), m_mph(mph), m_next(nullptr) {} + ~handler_entry_read_passthrough(); + + virtual handler_entry_read_passthrough *instantiate(handler_entry_read *next) const = 0; + + handler_entry_read *get_subhandler() const { return m_next; } + + void detach(const std::unordered_set &handlers) override; + +protected: + memory_passthrough_handler &m_mph; + handler_entry_read *m_next; + + handler_entry_read_passthrough(address_space *space, memory_passthrough_handler &mph, handler_entry_read *next) : handler_entry_read(space, handler_entry::F_PASSTHROUGH), m_mph(mph), m_next(next) { next->ref(); mph.add_handler(this); } +}; + +template class handler_entry_write_passthrough : public handler_entry_write +{ +public: + using uX = typename handler_entry_size::uX; + + handler_entry_write_passthrough(address_space *space, memory_passthrough_handler &mph) : handler_entry_write(space, handler_entry::F_PASSTHROUGH), m_mph(mph), m_next(nullptr) {} + ~handler_entry_write_passthrough(); + + virtual handler_entry_write_passthrough *instantiate(handler_entry_write *next) const = 0; + + handler_entry_write *get_subhandler() const { return m_next; } + + void detach(const std::unordered_set &handlers) override; + +protected: + memory_passthrough_handler &m_mph; + handler_entry_write *m_next; + + handler_entry_write_passthrough(address_space *space, memory_passthrough_handler &mph, handler_entry_write *next) : handler_entry_write(space, handler_entry::F_PASSTHROUGH), m_mph(mph), m_next(next) { next->ref(); mph.add_handler(this); } +}; diff --git a/src/emu/emumem_het.cpp b/src/emu/emumem_het.cpp new file mode 100644 index 00000000000..6870284d61d --- /dev/null +++ b/src/emu/emumem_het.cpp @@ -0,0 +1,89 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +#include "emu.h" +#include "emumem_hep.h" +#include "emumem_het.h" + +template typename handler_entry_size::uX handler_entry_read_tap::read(offs_t offset, uX mem_mask) +{ + uX data = inh::m_next->read(offset, mem_mask); + m_tap(offset, data, mem_mask); + return data; +} + +template std::string handler_entry_read_tap::name() const +{ + return '(' + m_name + ") " + inh::m_next->name(); +} + +template handler_entry_read_tap *handler_entry_read_tap::instantiate(handler_entry_read *next) const +{ + return new handler_entry_read_tap(inh::m_space, inh::m_mph, next, m_name, m_tap); +} + + +template void handler_entry_write_tap::write(offs_t offset, uX data, uX mem_mask) +{ + m_tap(offset, data, mem_mask); + inh::m_next->write(offset, data, mem_mask); +} + +template std::string handler_entry_write_tap::name() const +{ + return '(' + m_name + ") " + inh::m_next->name(); +} + + +template handler_entry_write_tap *handler_entry_write_tap::instantiate(handler_entry_write *next) const +{ + return new handler_entry_write_tap(inh::m_space, inh::m_mph, next, m_name, m_tap); +} + + + +template class handler_entry_read_tap<0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_tap<0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_tap<1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_tap<1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_tap<1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_tap<1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_tap<1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_tap<1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_tap<2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_tap<2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_tap<2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_tap<2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_tap<2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_tap<2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_tap<3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_tap<3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_tap<3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_tap<3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_tap<3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_tap<3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_tap<3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_tap<3, -3, ENDIANNESS_BIG>; + +template class handler_entry_write_tap<0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_tap<0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_tap<1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_tap<1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_tap<1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_tap<1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_tap<1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_tap<1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_tap<2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_tap<2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_tap<2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_tap<2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_tap<2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_tap<2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_tap<3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_tap<3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_tap<3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_tap<3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_tap<3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_tap<3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_tap<3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_tap<3, -3, ENDIANNESS_BIG>; diff --git a/src/emu/emumem_het.h b/src/emu/emumem_het.h new file mode 100644 index 00000000000..785c840d75d --- /dev/null +++ b/src/emu/emumem_het.h @@ -0,0 +1,50 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +// handler_entry_read_tap/handler_entry_write_tap + +// handler which tap on a bus access and possibly change the data value through a std::function + +template class handler_entry_read_tap : public handler_entry_read_passthrough +{ +public: + using uX = typename handler_entry_size::uX; + using inh = handler_entry_read_passthrough; + + handler_entry_read_tap(address_space *space, memory_passthrough_handler &mph, std::string name, std::function tap) : handler_entry_read_passthrough(space, mph), m_name(name), m_tap(std::move(tap)) {} + ~handler_entry_read_tap() = default; + + uX read(offs_t offset, uX mem_mask) override; + + std::string name() const override; + + handler_entry_read_tap *instantiate(handler_entry_read *next) const override; + +protected: + std::string m_name; + std::function m_tap; + + handler_entry_read_tap(address_space *space, memory_passthrough_handler &mph, handler_entry_read *next, std::string name, std::function tap) : handler_entry_read_passthrough(space, mph, next), m_name(name), m_tap(tap) {} +}; + +template class handler_entry_write_tap : public handler_entry_write_passthrough +{ +public: + using uX = typename handler_entry_size::uX; + using inh = handler_entry_write_passthrough; + + handler_entry_write_tap(address_space *space, memory_passthrough_handler &mph, std::string name, std::function tap) : handler_entry_write_passthrough(space, mph), m_name(name), m_tap(std::move(tap)) {} + ~handler_entry_write_tap() = default; + + void write(offs_t offset, uX data, uX mem_mask) override; + + std::string name() const override; + + handler_entry_write_tap *instantiate(handler_entry_write *next) const override; + +protected: + std::string m_name; + std::function m_tap; + + handler_entry_write_tap(address_space *space, memory_passthrough_handler &mph, handler_entry_write *next, std::string name, std::function tap) : handler_entry_write_passthrough(space, mph, next), m_name(name), m_tap(tap) {} +}; diff --git a/src/emu/emumem_heu.cpp b/src/emu/emumem_heu.cpp new file mode 100644 index 00000000000..8942ad4418b --- /dev/null +++ b/src/emu/emumem_heu.cpp @@ -0,0 +1,273 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +#include "emu.h" +#include "emumem_hea.h" +#include "emumem_mud.h" +#include "emumem_heu.h" + + +template handler_entry_read_units::handler_entry_read_units(const memory_units_descriptor &descriptor, u8 ukey, address_space *space) : + handler_entry_read(space, inh::F_UNITS), + m_subunits(0) +{ + const auto &entries = descriptor.get_entries_for_key(ukey); + fill(descriptor, entries); +} + +template handler_entry_read_units::handler_entry_read_units(const memory_units_descriptor &descriptor, u8 ukey, const handler_entry_read_units *src) : + handler_entry_read(src->m_space, inh::F_UNITS), + m_subunits(0) +{ + uX fullmask = 0; + const auto &entries = descriptor.get_entries_for_key(ukey); + for(const auto &e : entries) + fullmask |= e.m_dmask; + + for(u32 i=0; i != src->m_subunits; i++) + if(!(src->m_subunit_infos[i].m_dmask & fullmask)) { + m_subunit_infos[m_subunits] = src->m_subunit_infos[i]; + m_subunit_infos[m_subunits].m_handler->ref(); + m_subunits++; + } + + fill(descriptor, entries); +} + +template handler_entry_read_units::~handler_entry_read_units() +{ + for(u32 i=0; i != m_subunits; i++) + m_subunit_infos[i].m_handler->unref(); +} + +template void handler_entry_read_units::enumerate_references(handler_entry::reflist &refs) const +{ + for(u32 i=0; i != m_subunits; i++) + refs.add(m_subunit_infos[i].m_handler); +} + +template void handler_entry_read_units::fill(const memory_units_descriptor &descriptor, const std::vector::entry> &entries) +{ + handler_entry *handler = descriptor.get_subunit_handler(); + handler->ref(entries.size()); + for(const auto &e : entries) + m_subunit_infos[m_subunits++] = subunit_info{ handler, e.m_amask, e.m_dmask, e.m_ashift, e.m_offset, e.m_dshift, descriptor.get_subunit_width(), descriptor.get_subunit_endian() }; + m_unmap = inh::m_space->unmap(); + for(const auto &e : m_subunit_infos) + m_unmap &= ~e.m_dmask; +} + + +template typename handler_entry_size::uX handler_entry_read_units::read(offs_t offset, uX mem_mask) +{ + uX result = m_unmap; + for (int index = 0; index < m_subunits; index++) { + const subunit_info &si = m_subunit_infos[index]; + if (mem_mask & si.m_amask) { + offs_t aoffset = (si.m_ashift >= 0 ? offset >> si.m_ashift : offset << si.m_ashift) + si.m_offset; + switch(si.m_width) { + case 0: + if(si.m_endian == ENDIANNESS_LITTLE) + result |= uX(static_cast *>(si.m_handler)->read(aoffset, mem_mask >> si.m_dshift)) << si.m_dshift; + else + result |= uX(static_cast *>(si.m_handler)->read(aoffset, mem_mask >> si.m_dshift)) << si.m_dshift; + break; + case 1: + if(si.m_endian == ENDIANNESS_LITTLE) + result |= uX(static_cast *>(si.m_handler)->read(aoffset, mem_mask >> si.m_dshift)) << si.m_dshift; + else + result |= uX(static_cast *>(si.m_handler)->read(aoffset, mem_mask >> si.m_dshift)) << si.m_dshift; + break; + case 2: + if(si.m_endian == ENDIANNESS_LITTLE) + result |= uX(static_cast *>(si.m_handler)->read(aoffset, mem_mask >> si.m_dshift)) << si.m_dshift; + else + result |= uX(static_cast *>(si.m_handler)->read(aoffset, mem_mask >> si.m_dshift)) << si.m_dshift; + break; + default: + abort(); + } + } + } + return result; +} + +template std::string handler_entry_read_units::m2r(typename handler_entry_size::uX mask) +{ + constexpr u32 mbits = 8*sizeof(uX); + u32 start, end; + for(start = 0; start < mbits && !(mask & (uX(1)<= mbits || end >= mbits) + return "???"; + return util::string_format("%d-%d", end, start); +} + +template std::string handler_entry_read_units::name() const +{ + std::string result; + + for (int index = 0; index < m_subunits; index++) { + const subunit_info &si = m_subunit_infos[index]; + if(!result.empty()) + result += ' '; + result += util::string_format("%s:%s:%d:%d:%d:%s", m2r(si.m_amask), m2r(si.m_dmask), si.m_ashift, si.m_offset, si.m_dshift, si.m_handler->name()); + } + + return result; +} + + + + +template handler_entry_write_units::handler_entry_write_units(const memory_units_descriptor &descriptor, u8 ukey, address_space *space) : + handler_entry_write(space, inh::F_UNITS), + m_subunits(0) +{ + const auto &entries = descriptor.get_entries_for_key(ukey); + fill(descriptor, entries); +} + +template handler_entry_write_units::handler_entry_write_units(const memory_units_descriptor &descriptor, u8 ukey, const handler_entry_write_units *src) : + handler_entry_write(src->m_space, inh::F_UNITS), + m_subunits(0) +{ + uX fullmask = 0; + const auto &entries = descriptor.get_entries_for_key(ukey); + for(const auto &e : entries) + fullmask |= e.m_dmask; + + for(u32 i=0; i != src->m_subunits; i++) + if(!(src->m_subunit_infos[i].m_dmask & fullmask)) { + m_subunit_infos[m_subunits] = src->m_subunit_infos[i]; + m_subunit_infos[m_subunits].m_handler->ref(); + m_subunits++; + } + + fill(descriptor, entries); +} + +template handler_entry_write_units::~handler_entry_write_units() +{ + for(u32 i=0; i != m_subunits; i++) + m_subunit_infos[i].m_handler->unref(); +} + +template void handler_entry_write_units::enumerate_references(handler_entry::reflist &refs) const +{ + for(u32 i=0; i != m_subunits; i++) + refs.add(m_subunit_infos[i].m_handler); +} + +template void handler_entry_write_units::fill(const memory_units_descriptor &descriptor, const std::vector::entry> &entries) +{ + handler_entry *handler = descriptor.get_subunit_handler(); + handler->ref(entries.size()); + for(const auto &e : entries) + m_subunit_infos[m_subunits++] = subunit_info{ handler, e.m_amask, e.m_dmask, e.m_ashift, e.m_offset, e.m_dshift, descriptor.get_subunit_width(), descriptor.get_subunit_endian() }; +} + +template void handler_entry_write_units::write(offs_t offset, uX data, uX mem_mask) +{ + for (int index = 0; index < m_subunits; index++) { + const subunit_info &si = m_subunit_infos[index]; + if (mem_mask & si.m_amask) { + offs_t aoffset = (si.m_ashift >= 0 ? offset >> si.m_ashift : offset << si.m_ashift) + si.m_offset; + switch(si.m_width) { + case 0: + if(si.m_endian == ENDIANNESS_LITTLE) + static_cast *>(si.m_handler)->write(aoffset, data >> si.m_dshift, mem_mask >> si.m_dshift); + else + static_cast *>(si.m_handler)->write(aoffset, data >> si.m_dshift, mem_mask >> si.m_dshift); + break; + case 1: + if(si.m_endian == ENDIANNESS_LITTLE) + static_cast *>(si.m_handler)->write(aoffset, data >> si.m_dshift, mem_mask >> si.m_dshift); + else + static_cast *>(si.m_handler)->write(aoffset, data >> si.m_dshift, mem_mask >> si.m_dshift); + break; + case 2: + if(si.m_endian == ENDIANNESS_LITTLE) + static_cast *>(si.m_handler)->write(aoffset, data >> si.m_dshift, mem_mask >> si.m_dshift); + else + static_cast *>(si.m_handler)->write(aoffset, data >> si.m_dshift, mem_mask >> si.m_dshift); + break; + default: + abort(); + } + } + } +} + + +template std::string handler_entry_write_units::m2r(typename handler_entry_size::uX mask) +{ + constexpr u32 mbits = 8*sizeof(uX); + u32 start, end; + for(start = 0; start < mbits && !(mask & (uX(1)<= mbits || end >= mbits) + return "???"; + return util::string_format("%d-%d", end, start); +} + +template std::string handler_entry_write_units::name() const +{ + std::string result; + + for (int index = 0; index < m_subunits; index++) { + const subunit_info &si = m_subunit_infos[index]; + if(!result.empty()) + result += ' '; + result += util::string_format("%s:%s:%d:%d:%d:%s", m2r(si.m_amask), m2r(si.m_dmask), si.m_ashift, si.m_offset, si.m_dshift, si.m_handler->name()); + } + + return result; +} + + +template class handler_entry_read_units<0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_units<0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_units<1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_units<1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_units<1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_units<1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_units<1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_units<1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_units<2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_units<2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_units<2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_units<2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_units<2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_units<2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_units<3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_units<3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_units<3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_units<3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_units<3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_units<3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_units<3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_units<3, -3, ENDIANNESS_BIG>; + +template class handler_entry_write_units<0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_units<0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_units<1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_units<1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_units<1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_units<1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_units<1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_units<1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_units<2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_units<2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_units<2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_units<2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_units<2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_units<2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_units<3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_units<3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_units<3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_units<3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_units<3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_units<3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_units<3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_units<3, -3, ENDIANNESS_BIG>; diff --git a/src/emu/emumem_heu.h b/src/emu/emumem_heu.h new file mode 100644 index 00000000000..c7dcea23287 --- /dev/null +++ b/src/emu/emumem_heu.h @@ -0,0 +1,90 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +// handler_entry_read_units/handler_entry_write_units + +// merges/splits an access among multiple handlers (unitmask support) + +template class handler_entry_read_units : public handler_entry_read +{ +public: + using uX = typename handler_entry_size::uX; + using READ = typename handler_entry_size::READ; + using inh = handler_entry_read; + + handler_entry_read_units(const memory_units_descriptor &descriptor, u8 ukey, address_space *space); + handler_entry_read_units(const memory_units_descriptor &descriptor, u8 ukey, const handler_entry_read_units *src); + ~handler_entry_read_units(); + + uX read(offs_t offset, uX mem_mask) override; + + std::string name() const override; + + void enumerate_references(handler_entry::reflist &refs) const override; + +private: + static constexpr u32 SUBUNIT_COUNT = 1 << Width; + + struct subunit_info + { + handler_entry *m_handler; // the handler itself, the root to hide the templatization + + uX m_amask; // access mask (for filtering access) + uX m_dmask; // data mask (for removal on collisions) + s8 m_ashift; // shift to apply to the address (positive = right) + u8 m_offset; // offset to add to the address post shift + u8 m_dshift; // data shift of the subunit + + u8 m_width; // access width (0..3) + u8 m_endian; // endianness + }; + + subunit_info m_subunit_infos[SUBUNIT_COUNT]; // subunit information + uX m_unmap; // "unmapped" value to add to reads + u8 m_subunits; // number of subunits + + void fill(const memory_units_descriptor &descriptor, const std::vector::entry> &entries); + static std::string m2r(uX mask); +}; + +template class handler_entry_write_units : public handler_entry_write +{ +public: + using uX = typename handler_entry_size::uX; + using WRITE = typename handler_entry_size::WRITE; + using inh = handler_entry_write; + + handler_entry_write_units(const memory_units_descriptor &descriptor, u8 ukey, address_space *space); + handler_entry_write_units(const memory_units_descriptor &descriptor, u8 ukey, const handler_entry_write_units *src); + ~handler_entry_write_units(); + + void write(offs_t offset, uX data, uX mem_mask) override; + + std::string name() const override; + + void enumerate_references(handler_entry::reflist &refs) const override; + +private: + static constexpr u32 SUBUNIT_COUNT = 1 << Width; + + struct subunit_info + { + handler_entry *m_handler; // the handler itself, the root to hide the templatization + + uX m_amask; // access mask (for filtering access) + uX m_dmask; // data mask (for removal on collisions) + s8 m_ashift; // shift to apply to the address (positive = right) + u8 m_offset; // offset to add to the address post shift + u8 m_dshift; // data shift of the subunit + + u8 m_width; // access width (0..3) + u8 m_endian; // endianness + }; + + subunit_info m_subunit_infos[SUBUNIT_COUNT]; // subunit information + u8 m_subunits; // number of subunits + + void fill(const memory_units_descriptor &descriptor, const std::vector::entry> &entries); + static std::string m2r(uX mask); +}; + diff --git a/src/emu/emumem_heun.cpp b/src/emu/emumem_heun.cpp new file mode 100644 index 00000000000..1ab59b17c2f --- /dev/null +++ b/src/emu/emumem_heun.cpp @@ -0,0 +1,158 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +#include "emu.h" +#include "emumem_hea.h" +#include "emumem_heun.h" + +template typename handler_entry_size::uX handler_entry_read_unmapped::read(offs_t offset, uX mem_mask) +{ + if (inh::m_space->log_unmap() && !inh::m_space->m_manager.machine().side_effects_disabled()) + inh::m_space->device().logerror(inh::m_space->is_octal() + ? "%s: unmapped %s memory read from %0*o & %0*o\n" + : "%s: unmapped %s memory read from %0*X & %0*X\n", + inh::m_space->m_manager.machine().describe_context(), inh::m_space->name(), + inh::m_space->addrchars(), offset, + 2 << Width, mem_mask); + return inh::m_space->unmap(); +} + +template std::string handler_entry_read_unmapped::name() const +{ + return "unmapped"; +} + + +template void handler_entry_write_unmapped::write(offs_t offset, uX data, uX mem_mask) +{ + if (inh::m_space->log_unmap() && !inh::m_space->m_manager.machine().side_effects_disabled()) + inh::m_space->device().logerror(inh::m_space->is_octal() + ? "%s: unmapped %s memory write to %0*o = %0*o & %0*o\n" + : "%s: unmapped %s memory write to %0*X = %0*X & %0*X\n", + inh::m_space->m_manager.machine().describe_context(), inh::m_space->name(), + inh::m_space->addrchars(), offset, + 2 << Width, data, + 2 << Width, mem_mask); +} + +template std::string handler_entry_write_unmapped::name() const +{ + return "unmapped"; +} + + + + +template typename handler_entry_size::uX handler_entry_read_nop::read(offs_t offset, uX mem_mask) +{ + return inh::m_space->unmap(); +} + +template std::string handler_entry_read_nop::name() const +{ + return "nop"; +} + + +template void handler_entry_write_nop::write(offs_t offset, uX data, uX mem_mask) +{ +} + +template std::string handler_entry_write_nop::name() const +{ + return "nop"; +} + + +template class handler_entry_read_unmapped<0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_unmapped<0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_unmapped<1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_unmapped<1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_unmapped<1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_unmapped<1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_unmapped<1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_unmapped<1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_unmapped<2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_unmapped<2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_unmapped<2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_unmapped<2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_unmapped<2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_unmapped<2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_unmapped<3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_unmapped<3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_unmapped<3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_unmapped<3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_unmapped<3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_unmapped<3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_unmapped<3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_unmapped<3, -3, ENDIANNESS_BIG>; + +template class handler_entry_write_unmapped<0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_unmapped<0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_unmapped<1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_unmapped<1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_unmapped<1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_unmapped<1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_unmapped<1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_unmapped<1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_unmapped<2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_unmapped<2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_unmapped<2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_unmapped<2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_unmapped<2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_unmapped<2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_unmapped<3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_unmapped<3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_unmapped<3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_unmapped<3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_unmapped<3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_unmapped<3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_unmapped<3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_unmapped<3, -3, ENDIANNESS_BIG>; + + +template class handler_entry_read_nop<0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_nop<0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_nop<1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_nop<1, 3, ENDIANNESS_BIG>; +template class handler_entry_read_nop<1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_nop<1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_nop<1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_nop<1, -1, ENDIANNESS_BIG>; +template class handler_entry_read_nop<2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_nop<2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_nop<2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_nop<2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_nop<2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_nop<2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_nop<3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_nop<3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_nop<3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_nop<3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_nop<3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_nop<3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_nop<3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_nop<3, -3, ENDIANNESS_BIG>; + +template class handler_entry_write_nop<0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_nop<0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_nop<1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_nop<1, 3, ENDIANNESS_BIG>; +template class handler_entry_write_nop<1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_nop<1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_nop<1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_nop<1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_nop<2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_nop<2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_nop<2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_nop<2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_nop<2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_nop<2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_nop<3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_nop<3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_nop<3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_nop<3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_nop<3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_nop<3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_nop<3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_nop<3, -3, ENDIANNESS_BIG>; diff --git a/src/emu/emumem_heun.h b/src/emu/emumem_heun.h new file mode 100644 index 00000000000..2bc4a02a2dc --- /dev/null +++ b/src/emu/emumem_heun.h @@ -0,0 +1,68 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +// handler_entry_read_unmapped/handler_entry_write_unmapped + +// Logs an unmapped access + +template class handler_entry_read_unmapped : public handler_entry_read +{ +public: + using uX = typename handler_entry_size::uX; + using inh = handler_entry_read; + + handler_entry_read_unmapped(address_space *space) : handler_entry_read(space, 0) {} + ~handler_entry_read_unmapped() = default; + + uX read(offs_t offset, uX mem_mask) override; + + std::string name() const override; +}; + +template class handler_entry_write_unmapped : public handler_entry_write +{ +public: + using uX = typename handler_entry_size::uX; + using inh = handler_entry_write; + + handler_entry_write_unmapped(address_space *space) : handler_entry_write(space, 0) {} + ~handler_entry_write_unmapped() = default; + + void write(offs_t offset, uX data, uX mem_mask) override; + + std::string name() const override; +}; + + + +// handler_entry_read_nop/handler_entry_write_nop + +// Drops an unmapped access silently + +template class handler_entry_read_nop : public handler_entry_read +{ +public: + using uX = typename handler_entry_size::uX; + using inh = handler_entry_read; + + handler_entry_read_nop(address_space *space) : handler_entry_read(space, 0) {} + ~handler_entry_read_nop() = default; + + uX read(offs_t offset, uX mem_mask) override; + + std::string name() const override; +}; + +template class handler_entry_write_nop : public handler_entry_write +{ +public: + using uX = typename handler_entry_size::uX; + using inh = handler_entry_write; + + handler_entry_write_nop(address_space *space) : handler_entry_write(space, 0) {} + ~handler_entry_write_nop() = default; + + void write(offs_t offset, uX data, uX mem_mask) override; + + std::string name() const override; +}; diff --git a/src/emu/emumem_mud.cpp b/src/emu/emumem_mud.cpp new file mode 100644 index 00000000000..8279eea5635 --- /dev/null +++ b/src/emu/emumem_mud.cpp @@ -0,0 +1,127 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +#include "emu.h" +#include "emumem_mud.h" + +template static u8 mask_to_ukey(T mask); + +template<> u8 mask_to_ukey(u16 mask) +{ + return + (mask & 0xff00 ? 0x02 : 0x00) | + (mask & 0x00ff ? 0x01 : 0x00); +} + +template<> u8 mask_to_ukey(u32 mask) +{ + return + (mask & 0xff000000 ? 0x08 : 0x00) | + (mask & 0x00ff0000 ? 0x04 : 0x00) | + (mask & 0x0000ff00 ? 0x02 : 0x00) | + (mask & 0x000000ff ? 0x01 : 0x00); +} + +template<> u8 mask_to_ukey(u64 mask) +{ + return + (mask & 0xff00000000000000 ? 0x80 : 0x00) | + (mask & 0x00ff000000000000 ? 0x40 : 0x00) | + (mask & 0x0000ff0000000000 ? 0x20 : 0x00) | + (mask & 0x000000ff00000000 ? 0x10 : 0x00) | + (mask & 0x00000000ff000000 ? 0x08 : 0x00) | + (mask & 0x0000000000ff0000 ? 0x04 : 0x00) | + (mask & 0x000000000000ff00 ? 0x02 : 0x00) | + (mask & 0x00000000000000ff ? 0x01 : 0x00); +} + +template memory_units_descriptor::memory_units_descriptor(u8 access_width, u8 access_endian, handler_entry *handler, offs_t addrstart, offs_t addrend, offs_t mask, typename handler_entry_size::uX unitmask, int cswidth) : m_handler(handler), m_access_width(access_width), m_access_endian(access_endian) +{ + constexpr u32 NATIVE_MASK = Width + AddrShift >= 0 ? make_bitmask(Width + AddrShift) : 0; + u32 bits_per_access = 8 << access_width; + + // Compute the real base addresses + m_addrstart = addrstart & ~NATIVE_MASK; + m_addrend = addrend & ~NATIVE_MASK; + + + // Compute the masks and the keys + std::array umasks; + umasks.fill(unitmask); + + uX smask = ~make_bitmask((addrstart - m_addrstart) << (3 - AddrShift)); + uX emask = make_bitmask((addrend - m_addrend + 1) << (3 - AddrShift)); + + umasks[handler_entry::START] &= smask; + umasks[handler_entry::END] &= emask; + umasks[handler_entry::START|handler_entry::END] &= smask | emask; + + for(u32 i=0; i<4; i++) + m_keymap[i] = mask_to_ukey(umasks[i]); + + + // Compute the shift + uX dmask = make_bitmask(bits_per_access); + u32 active_count = 0; + for(u32 i=0; i != 8 << Width; i += bits_per_access) + if(unitmask & (dmask << i)) + active_count ++; + u32 active_count_log = active_count == 1 ? 0 : active_count == 2 ? 1 : active_count == 4 ? 2 : active_count == 8 ? 3 : 0xff; + if(active_count_log == 0xff) + abort(); + s8 base_shift = Width - access_width - active_count_log; + s8 shift = base_shift + access_width + AddrShift; + + + // Build the handler characteristics + m_handler_start = shift < 0 ? addrstart << -shift : addrstart >> shift; + m_handler_mask = shift < 0 ? (mask << -shift) | make_bitmask(-shift) : mask >> shift; + + for(u32 i=0; i<4; i++) + if(m_entries_for_key.find(m_keymap[i]) == m_entries_for_key.end()) + generate(m_keymap[i], umasks[i], cswidth, bits_per_access, base_shift, shift, active_count); +} + +template void memory_units_descriptor::generate(u8 ukey, typename handler_entry_size::uX umask, u32 cswidth, u32 bits_per_access, u8 base_shift, s8 shift, u32 active_count) +{ + auto &entries = m_entries_for_key[ukey]; + + // Compute the selection masks + if(!cswidth) + cswidth = bits_per_access; + + uX csmask = make_bitmask(cswidth); + uX dmask = make_bitmask(bits_per_access); + + u32 offset = 0; + + for(u32 i=0; i != 8 << Width; i += bits_per_access) { + uX numask = dmask << i; + if(umask & numask) { + uX amask = csmask << (i & ~(cswidth - 1)); + entries.emplace_back(entry{ amask, numask, shift, u8(i), u8(Endian == ENDIANNESS_BIG ? active_count - 1 - offset : offset) }); + offset ++; + } + } +} + +template class memory_units_descriptor<1, 3, ENDIANNESS_LITTLE>; +template class memory_units_descriptor<1, 3, ENDIANNESS_BIG>; +template class memory_units_descriptor<1, 0, ENDIANNESS_LITTLE>; +template class memory_units_descriptor<1, 0, ENDIANNESS_BIG>; +template class memory_units_descriptor<1, -1, ENDIANNESS_LITTLE>; +template class memory_units_descriptor<1, -1, ENDIANNESS_BIG>; +template class memory_units_descriptor<2, 0, ENDIANNESS_LITTLE>; +template class memory_units_descriptor<2, 0, ENDIANNESS_BIG>; +template class memory_units_descriptor<2, -1, ENDIANNESS_LITTLE>; +template class memory_units_descriptor<2, -1, ENDIANNESS_BIG>; +template class memory_units_descriptor<2, -2, ENDIANNESS_LITTLE>; +template class memory_units_descriptor<2, -2, ENDIANNESS_BIG>; +template class memory_units_descriptor<3, 0, ENDIANNESS_LITTLE>; +template class memory_units_descriptor<3, 0, ENDIANNESS_BIG>; +template class memory_units_descriptor<3, -1, ENDIANNESS_LITTLE>; +template class memory_units_descriptor<3, -1, ENDIANNESS_BIG>; +template class memory_units_descriptor<3, -2, ENDIANNESS_LITTLE>; +template class memory_units_descriptor<3, -2, ENDIANNESS_BIG>; +template class memory_units_descriptor<3, -3, ENDIANNESS_LITTLE>; +template class memory_units_descriptor<3, -3, ENDIANNESS_BIG>; diff --git a/src/emu/emumem_mud.h b/src/emu/emumem_mud.h new file mode 100644 index 00000000000..e1299ed7fcc --- /dev/null +++ b/src/emu/emumem_mud.h @@ -0,0 +1,41 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +// Descriptors for subunit support + +template class memory_units_descriptor { +public: + using uX = typename handler_entry_size::uX; + + struct entry { + uX m_amask; + uX m_dmask; + s8 m_ashift; + u8 m_dshift; + u8 m_offset; + }; + + memory_units_descriptor(u8 access_width, u8 access_endian, handler_entry *handler, offs_t addrstart, offs_t addrend, offs_t mask, uX unitmask, int cswidth); + + offs_t get_handler_start() const { return m_handler_start; } + offs_t get_handler_mask() const { return m_handler_mask; } + + u8 rkey_to_ukey(u8 rkey) const { return m_keymap[rkey]; } + const std::vector &get_entries_for_key(u8 key) const { return m_entries_for_key.find(key)->second; } + + u8 get_subunit_width() const { return m_access_width; } + u8 get_subunit_endian() const { return m_access_endian; } + + void set_subunit_handler(handler_entry *handler) { m_handler = handler; } + handler_entry *get_subunit_handler() const { return m_handler; } + +private: + std::map> m_entries_for_key; + offs_t m_addrstart, m_addrend, m_handler_start, m_handler_mask; + handler_entry *m_handler; + std::array m_keymap; + u8 m_access_width; + u8 m_access_endian; + + void generate(u8 ukey, uX umask, u32 cswidth, u32 bits_per_access, u8 base_shift, s8 shift, u32 active_count); +}; diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp index c4e7bbbbfdd..edc56ee13b9 100644 --- a/src/frontend/mame/luaengine.cpp +++ b/src/frontend/mame/luaengine.cpp @@ -1287,42 +1287,40 @@ void lua_engine::initialize() return table; }, "wpset", [](device_debug &dev, addr_space &sp, const std::string &type, offs_t addr, offs_t len, const char *cond, const char *act) { - int wptype = WATCHPOINT_READ; + read_or_write wptype = read_or_write::READ; if(type == "w") - wptype = WATCHPOINT_WRITE; + wptype = read_or_write::WRITE; else if((type == "rw") || (type == "wr")) - wptype = WATCHPOINT_READ | WATCHPOINT_WRITE; + wptype = read_or_write::READWRITE; return dev.watchpoint_set(sp.space, wptype, addr, len, cond, act); }, "wpclr", &device_debug::watchpoint_clear, "wplist", [this](device_debug &dev, addr_space &sp) { sol::table table = sol().create_table(); - device_debug::watchpoint *list = dev.watchpoint_first(sp.space.spacenum()); - while(list) + for(auto &wpp : dev.watchpoint_vector(sp.space.spacenum())) { sol::table wp = sol().create_table(); - wp["enabled"] = list->enabled(); - wp["address"] = list->address(); - wp["length"] = list->length(); - switch(list->type()) + wp["enabled"] = wpp->enabled(); + wp["address"] = wpp->address(); + wp["length"] = wpp->length(); + switch(wpp->type()) { - case WATCHPOINT_READ: + case read_or_write::READ: wp["type"] = "r"; break; - case WATCHPOINT_WRITE: + case read_or_write::WRITE: wp["type"] = "w"; break; - case WATCHPOINT_READ | WATCHPOINT_WRITE: + case read_or_write::READWRITE: wp["type"] = "rw"; break; default: // huh? wp["type"] = ""; break; } - wp["condition"] = list->condition(); - wp["action"] = list->action(); - table[list->index()] = wp; - list = list->next(); + wp["condition"] = wpp->condition(); + wp["action"] = wpp->action(); + table[wpp->index()] = wp; } return table; }); diff --git a/src/lib/util/coretmpl.h b/src/lib/util/coretmpl.h index 8d317db7596..08c3a6b8678 100644 --- a/src/lib/util/coretmpl.h +++ b/src/lib/util/coretmpl.h @@ -32,6 +32,14 @@ #include #include +// Generate a N-bit mask at compile time. N better be constant. +// Works even for signed types + +template constexpr T make_bitmask(unsigned int N) +{ + return T((N < (8 * sizeof(T)) ? (std::make_unsigned_t(1) << N) : std::make_unsigned_t(0)) - 1); +} + // ======================> simple_list diff --git a/src/mame/drivers/geneve.cpp b/src/mame/drivers/geneve.cpp index 0913d3a5477..f23ef639e10 100644 --- a/src/mame/drivers/geneve.cpp +++ b/src/mame/drivers/geneve.cpp @@ -279,6 +279,7 @@ private: void crumap(address_map &map); void memmap(address_map &map); + void memmap_setoffset(address_map &map); }; /* @@ -287,7 +288,12 @@ private: void geneve_state::memmap(address_map &map) { - map(0x0000, 0xffff).rw(GENEVE_MAPPER_TAG, FUNC(bus::ti99::internal::geneve_mapper_device::readm), FUNC(bus::ti99::internal::geneve_mapper_device::writem)).setoffset(GENEVE_MAPPER_TAG, FUNC(bus::ti99::internal::geneve_mapper_device::setoffset)); + map(0x0000, 0xffff).rw(GENEVE_MAPPER_TAG, FUNC(bus::ti99::internal::geneve_mapper_device::readm), FUNC(bus::ti99::internal::geneve_mapper_device::writem)); +} + +void geneve_state::memmap_setoffset(address_map &map) +{ + map(0x0000, 0xffff).r(GENEVE_MAPPER_TAG, FUNC(bus::ti99::internal::geneve_mapper_device::setoffset)); } /* @@ -717,6 +723,7 @@ MACHINE_CONFIG_START(geneve_state::geneve_common) // basic machine hardware // TMS9995 CPU @ 12.0 MHz MCFG_TMS99xx_ADD("maincpu", TMS9995, 12000000, memmap, crumap) + MCFG_DEVICE_ADDRESS_MAP(tms9995_device::AS_SETOFFSET, memmap_setoffset) MCFG_TMS9995_EXTOP_HANDLER( WRITE8(*this, geneve_state, external_operation) ) MCFG_TMS9995_CLKOUT_HANDLER( WRITELINE(*this, geneve_state, clock_out) ) MCFG_TMS9995_DBIN_HANDLER( WRITELINE(*this, geneve_state, dbin_line) ) diff --git a/src/mame/drivers/m6805evs.cpp b/src/mame/drivers/m6805evs.cpp index bd1c7164219..1fdf4179c16 100644 --- a/src/mame/drivers/m6805evs.cpp +++ b/src/mame/drivers/m6805evs.cpp @@ -83,7 +83,6 @@ private: void m6805evs_state::mem_map(address_map &map) { - map.global_mask(0x1fff); map.unmap_value_high(); // AM_RANGE(0x0000, 0x001f) I/O registers live here @@ -104,7 +103,9 @@ void m6805evs_state::machine_reset() MACHINE_CONFIG_START(m6805evs_state::m6805evs) /* basic machine hardware */ MCFG_DEVICE_ADD("maincpu", M6805, XTAL(4'000'000)) - MCFG_DEVICE_PROGRAM_MAP(mem_map) + +// Needs a 13-bits address bus wide version of the cpu +// MCFG_DEVICE_PROGRAM_MAP(mem_map) MACHINE_CONFIG_END ROM_START(m6805evs) diff --git a/src/mame/drivers/ti99_4p.cpp b/src/mame/drivers/ti99_4p.cpp index 1c577218d99..3d9d980d7ac 100644 --- a/src/mame/drivers/ti99_4p.cpp +++ b/src/mame/drivers/ti99_4p.cpp @@ -157,7 +157,7 @@ public: DECLARE_WRITE_LINE_MEMBER( notconnected ); DECLARE_READ8_MEMBER( interrupt_level ); - DECLARE_SETOFFSET_MEMBER( setoffset ); + DECLARE_READ8_MEMBER( setoffset ); DECLARE_READ16_MEMBER( memread ); DECLARE_WRITE16_MEMBER( memwrite ); DECLARE_WRITE_LINE_MEMBER( dbin_in ); @@ -189,6 +189,7 @@ public: void ti99_4p_60hz(machine_config &config); void cru_map(address_map &map); void memmap(address_map &map); + void memmap_setoffset(address_map &map); private: void datamux_clock_in(int clock); @@ -291,7 +292,12 @@ enum void ti99_4p_state::memmap(address_map &map) { - map(0x0000, 0xffff).rw(FUNC(ti99_4p_state::memread), FUNC(ti99_4p_state::memwrite)).setoffset(FUNC(ti99_4p_state::setoffset)); + map(0x0000, 0xffff).rw(FUNC(ti99_4p_state::memread), FUNC(ti99_4p_state::memwrite)); +} + +void ti99_4p_state::memmap_setoffset(address_map &map) +{ + map(0x0000, 0xffff).r(FUNC(ti99_4p_state::setoffset)); } void ti99_4p_state::cru_map(address_map &map) @@ -427,9 +433,9 @@ int ti99_4p_state::decode_address(int address) Called when the memory access starts by setting the address bus. From that point on, we suspend the CPU until all operations are done. */ -SETOFFSET_MEMBER( ti99_4p_state::setoffset ) +READ8_MEMBER( ti99_4p_state::setoffset ) { - m_addr_buf = offset << 1; + m_addr_buf = offset; m_waitcount = 0; if (TRACE_ADDRESS) logerror("set address %04x\n", m_addr_buf); @@ -453,6 +459,8 @@ SETOFFSET_MEMBER( ti99_4p_state::setoffset ) } ready_join(); + + return 0; } READ16_MEMBER( ti99_4p_state::memread ) @@ -1002,6 +1010,7 @@ MACHINE_CONFIG_START(ti99_4p_state::ti99_4p_60hz) /* basic machine hardware */ /* TMS9900 CPU @ 3.0 MHz */ MCFG_TMS99xx_ADD("maincpu", TMS9900, 3000000, memmap, cru_map) + MCFG_DEVICE_ADDRESS_MAP(tms99xx_device::AS_SETOFFSET, memmap_setoffset) MCFG_TMS99xx_EXTOP_HANDLER( WRITE8(*this, ti99_4p_state, external_operation) ) MCFG_TMS99xx_INTLEVEL_HANDLER( READ8(*this, ti99_4p_state, interrupt_level) ) MCFG_TMS99xx_CLKOUT_HANDLER( WRITELINE(*this, ti99_4p_state, clock_out) ) diff --git a/src/mame/drivers/ti99_4x.cpp b/src/mame/drivers/ti99_4x.cpp index b20c87c8fd5..0eb2f7a19ff 100644 --- a/src/mame/drivers/ti99_4x.cpp +++ b/src/mame/drivers/ti99_4x.cpp @@ -159,6 +159,7 @@ public: void ti99_4_60hz(machine_config &config); void cru_map(address_map &map); void memmap(address_map &map); + void memmap_setoffset(address_map &map); private: void set_keyboard_column(int number, int data); int m_keyboard_column; @@ -228,7 +229,13 @@ enum void ti99_4x_state::memmap(address_map &map) { map.global_mask(0xffff); - map(0x0000, 0xffff).rw(TI99_DATAMUX_TAG, FUNC(bus::ti99::internal::datamux_device::read), FUNC(bus::ti99::internal::datamux_device::write)).setoffset(TI99_DATAMUX_TAG, FUNC(bus::ti99::internal::datamux_device::setoffset)); + map(0x0000, 0xffff).rw(TI99_DATAMUX_TAG, FUNC(bus::ti99::internal::datamux_device::read), FUNC(bus::ti99::internal::datamux_device::write)); +} + +void ti99_4x_state::memmap_setoffset(address_map &map) +{ + map.global_mask(0xffff); + map(0x0000, 0xffff).r(TI99_DATAMUX_TAG, FUNC(bus::ti99::internal::datamux_device::setoffset)); } /* @@ -850,6 +857,7 @@ MACHINE_RESET_MEMBER(ti99_4x_state,ti99_4) MACHINE_CONFIG_START(ti99_4x_state::ti99_4) // CPU MCFG_TMS99xx_ADD("maincpu", TMS9900, 3000000, memmap, cru_map) + MCFG_DEVICE_ADDRESS_MAP(tms99xx_device::AS_SETOFFSET, memmap_setoffset) MCFG_TMS99xx_EXTOP_HANDLER( WRITE8(*this, ti99_4x_state, external_operation) ) MCFG_TMS99xx_INTLEVEL_HANDLER( READ8(*this, ti99_4x_state, interrupt_level) ) MCFG_TMS99xx_CLKOUT_HANDLER( WRITELINE(*this, ti99_4x_state, clock_out) ) @@ -968,6 +976,7 @@ MACHINE_RESET_MEMBER(ti99_4x_state,ti99_4a) MACHINE_CONFIG_START(ti99_4x_state::ti99_4a) // CPU MCFG_TMS99xx_ADD("maincpu", TMS9900, 3000000, memmap, cru_map) + MCFG_DEVICE_ADDRESS_MAP(tms99xx_device::AS_SETOFFSET, memmap_setoffset) MCFG_TMS99xx_EXTOP_HANDLER( WRITE8(*this, ti99_4x_state, external_operation) ) MCFG_TMS99xx_INTLEVEL_HANDLER( READ8(*this, ti99_4x_state, interrupt_level) ) MCFG_TMS99xx_CLKOUT_HANDLER( WRITELINE(*this, ti99_4x_state, clock_out) ) @@ -1128,6 +1137,7 @@ MACHINE_RESET_MEMBER(ti99_4x_state, ti99_4ev) MACHINE_CONFIG_START(ti99_4x_state::ti99_4ev_60hz) // CPU MCFG_TMS99xx_ADD("maincpu", TMS9900, 3000000, memmap, cru_map) + MCFG_DEVICE_ADDRESS_MAP(tms99xx_device::AS_SETOFFSET, memmap_setoffset) MCFG_TMS99xx_EXTOP_HANDLER( WRITE8(*this, ti99_4x_state, external_operation) ) MCFG_TMS99xx_INTLEVEL_HANDLER( READ8(*this, ti99_4x_state, interrupt_level) ) MCFG_TMS99xx_CLKOUT_HANDLER( WRITELINE(*this, ti99_4x_state, clock_out) ) diff --git a/src/mame/drivers/ti99_8.cpp b/src/mame/drivers/ti99_8.cpp index f45dbb0b894..9f2f3ae95c6 100644 --- a/src/mame/drivers/ti99_8.cpp +++ b/src/mame/drivers/ti99_8.cpp @@ -267,6 +267,7 @@ public: void ti99_8_50hz(machine_config &config); void crumap(address_map &map); void memmap(address_map &map); + void memmap_setoffset(address_map &map); private: // Keyboard support void set_keyboard_column(int number, int data); @@ -297,7 +298,12 @@ private: */ void ti99_8_state::memmap(address_map &map) { - map(0x0000, 0xffff).rw(TI998_MAINBOARD_TAG, FUNC(bus::ti99::internal::mainboard8_device::read), FUNC(bus::ti99::internal::mainboard8_device::write)).setoffset(TI998_MAINBOARD_TAG, FUNC(bus::ti99::internal::mainboard8_device::setoffset)); + map(0x0000, 0xffff).rw(TI998_MAINBOARD_TAG, FUNC(bus::ti99::internal::mainboard8_device::read), FUNC(bus::ti99::internal::mainboard8_device::write)); +} + +void ti99_8_state::memmap_setoffset(address_map &map) +{ + map(0x0000, 0xffff).r(TI998_MAINBOARD_TAG, FUNC(bus::ti99::internal::mainboard8_device::setoffset)); } /* @@ -723,6 +729,7 @@ MACHINE_CONFIG_START(ti99_8_state::ti99_8) // TMS9995-MP9537 CPU @ 10.7 MHz // MP9537 mask: This variant of the TMS9995 does not contain on-chip RAM MCFG_TMS99xx_ADD("maincpu", TMS9995_MP9537, XTAL(10'738'635), memmap, crumap) + MCFG_DEVICE_ADDRESS_MAP(tms9995_device::AS_SETOFFSET, memmap_setoffset) MCFG_TMS9995_EXTOP_HANDLER( WRITE8(*this, ti99_8_state, external_operation) ) MCFG_TMS9995_CLKOUT_HANDLER( WRITELINE(*this, ti99_8_state, clock_out) ) MCFG_TMS9995_DBIN_HANDLER( WRITELINE(*this, ti99_8_state, dbin_line) ) diff --git a/src/mame/machine/c117.cpp b/src/mame/machine/c117.cpp index ae8ed387190..ff01f311cda 100644 --- a/src/mame/machine/c117.cpp +++ b/src/mame/machine/c117.cpp @@ -92,9 +92,6 @@ void namco_c117_device::device_reset() m_offsets[1][0] = 0x0180 * 0x2000; // bank0 = 0x180(RAM) - evidence: wldcourt m_offsets[1][7] = 0x03ff * 0x2000; // bank7 = 0x3ff(PRG7) - m_cpucache[0]->force_update(); - m_cpucache[1]->force_update(); - m_subres = m_wdog = 0; m_subres_cb(ASSERT_LINE); @@ -192,10 +189,7 @@ void namco_c117_device::register_w(int whichcpu, offs_t offset, uint8_t data) break; case 14: // FC00 - set initial ROM bank for sub CPU if (whichcpu == 0) - { m_offsets[1][7] = 0x600000 | (data * 0x2000); - m_cpucache[1]->force_update(); - } else unknown_reg = true; break; @@ -215,8 +209,6 @@ void namco_c117_device::bankswitch(int whichcpu, int whichbank, int a0, uint8_t bank = (bank & 0x1fe000) | ((data & 0x03) * 0x200000); else bank = (bank & 0x600000) | (data * 0x2000); - - m_cpucache[whichcpu]->force_update(); } void namco_c117_device::kick_watchdog(int whichcpu) diff --git a/src/mame/machine/segaic16.cpp b/src/mame/machine/segaic16.cpp index b3690fd06cc..5f80c323933 100644 --- a/src/mame/machine/segaic16.cpp +++ b/src/mame/machine/segaic16.cpp @@ -621,6 +621,7 @@ void sega_315_5195_mapper_device::update_mapping() if (LOG_MEMORY_MAP) osd_printf_debug("----\nRemapping:\n"); // first reset everything back to the beginning + m_space->unmap_readwrite(0x000000, 0xffffff); m_space->install_readwrite_handler(0x000000, 0xffffff, read8_delegate(FUNC(sega_315_5195_mapper_device::read), this), write8_delegate(FUNC(sega_315_5195_mapper_device::write), this), 0x00ff); // loop over the regions -- cgit v1.2.3