* Make object finders behave like pointers for the purposes of implicit casts, dereferencing and array access, not something that's part pointer, part reference, part vector

* Require dummy tag to be specified explicitly, magical defaults are unhelpful here as the more common case it to search for a real object
* Make the search methods private in concrete classes where possible as users should rely on the resolution process for these things

Still can't hide the memory bank find method since atari400.cpp subverts the resolution process.
Can't get rid of set_target on shared_ptr_finder as it's abused all over the place.
This commit is contained in:
Vas Crabb 2016-08-27 08:34:06 +10:00
parent cdb531e83d
commit 17cf4acbef
12 changed files with 198 additions and 107 deletions

View File

@ -232,9 +232,9 @@ WRITE8_MEMBER( c6280_device::c6280_w )
const device_type C6280 = &device_creator<c6280_device>;
c6280_device::c6280_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: device_t(mconfig, C6280, "HuC6280", tag, owner, clock, "c6280", __FILE__),
device_sound_interface(mconfig, *this),
m_cpudevice(*this)
: device_t(mconfig, C6280, "HuC6280", tag, owner, clock, "c6280", __FILE__)
, device_sound_interface(mconfig, *this)
, m_cpudevice(*this, finder_base::DUMMY_TAG)
{
}

View File

@ -57,18 +57,15 @@ static wav_file* wavraw; // Raw waveform
const device_type GAELCO_GAE1 = &device_creator<gaelco_gae1_device>;
gaelco_gae1_device::gaelco_gae1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: device_t(mconfig, GAELCO_GAE1, "Gaelco GAE1", tag, owner, clock, "gaelco_gae1", __FILE__),
device_sound_interface(mconfig, *this),
m_stream(nullptr),
m_snd_data(*this)
: gaelco_gae1_device(mconfig, GAELCO_GAE1, "Gaelco GAE1", tag, owner, clock, "gaelco_gae1", __FILE__)
{
}
gaelco_gae1_device::gaelco_gae1_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source)
: device_t(mconfig, type, name, tag, owner, clock, shortname, source),
device_sound_interface(mconfig, *this),
m_stream(nullptr),
m_snd_data(*this)
: device_t(mconfig, type, name, tag, owner, clock, shortname, source)
, device_sound_interface(mconfig, *this)
, m_stream(nullptr)
, m_snd_data(*this, finder_base::DUMMY_TAG)
{
}

View File

@ -1524,14 +1524,7 @@ WRITE_LINE_MEMBER( tmsprom_device::enable_w )
const device_type TMS5110 = &device_creator<tms5110_device>;
tms5110_device::tms5110_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: device_t(mconfig, TMS5110, "TMS5110", tag, owner, clock, "tms5110", __FILE__)
, device_sound_interface(mconfig, *this)
, m_table(*this, DEVICE_SELF)
, m_m0_cb(*this)
, m_m1_cb(*this)
, m_addr_cb(*this)
, m_data_cb(*this)
, m_romclk_cb(*this)
: tms5110_device(mconfig, TMS5110, "TMS5110", tag, owner, clock, "tms5110", __FILE__)
{
}
@ -1610,7 +1603,7 @@ const device_type TMSPROM = &device_creator<tmsprom_device>;
tmsprom_device::tmsprom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: device_t(mconfig, TMSPROM, "TMSPROM", tag, owner, clock, "tmsprom", __FILE__),
m_rom(*this, DEVICE_SELF),
m_prom(*this, 0x20),
m_prom(*this, finder_base::DUMMY_TAG, 0x20),
m_rom_size(0),
m_pdc_bit(0),
m_ctl1_bit(0),

View File

