diff options
author | Vas Crabb <vas@vastheman.com> | 2018-05-08 07:35:22 +1000 |
---|---|---|
committer | Vas Crabb <vas@vastheman.com> | 2018-05-08 07:35:22 +1000 |
commit | 4ef4464aec13029fa7e394671743e9ea96394528 (patch) | |
tree | 757cd23c65c626d63f4c98afb366362f4c2d6bdb /src/emu | |
parent | 765d625ac78ea14cec1e1a84c56567d980924869 (diff) |
Add support for custom device constructors when replacing devices.
Current syntax: MCFG_DEVICE_REPLACE(tag_or_finder, TYPE, ...)
Next-generation syntax: TYPE(config.replace(), tag_or_finder, ...)
(nw) Kill off some more low-value macros that aren't needed any more,
and get rid of the token-pasting voodoo and casts in the discrete sound
macros.
Diffstat (limited to 'src/emu')
-rw-r--r-- | src/emu/device.h | 2 | ||||
-rw-r--r-- | src/emu/device.ipp | 15 | ||||
-rw-r--r-- | src/emu/emufwd.h | 1 | ||||
-rw-r--r-- | src/emu/mconfig.cpp | 175 | ||||
-rw-r--r-- | src/emu/mconfig.h | 49 |
5 files changed, 156 insertions, 86 deletions
diff --git a/src/emu/device.h b/src/emu/device.h index a7b9d8707e3..68ae68b7cd1 100644 --- a/src/emu/device.h +++ b/src/emu/device.h @@ -289,6 +289,8 @@ public: template <typename... Params> DeviceClass &operator()(machine_config &mconfig, char const *tag, Params &&... args) const; template <typename Exposed, bool Required, typename... Params> DeviceClass &operator()(machine_config &mconfig, device_finder<Exposed, Required> &finder, Params &&... args) const; + template <typename... Params> DeviceClass &operator()(machine_config_replace replace, char const *tag, Params &&... args) const; + template <typename Exposed, bool Required, typename... Params> DeviceClass &operator()(machine_config_replace replace, device_finder<Exposed, Required> &finder, Params &&... args) const; }; diff --git a/src/emu/device.ipp b/src/emu/device.ipp index 4fa6b2fe1ec..e90f6bd4e6c 100644 --- a/src/emu/device.ipp +++ b/src/emu/device.ipp @@ -45,6 +45,21 @@ inline DeviceClass &device_type_impl<DeviceClass>::operator()(machine_config &mc return finder = result; } +template <class DeviceClass> template <typename... Params> +inline DeviceClass &device_type_impl<DeviceClass>::operator()(machine_config_replace replace, char const *tag, Params &&... args) const +{ + return dynamic_cast<DeviceClass &>(*replace.config.device_replace(tag, *this, std::forward<Params>(args)...)); +} + +template <class DeviceClass> template <typename Exposed, bool Required, typename... Params> +inline DeviceClass &device_type_impl<DeviceClass>::operator()(machine_config_replace replace, device_finder<Exposed, Required> &finder, Params &&... args) const +{ + std::pair<device_t &, char const *> const target(finder.finder_target()); + assert(&replace.config.current_device() == &target.first); + DeviceClass &result(dynamic_cast<DeviceClass &>(*replace.config.device_replace(target.second, *this, std::forward<Params>(args)...))); + return finder = result; +} + } } // namespace emu::detail diff --git a/src/emu/emufwd.h b/src/emu/emufwd.h index 41e725e7a58..c548e09d3a7 100644 --- a/src/emu/emufwd.h +++ b/src/emu/emufwd.h @@ -179,6 +179,7 @@ struct ioport_port_live; class running_machine; // declared in mconfig.h +namespace emu { namespace detail { struct machine_config_replace; } } class machine_config; // declared in natkeyboard.h diff --git a/src/emu/mconfig.cpp b/src/emu/mconfig.cpp index 7f142ab5958..342651818bc 100644 --- a/src/emu/mconfig.cpp +++ b/src/emu/mconfig.cpp @@ -116,6 +116,61 @@ machine_config::~machine_config() //------------------------------------------------- +// device_add - configuration helper to add a +// new device +//------------------------------------------------- + +device_t *machine_config::device_add(const char *tag, device_type type, u32 clock) +{ + std::pair<const char *, device_t *> const owner(resolve_owner(tag)); + return &add_device(type.create(*this, owner.first, owner.second, clock), owner.second); +} + + +//------------------------------------------------- +// device_replace - configuration helper to +// replace one device with a new device +//------------------------------------------------- + +device_t *machine_config::device_replace(const char *tag, device_type type, u32 clock) +{ + std::tuple<const char *, device_t *, device_t *> const existing(prepare_replace(tag)); + std::unique_ptr<device_t> device(type.create(*this, std::get<0>(existing), std::get<1>(existing), clock)); + return &replace_device(std::move(device), *std::get<1>(existing), std::get<2>(existing)); +} + + +//------------------------------------------------- +// device_remove - configuration helper to +// remove a device +//------------------------------------------------- + +device_t *machine_config::device_remove(const char *tag) +{ + // find the original device by relative tag (must exist) + assert(m_current_device); + device_t *const device = m_current_device->subdevice(tag); + if (device == nullptr) + { + osd_printf_warning("Warning: attempting to remove non-existent device '%s'\n", tag); + } + else + { + // make sure we have the old device's actual owner + device_t *const owner = device->owner(); + assert(owner); + + // remove references to the old device + remove_references(*device); + + // let the device's owner do the work + owner->subdevices().m_list.remove(*device); + } + return nullptr; +} + + +//------------------------------------------------- // resolve_owner - get the actual owner and base // tag given tag relative to current context //------------------------------------------------- @@ -134,11 +189,12 @@ std::pair<const char *, device_t *> machine_config::resolve_owner(const char *ta } // go down the path until we're done with it + std::string part; while (strchr(tag, ':')) { const char *next = strchr(tag, ':'); assert(next != tag); - std::string part(tag, next-tag); + part.assign(tag, next - tag); owner = owner->subdevices().find(part); if (!owner) throw emu_fatalerror("Could not find %s when looking up path for device %s\n", part.c_str(), orig_tag); @@ -151,18 +207,40 @@ std::pair<const char *, device_t *> machine_config::resolve_owner(const char *ta //------------------------------------------------- +// prepare_replace - ensure owner is present and +// existing device is removed if necessary +//------------------------------------------------- + +std::tuple<const char *, device_t *, device_t *> machine_config::prepare_replace(const char *tag) +{ + // make sure we have the old device's actual owner + std::pair<const char *, device_t *> const owner(resolve_owner(tag)); + assert(owner.second); + + // remove references to the old device + device_t *const old_device(owner.second->subdevice(owner.first)); + if (old_device) + remove_references(*old_device); + else + osd_printf_warning("Warning: attempting to replace non-existent device '%s'\n", tag); + + return std::make_tuple(owner.first, owner.second, old_device); +} + + +//------------------------------------------------- // add_device - add a new device at the correct // point in the hierarchy //------------------------------------------------- -device_t *machine_config::add_device(std::unique_ptr<device_t> &&device, device_t *owner) +device_t &machine_config::add_device(std::unique_ptr<device_t> &&device, device_t *owner) { - current_device_stack context(*this); + current_device_stack const context(*this); if (owner) { // allocate the new device and append it to the owner's list - device_t *const result = &owner->subdevices().m_list.append(*device.release()); - result->add_machine_configuration(*this); + device_t &result(owner->subdevices().m_list.append(*device.release())); + result.add_machine_configuration(*this); return result; } else @@ -174,91 +252,24 @@ device_t *machine_config::add_device(std::unique_ptr<device_t> &&device, device_ if (driver) driver->set_game_driver(m_gamedrv); m_root_device->add_machine_configuration(*this); - return m_root_device.get(); + return *m_root_device; } } //------------------------------------------------- -// device_add - configuration helper to add a -// new device -//------------------------------------------------- - -device_t *machine_config::device_add(const char *tag, device_type type, u32 clock) -{ - std::pair<const char *, device_t *> const owner(resolve_owner(tag)); - return add_device(type.create(*this, owner.first, owner.second, clock), owner.second); -} - - -//------------------------------------------------- -// device_replace - configuration helper to -// replace one device with a new device +// replace_device - substitute the new device for +// the old one in the owner's list //------------------------------------------------- -device_t *machine_config::device_replace(const char *tag, device_type type, u32 clock) +device_t &machine_config::replace_device(std::unique_ptr<device_t> &&device, device_t &owner, device_t *existing) { - // find the original device by relative tag (must exist) - assert(m_current_device); - device_t *old_device = m_current_device->subdevice(tag); - if (!old_device) - { - osd_printf_warning("Warning: attempting to replace non-existent device '%s'\n", tag); - return device_add(tag, type, clock); - } - else - { - // make sure we have the old device's actual owner - device_t *const owner = old_device->owner(); - assert(owner); - - // remove references to the old device - remove_references(*old_device); - - // allocate the new device and substitute it for the old one in the owner's list - device_t *const new_device = &owner->subdevices().m_list.replace_and_remove(*type.create(*this, tag, owner, clock).release(), *old_device); - current_device_stack context(*this); - new_device->add_machine_configuration(*this); - return new_device; - } -} - - -device_t *machine_config::device_replace(const char *tag, device_type type, const XTAL &clock) -{ - std::string msg = std::string("Replacing device ") + tag; - clock.validate(msg); - return device_replace(tag, type, clock.value()); -} - - -//------------------------------------------------- -// device_remove - configuration helper to -// remove a device -//------------------------------------------------- - -device_t *machine_config::device_remove(const char *tag) -{ - // find the original device by relative tag (must exist) - assert(m_current_device); - device_t *const device = m_current_device->subdevice(tag); - if (device == nullptr) - { - osd_printf_warning("Warning: attempting to remove non-existent device '%s'\n", tag); - } - else - { - // make sure we have the old device's actual owner - device_t *const owner = device->owner(); - assert(owner); - - // remove references to the old device - remove_references(*device); - - // let the device's owner do the work - owner->subdevices().m_list.remove(*device); - } - return nullptr; + current_device_stack const context(*this); + device_t &result(existing + ? owner.subdevices().m_list.replace_and_remove(*device.release(), *existing) + : owner.subdevices().m_list.append(*device.release())); + result.add_machine_configuration(*this); + return result; } diff --git a/src/emu/mconfig.h b/src/emu/mconfig.h index ce3317a17b2..c7f071d0a91 100644 --- a/src/emu/mconfig.h +++ b/src/emu/mconfig.h @@ -20,6 +20,7 @@ #include <cassert> #include <memory> +#include <tuple> #include <type_traits> #include <typeinfo> #include <utility> @@ -36,6 +37,13 @@ // TYPE DEFINITIONS //************************************************************************** +namespace emu { namespace detail { + +struct machine_config_replace { machine_config &config; }; + +} } // namesapce emu::detail + + struct internal_layout { size_t decompressed_size; @@ -109,6 +117,7 @@ public: m_current_device = &device; return token(*this, device); } + emu::detail::machine_config_replace replace() { return emu::detail::machine_config_replace{ *this }; }; device_t *device_add(const char *tag, device_type type, u32 clock); template <typename Creator> device_t *device_add(const char *tag, Creator &&type, u32 clock) @@ -132,7 +141,27 @@ public: return device_add(tag, std::forward<Creator>(type), clock.value(), std::forward<Params>(args)...); } device_t *device_replace(const char *tag, device_type type, u32 clock); - device_t *device_replace(const char *tag, device_type type, const XTAL &xtal); + template <typename Creator> + device_t *device_replace(const char *tag, Creator &&type, u32 clock) + { + return device_add(tag, device_type(type), clock); + } + template <typename Creator, typename... Params> + auto device_replace(const char *tag, Creator &&type, Params &&... args) + { + std::tuple<const char *, device_t *, device_t *> const existing(prepare_replace(tag)); + auto device(type.create(*this, std::get<0>(existing), std::get<1>(existing), std::forward<Params>(args)...)); + auto &result(*device); + assert(type.type() == typeid(result)); + replace_device(std::move(device), *std::get<1>(existing), std::get<2>(existing)); + return &result; + } + template <typename Creator, typename... Params> + auto device_replace(const char *tag, Creator &&type, XTAL clock, Params &&... args) + { + clock.validate(std::string("Replacing device ") + tag); + return device_replace(tag, std::forward<Creator>(type), clock.value(), std::forward<Params>(args)...); + } device_t *device_remove(const char *tag); device_t *device_find(device_t *owner, const char *tag); @@ -141,7 +170,9 @@ private: // internal helpers std::pair<const char *, device_t *> resolve_owner(const char *tag) const; - device_t *add_device(std::unique_ptr<device_t> &&device, device_t *owner); + std::tuple<const char *, device_t *, device_t *> prepare_replace(const char *tag); + device_t &add_device(std::unique_ptr<device_t> &&device, device_t *owner); + device_t &replace_device(std::unique_ptr<device_t> &&device, device_t &owner, device_t *existing); void remove_references(ATTR_UNUSED device_t &device); // internal state @@ -164,6 +195,16 @@ inline std::enable_if_t<emu::detail::is_device_interface<typename std::remove_re { return &type(mconfig, std::forward<Tag>(tag), std::forward<Params>(args)...).device(); } +template <typename Tag, typename Creator, typename... Params> +inline std::enable_if_t<emu::detail::is_device_implementation<typename std::remove_reference_t<Creator>::exposed_type>::value, typename std::remove_reference_t<Creator>::exposed_type *> device_replace_impl(machine_config &mconfig, Tag &&tag, Creator &&type, Params &&... args) +{ + return &type(mconfig.replace(), std::forward<Tag>(tag), std::forward<Params>(args)...); +} +template <typename Tag, typename Creator, typename... Params> +inline std::enable_if_t<emu::detail::is_device_interface<typename std::remove_reference_t<Creator>::exposed_type>::value, device_t *> device_replace_impl(machine_config &mconfig, Tag &&tag, Creator &&type, Params &&... args) +{ + return &type(mconfig.replace(), std::forward<Tag>(tag), std::forward<Params>(args)...).device(); +} } } // namespace emu::detail @@ -211,8 +252,8 @@ Ends a machine_config. // add/remove devices #define MCFG_DEVICE_ADD(_tag, ...) \ device = emu::detail::device_add_impl(config, _tag, __VA_ARGS__); -#define MCFG_DEVICE_REPLACE(_tag, _type, _clock) \ - device = config.device_replace(_tag, _type, _clock); +#define MCFG_DEVICE_REPLACE(_tag, ...) \ + device = emu::detail::device_replace_impl(config, _tag, __VA_ARGS__); #define MCFG_DEVICE_REMOVE(_tag) \ device = config.device_remove(_tag); #define MCFG_DEVICE_MODIFY(_tag) \ |