Self-registering devices.

* MAME now walks all devices when generating -lx output irrespective of whether they're actually instantiated anywhere or not.
* -lx is at least 30% faster than previous implementation.
* Only possible drawback is that filtering drivers no longer filters devices.
This commit is contained in:
Vas Crabb 2017-03-02 23:25:17 +11:00
parent 8bf4bac0c1
commit aa739563d1
24 changed files with 329 additions and 149 deletions

View File

@ -310,9 +310,7 @@ SLOT_INTERFACE_EXTERN( abcbus_cards );
SLOT_INTERFACE_EXTERN( abc1600bus_cards );
typedef device_type_iterator<ABCBUS_SLOT, abcbus_slot_t> abcbus_slot_device_iterator;
typedef device_type_iterator<abcbus_slot_t> abcbus_slot_device_iterator;
#endif // MAME_DEVICES_ABCBUS_ABCBUS_H

View File

@ -67,6 +67,6 @@ private:
extern const device_type COCO_DWSOCK;
// device iterator
typedef device_type_iterator<COCO_DWSOCK, beckerport_device> beckerport_device_iterator;
typedef device_type_iterator<beckerport_device> beckerport_device_iterator;
#endif // MAME_DEVICES_BUS_COCO_DWSOCKH_H

View File

@ -1,6 +1,7 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
#include "emu.h"
#include "bitsocket.h"

View File

@ -1,6 +1,7 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
#include "emu.h"
#include "graphlinkhle.h"

View File

@ -1,6 +1,7 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
#include "emu.h"
#include "teeconn.h"

View File

@ -1,6 +1,7 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
#include "emu.h"
#include "tispeaker.h"
#include "speaker.h"

View File

@ -120,7 +120,7 @@ private:
extern const device_type CASSETTE;
// device iterator
typedef device_type_iterator<CASSETTE, cassette_image_device> cassette_device_iterator;
typedef device_type_iterator<cassette_image_device> cassette_device_iterator;
/***************************************************************************
DEVICE CONFIGURATION MACROS

View File

@ -821,15 +821,18 @@ void legacy_floppy_image_device::device_start()
void legacy_floppy_image_device::device_config_complete()
{
m_extension_list[0] = '\0';
const struct FloppyFormat *floppy_options = m_config->formats;
for (int i = 0; floppy_options[i].construct; i++)
if (m_config)
{
// only add if creatable
if (floppy_options[i].param_guidelines) {
// allocate a new format and append it to the list
add_format(floppy_options[i].name, floppy_options[i].description, floppy_options[i].extensions, floppy_options[i].param_guidelines);
const struct FloppyFormat *floppy_options = m_config->formats;
for (int i = 0; floppy_options && floppy_options[i].construct; i++)
{
// only add if creatable
if (floppy_options[i].param_guidelines) {
// allocate a new format and append it to the list
add_format(floppy_options[i].name, floppy_options[i].description, floppy_options[i].extensions, floppy_options[i].param_guidelines);
}
image_specify_extension(m_extension_list, 256, floppy_options[i].extensions);
}
image_specify_extension( m_extension_list, 256, floppy_options[i].extensions );
}
// set brief and instance name

View File

@ -73,6 +73,6 @@ private:
extern const device_type MIDIIN;
// device iterator
typedef device_type_iterator<MIDIIN, midiin_device> midiin_device_iterator;
typedef device_type_iterator<midiin_device> midiin_device_iterator;
#endif /* __MIDIIN_H__ */

View File

@ -68,6 +68,6 @@ private:
extern const device_type MIDIOUT;
// device iterator
typedef device_type_iterator<MIDIOUT, midiout_device> midiout_device_iterator;
typedef device_type_iterator<midiout_device> midiout_device_iterator;
#endif /* __MIDIOUT_H__ */

View File

@ -54,7 +54,7 @@ protected:
extern const device_type BARCODE_READER;
// device type iterator
typedef device_type_iterator<BARCODE_READER, barcode_reader_device> barcode_reader_device_iterator;
typedef device_type_iterator<barcode_reader_device> barcode_reader_device_iterator;
#endif

View File

@ -90,7 +90,7 @@ private:
extern const device_type RAM;
// device iterator
typedef device_type_iterator<RAM, ram_device> ram_device_iterator;
typedef device_type_iterator<ram_device> ram_device_iterator;
extern template class device_finder<ram_device, false>;
extern template class device_finder<ram_device, true>;

View File

