summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/emu/addrmap.cpp77
-rw-r--r--src/emu/addrmap.h10
-rw-r--r--src/emu/debug/debugcmd.cpp11
-rw-r--r--src/emu/emufwd.h1
-rw-r--r--src/emu/emumem.cpp1327
-rw-r--r--src/emu/emumem.h388
-rw-r--r--src/emu/emumem_aspace.cpp1200
-rw-r--r--src/emu/emumem_hedr.h26
-rw-r--r--src/emu/emumem_hedr.ipp320
-rw-r--r--src/emu/emumem_hedr0.cpp26
-rw-r--r--src/emu/emumem_hedw.h26
-rw-r--r--src/emu/emumem_hedw.ipp318
-rw-r--r--src/emu/emumem_hedw0.cpp30
-rw-r--r--src/emu/emumem_heu.cpp30
-rw-r--r--src/emu/emumem_heu.h4
-rw-r--r--src/emu/emumem_mview.cpp995
-rw-r--r--src/mame/drivers/simpsons.cpp24
-rw-r--r--src/mame/includes/simpsons.h10
-rw-r--r--src/mame/video/simpsons.cpp7
19 files changed, 3229 insertions, 1601 deletions
diff --git a/src/emu/addrmap.cpp b/src/emu/addrmap.cpp
index ebc0331a767..246a4306d87 100644
--- a/src/emu/addrmap.cpp
+++ b/src/emu/addrmap.cpp
@@ -19,39 +19,6 @@
#define DETECT_OVERLAPPING_MEMORY (0)
-/*-------------------------------------------------
- core_i64_hex_format - i64 format printf helper
- why isn't fatalerror going through the same
- channels as logerror exactly?
--------------------------------------------------*/
-
-static char *core_i64_hex_format(u64 value, u8 mindigits)
-{
- static char buffer[16][64];
- // TODO: this can overflow - e.g. when a lot of unmapped writes are logged
- static int index;
- char *bufbase = &buffer[index++ % 16][0];
- char *bufptr = bufbase;
- s8 curdigit;
-
- for (curdigit = 15; curdigit >= 0; curdigit--)
- {
- int nibble = (value >> (curdigit * 4)) & 0xf;
- if (nibble != 0 || curdigit < mindigits)
- {
- mindigits = curdigit;
- *bufptr++ = "0123456789ABCDEF"[nibble];
- }
- }
- if (bufptr == bufbase)
- *bufptr++ = '0';
- *bufptr = 0;
-
- return bufbase;
-}
-
-
-
//**************************************************************************
// ADDRESS MAP ENTRY
//**************************************************************************
@@ -201,6 +168,15 @@ address_map_entry &address_map_entry::m(device_t *device, address_map_constructo
return *this;
}
+void address_map_entry::view(memory_view &mv)
+{
+ m_read.m_type = AMH_VIEW;
+ m_read.m_tag = nullptr;
+ m_write.m_type = AMH_VIEW;
+ m_write.m_tag = nullptr;
+ m_view = &mv;
+ mv.initialize_from_address_map(m_addrstart, m_addrend, m_map.get_config());
+}
//-------------------------------------------------
// r/w/rw - handler setters for
@@ -787,8 +763,9 @@ bool address_map_entry::unitmask_is_appropriate(u8 width, u64 unitmask, const ch
address_map::address_map(device_t &device, int spacenum)
: m_spacenum(spacenum),
m_device(&device),
+ m_view(nullptr),
m_unmapval(0),
- m_globalmask(0)
+ m_globalmask(0)
{
// get our memory interface
const device_memory_interface *memintf;
@@ -796,8 +773,8 @@ address_map::address_map(device_t &device, int spacenum)
throw emu_fatalerror("No memory interface defined for device '%s'\n", m_device->tag());
// and then the configuration for the current address space
- const address_space_config *spaceconfig = memintf->space_config(spacenum);
- if (spaceconfig == nullptr)
+ m_config = memintf->space_config(spacenum);
+ if (m_config == nullptr)
throw emu_fatalerror("No memory address space configuration found for device '%s', space %d\n", m_device->tag(), spacenum);
// append the map provided by the owner
@@ -809,8 +786,8 @@ address_map::address_map(device_t &device, int spacenum)
}
// construct the internal device map (last so it takes priority)
- if (!spaceconfig->m_internal_map.isnull())
- spaceconfig->m_internal_map(*this);
+ if (!m_config->m_internal_map.isnull())
+ m_config->m_internal_map(*this);
}
@@ -822,6 +799,7 @@ address_map::address_map(device_t &device, int spacenum)
address_map::address_map(device_t &device, address_map_entry *entry)
: m_spacenum(AS_PROGRAM),
m_device(&device),
+ m_view(nullptr),
m_unmapval(0),
m_globalmask(0)
{
@@ -839,6 +817,7 @@ address_map::address_map(device_t &device, address_map_entry *entry)
address_map::address_map(const address_space &space, offs_t start, offs_t end, u64 unitmask, int cswidth, device_t &device, address_map_constructor submap_delegate)
: m_spacenum(space.spacenum()),
m_device(&device),
+ m_view(nullptr),
m_unmapval(space.unmap()),
m_globalmask(space.addrmask())
{
@@ -846,6 +825,21 @@ address_map::address_map(const address_space &space, offs_t start, offs_t end, u
}
+//----------------------------------------------------------
+// address_map - constructor memory view mapping case
+//----------------------------------------------------------
+
+address_map::address_map(memory_view &view)
+ : m_spacenum(-1),
+ m_device(&view.m_device),
+ m_view(&view),
+ m_config(view.m_config),
+ m_unmapval(0),
+ m_globalmask(0)
+{
+}
+
+
//-------------------------------------------------
// ~address_map - destructor
//-------------------------------------------------
@@ -981,7 +975,7 @@ void address_map::import_submaps(running_machine &machine, device_t &owner, int
subentry_ratio ++;
subentry_ratio = data_width / subentry_ratio;
if (ratio * subentry_ratio > data_width / 8)
- fatalerror("import_submap: In range %x-%x mask %x mirror %x select %x of device %s, the import unitmask of %s combined with an entry unitmask of %s does not fit in %d bits.\n", subentry->m_addrstart, subentry->m_addrend, subentry->m_addrmask, subentry->m_addrmirror, subentry->m_addrselect, entry->m_read.m_tag, core_i64_hex_format(entry->m_mask, data_width/4), core_i64_hex_format(subentry->m_mask, data_width/4), data_width);
+ fatalerror("import_submap: In range %x-%x mask %x mirror %x select %x of device %s, the import unitmask of %0*x combined with an entry unitmask of %0*x does not fit in %d bits.\n", subentry->m_addrstart, subentry->m_addrend, subentry->m_addrmask, subentry->m_addrmirror, subentry->m_addrselect, entry->m_read.m_tag, data_width/4, entry->m_mask, data_width/4, subentry->m_mask, data_width);
// Regenerate the unitmask
u64 newmask = 0;
@@ -1394,3 +1388,8 @@ void address_map::map_validity_check(validity_checker &valid, int spacenum) cons
valid.validate_tag(entry.m_share);
}
}
+
+const address_space_config &address_map::get_config() const
+{
+ return *m_config;
+}
diff --git a/src/emu/addrmap.h b/src/emu/addrmap.h
index 229db15caa1..6f2f903306d 100644
--- a/src/emu/addrmap.h
+++ b/src/emu/addrmap.h
@@ -40,7 +40,8 @@ enum map_handler_type
AMH_DEVICE_DELEGATE_SMO,
AMH_PORT,
AMH_BANK,
- AMH_DEVICE_SUBMAP
+ AMH_DEVICE_SUBMAP,
+ AMH_VIEW
};
@@ -184,6 +185,8 @@ public:
address_map_entry &m(const char *tag, address_map_constructor func);
address_map_entry &m(device_t *device, address_map_constructor func);
+ // view initialization
+ void view(memory_view &mv);
// implicit base -> delegate converter
template <typename T, typename Ret, typename... Params>
@@ -404,6 +407,7 @@ public:
device_t *m_submap_device;
address_map_constructor m_submap_delegate;
+ memory_view *m_view;
// information used during processing
void * m_memory; // pointer to memory backing this entry
@@ -477,6 +481,7 @@ class address_map
public:
// construction/destruction
address_map(device_t &device, int spacenum);
+ address_map(memory_view &view);
address_map(device_t &device, address_map_entry *entry);
address_map(const address_space &space, offs_t start, offs_t end, u64 unitmask, int cswidth, device_t &device, address_map_constructor submap_delegate);
~address_map();
@@ -492,12 +497,15 @@ public:
// public data
int m_spacenum; // space number of the map
device_t * m_device; // associated device
+ memory_view * m_view; // view, when in one
+ const address_space_config * m_config; // space configuration
u8 m_unmapval; // unmapped memory value
offs_t m_globalmask; // global mask
simple_list<address_map_entry> m_entrylist; // list of entries
void import_submaps(running_machine &machine, device_t &owner, int data_width, endianness_t endian, int addr_shift);
void map_validity_check(validity_checker &valid, int spacenum) const;
+ const address_space_config &get_config() const;
};
#endif // MAME_EMU_ADDRMAP_H
diff --git a/src/emu/debug/debugcmd.cpp b/src/emu/debug/debugcmd.cpp
index a5856a9b794..949f1194061 100644
--- a/src/emu/debug/debugcmd.cpp
+++ b/src/emu/debug/debugcmd.cpp
@@ -3767,10 +3767,15 @@ void debugger_commands::execute_memdump(int ref, const std::vector<std::string>
for (memory_entry &entry : entries[mode])
{
if (octal)
- fprintf(file, "%0*o - %0*o", nc, entry.start, nc, entry.end);
+ 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, "%0*x - %0*x:", nc, entry.start, nc, entry.end);
+ for(const auto &c : entry.context)
+ if(c.disabled)
+ fprintf(file, " %s[off]", c.view->name().c_str());
+ else
+ fprintf(file, " %s[%d]", c.view->name().c_str(), c.slot);
+ fprintf(file, " %s\n", entry.entry->name().c_str());
}
fprintf(file, "\n");
}
diff --git a/src/emu/emufwd.h b/src/emu/emufwd.h
index be33acf32ed..1b6b48af522 100644
--- a/src/emu/emufwd.h
+++ b/src/emu/emufwd.h
@@ -149,6 +149,7 @@ class memory_bank;
class memory_manager;
class memory_region;
class memory_share;
+class memory_view;
// declared in emuopts.h
class emu_options;
diff --git a/src/emu/emumem.cpp b/src/emu/emumem.cpp
index 4e8bfb26363..51eab43fcf7 100644
--- a/src/emu/emumem.cpp
+++ b/src/emu/emumem.cpp
@@ -48,6 +48,16 @@ void handler_entry::dump_map(std::vector<memory_entry> &map) const
fatalerror("dump_map called on non-dispatching class\n");
}
+void handler_entry::select_a(int slot)
+{
+ fatalerror("select_a called on non-view\n");
+}
+
+void handler_entry::select_u(int slot)
+{
+ fatalerror("select_u called on non-view\n");
+}
+
void handler_entry::reflist::add(const handler_entry *entry)
{
refcounts[entry]++;
@@ -132,11 +142,22 @@ template<int Width, int AddrShift, endianness_t Endian> void *handler_entry_read
return nullptr;
}
+template<int Width, int AddrShift, endianness_t Endian> handler_entry_read<Width, AddrShift, Endian> *handler_entry_read<Width, AddrShift, Endian>::dup()
+{
+ ref();
+ return this;
+}
+
template<int Width, int AddrShift, endianness_t Endian> void handler_entry_read<Width, AddrShift, Endian>::detach(const std::unordered_set<handler_entry *> &handlers)
{
fatalerror("detach called on non-dispatching class\n");
}
+template<int Width, int AddrShift, endianness_t Endian> void handler_entry_read<Width, AddrShift, Endian>::init_handlers(offs_t start_entry, offs_t end_entry, u32 lowbits, handler_entry_read<Width, AddrShift, Endian> **dispatch, handler_entry::range *ranges)
+{
+ fatalerror("init_handlers called on non-view class\n");
+}
+
template<int Width, int AddrShift, endianness_t Endian> const handler_entry_write<Width, AddrShift, Endian> *const *handler_entry_write<Width, AddrShift, Endian>::get_dispatch() const
{
@@ -183,651 +204,75 @@ template<int Width, int AddrShift, endianness_t Endian> void *handler_entry_writ
return nullptr;
}
-template<int Width, int AddrShift, endianness_t Endian> void handler_entry_write<Width, AddrShift, Endian>::detach(const std::unordered_set<handler_entry *> &handlers)
+template<int Width, int AddrShift, endianness_t Endian> handler_entry_write<Width, AddrShift, Endian> *handler_entry_write<Width, AddrShift, Endian>::dup()
{
- fatalerror("detach called on non-dispatching class\n");
+ ref();
+ return this;
}
-
-
-/*-------------------------------------------------
- core_i64_hex_format - i64 format printf helper
--------------------------------------------------*/
-
-static char *core_i64_hex_format(u64 value, u8 mindigits)
+template<int Width, int AddrShift, endianness_t Endian> void handler_entry_write<Width, AddrShift, Endian>::detach(const std::unordered_set<handler_entry *> &handlers)
{
- static char buffer[16][64];
- // TODO: this can overflow - e.g. when a lot of unmapped writes are logged
- static int index;
- char *bufbase = &buffer[index++ % 16][0];
- char *bufptr = bufbase;
- s8 curdigit;
-
- for (curdigit = 15; curdigit >= 0; curdigit--)
- {
- int nibble = (value >> (curdigit * 4)) & 0xf;
- if (nibble != 0 || curdigit < mindigits)
- {
- mindigits = curdigit;
- *bufptr++ = "0123456789ABCDEF"[nibble];
- }
- }
- if (bufptr == bufbase)
- *bufptr++ = '0';
- *bufptr = 0;
-
- return bufbase;
+ fatalerror("detach called on non-dispatching class\n");
}
-
-
-//**************************************************************************
-// CONSTANTS
-//**************************************************************************
-
-namespace {
-
-template <typename Delegate> struct handler_width;
-template <> struct handler_width<read8_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<read8m_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<read8s_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<read8sm_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<read8mo_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<read8smo_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<write8_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<write8m_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<write8s_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<write8sm_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<write8mo_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<write8smo_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<read16_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<read16m_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<read16s_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<read16sm_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<read16mo_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<read16smo_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<write16_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<write16m_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<write16s_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<write16sm_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<write16mo_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<write16smo_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<read32_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<read32m_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<read32s_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<read32sm_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<read32mo_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<read32smo_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<write32_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<write32m_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<write32s_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<write32sm_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<write32mo_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<write32smo_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<read64_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<read64m_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<read64s_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<read64sm_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<read64mo_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<read64smo_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<write64_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<write64m_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<write64s_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<write64sm_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<write64mo_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<write64smo_delegate> { static constexpr int value = 3; };
-} // anonymous namespace
-
-
-//**************************************************************************
-// TYPE DEFINITIONS
-//**************************************************************************
-
-// ======================> address_space_specific
-
-// this is a derived class of address_space with specific width, endianness, and table size
-template<int Level, int Width, int AddrShift, endianness_t Endian>
-class address_space_specific : public address_space
-{
- using uX = typename emu::detail::handler_entry_size<Width>::uX;
- using NativeType = uX;
- using this_type = address_space_specific<Level, Width, AddrShift, Endian>;
-
- // 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:
- const handler_entry_read<Width, AddrShift, Endian> *const *m_dispatch_read;
- const handler_entry_write<Width, AddrShift, Endian> *const *m_dispatch_write;
-
- std::string get_handler_string(read_or_write readorwrite, offs_t byteaddress) const override;
- void dump_maps(std::vector<memory_entry> &read_map, std::vector<memory_entry> &write_map) const override;
/**
 * Original code: automated SDL audio test written by Edgar Simo "bobbens"
 * New/updated tests: aschiffler at ferzkopp dot net
 */

/* quiet windows compiler warnings */
#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <string.h>

#include "SDL.h"
#include "SDL_test.h"

/* ================= Test Case Implementation ================== */

/* Fixture */

void
_audioSetUp(void *arg)
{
    /* Start SDL audio subsystem */
    int ret = SDL_InitSubSystem( SDL_INIT_AUDIO );
        SDLTest_AssertPass("Call to SDL_InitSubSystem(SDL_INIT_AUDIO)");
    SDLTest_AssertCheck(ret==0, "Check result from SDL_InitSubSystem(SDL_INIT_AUDIO)");
    if (ret != 0) {
           SDLTest_LogError("%s", SDL_GetError());
        }
}

void
_audioTearDown(void *arg)
{
    /* Remove a possibly created file from SDL disk writer audio driver; ignore errors */
    remove("sdlaudio.raw");

    SDLTest_AssertPass("Cleanup of test files completed");
}


/* Global counter for callback invocation */
int _audio_testCallbackCounter;

/* Global accumulator for total callback length */
int _audio_testCallbackLength;


/* Test callback function */
void _audio_testCallback(void *userdata, Uint8 *stream, int len)
{
   /* track that callback was called */
   _audio_testCallbackCounter++;
   _audio_testCallbackLength += len;
}


/* Test case functions */

/**
 * \brief Stop and restart audio subsystem
 *
 * \sa https://wiki.libsdl.org/SDL_QuitSubSystem
 * \sa https://wiki.libsdl.org/SDL_InitSubSystem
 */
int audio_quitInitAudioSubSystem()
{
    /* Stop SDL audio subsystem */
    SDL_QuitSubSystem( SDL_INIT_AUDIO );
        SDLTest_AssertPass("Call to SDL_QuitSubSystem(SDL_INIT_AUDIO)");

        /* Restart audio again */
        _audioSetUp(NULL);

    return TEST_COMPLETED;
}

/**
 * \brief Start and stop audio directly
 *
 * \sa https://wiki.libsdl.org/SDL_InitAudio
 * \sa https://wiki.libsdl.org/SDL_QuitAudio
 */
int audio_initQuitAudio()
{
        int result;
    int i, iMax;
    const char* audioDriver;

    /* Stop SDL audio subsystem */
    SDL_QuitSubSystem( SDL_INIT_AUDIO );
        SDLTest_AssertPass("Call to SDL_QuitSubSystem(SDL_INIT_AUDIO)");

        /* Loop over all available audio drivers */
        iMax = SDL_GetNumAudioDrivers();
        SDLTest_AssertPass("Call to SDL_GetNumAudioDrivers()");
        SDLTest_AssertCheck(iMax > 0, "Validate number of audio drivers; expected: >0 got: %d", iMax);
        for (i = 0; i < iMax; i++) {
            audioDriver = SDL_GetAudioDriver(i);
            SDLTest_AssertPass("Call to SDL_GetAudioDriver(%d)", i);
            SDLTest_AssertCheck(audioDriver != NULL, "Audio driver name is not NULL");
            SDLTest_AssertCheck(audioDriver[0] != '\0', "Audio driver name is not empty; got: %s", audioDriver);

            /* Call Init */
            result = SDL_AudioInit(audioDriver);
            SDLTest_AssertPass("Call to SDL_AudioInit('%s')", audioDriver);
            SDLTest_AssertCheck(result == 0, "Validate result value; expected: 0 got: %d", result);

            /* Call Quit */
            SDL_AudioQuit();
            SDLTest_AssertPass("Call to SDL_AudioQuit()");
    }

    /* NULL driver specification */
    audioDriver = NULL;

    /* Call Init */
    result = SDL_AudioInit(audioDriver);
    SDLTest_AssertPass("Call to SDL_AudioInit(NULL)");
    SDLTest_AssertCheck(result == 0, "Validate result value; expected: 0 got: %d", result);

    /* Call Quit */
    SDL_AudioQuit();
    SDLTest_AssertPass("Call to SDL_AudioQuit()");

        /* Restart audio again */
        _audioSetUp(NULL);

    return TEST_COMPLETED;
}

/**
 * \brief Start, open, close and stop audio
 *
 * \sa https://wiki.libsdl.org/SDL_InitAudio
 * \sa https://wiki.libsdl.org/SDL_OpenAudio
 * \sa https://wiki.libsdl.org/SDL_CloseAudio
 * \sa https://wiki.libsdl.org/SDL_QuitAudio
 */
int audio_initOpenCloseQuitAudio()
{
    int result, expectedResult;
    int i, iMax, j, k;
    const char* audioDriver;
    SDL_AudioSpec desired;

    /* Stop SDL audio subsystem */
    SDL_QuitSubSystem( SDL_INIT_AUDIO );
        SDLTest_AssertPass("Call to SDL_QuitSubSystem(SDL_INIT_AUDIO)");

        /* Loop over all available audio drivers */
        iMax = SDL_GetNumAudioDrivers();
        SDLTest_AssertPass("Call to SDL_GetNumAudioDrivers()");
        SDLTest_AssertCheck(iMax > 0, "Validate number of audio drivers; expected: >0 got: %d", iMax);
        for (i = 0; i < iMax; i++) {
            audioDriver = SDL_GetAudioDriver(i);
            SDLTest_AssertPass("Call to SDL_GetAudioDriver(%d)", i);
            SDLTest_AssertCheck(audioDriver != NULL, "Audio driver name is not NULL");
            SDLTest_AssertCheck(audioDriver[0] != '\0', "Audio driver name is not empty; got: %s", audioDriver);

            /* Change specs */
            for (j = 0; j < 2; j++) {

                /* Call Init */
                result = SDL_AudioInit(audioDriver);
                SDLTest_AssertPass("Call to SDL_AudioInit('%s')", audioDriver);
                SDLTest_AssertCheck(result == 0, "Validate result value; expected: 0 got: %d", result);

                /* Set spec */
                SDL_memset(&desired, 0, sizeof(desired));
                switch (j) {
                    case 0:
                    /* Set standard desired spec */
                    desired.freq = 22050;
                    desired.format = AUDIO_S16SYS;
                    desired.channels = 2;
                    desired.samples = 4096;
                    desired.callback = _audio_testCallback;
                    desired.userdata = NULL;

                    case 1:
                    /* Set custom desired spec */
                    desired.freq = 48000;
                    desired.format = AUDIO_F32SYS;
                    desired.channels = 2;
                    desired.samples = 2048;
                    desired.callback = _audio_testCallback;
                    desired.userdata = NULL;
                    break;
            }

            /* Call Open (maybe multiple times) */
            for (k=0; k <= j; k++) {
                result = SDL_OpenAudio(&desired, NULL);
                SDLTest_AssertPass("Call to SDL_OpenAudio(desired_spec_%d, NULL), call %d", j, k+1);
                expectedResult = (k==0) ? 0 : -1;
                SDLTest_AssertCheck(result == expectedResult, "Verify return value; expected: %d, got: %d", expectedResult, result);
            }

            /* Call Close (maybe multiple times) */
            for (k=0; k <= j; k++) {
                SDL_CloseAudio();
                SDLTest_AssertPass("Call to SDL_CloseAudio(), call %d", k+1);
            }

            /* Call Quit (maybe multiple times) */
            for (k=0; k <= j; k++) {
                SDL_AudioQuit();
                SDLTest_AssertPass("Call to SDL_AudioQuit(), call %d", k+1);
            }

        } /* spec loop */
    } /* driver loop */

        /* Restart audio again */
        _audioSetUp(NULL);

    return TEST_COMPLETED;
}

/**
 * \brief Pause and unpause audio
 *
 * \sa https://wiki.libsdl.org/SDL_PauseAudio
 */
int audio_pauseUnpauseAudio()
{
    int result;
    int i, iMax, j, k, l;
    int totalDelay;
    int pause_on;
    int originalCounter;
    const char* audioDriver;
    SDL_AudioSpec desired;

    /* Stop SDL audio subsystem */
    SDL_QuitSubSystem( SDL_INIT_AUDIO );
        SDLTest_AssertPass("Call to SDL_QuitSubSystem(SDL_INIT_AUDIO)");

        /* Loop over all available audio drivers */
        iMax = SDL_GetNumAudioDrivers();
        SDLTest_AssertPass("Call to SDL_GetNumAudioDrivers()");
        SDLTest_AssertCheck(iMax > 0, "Validate number of audio drivers; expected: >0 got: %d", iMax);
        for (i = 0; i < iMax; i++) {
            audioDriver = SDL_GetAudioDriver(i);
            SDLTest_AssertPass("Call to SDL_GetAudioDriver(%d)", i);
            SDLTest_AssertCheck(audioDriver != NULL, "Audio driver name is not NULL");
            SDLTest_AssertCheck(audioDriver[0] != '\0', "Audio driver name is not empty; got: %s", audioDriver);

            /* Change specs */
            for (j = 0; j < 2; j++) {

                /* Call Init */
                result = SDL_AudioInit(audioDriver);
                SDLTest_AssertPass("Call to SDL_AudioInit('%s')", audioDriver);
                SDLTest_AssertCheck(result == 0, "Validate result value; expected: 0 got: %d", result);

                /* Set spec */
                SDL_memset(&desired, 0, sizeof(desired));
                switch (j) {
                    case 0:
                    /* Set standard desired spec */
                    desired.freq = 22050;
                    desired.format = AUDIO_S16SYS;
                    desired.channels = 2;
                    desired.samples = 4096;
                    desired.callback = _audio_testCallback;
                    desired.userdata = NULL;

                    case 1:
                    /* Set custom desired spec */
                    desired.freq = 48000;
                    desired.format = AUDIO_F32SYS;
                    desired.channels = 2;
                    desired.samples = 2048;
                    desired.callback = _audio_testCallback;
                    desired.userdata = NULL;
                    break;
            }

            /* Call Open */
            result = SDL_OpenAudio(&desired, NULL);
            SDLTest_AssertPass("Call to SDL_OpenAudio(desired_spec_%d, NULL)", j);
            SDLTest_AssertCheck(result == 0, "Verify return value; expected: 0 got: %d", result);

            /* Start and stop audio multiple times */
            for (l=0; l<3; l++) {
                SDLTest_Log("Pause/Unpause iteration: %d", l+1);
            
                /* Reset callback counters */
                _audio_testCallbackCounter = 0;
                _audio_testCallbackLength = 0;

                /* Un-pause audio to start playing (maybe multiple times) */
                pause_on = 0;
                for (k=0; k <= j; k++) {
                    SDL_PauseAudio(pause_on);
                    SDLTest_AssertPass("Call to SDL_PauseAudio(%d), call %d", pause_on, k+1);
                }
            
                /* Wait for callback */
                totalDelay = 0;
                do {
                    SDL_Delay(10);
                    totalDelay += 10;
                } 
                while (_audio_testCallbackCounter == 0 && totalDelay < 1000);
                SDLTest_AssertCheck(_audio_testCallbackCounter > 0, "Verify callback counter; expected: >0 got: %d", _audio_testCallbackCounter);
                SDLTest_AssertCheck(_audio_testCallbackLength > 0, "Verify callback length; expected: >0 got: %d", _audio_testCallbackLength);

                /* Pause audio to stop playing (maybe multiple times) */
                for (k=0; k <= j; k++) {
                    pause_on = (k==0) ? 1 : SDLTest_RandomIntegerInRange(99, 9999);
                    SDL_PauseAudio(pause_on);
                    SDLTest_AssertPass("Call to SDL_PauseAudio(%d), call %d", pause_on, k+1);
                }
            
                /* Ensure callback is not called again */
                originalCounter = _audio_testCallbackCounter;
                SDL_Delay(totalDelay + 10);
                SDLTest_AssertCheck(originalCounter == _audio_testCallbackCounter, "Verify callback counter; expected: %d, got: %d", originalCounter, _audio_testCallbackCounter);
            }

            /* Call Close */
            SDL_CloseAudio();
            SDLTest_AssertPass("Call to SDL_CloseAudio()");

            /* Call Quit */
            SDL_AudioQuit();
            SDLTest_AssertPass("Call to SDL_AudioQuit()");

        } /* spec loop */
    } /* driver loop */

    /* Restart audio again */
    _audioSetUp(NULL);

    return TEST_COMPLETED;
}

/**
 * \brief Enumerate and name available audio devices (output and capture).
 *
 * \sa https://wiki.libsdl.org/SDL_GetNumAudioDevices
 * \sa https://wiki.libsdl.org/SDL_GetAudioDeviceName
 */
int audio_enumerateAndNameAudioDevices()
{
   int t, tt;
   int i, n, nn;
   const char *name, *nameAgain;

   /* Iterate over types: t=0 output device, t=1 input/capture device */
   for (t=0; t<2; t++) {

      /* Get number of devices. */
      n = SDL_GetNumAudioDevices(t);
      SDLTest_AssertPass("Call to SDL_GetNumAudioDevices(%i)", t);
      SDLTest_Log("Number of %s devices < 0, reported as %i", (t) ? "capture" : "output", n);
      SDLTest_AssertCheck(n >= 0, "Validate result is >= 0, got: %i", n);

      /* Variation of non-zero type */
      if (t==1) {
         tt = t + SDLTest_RandomIntegerInRange(1,10);
         nn = SDL_GetNumAudioDevices(tt);
         SDLTest_AssertCheck(n==nn, "Verify result from SDL_GetNumAudioDevices(%i), expected same number of audio devices %i, got %i", tt, n, nn);
         nn = SDL_GetNumAudioDevices(-tt);
         SDLTest_AssertCheck(n==nn, "Verify result from SDL_GetNumAudioDevices(%i), expected same number of audio devices %i, got %i", -tt, n, nn);
      }

      /* List devices. */
      if (n>0) {
         for (i=0; i<n; i++) {
            name = SDL_GetAudioDeviceName(i, t);
            SDLTest_AssertPass("Call to SDL_GetAudioDeviceName(%i, %i)", i, t);
            SDLTest_AssertCheck(name != NULL, "Verify result from SDL_GetAudioDeviceName(%i, %i) is not NULL", i, t);
            if (name != NULL) {
              SDLTest_AssertCheck(name[0] != '\0', "verify result from SDL_GetAudioDeviceName(%i, %i) is not empty, got: '%s'", i, t, name);
              if (t==1) {
                  /* Also try non-zero type */
                  tt = t + SDLTest_RandomIntegerInRange(1,10);
                  nameAgain = SDL_GetAudioDeviceName(i, tt);
                  SDLTest_AssertCheck(nameAgain != NULL, "Verify result from SDL_GetAudioDeviceName(%i, %i) is not NULL", i, tt);
                  if (nameAgain != NULL) {
                    SDLTest_AssertCheck(nameAgain[0] != '\0', "Verify result from SDL_GetAudioDeviceName(%i, %i) is not empty, got: '%s'", i, tt, nameAgain);
                    SDLTest_AssertCheck(SDL_strcmp(name, nameAgain)==0,
                      "Verify SDL_GetAudioDeviceName(%i, %i) and SDL_GetAudioDeviceName(%i %i) return the same string",
                      i, t, i, tt);
                  }
               }
            }
         }
      }
   }

   return TEST_COMPLETED;
}

/**
 * \brief Negative tests around enumeration and naming of audio devices.
 *
 * \sa https://wiki.libsdl.org/SDL_GetNumAudioDevices
 * \sa https://wiki.libsdl.org/SDL_GetAudioDeviceName
 */
int audio_enumerateAndNameAudioDevicesNegativeTests()
{
   int t;
   int i, j, no, nc;
   const char *name;

   /* Get number of devices. */
   no = SDL_GetNumAudioDevices(0);
   SDLTest_AssertPass("Call to SDL_GetNumAudioDevices(0)");
   nc = SDL_GetNumAudioDevices(1);
   SDLTest_AssertPass("Call to SDL_GetNumAudioDevices(1)");

   /* Invalid device index when getting name */
   for (t=0; t<2; t++) {
      /* Negative device index */
      i = SDLTest_RandomIntegerInRange(-10,-1);
      name = SDL_GetAudioDeviceName(i, t);
      SDLTest_AssertPass("Call to SDL_GetAudioDeviceName(%i, %i)", i, t);
      SDLTest_AssertCheck(name == NULL, "Check SDL_GetAudioDeviceName(%i, %i) result NULL, expected NULL, got: %s", i, t, (name == NULL) ? "NULL" : name);

      /* Device index past range */
      for (j=0; j<3; j++) {
         i = (t) ? nc+j : no+j;
         name = SDL_GetAudioDeviceName(i, t);
         SDLTest_AssertPass("Call to SDL_GetAudioDeviceName(%i, %i)", i, t);
         SDLTest_AssertCheck(name == NULL, "Check SDL_GetAudioDeviceName(%i, %i) result, expected: NULL, got: %s", i, t, (name == NULL) ? "NULL" : name);
      }

      /* Capture index past capture range but within output range */
      if ((no>0) && (no>nc) && (t==1)) {
         i = no-1;
         name = SDL_GetAudioDeviceName(i, t);
         SDLTest_AssertPass("Call to SDL_GetAudioDeviceName(%i, %i)", i, t);
         SDLTest_AssertCheck(name == NULL, "Check SDL_GetAudioDeviceName(%i, %i) result, expected: NULL, got: %s", i, t, (name == NULL) ? "NULL" : name);
      }
   }

   return TEST_COMPLETED;
}


/**
 * \brief Checks available audio driver names.
 *
 * \sa https://wiki.libsdl.org/SDL_GetNumAudioDrivers
 * \sa https://wiki.libsdl.org/SDL_GetAudioDriver
 */
int audio_printAudioDrivers()
{
   int i, n;
   const char *name;

   /* Get number of drivers */
   n = SDL_GetNumAudioDrivers();
   SDLTest_AssertPass("Call to SDL_GetNumAudioDrivers()");
   SDLTest_AssertCheck(n>=0, "Verify number of audio drivers >= 0, got: %i", n);

   /* List drivers. */
   if (n>0)
   {
      for (i=0; i<n; i++) {
         name = SDL_GetAudioDriver(i);
         SDLTest_AssertPass("Call to SDL_GetAudioDriver(%i)", i);
         SDLTest_AssertCheck(name != NULL, "Verify returned name is not NULL");
         if (name != NULL) {
            SDLTest_AssertCheck(name[0] != '\0', "Verify returned name is not empty, got: '%s'", name);
         }
      }
   }

   return TEST_COMPLETED;
}


/**
 * \brief Checks current audio driver name with initialized audio.
 *
 * \sa https://wiki.libsdl.org/SDL_GetCurrentAudioDriver
 */
int audio_printCurrentAudioDriver()
{
   /* Check current audio driver */
   const char *name = SDL_GetCurrentAudioDriver();
   SDLTest_AssertPass("Call to SDL_GetCurrentAudioDriver()");
   SDLTest_AssertCheck(name != NULL, "Verify returned name is not NULL");
   if (name != NULL) {
      SDLTest_AssertCheck(name[0] != '\0', "Verify returned name is not empty, got: '%s'", name);
   }

   return TEST_COMPLETED;
}

/* Definition of all formats, channels, and frequencies used to test audio conversions */
const int _numAudioFormats = 18;
SDL_AudioFormat _audioFormats[] = { AUDIO_S8, AUDIO_U8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_S16SYS, AUDIO_S16, AUDIO_U16LSB,
                AUDIO_U16MSB, AUDIO_U16SYS, AUDIO_U16, AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_S32SYS, AUDIO_S32,
                                AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_F32SYS, AUDIO_F32 };
char *_audioFormatsVerbose[] = { "AUDIO_S8", "AUDIO_U8", "AUDIO_S16LSB", "AUDIO_S16MSB", "AUDIO_S16SYS", "AUDIO_S16", "AUDIO_U16LSB",
                "AUDIO_U16MSB", "AUDIO_U16SYS", "AUDIO_U16", "AUDIO_S32LSB", "AUDIO_S32MSB", "AUDIO_S32SYS", "AUDIO_S32",
                                "AUDIO_F32LSB", "AUDIO_F32MSB", "AUDIO_F32SYS", "AUDIO_F32" };
const int _numAudioChannels = 4;
Uint8 _audioChannels[] = { 1, 2, 4, 6 };
const int _numAudioFrequencies = 4;
int _audioFrequencies[] = { 11025, 22050, 44100, 48000 };


/**
 * \brief Builds various audio conversion structures
 *
 * \sa https://wiki.libsdl.org/SDL_BuildAudioCVT
 */
int audio_buildAudioCVT()
{
  int result;
  SDL_AudioCVT  cvt;
  SDL_AudioSpec spec1;
  SDL_AudioSpec spec2;
  int i, ii, j, jj, k, kk;

  /* No conversion needed */
  spec1.format = AUDIO_S16LSB;
  spec1.channels = 2;
  spec1.freq = 22050;
  result = SDL_BuildAudioCVT(&cvt, spec1.format, spec1.channels, spec1.freq,
                                   spec1.format, spec1.channels, spec1.freq);
  SDLTest_AssertPass("Call to SDL_BuildAudioCVT(spec1 ==> spec1)");
  SDLTest_AssertCheck(result == 0, "Verify result value; expected: 0, got: %i", result);

  /* Typical conversion */
  spec1.format = AUDIO_S8;
  spec1.channels = 1;
  spec1.freq = 22050;
  spec2.format = AUDIO_S16LSB;
  spec2.channels = 2;
  spec2.freq = 44100;
  result = SDL_BuildAudioCVT(&cvt, spec1.format, spec1.channels, spec1.freq,
                                   spec2.format, spec2.channels, spec2.freq);
  SDLTest_AssertPass("Call to SDL_BuildAudioCVT(spec1 ==> spec2)");
  SDLTest_AssertCheck(result == 1, "Verify result value; expected: 1, got: %i", result);

  /* All source conversions with random conversion targets, allow 'null' conversions */
  for (i = 0; i < _numAudioFormats; i++) {
    for (j = 0; j < _numAudioChannels; j++) {
      for (k = 0; k < _numAudioFrequencies; k++) {
        spec1.format = _audioFormats[i];
        spec1.channels = _audioChannels[j];
        spec1.freq = _audioFrequencies[k];
        ii = SDLTest_RandomIntegerInRange(0, _numAudioFormats - 1);
        jj = SDLTest_RandomIntegerInRange(0, _numAudioChannels - 1);
        kk = SDLTest_RandomIntegerInRange(0, _numAudioFrequencies - 1);
        spec2.format = _audioFormats[ii];
        spec2.channels = _audioChannels[jj];
        spec2.freq = _audioFrequencies[kk];
        result = SDL_BuildAudioCVT(&cvt, spec1.format, spec1.channels, spec1.freq,
                                         spec2.format, spec2.channels, spec2.freq);
        SDLTest_AssertPass("Call to SDL_BuildAudioCVT(format[%i]=%s(%i),channels[%i]=%i,freq[%i]=%i ==> format[%i]=%s(%i),channels[%i]=%i,freq[%i]=%i)",
            i, _audioFormatsVerbose[i], spec1.format, j, spec1.channels, k, spec1.freq, ii, _audioFormatsVerbose[ii], spec2.format, jj, spec2.channels, kk, spec2.freq);
        SDLTest_AssertCheck(result == 0 || result == 1, "Verify result value; expected: 0 or 1, got: %i", result);
        if (result<0) {
          SDLTest_LogError("%s", SDL_GetError());
        } else {
          SDLTest_AssertCheck(cvt.len_mult > 0, "Verify that cvt.len_mult value; expected: >0, got: %i", cvt.len_mult);
        }
      }
    }
  }

   return TEST_COMPLETED;
}

/**
 * \brief Checkes calls with invalid input to SDL_BuildAudioCVT
 *
 * \sa https://wiki.libsdl.org/SDL_BuildAudioCVT
 */
int audio_buildAudioCVTNegative()
{
  const char *expectedError = "Parameter 'cvt' is invalid";
  const char *error;
  int result;
  SDL_AudioCVT  cvt;
  SDL_AudioSpec spec1;
  SDL_AudioSpec spec2;
  int i;
  char message[256];

  /* Valid format */
  spec1.format = AUDIO_S8;
  spec1.channels = 1;
  spec1.freq = 22050;
  spec2.format = AUDIO_S16LSB;
  spec2.channels = 2;
  spec2.freq = 44100;

  SDL_ClearError();
  SDLTest_AssertPass("Call to SDL_ClearError()");

  /* NULL input for CVT buffer */
  result = SDL_BuildAudioCVT((SDL_AudioCVT *)NULL, spec1.format, spec1.channels, spec1.freq,
                                                   spec2.format, spec2.channels, spec2.freq);
  SDLTest_AssertPass("Call to SDL_BuildAudioCVT(NULL,...)");
  SDLTest_AssertCheck(result == -1, "Verify result value; expected: -1, got: %i", result);
  error = SDL_GetError();
  SDLTest_AssertPass("Call to SDL_GetError()");
  SDLTest_AssertCheck(error != NULL, "Validate that error message was not NULL");
  if (error != NULL) {
      SDLTest_AssertCheck(SDL_strcmp(error, expectedError) == 0,
          "Validate error message, expected: '%s', got: '%s'", expectedError, error);
  }

  /* Invalid conversions */
  for (i = 1; i < 64; i++) {
    /* Valid format to start with */
    spec1.format = AUDIO_S8;
    spec1.channels = 1;
    spec1.freq = 22050;
    spec2.format = AUDIO_S16LSB;
    spec2.channels = 2;
    spec2.freq = 44100;

    SDL_ClearError();
    SDLTest_AssertPass("Call to SDL_ClearError()");

    /* Set various invalid format inputs */
    SDL_strlcpy(message, "Invalid: ", 256);
    if (i & 1) {
        SDL_strlcat(message, " spec1.format", 256);
        spec1.format = 0;
    }
    if (i & 2) {
        SDL_strlcat(message, " spec1.channels", 256);
        spec1.channels = 0;
    }
    if (i & 4) {
        SDL_strlcat(message, " spec1.freq", 256);
        spec1.freq = 0;
    }
    if (i & 8) {
        SDL_strlcat(message, " spec2.format", 256);
        spec2.format = 0;
    }
    if (i & 16) {
        SDL_strlcat(message, " spec2.channels", 256);
        spec2.channels = 0;
    }
    if (i & 32) {
        SDL_strlcat(message, " spec2.freq", 256);
        spec2.freq = 0;
    }
    SDLTest_Log("%s", message);
    result = SDL_BuildAudioCVT(&cvt, spec1.format, spec1.channels, spec1.freq,
                                   spec2.format, spec2.channels, spec2.freq);
    SDLTest_AssertPass("Call to SDL_BuildAudioCVT(spec1 ==> spec2)");
    SDLTest_AssertCheck(result == -1, "Verify result value; expected: -1, got: %i", result);
    error = SDL_GetError();
    SDLTest_AssertPass("Call to SDL_GetError()");
    SDLTest_AssertCheck(error != NULL && error[0] != '\0', "Validate that error message was not NULL or empty");
  }

  SDL_ClearError();
  SDLTest_AssertPass("Call to SDL_ClearError()");

  return TEST_COMPLETED;
}

/**
 * \brief Checks current audio status.
 *
 * \sa https://wiki.libsdl.org/SDL_GetAudioStatus
 */
int audio_getAudioStatus()
{
   SDL_AudioStatus result;

   /* Check current audio status */
   result = SDL_GetAudioStatus();
   SDLTest_AssertPass("Call to SDL_GetAudioStatus()");
   SDLTest_AssertCheck(result == SDL_AUDIO_STOPPED || result == SDL_AUDIO_PLAYING || result == SDL_AUDIO_PAUSED,
        "Verify returned value; expected: STOPPED (%i) | PLAYING (%i) | PAUSED (%i), got: %i",
        SDL_AUDIO_STOPPED, SDL_AUDIO_PLAYING, SDL_AUDIO_PAUSED, result);

   return TEST_COMPLETED;
}



/**
 * \brief Opens, checks current audio status, and closes a device.
 *
 * \sa https://wiki.libsdl.org/SDL_GetAudioStatus
 */
int audio_openCloseAndGetAudioStatus()
{
   SDL_AudioStatus result;
   int i;
   int count;
   char *device;
   SDL_AudioDeviceID id;
   SDL_AudioSpec desired, obtained;

   /* Get number of devices. */
   count = SDL_GetNumAudioDevices(0);
   SDLTest_AssertPass("Call to SDL_GetNumAudioDevices(0)");
   if (count > 0) {
     for (i = 0; i < count; i++) {
       /* Get device name */
       device = (char *)SDL_GetAudioDeviceName(i, 0);
       SDLTest_AssertPass("SDL_GetAudioDeviceName(%i,0)", i);
       SDLTest_AssertCheck(device != NULL, "Validate device name is not NULL; got: %s", (device != NULL) ? device : "NULL");
       if (device == NULL) return TEST_ABORTED;

       /* Set standard desired spec */
       desired.freq=22050;
       desired.format=AUDIO_S16SYS;
       desired.channels=2;
       desired.samples=4096;
       desired.callback=_audio_testCallback;
       desired.userdata=NULL;

       /* Open device */
       id = SDL_OpenAudioDevice((const char *)device, 0, &desired, &obtained, SDL_AUDIO_ALLOW_ANY_CHANGE);
       SDLTest_AssertPass("SDL_OpenAudioDevice('%s',...)", device);
       SDLTest_AssertCheck(id > 1, "Validate device ID; expected: >=2, got: %i", id);
       if (id > 1) {

         /* Check device audio status */
         result = SDL_GetAudioDeviceStatus(id);
         SDLTest_AssertPass("Call to SDL_GetAudioDeviceStatus()");
         SDLTest_AssertCheck(result == SDL_AUDIO_STOPPED || result == SDL_AUDIO_PLAYING || result == SDL_AUDIO_PAUSED,
            "Verify returned value; expected: STOPPED (%i) | PLAYING (%i) | PAUSED (%i), got: %i",
            SDL_AUDIO_STOPPED, SDL_AUDIO_PLAYING, SDL_AUDIO_PAUSED, result);

         /* Close device again */
         SDL_CloseAudioDevice(id);
         SDLTest_AssertPass("Call to SDL_CloseAudioDevice()");
       }
     }
   } else {
     SDLTest_Log("No devices to test with");
   }

   return TEST_COMPLETED;
}

/**
 * \brief Locks and unlocks open audio device.
 *
 * \sa https://wiki.libsdl.org/SDL_LockAudioDevice
 * \sa https://wiki.libsdl.org/SDL_UnlockAudioDevice
 */
int audio_lockUnlockOpenAudioDevice()
{
   int i;
   int count;
   char *device;
   SDL_AudioDeviceID id;
   SDL_AudioSpec desired, obtained;

   /* Get number of devices. */
   count = SDL_GetNumAudioDevices(0);
   SDLTest_AssertPass("Call to SDL_GetNumAudioDevices(0)");
   if (count > 0) {
     for (i = 0; i < count; i++) {
       /* Get device name */
       device = (char *)SDL_GetAudioDeviceName(i, 0);
       SDLTest_AssertPass("SDL_GetAudioDeviceName(%i,0)", i);
       SDLTest_AssertCheck(device != NULL, "Validate device name is not NULL; got: %s", (device != NULL) ? device : "NULL");
       if (device == NULL) return TEST_ABORTED;

       /* Set standard desired spec */
       desired.freq=22050;
       desired.format=AUDIO_S16SYS;
       desired.channels=2;
       desired.samples=4096;
       desired.callback=_audio_testCallback;
       desired.userdata=NULL;

       /* Open device */
       id = SDL_OpenAudioDevice((const char *)device, 0, &desired, &obtained, SDL_AUDIO_ALLOW_ANY_CHANGE);
       SDLTest_AssertPass("SDL_OpenAudioDevice('%s',...)", device);
       SDLTest_AssertCheck(id > 1, "Validate device ID; expected: >=2, got: %i", id);
       if (id > 1) {
         /* Lock to protect callback */
         SDL_LockAudioDevice(id);
         SDLTest_AssertPass("SDL_LockAudioDevice(%i)", id);

         /* Simulate callback processing */
         SDL_Delay(10);
         SDLTest_Log("Simulate callback processing - delay");

         /* Unlock again */
         SDL_UnlockAudioDevice(id);
         SDLTest_AssertPass("SDL_UnlockAudioDevice(%i)", id);

         /* Close device again */
         SDL_CloseAudioDevice(id);
         SDLTest_AssertPass("Call to SDL_CloseAudioDevice()");
       }
     }
   } else {
     SDLTest_Log("No devices to test with");
   }

   return TEST_COMPLETED;
}


/**
 * \brief Convert audio using various conversion structures
 *
 * \sa https://wiki.libsdl.org/SDL_BuildAudioCVT
 * \sa https://wiki.libsdl.org/SDL_ConvertAudio
 */
int audio_convertAudio()
{
  int result;
  SDL_AudioCVT  cvt;
  SDL_AudioSpec spec1;
  SDL_AudioSpec spec2;
  int c;
  char message[128];
  int i, ii, j, jj, k, kk, l, ll;

  /* Iterate over bitmask that determines which parameters are modified in the conversion */
  for (c = 1; c < 8; c++) {
    SDL_strlcpy(message, "Changing:", 128);
    if (c & 1) {
      SDL_strlcat(message, " Format", 128);
    }
    if (c & 2) {
      SDL_strlcat(message, " Channels", 128);
    }
    if (c & 4) {
      SDL_strlcat(message, " Frequencies", 128);
    }
    SDLTest_Log("%s", message);
    /* All source conversions with random conversion targets */
    for (i = 0; i < _numAudioFormats; i++) {
      for (j = 0; j < _numAudioChannels; j++) {
        for (k = 0; k < _numAudioFrequencies; k++) {
          spec1.format = _audioFormats[i];
          spec1.channels = _audioChannels[j];
          spec1.freq = _audioFrequencies[k];

          /* Ensure we have a different target format */
          do {
            if (c & 1) {
              ii = SDLTest_RandomIntegerInRange(0, _numAudioFormats - 1);
            } else {
              ii = 1;
            }
            if (c & 2) {
              jj = SDLTest_RandomIntegerInRange(0, _numAudioChannels - 1);
            } else {
              jj= j;
            }
            if (c & 4) {
              kk = SDLTest_RandomIntegerInRange(0, _numAudioFrequencies - 1);
            } else {
              kk = k;
            }
          } while ((i == ii) && (j == jj) && (k == kk));
          spec2.format = _audioFormats[ii];
          spec2.channels = _audioChannels[jj];
          spec2.freq = _audioFrequencies[kk];

          result = SDL_BuildAudioCVT(&cvt, spec1.format, spec1.channels, spec1.freq,
                                           spec2.format, spec2.channels, spec2.freq);
          SDLTest_AssertPass("Call to SDL_BuildAudioCVT(format[%i]=%s(%i),channels[%i]=%i,freq[%i]=%i ==> format[%i]=%s(%i),channels[%i]=%i,freq[%i]=%i)",
            i, _audioFormatsVerbose[i], spec1.format, j, spec1.channels, k, spec1.freq, ii, _audioFormatsVerbose[ii], spec2.format, jj, spec2.channels, kk, spec2.freq);
          SDLTest_AssertCheck(result == 1, "Verify result value; expected: 1, got: %i", result);
          if (result != 1) {
            SDLTest_LogError("%s", SDL_GetError());
          } else {
            SDLTest_AssertCheck(cvt.len_mult > 0, "Verify that cvt.len_mult value; expected: >0, got: %i", cvt.len_mult);
            if (cvt.len_mult < 1) return TEST_ABORTED;

            /* Create some random data to convert */
            l = 64;
            ll = l * cvt.len_mult;
            SDLTest_Log("Creating dummy sample buffer of %i length (%i bytes)", l, ll);
            cvt.len = l;
            cvt.buf = (Uint8 *)SDL_malloc(ll);
            SDLTest_AssertCheck(cvt.buf != NULL, "Check data buffer to convert is not NULL");
            if (cvt.buf == NULL) return TEST_ABORTED;

            /* Convert the data */
            result = SDL_ConvertAudio(&cvt);
            SDLTest_AssertPass("Call to SDL_ConvertAudio()");
            SDLTest_AssertCheck(result == 0, "Verify result value; expected: 0; got: %i", result);
            SDLTest_AssertCheck(cvt.buf != NULL, "Verify conversion buffer is not NULL");
            SDLTest_AssertCheck(cvt.len_ratio > 0.0, "Verify conversion length ratio; expected: >0; got: %f", cvt.len_ratio);

            /* Free converted buffer */
            SDL_free(cvt.buf);
            cvt.buf = NULL;
          }
        }
      }
    }
  }

   return TEST_COMPLETED;
}


/**
 * \brief Opens, checks current connected status, and closes a device.
 *
 * \sa https://wiki.libsdl.org/SDL_AudioDeviceConnected
 */
int audio_openCloseAudioDeviceConnected()
{
   int result = -1;
   int i;
   int count;
   char *device;
   SDL_AudioDeviceID id;
   SDL_AudioSpec desired, obtained;

   /* Get number of devices. */
   count = SDL_GetNumAudioDevices(0);
   SDLTest_AssertPass("Call to SDL_GetNumAudioDevices(0)");
   if (count > 0) {
     for (i = 0; i < count; i++) {
       /* Get device name */
       device = (char *)SDL_GetAudioDeviceName(i, 0);
       SDLTest_AssertPass("SDL_GetAudioDeviceName(%i,0)", i);
       SDLTest_AssertCheck(device != NULL, "Validate device name is not NULL; got: %s", (device != NULL) ? device : "NULL");
       if (device == NULL) return TEST_ABORTED;

       /* Set standard desired spec */
       desired.freq=22050;
       desired.format=AUDIO_S16SYS;
       desired.channels=2;
       desired.samples=4096;
       desired.callback=_audio_testCallback;
       desired.userdata=NULL;

       /* Open device */
       id = SDL_OpenAudioDevice((const char *)device, 0, &desired, &obtained, SDL_AUDIO_ALLOW_ANY_CHANGE);
       SDLTest_AssertPass("SDL_OpenAudioDevice('%s',...)", device);
       SDLTest_AssertCheck(id > 1, "Validate device ID; expected: >1, got: %i", id);
       if (id > 1) {

/* TODO: enable test code when function is available in SDL2 */

#ifdef AUDIODEVICECONNECTED_DEFINED
         /* Get connected status */
         result = SDL_AudioDeviceConnected(id);
         SDLTest_AssertPass("Call to SDL_AudioDeviceConnected()");
#endif
         SDLTest_AssertCheck(result == 1, "Verify returned value; expected: 1; got: %i", result);

         /* Close device again */
         SDL_CloseAudioDevice(id);
         SDLTest_AssertPass("Call to SDL_CloseAudioDevice()");
       }
     }
   } else {
     SDLTest_Log("No devices to test with");
   }

   return TEST_COMPLETED;
}



/* ================= Test Case References ================== */

/* Audio test cases */
static const SDLTest_TestCaseReference audioTest1 =
        { (SDLTest_TestCaseFp)audio_enumerateAndNameAudioDevices, "audio_enumerateAndNameAudioDevices", "Enumerate and name available audio devices (output and capture)", TEST_ENABLED };

static const SDLTest_TestCaseReference audioTest2 =
        { (SDLTest_TestCaseFp)audio_enumerateAndNameAudioDevicesNegativeTests, "audio_enumerateAndNameAudioDevicesNegativeTests", "Negative tests around enumeration and naming of audio devices.", TEST_ENABLED };

static const SDLTest_TestCaseReference audioTest3 =
        { (SDLTest_TestCaseFp)audio_printAudioDrivers, "audio_printAudioDrivers", "Checks available audio driver names.", TEST_ENABLED };

static const SDLTest_TestCaseReference audioTest4 =
        { (SDLTest_TestCaseFp)audio_printCurrentAudioDriver, "audio_printCurrentAudioDriver", "Checks current audio driver name with initialized audio.", TEST_ENABLED };

static const SDLTest_TestCaseReference audioTest5 =
        { (SDLTest_TestCaseFp)audio_buildAudioCVT, "audio_buildAudioCVT", "Builds various audio conversion structures.", TEST_ENABLED };

static const SDLTest_TestCaseReference audioTest6 =
        { (SDLTest_TestCaseFp)audio_buildAudioCVTNegative, "audio_buildAudioCVTNegative", "Checks calls with invalid input to SDL_BuildAudioCVT", TEST_ENABLED };

static const SDLTest_TestCaseReference audioTest7 =
        { (SDLTest_TestCaseFp)audio_getAudioStatus, "audio_getAudioStatus", "Checks current audio status.", TEST_ENABLED };

static const SDLTest_TestCaseReference audioTest8 =
        { (SDLTest_TestCaseFp)audio_openCloseAndGetAudioStatus, "audio_openCloseAndGetAudioStatus", "Opens and closes audio device and get audio status.", TEST_ENABLED };

static const SDLTest_TestCaseReference audioTest9 =
        { (SDLTest_TestCaseFp)audio_lockUnlockOpenAudioDevice, "audio_lockUnlockOpenAudioDevice", "Locks and unlocks an open audio device.", TEST_ENABLED };

/* TODO: enable test when SDL_ConvertAudio segfaults on cygwin have been fixed.    */
/* For debugging, test case can be run manually using --filter audio_convertAudio  */

static const SDLTest_TestCaseReference audioTest10 =
        { (SDLTest_TestCaseFp)audio_convertAudio, "audio_convertAudio", "Convert audio using available formats.", TEST_DISABLED };

/* TODO: enable test when SDL_AudioDeviceConnected has been implemented.           */

static const SDLTest_TestCaseReference audioTest11 =
        { (SDLTest_TestCaseFp)audio_openCloseAudioDeviceConnected, "audio_openCloseAudioDeviceConnected", "Opens and closes audio device and get connected status.", TEST_DISABLED };

static const SDLTest_TestCaseReference audioTest12 =
        { (SDLTest_TestCaseFp)audio_quitInitAudioSubSystem, "audio_quitInitAudioSubSystem", "Quit and re-init audio subsystem.", TEST_ENABLED };

static const SDLTest_TestCaseReference audioTest13 =
        { (SDLTest_TestCaseFp)audio_initQuitAudio, "audio_initQuitAudio", "Init and quit audio drivers directly.", TEST_ENABLED };

static const SDLTest_TestCaseReference audioTest14 =
        { (SDLTest_TestCaseFp)audio_initOpenCloseQuitAudio, "audio_initOpenCloseQuitAudio", "Cycle through init, open, close and quit with various audio specs.", TEST_ENABLED };

static const SDLTest_TestCaseReference audioTest15 =
        { (SDLTest_TestCaseFp)audio_pauseUnpauseAudio, "audio_pauseUnpauseAudio", "Pause and Unpause audio for various audio specs while testing callback.", TEST_ENABLED };

/* Sequence of Audio test cases */
static const SDLTest_TestCaseReference *audioTests[] =  {
    &audioTest1, &audioTest2, &audioTest3, &audioTest4, &audioTest5, &audioTest6,
    &audioTest7, &audioTest8, &audioTest9, &audioTest10, &audioTest11,
    &audioTest12, &audioTest13, &audioTest14, &audioTest15, NULL
};

/* Audio test suite (global) */
SDLTest_TestSuiteReference audioTestSuite = {
    "Audio",
    _audioSetUp,
    audioTests,
    _audioTearDown
};
0, int cswidth = 0) override
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+
+ void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); }
+ void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); }
+ void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8smo_delegate rhandler, write8smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+ void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); }
+ void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); }
+ void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16smo_delegate rhandler, write16smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+ void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); }
+ void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); }
+ void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32smo_delegate rhandler, write32smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+ void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); }
+ void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); }
+ void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64smo_delegate rhandler, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+
+ 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<void (offs_t offset, uX &data, uX mem_mask)> 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<void (offs_t offset, uX &data, uX mem_mask)> 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<void (offs_t offset, uX &data, uX mem_mask)> tapr, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapw, memory_passthrough_handler *mph) override;
+
+ // 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 <Width, AddrShift, Endian>(this);
+ m_unmap_w = new handler_entry_write_unmapped<Width, AddrShift, Endian>(this);
+ m_nop_r = new handler_entry_read_nop <Width, AddrShift, Endian>(this);
+ m_nop_w = new handler_entry_write_nop<Width, AddrShift, Endian>(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);
+ }
+
+ m_dispatch_read = m_root_read ->get_dispatch();
+ m_dispatch_write = m_root_write->get_dispatch();
+ }
+
+ std::pair<void *, void *> get_cache_info() override {
+ std::pair<void *, void *> rw;
+ rw.first = m_root_read;
+ rw.second = m_root_write;
+ return rw;
+ }
+
+ std::pair<const void *, const void *> get_specific_info() override {
+ std::pair<const void *, const void *> rw;
+ rw.first = m_dispatch_read;
+ rw.second = m_dispatch_write;
+ return rw;
+ }
+
+ void delayed_ref(handler_entry *e) {
+ e->ref();
+ m_delayed_unrefs.insert(e);
+ }
+
+ void delayed_unref(handler_entry *e) {
+ m_delayed_unrefs.erase(m_delayed_unrefs.find(e));
+ e->unref();
+ }
+
+ 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();
+ }
+
+ virtual void remove_passthrough(std::unordered_set<handler_entry *> &handlers) override {
+ invalidate_caches(read_or_write::READWRITE);
+ m_root_read->detach(handlers);
+ m_root_write->detach(handlers);
+ }
+
+ // generate accessor table
+ virtual void accessors(data_accessors &accessors) const override
+ {
+ accessors.read_byte = reinterpret_cast<u8 (*)(address_space &, offs_t)>(&read_byte_static);
+ accessors.read_word = reinterpret_cast<u16 (*)(address_space &, offs_t)>(&read_word_static);
+ accessors.read_word_masked = reinterpret_cast<u16 (*)(address_space &, offs_t, u16)>(&read_word_masked_static);
+ accessors.read_dword = reinterpret_cast<u32 (*)(address_space &, offs_t)>(&read_dword_static);
+ accessors.read_dword_masked = reinterpret_cast<u32 (*)(address_space &, offs_t, u32)>(&read_dword_masked_static);
+ accessors.read_qword = reinterpret_cast<u64 (*)(address_space &, offs_t)>(&read_qword_static);
+ accessors.read_qword_masked = reinterpret_cast<u64 (*)(address_space &, offs_t, u64)>(&read_qword_masked_static);
+ accessors.write_byte = reinterpret_cast<void (*)(address_space &, offs_t, u8)>(&write_byte_static);
+ accessors.write_word = reinterpret_cast<void (*)(address_space &, offs_t, u16)>(&write_word_static);
+ accessors.write_word_masked = reinterpret_cast<void (*)(address_space &, offs_t, u16, u16)>(&write_word_masked_static);
+ accessors.write_dword = reinterpret_cast<void (*)(address_space &, offs_t, u32)>(&write_dword_static);
+ accessors.write_dword_masked = reinterpret_cast<void (*)(address_space &, offs_t, u32, u32)>(&write_dword_masked_static);
+ accessors.write_qword = reinterpret_cast<void (*)(address_space &, offs_t, u64)>(&write_qword_static);
+ accessors.write_qword_masked = reinterpret_cast<void (*)(address_space &, offs_t, u64, u64)>(&write_qword_masked_static);
+ }
+
+ // return a pointer to the read bank, or nullptr if none
+ virtual void *get_read_ptr(offs_t address) const override
+ {
+ return m_root_read->get_ptr(address);
+ }
+
+ // 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);
+ }
+
+ // native read
+ NativeType read_native(offs_t offset, NativeType mask)
+ {
+ return dispatch_read<Level, Width, AddrShift, Endian>(offs_t(-1), offset & m_addrmask, mask, m_dispatch_read);
+ }
+
+ // mask-less native read
+ NativeType read_native(offs_t offset)
+ {
+ return dispatch_read<Level, Width, AddrShift, Endian>(offs_t(-1), offset & m_addrmask, uX(0xffffffffffffffffU), m_dispatch_read);
+ }
+
+ // native write
+ void write_native(offs_t offset, NativeType data, NativeType mask)
+ {
+ dispatch_write<Level, Width, AddrShift, Endian>(offs_t(-1), offset & m_addrmask, data, mask, m_dispatch_write);
+ }
+
+ // mask-less native write
+ void write_native(offs_t offset, NativeType data)
+ {
+ dispatch_write<Level, Width, AddrShift, Endian>(offs_t(-1), offset & m_addrmask, data, uX(0xffffffffffffffffU), m_dispatch_write);
+ }
+
+ // virtual access to these functions
+ u8 read_byte(offs_t address) override { return Width == 0 ? read_native(address & ~NATIVE_MASK) : memory_read_generic<Width, AddrShift, Endian, 0, true>([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<Width, AddrShift, Endian, 1, true>([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<Width, AddrShift, Endian, 1, true>([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<Width, AddrShift, Endian, 1, false>([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<Width, AddrShift, Endian, 1, false>([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<Width, AddrShift, Endian, 2, true>([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<Width, AddrShift, Endian, 2, true>([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<Width, AddrShift, Endian, 2, false>([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<Width, AddrShift, Endian, 2, false>([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<Width, AddrShift, Endian, 3, true>([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<Width, AddrShift, Endian, 3, true>([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<Width, AddrShift, Endian, 3, false>([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<Width, AddrShift, Endian, 3, false>([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<Width, AddrShift, Endian, 0, true>([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<Width, AddrShift, Endian, 1, true>([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<Width, AddrShift, Endian, 1, true>([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<Width, AddrShift, Endian, 1, false>([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<Width, AddrShift, Endian, 1, false>([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<Width, AddrShift, Endian, 2, true>([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<Width, AddrShift, Endian, 2, true>([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<Width, AddrShift, Endian, 2, false>([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<Width, AddrShift, Endian, 2, false>([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<Width, AddrShift, Endian, 3, true>([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<Width, AddrShift, Endian, 3, true>([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<Width, AddrShift, Endian, 3, false>([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<Width, AddrShift, Endian, 3, false>([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<Width, AddrShift, Endian, 0, true>([&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<Width, AddrShift, Endian, 1, true>([&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<Width, AddrShift, Endian, 1, true>([&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<Width, AddrShift, Endian, 2, true>([&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<Width, AddrShift, Endian, 2, true>([&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<Width, AddrShift, Endian, 3, true>([&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<Width, AddrShift, Endian, 3, true>([&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<Width, AddrShift, Endian, 0, true>([&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<Width, AddrShift, Endian, 1, true>([&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<Width, AddrShift, Endian, 1, true>([&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<Width, AddrShift, Endian, 2, true>([&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<Width, AddrShift, Endian, 2, true>([&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<Width, AddrShift, Endian, 3, false>([&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<Width, AddrShift, Endian, 3, false>([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, mask); }
+
+ handler_entry_read <Width, AddrShift, Endian> *m_root_read;
+ handler_entry_write<Width, AddrShift, Endian> *m_root_write;
+
+ std::unordered_set<handler_entry *> m_delayed_unrefs;
+
+private:
+ template<typename READ>
+ void install_read_handler_impl(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, READ &handler_r)
+ {
+ try { handler_r.resolve(); }
+ catch (const binding_type_exception &) {
+ osd_printf_error("Binding error while installing read handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_r.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask);
+ throw;
+ }
+ install_read_handler_helper<handler_width<READ>::value>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, handler_r);
+ }
+
+ template<typename WRITE>
+ void install_write_handler_impl(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, WRITE &handler_w)
+ {
+ try { handler_w.resolve(); }
+ catch (const binding_type_exception &) {
+ osd_printf_error("Binding error while installing write handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_w.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask);
+ throw;
+ }
+ install_write_handler_helper<handler_width<WRITE>::value>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, handler_w);
+ }
+
+ template<typename READ, typename WRITE>
+ void install_readwrite_handler_impl(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, READ &handler_r, WRITE &handler_w)
+ {
+ static_assert(handler_width<READ>::value == handler_width<WRITE>::value, "handler widths do not match");
+ try { handler_r.resolve(); }
+ catch (const binding_type_exception &) {
+ osd_printf_error("Binding error while installing read handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_r.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask);
+ throw;
+ }
+ try { handler_w.resolve(); }
+ catch (const binding_type_exception &) {
+ osd_printf_error("Binding error while installing write handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_w.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask);
+ throw;
+ }
+ install_readwrite_handler_helper<handler_width<READ>::value>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, handler_r, handler_w);
+ }
+
+ template<int AccessWidth, typename READ>
+ void install_read_handler_helper(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, const READ &handler_r)
+ {
+ if constexpr (Width < AccessWidth) {
+ fatalerror("install_read_handler: cannot install a %d-wide handler in a %d-wide bus", 8 << AccessWidth, 8 << Width);
+ } else {
+ VPRINTF("address_space::install_read_handler(%*x-%*x mask=%*x mirror=%*x, space width=%d, handler width=%d, %s, %*x)\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmask, m_addrchars, addrmirror,
+ 8 << Width, 8 << AccessWidth,
+ handler_r.name(), data_width() / 4, unitmask);
+
+ 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);
+
+ if constexpr (Width == AccessWidth) {
+ auto hand_r = new handler_entry_read_delegate<Width, AddrShift, Endian, READ>(this, handler_r);
+ hand_r->set_address_info(nstart, nmask);
+ m_root_read->populate(nstart, nend, nmirror, hand_r);
+ } else {
+ auto hand_r = new handler_entry_read_delegate<AccessWidth, -AccessWidth, Endian, READ>(this, handler_r);
+ memory_units_descriptor<Width, AddrShift, Endian> 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);
+ }
+ }
+
+ template<int AccessWidth, typename WRITE>
+ void install_write_handler_helper(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth,
+ const WRITE &handler_w)
+ {
+ if constexpr (Width < AccessWidth) {
+ fatalerror("install_write_handler: cannot install a %d-wide handler in a %d-wide bus", 8 << AccessWidth, 8 << Width);
+ } else {
+ VPRINTF("address_space::install_write_handler(%*x-%*x mask=%*x mirror=%*x, space width=%d, handler width=%d, %s, %*x)\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmask, m_addrchars, addrmirror,
+ 8 << Width, 8 << AccessWidth,
+ handler_w.name(), data_width() / 4, unitmask);
+
+ 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);
+
+ if constexpr (Width == AccessWidth) {
+ auto hand_w = new handler_entry_write_delegate<Width, AddrShift, Endian, WRITE>(this, handler_w);
+ hand_w->set_address_info(nstart, nmask);
+ m_root_write->populate(nstart, nend, nmirror, hand_w);
+ } else {
+ auto hand_w = new handler_entry_write_delegate<AccessWidth, -AccessWidth, Endian, WRITE>(this, handler_w);
+ memory_units_descriptor<Width, AddrShift, Endian> 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);
+ }
+ }
+
+ template<int AccessWidth, typename READ, typename WRITE>
+ void install_readwrite_handler_helper(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth,
+ const READ &handler_r,
+ const WRITE &handler_w)
+ {
+ if constexpr (Width < AccessWidth) {
+ fatalerror("install_readwrite_handler: cannot install a %d-wide handler in a %d-wide bus", 8 << AccessWidth, 8 << Width);
+ } else {
+ VPRINTF("address_space::install_readwrite_handler(%*x-%*x mask=%*x mirror=%*x, space width=%d, handler width=%d, %s, %s, %*x)\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmask, m_addrchars, addrmirror,
+ 8 << Width, 8 << AccessWidth,
+ handler_r.name(), handler_w.name(), data_width() / 4, unitmask);
+
+ 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);
+
+ if constexpr (Width == AccessWidth) {
+ auto hand_r = new handler_entry_read_delegate <Width, AddrShift, Endian, READ>(this, handler_r);
+ hand_r->set_address_info(nstart, nmask);
+ m_root_read ->populate(nstart, nend, nmirror, hand_r);
+
+ auto hand_w = new handler_entry_write_delegate<Width, AddrShift, Endian, WRITE>(this, handler_w);
+ hand_w->set_address_info(nstart, nmask);
+ m_root_write->populate(nstart, nend, nmirror, hand_w);
+ } else {
+ auto hand_r = new handler_entry_read_delegate <AccessWidth, -AccessWidth, Endian, READ>(this, handler_r);
+ memory_units_descriptor<Width, AddrShift, Endian> 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();
+
+ auto hand_w = new handler_entry_write_delegate<AccessWidth, -AccessWidth, Endian, WRITE>(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();
+ }
+ invalidate_caches(read_or_write::READWRITE);
+ }
+ }
+};
+
+
+
+//-------------------------------------------------
+// allocate - allocate memory spaces
+//-------------------------------------------------
+
+void memory_manager::allocate(device_memory_interface &memory)
+{
+ for (int spacenum = 0; spacenum < memory.max_space_count(); ++spacenum)
+ {
+ // if there is a configuration for this space, we need an address space
+ address_space_config const *const spaceconfig = memory.space_config(spacenum);
+ if (spaceconfig)
+ {
+ int level = emu::detail::handler_entry_dispatch_level(spaceconfig->addr_width());
+ // allocate one of the appropriate type
+ switch ((level << 8) | (spaceconfig->endianness() == ENDIANNESS_BIG ? 0x1000 : 0) |spaceconfig->data_width() | (spaceconfig->addr_shift() + 4))
+ {
+ case 0x0000|0x000| 8|(4+1): memory.allocate<address_space_specific<0, 0, 1, ENDIANNESS_LITTLE>>(*this, spacenum); break;
+ case 0x1000|0x000| 8|(4+1): memory.allocate<address_space_specific<0, 0, 1, ENDIANNESS_BIG >>(*this, spacenum); break;
+ case 0x0000|0x100| 8|(4+1): memory.allocate<address_space_specific<1, 0, 1, ENDIANNESS_LITTLE>>(*this, spacenum); break;
+ case 0x1000|0x100| 8|(4+1): memory.allocate<address_space_specific<1, 0, 1, ENDIANNESS_BIG >>(*this, spacenum); break;
+
+ case 0x0000|0x000| 8|(4-0): memory.allocate<address_space_specific<0, 0, 0, ENDIANNESS_LITTLE>>(*this, spacenum); break;
+ case 0x1000|0x000| 8|(4-0): memory.allocate<address_space_specific<0, 0, 0, ENDIANNESS_BIG >>(*this, spacenum); break;
+ case 0x0000|0x100| 8|(4-0): memory.allocate<address_space_specific<1, 0, 0, ENDIANNESS_LITTLE>>(*this, spacenum); break;
+ case 0x1000|0x100| 8|(4-0): memory.allocate<address_space_specific<1, 0, 0, ENDIANNESS_BIG >>(*this, spacenum); break;
+
+ case 0x0000|0x000|16|(4+3): memory.allocate<address_space_specific<0, 1, 3, ENDIANNESS_LITTLE>>(*this, spacenum); break;
+ case 0x1000|0x000|16|(4+3): memory.allocate<address_space_specific<0, 1, 3, ENDIANNESS_BIG >>(*this, spacenum); break;
+ case 0x0000|0x100|16|(4+3): memory.allocate<address_space_specific<1, 1, 3, ENDIANNESS_LITTLE>>(*this, spacenum); break;
+ case 0x1000|0x100|16|(4+3): memory.allocate<address_space_specific<1, 1, 3, ENDIANNESS_BIG >>(*this, spacenum); break;
+
+ case 0x0000|0x000|16|(4-0): memory.allocate<address_space_specific<0, 1, 0, ENDIANNESS_LITTLE>>(*this, spacenum); break;
+ case 0x1000|0x000|16|(4-0): memory.allocate<address_space_specific<0, 1, 0, ENDIANNESS_BIG >>(*this, spacenum); break;
+ case 0x0000|0x100|16|(4-0): memory.allocate<address_space_specific<1, 1, 0, ENDIANNESS_LITTLE>>(*this, spacenum); break;
+ case 0x1000|0x100|16|(4-0): memory.allocate<address_space_specific<1, 1, 0, ENDIANNESS_BIG >>(*this, spacenum); break;
+
+ case 0x0000|0x000|16|(4-1): memory.allocate<address_space_specific<0, 1, -1, ENDIANNESS_LITTLE>>(*this, spacenum); break;
+ case 0x1000|0x000|16|(4-1): memory.allocate<address_space_specific<0, 1, -1, ENDIANNESS_BIG >>(*this, spacenum); break;
+ case 0x0000|0x100|16|(4-1): memory.allocate<address_space_specific<1, 1, -1, ENDIANNESS_LITTLE>>(*this, spacenum); break;
+ case 0x1000|0x100|16|(4-1): memory.allocate<address_space_specific<1, 1, -1, ENDIANNESS_BIG >>(*this, spacenum); break;
+
+ case 0x0000|0x000|32|(4+3): memory.allocate<address_space_specific<0, 2, 3, ENDIANNESS_LITTLE>>(*this, spacenum); break;
+ case 0x1000|0x000|32|(4+3): memory.allocate<address_space_specific<0, 2, 3, ENDIANNESS_BIG >>(*this, spacenum); break;
+ case 0x0000|0x100|32|(4+3): memory.allocate<address_space_specific<1, 2, 3, ENDIANNESS_LITTLE>>(*this, spacenum); break;
+ case 0x1000|0x100|32|(4+3): memory.allocate<address_space_specific<1, 2, 3, ENDIANNESS_BIG >>(*this, spacenum); break;
+
+ case 0x0000|0x000|32|(4-0): memory.allocate<address_space_specific<0, 2, 0, ENDIANNESS_LITTLE>>(*this, spacenum); break;
+ case 0x1000|0x000|32|(4-0): memory.allocate<address_space_specific<0, 2, 0, ENDIANNESS_BIG >>(*this, spacenum); break;
+ case 0x0000|0x100|32|(4-0): memory.allocate<address_space_specific<1, 2, 0, ENDIANNESS_LITTLE>>(*this, spacenum); break;
+ case 0x1000|0x100|32|(4-0): memory.allocate<address_space_specific<1, 2, 0, ENDIANNESS_BIG >>(*this, spacenum); break;
+
+ case 0x0000|0x000|32|(4-1): memory.allocate<address_space_specific<0, 2, -1, ENDIANNESS_LITTLE>>(*this, spacenum); break;
+ case 0x1000|0x000|32|(4-1): memory.allocate<address_space_specific<0, 2, -1, ENDIANNESS_BIG >>(*this, spacenum); break;
+ case 0x0000|0x100|32|(4-1): memory.allocate<address_space_specific<1, 2, -1, ENDIANNESS_LITTLE>>(*this, spacenum); break;
+ case 0x1000|0x100|32|(4-1): memory.allocate<address_space_specific<1, 2, -1, ENDIANNESS_BIG >>(*this, spacenum); break;
+
+ case 0x0000|0x000|32|(4-2): memory.allocate<address_space_specific<0, 2, -2, ENDIANNESS_LITTLE>>(*this, spacenum); break;
+ case 0x1000|0x000|32|(4-2): memory.allocate<address_space_specific<0, 2, -2, ENDIANNESS_BIG >>(*this, spacenum); break;
+ case 0x0000|0x100|32|(4-2): memory.allocate<address_space_specific<1, 2, -2, ENDIANNESS_LITTLE>>(*this, spacenum); break;
+ case 0x1000|0x100|32|(4-2): memory.allocate<address_space_specific<1, 2, -2, ENDIANNESS_BIG >>(*this, spacenum); break;
+
+ case 0x0000|0x000|64|(4-0): memory.allocate<address_space_specific<0, 3, 0, ENDIANNESS_LITTLE>>(*this, spacenum); break;
+ case 0x1000|0x000|64|(4-0): memory.allocate<address_space_specific<0, 3, 0, ENDIANNESS_BIG >>(*this, spacenum); break;
+ case 0x0000|0x100|64|(4-0): memory.allocate<address_space_specific<1, 3, 0, ENDIANNESS_LITTLE>>(*this, spacenum); break;
+ case 0x1000|0x100|64|(4-0): memory.allocate<address_space_specific<1, 3, 0, ENDIANNESS_BIG >>(*this, spacenum); break;
+
+ case 0x0000|0x000|64|(4-1): memory.allocate<address_space_specific<0, 3, -1, ENDIANNESS_LITTLE>>(*this, spacenum); break;
+ case 0x1000|0x000|64|(4-1): memory.allocate<address_space_specific<0, 3, -1, ENDIANNESS_BIG >>(*this, spacenum); break;
+ case 0x0000|0x100|64|(4-1): memory.allocate<address_space_specific<1, 3, -1, ENDIANNESS_LITTLE>>(*this, spacenum); break;
+ case 0x1000|0x100|64|(4-1): memory.allocate<address_space_specific<1, 3, -1, ENDIANNESS_BIG >>(*this, spacenum); break;
+
+ case 0x0000|0x000|64|(4-2): memory.allocate<address_space_specific<0, 3, -2, ENDIANNESS_LITTLE>>(*this, spacenum); break;
+ case 0x1000|0x000|64|(4-2): memory.allocate<address_space_specific<0, 3, -2, ENDIANNESS_BIG >>(*this, spacenum); break;
+ case 0x0000|0x100|64|(4-2): memory.allocate<address_space_specific<1, 3, -2, ENDIANNESS_LITTLE>>(*this, spacenum); break;
+ case 0x1000|0x100|64|(4-2): memory.allocate<address_space_specific<1, 3, -2, ENDIANNESS_BIG >>(*this, spacenum); break;
+
+ case 0x0000|0x000|64|(4-3): memory.allocate<address_space_specific<0, 3, -3, ENDIANNESS_LITTLE>>(*this, spacenum); break;
+ case 0x1000|0x000|64|(4-3): memory.allocate<address_space_specific<0, 3, -3, ENDIANNESS_BIG >>(*this, spacenum); break;
+ case 0x0000|0x100|64|(4-3): memory.allocate<address_space_specific<1, 3, -3, ENDIANNESS_LITTLE>>(*this, spacenum); break;
+ case 0x1000|0x100|64|(4-3): memory.allocate<address_space_specific<1, 3, -3, ENDIANNESS_BIG >>(*this, spacenum); break;
+
+ default:
+ throw emu_fatalerror("Invalid width %d/shift %d specified for address_space::allocate", spaceconfig->data_width(), spaceconfig->addr_shift());
+ }
+ }
+ }
+}
+
+//**************************************************************************
+// ADDRESS SPACE
+//**************************************************************************
+
+//-------------------------------------------------
+// address_space - constructor
+//-------------------------------------------------
+
+address_space::address_space(memory_manager &manager, device_memory_interface &memory, int spacenum)
+ : address_space_installer(*memory.space_config(spacenum), manager),
+ m_device(memory.device()),
+ m_unmap(0),
+ m_spacenum(spacenum),
+ m_log_unmap(true),
+ m_name(memory.space_config(spacenum)->name()),
+ m_notifier_id(0),
+ m_in_notification(0)
+{
+}
+
+
+//-------------------------------------------------
+// ~address_space - destructor
+//-------------------------------------------------
+
+address_space::~address_space()
+{
+ m_unmap_r->unref();
+ m_unmap_w->unref();
+ m_nop_r->unref();
+ m_nop_w->unref();
+}
+
+
+//-------------------------------------------------
+// prepare_map - allocate the address map and
+// walk through it to find implicit memory regions
+// and identify shared regions
+//-------------------------------------------------
+
+void address_space::prepare_map()
+{
+ memory_region *devregion = (m_spacenum == 0) ? m_device.memregion(DEVICE_SELF) : nullptr;
+ u32 devregionsize = (devregion != nullptr) ? devregion->bytes() : 0;
+
+ // allocate the address map
+ m_map = std::make_unique<address_map>(m_device, m_spacenum);
+
+ // merge in the submaps
+ m_map->import_submaps(m_manager.machine(), m_device.owner() ? *m_device.owner() : m_device, data_width(), endianness(), addr_shift());
+
+ // 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)
+ {
+ // computed adjusted addresses first
+ adjust_addresses(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror);
+
+ // if we have a share entry, add it to our map
+ if (entry.m_share != nullptr)
+ {
+ // if we can't find it, add it to our map
+ std::string fulltag = entry.m_devbase.subtag(entry.m_share);
+ memory_share *share = m_manager.share_find(fulltag);
+ if (!share)
+ {
+ VPRINTF("Creating share '%s' of length 0x%X\n", fulltag, entry.m_addrend + 1 - entry.m_addrstart);
+ share = m_manager.share_alloc(m_device, fulltag, m_config.data_width(), address_to_byte(entry.m_addrend + 1 - entry.m_addrstart), endianness());
+ }
+ else
+ {
+ std::string result = share->compare(m_config.data_width(), address_to_byte(entry.m_addrend + 1 - entry.m_addrstart), endianness());
+ if (!result.empty())
+ fatalerror("%s\n", result);
+ }
+ entry.m_memory = share->ptr();
+ }
+
+ // if this is a ROM handler without a specified region and not shared, attach it to the implicit region
+ if (m_spacenum == AS_PROGRAM && entry.m_read.m_type == AMH_ROM && entry.m_region == nullptr && entry.m_share == nullptr)
+ {
+ // make sure it fits within the memory region before doing so, however
+ if (entry.m_addrend < devregionsize)
+ {
+ entry.m_region = m_device.tag();
+ entry.m_rgnoffs = address_to_byte(entry.m_addrstart);
+ }
+ }
+
+ // validate adjusted addresses against implicit regions
+ if (entry.m_region != nullptr)
+ {
+ // determine full tag
+ std::string fulltag = entry.m_devbase.subtag(entry.m_region);
+
+ // find the region
+ memory_region *region = m_manager.machine().root_device().memregion(fulltag);
+ if (region == nullptr)
+ fatalerror("device '%s' %s space memory map entry %X-%X references nonexistent region \"%s\"\n", m_device.tag(), m_name, entry.m_addrstart, entry.m_addrend, entry.m_region);
+
+ // validate the region
+ if (entry.m_rgnoffs + m_config.addr2byte(entry.m_addrend - entry.m_addrstart + 1) > region->bytes())
+ fatalerror("device '%s' %s space memory map entry %X-%X extends beyond region \"%s\" size (%X)\n", m_device.tag(), m_name, entry.m_addrstart, entry.m_addrend, entry.m_region, region->bytes());
+
+ if (entry.m_share != nullptr)
+ fatalerror("device '%s' %s space memory map entry %X-%X has both .region() and .share()\n", m_device.tag(), m_name, entry.m_addrstart, entry.m_addrend);
+ }
+
+ // convert any region-relative entries to their memory pointers
+ if (entry.m_region != nullptr)
+ {
+ // determine full tag
+ std::string fulltag = entry.m_devbase.subtag(entry.m_region);
+
+ // set the memory address
+ entry.m_memory = m_manager.machine().root_device().memregion(fulltag)->base() + entry.m_rgnoffs;
+ }
+
+ // allocate anonymous ram when needed
+ if (!entry.m_memory && (entry.m_read.m_type == AMH_RAM || entry.m_write.m_type == AMH_RAM))
+ entry.m_memory = m_manager.anonymous_alloc(*this, address_to_byte(entry.m_addrend + 1 - entry.m_addrstart), m_config.data_width(), entry.m_addrstart, entry.m_addrend);
+ }
+}
+
+
+//-------------------------------------------------
+// populate_from_map - walk the map in reverse
+// order and install the appropriate handler for
+// each case
+//-------------------------------------------------
+
+void address_space::populate_from_map(address_map *map)
+{
+ // no map specified, use the space-specific one
+ if (map == nullptr)
+ map = m_map.get();
+
+ // no map, nothing to do
+ if (map == nullptr)
+ return;
+
+ // install the handlers, using the original, unadjusted memory map
+ 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);
+ }
+
+ if (VALIDATE_REFCOUNTS)
+ validate_reference_counts();
+}
+
+//-------------------------------------------------
+// get_handler_string - return a string
+// describing the handler at a particular offset
+//-------------------------------------------------
+
+template<int Level, int Width, int AddrShift, endianness_t Endian> std::string address_space_specific<Level, Width, AddrShift, Endian>::get_handler_string(read_or_write readorwrite, offs_t address) const
+{
+ if (readorwrite == read_or_write::READ) {
+ offs_t start, end;
+ handler_entry_read<Width, AddrShift, Endian> *handler;
+ m_root_read->lookup(address, start, end, handler);
+ return handler->name();
+ } else {
+ offs_t start, end;
+ handler_entry_write<Width, AddrShift, Endian> *handler;
+ m_root_write->lookup(address, start, end, handler);
+ return handler->name();
+ }
+}
+
+template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::dump_maps(std::vector<memory_entry> &read_map, std::vector<memory_entry> &write_map) const
+{
+ read_map.clear();
+ write_map.clear();
+ m_root_read->dump_map(read_map);
+ m_root_write->dump_map(write_map);
+}
+
+
+//**************************************************************************
+// DYNAMIC ADDRESS SPACE MAPPING
+//**************************************************************************
+
+//-------------------------------------------------
+// unmap - unmap a section of address space
+//-------------------------------------------------
+
+template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, bool quiet)
+{
+ VPRINTF("address_space::unmap(%*x-%*x mirror=%*x, %s, %s)\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmirror,
+ (readorwrite == read_or_write::READ) ? "read" : (readorwrite == read_or_write::WRITE) ? "write" : (readorwrite == read_or_write::READWRITE) ? "read/write" : "??",
+ quiet ? "quiet" : "normal");
+
+ offs_t nstart, nend, nmask, nmirror;
+ 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) {
+ auto handler = static_cast<handler_entry_read<Width, AddrShift, Endian> *>(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) {
+ auto handler = static_cast<handler_entry_write<Width, AddrShift, Endian> *>(quiet ? m_nop_w : m_unmap_w);
+ handler->ref();
+ m_root_write->populate(nstart, nend, nmirror, handler);
+ }
+
+ invalidate_caches(readorwrite);
+}
+
+//-------------------------------------------------
+// install_view - install a view on the bus
+//-------------------------------------------------
+template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::install_view(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_view &view)
+{
+ offs_t nstart, nend, nmask, nmirror;
+ check_optimize_mirror("install_view", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+
+ auto handlers = view.make_handlers(*this, addrstart, addrend);
+ m_root_read ->populate(nstart, nend, nmirror, static_cast<handler_entry_read <Width, AddrShift, Endian> *>(handlers.first));
+ m_root_write->populate(nstart, nend, nmirror, static_cast<handler_entry_write<Width, AddrShift, Endian> *>(handlers.second));
+ view.make_subdispatch(""); // Must be called after populate
+}
+
+memory_passthrough_handler *address_space::make_mph()
+{
+ m_mphs.emplace_back(std::make_unique<memory_passthrough_handler>(*this));
+ return m_mphs.back().get();
+}
+
+//-------------------------------------------------
+// install_read_tap - install a read tap on the bus
+//-------------------------------------------------
+
+template<int Level, int Width, int AddrShift, endianness_t Endian> memory_passthrough_handler *address_space_specific<Level, Width, AddrShift, Endian>::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> 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)
+ mph = make_mph();
+
+ auto handler = new handler_entry_read_tap<Width, AddrShift, Endian>(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<int Level, int Width, int AddrShift, endianness_t Endian> memory_passthrough_handler *address_space_specific<Level, Width, AddrShift, Endian>::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> 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)
+ mph = make_mph();
+
+ auto handler = new handler_entry_write_tap<Width, AddrShift, Endian>(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<int Level, int Width, int AddrShift, endianness_t Endian> memory_passthrough_handler *address_space_specific<Level, Width, AddrShift, Endian>::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapr, std::function<void (offs_t offset, uX &data, uX mem_mask)> 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)
+ mph = make_mph();
+
+ auto rhandler = new handler_entry_read_tap <Width, AddrShift, Endian>(this, *mph, name, tapr);
+ m_root_read ->populate_passthrough(nstart, nend, nmirror, rhandler);
+ rhandler->unref();
+
+ auto whandler = new handler_entry_write_tap<Width, AddrShift, Endian>(this, *mph, name, tapw);
+ m_root_write->populate_passthrough(nstart, nend, nmirror, whandler);
+ whandler->unref();
+
+ invalidate_caches(read_or_write::READWRITE);
+
+ return mph;
+}
+
+
+
+
+
+//-------------------------------------------------
+// install_device_delegate - install the memory map
+// of a live device into this address space
+//-------------------------------------------------
+
+template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::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);
+ map.import_submaps(m_manager.machine(), device, data_width(), endianness(), addr_shift());
+ populate_from_map(&map);
+}
+
+
+
+//-------------------------------------------------
+// install_readwrite_port - install a new I/O port
+// handler into this address space
+//-------------------------------------------------
+
+template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::install_readwrite_port(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string rtag, std::string wtag)
+{
+ VPRINTF("address_space::install_readwrite_port(%*x-%*x mirror=%*x, read=\"%s\" / write=\"%s\")\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmirror,
+ rtag.empty() ? "(none)" : rtag, wtag.empty() ? "(none)" : wtag);
+
+ offs_t nstart, nend, nmask, nmirror;
+ check_optimize_mirror("install_readwrite_port", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+
+ // read handler
+ if (rtag != "")
+ {
+ // find the port
+ ioport_port *port = device().owner()->ioport(rtag);
+ if (port == nullptr)
+ 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
+ auto hand_r = new handler_entry_read_ioport<Width, AddrShift, Endian>(this, port);
+ m_root_read->populate(nstart, nend, nmirror, hand_r);
+ }
+
+ if (wtag != "")
+ {
+ // find the port
+ ioport_port *port = device().owner()->ioport(wtag);
+ if (port == nullptr)
+ 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
+ auto hand_w = new handler_entry_write_ioport<Width, AddrShift, Endian>(this, port);
+ m_root_write->populate(nstart, nend, nmirror, hand_w);
+ }
+
+ invalidate_caches(rtag != "" ? wtag != "" ? read_or_write::READWRITE : read_or_write::READ : read_or_write::WRITE);
+}
+
+
+//-------------------------------------------------
+// install_bank_generic - install a range as
+// mapping to a particular bank
+//-------------------------------------------------
+
+template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_bank *rbank, memory_bank *wbank)
+{
+ VPRINTF("address_space::install_readwrite_bank(%*x-%*x mirror=%*x, read=\"%s\" / write=\"%s\")\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmirror,
+ (rbank != nullptr) ? rbank->tag() : "(none)", (wbank != nullptr) ? wbank->tag() : "(none)");
+
+ offs_t nstart, nend, nmask, nmirror;
+ check_optimize_mirror("install_bank_generic", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+
+ // map the read bank
+ if (rbank != nullptr)
+ {
+ auto hand_r = new handler_entry_read_memory_bank<Width, AddrShift, Endian>(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)
+ {
+ auto hand_w = new handler_entry_write_memory_bank<Width, AddrShift, Endian>(this, *wbank);
+ hand_w->set_address_info(nstart, nmask);
+ m_root_write->populate(nstart, nend, nmirror, hand_w);
+ }
+
+ invalidate_caches(rbank ? wbank ? read_or_write::READWRITE : read_or_write::READ : read_or_write::WRITE);
+}
+
+
+//-------------------------------------------------
+// install_ram_generic - install a simple fixed
+// RAM region into the given address space
+//-------------------------------------------------
+
+template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::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",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmirror,
+ (readorwrite == read_or_write::READ) ? "read" : (readorwrite == read_or_write::WRITE) ? "write" : (readorwrite == read_or_write::READWRITE) ? "read/write" : "??",
+ baseptr);
+
+ offs_t nstart, nend, nmask, nmirror;
+ check_optimize_mirror("install_ram_generic", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+
+ // map for read
+ if (readorwrite == read_or_write::READ || readorwrite == read_or_write::READWRITE)
+ {
+ auto hand_r = new handler_entry_read_memory<Width, AddrShift, Endian>(this, baseptr);
+ hand_r->set_address_info(nstart, nmask);
+ m_root_read->populate(nstart, nend, nmirror, hand_r);
+ }
+
+ // map for write
+ if (readorwrite == read_or_write::WRITE || readorwrite == read_or_write::READWRITE)
+ {
+ auto hand_w = new handler_entry_write_memory<Width, AddrShift, Endian>(this, baseptr);
+ hand_w->set_address_info(nstart, nmask);
+ m_root_write->populate(nstart, nend, nmirror, hand_w);
+ }
+
+ invalidate_caches(readorwrite);
+}
+
+//**************************************************************************
+// MEMORY MAPPING HELPERS
+//**************************************************************************
+
+int address_space::add_change_notifier(std::function<void (read_or_write)> n)
+{
+ int id = m_notifier_id++;
+ m_notifiers.emplace_back(notifier_t{ std::move(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);
+}
diff --git a/src/emu/emumem_hedr.h b/src/emu/emumem_hedr.h
index 30e819bd990..0ef50471e8f 100644
--- a/src/emu/emumem_hedr.h
+++ b/src/emu/emumem_hedr.h
@@ -3,7 +3,8 @@
// handler_entry_read_dispatch
-// dispatches an access among multiple handlers indexed on part of the address
+// dispatches an access among multiple handlers indexed on part of the
+// address and when appropriate a selected view
template<int HighBits, int Width, int AddrShift, endianness_t Endian> class handler_entry_read_dispatch : public handler_entry_read<Width, AddrShift, Endian>
{
@@ -13,6 +14,8 @@ public:
using mapping = typename inh::mapping;
handler_entry_read_dispatch(address_space *space, const handler_entry::range &init, handler_entry_read<Width, AddrShift, Endian> *handler);
+ handler_entry_read_dispatch(address_space *space, memory_view &view);
+ handler_entry_read_dispatch(handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian> *src);
~handler_entry_read_dispatch();
uX read(offs_t offset, uX mem_mask) const override;
@@ -35,9 +38,13 @@ public:
void enumerate_references(handler_entry::reflist &refs) const override;
- virtual const handler_entry_read<Width, AddrShift, Endian> *const *get_dispatch() const override;
+ const handler_entry_read<Width, AddrShift, Endian> *const *get_dispatch() const override;
+ void select_a(int slot) override;
+ void select_u(int slot) override;
+ void init_handlers(offs_t start_entry, offs_t end_entry, u32 lowbits, handler_entry_read<Width, AddrShift, Endian> **dispatch, handler_entry::range *ranges) override;
+ handler_entry_read<Width, AddrShift, Endian> *dup() override;
-protected:
+private:
static constexpr int Level = emu::detail::handler_entry_dispatch_level(HighBits);
static constexpr u32 LowBits = emu::detail::handler_entry_dispatch_lowbits(HighBits, Width, AddrShift);
static constexpr u32 BITCOUNT = HighBits > LowBits ? HighBits - LowBits : 0;
@@ -47,10 +54,17 @@ protected:
static constexpr offs_t HIGHMASK = make_bitmask<offs_t>(HighBits) ^ LOWMASK;
static constexpr offs_t UPMASK = ~make_bitmask<offs_t>(HighBits);
- handler_entry_read<Width, AddrShift, Endian> *m_dispatch[COUNT];
- handler_entry::range m_ranges[COUNT];
+ memory_view *m_view;
+
+ std::vector<std::array<handler_entry_read<Width, AddrShift, Endian> *, COUNT>> m_dispatch_array;
+ std::vector<std::array<handler_entry::range, COUNT>> m_ranges_array;
+
+ handler_entry_read<Width, AddrShift, Endian> **m_a_dispatch;
+ handler_entry::range *m_a_ranges;
+
+ handler_entry_read<Width, AddrShift, Endian> **m_u_dispatch;
+ handler_entry::range *m_u_ranges;
-private:
void populate_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read<Width, AddrShift, Endian> *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<Width, AddrShift, Endian> *handler);
diff --git a/src/emu/emumem_hedr.ipp b/src/emu/emumem_hedr.ipp
index 844cae6dd90..41a209f75ec 100644
--- a/src/emu/emumem_hedr.ipp
+++ b/src/emu/emumem_hedr.ipp
@@ -11,71 +11,125 @@
template<int HighBits, int Width, int AddrShift, endianness_t Endian> const handler_entry_read<Width, AddrShift, Endian> *const *handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::get_dispatch() const
{
- return m_dispatch;
+ return m_a_dispatch;
}
-template<int HighBits, int Width, int AddrShift, endianness_t Endian> handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::handler_entry_read_dispatch(address_space *space, const handler_entry::range &init, handler_entry_read<Width, AddrShift, Endian> *handler) : handler_entry_read<Width, AddrShift, Endian>(space, handler_entry::F_DISPATCH)
+template<int HighBits, int Width, int AddrShift, endianness_t Endian> handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::handler_entry_read_dispatch(address_space *space, const handler_entry::range &init, handler_entry_read<Width, AddrShift, Endian> *handler) : handler_entry_read<Width, AddrShift, Endian>(space, handler_entry::F_DISPATCH), m_view(nullptr)
{
+ m_ranges_array.resize(1);
+ m_dispatch_array.resize(1);
+ m_a_ranges = m_ranges_array[0].data();
+ m_a_dispatch = m_dispatch_array[0].data();
+ m_u_ranges = m_ranges_array[0].data();
+ m_u_dispatch = m_dispatch_array[0].data();
+
if (!handler)
handler = space->get_unmap_r<Width, AddrShift, Endian>();
handler->ref(COUNT);
for(unsigned int i=0; i != COUNT; i++) {
- m_dispatch[i] = handler;
- m_ranges[i] = init;
+ m_u_dispatch[i] = handler;
+ m_u_ranges[i] = init;
+ }
+}
+
+template<int HighBits, int Width, int AddrShift, endianness_t Endian> handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::handler_entry_read_dispatch(address_space *space, memory_view &view) : handler_entry_read<Width, AddrShift, Endian>(space, handler_entry::F_VIEW), m_view(&view), m_a_dispatch(nullptr), m_a_ranges(nullptr), m_u_dispatch(nullptr), m_u_ranges(nullptr)
+{
+}
+
+template<int HighBits, int Width, int AddrShift, endianness_t Endian> handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::handler_entry_read_dispatch(handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian> *src) : handler_entry_read<Width, AddrShift, Endian>(src->m_space, handler_entry::F_DISPATCH), m_view(nullptr)
+{
+ m_ranges_array.resize(1);
+ m_dispatch_array.resize(1);
+ m_a_ranges = m_ranges_array[0].data();
+ m_a_dispatch = m_dispatch_array[0].data();
+ m_u_ranges = m_ranges_array[0].data();
+ m_u_dispatch = m_dispatch_array[0].data();
+
+ for(unsigned int i=0; i != COUNT; i++) {
+ m_u_dispatch[i] = src->m_u_dispatch[i];
+ m_u_ranges[i] = src->m_u_ranges[i];
}
}
+
template<int HighBits, int Width, int AddrShift, endianness_t Endian> handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::~handler_entry_read_dispatch()
{
- for(unsigned int i=0; i != COUNT; i++)
- m_dispatch[i]->unref();
+ for(auto &d : m_dispatch_array)
+ for(auto p : d)
+ if(p)
+ p->unref();
}
template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::enumerate_references(handler_entry::reflist &refs) const
{
- for(unsigned int i=0; i != COUNT; i++)
- refs.add(m_dispatch[i]);
+ for(auto &d : m_dispatch_array)
+ for(auto p : d)
+ if(p)
+ refs.add(p);
}
template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::dump_map(std::vector<memory_entry> &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));
-
+ if(m_view) {
+ for(u32 i = 0; i != m_dispatch_array.size(); i++) {
+ u32 j = map.size();
+ offs_t cur = map.empty() ? m_view->m_addrstart & HIGHMASK : map.back().end + 1;
+ offs_t end = m_view->m_addrend + 1;
+ do {
+ offs_t entry = (cur >> LowBits) & BITMASK;
+ if(m_dispatch_array[i][entry]->is_dispatch() || m_dispatch_array[i][entry]->is_view())
+ m_dispatch_array[i][entry]->dump_map(map);
+ else
+ map.emplace_back(memory_entry{ m_ranges_array[i][entry].start, m_ranges_array[i][entry].end, m_dispatch_array[i][entry] });
+ cur = map.back().end + 1;
+ } while(cur != end);
+ if(i == 0) {
+ for(u32 k = j; k != map.size(); k++)
+ map[k].context.emplace(map[k].context.begin(), memory_entry_context{ m_view, true, 0 });
+ } else {
+ int slot = m_view->id_to_slot(int(i)-1);
+ for(u32 k = j; k != map.size(); k++)
+ map[k].context.emplace(map[k].context.begin(), memory_entry_context{ m_view, false, slot });
+ }
+ }
+ } else {
+ offs_t cur = map.empty() ? 0 : map.back().end + 1;
+ offs_t base = cur & UPMASK;
+ do {
+ offs_t entry = (cur >> LowBits) & BITMASK;
+ if(m_a_dispatch[entry]->is_dispatch() || m_a_dispatch[entry]->is_view())
+ m_a_dispatch[entry]->dump_map(map);
+ else
+ map.emplace_back(memory_entry{ m_a_ranges[entry].start, m_a_ranges[entry].end, m_a_dispatch[entry] });
+ cur = map.back().end + 1;
+ } while(cur && !((cur ^ base) & UPMASK));
+ }
}
template<int HighBits, int Width, int AddrShift, endianness_t Endian> typename emu::detail::handler_entry_size<Width>::uX handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::read(offs_t offset, uX mem_mask) const
{
- return dispatch_read<Level, Width, AddrShift, Endian>(HIGHMASK, offset, mem_mask, m_dispatch);
+ return dispatch_read<Level, Width, AddrShift, Endian>(HIGHMASK, offset, mem_mask, m_a_dispatch);
}
template<int HighBits, int Width, int AddrShift, endianness_t Endian> void *handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::get_ptr(offs_t offset) const
{
- return m_dispatch[(offset & HIGHMASK) >> LowBits]->get_ptr(offset);
+ return m_a_dispatch[(offset & HIGHMASK) >> LowBits]->get_ptr(offset);
}
template<int HighBits, int Width, int AddrShift, endianness_t Endian> std::string handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::name() const
{
- return "dispatch";
+ return m_view ? "view" : "dispatch";
}
template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::lookup(offs_t address, offs_t &start, offs_t &end, handler_entry_read<Width, AddrShift, Endian> *&handler) const
{
offs_t slot = (address >> LowBits) & BITMASK;
- auto h = m_dispatch[slot];
- if(h->is_dispatch())
+ auto h = m_a_dispatch[slot];
+ if(h->is_dispatch() || h->is_view())
h->lookup(address, start, end, handler);
else {
- start = m_ranges[slot].start;
- end = m_ranges[slot].end;
+ start = m_a_ranges[slot].start;
+ end = m_a_ranges[slot].end;
handler = h;
}
}
@@ -83,62 +137,66 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::range_cut_before(offs_t address, int start)
{
while(--start >= 0) {
- if(int(LowBits) > -AddrShift && m_dispatch[start]->is_dispatch()) {
- static_cast<handler_entry_read_dispatch<LowBits, Width, AddrShift, Endian> *>(m_dispatch[start])->range_cut_before(address);
+ if(int(LowBits) > -AddrShift && m_u_dispatch[start]->is_dispatch()) {
+ static_cast<handler_entry_read_dispatch<LowBits, Width, AddrShift, Endian> *>(m_u_dispatch[start])->range_cut_before(address);
break;
}
- if(m_ranges[start].end <= address)
+ if(m_u_ranges[start].end <= address)
break;
- m_ranges[start].end = address;
+ m_u_ranges[start].end = address;
}
}
template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::range_cut_after(offs_t address, int start)
{
while(++start < COUNT) {
- if(int(LowBits) > -AddrShift && m_dispatch[start]->is_dispatch()) {
- static_cast<handler_entry_read_dispatch<LowBits, Width, AddrShift, Endian> *>(m_dispatch[start])->range_cut_after(address);
+ if(int(LowBits) > -AddrShift && m_u_dispatch[start]->is_dispatch()) {
+ static_cast<handler_entry_read_dispatch<LowBits, Width, AddrShift, Endian> *>(m_u_dispatch[start])->range_cut_after(address);
break;
}
- if(m_ranges[start].start >= address)
+ if(m_u_ranges[start].start >= address)
break;
- m_ranges[start].start = address;
+ m_u_ranges[start].start = address;
}
}
template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::populate_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read<Width, AddrShift, Endian> *handler)
{
- auto cur = m_dispatch[entry];
+ auto cur = m_u_dispatch[entry];
if(cur->is_dispatch())
cur->populate_nomirror(start, end, ostart, oend, handler);
else {
- auto subdispatch = new handler_entry_read_dispatch<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_ranges[entry], cur);
+ auto subdispatch = new handler_entry_read_dispatch<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_u_ranges[entry], cur);
cur->unref();
- m_dispatch[entry] = subdispatch;
+ m_u_dispatch[entry] = subdispatch;
subdispatch->populate_nomirror(start, end, ostart, oend, handler);
}
}
template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::populate_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read<Width, AddrShift, Endian> *handler)
{
- offs_t start_entry = start >> LowBits;
- offs_t end_entry = end >> LowBits;
+ 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) {
+ if(handler->is_view())
+ handler->init_handlers(start_entry, end_entry, LowBits, m_u_dispatch, m_u_ranges);
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);
+ m_u_dispatch[ent]->unref();
+ m_u_dispatch[ent] = handler;
+ m_u_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);
+ if(handler->is_view())
+ handler->init_handlers(start_entry, end_entry, LowBits, m_u_dispatch, m_u_ranges);
+ m_u_dispatch[start_entry]->unref();
+ m_u_dispatch[start_entry] = handler;
+ m_u_ranges[start_entry].set(ostart, oend);
} else
populate_nomirror_subdispatch(start_entry, start & LOWMASK, end & LOWMASK, ostart, oend, handler);
@@ -157,24 +215,26 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
}
if(start_entry <= end_entry) {
+ if(handler->is_view())
+ handler->init_handlers(start_entry, end_entry, LowBits, m_u_dispatch, m_u_ranges);
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);
+ m_u_dispatch[ent]->unref();
+ m_u_dispatch[ent] = handler;
+ m_u_ranges[ent].set(ostart, oend);
}
}
}
}
template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::populate_mirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_read<Width, AddrShift, Endian> *handler)
{
- auto cur = m_dispatch[entry];
+ auto cur = m_u_dispatch[entry];
if(cur->is_dispatch())
cur->populate_mirror(start, end, ostart, oend, mirror, handler);
else {
- auto subdispatch = new handler_entry_read_dispatch<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_ranges[entry], cur);
+ auto subdispatch = new handler_entry_read_dispatch<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_u_ranges[entry], cur);
cur->unref();
- m_dispatch[entry] = subdispatch;
+ m_u_dispatch[entry] = subdispatch;
subdispatch->populate_mirror(start, end, ostart, oend, mirror, handler);
}
}
@@ -236,13 +296,13 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::populate_mismatched_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, const memory_units_descriptor<Width, AddrShift, Endian> &descriptor, u8 rkey, std::vector<mapping> &mappings)
{
- auto cur = m_dispatch[entry];
+ auto cur = m_u_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<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_ranges[entry], cur);
+ auto subdispatch = new handler_entry_read_dispatch<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_u_ranges[entry], cur);
cur->unref();
- m_dispatch[entry] = subdispatch;
+ m_u_dispatch[entry] = subdispatch;
subdispatch->populate_mismatched_nomirror(start, end, ostart, oend, descriptor, rkey, mappings);
}
}
@@ -261,17 +321,17 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
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);
+ mismatched_patch(descriptor, rkey1, mappings, m_u_dispatch[ent]);
+ m_u_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);
+ if(m_u_dispatch[start_entry]->is_dispatch())
+ m_u_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);
+ mismatched_patch(descriptor, rkey, mappings, m_u_dispatch[start_entry]);
+ m_u_ranges[start_entry].set(ostart, oend);
}
} else
populate_mismatched_nomirror_subdispatch(start_entry, start & LOWMASK, end & LOWMASK, ostart, oend, descriptor, rkey, mappings);
@@ -295,11 +355,11 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
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);
+ if(m_u_dispatch[ent]->is_dispatch())
+ m_u_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);
+ mismatched_patch(descriptor, rkey1, mappings, m_u_dispatch[ent]);
+ m_u_ranges[ent].set(ostart, oend);
}
}
}
@@ -308,13 +368,13 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::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<Width, AddrShift, Endian> &descriptor, std::vector<mapping> &mappings)
{
- auto cur = m_dispatch[entry];
+ auto cur = m_u_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<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_ranges[entry], cur);
+ auto subdispatch = new handler_entry_read_dispatch<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_u_ranges[entry], cur);
cur->unref();
- m_dispatch[entry] = subdispatch;
+ m_u_dispatch[entry] = subdispatch;
subdispatch->populate_mismatched_mirror(start, end, ostart, oend, mirror, descriptor, mappings);
}
}
@@ -367,13 +427,13 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::populate_passthrough_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read_passthrough<Width, AddrShift, Endian> *handler, std::vector<mapping> &mappings)
{
- auto cur = m_dispatch[entry];
+ auto cur = m_u_dispatch[entry];
if(cur->is_dispatch())
cur->populate_passthrough_nomirror(start, end, ostart, oend, handler, mappings);
else {
- auto subdispatch = new handler_entry_read_dispatch<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_ranges[entry], cur);
+ auto subdispatch = new handler_entry_read_dispatch<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_u_ranges[entry], cur);
cur->unref();
- m_dispatch[entry] = subdispatch;
+ m_u_dispatch[entry] = subdispatch;
subdispatch->populate_passthrough_nomirror(start, end, ostart, oend, handler, mappings);
}
}
@@ -387,14 +447,14 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
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);
+ passthrough_patch(handler, mappings, m_u_dispatch[ent]);
+ m_u_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);
+ passthrough_patch(handler, mappings, m_u_dispatch[start_entry]);
+ m_u_ranges[start_entry].intersect(ostart, oend);
} else
populate_passthrough_nomirror_subdispatch(start_entry, start & LOWMASK, end & LOWMASK, ostart, oend, handler, mappings);
@@ -410,11 +470,11 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
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);
+ if(m_u_dispatch[ent]->is_dispatch())
+ m_u_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);
+ passthrough_patch(handler, mappings, m_u_dispatch[ent]);
+ m_u_ranges[ent].intersect(ostart, oend);
}
}
}
@@ -423,13 +483,13 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::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<Width, AddrShift, Endian> *handler, std::vector<mapping> &mappings)
{
- auto cur = m_dispatch[entry];
+ auto cur = m_u_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<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_ranges[entry], cur);
+ auto subdispatch = new handler_entry_read_dispatch<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_u_ranges[entry], cur);
cur->unref();
- m_dispatch[entry] = subdispatch;
+ m_u_dispatch[entry] = subdispatch;
subdispatch->populate_passthrough_mirror(start, end, ostart, oend, mirror, handler, mappings);
}
}
@@ -464,22 +524,108 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::detach(const std::unordered_set<handler_entry *> &handlers)
{
for(unsigned int i=0; i != COUNT; i++) {
- if(m_dispatch[i]->is_dispatch()) {
- m_dispatch[i]->detach(handlers);
+ if(m_u_dispatch[i]->is_dispatch()) {
+ m_u_dispatch[i]->detach(handlers);
continue;
}
- if(!m_dispatch[i]->is_passthrough())
+ if(!m_u_dispatch[i]->is_passthrough())
continue;
- auto np = static_cast<handler_entry_read_passthrough<Width, AddrShift, Endian> *>(m_dispatch[i]);
+ auto np = static_cast<handler_entry_read_passthrough<Width, AddrShift, Endian> *>(m_u_dispatch[i]);
if(handlers.find(np) != handlers.end()) {
- m_dispatch[i] = np->get_subhandler();
- m_dispatch[i]->ref();
+ m_u_dispatch[i] = np->get_subhandler();
+ m_u_dispatch[i]->ref();
np->unref();
} else
np->detach(handlers);
}
}
+
+template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::init_handlers(offs_t start_entry, offs_t end_entry, u32 lowbits, handler_entry_read<Width, AddrShift, Endian> **dispatch, handler_entry::range *ranges)
+{
+ if(!m_view)
+ fatalerror("init_handlers called on non-view handler_entry_read_dispatch.");
+ if(!m_dispatch_array.empty())
+ fatalerror("init_handlers called twice on handler_entry_read_dispatch.");
+
+ m_ranges_array.resize(1);
+ m_dispatch_array.resize(1);
+ m_a_ranges = m_ranges_array[0].data();
+ m_a_dispatch = m_dispatch_array[0].data();
+ m_u_ranges = m_ranges_array[0].data();
+ m_u_dispatch = m_dispatch_array[0].data();
+
+ auto filter = [s = m_view->m_addrstart, e = m_view->m_addrend] (handler_entry::range r) {
+ r.intersect(s, e);
+ return r;
+ };
+
+ if(lowbits != LowBits) {
+ u32 dt = lowbits - LowBits;
+ u32 ne = 1 << dt;
+ for(offs_t entry = start_entry; entry <= end_entry; entry++) {
+ m_u_dispatch[entry]->ref(ne);
+ u32 e0 = (entry << dt) & BITMASK;
+ for(offs_t e = 0; e != ne; e++) {
+ m_u_dispatch[e0 | e] = dispatch[entry];
+ m_u_ranges[e0 | e] = filter(ranges[entry]);
+ }
+ }
+
+ } else {
+ for(offs_t entry = start_entry; entry <= end_entry; entry++) {
+ m_u_dispatch[entry & BITMASK] = dispatch[entry];
+ m_u_ranges[entry & BITMASK] = filter(ranges[entry]);
+ dispatch[entry]->ref();
+ }
+ }
+}
+
+template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::select_a(int id)
+{
+ u32 i = id+1;
+ if(i >= m_dispatch_array.size())
+ fatalerror("out-of-range view selection.");
+
+ m_a_ranges = m_ranges_array[i].data();
+ m_a_dispatch = m_dispatch_array[i].data();
+}
+
+template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::select_u(int id)
+{
+ u32 i = id+1;
+ if(i > m_dispatch_array.size())
+ fatalerror("out-of-range view update selection.");
+ else if(i == m_dispatch_array.size()) {
+ u32 aid = (std::array<handler_entry_read<Width, AddrShift, Endian> *, COUNT> *)(m_a_dispatch) - m_dispatch_array.data();
+
+ m_dispatch_array.resize(i+1);
+ m_ranges_array.resize(i+1);
+ m_a_ranges = m_ranges_array[aid].data();
+ m_a_dispatch = m_dispatch_array[aid].data();
+ m_u_ranges = m_ranges_array[i].data();
+ m_u_dispatch = m_dispatch_array[i].data();
+
+ for(u32 entry = 0; entry != COUNT; entry++) {
+ m_u_dispatch[entry] = m_dispatch_array[0][entry]->dup();
+ m_u_ranges[entry] = m_ranges_array[0][entry];
+ }
+
+ } else {
+ m_u_ranges = m_ranges_array[i].data();
+ m_u_dispatch = m_dispatch_array[i].data();
+ }
+}
+
+template<int HighBits, int Width, int AddrShift, endianness_t Endian> handler_entry_read<Width, AddrShift, Endian> *handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::dup()
+{
+ if(m_view) {
+ handler_entry::ref();
+ return this;
+ }
+
+ return new handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>(this);
+}
diff --git a/src/emu/emumem_hedr0.cpp b/src/emu/emumem_hedr0.cpp
index 536c64e6274..0dbd929412e 100644
--- a/src/emu/emumem_hedr0.cpp
+++ b/src/emu/emumem_hedr0.cpp
@@ -5,6 +5,8 @@
#include "emumem_hedr.ipp"
+template class handler_entry_read_dispatch< 0, 0, 1, ENDIANNESS_LITTLE>;
+template class handler_entry_read_dispatch< 0, 0, 1, ENDIANNESS_BIG>;
template class handler_entry_read_dispatch< 1, 0, 1, ENDIANNESS_LITTLE>;
template class handler_entry_read_dispatch< 1, 0, 1, ENDIANNESS_BIG>;
template class handler_entry_read_dispatch< 2, 0, 1, ENDIANNESS_LITTLE>;
@@ -22,6 +24,8 @@ template class handler_entry_read_dispatch< 7, 0, 1, ENDIANNESS_BIG>;
template class handler_entry_read_dispatch< 8, 0, 1, ENDIANNESS_LITTLE>;
template class handler_entry_read_dispatch< 8, 0, 1, ENDIANNESS_BIG>;
+template class handler_entry_read_dispatch< 0, 0, 0, ENDIANNESS_LITTLE>;
+template class handler_entry_read_dispatch< 0, 0, 0, ENDIANNESS_BIG>;
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>;
@@ -39,6 +43,8 @@ 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< 0, 1, 3, ENDIANNESS_LITTLE>;
+template class handler_entry_read_dispatch< 0, 1, 3, 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>;
@@ -73,6 +79,8 @@ 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< 0, 1, -1, ENDIANNESS_LITTLE>;
+template class handler_entry_read_dispatch< 0, 1, -1, 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>;
@@ -120,6 +128,8 @@ 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< 1, 2, -1, ENDIANNESS_LITTLE>;
+template class handler_entry_read_dispatch< 1, 2, -1, 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>;
@@ -135,6 +145,10 @@ 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< 0, 2, -2, ENDIANNESS_LITTLE>;
+template class handler_entry_read_dispatch< 0, 2, -2, ENDIANNESS_BIG>;
+template class handler_entry_read_dispatch< 1, 2, -2, ENDIANNESS_LITTLE>;
+template class handler_entry_read_dispatch< 1, 2, -2, 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>;
@@ -163,6 +177,8 @@ 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< 2, 3, -1, ENDIANNESS_LITTLE>;
+template class handler_entry_read_dispatch< 2, 3, -1, 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>;
@@ -176,6 +192,10 @@ 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< 1, 3, -2, ENDIANNESS_LITTLE>;
+template class handler_entry_read_dispatch< 1, 3, -2, ENDIANNESS_BIG>;
+template class handler_entry_read_dispatch< 2, 3, -2, ENDIANNESS_LITTLE>;
+template class handler_entry_read_dispatch< 2, 3, -2, 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>;
@@ -189,6 +209,12 @@ 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< 0, 3, -3, ENDIANNESS_LITTLE>;
+template class handler_entry_read_dispatch< 0, 3, -3, ENDIANNESS_BIG>;
+template class handler_entry_read_dispatch< 1, 3, -3, ENDIANNESS_LITTLE>;
+template class handler_entry_read_dispatch< 1, 3, -3, ENDIANNESS_BIG>;
+template class handler_entry_read_dispatch< 2, 3, -3, ENDIANNESS_LITTLE>;
+template class handler_entry_read_dispatch< 2, 3, -3, 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>;
diff --git a/src/emu/emumem_hedw.h b/src/emu/emumem_hedw.h
index 219b51d89f7..bb591e3bff8 100644
--- a/src/emu/emumem_hedw.h
+++ b/src/emu/emumem_hedw.h
@@ -3,7 +3,8 @@
// handler_entry_write_dispatch
-// dispatches an access among multiple handlers indexed on part of the address
+// dispatches an access among multiple handlers indexed on part of the
+// address and when appropriate a selected view
template<int HighBits, int Width, int AddrShift, endianness_t Endian> class handler_entry_write_dispatch : public handler_entry_write<Width, AddrShift, Endian>
{
@@ -13,6 +14,8 @@ public:
using mapping = typename inh::mapping;
handler_entry_write_dispatch(address_space *space, const handler_entry::range &init, handler_entry_write<Width, AddrShift, Endian> *handler);
+ handler_entry_write_dispatch(address_space *space, memory_view &view);
+ handler_entry_write_dispatch(handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian> *src);
~handler_entry_write_dispatch();
void write(offs_t offset, uX data, uX mem_mask) const override;
@@ -35,9 +38,13 @@ public:
void enumerate_references(handler_entry::reflist &refs) const override;
- virtual const handler_entry_write<Width, AddrShift, Endian> *const *get_dispatch() const override;
+ const handler_entry_write<Width, AddrShift, Endian> *const *get_dispatch() const override;
+ void select_a(int slot) override;
+ void select_u(int slot) override;
+ void init_handlers(offs_t start_entry, offs_t end_entry, u32 lowbits, handler_entry_write<Width, AddrShift, Endian> **dispatch, handler_entry::range *ranges) override;
+ handler_entry_write<Width, AddrShift, Endian> *dup() override;
-protected:
+private:
static constexpr int Level = emu::detail::handler_entry_dispatch_level(HighBits);
static constexpr u32 LowBits = emu::detail::handler_entry_dispatch_lowbits(HighBits, Width, AddrShift);
static constexpr u32 BITCOUNT = HighBits > LowBits ? HighBits - LowBits : 0;
@@ -47,10 +54,17 @@ protected:
static constexpr offs_t HIGHMASK = make_bitmask<offs_t>(HighBits) ^ LOWMASK;
static constexpr offs_t UPMASK = ~make_bitmask<offs_t>(HighBits);
- handler_entry_write<Width, AddrShift, Endian> *m_dispatch[COUNT];
- handler_entry::range m_ranges[COUNT];
+ memory_view *m_view;
+
+ std::vector<std::array<handler_entry_write<Width, AddrShift, Endian> *, COUNT>> m_dispatch_array;
+ std::vector<std::array<handler_entry::range, COUNT>> m_ranges_array;
+
+ handler_entry_write<Width, AddrShift, Endian> **m_a_dispatch;
+ handler_entry::range *m_a_ranges;
+
+ handler_entry_write<Width, AddrShift, Endian> **m_u_dispatch;
+ handler_entry::range *m_u_ranges;
-private:
void populate_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_write<Width, AddrShift, Endian> *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<Width, AddrShift, Endian> *handler);
diff --git a/src/emu/emumem_hedw.ipp b/src/emu/emumem_hedw.ipp
index 3e12c702864..f63072b3bfb 100644
--- a/src/emu/emumem_hedw.ipp
+++ b/src/emu/emumem_hedw.ipp
@@ -12,70 +12,126 @@
template<int HighBits, int Width, int AddrShift, endianness_t Endian> const handler_entry_write<Width, AddrShift, Endian> *const *handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian>::get_dispatch() const
{
- return m_dispatch;
+ return m_a_dispatch;
}
-template<int HighBits, int Width, int AddrShift, endianness_t Endian> handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian>::handler_entry_write_dispatch(address_space *space, const handler_entry::range &init, handler_entry_write<Width, AddrShift, Endian> *handler) : handler_entry_write<Width, AddrShift, Endian>(space, handler_entry::F_DISPATCH)
+template<int HighBits, int Width, int AddrShift, endianness_t Endian> handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian>::handler_entry_write_dispatch(address_space *space, const handler_entry::range &init, handler_entry_write<Width, AddrShift, Endian> *handler) : handler_entry_write<Width, AddrShift, Endian>(space, handler_entry::F_DISPATCH), m_view(nullptr)
{
+ m_ranges_array.resize(1);
+ m_dispatch_array.resize(1);
+ m_a_ranges = m_ranges_array[0].data();
+ m_a_dispatch = m_dispatch_array[0].data();
+ m_u_ranges = m_ranges_array[0].data();
+ m_u_dispatch = m_dispatch_array[0].data();
+
if (!handler)
handler = space->get_unmap_w<Width, AddrShift, Endian>();
handler->ref(COUNT);
for(unsigned int i=0; i != COUNT; i++) {
- m_dispatch[i] = handler;
- m_ranges[i] = init;
+ m_u_dispatch[i] = handler;
+ m_u_ranges[i] = init;
+ }
+}
+
+template<int HighBits, int Width, int AddrShift, endianness_t Endian> handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian>::handler_entry_write_dispatch(address_space *space, memory_view &view) : handler_entry_write<Width, AddrShift, Endian>(space, handler_entry::F_VIEW), m_view(&view), m_a_dispatch(nullptr), m_a_ranges(nullptr), m_u_dispatch(nullptr), m_u_ranges(nullptr)
+{
+}
+
+
+template<int HighBits, int Width, int AddrShift, endianness_t Endian> handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian>::handler_entry_write_dispatch(handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian> *src) : handler_entry_write<Width, AddrShift, Endian>(src->m_space, handler_entry::F_DISPATCH), m_view(nullptr)
+{
+ m_ranges_array.resize(1);
+ m_dispatch_array.resize(1);
+ m_a_ranges = m_ranges_array[0].data();
+ m_a_dispatch = m_dispatch_array[0].data();
+ m_u_ranges = m_ranges_array[0].data();
+ m_u_dispatch = m_dispatch_array[0].data();
+
+ for(unsigned int i=0; i != COUNT; i++) {
+ m_u_dispatch[i] = src->m_u_dispatch[i];
+ m_u_ranges[i] = src->m_u_ranges[i];
}
}
+
template<int HighBits, int Width, int AddrShift, endianness_t Endian> handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian>::~handler_entry_write_dispatch()
{
- for(unsigned int i=0; i != COUNT; i++)
- m_dispatch[i]->unref();
+ for(auto &d : m_dispatch_array)
+ for(auto p : d)
+ if(p)
+ p->unref();
}
template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian>::enumerate_references(handler_entry::reflist &refs) const
{
- for(unsigned int i=0; i != COUNT; i++)
- refs.add(m_dispatch[i]);
+ for(auto &d : m_dispatch_array)
+ for(auto p : d)
+ if(p)
+ refs.add(p);
}
template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian>::dump_map(std::vector<memory_entry> &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));
+ if(m_view) {
+ for(u32 i = 0; i != m_dispatch_array.size(); i++) {
+ u32 j = map.size();
+ offs_t cur = map.empty() ? m_view->m_addrstart & HIGHMASK : map.back().end + 1;
+ offs_t end = m_view->m_addrend + 1;
+ do {
+ offs_t entry = (cur >> LowBits) & BITMASK;
+ if(m_dispatch_array[i][entry]->is_dispatch() || m_dispatch_array[i][entry]->is_view())
+ m_dispatch_array[i][entry]->dump_map(map);
+ else
+ map.emplace_back(memory_entry{ m_ranges_array[i][entry].start, m_ranges_array[i][entry].end, m_dispatch_array[i][entry] });
+ cur = map.back().end + 1;
+ } while(cur != end);
+ if(i == 0) {
+ for(u32 k = j; k != map.size(); k++)
+ map[k].context.emplace(map[k].context.begin(), memory_entry_context{ m_view, true, 0 });
+ } else {
+ int slot = m_view->id_to_slot(int(i)-1);
+ for(u32 k = j; k != map.size(); k++)
+ map[k].context.emplace(map[k].context.begin(), memory_entry_context{ m_view, false, slot });
+ }
+ }
+ } else {
+ offs_t cur = map.empty() ? 0 : map.back().end + 1;
+ offs_t base = cur & UPMASK;
+ do {
+ offs_t entry = (cur >> LowBits) & BITMASK;
+ if(m_a_dispatch[entry]->is_dispatch() || m_a_dispatch[entry]->is_view())
+ m_a_dispatch[entry]->dump_map(map);
+ else
+ map.emplace_back(memory_entry{ m_a_ranges[entry].start, m_a_ranges[entry].end, m_a_dispatch[entry] });
+ cur = map.back().end + 1;
+ } while(cur && !((cur ^ base) & UPMASK));
+ }
}
template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian>::write(offs_t offset, uX data, uX mem_mask) const
{
- dispatch_write<Level, Width, AddrShift, Endian>(HIGHMASK, offset, data, mem_mask, m_dispatch);
+ dispatch_write<Level, Width, AddrShift, Endian>(HIGHMASK, offset, data, mem_mask, m_a_dispatch);
}
template<int HighBits, int Width, int AddrShift, endianness_t Endian> void *handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian>::get_ptr(offs_t offset) const
{
- return m_dispatch[(offset & HIGHMASK) >> LowBits]->get_ptr(offset);
+ return m_a_dispatch[(offset & HIGHMASK) >> LowBits]->get_ptr(offset);
}
template<int HighBits, int Width, int AddrShift, endianness_t Endian> std::string handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian>::name() const
{
- return "dispatch";
+ return m_view ? "view" :"dispatch";
}
template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian>::lookup(offs_t address, offs_t &start, offs_t &end, handler_entry_write<Width, AddrShift, Endian> *&handler) const
{
offs_t slot = (address >> LowBits) & BITMASK;
- auto h = m_dispatch[slot];
+ auto h = m_a_dispatch[slot];
if(h->is_dispatch())
h->lookup(address, start, end, handler);
else {
- start = m_ranges[slot].start;
- end = m_ranges[slot].end;
+ start = m_a_ranges[slot].start;
+ end = m_a_ranges[slot].end;
handler = h;
}
}
@@ -83,38 +139,38 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian>::range_cut_before(offs_t address, int start)
{
while(--start >= 0) {
- if(int(LowBits) > -AddrShift && m_dispatch[start]->is_dispatch()) {
- static_cast<handler_entry_write_dispatch<LowBits, Width, AddrShift, Endian> *>(m_dispatch[start])->range_cut_before(address);
+ if(int(LowBits) > -AddrShift && m_u_dispatch[start]->is_dispatch()) {
+ static_cast<handler_entry_write_dispatch<LowBits, Width, AddrShift, Endian> *>(m_u_dispatch[start])->range_cut_before(address);
break;
}
- if(m_ranges[start].end <= address)
+ if(m_u_ranges[start].end <= address)
break;
- m_ranges[start].end = address;
+ m_u_ranges[start].end = address;
}
}
template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian>::range_cut_after(offs_t address, int start)
{
while(++start < COUNT) {
- if(int(LowBits) > -AddrShift && m_dispatch[start]->is_dispatch()) {
- static_cast<handler_entry_write_dispatch<LowBits, Width, AddrShift, Endian> *>(m_dispatch[start])->range_cut_after(address);
+ if(int(LowBits) > -AddrShift && m_u_dispatch[start]->is_dispatch()) {
+ static_cast<handler_entry_write_dispatch<LowBits, Width, AddrShift, Endian> *>(m_u_dispatch[start])->range_cut_after(address);
break;
}
- if(m_ranges[start].start >= address)
+ if(m_u_ranges[start].start >= address)
break;
- m_ranges[start].start = address;
+ m_u_ranges[start].start = address;
}
}
template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian>::populate_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_write<Width, AddrShift, Endian> *handler)
{
- auto cur = m_dispatch[entry];
+ auto cur = m_u_dispatch[entry];
if(cur->is_dispatch())
cur->populate_nomirror(start, end, ostart, oend, handler);
else {
- auto subdispatch = new handler_entry_write_dispatch<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_ranges[entry], cur);
+ auto subdispatch = new handler_entry_write_dispatch<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_u_ranges[entry], cur);
cur->unref();
- m_dispatch[entry] = subdispatch;
+ m_u_dispatch[entry] = subdispatch;
subdispatch->populate_nomirror(start, end, ostart, oend, handler);
}
}
@@ -127,18 +183,22 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
range_cut_after(oend+1, end_entry);
if(LowBits <= Width + AddrShift) {
+ if(handler->is_view())
+ handler->init_handlers(start_entry, end_entry, LowBits, m_u_dispatch, m_u_ranges);
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);
+ m_u_dispatch[ent]->unref();
+ m_u_dispatch[ent] = handler;
+ m_u_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);
+ if(handler->is_view())
+ handler->init_handlers(start_entry, end_entry, LowBits, m_u_dispatch, m_u_ranges);
+ m_u_dispatch[start_entry]->unref();
+ m_u_dispatch[start_entry] = handler;
+ m_u_ranges[start_entry].set(ostart, oend);
} else
populate_nomirror_subdispatch(start_entry, start & LOWMASK, end & LOWMASK, ostart, oend, handler);
@@ -157,11 +217,13 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
}
if(start_entry <= end_entry) {
+ if(handler->is_view())
+ handler->init_handlers(start_entry, end_entry, LowBits, m_u_dispatch, m_u_ranges);
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);
+ m_u_dispatch[ent]->unref();
+ m_u_dispatch[ent] = handler;
+ m_u_ranges[ent].set(ostart, oend);
}
}
}
@@ -169,13 +231,13 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian>::populate_mirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_write<Width, AddrShift, Endian> *handler)
{
- auto cur = m_dispatch[entry];
+ auto cur = m_u_dispatch[entry];
if(cur->is_dispatch())
cur->populate_mirror(start, end, ostart, oend, mirror, handler);
else {
- auto subdispatch = new handler_entry_write_dispatch<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_ranges[entry], cur);
+ auto subdispatch = new handler_entry_write_dispatch<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_u_ranges[entry], cur);
cur->unref();
- m_dispatch[entry] = subdispatch;
+ m_u_dispatch[entry] = subdispatch;
subdispatch->populate_mirror(start, end, ostart, oend, mirror, handler);
}
}
@@ -236,13 +298,13 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian>::populate_mismatched_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, const memory_units_descriptor<Width, AddrShift, Endian> &descriptor, u8 rkey, std::vector<mapping> &mappings)
{
- auto cur = m_dispatch[entry];
+ auto cur = m_u_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<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_ranges[entry], cur);
+ auto subdispatch = new handler_entry_write_dispatch<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_u_ranges[entry], cur);
cur->unref();
- m_dispatch[entry] = subdispatch;
+ m_u_dispatch[entry] = subdispatch;
subdispatch->populate_mismatched_nomirror(start, end, ostart, oend, descriptor, rkey, mappings);
}
}
@@ -261,17 +323,17 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
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);
+ mismatched_patch(descriptor, rkey1, mappings, m_u_dispatch[ent]);
+ m_u_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);
+ if(m_u_dispatch[start_entry]->is_dispatch())
+ m_u_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);
+ mismatched_patch(descriptor, rkey, mappings, m_u_dispatch[start_entry]);
+ m_u_ranges[start_entry].intersect(ostart, oend);
}
} else
populate_mismatched_nomirror_subdispatch(start_entry, start & LOWMASK, end & LOWMASK, ostart, oend, descriptor, rkey, mappings);
@@ -295,11 +357,11 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
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);
+ if(m_u_dispatch[ent]->is_dispatch())
+ m_u_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);
+ mismatched_patch(descriptor, rkey1, mappings, m_u_dispatch[ent]);
+ m_u_ranges[ent].intersect(ostart, oend);
}
}
}
@@ -308,13 +370,13 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian>::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<Width, AddrShift, Endian> &descriptor, std::vector<mapping> &mappings)
{
- auto cur = m_dispatch[entry];
+ auto cur = m_u_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<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_ranges[entry], cur);
+ auto subdispatch = new handler_entry_write_dispatch<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_u_ranges[entry], cur);
cur->unref();
- m_dispatch[entry] = subdispatch;
+ m_u_dispatch[entry] = subdispatch;
subdispatch->populate_mismatched_mirror(start, end, ostart, oend, mirror, descriptor, mappings);
}
}
@@ -367,13 +429,13 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian>::populate_passthrough_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_write_passthrough<Width, AddrShift, Endian> *handler, std::vector<mapping> &mappings)
{
- auto cur = m_dispatch[entry];
+ auto cur = m_u_dispatch[entry];
if(cur->is_dispatch())
cur->populate_passthrough_nomirror(start, end, ostart, oend, handler, mappings);
else {
- auto subdispatch = new handler_entry_write_dispatch<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_ranges[entry], cur);
+ auto subdispatch = new handler_entry_write_dispatch<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_u_ranges[entry], cur);
cur->unref();
- m_dispatch[entry] = subdispatch;
+ m_u_dispatch[entry] = subdispatch;
subdispatch->populate_passthrough_nomirror(start, end, ostart, oend, handler, mappings);
}
}
@@ -387,17 +449,17 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
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);
+ passthrough_patch(handler, mappings, m_u_dispatch[ent]);
+ m_u_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);
+ if(m_u_dispatch[start_entry]->is_dispatch())
+ m_u_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);
+ passthrough_patch(handler, mappings, m_u_dispatch[start_entry]);
+ m_u_ranges[start_entry].intersect(ostart, oend);
}
} else
populate_passthrough_nomirror_subdispatch(start_entry, start & LOWMASK, end & LOWMASK, ostart, oend, handler, mappings);
@@ -414,11 +476,11 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
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);
+ if(m_u_dispatch[ent]->is_dispatch())
+ m_u_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);
+ passthrough_patch(handler, mappings, m_u_dispatch[ent]);
+ m_u_ranges[ent].intersect(ostart, oend);
}
}
}
@@ -427,13 +489,13 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian>::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<Width, AddrShift, Endian> *handler, std::vector<mapping> &mappings)
{
- auto cur = m_dispatch[entry];
+ auto cur = m_u_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<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_ranges[entry], cur);
+ auto subdispatch = new handler_entry_write_dispatch<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_u_ranges[entry], cur);
cur->unref();
- m_dispatch[entry] = subdispatch;
+ m_u_dispatch[entry] = subdispatch;
subdispatch->populate_passthrough_mirror(start, end, ostart, oend, mirror, handler, mappings);
}
}
@@ -468,22 +530,108 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian>::detach(const std::unordered_set<handler_entry *> &handlers)
{
for(unsigned int i=0; i != COUNT; i++) {
- if(m_dispatch[i]->is_dispatch()) {
- m_dispatch[i]->detach(handlers);
+ if(m_u_dispatch[i]->is_dispatch()) {
+ m_u_dispatch[i]->detach(handlers);
continue;
}
- if(!m_dispatch[i]->is_passthrough())
+ if(!m_u_dispatch[i]->is_passthrough())
continue;
- auto np = static_cast<handler_entry_write_passthrough<Width, AddrShift, Endian> *>(m_dispatch[i]);
+ auto np = static_cast<handler_entry_write_passthrough<Width, AddrShift, Endian> *>(m_u_dispatch[i]);
if(handlers.find(np) != handlers.end()) {
- m_dispatch[i] = np->get_subhandler();
- m_dispatch[i]->ref();
+ m_u_dispatch[i] = np->get_subhandler();
+ m_u_dispatch[i]->ref();
np->unref();
} else
np->detach(handlers);
}
}
+
+template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian>::init_handlers(offs_t start_entry, offs_t end_entry, u32 lowbits, handler_entry_write<Width, AddrShift, Endian> **dispatch, handler_entry::range *ranges)
+{
+ if(!m_view)
+ fatalerror("init_handlers called on non-view handler_entry_write_dispatch.");
+ if(!m_dispatch_array.empty())
+ fatalerror("init_handlers called twice on handler_entry_write_dispatch.");
+
+ m_ranges_array.resize(1);
+ m_dispatch_array.resize(1);
+ m_a_ranges = m_ranges_array[0].data();
+ m_a_dispatch = m_dispatch_array[0].data();
+ m_u_ranges = m_ranges_array[0].data();
+ m_u_dispatch = m_dispatch_array[0].data();
+
+ auto filter = [s = m_view->m_addrstart, e = m_view->m_addrend] (handler_entry::range r) {
+ r.intersect(s, e);
+ return r;
+ };
+
+ if(lowbits != LowBits) {
+ u32 dt = lowbits - LowBits;
+ u32 ne = 1 << dt;
+ for(offs_t entry = start_entry; entry <= end_entry; entry++) {
+ m_u_dispatch[entry]->ref(ne);
+ u32 e0 = (entry << dt) & BITMASK;
+ for(offs_t e = 0; e != ne; e++) {
+ m_u_dispatch[e0 | e] = dispatch[entry];
+ m_u_ranges[e0 | e] = filter(ranges[entry]);
+ }
+ }
+
+ } else {
+ for(offs_t entry = start_entry; entry <= end_entry; entry++) {
+ m_u_dispatch[entry & BITMASK] = dispatch[entry];
+ m_u_ranges[entry & BITMASK] = filter(ranges[entry]);
+ dispatch[entry]->ref();
+ }
+ }
+}
+
+template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian>::select_a(int id)
+{
+ u32 i = id+1;
+ if(i >= m_dispatch_array.size())
+ fatalerror("out-of-range view selection.");
+
+ m_a_ranges = m_ranges_array[i].data();
+ m_a_dispatch = m_dispatch_array[i].data();
+}
+
+template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian>::select_u(int id)
+{
+ u32 i = id+1;
+ if(i > m_dispatch_array.size())
+ fatalerror("out-of-range view update selection.");
+ else if(i == m_dispatch_array.size()) {
+ u32 aid = (std::array<handler_entry_write<Width, AddrShift, Endian> *, COUNT> *)(m_a_dispatch) - m_dispatch_array.data();
+
+ m_dispatch_array.resize(i+1);
+ m_ranges_array.resize(i+1);
+ m_a_ranges = m_ranges_array[aid].data();
+ m_a_dispatch = m_dispatch_array[aid].data();
+ m_u_ranges = m_ranges_array[i].data();
+ m_u_dispatch = m_dispatch_array[i].data();
+
+ for(u32 entry = 0; entry != COUNT; entry++) {
+ m_u_dispatch[entry] = m_dispatch_array[0][entry]->dup();
+ m_u_ranges[entry] = m_ranges_array[0][entry];
+ }
+
+ } else {
+ m_u_ranges = m_ranges_array[i].data();
+ m_u_dispatch = m_dispatch_array[i].data();
+ }
+}
+
+template<int HighBits, int Width, int AddrShift, endianness_t Endian> handler_entry_write<Width, AddrShift, Endian> *handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian>::dup()
+{
+ if(m_view) {
+ handler_entry::ref();
+ return this;
+ }
+
+ return new handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian>(this);
+}
diff --git a/src/emu/emumem_hedw0.cpp b/src/emu/emumem_hedw0.cpp
index 593a42d7417..67244fc3044 100644
--- a/src/emu/emumem_hedw0.cpp
+++ b/src/emu/emumem_hedw0.cpp
@@ -5,6 +5,8 @@
#include "emumem_hedw.ipp"
+template class handler_entry_write_dispatch< 0, 0, 1, ENDIANNESS_LITTLE>;
+template class handler_entry_write_dispatch< 0, 0, 1, ENDIANNESS_BIG>;
template class handler_entry_write_dispatch< 1, 0, 1, ENDIANNESS_LITTLE>;
template class handler_entry_write_dispatch< 1, 0, 1, ENDIANNESS_BIG>;
template class handler_entry_write_dispatch< 2, 0, 1, ENDIANNESS_LITTLE>;
@@ -22,6 +24,8 @@ template class handler_entry_write_dispatch< 7, 0, 1, ENDIANNESS_BIG>;
template class handler_entry_write_dispatch< 8, 0, 1, ENDIANNESS_LITTLE>;
template class handler_entry_write_dispatch< 8, 0, 1, ENDIANNESS_BIG>;
+template class handler_entry_write_dispatch< 0, 0, 0, ENDIANNESS_LITTLE>;
+template class handler_entry_write_dispatch< 0, 0, 0, ENDIANNESS_BIG>;
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>;
@@ -39,6 +43,8 @@ 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< 0, 1, 3, ENDIANNESS_LITTLE>;
+template class handler_entry_write_dispatch< 0, 1, 3, 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>;
@@ -73,6 +79,8 @@ 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< 0, 1, -1, ENDIANNESS_LITTLE>;
+template class handler_entry_write_dispatch< 0, 1, -1, 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>;
@@ -90,6 +98,10 @@ 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< 0, 2, 3, ENDIANNESS_LITTLE>;
+template class handler_entry_write_dispatch< 0, 2, 3, ENDIANNESS_BIG>;
+template class handler_entry_write_dispatch< 1, 2, 3, ENDIANNESS_LITTLE>;
+template class handler_entry_write_dispatch< 1, 2, 3, ENDIANNESS_BIG>;
template class handler_entry_write_dispatch< 2, 2, 3, ENDIANNESS_LITTLE>;
template class handler_entry_write_dispatch< 2, 2, 3, ENDIANNESS_BIG>;
template class handler_entry_write_dispatch< 3, 2, 3, ENDIANNESS_LITTLE>;
@@ -120,6 +132,8 @@ 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< 1, 2, -1, ENDIANNESS_LITTLE>;
+template class handler_entry_write_dispatch< 1, 2, -1, 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>;
@@ -135,6 +149,10 @@ 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< 0, 2, -2, ENDIANNESS_LITTLE>;
+template class handler_entry_write_dispatch< 0, 2, -2, ENDIANNESS_BIG>;
+template class handler_entry_write_dispatch< 1, 2, -2, ENDIANNESS_LITTLE>;
+template class handler_entry_write_dispatch< 1, 2, -2, 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>;
@@ -163,6 +181,8 @@ 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< 2, 3, -1, ENDIANNESS_LITTLE>;
+template class handler_entry_write_dispatch< 2, 3, -1, 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>;
@@ -176,6 +196,10 @@ 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< 1, 3, -2, ENDIANNESS_LITTLE>;
+template class handler_entry_write_dispatch< 1, 3, -2, ENDIANNESS_BIG>;
+template class handler_entry_write_dispatch< 2, 3, -2, ENDIANNESS_LITTLE>;
+template class handler_entry_write_dispatch< 2, 3, -2, 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>;
@@ -189,6 +213,12 @@ 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< 0, 3, -3, ENDIANNESS_LITTLE>;
+template class handler_entry_write_dispatch< 0, 3, -3, ENDIANNESS_BIG>;
+template class handler_entry_write_dispatch< 1, 3, -3, ENDIANNESS_LITTLE>;
+template class handler_entry_write_dispatch< 1, 3, -3, ENDIANNESS_BIG>;
+template class handler_entry_write_dispatch< 2, 3, -3, ENDIANNESS_LITTLE>;
+template class handler_entry_write_dispatch< 2, 3, -3, 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>;
diff --git a/src/emu/emumem_heu.cpp b/src/emu/emumem_heu.cpp
index e556a39bd31..aba5a28f9c2 100644
--- a/src/emu/emumem_heu.cpp
+++ b/src/emu/emumem_heu.cpp
@@ -36,12 +36,27 @@ template<int Width, int AddrShift, endianness_t Endian> handler_entry_read_units
std::sort(m_subunit_infos, m_subunit_infos + m_subunits, [](const subunit_info &a, const subunit_info &b) { return a.m_offset < b.m_offset; });
}
+template<int Width, int AddrShift, endianness_t Endian> handler_entry_read_units<Width, AddrShift, Endian>::handler_entry_read_units(const handler_entry_read_units *src) :
+ handler_entry_read<Width, AddrShift, Endian>(src->m_space, inh::F_UNITS),
+ m_subunits(src->m_subunits)
+{
+ for(u32 i=0; i != src->m_subunits; i++) {
+ m_subunit_infos[i] = src->m_subunit_infos[i];
+ m_subunit_infos[i].m_handler = static_cast<handler_entry_write<Width, AddrShift, Endian> *>(m_subunit_infos[i].m_handler)->dup();
+ }
+}
+
template<int Width, int AddrShift, endianness_t Endian> handler_entry_read_units<Width, AddrShift, Endian>::~handler_entry_read_units()
{
for(u32 i=0; i != m_subunits; i++)
m_subunit_infos[i].m_handler->unref();
}
+template<int Width, int AddrShift, endianness_t Endian> handler_entry_read<Width, AddrShift, Endian> *handler_entry_read_units<Width, AddrShift, Endian>::dup()
+{
+ return new handler_entry_read_units<Width, AddrShift, Endian>(this);
+}
+
template<int Width, int AddrShift, endianness_t Endian> void handler_entry_read_units<Width, AddrShift, Endian>::enumerate_references(handler_entry::reflist &refs) const
{
for(u32 i=0; i != m_subunits; i++)
@@ -155,12 +170,27 @@ template<int Width, int AddrShift, endianness_t Endian> handler_entry_write_unit
std::sort(m_subunit_infos, m_subunit_infos + m_subunits, [](const subunit_info &a, const subunit_info &b) { return a.m_offset < b.m_offset; });
}
+template<int Width, int AddrShift, endianness_t Endian> handler_entry_write_units<Width, AddrShift, Endian>::handler_entry_write_units(const handler_entry_write_units *src) :
+ handler_entry_write<Width, AddrShift, Endian>(src->m_space, inh::F_UNITS),
+ m_subunits(src->m_subunits)
+{
+ for(u32 i=0; i != src->m_subunits; i++) {
+ m_subunit_infos[i] = src->m_subunit_infos[i];
+ m_subunit_infos[i].m_handler = static_cast<handler_entry_write<Width, AddrShift, Endian> *>(m_subunit_infos[i].m_handler)->dup();
+ }
+}
+
template<int Width, int AddrShift, endianness_t Endian> handler_entry_write_units<Width, AddrShift, Endian>::~handler_entry_write_units()
{
for(u32 i=0; i != m_subunits; i++)
m_subunit_infos[i].m_handler->unref();
}
+template<int Width, int AddrShift, endianness_t Endian> handler_entry_write<Width, AddrShift, Endian> *handler_entry_write_units<Width, AddrShift, Endian>::dup()
+{
+ return new handler_entry_write_units<Width, AddrShift, Endian>(this);
+}
+
template<int Width, int AddrShift, endianness_t Endian> void handler_entry_write_units<Width, AddrShift, Endian>::enumerate_references(handler_entry::reflist &refs) const
{
for(u32 i=0; i != m_subunits; i++)
diff --git a/src/emu/emumem_heu.h b/src/emu/emumem_heu.h
index d084fddfe98..670d489d00a 100644
--- a/src/emu/emumem_heu.h
+++ b/src/emu/emumem_heu.h
@@ -13,6 +13,7 @@ public:
handler_entry_read_units(const memory_units_descriptor<Width, AddrShift, Endian> &descriptor, u8 ukey, address_space *space);
handler_entry_read_units(const memory_units_descriptor<Width, AddrShift, Endian> &descriptor, u8 ukey, const handler_entry_read_units *src);
+ handler_entry_read_units(const handler_entry_read_units *src);
~handler_entry_read_units();
uX read(offs_t offset, uX mem_mask) const override;
@@ -20,6 +21,7 @@ public:
std::string name() const override;
void enumerate_references(handler_entry::reflist &refs) const override;
+ handler_entry_read<Width, AddrShift, Endian> *dup() override;
private:
static constexpr u32 SUBUNIT_COUNT = 1 << Width;
@@ -54,6 +56,7 @@ public:
handler_entry_write_units(const memory_units_descriptor<Width, AddrShift, Endian> &descriptor, u8 ukey, address_space *space);
handler_entry_write_units(const memory_units_descriptor<Width, AddrShift, Endian> &descriptor, u8 ukey, const handler_entry_write_units<Width, AddrShift, Endian> *src);
+ handler_entry_write_units(const handler_entry_write_units *src);
~handler_entry_write_units();
void write(offs_t offset, uX data, uX mem_mask) const override;
@@ -61,6 +64,7 @@ public:
std::string name() const override;
void enumerate_references(handler_entry::reflist &refs) const override;
+ handler_entry_write<Width, AddrShift, Endian> *dup() override;
private:
static constexpr u32 SUBUNIT_COUNT = 1 << Width;
diff --git a/src/emu/emumem_mview.cpp b/src/emu/emumem_mview.cpp
new file mode 100644
index 00000000000..f4f92e1a7b8
--- /dev/null
+++ b/src/emu/emumem_mview.cpp
@@ -0,0 +1,995 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles,Olivier Galibert
+/***************************************************************************
+
+ emumem.cpp
+
+ Functions which handle device memory access.
+ Memory view specific functions
+
+***************************************************************************/
+
+#include "emu.h"
+#include <list>
+#include <map>
+#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"
+
+#define VERBOSE 0
+
+#if VERBOSE
+template <typename Format, typename... Params> static void VPRINTF(Format &&fmt, Params &&...args)
+{
+ util::stream_format(std::cerr, std::forward<Format>(fmt), std::forward<Params>(args)...);
+}
+#else
+template <typename Format, typename... Params> static void VPRINTF(Format &&, Params &&...) {}
+#endif
+
+namespace {
+
+template <typename Delegate> struct handler_width;
+template <> struct handler_width<read8_delegate> { static constexpr int value = 0; };
+template <> struct handler_width<read8m_delegate> { static constexpr int value = 0; };
+template <> struct handler_width<read8s_delegate> { static constexpr int value = 0; };
+template <> struct handler_width<read8sm_delegate> { static constexpr int value = 0; };
+template <> struct handler_width<read8mo_delegate> { static constexpr int value = 0; };
+template <> struct handler_width<read8smo_delegate> { static constexpr int value = 0; };
+template <> struct handler_width<write8_delegate> { static constexpr int value = 0; };
+template <> struct handler_width<write8m_delegate> { static constexpr int value = 0; };
+template <> struct handler_width<write8s_delegate> { static constexpr int value = 0; };
+template <> struct handler_width<write8sm_delegate> { static constexpr int value = 0; };
+template <> struct handler_width<write8mo_delegate> { static constexpr int value = 0; };
+template <> struct handler_width<write8smo_delegate> { static constexpr int value = 0; };
+template <> struct handler_width<read16_delegate> { static constexpr int value = 1; };
+template <> struct handler_width<read16m_delegate> { static constexpr int value = 1; };
+template <> struct handler_width<read16s_delegate> { static constexpr int value = 1; };
+template <> struct handler_width<read16sm_delegate> { static constexpr int value = 1; };
+template <> struct handler_width<read16mo_delegate> { static constexpr int value = 1; };
+template <> struct handler_width<read16smo_delegate> { static constexpr int value = 1; };
+template <> struct handler_width<write16_delegate> { static constexpr int value = 1; };
+template <> struct handler_width<write16m_delegate> { static constexpr int value = 1; };
+template <> struct handler_width<write16s_delegate> { static constexpr int value = 1; };
+template <> struct handler_width<write16sm_delegate> { static constexpr int value = 1; };
+template <> struct handler_width<write16mo_delegate> { static constexpr int value = 1; };
+template <> struct handler_width<write16smo_delegate> { static constexpr int value = 1; };
+template <> struct handler_width<read32_delegate> { static constexpr int value = 2; };
+template <> struct handler_width<read32m_delegate> { static constexpr int value = 2; };
+template <> struct handler_width<read32s_delegate> { static constexpr int value = 2; };
+template <> struct handler_width<read32sm_delegate> { static constexpr int value = 2; };
+template <> struct handler_width<read32mo_delegate> { static constexpr int value = 2; };
+template <> struct handler_width<read32smo_delegate> { static constexpr int value = 2; };
+template <> struct handler_width<write32_delegate> { static constexpr int value = 2; };
+template <> struct handler_width<write32m_delegate> { static constexpr int value = 2; };
+template <> struct handler_width<write32s_delegate> { static constexpr int value = 2; };
+template <> struct handler_width<write32sm_delegate> { static constexpr int value = 2; };
+template <> struct handler_width<write32mo_delegate> { static constexpr int value = 2; };
+template <> struct handler_width<write32smo_delegate> { static constexpr int value = 2; };
+template <> struct handler_width<read64_delegate> { static constexpr int value = 3; };
+template <> struct handler_width<read64m_delegate> { static constexpr int value = 3; };
+template <> struct handler_width<read64s_delegate> { static constexpr int value = 3; };
+template <> struct handler_width<read64sm_delegate> { static constexpr int value = 3; };
+template <> struct handler_width<read64mo_delegate> { static constexpr int value = 3; };
+template <> struct handler_width<read64smo_delegate> { static constexpr int value = 3; };
+template <> struct handler_width<write64_delegate> { static constexpr int value = 3; };
+template <> struct handler_width<write64m_delegate> { static constexpr int value = 3; };
+template <> struct handler_width<write64s_delegate> { static constexpr int value = 3; };
+template <> struct handler_width<write64sm_delegate> { static constexpr int value = 3; };
+template <> struct handler_width<write64mo_delegate> { static constexpr int value = 3; };
+template <> struct handler_width<write64smo_delegate> { static constexpr int value = 3; };
+} // anonymous namespace
+
+address_map_entry &memory_view::memory_view_entry::operator()(offs_t start, offs_t end)
+{
+ return (*m_map)(start, end);
+}
+
+template<int Level, int Width, int AddrShift, endianness_t Endian>
+class memory_view_entry_specific : public memory_view::memory_view_entry
+{
+ using uX = typename emu::detail::handler_entry_size<Width>::uX;
+ using NativeType = uX;
+
+ // 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:
+ memory_view_entry_specific(const address_space_config &config, memory_manager &manager, memory_view &view, int id) : memory_view_entry(config, manager, view, id) {
+ }
+
+ virtual ~memory_view_entry_specific() = default;
+
+ handler_entry_read <Width, AddrShift, Endian> *r() { return static_cast<handler_entry_read <Width, AddrShift, Endian> *>(m_view.m_handler_read); }
+ handler_entry_write<Width, AddrShift, Endian> *w() { return static_cast<handler_entry_write<Width, AddrShift, Endian> *>(m_view.m_handler_write); }
+
+ void invalidate_caches(read_or_write readorwrite) { return m_view.m_space->invalidate_caches(readorwrite); }
+
+ virtual void populate_from_map(address_map *map = nullptr) override;
+
+ using address_space_installer::install_read_tap;
+ using address_space_installer::install_write_tap;
+ using address_space_installer::install_readwrite_tap;
+
+ virtual memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> 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<void (offs_t offset, uX &data, uX mem_mask)> 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<void (offs_t offset, uX &data, uX mem_mask)> tapr, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapw, memory_passthrough_handler *mph) override;
+
+ virtual void unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, bool quiet) override;
+ virtual void install_ram_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, void *baseptr) override;
+ virtual void install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_bank *rbank, memory_bank *wbank) override;
+ virtual void install_view(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_view &view) override;
+ virtual void install_readwrite_port(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string rtag, std::string wtag) override;
+ virtual void install_device_delegate(offs_t addrstart, offs_t addrend, device_t &device, address_map_constructor &map, u64 unitmask, int cswidth) 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
+ { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); }
+ 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
+ { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); }
+ 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
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+ 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
+ { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); }
+ 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
+ { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); }
+ 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
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+ 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
+ { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); }
+ 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
+ { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); }
+ 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
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+ 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
+ { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); }
+ 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
+ { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); }
+ 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
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+
+ void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8m_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); }
+ void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); }
+ void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8m_delegate rhandler, write8m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+ void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16m_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); }
+ void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); }
+ void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16m_delegate rhandler, write16m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+ void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32m_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); }
+ void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); }
+ void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32m_delegate rhandler, write32m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+ void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64m_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); }
+ void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); }
+ void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64m_delegate rhandler, write64m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+
+ void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8s_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); }
+ void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); }
+ void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8s_delegate rhandler, write8s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+ void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16s_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); }
+ void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); }
+ void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16s_delegate rhandler, write16s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+ void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32s_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); }
+ void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); }
+ void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32s_delegate rhandler, write32s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+ void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64s_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); }
+ void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); }
+ void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64s_delegate rhandler, write64s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+
+ void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); }
+ void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); }
+ void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8sm_delegate rhandler, write8sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+ void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); }
+ void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); }
+ void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16sm_delegate rhandler, write16sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+ void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); }
+ void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); }
+ void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32sm_delegate rhandler, write32sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+ void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); }
+ void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); }
+ void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64sm_delegate rhandler, write64sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+
+ void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); }
+ void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); }
+ void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8mo_delegate rhandler, write8mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+ void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); }
+ void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); }
+ void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16mo_delegate rhandler, write16mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+ void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); }
+ void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); }
+ void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32mo_delegate rhandler, write32mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+ void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); }
+ void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); }
+ void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64mo_delegate rhandler, write64mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+
+ void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); }
+ void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); }
+ void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8smo_delegate rhandler, write8smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+ void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); }
+ void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); }
+ void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16smo_delegate rhandler, write16smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+ void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); }
+ void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); }
+ void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32smo_delegate rhandler, write32smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+ void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); }
+ void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); }
+ void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64smo_delegate rhandler, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override
+ { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); }
+
+ template<typename READ>
+ void install_read_handler_impl(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, READ &handler_r)
+ {
+ try { handler_r.resolve(); }
+ catch (const binding_type_exception &) {
+ osd_printf_error("Binding error while installing read handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_r.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask);
+ throw;
+ }
+ install_read_handler_helper<handler_width<READ>::value>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, handler_r);
+ }
+
+ template<typename WRITE>
+ void install_write_handler_impl(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, WRITE &handler_w)
+ {
+ try { handler_w.resolve(); }
+ catch (const binding_type_exception &) {
+ osd_printf_error("Binding error while installing write handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_w.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask);
+ throw;
+ }
+ install_write_handler_helper<handler_width<WRITE>::value>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, handler_w);
+ }
+
+ template<typename READ, typename WRITE>
+ void install_readwrite_handler_impl(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, READ &handler_r, WRITE &handler_w)
+ {
+ static_assert(handler_width<READ>::value == handler_width<WRITE>::value, "handler widths do not match");
+ try { handler_r.resolve(); }
+ catch (const binding_type_exception &) {
+ osd_printf_error("Binding error while installing read handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_r.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask);
+ throw;
+ }
+ try { handler_w.resolve(); }
+ catch (const binding_type_exception &) {
+ osd_printf_error("Binding error while installing write handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_w.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask);
+ throw;
+ }
+ install_readwrite_handler_helper<handler_width<READ>::value>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, handler_r, handler_w);
+ }
+
+ template<int AccessWidth, typename READ>
+ void install_read_handler_helper(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, const READ &handler_r)
+ {
+ if constexpr (Width < AccessWidth) {
+ fatalerror("install_read_handler: cannot install a %d-wide handler in a %d-wide bus", 8 << AccessWidth, 8 << Width);
+ } else {
+ VPRINTF("memory_view::install_read_handler(%*x-%*x mask=%*x mirror=%*x, space width=%d, handler width=%d, %s, %*x)\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmask, m_addrchars, addrmirror,
+ 8 << Width, 8 << AccessWidth,
+ handler_r.name(), data_width() / 4, unitmask);
+
+ 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);
+
+ if constexpr (Width == AccessWidth) {
+ auto hand_r = new handler_entry_read_delegate<Width, AddrShift, Endian, READ>(m_view.m_space, handler_r);
+ hand_r->set_address_info(nstart, nmask);
+ r()->populate(nstart, nend, nmirror, hand_r);
+ } else {
+ auto hand_r = new handler_entry_read_delegate<AccessWidth, -AccessWidth, Endian, READ>(m_view.m_space, handler_r);
+ memory_units_descriptor<Width, AddrShift, Endian> descriptor(AccessWidth, Endian, hand_r, nstart, nend, nmask, nunitmask, ncswidth);
+ hand_r->set_address_info(descriptor.get_handler_start(), descriptor.get_handler_mask());
+ r()->populate_mismatched(nstart, nend, nmirror, descriptor);
+ hand_r->unref();
+ }
+ invalidate_caches(read_or_write::READ);
+ }
+ }
+
+ template<int AccessWidth, typename WRITE>
+ void install_write_handler_helper(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth,
+ const WRITE &handler_w)
+ {
+ if constexpr (Width < AccessWidth) {
+ fatalerror("install_write_handler: cannot install a %d-wide handler in a %d-wide bus", 8 << AccessWidth, 8 << Width);
+ } else {
+ VPRINTF("memory_view::install_write_handler(%*x-%*x mask=%*x mirror=%*x, space width=%d, handler width=%d, %s, %*x)\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmask, m_addrchars, addrmirror,
+ 8 << Width, 8 << AccessWidth,
+ handler_w.name(), data_width() / 4, unitmask);
+
+ 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);
+
+ if constexpr (Width == AccessWidth) {
+ auto hand_w = new handler_entry_write_delegate<Width, AddrShift, Endian, WRITE>(m_view.m_space, handler_w);
+ hand_w->set_address_info(nstart, nmask);
+ w()->populate(nstart, nend, nmirror, hand_w);
+ } else {
+ auto hand_w = new handler_entry_write_delegate<AccessWidth, -AccessWidth, Endian, WRITE>(m_view.m_space, handler_w);
+ memory_units_descriptor<Width, AddrShift, Endian> descriptor(AccessWidth, Endian, hand_w, nstart, nend, nmask, nunitmask, ncswidth);
+ hand_w->set_address_info(descriptor.get_handler_start(), descriptor.get_handler_mask());
+ w()->populate_mismatched(nstart, nend, nmirror, descriptor);
+ hand_w->unref();
+ }
+ invalidate_caches(read_or_write::WRITE);
+ }
+ }
+
+ template<int AccessWidth, typename READ, typename WRITE>
+ void install_readwrite_handler_helper(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth,
+ const READ &handler_r,
+ const WRITE &handler_w)
+ {
+ if constexpr (Width < AccessWidth) {
+ fatalerror("install_readwrite_handler: cannot install a %d-wide handler in a %d-wide bus", 8 << AccessWidth, 8 << Width);
+ } else {
+ VPRINTF("memory_view::install_readwrite_handler(%*x-%*x mask=%*x mirror=%*x, space width=%d, handler width=%d, %s, %s, %*x)\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmask, m_addrchars, addrmirror,
+ 8 << Width, 8 << AccessWidth,
+ handler_r.name(), handler_w.name(), data_width() / 4, unitmask);
+
+ 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);
+
+ if constexpr (Width == AccessWidth) {
+ auto hand_r = new handler_entry_read_delegate <Width, AddrShift, Endian, READ>(m_view.m_space, handler_r);
+ hand_r->set_address_info(nstart, nmask);
+ r() ->populate(nstart, nend, nmirror, hand_r);
+
+ auto hand_w = new handler_entry_write_delegate<Width, AddrShift, Endian, WRITE>(m_view.m_space, handler_w);
+ hand_w->set_address_info(nstart, nmask);
+ w()->populate(nstart, nend, nmirror, hand_w);
+ } else {
+ auto hand_r = new handler_entry_read_delegate <AccessWidth, -AccessWidth, Endian, READ>(m_view.m_space, handler_r);
+ memory_units_descriptor<Width, AddrShift, Endian> descriptor(AccessWidth, Endian, hand_r, nstart, nend, nmask, nunitmask, ncswidth);
+ hand_r->set_address_info(descriptor.get_handler_start(), descriptor.get_handler_mask());
+ r() ->populate_mismatched(nstart, nend, nmirror, descriptor);
+ hand_r->unref();
+
+ auto hand_w = new handler_entry_write_delegate<AccessWidth, -AccessWidth, Endian, WRITE>(m_view.m_space, handler_w);
+ descriptor.set_subunit_handler(hand_w);
+ hand_w->set_address_info(descriptor.get_handler_start(), descriptor.get_handler_mask());
+ w()->populate_mismatched(nstart, nend, nmirror, descriptor);
+ hand_w->unref();
+ }
+ invalidate_caches(read_or_write::READWRITE);
+ }
+ }
+};
+
+namespace {
+ template<int Level, int Width, int AddrShift, endianness_t Endian> memory_view::memory_view_entry *mve_make_1(const address_space_config &config, memory_manager &manager, memory_view &view, int id) {
+ return new memory_view_entry_specific<Level, Width, AddrShift, Endian>(config, manager, view, id);
+ }
+
+ template<int Width, int AddrShift, endianness_t Endian> memory_view::memory_view_entry *mve_make_2(int Level, const address_space_config &config, memory_manager &manager, memory_view &view, int id) {
+ switch(Level) {
+ case 0: return mve_make_1<0, Width, AddrShift, Endian>(config, manager, view, id);
+ case 1: return mve_make_1<1, Width, AddrShift, Endian>(config, manager, view, id);
+ default: abort();
+ }
+ }
+
+ template<int Width, int AddrShift> memory_view::memory_view_entry *mve_make_3(int Level, endianness_t Endian, const address_space_config &config, memory_manager &manager, memory_view &view, int id) {
+ switch(Endian) {
+ case ENDIANNESS_LITTLE: return mve_make_2<Width, AddrShift, ENDIANNESS_LITTLE>(Level, config, manager, view, id);
+ case ENDIANNESS_BIG: return mve_make_2<Width, AddrShift, ENDIANNESS_BIG> (Level, config, manager, view, id);
+ default: abort();
+ }
+ }
+
+ memory_view::memory_view_entry *mve_make(int Level, int Width, int AddrShift, endianness_t Endian, const address_space_config &config, memory_manager &manager, memory_view &view, int id) {
+ switch (Width | (AddrShift + 4)) {
+ case 8|(4+1): return mve_make_3<0, 1>(Level, Endian, config, manager, view, id);
+ case 8|(4-0): return mve_make_3<0, 0>(Level, Endian, config, manager, view, id);
+ case 16|(4+3): return mve_make_3<1, 3>(Level, Endian, config, manager, view, id);
+ case 16|(4-0): return mve_make_3<1, 0>(Level, Endian, config, manager, view, id);
+ case 16|(4-1): return mve_make_3<1, -1>(Level, Endian, config, manager, view, id);
+ case 32|(4+3): return mve_make_3<2, 3>(Level, Endian, config, manager, view, id);
+ case 32|(4-0): return mve_make_3<2, 0>(Level, Endian, config, manager, view, id);
+ case 32|(4-1): return mve_make_3<2, -1>(Level, Endian, config, manager, view, id);
+ case 32|(4-2): return mve_make_3<2, -2>(Level, Endian, config, manager, view, id);
+ case 64|(4-0): return mve_make_3<3, 0>(Level, Endian, config, manager, view, id);
+ case 64|(4-1): return mve_make_3<3, -1>(Level, Endian, config, manager, view, id);
+ case 64|(4-2): return mve_make_3<3, -2>(Level, Endian, config, manager, view, id);
+ case 64|(4-3): return mve_make_3<3, -3>(Level, Endian, config, manager, view, id);
+ default: abort();
+ }
+ }
+}
+
+memory_view::memory_view_entry &memory_view::operator[](int slot)
+{
+ if (!m_config)
+ fatalerror("A view must be in a map or a space before it can be setup.");
+
+ auto i = m_entry_mapping.find(slot);
+ if (i == m_entry_mapping.end()) {
+ memory_view_entry *e;
+ int id = m_entries.size();
+ e = mve_make(emu::detail::handler_entry_dispatch_level(m_config->addr_width()), m_config->data_width(), m_config->addr_shift(), m_config->endianness(),
+ *m_config, m_device.machine().memory(), *this, id);
+ m_entries.resize(id+1);
+ m_entries[id].reset(e);
+ m_entry_mapping[slot] = id;
+ return *e;
+
+ } else
+ return *m_entries[i->second];
+}
+
+memory_view::memory_view_entry::memory_view_entry(const address_space_config &config, memory_manager &manager, memory_view &view, int id) : address_space_installer(config, manager), m_view(view), m_id(id)
+{
+ m_map = std::make_unique<address_map>(m_view);
+}
+
+template<int Level, int Width, int AddrShift, endianness_t Endian> void memory_view_entry_specific<Level, Width, AddrShift, Endian>::populate_from_map(address_map *map)
+{
+ // no map specified, use the space-specific one
+ if (map == nullptr)
+ map = m_map.get();
+
+ memory_region *devregion = (m_view.m_space->spacenum() == 0) ? m_view.m_device.memregion(DEVICE_SELF) : nullptr;
+ u32 devregionsize = (devregion != nullptr) ? devregion->bytes() : 0;
+
+ // merge in the submaps
+ map->import_submaps(m_manager.machine(), m_view.m_device.owner() ? *m_view.m_device.owner() : m_view.m_device, data_width(), endianness(), addr_shift());
+
+ // make a pass over the address map, adjusting for the device and getting memory pointers
+ for (address_map_entry &entry : map->m_entrylist)
+ {
+ // computed adjusted addresses first
+ adjust_addresses(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror);
+
+ // if we have a share entry, add it to our map
+ if (entry.m_share != nullptr)
+ {
+ // if we can't find it, add it to our map
+ std::string fulltag = entry.m_devbase.subtag(entry.m_share);
+ memory_share *share = m_manager.share_find(fulltag);
+ if (!share)
+ {
+ VPRINTF("Creating share '%s' of length 0x%X\n", fulltag, entry.m_addrend + 1 - entry.m_addrstart);
+ share = m_manager.share_alloc(m_view.m_device, fulltag, data_width(), address_to_byte(entry.m_addrend + 1 - entry.m_addrstart), endianness());
+ }
+ else
+ {
+ std::string result = share->compare(data_width(), address_to_byte(entry.m_addrend + 1 - entry.m_addrstart), endianness());
+ if (!result.empty())
+ fatalerror("%s\n", result);
+ }
+ entry.m_memory = share->ptr();
+ }
+
+ // if this is a ROM handler without a specified region and not shared, attach it to the implicit region
+ if (m_view.m_space->spacenum() == AS_PROGRAM && entry.m_read.m_type == AMH_ROM && entry.m_region == nullptr && entry.m_share == nullptr)
+ {
+ // make sure it fits within the memory region before doing so, however
+ if (entry.m_addrend < devregionsize)
+ {
+ entry.m_region = m_view.m_device.tag();
+ entry.m_rgnoffs = address_to_byte(entry.m_addrstart);
+ }
+ }
+
+ // validate adjusted addresses against implicit regions
+ if (entry.m_region != nullptr)
+ {
+ // determine full tag
+ std::string fulltag = entry.m_devbase.subtag(entry.m_region);
+
+ // find the region
+ memory_region *region = m_manager.machine().root_device().memregion(fulltag);
+ if (region == nullptr)
+ fatalerror("device '%s' %s view memory map entry %X-%X references nonexistent region \"%s\"\n", m_view.m_device.tag(), m_view.m_name, entry.m_addrstart, entry.m_addrend, entry.m_region);
+
+ // validate the region
+ if (entry.m_rgnoffs + m_config.addr2byte(entry.m_addrend - entry.m_addrstart + 1) > region->bytes())
+ fatalerror("device '%s' %s view memory map entry %X-%X extends beyond region \"%s\" size (%X)\n", m_view.m_device.tag(), m_view.m_name, entry.m_addrstart, entry.m_addrend, entry.m_region, region->bytes());
+
+ if (entry.m_share != nullptr)
+ fatalerror("device '%s' %s view memory map entry %X-%X has both .region() and .share()\n", m_view.m_device.tag(), m_view.m_name, entry.m_addrstart, entry.m_addrend);
+ }
+
+ // convert any region-relative entries to their memory pointers
+ if (entry.m_region != nullptr)
+ {
+ // determine full tag
+ std::string fulltag = entry.m_devbase.subtag(entry.m_region);
+
+ // set the memory address
+ entry.m_memory = m_manager.machine().root_device().memregion(fulltag)->base() + entry.m_rgnoffs;
+ }
+
+ // allocate anonymous ram when needed
+ if (!entry.m_memory && (entry.m_read.m_type == AMH_RAM || entry.m_write.m_type == AMH_RAM))
+ entry.m_memory = m_manager.anonymous_alloc(*m_view.m_space, address_to_byte(entry.m_addrend + 1 - entry.m_addrstart), m_config.data_width(), entry.m_addrstart, entry.m_addrend, key());
+ }
+
+ // Force the slot to exist, in case the map is empty
+ m_view.m_select_u(m_id);
+
+ // install the handlers, using the original, unadjusted memory map
+ 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);
+ }
+}
+
+std::string memory_view::memory_view_entry::key() const
+{
+ std::string key = m_view.m_context;
+ if (m_id != -1)
+ key += util::string_format("%s[%d].", m_view.m_name, m_view.id_to_slot(m_id));
+ return key;
+}
+
+
+memory_view::memory_view(device_t &device, std::string name) : m_device(device), m_name(name), m_config(nullptr), m_addrstart(0), m_addrend(0), m_space(nullptr), m_handler_read(nullptr), m_handler_write(nullptr), m_cur_id(-1), m_cur_slot(-1)
+{
+}
+
+void memory_view::disable()
+{
+ m_cur_slot = -1;
+ m_cur_id = -1;
+ m_select_a(-1);
+}
+
+void memory_view::select(int slot)
+{
+ auto i = m_entry_mapping.find(slot);
+ if (i == m_entry_mapping.end())
+ fatalerror("memory_view %s: select of unknown slot %d", m_name, slot);
+
+ m_cur_slot = slot;
+ m_cur_id = i->second;
+ m_select_a(m_cur_id);
+}
+
+int memory_view::id_to_slot(int id) const
+{
+ for(const auto &p : m_entry_mapping)
+ if (p.second == id)
+ return p.first;
+ fatalerror("memory_view::id_to_slot on unknown id %d\n", id);
+}
+
+void memory_view::initialize_from_address_map(offs_t addrstart, offs_t addrend, const address_space_config &config)
+{
+ if (m_config)
+ fatalerror("A memory_view can be present in only one address map.");
+
+ m_config = &config;
+ m_addrstart = addrstart;
+ m_addrend = addrend;
+}
+
+namespace {
+ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void h_make_1(address_space &space, memory_view &view, handler_entry *&r, handler_entry *&w, std::function<void (int)> &sa, std::function<void (int)> &su) {
+ auto rx = new handler_entry_read_dispatch <HighBits, Width, AddrShift, Endian>(&space, view);
+ auto wx = new handler_entry_write_dispatch<HighBits, Width, AddrShift, Endian>(&space, view);
+ r = rx;
+ w = wx;
+
+ sa = [rx, wx](int s) { rx->select_a(s); wx->select_a(s); };
+ su = [rx, wx](int s) { rx->select_u(s); wx->select_u(s); };
+ }
+
+ template<int Width, int AddrShift, endianness_t Endian> void h_make_2(int HighBits, address_space &space, memory_view &view, handler_entry *&r, handler_entry *&w, std::function<void (int)> &sa, std::function<void (int)> &su) {
+ switch(HighBits) {
+ case 0: h_make_1<std::max(0, Width), Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 1: h_make_1<std::max(1, Width), Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 2: h_make_1<std::max(2, Width), Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 3: h_make_1<std::max(3, Width), Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 4: h_make_1< 4, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 5: h_make_1< 5, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 6: h_make_1< 6, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 7: h_make_1< 7, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 8: h_make_1< 8, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 9: h_make_1< 9, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 10: h_make_1<10, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 11: h_make_1<11, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 12: h_make_1<12, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 13: h_make_1<13, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 14: h_make_1<14, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 15: h_make_1<15, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 16: h_make_1<16, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 17: h_make_1<17, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 18: h_make_1<18, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 19: h_make_1<19, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 20: h_make_1<20, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 21: h_make_1<21, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 22: h_make_1<22, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 23: h_make_1<23, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 24: h_make_1<24, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 25: h_make_1<25, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 26: h_make_1<26, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 27: h_make_1<27, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 28: h_make_1<28, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 29: h_make_1<29, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 30: h_make_1<20, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 31: h_make_1<31, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ case 32: h_make_1<32, Width, AddrShift, Endian>(space, view, r, w, sa, su); break;
+ default: abort();
+ }
+ }
+
+ template<int Width, int AddrShift> void h_make_3(int HighBits, endianness_t Endian, address_space &space, memory_view &view, handler_entry *&r, handler_entry *&w, std::function<void (int)> &sa, std::function<void (int)> &su) {
+ switch(Endian) {
+ case ENDIANNESS_LITTLE: h_make_2<Width, AddrShift, ENDIANNESS_LITTLE>(HighBits, space, view, r, w, sa, su); break;
+ case ENDIANNESS_BIG: h_make_2<Width, AddrShift, ENDIANNESS_BIG> (HighBits, space, view, r, w, sa, su); break;
+ default: abort();
+ }
+ }
+
+ void h_make(int HighBits, int Width, int AddrShift, endianness_t Endian, address_space &space, memory_view &view, handler_entry *&r, handler_entry *&w, std::function<void (int)> &sa, std::function<void (int)> &su) {
+ switch (Width | (AddrShift + 4)) {
+ case 8|(4+1): h_make_3<0, 1>(HighBits, Endian, space, view, r, w, sa, su); break;
+ case 8|(4-0): h_make_3<0, 0>(HighBits, Endian, space, view, r, w, sa, su); break;
+ case 16|(4+3): h_make_3<1, 3>(HighBits, Endian, space, view, r, w, sa, su); break;
+ case 16|(4-0): h_make_3<1, 0>(HighBits, Endian, space, view, r, w, sa, su); break;
+ case 16|(4-1): h_make_3<1, -1>(HighBits, Endian, space, view, r, w, sa, su); break;
+ case 32|(4+3): h_make_3<2, 3>(HighBits, Endian, space, view, r, w, sa, su); break;
+ case 32|(4-0): h_make_3<2, 0>(HighBits, Endian, space, view, r, w, sa, su); break;
+ case 32|(4-1): h_make_3<2, -1>(HighBits, Endian, space, view, r, w, sa, su); break;
+ case 32|(4-2): h_make_3<2, -2>(HighBits, Endian, space, view, r, w, sa, su); break;
+ case 64|(4-0): h_make_3<3, 0>(HighBits, Endian, space, view, r, w, sa, su); break;
+ case 64|(4-1): h_make_3<3, -1>(HighBits, Endian, space, view, r, w, sa, su); break;
+ case 64|(4-2): h_make_3<3, -2>(HighBits, Endian, space, view, r, w, sa, su); break;
+ case 64|(4-3): h_make_3<3, -3>(HighBits, Endian, space, view, r, w, sa, su); break;
+ default: abort();
+ }
+ }
+}
+
+std::pair<handler_entry *, handler_entry *> memory_view::make_handlers(address_space &space, offs_t addrstart, offs_t addrend)
+{
+ if (m_space != &space || m_addrstart != addrstart || m_addrend != addrend) {
+ if (m_space)
+ fatalerror("A memory_view can be installed only once.");
+
+ if (m_config) {
+ if (m_addrstart != addrstart || m_addrend != addrend)
+ fatalerror("A memory_view must be installed at its configuration address.");
+ } else {
+ m_config = &space.space_config();
+ m_addrstart = addrstart;
+ m_addrend = addrend;
+ }
+
+ m_space = &space;
+
+ offs_t span = addrstart ^ addrend;
+ u32 awidth = 0;
+ if (span) {
+ for(awidth = 1; awidth != 32; awidth++)
+ if ((1 << awidth) >= span)
+ break;
+ }
+
+ h_make(awidth, m_config->data_width(), m_config->addr_shift(), m_config->endianness(), space, *this, m_handler_read, m_handler_write, m_select_a, m_select_u);
+ }
+
+ return std::make_pair(m_handler_read, m_handler_write);
+}
+
+void memory_view::make_subdispatch(std::string context)
+{
+ m_context = context;
+ for(auto &e : m_entries)
+ e->populate_from_map();
+}
+
+void memory_view::memory_view_entry::check_range_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)
+{
+ check_optimize_mirror(function, addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+ if (nstart < m_view.m_addrstart || (nend | nmirror) > m_view.m_addrend)
+ fatalerror("%s: The range %x-%x mirror %x, exceeds the view window boundaries %x-%x.\n", function, addrstart, addrend, addrmirror, m_view.m_addrstart, m_view.m_addrend);
+}
+
+void memory_view::memory_view_entry::check_range_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)
+{
+ check_optimize_all(function, width, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth);
+ if (nstart < m_view.m_addrstart || (nend | nmirror | addrselect) > m_view.m_addrend)
+ fatalerror("%s: The range %x-%x mirror %x select %x, exceeds the view window boundaries %x-%x.\n", function, addrstart, addrend, addrmirror, addrselect, m_view.m_addrstart, m_view.m_addrend);
+}
+
+void memory_view::memory_view_entry::check_range_address(const char *function, offs_t addrstart, offs_t addrend)
+{
+ check_address(function, addrstart, addrend);
+ if (addrstart < m_view.m_addrstart || addrend > m_view.m_addrend)
+ fatalerror("%s: The range %x-%x exceeds the view window boundaries %x-%x.\n", function, addrstart, addrend, m_view.m_addrstart, m_view.m_addrend);
+}
+
+template<int Level, int Width, int AddrShift, endianness_t Endian> void memory_view_entry_specific<Level, Width, AddrShift, Endian>::install_ram_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, void *baseptr)
+{
+ VPRINTF("memory_view::install_ram_generic(%s-%s mirror=%s, %s, %p)\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmirror,
+ (readorwrite == read_or_write::READ) ? "read" : (readorwrite == read_or_write::WRITE) ? "write" : (readorwrite == read_or_write::READWRITE) ? "read/write" : "??",
+ baseptr);
+
+ offs_t nstart, nend, nmask, nmirror;
+ check_range_optimize_mirror("install_ram_generic", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+
+ m_view.m_select_u(m_id);
+
+ // map for read
+ if (readorwrite == read_or_write::READ || readorwrite == read_or_write::READWRITE)
+ {
+ auto hand_r = new handler_entry_read_memory<Width, AddrShift, Endian>(m_view.m_space, baseptr);
+ hand_r->set_address_info(nstart, nmask);
+ r()->populate(nstart, nend, nmirror, hand_r);
+ }
+
+ // map for write
+ if (readorwrite == read_or_write::WRITE || readorwrite == read_or_write::READWRITE)
+ {
+ auto hand_w = new handler_entry_write_memory<Width, AddrShift, Endian>(m_view.m_space, baseptr);
+ hand_w->set_address_info(nstart, nmask);
+ w()->populate(nstart, nend, nmirror, hand_w);
+ }
+
+ invalidate_caches(readorwrite);
+}
+
+template<int Level, int Width, int AddrShift, endianness_t Endian> void memory_view_entry_specific<Level, Width, AddrShift, Endian>::unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, bool quiet)
+{
+ VPRINTF("memory_view::unmap(%*x-%*x mirror=%*x, %s, %s)\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmirror,
+ (readorwrite == read_or_write::READ) ? "read" : (readorwrite == read_or_write::WRITE) ? "write" : (readorwrite == read_or_write::READWRITE) ? "read/write" : "??",
+ quiet ? "quiet" : "normal");
+
+ offs_t nstart, nend, nmask, nmirror;
+ check_range_optimize_mirror("unmap_generic", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+
+ m_view.m_select_u(m_id);
+
+ // read space
+ if (readorwrite == read_or_write::READ || readorwrite == read_or_write::READWRITE) {
+ auto handler = static_cast<handler_entry_read<Width, AddrShift, Endian> *>(quiet ? m_view.m_space->nop_r() : m_view.m_space->unmap_r());
+ handler->ref();
+ r()->populate(nstart, nend, nmirror, handler);
+ }
+
+ // write space
+ if (readorwrite == read_or_write::WRITE || readorwrite == read_or_write::READWRITE) {
+ auto handler = static_cast<handler_entry_write<Width, AddrShift, Endian> *>(quiet ? m_view.m_space->nop_w() : m_view.m_space->unmap_w());
+ handler->ref();
+ w()->populate(nstart, nend, nmirror, handler);
+ }
+
+ invalidate_caches(readorwrite);
+}
+
+template<int Level, int Width, int AddrShift, endianness_t Endian> void memory_view_entry_specific<Level, Width, AddrShift, Endian>::install_view(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_view &view)
+{
+ offs_t nstart, nend, nmask, nmirror;
+ check_range_optimize_mirror("install_view", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+
+ m_view.m_select_u(m_id);
+
+ auto handlers = view.make_handlers(*m_view.m_space, addrstart, addrend);
+ r()->populate(nstart, nend, nmirror, static_cast<handler_entry_read <Width, AddrShift, Endian> *>(handlers.first));
+ w()->populate(nstart, nend, nmirror, static_cast<handler_entry_write<Width, AddrShift, Endian> *>(handlers.second));
+ view.make_subdispatch(key()); // Must be called after populate
+}
+
+template<int Level, int Width, int AddrShift, endianness_t Endian> memory_passthrough_handler *memory_view_entry_specific<Level, Width, AddrShift, Endian>::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph)
+{
+ offs_t nstart, nend, nmask, nmirror;
+ check_range_optimize_mirror("install_read_tap", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+ if (!mph)
+ mph = m_view.m_space->make_mph();
+
+ m_view.m_select_u(m_id);
+
+ auto handler = new handler_entry_read_tap<Width, AddrShift, Endian>(m_view.m_space, *mph, name, tap);
+ r()->populate_passthrough(nstart, nend, nmirror, handler);
+ handler->unref();
+
+ invalidate_caches(read_or_write::READ);
+
+ return mph;
+}
+
+template<int Level, int Width, int AddrShift, endianness_t Endian> memory_passthrough_handler *memory_view_entry_specific<Level, Width, AddrShift, Endian>::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph)
+{
+ offs_t nstart, nend, nmask, nmirror;
+ check_range_optimize_mirror("install_write_tap", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+ if (!mph)
+ mph = m_view.m_space->make_mph();
+
+ m_view.m_select_u(m_id);
+
+ auto handler = new handler_entry_write_tap<Width, AddrShift, Endian>(m_view.m_space, *mph, name, tap);
+ w()->populate_passthrough(nstart, nend, nmirror, handler);
+ handler->unref();
+
+ invalidate_caches(read_or_write::WRITE);
+
+ return mph;
+}
+
+template<int Level, int Width, int AddrShift, endianness_t Endian> memory_passthrough_handler *memory_view_entry_specific<Level, Width, AddrShift, Endian>::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapr, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapw, memory_passthrough_handler *mph)
+{
+ offs_t nstart, nend, nmask, nmirror;
+ check_range_optimize_mirror("install_readwrite_tap", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+ if (!mph)
+ mph = m_view.m_space->make_mph();
+
+ m_view.m_select_u(m_id);
+
+ auto rhandler = new handler_entry_read_tap <Width, AddrShift, Endian>(m_view.m_space, *mph, name, tapr);
+ r() ->populate_passthrough(nstart, nend, nmirror, rhandler);
+ rhandler->unref();
+
+ auto whandler = new handler_entry_write_tap<Width, AddrShift, Endian>(m_view.m_space, *mph, name, tapw);
+ w()->populate_passthrough(nstart, nend, nmirror, whandler);
+ whandler->unref();
+
+ invalidate_caches(read_or_write::READWRITE);
+
+ return mph;
+}
+
+template<int Level, int Width, int AddrShift, endianness_t Endian> void memory_view_entry_specific<Level, Width, AddrShift, Endian>::install_device_delegate(offs_t addrstart, offs_t addrend, device_t &device, address_map_constructor &delegate, u64 unitmask, int cswidth)
+{
+ check_range_address("install_device_delegate", addrstart, addrend);
+ address_map map(*m_view.m_space, addrstart, addrend, unitmask, cswidth, m_view.m_device, delegate);
+ map.import_submaps(m_manager.machine(), device, data_width(), endianness(), addr_shift());
+ populate_from_map(&map);
+}
+
+template<int Level, int Width, int AddrShift, endianness_t Endian> void memory_view_entry_specific<Level, Width, AddrShift, Endian>::install_readwrite_port(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string rtag, std::string wtag)
+{
+ VPRINTF("memory_view::install_readwrite_port(%*x-%*x mirror=%*x, read=\"%s\" / write=\"%s\")\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmirror,
+ rtag.empty() ? "(none)" : rtag, wtag.empty() ? "(none)" : wtag);
+
+ offs_t nstart, nend, nmask, nmirror;
+ check_range_optimize_mirror("install_readwrite_port", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+
+ m_view.m_select_u(m_id);
+
+ // read handler
+ if (rtag != "")
+ {
+ // find the port
+ ioport_port *port = m_view.m_device.owner()->ioport(rtag);
+ if (port == nullptr)
+ throw emu_fatalerror("Attempted to map non-existent port '%s' for read in space %s of device '%s'\n", rtag, m_view.m_name, m_view.m_device.tag());
+
+ // map the range and set the ioport
+ auto hand_r = new handler_entry_read_ioport<Width, AddrShift, Endian>(m_view.m_space, port);
+ r()->populate(nstart, nend, nmirror, hand_r);
+ }
+
+ if (wtag != "")
+ {
+ // find the port
+ ioport_port *port = m_view.m_device.owner()->ioport(wtag);
+ if (port == nullptr)
+ fatalerror("Attempted to map non-existent port '%s' for write in space %s of device '%s'\n", wtag, m_view.m_name, m_view.m_device.tag());
+
+ // map the range and set the ioport
+ auto hand_w = new handler_entry_write_ioport<Width, AddrShift, Endian>(m_view.m_space, port);
+ w()->populate(nstart, nend, nmirror, hand_w);
+ }
+
+ invalidate_caches(rtag != "" ? wtag != "" ? read_or_write::READWRITE : read_or_write::READ : read_or_write::WRITE);
+}
+template<int Level, int Width, int AddrShift, endianness_t Endian> void memory_view_entry_specific<Level, Width, AddrShift, Endian>::install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_bank *rbank, memory_bank *wbank)
+{
+ VPRINTF("memory_view::install_readwrite_bank(%*x-%*x mirror=%*x, read=\"%s\" / write=\"%s\")\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmirror,
+ (rbank != nullptr) ? rbank->tag() : "(none)", (wbank != nullptr) ? wbank->tag() : "(none)");
+
+ offs_t nstart, nend, nmask, nmirror;
+ check_range_optimize_mirror("install_bank_generic", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+
+ m_view.m_select_u(m_id);
+
+ // map the read bank
+ if (rbank != nullptr)
+ {
+ auto hand_r = new handler_entry_read_memory_bank<Width, AddrShift, Endian>(m_view.m_space, *rbank);
+ hand_r->set_address_info(nstart, nmask);
+ r()->populate(nstart, nend, nmirror, hand_r);
+ }
+
+ // map the write bank
+ if (wbank != nullptr)
+ {
+ auto hand_w = new handler_entry_write_memory_bank<Width, AddrShift, Endian>(m_view.m_space, *wbank);
+ hand_w->set_address_info(nstart, nmask);
+ w()->populate(nstart, nend, nmirror, hand_w);
+ }
+
+ invalidate_caches(rbank ? wbank ? read_or_write::READWRITE : read_or_write::READ : read_or_write::WRITE);
+}
diff --git a/src/mame/drivers/simpsons.cpp b/src/mame/drivers/simpsons.cpp
index 86fb6c95c78..356baeda1f9 100644
--- a/src/mame/drivers/simpsons.cpp
+++ b/src/mame/drivers/simpsons.cpp
@@ -118,8 +118,8 @@ Notes:
void simpsons_state::main_map(address_map &map)
{
map(0x0000, 0x1fff).rw(m_k052109, FUNC(k052109_device::read), FUNC(k052109_device::write));
- map(0x0000, 0x0fff).m(m_bank0000, FUNC(address_map_bank_device::amap8));
- map(0x2000, 0x3fff).m(m_bank2000, FUNC(address_map_bank_device::amap8));
+ map(0x0000, 0x0fff).view(m_palette_view);
+ m_palette_view[0](0x0000, 0x0fff).ram().w("palette", FUNC(palette_device::write8)).share("palette");
map(0x1f80, 0x1f80).portr("COIN");
map(0x1f81, 0x1f81).portr("TEST");
map(0x1f90, 0x1f90).portr("P1");
@@ -134,24 +134,15 @@ void simpsons_state::main_map(address_map &map)
map(0x1fc6, 0x1fc7).rw("k053260", FUNC(k053260_device::main_read), FUNC(k053260_device::main_write));
map(0x1fc8, 0x1fc9).r(m_k053246, FUNC(k053247_device::k053246_r));
map(0x1fca, 0x1fca).r("watchdog", FUNC(watchdog_timer_device::reset_r));
+ map(0x2000, 0x3fff).view(m_video_view);
+ m_video_view[0](0x2000, 0x3fff).rw(FUNC(simpsons_state::simpsons_k052109_r), FUNC(simpsons_state::simpsons_k052109_w));
+ m_video_view[1](0x2000, 0x2fff).rw(FUNC(simpsons_state::simpsons_k053247_r), FUNC(simpsons_state::simpsons_k053247_w));
+ m_video_view[1](0x3000, 0x3fff).ram();
map(0x4000, 0x5fff).ram();
map(0x6000, 0x7fff).bankr("bank1");
map(0x8000, 0xffff).rom().region("maincpu", 0x78000);
}
-void simpsons_state::bank0000_map(address_map &map)
-{
- map(0x0000, 0x0fff).rw(m_k052109, FUNC(k052109_device::read), FUNC(k052109_device::write));
- map(0x1000, 0x1fff).ram().w("palette", FUNC(palette_device::write8)).share("palette");
-}
-
-void simpsons_state::bank2000_map(address_map &map)
-{
- map(0x0000, 0x1fff).rw(FUNC(simpsons_state::simpsons_k052109_r), FUNC(simpsons_state::simpsons_k052109_w));
- map(0x2000, 0x2fff).rw(FUNC(simpsons_state::simpsons_k053247_r), FUNC(simpsons_state::simpsons_k053247_w));
- map(0x3000, 0x3fff).ram();
-}
-
void simpsons_state::z80_bankswitch_w(uint8_t data)
{
membank("bank2")->set_entry(data & 7);
@@ -331,9 +322,6 @@ void simpsons_state::simpsons(machine_config &config)
Z80(config, m_audiocpu, XTAL(3'579'545)); /* verified on pcb */
m_audiocpu->set_addrmap(AS_PROGRAM, &simpsons_state::z80_map); /* NMIs are generated by the 053260 */
- ADDRESS_MAP_BANK(config, "bank0000").set_map(&simpsons_state::bank0000_map).set_options(ENDIANNESS_BIG, 8, 13, 0x1000);
- ADDRESS_MAP_BANK(config, "bank2000").set_map(&simpsons_state::bank2000_map).set_options(ENDIANNESS_BIG, 8, 14, 0x2000);
-
EEPROM_ER5911_8BIT(config, "eeprom");
WATCHDOG_TIMER(config, "watchdog");
diff --git a/src/mame/includes/simpsons.h b/src/mame/includes/simpsons.h
index 69a9dbfa98c..7a766965378 100644
--- a/src/mame/includes/simpsons.h
+++ b/src/mame/includes/simpsons.h
@@ -17,10 +17,10 @@ class simpsons_state : public driver_device
public:
simpsons_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
+ m_palette_view(*this, "palette_view"),
+ m_video_view(*this, "video_view"),
m_maincpu(*this, "maincpu"),
m_audiocpu(*this, "audiocpu"),
- m_bank0000(*this, "bank0000"),
- m_bank2000(*this, "bank2000"),
m_k052109(*this, "k052109"),
m_k053246(*this, "k053246"),
m_k053251(*this, "k053251")
@@ -47,11 +47,13 @@ private:
int m_firq_enabled;
u64 m_nmi_enabled;
+ /* views */
+ memory_view m_palette_view;
+ memory_view m_video_view;
+
/* devices */
required_device<konami_cpu_device> m_maincpu;
required_device<cpu_device> m_audiocpu;
- required_device<address_map_bank_device> m_bank0000;
- required_device<address_map_bank_device> m_bank2000;
required_device<k052109_device> m_k052109;
required_device<k053247_device> m_k053246;
required_device<k053251_device> m_k053251;
diff --git a/src/mame/video/simpsons.cpp b/src/mame/video/simpsons.cpp
index 2caafb9bac0..1c43114823d 100644
--- a/src/mame/video/simpsons.cpp
+++ b/src/mame/video/simpsons.cpp
@@ -77,8 +77,11 @@ void simpsons_state::simpsons_k053247_w(offs_t offset, uint8_t data)
void simpsons_state::simpsons_video_banking( int bank )
{
- m_bank0000->set_bank(bank & 1);
- m_bank2000->set_bank((bank >> 1) & 1);
+ if(bank & 1)
+ m_palette_view.select(0);
+ else
+ m_palette_view.disable();
+ m_video_view.select((bank >> 1) & 1);
}