summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu
diff options
context:
space:
mode:
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
commit4ef4464aec13029fa7e394671743e9ea96394528 (patch)
tree757cd23c65c626d63f4c98afb366362f4c2d6bdb /src/emu
parent765d625ac78ea14cec1e1a84c56567d980924869 (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.h2
-rw-r--r--src/emu/device.ipp15
-rw-r--r--src/emu/emufwd.h1
-rw-r--r--src/emu/mconfig.cpp175
-rw-r--r--src/emu/mconfig.h49
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) \