summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/device.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/device.h')
-rw-r--r--src/emu/device.h888
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