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