@ -132,7 +132,7 @@ protected:
};
// iterator, since lots of people are interested in these devices
typedef device_type_iterator<SAMPLES, samples_device> samples_device_iterator;
typedef device_type_iterator<samples_device> samples_device_iterator;
// ======================> samples_iterator

View File

@ -15,6 +15,62 @@
#include <string.h>
//**************************************************************************
// DEVICE TYPE REGISTRATION
//**************************************************************************
namespace emu { namespace detail {
namespace {
struct device_registrations
{
device_type_impl *first = nullptr;
device_type_impl *last = nullptr;
device_type_impl *unsorted = nullptr;
};
device_registrations &device_registration_data()
{
// this is necessary to avoid issues with static initialisation order across units being indeterminate
// thread safety issues are avoided by always calling this function during static initialisation before the app can go threaded
static device_registrations instance;
return instance;
}
} // anonymous namespace
device_registrar::const_iterator device_registrar::cbegin() const
{
return const_iterator_helper(device_registration_data().first);
}
device_registrar::const_iterator device_registrar::cend() const
{
return const_iterator_helper(nullptr);
}
device_type_impl *device_registrar::register_device(device_type_impl &type)
{
device_registrations &data(device_registration_data());
if (!data.first) data.first = &type;
if (data.last) data.last->m_next = &type;
if (!data.unsorted) data.unsorted = &type;
data.last = &type;
return nullptr;
}
} } // namespace emu::detail
emu::detail::device_registrar const registered_device_types;
//**************************************************************************
// LIVE DEVICE MANAGEMENT
//**************************************************************************

View File

