1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles
3 /***************************************************************************
4
5 device.h
6
7 Device interface functions.
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_DEVICE_H
18 #define MAME_EMU_DEVICE_H
19
20 #include <iterator>
21 #include <memory>
22 #include <string>
23 #include <type_traits>
24 #include <typeinfo>
25 #include <unordered_map>
26 #include <vector>
27
28
29
30 //**************************************************************************
31 // MACROS
32 //**************************************************************************
33
34 // macro for specifying a clock derived from an owning device
35 #define DERIVED_CLOCK(num, den) (0xff000000 | ((num) << 12) | ((den) << 0))
36
37
38
39 //**************************************************************************
40 // DEVICE CONFIGURATION MACROS
41 //**************************************************************************
42
43 // configure devices
44
45 #define DECLARE_READ_LINE_MEMBER(name) int name()
46 #define READ_LINE_MEMBER(name) int name()
47 #define DECLARE_WRITE_LINE_MEMBER(name) void name(ATTR_UNUSED int state)
48 #define WRITE_LINE_MEMBER(name) void name(ATTR_UNUSED int state)
49
50
51
52 //**************************************************************************
53 // GLOBAL VARIABLES
54 //**************************************************************************
55
56 // use this to refer to the owning device when providing a device tag
57 static const char DEVICE_SELF[] = "";
58
59 // use this to refer to the owning device's owner when providing a device tag
60 static const char DEVICE_SELF_OWNER[] = "^";
61
62
63 //**************************************************************************
64 // TYPE DEFINITIONS
65 //**************************************************************************
66
67 namespace emu { namespace detail {
68
69 class device_type_impl_base;
70
71
72 template <typename T> struct is_device_implementation
73 {
74 static constexpr bool value = std::is_base_of<device_t, T>::value;
75 };
76
77 template <typename T> struct is_device_interface
78 {
79 static constexpr bool value = std::is_base_of<device_interface, T>::value && !is_device_implementation<T>::value;
80 };
81
82
83 struct device_feature
84 {
85 enum type : u32
86 {
87 // Functionality-related
88 PROTECTION = u32(1) << 0,
89 TIMING = u32(1) << 1,
90
91 // Graphics
92 GRAPHICS = u32(1) << 2,
93 PALETTE = u32(1) << 3,
94
95 // Sound
96 SOUND = u32(1) << 4,
97
98 // Capture/Media Output
99 CAPTURE = u32(1) << 5,
100 CAMERA = u32(1) << 6,
101 MICROPHONE = u32(1) << 7,
102
103 // Controls/HID
104 CONTROLS = u32(1) << 8,
105 KEYBOARD = u32(1) << 9,
106 MOUSE = u32(1) << 10,
107
108 // Media Output
109 MEDIA = u32(1) << 11,
110 DISK = u32(1) << 12,
111 PRINTER = u32(1) << 13,
112 TAPE = u32(1) << 14,
113 PUNCH = u32(1) << 15,
114 DRUM = u32(1) << 16,
115 ROM = u32(1) << 17,
116
117 // Comms/Network
118 COMMS = u32(1) << 18,
119 LAN = u32(1) << 19,
120 WAN = u32(1) << 20,
121
122 NONE = u32(0),
123 ALL = (u32(1) << 21) - 1U
124 };
125 };
126
127 DECLARE_ENUM_BITWISE_OPERATORS(device_feature::type);
128
129
130 class device_registrar
131 {
132 private:
133 class const_iterator_helper;
134
135 public:
136 class const_iterator
137 {
138 public:
139 typedef std::ptrdiff_t difference_type;
140 typedef device_type_impl_base value_type;
141 typedef device_type_impl_base *pointer;
142 typedef device_type_impl_base &reference;
143 typedef std::forward_iterator_tag iterator_category;
144
145 const_iterator() = default;
146 const_iterator(const_iterator const &) = default;
147 const_iterator &operator=(const_iterator const &) = default;
148
149 bool operator==(const_iterator const &that) const { return m_type == that.m_type; }
150 bool operator!=(const_iterator const &that) const { return m_type != that.m_type; }
151 reference operator*() const { assert(m_type); return *m_type; }
152 pointer operator->() const { return m_type; }
153 const_iterator &operator++();
154 const_iterator operator++(int) { const_iterator const result(*this); ++*this; return result; }
155
156 private:
157 friend class const_iterator_helper;
158
159 pointer m_type = nullptr;
160 };
161
162 // explicit constructor is required for const variable initialization
device_registrar()163 constexpr device_registrar() { }
164
begin()165 const_iterator begin() const { return cbegin(); }
end()166 const_iterator end() const { return cend(); }
167 const_iterator cbegin() const;
168 const_iterator cend() const;
169
170 private:
171 friend class device_type_impl_base;
172
173 class const_iterator_helper : public const_iterator
174 {
175 public:
const_iterator_helper(device_type_impl_base * type)176 const_iterator_helper(device_type_impl_base *type) { m_type = type; }
177 };
178
179 static device_type_impl_base *register_device(device_type_impl_base &type);
180 };
181
182
183 template <class DeviceClass, char const *ShortName, char const *FullName, char const *Source>
184 struct device_tag_struct { typedef DeviceClass type; };
185 template <class DriverClass, char const *ShortName, char const *FullName, char const *Source, device_feature::type Unemulated, device_feature::type Imperfect>
186 struct driver_tag_struct { typedef DriverClass type; };
187
188 template <class DeviceClass, char const *ShortName, char const *FullName, char const *Source>
device_tag_func()189 auto device_tag_func() { return device_tag_struct<DeviceClass, ShortName, FullName, Source>{ }; };
190 template <class DriverClass, char const *ShortName, char const *FullName, char const *Source, device_feature::type Unemulated, device_feature::type Imperfect>
driver_tag_func()191 auto driver_tag_func() { return driver_tag_struct<DriverClass, ShortName, FullName, Source, Unemulated, Imperfect>{ }; };
192
193 class device_type_impl_base
194 {
195 private:
196 friend class device_registrar;
197
198 typedef std::unique_ptr<device_t> (*create_func)(device_type_impl_base const &type, machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
199
200 device_type_impl_base(device_type_impl_base const &) = delete;
201 device_type_impl_base(device_type_impl_base &&) = delete;
202 device_type_impl_base &operator=(device_type_impl_base const &) = delete;
203 device_type_impl_base &operator=(device_type_impl_base &&) = delete;
204
205 template <typename DeviceClass>
create_device(device_type_impl_base const & type,machine_config const & mconfig,char const * tag,device_t * owner,u32 clock)206 static std::unique_ptr<device_t> create_device(device_type_impl_base const &type, machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
207 {
208 return std::make_unique<DeviceClass>(mconfig, tag, owner, clock);
209 }
210
211 template <typename DriverClass>
create_driver(device_type_impl_base const & type,machine_config const & mconfig,char const * tag,device_t * owner,u32 clock)212 static std::unique_ptr<device_t> create_driver(device_type_impl_base const &type, machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
213 {
214 assert(!owner);
215 assert(!clock);
216
217 return make_unique_clear<DriverClass>(mconfig, type, tag);
218 }
219
220 create_func const m_creator;
221 std::type_info const &m_type;
222 char const *const m_shortname;
223 char const *const m_fullname;
224 char const *const m_source;
225 device_feature::type const m_unemulated_features;
226 device_feature::type const m_imperfect_features;
227
228 device_type_impl_base *m_next;
229
230 public:
231 using exposed_type = device_t;
232
device_type_impl_base(std::nullptr_t)233 device_type_impl_base(std::nullptr_t)
234 : m_creator(nullptr)
235 , m_type(typeid(std::nullptr_t))
236 , m_shortname(nullptr)
237 , m_fullname(nullptr)
238 , m_source(nullptr)
239 , m_unemulated_features(device_feature::NONE)
240 , m_imperfect_features(device_feature::NONE)
241 , m_next(nullptr)
242 {
243 }
244
245 template <class DeviceClass, char const *ShortName, char const *FullName, char const *Source>
device_type_impl_base(device_tag_struct<DeviceClass,ShortName,FullName,Source> (*)())246 device_type_impl_base(device_tag_struct<DeviceClass, ShortName, FullName, Source> (*)())
247 : m_creator(&create_device<DeviceClass>)
248 , m_type(typeid(DeviceClass))
249 , m_shortname(ShortName)
250 , m_fullname(FullName)
251 , m_source(Source)
252 , m_unemulated_features(DeviceClass::unemulated_features())
253 , m_imperfect_features(DeviceClass::imperfect_features())
254 , m_next(device_registrar::register_device(*this))
255 {
256 }
257
258 template <class DriverClass, char const *ShortName, char const *FullName, char const *Source, device_feature::type Unemulated, device_feature::type Imperfect>
device_type_impl_base(driver_tag_struct<DriverClass,ShortName,FullName,Source,Unemulated,Imperfect> (*)())259 device_type_impl_base(driver_tag_struct<DriverClass, ShortName, FullName, Source, Unemulated, Imperfect> (*)())
260 : m_creator(&create_driver<DriverClass>)
261 , m_type(typeid(DriverClass))
262 , m_shortname(ShortName)
263 , m_fullname(FullName)
264 , m_source(Source)
265 , m_unemulated_features(DriverClass::unemulated_features() | Unemulated)
266 , m_imperfect_features((DriverClass::imperfect_features() & ~Unemulated) | Imperfect)
267 , m_next(nullptr)
268 {
269 }
270
type()271 std::type_info const &type() const { return m_type; }
shortname()272 char const *shortname() const { return m_shortname; }
fullname()273 char const *fullname() const { return m_fullname; }
source()274 char const *source() const { return m_source; }
unemulated_features()275 device_feature::type unemulated_features() const { return m_unemulated_features; }
imperfect_features()276 device_feature::type imperfect_features() const { return m_imperfect_features; }
277
create(machine_config const & mconfig,char const * tag,device_t * owner,u32 clock)278 std::unique_ptr<device_t> create(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) const
279 {
280 return m_creator(*this, mconfig, tag, owner, clock);
281 }
282
283 explicit operator bool() const { return bool(m_creator); }
284 bool operator==(device_type_impl_base const &that) const { return &that == this; }
285 bool operator!=(device_type_impl_base const &that) const { return &that != this; }
286 };
287
288
289 template <class DeviceClass>
290 class device_type_impl : public device_type_impl_base
291 {
292 public:
293 using exposed_type = DeviceClass;
294
295 using device_type_impl_base::device_type_impl_base;
296 using device_type_impl_base::create;
297
298 template <typename... Params>
create(machine_config & mconfig,char const * tag,device_t * owner,Params &&...args)299 std::unique_ptr<DeviceClass> create(machine_config &mconfig, char const *tag, device_t *owner, Params &&... args) const
300 {
301 return std::make_unique<DeviceClass>(mconfig, tag, owner, std::forward<Params>(args)...);
302 }
303
304 template <typename... Params> DeviceClass &operator()(machine_config &mconfig, char const *tag, Params &&... args) const;
305 template <typename Exposed, bool Required, typename... Params> DeviceClass &operator()(machine_config &mconfig, device_finder<Exposed, Required> &finder, Params &&... args) const;
306 template <typename... Params> DeviceClass &operator()(machine_config_replace replace, char const *tag, Params &&... args) const;
307 template <typename Exposed, bool Required, typename... Params> DeviceClass &operator()(machine_config_replace replace, device_finder<Exposed, Required> &finder, Params &&... args) const;
308 };
309
310
311 inline device_registrar::const_iterator &device_registrar::const_iterator::operator++() { m_type = m_type->m_next; return *this; }
312
313 } } // namespace emu::detail
314
315
316 // device types
317 typedef emu::detail::device_type_impl_base const &device_type;
318 typedef std::add_pointer_t<device_type> device_type_ptr;
319 extern emu::detail::device_registrar const registered_device_types;
320
321 template <
322 typename DeviceClass,
323 char const *ShortName,
324 char const *FullName,
325 char const *Source>
326 constexpr auto device_creator = &emu::detail::device_tag_func<DeviceClass, ShortName, FullName, Source>;
327
328 template <
329 typename DriverClass,
330 char const *ShortName,
331 char const *FullName,
332 char const *Source,
333 emu::detail::device_feature::type Unemulated,
334 emu::detail::device_feature::type Imperfect>
335 constexpr auto driver_device_creator = &emu::detail::driver_tag_func<DriverClass, ShortName, FullName, Source, Unemulated, Imperfect>;
336
337 #define DECLARE_DEVICE_TYPE(Type, Class) \
338 class Class; \
339 extern emu::detail::device_type_impl<Class> const &Type; \
340 extern template class device_finder<Class, false>; \
341 extern template class device_finder<Class, true>;
342
343 #define DECLARE_DEVICE_TYPE_NS(Type, Namespace, Class) \
344 extern emu::detail::device_type_impl<Namespace::Class> const &Type; \
345 extern template class device_finder<Namespace::Class, false>; \
346 extern template class device_finder<Namespace::Class, true>;
347
348 #define DEFINE_DEVICE_TYPE(Type, Class, ShortName, FullName) \
349 namespace { \
350 struct Class##_device_traits { static constexpr char const shortname[] = ShortName, fullname[] = FullName, source[] = __FILE__; }; \
351 constexpr char const Class##_device_traits::shortname[], Class##_device_traits::fullname[], Class##_device_traits::source[]; \
352 } \
353 emu::detail::device_type_impl<Class> const &Type = device_creator<Class, (Class##_device_traits::shortname), (Class##_device_traits::fullname), (Class##_device_traits::source)>; \
354 template class device_finder<Class, false>; \
355 template class device_finder<Class, true>;
356
357 #define DEFINE_DEVICE_TYPE_PRIVATE(Type, Base, Class, ShortName, FullName) \
358 namespace { \
359 struct Class##_device_traits { static constexpr char const shortname[] = ShortName, fullname[] = FullName, source[] = __FILE__; }; \
360 constexpr char const Class##_device_traits::shortname[], Class##_device_traits::fullname[], Class##_device_traits::source[]; \
361 } \
362 emu::detail::device_type_impl<Base> const &Type = device_creator<Class, (Class##_device_traits::shortname), (Class##_device_traits::fullname), (Class##_device_traits::source)>;
363
364 #define DEFINE_DEVICE_TYPE_NS(Type, Namespace, Class, ShortName, FullName) \
365 namespace { \
366 struct Class##_device_traits { static constexpr char const shortname[] = ShortName, fullname[] = FullName, source[] = __FILE__; }; \
367 constexpr char const Class##_device_traits::shortname[], Class##_device_traits::fullname[], Class##_device_traits::source[]; \
368 } \
369 emu::detail::device_type_impl<Namespace::Class> const &Type = device_creator<Namespace::Class, (Class##_device_traits::shortname), (Class##_device_traits::fullname), (Class##_device_traits::source)>; \
370 template class device_finder<Namespace::Class, false>; \
371 template class device_finder<Namespace::Class, true>;
372
373
374 // exception classes
375 class device_missing_dependencies : public emu_exception { };
376
377
378 // timer IDs for devices
379 typedef u32 device_timer_id;
380
381 // ======================> device_t
382
383 // device_t represents a device
384 class device_t : public delegate_late_bind
385 {
386 DISABLE_COPYING(device_t);
387
388 friend class simple_list<device_t>;
389 friend class running_machine;
390 friend class finder_base;
391 friend class devcb_base;
392
393 class subdevice_list
394 {
395 friend class device_t;
396 friend class machine_config;
397
398 public:
399 // construction/destruction
subdevice_list()400 subdevice_list() { }
401
402 // getters
first()403 device_t *first() const { return m_list.first(); }
count()404 int count() const { return m_list.count(); }
empty()405 bool empty() const { return m_list.empty(); }
406
407 // range iterators
408 using auto_iterator = simple_list<device_t>::auto_iterator;
begin()409 auto_iterator begin() const { return m_list.begin(); }
end()410 auto_iterator end() const { return m_list.end(); }
411
412 private:
413 // private helpers
find(const std::string & name)414 device_t *find(const std::string &name) const
415 {
416 device_t *curdevice;
417 for (curdevice = m_list.first(); curdevice != nullptr; curdevice = curdevice->next())
418 if (name.compare(curdevice->m_basetag) == 0)
419 return curdevice;
420 return nullptr;
421 }
422
423 // private state
424 simple_list<device_t> m_list; // list of sub-devices we own
425 mutable std::unordered_map<std::string,device_t *> m_tagmap; // map of devices looked up and found by subtag
426 };
427
428 class interface_list
429 {
430 friend class device_t;
431 friend class device_interface;
432 friend class device_memory_interface;
433 friend class device_state_interface;
434 friend class device_execute_interface;
435
436 public:
437 class auto_iterator
438 {
439 public:
440 typedef std::ptrdiff_t difference_type;
441 typedef device_interface value_type;
442 typedef device_interface *pointer;
443 typedef device_interface &reference;
444 typedef std::forward_iterator_tag iterator_category;
445
446 // construction/destruction
auto_iterator(device_interface * intf)447 auto_iterator(device_interface *intf) : m_current(intf) { }
448
449 // required operator overloads
450 bool operator==(const auto_iterator &iter) const { return m_current == iter.m_current; }
451 bool operator!=(const auto_iterator &iter) const { return m_current != iter.m_current; }
452 device_interface &operator*() const { return *m_current; }
453 device_interface *operator->() const { return m_current; }
454 auto_iterator &operator++();
455 auto_iterator operator++(int);
456
457 private:
458 // private state
459 device_interface *m_current;
460 };
461
462 // construction/destruction
interface_list()463 interface_list() : m_head(nullptr), m_execute(nullptr), m_memory(nullptr), m_state(nullptr) { }
464
465 // getters
first()466 device_interface *first() const { return m_head; }
467
468 // range iterators
begin()469 auto_iterator begin() const { return auto_iterator(m_head); }
end()470 auto_iterator end() const { return auto_iterator(nullptr); }
471
472 private:
473 device_interface *m_head; // head of interface list
474 device_execute_interface *m_execute; // pre-cached pointer to execute interface
475 device_memory_interface *m_memory; // pre-cached pointer to memory interface
476 device_state_interface *m_state; // pre-cached pointer to state interface
477 };
478
479 protected:
480 // construction/destruction
481 device_t(
482 const machine_config &mconfig,
483 device_type type,
484 const char *tag,
485 device_t *owner,
486 u32 clock);
487
488 public:
489 // device flags
490 using feature = emu::detail::device_feature;
491 using feature_type = emu::detail::device_feature::type;
492
493 /// \brief Report unemulated features
494 ///
495 /// Implement this member in a derived class to declare features
496 /// that are not emulated. This will propagate to all other devices
497 /// and systems that use the device. Unemulated features are shown
498 /// in the system selection UI, and cause a red warning to be
499 /// displayed on starting a system.
500 /// \return Bitwise or of the feature constants for unemulated
501 /// features of the device.
502 /// \sa imperfect_features
unemulated_features()503 static constexpr feature_type unemulated_features() { return feature::NONE; }
504
505 /// \brief Report imperfectly emulated features
506 ///
507 /// Implement this member in a derived class to declare features
508 /// that are imperfectly emulated. This will propagate to all other
509 /// devices and systems that use the device. Imperfectly emulated
510 /// features are shown in the system selection UI, and cause a
511 /// yellow warning to be displayed on starting a system (provided
512 /// there are no unemulated features, which take precedence and
513 /// cause the warning to be red).
514 ///
515 /// An exception is imperfectly emulated protection, which results
516 /// in a red warning being displayed when starting a system.
517 /// \return Bitwise or of the feature constants for imperfectly
518 /// emulated features of the device.
519 /// \sa unemulated_features
imperfect_features()520 static constexpr feature_type imperfect_features() { return feature::NONE; }
521
522 virtual ~device_t();
523
524 // getters
has_running_machine()525 bool has_running_machine() const { return m_machine != nullptr; }
machine()526 running_machine &machine() const { /*assert(m_machine != nullptr);*/ return *m_machine; }
tag()527 const char *tag() const { return m_tag.c_str(); }
basetag()528 const char *basetag() const { return m_basetag.c_str(); }
type()529 device_type type() const { return m_type; }
name()530 const char *name() const { return m_type.fullname(); }
shortname()531 const char *shortname() const { return m_type.shortname(); }
532 virtual std::vector<std::string> searchpath() const;
source()533 const char *source() const { return m_type.source(); }
owner()534 device_t *owner() const { return m_owner; }
next()535 device_t *next() const { return m_next; }
configured_clock()536 u32 configured_clock() const { return m_configured_clock; }
mconfig()537 const machine_config &mconfig() const { return m_machine_config; }
input_ports_defaults()538 const input_device_default *input_ports_defaults() const { return m_input_defaults; }
539 const std::vector<rom_entry> &rom_region_vector() const;
rom_region()540 const tiny_rom_entry *rom_region() const { return device_rom_region(); }
input_ports()541 ioport_constructor input_ports() const { return device_input_ports(); }
get_default_bios_tag()542 std::string const &get_default_bios_tag() const { return m_default_bios_tag; }
default_bios()543 u8 default_bios() const { assert(configured()); return m_default_bios; }
system_bios()544 u8 system_bios() const { return m_system_bios; }
545
546 // interface helpers
interfaces()547 interface_list &interfaces() { return m_interfaces; }
interfaces()548 const interface_list &interfaces() const { return m_interfaces; }
interface(DeviceClass * & intf)549 template<class DeviceClass> bool interface(DeviceClass *&intf) { intf = dynamic_cast<DeviceClass *>(this); return (intf != nullptr); }
interface(DeviceClass * & intf)550 template<class DeviceClass> bool interface(DeviceClass *&intf) const { intf = dynamic_cast<const DeviceClass *>(this); return (intf != nullptr); }
551
552 // specialized helpers for common core interfaces
interface(device_execute_interface * & intf)553 bool interface(device_execute_interface *&intf) { intf = m_interfaces.m_execute; return (intf != nullptr); }
interface(device_execute_interface * & intf)554 bool interface(device_execute_interface *&intf) const { intf = m_interfaces.m_execute; return (intf != nullptr); }
interface(device_memory_interface * & intf)555 bool interface(device_memory_interface *&intf) { intf = m_interfaces.m_memory; return (intf != nullptr); }
interface(device_memory_interface * & intf)556 bool interface(device_memory_interface *&intf) const { intf = m_interfaces.m_memory; return (intf != nullptr); }
interface(device_state_interface * & intf)557 bool interface(device_state_interface *&intf) { intf = m_interfaces.m_state; return (intf != nullptr); }
interface(device_state_interface * & intf)558 bool interface(device_state_interface *&intf) const { intf = m_interfaces.m_state; return (intf != nullptr); }
execute()559 device_execute_interface &execute() const { assert(m_interfaces.m_execute != nullptr); return *m_interfaces.m_execute; }
memory()560 device_memory_interface &memory() const { assert(m_interfaces.m_memory != nullptr); return *m_interfaces.m_memory; }
state()561 device_state_interface &state() const { assert(m_interfaces.m_state != nullptr); return *m_interfaces.m_state; }
562
563 // owned object helpers
subdevices()564 subdevice_list &subdevices() { return m_subdevices; }
subdevices()565 const subdevice_list &subdevices() const { return m_subdevices; }
566
567 // device-relative tag lookups
568 std::string subtag(std::string tag) const;
siblingtag(std::string tag)569 std::string siblingtag(std::string tag) const { return (m_owner != nullptr) ? m_owner->subtag(tag) : tag; }
570 memory_region *memregion(std::string tag) const;
571 memory_share *memshare(std::string tag) const;
572 memory_bank *membank(std::string tag) const;
573 ioport_port *ioport(std::string tag) const;
574 device_t *subdevice(const char *tag) const;
575 device_t *siblingdevice(const char *tag) const;
subdevice(const char * tag)576 template<class DeviceClass> DeviceClass *subdevice(const char *tag) const { return downcast<DeviceClass *>(subdevice(tag)); }
siblingdevice(const char * tag)577 template<class DeviceClass> DeviceClass *siblingdevice(const char *tag) const { return downcast<DeviceClass *>(siblingdevice(tag)); }
578 std::string parameter(const char *tag) const;
579
580 // configuration helpers
581 void add_machine_configuration(machine_config &config);
582 void set_clock(u32 clock);
set_clock(const XTAL & xtal)583 void set_clock(const XTAL &xtal) { set_clock(xtal.value()); }
set_input_default(const input_device_default * config)584 void set_input_default(const input_device_default *config) { m_input_defaults = config; }
set_default_bios_tag(Params &&...args)585 template <typename... Params> void set_default_bios_tag(Params &&... args) { assert(!configured()); m_default_bios_tag.assign(std::forward<Params>(args)...); }
586
587 // state helpers
588 void config_complete();
configured()589 bool configured() const { return m_config_complete; }
590 void validity_check(validity_checker &valid) const;
started()591 bool started() const { return m_started; }
592 void reset();
593
594 // clock/timing accessors
clock()595 u32 clock() const { return m_clock; }
unscaled_clock()596 u32 unscaled_clock() const { return m_unscaled_clock; }
597 void set_unscaled_clock(u32 clock);
set_unscaled_clock(const XTAL & xtal)598 void set_unscaled_clock(const XTAL &xtal) { set_unscaled_clock(xtal.value()); }
set_unscaled_clock_int(u32 clock)599 void set_unscaled_clock_int(u32 clock) { set_unscaled_clock(clock); } // non-overloaded name because binding to overloads is ugly
clock_scale()600 double clock_scale() const { return m_clock_scale; }
601 void set_clock_scale(double clockscale);
602 attotime clocks_to_attotime(u64 clocks) const noexcept;
603 u64 attotime_to_clocks(const attotime &duration) const noexcept;
604
605 // timer interfaces
606 emu_timer *timer_alloc(device_timer_id id = 0, void *ptr = nullptr);
607 void timer_set(const attotime &duration, device_timer_id id = 0, int param = 0, void *ptr = nullptr);
608 void synchronize(device_timer_id id = 0, int param = 0, void *ptr = nullptr) { timer_set(attotime::zero, id, param, ptr); }
timer_expired(emu_timer & timer,device_timer_id id,int param,void * ptr)609 void timer_expired(emu_timer &timer, device_timer_id id, int param, void *ptr) { device_timer(timer, id, param, ptr); }
610
611 // state saving interfaces
612 template<typename ItemType>
613 void ATTR_COLD save_item(ItemType &value, const char *valname, int index = 0)
614 {
615 assert(m_save);
616 m_save->save_item(this, name(), tag(), index, value, valname);
617 }
618 template<typename ItemType, typename StructType, typename ElementType>
619 void ATTR_COLD save_item(ItemType &value, ElementType StructType::*element, const char *valname, int index = 0)
620 {
621 assert(m_save);
622 m_save->save_item(this, name(), tag(), index, value, element, valname);
623 }
624 template<typename ItemType>
625 void ATTR_COLD save_pointer(ItemType &&value, const char *valname, u32 count, int index = 0)
626 {
627 assert(m_save);
628 m_save->save_pointer(this, name(), tag(), index, std::forward<ItemType>(value), valname, count);
629 }
630 template<typename ItemType, typename StructType, typename ElementType>
631 void ATTR_COLD save_pointer(ItemType &&value, ElementType StructType::*element, const char *valname, u32 count, int index = 0)
632 {
633 assert(m_save);
634 m_save->save_pointer(this, name(), tag(), index, std::forward<ItemType>(value), element, valname, count);
635 }
636
637 // debugging
debug()638 device_debug *debug() const { return m_debug.get(); }
639
set_system_bios(u8 bios)640 void set_system_bios(u8 bios) { m_system_bios = bios; }
641 bool findit(validity_checker *valid) const;
642
643 // misc
644 template <typename Format, typename... Params> void popmessage(Format &&fmt, Params &&... args) const;
645 template <typename Format, typename... Params> void logerror(Format &&fmt, Params &&... args) const;
646
647 protected:
648 // miscellaneous helpers
649 void set_machine(running_machine &machine);
650 void resolve_pre_map();
651 void resolve_post_map();
652 void start();
653 void stop();
654 void debug_setup();
655 void pre_save();
656 void post_load();
657 void notify_clock_changed();
658 finder_base *register_auto_finder(finder_base &autodev);
659 void register_callback(devcb_base &callback);
660
661 //------------------- begin derived class overrides
662
663 // device-level overrides
664 virtual const tiny_rom_entry *device_rom_region() const;
665 virtual void device_add_mconfig(machine_config &config);
666 virtual ioport_constructor device_input_ports() const;
667
668 /// \brief Finalise device configuration
669 ///
670 /// Perform any final configuration tasks after all devices in the
671 /// system have added machine configuration. This is called after
672 /// any #device_interface mix-in interface_config_complete members
673 /// have completed.
674 ///
675 /// Note that automatic object finders will not have been resolved
676 /// at the time this member is called.
677 virtual void device_config_complete();
678
679 /// \brief Additional device validity checks
680 ///
681 /// Implement this member to provide additional validity checks.
682 /// Report errors using #osd_printf_error and report warnings using
683 /// #osd_printf_warning. The system being validated, device type
684 /// and device tag are collected automatically. Do not throw
685 /// exceptions to report errors.
686 ///
687 /// This provides an opportunity to check that the device has been
688 /// configured correctly. Systems are validated on start, and also
689 /// when the user manually runs a validity check. Validity checks
690 /// are only run for devices configured in runnable systems, not
691 /// when checking that a device can be instantiated in isolation.
692 /// \param [in] valid Reference to the validity checker object
693 /// performing validation (provides some helper member functions).
694 /// \sa device_interface::interface_validity_check
695 virtual void device_validity_check(validity_checker &valid) const ATTR_COLD;
696
697 /// \brief Resolve objects that may be needed while starting
698 ///
699 /// Implement this member to complete object resolution before any
700 /// devices are started. For example it may be necessary to resolve
701 /// callbacks before any devices start so initial input conditions
702 /// can be set. This is called after all registerd automatic object
703 /// finders are resolved.
704 virtual void device_resolve_objects() ATTR_COLD;
705
706 /// \brief Device start handler
707 ///
708 /// Implement this member to set up the initial state of the device
709 /// on start. This will be called after all #device_interface
710 // /mix-in interface_pre_start members have completed successfully.
711 /// If the device can't start until another device has completed
712 /// starting, throw a #device_missing_dependencies exception.
713 /// Starting will be postponed until additional devices have been
714 /// started.
715 ///
716 /// If a device's base class is not device_t, it's good practice to
717 /// check start order dependencies (and throw
718 /// #device_missing_dependencies if necessary) before calling the
719 /// base implementation. This will ensure that the base
720 /// implementation won't be called twice if starting needs to be
721 /// postponed.
722 ///
723 /// This is the correct place to register for save states.
724 /// \sa device_reset device_stop
725 /// device_interface::interface_pre_start
726 /// device_interface::interface_post_start
727 virtual void device_start() ATTR_COLD = 0;
728
729 /// \brief Device stop handler
730 ///
731 /// Implement this member to perform additional tasks on ending an
732 /// emulation session. You may deallocate memory here. This is
733 /// called after interface_pre_stop is called for all
734 /// #device_interface mix-ins, and before interface_post_stop is
735 /// called for any #device_interface mix-ins.
736 /// \sa device_interface::interface_pre_stop
737 /// device_interface::interface_post_stop
738 virtual void device_stop() ATTR_COLD;
739
740 /// \brief Device reset handler
741 ///
742 /// Implement this member to provide reset behaviour. This is
743 /// called after all #device_interface mix-in interface_pre_reset
744 /// members have completed, and before any child devices are reset.
745 /// All devices are reset at the beginning of an emulation session
746 /// (after all devices have been started), and also when the user
747 /// requests a soft reset (by pressing F3 by default, and also
748 /// available from the debugger).
749 ///
750 /// Note that child devices are reset automatically when a device is
751 /// reset. You should not reset child devices manually from this
752 /// member. If you need to provide additional behaviour after child
753 /// devices are reset, implement #device_reset_after_children.
754 ///
755 /// Only implement warm reset behaviour in this member. Initial
756 /// cold reset conditions should be set up in #device_start.
757 /// \sa device_reset_after_children device_start
758 /// device_interface::interface_pre_reset
759 /// device_interface::interface_post_reset
760 virtual void device_reset() ATTR_COLD;
761
762 /// \brief Additional reset behaviour after child device reset
763 ///
764 /// Implement this member to provide additional reset behaviour
765 /// after child devices are reset. This is called when resetting a
766 /// device after #device_reset has been called and all child devices
767 /// have been reset, and before any #device_interface mix-in
768 /// interface_post_reset members are called.
769 /// \sa device_reset device_interface::interface_pre_reset
770 /// device_interface::interface_post_reset
771 virtual void device_reset_after_children() ATTR_COLD;
772
773 /// \brief Prepare for a save state to be written
774 ///
775 /// Implement this member to perform any tasks necessary before any
776 /// registered save state items are recorded. For example it may be
777 /// necessary to flush caches, serialise self-referencing members or
778 /// pointers into data structures. This is called after all
779 /// #device_interface mix-in interface_pre_save members are called.
780 /// \sa device_post_load device_interface::interface_pre_save
781 virtual void device_pre_save() ATTR_COLD;
782
783 /// \brief Complete save state loading
784 ///
785 /// Implement this member to perform any tasks necessary after
786 /// registered save state items are loaded. For example it may be
787 /// necessary to update or invalidate caches, or de-serialise
788 /// pointers into data structures. This is called after all
789 /// #device_interface mix-in interface_post_load members are called.
790 /// \sa device_pre_save device_interface::interface_post_load
791 virtual void device_post_load() ATTR_COLD;
792
793 virtual void device_clock_changed();
794 virtual void device_debug_setup();
795 virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
796
797 //------------------- end derived class overrides
798
799 // core device properties
800 device_type m_type; // device type
801
802 // device relationships & interfaces
803 device_t * m_owner; // device that owns us
804 device_t * m_next; // next device by the same owner (of any type/class)
805 subdevice_list m_subdevices; // container for list of subdevices
806 interface_list m_interfaces; // container for list of interfaces
807
808 // device clocks
809 u32 m_configured_clock; // originally configured device clock
810 u32 m_unscaled_clock; // current unscaled device clock
811 u32 m_clock; // current device clock, after scaling
812 double m_clock_scale; // clock scale factor
813 attoseconds_t m_attoseconds_per_clock;// period in attoseconds
814
815 std::unique_ptr<device_debug> m_debug;
816 const machine_config & m_machine_config; // reference to the machine's configuration
817 const input_device_default *m_input_defaults; // devices input ports default overrides
818
819 u8 m_system_bios; // the system BIOS we wish to load
820 u8 m_default_bios; // the default system BIOS
821 std::string m_default_bios_tag; // tag of the default system BIOS
822
823 private:
824 // internal helpers
825 device_t *subdevice_slow(const char *tag) const;
826 void calculate_derived_clock();
827
828 // private state; accessor use required
829 running_machine * m_machine;
830 save_manager * m_save;
831 std::string m_tag; // full tag for this instance
832 std::string m_basetag; // base part of the tag
833 bool m_config_complete; // have we completed our configuration?
834 bool m_started; // true if the start function has succeeded
835 finder_base * m_auto_finder_list; // list of objects to auto-find
836 mutable std::vector<rom_entry> m_rom_entries;
837 std::list<devcb_base *> m_callbacks;
838
839 // string formatting buffer for logerror
840 mutable util::ovectorstream m_string_buffer;
841 };
842
843
844 /// \brief Device mix-in base
845 ///
846 /// Provides a base for #device_t mix-ins that integrate with the device
847 /// lifecycle. Derived classes are used to implement a number of
848 /// standard concepts and interfaces, and integrate with the scheduler,
849 /// debugger and user interface.
850 class device_interface
851 {
852 DISABLE_COPYING(device_interface);
853
854 protected:
855 // construction/destruction
856 device_interface(device_t &device, const char *type);
857 virtual ~device_interface();
858
859 public:
interface_type()860 const char *interface_type() const { return m_type; }
861
862 // casting helpers
device()863 device_t &device() { return m_device; }
device()864 const device_t &device() const { return m_device; }
865 operator device_t &() { return m_device; }
866
867 // iteration helpers
interface_next()868 device_interface *interface_next() const { return m_interface_next; }
869
870 // optional operation overrides
871
872 /// \brief Finalise mix-in configuration
873 ///
874 /// Perform any final configuration tasks after all devices in the
875 /// system have added machine configuration. This is called before
876 /// device_config_complete is called for the device.
877 ///
878 /// Note that automatic object finders will not have been resolved
879 /// at this time.
880 /// \sa device_t::device_config_complete
881 virtual void interface_config_complete();
882
883 /// \brief Additional mix-in validity checks
884 ///
885 /// Implement this member to provide additional validity checks.
886 /// Report errors using #osd_printf_error and report warnings using
887 /// #osd_printf_warning. The system being validated, device type
888 /// and device tag are collected automatically. Do not throw
889 /// exceptions to report errors.
890 ///
891 /// This provides an opportunity to check that the mix-in has been
892 /// configured correctly. Systems are validated on start, and also
893 /// when the user manually runs a validity check. Validity checks
894 /// are only run for devices configured in runnable systems, not
895 /// when checking that a device can be instantiated in isolation.
896 /// \param [in] valid Reference to the validity checker object
897 /// performing validation (provides some helper member functions).
898 /// \sa device_t::device_validity_check
899 virtual void interface_validity_check(validity_checker &valid) const ATTR_COLD;
900
901 /// \brief Mix-in start handler
902 ///
903 /// Implement this member to set up the initial state of the mix-in
904 /// on start. This is called before the device_start member is
905 /// called for the device. If the mix-in can't be started until
906 /// another device has started, throw a #device_missing_dependencies
907 /// exception. Starting will be postponed until additional devices
908 /// have been started.
909 ///
910 /// Note that this member may be called multiple times if another
911 /// device_interface mix-in throws a #device_missing_dependencies
912 /// exception from its interface_pre_start member, or if the device
913 /// throws a #device_missing_dependencies exception from its
914 /// device_start member. You must check to ensure that operations
915 /// like resource allocation are not performed multiple times, or
916 /// postpone them until #interface_post_start is called.
917 ///
918 /// It's simpler to register for save states when
919 /// #interface_post_start is called.
920 /// \sa interface_post_start device_t::device_start
921 virtual void interface_pre_start() ATTR_COLD;
922
923 /// \brief Mix-in start completion handler
924 ///
925 /// Implement this member to complete mix-in start-up. This is
926 /// called after #interface_pre_start is called for all
927 /// device_interface mix-ins, and after device_start is called for
928 /// the device. This member will only be called once, it will not
929 /// be called multiple times if device starting is postponed.
930 ///
931 /// This member must not throw #device_missing_dependencies (start
932 /// order dependencies should be checked in #interface_pre_start).
933 /// This is the appropriate place to allocate resources like
934 /// timers and register for save states.
935 /// \sa interface_pre_start device_t::device_start
936 virtual void interface_post_start() ATTR_COLD;
937
938 /// \brief Mix-in reset handler
939 ///
940 /// Implement this member to provide reset behaviour. This is
941 /// called before device_reset is called for the device, and before
942 /// any child devices are reset. Only implement warm reset
943 /// behaviour in this member. Initial cold reset conditions should
944 /// be set up in #interface_pre_start and/or #interface_post_start.
945 /// If you need to provide additional behaviour after child devices
946 /// are reset, implement #interface_post_reset.
947 /// \sa interface_post_reset device_t::device_reset
948 virtual void interface_pre_reset() ATTR_COLD;
949
950 /// \brief Mix-in reset completion handler
951 ///
952 /// Implement this member to provide additional reset behaviour
953 /// after child devices are reset. This is called after
954 /// device_reset_after_children has been called for the device.
955 /// \sa interface_pre_reset device_t::device_reset
956 /// device_t::device_reset_after_children
957 virtual void interface_post_reset() ATTR_COLD;
958
959 /// \brief Mix-in stop handler
960 ///
961 /// Implement this member to perform additional tasks on ending an
962 /// emulation session. Do not deallocate anything that may need to
963 /// be referenced from another device_interface mix-in's
964 /// interface_pre_stop member or from the device's device_stop
965 /// member. This is called before device_stop is called for the
966 /// device.
967 /// \sa interface_post_stop device_t::device_stop
968 virtual void interface_pre_stop() ATTR_COLD;
969
970 /// \brief Mix-in stop completion handler
971 ///
972 /// Implement this member to perform additional tasks on ending an
973 /// emulation session after the device is stopped. You can
974 /// deallocate memory here. This is called after device_stop is
975 /// called for the device.
976 /// \sa interface_pre_stop device_t::device_stop
977 virtual void interface_post_stop() ATTR_COLD;
978
979 /// \brief Prepare for a save state to be written
980 ///
981 /// Implement this member to perform any tasks necessary before any
982 /// registered save state items are recorded. For example it may be
983 /// necessary to flush caches, serialise self-referencing members or
984 /// pointers into data structures. This is called before
985 /// device_pre_save is called for the device.
986 /// \sa interface_post_load device_t::device_pre_save
987 virtual void interface_pre_save() ATTR_COLD;
988
989 /// \brief Complete save state loading
990 ///
991 /// Implement this member to perform any tasks necessary after
992 /// registered save state items are loaded. For example it may be
993 /// necessary to update or invalidate caches, or de-serialise
994 /// pointers into data structures. This is called before
995 /// device_post_load is called for the device.
996 /// \sa interface_pre_save device_t::device_post_load
997 virtual void interface_post_load() ATTR_COLD;
998
999 virtual void interface_clock_changed();
1000 virtual void interface_debug_setup();
1001
1002 private:
1003 // internal state
1004 device_interface * m_interface_next;
1005 device_t & m_device;
1006 const char * m_type;
1007 };
1008
1009
1010 // ======================> device_iterator
1011
1012 // helper class to iterate over the hierarchy of devices depth-first
1013 class device_iterator
1014 {
1015 public:
1016 class auto_iterator
1017 {
1018 public:
1019 typedef std::ptrdiff_t difference_type;
1020 typedef device_t value_type;
1021 typedef device_t *pointer;
1022 typedef device_t &reference;
1023 typedef std::forward_iterator_tag iterator_category;
1024
1025 // construction
auto_iterator(device_t * devptr,int curdepth,int maxdepth)1026 auto_iterator(device_t *devptr, int curdepth, int maxdepth)
1027 : m_curdevice(devptr)
1028 , m_curdepth(curdepth)
1029 , m_maxdepth(maxdepth)
1030 {
1031 }
1032
1033 // getters
current()1034 device_t *current() const { return m_curdevice; }
depth()1035 int depth() const { return m_curdepth; }
1036
1037 // required operator overrides
1038 bool operator==(auto_iterator const &iter) const { return m_curdevice == iter.m_curdevice; }
1039 bool operator!=(auto_iterator const &iter) const { return m_curdevice != iter.m_curdevice; }
1040 device_t &operator*() const { assert(m_curdevice); return *m_curdevice; }
1041 device_t *operator->() const { return m_curdevice; }
1042 auto_iterator &operator++() { advance(); return *this; }
1043 auto_iterator operator++(int) { auto_iterator const result(*this); ++*this; return result; }
1044
1045 protected:
1046 // search depth-first for the next device
advance()1047 void advance()
1048 {
1049 // remember our starting position, and end immediately if we're nullptr
1050 if (m_curdevice)
1051 {
1052 device_t *start = m_curdevice;
1053
1054 // search down first
1055 if (m_curdepth < m_maxdepth)
1056 {
1057 m_curdevice = start->subdevices().first();
1058 if (m_curdevice)
1059 {
1060 m_curdepth++;
1061 return;
1062 }
1063 }
1064
1065 // search next for neighbors up the ownership chain
1066 while (m_curdepth > 0 && start)
1067 {
1068 // found a neighbor? great!
1069 m_curdevice = start->next();
1070 if (m_curdevice)
1071 return;
1072
1073 // no? try our parent
1074 start = start->owner();
1075 m_curdepth--;
1076 }
1077
1078 // returned to the top; we're done
1079 m_curdevice = nullptr;
1080 }
1081 }
1082
1083 // protected state
1084 device_t * m_curdevice;
1085 int m_curdepth;
1086 const int m_maxdepth;
1087 };
1088
1089 // construction
1090 device_iterator(device_t &root, int maxdepth = 255)
m_root(root)1091 : m_root(root), m_maxdepth(maxdepth) { }
1092
1093 // standard iterators
begin()1094 auto_iterator begin() const { return auto_iterator(&m_root, 0, m_maxdepth); }
end()1095 auto_iterator end() const { return auto_iterator(nullptr, 0, m_maxdepth); }
1096
1097 // return first item
first()1098 device_t *first() const { return begin().current(); }
1099
1100 // return the number of items available
count()1101 int count() const
1102 {
1103 int result = 0;
1104 for (device_t &item : *this)
1105 {
1106 (void)&item;
1107 result++;
1108 }
1109 return result;
1110 }
1111
1112 // return the index of a given item in the virtual list
indexof(device_t & device)1113 int indexof(device_t &device) const
1114 {
1115 int index = 0;
1116 for (device_t &item : *this)
1117 {
1118 if (&item == &device)
1119 return index;
1120 else
1121 index++;
1122 }
1123 return -1;
1124 }
1125
1126 // return the indexed item in the list
byindex(int index)1127 device_t *byindex(int index) const
1128 {
1129 for (device_t &item : *this)
1130 if (index-- == 0)
1131 return &item;
1132 return nullptr;
1133 }
1134
1135 private:
1136 // internal state
1137 device_t & m_root;
1138 int m_maxdepth;
1139 };
1140
1141
1142 // ======================> device_type_iterator
1143
1144 // helper class to find devices of a given type in the device hierarchy
1145 template <class DeviceType, class DeviceClass = DeviceType>
1146 class device_type_iterator
1147 {
1148 public:
1149 class auto_iterator : protected device_iterator::auto_iterator
1150 {
1151 public:
1152 using device_iterator::auto_iterator::difference_type;
1153 using device_iterator::auto_iterator::iterator_category;
1154 using device_iterator::auto_iterator::depth;
1155
1156 typedef DeviceClass value_type;
1157 typedef DeviceClass *pointer;
1158 typedef DeviceClass &reference;
1159
1160 // construction
auto_iterator(device_t * devptr,int curdepth,int maxdepth)1161 auto_iterator(device_t *devptr, int curdepth, int maxdepth)
1162 : device_iterator::auto_iterator(devptr, curdepth, maxdepth)
1163 {
1164 // make sure the first device is of the specified type
1165 while (m_curdevice && (m_curdevice->type().type() != typeid(DeviceType)))
1166 advance();
1167 }
1168
1169 // required operator overrides
1170 bool operator==(auto_iterator const &iter) const { return m_curdevice == iter.m_curdevice; }
1171 bool operator!=(auto_iterator const &iter) const { return m_curdevice != iter.m_curdevice; }
1172
1173 // getters returning specified device type
current()1174 DeviceClass *current() const { return downcast<DeviceClass *>(m_curdevice); }
1175 DeviceClass &operator*() const { assert(m_curdevice); return downcast<DeviceClass &>(*m_curdevice); }
1176 DeviceClass *operator->() const { return downcast<DeviceClass *>(m_curdevice); }
1177
1178 // search for devices of the specified type
1179 auto_iterator &operator++()
1180 {
1181 advance();
1182 while (m_curdevice && (m_curdevice->type().type() != typeid(DeviceType)))
1183 advance();
1184 return *this;
1185 }
1186
1187 auto_iterator operator++(int) { auto_iterator const result(*this); ++*this; return result; }
1188 };
1189
1190 // construction
m_root(root)1191 device_type_iterator(device_t &root, int maxdepth = 255) : m_root(root), m_maxdepth(maxdepth) { }
1192
1193 // standard iterators
begin()1194 auto_iterator begin() const { return auto_iterator(&m_root, 0, m_maxdepth); }
end()1195 auto_iterator end() const { return auto_iterator(nullptr, 0, m_maxdepth); }
cbegin()1196 auto_iterator cbegin() const { return auto_iterator(&m_root, 0, m_maxdepth); }
cend()1197 auto_iterator cend() const { return auto_iterator(nullptr, 0, m_maxdepth); }
1198
1199 // return first item
first()1200 DeviceClass *first() const { return begin().current(); }
1201
1202 // return the number of items available
count()1203 int count() const { return std::distance(cbegin(), cend()); }
1204
1205 // return the index of a given item in the virtual list
indexof(DeviceClass & device)1206 int indexof(DeviceClass &device) const
1207 {
1208 int index = 0;
1209 for (DeviceClass &item : *this)
1210 {
1211 if (&item == &device)
1212 return index;
1213 else
1214 index++;
1215 }
1216 return -1;
1217 }
1218
1219 // return the indexed item in the list
byindex(int index)1220 DeviceClass *byindex(int index) const
1221 {
1222 for (DeviceClass &item : *this)
1223 if (index-- == 0)
1224 return &item;
1225 return nullptr;
1226 }
1227
1228 private:
1229 // internal state
1230 device_t & m_root;
1231 int m_maxdepth;
1232 };
1233
1234
1235 // ======================> device_interface_iterator
1236
1237 // helper class to find devices with a given interface in the device hierarchy
1238 // also works for finding devices derived from a given subclass
1239 template<class InterfaceClass>
1240 class device_interface_iterator
1241 {
1242 public:
1243 class auto_iterator : public device_iterator::auto_iterator
1244 {
1245 public:
1246 // construction
auto_iterator(device_t * devptr,int curdepth,int maxdepth)1247 auto_iterator(device_t *devptr, int curdepth, int maxdepth)
1248 : device_iterator::auto_iterator(devptr, curdepth, maxdepth)
1249 {
1250 // set the iterator for the first device with the interface
1251 find_interface();
1252 }
1253
1254 // getters returning specified interface type
current()1255 InterfaceClass *current() const { return m_interface; }
1256 InterfaceClass &operator*() const { assert(m_interface != nullptr); return *m_interface; }
1257
1258 // search for devices with the specified interface
1259 const auto_iterator &operator++() { advance(); find_interface(); return *this; }
1260
1261 private:
1262 // private helper
find_interface()1263 void find_interface()
1264 {
1265 // advance until finding a device with the interface
1266 for ( ; m_curdevice != nullptr; advance())
1267 if (m_curdevice->interface(m_interface))
1268 return;
1269
1270 // if we run out of devices, make sure the interface pointer is null
1271 m_interface = nullptr;
1272 }
1273
1274 // private state
1275 InterfaceClass *m_interface;
1276 };
1277
1278 public:
1279 // construction
1280 device_interface_iterator(device_t &root, int maxdepth = 255)
m_root(root)1281 : m_root(root), m_maxdepth(maxdepth) { }
1282
1283 // standard iterators
begin()1284 auto_iterator begin() const { return auto_iterator(&m_root, 0, m_maxdepth); }
end()1285 auto_iterator end() const { return auto_iterator(nullptr, 0, m_maxdepth); }
1286
1287 // return first item
first()1288 InterfaceClass *first() const { return begin().current(); }
1289
1290 // return the number of items available
count()1291 int count() const
1292 {
1293 int result = 0;
1294 for (InterfaceClass &item : *this)
1295 {
1296 (void)&item;
1297 result++;
1298 }
1299 return result;
1300 }
1301
1302 // return the index of a given item in the virtual list
indexof(InterfaceClass & intrf)1303 int indexof(InterfaceClass &intrf) const
1304 {
1305 int index = 0;
1306 for (InterfaceClass &item : *this)
1307 {
1308 if (&item == &intrf)
1309 return index;
1310 else
1311 index++;
1312 }
1313 return -1;
1314 }
1315
1316 // return the indexed item in the list
byindex(int index)1317 InterfaceClass *byindex(int index) const
1318 {
1319 for (InterfaceClass &item : *this)
1320 if (index-- == 0)
1321 return &item;
1322 return nullptr;
1323 }
1324
1325 private:
1326 // internal state
1327 device_t & m_root;
1328 int m_maxdepth;
1329 };
1330
1331
1332
1333 //**************************************************************************
1334 // INLINE FUNCTIONS
1335 //**************************************************************************
1336
1337 //-------------------------------------------------
1338 // subdevice - given a tag, find the device by
1339 // name relative to this device
1340 //-------------------------------------------------
1341
subdevice(const char * tag)1342 inline device_t *device_t::subdevice(const char *tag) const
1343 {
1344 // empty string or nullptr means this device
1345 if (tag == nullptr || *tag == 0)
1346 return const_cast<device_t *>(this);
1347
1348 // do a quick lookup and return that if possible
1349 auto quick = m_subdevices.m_tagmap.find(tag);
1350 return (quick != m_subdevices.m_tagmap.end()) ? quick->second : subdevice_slow(tag);
1351 }
1352
1353
1354 //-------------------------------------------------
1355 // siblingdevice - given a tag, find the device
1356 // by name relative to this device's parent
1357 //-------------------------------------------------
1358
siblingdevice(const char * tag)1359 inline device_t *device_t::siblingdevice(const char *tag) const
1360 {
1361 // empty string or nullptr means this device
1362 if (tag == nullptr || *tag == 0)
1363 return const_cast<device_t *>(this);
1364
1365 // leading caret implies the owner, just skip it
1366 if (tag[0] == '^') tag++;
1367
1368 // query relative to the parent, if we have one
1369 if (m_owner != nullptr)
1370 return m_owner->subdevice(tag);
1371
1372 // otherwise, it's nullptr unless the tag is absolute
1373 return (tag[0] == ':') ? subdevice(tag) : nullptr;
1374 }
1375
1376
1377 // these operators requires device_interface to be a complete type
1378 inline device_t::interface_list::auto_iterator &device_t::interface_list::auto_iterator::operator++()
1379 {
1380 m_current = m_current->interface_next();
1381 return *this;
1382 }
1383
1384 inline device_t::interface_list::auto_iterator device_t::interface_list::auto_iterator::operator++(int)
1385 {
1386 auto_iterator result(*this);
1387 m_current = m_current->interface_next();
1388 return result;
1389 }
1390
1391
1392 #endif /* MAME_EMU_DEVICE_H */
1393