summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/devcb.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/devcb.h')
-rw-r--r--src/emu/devcb.h2980
1 files changed, 2487 insertions, 493 deletions
diff --git a/src/emu/devcb.h b/src/emu/devcb.h
index 833d6938a1c..5f65235cb70 100644
--- a/src/emu/devcb.h
+++ b/src/emu/devcb.h
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
+// copyright-holders:Vas Crabb
/***************************************************************************
devcb.h
@@ -7,636 +7,2630 @@
Device callback interface helpers.
***************************************************************************/
-
-#pragma once
-
-#ifndef __EMU_H__
-#error Dont include this file directly; include emu.h instead.
-#endif
-
#ifndef MAME_EMU_DEVCB_H
#define MAME_EMU_DEVCB_H
+#pragma once
+
+#include <cassert>
#include <functional>
+#include <memory>
+#include <string>
+#include <typeinfo>
#include <type_traits>
#include <utility>
+#include <vector>
-namespace emu { namespace detail {
-template <typename Delegate> struct devcb_delegate_initialiser
+//**************************************************************************
+// LEGACY SYNAX SUPPORT - WILL BE REMOVED
+//**************************************************************************
+
+#include <tuple>
+
+#define DEVCB_READ8(tag, _class, _func) (std::forward_as_tuple((tag), &_class::_func, #_class "::" #_func))
+#define DEVCB_READ16(tag, _class, _func) (std::forward_as_tuple((tag), &_class::_func, #_class "::" #_func))
+#define DEVCB_READ32(tag, _class, _func) (std::forward_as_tuple((tag), &_class::_func, #_class "::" #_func))
+#define DEVCB_READ64(tag, _class, _func) (std::forward_as_tuple((tag), &_class::_func, #_class "::" #_func))
+#define DEVCB_READLINE(tag, _class, _func) (std::forward_as_tuple((tag), &_class::_func, #_class "::" #_func))
+
+#define DEVCB_WRITE8(tag, _class, _func) (std::forward_as_tuple((tag), &_class::_func, #_class "::" #_func))
+#define DEVCB_WRITE16(tag, _class, _func) (std::forward_as_tuple((tag), &_class::_func, #_class "::" #_func))
+#define DEVCB_WRITE32(tag, _class, _func) (std::forward_as_tuple((tag), &_class::_func, #_class "::" #_func))
+#define DEVCB_WRITE64(tag, _class, _func) (std::forward_as_tuple((tag), &_class::_func, #_class "::" #_func))
+#define DEVCB_WRITELINE(tag, _class, _func) (std::forward_as_tuple((tag), &_class::_func, #_class "::" #_func))
+
+template <typename T> struct devcb_constant_t { T m_value; };
+template <typename T> auto DEVCB_CONSTANT(T &&value) { return devcb_constant_t<std::decay_t<T> >{ std::forward<T>(value) }; }
+
+struct DEVCB_IOPORT
{
- devcb_delegate_initialiser(char const *tag, Delegate &&delegate) : m_base(nullptr), m_delegate(std::move(delegate))
- {
- }
- template <typename T>
- devcb_delegate_initialiser(T &device, std::enable_if_t<is_device_implementation<T>::value, Delegate &&> delegate) : m_base(&device), m_delegate(std::move(delegate))
- {
- }
- template <typename T>
- devcb_delegate_initialiser(T &interface, std::enable_if_t<is_device_interface<T>::value, Delegate &&> delegate) : m_base(&interface.device()), m_delegate(std::move(delegate))
- {
- }
- template <typename DeviceClass, bool Required>
- devcb_delegate_initialiser(device_finder<DeviceClass, Required> const &finder, Delegate &&delegate) : m_base(&finder.finder_target().first), m_delegate(std::move(delegate))
- {
- }
+ constexpr DEVCB_IOPORT(char const *tag) : m_tag(tag) { }
+ char const *m_tag;
+};
- device_t *m_base;
- Delegate &&m_delegate;
+struct DEVCB_INPUTLINE
+{
+ constexpr DEVCB_INPUTLINE(char const *tag, int linenum) : m_tag(tag), m_linenum(linenum) { }
+ char const *m_tag;
+ int m_linenum;
};
-inline char const *devcb_delegate_get_tag(char const *tag) { return tag; }
-template <typename T>
-inline std::enable_if_t<is_device_implementation<T>::value, char const *> devcb_delegate_get_tag(T &device) { return DEVICE_SELF; }
-template <typename T>
-inline std::enable_if_t<is_device_interface<T>::value, char const *> devcb_delegate_get_tag(T &interface) { return DEVICE_SELF; }
-template <typename DeviceClass, bool Required>
-inline char const *devcb_delegate_get_tag(device_finder<DeviceClass, Required> const &finder) { return finder.finder_tag(); }
+struct DEVCB_ASSERTLINE
+{
+ constexpr DEVCB_ASSERTLINE(char const *tag, int linenum) : m_tag(tag), m_linenum(linenum) { }
+ char const *m_tag;
+ int m_linenum;
+};
-template <typename DescType> struct devcb_tag_desc_creator
+struct DEVCB_CLEARLINE
{
- static DescType create(char const *tag)
- {
- return DescType{ nullptr, tag };
- }
- static DescType create(device_t &device)
- {
- return DescType{ &device, DEVICE_SELF };
- }
- static DescType create(device_interface &interface)
- {
- return DescType{ &interface.device(), DEVICE_SELF };
- }
- template <typename DeviceClass, bool Required>
- static DescType create(device_finder<DeviceClass, Required> const &finder)
- {
- std::pair<device_t &, char const *> const target(finder.finder_target());
- return DescType{ &target.first, target.second };
- }
+ constexpr DEVCB_CLEARLINE(char const *tag, int linenum) : m_tag(tag), m_linenum(linenum) { }
+ char const *m_tag;
+ int m_linenum;
};
-template <typename DescType> struct devcb_line_desc_creator
+struct DEVCB_HOLDLINE
{
- static DescType create(char const *tag, int inputnum)
- {
- return DescType{ nullptr, tag, inputnum };
- }
- static DescType create(device_t &device, int inputnum)
- {
- return DescType{ &device, DEVICE_SELF, inputnum };
- }
- static DescType create(device_interface &interface, int inputnum)
- {
- return DescType{ &interface.device(), DEVICE_SELF, inputnum };
- }
- template <typename DeviceClass, bool Required>
- static DescType create(device_finder<DeviceClass, Required> const &finder, int inputnum)
- {
- std::pair<device_t &, char const *> const target(finder.finder_target());
- return DescType{ &target.first, target.second, inputnum };
- }
+ constexpr DEVCB_HOLDLINE(char const *tag, int linenum) : m_tag(tag), m_linenum(linenum) { }
+ char const *m_tag;
+ int m_linenum;
};
-} } // namespace emu::detail
+struct DEVCB_MEMBANK
+{
+ constexpr DEVCB_MEMBANK(char const *tag) : m_tag(tag) { }
+ char const *m_tag;
+};
+struct DEVCB_OUTPUT
+{
+ constexpr DEVCB_OUTPUT(char const *tag) : m_tag(tag) { }
+ char const *m_tag;
+};
-//**************************************************************************
-// MACROS
-//**************************************************************************
+enum devcb_noop_t { DEVCB_NOOP };
-// wrappers for read callbacks into any tagged device
-#define DEVCB_READLINE(tag, _class, _func) (emu::detail::devcb_delegate_initialiser<read_line_delegate>((tag), read_line_delegate(&_class::_func, #_class "::" #_func, emu::detail::devcb_delegate_get_tag(tag), (_class *)nullptr)))
-#define DEVCB_READ8(tag, _class, _func) (emu::detail::devcb_delegate_initialiser<read8_delegate>((tag), read8_delegate(&_class::_func, #_class "::" #_func, emu::detail::devcb_delegate_get_tag(tag), (_class *)nullptr)))
-#define DEVCB_READ16(tag, _class, _func) (emu::detail::devcb_delegate_initialiser<read16_delegate>((tag), read16_delegate(&_class::_func, #_class "::" #_func, emu::detail::devcb_delegate_get_tag(tag), (_class *)nullptr)))
-#define DEVCB_READ32(tag, _class, _func) (emu::detail::devcb_delegate_initialiser<read32_delegate>((tag), read32_delegate(&_class::_func, #_class "::" #_func, emu::detail::devcb_delegate_get_tag(tag), (_class *)nullptr)))
-#define DEVCB_READ64(tag, _class, _func) (emu::detail::devcb_delegate_initialiser<read64_delegate>((tag), read64_delegate(&_class::_func, #_class "::" #_func, emu::detail::devcb_delegate_get_tag(tag), (_class *)nullptr)))
-
-// wrappers for write callbacks into any tagged device
-#define DEVCB_WRITELINE(tag, _class, _func) (emu::detail::devcb_delegate_initialiser<write_line_delegate>((tag), write_line_delegate(&_class::_func, #_class "::" #_func, emu::detail::devcb_delegate_get_tag(tag), (_class *)nullptr)))
-#define DEVCB_WRITE8(tag, _class, _func) (emu::detail::devcb_delegate_initialiser<write8_delegate>((tag), write8_delegate(&_class::_func, #_class "::" #_func, emu::detail::devcb_delegate_get_tag(tag), (_class *)nullptr)))
-#define DEVCB_WRITE16(tag, _class, _func) (emu::detail::devcb_delegate_initialiser<write16_delegate>((tag), write16_delegate(&_class::_func, #_class "::" #_func, emu::detail::devcb_delegate_get_tag(tag), (_class *)nullptr)))
-#define DEVCB_WRITE32(tag, _class, _func) (emu::detail::devcb_delegate_initialiser<write32_delegate>((tag), write32_delegate(&_class::_func, #_class "::" #_func, emu::detail::devcb_delegate_get_tag(tag), (_class *)nullptr)))
-#define DEVCB_WRITE64(tag, _class, _func) (emu::detail::devcb_delegate_initialiser<write64_delegate>((tag), write64_delegate(&_class::_func, #_class "::" #_func, emu::detail::devcb_delegate_get_tag(tag), (_class *)nullptr)))
-
-// machine config helpers to add shift, mask, or address space configuration
-#define MCFG_DEVCB_RSHIFT(_shift) devcb->set_rshift(_shift);
-#define MCFG_DEVCB_MASK(_mask) devcb->set_mask(_mask);
-#define MCFG_DEVCB_BIT(_bit) devcb->set_rshift(-(_bit)).set_mask(1ULL << (_bit));
-#define MCFG_DEVCB_XOR(_xor) devcb->set_xor(_xor);
-#define MCFG_DEVCB_INVERT devcb->set_xor(~u64(0));
-#define MCFG_DEVCB_ADDRESS_SPACE(_device, _spacenum) devcb->set_space(_device, _spacenum);
-
-// machine config helpers for chaining callbacks
-#define MCFG_DEVCB_CHAIN_INPUT(_desc) devcb = &downcast<devcb_read_base &>(*devcb).chain_alloc().set_callback(DEVCB_##_desc);
-#define MCFG_DEVCB_CHAIN_OUTPUT(_desc) devcb = &downcast<devcb_write_base &>(*devcb).chain_alloc().set_callback(DEVCB_##_desc);
//**************************************************************************
-// TYPE DEFINITIONS
+// DELEGATE TYPES
//**************************************************************************
-// base delegate type for a read_line/write_line
typedef device_delegate<int ()> read_line_delegate;
typedef device_delegate<void (int)> write_line_delegate;
+namespace emu { namespace detail {
-// ======================> devcb_base
-
-class devcb_base
-{
-protected:
- // enumerate the types of callbacks
- enum callback_type
- {
- CALLBACK_NONE,
- CALLBACK_LINE,
- CALLBACK_8,
- CALLBACK_16,
- CALLBACK_32,
- CALLBACK_64,
- CALLBACK_IOPORT,
- CALLBACK_MEMBANK,
- CALLBACK_OUTPUT,
- CALLBACK_LOG,
- CALLBACK_CONSTANT,
- CALLBACK_INPUTLINE,
- CALLBACK_ASSERTLINE,
- CALLBACK_CLEARLINE,
- CALLBACK_HOLDLINE
- };
+template <typename T, typename Enable = void> struct read_line_device_class { };
+template <typename T, typename Enable = void> struct write_line_device_class { };
+
+template <typename T, typename Ret, typename... Params>
+struct read_line_device_class<Ret (T::*)(Params...), std::enable_if_t<std::is_constructible<read_line_delegate, Ret (T::*)(Params...), char const *, char const *, T *>::value> > { using type = T; };
+template <typename T, typename Ret, typename... Params>
+struct read_line_device_class<Ret (T::*)(Params...) const, std::enable_if_t<std::is_constructible<read_line_delegate, Ret (T::*)(Params...) const, char const *, char const *, T *>::value> > { using type = T; };
+template <typename T, typename Ret, typename... Params>
+struct read_line_device_class<Ret (*)(T &, Params...), std::enable_if_t<std::is_constructible<read_line_delegate, Ret (*)(T &, Params...), char const *, char const *, T *>::value> > { using type = T; };
+template <typename T, typename Ret, typename... Params>
+struct read_line_device_class<Ret (*)(T *, Params...), std::enable_if_t<std::is_constructible<read_line_delegate, Ret (*)(T *, Params...), char const *, char const *, T *>::value> > { using type = T; };
+
+template <typename T, typename Ret, typename... Params>
+struct write_line_device_class<Ret (T::*)(Params...), std::enable_if_t<std::is_constructible<write_line_delegate, Ret (T::*)(Params...), char const *, char const *, T *>::value> > { using type = T; };
+template <typename T, typename Ret, typename... Params>
+struct write_line_device_class<Ret (T::*)(Params...) const, std::enable_if_t<std::is_constructible<write_line_delegate, Ret (T::*)(Params...) const, char const *, char const *, T *>::value> > { using type = T; };
+template <typename T, typename Ret, typename... Params>
+struct write_line_device_class<Ret (*)(T &, Params...), std::enable_if_t<std::is_constructible<write_line_delegate, Ret (*)(T &, Params...), char const *, char const *, T *>::value> > { using type = T; };
+template <typename T, typename Ret, typename... Params>
+struct write_line_device_class<Ret (*)(T *, Params...), std::enable_if_t<std::is_constructible<write_line_delegate, Ret (*)(T *, Params...), char const *, char const *, T *>::value> > { using type = T; };
+
+template <typename T> using read_line_device_class_t = typename read_line_device_class<T>::type;
+template <typename T> using write_line_device_class_t = typename write_line_device_class<T>::type;
- // construction/destruction
- devcb_base(device_t &device, u64 defmask);
- virtual ~devcb_base();
+template <typename T>
+inline read_line_delegate make_delegate(T &&func, char const *name, char const *tag, read_line_device_class_t<std::remove_reference_t<T> > *obj)
+{ return read_line_delegate(func, name, tag, obj); }
- template <callback_type Type> struct tag_desc
- {
- device_t *m_base;
- char const *m_tag;
- };
+template <typename T>
+inline write_line_delegate make_delegate(T &&func, char const *name, char const *tag, write_line_device_class_t<std::remove_reference_t<T> > *obj)
+{ return write_line_delegate(func, name, tag, obj); }
- template <callback_type Type> struct line_desc
- {
- device_t *m_base;
- char const *m_tag;
- int m_inputnum;
- };
+} } // namespace emu::detail
-public:
- // getters
- bool isnull() const { return (m_type == CALLBACK_NONE); }
- // additional configuration
- devcb_base &set_space(const char *device, int space = 0) { m_space_tag = device; m_space_num = space; return *this; }
- devcb_base &set_rshift(int rshift) { m_rshift = rshift; return *this; }
- devcb_base &set_mask(u64 mask) { m_mask = mask; return *this; }
- devcb_base &set_xor(u64 xorval) { m_xor = xorval; return *this; }
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
- // construction helper classes
- struct null_desc
+/// \brief Base callback helper
+///
+/// Provides utilities for supporting multiple read/write/transform
+/// signatures, and the base exclusive-or/mask transform methods.
+class devcb_base
+{
+public:
+ template <typename T> void set_space(T &&tag, int index)
{
- };
+ m_dflt_space_finder.set_tag(std::forward<T>(tag));
+ m_dflt_space_index = index;
+ }
- using ioport_desc = tag_desc<CALLBACK_IOPORT>;
- using membank_desc = tag_desc<CALLBACK_MEMBANK>;
- using output_desc = tag_desc<CALLBACK_OUTPUT>;
+ virtual void validity_check(validity_checker &valid) const;
- struct constant_desc
+protected:
+ // This is in C++17 but not C++14
+ template <typename... T> struct void_wrapper { using type = void; };
+ template <typename... T> using void_t = typename void_wrapper<T...>::type;
+
+ // Intermediate is larger of input and output, mask is forced to unsigned
+ template <typename T, typename U, typename Enable = void> struct intermediate;
+ template <typename T, typename U> struct intermediate<T, U, std::enable_if_t<sizeof(T) >= sizeof(U)> > { using type = T; };
+ template <typename T, typename U> struct intermediate<T, U, std::enable_if_t<sizeof(T) < sizeof(U)> > { using type = U; };
+ template <typename T, typename U> using intermediate_t = typename intermediate<T, U>::type;
+ template <typename T, typename U> using mask_t = std::make_unsigned_t<intermediate_t<T, U> >;
+
+ // Detecting candidates for transform functions
+ template <typename Input, typename Result, typename Func, typename Enable = void> struct is_transform_form1 { static constexpr bool value = false; };
+ template <typename Input, typename Result, typename Func, typename Enable = void> struct is_transform_form2 { static constexpr bool value = false; };
+ template <typename Input, typename Result, typename Func, typename Enable = void> struct is_transform_form3 { static constexpr bool value = false; };
+ template <typename Input, typename Result, typename Func, typename Enable = void> struct is_transform_form4 { static constexpr bool value = false; };
+ template <typename Input, typename Result, typename Func, typename Enable = void> struct is_transform_form5 { static constexpr bool value = false; };
+ template <typename Input, typename Result, typename Func, typename Enable = void> struct is_transform_form6 { static constexpr bool value = false; };
+ template <typename Input, typename Result, typename Func> struct is_transform_form1<Input, Result, Func, std::enable_if_t<std::is_convertible<std::result_of_t<Func (address_space &, offs_t &, Input, std::make_unsigned_t<Input> &)>, Result>::value> > { static constexpr bool value = true; };
+ template <typename Input, typename Result, typename Func> struct is_transform_form2<Input, Result, Func, std::enable_if_t<std::is_convertible<std::result_of_t<Func (address_space &, offs_t &, Input)>, Result>::value> > { static constexpr bool value = true; };
+ template <typename Input, typename Result, typename Func> struct is_transform_form3<Input, Result, Func, std::enable_if_t<std::is_convertible<std::result_of_t<Func (offs_t &, Input, std::make_unsigned_t<Input> &)>, Result>::value> > { static constexpr bool value = true; };
+ template <typename Input, typename Result, typename Func> struct is_transform_form4<Input, Result, Func, std::enable_if_t<std::is_convertible<std::result_of_t<Func (offs_t &, Input)>, Result>::value> > { static constexpr bool value = true; };
+ template <typename Input, typename Result, typename Func> struct is_transform_form5<Input, Result, Func, std::enable_if_t<std::is_convertible<std::result_of_t<Func (address_space &, Input)>, Result>::value> > { static constexpr bool value = true; };
+ template <typename Input, typename Result, typename Func> struct is_transform_form6<Input, Result, Func, std::enable_if_t<std::is_convertible<std::result_of_t<Func (Input)>, Result>::value> > { static constexpr bool value = true; };
+ template <typename Input, typename Result, typename Func> struct is_transform { static constexpr bool value = is_transform_form1<Input, Result, Func>::value || is_transform_form2<Input, Result, Func>::value || is_transform_form3<Input, Result, Func>::value || is_transform_form4<Input, Result, Func>::value || is_transform_form5<Input, Result, Func>::value || is_transform_form6<Input, Result, Func>::value; };
+
+ // Determining the result type of a transform function
+ template <typename Input, typename Result, typename Func, typename Enable = void> struct transform_result;
+ template <typename Input, typename Result, typename Func> struct transform_result<Input, Result, Func, std::enable_if_t<is_transform_form1<Input, Result, Func>::value> > { using type = std::result_of_t<Func (address_space &, offs_t &, Input, std::make_unsigned_t<Input> &)>; };
+ template <typename Input, typename Result, typename Func> struct transform_result<Input, Result, Func, std::enable_if_t<is_transform_form2<Input, Result, Func>::value> > { using type = std::result_of_t<Func (address_space &, offs_t &, Input)>; };
+ template <typename Input, typename Result, typename Func> struct transform_result<Input, Result, Func, std::enable_if_t<is_transform_form3<Input, Result, Func>::value> > { using type = std::result_of_t<Func (offs_t &, Input, std::make_unsigned_t<Input> &)>; };
+ template <typename Input, typename Result, typename Func> struct transform_result<Input, Result, Func, std::enable_if_t<is_transform_form4<Input, Result, Func>::value> > { using type = std::result_of_t<Func (offs_t &, Input)>; };
+ template <typename Input, typename Result, typename Func> struct transform_result<Input, Result, Func, std::enable_if_t<is_transform_form5<Input, Result, Func>::value> > { using type = std::result_of_t<Func (address_space &, Input)>; };
+ template <typename Input, typename Result, typename Func> struct transform_result<Input, Result, Func, std::enable_if_t<is_transform_form6<Input, Result, Func>::value> > { using type = std::result_of_t<Func (Input)>; };
+ template <typename Input, typename Result, typename Func> using transform_result_t = typename transform_result<Input, Result, Func>::type;
+
+ // Mapping method types to delegate types
+ template <typename T, typename Enable = void> struct delegate_type;
+ template <typename T> struct delegate_type<T, void_t<emu::detail::read8_device_class_t<std::remove_reference_t<T> > > > { using type = read8_delegate; using device_class = emu::detail::read8_device_class_t<std::remove_reference_t<T> >; };
+ template <typename T> struct delegate_type<T, void_t<emu::detail::read16_device_class_t<std::remove_reference_t<T> > > > { using type = read16_delegate; using device_class = emu::detail::read16_device_class_t<std::remove_reference_t<T> >; };
+ template <typename T> struct delegate_type<T, void_t<emu::detail::read32_device_class_t<std::remove_reference_t<T> > > > { using type = read32_delegate; using device_class = emu::detail::read32_device_class_t<std::remove_reference_t<T> >; };
+ template <typename T> struct delegate_type<T, void_t<emu::detail::read64_device_class_t<std::remove_reference_t<T> > > > { using type = read64_delegate; using device_class = emu::detail::read64_device_class_t<std::remove_reference_t<T> >; };
+ template <typename T> struct delegate_type<T, void_t<emu::detail::read_line_device_class_t<std::remove_reference_t<T> > > > { using type = read_line_delegate; using device_class = emu::detail::read_line_device_class_t<std::remove_reference_t<T> >; };
+ template <typename T> struct delegate_type<T, void_t<emu::detail::write8_device_class_t<std::remove_reference_t<T> > > > { using type = write8_delegate; using device_class = emu::detail::write8_device_class_t<std::remove_reference_t<T> >; };
+ template <typename T> struct delegate_type<T, void_t<emu::detail::write16_device_class_t<std::remove_reference_t<T> > > > { using type = write16_delegate; using device_class = emu::detail::write16_device_class_t<std::remove_reference_t<T> >; };
+ template <typename T> struct delegate_type<T, void_t<emu::detail::write32_device_class_t<std::remove_reference_t<T> > > > { using type = write32_delegate; using device_class = emu::detail::write32_device_class_t<std::remove_reference_t<T> >; };
+ template <typename T> struct delegate_type<T, void_t<emu::detail::write64_device_class_t<std::remove_reference_t<T> > > > { using type = write64_delegate; using device_class = emu::detail::write64_device_class_t<std::remove_reference_t<T> >; };
+ template <typename T> struct delegate_type<T, void_t<emu::detail::write_line_device_class_t<std::remove_reference_t<T> > > > { using type = write_line_delegate; using device_class = emu::detail::write_line_device_class_t<std::remove_reference_t<T> >; };
+ template <typename T> using delegate_type_t = typename delegate_type<T>::type;
+ template <typename T> using delegate_device_class_t = typename delegate_type<T>::device_class;
+
+ // Invoking transform callbacks
+ template <typename Input, typename Result, typename T> static std::enable_if_t<is_transform_form1<Input, Result, T>::value, mask_t<transform_result_t<Input, Result, T>, Result> > invoke_transform(T const &cb, address_space &space, offs_t &offset, Input data, std::make_unsigned_t<Input> &mem_mask) { return std::make_unsigned_t<transform_result_t<Input, Result, T> >(cb(space, offset, data, mem_mask)); }
+ template <typename Input, typename Result, typename T> static std::enable_if_t<is_transform_form2<Input, Result, T>::value, mask_t<transform_result_t<Input, Result, T>, Result> > invoke_transform(T const &cb, address_space &space, offs_t &offset, Input data, std::make_unsigned_t<Input> &mem_mask) { return std::make_unsigned_t<transform_result_t<Input, Result, T> >(cb(space, data, offset)); }
+ template <typename Input, typename Result, typename T> static std::enable_if_t<is_transform_form3<Input, Result, T>::value, mask_t<transform_result_t<Input, Result, T>, Result> > invoke_transform(T const &cb, address_space &space, offs_t &offset, Input data, std::make_unsigned_t<Input> &mem_mask) { return std::make_unsigned_t<transform_result_t<Input, Result, T> >(cb(offset, data, mem_mask)); }
+ template <typename Input, typename Result, typename T> static std::enable_if_t<is_transform_form4<Input, Result, T>::value, mask_t<transform_result_t<Input, Result, T>, Result> > invoke_transform(T const &cb, address_space &space, offs_t &offset, Input data, std::make_unsigned_t<Input> &mem_mask) { return std::make_unsigned_t<transform_result_t<Input, Result, T> >(cb(offset, data)); }
+ template <typename Input, typename Result, typename T> static std::enable_if_t<is_transform_form5<Input, Result, T>::value, mask_t<transform_result_t<Input, Result, T>, Result> > invoke_transform(T const &cb, address_space &space, offs_t &offset, Input data, std::make_unsigned_t<Input> &mem_mask) { return std::make_unsigned_t<transform_result_t<Input, Result, T> >(cb(space, data)); }
+ template <typename Input, typename Result, typename T> static std::enable_if_t<is_transform_form6<Input, Result, T>::value, mask_t<transform_result_t<Input, Result, T>, Result> > invoke_transform(T const &cb, address_space &space, offs_t &offset, Input data, std::make_unsigned_t<Input> &mem_mask) { return std::make_unsigned_t<transform_result_t<Input, Result, T> >(cb(data)); }
+
+ // Working with devices and interfaces
+ template <typename T> static std::enable_if_t<emu::detail::is_device_implementation<T>::value, const char *> get_tag(T &obj) { return obj.tag(); }
+ template <typename T> static std::enable_if_t<emu::detail::is_device_interface<T>::value, const char *> get_tag(T &obj) { return obj.device().tag(); }
+ template <typename T, typename U> static std::enable_if_t<std::is_convertible<std::add_pointer_t<U>, std::add_pointer_t<T> >::value, T &> cast_reference(U &obj) { return downcast<T &>(obj); }
+ template <typename T, typename U> static std::enable_if_t<!std::is_convertible<std::add_pointer_t<U>, std::add_pointer_t<T> >::value, T &> cast_reference(U &obj) { return dynamic_cast<T &>(obj); }
+
+ /// \brief Base transform helper
+ ///
+ /// Provides member functions for setting exclusive-or, mask and
+ /// shifts. Exclusive-or and mask values are stored; it's assumed
+ /// that the implementation supports lamba transforms to allow
+ /// shifts.
+ template <typename T, typename Impl>
+ class transform_base
{
- u64 m_value;
+ public:
+ Impl &exor(std::make_unsigned_t<T> val) { m_exor ^= val; return static_cast<Impl &>(*this); }
+ Impl &mask(std::make_unsigned_t<T> val) { m_mask = m_inherited_mask ? val : (m_mask & val); m_inherited_mask = false; return static_cast<Impl &>(*this); }
+ Impl &invert() { return exor(~std::make_unsigned_t<T>(0)); }
+
+ auto rshift(unsigned val)
+ {
+ auto trans(static_cast<Impl &>(*this).transform([val] (offs_t offset, T data, std::make_unsigned_t<T> &mem_mask) { mem_mask >>= val; return data >> val; }));
+ return std::move(trans.mask(m_mask >> val));
+ }
+ auto lshift(unsigned val)
+ {
+ auto trans(static_cast<Impl &>(*this).transform([val] (offs_t offset, T data, std::make_unsigned_t<T> &mem_mask) { mem_mask <<= val; return data << val; }));
+ return std::move(trans.mask(m_mask << val));
+ }
+ auto bit(unsigned val) { return std::move(rshift(val).mask(T(1U))); }
+
+ constexpr std::make_unsigned_t<T> exor() const { return m_exor & m_mask; }
+ constexpr std::make_unsigned_t<T> mask() const { return m_mask; }
+
+ protected:
+ constexpr bool need_exor() const { return std::make_unsigned_t<T>(0) != (m_exor & m_mask); }
+ constexpr bool need_mask() const { return std::make_unsigned_t<T>(~std::make_unsigned_t<T>(0)) != m_mask; }
+
+ constexpr bool inherited_mask() const { return m_inherited_mask; }
+
+ constexpr transform_base(std::make_unsigned_t<T> mask) : m_mask(mask) { }
+ constexpr transform_base(transform_base const &) = default;
+ transform_base(transform_base &&) = default;
+ transform_base &operator=(transform_base const &) = default;
+ transform_base &operator=(transform_base &&) = default;
+
+ private:
+ std::make_unsigned_t<T> m_exor = std::make_unsigned_t<T>(0);
+ std::make_unsigned_t<T> m_mask;
+ bool m_inherited_mask = true;
};
- struct logger_desc
- {
- const char *m_string;
- };
+ devcb_base(device_t &owner);
+ ~devcb_base();
- using inputline_desc = line_desc<CALLBACK_INPUTLINE>;
- using assertline_desc = line_desc<CALLBACK_ASSERTLINE>;
- using clearline_desc = line_desc<CALLBACK_CLEARLINE>;
- using holdline_desc = line_desc<CALLBACK_HOLDLINE>;
+ device_t &owner() const { return m_owner; }
- // shared callback setters
- devcb_base &set_callback(null_desc null) { reset(CALLBACK_NONE); return *this; }
- template <callback_type Type> devcb_base &set_callback(tag_desc<Type> desc)
- {
- if (desc.m_base) reset(*desc.m_base, Type);
- else reset(Type);
- m_target_tag = desc.m_tag;
- return *this;
- }
- devcb_base &set_callback(constant_desc constant) { reset(CALLBACK_CONSTANT); m_target_int = constant.m_value; return *this; }
- devcb_base &set_callback(logger_desc logger) { reset(CALLBACK_LOG); m_target_tag = logger.m_string; return *this; }
- void reset() { reset(m_owner, CALLBACK_NONE); }
+ void resolve();
-protected:
- // internal helpers
- inline u64 shift_mask(u64 value) const { return ((m_rshift < 0) ? (value << -m_rshift) : (value >> m_rshift)) & m_mask; }
- inline u64 shift_mask_xor(u64 value) const { return (((m_rshift < 0) ? (value << -m_rshift) : (value >> m_rshift)) ^ m_xor) & m_mask; }
- inline u64 unshift_mask(u64 value) const { return (m_rshift < 0) ? ((value & m_mask) >> -m_rshift) : ((value & m_mask) << m_rshift); }
- inline u64 unshift_mask_xor(u64 value) const { return (m_rshift < 0) ? (((value ^ m_xor) & m_mask) >> -m_rshift) : (((value ^ m_xor) & m_mask) << m_rshift); }
- void reset(callback_type type);
- void reset(device_t &base, callback_type type);
- virtual void devcb_reset() = 0;
- void resolve_ioport();
- void resolve_membank();
- void resolve_output();
- void resolve_inputline();
- void resolve_space();
-
- // the callback target is going to be one of these
- union callback_target
- {
- void * ptr;
- device_t * device;
- ioport_port * ioport;
- memory_bank * membank;
- output_manager::output_item *item;
- };
+ address_space &default_space() { assert(m_dflt_space); return *m_dflt_space; }
- // configuration
- device_t & m_owner; // reference to our owning device
- std::reference_wrapper<device_t> m_base; // device to resolve relative to
- callback_type m_type; // type of callback registered
- const char * m_target_tag; // tag of target object
- u64 m_target_int; // integer value of target object
- const char * m_space_tag; // tag of address space device
- int m_space_num; // address space number of space device
-
- // derived state
- address_space * m_space; // target address space
- callback_target m_target; // resolved pointer to target object
- int m_rshift; // right shift to apply to data read
- u64 m_mask; // mask to apply to data read
- const u64 m_defmask; // default mask
- u64 m_xor; // XOR to apply to data read
+private:
+ device_t &m_owner;
+ optional_device<device_memory_interface> m_dflt_space_finder;
+ int m_dflt_space_index;
+ address_space *m_dflt_space;
};
-// ======================> devcb_read_base
-
+/// \brief Read callback utilities
+///
+/// Helpers that don't need to be templated on callback type.
class devcb_read_base : public devcb_base
{
protected:
- // construction/destruction
- devcb_read_base(device_t &device, u64 defmask, bool chained = false);
+ // Detecting candidates for read functions
+ template <typename Result, typename Func, typename Enable = void> struct is_read_form1 { static constexpr bool value = false; };
+ template <typename Result, typename Func, typename Enable = void> struct is_read_form2 { static constexpr bool value = false; };
+ template <typename Result, typename Func, typename Enable = void> struct is_read_form3 { static constexpr bool value = false; };
+ template <typename Result, typename Func, typename Enable = void> struct is_read_form4 { static constexpr bool value = false; };
+ template <typename Result, typename Func, typename Enable = void> struct is_read_form5 { static constexpr bool value = false; };
+ template <typename Result, typename Func, typename Enable = void> struct is_read_form6 { static constexpr bool value = false; };
+ template <typename Result, typename Func> struct is_read_form1<Result, Func, std::enable_if_t<std::is_convertible<std::result_of_t<Func (address_space &, offs_t, Result)>, Result>::value> > { static constexpr bool value = true; };
+ template <typename Result, typename Func> struct is_read_form2<Result, Func, std::enable_if_t<std::is_convertible<std::result_of_t<Func (address_space &, offs_t)>, Result>::value> > { static constexpr bool value = true; };
+ template <typename Result, typename Func> struct is_read_form3<Result, Func, std::enable_if_t<std::is_convertible<std::result_of_t<Func (offs_t, Result)>, Result>::value> > { static constexpr bool value = true; };
+ template <typename Result, typename Func> struct is_read_form4<Result, Func, std::enable_if_t<std::is_convertible<std::result_of_t<Func (offs_t)>, Result>::value> > { static constexpr bool value = true; };
+ template <typename Result, typename Func> struct is_read_form5<Result, Func, std::enable_if_t<std::is_convertible<std::result_of_t<Func (address_space &)>, Result>::value> > { static constexpr bool value = true; };
+ template <typename Result, typename Func> struct is_read_form6<Result, Func, std::enable_if_t<std::is_convertible<std::result_of_t<Func ()>, Result>::value> > { static constexpr bool value = true; };
+ template <typename Result, typename Func> struct is_read { static constexpr bool value = is_read_form1<Result, Func>::value || is_read_form2<Result, Func>::value || is_read_form3<Result, Func>::value || is_read_form4<Result, Func>::value || is_read_form5<Result, Func>::value || is_read_form6<Result, Func>::value; };
+
+ // Determining the result type of a read function
+ template <typename Result, typename Func, typename Enable = void> struct read_result;
+ template <typename Result, typename Func> struct read_result<Result, Func, std::enable_if_t<is_read_form1<Result, Func>::value> > { using type = std::result_of_t<Func (address_space &, offs_t, std::make_unsigned_t<Result>)>; };
+ template <typename Result, typename Func> struct read_result<Result, Func, std::enable_if_t<is_read_form2<Result, Func>::value> > { using type = std::result_of_t<Func (address_space &, offs_t)>; };
+ template <typename Result, typename Func> struct read_result<Result, Func, std::enable_if_t<is_read_form3<Result, Func>::value> > { using type = std::result_of_t<Func (offs_t, std::make_unsigned_t<Result>)>; };
+ template <typename Result, typename Func> struct read_result<Result, Func, std::enable_if_t<is_read_form4<Result, Func>::value> > { using type = std::result_of_t<Func (offs_t)>; };
+ template <typename Result, typename Func> struct read_result<Result, Func, std::enable_if_t<is_read_form5<Result, Func>::value> > { using type = std::result_of_t<Func (address_space &)>; };
+ template <typename Result, typename Func> struct read_result<Result, Func, std::enable_if_t<is_read_form6<Result, Func>::value> > { using type = std::result_of_t<Func ()>; };
+ template <typename Result, typename Func> using read_result_t = typename read_result<Result, Func>::type;
+
+ // Detecting candidates for read delegates
+ template <typename T, typename Enable = void> struct is_read_method { static constexpr bool value = false; };
+ template <typename T> struct is_read_method<T, void_t<emu::detail::read8_device_class_t<std::remove_reference_t<T> > > > { static constexpr bool value = true; };
+ template <typename T> struct is_read_method<T, void_t<emu::detail::read16_device_class_t<std::remove_reference_t<T> > > > { static constexpr bool value = true; };
+ template <typename T> struct is_read_method<T, void_t<emu::detail::read32_device_class_t<std::remove_reference_t<T> > > > { static constexpr bool value = true; };
+ template <typename T> struct is_read_method<T, void_t<emu::detail::read64_device_class_t<std::remove_reference_t<T> > > > { static constexpr bool value = true; };
+ template <typename T> struct is_read_method<T, void_t<emu::detail::read_line_device_class_t<std::remove_reference_t<T> > > > { static constexpr bool value = true; };
+
+ // Invoking read callbacks
+ template <typename Result, typename T> static std::enable_if_t<is_read_form1<Result, T>::value, mask_t<read_result_t<Result, T>, Result> > invoke_read(T const &cb, address_space &space, offs_t offset, std::make_unsigned_t<Result> mem_mask) { return std::make_unsigned_t<read_result_t<Result, T> >(cb(space, offset, mem_mask)); }
+ template <typename Result, typename T> static std::enable_if_t<is_read_form2<Result, T>::value, mask_t<read_result_t<Result, T>, Result> > invoke_read(T const &cb, address_space &space, offs_t offset, std::make_unsigned_t<Result> mem_mask) { return std::make_unsigned_t<read_result_t<Result, T> >(cb(space, offset)); }
+ template <typename Result, typename T> static std::enable_if_t<is_read_form3<Result, T>::value, mask_t<read_result_t<Result, T>, Result> > invoke_read(T const &cb, address_space &space, offs_t offset, std::make_unsigned_t<Result> mem_mask) { return std::make_unsigned_t<read_result_t<Result, T> >(cb(offset, mem_mask)); }
+ template <typename Result, typename T> static std::enable_if_t<is_read_form4<Result, T>::value, mask_t<read_result_t<Result, T>, Result> > invoke_read(T const &cb, address_space &space, offs_t offset, std::make_unsigned_t<Result> mem_mask) { return std::make_unsigned_t<read_result_t<Result, T> >(cb(offset)); }
+ template <typename Result, typename T> static std::enable_if_t<is_read_form5<Result, T>::value, mask_t<read_result_t<Result, T>, Result> > invoke_read(T const &cb, address_space &space, offs_t offset, std::make_unsigned_t<Result> mem_mask) { return std::make_unsigned_t<read_result_t<Result, T> >(cb(space)); }
+ template <typename Result, typename T> static std::enable_if_t<is_read_form6<Result, T>::value, mask_t<read_result_t<Result, T>, Result> > invoke_read(T const &cb, address_space &space, offs_t offset, std::make_unsigned_t<Result> mem_mask) { return std::make_unsigned_t<read_result_t<Result, T> >(cb()); }
+
+ // Delegate characteristics
+ template <typename T, typename Dummy = void> struct delegate_traits;
+ template <typename Dummy> struct delegate_traits<read8_delegate, Dummy> { static constexpr u8 default_mask = ~u8(0); };
+ template <typename Dummy> struct delegate_traits<read16_delegate, Dummy> { static constexpr u16 default_mask = ~u16(0); };
+ template <typename Dummy> struct delegate_traits<read32_delegate, Dummy> { static constexpr u32 default_mask = ~u32(0); };
+ template <typename Dummy> struct delegate_traits<read64_delegate, Dummy> { static constexpr u64 default_mask = ~u64(0); };
+ template <typename Dummy> struct delegate_traits<read_line_delegate, Dummy> { static constexpr unsigned default_mask = 1U; };
+
+ using devcb_base::devcb_base;
+ ~devcb_read_base();
+};
- template <typename Delegate, typename Dummy> struct set_helper
- {
- static constexpr bool valid = false;
- };
- template <typename Dummy> struct set_helper<read_line_delegate, Dummy>
- {
- static constexpr bool valid = true;
- static constexpr callback_type type = CALLBACK_LINE;
- static void apply(devcb_read_base &devcb, read_line_delegate &&delegate) { devcb.m_readline = std::move(delegate); }
- };
- template <typename Dummy> struct set_helper<read8_delegate, Dummy>
- {
- static constexpr bool valid = true;
- static constexpr callback_type type = CALLBACK_8;
- static void apply(devcb_read_base &devcb, read8_delegate &&delegate) { devcb.m_read8 = std::move(delegate); }
- };
- template <typename Dummy> struct set_helper<read16_delegate, Dummy>
- {
- static constexpr bool valid = true;
- static constexpr callback_type type = CALLBACK_16;
- static void apply(devcb_read_base &devcb, read16_delegate &&delegate) { devcb.m_read16 = std::move(delegate); }
- };
- template <typename Dummy> struct set_helper<read32_delegate, Dummy>
- {
- static constexpr bool valid = true;
- static constexpr callback_type type = CALLBACK_32;
- static void apply(devcb_read_base &devcb, read32_delegate &&delegate) { devcb.m_read32 = std::move(delegate); }
- };
- template <typename Dummy> struct set_helper<read64_delegate, Dummy>
- {
- static constexpr bool valid = true;
- static constexpr callback_type type = CALLBACK_64;
- static void apply(devcb_read_base &devcb, read64_delegate &&delegate) { devcb.m_read64 = std::move(delegate); }
- };
-public:
- // callback configuration
- using devcb_base::set_callback;
- template <typename Delegate>
- std::enable_if_t<set_helper<Delegate, void>::valid, devcb_read_base &> set_callback(emu::detail::devcb_delegate_initialiser<Delegate> &&desc)
+/// \brief Write callback utilities
+///
+/// Helpers that don't need to be templated on callback type.
+class devcb_write_base : public devcb_base
+{
+protected:
+ // Detecting candidates for write functions
+ template <typename Input, typename Func, typename Enable = void> struct is_write_form1 { static constexpr bool value = false; };
+ template <typename Input, typename Func, typename Enable = void> struct is_write_form2 { static constexpr bool value = false; };
+ template <typename Input, typename Func, typename Enable = void> struct is_write_form3 { static constexpr bool value = false; };
+ template <typename Input, typename Func, typename Enable = void> struct is_write_form4 { static constexpr bool value = false; };
+ template <typename Input, typename Func, typename Enable = void> struct is_write_form5 { static constexpr bool value = false; };
+ template <typename Input, typename Func, typename Enable = void> struct is_write_form6 { static constexpr bool value = false; };
+ template <typename Input, typename Func> struct is_write_form1<Input, Func, void_t<std::result_of_t<Func (address_space &, offs_t, Input, std::make_unsigned_t<Input>)> > > { static constexpr bool value = true; };
+ template <typename Input, typename Func> struct is_write_form2<Input, Func, void_t<std::result_of_t<Func (address_space &, offs_t, Input)> > > { static constexpr bool value = true; };
+ template <typename Input, typename Func> struct is_write_form3<Input, Func, void_t<std::result_of_t<Func (offs_t, Input, std::make_unsigned_t<Input>)> > > { static constexpr bool value = true; };
+ template <typename Input, typename Func> struct is_write_form4<Input, Func, void_t<std::result_of_t<Func (offs_t, Input)> > > { static constexpr bool value = true; };
+ template <typename Input, typename Func> struct is_write_form5<Input, Func, void_t<std::result_of_t<Func (address_space &, Input)> > > { static constexpr bool value = true; };
+ template <typename Input, typename Func> struct is_write_form6<Input, Func, void_t<std::result_of_t<Func (Input)> > > { static constexpr bool value = true; };
+ template <typename Input, typename Func> struct is_write { static constexpr bool value = is_write_form1<Input, Func>::value || is_write_form2<Input, Func>::value || is_write_form3<Input, Func>::value || is_write_form4<Input, Func>::value || is_write_form5<Input, Func>::value || is_write_form6<Input, Func>::value; };
+
+ // Detecting candidates for write delegates
+ template <typename T, typename Enable = void> struct is_write_method { static constexpr bool value = false; };
+ template <typename T> struct is_write_method<T, void_t<emu::detail::write8_device_class_t<std::remove_reference_t<T> > > > { static constexpr bool value = true; };
+ template <typename T> struct is_write_method<T, void_t<emu::detail::write16_device_class_t<std::remove_reference_t<T> > > > { static constexpr bool value = true; };
+ template <typename T> struct is_write_method<T, void_t<emu::detail::write32_device_class_t<std::remove_reference_t<T> > > > { static constexpr bool value = true; };
+ template <typename T> struct is_write_method<T, void_t<emu::detail::write64_device_class_t<std::remove_reference_t<T> > > > { static constexpr bool value = true; };
+ template <typename T> struct is_write_method<T, void_t<emu::detail::write_line_device_class_t<std::remove_reference_t<T> > > > { static constexpr bool value = true; };
+
+ // Invoking write callbacks
+ template <typename Input, typename T> static std::enable_if_t<is_write_form1<Input, T>::value> invoke_write(T const &cb, address_space &space, offs_t &offset, Input data, std::make_unsigned_t<Input> mem_mask) { return cb(space, offset, data, mem_mask); }
+ template <typename Input, typename T> static std::enable_if_t<is_write_form2<Input, T>::value> invoke_write(T const &cb, address_space &space, offs_t &offset, Input data, std::make_unsigned_t<Input> mem_mask) { return cb(space, data, offset); }
+ template <typename Input, typename T> static std::enable_if_t<is_write_form3<Input, T>::value> invoke_write(T const &cb, address_space &space, offs_t &offset, Input data, std::make_unsigned_t<Input> mem_mask) { return cb(offset, data, mem_mask); }
+ template <typename Input, typename T> static std::enable_if_t<is_write_form4<Input, T>::value> invoke_write(T const &cb, address_space &space, offs_t &offset, Input data, std::make_unsigned_t<Input> mem_mask) { return cb(offset, data); }
+ template <typename Input, typename T> static std::enable_if_t<is_write_form5<Input, T>::value> invoke_write(T const &cb, address_space &space, offs_t &offset, Input data, std::make_unsigned_t<Input> mem_mask) { return cb(space, data); }
+ template <typename Input, typename T> static std::enable_if_t<is_write_form6<Input, T>::value> invoke_write(T const &cb, address_space &space, offs_t &offset, Input data, std::make_unsigned_t<Input> mem_mask) { return cb(data); }
+
+ // Delegate characteristics
+ template <typename T, typename Dummy = void> struct delegate_traits;
+ template <typename Dummy> struct delegate_traits<write8_delegate, Dummy> { using input_t = u8; static constexpr u8 default_mask = ~u8(0); };
+ template <typename Dummy> struct delegate_traits<write16_delegate, Dummy> { using input_t = u16; static constexpr u16 default_mask = ~u16(0); };
+ template <typename Dummy> struct delegate_traits<write32_delegate, Dummy> { using input_t = u32; static constexpr u32 default_mask = ~u32(0); };
+ template <typename Dummy> struct delegate_traits<write64_delegate, Dummy> { using input_t = u64; static constexpr u64 default_mask = ~u64(0); };
+ template <typename Dummy> struct delegate_traits<write_line_delegate, Dummy> { using input_t = int; static constexpr unsigned default_mask = 1U; };
+
+ using devcb_base::devcb_base;
+ ~devcb_write_base();
+};
+
+
+/// \brief Read callback helper
+///
+/// Allows binding a variety of signatures, composing a result from
+/// multiple callbacks, and chained arbitrary transforms. Transforms
+/// may modify the offset and mask.
+template <typename Result, std::make_unsigned_t<Result> DefaultMask = std::make_unsigned_t<Result>(~std::make_unsigned_t<Result>(0))>
+class devcb_read : public devcb_read_base
+{
+private:
+ using func_t = std::function<Result (address_space &, offs_t, std::make_unsigned_t<Result>)>;
+
+ class creator
{
- if (desc.m_base) reset(*desc.m_base, set_helper<Delegate, void>::type);
- else reset(set_helper<Delegate, void>::type);
- set_helper<Delegate, void>::apply(*this, std::move(desc.m_delegate));
- return *this;
- }
- template <typename... Params> auto &chain(Params &&... args) { return chain_alloc().set_callback(std::forward<Params>(args)...); }
- devcb_read_base &chain_alloc();
+ public:
+ using ptr = std::unique_ptr<creator>;
- // resolution
- void resolve();
- void resolve_safe(u64 none_constant_value);
+ virtual ~creator() { }
+ virtual void validity_check(validity_checker &valid) const = 0;
+ virtual func_t create() = 0;
- // validity checking
- void validity_check(validity_checker &valid) const;
+ std::make_unsigned_t<Result> mask() const { return m_mask; }
-protected:
- // internal helpers
- virtual void devcb_reset() override;
- inline u64 read(address_space &space, offs_t offset, u64 mask);
+ protected:
+ creator(std::make_unsigned_t<Result> mask) : m_mask(mask) { }
-private:
- // adapters
- u64 read_unresolved_adapter(address_space &space, offs_t offset, u64 mask);
- u64 read_line_adapter(address_space &space, offs_t offset, u64 mask);
- u64 read8_adapter(address_space &space, offs_t offset, u64 mask);
- u64 read16_adapter(address_space &space, offs_t offset, u64 mask);
- u64 read32_adapter(address_space &space, offs_t offset, u64 mask);
- u64 read64_adapter(address_space &space, offs_t offset, u64 mask);
- u64 read_ioport_adapter(address_space &space, offs_t offset, u64 mask);
- u64 read_logged_adapter(address_space &space, offs_t offset, u64 mask);
- u64 read_constant_adapter(address_space &space, offs_t offset, u64 mask);
-
- // configuration
- read_line_delegate m_readline; // copy of registered line reader
- read8_delegate m_read8; // copy of registered 8-bit reader
- read16_delegate m_read16; // copy of registered 16-bit reader
- read32_delegate m_read32; // copy of registered 32-bit reader
- read64_delegate m_read64; // copy of registered 64-bit reader
-
- // derived state
- typedef u64 (devcb_read_base::*adapter_func)(address_space &, offs_t, u64);
- adapter_func m_adapter; // actual callback to invoke
- std::unique_ptr<devcb_read_base> m_chain; // next callback for chained input
-};
+ std::make_unsigned_t<Result> m_mask;
+ };
+ template <typename T>
+ class creator_impl : public creator
+ {
+ public:
+ creator_impl(T &&builder) : creator(builder.mask()), m_builder(std::move(builder)) { }
-// ======================> devcb_write_base
+ virtual void validity_check(validity_checker &valid) const override { m_builder.validity_check(valid); }
-class devcb_write_base : public devcb_base
-{
-protected:
- // construction/destruction
- devcb_write_base(device_t &device, u64 defmask, bool chained = false);
+ virtual func_t create() override
+ {
+ func_t result;
+ m_builder.build([&result] (auto &&f) { result = [cb = std::move(f)] (address_space &space, offs_t offset, typename T::input_mask_t mem_mask) { return cb(space, offset, mem_mask); }; });
+ return std::move(result);
+ }
+
+ private:
+ T m_builder;
+ };
- template <typename Delegate, typename Dummy> struct set_helper
+ class log_creator : public creator
{
- static constexpr bool valid = false;
+ public:
+ log_creator(device_t &devbase, std::string &&message) : creator(0U), m_devbase(devbase), m_message(std::move(message)) { }
+
+ virtual void validity_check(validity_checker &valid) const override { }
+
+ virtual func_t create() override
+ {
+ return
+ [&devbase = m_devbase, message = std::move(m_message)] (address_space &space, offs_t offset, std::make_unsigned_t<Result> mem_mask)
+ {
+ devbase.logerror("%s: %s\n", devbase.machine().describe_context(), message);
+ return Result(0);
+ };
+ }
+
+ private:
+ device_t &m_devbase;
+ std::string m_message;
};
- template <typename Dummy> struct set_helper<write_line_delegate, Dummy>
+
+ class builder_base
+ {
+ protected:
+ builder_base(devcb_read &target, bool append) : m_target(target), m_append(append) { }
+ builder_base(builder_base const &) = delete;
+ builder_base(builder_base &&) = default;
+ ~builder_base() { assert(m_consumed); }
+ builder_base &operator=(builder_base const &) = delete;
+ builder_base &operator=(builder_base &&) = default;
+
+ void consume() { m_consumed = true; }
+ void built() { assert(!m_built); m_built = true; }
+
+ template <typename T>
+ void register_creator()
+ {
+ if (!m_consumed)
+ {
+ if (!m_append)
+ m_target.m_creators.clear();
+ consume();
+ m_target.m_creators.emplace_back(std::make_unique<creator_impl<T> >(std::move(static_cast<T &>(*this))));
+ }
+ }
+
+ devcb_read &m_target;
+ bool const m_append;
+ bool m_consumed = false;
+ bool m_built = false;
+ };
+
+ template <typename Source, typename Func>
+ class transform_builder : public builder_base, public transform_base<mask_t<transform_result_t<typename Source::output_t, Result, Func>, Result>, transform_builder<Source, Func> >
{
- static constexpr bool valid = true;
- static constexpr callback_type type = CALLBACK_LINE;
- static void apply(devcb_write_base &devcb, write_line_delegate &&delegate) { devcb.m_writeline = std::move(delegate); }
+ public:
+ template <typename T, typename U> friend class transform_builder;
+
+ using input_t = typename Source::output_t;
+ using output_t = mask_t<transform_result_t<input_t, Result, Func>, Result>;
+ using input_mask_t = mask_t<input_t, typename Source::input_mask_t>;
+
+ template <typename T>
+ transform_builder(devcb_read &target, bool append, Source &&src, T &&cb, output_t mask)
+ : builder_base(target, append)
+ , transform_base<output_t, transform_builder>(mask)
+ , m_src(std::move(src))
+ , m_cb(std::forward<T>(cb))
+ { m_src.consume(); }
+ transform_builder(transform_builder &&that)
+ : builder_base(std::move(that))
+ , transform_base<output_t, transform_builder>(std::move(that))
+ , m_src(std::move(that.m_src))
+ , m_cb(std::move(that.m_cb))
+ {
+ m_src.consume();
+ that.consume();
+ that.built();
+ }
+ ~transform_builder() { this->template register_creator<transform_builder>(); }
+
+ template <typename T>
+ std::enable_if_t<is_transform<output_t, Result, T>::value, transform_builder<transform_builder, std::remove_reference_t<T> > > transform(T &&cb)
+ {
+ output_t const m(this->mask());
+ if (this->inherited_mask())
+ this->mask(std::make_unsigned_t<transform_result_t<typename Source::output_t, Result, Func> >(~std::make_unsigned_t<transform_result_t<typename Source::output_t, Result, Func> >(0)));
+ return transform_builder<transform_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, std::move(*this), std::forward<T>(cb), m);
+ }
+
+ void validity_check(validity_checker &valid) const { m_src.validity_check(valid); }
+
+ template <typename T>
+ void build(T &&chain)
+ {
+ assert(this->m_consumed);
+ auto wrap([this, c = std::forward<T>(chain)] (auto &&f) mutable { this->build(std::move(c), std::move(f)); });
+ m_src.build(std::move(wrap));
+ }
+
+ private:
+ transform_builder(transform_builder const &) = delete;
+ transform_builder &operator=(transform_builder const &) = delete;
+ transform_builder &operator=(transform_builder &&that) = delete;
+
+ template <typename T, typename U>
+ void build(T &&chain, U &&f)
+ {
+ assert(this->m_consumed);
+ this->built();
+ chain(
+ [src = std::forward<U>(f), cb = std::move(this->m_cb), exor = this->exor(), mask = this->mask()] (address_space &space, offs_t &offset, input_mask_t &mem_mask)
+ {
+ typename Source::input_mask_t source_mask(mem_mask);
+ auto const data(src(space, offset, source_mask));
+ mem_mask = source_mask & mask;
+ return (devcb_read::invoke_transform<input_t, Result>(cb, space, offset, data, mem_mask) ^ exor) & mask;
+ });
+ }
+
+ Source m_src;
+ Func m_cb;
};
- template <typename Dummy> struct set_helper<write8_delegate, Dummy>
+
+ template <typename Func>
+ class functoid_builder : public builder_base, public transform_base<mask_t<read_result_t<Result, Func>, Result>, functoid_builder<Func> >
{
- static constexpr bool valid = true;
- static constexpr callback_type type = CALLBACK_8;
- static void apply(devcb_write_base &devcb, write8_delegate &&delegate) { devcb.m_write8 = std::move(delegate); }
+ public:
+ template <typename T, typename U> friend class transform_builder;
+
+ using output_t = mask_t<read_result_t<Result, Func>, Result>;
+ using input_mask_t = std::make_unsigned_t<Result>;
+
+ template <typename T>
+ functoid_builder(devcb_read &target, bool append, T &&cb)
+ : builder_base(target, append)
+ , transform_base<output_t, functoid_builder>(DefaultMask)
+ , m_cb(std::forward<T>(cb))
+ { }
+ functoid_builder(functoid_builder &&that)
+ : builder_base(std::move(that))
+ , transform_base<output_t, functoid_builder>(std::move(that))
+ , m_cb(std::move(that.m_cb))
+ {
+ that.consume();
+ that.built();
+ }
+ ~functoid_builder() { this->template register_creator<functoid_builder>(); }
+
+ template <typename T>
+ std::enable_if_t<is_transform<output_t, Result, T>::value, transform_builder<functoid_builder, std::remove_reference_t<T> > > transform(T &&cb)
+ {
+ output_t const m(this->mask());
+ if (this->inherited_mask())
+ this->mask(std::make_unsigned_t<read_result_t<Result, Func> >(~std::make_unsigned_t<read_result_t<Result, Func> >(0)));
+ return transform_builder<functoid_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, std::move(*this), std::forward<T>(cb), m);
+ }
+
+ void validity_check(validity_checker &valid) const { }
+
+ template <typename T>
+ void build(T &&chain)
+ {
+ assert(this->m_consumed);
+ this->built();
+ chain(
+ [cb = std::move(this->m_cb), exor = this->exor(), mask = this->mask()] (address_space &space, offs_t offset, input_mask_t mem_mask)
+ { return (devcb_read::invoke_read<Result>(cb, space, offset, mem_mask & mask) ^ exor) & mask; });
+ }
+
+ private:
+ functoid_builder(functoid_builder const &) = delete;
+ functoid_builder &operator=(functoid_builder const &) = delete;
+ functoid_builder &operator=(functoid_builder &&that) = delete;
+
+ Func m_cb;
};
- template <typename Dummy> struct set_helper<write16_delegate, Dummy>
+
+ template <typename Delegate>
+ class delegate_builder : public builder_base, public transform_base<mask_t<read_result_t<Result, Delegate>, Result>, delegate_builder<Delegate> >
{
- static constexpr bool valid = true;
- static constexpr callback_type type = CALLBACK_16;
- static void apply(devcb_write_base &devcb, write16_delegate &&delegate) { devcb.m_write16 = std::move(delegate); }
+ public:
+ template <typename T, typename U> friend class transform_builder;
+
+ using output_t = mask_t<read_result_t<Result, Delegate>, Result>;
+ using input_mask_t = std::make_unsigned_t<Result>;
+
+ template <typename T>
+ delegate_builder(devcb_read &target, bool append, device_t &devbase, char const *tag, T &&func, char const *name)
+ : builder_base(target, append)
+ , transform_base<output_t, delegate_builder>(DefaultMask & delegate_traits<Delegate>::default_mask)
+ , m_devbase(devbase)
+ , m_delegate(std::forward<T>(func), name, tag, std::add_pointer_t<devcb_read::delegate_device_class_t<T> >(nullptr))
+ { }
+ template <typename T>
+ delegate_builder(devcb_read &target, bool append, device_t &devbase, devcb_read::delegate_device_class_t<T> &obj, T &&func, char const *name)
+ : builder_base(target, append)
+ , transform_base<output_t, delegate_builder>(DefaultMask & delegate_traits<Delegate>::default_mask)
+ , m_devbase(devbase)
+ , m_delegate(std::forward<T>(func), name, devcb_read::get_tag(obj), &obj)
+ { }
+ delegate_builder(delegate_builder &&that)
+ : builder_base(std::move(that))
+ , transform_base<output_t, delegate_builder>(std::move(that))
+ , m_devbase(that.m_devbase)
+ , m_delegate(std::move(that.m_delegate))
+ {
+ that.consume();
+ that.built();
+ }
+ ~delegate_builder() { this->template register_creator<delegate_builder>(); }
+
+ template <typename T>
+ std::enable_if_t<is_transform<output_t, Result, T>::value, transform_builder<delegate_builder, std::remove_reference_t<T> > > transform(T &&cb)
+ {
+ output_t const m(this->mask());
+ if (this->inherited_mask())
+ this->mask(delegate_traits<Delegate>::default_mask);
+ return transform_builder<delegate_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, std::move(*this), std::forward<T>(cb), m);
+ }
+
+ void validity_check(validity_checker &valid) const
+ {
+ if (!m_devbase.subdevice(m_delegate.device_name()))
+ osd_printf_error("Read callback bound to non-existent object tag %s (%s)\n", m_delegate.device_name(), m_delegate.name());
+ }
+
+ template <typename T>
+ void build(T &&chain)
+ {
+ assert(this->m_consumed);
+ this->built();
+ m_delegate.bind_relative_to(m_devbase);
+ chain(
+ [cb = std::move(this->m_delegate), exor = this->exor(), mask = this->mask()] (address_space &space, offs_t offset, input_mask_t mem_mask)
+ { return (devcb_read::invoke_read<Result>(cb, space, offset, mem_mask & mask) ^ exor) & mask; });
+ }
+
+ private:
+ delegate_builder(delegate_builder const &) = delete;
+ delegate_builder &operator=(delegate_builder const &) = delete;
+ delegate_builder &operator=(delegate_builder &&that) = delete;
+
+ device_t &m_devbase;
+ Delegate m_delegate;
};
- template <typename Dummy> struct set_helper<write32_delegate, Dummy>
+
+ class ioport_builder : public builder_base, public transform_base<mask_t<ioport_value, Result>, ioport_builder>
{
- static constexpr bool valid = true;
- static constexpr callback_type type = CALLBACK_32;
- static void apply(devcb_write_base &devcb, write32_delegate &&delegate) { devcb.m_write32 = std::move(delegate); }
+ public:
+ template <typename T, typename U> friend class transform_builder;
+
+ using output_t = mask_t<ioport_value, Result>;
+ using input_mask_t = std::make_unsigned_t<Result>;
+
+ ioport_builder(devcb_read &target, bool append, device_t &devbase, std::string &&tag)
+ : builder_base(target, append)
+ , transform_base<output_t, ioport_builder>(DefaultMask)
+ , m_devbase(devbase)
+ , m_tag(std::move(tag))
+ { }
+ ioport_builder(ioport_builder &&that)
+ : builder_base(std::move(that))
+ , transform_base<output_t, ioport_builder>(std::move(that))
+ , m_devbase(that.m_devbase)
+ , m_tag(std::move(that.m_tag))
+ {
+ that.consume();
+ that.built();
+ }
+ ~ioport_builder() { this->template register_creator<ioport_builder>(); }
+
+ template <typename T>
+ std::enable_if_t<is_transform<output_t, Result, T>::value, transform_builder<ioport_builder, std::remove_reference_t<T> > > transform(T &&cb)
+ {
+ output_t const m(this->mask());
+ if (this->inherited_mask())
+ this->mask(std::make_unsigned_t<ioport_value>(~std::make_unsigned_t<ioport_value>(0)));
+ return transform_builder<ioport_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, std::move(*this), std::forward<T>(cb), m);
+ }
+
+ void validity_check(validity_checker &valid) const { }
+
+ template <typename T>
+ void build(T &&chain)
+ {
+ assert(this->m_consumed);
+ this->built();
+ ioport_port *const ioport(m_devbase.ioport(m_tag.c_str()));
+ if (!ioport)
+ throw emu_fatalerror("Read callback bound to non-existent I/O port %s of device %s (%s)\n", m_tag.c_str(), m_devbase.tag(), m_devbase.name());
+ chain(
+ [&port = *ioport, exor = this->exor(), mask = this->mask()] (address_space &space, offs_t offset, input_mask_t mem_mask)
+ { return (port.read() ^ exor) & mask; });
+ }
+
+ private:
+ ioport_builder(ioport_builder const &) = delete;
+ ioport_builder &operator=(ioport_builder const &) = delete;
+ ioport_builder &operator=(ioport_builder &&that) = delete;
+
+ device_t &m_devbase;
+ std::string m_tag;
};
- template <typename Dummy> struct set_helper<write64_delegate, Dummy>
+
+ class binder
{
- static constexpr bool valid = true;
- static constexpr callback_type type = CALLBACK_64;
- static void apply(devcb_write_base &devcb, write64_delegate &&delegate) { devcb.m_write64 = std::move(delegate); }
+ public:
+ binder(devcb_read &target) : m_target(target) { }
+ binder(binder const &) = delete;
+ binder(binder &&that) : m_target(that.m_target), m_append(that.m_append), m_used(that.m_used) { that.m_used = true; }
+ binder &operator=(binder const &) = delete;
+ binder &operator=(binder &&) = delete;
+
+ template <typename T>
+ std::enable_if_t<is_read<Result, T>::value, functoid_builder<std::remove_reference_t<T> > > set(T &&cb)
+ {
+ set_used();
+ return functoid_builder<std::remove_reference_t<T> >(m_target, m_append, std::forward<T>(cb));
+ }
+
+ template <typename T>
+ std::enable_if_t<is_read_method<T>::value, delegate_builder<delegate_type_t<T> > > set(T &&func, char const *name)
+ {
+ set_used();
+ return delegate_builder<delegate_type_t<T> >(m_target, m_append, m_target.owner().mconfig().current_device(), DEVICE_SELF, std::forward<T>(func), name);
+ }
+
+ template <typename T>
+ std::enable_if_t<is_read_method<T>::value, delegate_builder<delegate_type_t<T> > > set(char const *tag, T &&func, char const *name)
+ {
+ set_used();
+ return delegate_builder<delegate_type_t<T> >(m_target, m_append, m_target.owner().mconfig().current_device(), tag, std::forward<T>(func), name);
+ }
+
+ template <typename T, typename U>
+ std::enable_if_t<is_read_method<T>::value, delegate_builder<delegate_type_t<T> > > set(U &obj, T &&func, char const *name)
+ {
+ set_used();
+ return delegate_builder<delegate_type_t<T> >(m_target, m_append, m_target.owner().mconfig().current_device(), devcb_read::cast_reference<delegate_device_class_t<T> >(obj), std::forward<T>(func), name);
+ }
+
+ template <typename T, typename U, bool R>
+ std::enable_if_t<is_read_method<T>::value, delegate_builder<delegate_type_t<T> > > set(device_finder<U, R> &finder, T &&func, char const *name)
+ {
+ set_used();
+ std::pair<device_t &, char const *> const target(finder.finder_target());
+ return delegate_builder<delegate_type_t<T> >(m_target, m_append, target.first, target.second, std::forward<T>(func), name);
+ }
+
+ template <typename T, typename U, bool R>
+ std::enable_if_t<is_read_method<T>::value, delegate_builder<delegate_type_t<T> > > set(device_finder<U, R> const &finder, T &&func, char const *name)
+ {
+ set_used();
+ std::pair<device_t &, char const *> const target(finder.finder_target());
+ return delegate_builder<delegate_type_t<T> >(m_target, m_append, target.first, target.second, std::forward<T>(func), name);
+ }
+
+ template <typename... Params>
+ auto append(Params &&... args)
+ {
+ m_append = true;
+ return set(std::forward<Params>(args)...);
+ }
+
+ template <typename... Params>
+ ioport_builder set_ioport(Params &&... args)
+ {
+ set_used();
+ return ioport_builder(m_target, m_append, m_target.owner().mconfig().current_device(), std::string(std::forward<Params>(args)...));
+ }
+
+ template <bool R>
+ ioport_builder set_ioport(ioport_finder<R> &finder)
+ {
+ set_used();
+ std::pair<device_t &, char const *> const target(finder.finder_target());
+ return ioport_builder(m_target, m_append, target.first, std::string(target.second));
+ }
+
+ template <bool R>
+ ioport_builder set_ioport(ioport_finder<R> const &finder)
+ {
+ set_used();
+ std::pair<device_t &, char const *> const target(finder.finder_target());
+ return ioport_builder(m_target, m_append, target.first, std::string(target.second));
+ }
+
+ template <typename... Params>
+ ioport_builder append_ioport(Params &&... args)
+ {
+ m_append = true;
+ return set_ioport(std::forward<Params>(args)...);
+ }
+
+ template <typename... Params>
+ void set_log(device_t &devbase, Params &&... args)
+ {
+ set_used();
+ if (!m_append)
+ m_target.m_creators.clear();
+ m_target.m_creators.emplace_back(std::make_unique<log_creator>(devbase, std::string(std::forward<Params>(args)...)));
+ }
+
+ template <typename T, typename... Params>
+ std::enable_if_t<emu::detail::is_device_implementation<std::remove_reference_t<T> >::value> set_log(T &devbase, Params &&... args)
+ {
+ set_log(static_cast<device_t &>(devbase), std::forward<Params>(args)...);
+ }
+
+ template <typename T, typename... Params>
+ std::enable_if_t<emu::detail::is_device_interface<std::remove_reference_t<T> >::value> set_log(T &devbase, Params &&... args)
+ {
+ set_log(devbase.device(), std::forward<Params>(args)...);
+ }
+
+ template <typename... Params>
+ void set_log(Params &&... args)
+ {
+ set_log(m_target.owner().mconfig().current_device(), std::forward<Params>(args)...);
+ }
+
+ template <typename... Params>
+ void append_log(Params &&... args)
+ {
+ m_append = true;
+ set_log(std::forward<Params>(args)...);
+ }
+
+ auto set_constant(Result val) { return set([val] () { return val; }); }
+ auto append_constant(Result val) { return append([val] () { return val; }); }
+
+ private:
+ void set_used() { assert(!m_used); m_used = true; }
+
+ devcb_read &m_target;
+ bool m_append = false;
+ bool m_used = false;
};
+ std::vector<func_t> m_functions;
+ std::vector<typename creator::ptr> m_creators;
+
public:
- // callback configuration
- using devcb_base::set_callback;
- template <typename Delegate>
- std::enable_if_t<set_helper<Delegate, void>::valid, devcb_write_base &> set_callback(emu::detail::devcb_delegate_initialiser<Delegate> &&desc)
+ devcb_read(device_t &owner);
+
+ binder bind();
+ void reset();
+
+ // legacy syntax support - will be removed
+ template <typename T, typename U, typename V>
+ devcb_base &set_callback(std::tuple<T, U, V> const &desc)
{
- if (desc.m_base) reset(*desc.m_base, set_helper<Delegate, void>::type);
- else reset(set_helper<Delegate, void>::type);
- set_helper<Delegate, void>::apply(*this, std::move(desc.m_delegate));
+ bind().set(std::forward<T>(std::get<0>(desc)), std::forward<U>(std::get<1>(desc)), std::forward<V>(std::get<2>(desc)));
return *this;
}
- template <callback_type Type> devcb_write_base &set_callback(line_desc<Type> desc)
+ devcb_base &set_callback(DEVCB_IOPORT &&desc) { bind().set_ioport(desc.m_tag); return *this; }
+ template <typename T>
+ devcb_base &set_callback(devcb_constant_t<T> &&desc)
{
- if (desc.m_base) reset(*desc.m_base, Type);
- else reset(Type);
- m_target_tag = desc.m_tag;
- m_target_int = desc.m_inputnum;
+ bind().set_constant(std::move(desc.m_value));
return *this;
}
- template <typename... Params> auto &chain(Params &&... args) { return chain_alloc().set_callback(std::forward<Params>(args)...); }
- devcb_write_base &chain_alloc();
- // resolution
- void resolve();
- void resolve_safe();
+ virtual void validity_check(validity_checker &valid) const override;
- // validity checking
- void validity_check(validity_checker &valid) const;
+ void resolve();
+ void resolve_safe(Result dflt);
-protected:
- // internal helpers
- virtual void devcb_reset() override;
- inline void write(address_space &space, offs_t offset, u64 data, u64 mask);
+ Result operator()(address_space &space, offs_t offset = 0, std::make_unsigned_t<Result> mem_mask = DefaultMask);
+ Result operator()(offs_t offset, std::make_unsigned_t<Result> mem_mask = DefaultMask);
+ Result operator()();
-private:
- // adapters
- void write_unresolved_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
- void write_line_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
- void write8_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
- void write16_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
- void write32_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
- void write64_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
- void write_ioport_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
- void write_membank_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
- void write_output_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
- void write_logged_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
- void write_noop_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
- void write_inputline_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
- void write_assertline_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
- void write_clearline_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
- void write_holdline_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
-
- // configuration
- write_line_delegate m_writeline; // copy of registered line writer
- write8_delegate m_write8; // copy of registered 8-bit writer
- write16_delegate m_write16; // copy of registered 16-bit writer
- write32_delegate m_write32; // copy of registered 32-bit writer
- write64_delegate m_write64; // copy of registered 64-bit writer
-
- // derived state
- typedef void (devcb_write_base::*adapter_func)(address_space &, offs_t, u64, u64);
- adapter_func m_adapter; // actual callback to invoke
- std::unique_ptr<devcb_write_base> m_chain; // next callback for chained output
+ bool isnull() const { return m_functions.empty() && m_creators.empty(); }
+ explicit operator bool() const { return !m_functions.empty(); }
};
+template <typename Result, std::make_unsigned_t<Result> DefaultMask>
+devcb_read<Result, DefaultMask>::devcb_read(device_t &owner)
+ : devcb_read_base(owner)
+{
+}
-// ======================> devcb_read_line
-
-class devcb_read_line : public devcb_read_base
+template <typename Result, std::make_unsigned_t<Result> DefaultMask>
+typename devcb_read<Result, DefaultMask>::binder devcb_read<Result, DefaultMask>::bind()
{
-public:
- devcb_read_line(device_t &device) : devcb_read_base(device, 1) { }
- int operator()() { return read(*m_space, 0, 0xffU) & 1; }
- int operator()(address_space &space) { return read((m_space_tag != nullptr) ? *m_space : space, 0, 0xffU) & 1; }
-};
+ return binder(*this);
+}
+template <typename Result, std::make_unsigned_t<Result> DefaultMask>
+void devcb_read<Result, DefaultMask>::reset()
+{
+ assert(m_functions.empty());
+ m_creators.clear();
+}
-// ======================> devcb_read8
+template <typename Result, std::make_unsigned_t<Result> DefaultMask>
+void devcb_read<Result, DefaultMask>::validity_check(validity_checker &valid) const
+{
+ assert(m_functions.empty());
+ devcb_read_base::validity_check(valid);
+ for (typename std::vector<typename creator::ptr>::const_iterator i = m_creators.begin(); m_creators.end() != i; ++i)
+ {
+ (*i)->validity_check(valid);
+ std::make_unsigned_t<Result> const m((*i)->mask());
+ for (typename std::vector<typename creator::ptr>::const_iterator j = std::next(i); m_creators.end() != j; ++j)
+ {
+ std::make_unsigned_t<Result> const n((*j)->mask());
+ if (m & n)
+ osd_printf_error("Read callback masks %lX and %lX overlap\n", static_cast<unsigned long>(m), static_cast<unsigned long>(n)); // FIXME: doesn't work with u64
+ }
+ }
+}
-class devcb_read8 : public devcb_read_base
+template <typename Result, std::make_unsigned_t<Result> DefaultMask>
+void devcb_read<Result, DefaultMask>::resolve()
{
-public:
- devcb_read8(device_t &device) : devcb_read_base(device, 0xff) { }
- u8 operator()(offs_t offset = 0, u8 mask = 0xff) { return read(*m_space, offset, mask) & mask; }
- u8 operator()(address_space &space, offs_t offset = 0, u8 mask = 0xff) { return read((m_space_tag != nullptr) ? *m_space : space, offset, mask) & mask; }
-};
+ assert(m_functions.empty());
+ devcb_read_base::resolve();
+ m_functions.reserve(m_creators.size());
+ for (typename creator::ptr const &c : m_creators)
+ m_functions.emplace_back(c->create());
+ m_creators.clear();
+}
+template <typename Result, std::make_unsigned_t<Result> DefaultMask>
+void devcb_read<Result, DefaultMask>::resolve_safe(Result dflt)
+{
+ resolve();
+ if (m_functions.empty())
+ m_functions.emplace_back([dflt] (address_space &space, offs_t offset, std::make_unsigned_t<Result> mem_mask) { return dflt; });
+}
-// ======================> devcb_read16
+template <typename Result, std::make_unsigned_t<Result> DefaultMask>
+Result devcb_read<Result, DefaultMask>::operator()(address_space &space, offs_t offset, std::make_unsigned_t<Result> mem_mask)
+{
+ assert(m_creators.empty() && !m_functions.empty());
+ typename std::vector<func_t>::const_iterator it(m_functions.begin());
+ std::make_unsigned_t<Result> result((*it)(space, offset, mem_mask));
+ while (m_functions.end() != ++it)
+ result |= (*it)(space, offset, mem_mask);
+ return result;
+}
-class devcb_read16 : public devcb_read_base
+template <typename Result, std::make_unsigned_t<Result> DefaultMask>
+Result devcb_read<Result, DefaultMask>::operator()(offs_t offset, std::make_unsigned_t<Result> mem_mask)
{
-public:
- devcb_read16(device_t &device) : devcb_read_base(device, 0xffff) { }
- u16 operator()(offs_t offset = 0, u16 mask = 0xffff) { return read(*m_space, offset, mask) & mask; }
- u16 operator()(address_space &space, offs_t offset = 0, u16 mask = 0xffff) { return read((m_space_tag != nullptr) ? *m_space : space, offset, mask) & mask; }
-};
+ return this->operator()(this->default_space(), offset, mem_mask);
+}
+template <typename Result, std::make_unsigned_t<Result> DefaultMask>
+Result devcb_read<Result, DefaultMask>::operator()()
+{
+ return this->operator()(this->default_space(), 0U, DefaultMask);
+}
-// ======================> devcb_read32
-class devcb_read32 : public devcb_read_base
+/// \brief Write callback helper
+///
+/// Allows binding a variety of signatures, sending the value to
+/// multiple callbacks, and chained arbitrary transforms. Transforms
+/// may modify the offset and mask.
+template <typename Input, std::make_unsigned_t<Input> DefaultMask = std::make_unsigned_t<Input>(~std::make_unsigned_t<Input>(0))>
+class devcb_write : public devcb_write_base
{
-public:
- devcb_read32(device_t &device) : devcb_read_base(device, 0xffffffff) { }
- u32 operator()(offs_t offset = 0, u32 mask = 0xffffffff) { return read(*m_space, offset, mask) & mask; }
- u32 operator()(address_space &space, offs_t offset = 0, u32 mask = 0xffffffff) { return read((m_space_tag != nullptr) ? *m_space : space, offset, mask) & mask; }
-};
+private:
+ using func_t = std::function<void (address_space &, offs_t, Input, std::make_unsigned_t<Input>)>;
+ class creator
+ {
+ public:
+ using ptr = std::unique_ptr<creator>;
-// ======================> devcb_read64
+ virtual ~creator() { }
+ virtual void validity_check(validity_checker &valid) const = 0;
+ virtual func_t create() = 0;
+ };
-class devcb_read64 : public devcb_read_base
-{
-public:
- devcb_read64(device_t &device) : devcb_read_base(device, 0xffffffffffffffffU) { }
- u64 operator()(offs_t offset = 0, u64 mask = 0xffffffffffffffffU) { return read(*m_space, offset, mask) & mask; }
- u64 operator()(address_space &space, offs_t offset = 0, u64 mask = 0xffffffffffffffffU) { return read((m_space_tag != nullptr) ? *m_space : space, offset, mask) & mask; }
-};
+ template <typename T>
+ class creator_impl : public creator
+ {
+ public:
+ creator_impl(T &&builder) : m_builder(std::move(builder)) { }
+ virtual void validity_check(validity_checker &valid) const override { m_builder.validity_check(valid); }
-// ======================> devcb_write_line
+ virtual func_t create() override
+ {
+ return [cb = m_builder.build()] (address_space &space, offs_t offset, Input data, std::make_unsigned_t<Input> mem_mask) { cb(space, offset, data, mem_mask); };
+ }
-class devcb_write_line : public devcb_write_base
-{
-public:
- devcb_write_line(device_t &device) : devcb_write_base(device, 1) { }
- void operator()(int state) { write(*m_space, 0, state & 1, 0xffU); }
- void operator()(address_space &space, int state) { write((m_space_tag != nullptr) ? *m_space : space, 0, state & 1, 0xffU); }
-};
+ private:
+ T m_builder;
+ };
+ class nop_creator : public creator
+ {
+ public:
+ virtual void validity_check(validity_checker &valid) const override { }
+ virtual func_t create() override { return [] (address_space &space, offs_t offset, Input data, std::make_unsigned_t<Input> mem_mask) { }; }
+ };
-// ======================> devcb_write8
+ class builder_base
+ {
+ protected:
+ builder_base(devcb_write &target, bool append) : m_target(target), m_append(append) { }
+ builder_base(builder_base const &) = delete;
+ builder_base(builder_base &&) = default;
+ ~builder_base() { assert(m_consumed); }
+ builder_base &operator=(builder_base const &) = delete;
+ builder_base &operator=(builder_base &&) = default;
+
+ void consume() { m_consumed = true; }
+ void built() { assert(!m_built); m_built = true; }
+
+ template <typename T>
+ void register_creator()
+ {
+ if (!m_consumed)
+ {
+ if (!m_append)
+ m_target.m_creators.clear();
+ consume();
+ m_target.m_creators.emplace_back(std::make_unique<creator_impl<T> >(std::move(static_cast<T &>(*this))));
+ }
+ }
+
+ devcb_write &m_target;
+ bool const m_append;
+ bool m_consumed = false;
+ bool m_built = false;
+ };
-class devcb_write8 : public devcb_write_base
-{
-public:
- devcb_write8(device_t &device) : devcb_write_base(device, 0xff) { }
- void operator()(u8 data, u8 mask = 0xff) { write(*m_space, 0, data, mask); }
- void operator()(offs_t offset, u8 data, u8 mask = 0xff) { write(*m_space, offset, data, mask); }
- void operator()(address_space &space, offs_t offset, u8 data, u8 mask = 0xff) { write((m_space_tag != nullptr) ? *m_space : space, offset, data, mask); }
-};
+ template <typename Source, typename Func>
+ class transform_builder : public builder_base, public transform_base<mask_t<transform_result_t<typename Source::output_t, typename Source::output_t, Func>, typename Source::output_t>, transform_builder<Source, Func> >
+ {
+ public:
+ template <typename T, typename U> friend class transform_builder;
+
+ using input_t = typename Source::output_t;
+ using output_t = mask_t<transform_result_t<typename Source::output_t, typename Source::output_t, Func>, typename Source::output_t>;
+
+ template <typename T>
+ transform_builder(devcb_write &target, bool append, Source &&src, T &&cb, output_t mask)
+ : builder_base(target, append)
+ , transform_base<output_t, transform_builder>(mask)
+ , m_src(std::move(src))
+ , m_cb(std::forward<T>(cb))
+ { m_src.consume(); }
+ transform_builder(transform_builder &&that)
+ : builder_base(std::move(that))
+ , transform_base<output_t, transform_builder>(std::move(that))
+ , m_src(std::move(that.m_src))
+ , m_cb(std::move(that.m_cb))
+ {
+ m_src.consume();
+ that.consume();
+ that.built();
+ }
+ ~transform_builder() { this->template register_creator<transform_builder>(); }
+
+ template <typename T>
+ std::enable_if_t<is_transform<output_t, output_t, T>::value, transform_builder<transform_builder, std::remove_reference_t<T> > > transform(T &&cb)
+ {
+ return transform_builder<transform_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, std::move(*this), std::forward<T>(cb), this->mask());
+ }
+
+ auto build()
+ {
+ assert(this->m_consumed);
+ this->built();
+ return m_src.build(
+ [cb = std::move(m_cb), exor = this->exor(), mask = this->mask()] (address_space &space, offs_t &offset, input_t data, std::make_unsigned_t<input_t> &mem_mask)
+ {
+ auto const trans(devcb_write::invoke_transform<input_t, output_t>(cb, space, offset, data, mem_mask));
+ mem_mask &= mask;
+ return (trans ^ exor) & mask;
+ });
+ }
+
+ void validity_check(validity_checker &valid) const { m_src.validity_check(valid); }
+
+ private:
+ transform_builder(transform_builder const &) = delete;
+ transform_builder &operator=(transform_builder const &) = delete;
+ transform_builder &operator=(transform_builder &&that) = delete;
+
+ template <typename T>
+ auto build(T &&chain)
+ {
+ assert(this->m_consumed);
+ this->built();
+ return m_src.build(
+ [f = std::move(chain), cb = std::move(this->m_cb), exor = this->exor(), mask = this->mask()] (address_space &space, offs_t &offset, input_t data, std::make_unsigned_t<input_t> &mem_mask)
+ {
+ auto const trans(devcb_write::invoke_transform<input_t, output_t>(cb, space, offset, data, mem_mask));
+ output_t out_mask(mem_mask & mask);
+ return f(space, offset, (trans ^ exor) & mask, out_mask);
+ });
+ }
+
+ Source m_src;
+ Func m_cb;
+ };
+ template <typename Sink, typename Func>
+ class first_transform_builder : public builder_base, public transform_base<mask_t<transform_result_t<typename Sink::input_t, typename Sink::input_t, Func>, typename Sink::input_t>, first_transform_builder<Sink, Func> >
+ {
+ public:
+ template <typename T, typename U> friend class transform_builder;
+
+ using input_t = typename Sink::input_t;
+ using output_t = mask_t<transform_result_t<typename Sink::input_t, typename Sink::input_t, Func>, typename Sink::input_t>;
+
+ template <typename T>
+ first_transform_builder(devcb_write &target, bool append, Sink &&sink, T &&cb, std::make_unsigned_t<Input> in_exor, std::make_unsigned_t<Input> in_mask)
+ : builder_base(target, append)
+ , transform_base<output_t, first_transform_builder>(DefaultMask)
+ , m_sink(std::move(sink))
+ , m_cb(std::forward<T>(cb))
+ , m_in_exor(in_exor & in_mask)
+ , m_in_mask(in_mask)
+ { m_sink.consume(); }
+ first_transform_builder(first_transform_builder &&that)
+ : builder_base(std::move(that))
+ , transform_base<output_t, first_transform_builder>(std::move(that))
+ , m_sink(std::move(that.m_sink))
+ , m_cb(std::move(that.m_cb))
+ , m_in_exor(that.m_in_exor)
+ , m_in_mask(that.m_in_mask)
+ {
+ m_sink.consume();
+ that.consume();
+ that.built();
+ }
+ ~first_transform_builder() { this->template register_creator<first_transform_builder>(); }
+
+ void validity_check(validity_checker &valid) const { m_sink.validity_check(valid); }
+
+ template <typename T>
+ std::enable_if_t<is_transform<output_t, output_t, T>::value, transform_builder<first_transform_builder, std::remove_reference_t<T> > > transform(T &&cb)
+ {
+ return transform_builder<first_transform_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, std::move(*this), std::forward<T>(cb), this->mask());
+ }
+
+ auto build()
+ {
+ assert(this->m_consumed);
+ this->built();
+ return
+ [sink = m_sink.build(), cb = std::move(this->m_cb), in_exor = m_in_exor, in_mask = m_in_mask, exor = this->exor(), mask = this->mask()] (address_space &space, offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
+ {
+ data = (data ^ in_exor) & in_mask;
+ mem_mask &= in_mask;
+ auto const trans(devcb_write::invoke_transform<input_t, output_t>(cb, space, offset, data, mem_mask));
+ mem_mask &= mask;
+ sink(space, offset, (trans ^ exor) & mask, mem_mask);
+ };
+ }
+
+ private:
+ first_transform_builder(first_transform_builder const &) = delete;
+ first_transform_builder operator=(first_transform_builder const &) = delete;
+ first_transform_builder operator=(first_transform_builder &&that) = delete;
+
+ template <typename T>
+ auto build(T &&chain)
+ {
+ assert(this->m_consumed);
+ this->built();
+ return
+ [f = std::move(chain), sink = m_sink.build(), cb = std::move(this->m_cb), in_exor = m_in_exor, in_mask = m_in_mask, exor = this->exor(), mask = this->mask()] (address_space &space, offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
+ {
+ data = (data ^ in_exor) & in_mask;
+ mem_mask &= in_mask;
+ auto const trans_1(devcb_write::invoke_transform<input_t, output_t>(cb, space, offset, data, mem_mask));
+ output_t out_mask(mem_mask & mask);
+ auto const trans_n(f(space, offset, (trans_1 ^ exor) & mask, out_mask));
+ sink(space, offset, trans_n, out_mask);
+ };
+ }
+
+ Sink m_sink;
+ Func m_cb;
+ std::make_unsigned_t<Input> const m_in_exor, m_in_mask;
+ };
-// ======================> devcb_write16
+ template <typename Func>
+ class functoid_builder : public builder_base, public transform_base<std::make_unsigned_t<Input>, functoid_builder<Func> >
+ {
+ private:
+ class wrapped_builder : public builder_base
+ {
+ public:
+ template <typename T, typename U> friend class first_transform_builder;
+
+ using input_t = Input;
+
+ wrapped_builder(functoid_builder &&that) : builder_base(std::move(that)), m_cb(std::move(that.m_cb)) { that.consume(); that.built(); }
+ wrapped_builder(wrapped_builder &&that) : builder_base(std::move(that)), m_cb(std::move(that.m_cb)) { that.consume(); that.built(); }
+
+ void validity_check(validity_checker &valid) const { }
+
+ auto build()
+ {
+ assert(this->m_consumed);
+ this->built();
+ return
+ [cb = std::move(this->m_cb)] (address_space &space, offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
+ { devcb_write::invoke_write<Input>(cb, space, offset, data, mem_mask); };
+ }
+
+ private:
+ wrapped_builder(wrapped_builder const &) = delete;
+ wrapped_builder operator=(wrapped_builder const &) = delete;
+ wrapped_builder operator=(wrapped_builder &&that) = delete;
+
+ Func m_cb;
+ };
+
+ functoid_builder(functoid_builder const &) = delete;
+ functoid_builder &operator=(functoid_builder const &) = delete;
+ functoid_builder &operator=(functoid_builder &&that) = delete;
+
+ Func m_cb;
+
+ public:
+ using input_t = Input;
+
+ template <typename T>
+ functoid_builder(devcb_write &target, bool append, T &&cb)
+ : builder_base(target, append)
+ , transform_base<std::make_unsigned_t<Input>, functoid_builder>(DefaultMask)
+ , m_cb(std::forward<T>(cb))
+ { }
+ functoid_builder(functoid_builder &&that)
+ : builder_base(std::move(that))
+ , transform_base<std::make_unsigned_t<Input>, functoid_builder>(std::move(that))
+ , m_cb(std::move(that.m_cb))
+ {
+ that.consume();
+ that.built();
+ }
+ ~functoid_builder() { this->template register_creator<functoid_builder>(); }
+
+ template <typename T>
+ std::enable_if_t<is_transform<input_t, input_t, T>::value, first_transform_builder<wrapped_builder, std::remove_reference_t<T> > > transform(T &&cb)
+ {
+ return first_transform_builder<wrapped_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, wrapped_builder(std::move(*this)), std::forward<T>(cb), this->exor(), this->mask());
+ }
+
+ void validity_check(validity_checker &valid) const { }
+
+ auto build()
+ {
+ assert(this->m_consumed);
+ this->built();
+ return
+ [cb = std::move(this->m_cb), exor = this->exor(), mask = this->mask()] (address_space &space, offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
+ { devcb_write::invoke_write<Input>(cb, space, offset, (data ^ exor) & mask, mem_mask & mask); };
+ }
+ };
-class devcb_write16 : public devcb_write_base
-{
-public:
- devcb_write16(device_t &device) : devcb_write_base(device, 0xffff) { }
- void operator()(u16 data, u16 mask = 0xffff) { write(*m_space, 0, data, mask); }
- void operator()(offs_t offset, u16 data, u16 mask = 0xffff) { write(*m_space, offset, data, mask); }
- void operator()(address_space &space, offs_t offset, u16 data, u16 mask = 0xffff) { write((m_space_tag != nullptr) ? *m_space : space, offset, data, mask); }
-};
+ template <typename Delegate>
+ class delegate_builder : public builder_base, public transform_base<mask_t<Input, typename delegate_traits<Delegate>::input_t>, delegate_builder<Delegate> >
+ {
+ private:
+ class wrapped_builder : public builder_base
+ {
+ public:
+ template <typename T, typename U> friend class first_transform_builder;
+
+ using input_t = intermediate_t<Input, typename delegate_traits<Delegate>::input_t>;
+
+ wrapped_builder(delegate_builder &&that)
+ : builder_base(std::move(that))
+ , m_devbase(that.m_devbase)
+ , m_delegate(std::move(that.m_delegate))
+ {
+ that.consume();
+ that.built();
+ }
+ wrapped_builder(wrapped_builder &&that)
+ : builder_base(std::move(that))
+ , m_devbase(that.m_devbase)
+ , m_delegate(std::move(that.m_delegate))
+ {
+ that.consume();
+ that.built();
+ }
+
+ void validity_check(validity_checker &valid) const
+ {
+ if (!m_devbase.subdevice(m_delegate.device_name()))
+ osd_printf_error("Write callback bound to non-existent object tag %s (%s)\n", m_delegate.device_name(), m_delegate.name());
+ }
+
+ auto build()
+ {
+ assert(this->m_consumed);
+ this->built();
+ m_delegate.bind_relative_to(m_devbase);
+ return
+ [cb = std::move(this->m_delegate)] (address_space &space, offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
+ { devcb_write::invoke_write<Input>(cb, space, offset, data, mem_mask); };
+ }
+
+ private:
+ wrapped_builder(wrapped_builder const &) = delete;
+ wrapped_builder operator=(wrapped_builder const &) = delete;
+ wrapped_builder operator=(wrapped_builder &&that) = delete;
+
+ device_t &m_devbase;
+ Delegate m_delegate;
+ };
+
+ delegate_builder(delegate_builder const &) = delete;
+ delegate_builder &operator=(delegate_builder const &) = delete;
+ delegate_builder &operator=(delegate_builder &&that) = delete;
+
+ device_t &m_devbase;
+ Delegate m_delegate;
+
+ public:
+ using input_t = intermediate_t<Input, typename delegate_traits<Delegate>::input_t>;
+
+ template <typename T>
+ delegate_builder(devcb_write &target, bool append, device_t &devbase, char const *tag, T &&func, char const *name)
+ : builder_base(target, append)
+ , transform_base<mask_t<Input, typename delegate_traits<Delegate>::input_t>, delegate_builder>(DefaultMask & delegate_traits<Delegate>::default_mask)
+ , m_devbase(devbase)
+ , m_delegate(std::forward<T>(func), name, tag, std::add_pointer_t<devcb_write::delegate_device_class_t<T> >(nullptr))
+ { }
+ template <typename T>
+ delegate_builder(devcb_write &target, bool append, device_t &devbase, devcb_write::delegate_device_class_t<T> &obj, T &&func, char const *name)
+ : builder_base(target, append)
+ , transform_base<mask_t<Input, typename delegate_traits<Delegate>::input_t>, delegate_builder>(DefaultMask & delegate_traits<Delegate>::default_mask)
+ , m_devbase(devbase)
+ , m_delegate(std::forward<T>(func), name, devcb_write::get_tag(obj), &obj)
+ { }
+ delegate_builder(delegate_builder &&that)
+ : builder_base(std::move(that))
+ , transform_base<mask_t<Input, typename delegate_traits<Delegate>::input_t>, delegate_builder>(std::move(that))
+ , m_devbase(that.m_devbase)
+ , m_delegate(std::move(that.m_delegate))
+ {
+ that.consume();
+ that.built();
+ }
+ ~delegate_builder() { this->template register_creator<delegate_builder>(); }
+
+ template <typename T>
+ std::enable_if_t<is_transform<input_t, input_t, T>::value, first_transform_builder<wrapped_builder, std::remove_reference_t<T> > > transform(T &&cb)
+ {
+ return first_transform_builder<wrapped_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, wrapped_builder(std::move(*this)), std::forward<T>(cb), this->exor(), this->mask());
+ }
+
+ void validity_check(validity_checker &valid) const
+ {
+ if (!m_devbase.subdevice(m_delegate.device_name()))
+ osd_printf_error("Write callback bound to non-existent object tag %s (%s)\n", m_delegate.device_name(), m_delegate.name());
+ }
+
+ auto build()
+ {
+ assert(this->m_consumed);
+ this->built();
+ m_delegate.bind_relative_to(m_devbase);
+ return
+ [cb = std::move(this->m_delegate), exor = this->exor(), mask = this->mask()] (address_space &space, offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
+ { devcb_write::invoke_write<Input>(cb, space, offset, (data ^ exor) & mask, mem_mask & mask); };
+ }
+ };
+ class inputline_builder : public builder_base, public transform_base<mask_t<Input, int>, inputline_builder>
+ {
+ private:
+ class wrapped_builder : public builder_base
+ {
+ public:
+ template <typename T, typename U> friend class first_transform_builder;
+
+ using input_t = intermediate_t<Input, int>;
+
+ wrapped_builder(inputline_builder &&that)
+ : builder_base(std::move(that))
+ , m_devbase(that.m_devbase)
+ , m_tag(that.m_tag)
+ , m_exec(that.m_exec)
+ , m_linenum(that.m_linenum)
+ {
+ that.consume();
+ that.built();
+ }
+ wrapped_builder(wrapped_builder &&that)
+ : builder_base(std::move(that))
+ , m_devbase(that.m_devbase)
+ , m_tag(that.m_tag)
+ , m_exec(that.m_exec)
+ , m_linenum(that.m_linenum)
+ {
+ that.consume();
+ that.built();
+ }
+
+ void validity_check(validity_checker &valid) const
+ {
+ if (!m_exec)
+ {
+ device_t *const device(m_devbase.subdevice(m_tag));
+ if (!device)
+ osd_printf_error("Write callback bound to non-existent object tag %s\n", m_tag);
+ else if (!dynamic_cast<device_execute_interface *>(device))
+ osd_printf_error("Write callback bound to device %s (%s) that does not implement device_execute_interface\n", device->tag(), device->name());
+ }
+ }
+
+ auto build()
+ {
+ assert(this->m_consumed);
+ this->built();
+ if (!m_exec)
+ {
+ device_t *const device(m_devbase.subdevice(m_tag));
+ if (!device)
+ throw emu_fatalerror("Write callback bound to non-existent object tag %s\n", m_tag);
+ m_exec = dynamic_cast<device_execute_interface *>(device);
+ if (!m_exec)
+ throw emu_fatalerror("Write callback bound to device %s (%s) that does not implement device_execute_interface\n", device->tag(), device->name());
+ }
+ return
+ [&exec = *m_exec, linenum = m_linenum] (address_space &space, offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
+ { exec.set_input_line(linenum, data); };
+ }
+
+ private:
+ wrapped_builder(wrapped_builder const &) = delete;
+ wrapped_builder operator=(wrapped_builder const &) = delete;
+ wrapped_builder operator=(wrapped_builder &&that) = delete;
+
+ device_t &m_devbase;
+ char const *const m_tag;
+ device_execute_interface *m_exec;
+ int const m_linenum;
+ };
+
+ inputline_builder(inputline_builder const &) = delete;
+ inputline_builder &operator=(inputline_builder const &) = delete;
+ inputline_builder &operator=(inputline_builder &&that) = delete;
+
+ device_t &m_devbase;
+ char const *const m_tag;
+ device_execute_interface *m_exec;
+ int const m_linenum;
+
+ public:
+ using input_t = intermediate_t<Input, int>;
+
+ inputline_builder(devcb_write &target, bool append, device_t &devbase, char const *tag, int linenum)
+ : builder_base(target, append)
+ , transform_base<mask_t<Input, int>, inputline_builder>(1U)
+ , m_devbase(devbase)
+ , m_tag(tag)
+ , m_exec(nullptr)
+ , m_linenum(linenum)
+ { }
+ inputline_builder(devcb_write &target, bool append, device_execute_interface &exec, int linenum)
+ : builder_base(target, append)
+ , transform_base<mask_t<Input, int>, inputline_builder>(1U)
+ , m_devbase(exec.device())
+ , m_tag(exec.device().tag())
+ , m_exec(&exec)
+ , m_linenum(linenum)
+ { }
+ inputline_builder(inputline_builder &&that)
+ : builder_base(std::move(that))
+ , transform_base<mask_t<Input, int>, inputline_builder>(std::move(that))
+ , m_devbase(that.m_devbase)
+ , m_tag(that.m_tag)
+ , m_exec(that.m_exec)
+ , m_linenum(that.m_linenum)
+ {
+ that.consume();
+ that.built();
+ }
+ ~inputline_builder() { this->template register_creator<inputline_builder>(); }
+
+ template <typename T>
+ std::enable_if_t<is_transform<input_t, input_t, T>::value, first_transform_builder<wrapped_builder, std::remove_reference_t<T> > > transform(T &&cb)
+ {
+ first_transform_builder<wrapped_builder, std::remove_reference_t<T> > result(this->m_target, this->m_append, wrapped_builder(std::move(*this)), std::forward<T>(cb), this->exor(), this->inherited_mask() ? DefaultMask : this->mask());
+ result.mask(1);
+ return std::move(result);
+ }
+
+ void validity_check(validity_checker &valid) const
+ {
+ if (!m_exec)
+ {
+ device_t *const device(m_devbase.subdevice(m_tag));
+ if (!device)
+ osd_printf_error("Write callback bound to non-existent object tag %s\n", m_tag);
+ else if (!dynamic_cast<device_execute_interface *>(device))
+ osd_printf_error("Write callback bound to device %s (%s) that does not implement device_execute_interface\n", device->tag(), device->name());
+ }
+ }
+
+ auto build()
+ {
+ assert(this->m_consumed);
+ this->built();
+ if (!m_exec)
+ {
+ device_t *const device(m_devbase.subdevice(m_tag));
+ if (!device)
+ throw emu_fatalerror("Write callback bound to non-existent object tag %s\n", m_tag);
+ m_exec = dynamic_cast<device_execute_interface *>(device);
+ if (!m_exec)
+ throw emu_fatalerror("Write callback bound to device %s (%s) that does not implement device_execute_interface\n", device->tag(), device->name());
+ }
+ return
+ [&exec = *m_exec, linenum = m_linenum, exor = this->exor(), mask = this->mask()] (address_space &space, offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
+ { exec.set_input_line(linenum, (data ^ exor) & mask); };
+ }
+ };
-// ======================> devcb_write32
+ class latched_inputline_builder : public builder_base, public transform_base<std::make_unsigned_t<Input>, latched_inputline_builder>
+ {
+ private:
+ class wrapped_builder : public builder_base
+ {
+ public:
+ template <typename T, typename U> friend class first_transform_builder;
+
+ using input_t = Input;
+
+ wrapped_builder(latched_inputline_builder &&that)
+ : builder_base(std::move(that))
+ , m_devbase(that.m_devbase)
+ , m_tag(that.m_tag)
+ , m_exec(that.m_exec)
+ , m_linenum(that.m_linenum)
+ , m_value(that.m_value)
+ {
+ that.consume();
+ that.built();
+ }
+ wrapped_builder(wrapped_builder &&that)
+ : builder_base(std::move(that))
+ , m_devbase(that.m_devbase)
+ , m_tag(that.m_tag)
+ , m_exec(that.m_exec)
+ , m_linenum(that.m_linenum)
+ , m_value(that.m_value)
+ {
+ that.consume();
+ that.built();
+ }
+
+ void validity_check(validity_checker &valid) const
+ {
+ if (!m_exec)
+ {
+ device_t *const device(m_devbase.subdevice(m_tag));
+ if (!device)
+ osd_printf_error("Write callback bound to non-existent object tag %s\n", m_tag);
+ else if (!dynamic_cast<device_execute_interface *>(device))
+ osd_printf_error("Write callback bound to device %s (%s) that does not implement device_execute_interface\n", device->tag(), device->name());
+ }
+ }
+
+ auto build()
+ {
+ assert(this->m_consumed);
+ this->built();
+ if (!m_exec)
+ {
+ device_t *const device(m_devbase.subdevice(m_tag));
+ if (!device)
+ throw emu_fatalerror("Write callback bound to non-existent object tag %s\n", m_tag);
+ m_exec = dynamic_cast<device_execute_interface *>(device);
+ if (!m_exec)
+ throw emu_fatalerror("Write callback bound to device %s (%s) that does not implement device_execute_interface\n", device->tag(), device->name());
+ }
+ return
+ [&exec = *m_exec, linenum = m_linenum, value = m_value] (address_space &space, offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
+ { if (data) exec.set_input_line(linenum, value); };
+ }
+
+ private:
+ wrapped_builder(wrapped_builder const &) = delete;
+ wrapped_builder operator=(wrapped_builder const &) = delete;
+ wrapped_builder operator=(wrapped_builder &&that) = delete;
+
+ device_t &m_devbase;
+ char const *const m_tag;
+ device_execute_interface *m_exec;
+ int const m_linenum;
+ int const m_value;
+ };
+
+ latched_inputline_builder(latched_inputline_builder const &) = delete;
+ latched_inputline_builder &operator=(latched_inputline_builder const &) = delete;
+ latched_inputline_builder &operator=(latched_inputline_builder &&that) = delete;
+
+ device_t &m_devbase;
+ char const *const m_tag;
+ device_execute_interface *m_exec;
+ int const m_linenum;
+ int const m_value;
+
+ public:
+ using input_t = Input;
+
+ latched_inputline_builder(devcb_write &target, bool append, device_t &devbase, char const *tag, int linenum, int value)
+ : builder_base(target, append)
+ , transform_base<std::make_unsigned_t<Input>, latched_inputline_builder>(DefaultMask)
+ , m_devbase(devbase)
+ , m_tag(tag)
+ , m_exec(nullptr)
+ , m_linenum(linenum)
+ , m_value(value)
+ { }
+ latched_inputline_builder(devcb_write &target, bool append, device_execute_interface &exec, int linenum, int value)
+ : builder_base(target, append)
+ , transform_base<std::make_unsigned_t<Input>, latched_inputline_builder>(DefaultMask)
+ , m_devbase(exec.device())
+ , m_tag(exec.device().tag())
+ , m_exec(&exec)
+ , m_linenum(linenum)
+ , m_value(value)
+ { }
+ latched_inputline_builder(latched_inputline_builder &&that)
+ : builder_base(std::move(that))
+ , transform_base<std::make_unsigned_t<Input>, latched_inputline_builder>(std::move(that))
+ , m_devbase(that.m_devbase)
+ , m_tag(that.m_tag)
+ , m_exec(that.m_exec)
+ , m_linenum(that.m_linenum)
+ , m_value(that.m_value)
+ {
+ that.consume();
+ that.built();
+ }
+ ~latched_inputline_builder() { this->template register_creator<latched_inputline_builder>(); }
+
+ template <typename T>
+ std::enable_if_t<is_transform<input_t, input_t, T>::value, first_transform_builder<wrapped_builder, std::remove_reference_t<T> > > transform(T &&cb)
+ {
+ return first_transform_builder<wrapped_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, wrapped_builder(std::move(*this)), std::forward<T>(cb), this->exor(), this->inherited_mask() ? DefaultMask : this->mask());
+ }
+
+ void validity_check(validity_checker &valid) const
+ {
+ if (!m_exec)
+ {
+ device_t *const device(m_devbase.subdevice(m_tag));
+ if (!device)
+ osd_printf_error("Write callback bound to non-existent object tag %s\n", m_tag);
+ else if (!dynamic_cast<device_execute_interface *>(device))
+ osd_printf_error("Write callback bound to device %s (%s) that does not implement device_execute_interface\n", device->tag(), device->name());
+ }
+ }
+
+ auto build()
+ {
+ assert(this->m_consumed);
+ this->built();
+ if (!m_exec)
+ {
+ device_t *const device(m_devbase.subdevice(m_tag));
+ if (!device)
+ throw emu_fatalerror("Write callback bound to non-existent object tag %s\n", m_tag);
+ m_exec = dynamic_cast<device_execute_interface *>(device);
+ if (!m_exec)
+ throw emu_fatalerror("Write callback bound to device %s (%s) that does not implement device_execute_interface\n", device->tag(), device->name());
+ }
+ return
+ [&exec = *m_exec, linenum = m_linenum, value = m_value, exor = this->exor(), mask = this->mask()] (address_space &space, offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
+ { if ((data ^ exor) & mask) exec.set_input_line(linenum, value); };
+ }
+ };
-class devcb_write32 : public devcb_write_base
-{
-public:
- devcb_write32(device_t &device) : devcb_write_base(device, 0xffffffff) { }
- void operator()(u32 data, u32 mask = 0xffffffff) { write(*m_space, 0, data, mask); }
- void operator()(offs_t offset, u32 data, u32 mask = 0xffffffff) { write(*m_space, offset, data, mask); }
- void operator()(address_space &space, offs_t offset, u32 data, u32 mask = 0xffffffff) { write((m_space_tag != nullptr) ? *m_space : space, offset, data, mask); }
-};
+ class ioport_builder : public builder_base, public transform_base<mask_t<Input, ioport_value>, ioport_builder>
+ {
+ private:
+ class wrapped_builder : public builder_base
+ {
+ public:
+ template <typename T, typename U> friend class first_transform_builder;
+
+ using input_t = intermediate_t<Input, ioport_value>;
+
+ wrapped_builder(ioport_builder &&that)
+ : builder_base(std::move(that))
+ , m_devbase(that.m_devbase)
+ , m_tag(std::move(that.m_tag))
+ {
+ that.consume();
+ that.built();
+ }
+ wrapped_builder(wrapped_builder &&that)
+ : builder_base(std::move(that))
+ , m_devbase(that.m_devbase)
+ , m_tag(std::move(that.m_tag))
+ {
+ that.consume();
+ that.built();
+ }
+
+ void validity_check(validity_checker &valid) const { }
+
+ auto build()
+ {
+ assert(this->m_consumed);
+ this->built();
+ ioport_port *const ioport(m_devbase.ioport(m_tag.c_str()));
+ if (!ioport)
+ throw emu_fatalerror("Write callback bound to non-existent I/O port %s of device %s (%s)\n", m_tag.c_str(), m_devbase.tag(), m_devbase.name());
+ return
+ [&port = *ioport] (address_space &space, offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
+ { port.write(data); };
+ }
+
+ private:
+ wrapped_builder(wrapped_builder const &) = delete;
+ wrapped_builder operator=(wrapped_builder const &) = delete;
+ wrapped_builder operator=(wrapped_builder &&that) = delete;
+
+ device_t &m_devbase;
+ std::string m_tag;
+ };
+
+ ioport_builder(ioport_builder const &) = delete;
+ ioport_builder &operator=(ioport_builder const &) = delete;
+ ioport_builder &operator=(ioport_builder &&that) = delete;
+
+ device_t &m_devbase;
+ std::string m_tag;
+
+ public:
+ using input_t = intermediate_t<Input, ioport_value>;
+
+ ioport_builder(devcb_write &target, bool append, device_t &devbase, std::string &&tag)
+ : builder_base(target, append)
+ , transform_base<mask_t<Input, ioport_value>, ioport_builder>(DefaultMask)
+ , m_devbase(devbase)
+ , m_tag(std::move(tag))
+ { }
+ ioport_builder(ioport_builder &&that)
+ : builder_base(std::move(that))
+ , transform_base<mask_t<Input, ioport_value>, ioport_builder>(std::move(that))
+ , m_devbase(that.m_devbase)
+ , m_tag(std::move(that.m_tag))
+ {
+ that.consume();
+ that.built();
+ }
+ ~ioport_builder() { this->template register_creator<ioport_builder>(); }
+
+ template <typename T>
+ std::enable_if_t<is_transform<input_t, input_t, T>::value, first_transform_builder<wrapped_builder, std::remove_reference_t<T> > > transform(T &&cb)
+ {
+ return first_transform_builder<wrapped_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, wrapped_builder(std::move(*this)), std::forward<T>(cb), this->exor(), this->mask());
+ }
+
+ void validity_check(validity_checker &valid) const { }
+
+ auto build()
+ {
+ assert(this->m_consumed);
+ this->built();
+ ioport_port *const ioport(m_devbase.ioport(m_tag.c_str()));
+ if (!ioport)
+ throw emu_fatalerror("Write callback bound to non-existent I/O port %s of device %s (%s)\n", m_tag.c_str(), m_devbase.tag(), m_devbase.name());
+ return
+ [&port = *ioport, exor = this->exor(), mask = this->mask()] (address_space &space, offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
+ { port.write((data ^ exor) & mask); };
+ }
+ };
+ class membank_builder : public builder_base, public transform_base<mask_t<Input, int>, membank_builder>
+ {
+ private:
+ class wrapped_builder : public builder_base
+ {
+ public:
+ template <typename T, typename U> friend class first_transform_builder;
+
+ using input_t = intermediate_t<Input, int>;
+
+ wrapped_builder(membank_builder &&that)
+ : builder_base(std::move(that))
+ , m_devbase(that.m_devbase)
+ , m_tag(std::move(that.m_tag))
+ {
+ that.consume();
+ that.built();
+ }
+ wrapped_builder(wrapped_builder &&that)
+ : builder_base(std::move(that))
+ , m_devbase(that.m_devbase)
+ , m_tag(std::move(that.m_tag))
+ {
+ that.consume();
+ that.built();
+ }
+
+ void validity_check(validity_checker &valid) const { }
+
+ auto build()
+ {
+ assert(this->m_consumed);
+ this->built();
+ memory_bank *const bank(m_devbase.membank(m_tag.c_str()));
+ if (!bank)
+ throw emu_fatalerror("Write callback bound to non-existent memory bank %s of device %s (%s)\n", m_tag.c_str(), m_devbase.tag(), m_devbase.name());
+ return
+ [&membank = *bank] (address_space &space, offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
+ { membank.set_entry(data); };
+ }
+
+ private:
+ wrapped_builder(wrapped_builder const &) = delete;
+ wrapped_builder operator=(wrapped_builder const &) = delete;
+ wrapped_builder operator=(wrapped_builder &&that) = delete;
+
+ device_t &m_devbase;
+ std::string m_tag;
+ };
+
+ membank_builder(membank_builder const &) = delete;
+ membank_builder &operator=(membank_builder const &) = delete;
+ membank_builder &operator=(membank_builder &&that) = delete;
+
+ device_t &m_devbase;
+ std::string m_tag;
+
+ public:
+ using input_t = intermediate_t<Input, int>;
+
+ membank_builder(devcb_write &target, bool append, device_t &devbase, std::string &&tag)
+ : builder_base(target, append)
+ , transform_base<mask_t<Input, int>, membank_builder>(DefaultMask)
+ , m_devbase(devbase)
+ , m_tag(std::move(tag))
+ { }
+ membank_builder(membank_builder &&that)
+ : builder_base(std::move(that))
+ , transform_base<mask_t<Input, int>, membank_builder>(std::move(that))
+ , m_devbase(that.m_devbase)
+ , m_tag(std::move(that.m_tag))
+ {
+ that.consume();
+ that.built();
+ }
+ ~membank_builder() { this->template register_creator<membank_builder>(); }
+
+ template <typename T>
+ std::enable_if_t<is_transform<input_t, input_t, T>::value, first_transform_builder<wrapped_builder, std::remove_reference_t<T> > > transform(T &&cb)
+ {
+ return first_transform_builder<wrapped_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, wrapped_builder(std::move(*this)), std::forward<T>(cb), this->exor(), this->mask());
+ }
+
+ void validity_check(validity_checker &valid) const { }
+
+ auto build()
+ {
+ assert(this->m_consumed);
+ this->built();
+ memory_bank *const bank(m_devbase.membank(m_tag.c_str()));
+ if (!bank)
+ throw emu_fatalerror("Write callback bound to non-existent memory bank %s of device %s (%s)\n", m_tag.c_str(), m_devbase.tag(), m_devbase.name());
+ return
+ [&membank = *bank, exor = this->exor(), mask = this->mask()] (address_space &space, offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
+ { membank.set_entry((data ^ exor) & mask); };
+ }
+ };
-// ======================> devcb_write64
+ class output_builder : public builder_base, public transform_base<mask_t<Input, s32>, output_builder>
+ {
+ private:
+ class wrapped_builder : public builder_base
+ {
+ public:
+ template <typename T, typename U> friend class first_transform_builder;
+
+ using input_t = intermediate_t<Input, s32>;
+
+ wrapped_builder(output_builder &&that)
+ : builder_base(std::move(that))
+ , m_devbase(that.m_devbase)
+ , m_tag(std::move(that.m_tag))
+ {
+ that.consume();
+ that.built();
+ }
+ wrapped_builder(wrapped_builder &&that)
+ : builder_base(std::move(that))
+ , m_devbase(that.m_devbase)
+ , m_tag(std::move(that.m_tag))
+ {
+ that.consume();
+ that.built();
+ }
+
+ void validity_check(validity_checker &valid) const { }
+
+ auto build()
+ {
+ assert(this->m_consumed);
+ this->built();
+ return
+ [&item = m_devbase.machine().output().find_or_create_item(m_tag.c_str(), 0)] (address_space &space, offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
+ { item.set(data); };
+ }
+
+ private:
+ wrapped_builder(wrapped_builder const &) = delete;
+ wrapped_builder operator=(wrapped_builder const &) = delete;
+ wrapped_builder operator=(wrapped_builder &&that) = delete;
+
+ device_t &m_devbase;
+ std::string m_tag;
+ };
+
+ output_builder(output_builder const &) = delete;
+ output_builder &operator=(output_builder const &) = delete;
+ output_builder &operator=(output_builder &&that) = delete;
+
+ device_t &m_devbase;
+ std::string m_tag;
+
+ public:
+ using input_t = intermediate_t<Input, s32>;
+
+ output_builder(devcb_write &target, bool append, device_t &devbase, std::string &&tag)
+ : builder_base(target, append)
+ , transform_base<mask_t<Input, s32>, output_builder>(DefaultMask)
+ , m_devbase(devbase)
+ , m_tag(std::move(tag))
+ { }
+ output_builder(output_builder &&that)
+ : builder_base(std::move(that))
+ , transform_base<mask_t<Input, s32>, output_builder>(std::move(that))
+ , m_devbase(that.m_devbase)
+ , m_tag(std::move(that.m_tag))
+ {
+ that.consume();
+ that.built();
+ }
+ ~output_builder() { this->template register_creator<output_builder>(); }
+
+ template <typename T>
+ std::enable_if_t<is_transform<input_t, input_t, T>::value, first_transform_builder<wrapped_builder, std::remove_reference_t<T> > > transform(T &&cb)
+ {
+ return first_transform_builder<wrapped_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, wrapped_builder(std::move(*this)), std::forward<T>(cb), this->exor(), this->mask());
+ }
+
+ void validity_check(validity_checker &valid) const { }
+
+ auto build()
+ {
+ assert(this->m_consumed);
+ this->built();
+ return
+ [&item = m_devbase.machine().output().find_or_create_item(m_tag.c_str(), 0), exor = this->exor(), mask = this->mask()] (address_space &space, offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
+ { item.set((data ^ exor) & mask); };
+ }
+ };
+
+ class log_builder : public builder_base, public transform_base<std::make_unsigned_t<Input>, log_builder>
+ {
+ private:
+ class wrapped_builder : public builder_base
+ {
+ public:
+ template <typename T, typename U> friend class first_transform_builder;
+
+ using input_t = Input;
+
+ wrapped_builder(log_builder &&that)
+ : builder_base(std::move(that))
+ , m_devbase(that.m_devbase)
+ , m_message(std::move(that.m_message))
+ {
+ that.consume();
+ that.built();
+ }
+ wrapped_builder(wrapped_builder &&that)
+ : builder_base(std::move(that))
+ , m_devbase(that.m_devbase)
+ , m_message(std::move(that.m_message))
+ {
+ that.consume();
+ that.built();
+ }
+
+ void validity_check(validity_checker &valid) const { }
+
+ auto build()
+ {
+ assert(this->m_consumed);
+ this->built();
+ return
+ [&devbase = m_devbase, message = std::move(m_message)] (address_space &space, offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
+ { if (data) devbase.logerror("%s: %s\n", devbase.machine().describe_context(), message); };
+ }
+
+ private:
+ wrapped_builder(wrapped_builder const &) = delete;
+ wrapped_builder operator=(wrapped_builder const &) = delete;
+ wrapped_builder operator=(wrapped_builder &&that) = delete;
+
+ device_t &m_devbase;
+ std::string m_message;
+ };
+
+ log_builder(log_builder const &) = delete;
+ log_builder &operator=(log_builder const &) = delete;
+ log_builder &operator=(log_builder &&that) = delete;
+
+ device_t &m_devbase;
+ std::string m_message;
+
+ public:
+ using input_t = Input;
+
+ log_builder(devcb_write &target, bool append, device_t &devbase, std::string &&message)
+ : builder_base(target, append)
+ , transform_base<std::make_unsigned_t<Input>, log_builder>(DefaultMask)
+ , m_devbase(devbase)
+ , m_message(std::move(message))
+ { }
+ log_builder(log_builder &&that)
+ : builder_base(std::move(that))
+ , transform_base<std::make_unsigned_t<Input>, log_builder>(std::move(that))
+ , m_devbase(that.m_devbase)
+ , m_message(std::move(that.m_message))
+ {
+ that.consume();
+ that.built();
+ }
+ ~log_builder() { this->template register_creator<log_builder>(); }
+
+ template <typename T>
+ std::enable_if_t<is_transform<input_t, input_t, T>::value, first_transform_builder<wrapped_builder, std::remove_reference_t<T> > > transform(T &&cb)
+ {
+ return first_transform_builder<wrapped_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, wrapped_builder(std::move(*this)), std::forward<T>(cb), this->exor(), this->inherited_mask() ? DefaultMask : this->mask());
+ }
+
+ void validity_check(validity_checker &valid) const { }
+
+ auto build()
+ {
+ assert(this->m_consumed);
+ this->built();
+ return
+ [&devbase = m_devbase, message = std::move(m_message), exor = this->exor(), mask = this->mask()] (address_space &space, offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
+ { if ((data ^ exor) & mask) devbase.logerror("%s: %s\n", devbase.machine().describe_context(), message); };
+ }
+ };
+ class binder
+ {
+ public:
+ binder(devcb_write &target) : m_target(target) { }
+ binder(binder const &) = delete;
+ binder(binder &&that) : m_target(that.m_target), m_append(that.m_append), m_used(that.m_used) { that.m_used = true; }
+ binder &operator=(binder const &) = delete;
+ binder &operator=(binder &&) = delete;
+
+ template <typename T>
+ std::enable_if_t<is_write<Input, T>::value, functoid_builder<std::remove_reference_t<T> > > set(T &&cb)
+ {
+ set_used();
+ return functoid_builder<std::remove_reference_t<T> >(m_target, m_append, std::forward<T>(cb));
+ }
+
+ template <typename T>
+ std::enable_if_t<is_write_method<T>::value, delegate_builder<delegate_type_t<T> > > set(T &&func, char const *name)
+ {
+ set_used();
+ return delegate_builder<delegate_type_t<T> >(m_target, m_append, m_target.owner().mconfig().current_device(), DEVICE_SELF, std::forward<T>(func), name);
+ }
+
+ template <typename T>
+ std::enable_if_t<is_write_method<T>::value, delegate_builder<delegate_type_t<T> > > set(char const *tag, T &&func, char const *name)
+ {
+ set_used();
+ return delegate_builder<delegate_type_t<T> >(m_target, m_append, m_target.owner().mconfig().current_device(), tag, std::forward<T>(func), name);
+ }
+
+ template <typename T, typename U>
+ std::enable_if_t<is_write_method<T>::value, delegate_builder<delegate_type_t<T> > > set(U &obj, T &&func, char const *name)
+ {
+ set_used();
+ return delegate_builder<delegate_type_t<T> >(m_target, m_append, m_target.owner().mconfig().current_device(), devcb_write::cast_reference<delegate_device_class_t<T> >(obj), std::forward<T>(func), name);
+ }
+
+ template <typename T, typename U, bool R>
+ std::enable_if_t<is_write_method<T>::value, delegate_builder<delegate_type_t<T> > > set(device_finder<U, R> &finder, T &&func, char const *name)
+ {
+ set_used();
+ std::pair<device_t &, char const *> const target(finder.finder_target());
+ return delegate_builder<delegate_type_t<T> >(m_target, m_append, target.first, target.second, std::forward<T>(func), name);
+ }
+
+ template <typename T, typename U, bool R>
+ std::enable_if_t<is_write_method<T>::value, delegate_builder<delegate_type_t<T> > > set(device_finder<U, R> const &finder, T &&func, char const *name)
+ {
+ set_used();
+ std::pair<device_t &, char const *> const target(finder.finder_target());
+ return delegate_builder<delegate_type_t<T> >(m_target, m_append, target.first, target.second, std::forward<T>(func), name);
+ }
+
+ template <typename... Params>
+ auto append(Params &&... args)
+ {
+ m_append = true;
+ return set(std::forward<Params>(args)...);
+ }
+
+ inputline_builder set_inputline(char const *tag, int linenum)
+ {
+ set_used();
+ return inputline_builder(m_target, m_append, m_target.owner().mconfig().current_device(), tag, linenum);
+ }
+
+ latched_inputline_builder set_inputline(char const *tag, int linenum, int value)
+ {
+ set_used();
+ return latched_inputline_builder(m_target, m_append, m_target.owner().mconfig().current_device(), tag, linenum, value);
+ }
+
+ inputline_builder set_inputline(device_execute_interface &obj, int linenum)
+ {
+ set_used();
+ return inputline_builder(m_target, m_append, obj, linenum);
+ }
+
+ latched_inputline_builder set_inputline(device_execute_interface &obj, int linenum, int value)
+ {
+ set_used();
+ return latched_inputline_builder(m_target, m_append, obj, linenum, value);
+ }
+
+ template <typename T, bool R>
+ inputline_builder set_inputline(device_finder<T, R> const &finder, int linenum)
+ {
+ set_used();
+ std::pair<device_t &, char const *> const target(finder.finder_target());
+ return inputline_builder(m_target, m_append, target.first, target.second, linenum);
+ }
+
+ template <typename T, bool R>
+ latched_inputline_builder set_inputline(device_finder<T, R> const &finder, int linenum, int value)
+ {
+ set_used();
+ std::pair<device_t &, char const *> const target(finder.finder_target());
+ return latched_inputline_builder(m_target, m_append, target.first, target.second, linenum, value);
+ }
+
+ template <typename... Params>
+ auto append_inputline(Params &&... args)
+ {
+ m_append = true;
+ return set_inputline(std::forward<Params>(args)...);
+ }
+
+ template <typename... Params>
+ ioport_builder set_ioport(Params &&... args)
+ {
+ set_used();
+ return ioport_builder(m_target, m_append, m_target.owner().mconfig().current_device(), std::string(std::forward<Params>(args)...));
+ }
+
+ template <bool R>
+ ioport_builder set_ioport(ioport_finder<R> &finder)
+ {
+ set_used();
+ std::pair<device_t &, char const *> const target(finder.finder_target());
+ return ioport_builder(m_target, m_append, target.first, std::string(target.second));
+ }
+
+ template <bool R>
+ ioport_builder set_ioport(ioport_finder<R> const &finder)
+ {
+ set_used();
+ std::pair<device_t &, char const *> const target(finder.finder_target());
+ return ioport_builder(m_target, m_append, target.first, std::string(target.second));
+ }
+
+ template <typename... Params>
+ ioport_builder append_ioport(Params &&... args)
+ {
+ m_append = true;
+ return set_ioport(std::forward<Params>(args)...);
+ }
+
+ template <typename... Params>
+ membank_builder set_membank(Params &&... args)
+ {
+ set_used();
+ return membank_builder(m_target, m_append, m_target.owner().mconfig().current_device(), std::string(std::forward<Params>(args)...));
+ }
+
+ template <bool R>
+ membank_builder set_membank(memory_bank_finder<R> &finder)
+ {
+ set_used();
+ std::pair<device_t &, char const *> const target(finder.finder_target());
+ return membank_builder(m_target, m_append, target.first, std::string(target.second));
+ }
+
+ template <bool R>
+ membank_builder set_membank(memory_bank_finder<R> const &finder)
+ {
+ set_used();
+ std::pair<device_t &, char const *> const target(finder.finder_target());
+ return membank_builder(m_target, m_append, target.first, std::string(target.second));
+ }
+
+ template <typename... Params>
+ membank_builder append_membank(Params &&... args)
+ {
+ m_append = true;
+ return set_membank(std::forward<Params>(args)...);
+ }
+
+ template <typename... Params>
+ output_builder set_output(Params &&... args)
+ {
+ set_used();
+ return output_builder(m_target, m_append, m_target.owner().mconfig().current_device(), std::string(std::forward<Params>(args)...));
+ }
+
+ template <typename... Params>
+ output_builder append_output(Params &&... args)
+ {
+ m_append = true;
+ return set_output(std::forward<Params>(args)...);
+ }
+
+ template <typename... Params>
+ log_builder set_log(device_t &devbase, Params &&... args)
+ {
+ set_used();
+ return log_builder(m_target, m_append, devbase, std::string(std::forward<Params>(args)...));
+ }
+
+ template <typename T, typename... Params>
+ std::enable_if_t<emu::detail::is_device_implementation<std::remove_reference_t<T> >::value, log_builder> set_log(T &devbase, Params &&... args)
+ {
+ return set_log(static_cast<device_t &>(devbase), std::forward<Params>(args)...);
+ }
+
+ template <typename T, typename... Params>
+ std::enable_if_t<emu::detail::is_device_interface<std::remove_reference_t<T> >::value, log_builder> set_log(T &devbase, Params &&... args)
+ {
+ return set_log(devbase.device(), std::forward<Params>(args)...);
+ }
+
+ template <typename... Params>
+ log_builder set_log(Params &&... args)
+ {
+ return set_log(m_target.owner().mconfig().current_device(), std::forward<Params>(args)...);
+ }
+
+ template <typename... Params>
+ log_builder append_log(Params &&... args)
+ {
+ m_append = true;
+ return set_log(std::forward<Params>(args)...);
+ }
+
+ void set_nop()
+ {
+ set_used();
+ m_target.m_creators.clear();
+ m_target.m_creators.emplace_back(std::make_unique<nop_creator>());
+ }
+
+ private:
+ void set_used() { assert(!m_used); m_used = true; }
+
+ devcb_write &m_target;
+ bool m_append = false;
+ bool m_used = false;
+ };
+
+ std::vector<func_t> m_functions;
+ std::vector<typename creator::ptr> m_creators;
-class devcb_write64 : public devcb_write_base
-{
public:
- devcb_write64(device_t &device) : devcb_write_base(device, 0xffffffffffffffffU) { }
- void operator()(u64 data, u64 mask = 0xffffffffffffffffU) { write(*m_space, 0, data, mask); }
- void operator()(offs_t offset, u64 data, u64 mask = 0xffffffffffffffffU) { write(*m_space, offset, data, mask); }
- void operator()(address_space &space, offs_t offset, u64 data, u64 mask = 0xffffffffffffffffU) { write((m_space_tag != nullptr) ? *m_space : space, offset, data, mask); }
+ devcb_write(device_t &owner);
+
+ binder bind();
+ void reset();
+
+ // legacy syntax support - will be removed
+ template <typename T, typename U, typename V>
+ devcb_base &set_callback(std::tuple<T, U, V> const &desc)
+ {
+ bind().set(std::forward<T>(std::get<0>(desc)), std::forward<U>(std::get<1>(desc)), std::forward<V>(std::get<2>(desc)));
+ return *this;
+ }
+ devcb_base &set_callback(DEVCB_INPUTLINE &&desc) { bind().set_inputline(desc.m_tag, desc.m_linenum); return *this; }
+ devcb_base &set_callback(DEVCB_ASSERTLINE &&desc) { bind().set_inputline(desc.m_tag, desc.m_linenum, ASSERT_LINE); return *this; }
+ devcb_base &set_callback(DEVCB_CLEARLINE &&desc) { bind().set_inputline(desc.m_tag, desc.m_linenum, CLEAR_LINE); return *this; }
+ devcb_base &set_callback(DEVCB_HOLDLINE &&desc) { bind().set_inputline(desc.m_tag, desc.m_linenum, HOLD_LINE); return *this; }
+ devcb_base &set_callback(DEVCB_MEMBANK &&desc) { bind().set_membank(desc.m_tag); return *this; }
+ devcb_base &set_callback(DEVCB_OUTPUT &&desc) { bind().set_output(desc.m_tag); return *this; }
+ devcb_base &set_callback(devcb_noop_t desc) { bind().set_nop(); return *this; }
+
+ virtual void validity_check(validity_checker &valid) const override;
+
+ void resolve();
+ void resolve_safe();
+
+ void operator()(address_space &space, offs_t offset, Input data, std::make_unsigned_t<Input> mem_mask = DefaultMask);
+ void operator()(address_space &space, Input data);
+ void operator()(offs_t offset, Input data, std::make_unsigned_t<Input> mem_mask = DefaultMask);
+ void operator()(Input data);
+
+ bool isnull() const { return m_functions.empty() && m_creators.empty(); }
+ explicit operator bool() const { return !m_functions.empty(); }
};
+template <typename Input, std::make_unsigned_t<Input> DefaultMask>
+devcb_write<Input, DefaultMask>::devcb_write(device_t &owner)
+ : devcb_write_base(owner)
+{
+}
+template <typename Input, std::make_unsigned_t<Input> DefaultMask>
+typename devcb_write<Input, DefaultMask>::binder devcb_write<Input, DefaultMask>::bind()
+{
+ return binder(*this);
+}
-//**************************************************************************
-// INLINE FUNCTIONS
-//**************************************************************************
+template <typename Input, std::make_unsigned_t<Input> DefaultMask>
+void devcb_write<Input, DefaultMask>::reset()
+{
+ assert(m_functions.empty());
+ m_creators.clear();
+}
-//-------------------------------------------------
-// read - generic read callback dispatch
-//-------------------------------------------------
+template <typename Input, std::make_unsigned_t<Input> DefaultMask>
+void devcb_write<Input, DefaultMask>::validity_check(validity_checker &valid) const
+{
+ assert(m_functions.empty());
+ devcb_write_base::validity_check(valid);
+ for (typename creator::ptr const &c : m_creators)
+ c->validity_check(valid);
+}
-inline u64 devcb_read_base::read(address_space &space, offs_t offset, u64 mask)
+template <typename Input, std::make_unsigned_t<Input> DefaultMask>
+void devcb_write<Input, DefaultMask>::resolve()
{
- u64 result = (this->*m_adapter)(space, offset, mask);
- if (m_chain != nullptr)
- result |= m_chain->read(space, offset, mask);
- return result;
+ assert(m_functions.empty());
+ devcb_write_base::resolve();
+ m_functions.reserve(m_creators.size());
+ for (typename creator::ptr const &c : m_creators)
+ m_functions.emplace_back(c->create());
+ m_creators.clear();
}
+template <typename Input, std::make_unsigned_t<Input> DefaultMask>
+void devcb_write<Input, DefaultMask>::resolve_safe()
+{
+ resolve();
+ if (m_functions.empty())
+ m_functions.emplace_back([] (address_space &space, offs_t offset, Input data, std::make_unsigned_t<Input> mem_mask) { });
+}
+
+template <typename Input, std::make_unsigned_t<Input> DefaultMask>
+void devcb_write<Input, DefaultMask>::operator()(address_space &space, offs_t offset, Input data, std::make_unsigned_t<Input> mem_mask)
+{
+ assert(m_creators.empty() && !m_functions.empty());
+ typename std::vector<func_t>::const_iterator it(m_functions.begin());
+ (*it)(space, offset, data, mem_mask);
+ while (m_functions.end() != ++it)
+ (*it)(space, offset, data, mem_mask);
+}
+
+template <typename Input, std::make_unsigned_t<Input> DefaultMask>
+void devcb_write<Input, DefaultMask>::operator()(address_space &space, Input data)
+{
+ this->operator()(space, 0U, data, DefaultMask);
+}
-//-------------------------------------------------
-// write - generic write callback dispatch
-//-------------------------------------------------
+template <typename Input, std::make_unsigned_t<Input> DefaultMask>
+void devcb_write<Input, DefaultMask>::operator()(offs_t offset, Input data, std::make_unsigned_t<Input> mem_mask)
+{
+ this->operator()(this->default_space(), offset, data, mem_mask);
+}
-inline void devcb_write_base::write(address_space &space, offs_t offset, u64 data, u64 mask)
+template <typename Input, std::make_unsigned_t<Input> DefaultMask>
+void devcb_write<Input, DefaultMask>::operator()(Input data)
{
- (this->*m_adapter)(space, offset, data, mask);
- if (m_chain != nullptr)
- m_chain->write(space, offset, data, mask);
+ this->operator()(this->default_space(), 0U, data, DefaultMask);
}
-//-------------------------------------------------
-// wrappers for ioports, constants, and loggers
-//-------------------------------------------------
-
-#define DEVCB_NOOP devcb_base::null_desc{ }
-template <typename... Params> inline devcb_base::ioport_desc DEVCB_IOPORT(Params &&... args) { return emu::detail::devcb_tag_desc_creator<devcb_base::ioport_desc>::create(std::forward<Params>(args)...); }
-template <typename... Params> inline devcb_base::membank_desc DEVCB_MEMBANK(Params &&... args) { return emu::detail::devcb_tag_desc_creator<devcb_base::membank_desc>::create(std::forward<Params>(args)...); }
-template <typename... Params> inline devcb_base::output_desc DEVCB_OUTPUT(Params &&... args) { return emu::detail::devcb_tag_desc_creator<devcb_base::output_desc>::create(std::forward<Params>(args)...); }
-inline devcb_base::constant_desc DEVCB_CONSTANT(u64 value) { return devcb_base::constant_desc{ value }; }
-inline devcb_base::logger_desc DEVCB_LOGGER(char const *string) { return devcb_base::logger_desc{ string }; }
-template <typename... Params> inline devcb_base::inputline_desc DEVCB_INPUTLINE(Params &&... args) { return emu::detail::devcb_line_desc_creator<devcb_base::inputline_desc>::create(std::forward<Params>(args)...); }
-template <typename... Params> inline devcb_base::assertline_desc DEVCB_ASSERTLINE(Params &&... args) { return emu::detail::devcb_line_desc_creator<devcb_base::assertline_desc>::create(std::forward<Params>(args)...); }
-template <typename... Params> inline devcb_base::clearline_desc DEVCB_CLEARLINE(Params &&... args) { return emu::detail::devcb_line_desc_creator<devcb_base::clearline_desc>::create(std::forward<Params>(args)...); }
-template <typename... Params> inline devcb_base::holdline_desc DEVCB_HOLDLINE(Params &&... args) { return emu::detail::devcb_line_desc_creator<devcb_base::holdline_desc>::create(std::forward<Params>(args)...); }
-#define DEVCB_VCC DEVCB_CONSTANT(1)
-#define DEVCB_GND DEVCB_CONSTANT(0)
+using devcb_read8 = devcb_read<u8>;
+using devcb_read16 = devcb_read<u16>;
+using devcb_read32 = devcb_read<u32>;
+using devcb_read64 = devcb_read<u64>;
+using devcb_read_line = devcb_read<int, 1U>;
+
+using devcb_write8 = devcb_write<u8>;
+using devcb_write16 = devcb_write<u16>;
+using devcb_write32 = devcb_write<u32>;
+using devcb_write64 = devcb_write<u64>;
+using devcb_write_line = devcb_write<int, 1U>;
+
+
+//**************************************************************************
+// TEMPLATE INSTANTIATIONS
+//**************************************************************************
+
+extern template class devcb_read<u8>;
+extern template class devcb_read<u16>;
+extern template class devcb_read<u32>;
+extern template class devcb_read<u64>;
+extern template class devcb_read<int, 1U>;
+
+extern template class devcb_read8::delegate_builder<read8_delegate>;
+extern template class devcb_read8::delegate_builder<read16_delegate>;
+extern template class devcb_read8::delegate_builder<read32_delegate>;
+extern template class devcb_read8::delegate_builder<read64_delegate>;
+extern template class devcb_read8::delegate_builder<read_line_delegate>;
+
+extern template class devcb_read16::delegate_builder<read8_delegate>;
+extern template class devcb_read16::delegate_builder<read16_delegate>;
+extern template class devcb_read16::delegate_builder<read32_delegate>;
+extern template class devcb_read16::delegate_builder<read64_delegate>;
+extern template class devcb_read16::delegate_builder<read_line_delegate>;
+
+extern template class devcb_read32::delegate_builder<read8_delegate>;
+extern template class devcb_read32::delegate_builder<read16_delegate>;
+extern template class devcb_read32::delegate_builder<read32_delegate>;
+extern template class devcb_read32::delegate_builder<read64_delegate>;
+extern template class devcb_read32::delegate_builder<read_line_delegate>;
+
+extern template class devcb_read64::delegate_builder<read8_delegate>;
+extern template class devcb_read64::delegate_builder<read16_delegate>;
+extern template class devcb_read64::delegate_builder<read32_delegate>;
+extern template class devcb_read64::delegate_builder<read64_delegate>;
+extern template class devcb_read64::delegate_builder<read_line_delegate>;
+
+extern template class devcb_read_line::delegate_builder<read8_delegate>;
+extern template class devcb_read_line::delegate_builder<read16_delegate>;
+extern template class devcb_read_line::delegate_builder<read32_delegate>;
+extern template class devcb_read_line::delegate_builder<read64_delegate>;
+extern template class devcb_read_line::delegate_builder<read_line_delegate>;
+
+extern template class devcb_read8::creator_impl<devcb_read8::delegate_builder<read8_delegate> >;
+extern template class devcb_read8::creator_impl<devcb_read8::delegate_builder<read16_delegate> >;
+extern template class devcb_read8::creator_impl<devcb_read8::delegate_builder<read32_delegate> >;
+extern template class devcb_read8::creator_impl<devcb_read8::delegate_builder<read64_delegate> >;
+extern template class devcb_read8::creator_impl<devcb_read8::delegate_builder<read_line_delegate> >;
+extern template class devcb_read8::creator_impl<devcb_read8::ioport_builder>;
+
+extern template class devcb_read16::creator_impl<devcb_read16::delegate_builder<read8_delegate> >;
+extern template class devcb_read16::creator_impl<devcb_read16::delegate_builder<read16_delegate> >;
+extern template class devcb_read16::creator_impl<devcb_read16::delegate_builder<read32_delegate> >;
+extern template class devcb_read16::creator_impl<devcb_read16::delegate_builder<read64_delegate> >;
+extern template class devcb_read16::creator_impl<devcb_read16::delegate_builder<read_line_delegate> >;
+extern template class devcb_read16::creator_impl<devcb_read16::ioport_builder>;
+
+extern template class devcb_read32::creator_impl<devcb_read32::delegate_builder<read8_delegate> >;
+extern template class devcb_read32::creator_impl<devcb_read32::delegate_builder<read16_delegate> >;
+extern template class devcb_read32::creator_impl<devcb_read32::delegate_builder<read32_delegate> >;
+extern template class devcb_read32::creator_impl<devcb_read32::delegate_builder<read64_delegate> >;
+extern template class devcb_read32::creator_impl<devcb_read32::delegate_builder<read_line_delegate> >;
+extern template class devcb_read32::creator_impl<devcb_read32::ioport_builder>;
+
+extern template class devcb_read64::creator_impl<devcb_read64::delegate_builder<read8_delegate> >;
+extern template class devcb_read64::creator_impl<devcb_read64::delegate_builder<read16_delegate> >;
+extern template class devcb_read64::creator_impl<devcb_read64::delegate_builder<read32_delegate> >;
+extern template class devcb_read64::creator_impl<devcb_read64::delegate_builder<read64_delegate> >;
+extern template class devcb_read64::creator_impl<devcb_read64::delegate_builder<read_line_delegate> >;
+extern template class devcb_read64::creator_impl<devcb_read64::ioport_builder>;
+
+extern template class devcb_read_line::creator_impl<devcb_read_line::delegate_builder<read8_delegate> >;
+extern template class devcb_read_line::creator_impl<devcb_read_line::delegate_builder<read16_delegate> >;
+extern template class devcb_read_line::creator_impl<devcb_read_line::delegate_builder<read32_delegate> >;
+extern template class devcb_read_line::creator_impl<devcb_read_line::delegate_builder<read64_delegate> >;
+extern template class devcb_read_line::creator_impl<devcb_read_line::delegate_builder<read_line_delegate> >;
+extern template class devcb_read_line::creator_impl<devcb_read_line::ioport_builder>;
+
+extern template class devcb_write<u8>;
+extern template class devcb_write<u16>;
+extern template class devcb_write<u32>;
+extern template class devcb_write<u64>;
+extern template class devcb_write<int, 1U>;
+
+extern template class devcb_write8::delegate_builder<write8_delegate>;
+extern template class devcb_write8::delegate_builder<write16_delegate>;
+extern template class devcb_write8::delegate_builder<write32_delegate>;
+extern template class devcb_write8::delegate_builder<write64_delegate>;
+extern template class devcb_write8::delegate_builder<write_line_delegate>;
+
+extern template class devcb_write16::delegate_builder<write8_delegate>;
+extern template class devcb_write16::delegate_builder<write16_delegate>;
+extern template class devcb_write16::delegate_builder<write32_delegate>;
+extern template class devcb_write16::delegate_builder<write64_delegate>;
+extern template class devcb_write16::delegate_builder<write_line_delegate>;
+
+extern template class devcb_write32::delegate_builder<write8_delegate>;
+extern template class devcb_write32::delegate_builder<write16_delegate>;
+extern template class devcb_write32::delegate_builder<write32_delegate>;
+extern template class devcb_write32::delegate_builder<write64_delegate>;
+extern template class devcb_write32::delegate_builder<write_line_delegate>;
+
+extern template class devcb_write64::delegate_builder<write8_delegate>;
+extern template class devcb_write64::delegate_builder<write16_delegate>;
+extern template class devcb_write64::delegate_builder<write32_delegate>;
+extern template class devcb_write64::delegate_builder<write64_delegate>;
+extern template class devcb_write64::delegate_builder<write_line_delegate>;
+
+extern template class devcb_write_line::delegate_builder<write8_delegate>;
+extern template class devcb_write_line::delegate_builder<write16_delegate>;
+extern template class devcb_write_line::delegate_builder<write32_delegate>;
+extern template class devcb_write_line::delegate_builder<write64_delegate>;
+extern template class devcb_write_line::delegate_builder<write_line_delegate>;
+
+extern template class devcb_write8::creator_impl<devcb_write8::delegate_builder<write8_delegate> >;
+extern template class devcb_write8::creator_impl<devcb_write8::delegate_builder<write16_delegate> >;
+extern template class devcb_write8::creator_impl<devcb_write8::delegate_builder<write32_delegate> >;
+extern template class devcb_write8::creator_impl<devcb_write8::delegate_builder<write64_delegate> >;
+extern template class devcb_write8::creator_impl<devcb_write8::delegate_builder<write_line_delegate> >;
+extern template class devcb_write8::creator_impl<devcb_write8::inputline_builder>;
+extern template class devcb_write8::creator_impl<devcb_write8::latched_inputline_builder>;
+extern template class devcb_write8::creator_impl<devcb_write8::ioport_builder>;
+extern template class devcb_write8::creator_impl<devcb_write8::membank_builder>;
+extern template class devcb_write8::creator_impl<devcb_write8::output_builder>;
+extern template class devcb_write8::creator_impl<devcb_write8::log_builder>;
+
+extern template class devcb_write16::creator_impl<devcb_write16::delegate_builder<write8_delegate> >;
+extern template class devcb_write16::creator_impl<devcb_write16::delegate_builder<write16_delegate> >;
+extern template class devcb_write16::creator_impl<devcb_write16::delegate_builder<write32_delegate> >;
+extern template class devcb_write16::creator_impl<devcb_write16::delegate_builder<write64_delegate> >;
+extern template class devcb_write16::creator_impl<devcb_write16::delegate_builder<write_line_delegate> >;
+extern template class devcb_write16::creator_impl<devcb_write16::inputline_builder>;
+extern template class devcb_write16::creator_impl<devcb_write16::latched_inputline_builder>;
+extern template class devcb_write16::creator_impl<devcb_write16::ioport_builder>;
+extern template class devcb_write16::creator_impl<devcb_write16::membank_builder>;
+extern template class devcb_write16::creator_impl<devcb_write16::output_builder>;
+extern template class devcb_write16::creator_impl<devcb_write16::log_builder>;
+
+extern template class devcb_write32::creator_impl<devcb_write32::delegate_builder<write8_delegate> >;
+extern template class devcb_write32::creator_impl<devcb_write32::delegate_builder<write16_delegate> >;
+extern template class devcb_write32::creator_impl<devcb_write32::delegate_builder<write32_delegate> >;
+extern template class devcb_write32::creator_impl<devcb_write32::delegate_builder<write64_delegate> >;
+extern template class devcb_write32::creator_impl<devcb_write32::delegate_builder<write_line_delegate> >;
+extern template class devcb_write32::creator_impl<devcb_write32::inputline_builder>;
+extern template class devcb_write32::creator_impl<devcb_write32::latched_inputline_builder>;
+extern template class devcb_write32::creator_impl<devcb_write32::ioport_builder>;
+extern template class devcb_write32::creator_impl<devcb_write32::membank_builder>;
+extern template class devcb_write32::creator_impl<devcb_write32::output_builder>;
+extern template class devcb_write32::creator_impl<devcb_write32::log_builder>;
+
+extern template class devcb_write64::creator_impl<devcb_write64::delegate_builder<write8_delegate> >;
+extern template class devcb_write64::creator_impl<devcb_write64::delegate_builder<write16_delegate> >;
+extern template class devcb_write64::creator_impl<devcb_write64::delegate_builder<write32_delegate> >;
+extern template class devcb_write64::creator_impl<devcb_write64::delegate_builder<write64_delegate> >;
+extern template class devcb_write64::creator_impl<devcb_write64::delegate_builder<write_line_delegate> >;
+extern template class devcb_write64::creator_impl<devcb_write64::inputline_builder>;
+extern template class devcb_write64::creator_impl<devcb_write64::latched_inputline_builder>;
+extern template class devcb_write64::creator_impl<devcb_write64::ioport_builder>;
+extern template class devcb_write64::creator_impl<devcb_write64::membank_builder>;
+extern template class devcb_write64::creator_impl<devcb_write64::output_builder>;
+extern template class devcb_write64::creator_impl<devcb_write64::log_builder>;
+
+extern template class devcb_write_line::creator_impl<devcb_write_line::delegate_builder<write8_delegate> >;
+extern template class devcb_write_line::creator_impl<devcb_write_line::delegate_builder<write16_delegate> >;
+extern template class devcb_write_line::creator_impl<devcb_write_line::delegate_builder<write32_delegate> >;
+extern template class devcb_write_line::creator_impl<devcb_write_line::delegate_builder<write64_delegate> >;
+extern template class devcb_write_line::creator_impl<devcb_write_line::delegate_builder<write_line_delegate> >;
+extern template class devcb_write_line::creator_impl<devcb_write_line::inputline_builder>;
+extern template class devcb_write_line::creator_impl<devcb_write_line::latched_inputline_builder>;
+extern template class devcb_write_line::creator_impl<devcb_write_line::ioport_builder>;
+extern template class devcb_write_line::creator_impl<devcb_write_line::membank_builder>;
+extern template class devcb_write_line::creator_impl<devcb_write_line::output_builder>;
+extern template class devcb_write_line::creator_impl<devcb_write_line::log_builder>;
#endif // MAME_EMU_DEVCB_H