@ -102,7 +102,7 @@ ef9345_device::ef9345_device(const machine_config &mconfig, const char *tag, dev
device_video_interface(mconfig, *this),
m_space_config("videoram", ENDIANNESS_LITTLE, 8, 16, 0, nullptr, *ADDRESS_MAP_NAME(ef9345)),
m_charset(*this, DEVICE_SELF),
m_palette(*this)
m_palette(*this, finder_base::DUMMY_TAG)
{
}

View File

@ -62,7 +62,7 @@ ef9364_device::ef9364_device(const machine_config &mconfig, const char *tag, dev
device_video_interface(mconfig, *this),
m_space_config("textram", ENDIANNESS_LITTLE, 8, 12, 0, nullptr, *ADDRESS_MAP_NAME(ef9364)),
m_charset(*this, DEVICE_SELF),
m_palette(*this)
m_palette(*this, finder_base::DUMMY_TAG)
{
clock_freq = clock;
}

View File

@ -176,7 +176,7 @@ ef9365_device::ef9365_device(const machine_config &mconfig, const char *tag, dev
device_video_interface(mconfig, *this),
m_space_config("videoram", ENDIANNESS_LITTLE, 8, 18, 0, nullptr, *ADDRESS_MAP_NAME(ef9365)),
m_charset(*this, "ef9365"),
m_palette(*this),
m_palette(*this, finder_base::DUMMY_TAG),
m_irq_handler(*this)
{
clock_freq = clock;

View File

@ -573,19 +573,7 @@ inline void mos6566_device::draw_multi( UINT16 p, UINT8 c0, UINT8 c1, UINT8 c2,
//-------------------------------------------------
mos6566_device::mos6566_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: device_t(mconfig, MOS6566, "MOS6566", tag, owner, clock, "mos6566", __FILE__),
device_memory_interface(mconfig, *this),
device_video_interface(mconfig, *this),
device_execute_interface(mconfig, *this),
m_icount(0),
m_variant(TYPE_6566),
m_videoram_space_config("videoram", ENDIANNESS_LITTLE, 8, 14, 0, nullptr, *ADDRESS_MAP_NAME(mos6566_videoram_map)),
m_colorram_space_config("colorram", ENDIANNESS_LITTLE, 8, 10, 0, nullptr, *ADDRESS_MAP_NAME(mos6566_colorram_map)),
m_write_irq(*this),
m_write_ba(*this),
m_write_aec(*this),
m_write_k(*this),
m_cpu(*this)
: mos6566_device(mconfig, MOS6566, "MOS6566", tag, owner, clock, TYPE_6566, "mos6566", __FILE__)
{
}
@ -602,7 +590,7 @@ mos6566_device::mos6566_device(const machine_config &mconfig, device_type type,
m_write_ba(*this),
m_write_aec(*this),
m_write_k(*this),
m_cpu(*this),
m_cpu(*this, finder_base::DUMMY_TAG),
m_phi0(1),
m_ba(ASSERT_LINE),
m_aec(ASSERT_LINE)

View File

@ -23,7 +23,7 @@ ROM_END
msm6222b_device::msm6222b_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) :
device_t(mconfig, type, name, tag, owner, clock, shortname, source), cursor_direction(false), cursor_blinking(false), two_line(false), shift_on_write(false), double_height(false), cursor_on(false), display_on(false), adc(0), shift(0),
m_cgrom(*this)
m_cgrom(*this, finder_base::DUMMY_TAG)
{
}

View File

@ -44,7 +44,7 @@ ramdac_device::ramdac_device(const machine_config &mconfig, const char *tag, dev
: device_t(mconfig, RAMDAC, "RAMDAC", tag, owner, clock, "ramdac", __FILE__),
device_memory_interface(mconfig, *this),
m_space_config("videoram", ENDIANNESS_LITTLE, 8, 10, 0, nullptr, *ADDRESS_MAP_NAME(ramdac_palram)),
m_palette(*this),
m_palette(*this, finder_base::DUMMY_TAG),
m_split_read_reg(0)
{
}

View File

@ -148,7 +148,7 @@ vic3_device::vic3_device(const machine_config &mconfig, const char *tag, device_
: device_t(mconfig, VIC3, "4567 VIC III", tag, owner, clock, "vic3", __FILE__),
device_video_interface(mconfig, *this),
m_type(VIC4567_NTSC),
m_cpu(*this),
m_cpu(*this, finder_base::DUMMY_TAG),
m_dma_read_cb(*this),
m_dma_read_color_cb(*this),
m_interrupt_cb(*this),

View File

@ -356,14 +356,25 @@ template <class DeviceClass, bool Required>
class device_finder : public object_finder_base<DeviceClass, Required>
{
public:
// construction/destruction
device_finder(device_t &base, const char *tag = finder_base::DUMMY_TAG) : object_finder_base<DeviceClass, Required>(base, tag) { }
/// \brief Device finder constructor
/// \param [in] base Base device to search from.
/// \param [in] tag Device tag to search for. This is not copied,
/// it is the caller's responsibility to ensure this pointer
/// remains valid until resolution time.
device_finder(device_t &base, char const *tag) : object_finder_base<DeviceClass, Required>(base, tag) { }
// make reference use transparent as well
operator DeviceClass &() { assert(this->m_target); return *this->m_target; }
// finder
virtual bool findit(bool isvalidation = false) override
private:
/// \brief Find device
///
/// Find device of desired type with requested tag. If a device
/// 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).
/// \return True if the device is optional or if a matching device
/// is found, false otherwise.
virtual bool findit(bool isvalidation) override
{
device_t *const device = this->m_base.subdevice(this->m_tag);
this->m_target = dynamic_cast<DeviceClass *>(device);
@ -411,14 +422,24 @@ template <bool Required>
class memory_region_finder : public object_finder_base<memory_region, Required>
{
public:
// construction/destruction
memory_region_finder(device_t &base, const char *tag = finder_base::DUMMY_TAG) : object_finder_base<memory_region, Required>(base, tag) { }
/// \brief Memory region finder constructor
/// \param [in] base Base device to search from.
/// \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) { }
// make reference use transparent as well
operator memory_region &() const { assert(this->m_target); return *this->m_target; }
// finder
virtual bool findit(bool isvalidation = false) override
private:
/// \brief Find memory region
///
/// 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).
/// \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);
this->m_target = this->m_base.memregion(this->m_tag);
@ -462,14 +483,23 @@ template <bool Required>
class memory_bank_finder : public object_finder_base<memory_bank, Required>
{
public:
// construction/destruction
memory_bank_finder(device_t &base, const char *tag = finder_base::DUMMY_TAG) : object_finder_base<memory_bank, Required>(base, tag) { }
/// \brief Memory bank finder constructor
/// \param [in] base Base device to search from.
/// \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) { }
// make reference use transparent as well
operator memory_bank &() const { assert(this->m_target); return *this->m_target; }
// finder
virtual bool findit(bool isvalidation = false) override
/// \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).
/// \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;
this->m_target = this->m_base.membank(this->m_tag);
@ -501,27 +531,46 @@ template <unsigned Count, bool Required> using memory_bank_array_finder = object
template <unsigned Count> using optional_memory_bank_array = memory_bank_array_finder<Count, false>;
template <unsigned Count> using required_memory_bank_array = memory_bank_array_finder<Count, true>;
extern template class object_finder_base<memory_bank, false>;
extern template class object_finder_base<memory_bank, true>;
extern template class memory_bank_finder<false>;
extern template class memory_bank_finder<true>;
// ======================> ioport_finder
// ioport finder template
/// \brief I/O port finder template
///
/// Template argument is whether the I/O port is required. It is a
/// validation error if a required I/O port is not found. This class is
/// generally not used directly, instead the optional_ioport and
/// required_ioport helpers are used.
/// \sa optional_ioport required_ioport
template <bool Required>
class ioport_finder : public object_finder_base<ioport_port, Required>
{
public:
// construction/destruction
ioport_finder(device_t &base, const char *tag = finder_base::DUMMY_TAG) : object_finder_base<ioport_port, Required>(base, tag) { }
/// \brief I/O port finder constructor
/// \param [in] base Base device to search from.
/// \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) { }
// read if found, or else return a default value
/// \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; }
// finder
virtual bool findit(bool isvalidation = false) override
private:
/// \brief Find I/O port
///
/// 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).
/// \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;
this->m_target = this->m_base.ioport(this->m_tag);
@ -551,49 +600,113 @@ template <unsigned Count> using optional_ioport_array = ioport_array_finder<Coun
template <unsigned Count> using required_ioport_array = ioport_array_finder<Count, true>;
// ======================> region_ptr_finder
// memory region pointer finder template
/// \brief Memory region base pointer finder
///
/// Template arguments are the element type of the memory region and
/// whether the memory region is required. It is a validation error if
/// a required memory region is not found. This class is generally not
/// used directly, instead the optional_region_ptr and
/// required_region_ptr helpers are used.
/// \sa optional_region_ptr required_region_ptr
template <typename PointerType, bool Required>
class region_ptr_finder : public object_finder_base<PointerType, Required>
{
public:
// construction/destruction
region_ptr_finder(device_t &base, const char *tag, size_t length = 0)
/// \brief Memory region base pointer finder constructor
///
/// Desired width is implied by sizeof(PointerType).
/// \param [in] base Base device to search from.
/// \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)
: object_finder_base<PointerType, Required>(base, tag)
, m_length(length)
{
}
region_ptr_finder(device_t &base, size_t length = 0)
: object_finder_base<PointerType, Required>(base, finder_base::DUMMY_TAG)
, m_length(length)
, m_desired_length(length)
, m_length(0)
{
}
// operators to make use transparent
const PointerType &operator[](int index) const { assert(index < m_length); return this->m_target[index]; }
PointerType &operator[](int index) { assert(index < m_length); return this->m_target[index]; }
/// \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.
/// \param [in] index Non-negative element index.
/// \return Non-const reference to element at requested index.
PointerType &operator[](size_t index) const { assert(index < m_length); return this->m_target[index]; }
// getter for explicit fetching
/// \brief Get length in units of elements
/// \return Length in units of elements or zero if no matching
/// memory region has been found.
UINT32 length() const { return m_length; }
UINT32 bytes() const { return m_length * sizeof(PointerType); }
UINT32 mask() const { return m_length - 1; } // only valid if length is known to be a power of 2
// finder
virtual bool findit(bool isvalidation = false) override
/// \brief Get length in units of bytes
/// \return Length in units of bytes or zero if no matching memory
/// region has been found.
UINT32 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.
UINT32 mask() const { return m_length - 1; }
private:
/// \brief Find memory region base pointer
///
/// Find base pointer of memory region with with requested tag,
/// width and length. Width of memory region is checked against
/// sizeof(PointerType). For a dry run, only the tag and length are
/// 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).
/// \return True if the memory region is optional or a matching
/// memory region is found, or false otherwise.
virtual bool findit(bool isvalidation) override
{
if (isvalidation) return this->validate_memregion(sizeof(PointerType) * m_length, Required);
if (isvalidation) return this->validate_memregion(sizeof(PointerType) * m_desired_length, Required);
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");
}
protected:
// internal state
/// \brief Desired region length
///
/// Desired region length in units of elements.
size_t const m_desired_length;
/// \brief Matched region length
///
/// Actual length of the region that was found in units of
/// elements, or zero if no matching region has been found.
size_t m_length;
};
/// \brief Optional memory region base pointer finder
///
/// Finds base pointer of memory region with maching 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
/// optional_region_ptr_array.
/// \sa required_region_ptr optional_region_ptr_array region_ptr_finder
template <typename PointerType> using optional_region_ptr = region_ptr_finder<PointerType, false>;
/// \brief Required memory region base pointer finder
///
/// Finds base pointer of memory region with maching 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.
/// \sa optional_region_ptr required_region_ptr_array region_ptr_finder
template <typename PointerType> using required_region_ptr = region_ptr_finder<PointerType, true>;
template <typename PointerType, unsigned Count, bool Required> using region_ptr_array_finder = object_array_finder<region_ptr_finder<PointerType, Required>, Count>;
template <typename PointerType, unsigned Count> using optional_region_ptr_array = region_ptr_array_finder<PointerType, Count, false>;
template <typename PointerType, unsigned Count> using required_region_ptr_array = region_ptr_array_finder<PointerType, Count, true>;
@ -607,16 +720,16 @@ class shared_ptr_finder : public object_finder_base<PointerType, Required>
{
public:
// construction/destruction
shared_ptr_finder(device_t &base, const char *tag = finder_base::DUMMY_TAG, UINT8 width = sizeof(PointerType) * 8)
shared_ptr_finder(device_t &base, char const *tag, UINT8 width = sizeof(PointerType) * 8)
: object_finder_base<PointerType, Required>(base, tag)
, m_bytes(0)
, m_width(width)
, m_bytes(0)
, m_allocated(0)
{
}
// operators to make use transparent
const PointerType &operator[](int index) const { return this->m_target[index]; }
PointerType &operator[](int index) { return this->m_target[index]; }
PointerType &operator[](size_t index) const { return this->m_target[index]; }
// getter for explicit fetching
UINT32 bytes() const { return m_bytes; }
@ -632,21 +745,21 @@ public:
m_allocated.resize(entries);
this->m_target = &m_allocated[0];
m_bytes = entries * sizeof(PointerType);
this->m_base.save_item(this->m_allocated, this->m_tag);
this->m_base.save_item(m_allocated, this->m_tag);
}
private:
// finder
virtual bool findit(bool isvalidation = false) override
virtual bool findit(bool isvalidation) override
{
if (isvalidation) return true;
this->m_target = reinterpret_cast<PointerType *>(this->find_memshare(m_width, m_bytes, Required));
return this->report_missing("shared pointer");
}
protected:
// internal state
UINT8 const m_width;
size_t m_bytes;
UINT8 m_width;
std::vector<PointerType> m_allocated;
};

View File

@ -1710,7 +1710,7 @@ void a400_state::setup_ram(int bank, UINT32 size)
ram_top = std::min(size, UINT32(0x8000)) - 1;
m_maincpu->space(AS_PROGRAM).install_readwrite_bank(0x0000, ram_top, "0000");
if (m_0000 == nullptr)
m_0000.findit();
m_0000.findit(false);
m_0000->set_base(m_ram->pointer());
break;
case 1: // 0x8000-0x9fff
@ -1719,7 +1719,7 @@ void a400_state::setup_ram(int bank, UINT32 size)
{
m_maincpu->space(AS_PROGRAM).install_readwrite_bank(0x8000, ram_top, "8000");
if (m_8000 == nullptr)
m_8000.findit();
m_8000.findit(false);
m_8000->set_base(m_ram->pointer() + 0x8000);
}
break;
@ -1729,7 +1729,7 @@ void a400_state::setup_ram(int bank, UINT32 size)
{
m_maincpu->space(AS_PROGRAM).install_readwrite_bank(0xa000, ram_top, "a000");
if (m_a000 == nullptr)
m_a000.findit();
m_a000.findit(false);
m_a000->set_base(m_ram->pointer() + 0xa000);
}
break;