mirror of
https://github.com/holub/mame
synced 2025-04-19 23:12:11 +03:00
Implement views, which are essentially bankdevs integrated into the
memory map system. [O. Galibert]
This commit is contained in:
parent
8d4559070f
commit
574daf4e49
@ -64,6 +64,20 @@ Memory regions are read-only memory zones in which ROMs are loaded.
|
||||
|
||||
All of these have names allowing to access them.
|
||||
|
||||
2.4 Views
|
||||
~~~~~~~~~
|
||||
|
||||
Views are a way to multiplex different submaps over a memory range
|
||||
with fast switching. It is to be used when multiple devices map at
|
||||
the same addresses and are switched in externally. They must be
|
||||
created as an object of the device and then setup either statically in
|
||||
a memory map or dynamically through install_* calls.
|
||||
|
||||
Switchable submaps, aka variants, are named through an integer. An
|
||||
internal indirection through a map ensures that any integer value can
|
||||
be used.
|
||||
|
||||
|
||||
3. Memory objects
|
||||
-----------------
|
||||
|
||||
@ -225,6 +239,37 @@ The ``memregion`` device method retrieves a memory region by name.
|
||||
Beware that the lookup can be expensive, prefer finders instead.
|
||||
|
||||
|
||||
3.4 Views - memory_view
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: C++
|
||||
|
||||
class memory_view {
|
||||
memory_view(device_t &device, std::string name);
|
||||
memory_view_entry &operator[](int slot);
|
||||
|
||||
void select(int entry);
|
||||
void disable();
|
||||
|
||||
const std::string &name() const;
|
||||
}
|
||||
|
||||
A view allows to switch part of a memory map between multiple
|
||||
possibilities, or even disable it entirely to see what was there
|
||||
before. It is created as an object of the device.
|
||||
|
||||
.. code-block:: C++
|
||||
|
||||
memory_view m_view;
|
||||
|
||||
[device constructor] m_view(*this, "name"),
|
||||
|
||||
It is then setup through the address map API or dynamically. The, at
|
||||
runtime, a variant, which is numbered, can be selected through the
|
||||
``select`` method or the view can be disabled through the ``disabled``
|
||||
method. A disabled view can be reenabled at any time.
|
||||
|
||||
|
||||
4. Address maps API
|
||||
-------------------
|
||||
|
||||
@ -543,6 +588,40 @@ trigger the handler if a wider part of the bus is accessed. The
|
||||
parameter is that trigger width (would be 16 in the 68000 case).
|
||||
|
||||
|
||||
4.5 View setup
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: C++
|
||||
|
||||
map(start, end).view(m_view);
|
||||
m_view[0](start1, end1).[...];
|
||||
|
||||
A view is setup in a address map with the view method. The only
|
||||
qualifier accepted is mirror. The "disabled" version of the view will
|
||||
include what was in the range prior to the view setup.
|
||||
|
||||
The different variants are setup by indexing the view with the variant
|
||||
number and setting up an entry in the usual way. The entries within a
|
||||
variant must of course stay within the range. There are no other
|
||||
additional constraints. The contents of a variant, by default, are
|
||||
what was there before, e.g. the contents of the disabled view, and
|
||||
then setting it up allows to override part or all of it.
|
||||
|
||||
Variants can only be setup once the view itself has been setup with
|
||||
the ``view`` method.
|
||||
|
||||
A view can only be put in one address map and in only one position.
|
||||
If multiple views have identical or similar contents remember that
|
||||
setting up a map is nothing more than a method call, and creating a
|
||||
second method to setup a view is perfectly reasonable. A view is of
|
||||
type **memory_view** and an indexed entry (e.g. a variant to setup) is
|
||||
of type **memory_view::memory_view_entry &**.
|
||||
|
||||
A view can be installed in another view, but don't forget that a view
|
||||
can be installed only once. A view can also being part of "what was
|
||||
there before".
|
||||
|
||||
|
||||
5. Address space dynamic mapping API
|
||||
------------------------------------
|
||||
|
||||
@ -695,3 +774,21 @@ with an optional mirror.
|
||||
|
||||
Install a device address with an address map in a space. The
|
||||
``unitmask`` and ``cswidth`` arguments are optional.
|
||||
|
||||
5.9 View installation
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: C++
|
||||
|
||||
space.install_view(addrstart, addrend, view)
|
||||
space.install_view(addrstart, addrend, addrmirror, view)
|
||||
|
||||
view[0].install...
|
||||
|
||||
Installs a view in a space. This can be only done once and in only
|
||||
one space, and the view must not have been setup through the address
|
||||
map API before. Once the view is installed variants can be selected
|
||||
through indexation to call a dynamic mapping method on it.
|
||||
|
||||
A view can be installed into a variant of another view without issues
|
||||
with the only usual constraint of single installation.
|
||||
|
@ -117,6 +117,8 @@ files {
|
||||
MAME_DIR .. "src/emu/emucore.h",
|
||||
MAME_DIR .. "src/emu/emumem.cpp",
|
||||
MAME_DIR .. "src/emu/emumem.h",
|
||||
MAME_DIR .. "src/emu/emumem_aspace.cpp",
|
||||
MAME_DIR .. "src/emu/emumem_mview.cpp",
|
||||
MAME_DIR .. "src/emu/emumem_mud.cpp",
|
||||
MAME_DIR .. "src/emu/emumem_mud.h",
|
||||
MAME_DIR .. "src/emu/emumem_hea.h",
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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;
|
||||
|
1321
src/emu/emumem.cpp
1321
src/emu/emumem.cpp
File diff suppressed because it is too large
Load Diff
388
src/emu/emumem.h
388
src/emu/emumem.h
@ -80,9 +80,16 @@ struct data_accessors
|
||||
};
|
||||
|
||||
// a line in the memory structure dump
|
||||
struct memory_entry_context {
|
||||
memory_view *view;
|
||||
bool disabled;
|
||||
int slot;
|
||||
};
|
||||
|
||||
struct memory_entry {
|
||||
offs_t start, end;
|
||||
class handler_entry *entry;
|
||||
std::vector<memory_entry_context> context;
|
||||
};
|
||||
|
||||
|
||||
@ -480,6 +487,7 @@ public:
|
||||
static constexpr u32 F_DISPATCH = 0x00000001; // handler that forwards the access to other handlers
|
||||
static constexpr u32 F_UNITS = 0x00000002; // handler that merges/splits an access among multiple handlers (unitmask support)
|
||||
static constexpr u32 F_PASSTHROUGH = 0x00000004; // handler that passes through the request to another handler
|
||||
static constexpr u32 F_VIEW = 0x00000008; // handler for a view (kinda like dispatch except not entirely)
|
||||
|
||||
// Start/end of range flags
|
||||
static constexpr u8 START = 1;
|
||||
@ -507,6 +515,7 @@ public:
|
||||
inline u32 flags() const { return m_flags; }
|
||||
|
||||
inline bool is_dispatch() const { return m_flags & F_DISPATCH; }
|
||||
inline bool is_view() const { return m_flags & F_VIEW; }
|
||||
inline bool is_units() const { return m_flags & F_UNITS; }
|
||||
inline bool is_passthrough() const { return m_flags & F_PASSTHROUGH; }
|
||||
|
||||
@ -516,6 +525,9 @@ public:
|
||||
virtual void enumerate_references(handler_entry::reflist &refs) const;
|
||||
u32 get_refcount() const { return m_refcount; }
|
||||
|
||||
virtual void select_a(int slot);
|
||||
virtual void select_u(int slot);
|
||||
|
||||
protected:
|
||||
// Address range storage
|
||||
struct range {
|
||||
@ -610,6 +622,9 @@ public:
|
||||
|
||||
// Return the internal structures of the root dispatch
|
||||
virtual const handler_entry_read<Width, AddrShift, Endian> *const *get_dispatch() const;
|
||||
|
||||
virtual void init_handlers(offs_t start_entry, offs_t end_entry, u32 lowbits, handler_entry_read<Width, AddrShift, Endian> **dispatch, handler_entry::range *ranges);
|
||||
virtual handler_entry_read<Width, AddrShift, Endian> *dup();
|
||||
};
|
||||
|
||||
// =====================-> The parent class of all write handlers
|
||||
@ -682,6 +697,9 @@ public:
|
||||
|
||||
// Return the internal structures of the root dispatch
|
||||
virtual const handler_entry_write<Width, AddrShift, Endian> *const *get_dispatch() const;
|
||||
|
||||
virtual void init_handlers(offs_t start_entry, offs_t end_entry, u32 lowbits, handler_entry_write<Width, AddrShift, Endian> **dispatch, handler_entry::range *ranges);
|
||||
virtual handler_entry_write<Width, AddrShift, Endian> *dup();
|
||||
};
|
||||
|
||||
// =====================-> Passthrough handler management structure
|
||||
@ -1231,137 +1249,29 @@ public:
|
||||
|
||||
// ======================> address_space
|
||||
|
||||
// address_space holds live information about an address space
|
||||
class address_space
|
||||
{
|
||||
friend class memory_bank;
|
||||
friend class memory_block;
|
||||
template<int Width, int AddrShift, endianness_t Endian> friend class handler_entry_read_unmapped;
|
||||
template<int Width, int AddrShift, endianness_t Endian> friend class handler_entry_write_unmapped;
|
||||
|
||||
struct notifier_t {
|
||||
std::function<void (read_or_write)> m_notifier;
|
||||
int m_id;
|
||||
};
|
||||
|
||||
protected:
|
||||
// construction/destruction
|
||||
address_space(memory_manager &manager, device_memory_interface &memory, int spacenum);
|
||||
|
||||
class address_space_installer {
|
||||
public:
|
||||
virtual ~address_space();
|
||||
|
||||
// getters
|
||||
device_t &device() const { return m_device; }
|
||||
const char *name() const { return m_name; }
|
||||
int spacenum() const { return m_spacenum; }
|
||||
address_map *map() const { return m_map.get(); }
|
||||
|
||||
template<int Width, int AddrShift, endianness_t Endian> void cache(emu::detail::memory_access_cache<Width, AddrShift, Endian> &v) {
|
||||
if(AddrShift != m_config.addr_shift())
|
||||
fatalerror("Requesting cache() with address shift %d while the config says %d\n", AddrShift, m_config.addr_shift());
|
||||
if(8 << Width != m_config.data_width())
|
||||
fatalerror("Requesting cache() with data width %d while the config says %d\n", 8 << Width, m_config.data_width());
|
||||
if(Endian != m_config.endianness())
|
||||
fatalerror("Requesting cache() with endianness %s while the config says %s\n",
|
||||
endianness_names[Endian], endianness_names[m_config.endianness()]);
|
||||
|
||||
v.set(this, get_cache_info());
|
||||
}
|
||||
|
||||
template<int Level, int Width, int AddrShift, endianness_t Endian> void specific(emu::detail::memory_access_specific<Level, Width, AddrShift, Endian> &v) {
|
||||
if(Level != emu::detail::handler_entry_dispatch_level(m_config.addr_width()))
|
||||
fatalerror("Requesting specific() with wrong level, bad address width (the config says %d)\n", m_config.addr_width());
|
||||
if(AddrShift != m_config.addr_shift())
|
||||
fatalerror("Requesting specific() with address shift %d while the config says %d\n", AddrShift, m_config.addr_shift());
|
||||
if(8 << Width != m_config.data_width())
|
||||
fatalerror("Requesting specific() with data width %d while the config says %d\n", 8 << Width, m_config.data_width());
|
||||
if(Endian != m_config.endianness())
|
||||
fatalerror("Requesting spefific() with endianness %s while the config says %s\n",
|
||||
endianness_names[Endian], endianness_names[m_config.endianness()]);
|
||||
|
||||
v.set(this, get_specific_info());
|
||||
}
|
||||
|
||||
int add_change_notifier(std::function<void (read_or_write)> n);
|
||||
void remove_change_notifier(int id);
|
||||
|
||||
void invalidate_caches(read_or_write mode) {
|
||||
if(u32(mode) & ~m_in_notification) {
|
||||
u32 old = m_in_notification;
|
||||
m_in_notification |= u32(mode);
|
||||
for(const auto &n : m_notifiers)
|
||||
n.m_notifier(mode);
|
||||
m_in_notification = old;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void validate_reference_counts() const = 0;
|
||||
|
||||
virtual void remove_passthrough(std::unordered_set<handler_entry *> &handlers) = 0;
|
||||
|
||||
const address_space_config &space_config() const { return m_config; }
|
||||
int data_width() const { return m_config.data_width(); }
|
||||
int addr_width() const { return m_config.addr_width(); }
|
||||
int logaddr_width() const { return m_config.logaddr_width(); }
|
||||
int alignment() const { return m_config.alignment(); }
|
||||
endianness_t endianness() const { return m_config.endianness(); }
|
||||
int addr_shift() const { return m_config.addr_shift(); }
|
||||
u64 unmap() const { return m_unmap; }
|
||||
bool is_octal() const { return m_config.is_octal(); }
|
||||
|
||||
offs_t addrmask() const { return m_addrmask; }
|
||||
u8 addrchars() const { return m_addrchars; }
|
||||
offs_t logaddrmask() const { return m_logaddrmask; }
|
||||
u8 logaddrchars() const { return m_logaddrchars; }
|
||||
|
||||
// debug helpers
|
||||
virtual std::string get_handler_string(read_or_write readorwrite, offs_t byteaddress) const = 0;
|
||||
virtual void dump_maps(std::vector<memory_entry> &read_map, std::vector<memory_entry> &write_map) const = 0;
|
||||
bool log_unmap() const { return m_log_unmap; }
|
||||
void set_log_unmap(bool log) { m_log_unmap = log; }
|
||||
|
||||
// general accessors
|
||||
virtual void accessors(data_accessors &accessors) const = 0;
|
||||
virtual void *get_read_ptr(offs_t address) const = 0;
|
||||
virtual void *get_write_ptr(offs_t address) const = 0;
|
||||
|
||||
// read accessors
|
||||
virtual u8 read_byte(offs_t address) = 0;
|
||||
virtual u16 read_word(offs_t address) = 0;
|
||||
virtual u16 read_word(offs_t address, u16 mask) = 0;
|
||||
virtual u16 read_word_unaligned(offs_t address) = 0;
|
||||
virtual u16 read_word_unaligned(offs_t address, u16 mask) = 0;
|
||||
virtual u32 read_dword(offs_t address) = 0;
|
||||
virtual u32 read_dword(offs_t address, u32 mask) = 0;
|
||||
virtual u32 read_dword_unaligned(offs_t address) = 0;
|
||||
virtual u32 read_dword_unaligned(offs_t address, u32 mask) = 0;
|
||||
virtual u64 read_qword(offs_t address) = 0;
|
||||
virtual u64 read_qword(offs_t address, u64 mask) = 0;
|
||||
virtual u64 read_qword_unaligned(offs_t address) = 0;
|
||||
virtual u64 read_qword_unaligned(offs_t address, u64 mask) = 0;
|
||||
|
||||
// write accessors
|
||||
virtual void write_byte(offs_t address, u8 data) = 0;
|
||||
virtual void write_word(offs_t address, u16 data) = 0;
|
||||
virtual void write_word(offs_t address, u16 data, u16 mask) = 0;
|
||||
virtual void write_word_unaligned(offs_t address, u16 data) = 0;
|
||||
virtual void write_word_unaligned(offs_t address, u16 data, u16 mask) = 0;
|
||||
virtual void write_dword(offs_t address, u32 data) = 0;
|
||||
virtual void write_dword(offs_t address, u32 data, u32 mask) = 0;
|
||||
virtual void write_dword_unaligned(offs_t address, u32 data) = 0;
|
||||
virtual void write_dword_unaligned(offs_t address, u32 data, u32 mask) = 0;
|
||||
virtual void write_qword(offs_t address, u64 data) = 0;
|
||||
virtual void write_qword(offs_t address, u64 data, u64 mask) = 0;
|
||||
virtual void write_qword_unaligned(offs_t address, u64 data) = 0;
|
||||
virtual void write_qword_unaligned(offs_t address, u64 data, u64 mask) = 0;
|
||||
|
||||
// address-to-byte conversion helpers
|
||||
offs_t address_to_byte(offs_t address) const { return m_config.addr2byte(address); }
|
||||
offs_t address_to_byte_end(offs_t address) const { return m_config.addr2byte_end(address); }
|
||||
offs_t byte_to_address(offs_t address) const { return m_config.byte2addr(address); }
|
||||
offs_t byte_to_address_end(offs_t address) const { return m_config.byte2addr_end(address); }
|
||||
|
||||
// umap ranges (short form)
|
||||
offs_t addrmask() const { return m_addrmask; }
|
||||
u8 addrchars() const { return m_addrchars; }
|
||||
offs_t logaddrmask() const { return m_logaddrmask; }
|
||||
u8 logaddrchars() const { return m_logaddrchars; }
|
||||
|
||||
// unmap ranges (short form)
|
||||
void unmap_read(offs_t addrstart, offs_t addrend, offs_t addrmirror = 0) { unmap_generic(addrstart, addrend, addrmirror, read_or_write::READ, false); }
|
||||
void unmap_write(offs_t addrstart, offs_t addrend, offs_t addrmirror = 0) { unmap_generic(addrstart, addrend, addrmirror, read_or_write::WRITE, false); }
|
||||
void unmap_readwrite(offs_t addrstart, offs_t addrend, offs_t addrmirror = 0) { unmap_generic(addrstart, addrend, addrmirror, read_or_write::READWRITE, false); }
|
||||
@ -1427,6 +1337,9 @@ public:
|
||||
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, u32 &data, u32 mem_mask)> tapr, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr);
|
||||
virtual memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tapr, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr);
|
||||
|
||||
// install views
|
||||
void install_view(offs_t addrstart, offs_t addrend, memory_view &view) { install_view(addrstart, addrend, 0, view); }
|
||||
virtual void install_view(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_view &view) = 0;
|
||||
|
||||
// install new-style delegate handlers (short form)
|
||||
void install_read_handler(offs_t addrstart, offs_t addrend, read8_delegate rhandler, u64 unitmask = 0, int cswidth = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth); }
|
||||
@ -1586,6 +1499,154 @@ public:
|
||||
virtual 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) = 0;
|
||||
virtual 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) = 0;
|
||||
|
||||
protected:
|
||||
virtual void unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, bool quiet) = 0;
|
||||
virtual void install_ram_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, void *baseptr) = 0;
|
||||
virtual void install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_bank *rbank, memory_bank *wbank) = 0;
|
||||
|
||||
void populate_map_entry(const address_map_entry &entry, read_or_write readorwrite);
|
||||
void adjust_addresses(offs_t &start, offs_t &end, offs_t &mask, offs_t &mirror) {
|
||||
// adjust start/end/mask values
|
||||
mask &= m_addrmask;
|
||||
start &= ~mirror & m_addrmask;
|
||||
end &= ~mirror & m_addrmask;
|
||||
}
|
||||
|
||||
void check_optimize_all(const char *function, int width, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, offs_t &nstart, offs_t &nend, offs_t &nmask, offs_t &nmirror, u64 &nunitmask, int &ncswidth);
|
||||
void check_optimize_mirror(const char *function, offs_t addrstart, offs_t addrend, offs_t addrmirror, offs_t &nstart, offs_t &nend, offs_t &nmask, offs_t &nmirror);
|
||||
void check_address(const char *function, offs_t addrstart, offs_t addrend);
|
||||
|
||||
address_space_installer(const address_space_config &config, memory_manager &manager)
|
||||
: m_config(config),
|
||||
m_manager(manager),
|
||||
m_addrmask(make_bitmask<offs_t>(m_config.addr_width())),
|
||||
m_logaddrmask(make_bitmask<offs_t>(m_config.logaddr_width())),
|
||||
m_addrchars((m_config.addr_width() + 3) / 4),
|
||||
m_logaddrchars((m_config.logaddr_width() + 3) / 4)
|
||||
{}
|
||||
|
||||
const address_space_config &m_config; // configuration of this space
|
||||
memory_manager & m_manager; // reference to the owning manager
|
||||
offs_t m_addrmask; // physical address mask
|
||||
offs_t m_logaddrmask; // logical address mask
|
||||
u8 m_addrchars; // number of characters to use for physical addresses
|
||||
u8 m_logaddrchars; // number of characters to use for logical addresses
|
||||
};
|
||||
|
||||
// address_space holds live information about an address space
|
||||
class address_space : public address_space_installer
|
||||
{
|
||||
friend class memory_bank;
|
||||
friend class memory_block;
|
||||
template<int Width, int AddrShift, endianness_t Endian> friend class handler_entry_read_unmapped;
|
||||
template<int Width, int AddrShift, endianness_t Endian> friend class handler_entry_write_unmapped;
|
||||
|
||||
struct notifier_t {
|
||||
std::function<void (read_or_write)> m_notifier;
|
||||
int m_id;
|
||||
};
|
||||
|
||||
protected:
|
||||
// construction/destruction
|
||||
address_space(memory_manager &manager, device_memory_interface &memory, int spacenum);
|
||||
|
||||
public:
|
||||
virtual ~address_space();
|
||||
|
||||
// getters
|
||||
device_t &device() const { return m_device; }
|
||||
const char *name() const { return m_name; }
|
||||
int spacenum() const { return m_spacenum; }
|
||||
address_map *map() const { return m_map.get(); }
|
||||
|
||||
template<int Width, int AddrShift, endianness_t Endian> void cache(emu::detail::memory_access_cache<Width, AddrShift, Endian> &v) {
|
||||
if(AddrShift != m_config.addr_shift())
|
||||
fatalerror("Requesting cache() with address shift %d while the config says %d\n", AddrShift, m_config.addr_shift());
|
||||
if(8 << Width != m_config.data_width())
|
||||
fatalerror("Requesting cache() with data width %d while the config says %d\n", 8 << Width, m_config.data_width());
|
||||
if(Endian != m_config.endianness())
|
||||
fatalerror("Requesting cache() with endianness %s while the config says %s\n",
|
||||
endianness_names[Endian], endianness_names[m_config.endianness()]);
|
||||
|
||||
v.set(this, get_cache_info());
|
||||
}
|
||||
|
||||
template<int Level, int Width, int AddrShift, endianness_t Endian> void specific(emu::detail::memory_access_specific<Level, Width, AddrShift, Endian> &v) {
|
||||
if(Level != emu::detail::handler_entry_dispatch_level(m_config.addr_width()))
|
||||
fatalerror("Requesting specific() with wrong level, bad address width (the config says %d)\n", m_config.addr_width());
|
||||
if(AddrShift != m_config.addr_shift())
|
||||
fatalerror("Requesting specific() with address shift %d while the config says %d\n", AddrShift, m_config.addr_shift());
|
||||
if(8 << Width != m_config.data_width())
|
||||
fatalerror("Requesting specific() with data width %d while the config says %d\n", 8 << Width, m_config.data_width());
|
||||
if(Endian != m_config.endianness())
|
||||
fatalerror("Requesting spefific() with endianness %s while the config says %s\n",
|
||||
endianness_names[Endian], endianness_names[m_config.endianness()]);
|
||||
|
||||
v.set(this, get_specific_info());
|
||||
}
|
||||
|
||||
int add_change_notifier(std::function<void (read_or_write)> n);
|
||||
void remove_change_notifier(int id);
|
||||
|
||||
void invalidate_caches(read_or_write mode) {
|
||||
if(u32(mode) & ~m_in_notification) {
|
||||
u32 old = m_in_notification;
|
||||
m_in_notification |= u32(mode);
|
||||
for(const auto &n : m_notifiers)
|
||||
n.m_notifier(mode);
|
||||
m_in_notification = old;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void validate_reference_counts() const = 0;
|
||||
|
||||
virtual void remove_passthrough(std::unordered_set<handler_entry *> &handlers) = 0;
|
||||
|
||||
u64 unmap() const { return m_unmap; }
|
||||
|
||||
memory_passthrough_handler *make_mph();
|
||||
|
||||
// debug helpers
|
||||
virtual std::string get_handler_string(read_or_write readorwrite, offs_t byteaddress) const = 0;
|
||||
virtual void dump_maps(std::vector<memory_entry> &read_map, std::vector<memory_entry> &write_map) const = 0;
|
||||
bool log_unmap() const { return m_log_unmap; }
|
||||
void set_log_unmap(bool log) { m_log_unmap = log; }
|
||||
|
||||
// general accessors
|
||||
virtual void accessors(data_accessors &accessors) const = 0;
|
||||
virtual void *get_read_ptr(offs_t address) const = 0;
|
||||
virtual void *get_write_ptr(offs_t address) const = 0;
|
||||
|
||||
// read accessors
|
||||
virtual u8 read_byte(offs_t address) = 0;
|
||||
virtual u16 read_word(offs_t address) = 0;
|
||||
virtual u16 read_word(offs_t address, u16 mask) = 0;
|
||||
virtual u16 read_word_unaligned(offs_t address) = 0;
|
||||
virtual u16 read_word_unaligned(offs_t address, u16 mask) = 0;
|
||||
virtual u32 read_dword(offs_t address) = 0;
|
||||
virtual u32 read_dword(offs_t address, u32 mask) = 0;
|
||||
virtual u32 read_dword_unaligned(offs_t address) = 0;
|
||||
virtual u32 read_dword_unaligned(offs_t address, u32 mask) = 0;
|
||||
virtual u64 read_qword(offs_t address) = 0;
|
||||
virtual u64 read_qword(offs_t address, u64 mask) = 0;
|
||||
virtual u64 read_qword_unaligned(offs_t address) = 0;
|
||||
virtual u64 read_qword_unaligned(offs_t address, u64 mask) = 0;
|
||||
|
||||
// write accessors
|
||||
virtual void write_byte(offs_t address, u8 data) = 0;
|
||||
virtual void write_word(offs_t address, u16 data) = 0;
|
||||
virtual void write_word(offs_t address, u16 data, u16 mask) = 0;
|
||||
virtual void write_word_unaligned(offs_t address, u16 data) = 0;
|
||||
virtual void write_word_unaligned(offs_t address, u16 data, u16 mask) = 0;
|
||||
virtual void write_dword(offs_t address, u32 data) = 0;
|
||||
virtual void write_dword(offs_t address, u32 data, u32 mask) = 0;
|
||||
virtual void write_dword_unaligned(offs_t address, u32 data) = 0;
|
||||
virtual void write_dword_unaligned(offs_t address, u32 data, u32 mask) = 0;
|
||||
virtual void write_qword(offs_t address, u64 data) = 0;
|
||||
virtual void write_qword(offs_t address, u64 data, u64 mask) = 0;
|
||||
virtual void write_qword_unaligned(offs_t address, u64 data) = 0;
|
||||
virtual void write_qword_unaligned(offs_t address, u64 data, u64 mask) = 0;
|
||||
|
||||
// setup
|
||||
void prepare_map();
|
||||
void populate_from_map(address_map *map = nullptr);
|
||||
@ -1593,32 +1654,23 @@ public:
|
||||
template<int Width, int AddrShift, endianness_t Endian> handler_entry_read_unmapped <Width, AddrShift, Endian> *get_unmap_r() const { return static_cast<handler_entry_read_unmapped <Width, AddrShift, Endian> *>(m_unmap_r); }
|
||||
template<int Width, int AddrShift, endianness_t Endian> handler_entry_write_unmapped<Width, AddrShift, Endian> *get_unmap_w() const { return static_cast<handler_entry_write_unmapped<Width, AddrShift, Endian> *>(m_unmap_w); }
|
||||
|
||||
handler_entry *unmap_r() const { return m_unmap_r; }
|
||||
handler_entry *unmap_w() const { return m_unmap_w; }
|
||||
handler_entry *nop_r() const { return m_nop_r; }
|
||||
handler_entry *nop_w() const { return m_nop_w; }
|
||||
|
||||
protected:
|
||||
// internal helpers
|
||||
virtual std::pair<void *, void *> get_cache_info() = 0;
|
||||
virtual std::pair<const void *, const void *> get_specific_info() = 0;
|
||||
|
||||
void populate_map_entry(const address_map_entry &entry, read_or_write readorwrite);
|
||||
virtual void unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, bool quiet) = 0;
|
||||
virtual void install_ram_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, void *baseptr) = 0;
|
||||
virtual void install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_bank *rbank, memory_bank *wbank) = 0;
|
||||
void adjust_addresses(offs_t &start, offs_t &end, offs_t &mask, offs_t &mirror);
|
||||
void check_optimize_all(const char *function, int width, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, offs_t &nstart, offs_t &nend, offs_t &nmask, offs_t &nmirror, u64 &nunitmask, int &ncswidth);
|
||||
void check_optimize_mirror(const char *function, offs_t addrstart, offs_t addrend, offs_t addrmirror, offs_t &nstart, offs_t &nend, offs_t &nmask, offs_t &nmirror);
|
||||
void check_address(const char *function, offs_t addrstart, offs_t addrend);
|
||||
|
||||
// private state
|
||||
const address_space_config &m_config; // configuration of this space
|
||||
device_t & m_device; // reference to the owning device
|
||||
std::unique_ptr<address_map> m_map; // original memory map
|
||||
offs_t m_addrmask; // physical address mask
|
||||
offs_t m_logaddrmask; // logical address mask
|
||||
u64 m_unmap; // unmapped value
|
||||
int m_spacenum; // address space index
|
||||
bool m_log_unmap; // log unmapped accesses in this space?
|
||||
const char * m_name; // friendly name of the address space
|
||||
u8 m_addrchars; // number of characters to use for physical addresses
|
||||
u8 m_logaddrchars; // number of characters to use for logical addresses
|
||||
|
||||
handler_entry *m_unmap_r;
|
||||
handler_entry *m_unmap_w;
|
||||
@ -1631,7 +1683,6 @@ protected:
|
||||
std::vector<notifier_t> m_notifiers; // notifier list for address map change
|
||||
int m_notifier_id; // next notifier id
|
||||
u32 m_in_notification; // notification(s) currently being done
|
||||
memory_manager & m_manager; // reference to the owning manager
|
||||
};
|
||||
|
||||
|
||||
@ -1748,6 +1799,79 @@ private:
|
||||
|
||||
|
||||
|
||||
// ======================> memory_view
|
||||
|
||||
// a memory view allows switching between submaps in the map
|
||||
class memory_view
|
||||
{
|
||||
template<int Level, int Width, int AddrShift, endianness_t Endian> friend class address_space_specific;
|
||||
template<int Level, int Width, int AddrShift, endianness_t Endian> friend class memory_view_entry_specific;
|
||||
template<int HighBits, int Width, int AddrShift, endianness_t Endian> friend class handler_entry_write_dispatch;
|
||||
template<int HighBits, int Width, int AddrShift, endianness_t Endian> friend class handler_entry_read_dispatch;
|
||||
friend class memory_view_entry;
|
||||
friend class address_map_entry;
|
||||
friend class address_map;
|
||||
|
||||
DISABLE_COPYING(memory_view);
|
||||
|
||||
public:
|
||||
class memory_view_entry : public address_space_installer {
|
||||
public:
|
||||
virtual ~memory_view_entry() = default;
|
||||
|
||||
address_map_entry &operator()(offs_t start, offs_t end);
|
||||
|
||||
virtual void populate_from_map(address_map *map = nullptr) = 0;
|
||||
|
||||
std::string key() const;
|
||||
|
||||
protected:
|
||||
memory_view &m_view;
|
||||
std::unique_ptr<address_map> m_map;
|
||||
int m_id;
|
||||
|
||||
memory_view_entry(const address_space_config &config, memory_manager &manager, memory_view &view, int id);
|
||||
|
||||
void 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);
|
||||
void 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);
|
||||
void check_range_address(const char *function, offs_t addrstart, offs_t addrend);
|
||||
};
|
||||
|
||||
memory_view(device_t &device, std::string name);
|
||||
|
||||
memory_view_entry &operator[](int slot);
|
||||
|
||||
void select(int entry);
|
||||
void disable();
|
||||
|
||||
const std::string &name() const { return m_name; }
|
||||
|
||||
private:
|
||||
|
||||
device_t & m_device;
|
||||
std::string m_name;
|
||||
std::map<int, int> m_entry_mapping;
|
||||
std::vector<std::unique_ptr<memory_view_entry>> m_entries;
|
||||
const address_space_config * m_config;
|
||||
offs_t m_addrstart;
|
||||
offs_t m_addrend;
|
||||
address_space * m_space;
|
||||
handler_entry * m_handler_read;
|
||||
handler_entry * m_handler_write;
|
||||
std::function<void (int)> m_select_a;
|
||||
std::function<void (int)> m_select_u;
|
||||
int m_cur_id;
|
||||
int m_cur_slot;
|
||||
std::string m_context;
|
||||
|
||||
void initialize_from_address_map(offs_t addrstart, offs_t addrend, const address_space_config &config);
|
||||
std::pair<handler_entry *, handler_entry *> make_handlers(address_space &space, offs_t addrstart, offs_t addrend);
|
||||
void make_subdispatch(std::string context);
|
||||
int id_to_slot(int id) const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// ======================> memory_manager
|
||||
|
||||
// holds internal state for the memory system
|
||||
@ -1772,7 +1896,7 @@ public:
|
||||
const std::unordered_map<std::string, std::unique_ptr<memory_share>> &shares() const { return m_sharelist; }
|
||||
|
||||
// anonymous memory zones
|
||||
void *anonymous_alloc(address_space &space, size_t bytes, u8 width, offs_t start, offs_t end);
|
||||
void *anonymous_alloc(address_space &space, size_t bytes, u8 width, offs_t start, offs_t end, const std::string &key = "");
|
||||
|
||||
// shares
|
||||
memory_share *share_alloc(device_t &dev, std::string name, u8 width, size_t bytes, endianness_t endianness);
|
||||
|
1200
src/emu/emumem_aspace.cpp
Normal file
1200
src/emu/emumem_aspace.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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>;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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>;
|
||||
|
@ -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++)
|
||||
|
@ -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;
|
||||
|
995
src/emu/emumem_mview.cpp
Normal file
995
src/emu/emumem_mview.cpp
Normal file
@ -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);
|
||||
}
|
@ -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");
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user