Add object finder for address spaces

(nw) The constructor and set_tag methods for required_address_space and optional_address_space work slightly differently from other finders in that they take the address space number as an extra argument. There is also an option to request a space having a specific data width, and validation checks this as well as the space number. There is also no (required|optional)_address_space_array, but that shouldn't really be necessary since devices shouldn't need large numbers of these finders.
This commit is contained in:
AJR 2019-01-22 11:35:46 -05:00
parent 8bca61dcd6
commit a6f64287a3
2 changed files with 212 additions and 2 deletions

View File

@ -22,6 +22,8 @@ template class object_finder_base<memory_bank, false>;
template class object_finder_base<memory_bank, true>;
template class object_finder_base<ioport_port, false>;
template class object_finder_base<ioport_port, true>;
template class object_finder_base<address_space, false>;
template class object_finder_base<address_space, true>;
template class object_finder_base<u8, false>;
template class object_finder_base<u8, true>;
@ -50,6 +52,9 @@ template class memory_bank_finder<true>;
template class ioport_finder<false>;
template class ioport_finder<true>;
template class address_space_finder<false>;
template class address_space_finder<true>;
template class region_ptr_finder<u8, false>;
template class region_ptr_finder<u8, true>;
template class region_ptr_finder<u16, false>;
@ -229,6 +234,79 @@ void *finder_base::find_memshare(u8 width, size_t &bytes, bool required) const
}
//-------------------------------------------------
// find_addrspace - find address space
//-------------------------------------------------
address_space *finder_base::find_addrspace(int spacenum, u8 width, bool required) const
{
// look up the device and return nullptr if not found
device_t *const device(m_base.get().subdevice(m_tag));
if (device == nullptr)
return nullptr;
// check for memory interface and the specified space number
const device_memory_interface *memory;
if (!device->interface(memory))
{
if (required)
osd_printf_warning("Device '%s' found but lacks memory interface\n", m_tag);
return nullptr;
}
if (!memory->has_space(spacenum))
{
if (required)
osd_printf_warning("Device '%s' found but lacks address space #%d\n", m_tag, spacenum);
return nullptr;
}
// check data width
address_space &space(memory->space(spacenum));
if (width != 0 && width != space.data_width())
{
if (required)
osd_printf_warning("Device '%s' found but address space #%d has the wrong data width (expected %d, found %d)\n", m_tag, spacenum, width, space.data_width());
return nullptr;
}
// return result
return &space;
}
//-------------------------------------------------
// validate_addrspace - find address space
//-------------------------------------------------
bool finder_base::validate_addrspace(int spacenum, u8 width, bool required) const
{
// look up the device and return false if not found
device_t *const device(m_base.get().subdevice(m_tag));
if (device == nullptr)
return report_missing(false, "address space", required);
// check for memory interface and a configuration for the designated space
const device_memory_interface *memory = nullptr;
const address_space_config *config = nullptr;
if (device->interface(memory))
{
config = memory->space_config(spacenum);
if (required)
{
if (config == nullptr)
osd_printf_warning("Device '%s' found but lacks address space #%d\n", m_tag, spacenum);
else if (width != 0 && width != config->data_width())
osd_printf_warning("Device '%s' found but space #%d has the wrong data width (expected %d, found %d)\n", m_tag, spacenum, width, config->data_width());
}
}
else if (required)
osd_printf_warning("Device '%s' found but lacks memory interface\n", m_tag);
// report result
return report_missing(config != nullptr && (width == 0 || width == config->data_width()), "address space", required);
}
//-------------------------------------------------
// report_missing - report missing objects and
// return true if it's ok
@ -240,7 +318,7 @@ bool finder_base::report_missing(bool found, const char *objname, bool required)
{
osd_printf_error("Tag not defined for required %s\n", objname);
return false;
}
}
// just pass through in the found case
if (found)

View File

@ -346,7 +346,7 @@ protected:
///
/// Walks ROM regions of all devices starting from the root looking
/// for one with matching tag and length in bytes. Prints a warning
/// message if the region is required, a region iwth the requested
/// message if the region is required, a region with the requested
/// tag is found, but its length does not match. Calls
/// report_missing to print an error message if the region is
/// not found. Returns true if the region is required but no
@ -377,6 +377,36 @@ protected:
/// share is found, or nullptr otherwise.
void *find_memshare(u8 width, size_t &bytes, bool required) const;
/// \brief Find an address space
///
/// Look up address space and check that its width matches desired
/// value. Returns pointer to address space if a matching space
/// is found, or nullptr otherwise. Prints a message at warning
/// level if the address space is required, a device with the
/// requested tag is found, but it doesn't have a memory interface
/// 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
/// if a device with no memory interface or space of that number
/// is found.
/// \return Pointer to address space if a matching address space
/// is found, or nullptr otherwise.
address_space *find_addrspace(int spacenum, u8 width, bool required) const;
/// \brief Check that address space exists
///
/// Returns true if the space is required but no matching space is
/// 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
/// 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
/// space and a matching space is found, or false otherwise.
bool validate_addrspace(int spacenum, u8 width, bool required) const;
/// \brief Log if object was not found
///
/// Logs a message at error level if the target object is required
@ -820,6 +850,108 @@ template <unsigned Count> using optional_ioport_array = ioport_array_finder<Coun
template <unsigned Count> using required_ioport_array = ioport_array_finder<Count, true>;
/// \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.
/// \sa optional_address_space required_address_space
template <bool Required>
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] 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) { }
/// \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.
/// \param [in] base Updated search base. The tag must be specified
/// relative to this device.
/// \param [in] tag Updated search tag. 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.
void set_tag(device_t &base, char const *tag, int spacenum) { finder_base::set_tag(base, tag); m_spacenum = spacenum; }
/// \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.
/// \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
/// until resolution time.
/// \param [in] spacenum Address space number.
void set_tag(char const *tag, int spacenum) { finder_base::set_tag(tag); m_spacenum = spacenum; }
/// \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.
/// \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 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; }
private:
/// \brief Find address space
///
/// 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");
}
int m_spacenum;
u8 m_data_width;
};
/// \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).
/// \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.
/// \sa optional_address_space address_space_finder
using required_address_space = address_space_finder<true>;
/// \brief Memory region base pointer finder
///
/// Template arguments are the element type of the memory region and