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>> &regions() 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