diff options
Diffstat (limited to 'src/emu/device.h')
-rw-r--r-- | src/emu/device.h | 888 |
1 files changed, 685 insertions, 203 deletions
diff --git a/src/emu/device.h b/src/emu/device.h index fc8da68f65c..4c2e1d8a180 100644 --- a/src/emu/device.h +++ b/src/emu/device.h @@ -37,19 +37,6 @@ //************************************************************************** -// DEVICE CONFIGURATION MACROS -//************************************************************************** - -// configure devices - -#define DECLARE_READ_LINE_MEMBER(name) int name() -#define READ_LINE_MEMBER(name) int name() -#define DECLARE_WRITE_LINE_MEMBER(name) void name(ATTR_UNUSED int state) -#define WRITE_LINE_MEMBER(name) void name(ATTR_UNUSED int state) - - - -//************************************************************************** // GLOBAL VARIABLES //************************************************************************** @@ -64,21 +51,29 @@ static const char DEVICE_SELF_OWNER[] = "^"; // TYPE DEFINITIONS //************************************************************************** -namespace emu { namespace detail { +namespace emu::detail { class device_type_impl_base; -template <typename T> struct is_device_implementation -{ - static constexpr bool value = std::is_base_of<device_t, T>::value; -}; +template <typename T> +using is_device_implementation = std::bool_constant<std::is_base_of_v<device_t, T> >; + +template <typename T> +using is_device_interface = std::bool_constant<std::is_base_of_v<device_interface, T> && !is_device_implementation<T>::value>; -template <typename T> struct is_device_interface + +struct device_flags { - static constexpr bool value = std::is_base_of<device_interface, T>::value && !is_device_implementation<T>::value; -}; + enum type : u16 + { + NOT_WORKING = u16(1) << 0, + SAVE_UNSUPPORTED = u16(1) << 1, + NONE = u16(0), + ALL = (u16(1) << 2) - 1U + }; +}; struct device_feature { @@ -124,6 +119,7 @@ struct device_feature }; }; +DECLARE_ENUM_BITWISE_OPERATORS(device_flags::type); DECLARE_ENUM_BITWISE_OPERATORS(device_feature::type); @@ -182,14 +178,9 @@ private: template <class DeviceClass, char const *ShortName, char const *FullName, char const *Source> struct device_tag_struct { typedef DeviceClass type; }; -template <class DriverClass, char const *ShortName, char const *FullName, char const *Source, device_feature::type Unemulated, device_feature::type Imperfect> +template <class DriverClass, char const *ShortName, char const *FullName, char const *Source, device_flags::type Flags, device_feature::type Unemulated, device_feature::type Imperfect> struct driver_tag_struct { typedef DriverClass type; }; -template <class DeviceClass, char const *ShortName, char const *FullName, char const *Source> -auto device_tag_func() { return device_tag_struct<DeviceClass, ShortName, FullName, Source>{ }; }; -template <class DriverClass, char const *ShortName, char const *FullName, char const *Source, device_feature::type Unemulated, device_feature::type Imperfect> -auto driver_tag_func() { return driver_tag_struct<DriverClass, ShortName, FullName, Source, Unemulated, Imperfect>{ }; }; - class device_type_impl_base { private: @@ -205,7 +196,7 @@ private: template <typename DeviceClass> 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) { - return make_unique_clear<DeviceClass>(mconfig, tag, owner, clock); + return std::make_unique<DeviceClass>(mconfig, tag, owner, clock); } template <typename DriverClass> @@ -214,7 +205,7 @@ private: assert(!owner); assert(!clock); - return make_unique_clear<DriverClass>(mconfig, type, tag); + return std::make_unique<DriverClass>(mconfig, type, tag); } create_func const m_creator; @@ -222,8 +213,10 @@ private: char const *const m_shortname; char const *const m_fullname; char const *const m_source; + device_flags::type const m_emulation_flags; device_feature::type const m_unemulated_features; device_feature::type const m_imperfect_features; + device_type_impl_base const *const m_parent_rom; device_type_impl_base *m_next; @@ -236,34 +229,40 @@ public: , m_shortname(nullptr) , m_fullname(nullptr) , m_source(nullptr) + , m_emulation_flags(device_flags::NONE) , m_unemulated_features(device_feature::NONE) , m_imperfect_features(device_feature::NONE) + , m_parent_rom(nullptr) , m_next(nullptr) { } template <class DeviceClass, char const *ShortName, char const *FullName, char const *Source> - device_type_impl_base(device_tag_struct<DeviceClass, ShortName, FullName, Source> (*)()) + device_type_impl_base(device_tag_struct<DeviceClass, ShortName, FullName, Source>) : m_creator(&create_device<DeviceClass>) , m_type(typeid(DeviceClass)) , m_shortname(ShortName) , m_fullname(FullName) , m_source(Source) + , m_emulation_flags(DeviceClass::emulation_flags()) , m_unemulated_features(DeviceClass::unemulated_features()) , m_imperfect_features(DeviceClass::imperfect_features()) + , m_parent_rom(DeviceClass::parent_rom_device_type()) , m_next(device_registrar::register_device(*this)) { } - 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> (*)()) + template <class DriverClass, char const *ShortName, char const *FullName, char const *Source, device_flags::type Flags, device_feature::type Unemulated, device_feature::type Imperfect> + device_type_impl_base(driver_tag_struct<DriverClass, ShortName, FullName, Source, Flags, Unemulated, Imperfect>) : m_creator(&create_driver<DriverClass>) , m_type(typeid(DriverClass)) , m_shortname(ShortName) , m_fullname(FullName) , m_source(Source) + , m_emulation_flags(DriverClass::emulation_flags() | Flags) , m_unemulated_features(DriverClass::unemulated_features() | Unemulated) , m_imperfect_features((DriverClass::imperfect_features() & ~Unemulated) | Imperfect) + , m_parent_rom(DriverClass::parent_rom_device_type()) , m_next(nullptr) { } @@ -272,8 +271,10 @@ public: char const *shortname() const { return m_shortname; } char const *fullname() const { return m_fullname; } char const *source() const { return m_source; } + device_flags::type emulation_flags() const { return m_emulation_flags; } device_feature::type unemulated_features() const { return m_unemulated_features; } device_feature::type imperfect_features() const { return m_imperfect_features; } + device_type_impl_base const *parent_rom_device_type() const { return m_parent_rom; } std::unique_ptr<device_t> create(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) const { @@ -298,7 +299,7 @@ public: template <typename... Params> std::unique_ptr<DeviceClass> create(machine_config &mconfig, char const *tag, device_t *owner, Params &&... args) const { - return make_unique_clear<DeviceClass>(mconfig, tag, owner, std::forward<Params>(args)...); + return std::make_unique<DeviceClass>(mconfig, tag, owner, std::forward<Params>(args)...); } template <typename... Params> DeviceClass &operator()(machine_config &mconfig, char const *tag, Params &&... args) const; @@ -310,7 +311,7 @@ public: inline device_registrar::const_iterator &device_registrar::const_iterator::operator++() { m_type = m_type->m_next; return *this; } -} } // namespace emu::detail +} // namespace emu::detail // device types @@ -318,77 +319,150 @@ typedef emu::detail::device_type_impl_base const &device_type; typedef std::add_pointer_t<device_type> device_type_ptr; extern emu::detail::device_registrar const registered_device_types; -template < - typename DeviceClass, - char const *ShortName, - char const *FullName, - char const *Source> -constexpr auto device_creator = &emu::detail::device_tag_func<DeviceClass, ShortName, FullName, Source>; - -template < - typename DriverClass, - char const *ShortName, - char const *FullName, - char const *Source, - emu::detail::device_feature::type Unemulated, - emu::detail::device_feature::type Imperfect> -constexpr auto driver_device_creator = &emu::detail::driver_tag_func<DriverClass, ShortName, FullName, Source, Unemulated, Imperfect>; +/// \addtogroup machinedef +/// \{ + +/// \brief Declare a device type +/// +/// Declares a device type where the exposed device class is in the +/// global namespace. Must be used in the global namespace. +/// +/// In addition to declaring the device type itself, a forward +/// declaration for the exposed device class is generated, and automatic +/// instantiation of device finder templates for the exposed device +/// class is suppressed. +/// \param Type The device type name (an identifier). By convention, +/// these start with an uppercase letter and consist only of uppercase +/// letters and underscores. +/// \param Class The exposed device class name. Must be the device +/// implementation class, or a public base of it, and must be derived +/// from #device_t or #device_interface. +/// \sa DECLARE_DEVICE_TYPE_NS DEFINE_DEVICE_TYPE +/// DEFINE_DEVICE_TYPE_PRIVATE #define DECLARE_DEVICE_TYPE(Type, Class) \ class Class; \ - extern emu::detail::device_type_impl<Class> const &Type; \ + extern emu::detail::device_type_impl<Class> const Type; \ extern template class device_finder<Class, false>; \ extern template class device_finder<Class, true>; + +/// \brief Declare a device type for a class in a namespace +/// +/// Declares a device type where the exposed device class is not in the +/// global namespace. Must be used in the global namespace. +/// +/// In addition to declaring the device type itself, a forward +/// declaration for the exposed device class is generated, and automatic +/// instantiation of device finder templates for the exposed device +/// class is suppressed. +/// \param Type The device type name (an identifier). By convention, +/// these start with an uppercase letter and consist only of uppercase +/// letters and underscores. +/// \param Namespace The fully qualified name of the namespace +/// containing the exposed device class. +/// \param Class The exposed device class name, without namespace +/// qualifiers. Must be the device implementation class, or a public +/// base of it, and must be derived from #device_t or +/// #device_interface. +/// \sa DECLARE_DEVICE_TYPE DEFINE_DEVICE_TYPE +/// DEFINE_DEVICE_TYPE_PRIVATE #define DECLARE_DEVICE_TYPE_NS(Type, Namespace, Class) \ - extern emu::detail::device_type_impl<Namespace::Class> const &Type; \ + namespace Namespace { class Class; } \ + extern emu::detail::device_type_impl<Namespace::Class> const Type; \ extern template class device_finder<Namespace::Class, false>; \ extern template class device_finder<Namespace::Class, true>; + +/// \brief Define a device type +/// +/// Defines a device type where the exposed device class is the same as +/// the device implementation class. Must be used in the global +/// namespace. +/// +/// As well as defining the device type, device finder templates are +/// instantiated for the device class. +/// \param Type The device type name (an identifier). By convention, +/// these start with an uppercase letter and consist only of uppercase +/// letters and underscores. +/// \param Class The device implementation class name. Must be the same +/// as the exposed device class, and must be derived from #device_t. +/// \param ShortName The short name of the device, used for +/// identification, and in filesystem paths for assets and data. Must +/// be a string no longer than thirty-two characters, containing only +/// ASCII lowercase letters, digits and underscores. Must be globally +/// unique across systems and devices. +/// \param FullName Display name for the device. Must be a string, and +/// must be globally unique across systems and devices. +/// \sa DECLARE_DEVICE_TYPE DECLARE_DEVICE_TYPE_NS +/// DEFINE_DEVICE_TYPE_PRIVATE #define DEFINE_DEVICE_TYPE(Type, Class, ShortName, FullName) \ namespace { \ - struct Class##_device_traits { static constexpr char const shortname[] = ShortName, fullname[] = FullName, source[] = __FILE__; }; \ - constexpr char const Class##_device_traits::shortname[], Class##_device_traits::fullname[], Class##_device_traits::source[]; \ + struct Type##_device_traits { static constexpr char const shortname[] = ShortName, fullname[] = FullName, source[] = __FILE__; }; \ + constexpr char const Type##_device_traits::shortname[], Type##_device_traits::fullname[], Type##_device_traits::source[]; \ } \ - emu::detail::device_type_impl<Class> const &Type = device_creator<Class, (Class##_device_traits::shortname), (Class##_device_traits::fullname), (Class##_device_traits::source)>; \ + emu::detail::device_type_impl<Class> const Type = emu::detail::device_tag_struct<Class, (Type##_device_traits::shortname), (Type##_device_traits::fullname), (Type##_device_traits::source)>{ }; \ template class device_finder<Class, false>; \ template class device_finder<Class, true>; + +/// \brief Define a device type with a private implementation class +/// +/// Defines a device type where the exposed device class is a base of +/// the device implementation class. Must be used in the global +/// namespace. +/// +/// Device finder templates are not instantiated for the exposed device +/// class. This must be done explicitly in a single location for the +/// project. +/// \param Type The device type name (an identifier). By convention, +/// these start with an uppercase letter and consist only of uppercase +/// letters and underscores. +/// \param Base The fully-qualified exposed device class name. Must be +/// a public base of the device implementation class, and must be +/// derived from #device_t or #device_interface. +/// \param Class The fully-qualified device implementation class name. +/// Must be derived from the exposed device class, and indirectly from +/// #device_t. +/// \param ShortName The short name of the device, used for +/// identification, and in filesystem paths for assets and data. Must +/// be a string no longer than thirty-two characters, containing only +/// ASCII lowercase letters, digits and underscores. Must be globally +/// unique across systems and devices. +/// \param FullName Display name for the device. Must be a string, and +/// must be globally unique across systems and devices. +/// \sa DECLARE_DEVICE_TYPE DECLARE_DEVICE_TYPE_NS DEFINE_DEVICE_TYPE #define DEFINE_DEVICE_TYPE_PRIVATE(Type, Base, Class, ShortName, FullName) \ namespace { \ - struct Class##_device_traits { static constexpr char const shortname[] = ShortName, fullname[] = FullName, source[] = __FILE__; }; \ - constexpr char const Class##_device_traits::shortname[], Class##_device_traits::fullname[], Class##_device_traits::source[]; \ + struct Type##_device_traits { static constexpr char const shortname[] = ShortName, fullname[] = FullName, source[] = __FILE__; }; \ + constexpr char const Type##_device_traits::shortname[], Type##_device_traits::fullname[], Type##_device_traits::source[]; \ } \ - emu::detail::device_type_impl<Base> const &Type = device_creator<Class, (Class##_device_traits::shortname), (Class##_device_traits::fullname), (Class##_device_traits::source)>; + emu::detail::device_type_impl<Base> const Type = emu::detail::device_tag_struct<Class, (Type##_device_traits::shortname), (Type##_device_traits::fullname), (Type##_device_traits::source)>{ }; -#define DEFINE_DEVICE_TYPE_NS(Type, Namespace, Class, ShortName, FullName) \ - namespace { \ - struct Class##_device_traits { static constexpr char const shortname[] = ShortName, fullname[] = FullName, source[] = __FILE__; }; \ - constexpr char const Class##_device_traits::shortname[], Class##_device_traits::fullname[], Class##_device_traits::source[]; \ - } \ - 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)>; \ - template class device_finder<Namespace::Class, false>; \ - template class device_finder<Namespace::Class, true>; +/// \} -// exception classes +/// \brief Start order dependencies not satisfied exception +/// +/// May be thrown from the start member functions of #device_t and +/// #device_interface implementations if start order dependencies have +/// not been satisfied. MAME will start additional devices before +/// reattempting to start the device that threw the exception. +/// \sa device_t::device_start device_interface::interface_pre_start class device_missing_dependencies : public emu_exception { }; -// timer IDs for devices -typedef u32 device_timer_id; - -// ======================> device_t - -// device_t represents a device +/// \brief Base class for devices +/// +/// The base class for all device implementations in MAME's modular +/// architecture. class device_t : public delegate_late_bind { DISABLE_COPYING(device_t); friend class simple_list<device_t>; friend class running_machine; - friend class finder_base; - friend class devcb_base; + friend class device_resolver_base; class subdevice_list { @@ -411,18 +485,21 @@ class device_t : public delegate_late_bind private: // private helpers - device_t *find(const std::string &name) const + device_t &append(std::unique_ptr<device_t> &&device); + device_t &replace_and_remove(std::unique_ptr<device_t> &&device, device_t &existing); + void remove(device_t &device); + device_t *find(std::string_view name) const { - device_t *curdevice; - for (curdevice = m_list.first(); curdevice != nullptr; curdevice = curdevice->next()) - if (name.compare(curdevice->m_basetag) == 0) - return curdevice; - return nullptr; + auto result = m_tagmap.find(name); + if (result != m_tagmap.end()) + return &result->second.get(); + else + return nullptr; } // private state simple_list<device_t> m_list; // list of sub-devices we own - mutable std::unordered_map<std::string,device_t *> m_tagmap; // map of devices looked up and found by subtag + std::unordered_map<std::string_view, std::reference_wrapper<device_t>> m_tagmap; // map of devices looked up and found by subtag }; class interface_list @@ -430,7 +507,6 @@ class device_t : public delegate_late_bind friend class device_t; friend class device_interface; friend class device_memory_interface; - friend class device_state_interface; friend class device_execute_interface; public: @@ -460,7 +536,7 @@ class device_t : public delegate_late_bind }; // construction/destruction - interface_list() : m_head(nullptr), m_execute(nullptr), m_memory(nullptr), m_state(nullptr) { } + interface_list() : m_head(nullptr), m_execute(nullptr), m_memory(nullptr) { } // getters device_interface *first() const { return m_head; } @@ -473,7 +549,6 @@ class device_t : public delegate_late_bind device_interface *m_head; // head of interface list device_execute_interface *m_execute; // pre-cached pointer to execute interface device_memory_interface *m_memory; // pre-cached pointer to memory interface - device_state_interface *m_state; // pre-cached pointer to state interface }; protected: @@ -487,11 +562,60 @@ protected: public: // device flags + using flags = emu::detail::device_flags; + using flags_type = emu::detail::device_flags::type; using feature = emu::detail::device_feature; using feature_type = emu::detail::device_feature::type; + + /// \brief Report emulation status flags + /// + /// Implement this member in a derived class to declare flags + /// pertaining to the overall emulation status of the device. Some + /// flags propagate to all other devices and systems that use the + /// device. + /// \return Bitwise or of the flag constants pertaining to the + /// device emulation. + /// \sa unemulated_features imperfect_features + static constexpr flags_type emulation_flags() { return flags::NONE; } + + /// \brief Report unemulated features + /// + /// Implement this member in a derived class to declare features + /// that are not emulated. This will propagate to all other devices + /// and systems that use the device. Unemulated features are shown + /// in the system selection UI, and cause a red warning to be + /// displayed on starting a system. + /// \return Bitwise or of the feature constants for unemulated + /// features of the device. + /// \sa emulation_flags imperfect_features static constexpr feature_type unemulated_features() { return feature::NONE; } + + /// \brief Report imperfectly emulated features + /// + /// Implement this member in a derived class to declare features + /// that are imperfectly emulated. This will propagate to all other + /// devices and systems that use the device. Imperfectly emulated + /// features are shown in the system selection UI, and cause a + /// yellow warning to be displayed on starting a system (provided + /// there are no unemulated features, which take precedence and + /// cause the warning to be red). + /// + /// An exception is imperfectly emulated protection, which results + /// in a red warning being displayed when starting a system. + /// \return Bitwise or of the feature constants for imperfectly + /// emulated features of the device. + /// \sa emulation_flags unemulated_features static constexpr feature_type imperfect_features() { return feature::NONE; } + /// \brief Get parent device type for ROM search + /// + /// Implement this member in a derived class to declare the parent + /// device type for the purpose of searching for ROMs. Only one + /// level is allowed. It is an error if the parent device type + /// itself declares a parent device type. + /// \return Pointer to parent device type, or nullptr. + static auto parent_rom_device_type() { return nullptr; } + virtual ~device_t(); // getters @@ -502,7 +626,7 @@ public: device_type type() const { return m_type; } const char *name() const { return m_type.fullname(); } const char *shortname() const { return m_type.shortname(); } - const char *searchpath() const { return m_searchpath.c_str(); } + virtual std::vector<std::string> searchpath() const; const char *source() const { return m_type.source(); } device_t *owner() const { return m_owner; } device_t *next() const { return m_next; } @@ -519,36 +643,67 @@ public: // interface helpers interface_list &interfaces() { return m_interfaces; } const interface_list &interfaces() const { return m_interfaces; } - template<class DeviceClass> bool interface(DeviceClass *&intf) { intf = dynamic_cast<DeviceClass *>(this); return (intf != nullptr); } - template<class DeviceClass> bool interface(DeviceClass *&intf) const { intf = dynamic_cast<const DeviceClass *>(this); return (intf != nullptr); } + template <class DeviceClass> bool interface(DeviceClass *&intf) { intf = dynamic_cast<DeviceClass *>(this); return (intf != nullptr); } + template <class DeviceClass> bool interface(DeviceClass *&intf) const { intf = dynamic_cast<const DeviceClass *>(this); return (intf != nullptr); } // specialized helpers for common core interfaces bool interface(device_execute_interface *&intf) { intf = m_interfaces.m_execute; return (intf != nullptr); } bool interface(device_execute_interface *&intf) const { intf = m_interfaces.m_execute; return (intf != nullptr); } bool interface(device_memory_interface *&intf) { intf = m_interfaces.m_memory; return (intf != nullptr); } bool interface(device_memory_interface *&intf) const { intf = m_interfaces.m_memory; return (intf != nullptr); } - bool interface(device_state_interface *&intf) { intf = m_interfaces.m_state; return (intf != nullptr); } - bool interface(device_state_interface *&intf) const { intf = m_interfaces.m_state; return (intf != nullptr); } device_execute_interface &execute() const { assert(m_interfaces.m_execute != nullptr); return *m_interfaces.m_execute; } device_memory_interface &memory() const { assert(m_interfaces.m_memory != nullptr); return *m_interfaces.m_memory; } - device_state_interface &state() const { assert(m_interfaces.m_state != nullptr); return *m_interfaces.m_state; } // owned object helpers subdevice_list &subdevices() { return m_subdevices; } const subdevice_list &subdevices() const { return m_subdevices; } // device-relative tag lookups - std::string subtag(std::string tag) const; - std::string siblingtag(std::string tag) const { return (m_owner != nullptr) ? m_owner->subtag(tag) : tag; } - memory_region *memregion(std::string tag) const; - memory_share *memshare(std::string tag) const; - memory_bank *membank(std::string tag) const; - ioport_port *ioport(std::string tag) const; - device_t *subdevice(const char *tag) const; - device_t *siblingdevice(const char *tag) const; - template<class DeviceClass> DeviceClass *subdevice(const char *tag) const { return downcast<DeviceClass *>(subdevice(tag)); } - template<class DeviceClass> DeviceClass *siblingdevice(const char *tag) const { return downcast<DeviceClass *>(siblingdevice(tag)); } - std::string parameter(const char *tag) const; + std::string subtag(std::string_view tag) const; + std::string siblingtag(std::string_view tag) const { return (m_owner != nullptr) ? m_owner->subtag(tag) : std::string(tag); } + memory_region *memregion(std::string_view tag) const; + memory_share *memshare(std::string_view tag) const; + memory_bank *membank(std::string_view tag) const; + ioport_port *ioport(std::string_view tag) const; + device_t *subdevice(std::string_view tag) const; + device_t *siblingdevice(std::string_view tag) const; + template <class DeviceClass> + DeviceClass *subdevice(std::string_view tag) const + { + device_t *const found = subdevice(tag); + if constexpr (std::is_base_of_v<device_t, DeviceClass>) + { + return downcast<DeviceClass *>(found); + } + else + { + auto const result = dynamic_cast<DeviceClass *>(found); +#if defined(MAME_DEBUG) + if (found && !result) + report_bad_device_cast(found, typeid(device_t), typeid(DeviceClass)); +#endif + return result; + } + } + template <class DeviceClass> + DeviceClass *siblingdevice(std::string_view tag) const + { + device_t *const found = siblingdevice(tag); + if constexpr (std::is_base_of_v<device_t, DeviceClass>) + { + return downcast<DeviceClass *>(found); + } + else + { + auto const result = dynamic_cast<DeviceClass *>(found); +#if defined(MAME_DEBUG) + if (found && !result) + report_bad_device_cast(found, typeid(device_t), typeid(DeviceClass)); +#endif + return result; + } + } + std::string parameter(std::string_view tag) const; // configuration helpers void add_machine_configuration(machine_config &config); @@ -567,34 +722,131 @@ public: // clock/timing accessors u32 clock() const { return m_clock; } u32 unscaled_clock() const { return m_unscaled_clock; } - void set_unscaled_clock(u32 clock); - void set_unscaled_clock(const XTAL &xtal) { set_unscaled_clock(xtal.value()); } + void set_unscaled_clock(u32 clock, bool sync_on_new_clock_domain = false); + void set_unscaled_clock(const XTAL &xtal, bool sync_on_new_clock_domain = false) { set_unscaled_clock(xtal.value(), sync_on_new_clock_domain); } + void set_unscaled_clock_int(u32 clock) { set_unscaled_clock(clock, false); } // non-overloaded name because binding to overloads is ugly + void set_unscaled_clock_int_sync(u32 clock) { set_unscaled_clock(clock, true); } // non-overloaded name because binding to overloads is ugly double clock_scale() const { return m_clock_scale; } void set_clock_scale(double clockscale); - attotime clocks_to_attotime(u64 clocks) const; - u64 attotime_to_clocks(const attotime &duration) const; + attotime clocks_to_attotime(u64 clocks) const noexcept; + u64 attotime_to_clocks(const attotime &duration) const noexcept; // timer interfaces - emu_timer *timer_alloc(device_timer_id id = 0, void *ptr = nullptr); - void timer_set(const attotime &duration, device_timer_id id = 0, int param = 0, void *ptr = nullptr); - void synchronize(device_timer_id id = 0, int param = 0, void *ptr = nullptr) { timer_set(attotime::zero, id, param, ptr); } - void timer_expired(emu_timer &timer, device_timer_id id, int param, void *ptr) { device_timer(timer, id, param, ptr); } + template <typename... T> emu_timer *timer_alloc(T &&... args); + + /// \brief Register data for save states + /// + /// Registers data to be automatically saved/restored. Can be used + /// with fixed-sized integer types, enumerated types marked safe for + /// saving (see #ALLOW_SAVE_TYPE and #ALLOW_SAVE_TYPE_AND_VECTOR). + /// Supports C arrays, \c std::array and \c std::vector. Note that + /// \c std::vector instances must not be resized after being + /// registered to be saved/restored. + /// \param value Reference to the data to be saved/restored. The + /// \c NAME macro can be used to simplify specifying the + /// \p valname argument at the same time. + /// \param [in] valname The name of the saved item. The combination + /// of the \p valname and \p index arguments must be unique across + /// saved items for a device. + /// \param [in] index A numeric value to distinguish between saved + /// items with the same name. + template <typename ItemType> + void ATTR_COLD save_item(ItemType &value, const char *valname, int index = 0) + { + assert(m_save); + m_save->save_item(this, name(), tag(), index, value, valname); + } - // state saving interfaces - template<typename ItemType> - void ATTR_COLD save_item(ItemType &&value, const char *valname, int index = 0) { assert(m_save != nullptr); m_save->save_item(this, name(), tag(), index, std::forward<ItemType>(value), valname); } - template<typename ItemType> - void ATTR_COLD save_pointer(ItemType &&value, const char *valname, u32 count, int index = 0) { assert(m_save != nullptr); m_save->save_pointer(this, name(), tag(), index, std::forward<ItemType>(value), valname, count); } + /// \brief Register a member of a structure in an array for save + /// states + /// + /// Registers data to be automatically saved/restored. Can be used + /// with fixed-sized integer types, enumerated types marked safe for + /// saving (see #ALLOW_SAVE_TYPE and #ALLOW_SAVE_TYPE_AND_VECTOR). + /// Used to allow saving/restoring members of structures in C arrays + /// or \c std::array instances. + /// \param value Reference to the array of structures containing the + /// member to be saved/restored. The #STRUCT_MEMBER macro can be + /// used to simplify specifying the \p element and \p valname + /// arguments at the same time. + /// \param [in] element Pointer to the member of the structure to + /// save/restore. + /// \param [in] valname The name of the saved item. The combination + /// of the \p valname and \p index arguments must be unique across + /// saved items for a device. + /// \param [in] index A numeric value to distinguish between saved + /// items with the same name. + template <typename ItemType, typename StructType, typename ElementType> + void ATTR_COLD save_item(ItemType &value, ElementType StructType::*element, const char *valname, int index = 0) + { + assert(m_save); + m_save->save_item(this, name(), tag(), index, value, element, valname); + } + + /// \brief Register an array of indeterminate for save states + /// + /// Registers data to be automatically saved/restored when the + /// length of the outermost array cannot be automatically determined + /// at compile time. Can be used with C arrays of indeterminate + /// length, pointers, and \c std::unique_ptr instances pointing to + /// arrays. Use #save_item if length of the array can be determined + /// at compile time. + /// \param value Pointer to the array containing the data to be + /// saved/restored. The \c NAME macro can be used to simplify + /// specifying the \p valname argument at the same time. + /// \param [in] valname The name of the saved item. The combination + /// of the \p valname and \p index arguments must be unique across + /// saved items for a device. + /// \param [in] count The number of elements in the outermost array. + /// \param [in] index A numeric value to distinguish between saved + /// items with the same name. + /// \sa save_item + template <typename ItemType> + void ATTR_COLD save_pointer(ItemType &&value, const char *valname, u32 count, int index = 0) + { + assert(m_save); + m_save->save_pointer(this, name(), tag(), index, std::forward<ItemType>(value), valname, count); + } + + /// \brief Register a member of a structure in an array of + /// indeterminate for save states + /// + /// Registers data to be automatically saved/restored when the + /// length of the outermost array cannot be automatically determined + /// at compile time. Can be used with C arrays of indeterminate + /// length, pointers, and \c std::unique_ptr instances pointing to + /// arrays. Use #save_item if length of the array can be determined + /// at compile time. + /// \param value Pointer to the array of structures containing the + /// member to be saved/restored. The #STRUCT_MEMBER macro can be + /// used to simplify specifying the \p element and \p valname + /// arguments at the same time. + /// \param [in] element Pointer to the member of the structure to + /// save/restore. + /// \param [in] valname The name of the saved item. The combination + /// of the \p valname and \p index arguments must be unique across + /// saved items for a device. + /// \param [in] count The number of elements in the outermost array. + /// \param [in] index A numeric value to distinguish between saved + /// items with the same name. + /// \sa save_item + template <typename ItemType, typename StructType, typename ElementType> + void ATTR_COLD save_pointer(ItemType &&value, ElementType StructType::*element, const char *valname, u32 count, int index = 0) + { + assert(m_save); + m_save->save_pointer(this, name(), tag(), index, std::forward<ItemType>(value), element, valname, count); + } // debugging device_debug *debug() const { return m_debug.get(); } void set_system_bios(u8 bios) { m_system_bios = bios; } - bool findit(bool isvalidation) const; + bool findit(validity_checker *valid) const; // misc template <typename Format, typename... Params> void popmessage(Format &&fmt, Params &&... args) const; template <typename Format, typename... Params> void logerror(Format &&fmt, Params &&... args) const; + void view_register(memory_view *view); protected: // miscellaneous helpers @@ -606,9 +858,8 @@ protected: void debug_setup(); void pre_save(); void post_load(); - void notify_clock_changed(); - finder_base *register_auto_finder(finder_base &autodev); - void register_callback(devcb_base &callback); + void notify_clock_changed(bool sync_on_new_clock_domain = false); + device_resolver_base *register_auto_finder(device_resolver_base &autodev); //------------------- begin derived class overrides @@ -616,24 +867,143 @@ protected: virtual const tiny_rom_entry *device_rom_region() const; virtual void device_add_mconfig(machine_config &config); virtual ioport_constructor device_input_ports() const; + + /// \brief Finalise device configuration + /// + /// Perform any final configuration tasks after all devices in the + /// system have added machine configuration. This is called after + /// any #device_interface mix-in \c interface_config_complete + /// members have completed. + /// + /// Note that automatic object finders will not have been resolved + /// at the time this member is called. virtual void device_config_complete(); + + /// \brief Additional device validity checks + /// + /// Implement this member to provide additional validity checks. + /// Report errors using #osd_printf_error and report warnings using + /// #osd_printf_warning. The system being validated, device type + /// and device tag are collected automatically. Do not throw + /// exceptions to report errors. + /// + /// This provides an opportunity to check that the device has been + /// configured correctly. Systems are validated on start, and also + /// when the user manually runs a validity check. Validity checks + /// are only run for devices configured in runnable systems, not + /// when checking that a device can be instantiated in isolation. + /// \param [in] valid Reference to the validity checker object + /// performing validation (provides some helper member functions). + /// \sa device_interface::interface_validity_check virtual void device_validity_check(validity_checker &valid) const ATTR_COLD; + + /// \brief Resolve objects that may be needed while starting + /// + /// Implement this member to complete object resolution before any + /// devices are started. For example it may be necessary to resolve + /// callbacks before any devices start so initial input conditions + /// can be set. This is called after all registered automatic + /// object finders are resolved. virtual void device_resolve_objects() ATTR_COLD; + + /// \brief Device start handler + /// + /// Implement this member to set up the initial state of the device + /// on start. This will be called after all #device_interface + /// mix-in \c interface_pre_start members have completed + /// successfully. If the device can't start until another device + /// has completed starting, throw a #device_missing_dependencies + /// exception. Starting will be postponed until additional devices + /// have started. + /// + /// If a device's direct base class is not #device_t, it's good + /// practice to check start order dependencies (and throw + /// #device_missing_dependencies if necessary) before calling the + /// base implementation. This will ensure that the base + /// implementation won't be called twice if starting needs to be + /// postponed. + /// + /// This is the correct place to register for save states. + /// \sa device_reset device_stop save_item save_pointer + /// device_interface::interface_pre_start + /// device_interface::interface_post_start virtual void device_start() ATTR_COLD = 0; + + /// \brief Device stop handler + /// + /// Implement this member to perform additional tasks on ending an + /// emulation session. You may deallocate memory here. This is + /// called after \c interface_pre_stop is called for all + /// #device_interface mix-ins, and before \c interface_post_stop is + /// called for any #device_interface mix-ins. + /// \sa device_interface::interface_pre_stop + /// device_interface::interface_post_stop virtual void device_stop() ATTR_COLD; + + /// \brief Device reset handler + /// + /// Implement this member to provide reset behaviour. This is + /// called after all #device_interface mix-in \c interface_pre_reset + /// members have completed, and before any child devices are reset. + /// All devices are reset at the beginning of an emulation session + /// (after all devices have been started), and also when the user + /// requests a soft reset (by pressing F3 by default, and also + /// available from the debugger). + /// + /// Note that child devices are reset automatically when a device is + /// reset. You should not reset child devices manually from this + /// member. If you need to provide additional behaviour after child + /// devices are reset, implement #device_reset_after_children. + /// + /// Only implement warm reset behaviour in this member. Initial + /// cold reset conditions should be set up in #device_start. + /// \sa device_reset_after_children device_start + /// device_interface::interface_pre_reset + /// device_interface::interface_post_reset virtual void device_reset() ATTR_COLD; + + /// \brief Additional reset behaviour after child device reset + /// + /// Implement this member to provide additional reset behaviour + /// after child devices are reset. This is called when resetting a + /// device after #device_reset has been called and all child devices + /// have been reset, and before any #device_interface mix-in + /// \c interface_post_reset members are called. + /// \sa device_reset device_interface::interface_pre_reset + /// device_interface::interface_post_reset virtual void device_reset_after_children() ATTR_COLD; + + /// \brief Prepare for a save state to be written + /// + /// Implement this member to perform any tasks necessary before any + /// registered save state items are recorded. For example it may be + /// necessary to flush caches, serialise self-referencing members or + /// pointers into data structures. This is called after all + /// #device_interface mix-in \c interface_pre_save members are + /// called. + /// \sa device_post_load save_item save_pointer + /// device_interface::interface_pre_save virtual void device_pre_save() ATTR_COLD; + + /// \brief Complete save state loading + /// + /// Implement this member to perform any tasks necessary after + /// registered save state items are loaded. For example it may be + /// necessary to update or invalidate caches, or de-serialise + /// pointers into data structures. This is called after all + /// #device_interface mix-in \c interface_post_load members are + /// called. + /// \sa device_pre_save save_item save_pointer + /// device_interface::interface_post_load virtual void device_post_load() ATTR_COLD; + virtual void device_clock_changed(); virtual void device_debug_setup(); - virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); //------------------- end derived class overrides // core device properties device_type m_type; // device type - std::string m_searchpath; // search path, used for media loading // device relationships & interfaces device_t * m_owner; // device that owns us @@ -658,7 +1028,7 @@ protected: private: // internal helpers - device_t *subdevice_slow(const char *tag) const; + device_t *subdevice_slow(std::string_view tag) const; void calculate_derived_clock(); // private state; accessor use required @@ -668,18 +1038,21 @@ private: std::string m_basetag; // base part of the tag bool m_config_complete; // have we completed our configuration? bool m_started; // true if the start function has succeeded - finder_base * m_auto_finder_list; // list of objects to auto-find + device_resolver_base * m_auto_finder_list; // list of objects to auto-find mutable std::vector<rom_entry> m_rom_entries; - std::list<devcb_base *> m_callbacks; + std::vector<memory_view *> m_viewlist; // list of views // string formatting buffer for logerror mutable util::ovectorstream m_string_buffer; }; -// ======================> device_interface - -// device_interface represents runtime information for a particular device interface +/// \brief Device mix-in base +/// +/// Provides a base for #device_t mix-ins that integrate with the device +/// lifecycle. Derived classes are used to implement a number of +/// standard concepts and interfaces, and integrate with the scheduler, +/// debugger and user interface. class device_interface { DISABLE_COPYING(device_interface); @@ -701,24 +1074,139 @@ public: device_interface *interface_next() const { return m_interface_next; } // optional operation overrides - // - // WARNING: interface_pre_start must be callable multiple times in - // case another interface throws a missing dependency. In - // particular, state saving registrations should be done in post. + + /// \brief Finalise mix-in configuration + /// + /// Perform any final configuration tasks after all devices in the + /// system have added machine configuration. This is called before + /// \c device_config_complete is called for the device. + /// + /// Note that automatic object finders will not have been resolved + /// at this time. + /// \sa device_t::device_config_complete virtual void interface_config_complete(); - virtual void interface_validity_check(validity_checker &valid) const; - virtual void interface_pre_start(); - virtual void interface_post_start(); - virtual void interface_pre_reset(); - virtual void interface_post_reset(); - virtual void interface_pre_stop(); - virtual void interface_post_stop(); - virtual void interface_pre_save(); - virtual void interface_post_load(); - virtual void interface_clock_changed(); + + /// \brief Additional mix-in validity checks + /// + /// Implement this member to provide additional validity checks. + /// Report errors using #osd_printf_error and report warnings using + /// #osd_printf_warning. The system being validated, device type + /// and device tag are collected automatically. Do not throw + /// exceptions to report errors. + /// + /// This provides an opportunity to check that the mix-in has been + /// configured correctly. Systems are validated on start, and also + /// when the user manually runs a validity check. Validity checks + /// are only run for devices configured in runnable systems, not + /// when checking that a device can be instantiated in isolation. + /// \param [in] valid Reference to the validity checker object + /// performing validation (provides some helper member functions). + /// \sa device_t::device_validity_check + virtual void interface_validity_check(validity_checker &valid) const ATTR_COLD; + + /// \brief Mix-in start handler + /// + /// Implement this member to set up the initial state of the mix-in + /// on start. This is called before the device_start member is + /// called for the device. If the mix-in can't be started until + /// another device has started, throw a #device_missing_dependencies + /// exception. Starting will be postponed until additional devices + /// have been started. + /// + /// Note that this member may be called multiple times if another + /// \c device_interface mix-in throws a #device_missing_dependencies + /// exception from its \c interface_pre_start member, or if the + /// device throws a #device_missing_dependencies exception from its + /// \c device_start member. You must check to ensure that + /// operations like resource allocation are not performed multiple + /// times, or postpone them until #interface_post_start is called. + /// + /// It's simpler to register for save states when + /// #interface_post_start is called. + /// \sa interface_post_start device_t::device_start + virtual void interface_pre_start() ATTR_COLD; + + /// \brief Mix-in start completion handler + /// + /// Implement this member to complete mix-in start-up. This is + /// called after #interface_pre_start is called for all + /// device_interface mix-ins, and after \c device_start is called + /// for the device. This member will only be called once, it will + /// not be called multiple times if device starting is postponed. + /// + /// This member must not throw #device_missing_dependencies (start + /// order dependencies should be checked in #interface_pre_start). + /// This is the appropriate place to allocate resources like + /// timers and register for save states. + /// \sa interface_pre_start device_t::device_start + /// device_t::save_item device_t::save_pointer + virtual void interface_post_start() ATTR_COLD; + + /// \brief Mix-in reset handler + /// + /// Implement this member to provide reset behaviour. This is + /// called before \c device_reset is called for the device, and + /// before any child devices are reset. Only implement warm reset + /// behaviour in this member. Initial cold reset conditions should + /// be set up in #interface_pre_start and/or #interface_post_start. + /// If you need to provide additional behaviour after child devices + /// are reset, implement #interface_post_reset. + /// \sa interface_post_reset device_t::device_reset + virtual void interface_pre_reset() ATTR_COLD; + + /// \brief Mix-in reset completion handler + /// + /// Implement this member to provide additional reset behaviour + /// after child devices are reset. This is called after + /// \c device_reset_after_children has been called for the device. + /// \sa interface_pre_reset device_t::device_reset + /// device_t::device_reset_after_children + virtual void interface_post_reset() ATTR_COLD; + + /// \brief Mix-in stop handler + /// + /// Implement this member to perform additional tasks on ending an + /// emulation session. Do not deallocate anything that may need to + /// be referenced from another device_interface mix-in's + /// \c interface_pre_stop member or from the device's \c device_stop + /// member. This is called before device_stop is called for the + /// device. + /// \sa interface_post_stop device_t::device_stop + virtual void interface_pre_stop() ATTR_COLD; + + /// \brief Mix-in stop completion handler + /// + /// Implement this member to perform additional tasks on ending an + /// emulation session after the device is stopped. You can + /// deallocate memory here. This is called after \c device_stop is + /// called for the device. + /// \sa interface_pre_stop device_t::device_stop + virtual void interface_post_stop() ATTR_COLD; + + /// \brief Prepare for a save state to be written + /// + /// Implement this member to perform any tasks necessary before any + /// registered save state items are recorded. For example it may be + /// necessary to flush caches, serialise self-referencing members or + /// pointers into data structures. This is called before + /// \c device_pre_save is called for the device. + /// \sa interface_post_load device_t::device_pre_save + virtual void interface_pre_save() ATTR_COLD; + + /// \brief Complete save state loading + /// + /// Implement this member to perform any tasks necessary after + /// registered save state items are loaded. For example it may be + /// necessary to update or invalidate caches, or de-serialise + /// pointers into data structures. This is called before + /// \c device_post_load is called for the device. + /// \sa interface_pre_save device_t::device_post_load + virtual void interface_post_load() ATTR_COLD; + + virtual void interface_clock_changed(bool sync_on_new_clock_domain); virtual void interface_debug_setup(); -protected: +private: // internal state device_interface * m_interface_next; device_t & m_device; @@ -726,13 +1214,13 @@ protected: }; -// ======================> device_iterator +// ======================> device_enumerator // helper class to iterate over the hierarchy of devices depth-first -class device_iterator +class device_enumerator { public: - class auto_iterator + class iterator { public: typedef std::ptrdiff_t difference_type; @@ -742,7 +1230,7 @@ public: typedef std::forward_iterator_tag iterator_category; // construction - auto_iterator(device_t *devptr, int curdepth, int maxdepth) + iterator(device_t *devptr, int curdepth, int maxdepth) : m_curdevice(devptr) , m_curdepth(curdepth) , m_maxdepth(maxdepth) @@ -754,12 +1242,12 @@ public: int depth() const { return m_curdepth; } // required operator overrides - bool operator==(auto_iterator const &iter) const { return m_curdevice == iter.m_curdevice; } - bool operator!=(auto_iterator const &iter) const { return m_curdevice != iter.m_curdevice; } + bool operator==(iterator const &iter) const { return m_curdevice == iter.m_curdevice; } + bool operator!=(iterator const &iter) const { return m_curdevice != iter.m_curdevice; } device_t &operator*() const { assert(m_curdevice); return *m_curdevice; } device_t *operator->() const { return m_curdevice; } - auto_iterator &operator++() { advance(); return *this; } - auto_iterator operator++(int) { auto_iterator const result(*this); ++*this; return result; } + iterator &operator++() { advance(); return *this; } + iterator operator++(int) { iterator const result(*this); ++*this; return result; } protected: // search depth-first for the next device @@ -800,18 +1288,17 @@ public: } // protected state - device_t * m_curdevice; - int m_curdepth; - const int m_maxdepth; + device_t * m_curdevice; + int m_curdepth; + int m_maxdepth; }; // construction - device_iterator(device_t &root, int maxdepth = 255) - : m_root(root), m_maxdepth(maxdepth) { } + device_enumerator(device_t &root, int maxdepth = 255) : m_root(root), m_maxdepth(maxdepth) { } // standard iterators - auto_iterator begin() const { return auto_iterator(&m_root, 0, m_maxdepth); } - auto_iterator end() const { return auto_iterator(nullptr, 0, m_maxdepth); } + iterator begin() const { return iterator(&m_root, 0, m_maxdepth); } + iterator end() const { return iterator(nullptr, 0, m_maxdepth); } // return first item device_t *first() const { return begin().current(); } @@ -853,32 +1340,31 @@ public: private: // internal state - device_t & m_root; - int m_maxdepth; + device_t & m_root; + int m_maxdepth; }; -// ======================> device_type_iterator +// ======================> device_type_enumerator // helper class to find devices of a given type in the device hierarchy template <class DeviceType, class DeviceClass = DeviceType> -class device_type_iterator +class device_type_enumerator { public: - class auto_iterator : protected device_iterator::auto_iterator + class iterator : protected device_enumerator::iterator { public: - using device_iterator::auto_iterator::difference_type; - using device_iterator::auto_iterator::iterator_category; - using device_iterator::auto_iterator::depth; + using device_enumerator::iterator::difference_type; + using device_enumerator::iterator::iterator_category; + using device_enumerator::iterator::depth; typedef DeviceClass value_type; typedef DeviceClass *pointer; typedef DeviceClass &reference; // construction - auto_iterator(device_t *devptr, int curdepth, int maxdepth) - : device_iterator::auto_iterator(devptr, curdepth, maxdepth) + iterator(device_t *devptr, int curdepth, int maxdepth) : device_enumerator::iterator(devptr, curdepth, maxdepth) { // make sure the first device is of the specified type while (m_curdevice && (m_curdevice->type().type() != typeid(DeviceType))) @@ -886,8 +1372,8 @@ public: } // required operator overrides - bool operator==(auto_iterator const &iter) const { return m_curdevice == iter.m_curdevice; } - bool operator!=(auto_iterator const &iter) const { return m_curdevice != iter.m_curdevice; } + bool operator==(iterator const &iter) const { return m_curdevice == iter.m_curdevice; } + bool operator!=(iterator const &iter) const { return m_curdevice != iter.m_curdevice; } // getters returning specified device type DeviceClass *current() const { return downcast<DeviceClass *>(m_curdevice); } @@ -895,25 +1381,23 @@ public: DeviceClass *operator->() const { return downcast<DeviceClass *>(m_curdevice); } // search for devices of the specified type - auto_iterator &operator++() + iterator &operator++() { - advance(); - while (m_curdevice && (m_curdevice->type().type() != typeid(DeviceType))) - advance(); + do { advance(); } while (m_curdevice && (m_curdevice->type().type() != typeid(DeviceType))); return *this; } - auto_iterator operator++(int) { auto_iterator const result(*this); ++*this; return result; } + iterator operator++(int) { iterator const result(*this); ++*this; return result; } }; // construction - device_type_iterator(device_t &root, int maxdepth = 255) : m_root(root), m_maxdepth(maxdepth) { } + device_type_enumerator(device_t &root, int maxdepth = 255) : m_root(root), m_maxdepth(maxdepth) { } // standard iterators - auto_iterator begin() const { return auto_iterator(&m_root, 0, m_maxdepth); } - auto_iterator end() const { return auto_iterator(nullptr, 0, m_maxdepth); } - auto_iterator cbegin() const { return auto_iterator(&m_root, 0, m_maxdepth); } - auto_iterator cend() const { return auto_iterator(nullptr, 0, m_maxdepth); } + iterator begin() const { return iterator(&m_root, 0, m_maxdepth); } + iterator end() const { return iterator(nullptr, 0, m_maxdepth); } + iterator cbegin() const { return iterator(&m_root, 0, m_maxdepth); } + iterator cend() const { return iterator(nullptr, 0, m_maxdepth); } // return first item DeviceClass *first() const { return begin().current(); } @@ -951,20 +1435,19 @@ private: }; -// ======================> device_interface_iterator +// ======================> device_interface_enumerator // helper class to find devices with a given interface in the device hierarchy // also works for finding devices derived from a given subclass -template<class InterfaceClass> -class device_interface_iterator +template <class InterfaceClass> +class device_interface_enumerator { public: - class auto_iterator : public device_iterator::auto_iterator + class iterator : public device_enumerator::iterator { -public: + public: // construction - auto_iterator(device_t *devptr, int curdepth, int maxdepth) - : device_iterator::auto_iterator(devptr, curdepth, maxdepth) + iterator(device_t *devptr, int curdepth, int maxdepth) : device_enumerator::iterator(devptr, curdepth, maxdepth) { // set the iterator for the first device with the interface find_interface(); @@ -975,14 +1458,15 @@ public: InterfaceClass &operator*() const { assert(m_interface != nullptr); return *m_interface; } // search for devices with the specified interface - const auto_iterator &operator++() { advance(); find_interface(); return *this; } + const iterator &operator++() { advance(); find_interface(); return *this; } + iterator operator++(int) { iterator const result(*this); ++*this; return result; } -private: + private: // private helper void find_interface() { // advance until finding a device with the interface - for ( ; m_curdevice != nullptr; advance()) + for ( ; m_curdevice; advance()) if (m_curdevice->interface(m_interface)) return; @@ -994,14 +1478,12 @@ private: InterfaceClass *m_interface; }; -public: // construction - device_interface_iterator(device_t &root, int maxdepth = 255) - : m_root(root), m_maxdepth(maxdepth) { } + device_interface_enumerator(device_t &root, int maxdepth = 255) : m_root(root), m_maxdepth(maxdepth) { } // standard iterators - auto_iterator begin() const { return auto_iterator(&m_root, 0, m_maxdepth); } - auto_iterator end() const { return auto_iterator(nullptr, 0, m_maxdepth); } + iterator begin() const { return iterator(&m_root, 0, m_maxdepth); } + iterator end() const { return iterator(nullptr, 0, m_maxdepth); } // return first item InterfaceClass *first() const { return begin().current(); } @@ -1058,15 +1540,15 @@ private: // name relative to this device //------------------------------------------------- -inline device_t *device_t::subdevice(const char *tag) const +inline device_t *device_t::subdevice(std::string_view tag) const { - // empty string or nullptr means this device - if (tag == nullptr || *tag == 0) + // empty string means this device (DEVICE_SELF) + if (tag.empty()) return const_cast<device_t *>(this); // do a quick lookup and return that if possible auto quick = m_subdevices.m_tagmap.find(tag); - return (quick != m_subdevices.m_tagmap.end()) ? quick->second : subdevice_slow(tag); + return (quick != m_subdevices.m_tagmap.end()) ? &quick->second.get() : subdevice_slow(tag); } @@ -1075,21 +1557,21 @@ inline device_t *device_t::subdevice(const char *tag) const // by name relative to this device's parent //------------------------------------------------- -inline device_t *device_t::siblingdevice(const char *tag) const +inline device_t *device_t::siblingdevice(std::string_view tag) const { - // empty string or nullptr means this device - if (tag == nullptr || *tag == 0) + // empty string means this device (DEVICE_SELF) + if (tag.empty()) return const_cast<device_t *>(this); // leading caret implies the owner, just skip it - if (tag[0] == '^') tag++; + if (tag[0] == '^') tag.remove_prefix(1); // query relative to the parent, if we have one if (m_owner != nullptr) return m_owner->subdevice(tag); // otherwise, it's nullptr unless the tag is absolute - return (tag[0] == ':') ? subdevice(tag) : nullptr; + return (!tag.empty() && tag[0] == ':') ? subdevice(tag) : nullptr; } @@ -1108,4 +1590,4 @@ inline device_t::interface_list::auto_iterator device_t::interface_list::auto_it } -#endif /* MAME_EMU_DEVICE_H */ +#endif // MAME_EMU_DEVICE_H |