summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/emumem.h
diff options
context:
space:
mode:
author Olivier Galibert <galibert@pobox.com>2022-12-20 22:41:19 +0100
committer Olivier Galibert <galibert@pobox.com>2023-02-22 11:29:48 +0100
commit0b6732cf9163902691fd1bdda5436460f19ef6f4 (patch)
tree394eaaf2ecfd6a4578b34855b63c3407109a62d9 /src/emu/emumem.h
parent82814d3b50831a1d9a67ca26a317b31a76bb904e (diff)
emumem: First try at wait states
Diffstat (limited to 'src/emu/emumem.h')
-rw-r--r--src/emu/emumem.h73
1 files changed, 67 insertions, 6 deletions
diff --git a/src/emu/emumem.h b/src/emu/emumem.h
index b9a8ed08763..7fa9f3481ff 100644
--- a/src/emu/emumem.h
+++ b/src/emu/emumem.h
@@ -173,6 +173,12 @@ using write32smo_delegate = device_delegate<void (u32)>;
using write64smo_delegate = device_delegate<void (u64)>;
+// =====================-> Wait states delegates
+
+using ws_time_delegate = device_delegate<u64 (offs_t, u64)>;
+using ws_delay_delegate = device_delegate<u32 (offs_t)>;
+
+
namespace emu::detail {
// TODO: replace with std::void_t when we move to C++17
@@ -518,11 +524,14 @@ class handler_entry
public:
// Typing flags (low 16 bits are for the user)
- static constexpr u32 F_UNMAP = 0x00010000; // the unmapped memory accessed handler
- static constexpr u32 F_DISPATCH = 0x00020000; // handler that forwards the access to other handlers
- static constexpr u32 F_UNITS = 0x00040000; // handler that merges/splits an access among multiple handlers (unitmask support)
- static constexpr u32 F_PASSTHROUGH = 0x00080000; // handler that passes through the request to another handler
- static constexpr u32 F_VIEW = 0x00100000; // handler for a view (kinda like dispatch except not entirely)
+ static constexpr u32 F_UNMAP = 0x00010000; // the unmapped memory accessed handler
+ static constexpr u32 F_DISPATCH = 0x00020000; // handler that forwards the access to other handlers
+ static constexpr u32 F_UNITS = 0x00040000; // handler that merges/splits an access among multiple handlers (unitmask support)
+ static constexpr u32 F_VIEW = 0x00080000; // handler for a view (kinda like dispatch except not entirely)
+ static constexpr u32 F_PT_BITS = 24; // position of the 4-bit priority for a passthrough handler. The highest the priority the earlier it is called in the chain. 0 = not passthrough
+ static constexpr u32 F_PT_REPLACE = 1 << F_PT_BITS; // a passthrough with a odd priority can only happen once in a path
+
+ static constexpr u32 f_pt(u32 priority) { return (priority << F_PT_BITS); }
// Start/end of range flags
static constexpr u8 START = 1;
@@ -552,7 +561,8 @@ public:
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; }
+ inline bool is_passthrough() const { return f_get_pt() != 0; }
+ inline u32 f_get_pt() const { return (m_flags >> F_PT_BITS) & 15; }
virtual void dump_map(std::vector<memory_entry> &map) const;
@@ -611,6 +621,7 @@ public:
~handler_entry_read() {}
virtual uX read(offs_t offset, uX mem_mask) const = 0;
+ virtual uX read_interruptible(offs_t offset, uX mem_mask) const = 0;
virtual std::pair<uX, u16> read_flags(offs_t offset, uX mem_mask) const = 0;
virtual u16 lookup_flags(offs_t offset, uX mem_mask) const = 0;
virtual void *get_ptr(offs_t offset) const;
@@ -685,6 +696,7 @@ public:
virtual ~handler_entry_write() {}
virtual void write(offs_t offset, uX data, uX mem_mask) const = 0;
+ virtual void write_interruptible(offs_t offset, uX data, uX mem_mask) const = 0;
virtual u16 write_flags(offs_t offset, uX data, uX mem_mask) const = 0;
virtual u16 lookup_flags(offs_t offset, uX mem_mask) const = 0;
virtual void *get_ptr(offs_t offset) const;
@@ -1605,6 +1617,21 @@ template<int Level, int Width, int AddrShift> u16 dispatch_lookup_write_flags(of
}
+
+template<int Level, int Width, int AddrShift> typename emu::detail::handler_entry_size<Width>::uX dispatch_read_interruptible(offs_t mask, offs_t offset, typename emu::detail::handler_entry_size<Width>::uX mem_mask, const handler_entry_read<Width, AddrShift> *const *dispatch)
+{
+ static constexpr u32 LowBits = emu::detail::handler_entry_dispatch_level_to_lowbits(Level, Width, AddrShift);
+ return dispatch[(offset & mask) >> LowBits]->read_interruptible(offset, mem_mask);
+}
+
+
+template<int Level, int Width, int AddrShift> void dispatch_write_interruptible(offs_t mask, offs_t offset, typename emu::detail::handler_entry_size<Width>::uX data, typename emu::detail::handler_entry_size<Width>::uX mem_mask, const handler_entry_write<Width, AddrShift> *const *dispatch)
+{
+ static constexpr u32 LowBits = emu::detail::handler_entry_dispatch_level_to_lowbits(Level, Width, AddrShift);
+ return dispatch[(offset & mask) >> LowBits]->write_interruptible(offset, data, mem_mask);
+}
+
+
// ======================> memory_access_specific
// memory_access_specific does uncached but faster accesses by shortcutting the address_space virtual call
@@ -1725,6 +1752,14 @@ public:
u16 lookup_write_qword_unaligned_flags(offs_t address) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 3, false>(lwopf(), address, 0xffffffffffffffffU); }
u16 lookup_write_qword_unaligned_flags(offs_t address, u64 mask) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 3, false>(lwopf(), address, mask); }
+ NativeType read_interruptible(offs_t address, NativeType mask = ~NativeType(0)) {
+ return dispatch_read_interruptible<Level, Width, AddrShift>(offs_t(-1), address & m_addrmask, mask, m_dispatch_read);
+ }
+
+ void write_interruptible(offs_t address, NativeType data, NativeType mask = ~NativeType(0)) {
+ dispatch_write_interruptible<Level, Width, AddrShift>(offs_t(-1), address & m_addrmask, data, mask, m_dispatch_write);
+ }
+
private:
address_space * m_space;
@@ -2102,6 +2137,28 @@ public:
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 wait state handlers
+ void install_read_before_time(offs_t addrstart, offs_t addrend, ws_time_delegate ws) { install_read_before_time(addrstart, addrend, 0, ws); }
+ virtual void install_read_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws) = 0;
+ void install_read_before_delay(offs_t addrstart, offs_t addrend, ws_delay_delegate ws) { install_read_before_delay(addrstart, addrend, 0, ws); }
+ virtual void install_read_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) = 0;
+ void install_read_after_delay(offs_t addrstart, offs_t addrend, ws_delay_delegate ws) { install_read_after_delay(addrstart, addrend, 0, ws); }
+ virtual void install_read_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) = 0;
+
+ void install_write_before_time(offs_t addrstart, offs_t addrend, ws_time_delegate ws) { install_write_before_time(addrstart, addrend, 0, ws); }
+ virtual void install_write_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws) = 0;
+ void install_write_before_delay(offs_t addrstart, offs_t addrend, ws_delay_delegate ws) { install_write_before_delay(addrstart, addrend, 0, ws); }
+ virtual void install_write_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) = 0;
+ void install_write_after_delay(offs_t addrstart, offs_t addrend, ws_delay_delegate ws) { install_write_after_delay(addrstart, addrend, 0, ws); }
+ virtual void install_write_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) = 0;
+
+ void install_readwrite_before_time(offs_t addrstart, offs_t addrend, ws_time_delegate ws) { install_readwrite_before_time(addrstart, addrend, 0, ws); }
+ virtual void install_readwrite_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws) = 0;
+ void install_readwrite_before_delay(offs_t addrstart, offs_t addrend, ws_delay_delegate ws) { install_readwrite_before_delay(addrstart, addrend, 0, ws); }
+ virtual void install_readwrite_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) = 0;
+ void install_readwrite_after_delay(offs_t addrstart, offs_t addrend, ws_delay_delegate ws) { install_readwrite_after_delay(addrstart, addrend, 0, ws); }
+ virtual void install_readwrite_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) = 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, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); }
void install_write_handler(offs_t addrstart, offs_t addrend, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); }
@@ -2360,6 +2417,7 @@ public:
u64 unmap() const { return m_unmap; }
std::shared_ptr<emu::detail::memory_passthrough_handler_impl> make_mph(memory_passthrough_handler *mph);
+ std::shared_ptr<emu::detail::memory_passthrough_handler_impl> get_default_mpl() { return m_default_mpl; }
// debug helpers
virtual std::string get_handler_string(read_or_write readorwrite, offs_t byteaddress) const = 0;
@@ -2440,6 +2498,9 @@ protected:
util::notifier<read_or_write> m_notifiers; // notifier list for address map change
u32 m_in_notification; // notification(s) currently being done
+
+ // passthrough handler used for wait states
+ std::shared_ptr<emu::detail::memory_passthrough_handler_impl> m_default_mpl;
};