@ -17,6 +17,13 @@
#ifndef MAME_EMU_DEVICE_H
#define MAME_EMU_DEVICE_H
#include <iterator>
#include <memory>
#include <string>
#include <typeinfo>
#include <unordered_map>
#include <vector>
//**************************************************************************
@ -76,23 +83,156 @@ struct input_device_default;
class finder_base;
// exception classes
class device_missing_dependencies : public emu_exception { };
namespace emu { namespace detail {
class device_type_impl;
// a device_type is simply a pointer to its alloc function
typedef std::unique_ptr<device_t> (*device_type)(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
class device_registrar
{
private:
class const_iterator_helper;
public:
class const_iterator
{
public:
typedef std::ptrdiff_t difference_type;
typedef device_type_impl value_type;
typedef device_type_impl *pointer;
typedef device_type_impl &reference;
typedef std::forward_iterator_tag iterator_category;
const_iterator() = default;
const_iterator(const_iterator const &) = default;
const_iterator &operator=(const_iterator const &) = default;
bool operator==(const_iterator const &that) const { return m_type == that.m_type; }
bool operator!=(const_iterator const &that) const { return m_type != that.m_type; }
reference operator*() const { assert(m_type); return *m_type; }
pointer operator->() const { return m_type; }
const_iterator &operator++();
const_iterator operator++(int) { const_iterator const result(*this); ++*this; return result; }
private:
friend class const_iterator_helper;
pointer m_type = nullptr;
};
const_iterator begin() const { return cbegin(); }
const_iterator end() const { return cend(); }
const_iterator cbegin() const;
const_iterator cend() const;
private:
friend class device_type_impl;
class const_iterator_helper : public const_iterator
{
public:
const_iterator_helper(device_type_impl *type) { m_type = type; }
};
static device_type_impl *register_device(device_type_impl &type);
};
// this template function creates a stub which constructs a device
template <class DeviceClass>
std::unique_ptr<device_t> device_creator_impl(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
template <class DeviceClass> struct device_tag_struct { typedef DeviceClass type; };
template <class DriverClass> struct driver_tag_struct { typedef DriverClass type; };
template <class DeviceClass> inline device_tag_struct<DeviceClass> device_tag_func() { return device_tag_struct<DeviceClass>{ }; }
template <class DriverClass> inline driver_tag_struct<DriverClass> driver_tag_func() { return driver_tag_struct<DriverClass>{ }; }
class device_type_impl
{
private:
friend class device_registrar;
typedef std::unique_ptr<device_t> (*create_func)(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
device_type_impl(device_type_impl const &) = delete;
device_type_impl(device_type_impl &&) = delete;
device_type_impl &operator=(device_type_impl const &) = delete;
device_type_impl &operator=(device_type_impl &&) = delete;
// don't make these static member function templates inline
template <typename DeviceClass> static std::unique_ptr<device_t> create_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
template <typename DriverClass> static std::unique_ptr<device_t> create_driver(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
create_func const m_creator;
std::type_info const &m_type;
device_type_impl *m_next;
public:
device_type_impl(std::nullptr_t)
: m_creator(nullptr)
, m_type(typeid(nullptr_t))
, m_next(nullptr)
{
}
template <class DeviceClass> device_type_impl(device_tag_struct<DeviceClass> (*)())
: m_creator(&create_device<DeviceClass>)
, m_type(typeid(DeviceClass))
, m_next(device_registrar::register_device(*this))
{
}
template <class DriverClass> device_type_impl(driver_tag_struct<DriverClass> (*)())
: m_creator(&create_driver<DriverClass>)
, m_type(typeid(DriverClass))
, m_next(nullptr)
{
}
std::type_info const &type() const { return m_type; }
std::unique_ptr<device_t> operator()(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) const
{
return m_creator(mconfig, tag, owner, clock);
}
explicit operator bool() const { return bool(m_creator); }
bool operator==(device_type_impl const &that) const { return &that == this; }
bool operator!=(device_type_impl const &that) const { return &that != this; }
};
inline device_registrar::const_iterator &device_registrar::const_iterator::operator++() { m_type = m_type->m_next; return *this; }
template <typename DeviceClass>
std::unique_ptr<device_t> device_type_impl::create_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
{
return make_unique_clear<DeviceClass>(mconfig, tag, owner, clock);
}
template <class DeviceClass>
constexpr device_type device_creator = &device_creator_impl<DeviceClass>;
template <typename DriverClass>
std::unique_ptr<device_t> device_type_impl::create_driver(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
{
assert(!owner);
assert(!clock);
// this is not thread-safe
// we can get away with it because driver creators aren't registered
// hence all members are initialised with constant values and the race won't cause issues
static device_type_impl const &driver_type = &driver_tag_func<DriverClass>;
return make_unique_clear<DriverClass>(mconfig, driver_type, tag);
}
} } // namespace emu::detail
// device types
typedef emu::detail::device_type_impl const &device_type;
template <class DeviceClass> constexpr auto device_creator = &emu::detail::device_tag_func<DeviceClass>;
template <class DriverClass> constexpr auto driver_device_creator = &emu::detail::driver_tag_func<DriverClass>;
extern emu::detail::device_registrar const registered_device_types;
// exception classes
class device_missing_dependencies : public emu_exception { };
// timer IDs for devices
@ -448,57 +588,68 @@ public:
class auto_iterator
{
public:
typedef std::ptrdiff_t difference_type;
typedef device_t value_type;
typedef device_t *pointer;
typedef device_t &reference;
typedef std::forward_iterator_tag iterator_category;
// construction
auto_iterator(device_t *devptr, int curdepth, int maxdepth)
: m_curdevice(devptr)
, m_curdepth(curdepth)
, m_maxdepth(maxdepth)
{ }
{
}
// getters
device_t *current() const { return m_curdevice; }
int depth() const { return m_curdepth; }
// required operator overrides
bool operator!=(const auto_iterator &iter) const { return m_curdevice != iter.m_curdevice; }
device_t &operator*() const { assert(m_curdevice != nullptr); return *m_curdevice; }
const auto_iterator &operator++() { advance(); return *this; }
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; }
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; }
protected:
// search depth-first for the next device
void advance()
{
// remember our starting position, and end immediately if we're nullptr
device_t *start = m_curdevice;
if (start == nullptr)
return;
// search down first
if (m_curdepth < m_maxdepth)
if (m_curdevice)
{
m_curdevice = start->subdevices().first();
if (m_curdevice != nullptr)
device_t *start = m_curdevice;
// search down first
if (m_curdepth < m_maxdepth)
{
m_curdepth++;
return;
m_curdevice = start->subdevices().first();
if (m_curdevice)
{
m_curdepth++;
return;
}
}
// search next for neighbors up the ownership chain
while (m_curdepth > 0 && start)
{
// found a neighbor? great!
m_curdevice = start->next();
if (m_curdevice)
return;
// no? try our parent
start = start->owner();
m_curdepth--;
}
// returned to the top; we're done
m_curdevice = nullptr;
}
// search next for neighbors up the ownership chain
while (m_curdepth > 0 && start != nullptr)
{
// found a neighbor? great!
m_curdevice = start->next();
if (m_curdevice != nullptr)
return;
// no? try our parent
start = start->owner();
m_curdepth--;
}
// returned to the top; we're done
m_curdevice = nullptr;
}
// protected state
@ -563,65 +714,71 @@ private:
// ======================> device_type_iterator
// helper class to find devices of a given type in the device hierarchy
template <device_type const &_DeviceType, class _DeviceClass = device_t>
template <class DeviceType, class DeviceClass = DeviceType>
class device_type_iterator
{
public:
class auto_iterator : public device_iterator::auto_iterator
class auto_iterator : protected device_iterator::auto_iterator
{
public:
public:
using device_iterator::auto_iterator::difference_type;
using device_iterator::auto_iterator::iterator_category;
using device_iterator::auto_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)
{
// make sure the first device is of the specified type
while (m_curdevice && (m_curdevice->type() != _DeviceType))
while (m_curdevice && (m_curdevice->type().type() != typeid(DeviceType)))
advance();
}
// 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; }
// getters returning specified device type
_DeviceClass *current() const { return downcast<_DeviceClass *>(m_curdevice); }
_DeviceClass &operator*() const { assert(m_curdevice != nullptr); return downcast<_DeviceClass &>(*m_curdevice); }
DeviceClass *current() const { return downcast<DeviceClass *>(m_curdevice); }
DeviceClass &operator*() const { assert(m_curdevice); return downcast<DeviceClass &>(*m_curdevice); }
DeviceClass *operator->() const { return downcast<DeviceClass *>(m_curdevice); }
// search for devices of the specified type
const auto_iterator &operator++()
auto_iterator &operator++()
{
advance();
while (m_curdevice != nullptr && m_curdevice->type() != _DeviceType)
while (m_curdevice && (m_curdevice->type().type() != typeid(DeviceType)))
advance();
return *this;
}
auto_iterator operator++(int) { auto_iterator const result(*this); ++*this; return result; }
};
public:
// construction
device_type_iterator(device_t &root, int maxdepth = 255)
: m_root(root), m_maxdepth(maxdepth) { }
device_type_iterator(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); }
// return first item
_DeviceClass *first() const { return begin().current(); }
DeviceClass *first() const { return begin().current(); }
// return the number of items available
int count() const
{
int result = 0;
for (_DeviceClass &item : *this)
{
(void)&item;
result++;
}
return result;
}
int count() const { return std::distance(cbegin(), cend()); }
// return the index of a given item in the virtual list
int indexof(_DeviceClass &device) const
int indexof(DeviceClass &device) const
{
int index = 0;
for (_DeviceClass &item : *this)
for (DeviceClass &item : *this)
{
if (&item == &device)
return index;
@ -632,9 +789,9 @@ public:
}
// return the indexed item in the list
_DeviceClass *byindex(int index) const
DeviceClass *byindex(int index) const
{
for (_DeviceClass &item : *this)
for (DeviceClass &item : *this)
if (index-- == 0)
return &item;
return nullptr;

View File

@ -1321,8 +1321,8 @@ void device_image_interface::update_names(const device_type device_type, const c
}
else
{
m_instance_name = inst_name;
m_brief_instance_name = brief_name;
m_instance_name = inst_name ? inst_name : "";
m_brief_instance_name = brief_name ? brief_name : "";
}
}

View File

@ -225,17 +225,4 @@ private:
};
// this template function creates a stub which constructs a device
template<class DriverClass>
std::unique_ptr<device_t> driver_device_creator_impl(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
{
assert(owner == nullptr);
assert(clock == 0);
return make_unique_clear<DriverClass>(mconfig, &driver_device_creator_impl<DriverClass>, tag);
}
template <class DriverClass>
constexpr device_type driver_device_creator = &driver_device_creator_impl<DriverClass>;
#endif /* MAME_EMU_DRIVER_H */

View File

@ -523,7 +523,7 @@ private:
};
// device type iterator
typedef device_type_iterator<PALETTE, palette_device> palette_device_iterator;
typedef device_type_iterator<palette_device> palette_device_iterator;
#endif // MAME_EMU_EMUPAL_H

View File

@ -365,7 +365,7 @@ private:
extern const device_type SCREEN;
// iterator helper
typedef device_type_iterator<SCREEN, screen_device> screen_device_iterator;
typedef device_type_iterator<screen_device> screen_device_iterator;
extern template class device_finder<screen_device, false>;
extern template class device_finder<screen_device, true>;

View File

@ -8,8 +8,8 @@
*********************************************************************/
#ifndef __SOFTLIST_DEV_H_
#define __SOFTLIST_DEV_H_
#ifndef MAME_EMU_SOFTLIST_DEV
#define MAME_EMU_SOFTLIST_DEV
#include "softlist.h"
@ -189,7 +189,7 @@ private:
extern const device_type SOFTWARE_LIST;
// device type iterator
typedef device_type_iterator<SOFTWARE_LIST, software_list_device> software_list_device_iterator;
typedef device_type_iterator<software_list_device> software_list_device_iterator;
#endif // __SOFTLIST_DEV_H_
#endif // MAME_EMU_SOFTLIST_DEV

View File

@ -77,7 +77,7 @@ protected:
// speaker device iterator
typedef device_type_iterator<SPEAKER, speaker_device> speaker_device_iterator;
typedef device_type_iterator<speaker_device> speaker_device_iterator;
extern template class device_finder<speaker_device, false>;
extern template class device_finder<speaker_device, true>;

View File

@ -377,7 +377,7 @@ void info_xml_creator::output_one_device(device_t &device, const char *devtag)
for (ioport_field &field : port.second->fields())
if (field.type() >= IPT_START1 && field.type() < IPT_UI_FIRST)
{
has_input = true;
has_input = true; break;
break;
}
@ -427,51 +427,25 @@ void info_xml_creator::output_one_device(device_t &device, const char *devtag)
void info_xml_creator::output_devices()
{
// get config for some arbitrary machine
m_drivlist.reset();
std::unordered_set<std::string> shortnames;
m_drivlist.next();
std::shared_ptr<machine_config> config = m_drivlist.config();
while (m_drivlist.next())
// run through devices
for (device_type type : registered_device_types)
{
// first, run through devices with roms which belongs to the default configuration
for (device_t &device : device_iterator(m_drivlist.config()->root_device()))
{
if (device.owner() != nullptr && device.shortname() != nullptr && device.shortname()[0]!='\0')
{
if (shortnames.insert(device.shortname()).second)
output_one_device(device, device.tag());
}
}
// add it at the root of the machine config
device_t *const dev = config->device_add(&config->root_device(), "_tmp", type, 0);
// then, run through slot devices
for (const device_slot_interface &slot : slot_interface_iterator(m_drivlist.config()->root_device()))
{
for (auto &option : slot.option_list())
{
std::string temptag("_");
temptag.append(option.second->name());
device_t *dev = m_drivlist.config()->device_add(&m_drivlist.config()->root_device(), temptag.c_str(), option.second->devtype(), 0);
// notify this device and all its subdevices that they are now configured
for (device_t &device : device_iterator(*dev))
if (!device.configured())
device.config_complete();
// notify this device and all its subdevices that they are now configured
for (device_t &device : device_iterator(*dev))
if (!device.configured())
device.config_complete();
if (shortnames.insert(dev->shortname()).second)
output_one_device(*dev, temptag.c_str());
// also, check for subdevices with ROMs (a few devices are missed otherwise, e.g. MPU401)
for (device_t &device : device_iterator(*dev))
{
if (device.owner() == dev && device.shortname() != nullptr && device.shortname()[0]!='\0')
{
if (shortnames.insert(device.shortname()).second)
output_one_device(device, device.tag());
}
}
m_drivlist.config()->device_remove(&m_drivlist.config()->root_device(), temptag.c_str());
}
}
// print details and remove it
output_one_device(*dev, dev->tag());
config->device_remove(&config->root_device(), "_tmp");
}
}

View File

@ -44,8 +44,7 @@ protected:
private:
// device iterator
static constexpr device_type TYPE = device_creator<DeviceType>;
typedef device_type_iterator<TYPE, DeviceType> iterator;
typedef device_type_iterator<DeviceType> iterator;
DeviceType * m_device;
int m_count;

View File

@ -258,13 +258,15 @@ vis_vga_device::vis_vga_device(const machine_config &mconfig, const char *tag, d
: svga_device(mconfig, VIS_VGA, "vis_vga", tag, owner, clock, "vis_vga", __FILE__),
device_isa16_card_interface(mconfig, *this)
{
m_palette.set_tag("palette");
m_screen.set_tag("screen");
}
static MACHINE_CONFIG_FRAGMENT( vis_vga_config )
MCFG_SCREEN_ADD(":visvga:screen", RASTER)
MCFG_SCREEN_ADD("screen", RASTER)
MCFG_SCREEN_RAW_PARAMS(XTAL_25_1748MHz,900,0,640,526,0,480)
MCFG_SCREEN_UPDATE_DEVICE("visvga", vis_vga_device, screen_update)
MCFG_PALETTE_ADD(":visvga:palette", 0x100)
MCFG_PALETTE_ADD("palette", 0x100)
MACHINE_CONFIG_END
machine_config_constructor vis_vga_device::device_mconfig_additions() const