Implement views, which are essentially bankdevs integrated into the

memory map system. [O. Galibert]
This commit is contained in:
Olivier Galibert 2020-11-12 15:52:20 +01:00
parent 8d4559070f
commit 574daf4e49
21 changed files with 3325 additions and 1598 deletions

View File

@ -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.

View File

@ -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",

View File

@ -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;
}

View File

@ -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

View File

@ -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");
}

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -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);
}

View File

@ -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>;

View File

@ -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);

View File

@ -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);
}

View File

@ -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>;

View File

@ -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++)

View File

@ -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
View 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);
}

View File

@ -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");

View File

@ -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;

View File

@ -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);
}