summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/devfind.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/devfind.h')
-rw-r--r--src/emu/devfind.h731
1 files changed, 513 insertions, 218 deletions
diff --git a/src/emu/devfind.h b/src/emu/devfind.h
index 2428e1a7325..81ebb9f9812 100644
--- a/src/emu/devfind.h
+++ b/src/emu/devfind.h
@@ -1,13 +1,9 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles, Vas Crabb
-/**
- * \file devfind.h
- * Object auto-discovery helpers
- * \defgroup devfind
- * \{
- * Object auto-discovery helpers
- */
-
+/// \file
+/// \brief Object auto-discovery helpers
+/// \defgroup devfind Object auto-discovery helpers
+/// \{
#ifndef __EMU_H__
#error Dont include this file directly; include emu.h instead.
#endif
@@ -19,11 +15,13 @@
#include <functional>
#include <iterator>
+#include <memory>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <utility>
+
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
@@ -100,8 +98,8 @@ public:
/// int argument.
/// \param [in] start Number to add to element index when
/// calculating values for string format argument.
- /// \arg [in] Optional additional constructor argument(s) passed to
- /// all elements.
+ /// \param [in] arg Optional additional constructor argument(s) passed
+ /// to all elements.
/// \sa util::string_format
template <typename F, typename... Param>
object_array_finder(device_t &base, F const &fmt, unsigned start, Param const &... arg)
@@ -117,8 +115,8 @@ public:
/// \param [in] tags Tags to search for, e.g. { "player", "dips" }.
/// The tags are not copied, it is the caller's responsibility to
/// ensure the pointers remain valid until resolution time.
- /// \arg [in] Optional additional constructor argument(s) passed to
- /// all elements.
+ /// \param [in] arg Optional additional constructor argument(s) passed
+ /// to all elements.
template <typename... Param>
object_array_finder(device_t &base, std::array<char const *, Count> const &tags, Param const &... arg)
: object_array_finder(base, tags, std::make_integer_sequence<unsigned, Count>(), arg...)
@@ -147,7 +145,7 @@ public:
/// \brief Get constant iterator beyond last element
///
- /// Returns aconstant iterator one past the last element in the
+ /// Returns a constant iterator one past the last element in the
/// array.
/// \return Constant iterator one past last element.
const_iterator cend() const { return m_array + Count; }
@@ -167,7 +165,7 @@ public:
/// \brief Does array have no elements
///
- /// Returns whether the arary has no elements (compile-time
+ /// Returns whether the array has no elements (compile-time
/// constant).
/// \return True if the array has no elements, false otherwise.
constexpr bool empty() const { return !Count; }
@@ -200,7 +198,7 @@ public:
/// \return Reference to element at specified index.
T &operator[](unsigned index) { assert(index < Count); return m_array[index]; }
- /// \brief Checked element accesor
+ /// \brief Checked element accessor
///
/// Returns a reference to the element at the supplied index if less
/// than the size of the array, or throws std::out_of_range
@@ -218,33 +216,34 @@ public:
/// Abstract non-template base class for object auto-discovery helpers.
/// Provides the interface that the device_t uses to manage discovery at
/// resolution time.
-class finder_base
+class device_resolver_base
{
public:
/// \brief Destructor
///
/// Destruction via base class pointer and dynamic type behaviour
/// are allowed.
- virtual ~finder_base();
+ virtual ~device_resolver_base();
/// \brief Get next registered object discovery helper
///
/// Implementation of basic single-linked list behaviour.
/// \return Pointer to the next registered object discovery helper,
/// or nullptr if this is the last.
- finder_base *next() const { return m_next; }
+ device_resolver_base *next() const noexcept { return m_next; }
/// \brief Attempt discovery
///
/// Concrete derived classes must implement this member function.
- /// Should return false if the the object is required but not found,
- /// or true otherwise (the report_missing member function can assist
+ /// Should return false if the object is required but not found, or
+ /// true otherwise (the report_missing member function can assist
/// in implementing this behaviour).
- /// \param [in] isvalidation Pass true if this is a dry run (i.e. no
- /// intention to actually start the device), or false otherwise.
+ /// \param [in] valid Pass a pointer to the validity checker if this
+ /// is a dry run (i.e. no intention to actually start the device),
+ /// or nullptr otherwise.
/// \return False if the object is required but not found, or true
/// otherwise.
- virtual bool findit(bool isvalidation = false) = 0;
+ virtual bool findit(validity_checker *valid) = 0;
/// \brief Clear temporary binding from configuration
///
@@ -255,6 +254,32 @@ public:
/// subsequently removes or replaces devices.
virtual void end_configuration() = 0;
+protected:
+ /// \brief Designated constructor
+ ///
+ /// Construct base object discovery helper and register with device
+ /// to be invoked at resolution time.
+ /// \param [in] base Device to register with for resolution.
+ device_resolver_base(device_t &base);
+
+
+ /// \brief Pointer to next registered discovery helper
+ ///
+ /// This is a polymorphic class, so it can't be held in a standard
+ /// list container that requires elements of the same type. Hence
+ /// it implements basic intrusive single-linked list behaviour.
+ device_resolver_base *const m_next;
+};
+
+
+/// \brief Base class for object discovery helpers
+///
+/// Abstract non-template base class for object auto-discovery helpers.
+/// Provides functionality for specifying a target as a base device and
+/// relative tag. Also supplies helpers for looking up resources.
+class finder_base : protected device_resolver_base
+{
+public:
/// \brief Get search tag
///
/// Returns the search tag.
@@ -281,6 +306,7 @@ public:
void set_tag(device_t &base, char const *tag)
{
assert(!m_resolved);
+ assert(tag);
m_base = base;
m_tag = tag;
}
@@ -309,14 +335,16 @@ public:
}
/// \brief Dummy tag always treated as not found
- constexpr static char DUMMY_TAG[17] = "finder_dummy_tag";
+ static constexpr char DUMMY_TAG[17] = "finder_dummy_tag";
protected:
/// \brief Designated constructor
///
/// Construct base object discovery helper and register with device
/// to be invoked at resolution time.
- /// \param [in] base Base device to search from.
+ /// \param [in] base Device to register with for resolution. Also
+ /// sets initial base device to search from. The tag must be
+ /// specified relative to this device.
/// \param [in] tag Object tag to search for. This is not copied,
/// it is the caller's responsibility to ensure this pointer
/// remains valid until resolution time.
@@ -351,13 +379,11 @@ protected:
/// report_missing to print an error message if the region is
/// not found. Returns true if the region is required but no
/// matching region is found, or false otherwise.
- /// \param [in] bytes Desired region length in bytes, or 0U to match
- /// any length.
/// \param [in] required True if the region is required, or false if
/// it is optional.
/// \return True if the region is optional, or if the region is
/// required and a matching region is found, or false otherwise.
- bool validate_memregion(size_t bytes, bool required) const;
+ bool validate_memregion(bool required) const;
/// \brief Find a memory share
///
@@ -368,9 +394,9 @@ protected:
/// with the requested tag is found, but it doesn't match the
/// desired width.
/// \param [in] width Desired memory share width in bits.
- /// \param [out] bytes Set to memoyr share length in bytes if a
+ /// \param [out] bytes Set to memory share length in bytes if a
/// matching memory share is found, otherwise left unchanged.
- /// \param [in] required. Whether warning message should be printed
+ /// \param [in] required Whether warning message should be printed
/// if a memory share with matching tag of incorrect width is
/// found.
/// \return Pointer to base of memory share if a matching memory
@@ -387,7 +413,7 @@ protected:
/// or a space with the designated number.
/// \param [in] spacenum Address space number.
/// \param [in] width Specific data width, or 0.
- /// \param [in] required. Whether warning message should be printed
+ /// \param [in] required Whether warning message should be printed
/// if a device with no memory interface or space of that number
/// is found.
/// \return Pointer to address space if a matching address space
@@ -400,7 +426,7 @@ protected:
/// found, or false otherwise.
/// \param [in] spacenum Address space number.
/// \param [in] width Specific data width, or 0.
- /// \param [in] required. Whether warning message should be printed
+ /// \param [in] required Whether warning message should be printed
/// if a device with no memory interface or space of that number
/// is found.
/// \return True if the space is optional, or if the space is
@@ -421,21 +447,6 @@ protected:
/// \return True if found or not required, false otherwise.
bool report_missing(bool found, char const *objname, bool required) const;
- /// \brief Print a message at warning level
- ///
- /// Prints a message if logging is enabled at warning level or more
- /// detailed. Uses printf semantics of the C runtime library.
- /// \param [in] format Format string as used by printf function in
- /// runtime library
- void printf_warning(char const *format, ...) ATTR_PRINTF(2,3);
-
-
- /// \brief Pointer to next registered discovery helper
- ///
- /// This is a polymorphic class, so it can't be held in a standardlist
- /// container that requires elements of the same type. Hence it
- /// implements basic single-linked list behaviour.
- finder_base *const m_next;
/// \brief Base device to search from
std::reference_wrapper<device_t> m_base;
@@ -457,7 +468,7 @@ protected:
/// Assumes that non-null pointer is found, and null pointer is not
/// found.
template <class ObjectClass, bool Required>
-class object_finder_base : public finder_base
+class object_finder_common_base : public finder_base
{
public:
/// \brief Clear temporary binding from configuration
@@ -469,16 +480,10 @@ public:
virtual void end_configuration() override { assert(!m_resolved); m_target = nullptr; }
/// \brief Get pointer to target object
+ ///
/// \return Pointer to target object if found, or nullptr otherwise.
ObjectClass *target() const { return m_target; }
- /// \brief Return whether target has been found
- ///
- /// Works on the assumption that the target object pointer will be
- /// non-null if the target has been found, and null otherwise.
- /// \return True if object has been found, or false otherwise.
- bool found() const { return m_target != nullptr; }
-
/// \brief Cast-to-pointer operator
///
/// Allows implicit casting to a pointer to the target object.
@@ -492,7 +497,7 @@ public:
/// Allows pointer-member-style access to members of the target
/// object. Asserts that the target object has been found.
/// \return Pointer to target object if found, or nullptr otherwise.
- virtual ObjectClass *operator->() const { assert(m_target); return m_target; }
+ ObjectClass *operator->() const { assert(m_target); return m_target; }
protected:
/// \brief Designated constructor
@@ -504,7 +509,7 @@ protected:
/// \param [in] tag Object tag to search for. This is not copied,
/// it is the caller's responsibility to ensure this pointer
/// remains valid until resolution time.
- object_finder_base(device_t &base, const char *tag) : finder_base(base, tag) { }
+ object_finder_common_base(device_t &base, const char *tag) : finder_base(base, tag) { }
/// \brief Log if object was not found
///
@@ -514,7 +519,7 @@ protected:
/// implementation for more detail.
/// \param [in] objname Display name for target object type.
/// \return True if found or not required, false otherwise.
- bool report_missing(char const *objname) const { return finder_base::report_missing(found(), objname, Required); }
+ bool report_missing(char const *objname) const { return finder_base::report_missing(m_target != nullptr, objname, Required); }
/// \brief Pointer to target object
///
@@ -525,6 +530,48 @@ protected:
};
+/// \brief Base class for object discovery helpers
+///
+/// Allows partial specialisations to add members based on object class
+/// and/or whether the object is required. Template arguments are the
+/// type of object to discover, and whether failure to find the object
+/// is considered an error.
+template <class ObjectClass, bool Required>
+class object_finder_base : public object_finder_common_base<ObjectClass, Required>
+{
+ using object_finder_common_base<ObjectClass, Required>::object_finder_common_base;
+};
+
+
+/// \brief Base class for optional object discovery helpers
+///
+/// Adds helpers for to test whether the object was found, and by
+/// extension whether it's safe to dereference. Template argument is
+/// the type of object to discover.
+template <class ObjectClass>
+class object_finder_base<ObjectClass, false> : public object_finder_common_base<ObjectClass, false>
+{
+public:
+ /// \brief Return whether target has been found
+ ///
+ /// Works on the assumption that the target object pointer will
+ /// be non-null if the target has been found, and null
+ /// otherwise.
+ /// \return True if object has been found, or false otherwise.
+ bool found() const { return this->m_target != nullptr; }
+
+ /// \brief Cast-to-Boolean operator
+ ///
+ /// Allows truth tests to test whether it's safe to dereference
+ /// the object, similar to pointers and various C++ standard
+ /// library objects.
+ /// \return True if safe to dereference, or false otherwise.
+ explicit operator bool() const { return this->m_target != nullptr; }
+
+ using object_finder_common_base<ObjectClass, false>::object_finder_common_base;
+};
+
+
/// \brief Device finder template
///
/// Template arguments are the device class to find, and whether the
@@ -575,6 +622,12 @@ public:
return device;
}
+ /// \brief Look up target during configuration
+ /// Look up the current target device during configuration, before
+ /// resolution.
+ /// \return Pointer to target device if found, or nullptr otherwise.
+ DeviceClass *lookup() const { return this->m_base.get().template subdevice<DeviceClass>(this->m_tag); }
+
private:
/// \brief Check that device implementation has expected tag
/// \param [in] device Reference to device.
@@ -602,13 +655,14 @@ private:
/// with the requested tag is found but the type is incorrect, a
/// warning message will be printed. This method is called by the
/// base device at resolution time.
- /// \param [in] isvalidation True if this is a dry run (not
- /// intending to run the machine, just checking for errors).
+ /// \param [in] valid Pass a pointer to the validity checker if this
+ /// is a dry run (i.e. no intention to actually start the device),
+ /// or nullptr otherwise.
/// \return True if the device is optional or if a matching device
/// is found, false otherwise.
- virtual bool findit(bool isvalidation) override
+ virtual bool findit(validity_checker *valid) override
{
- if (!isvalidation)
+ if (!valid)
{
assert(!this->m_resolved);
this->m_resolved = true;
@@ -617,7 +671,7 @@ private:
device_t *const device = this->m_base.get().subdevice(this->m_tag);
this->m_target = dynamic_cast<DeviceClass *>(device);
if (device && !this->m_target)
- this->printf_warning("Device '%s' found but is of incorrect type (actual type is %s)\n", this->m_tag, device->name());
+ osd_printf_warning("Device '%s' found but is of incorrect type (actual type is %s)\n", this->m_tag, device->name());
return this->report_missing("device");
}
@@ -625,7 +679,7 @@ private:
/// \brief Optional device finder
///
-/// Finds device with maching type and tag. If a device with matching
+/// Finds device with matching type and tag. If a device with matching
/// tag is found but the type does not match, a message is printed at
/// warning level. No error is generated if a matching device is not
/// found (the target object pointer will be null). If you have a
@@ -636,7 +690,7 @@ template <class DeviceClass> using optional_device = device_finder<DeviceClass,
/// \brief Required device finder
///
-/// Finds device with maching type and tag. If a device with matching
+/// Finds device with matching type and tag. If a device with matching
/// tag is found but the type does not match, a message is printed at
/// warning level. A validation error is generated if a matching device
/// is not found. If you have a number of similar required devices,
@@ -665,7 +719,7 @@ public:
/// \param [in] tag Memory region tag to search for. This is not
/// copied, it is the caller's responsibility to ensure this
/// pointer remains valid until resolution time.
- memory_region_finder(device_t &base, char const *tag) : object_finder_base<memory_region, Required>(base, tag) { }
+ memory_region_finder(device_t &base, char const *tag);
private:
/// \brief Find memory region
@@ -673,25 +727,17 @@ private:
/// Find memory region with requested tag. For a dry run, the
/// target object pointer will not be set. This method is called by
/// the base device at resolution time.
- /// \param [in] isvalidation True if this is a dry run (not
- /// intending to run the machine, just checking for errors).
+ /// \param [in] valid Pass a pointer to the validity checker if this
+ /// is a dry run (i.e. no intention to actually start the device),
+ /// or nullptr otherwise.
/// \return True if the memory region is optional or if a matching
/// memory region is found, false otherwise.
- virtual bool findit(bool isvalidation) override
- {
- if (isvalidation)
- return this->validate_memregion(0, Required);
-
- assert(!this->m_resolved);
- this->m_resolved = true;
- this->m_target = this->m_base.get().memregion(this->m_tag);
- return this->report_missing("memory region");
- }
+ virtual bool findit(validity_checker *valid) override;
};
/// \brief Optional memory region finder
///
-/// Finds memory region with maching tag. No error is generated if a
+/// Finds memory region with matching tag. No error is generated if a
/// matching memory region is not found (the target object pointer will
/// be null). If you have a number of similar optional memory regions,
/// consider using optional_memory_region_array.
@@ -701,7 +747,7 @@ using optional_memory_region = memory_region_finder<false>;
/// \brief Required memory region finder
///
-/// Finds memory region with maching tag. A validation error is
+/// Finds memory region with matching tag. A validation error is
/// generated if a matching memory region is not found. If you have a
/// number of similar required memory regions, consider using
/// required_memory_region_array.
@@ -730,32 +776,24 @@ public:
/// \param [in] tag Memory bank tag to search for. This is not
/// copied, it is the caller's responsibility to ensure this
/// pointer remains valid until resolution time.
- memory_bank_finder(device_t &base, char const *tag) : object_finder_base<memory_bank, Required>(base, tag) { }
+ memory_bank_finder(device_t &base, char const *tag);
/// \brief Find memory bank
///
/// Find memory bank with requested tag. Just returns true for a
/// dry run. This method is called by the base device at resolution
/// time.
- /// \param [in] isvalidation True if this is a dry run (not
- /// intending to run the machine, just checking for errors).
+ /// \param [in] valid Pass a pointer to the validity checker if this
+ /// is a dry run (i.e. no intention to actually start the device),
+ /// or nullptr otherwise.
/// \return True if the memory bank is optional, a matching memory
/// bank is found or this is a dry run, false otherwise.
- virtual bool findit(bool isvalidation) override
- {
- if (isvalidation)
- return true;
-
- assert(!this->m_resolved);
- this->m_resolved = true;
- this->m_target = this->m_base.get().membank(this->m_tag);
- return this->report_missing("memory bank");
- }
+ virtual bool findit(validity_checker *valid) override;
};
/// \brief Optional memory bank finder
///
-/// Finds memory bank with maching tag. No error is generated if a
+/// Finds memory bank with matching tag. No error is generated if a
/// matching memory bank is not found (the target object pointer will
/// be null). If you have a number of similar optional memory banks,
/// consider using optional_memory_bank_array.
@@ -765,7 +803,7 @@ using optional_memory_bank = memory_bank_finder<false>;
/// \brief Required memory bank finder
///
-/// Finds memory bank with maching tag. A validation error is
+/// Finds memory bank with matching tag. A validation error is
/// generated if a matching memory bank is not found. If you have a
/// number of similar required memory banks, consider using
/// required_memory_bank_array.
@@ -778,6 +816,90 @@ template <unsigned Count> using optional_memory_bank_array = memory_bank_array_f
template <unsigned Count> using required_memory_bank_array = memory_bank_array_finder<Count, true>;
+/// \brief Memory bank creator
+///
+/// Creates a memory bank or finds an existing one instantiated via an
+/// address map.
+class memory_bank_creator : public finder_base
+{
+public:
+ /// \brief Memory bank creator constructor
+ /// \param [in] base Base device to search from.
+ /// \param [in] tag Memory bank tag to search for or create. This
+ /// is not copied, it is the caller's responsibility to ensure
+ /// this pointer remains valid until resolution time.
+ memory_bank_creator(device_t &base, char const *tag) : finder_base(base, tag) { }
+
+ /// \brief Get pointer to memory bank object
+ /// \return Pointer to found or created bank object.
+ memory_bank *target() const { return m_target; }
+
+ /// \brief Cast-to-pointer operator
+ ///
+ /// Allows implicit casting to a pointer to the target
+ /// memory bank object.
+ /// \return Pointer to found or created memory bank object.
+ operator memory_bank *() const { return m_target; }
+
+ /// \brief Pointer member access operator
+ ///
+ /// Allows pointer-member-style access to members of the target
+ /// memory bank object. Asserts that the target has been found.
+ /// \return Pointer to found or created bank object.
+ memory_bank *operator->() const { assert(m_target); return m_target; }
+
+protected:
+ virtual bool findit(validity_checker *valid) override;
+ virtual void end_configuration() override;
+
+ /// \brief Pointer to target object
+ ///
+ /// Pointer to target memory bank object, or nullptr if creation has
+ /// not been attempted yet.
+ memory_bank *m_target = nullptr;
+};
+
+template <unsigned Count> using memory_bank_array_creator = object_array_finder<memory_bank_creator, Count>;
+
+
+/// \brief Base class for optional I/O port finders
+///
+/// Adds helpers for to test whether the I/O port was found, and to read
+/// the port value or return a default if the I/O port was not found.
+template <>
+class object_finder_base<ioport_port, false> : public object_finder_common_base<ioport_port, false>
+{
+public:
+ /// \brief Read I/O port if found or return default value
+ ///
+ /// If the I/O port was found, this reads a value from the I/O port
+ /// and returns it. If the I/O port was not found, the default
+ /// value (supplied as a parameter) is returned.
+ /// \param [in] defval Value to return if I/O port was not found.
+ /// \return Value read from I/O port if found, or supplied default
+ /// value otherwise.
+ ioport_value read_safe(ioport_value defval) { return this->m_target ? this->m_target->read() : defval; }
+
+ /// \brief Return whether target has been found
+ ///
+ /// Works on the assumption that the target object pointer will
+ /// be non-null if the target has been found, and null
+ /// otherwise.
+ /// \return True if object has been found, or false otherwise.
+ bool found() const { return this->m_target != nullptr; }
+
+ /// \brief Cast-to-Boolean operator
+ ///
+ /// Allows truth tests to test whether it's safe to dereference
+ /// the object, similar to pointers and various C++ standard
+ /// library objects.
+ /// \return True if safe to dereference, or false otherwise.
+ explicit operator bool() const { return this->m_target != nullptr; }
+
+ using object_finder_common_base<ioport_port, false>::object_finder_common_base;
+};
+
+
/// \brief I/O port finder template
///
/// Template argument is whether the I/O port is required. It is a
@@ -794,17 +916,7 @@ public:
/// \param [in] tag I/O port tag to search for. This is not copied,
/// it is the caller's responsibility to ensure this pointer
/// remains valid until resolution time.
- ioport_finder(device_t &base, char const *tag) : object_finder_base<ioport_port, Required>(base, tag) { }
-
- /// \brief Read I/O port if found or return default value
- ///
- /// If the I/O port was found, this reads a value from the I/O port
- /// and returns it. If the I/O port was not found, the default
- /// value (supplied as a parameter) is returned.
- /// \param [in] defval Value to return if I/O port was not found.
- /// \return Value read from I/O port if found, or supplied default
- /// value otherwise.
- ioport_value read_safe(ioport_value defval) { return this->m_target ? this->m_target->read() : defval; }
+ ioport_finder(device_t &base, char const *tag);
private:
/// \brief Find I/O port
@@ -812,25 +924,17 @@ private:
/// Find I/O port with requested tag. Just returns true for a dry
/// run. This method is called by the base device at resolution
/// time.
- /// \param [in] isvalidation True if this is a dry run (not
- /// intending to run the machine, just checking for errors).
+ /// \param [in] valid Pass a pointer to the validity checker if this
+ /// is a dry run (i.e. no intention to actually start the device),
+ /// or nullptr otherwise.
/// \return True if the I/O port is optional, a matching I/O port is
/// is found or this is a dry run, false otherwise.
- virtual bool findit(bool isvalidation) override
- {
- if (isvalidation)
- return true;
-
- assert(!this->m_resolved);
- this->m_resolved = true;
- this->m_target = this->m_base.get().ioport(this->m_tag);
- return this->report_missing("I/O port");
- }
+ virtual bool findit(validity_checker *valid) override;
};
/// \brief Optional I/O port finder
///
-/// Finds I/O port with maching tag. No error is generated if a
+/// Finds I/O port with matching tag. No error is generated if a
/// matching I/O port is not found (the target object pointer will be
/// null). If you have a number of similar optional I/O ports, consider
/// using optional_ioport_array.
@@ -839,9 +943,9 @@ using optional_ioport = ioport_finder<false>;
/// \brief Required I/O port finder
///
-/// Finds I/O port with maching tag. A validation error is generated if
-/// a matching I/O port is not found. If you have a number of similar
-/// required I/O ports, consider using required_ioport_array.
+/// Finds I/O port with matching tag. A validation error is generated
+/// if a matching I/O port is not found. If you have a number of
+/// similar required I/O ports, consider using required_ioport_array.
/// \sa optional_ioport required_ioport_array ioport_finder
using required_ioport = ioport_finder<true>;
@@ -853,9 +957,9 @@ template <unsigned Count> using required_ioport_array = ioport_array_finder<Coun
/// \brief Address space finder template
///
/// Template argument is whether the address space is required. It is a
-/// validation error if a required address space is not found. This class is
-/// generally not used directly, instead the optional_address_space and
-/// required_address_space helpers are used.
+/// validation error if a required address space is not found. This
+/// class is generally not used directly, instead the
+/// optional_address_space and required_address_space helpers are used.
/// \sa optional_address_space required_address_space
template <bool Required>
class address_space_finder : public object_finder_base<address_space, Required>
@@ -863,12 +967,13 @@ class address_space_finder : public object_finder_base<address_space, Required>
public:
/// \brief Address space finder constructor
/// \param [in] base Base device to search from.
- /// \param [in] tag Address space tag to search for. This is not copied,
- /// it is the caller's responsibility to ensure this pointer
- /// remains valid until resolution time.
+ /// \param [in] tag Address space device tag to search for.
+ /// This is not copied, it is the caller's responsibility to
+ /// ensure this pointer remains valid until resolution time.
/// \param [in] spacenum Address space number.
- /// \param [in] width Specific data width (optional).
- address_space_finder(device_t &base, char const *tag, int spacenum, u8 width = 0) : object_finder_base<address_space, Required>(base, tag), m_spacenum(spacenum), m_data_width(width) { }
+ /// \param [in] width Required data width in bits, or zero if
+ /// any data width is acceptable.
+ address_space_finder(device_t &base, char const *tag, int spacenum, u8 width = 0);
/// \brief Set search tag and space number
///
@@ -885,9 +990,9 @@ public:
/// \brief Set search tag and space number
///
- /// Allows search tag to be changed after construction. Note that
- /// this must be done before resolution time to take effect. Also
- /// note that the tag is not copied.
+ /// Allows search tag and address space number to be changed after
+ /// construction. Note that this must be done before resolution
+ /// time to take effect. Also note that the tag is not copied.
/// \param [in] tag Updated search tag relative to the current
/// device being configured. This is not copied, it is the
/// caller's responsibility to ensure this pointer remains valid
@@ -897,19 +1002,30 @@ public:
/// \brief Set search tag and space number
///
- /// Allows search tag to be changed after construction. Note that
- /// this must be done before resolution time to take effect.
+ /// Allows search tag and address space number to be changed after
+ /// construction. Note that this must be done before resolution
+ /// time to take effect. Also note that the tag is not copied.
/// \param [in] finder Object finder to take the search base and tag
/// from.
/// \param [in] spacenum Address space number.
void set_tag(finder_base const &finder, int spacenum) { finder_base::set_tag(finder); this->m_spacenum = spacenum; }
+ /// \brief Set search tag and space number
+ ///
+ /// Allows search tag and address space number to be changed after
+ /// construction. Note that this must be done before resolution
+ /// time to take effect. Also note that the tag is not copied.
+ /// \param [in] finder Address space finder to take the search base,
+ /// tag and address space number from.
+ template <bool R> void set_tag(address_space_finder<R> const &finder) { set_tag(finder, finder.spacenum()); }
+
/// \brief Set data width of space
///
- /// Allows data width to be specified after construction. Note that
- /// this must be done before resolution time to take effect.
- /// \param [in] width Data width in bits (0 = don't care).
- void set_data_width(u8 width) { this->m_data_width = width; }
+ /// Allows data width to be specified after construction. Note
+ /// that this must be done before resolution time to take effect.
+ /// \param [in] width Required data width in bits, or zero if any
+ /// data width is acceptable.
+ void set_data_width(u8 width) { assert(!this->m_resolved); this->m_data_width = width; }
/// \brief Get space number
///
@@ -923,20 +1039,12 @@ private:
/// Find address space with requested tag. For a dry run, the
/// target object pointer will not be set. This method is called by
/// the base device at resolution time.
- /// \param [in] isvalidation True if this is a dry run (not
- /// intending to run the machine, just checking for errors).
- /// \return True if the address space is optional, a matching address space is
- /// is found or this is a dry run, false otherwise.
- virtual bool findit(bool isvalidation) override
- {
- if (isvalidation)
- return this->validate_addrspace(this->m_spacenum, this->m_data_width, Required);
-
- assert(!this->m_resolved);
- this->m_resolved = true;
- this->m_target = this->find_addrspace(this->m_spacenum, this->m_data_width, Required);
- return this->report_missing("address space");
- }
+ /// \param [in] valid Pass a pointer to the validity checker if this
+ /// is a dry run (i.e. no intention to actually start the device),
+ /// or nullptr otherwise.
+ /// \return True if the address space is optional, a matching
+ /// address space is found or this is a dry run, false otherwise.
+ virtual bool findit(validity_checker *valid) override;
int m_spacenum;
u8 m_data_width;
@@ -944,16 +1052,16 @@ private:
/// \brief Optional address space finder
///
-/// Finds address space with maching tag and number. No error is generated if a
-/// matching address space is not found (the target object pointer will be
-/// null).
+/// Finds address space with matching tag and number. No error is
+/// generated if a matching address space is not found (the target
+/// object pointer will be null).
/// \sa required_address_space address_space_finder
using optional_address_space = address_space_finder<false>;
/// \brief Required address space finder
///
-/// Finds address space with maching tag and number. A validation error is generated if
-/// a matching address space is not found.
+/// Finds address space with matching tag and number. A validation
+/// error is generated if a matching address space is not found.
/// \sa optional_address_space address_space_finder
using required_address_space = address_space_finder<true>;
@@ -977,11 +1085,8 @@ public:
/// \param [in] tag Memory region tag to search for. This is not
/// copied, it is the caller's responsibility to ensure this
/// pointer remains valid until resolution time.
- /// \param [in] length Desired memory region length in units of the
- /// size of the element type, or zero to match any region length.
- region_ptr_finder(device_t &base, char const *tag, size_t length = 0)
+ region_ptr_finder(device_t &base, char const *tag)
: object_finder_base<PointerType, Required>(base, tag)
- , m_desired_length(length)
, m_length(0)
{
}
@@ -989,29 +1094,23 @@ public:
/// \brief Array access operator
///
/// Returns a non-const reference to the element of the memory
- /// region at the supplied zero-based index.
- /// Behaviour is undefined for negative element indices.
+ /// region at the supplied zero-based index. Behaviour is undefined
+ /// for negative element indices.
/// \param [in] index Non-negative element index.
/// \return Non-const reference to element at requested index.
PointerType &operator[](int index) const { assert(index < m_length); return this->m_target[index]; }
/// \brief Get length in units of elements
+ ///
/// \return Length in units of elements or zero if no matching
/// memory region has been found.
- u32 length() const { return m_length; }
+ size_t length() const { return m_length; }
/// \brief Get length in units of bytes
+ ///
/// \return Length in units of bytes or zero if no matching memory
/// region has been found.
- u32 bytes() const { return m_length * sizeof(PointerType); }
-
- /// \brief Get index mask
- ///
- /// Returns the length in units of elements minus one, which can be
- /// used as a mask for index values if the length is a power of two.
- /// Result is undefined if no matching memory region has been found.
- /// \return Length in units of elements minus one.
- u32 mask() const { return m_length - 1; }
+ size_t bytes() const { return m_length * sizeof(PointerType); }
private:
/// \brief Find memory region base pointer
@@ -1022,28 +1121,23 @@ private:
/// checked - the width is not checked and the target pointer is not
/// set. This method is called by the base device at resolution
/// time.
- /// \param [in] isvalidation True if this is a dry run (not
- /// intending to run the machine, just checking for errors).
+ /// \param [in] valid Pass a pointer to the validity checker if this
+ /// is a dry run (i.e. no intention to actually start the device),
+ /// or nullptr otherwise.
/// \return True if the memory region is optional or a matching
/// memory region is found, or false otherwise.
- virtual bool findit(bool isvalidation) override
+ virtual bool findit(validity_checker *valid) override
{
- if (isvalidation)
- return this->validate_memregion(sizeof(PointerType) * m_desired_length, Required);
+ if (valid)
+ return this->validate_memregion(Required);
assert(!this->m_resolved);
this->m_resolved = true;
- m_length = m_desired_length;
this->m_target = reinterpret_cast<PointerType *>(this->find_memregion(sizeof(PointerType), m_length, Required));
return this->report_missing("memory region");
}
- /// \brief Desired region length
- ///
- /// Desired region length in units of elements.
- size_t const m_desired_length;
-
- /// \brief Matched region length
+ /// \brief Region length
///
/// Actual length of the region that was found in units of
/// elements, or zero if no matching region has been found.
@@ -1052,7 +1146,7 @@ private:
/// \brief Optional memory region base pointer finder
///
-/// Finds base pointer of memory region with maching tag, width and
+/// Finds base pointer of memory region with matching tag, width and
/// length. No error is generated if a matching memory region is not
/// found (the target pointer will be null). If you have a number of
/// similar optional memory regions, consider using
@@ -1062,7 +1156,7 @@ template <typename PointerType> using optional_region_ptr = region_ptr_finder<Po
/// \brief Required memory region base pointer finder
///
-/// Finds base pointer of memory region with maching tag, width and
+/// Finds base pointer of memory region with matching tag, width and
/// length. A validation error is generated if a matching memory region
/// is not found. If you have a number of similar required memory
/// regions, consider using required_region_ptr_array.
@@ -1074,68 +1168,256 @@ template <typename PointerType, unsigned Count> using optional_region_ptr_array
template <typename PointerType, unsigned Count> using required_region_ptr_array = region_ptr_array_finder<PointerType, Count, true>;
-// ======================> shared_ptr_finder
-
-// shared pointer finder template
+/// \brief Memory share base pointer finder
+///
+/// Template arguments are the element type of the memory share and
+/// whether the memory share is required. It is a validation error if a
+/// required memory share is not found. This class is generally not
+/// used directly, instead the optional_shared_ptr and
+/// required_shared_ptr helpers are used.
+/// \sa optional_shared_ptr required_shared_ptr
template <typename PointerType, bool Required>
class shared_ptr_finder : public object_finder_base<PointerType, Required>
{
public:
- // construction/destruction
- shared_ptr_finder(device_t &base, char const *tag, u8 width = sizeof(PointerType) * 8)
+ /// \brief Memory share finder constructor
+ ///
+ /// Desired width is implied by sizeof(PointerType).
+ /// \param [in] base Base device to search from.
+ /// \param [in] tag Memory share tag to search for. This is not
+ /// copied, it is the caller's responsibility to ensure this
+ /// pointer remains valid until resolution time.
+ shared_ptr_finder(device_t &base, char const *tag)
: object_finder_base<PointerType, Required>(base, tag)
- , m_width(width)
, m_bytes(0)
- , m_allocated(0)
{
}
- // operators to make use transparent
+ /// \brief Array access operator
+ ///
+ /// Returns a non-const reference to the element of the memory
+ /// share at the supplied zero-based index. Behaviour is undefined
+ /// for negative element indices.
+ /// \param [in] index Non-negative element index.
+ /// \return Non-const reference to element at requested index.
PointerType &operator[](int index) const { return this->m_target[index]; }
- // getter for explicit fetching
- u32 bytes() const { return m_bytes; }
- u32 mask() const { return m_bytes - 1; } // FIXME: wrong when sizeof(PointerType) != 1
+ /// \brief Get length in units of elements
+ ///
+ /// \return Length in units of elements or zero if no matching
+ /// memory region has been found.
+ size_t length() const { return m_bytes / sizeof(PointerType); }
- // setter for setting the object
- void set_target(PointerType *target, size_t bytes) { this->m_target = target; m_bytes = bytes; }
+ /// \brief Get length in bytes
+ ///
+ /// \return Length in bytes or zero if no matching memory share has
+ /// been found.
+ size_t bytes() const { return m_bytes; }
- // dynamic allocation of a shared pointer
- void allocate(u32 entries)
- {
- assert(m_allocated.empty());
- m_allocated.resize(entries);
- this->m_target = &m_allocated[0];
- m_bytes = entries * sizeof(PointerType);
- this->m_base.get().save_item(m_allocated, this->m_tag);
- }
+ /// \brief Get iterator to first element
+ ///
+ /// Returns an iterator to the first element of the memory share.
+ /// \return Iterator to first element.
+ PointerType *begin() const { return this->m_target; }
+
+ /// \brief Get iterator beyond last element
+ ///
+ /// Returns an iterator one past the last element of the memory
+ /// share.
+ /// \return Iterator one past last element.
+ PointerType *end() const { return this->m_target + length(); }
+
+ /// \brief Get constant iterator to first element
+ ///
+ /// Returns a constant iterator to the first element of the memory
+ /// share.
+ /// \return Constant iterator to first element.
+ PointerType const *cbegin() const { return this->m_target; }
+
+ /// \brief Get constant iterator beyond last element
+ ///
+ /// Returns a constant iterator one past the last element of the
+ /// memory share.
+ /// \return Constant iterator one past last element.
+ PointerType const *cend() const { return this->m_target + length(); }
private:
- // finder
- virtual bool findit(bool isvalidation) override
+ /// \brief Find memory share base pointer
+ ///
+ /// Find base pointer of memory share with with requested tag.
+ /// Width of memory share is checked against sizeof(PointerType).
+ /// This method is called by the base device at resolution time.
+ /// \param [in] valid Pass a pointer to the validity checker if this
+ /// is a dry run (i.e. no intention to actually start the device),
+ /// or nullptr otherwise.
+ /// \return True if the memory share is optional or a matching
+ /// memory share is found, or false otherwise.
+ virtual bool findit(validity_checker *valid) override
{
- if (isvalidation)
+ if (valid)
return true;
assert(!this->m_resolved);
this->m_resolved = true;
- this->m_target = reinterpret_cast<PointerType *>(this->find_memshare(m_width, m_bytes, Required));
+ this->m_target = reinterpret_cast<PointerType *>(this->find_memshare(sizeof(PointerType)*8, m_bytes, Required));
return this->report_missing("shared pointer");
}
- // internal state
- u8 const m_width;
+ /// \brief Memory share length
+ ///
+ /// Actual length of the memory share that was found in bytes, or
+ /// zero if no matching region has been found.
size_t m_bytes;
- std::vector<PointerType> m_allocated;
};
+/// \brief Optional memory share base pointer finder
+///
+/// Finds base pointer of memory share with matching tag and width. No
+/// error is generated if a matching memory share is not found (the
+/// target pointer will be null). If you have a number of similar
+/// optional memory regions, consider using optional_shared_ptr_array.
+/// \sa required_shared_ptr optional_shared_ptr_array shared_ptr_finder
template <typename PointerType> using optional_shared_ptr = shared_ptr_finder<PointerType, false>;
+
+/// \brief Required memory share base pointer finder
+///
+/// Finds base pointer of memory share with matching tag and width. A
+/// validation error is generated if a matching memory share is not
+/// found. If you have a number of similar required memory shares,
+/// consider using required_shared_ptr_array.
+/// \sa optional_shared_ptr required_shared_ptr_array shared_ptr_finder
template <typename PointerType> using required_shared_ptr = shared_ptr_finder<PointerType, true>;
+
template <typename PointerType, unsigned Count, bool Required> using shared_ptr_array_finder = object_array_finder<shared_ptr_finder<PointerType, Required>, Count>;
template <typename PointerType, unsigned Count> using optional_shared_ptr_array = shared_ptr_array_finder<PointerType, Count, false>;
template <typename PointerType, unsigned Count> using required_shared_ptr_array = shared_ptr_array_finder<PointerType, Count, true>;
+/// \brief Memory share creator template
+///
+/// Creates a memory share or finds an existing one instantiated via an
+/// address map. Template argument is the element type of the memory
+/// share. If an existing memory share is found, it is an error if it
+/// doesn't match the requested width, length and endianness.
+template <typename PointerType>
+class memory_share_creator : public finder_base
+{
+public:
+ /// \brief Memory share creator constructor
+ ///
+ /// Desired width is implied by sizeof(PointerType).
+ /// \param [in] base Base device to search from.
+ /// \param [in] tag Memory share tag to search for or create. This
+ /// is not copied, it is the caller's responsibility to ensure
+ /// this pointer remains valid until resolution time.
+ /// \param [in] bytes Desired memory share length in bytes.
+ /// \param [in] endianness Desired endianness of the memory share.
+ memory_share_creator(device_t &base, char const *tag, size_t bytes, endianness_t endianness);
+
+ /// \brief Get target memory share base pointer
+ ///
+ /// Must not be called before creation is attempted.
+ /// \return Base pointer of found or created memory share.
+ PointerType *target() const { return reinterpret_cast<PointerType *>(m_target->ptr()); }
+
+ /// \brief Cast-to-pointer operator
+ ///
+ /// Allows implicit casting to the base pointer of the target memory
+ /// share. Must not be called before creation is attempted.
+ /// \return Base pointer of found or created memory share.
+ operator PointerType *() const { return target(); }
+
+ /// \brief Array access operator
+ ///
+ /// Returns a non-const reference to the element of the memory
+ /// share at the supplied zero-based index. Behaviour is undefined
+ /// for negative element indices. Must not be called before
+ /// creation is attempted.
+ /// \param [in] index Non-negative element index.
+ /// \return Non-const reference to element at requested index.
+ PointerType &operator[](int index) const { return target()[index]; }
+
+ /// \brief Get length in units of elements
+ ///
+ /// Must not be called before creation is attempted.
+ /// \return Length of memory share in units of elements.
+ size_t length() const { return m_target->bytes() / sizeof(PointerType); }
+
+ /// \brief Get length in bytes
+ ///
+ /// Must not be called before creation is attempted.
+ /// \return Length of memory share in bytes.
+ size_t bytes() const { return m_target->bytes(); }
+
+ /// \brief Get endianness
+ ///
+ /// Must not be called before creation is attempted.
+ /// \return Endianness of memory share.
+ endianness_t endianness() const { return m_target->endianness(); }
+
+ /// \brief Get width in bits
+ ///
+ /// Must not be called before creation is attempted.
+ /// \return Memory share width in bits.
+ u8 bitwidth() const { return m_target->bitwidth(); }
+
+ /// \brief Get width in bytes
+ ///
+ /// Must not be called before creation is attempted.
+ /// \return Memory share width in bytes.
+ u8 bytewidth() const { return m_target->bytewidth(); }
+
+ /// \brief Get iterator to first element
+ ///
+ /// Returns an iterator to the first element of the memory share.
+ /// Must not be called before creation is attempted.
+ /// \return Iterator to first element.
+ PointerType *begin() const { return target(); }
+
+ /// \brief Get iterator beyond last element
+ ///
+ /// Returns an iterator one past the last element of the memory
+ /// share. Must not be called before creation is attempted.
+ /// \return Iterator one past last element.
+ PointerType *end() const { return target() + length(); }
+
+ /// \brief Get constant iterator to first element
+ ///
+ /// Returns a constant iterator to the first element of the memory
+ /// share. Must not be called before creation is attempted.
+ /// \return Constant iterator to first element.
+ PointerType const *cbegin() const { return target(); }
+
+ /// \brief Get constant iterator beyond last element
+ ///
+ /// Returns a constant iterator one past the last element of the
+ /// memory share. Must not be called before creation is attempted.
+ /// \return Constant iterator one past last element.
+ PointerType const *cend() const { return target() + length(); }
+
+protected:
+ virtual bool findit(validity_checker *valid) override;
+ virtual void end_configuration() override;
+
+ /// \brief Pointer to target object
+ ///
+ /// Pointer to target memory share object, or nullptr if creation
+ /// has not been attempted yet.
+ memory_share *m_target = nullptr;
+
+ /// \brief Requested memory share width in bits
+ u8 const m_width;
+
+ /// \brief Requested memory share length in bytes
+ size_t const m_bytes;
+
+ /// \brief Requested memory share endianness
+ endianness_t const m_endianness;
+};
+
+template <typename PointerType, unsigned Count> using memory_share_array_creator = object_array_finder<memory_share_creator<PointerType>, Count>;
+
+
//**************************************************************************
// EXTERNAL TEMPLATE INSTANTIATIONS
@@ -1175,6 +1457,9 @@ extern template class memory_bank_finder<true>;
extern template class ioport_finder<false>;
extern template class ioport_finder<true>;
+extern template class address_space_finder<false>;
+extern template class address_space_finder<true>;
+
extern template class region_ptr_finder<u8, false>;
extern template class region_ptr_finder<u8, true>;
extern template class region_ptr_finder<u16, false>;
@@ -1211,5 +1496,15 @@ extern template class shared_ptr_finder<s32, true>;
extern template class shared_ptr_finder<s64, false>;
extern template class shared_ptr_finder<s64, true>;
+extern template class memory_share_creator<u8>;
+extern template class memory_share_creator<u16>;
+extern template class memory_share_creator<u32>;
+extern template class memory_share_creator<u64>;
+
+extern template class memory_share_creator<s8>;
+extern template class memory_share_creator<s16>;
+extern template class memory_share_creator<s32>;
+extern template class memory_share_creator<s64>;
+
#endif // MAME_EMU_DEVFIND_H
-/** \} */
+/// \}