diff options
Diffstat (limited to 'src/emu/devcb.h')
-rw-r--r-- | src/emu/devcb.h | 1014 |
1 files changed, 373 insertions, 641 deletions
diff --git a/src/emu/devcb.h b/src/emu/devcb.h index 6b16c37b33a..d2ee406aa60 100644 --- a/src/emu/devcb.h +++ b/src/emu/devcb.h @@ -7,11 +7,13 @@ Device callback interface helpers. ***************************************************************************/ + #ifndef MAME_EMU_DEVCB_H #define MAME_EMU_DEVCB_H #pragma once +#include <array> #include <cassert> #include <functional> #include <memory> @@ -28,12 +30,16 @@ //************************************************************************** #if defined(__GNUC__) && !defined(__clang__) -#if __GNUC__ >= 8 +#if (__GNUC__ >= 8) #define MAME_DEVCB_GNUC_BROKEN_FRIEND 1 -#endif // __GNUC__ >= 8 -#endif // defined(__GNUC__) && !defined(__clang__) - +#endif // (__GNUC__ >= 8) && !defined(__clang__) +#endif // defined(__GNUC__) +#if defined(__clang__) +#if (__clang_major__ == 8) +#define MAME_DEVCB_GNUC_BROKEN_FRIEND 1 +#endif // (__clang_major__ == 8) +#endif // defined(__clang__) //************************************************************************** // DELEGATE TYPES @@ -42,20 +48,12 @@ typedef device_delegate<int ()> read_line_delegate; typedef device_delegate<void (int)> write_line_delegate; -namespace emu { namespace detail { - -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> -inline read_line_delegate make_delegate(T &&func, char const *name, char const *tag, rw_device_class_t<read_line_delegate, std::remove_reference_t<T> > *obj) -{ return read_line_delegate(func, name, tag, obj); } +namespace emu::detail { -template <typename T> -inline write_line_delegate make_delegate(T &&func, char const *name, char const *tag, rw_device_class_t<write_line_delegate, std::remove_reference_t<T> > *obj) -{ return write_line_delegate(func, name, tag, obj); } +template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<read_line_delegate, std::remove_reference_t<T> > > > { using type = read_line_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; +template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<write_line_delegate, std::remove_reference_t<T> > > > { using type = write_line_delegate; using device_class = rw_device_class_t<type, std::remove_reference_t<T> >; }; -} } // namespace emu::detail +} // namespace emu::detail //************************************************************************** @@ -66,17 +64,8 @@ inline write_line_delegate make_delegate(T &&func, char const *name, char const /// /// Provides utilities for supporting multiple read/write/transform /// signatures, and the base exclusive-or/mask transform methods. -class devcb_base +class devcb_base : protected device_resolver_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; - } - - virtual void validity_check(validity_checker &valid) const; - protected: // This is in C++17 but not C++14 template <typename... T> struct void_wrapper { using type = void; }; @@ -90,82 +79,37 @@ protected: 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; }; + template <typename Input, typename Result, typename Func> using is_transform_form3 = std::is_invocable_r<Result, Func, offs_t &, Input, std::make_unsigned_t<Input> &>; + template <typename Input, typename Result, typename Func> using is_transform_form4 = std::is_invocable_r<Result, Func, offs_t &, Input>; + template <typename Input, typename Result, typename Func> using is_transform_form6 = std::is_invocable_r<Result, Func, Input>; + template <typename Input, typename Result, typename Func> using is_transform = std::bool_constant<is_transform_form3<Input, Result, Func>::value || is_transform_form4<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> struct transform_result<Input, Result, Func, std::enable_if_t<is_transform_form3<Input, Result, Func>::value> > { using type = std::invoke_result_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::invoke_result_t<Func, offs_t &, 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::invoke_result_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::rw_device_class_t<read8_delegate, std::remove_reference_t<T> > > > { using type = read8_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<read16_delegate, std::remove_reference_t<T> > > > { using type = read16_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<read32_delegate, std::remove_reference_t<T> > > > { using type = read32_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<read64_delegate, std::remove_reference_t<T> > > > { using type = read64_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<read8s_delegate, std::remove_reference_t<T> > > > { using type = read8s_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<read16s_delegate, std::remove_reference_t<T> > > > { using type = read16s_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<read32s_delegate, std::remove_reference_t<T> > > > { using type = read32s_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<read64s_delegate, std::remove_reference_t<T> > > > { using type = read64s_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<read8sm_delegate, std::remove_reference_t<T> > > > { using type = read8sm_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<read16sm_delegate, std::remove_reference_t<T> > > > { using type = read16sm_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<read32sm_delegate, std::remove_reference_t<T> > > > { using type = read32sm_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<read64sm_delegate, std::remove_reference_t<T> > > > { using type = read64sm_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<read8smo_delegate, std::remove_reference_t<T> > > > { using type = read8smo_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<read16smo_delegate, std::remove_reference_t<T> > > > { using type = read16smo_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<read32smo_delegate, std::remove_reference_t<T> > > > { using type = read32smo_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<read64smo_delegate, std::remove_reference_t<T> > > > { using type = read64smo_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<read_line_delegate, std::remove_reference_t<T> > > > { using type = read_line_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<write8_delegate, std::remove_reference_t<T> > > > { using type = write8_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<write16_delegate, std::remove_reference_t<T> > > > { using type = write16_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<write32_delegate, std::remove_reference_t<T> > > > { using type = write32_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<write64_delegate, std::remove_reference_t<T> > > > { using type = write64_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<write8s_delegate, std::remove_reference_t<T> > > > { using type = write8s_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<write16s_delegate, std::remove_reference_t<T> > > > { using type = write16s_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<write32s_delegate, std::remove_reference_t<T> > > > { using type = write32s_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<write64s_delegate, std::remove_reference_t<T> > > > { using type = write64s_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<write8sm_delegate, std::remove_reference_t<T> > > > { using type = write8sm_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<write16sm_delegate, std::remove_reference_t<T> > > > { using type = write16sm_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<write32sm_delegate, std::remove_reference_t<T> > > > { using type = write32sm_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<write64sm_delegate, std::remove_reference_t<T> > > > { using type = write64sm_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<write8smo_delegate, std::remove_reference_t<T> > > > { using type = write8smo_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<write16smo_delegate, std::remove_reference_t<T> > > > { using type = write16smo_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<write32smo_delegate, std::remove_reference_t<T> > > > { using type = write32smo_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<write64smo_delegate, std::remove_reference_t<T> > > > { using type = write64smo_delegate; using device_class = emu::detail::rw_device_class_t<type, std::remove_reference_t<T> >; }; - template <typename T> struct delegate_type<T, void_t<emu::detail::rw_device_class_t<write_line_delegate, std::remove_reference_t<T> > > > { using type = write_line_delegate; using device_class = emu::detail::rw_device_class_t<type, 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; + template <typename T> using delegate_type_t = emu::detail::rw_delegate_type_t<T>; + template <typename T> using delegate_device_class_t = emu::detail::rw_delegate_device_class_t<T>; // 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)); } + 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, 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, 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_form6<Input, Result, T>::value, mask_t<transform_result_t<Input, Result, T>, Result> > invoke_transform(T const &cb, 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); } + template <typename T, typename U> static T &cast_reference(U &obj) + { + if constexpr (std::is_convertible_v<std::add_pointer_t<U>, std::add_pointer_t<T> >) + return downcast<T &>(obj); + else + return dynamic_cast<T &>(obj); + } /// \brief Base transform helper /// @@ -184,12 +128,18 @@ protected: 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 inherited_mask() ? std::move(trans) : std::move(trans.mask(m_mask >> val)); + if (inherited_mask()) + return trans; + else + 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 inherited_mask() ? std::move(trans) : std::move(trans.mask(m_mask << val)); + if (inherited_mask()) + return trans; + else + return std::move(trans.mask(m_mask << val)); } auto bit(unsigned val) { return std::move(rshift(val).mask(T(1U))); } @@ -214,20 +164,38 @@ protected: bool m_inherited_mask = true; }; + /// \brief Callback array helper + /// + /// Simplifies construction and resolution of arrays of callbacks. + template <typename T, unsigned Count> + class array : public std::array<T, Count> + { + private: + template <unsigned... V, typename... Params> + array(device_t &owner, std::integer_sequence<unsigned, V...>, Params &&... args) + : std::array<T, Count>{{ { make_one<V>(owner), std::forward<Params>(args)... }... }} + { + } + + template <unsigned N> device_t &make_one(device_t &owner) { return owner; } + + public: + using std::array<T, Count>::array; + + template <typename... Params> + array(device_t &owner, Params &&... args) + : array(owner, std::make_integer_sequence<unsigned, Count>(), std::forward<Params>(args)...) + { + } + }; + devcb_base(device_t &owner); ~devcb_base(); device_t &owner() const { return m_owner; } - void resolve(); - - address_space &default_space() { assert(m_dflt_space); return *m_dflt_space; } - private: device_t &m_owner; - optional_device<device_memory_interface> m_dflt_space_finder; - int m_dflt_space_index; - address_space *m_dflt_space; }; @@ -238,64 +206,41 @@ class devcb_read_base : public devcb_base { protected: // 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; }; + template <typename Result, typename Func> using is_read_form1 = std::is_invocable_r<Result, Func, offs_t, Result>; + template <typename Result, typename Func> using is_read_form2 = std::is_invocable_r<Result, Func, offs_t>; + template <typename Result, typename Func> using is_read_form3 = std::is_invocable_r<Result, Func>; + template <typename Result, typename Func> using is_read = std::bool_constant<is_read_form1<Result, Func>::value || is_read_form2<Result, Func>::value || is_read_form3<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> struct read_result<Result, Func, std::enable_if_t<is_read_form1<Result, Func>::value> > { using type = std::invoke_result_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_form2<Result, Func>::value> > { using type = std::invoke_result_t<Func, 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::invoke_result_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::rw_device_class_t<read8_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read16_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read32_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read64_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read8s_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read16s_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read32s_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read64s_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read8sm_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read16sm_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read32sm_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read64sm_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read8smo_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read16smo_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read32smo_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read64smo_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read_line_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; + template <typename T, typename Enable = void> struct is_read_method : public std::false_type { }; + template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read8s_delegate, std::remove_reference_t<T> > > > : public std::true_type { }; + template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read16s_delegate, std::remove_reference_t<T> > > > : public std::true_type { }; + template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read32s_delegate, std::remove_reference_t<T> > > > : public std::true_type { }; + template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read64s_delegate, std::remove_reference_t<T> > > > : public std::true_type { }; + template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read8sm_delegate, std::remove_reference_t<T> > > > : public std::true_type { }; + template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read16sm_delegate, std::remove_reference_t<T> > > > : public std::true_type { }; + template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read32sm_delegate, std::remove_reference_t<T> > > > : public std::true_type { }; + template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read64sm_delegate, std::remove_reference_t<T> > > > : public std::true_type { }; + template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read8smo_delegate, std::remove_reference_t<T> > > > : public std::true_type { }; + template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read16smo_delegate, std::remove_reference_t<T> > > > : public std::true_type { }; + template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read32smo_delegate, std::remove_reference_t<T> > > > : public std::true_type { }; + template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read64smo_delegate, std::remove_reference_t<T> > > > : public std::true_type { }; + template <typename T> struct is_read_method<T, void_t<emu::detail::rw_device_class_t<read_line_delegate, std::remove_reference_t<T> > > > : public std::true_type { }; // 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()); } + 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, 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_form2<Result, T>::value, mask_t<read_result_t<Result, T>, Result> > invoke_read(T const &cb, 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_form3<Result, T>::value, mask_t<read_result_t<Result, T>, Result> > invoke_read(T const &cb, 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<read8s_delegate, Dummy> { static constexpr u8 default_mask = ~u8(0); }; template <typename Dummy> struct delegate_traits<read16s_delegate, Dummy> { static constexpr u16 default_mask = ~u16(0); }; template <typename Dummy> struct delegate_traits<read32s_delegate, Dummy> { static constexpr u32 default_mask = ~u32(0); }; @@ -322,54 +267,34 @@ 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; }; + template <typename Input, typename Func> using is_write_form1 = std::is_invocable<Func, offs_t, Input, std::make_unsigned_t<Input> >; + template <typename Input, typename Func> using is_write_form2 = std::is_invocable<Func, offs_t, Input>; + template <typename Input, typename Func> using is_write_form3 = std::is_invocable<Func, Input>; + template <typename Input, typename Func> using is_write = std::bool_constant<is_write_form1<Input, Func>::value || is_write_form2<Input, Func>::value || is_write_form3<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::rw_device_class_t<write8_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write16_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write32_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write64_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write8s_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write16s_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write32s_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write64s_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write8sm_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write16sm_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write32sm_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write64sm_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write8smo_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write16smo_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write32smo_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write64smo_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; - template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write_line_delegate, std::remove_reference_t<T> > > > { static constexpr bool value = true; }; + template <typename T, typename Enable = void> struct is_write_method : public std::false_type { }; + template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write8s_delegate, std::remove_reference_t<T> > > > : public std::true_type { }; + template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write16s_delegate, std::remove_reference_t<T> > > > : public std::true_type { }; + template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write32s_delegate, std::remove_reference_t<T> > > > : public std::true_type { }; + template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write64s_delegate, std::remove_reference_t<T> > > > : public std::true_type { }; + template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write8sm_delegate, std::remove_reference_t<T> > > > : public std::true_type { }; + template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write16sm_delegate, std::remove_reference_t<T> > > > : public std::true_type { }; + template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write32sm_delegate, std::remove_reference_t<T> > > > : public std::true_type { }; + template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write64sm_delegate, std::remove_reference_t<T> > > > : public std::true_type { }; + template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write8smo_delegate, std::remove_reference_t<T> > > > : public std::true_type { }; + template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write16smo_delegate, std::remove_reference_t<T> > > > : public std::true_type { }; + template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write32smo_delegate, std::remove_reference_t<T> > > > : public std::true_type { }; + template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write64smo_delegate, std::remove_reference_t<T> > > > : public std::true_type { }; + template <typename T> struct is_write_method<T, void_t<emu::detail::rw_device_class_t<write_line_delegate, std::remove_reference_t<T> > > > : public std::true_type { }; // 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, offset, data); } - 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); } + template <typename Input, typename T> static std::enable_if_t<is_write_form1<Input, T>::value> invoke_write(T const &cb, 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_form2<Input, T>::value> invoke_write(T const &cb, 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_form3<Input, T>::value> invoke_write(T const &cb, 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<write8s_delegate, Dummy> { using input_t = u8; static constexpr u8 default_mask = ~u8(0); }; template <typename Dummy> struct delegate_traits<write16s_delegate, Dummy> { using input_t = u16; static constexpr u16 default_mask = ~u16(0); }; template <typename Dummy> struct delegate_traits<write32s_delegate, Dummy> { using input_t = u32; static constexpr u32 default_mask = ~u32(0); }; @@ -398,7 +323,7 @@ template <typename Result, std::make_unsigned_t<Result> DefaultMask = std::make_ class devcb_read : public devcb_read_base { private: - using func_t = std::function<Result (address_space &, offs_t, std::make_unsigned_t<Result>)>; + using func_t = std::function<Result (offs_t, std::make_unsigned_t<Result>)>; class creator { @@ -406,7 +331,7 @@ private: using ptr = std::unique_ptr<creator>; virtual ~creator() { } - virtual void validity_check(validity_checker &valid) const = 0; + virtual bool validity_check(validity_checker &valid) const = 0; virtual func_t create() = 0; std::make_unsigned_t<Result> mask() const { return m_mask; } @@ -423,12 +348,12 @@ private: public: creator_impl(T &&builder) : creator(builder.mask()), m_builder(std::move(builder)) { } - virtual void validity_check(validity_checker &valid) const override { m_builder.validity_check(valid); } + virtual bool validity_check(validity_checker &valid) const override { return m_builder.validity_check(valid); } 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); }; }); + m_builder.build([&result] (auto &&f) { result = [cb = std::move(f)] (offs_t offset, typename T::input_mask_t mem_mask) { return cb(offset, mem_mask); }; }); return result; } @@ -436,28 +361,6 @@ private: T m_builder; }; - class log_creator : public creator - { - 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 Source, typename Func> class transform_builder; // workaround for MSVC class builder_base @@ -537,7 +440,7 @@ private: 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); } + bool validity_check(validity_checker &valid) const { return m_src.validity_check(valid); } template <typename T> void build(T &&chain) @@ -558,12 +461,12 @@ private: 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) + [src = std::forward<U>(f), cb = std::move(m_cb), exor = this->exor(), mask = this->mask()] (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)); + auto const data(src(offset, source_mask)); mem_mask = source_mask & mask; - return (devcb_read::invoke_transform<input_t, Result>(cb, space, offset, data, mem_mask) ^ exor) & mask; + return (devcb_read::invoke_transform<input_t, Result>(cb, offset, data, mem_mask) ^ exor) & mask; }); } @@ -605,7 +508,7 @@ private: 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 { } + bool validity_check(validity_checker &valid) const { return true; } template <typename T> void build(T &&chain) @@ -613,8 +516,8 @@ private: 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; }); + [cb = std::move(m_cb), exor = this->exor(), mask = this->mask()] (offs_t offset, input_mask_t mem_mask) + { return (devcb_read::invoke_read<Result>(cb, offset, mem_mask & mask) ^ exor) & mask; }); } private: @@ -638,20 +541,17 @@ private: 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)) + , m_delegate(devbase, tag, std::forward<T>(func), name) { } 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) + , m_delegate(obj, std::forward<T>(func), name) { } 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(); @@ -668,10 +568,15 @@ private: 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 + bool 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()); + auto const target(m_delegate.finder_target()); + if (target.second && !target.first.subdevice(target.second)) + { + osd_printf_error("Read callback bound to non-existent object tag %s (%s)\n", target.first.subtag(target.second), m_delegate.name()); + return false; + } + return true; } template <typename T> @@ -679,10 +584,10 @@ private: { assert(this->m_consumed); this->built(); - m_delegate.bind_relative_to(m_devbase); + m_delegate.resolve(); 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; }); + [cb = std::move(m_delegate), exor = this->exor(), mask = this->mask()] (offs_t offset, input_mask_t mem_mask) + { return (devcb_read::invoke_read<Result>(cb, offset, mem_mask & mask) ^ exor) & mask; }); } private: @@ -690,7 +595,6 @@ private: delegate_builder &operator=(delegate_builder const &) = delete; delegate_builder &operator=(delegate_builder &&that) = delete; - device_t &m_devbase; Delegate m_delegate; }; @@ -728,18 +632,18 @@ private: 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 { } + bool validity_check(validity_checker &valid) const { return true; } template <typename T> void build(T &&chain) { assert(this->m_consumed); this->built(); - ioport_port *const ioport(m_devbase.ioport(m_tag.c_str())); + ioport_port *const ioport(m_devbase.ioport(m_tag)); 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()); + throw emu_fatalerror("Read callback bound to non-existent I/O port %s of device %s (%s)\n", m_tag, 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) + [&port = *ioport, exor = this->exor(), mask = this->mask()] (offs_t offset, input_mask_t mem_mask) { return (port.read() ^ exor) & mask; }); } @@ -789,6 +693,13 @@ private: return delegate_builder<delegate_type_t<T> >(m_target, m_append, m_target.owner(), devcb_read::cast_reference<delegate_device_class_t<T> >(obj), std::forward<T>(func), name); } + template <typename T> + std::enable_if_t<is_read_method<T>::value, delegate_builder<delegate_type_t<T> > > set(device_t &devbase, char const *tag, T &&func, char const *name) + { + set_used(); + return delegate_builder<delegate_type_t<T> >(m_target, m_append, devbase, tag, 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) { @@ -842,43 +753,15 @@ private: 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)...); - } + auto set_constant(Result val) { return set([val] () { return val; }); } + auto append_constant(Result val) { return append([val] () { return val; }); } - template <typename... Params> - void append_log(Params &&... args) + void remove() { - m_append = true; - set_log(std::forward<Params>(args)...); + set_used(); + m_target.m_creators.clear(); } - 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; } @@ -889,35 +772,46 @@ private: std::vector<func_t> m_functions; std::vector<typename creator::ptr> m_creators; + Result const m_default; + bool m_unset = false; + +protected: + virtual bool findit(validity_checker *valid) override; + virtual void end_configuration() override; public: - devcb_read(device_t &owner); + template <unsigned Count> + class array : public devcb_read_base::array<devcb_read<Result, DefaultMask>, Count> + { + public: + array(device_t &owner, Result dflt) + : devcb_read_base::array<devcb_read<Result, DefaultMask>, Count>::array(owner, dflt) + { + } + }; + + devcb_read(device_t &owner, Result dflt); binder bind(); void reset(); - virtual void validity_check(validity_checker &valid) const override; - - void resolve(); - void resolve_safe(Result dflt); - - 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()(); - bool isnull() const { return m_functions.empty() && m_creators.empty(); } - explicit operator bool() const { return !m_functions.empty(); } + bool isunset() const noexcept { return m_unset || (m_functions.empty() && m_creators.empty()); } }; template <typename Result, std::make_unsigned_t<Result> DefaultMask> -devcb_read<Result, DefaultMask>::devcb_read(device_t &owner) +devcb_read<Result, DefaultMask>::devcb_read(device_t &owner, Result dflt) : devcb_read_base(owner) + , m_default(dflt & DefaultMask) { } template <typename Result, std::make_unsigned_t<Result> DefaultMask> typename devcb_read<Result, DefaultMask>::binder devcb_read<Result, DefaultMask>::bind() { + assert(m_functions.empty()); return binder(*this); } @@ -929,63 +823,65 @@ void devcb_read<Result, DefaultMask>::reset() } template <typename Result, std::make_unsigned_t<Result> DefaultMask> -void devcb_read<Result, DefaultMask>::validity_check(validity_checker &valid) const +bool devcb_read<Result, DefaultMask>::findit(validity_checker *valid) { 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) + if (!valid) { - (*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) + // FIXME: report errors by returning false rather than throwing fatal errors + m_functions.reserve(m_creators.size()); + for (typename creator::ptr const &c : m_creators) + m_functions.emplace_back(c->create()); + m_creators.clear(); + if (m_functions.empty()) { - 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 + m_functions.emplace_back([dflt = m_default] (offs_t offset, std::make_unsigned_t<Result> mem_mask) { return dflt; }); + m_unset = true; } + return true; + } + else + { + bool success(true); + for (typename std::vector<typename creator::ptr>::const_iterator i = m_creators.begin(); m_creators.end() != i; ++i) + { + if (!(*i)->validity_check(*valid)) + success = false; + 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 0x%X and 0x%X overlap\n", m, n); + success = false; + } + } + } + return success; } } template <typename Result, std::make_unsigned_t<Result> DefaultMask> -void devcb_read<Result, DefaultMask>::resolve() -{ - 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) +void devcb_read<Result, DefaultMask>::end_configuration() { - 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; }); } 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) +Result devcb_read<Result, DefaultMask>::operator()(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)); + std::make_unsigned_t<Result> result((*it)(offset, mem_mask)); while (m_functions.end() != ++it) - result |= (*it)(space, offset, mem_mask); + result |= (*it)(offset, mem_mask); return result; } 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) -{ - 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); + return this->operator()(0U, DefaultMask); } @@ -998,7 +894,7 @@ template <typename Input, std::make_unsigned_t<Input> DefaultMask = std::make_un class devcb_write : public devcb_write_base { private: - using func_t = std::function<void (address_space &, offs_t, Input, std::make_unsigned_t<Input>)>; + using func_t = std::function<void (offs_t, Input, std::make_unsigned_t<Input>)>; class creator { @@ -1006,7 +902,7 @@ private: using ptr = std::unique_ptr<creator>; virtual ~creator() { } - virtual void validity_check(validity_checker &valid) const = 0; + virtual bool validity_check(validity_checker &valid) const = 0; virtual func_t create() = 0; }; @@ -1016,11 +912,11 @@ private: public: creator_impl(T &&builder) : m_builder(std::move(builder)) { } - virtual void validity_check(validity_checker &valid) const override { m_builder.validity_check(valid); } + virtual bool validity_check(validity_checker &valid) const override { return m_builder.validity_check(valid); } 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); }; + return [cb = m_builder.build()] (offs_t offset, Input data, std::make_unsigned_t<Input> mem_mask) { cb(offset, data, mem_mask); }; } private: @@ -1030,8 +926,8 @@ private: 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) { }; } + virtual bool validity_check(validity_checker &valid) const override { return true; } + virtual func_t create() override { return [] (offs_t offset, Input data, std::make_unsigned_t<Input> mem_mask) { }; } }; template <typename Source, typename Func> class transform_builder; // workaround for MSVC @@ -1121,15 +1017,15 @@ private: 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) + [cb = std::move(m_cb), exor = this->exor(), mask = this->mask()] (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)); + auto const trans(devcb_write::invoke_transform<input_t, output_t>(cb, offset, data, mem_mask)); mem_mask &= mask; return (trans ^ exor) & mask; }); } - void validity_check(validity_checker &valid) const { m_src.validity_check(valid); } + bool validity_check(validity_checker &valid) const { return m_src.validity_check(valid); } private: transform_builder(transform_builder const &) = delete; @@ -1142,11 +1038,11 @@ private: 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) + [f = std::move(chain), cb = std::move(m_cb), exor = this->exor(), mask = this->mask()] (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)); + auto const trans(devcb_write::invoke_transform<input_t, output_t>(cb, offset, data, mem_mask)); output_t out_mask(mem_mask & mask); - return f(space, offset, (trans ^ exor) & mask, out_mask); + return f(offset, (trans ^ exor) & mask, out_mask); }); } @@ -1186,7 +1082,7 @@ private: } ~first_transform_builder() { this->template register_creator<first_transform_builder>(); } - void validity_check(validity_checker &valid) const { m_sink.validity_check(valid); } + bool validity_check(validity_checker &valid) const { return 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) @@ -1202,13 +1098,13 @@ private: 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) + [sink = m_sink.build(), cb = std::move(m_cb), in_exor = m_in_exor, in_mask = m_in_mask, exor = this->exor(), mask = this->mask()] (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)); + auto const trans(devcb_write::invoke_transform<input_t, output_t>(cb, offset, data, mem_mask)); mem_mask &= mask; - sink(space, offset, (trans ^ exor) & mask, mem_mask); + sink(offset, (trans ^ exor) & mask, mem_mask); }; } @@ -1223,14 +1119,14 @@ private: 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) + [f = std::move(chain), sink = m_sink.build(), cb = std::move(m_cb), in_exor = m_in_exor, in_mask = m_in_mask, exor = this->exor(), mask = this->mask()] (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)); + auto const trans_1(devcb_write::invoke_transform<input_t, output_t>(cb, 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); + auto const trans_n(f(offset, (trans_1 ^ exor) & mask, out_mask)); + sink(offset, trans_n, out_mask); }; } @@ -1253,15 +1149,15 @@ private: 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 { } + bool validity_check(validity_checker &valid) const { return true; } 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); }; + [cb = std::move(m_cb)] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) + { devcb_write::invoke_write<Input>(cb, offset, data, mem_mask); }; } private: @@ -1303,15 +1199,15 @@ private: 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(), DefaultMask); } - void validity_check(validity_checker &valid) const { } + bool validity_check(validity_checker &valid) const { return true; } 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); }; + [cb = std::move(m_cb), exor = this->exor(), mask = this->mask()] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) + { devcb_write::invoke_write<Input>(cb, offset, (data ^ exor) & mask, mem_mask & mask); }; } }; @@ -1328,7 +1224,6 @@ private: wrapped_builder(delegate_builder &&that) : builder_base(std::move(that)) - , m_devbase(that.m_devbase) , m_delegate(std::move(that.m_delegate)) { that.consume(); @@ -1336,27 +1231,31 @@ private: } 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 + bool 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 const target(m_delegate.finder_target()); + if (target.second && !target.first.subdevice(target.second)) + { + osd_printf_error("Write callback bound to non-existent object tag %s (%s)\n", target.first.subtag(target.second), m_delegate.name()); + return false; + } + return true; } auto build() { assert(this->m_consumed); this->built(); - m_delegate.bind_relative_to(m_devbase); + m_delegate.resolve(); 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); }; + [cb = std::move(m_delegate)] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) + { devcb_write::invoke_write<Input>(cb, offset, data, mem_mask); }; } private: @@ -1364,7 +1263,6 @@ private: wrapped_builder operator=(wrapped_builder const &) = delete; wrapped_builder operator=(wrapped_builder &&that) = delete; - device_t &m_devbase; Delegate m_delegate; }; @@ -1374,7 +1272,6 @@ private: delegate_builder &operator=(delegate_builder const &) = delete; delegate_builder &operator=(delegate_builder &&that) = delete; - device_t &m_devbase; Delegate m_delegate; public: @@ -1384,20 +1281,17 @@ private: 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)) + , m_delegate(devbase, tag, std::forward<T>(func), name) { } 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) + , m_delegate(obj, std::forward<T>(func), name) { } 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(); @@ -1413,20 +1307,25 @@ private: 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(), in_mask, out_mask); } - void validity_check(validity_checker &valid) const + bool 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 const target(m_delegate.finder_target()); + if (target.second && !target.first.subdevice(target.second)) + { + osd_printf_error("Write callback bound to non-existent object tag %s (%s)\n", target.first.subtag(target.second), m_delegate.name()); + return false; + } + return true; } auto build() { assert(this->m_consumed); this->built(); - m_delegate.bind_relative_to(m_devbase); + m_delegate.resolve(); 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); }; + [cb = std::move(m_delegate), exor = this->exor(), mask = this->mask()] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) + { devcb_write::invoke_write<Input>(cb, offset, (data ^ exor) & mask, mem_mask & mask); }; } }; @@ -1461,16 +1360,23 @@ private: that.built(); } - void validity_check(validity_checker &valid) const + bool 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); + return false; + } 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()); + return false; + } } + return true; } auto build() @@ -1487,7 +1393,7 @@ private: 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 = *m_exec, linenum = m_linenum] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) { exec.set_input_line(linenum, data); }; } @@ -1552,16 +1458,23 @@ private: 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(), in_mask, 1U); } - void validity_check(validity_checker &valid) const + bool 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); + return false; + } 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()); + return false; + } } + return true; } auto build() @@ -1578,7 +1491,7 @@ private: 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 = *m_exec, linenum = m_linenum, exor = this->exor(), mask = this->mask()] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) { exec.set_input_line(linenum, (data ^ exor) & mask); }; } }; @@ -1616,16 +1529,23 @@ private: that.built(); } - void validity_check(validity_checker &valid) const + bool 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); + return false; + } 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()); + return false; + } } + return true; } auto build() @@ -1642,7 +1562,7 @@ private: 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) + [&exec = *m_exec, linenum = m_linenum, value = m_value] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) { if (data) exec.set_input_line(linenum, value); }; } @@ -1711,16 +1631,23 @@ private: 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(), DefaultMask); } - void validity_check(validity_checker &valid) const + bool 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); + return false; + } 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()); + return false; + } } + return true; } auto build() @@ -1737,7 +1664,7 @@ private: 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) + [&exec = *m_exec, linenum = m_linenum, value = m_value, exor = this->exor(), mask = this->mask()] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) { if ((data ^ exor) & mask) exec.set_input_line(linenum, value); }; } }; @@ -1769,17 +1696,17 @@ private: that.built(); } - void validity_check(validity_checker &valid) const { } + bool validity_check(validity_checker &valid) const { return true; } auto build() { assert(this->m_consumed); this->built(); - ioport_port *const ioport(m_devbase.ioport(m_tag.c_str())); + ioport_port *const ioport(m_devbase.ioport(m_tag)); 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()); + throw emu_fatalerror("Write callback bound to non-existent I/O port %s of device %s (%s)\n", m_tag, 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 = *ioport] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) { port.write(data); }; } @@ -1827,17 +1754,17 @@ private: 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(), DefaultMask); } - void validity_check(validity_checker &valid) const { } + bool validity_check(validity_checker &valid) const { return true; } auto build() { assert(this->m_consumed); this->built(); - ioport_port *const ioport(m_devbase.ioport(m_tag.c_str())); + ioport_port *const ioport(m_devbase.ioport(m_tag)); 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()); + throw emu_fatalerror("Write callback bound to non-existent I/O port %s of device %s (%s)\n", m_tag, 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 = *ioport, exor = this->exor(), mask = this->mask()] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) { port.write((data ^ exor) & mask); }; } }; @@ -1869,17 +1796,17 @@ private: that.built(); } - void validity_check(validity_checker &valid) const { } + bool validity_check(validity_checker &valid) const { return true; } auto build() { assert(this->m_consumed); this->built(); - memory_bank *const bank(m_devbase.membank(m_tag.c_str())); + memory_bank *const bank(m_devbase.membank(m_tag)); 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()); + throw emu_fatalerror("Write callback bound to non-existent memory bank %s of device %s (%s)\n", m_tag, 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 = *bank] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) { membank.set_entry(data); }; } @@ -1927,17 +1854,17 @@ private: 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(), DefaultMask); } - void validity_check(validity_checker &valid) const { } + bool validity_check(validity_checker &valid) const { return true; } auto build() { assert(this->m_consumed); this->built(); - memory_bank *const bank(m_devbase.membank(m_tag.c_str())); + memory_bank *const bank(m_devbase.membank(m_tag)); 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()); + throw emu_fatalerror("Write callback bound to non-existent memory bank %s of device %s (%s)\n", m_tag, 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 = *bank, exor = this->exor(), mask = this->mask()] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) { membank.set_entry((data ^ exor) & mask); }; } }; @@ -1969,14 +1896,14 @@ private: that.built(); } - void validity_check(validity_checker &valid) const { } + bool validity_check(validity_checker &valid) const { return true; } 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 = m_devbase.machine().output().find_or_create_item(m_tag, 0)] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) { item.set(data); }; } @@ -2024,111 +1951,18 @@ private: 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(), DefaultMask); } - void validity_check(validity_checker &valid) const { } + bool validity_check(validity_checker &valid) const { return true; } 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 = m_devbase.machine().output().find_or_create_item(m_tag, 0), exor = this->exor(), mask = this->mask()] (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; - }; - - friend class wrapped_builder; // workaround for MSVC - - 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->mask(), DefaultMask); - } - - 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: @@ -2166,6 +2000,13 @@ private: return delegate_builder<delegate_type_t<T> >(m_target, m_append, m_target.owner(), devcb_write::cast_reference<delegate_device_class_t<T> >(obj), std::forward<T>(func), name); } + template <typename T> + std::enable_if_t<is_write_method<T>::value, delegate_builder<delegate_type_t<T> > > set(device_t &devbase, char const *tag, T &&func, char const *name) + { + set_used(); + return delegate_builder<delegate_type_t<T> >(m_target, m_append, devbase, tag, 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) { @@ -2310,43 +2151,17 @@ private: return set_output(std::forward<Params>(args)...); } - template <typename... Params> - log_builder set_log(device_t &devbase, Params &&... args) + void set_nop() { 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)...); + m_target.m_creators.clear(); + m_target.m_creators.emplace_back(std::make_unique<nop_creator>()); } - void set_nop() + void remove() { set_used(); m_target.m_creators.clear(); - m_target.m_creators.emplace_back(std::make_unique<nop_creator>()); } private: @@ -2359,25 +2174,32 @@ private: std::vector<func_t> m_functions; std::vector<typename creator::ptr> m_creators; + bool m_unset = false; + +protected: + virtual bool findit(validity_checker *valid) override; + virtual void end_configuration() override; public: + template <unsigned Count> + class array : public devcb_write_base::array<devcb_write<Input, DefaultMask>, Count> + { + public: + array(device_t &owner) + : devcb_write_base::array<devcb_write<Input, DefaultMask>, Count>::array(owner) + { + } + }; + devcb_write(device_t &owner); binder bind(); void reset(); - 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(); } + bool isunset() const noexcept { return m_unset || (m_functions.empty() && m_creators.empty()); } }; template <typename Input, std::make_unsigned_t<Input> DefaultMask> @@ -2389,6 +2211,7 @@ devcb_write<Input, DefaultMask>::devcb_write(device_t &owner) template <typename Input, std::make_unsigned_t<Input> DefaultMask> typename devcb_write<Input, DefaultMask>::binder devcb_write<Input, DefaultMask>::bind() { + assert(m_functions.empty()); return binder(*this); } @@ -2400,62 +2223,56 @@ void devcb_write<Input, DefaultMask>::reset() } template <typename Input, std::make_unsigned_t<Input> DefaultMask> -void devcb_write<Input, DefaultMask>::validity_check(validity_checker &valid) const +bool devcb_write<Input, DefaultMask>::findit(validity_checker *valid) { assert(m_functions.empty()); - devcb_write_base::validity_check(valid); - for (typename creator::ptr const &c : m_creators) - c->validity_check(valid); -} - -template <typename Input, std::make_unsigned_t<Input> DefaultMask> -void devcb_write<Input, DefaultMask>::resolve() -{ - 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(); + if (!valid) + { + // FIXME: report errors by returning false rather than throwing fatal errors + m_functions.reserve(m_creators.size()); + for (typename creator::ptr const &c : m_creators) + m_functions.emplace_back(c->create()); + m_creators.clear(); + if (m_functions.empty()) + { + m_functions.emplace_back([] (offs_t offset, Input data, std::make_unsigned_t<Input> mem_mask) { }); + m_unset = true; + } + return true; + } + else + { + bool success(true); + for (typename creator::ptr const &c : m_creators) + { + if (!c->validity_check(*valid)) + success = false; + } + return success; + } } template <typename Input, std::make_unsigned_t<Input> DefaultMask> -void devcb_write<Input, DefaultMask>::resolve_safe() +void devcb_write<Input, DefaultMask>::end_configuration() { - 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) +void devcb_write<Input, DefaultMask>::operator()(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); + (*it)(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); -} - -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); + (*it)(offset, data, mem_mask); } template <typename Input, std::make_unsigned_t<Input> DefaultMask> void devcb_write<Input, DefaultMask>::operator()(Input data) { - this->operator()(this->default_space(), 0U, data, DefaultMask); + this->operator()(0U, data, DefaultMask); } - using devcb_read8 = devcb_read<u8>; using devcb_read16 = devcb_read<u16>; using devcb_read32 = devcb_read<u32>; @@ -2479,10 +2296,6 @@ 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<read8s_delegate>; extern template class devcb_read8::delegate_builder<read16s_delegate>; extern template class devcb_read8::delegate_builder<read32s_delegate>; @@ -2497,10 +2310,6 @@ extern template class devcb_read8::delegate_builder<read32smo_delegate>; extern template class devcb_read8::delegate_builder<read64smo_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<read8s_delegate>; extern template class devcb_read16::delegate_builder<read16s_delegate>; extern template class devcb_read16::delegate_builder<read32s_delegate>; @@ -2515,10 +2324,6 @@ extern template class devcb_read16::delegate_builder<read32smo_delegate>; extern template class devcb_read16::delegate_builder<read64smo_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<read8s_delegate>; extern template class devcb_read32::delegate_builder<read16s_delegate>; extern template class devcb_read32::delegate_builder<read32s_delegate>; @@ -2533,10 +2338,6 @@ extern template class devcb_read32::delegate_builder<read32smo_delegate>; extern template class devcb_read32::delegate_builder<read64smo_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<read8s_delegate>; extern template class devcb_read64::delegate_builder<read16s_delegate>; extern template class devcb_read64::delegate_builder<read32s_delegate>; @@ -2551,10 +2352,6 @@ extern template class devcb_read64::delegate_builder<read32smo_delegate>; extern template class devcb_read64::delegate_builder<read64smo_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<read8s_delegate>; extern template class devcb_read_line::delegate_builder<read16s_delegate>; extern template class devcb_read_line::delegate_builder<read32s_delegate>; @@ -2569,10 +2366,6 @@ extern template class devcb_read_line::delegate_builder<read32smo_delegate>; extern template class devcb_read_line::delegate_builder<read64smo_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<read8s_delegate> >; extern template class devcb_read8::creator_impl<devcb_read8::delegate_builder<read16s_delegate> >; extern template class devcb_read8::creator_impl<devcb_read8::delegate_builder<read32s_delegate> >; @@ -2588,10 +2381,6 @@ extern template class devcb_read8::creator_impl<devcb_read8::delegate_builder<re 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<read8s_delegate> >; extern template class devcb_read16::creator_impl<devcb_read16::delegate_builder<read16s_delegate> >; extern template class devcb_read16::creator_impl<devcb_read16::delegate_builder<read32s_delegate> >; @@ -2607,10 +2396,6 @@ extern template class devcb_read16::creator_impl<devcb_read16::delegate_builder< 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<read8s_delegate> >; extern template class devcb_read32::creator_impl<devcb_read32::delegate_builder<read16s_delegate> >; extern template class devcb_read32::creator_impl<devcb_read32::delegate_builder<read32s_delegate> >; @@ -2626,10 +2411,6 @@ extern template class devcb_read32::creator_impl<devcb_read32::delegate_builder< 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<read8s_delegate> >; extern template class devcb_read64::creator_impl<devcb_read64::delegate_builder<read16s_delegate> >; extern template class devcb_read64::creator_impl<devcb_read64::delegate_builder<read32s_delegate> >; @@ -2645,10 +2426,6 @@ extern template class devcb_read64::creator_impl<devcb_read64::delegate_builder< 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<read8s_delegate> >; extern template class devcb_read_line::creator_impl<devcb_read_line::delegate_builder<read16s_delegate> >; extern template class devcb_read_line::creator_impl<devcb_read_line::delegate_builder<read32s_delegate> >; @@ -2670,10 +2447,6 @@ 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<write8s_delegate>; extern template class devcb_write8::delegate_builder<write16s_delegate>; extern template class devcb_write8::delegate_builder<write32s_delegate>; @@ -2688,10 +2461,6 @@ extern template class devcb_write8::delegate_builder<write32smo_delegate>; extern template class devcb_write8::delegate_builder<write64smo_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<write8s_delegate>; extern template class devcb_write16::delegate_builder<write16s_delegate>; extern template class devcb_write16::delegate_builder<write32s_delegate>; @@ -2706,10 +2475,6 @@ extern template class devcb_write16::delegate_builder<write32smo_delegate>; extern template class devcb_write16::delegate_builder<write64smo_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<write8s_delegate>; extern template class devcb_write32::delegate_builder<write16s_delegate>; extern template class devcb_write32::delegate_builder<write32s_delegate>; @@ -2724,10 +2489,6 @@ extern template class devcb_write32::delegate_builder<write32smo_delegate>; extern template class devcb_write32::delegate_builder<write64smo_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<write8s_delegate>; extern template class devcb_write64::delegate_builder<write16s_delegate>; extern template class devcb_write64::delegate_builder<write32s_delegate>; @@ -2742,10 +2503,6 @@ extern template class devcb_write64::delegate_builder<write32smo_delegate>; extern template class devcb_write64::delegate_builder<write64smo_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<write8s_delegate>; extern template class devcb_write_line::delegate_builder<write16s_delegate>; extern template class devcb_write_line::delegate_builder<write32s_delegate>; @@ -2760,10 +2517,6 @@ extern template class devcb_write_line::delegate_builder<write32smo_delegate>; extern template class devcb_write_line::delegate_builder<write64smo_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<write8s_delegate> >; extern template class devcb_write8::creator_impl<devcb_write8::delegate_builder<write16s_delegate> >; extern template class devcb_write8::creator_impl<devcb_write8::delegate_builder<write32s_delegate> >; @@ -2782,12 +2535,7 @@ extern template class devcb_write8::creator_impl<devcb_write8::latched_inputline 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<write8s_delegate> >; extern template class devcb_write16::creator_impl<devcb_write16::delegate_builder<write16s_delegate> >; extern template class devcb_write16::creator_impl<devcb_write16::delegate_builder<write32s_delegate> >; @@ -2806,12 +2554,7 @@ extern template class devcb_write16::creator_impl<devcb_write16::latched_inputli 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<write8s_delegate> >; extern template class devcb_write32::creator_impl<devcb_write32::delegate_builder<write16s_delegate> >; extern template class devcb_write32::creator_impl<devcb_write32::delegate_builder<write32s_delegate> >; @@ -2830,12 +2573,7 @@ extern template class devcb_write32::creator_impl<devcb_write32::latched_inputli 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<write8s_delegate> >; extern template class devcb_write64::creator_impl<devcb_write64::delegate_builder<write16s_delegate> >; extern template class devcb_write64::creator_impl<devcb_write64::delegate_builder<write32s_delegate> >; @@ -2854,12 +2592,7 @@ extern template class devcb_write64::creator_impl<devcb_write64::latched_inputli 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<write8s_delegate> >; extern template class devcb_write_line::creator_impl<devcb_write_line::delegate_builder<write16s_delegate> >; extern template class devcb_write_line::creator_impl<devcb_write_line::delegate_builder<write32s_delegate> >; @@ -2878,6 +2611,5 @@ extern template class devcb_write_line::creator_impl<devcb_write_line::latched_i 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 |