1 // license:BSD-3-Clause 2 // copyright-holders:Aaron Giles,Olivier Galibert 3 /*************************************************************************** 4 5 emumem.h 6 7 Functions which handle device memory accesses. 8 9 ***************************************************************************/ 10 11 #pragma once 12 13 #ifndef __EMU_H__ 14 #error Dont include this file directly; include emu.h instead. 15 #endif 16 17 #ifndef MAME_EMU_EMUMEM_H 18 #define MAME_EMU_EMUMEM_H 19 20 #include <type_traits> 21 22 using s8 = std::int8_t; 23 using u8 = std::uint8_t; 24 using s16 = std::int16_t; 25 using u16 = std::uint16_t; 26 using s32 = std::int32_t; 27 using u32 = std::uint32_t; 28 using s64 = std::int64_t; 29 using u64 = std::uint64_t; 30 31 32 //************************************************************************** 33 // CONSTANTS 34 //************************************************************************** 35 36 // address space names for common use 37 constexpr int AS_PROGRAM = 0; // program address space 38 constexpr int AS_DATA = 1; // data address space 39 constexpr int AS_IO = 2; // I/O address space 40 constexpr int AS_OPCODES = 3; // (decrypted) opcodes, when separate from data accesses 41 42 // read or write constants 43 enum class read_or_write 44 { 45 READ = 1, 46 WRITE = 2, 47 READWRITE = 3 48 }; 49 50 51 52 //************************************************************************** 53 // TYPE DEFINITIONS 54 //************************************************************************** 55 56 // offsets and addresses are 32-bit (for now...) 57 using offs_t = u32; 58 59 // address map constructors are delegates that build up an address_map 60 using address_map_constructor = named_delegate<void (address_map &)>; 61 62 // struct with function pointers for accessors; use is generally discouraged unless necessary 63 struct data_accessors 64 { 65 u8 (*read_byte)(address_space &space, offs_t address); 66 u16 (*read_word)(address_space &space, offs_t address); 67 u16 (*read_word_masked)(address_space &space, offs_t address, u16 mask); 68 u32 (*read_dword)(address_space &space, offs_t address); 69 u32 (*read_dword_masked)(address_space &space, offs_t address, u32 mask); 70 u64 (*read_qword)(address_space &space, offs_t address); 71 u64 (*read_qword_masked)(address_space &space, offs_t address, u64 mask); 72 73 void (*write_byte)(address_space &space, offs_t address, u8 data); 74 void (*write_word)(address_space &space, offs_t address, u16 data); 75 void (*write_word_masked)(address_space &space, offs_t address, u16 data, u16 mask); 76 void (*write_dword)(address_space &space, offs_t address, u32 data); 77 void (*write_dword_masked)(address_space &space, offs_t address, u32 data, u32 mask); 78 void (*write_qword)(address_space &space, offs_t address, u64 data); 79 void (*write_qword_masked)(address_space &space, offs_t address, u64 data, u64 mask); 80 }; 81 82 // a line in the memory structure dump 83 struct memory_entry { 84 offs_t start, end; 85 class handler_entry *entry; 86 }; 87 88 89 // ======================> read_delegate 90 91 // declare delegates for each width 92 using read8_delegate = device_delegate<u8 (address_space &, offs_t, u8 )>; 93 using read16_delegate = device_delegate<u16 (address_space &, offs_t, u16)>; 94 using read32_delegate = device_delegate<u32 (address_space &, offs_t, u32)>; 95 using read64_delegate = device_delegate<u64 (address_space &, offs_t, u64)>; 96 97 using read8m_delegate = device_delegate<u8 (address_space &, offs_t)>; 98 using read16m_delegate = device_delegate<u16 (address_space &, offs_t)>; 99 using read32m_delegate = device_delegate<u32 (address_space &, offs_t)>; 100 using read64m_delegate = device_delegate<u64 (address_space &, offs_t)>; 101 102 using read8s_delegate = device_delegate<u8 (offs_t, u8 )>; 103 using read16s_delegate = device_delegate<u16 (offs_t, u16)>; 104 using read32s_delegate = device_delegate<u32 (offs_t, u32)>; 105 using read64s_delegate = device_delegate<u64 (offs_t, u64)>; 106 107 using read8sm_delegate = device_delegate<u8 (offs_t)>; 108 using read16sm_delegate = device_delegate<u16 (offs_t)>; 109 using read32sm_delegate = device_delegate<u32 (offs_t)>; 110 using read64sm_delegate = device_delegate<u64 (offs_t)>; 111 112 using read8mo_delegate = device_delegate<u8 (address_space &)>; 113 using read16mo_delegate = device_delegate<u16 (address_space &)>; 114 using read32mo_delegate = device_delegate<u32 (address_space &)>; 115 using read64mo_delegate = device_delegate<u64 (address_space &)>; 116 117 using read8smo_delegate = device_delegate<u8 ()>; 118 using read16smo_delegate = device_delegate<u16 ()>; 119 using read32smo_delegate = device_delegate<u32 ()>; 120 using read64smo_delegate = device_delegate<u64 ()>; 121 122 123 // ======================> write_delegate 124 125 // declare delegates for each width 126 using write8_delegate = device_delegate<void (address_space &, offs_t, u8, u8 )>; 127 using write16_delegate = device_delegate<void (address_space &, offs_t, u16, u16)>; 128 using write32_delegate = device_delegate<void (address_space &, offs_t, u32, u32)>; 129 using write64_delegate = device_delegate<void (address_space &, offs_t, u64, u64)>; 130 131 using write8m_delegate = device_delegate<void (address_space &, offs_t, u8 )>; 132 using write16m_delegate = device_delegate<void (address_space &, offs_t, u16)>; 133 using write32m_delegate = device_delegate<void (address_space &, offs_t, u32)>; 134 using write64m_delegate = device_delegate<void (address_space &, offs_t, u64)>; 135 136 using write8s_delegate = device_delegate<void (offs_t, u8, u8 )>; 137 using write16s_delegate = device_delegate<void (offs_t, u16, u16)>; 138 using write32s_delegate = device_delegate<void (offs_t, u32, u32)>; 139 using write64s_delegate = device_delegate<void (offs_t, u64, u64)>; 140 141 using write8sm_delegate = device_delegate<void (offs_t, u8 )>; 142 using write16sm_delegate = device_delegate<void (offs_t, u16)>; 143 using write32sm_delegate = device_delegate<void (offs_t, u32)>; 144 using write64sm_delegate = device_delegate<void (offs_t, u64)>; 145 146 using write8mo_delegate = device_delegate<void (address_space &, u8 )>; 147 using write16mo_delegate = device_delegate<void (address_space &, u16)>; 148 using write32mo_delegate = device_delegate<void (address_space &, u32)>; 149 using write64mo_delegate = device_delegate<void (address_space &, u64)>; 150 151 using write8smo_delegate = device_delegate<void (u8 )>; 152 using write16smo_delegate = device_delegate<void (u16)>; 153 using write32smo_delegate = device_delegate<void (u32)>; 154 using write64smo_delegate = device_delegate<void (u64)>; 155 156 157 namespace emu { namespace detail { 158 159 // TODO: replace with std::void_t when we move to C++17 160 template <typename... T> struct void_wrapper { using type = void; }; 161 template <typename... T> using void_t = typename void_wrapper<T...>::type; 162 163 template <typename D, typename T, typename Enable = void> struct rw_device_class { }; 164 165 template <typename D, typename T, typename Ret, typename... Params> 166 struct rw_device_class<D, Ret (T::*)(Params...), std::enable_if_t<std::is_constructible<D, device_t &, const char *, Ret (T::*)(Params...), const char *>::value> > { using type = T; }; 167 template <typename D, typename T, typename Ret, typename... Params> 168 struct rw_device_class<D, Ret (T::*)(Params...) const, std::enable_if_t<std::is_constructible<D, device_t &, const char *, Ret (T::*)(Params...) const, const char *>::value> > { using type = T; }; 169 template <typename D, typename T, typename Ret, typename... Params> 170 struct rw_device_class<D, Ret (*)(T &, Params...), std::enable_if_t<std::is_constructible<D, device_t &, const char *, Ret (*)(T &, Params...), const char *>::value> > { using type = T; }; 171 172 template <typename D, typename T> using rw_device_class_t = typename rw_device_class<D, T>::type; 173 174 template <typename T, typename Enable = void> struct rw_delegate_type; 175 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<read8_delegate, std::remove_reference_t<T> > > > { using type = read8_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 176 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<read16_delegate, std::remove_reference_t<T> > > > { using type = read16_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 177 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<read32_delegate, std::remove_reference_t<T> > > > { using type = read32_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 178 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<read64_delegate, std::remove_reference_t<T> > > > { using type = read64_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 179 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<read8m_delegate, std::remove_reference_t<T> > > > { using type = read8m_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 180 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<read16m_delegate, std::remove_reference_t<T> > > > { using type = read16m_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 181 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<read32m_delegate, std::remove_reference_t<T> > > > { using type = read32m_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 182 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<read64m_delegate, std::remove_reference_t<T> > > > { using type = read64m_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 183 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<read8s_delegate, std::remove_reference_t<T> > > > { using type = read8s_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 184 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<read16s_delegate, std::remove_reference_t<T> > > > { using type = read16s_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 185 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<read32s_delegate, std::remove_reference_t<T> > > > { using type = read32s_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 186 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<read64s_delegate, std::remove_reference_t<T> > > > { using type = read64s_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 187 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<read8sm_delegate, std::remove_reference_t<T> > > > { using type = read8sm_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 188 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<read16sm_delegate, std::remove_reference_t<T> > > > { using type = read16sm_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 189 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<read32sm_delegate, std::remove_reference_t<T> > > > { using type = read32sm_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 190 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<read64sm_delegate, std::remove_reference_t<T> > > > { using type = read64sm_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 191 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<read8mo_delegate, std::remove_reference_t<T> > > > { using type = read8mo_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 192 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<read16mo_delegate, std::remove_reference_t<T> > > > { using type = read16mo_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 193 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<read32mo_delegate, std::remove_reference_t<T> > > > { using type = read32mo_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 194 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<read64mo_delegate, std::remove_reference_t<T> > > > { using type = read64mo_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 195 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<read8smo_delegate, std::remove_reference_t<T> > > > { using type = read8smo_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 196 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<read16smo_delegate, std::remove_reference_t<T> > > > { using type = read16smo_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 197 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<read32smo_delegate, std::remove_reference_t<T> > > > { using type = read32smo_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 198 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<read64smo_delegate, std::remove_reference_t<T> > > > { using type = read64smo_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 199 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<write8_delegate, std::remove_reference_t<T> > > > { using type = write8_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 200 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<write16_delegate, std::remove_reference_t<T> > > > { using type = write16_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 201 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<write32_delegate, std::remove_reference_t<T> > > > { using type = write32_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 202 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<write64_delegate, std::remove_reference_t<T> > > > { using type = write64_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 203 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<write8m_delegate, std::remove_reference_t<T> > > > { using type = write8m_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 204 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<write16m_delegate, std::remove_reference_t<T> > > > { using type = write16m_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 205 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<write32m_delegate, std::remove_reference_t<T> > > > { using type = write32m_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 206 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<write64m_delegate, std::remove_reference_t<T> > > > { using type = write64m_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 207 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<write8s_delegate, std::remove_reference_t<T> > > > { using type = write8s_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 208 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<write16s_delegate, std::remove_reference_t<T> > > > { using type = write16s_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 209 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<write32s_delegate, std::remove_reference_t<T> > > > { using type = write32s_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 210 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<write64s_delegate, std::remove_reference_t<T> > > > { using type = write64s_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 211 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<write8sm_delegate, std::remove_reference_t<T> > > > { using type = write8sm_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 212 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<write16sm_delegate, std::remove_reference_t<T> > > > { using type = write16sm_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 213 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<write32sm_delegate, std::remove_reference_t<T> > > > { using type = write32sm_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 214 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<write64sm_delegate, std::remove_reference_t<T> > > > { using type = write64sm_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 215 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<write8mo_delegate, std::remove_reference_t<T> > > > { using type = write8mo_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 216 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<write16mo_delegate, std::remove_reference_t<T> > > > { using type = write16mo_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 217 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<write32mo_delegate, std::remove_reference_t<T> > > > { using type = write32mo_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 218 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<write64mo_delegate, std::remove_reference_t<T> > > > { using type = write64mo_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 219 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<write8smo_delegate, std::remove_reference_t<T> > > > { using type = write8smo_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 220 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<write16smo_delegate, std::remove_reference_t<T> > > > { using type = write16smo_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 221 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<write32smo_delegate, std::remove_reference_t<T> > > > { using type = write32smo_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 222 template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<write64smo_delegate, std::remove_reference_t<T> > > > { using type = write64smo_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; 223 template <typename T> using rw_delegate_type_t = typename rw_delegate_type<T>::type; 224 template <typename T> using rw_delegate_device_class_t = typename rw_delegate_type<T>::device_class; 225 226 227 template <typename T> 228 inline rw_delegate_type_t<T> make_delegate(device_t &base, char const *tag, T &&func, char const *name) 229 { return rw_delegate_type_t<T>(base, tag, std::forward<T>(func), name); } 230 231 template <typename T> 232 inline rw_delegate_type_t<T> make_delegate(rw_delegate_device_class_t<T> &object, T &&func, char const *name) 233 { return rw_delegate_type_t<T>(object, std::forward<T>(func), name); } 234 235 236 template <typename L> 237 inline std::enable_if_t<std::is_constructible<read8_delegate, device_t &, L, const char *>::value, read8_delegate> make_lr8_delegate(device_t &owner, L &&l, const char *name) 238 { return read8_delegate(owner, std::forward<L>(l), name); } 239 240 template <typename L> 241 inline std::enable_if_t<std::is_constructible<read8m_delegate, device_t &, L, const char *>::value, read8m_delegate> make_lr8_delegate(device_t &owner, L &&l, const char *name) 242 { return read8m_delegate(owner, std::forward<L>(l), name); } 243 244 template <typename L> 245 inline std::enable_if_t<std::is_constructible<read8s_delegate, device_t &, L, const char *>::value, read8s_delegate> make_lr8_delegate(device_t &owner, L &&l, const char *name) 246 { return read8s_delegate(owner, std::forward<L>(l), name); } 247 248 template <typename L> 249 inline std::enable_if_t<std::is_constructible<read8sm_delegate, device_t &, L, const char *>::value, read8sm_delegate> make_lr8_delegate(device_t &owner, L &&l, const char *name) 250 { return read8sm_delegate(owner, std::forward<L>(l), name); } 251 252 template <typename L> 253 inline std::enable_if_t<std::is_constructible<read8mo_delegate, device_t &, L, const char *>::value, read8mo_delegate> make_lr8_delegate(device_t &owner, L &&l, const char *name) 254 { return read8mo_delegate(owner, std::forward<L>(l), name); } 255 256 template <typename L> 257 inline std::enable_if_t<std::is_constructible<read8smo_delegate, device_t &, L, const char *>::value, read8smo_delegate> make_lr8_delegate(device_t &owner, L &&l, const char *name) 258 { return read8smo_delegate(owner, std::forward<L>(l), name); } 259 260 template <typename L> 261 inline std::enable_if_t<std::is_constructible<read16_delegate, device_t &, L, const char *>::value, read16_delegate> make_lr16_delegate(device_t &owner, L &&l, const char *name) 262 { return read16_delegate(owner, std::forward<L>(l), name); } 263 264 template <typename L> 265 inline std::enable_if_t<std::is_constructible<read16m_delegate, device_t &, L, const char *>::value, read16m_delegate> make_lr16_delegate(device_t &owner, L &&l, const char *name) 266 { return read16m_delegate(owner, std::forward<L>(l), name); } 267 268 template <typename L> 269 inline std::enable_if_t<std::is_constructible<read16s_delegate, device_t &, L, const char *>::value, read16s_delegate> make_lr16_delegate(device_t &owner, L &&l, const char *name) 270 { return read16s_delegate(owner, std::forward<L>(l), name); } 271 272 template <typename L> 273 inline std::enable_if_t<std::is_constructible<read16sm_delegate, device_t &, L, const char *>::value, read16sm_delegate> make_lr16_delegate(device_t &owner, L &&l, const char *name) 274 { return read16sm_delegate(owner, std::forward<L>(l), name); } 275 276 template <typename L> 277 inline std::enable_if_t<std::is_constructible<read16mo_delegate, device_t &, L, const char *>::value, read16mo_delegate> make_lr16_delegate(device_t &owner, L &&l, const char *name) 278 { return read16mo_delegate(owner, std::forward<L>(l), name); } 279 280 template <typename L> 281 inline std::enable_if_t<std::is_constructible<read16smo_delegate, device_t &, L, const char *>::value, read16smo_delegate> make_lr16_delegate(device_t &owner, L &&l, const char *name) 282 { return read16smo_delegate(owner, std::forward<L>(l), name); } 283 284 template <typename L> 285 inline std::enable_if_t<std::is_constructible<read32_delegate, device_t &, L, const char *>::value, read32_delegate> make_lr32_delegate(device_t &owner, L &&l, const char *name) 286 { return read32_delegate(owner, std::forward<L>(l), name); } 287 288 template <typename L> 289 inline std::enable_if_t<std::is_constructible<read32m_delegate, device_t &, L, const char *>::value, read32m_delegate> make_lr32_delegate(device_t &owner, L &&l, const char *name) 290 { return read32m_delegate(owner, std::forward<L>(l), name); } 291 292 template <typename L> 293 inline std::enable_if_t<std::is_constructible<read32s_delegate, device_t &, L, const char *>::value, read32s_delegate> make_lr32_delegate(device_t &owner, L &&l, const char *name) 294 { return read32s_delegate(owner, std::forward<L>(l), name); } 295 296 template <typename L> 297 inline std::enable_if_t<std::is_constructible<read32sm_delegate, device_t &, L, const char *>::value, read32sm_delegate> make_lr32_delegate(device_t &owner, L &&l, const char *name) 298 { return read32sm_delegate(owner, std::forward<L>(l), name); } 299 300 template <typename L> 301 inline std::enable_if_t<std::is_constructible<read32mo_delegate, device_t &, L, const char *>::value, read32mo_delegate> make_lr32_delegate(device_t &owner, L &&l, const char *name) 302 { return read32mo_delegate(owner, std::forward<L>(l), name); } 303 304 template <typename L> 305 inline std::enable_if_t<std::is_constructible<read32smo_delegate, device_t &, L, const char *>::value, read32smo_delegate> make_lr32_delegate(device_t &owner, L &&l, const char *name) 306 { return read32smo_delegate(owner, std::forward<L>(l), name); } 307 308 template <typename L> 309 inline std::enable_if_t<std::is_constructible<read64_delegate, device_t &, L, const char *>::value, read64_delegate> make_lr64_delegate(device_t &owner, L &&l, const char *name) 310 { return read64_delegate(owner, std::forward<L>(l), name); } 311 312 template <typename L> 313 inline std::enable_if_t<std::is_constructible<read64m_delegate, device_t &, L, const char *>::value, read64m_delegate> make_lr64_delegate(device_t &owner, L &&l, const char *name) 314 { return read64m_delegate(owner, std::forward<L>(l), name); } 315 316 template <typename L> 317 inline std::enable_if_t<std::is_constructible<read64s_delegate, device_t &, L, const char *>::value, read64s_delegate> make_lr64_delegate(device_t &owner, L &&l, const char *name) 318 { return read64s_delegate(owner, std::forward<L>(l), name); } 319 320 template <typename L> 321 inline std::enable_if_t<std::is_constructible<read64sm_delegate, device_t &, L, const char *>::value, read64sm_delegate> make_lr64_delegate(device_t &owner, L &&l, const char *name) 322 { return read64sm_delegate(owner, std::forward<L>(l), name); } 323 324 template <typename L> 325 inline std::enable_if_t<std::is_constructible<read64mo_delegate, device_t &, L, const char *>::value, read64mo_delegate> make_lr64_delegate(device_t &owner, L &&l, const char *name) 326 { return read64mo_delegate(owner, std::forward<L>(l), name); } 327 328 template <typename L> 329 inline std::enable_if_t<std::is_constructible<read64smo_delegate, device_t &, L, const char *>::value, read64smo_delegate> make_lr64_delegate(device_t &owner, L &&l, const char *name) 330 { return read64smo_delegate(owner, std::forward<L>(l), name); } 331 332 333 template <typename L> 334 inline std::enable_if_t<std::is_constructible<write8_delegate, device_t &, L, const char *>::value, write8_delegate> make_lw8_delegate(device_t &owner, L &&l, const char *name) 335 { return write8_delegate(owner, std::forward<L>(l), name); } 336 337 template <typename L> 338 inline std::enable_if_t<std::is_constructible<write8m_delegate, device_t &, L, const char *>::value, write8m_delegate> make_lw8_delegate(device_t &owner, L &&l, const char *name) 339 { return write8m_delegate(owner, std::forward<L>(l), name); } 340 341 template <typename L> 342 inline std::enable_if_t<std::is_constructible<write8s_delegate, device_t &, L, const char *>::value, write8s_delegate> make_lw8_delegate(device_t &owner, L &&l, const char *name) 343 { return write8s_delegate(owner, std::forward<L>(l), name); } 344 345 template <typename L> 346 inline std::enable_if_t<std::is_constructible<write8sm_delegate, device_t &, L, const char *>::value, write8sm_delegate> make_lw8_delegate(device_t &owner, L &&l, const char *name) 347 { return write8sm_delegate(owner, std::forward<L>(l), name); } 348 349 template <typename L> 350 inline std::enable_if_t<std::is_constructible<write8mo_delegate, device_t &, L, const char *>::value, write8mo_delegate> make_lw8_delegate(device_t &owner, L &&l, const char *name) 351 { return write8mo_delegate(owner, std::forward<L>(l), name); } 352 353 template <typename L> 354 inline std::enable_if_t<std::is_constructible<write8smo_delegate, device_t &, L, const char *>::value, write8smo_delegate> make_lw8_delegate(device_t &owner, L &&l, const char *name) 355 { return write8smo_delegate(owner, std::forward<L>(l), name); } 356 357 template <typename L> 358 inline std::enable_if_t<std::is_constructible<write16_delegate, device_t &, L, const char *>::value, write16_delegate> make_lw16_delegate(device_t &owner, L &&l, const char *name) 359 { return write16_delegate(owner, std::forward<L>(l), name); } 360 361 template <typename L> 362 inline std::enable_if_t<std::is_constructible<write16m_delegate, device_t &, L, const char *>::value, write16m_delegate> make_lw16_delegate(device_t &owner, L &&l, const char *name) 363 { return write16m_delegate(owner, std::forward<L>(l), name); } 364 365 template <typename L> 366 inline std::enable_if_t<std::is_constructible<write16s_delegate, device_t &, L, const char *>::value, write16s_delegate> make_lw16_delegate(device_t &owner, L &&l, const char *name) 367 { return write16s_delegate(owner, std::forward<L>(l), name); } 368 369 template <typename L> 370 inline std::enable_if_t<std::is_constructible<write16sm_delegate, device_t &, L, const char *>::value, write16sm_delegate> make_lw16_delegate(device_t &owner, L &&l, const char *name) 371 { return write16sm_delegate(owner, std::forward<L>(l), name); } 372 373 template <typename L> 374 inline std::enable_if_t<std::is_constructible<write16mo_delegate, device_t &, L, const char *>::value, write16mo_delegate> make_lw16_delegate(device_t &owner, L &&l, const char *name) 375 { return write16mo_delegate(owner, std::forward<L>(l), name); } 376 377 template <typename L> 378 inline std::enable_if_t<std::is_constructible<write16smo_delegate, device_t &, L, const char *>::value, write16smo_delegate> make_lw16_delegate(device_t &owner, L &&l, const char *name) 379 { return write16smo_delegate(owner, std::forward<L>(l), name); } 380 381 template <typename L> 382 inline std::enable_if_t<std::is_constructible<write32_delegate, device_t &, L, const char *>::value, write32_delegate> make_lw32_delegate(device_t &owner, L &&l, const char *name) 383 { return write32_delegate(owner, std::forward<L>(l), name); } 384 385 template <typename L> 386 inline std::enable_if_t<std::is_constructible<write32m_delegate, device_t &, L, const char *>::value, write32m_delegate> make_lw32_delegate(device_t &owner, L &&l, const char *name) 387 { return write32m_delegate(owner, std::forward<L>(l), name); } 388 389 template <typename L> 390 inline std::enable_if_t<std::is_constructible<write32s_delegate, device_t &, L, const char *>::value, write32s_delegate> make_lw32_delegate(device_t &owner, L &&l, const char *name) 391 { return write32s_delegate(owner, std::forward<L>(l), name); } 392 393 template <typename L> 394 inline std::enable_if_t<std::is_constructible<write32sm_delegate, device_t &, L, const char *>::value, write32sm_delegate> make_lw32_delegate(device_t &owner, L &&l, const char *name) 395 { return write32sm_delegate(owner, std::forward<L>(l), name); } 396 397 template <typename L> 398 inline std::enable_if_t<std::is_constructible<write32mo_delegate, device_t &, L, const char *>::value, write32mo_delegate> make_lw32_delegate(device_t &owner, L &&l, const char *name) 399 { return write32mo_delegate(owner, std::forward<L>(l), name); } 400 401 template <typename L> 402 inline std::enable_if_t<std::is_constructible<write32smo_delegate, device_t &, L, const char *>::value, write32smo_delegate> make_lw32_delegate(device_t &owner, L &&l, const char *name) 403 { return write32smo_delegate(owner, std::forward<L>(l), name); } 404 405 template <typename L> 406 inline std::enable_if_t<std::is_constructible<write64_delegate, device_t &, L, const char *>::value, write64_delegate> make_lw64_delegate(device_t &owner, L &&l, const char *name) 407 { return write64_delegate(owner, std::forward<L>(l), name); } 408 409 template <typename L> 410 inline std::enable_if_t<std::is_constructible<write64m_delegate, device_t &, L, const char *>::value, write64m_delegate> make_lw64_delegate(device_t &owner, L &&l, const char *name) 411 { return write64m_delegate(owner, std::forward<L>(l), name); } 412 413 template <typename L> 414 inline std::enable_if_t<std::is_constructible<write64s_delegate, device_t &, L, const char *>::value, write64s_delegate> make_lw64_delegate(device_t &owner, L &&l, const char *name) 415 { return write64s_delegate(owner, std::forward<L>(l), name); } 416 417 template <typename L> 418 inline std::enable_if_t<std::is_constructible<write64sm_delegate, device_t &, L, const char *>::value, write64sm_delegate> make_lw64_delegate(device_t &owner, L &&l, const char *name) 419 { return write64sm_delegate(owner, std::forward<L>(l), name); } 420 421 template <typename L> 422 inline std::enable_if_t<std::is_constructible<write64mo_delegate, device_t &, L, const char *>::value, write64mo_delegate> make_lw64_delegate(device_t &owner, L &&l, const char *name) 423 { return write64mo_delegate(owner, std::forward<L>(l), name); } 424 425 template <typename L> 426 inline std::enable_if_t<std::is_constructible<write64smo_delegate, device_t &, L, const char *>::value, write64smo_delegate> make_lw64_delegate(device_t &owner, L &&l, const char *name) 427 { return write64smo_delegate(owner, std::forward<L>(l), name); } 428 429 430 431 // =====================-> Width -> types 432 433 template<int Width> struct handler_entry_size {}; 434 template<> struct handler_entry_size<0> { using uX = u8; }; 435 template<> struct handler_entry_size<1> { using uX = u16; }; 436 template<> struct handler_entry_size<2> { using uX = u32; }; 437 template<> struct handler_entry_size<3> { using uX = u64; }; 438 439 // =====================-> Address segmentation for the search tree 440 441 constexpr int handler_entry_dispatch_level(int highbits) 442 { 443 return (highbits > 48) ? 3 : (highbits > 32) ? 2 : (highbits > 14) ? 1 : 0; 444 } 445 446 constexpr int handler_entry_dispatch_level_to_lowbits(int level, int width, int ashift) 447 { 448 return level == 3 ? 48 : level == 2 ? 32 : level == 1 ? 14 : width + ashift; 449 } 450 451 constexpr int handler_entry_dispatch_lowbits(int highbits, int width, int ashift) 452 { 453 return (highbits > 48) ? 48 : 454 (highbits > 32) ? 32 : 455 (highbits > 14) ? 14 : 456 width + ashift; 457 } 458 459 } } // namespace emu::detail 460 461 462 // ======================> memory_units_descritor forwards declaration 463 464 template<int Width, int AddrShift, endianness_t Endian> class memory_units_descriptor; 465 466 467 468 // =====================-> The root class of all handlers 469 470 // Handlers the refcounting as part of the interface 471 472 class handler_entry 473 { 474 DISABLE_COPYING(handler_entry); 475 476 template<int Level, int Width, int AddrShift, endianness_t Endian> friend class address_space_specific; 477 478 public: 479 // Typing flags 480 static constexpr u32 F_DISPATCH = 0x00000001; // handler that forwards the access to other handlers 481 static constexpr u32 F_UNITS = 0x00000002; // handler that merges/splits an access among multiple handlers (unitmask support) 482 static constexpr u32 F_PASSTHROUGH = 0x00000004; // handler that passes through the request to another handler 483 484 // Start/end of range flags 485 static constexpr u8 START = 1; 486 static constexpr u8 END = 2; 487 488 // Intermediary structure for reference count checking 489 class reflist { 490 public: 491 void add(const handler_entry *entry); 492 493 void propagate(); 494 void check(); 495 496 private: 497 std::unordered_map<const handler_entry *, u32> refcounts; 498 std::unordered_set<const handler_entry *> seen; 499 std::unordered_set<const handler_entry *> todo; 500 }; 501 502 handler_entry(address_space *space, u32 flags) { m_space = space; m_refcount = 1; m_flags = flags; } 503 virtual ~handler_entry() {} 504 505 inline void ref(int count = 1) const { m_refcount += count; } 506 inline void unref(int count = 1) const { m_refcount -= count; if(!m_refcount) delete this; } 507 inline u32 flags() const { return m_flags; } 508 509 inline bool is_dispatch() const { return m_flags & F_DISPATCH; } 510 inline bool is_units() const { return m_flags & F_UNITS; } 511 inline bool is_passthrough() const { return m_flags & F_PASSTHROUGH; } 512 513 virtual void dump_map(std::vector<memory_entry> &map) const; 514 515 virtual std::string name() const = 0; 516 virtual void enumerate_references(handler_entry::reflist &refs) const; 517 u32 get_refcount() const { return m_refcount; } 518 519 protected: 520 // Address range storage 521 struct range { 522 offs_t start; 523 offs_t end; 524 525 inline void set(offs_t _start, offs_t _end) { 526 start = _start; 527 end = _end; 528 } 529 530 inline void intersect(offs_t _start, offs_t _end) { 531 if(_start > start) 532 start = _start; 533 if(_end < end) 534 end = _end; 535 } 536 }; 537 538 address_space *m_space; 539 mutable u32 m_refcount; 540 u32 m_flags; 541 }; 542 543 544 // =====================-> The parent class of all read handlers 545 546 // Provides the populate/read/get_ptr/lookup API 547 548 template<int Width, int AddrShift, endianness_t Endian> class handler_entry_read_passthrough; 549 550 template<int Width, int AddrShift, endianness_t Endian> class handler_entry_read : public handler_entry 551 { 552 public: 553 using uX = typename emu::detail::handler_entry_size<Width>::uX; 554 555 static constexpr u32 NATIVE_MASK = Width + AddrShift >= 0 ? make_bitmask<u32>(Width + AddrShift) : 0; 556 557 struct mapping { 558 handler_entry_read<Width, AddrShift, Endian> *original; 559 handler_entry_read<Width, AddrShift, Endian> *patched; 560 u8 ukey; 561 }; 562 563 handler_entry_read(address_space *space, u32 flags) : handler_entry(space, flags) {} 564 ~handler_entry_read() {} 565 566 virtual uX read(offs_t offset, uX mem_mask) const = 0; 567 virtual void *get_ptr(offs_t offset) const; 568 virtual void lookup(offs_t address, offs_t &start, offs_t &end, handler_entry_read<Width, AddrShift, Endian> *&handler) const; 569 570 inline void populate(offs_t start, offs_t end, offs_t mirror, handler_entry_read<Width, AddrShift, Endian> *handler) { 571 start &= ~NATIVE_MASK; 572 end |= NATIVE_MASK; 573 if(mirror) 574 populate_mirror(start, end, start, end, mirror, handler); 575 else 576 populate_nomirror(start, end, start, end, handler); 577 } 578 579 virtual void populate_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read<Width, AddrShift, Endian> *handler); 580 virtual void populate_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_read<Width, AddrShift, Endian> *handler); 581 582 inline void populate_mismatched(offs_t start, offs_t end, offs_t mirror, const memory_units_descriptor<Width, AddrShift, Endian> &descriptor) { 583 start &= ~NATIVE_MASK; 584 end |= NATIVE_MASK; 585 std::vector<mapping> mappings; 586 if(mirror) 587 populate_mismatched_mirror(start, end, start, end, mirror, descriptor, mappings); 588 else 589 populate_mismatched_nomirror(start, end, start, end, descriptor, START|END, mappings); 590 } 591 592 virtual void populate_mismatched_nomirror(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); 593 virtual void populate_mismatched_mirror(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); 594 595 inline void populate_passthrough(offs_t start, offs_t end, offs_t mirror, handler_entry_read_passthrough<Width, AddrShift, Endian> *handler) { 596 start &= ~NATIVE_MASK; 597 end |= NATIVE_MASK; 598 std::vector<mapping> mappings; 599 if(mirror) 600 populate_passthrough_mirror(start, end, start, end, mirror, handler, mappings); 601 else 602 populate_passthrough_nomirror(start, end, start, end, handler, mappings); 603 } 604 605 virtual void populate_passthrough_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read_passthrough<Width, AddrShift, Endian> *handler, std::vector<mapping> &mappings); 606 virtual void populate_passthrough_mirror(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); 607 608 // Remove a set of passthrough handlers, leaving the lower handler in their place 609 virtual void detach(const std::unordered_set<handler_entry *> &handlers); 610 611 // Return the internal structures of the root dispatch 612 virtual const handler_entry_read<Width, AddrShift, Endian> *const *get_dispatch() const; 613 }; 614 615 // =====================-> The parent class of all write handlers 616 617 // Provides the populate/write/get_ptr/lookup API 618 619 template<int Width, int AddrShift, endianness_t Endian> class handler_entry_write_passthrough; 620 621 template<int Width, int AddrShift, endianness_t Endian> class handler_entry_write : public handler_entry 622 { 623 public: 624 using uX = typename emu::detail::handler_entry_size<Width>::uX; 625 626 static constexpr u32 NATIVE_MASK = Width + AddrShift >= 0 ? make_bitmask<u32>(Width + AddrShift) : 0; 627 628 struct mapping { 629 handler_entry_write<Width, AddrShift, Endian> *original; 630 handler_entry_write<Width, AddrShift, Endian> *patched; 631 u8 ukey; 632 }; 633 634 handler_entry_write(address_space *space, u32 flags) : handler_entry(space, flags) {} 635 virtual ~handler_entry_write() {} 636 637 virtual void write(offs_t offset, uX data, uX mem_mask) const = 0; 638 virtual void *get_ptr(offs_t offset) const; 639 virtual void lookup(offs_t address, offs_t &start, offs_t &end, handler_entry_write<Width, AddrShift, Endian> *&handler) const; 640 641 inline void populate(offs_t start, offs_t end, offs_t mirror, handler_entry_write<Width, AddrShift, Endian> *handler) { 642 start &= ~NATIVE_MASK; 643 end |= NATIVE_MASK; 644 if(mirror) 645 populate_mirror(start, end, start, end, mirror, handler); 646 else 647 populate_nomirror(start, end, start, end, handler); 648 } 649 650 virtual void populate_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_write<Width, AddrShift, Endian> *handler); 651 virtual void populate_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_write<Width, AddrShift, Endian> *handler); 652 653 inline void populate_mismatched(offs_t start, offs_t end, offs_t mirror, const memory_units_descriptor<Width, AddrShift, Endian> &descriptor) { 654 start &= ~NATIVE_MASK; 655 end |= NATIVE_MASK; 656 657 std::vector<mapping> mappings; 658 if(mirror) 659 populate_mismatched_mirror(start, end, start, end, mirror, descriptor, mappings); 660 else 661 populate_mismatched_nomirror(start, end, start, end, descriptor, START|END, mappings); 662 } 663 664 virtual void populate_mismatched_nomirror(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); 665 virtual void populate_mismatched_mirror(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); 666 667 inline void populate_passthrough(offs_t start, offs_t end, offs_t mirror, handler_entry_write_passthrough<Width, AddrShift, Endian> *handler) { 668 start &= ~NATIVE_MASK; 669 end |= NATIVE_MASK; 670 std::vector<mapping> mappings; 671 if(mirror) 672 populate_passthrough_mirror(start, end, start, end, mirror, handler, mappings); 673 else 674 populate_passthrough_nomirror(start, end, start, end, handler, mappings); 675 } 676 677 virtual void populate_passthrough_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_write_passthrough<Width, AddrShift, Endian> *handler, std::vector<mapping> &mappings); 678 virtual void populate_passthrough_mirror(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); 679 680 // Remove a set of passthrough handlers, leaving the lower handler in their place 681 virtual void detach(const std::unordered_set<handler_entry *> &handlers); 682 683 // Return the internal structures of the root dispatch 684 virtual const handler_entry_write<Width, AddrShift, Endian> *const *get_dispatch() const; 685 }; 686 687 // =====================-> Passthrough handler management structure 688 class memory_passthrough_handler 689 { 690 template<int Width, int AddrShift, endianness_t Endian> friend class handler_entry_read_passthrough; 691 template<int Width, int AddrShift, endianness_t Endian> friend class handler_entry_write_passthrough; 692 693 public: 694 memory_passthrough_handler(address_space &space) : m_space(space) {} 695 696 inline void remove(); 697 698 private: 699 address_space &m_space; 700 std::unordered_set<handler_entry *> m_handlers; 701 702 void add_handler(handler_entry *handler) { m_handlers.insert(handler); } 703 void remove_handler(handler_entry *handler) { m_handlers.erase(m_handlers.find(handler)); } 704 }; 705 706 // =====================-> Forward declaration for address_space 707 708 template<int Width, int AddrShift, endianness_t Endian> class handler_entry_read_unmapped; 709 template<int Width, int AddrShift, endianness_t Endian> class handler_entry_write_unmapped; 710 711 // ======================> address offset -> byte offset 712 713 constexpr offs_t memory_offset_to_byte(offs_t offset, int AddrShift) { return AddrShift < 0 ? offset << iabs(AddrShift) : offset >> iabs(AddrShift); } 714 715 // ======================> generic read/write decomposition routines 716 717 // generic direct read 718 template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Aligned, typename T> typename emu::detail::handler_entry_size<TargetWidth>::uX memory_read_generic(T rop, offs_t address, typename emu::detail::handler_entry_size<TargetWidth>::uX mask) 719 { 720 using TargetType = typename emu::detail::handler_entry_size<TargetWidth>::uX; 721 using NativeType = typename emu::detail::handler_entry_size<Width>::uX; 722 723 constexpr u32 TARGET_BYTES = 1 << TargetWidth; 724 constexpr u32 TARGET_BITS = 8 * TARGET_BYTES; 725 constexpr u32 NATIVE_BYTES = 1 << Width; 726 constexpr u32 NATIVE_BITS = 8 * NATIVE_BYTES; 727 constexpr u32 NATIVE_STEP = AddrShift >= 0 ? NATIVE_BYTES << iabs(AddrShift) : NATIVE_BYTES >> iabs(AddrShift); 728 constexpr u32 NATIVE_MASK = Width + AddrShift >= 0 ? make_bitmask<u32>(Width + AddrShift) : 0; 729 730 // equal to native size and aligned; simple pass-through to the native reader 731 if (NATIVE_BYTES == TARGET_BYTES && (Aligned || (address & NATIVE_MASK) == 0)) 732 return rop(address & ~NATIVE_MASK, mask); 733 734 // if native size is larger, see if we can do a single masked read (guaranteed if we're aligned) 735 if (NATIVE_BYTES > TARGET_BYTES) 736 { 737 u32 offsbits = 8 * (memory_offset_to_byte(address, AddrShift) & (NATIVE_BYTES - (Aligned ? TARGET_BYTES : 1))); 738 if (Aligned || (offsbits + TARGET_BITS <= NATIVE_BITS)) 739 { 740 if (Endian != ENDIANNESS_LITTLE) offsbits = NATIVE_BITS - TARGET_BITS - offsbits; 741 return rop(address & ~NATIVE_MASK, (NativeType)mask << offsbits) >> offsbits; 742 } 743 } 744 745 // determine our alignment against the native boundaries, and mask the address 746 u32 offsbits = 8 * (memory_offset_to_byte(address, AddrShift) & (NATIVE_BYTES - 1)); 747 address &= ~NATIVE_MASK; 748 749 // if we're here, and native size is larger or equal to the target, we need exactly 2 reads 750 if (NATIVE_BYTES >= TARGET_BYTES) 751 { 752 // little-endian case 753 if (Endian == ENDIANNESS_LITTLE) 754 { 755 // read lower bits from lower address 756 TargetType result = 0; 757 NativeType curmask = (NativeType)mask << offsbits; 758 if (curmask != 0) result = rop(address, curmask) >> offsbits; 759 760 // read upper bits from upper address 761 offsbits = NATIVE_BITS - offsbits; 762 curmask = mask >> offsbits; 763 if (curmask != 0) result |= rop(address + NATIVE_STEP, curmask) << offsbits; 764 return result; 765 } 766 767 // big-endian case 768 else 769 { 770 // left-justify the mask to the target type 771 constexpr u32 LEFT_JUSTIFY_TARGET_TO_NATIVE_SHIFT = ((NATIVE_BITS >= TARGET_BITS) ? (NATIVE_BITS - TARGET_BITS) : 0); 772 NativeType result = 0; 773 NativeType ljmask = (NativeType)mask << LEFT_JUSTIFY_TARGET_TO_NATIVE_SHIFT; 774 NativeType curmask = ljmask >> offsbits; 775 776 // read upper bits from lower address 777 if (curmask != 0) result = rop(address, curmask) << offsbits; 778 offsbits = NATIVE_BITS - offsbits; 779 780 // read lower bits from upper address 781 curmask = ljmask << offsbits; 782 if (curmask != 0) result |= rop(address + NATIVE_STEP, curmask) >> offsbits; 783 784 // return the un-justified result 785 return result >> LEFT_JUSTIFY_TARGET_TO_NATIVE_SHIFT; 786 } 787 } 788 789 // if we're here, then we have 2 or more reads needed to get our final result 790 else 791 { 792 // compute the maximum number of loops; we do it this way so that there are 793 // a fixed number of loops for the compiler to unroll if it desires 794 constexpr u32 MAX_SPLITS_MINUS_ONE = TARGET_BYTES / NATIVE_BYTES - 1; 795 TargetType result = 0; 796 797 // little-endian case 798 if (Endian == ENDIANNESS_LITTLE) 799 { 800 // read lowest bits from first address 801 NativeType curmask = mask << offsbits; 802 if (curmask != 0) result = rop(address, curmask) >> offsbits; 803 804 // read middle bits from subsequent addresses 805 offsbits = NATIVE_BITS - offsbits; 806 for (u32 index = 0; index < MAX_SPLITS_MINUS_ONE; index++) 807 { 808 address += NATIVE_STEP; 809 curmask = mask >> offsbits; 810 if (curmask != 0) result |= (TargetType)rop(address, curmask) << offsbits; 811 offsbits += NATIVE_BITS; 812 } 813 814 // if we're not aligned and we still have bits left, read uppermost bits from last address 815 if (!Aligned && offsbits < TARGET_BITS) 816 { 817 curmask = mask >> offsbits; 818 if (curmask != 0) result |= (TargetType)rop(address + NATIVE_STEP, curmask) << offsbits; 819 } 820 } 821 822 // big-endian case 823 else 824 { 825 // read highest bits from first address 826 offsbits = TARGET_BITS - (NATIVE_BITS - offsbits); 827 NativeType curmask = mask >> offsbits; 828 if (curmask != 0) result = (TargetType)rop(address, curmask) << offsbits; 829 830 // read middle bits from subsequent addresses 831 for (u32 index = 0; index < MAX_SPLITS_MINUS_ONE; index++) 832 { 833 offsbits -= NATIVE_BITS; 834 address += NATIVE_STEP; 835 curmask = mask >> offsbits; 836 if (curmask != 0) result |= (TargetType)rop(address, curmask) << offsbits; 837 } 838 839 // if we're not aligned and we still have bits left, read lowermost bits from the last address 840 if (!Aligned && offsbits != 0) 841 { 842 offsbits = NATIVE_BITS - offsbits; 843 curmask = mask << offsbits; 844 if (curmask != 0) result |= rop(address + NATIVE_STEP, curmask) >> offsbits; 845 } 846 } 847 return result; 848 } 849 } 850 851 // generic direct write 852 template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Aligned, typename T> void memory_write_generic(T wop, offs_t address, typename emu::detail::handler_entry_size<TargetWidth>::uX data, typename emu::detail::handler_entry_size<TargetWidth>::uX mask) 853 { 854 using NativeType = typename emu::detail::handler_entry_size<Width>::uX; 855 856 constexpr u32 TARGET_BYTES = 1 << TargetWidth; 857 constexpr u32 TARGET_BITS = 8 * TARGET_BYTES; 858 constexpr u32 NATIVE_BYTES = 1 << Width; 859 constexpr u32 NATIVE_BITS = 8 * NATIVE_BYTES; 860 constexpr u32 NATIVE_STEP = AddrShift >= 0 ? NATIVE_BYTES << iabs(AddrShift) : NATIVE_BYTES >> iabs(AddrShift); 861 constexpr u32 NATIVE_MASK = Width + AddrShift >= 0 ? (1 << (Width + AddrShift)) - 1 : 0; 862 863 // equal to native size and aligned; simple pass-through to the native writer 864 if (NATIVE_BYTES == TARGET_BYTES && (Aligned || (address & NATIVE_MASK) == 0)) 865 return wop(address & ~NATIVE_MASK, data, mask); 866 867 // if native size is larger, see if we can do a single masked write (guaranteed if we're aligned) 868 if (NATIVE_BYTES > TARGET_BYTES) 869 { 870 u32 offsbits = 8 * (memory_offset_to_byte(address, AddrShift) & (NATIVE_BYTES - (Aligned ? TARGET_BYTES : 1))); 871 if (Aligned || (offsbits + TARGET_BITS <= NATIVE_BITS)) 872 { 873 if (Endian != ENDIANNESS_LITTLE) offsbits = NATIVE_BITS - TARGET_BITS - offsbits; 874 return wop(address & ~NATIVE_MASK, (NativeType)data << offsbits, (NativeType)mask << offsbits); 875 } 876 } 877 878 // determine our alignment against the native boundaries, and mask the address 879 u32 offsbits = 8 * (memory_offset_to_byte(address, AddrShift) & (NATIVE_BYTES - 1)); 880 address &= ~NATIVE_MASK; 881 882 // if we're here, and native size is larger or equal to the target, we need exactly 2 writes 883 if (NATIVE_BYTES >= TARGET_BYTES) 884 { 885 // little-endian case 886 if (Endian == ENDIANNESS_LITTLE) 887 { 888 // write lower bits to lower address 889 NativeType curmask = (NativeType)mask << offsbits; 890 if (curmask != 0) wop(address, (NativeType)data << offsbits, curmask); 891 892 // write upper bits to upper address 893 offsbits = NATIVE_BITS - offsbits; 894 curmask = mask >> offsbits; 895 if (curmask != 0) wop(address + NATIVE_STEP, data >> offsbits, curmask); 896 } 897 898 // big-endian case 899 else 900 { 901 // left-justify the mask and data to the target type 902 constexpr u32 LEFT_JUSTIFY_TARGET_TO_NATIVE_SHIFT = ((NATIVE_BITS >= TARGET_BITS) ? (NATIVE_BITS - TARGET_BITS) : 0); 903 NativeType ljdata = (NativeType)data << LEFT_JUSTIFY_TARGET_TO_NATIVE_SHIFT; 904 NativeType ljmask = (NativeType)mask << LEFT_JUSTIFY_TARGET_TO_NATIVE_SHIFT; 905 // write upper bits to lower address 906 NativeType curmask = ljmask >> offsbits; 907 if (curmask != 0) wop(address, ljdata >> offsbits, curmask); 908 // write lower bits to upper address 909 offsbits = NATIVE_BITS - offsbits; 910 curmask = ljmask << offsbits; 911 if (curmask != 0) wop(address + NATIVE_STEP, ljdata << offsbits, curmask); 912 } 913 } 914 915 // if we're here, then we have 2 or more writes needed to get our final result 916 else 917 { 918 // compute the maximum number of loops; we do it this way so that there are 919 // a fixed number of loops for the compiler to unroll if it desires 920 constexpr u32 MAX_SPLITS_MINUS_ONE = TARGET_BYTES / NATIVE_BYTES - 1; 921 922 // little-endian case 923 if (Endian == ENDIANNESS_LITTLE) 924 { 925 // write lowest bits to first address 926 NativeType curmask = mask << offsbits; 927 if (curmask != 0) wop(address, data << offsbits, curmask); 928 929 // write middle bits to subsequent addresses 930 offsbits = NATIVE_BITS - offsbits; 931 for (u32 index = 0; index < MAX_SPLITS_MINUS_ONE; index++) 932 { 933 address += NATIVE_STEP; 934 curmask = mask >> offsbits; 935 if (curmask != 0) wop(address, data >> offsbits, curmask); 936 offsbits += NATIVE_BITS; 937 } 938 939 // if we're not aligned and we still have bits left, write uppermost bits to last address 940 if (!Aligned && offsbits < TARGET_BITS) 941 { 942 curmask = mask >> offsbits; 943 if (curmask != 0) wop(address + NATIVE_STEP, data >> offsbits, curmask); 944 } 945 } 946 947 // big-endian case 948 else 949 { 950 // write highest bits to first address 951 offsbits = TARGET_BITS - (NATIVE_BITS - offsbits); 952 NativeType curmask = mask >> offsbits; 953 if (curmask != 0) wop(address, data >> offsbits, curmask); 954 955 // write middle bits to subsequent addresses 956 for (u32 index = 0; index < MAX_SPLITS_MINUS_ONE; index++) 957 { 958 offsbits -= NATIVE_BITS; 959 address += NATIVE_STEP; 960 curmask = mask >> offsbits; 961 if (curmask != 0) wop(address, data >> offsbits, curmask); 962 } 963 964 // if we're not aligned and we still have bits left, write lowermost bits to the last address 965 if (!Aligned && offsbits != 0) 966 { 967 offsbits = NATIVE_BITS - offsbits; 968 curmask = mask << offsbits; 969 if (curmask != 0) wop(address + NATIVE_STEP, data << offsbits, curmask); 970 } 971 } 972 } 973 } 974 975 // ======================> Direct dispatching 976 977 template<int Level, int Width, int AddrShift, endianness_t Endian> typename emu::detail::handler_entry_size<Width>::uX dispatch_read(offs_t mask, offs_t offset, typename emu::detail::handler_entry_size<Width>::uX mem_mask, const handler_entry_read<Width, AddrShift, Endian> *const *dispatch) 978 { 979 static constexpr u32 LowBits = emu::detail::handler_entry_dispatch_level_to_lowbits(Level, Width, AddrShift); 980 return dispatch[(offset & mask) >> LowBits]->read(offset, mem_mask); 981 } 982 983 984 template<int Level, int Width, int AddrShift, endianness_t Endian> void dispatch_write(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, Endian> *const *dispatch) 985 { 986 static constexpr u32 LowBits = emu::detail::handler_entry_dispatch_level_to_lowbits(Level, Width, AddrShift); 987 return dispatch[(offset & mask) >> LowBits]->write(offset, data, mem_mask); 988 } 989 990 991 // ======================> memory_access_specific 992 993 // memory_access_specific does uncached but faster accesses by shortcutting the address_space virtual call 994 995 namespace emu { namespace detail { 996 997 template<int Level, int Width, int AddrShift, endianness_t Endian> class memory_access_specific 998 { 999 friend class ::address_space; 1000 1001 using NativeType = typename emu::detail::handler_entry_size<Width>::uX; 1002 static constexpr u32 NATIVE_BYTES = 1 << Width; 1003 static constexpr u32 NATIVE_MASK = Width + AddrShift >= 0 ? (1 << (Width + AddrShift)) - 1 : 0; 1004 1005 public: 1006 // construction/destruction 1007 memory_access_specific() 1008 : m_space(nullptr), 1009 m_addrmask(0), 1010 m_dispatch_read(nullptr), 1011 m_dispatch_write(nullptr) 1012 { 1013 } 1014 1015 inline address_space &space() const { 1016 return *m_space; 1017 } 1018 1019 u8 read_byte(offs_t address) { return Width == 0 ? read_native(address & ~NATIVE_MASK) : memory_read_generic<Width, AddrShift, Endian, 0, true>([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xff); } 1020 u16 read_word(offs_t address) { return Width == 1 ? read_native(address & ~NATIVE_MASK) : memory_read_generic<Width, AddrShift, Endian, 1, true>([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffff); } 1021 u16 read_word(offs_t address, u16 mask) { return memory_read_generic<Width, AddrShift, Endian, 1, true>([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } 1022 u16 read_word_unaligned(offs_t address) { return memory_read_generic<Width, AddrShift, Endian, 1, false>([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffff); } 1023 u16 read_word_unaligned(offs_t address, u16 mask) { return memory_read_generic<Width, AddrShift, Endian, 1, false>([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } 1024 u32 read_dword(offs_t address) { return Width == 2 ? read_native(address & ~NATIVE_MASK) : memory_read_generic<Width, AddrShift, Endian, 2, true>([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffff); } 1025 u32 read_dword(offs_t address, u32 mask) { return memory_read_generic<Width, AddrShift, Endian, 2, true>([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } 1026 u32 read_dword_unaligned(offs_t address) { return memory_read_generic<Width, AddrShift, Endian, 2, false>([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffff); } 1027 u32 read_dword_unaligned(offs_t address, u32 mask) { return memory_read_generic<Width, AddrShift, Endian, 2, false>([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } 1028 u64 read_qword(offs_t address) { return Width == 3 ? read_native(address & ~NATIVE_MASK) : memory_read_generic<Width, AddrShift, Endian, 3, true>([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffffffffffffU); } 1029 u64 read_qword(offs_t address, u64 mask) { return memory_read_generic<Width, AddrShift, Endian, 3, true>([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } 1030 u64 read_qword_unaligned(offs_t address) { return memory_read_generic<Width, AddrShift, Endian, 3, false>([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffffffffffffU); } 1031 u64 read_qword_unaligned(offs_t address, u64 mask) { return memory_read_generic<Width, AddrShift, Endian, 3, false>([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } 1032 1033 void write_byte(offs_t address, u8 data) { if (Width == 0) write_native(address & ~NATIVE_MASK, data); else memory_write_generic<Width, AddrShift, Endian, 0, true>([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xff); } 1034 void write_word(offs_t address, u16 data) { if (Width == 1) write_native(address & ~NATIVE_MASK, data); else memory_write_generic<Width, AddrShift, Endian, 1, true>([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffff); } 1035 void write_word(offs_t address, u16 data, u16 mask) { memory_write_generic<Width, AddrShift, Endian, 1, true>([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } 1036 void write_word_unaligned(offs_t address, u16 data) { memory_write_generic<Width, AddrShift, Endian, 1, false>([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffff); } 1037 void write_word_unaligned(offs_t address, u16 data, u16 mask) { memory_write_generic<Width, AddrShift, Endian, 1, false>([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } 1038 void write_dword(offs_t address, u32 data) { if (Width == 2) write_native(address & ~NATIVE_MASK, data); else memory_write_generic<Width, AddrShift, Endian, 2, true>([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffff); } 1039 void write_dword(offs_t address, u32 data, u32 mask) { memory_write_generic<Width, AddrShift, Endian, 2, true>([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } 1040 void write_dword_unaligned(offs_t address, u32 data) { memory_write_generic<Width, AddrShift, Endian, 2, false>([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffff); } 1041 void write_dword_unaligned(offs_t address, u32 data, u32 mask) { memory_write_generic<Width, AddrShift, Endian, 2, false>([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } 1042 void write_qword(offs_t address, u64 data) { if (Width == 3) write_native(address & ~NATIVE_MASK, data); else memory_write_generic<Width, AddrShift, Endian, 3, true>([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffffffffffffU); } 1043 void write_qword(offs_t address, u64 data, u64 mask) { memory_write_generic<Width, AddrShift, Endian, 3, true>([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } 1044 void write_qword_unaligned(offs_t address, u64 data) { memory_write_generic<Width, AddrShift, Endian, 3, false>([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffffffffffffU); } 1045 void write_qword_unaligned(offs_t address, u64 data, u64 mask) { memory_write_generic<Width, AddrShift, Endian, 3, false>([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } 1046 1047 private: 1048 address_space * m_space; 1049 1050 offs_t m_addrmask; // address mask 1051 1052 const handler_entry_read<Width, AddrShift, Endian> *const *m_dispatch_read; 1053 const handler_entry_write<Width, AddrShift, Endian> *const *m_dispatch_write; 1054 1055 NativeType read_native(offs_t address, NativeType mask = ~NativeType(0)) { 1056 return dispatch_read<Level, Width, AddrShift, Endian>(offs_t(-1), address & m_addrmask, mask, m_dispatch_read);; 1057 } 1058 1059 void write_native(offs_t address, NativeType data, NativeType mask = ~NativeType(0)) { 1060 dispatch_write<Level, Width, AddrShift, Endian>(offs_t(-1), address & m_addrmask, data, mask, m_dispatch_write);; 1061 } 1062 1063 void set(address_space *space, std::pair<const void *, const void *> rw); 1064 }; 1065 1066 1067 1068 // ======================> memory_access_cache 1069 1070 // memory_access_cache contains state data for cached access 1071 template<int Width, int AddrShift, endianness_t Endian> class memory_access_cache 1072 { 1073 friend class ::address_space; 1074 1075 using NativeType = typename emu::detail::handler_entry_size<Width>::uX; 1076 static constexpr u32 NATIVE_BYTES = 1 << Width; 1077 static constexpr u32 NATIVE_MASK = Width + AddrShift >= 0 ? (1 << (Width + AddrShift)) - 1 : 0; 1078 1079 public: 1080 // construction/destruction 1081 memory_access_cache() 1082 : m_space(nullptr), 1083 m_addrmask(0), 1084 m_addrstart_r(1), 1085 m_addrend_r(0), 1086 m_addrstart_w(1), 1087 m_addrend_w(0), 1088 m_cache_r(nullptr), 1089 m_cache_w(nullptr), 1090 m_root_read(nullptr), 1091 m_root_write(nullptr) 1092 { 1093 } 1094 1095 ~memory_access_cache(); 1096 1097 // see if an address is within bounds, update it if not 1098 void check_address_r(offs_t address) { 1099 if(address >= m_addrstart_r && address <= m_addrend_r) 1100 return; 1101 m_root_read->lookup(address, m_addrstart_r, m_addrend_r, m_cache_r); 1102 } 1103 1104 void check_address_w(offs_t address) { 1105 if(address >= m_addrstart_w && address <= m_addrend_w) 1106 return; 1107 m_root_write->lookup(address, m_addrstart_w, m_addrend_w, m_cache_w); 1108 } 1109 1110 // accessor methods 1111 1112 inline address_space &space() const { 1113 return *m_space; 1114 } 1115 1116 void *read_ptr(offs_t address) { 1117 address &= m_addrmask; 1118 check_address_r(address); 1119 return m_cache_r->get_ptr(address); 1120 } 1121 1122 u8 read_byte(offs_t address) { return Width == 0 ? read_native(address & ~NATIVE_MASK) : memory_read_generic<Width, AddrShift, Endian, 0, true>([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xff); } 1123 u16 read_word(offs_t address) { return Width == 1 ? read_native(address & ~NATIVE_MASK) : memory_read_generic<Width, AddrShift, Endian, 1, true>([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffff); } 1124 u16 read_word(offs_t address, u16 mask) { return memory_read_generic<Width, AddrShift, Endian, 1, true>([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } 1125 u16 read_word_unaligned(offs_t address) { return memory_read_generic<Width, AddrShift, Endian, 1, false>([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffff); } 1126 u16 read_word_unaligned(offs_t address, u16 mask) { return memory_read_generic<Width, AddrShift, Endian, 1, false>([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } 1127 u32 read_dword(offs_t address) { return Width == 2 ? read_native(address & ~NATIVE_MASK) : memory_read_generic<Width, AddrShift, Endian, 2, true>([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffff); } 1128 u32 read_dword(offs_t address, u32 mask) { return memory_read_generic<Width, AddrShift, Endian, 2, true>([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } 1129 u32 read_dword_unaligned(offs_t address) { return memory_read_generic<Width, AddrShift, Endian, 2, false>([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffff); } 1130 u32 read_dword_unaligned(offs_t address, u32 mask) { return memory_read_generic<Width, AddrShift, Endian, 2, false>([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } 1131 u64 read_qword(offs_t address) { return Width == 3 ? read_native(address & ~NATIVE_MASK) : memory_read_generic<Width, AddrShift, Endian, 3, true>([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffffffffffffU); } 1132 u64 read_qword(offs_t address, u64 mask) { return memory_read_generic<Width, AddrShift, Endian, 3, true>([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } 1133 u64 read_qword_unaligned(offs_t address) { return memory_read_generic<Width, AddrShift, Endian, 3, false>([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffffffffffffU); } 1134 u64 read_qword_unaligned(offs_t address, u64 mask) { return memory_read_generic<Width, AddrShift, Endian, 3, false>([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } 1135 1136 void write_byte(offs_t address, u8 data) { if (Width == 0) write_native(address & ~NATIVE_MASK, data); else memory_write_generic<Width, AddrShift, Endian, 0, true>([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xff); } 1137 void write_word(offs_t address, u16 data) { if (Width == 1) write_native(address & ~NATIVE_MASK, data); else memory_write_generic<Width, AddrShift, Endian, 1, true>([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffff); } 1138 void write_word(offs_t address, u16 data, u16 mask) { memory_write_generic<Width, AddrShift, Endian, 1, true>([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } 1139 void write_word_unaligned(offs_t address, u16 data) { memory_write_generic<Width, AddrShift, Endian, 1, false>([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffff); } 1140 void write_word_unaligned(offs_t address, u16 data, u16 mask) { memory_write_generic<Width, AddrShift, Endian, 1, false>([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } 1141 void write_dword(offs_t address, u32 data) { if (Width == 2) write_native(address & ~NATIVE_MASK, data); else memory_write_generic<Width, AddrShift, Endian, 2, true>([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffff); } 1142 void write_dword(offs_t address, u32 data, u32 mask) { memory_write_generic<Width, AddrShift, Endian, 2, true>([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } 1143 void write_dword_unaligned(offs_t address, u32 data) { memory_write_generic<Width, AddrShift, Endian, 2, false>([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffff); } 1144 void write_dword_unaligned(offs_t address, u32 data, u32 mask) { memory_write_generic<Width, AddrShift, Endian, 2, false>([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } 1145 void write_qword(offs_t address, u64 data) { if (Width == 3) write_native(address & ~NATIVE_MASK, data); else memory_write_generic<Width, AddrShift, Endian, 3, true>([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffffffffffffU); } 1146 void write_qword(offs_t address, u64 data, u64 mask) { memory_write_generic<Width, AddrShift, Endian, 3, true>([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } 1147 void write_qword_unaligned(offs_t address, u64 data) { memory_write_generic<Width, AddrShift, Endian, 3, false>([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffffffffffffU); } 1148 void write_qword_unaligned(offs_t address, u64 data, u64 mask) { memory_write_generic<Width, AddrShift, Endian, 3, false>([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } 1149 1150 private: 1151 address_space * m_space; 1152 1153 offs_t m_addrmask; // address mask 1154 offs_t m_addrstart_r; // minimum valid address for reading 1155 offs_t m_addrend_r; // maximum valid address for reading 1156 offs_t m_addrstart_w; // minimum valid address for writing 1157 offs_t m_addrend_w; // maximum valid address for writing 1158 handler_entry_read <Width, AddrShift, Endian> *m_cache_r; // read cache 1159 handler_entry_write<Width, AddrShift, Endian> *m_cache_w; // write cache 1160 1161 handler_entry_read <Width, AddrShift, Endian> *m_root_read; // decode tree roots 1162 handler_entry_write<Width, AddrShift, Endian> *m_root_write; 1163 1164 NativeType read_native(offs_t address, NativeType mask = ~NativeType(0)); 1165 void write_native(offs_t address, NativeType data, NativeType mask = ~NativeType(0)); 1166 1167 void set(address_space *space, std::pair<void *, void *> rw); 1168 }; 1169 }} 1170 1171 1172 // ======================> memory_access cache/specific type dispatcher 1173 1174 template<int HighBits, int Width, int AddrShift, endianness_t Endian> struct memory_access { 1175 static constexpr int Level = emu::detail::handler_entry_dispatch_level(HighBits); 1176 1177 using cache = emu::detail::memory_access_cache<Width, AddrShift, Endian>; 1178 using specific = emu::detail::memory_access_specific<Level, Width, AddrShift, Endian>; 1179 }; 1180 1181 1182 1183 // ======================> address_space_config 1184 1185 // describes an address space and provides basic functions to map addresses to bytes 1186 class address_space_config 1187 { 1188 friend class address_map; 1189 1190 public: 1191 // construction/destruction 1192 address_space_config(); 1193 address_space_config(const char *name, endianness_t endian, u8 datawidth, u8 addrwidth, s8 addrshift = 0, address_map_constructor internal = address_map_constructor()); 1194 address_space_config(const char *name, endianness_t endian, u8 datawidth, u8 addrwidth, s8 addrshift, u8 logwidth, u8 pageshift, address_map_constructor internal = address_map_constructor()); 1195 1196 // getters 1197 const char *name() const { return m_name; } 1198 endianness_t endianness() const { return m_endianness; } 1199 int data_width() const { return m_data_width; } 1200 int addr_width() const { return m_addr_width; } 1201 int addr_shift() const { return m_addr_shift; } 1202 int logaddr_width() const { return m_logaddr_width; } 1203 int page_shift() const { return m_page_shift; } 1204 bool is_octal() const { return m_is_octal; } 1205 1206 // Actual alignment of the bus addresses 1207 int alignment() const { int bytes = m_data_width / 8; return m_addr_shift < 0 ? bytes >> -m_addr_shift : bytes << m_addr_shift; } 1208 1209 // Address delta to byte delta helpers 1210 inline offs_t addr2byte(offs_t address) const { return (m_addr_shift < 0) ? (address << -m_addr_shift) : (address >> m_addr_shift); } 1211 inline offs_t byte2addr(offs_t address) const { return (m_addr_shift > 0) ? (address << m_addr_shift) : (address >> -m_addr_shift); } 1212 1213 // address-to-byte conversion helpers 1214 inline offs_t addr2byte_end(offs_t address) const { return (m_addr_shift < 0) ? ((address << -m_addr_shift) | ((1 << -m_addr_shift) - 1)) : (address >> m_addr_shift); } 1215 inline offs_t byte2addr_end(offs_t address) const { return (m_addr_shift > 0) ? ((address << m_addr_shift) | ((1 << m_addr_shift) - 1)) : (address >> -m_addr_shift); } 1216 1217 // state (TODO: privatize) 1218 const char * m_name; 1219 endianness_t m_endianness; 1220 u8 m_data_width; 1221 u8 m_addr_width; 1222 s8 m_addr_shift; 1223 u8 m_logaddr_width; 1224 u8 m_page_shift; 1225 bool m_is_octal; // to determine if messages/debugger will show octal or hex 1226 1227 address_map_constructor m_internal_map; 1228 }; 1229 1230 1231 // ======================> address_space 1232 1233 // address_space holds live information about an address space 1234 class address_space 1235 { 1236 friend class memory_bank; 1237 friend class memory_block; 1238 template<int Width, int AddrShift, endianness_t Endian> friend class handler_entry_read_unmapped; 1239 template<int Width, int AddrShift, endianness_t Endian> friend class handler_entry_write_unmapped; 1240 1241 struct notifier_t { 1242 std::function<void (read_or_write)> m_notifier; 1243 int m_id; 1244 }; 1245 1246 protected: 1247 // construction/destruction 1248 address_space(memory_manager &manager, device_memory_interface &memory, int spacenum); 1249 1250 public: 1251 virtual ~address_space(); 1252 1253 // getters 1254 device_t &device() const { return m_device; } 1255 const char *name() const { return m_name; } 1256 int spacenum() const { return m_spacenum; } 1257 address_map *map() const { return m_map.get(); } 1258 1259 template<int Width, int AddrShift, endianness_t Endian> void cache(emu::detail::memory_access_cache<Width, AddrShift, Endian> &v) { 1260 if(AddrShift != m_config.addr_shift()) 1261 fatalerror("Requesting cache() with address shift %d while the config says %d\n", AddrShift, m_config.addr_shift()); 1262 if(8 << Width != m_config.data_width()) 1263 fatalerror("Requesting cache() with data width %d while the config says %d\n", 8 << Width, m_config.data_width()); 1264 if(Endian != m_config.endianness()) 1265 fatalerror("Requesting cache() with endianness %s while the config says %s\n", 1266 endianness_names[Endian], endianness_names[m_config.endianness()]); 1267 1268 v.set(this, get_cache_info()); 1269 } 1270 1271 template<int Level, int Width, int AddrShift, endianness_t Endian> void specific(emu::detail::memory_access_specific<Level, Width, AddrShift, Endian> &v) { 1272 if(Level != emu::detail::handler_entry_dispatch_level(m_config.addr_width())) 1273 fatalerror("Requesting specific() with wrong level, bad address width (the config says %d)\n", m_config.addr_width()); 1274 if(AddrShift != m_config.addr_shift()) 1275 fatalerror("Requesting specific() with address shift %d while the config says %d\n", AddrShift, m_config.addr_shift()); 1276 if(8 << Width != m_config.data_width()) 1277 fatalerror("Requesting specific() with data width %d while the config says %d\n", 8 << Width, m_config.data_width()); 1278 if(Endian != m_config.endianness()) 1279 fatalerror("Requesting spefific() with endianness %s while the config says %s\n", 1280 endianness_names[Endian], endianness_names[m_config.endianness()]); 1281 1282 v.set(this, get_specific_info()); 1283 } 1284 1285 int add_change_notifier(std::function<void (read_or_write)> n); 1286 void remove_change_notifier(int id); 1287 1288 void invalidate_caches(read_or_write mode) { 1289 if(u32(mode) & ~m_in_notification) { 1290 u32 old = m_in_notification; 1291 m_in_notification |= u32(mode); 1292 for(const auto &n : m_notifiers) 1293 n.m_notifier(mode); 1294 m_in_notification = old; 1295 } 1296 } 1297 1298 virtual void validate_reference_counts() const = 0; 1299 1300 virtual void remove_passthrough(std::unordered_set<handler_entry *> &handlers) = 0; 1301 1302 int data_width() const { return m_config.data_width(); } 1303 int addr_width() const { return m_config.addr_width(); } 1304 int logaddr_width() const { return m_config.logaddr_width(); } 1305 int alignment() const { return m_config.alignment(); } 1306 endianness_t endianness() const { return m_config.endianness(); } 1307 int addr_shift() const { return m_config.addr_shift(); } 1308 u64 unmap() const { return m_unmap; } 1309 bool is_octal() const { return m_config.is_octal(); } 1310 1311 offs_t addrmask() const { return m_addrmask; } 1312 u8 addrchars() const { return m_addrchars; } 1313 offs_t logaddrmask() const { return m_logaddrmask; } 1314 u8 logaddrchars() const { return m_logaddrchars; } 1315 1316 // debug helpers 1317 virtual std::string get_handler_string(read_or_write readorwrite, offs_t byteaddress) const = 0; 1318 virtual void dump_maps(std::vector<memory_entry> &read_map, std::vector<memory_entry> &write_map) const = 0; 1319 bool log_unmap() const { return m_log_unmap; } 1320 void set_log_unmap(bool log) { m_log_unmap = log; } 1321 1322 // general accessors 1323 virtual void accessors(data_accessors &accessors) const = 0; 1324 virtual void *get_read_ptr(offs_t address) const = 0; 1325 virtual void *get_write_ptr(offs_t address) const = 0; 1326 1327 // read accessors 1328 virtual u8 read_byte(offs_t address) = 0; 1329 virtual u16 read_word(offs_t address) = 0; 1330 virtual u16 read_word(offs_t address, u16 mask) = 0; 1331 virtual u16 read_word_unaligned(offs_t address) = 0; 1332 virtual u16 read_word_unaligned(offs_t address, u16 mask) = 0; 1333 virtual u32 read_dword(offs_t address) = 0; 1334 virtual u32 read_dword(offs_t address, u32 mask) = 0; 1335 virtual u32 read_dword_unaligned(offs_t address) = 0; 1336 virtual u32 read_dword_unaligned(offs_t address, u32 mask) = 0; 1337 virtual u64 read_qword(offs_t address) = 0; 1338 virtual u64 read_qword(offs_t address, u64 mask) = 0; 1339 virtual u64 read_qword_unaligned(offs_t address) = 0; 1340 virtual u64 read_qword_unaligned(offs_t address, u64 mask) = 0; 1341 1342 // write accessors 1343 virtual void write_byte(offs_t address, u8 data) = 0; 1344 virtual void write_word(offs_t address, u16 data) = 0; 1345 virtual void write_word(offs_t address, u16 data, u16 mask) = 0; 1346 virtual void write_word_unaligned(offs_t address, u16 data) = 0; 1347 virtual void write_word_unaligned(offs_t address, u16 data, u16 mask) = 0; 1348 virtual void write_dword(offs_t address, u32 data) = 0; 1349 virtual void write_dword(offs_t address, u32 data, u32 mask) = 0; 1350 virtual void write_dword_unaligned(offs_t address, u32 data) = 0; 1351 virtual void write_dword_unaligned(offs_t address, u32 data, u32 mask) = 0; 1352 virtual void write_qword(offs_t address, u64 data) = 0; 1353 virtual void write_qword(offs_t address, u64 data, u64 mask) = 0; 1354 virtual void write_qword_unaligned(offs_t address, u64 data) = 0; 1355 virtual void write_qword_unaligned(offs_t address, u64 data, u64 mask) = 0; 1356 1357 // address-to-byte conversion helpers 1358 offs_t address_to_byte(offs_t address) const { return m_config.addr2byte(address); } 1359 offs_t address_to_byte_end(offs_t address) const { return m_config.addr2byte_end(address); } 1360 offs_t byte_to_address(offs_t address) const { return m_config.byte2addr(address); } 1361 offs_t byte_to_address_end(offs_t address) const { return m_config.byte2addr_end(address); } 1362 1363 // umap ranges (short form) 1364 void unmap_read(offs_t addrstart, offs_t addrend, offs_t addrmirror = 0) { unmap_generic(addrstart, addrend, addrmirror, read_or_write::READ, false); } 1365 void unmap_write(offs_t addrstart, offs_t addrend, offs_t addrmirror = 0) { unmap_generic(addrstart, addrend, addrmirror, read_or_write::WRITE, false); } 1366 void unmap_readwrite(offs_t addrstart, offs_t addrend, offs_t addrmirror = 0) { unmap_generic(addrstart, addrend, addrmirror, read_or_write::READWRITE, false); } 1367 void nop_read(offs_t addrstart, offs_t addrend, offs_t addrmirror = 0) { unmap_generic(addrstart, addrend, addrmirror, read_or_write::READ, true); } 1368 void nop_write(offs_t addrstart, offs_t addrend, offs_t addrmirror = 0) { unmap_generic(addrstart, addrend, addrmirror, read_or_write::WRITE, true); } 1369 void nop_readwrite(offs_t addrstart, offs_t addrend, offs_t addrmirror = 0) { unmap_generic(addrstart, addrend, addrmirror, read_or_write::READWRITE, true); } 1370 1371 // install ports, banks, RAM (short form) 1372 void install_read_port(offs_t addrstart, offs_t addrend, const char *rtag) { install_read_port(addrstart, addrend, 0, rtag); } 1373 void install_write_port(offs_t addrstart, offs_t addrend, const char *wtag) { install_write_port(addrstart, addrend, 0, wtag); } 1374 void install_readwrite_port(offs_t addrstart, offs_t addrend, const char *rtag, const char *wtag) { install_readwrite_port(addrstart, addrend, 0, rtag, wtag); } 1375 void install_read_bank(offs_t addrstart, offs_t addrend, const char *tag) { install_read_bank(addrstart, addrend, 0, tag); } 1376 void install_write_bank(offs_t addrstart, offs_t addrend, const char *tag) { install_write_bank(addrstart, addrend, 0, tag); } 1377 void install_readwrite_bank(offs_t addrstart, offs_t addrend, const char *tag) { install_readwrite_bank(addrstart, addrend, 0, tag); } 1378 void install_read_bank(offs_t addrstart, offs_t addrend, memory_bank *bank) { install_read_bank(addrstart, addrend, 0, bank); } 1379 void install_write_bank(offs_t addrstart, offs_t addrend, memory_bank *bank) { install_write_bank(addrstart, addrend, 0, bank); } 1380 void install_readwrite_bank(offs_t addrstart, offs_t addrend, memory_bank *bank) { install_readwrite_bank(addrstart, addrend, 0, bank); } 1381 void install_rom(offs_t addrstart, offs_t addrend, void *baseptr = nullptr) { install_rom(addrstart, addrend, 0, baseptr); } 1382 void install_writeonly(offs_t addrstart, offs_t addrend, void *baseptr = nullptr) { install_writeonly(addrstart, addrend, 0, baseptr); } 1383 void install_ram(offs_t addrstart, offs_t addrend, void *baseptr = nullptr) { install_ram(addrstart, addrend, 0, baseptr); } 1384 1385 // install ports, banks, RAM (with mirror/mask) 1386 void install_read_port(offs_t addrstart, offs_t addrend, offs_t addrmirror, const char *rtag) { install_readwrite_port(addrstart, addrend, addrmirror, rtag, ""); } 1387 void install_write_port(offs_t addrstart, offs_t addrend, offs_t addrmirror, const char *wtag) { install_readwrite_port(addrstart, addrend, addrmirror, "", wtag); } 1388 virtual void install_readwrite_port(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string rtag, std::string wtag) = 0; 1389 void install_read_bank(offs_t addrstart, offs_t addrend, offs_t addrmirror, const char *tag) { install_bank_generic(addrstart, addrend, addrmirror, tag, ""); } 1390 void install_write_bank(offs_t addrstart, offs_t addrend, offs_t addrmirror, const char *tag) { install_bank_generic(addrstart, addrend, addrmirror, "", tag); } 1391 void install_readwrite_bank(offs_t addrstart, offs_t addrend, offs_t addrmirror, const char *tag) { install_bank_generic(addrstart, addrend, addrmirror, tag, tag); } 1392 void install_read_bank(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_bank *bank) { install_bank_generic(addrstart, addrend, addrmirror, bank, nullptr); } 1393 void install_write_bank(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_bank *bank) { install_bank_generic(addrstart, addrend, addrmirror, nullptr, bank); } 1394 void install_readwrite_bank(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_bank *bank) { install_bank_generic(addrstart, addrend, addrmirror, bank, bank); } 1395 void install_rom(offs_t addrstart, offs_t addrend, offs_t addrmirror, void *baseptr = nullptr) { install_ram_generic(addrstart, addrend, addrmirror, read_or_write::READ, baseptr); } 1396 void install_writeonly(offs_t addrstart, offs_t addrend, offs_t addrmirror, void *baseptr = nullptr) { install_ram_generic(addrstart, addrend, addrmirror, read_or_write::WRITE, baseptr); } 1397 void install_ram(offs_t addrstart, offs_t addrend, offs_t addrmirror, void *baseptr = nullptr) { install_ram_generic(addrstart, addrend, addrmirror, read_or_write::READWRITE, baseptr); } 1398 1399 // install device memory maps 1400 template <typename T> void install_device(offs_t addrstart, offs_t addrend, T &device, void (T::*map)(address_map &map), u64 unitmask = 0, int cswidth = 0) { 1401 address_map_constructor delegate(map, "dynamic_device_install", &device); 1402 install_device_delegate(addrstart, addrend, device, delegate, unitmask, cswidth); 1403 } 1404 1405 virtual void install_device_delegate(offs_t addrstart, offs_t addrend, device_t &device, address_map_constructor &map, u64 unitmask = 0, int cswidth = 0) = 0; 1406 1407 // install taps without mirroring 1408 memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_read_tap(addrstart, addrend, 0, name, tap, mph); } 1409 memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_read_tap(addrstart, addrend, 0, name, tap, mph); } 1410 memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_read_tap(addrstart, addrend, 0, name, tap, mph); } 1411 memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_read_tap(addrstart, addrend, 0, name, tap, mph); } 1412 memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_write_tap(addrstart, addrend, 0, name, tap, mph); } 1413 memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_write_tap(addrstart, addrend, 0, name, tap, mph); } 1414 memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_write_tap(addrstart, addrend, 0, name, tap, mph); } 1415 memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_write_tap(addrstart, addrend, 0, name, tap, mph); } 1416 memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tapr, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr) { return install_readwrite_tap(addrstart, addrend, 0, name, tapr, tapw, mph); } 1417 memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tapr, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr) { return install_readwrite_tap(addrstart, addrend, 0, name, tapr, tapw, mph); } 1418 memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, 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) { return install_readwrite_tap(addrstart, addrend, 0, name, tapr, tapw, mph); } 1419 memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, 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) { return install_readwrite_tap(addrstart, addrend, 0, name, tapr, tapw, mph); } 1420 1421 // install taps with mirroring 1422 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, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph = nullptr); 1423 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, u16 &data, u16 mem_mask)> tap, memory_passthrough_handler *mph = nullptr); 1424 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, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph = nullptr); 1425 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, u64 &data, u64 mem_mask)> tap, memory_passthrough_handler *mph = nullptr); 1426 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, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph = nullptr); 1427 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, u16 &data, u16 mem_mask)> tap, memory_passthrough_handler *mph = nullptr); 1428 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, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph = nullptr); 1429 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, u64 &data, u64 mem_mask)> tap, memory_passthrough_handler *mph = nullptr); 1430 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, u8 &data, u8 mem_mask)> tapr, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr); 1431 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, u16 &data, u16 mem_mask)> tapr, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr); 1432 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); 1433 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); 1434 1435 1436 // install new-style delegate handlers (short form) 1437 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); } 1438 void install_write_handler(offs_t addrstart, offs_t addrend, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth); } 1439 void install_readwrite_handler(offs_t addrstart, offs_t addrend, read8_delegate rhandler, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth); } 1440 void install_read_handler(offs_t addrstart, offs_t addrend, read16_delegate rhandler, u64 unitmask = 0, int cswidth = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth); } 1441 void install_write_handler(offs_t addrstart, offs_t addrend, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth); } 1442 void install_readwrite_handler(offs_t addrstart, offs_t addrend, read16_delegate rhandler, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth); } 1443 void install_read_handler(offs_t addrstart, offs_t addrend, read32_delegate rhandler, u64 unitmask = 0, int cswidth = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth); } 1444 void install_write_handler(offs_t addrstart, offs_t addrend, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth); } 1445 void install_readwrite_handler(offs_t addrstart, offs_t addrend, read32_delegate rhandler, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth); } 1446 void install_read_handler(offs_t addrstart, offs_t addrend, read64_delegate rhandler, u64 unitmask = 0, int cswidth = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth); } 1447 void install_write_handler(offs_t addrstart, offs_t addrend, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth); } 1448 void install_readwrite_handler(offs_t addrstart, offs_t addrend, read64_delegate rhandler, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth); } 1449 1450 void install_read_handler(offs_t addrstart, offs_t addrend, read8m_delegate rhandler, u64 unitmask = 0, int cswidth = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth); } 1451 void install_write_handler(offs_t addrstart, offs_t addrend, write8m_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth); } 1452 void install_readwrite_handler(offs_t addrstart, offs_t addrend, read8m_delegate rhandler, write8m_delegate whandler, u64 unitmask = 0, int cswidth = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth); } 1453 void install_read_handler(offs_t addrstart, offs_t addrend, read16m_delegate rhandler, u64 unitmask = 0, int cswidth = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth); } 1454 void install_write_handler(offs_t addrstart, offs_t addrend, write16m_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth); } 1455 void install_readwrite_handler(offs_t addrstart, offs_t addrend, read16m_delegate rhandler, write16m_delegate whandler, u64 unitmask = 0, int cswidth = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth); } 1456 void install_read_handler(offs_t addrstart, offs_t addrend, read32m_delegate rhandler, u64 unitmask = 0, int cswidth = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth); } 1457 void install_write_handler(offs_t addrstart, offs_t addrend, write32m_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth); } 1458 void install_readwrite_handler(offs_t addrstart, offs_t addrend, read32m_delegate rhandler, write32m_delegate whandler, u64 unitmask = 0, int cswidth = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth); } 1459 void install_read_handler(offs_t addrstart, offs_t addrend, read64m_delegate rhandler, u64 unitmask = 0, int cswidth = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth); } 1460 void install_write_handler(offs_t addrstart, offs_t addrend, write64m_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth); } 1461 void install_readwrite_handler(offs_t addrstart, offs_t addrend, read64m_delegate rhandler, write64m_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth); } 1462 1463 void install_read_handler(offs_t addrstart, offs_t addrend, read8s_delegate rhandler, u64 unitmask = 0, int cswidth = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth); } 1464 void install_write_handler(offs_t addrstart, offs_t addrend, write8s_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth); } 1465 void install_readwrite_handler(offs_t addrstart, offs_t addrend, read8s_delegate rhandler, write8s_delegate whandler, u64 unitmask = 0, int cswidth = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth); } 1466 void install_read_handler(offs_t addrstart, offs_t addrend, read16s_delegate rhandler, u64 unitmask = 0, int cswidth = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth); } 1467 void install_write_handler(offs_t addrstart, offs_t addrend, write16s_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth); } 1468 void install_readwrite_handler(offs_t addrstart, offs_t addrend, read16s_delegate rhandler, write16s_delegate whandler, u64 unitmask = 0, int cswidth = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth); } 1469 void install_read_handler(offs_t addrstart, offs_t addrend, read32s_delegate rhandler, u64 unitmask = 0, int cswidth = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth); } 1470 void install_write_handler(offs_t addrstart, offs_t addrend, write32s_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth); } 1471 void install_readwrite_handler(offs_t addrstart, offs_t addrend, read32s_delegate rhandler, write32s_delegate whandler, u64 unitmask = 0, int cswidth = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth); } 1472 void install_read_handler(offs_t addrstart, offs_t addrend, read64s_delegate rhandler, u64 unitmask = 0, int cswidth = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth); } 1473 void install_write_handler(offs_t addrstart, offs_t addrend, write64s_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth); } 1474 void install_readwrite_handler(offs_t addrstart, offs_t addrend, read64s_delegate rhandler, write64s_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth); } 1475 1476 void install_read_handler(offs_t addrstart, offs_t addrend, read8sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth); } 1477 void install_write_handler(offs_t addrstart, offs_t addrend, write8sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth); } 1478 void install_readwrite_handler(offs_t addrstart, offs_t addrend, read8sm_delegate rhandler, write8sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth); } 1479 void install_read_handler(offs_t addrstart, offs_t addrend, read16sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth); } 1480 void install_write_handler(offs_t addrstart, offs_t addrend, write16sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth); } 1481 void install_readwrite_handler(offs_t addrstart, offs_t addrend, read16sm_delegate rhandler, write16sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth); } 1482 void install_read_handler(offs_t addrstart, offs_t addrend, read32sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth); } 1483 void install_write_handler(offs_t addrstart, offs_t addrend, write32sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth); } 1484 void install_readwrite_handler(offs_t addrstart, offs_t addrend, read32sm_delegate rhandler, write32sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth); } 1485 void install_read_handler(offs_t addrstart, offs_t addrend, read64sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth); } 1486 void install_write_handler(offs_t addrstart, offs_t addrend, write64sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth); } 1487 void install_readwrite_handler(offs_t addrstart, offs_t addrend, read64sm_delegate rhandler, write64sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth); } 1488 1489 void install_read_handler(offs_t addrstart, offs_t addrend, read8mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth); } 1490 void install_write_handler(offs_t addrstart, offs_t addrend, write8mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth); } 1491 void install_readwrite_handler(offs_t addrstart, offs_t addrend, read8mo_delegate rhandler, write8mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth); } 1492 void install_read_handler(offs_t addrstart, offs_t addrend, read16mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth); } 1493 void install_write_handler(offs_t addrstart, offs_t addrend, write16mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth); } 1494 void install_readwrite_handler(offs_t addrstart, offs_t addrend, read16mo_delegate rhandler, write16mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth); } 1495 void install_read_handler(offs_t addrstart, offs_t addrend, read32mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth); } 1496 void install_write_handler(offs_t addrstart, offs_t addrend, write32mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth); } 1497 void install_readwrite_handler(offs_t addrstart, offs_t addrend, read32mo_delegate rhandler, write32mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth); } 1498 void install_read_handler(offs_t addrstart, offs_t addrend, read64mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth); } 1499 void install_write_handler(offs_t addrstart, offs_t addrend, write64mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth); } 1500 void install_readwrite_handler(offs_t addrstart, offs_t addrend, read64mo_delegate rhandler, write64mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth); } 1501 1502 void install_read_handler(offs_t addrstart, offs_t addrend, read8smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth); } 1503 void install_write_handler(offs_t addrstart, offs_t addrend, write8smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth); } 1504 void install_readwrite_handler(offs_t addrstart, offs_t addrend, read8smo_delegate rhandler, write8smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth); } 1505 void install_read_handler(offs_t addrstart, offs_t addrend, read16smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth); } 1506 void install_write_handler(offs_t addrstart, offs_t addrend, write16smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth); } 1507 void install_readwrite_handler(offs_t addrstart, offs_t addrend, read16smo_delegate rhandler, write16smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth); } 1508 void install_read_handler(offs_t addrstart, offs_t addrend, read32smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth); } 1509 void install_write_handler(offs_t addrstart, offs_t addrend, write32smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth); } 1510 void install_readwrite_handler(offs_t addrstart, offs_t addrend, read32smo_delegate rhandler, write32smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth); } 1511 void install_read_handler(offs_t addrstart, offs_t addrend, read64smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth); } 1512 void install_write_handler(offs_t addrstart, offs_t addrend, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth); } 1513 void install_readwrite_handler(offs_t addrstart, offs_t addrend, read64smo_delegate rhandler, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) { install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth); } 1514 1515 // install new-style delegate handlers (with mirror/mask) 1516 virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate rhandler, u64 unitmask = 0, int cswidth = 0) = 0; 1517 virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0) = 0; 1518 virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate rhandler, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0) = 0; 1519 virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate rhandler, u64 unitmask = 0, int cswidth = 0) = 0; 1520 virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0) = 0; 1521 virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate rhandler, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0) = 0; 1522 virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate rhandler, u64 unitmask = 0, int cswidth = 0) = 0; 1523 virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0) = 0; 1524 virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate rhandler, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0) = 0; 1525 virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate rhandler, u64 unitmask = 0, int cswidth = 0) = 0; 1526 virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0) = 0; 1527 virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate rhandler, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0) = 0; 1528 1529 virtual 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) = 0; 1530 virtual 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) = 0; 1531 virtual 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) = 0; 1532 virtual 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) = 0; 1533 virtual 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) = 0; 1534 virtual 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) = 0; 1535 virtual 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) = 0; 1536 virtual 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) = 0; 1537 virtual 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) = 0; 1538 virtual 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) = 0; 1539 virtual 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) = 0; 1540 virtual 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) = 0; 1541 1542 virtual 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) = 0; 1543 virtual 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) = 0; 1544 virtual 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) = 0; 1545 virtual 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) = 0; 1546 virtual 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) = 0; 1547 virtual 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) = 0; 1548 virtual 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) = 0; 1549 virtual 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) = 0; 1550 virtual 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) = 0; 1551 virtual 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) = 0; 1552 virtual 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) = 0; 1553 virtual 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) = 0; 1554 1555 virtual 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) = 0; 1556 virtual 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) = 0; 1557 virtual 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) = 0; 1558 virtual 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) = 0; 1559 virtual 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) = 0; 1560 virtual 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) = 0; 1561 virtual 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) = 0; 1562 virtual 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) = 0; 1563 virtual 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) = 0; 1564 virtual 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) = 0; 1565 virtual 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) = 0; 1566 virtual 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) = 0; 1567 1568 virtual 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) = 0; 1569 virtual 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) = 0; 1570 virtual 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) = 0; 1571 virtual 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) = 0; 1572 virtual 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) = 0; 1573 virtual 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) = 0; 1574 virtual 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) = 0; 1575 virtual 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) = 0; 1576 virtual 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) = 0; 1577 virtual 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) = 0; 1578 virtual 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) = 0; 1579 virtual 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) = 0; 1580 1581 virtual 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) = 0; 1582 virtual 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) = 0; 1583 virtual 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) = 0; 1584 virtual 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) = 0; 1585 virtual 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) = 0; 1586 virtual 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) = 0; 1587 virtual 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) = 0; 1588 virtual 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) = 0; 1589 virtual 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) = 0; 1590 virtual 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) = 0; 1591 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; 1592 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; 1593 1594 // setup 1595 void prepare_map(); 1596 void populate_from_map(address_map *map = nullptr); 1597 void allocate_memory(); 1598 void locate_memory(); 1599 1600 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); } 1601 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); } 1602 1603 protected: 1604 // internal helpers 1605 virtual std::pair<void *, void *> get_cache_info() = 0; 1606 virtual std::pair<const void *, const void *> get_specific_info() = 0; 1607 1608 void populate_map_entry(const address_map_entry &entry, read_or_write readorwrite); 1609 virtual void unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, bool quiet) = 0; 1610 virtual void install_ram_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, void *baseptr) = 0; 1611 virtual void install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string rtag, std::string wtag) = 0; 1612 virtual void install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_bank *rbank, memory_bank *wbank) = 0; 1613 void adjust_addresses(offs_t &start, offs_t &end, offs_t &mask, offs_t &mirror); 1614 void *find_backing_memory(offs_t addrstart, offs_t addrend); 1615 bool needs_backing_store(const address_map_entry &entry); 1616 memory_bank &bank_find_or_allocate(const char *tag, offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite); 1617 address_map_entry *block_assign_intersecting(offs_t bytestart, offs_t byteend, u8 *base); 1618 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); 1619 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); 1620 void check_address(const char *function, offs_t addrstart, offs_t addrend); 1621 1622 // private state 1623 const address_space_config &m_config; // configuration of this space 1624 device_t & m_device; // reference to the owning device 1625 std::unique_ptr<address_map> m_map; // original memory map 1626 offs_t m_addrmask; // physical address mask 1627 offs_t m_logaddrmask; // logical address mask 1628 u64 m_unmap; // unmapped value 1629 int m_spacenum; // address space index 1630 bool m_log_unmap; // log unmapped accesses in this space? 1631 const char * m_name; // friendly name of the address space 1632 u8 m_addrchars; // number of characters to use for physical addresses 1633 u8 m_logaddrchars; // number of characters to use for logical addresses 1634 1635 handler_entry *m_unmap_r; 1636 handler_entry *m_unmap_w; 1637 1638 handler_entry *m_nop_r; 1639 handler_entry *m_nop_w; 1640 1641 std::vector<std::unique_ptr<memory_passthrough_handler>> m_mphs; 1642 1643 std::vector<notifier_t> m_notifiers; // notifier list for address map change 1644 int m_notifier_id; // next notifier id 1645 u32 m_in_notification; // notification(s) currently being done 1646 memory_manager & m_manager; // reference to the owning manager 1647 }; 1648 1649 1650 // ======================> memory_block 1651 1652 // a memory block is a chunk of RAM associated with a range of memory in a device's address space 1653 class memory_block 1654 { 1655 DISABLE_COPYING(memory_block); 1656 1657 public: 1658 // construction/destruction 1659 memory_block(address_space &space, offs_t start, offs_t end, void *memory = nullptr); 1660 ~memory_block(); 1661 1662 // getters 1663 running_machine &machine() const { return m_machine; } 1664 offs_t addrstart() const { return m_addrstart; } 1665 offs_t addrend() const { return m_addrend; } 1666 u8 *data() const { return m_data; } 1667 1668 // is the given range contained by this memory block? 1669 bool contains(address_space &space, offs_t addrstart, offs_t addrend) const 1670 { 1671 return (&space == &m_space && m_addrstart <= addrstart && m_addrend >= addrend); 1672 } 1673 1674 private: 1675 // internal state 1676 running_machine & m_machine; // need the machine to free our memory 1677 address_space & m_space; // which address space are we associated with? 1678 offs_t m_addrstart, m_addrend; // start/end for verifying a match 1679 u8 * m_data; // pointer to the data for this block 1680 std::vector<u8> m_allocated; // pointer to the actually allocated block 1681 }; 1682 1683 1684 // ======================> memory_bank 1685 1686 // a memory bank is a global pointer to memory that can be shared across devices and changed dynamically 1687 class memory_bank 1688 { 1689 // a bank reference is an entry in a list of address spaces that reference a given bank 1690 class bank_reference 1691 { 1692 public: 1693 // construction/destruction 1694 bank_reference(address_space &space, read_or_write readorwrite) 1695 : m_space(space), 1696 m_readorwrite(readorwrite) { } 1697 1698 // getters 1699 address_space &space() const { return m_space; } 1700 1701 // does this reference match the space+read/write combination? 1702 bool matches(const address_space &space, read_or_write readorwrite) const 1703 { 1704 return (&space == &m_space && (readorwrite == read_or_write::READWRITE || readorwrite == m_readorwrite)); 1705 } 1706 1707 private: 1708 // internal state 1709 address_space & m_space; // address space that references us 1710 read_or_write m_readorwrite; // used for read or write? 1711 1712 }; 1713 1714 public: 1715 // construction/destruction 1716 memory_bank(address_space &space, int index, offs_t start, offs_t end, const char *tag = nullptr); 1717 ~memory_bank(); 1718 1719 // getters 1720 running_machine &machine() const { return m_machine; } 1721 int entry() const { return m_curentry; } 1722 bool anonymous() const { return m_anonymous; } 1723 offs_t addrstart() const { return m_addrstart; } 1724 void *base() const { return m_entries.empty() ? nullptr : m_entries[m_curentry]; } 1725 const char *tag() const { return m_tag.c_str(); } 1726 const char *name() const { return m_name.c_str(); } 1727 1728 // compare a range against our range 1729 bool matches_exactly(offs_t addrstart, offs_t addrend) const { return (m_addrstart == addrstart && m_addrend == addrend); } 1730 bool fully_covers(offs_t addrstart, offs_t addrend) const { return (m_addrstart <= addrstart && m_addrend >= addrend); } 1731 bool is_covered_by(offs_t addrstart, offs_t addrend) const { return (m_addrstart >= addrstart && m_addrend <= addrend); } 1732 bool straddles(offs_t addrstart, offs_t addrend) const { return (m_addrstart < addrend && m_addrend > addrstart); } 1733 1734 // track and verify address space references to this bank 1735 bool references_space(const address_space &space, read_or_write readorwrite) const; 1736 void add_reference(address_space &space, read_or_write readorwrite); 1737 1738 // set the base explicitly 1739 void set_base(void *base); 1740 1741 // configure and set entries 1742 void configure_entry(int entrynum, void *base); 1743 void configure_entries(int startentry, int numentries, void *base, offs_t stride); 1744 void set_entry(int entrynum); 1745 void add_notifier(std::function<void (void *)> cb); 1746 1747 private: 1748 // internal state 1749 running_machine & m_machine; // need the machine to free our memory 1750 std::vector<u8 *> m_entries; // the entries 1751 bool m_anonymous; // are we anonymous or explicit? 1752 offs_t m_addrstart; // start offset 1753 offs_t m_addrend; // end offset 1754 int m_curentry; // current entry 1755 std::string m_name; // friendly name for this bank 1756 std::string m_tag; // tag for this bank 1757 std::vector<std::unique_ptr<bank_reference>> m_reflist; // list of address spaces referencing this bank 1758 std::vector<std::function<void (void *)>> m_alloc_notifier; // list of notifier targets when allocating 1759 }; 1760 1761 1762 // ======================> memory_share 1763 1764 // a memory share contains information about shared memory region 1765 class memory_share 1766 { 1767 public: 1768 // construction/destruction 1769 memory_share(u8 width, size_t bytes, endianness_t endianness, void *ptr = nullptr) 1770 : m_ptr(ptr), 1771 m_bytes(bytes), 1772 m_endianness(endianness), 1773 m_bitwidth(width), 1774 m_bytewidth(width <= 8 ? 1 : width <= 16 ? 2 : width <= 32 ? 4 : 8) 1775 { } 1776 1777 // getters 1778 void *ptr() const { return m_ptr; } 1779 size_t bytes() const { return m_bytes; } 1780 endianness_t endianness() const { return m_endianness; } 1781 u8 bitwidth() const { return m_bitwidth; } 1782 u8 bytewidth() const { return m_bytewidth; } 1783 1784 // setters 1785 void set_ptr(void *ptr) { m_ptr = ptr; } 1786 1787 private: 1788 // internal state 1789 void * m_ptr; // pointer to the memory backing the region 1790 size_t m_bytes; // size of the shared region in bytes 1791 endianness_t m_endianness; // endianness of the memory 1792 u8 m_bitwidth; // width of the shared region in bits 1793 u8 m_bytewidth; // width in bytes, rounded up to a power of 2 1794 1795 }; 1796 1797 1798 // ======================> memory_region 1799 1800 // memory region object 1801 class memory_region 1802 { 1803 DISABLE_COPYING(memory_region); 1804 1805 friend class memory_manager; 1806 public: 1807 // construction/destruction 1808 memory_region(running_machine &machine, const char *name, u32 length, u8 width, endianness_t endian); 1809 1810 // getters 1811 running_machine &machine() const { return m_machine; } 1812 u8 *base() { return (m_buffer.size() > 0) ? &m_buffer[0] : nullptr; } 1813 u8 *end() { return base() + m_buffer.size(); } 1814 u32 bytes() const { return m_buffer.size(); } 1815 const char *name() const { return m_name.c_str(); } 1816 1817 // flag expansion 1818 endianness_t endianness() const { return m_endianness; } 1819 u8 bitwidth() const { return m_bitwidth; } 1820 u8 bytewidth() const { return m_bytewidth; } 1821 1822 // data access 1823 u8 &as_u8(offs_t offset = 0) { return m_buffer[offset]; } 1824 u16 &as_u16(offs_t offset = 0) { return reinterpret_cast<u16 *>(base())[offset]; } 1825 u32 &as_u32(offs_t offset = 0) { return reinterpret_cast<u32 *>(base())[offset]; } 1826 u64 &as_u64(offs_t offset = 0) { return reinterpret_cast<u64 *>(base())[offset]; } 1827 1828 private: 1829 // internal data 1830 running_machine & m_machine; 1831 std::string m_name; 1832 std::vector<u8> m_buffer; 1833 endianness_t m_endianness; 1834 u8 m_bitwidth; 1835 u8 m_bytewidth; 1836 }; 1837 1838 1839 1840 // ======================> memory_manager 1841 1842 // holds internal state for the memory system 1843 class memory_manager 1844 { 1845 friend class address_space; 1846 template<int Level, int Width, int AddrShift, endianness_t Endian> friend class address_space_specific; 1847 friend memory_region::memory_region(running_machine &machine, const char *name, u32 length, u8 width, endianness_t endian); 1848 public: 1849 // construction/destruction 1850 memory_manager(running_machine &machine); 1851 void initialize(); 1852 1853 // getters 1854 running_machine &machine() const { return m_machine; } 1855 const std::unordered_map<std::string, std::unique_ptr<memory_bank>> &banks() const { return m_banklist; } 1856 const std::unordered_map<std::string, std::unique_ptr<memory_region>> ®ions() const { return m_regionlist; } 1857 const std::unordered_map<std::string, std::unique_ptr<memory_share>> &shares() const { return m_sharelist; } 1858 1859 // regions 1860 memory_region *region_alloc(const char *name, u32 length, u8 width, endianness_t endian); 1861 void region_free(const char *name); 1862 memory_region *region_containing(const void *memory, offs_t bytes) const; 1863 1864 memory_bank *find(const char *tag) const; 1865 memory_bank *find(address_space &space, offs_t addrstart, offs_t addrend) const; 1866 memory_bank *allocate(address_space &space, offs_t addrstart, offs_t addrend, const char *tag = nullptr); 1867 1868 private: 1869 void allocate(device_memory_interface &memory); 1870 1871 // internal state 1872 running_machine & m_machine; // reference to the machine 1873 bool m_initialized; // have we completed initialization? 1874 1875 std::vector<std::unique_ptr<memory_block>> m_blocklist; // head of the list of memory blocks 1876 1877 std::unordered_map<std::string, std::unique_ptr<memory_bank>> m_banklist; // data gathered for each bank 1878 std::unordered_map<std::string, std::unique_ptr<memory_share>> m_sharelist; // map for share lookups 1879 std::unordered_map<std::string, std::unique_ptr<memory_region>> m_regionlist; // list of memory regions 1880 }; 1881 1882 1883 1884 //************************************************************************** 1885 // MACROS 1886 //************************************************************************** 1887 1888 1889 // helper macro for merging data with the memory mask 1890 #define COMBINE_DATA(varptr) (*(varptr) = (*(varptr) & ~mem_mask) | (data & mem_mask)) 1891 1892 #define ACCESSING_BITS_0_7 ((mem_mask & 0x000000ffU) != 0) 1893 #define ACCESSING_BITS_8_15 ((mem_mask & 0x0000ff00U) != 0) 1894 #define ACCESSING_BITS_16_23 ((mem_mask & 0x00ff0000U) != 0) 1895 #define ACCESSING_BITS_24_31 ((mem_mask & 0xff000000U) != 0) 1896 #define ACCESSING_BITS_32_39 ((mem_mask & 0x000000ff00000000U) != 0) 1897 #define ACCESSING_BITS_40_47 ((mem_mask & 0x0000ff0000000000U) != 0) 1898 #define ACCESSING_BITS_48_55 ((mem_mask & 0x00ff000000000000U) != 0) 1899 #define ACCESSING_BITS_56_63 ((mem_mask & 0xff00000000000000U) != 0) 1900 1901 #define ACCESSING_BITS_0_15 ((mem_mask & 0x0000ffffU) != 0) 1902 #define ACCESSING_BITS_16_31 ((mem_mask & 0xffff0000U) != 0) 1903 #define ACCESSING_BITS_32_47 ((mem_mask & 0x0000ffff00000000U) != 0) 1904 #define ACCESSING_BITS_48_63 ((mem_mask & 0xffff000000000000U) != 0) 1905 1906 #define ACCESSING_BITS_0_31 ((mem_mask & 0xffffffffU) != 0) 1907 #define ACCESSING_BITS_32_63 ((mem_mask & 0xffffffff00000000U) != 0) 1908 1909 1910 // macros for accessing bytes and words within larger chunks 1911 1912 // read/write a byte to a 16-bit space 1913 #define BYTE_XOR_BE(a) ((a) ^ NATIVE_ENDIAN_VALUE_LE_BE(1,0)) 1914 #define BYTE_XOR_LE(a) ((a) ^ NATIVE_ENDIAN_VALUE_LE_BE(0,1)) 1915 1916 // read/write a byte to a 32-bit space 1917 #define BYTE4_XOR_BE(a) ((a) ^ NATIVE_ENDIAN_VALUE_LE_BE(3,0)) 1918 #define BYTE4_XOR_LE(a) ((a) ^ NATIVE_ENDIAN_VALUE_LE_BE(0,3)) 1919 1920 // read/write a word to a 32-bit space 1921 #define WORD_XOR_BE(a) ((a) ^ NATIVE_ENDIAN_VALUE_LE_BE(2,0)) 1922 #define WORD_XOR_LE(a) ((a) ^ NATIVE_ENDIAN_VALUE_LE_BE(0,2)) 1923 1924 // read/write a byte to a 64-bit space 1925 #define BYTE8_XOR_BE(a) ((a) ^ NATIVE_ENDIAN_VALUE_LE_BE(7,0)) 1926 #define BYTE8_XOR_LE(a) ((a) ^ NATIVE_ENDIAN_VALUE_LE_BE(0,7)) 1927 1928 // read/write a word to a 64-bit space 1929 #define WORD2_XOR_BE(a) ((a) ^ NATIVE_ENDIAN_VALUE_LE_BE(6,0)) 1930 #define WORD2_XOR_LE(a) ((a) ^ NATIVE_ENDIAN_VALUE_LE_BE(0,6)) 1931 1932 // read/write a dword to a 64-bit space 1933 #define DWORD_XOR_BE(a) ((a) ^ NATIVE_ENDIAN_VALUE_LE_BE(4,0)) 1934 #define DWORD_XOR_LE(a) ((a) ^ NATIVE_ENDIAN_VALUE_LE_BE(0,4)) 1935 1936 1937 // helpers for checking address alignment 1938 #define WORD_ALIGNED(a) (((a) & 1) == 0) 1939 #define DWORD_ALIGNED(a) (((a) & 3) == 0) 1940 #define QWORD_ALIGNED(a) (((a) & 7) == 0) 1941 1942 1943 template<int Width, int AddrShift, endianness_t Endian> 1944 typename emu::detail::handler_entry_size<Width>::uX 1945 emu::detail::memory_access_cache<Width, AddrShift, Endian>:: 1946 read_native(offs_t address, typename emu::detail::handler_entry_size<Width>::uX mask) 1947 { 1948 address &= m_addrmask; 1949 check_address_r(address); 1950 return m_cache_r->read(address, mask); 1951 } 1952 1953 template<int Width, int AddrShift, endianness_t Endian> 1954 void emu::detail::memory_access_cache<Width, AddrShift, Endian>:: 1955 write_native(offs_t address, typename emu::detail::handler_entry_size<Width>::uX data, typename emu::detail::handler_entry_size<Width>::uX mask) 1956 { 1957 address &= m_addrmask; 1958 check_address_w(address); 1959 m_cache_w->write(address, data, mask); 1960 } 1961 1962 void memory_passthrough_handler::remove() 1963 { 1964 m_space.remove_passthrough(m_handlers); 1965 } 1966 1967 1968 template<int Level, int Width, int AddrShift, endianness_t Endian> 1969 void emu::detail::memory_access_specific<Level, Width, AddrShift, Endian>:: 1970 set(address_space *space, std::pair<const void *, const void *> rw) 1971 { 1972 m_space = space; 1973 m_addrmask = space->addrmask(); 1974 m_dispatch_read = (const handler_entry_read <Width, AddrShift, Endian> *const *)(rw.first); 1975 m_dispatch_write = (const handler_entry_write<Width, AddrShift, Endian> *const *)(rw.second); 1976 } 1977 1978 1979 template<int Width, int AddrShift, endianness_t Endian> 1980 void emu::detail::memory_access_cache<Width, AddrShift, Endian>:: 1981 set(address_space *space, std::pair<void *, void *> rw) 1982 { 1983 m_space = space; 1984 m_addrmask = space->addrmask(); 1985 1986 space->add_change_notifier([this](read_or_write mode) { 1987 if(u32(mode) & u32(read_or_write::READ)) { 1988 m_addrend_r = 0; 1989 m_addrstart_r = 1; 1990 m_cache_r = nullptr; 1991 } 1992 if(u32(mode) & u32(read_or_write::WRITE)) { 1993 m_addrend_w = 0; 1994 m_addrstart_w = 1; 1995 m_cache_w = nullptr; 1996 } 1997 }); 1998 m_root_read = (handler_entry_read <Width, AddrShift, Endian> *)(rw.first); 1999 m_root_write = (handler_entry_write<Width, AddrShift, Endian> *)(rw.second); 2000 2001 // Protect against a wandering memset 2002 m_addrstart_r = 1; 2003 m_addrend_r = 0; 2004 m_cache_r = nullptr; 2005 m_addrstart_w = 1; 2006 m_addrend_w = 0; 2007 m_cache_w = nullptr; 2008 } 2009 2010 template<int Width, int AddrShift, endianness_t Endian> 2011 emu::detail::memory_access_cache<Width, AddrShift, Endian>:: 2012 ~memory_access_cache() 2013 { 2014 } 2015 2016 #endif /* MAME_EMU_EMUMEM_H */ 2017