diff options
Diffstat (limited to 'src/emu/devcb.h')
-rw-r--r-- | src/emu/devcb.h | 631 |
1 files changed, 254 insertions, 377 deletions
diff --git a/src/emu/devcb.h b/src/emu/devcb.h index 816ce6b3810..be62d8b6365 100644 --- a/src/emu/devcb.h +++ b/src/emu/devcb.h @@ -48,12 +48,12 @@ typedef device_delegate<int ()> read_line_delegate; typedef device_delegate<void (int)> write_line_delegate; -namespace emu { namespace detail { +namespace emu::detail { 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 //************************************************************************** @@ -64,11 +64,8 @@ template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<write_ /// /// 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: - virtual void validity_check(validity_checker &valid) const = 0; - protected: // This is in C++17 but not C++14 template <typename... T> struct void_wrapper { using type = void; }; @@ -82,22 +79,16 @@ 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_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_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_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_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 @@ -112,8 +103,13 @@ protected: // 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 /// @@ -132,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))); } @@ -169,9 +171,9 @@ protected: class array : public std::array<T, Count> { private: - template <unsigned... V> - array(device_t &owner, std::integer_sequence<unsigned, V...> const &) - : std::array<T, Count>{{ { make_one<V>(owner) }... }} + 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)... }... }} { } @@ -180,12 +182,10 @@ protected: public: using std::array<T, Count>::array; - array(device_t &owner) : array(owner, std::make_integer_sequence<unsigned, Count>()) { } - - void resolve_all() + template <typename... Params> + array(device_t &owner, Params &&... args) + : array(owner, std::make_integer_sequence<unsigned, Count>(), std::forward<Params>(args)...) { - for (T &elem : *this) - elem.resolve(); } }; @@ -206,36 +206,33 @@ 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> struct is_read_form1<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_form2<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_form3<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; }; + 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 (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 (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 ()>; }; + 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<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, offs_t offset, std::make_unsigned_t<Result> mem_mask) { return std::make_unsigned_t<read_result_t<Result, T> >(cb(offset, mem_mask)); } @@ -270,29 +267,26 @@ 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> struct is_write_form1<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_form2<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_form3<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; }; + 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<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, offs_t &offset, Input data, std::make_unsigned_t<Input> mem_mask) { return cb(offset, data, mem_mask); } @@ -337,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; } @@ -354,7 +348,7 @@ 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 { @@ -367,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)] (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 @@ -468,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) @@ -489,7 +461,7 @@ 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()] (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(offset, source_mask)); @@ -536,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) @@ -544,7 +516,7 @@ private: assert(this->m_consumed); this->built(); chain( - [cb = std::move(this->m_cb), exor = this->exor(), mask = this->mask()] (offs_t offset, input_mask_t mem_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; }); } @@ -596,11 +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 { 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).c_str(), m_delegate.name()); + { + 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> @@ -610,7 +586,7 @@ private: this->built(); m_delegate.resolve(); chain( - [cb = std::move(this->m_delegate), exor = this->exor(), mask = this->mask()] (offs_t offset, input_mask_t mem_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; }); } @@ -656,16 +632,16 @@ 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()] (offs_t offset, input_mask_t mem_mask) { return (port.read() ^ exor) & mask; }); @@ -717,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) { @@ -770,40 +753,6 @@ 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)...); - } - - template <typename... Params> - void append_log(Params &&... args) - { - m_append = true; - set_log(std::forward<Params>(args)...); - } - auto set_constant(Result val) { return set([val] () { return val; }); } auto append_constant(Result val) { return append([val] () { return val; }); } @@ -817,47 +766,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: template <unsigned Count> class array : public devcb_read_base::array<devcb_read<Result, DefaultMask>, Count> { public: - using devcb_read_base::array<devcb_read<Result, DefaultMask>, Count>::array; - - void resolve_all_safe(Result dflt) + array(device_t &owner, Result dflt) + : devcb_read_base::array<devcb_read<Result, DefaultMask>, Count>::array(owner, dflt) { - for (devcb_read<Result, DefaultMask> &elem : *this) - elem.resolve_safe(dflt); } }; - devcb_read(device_t &owner); + 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()(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); } @@ -869,38 +817,48 @@ 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()); - 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()); - 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] (offs_t offset, std::make_unsigned_t<Result> mem_mask) { return dflt; }); } template <typename Result, std::make_unsigned_t<Result> DefaultMask> @@ -938,7 +896,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; }; @@ -948,7 +906,7 @@ 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 { @@ -962,7 +920,7 @@ private: class nop_creator : public creator { public: - virtual void validity_check(validity_checker &valid) const override { } + 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) { }; } }; @@ -1061,7 +1019,7 @@ private: }); } - 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; @@ -1074,7 +1032,7 @@ 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()] (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, offset, data, mem_mask)); output_t out_mask(mem_mask & mask); @@ -1118,7 +1076,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) @@ -1134,7 +1092,7 @@ 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()] (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; @@ -1155,7 +1113,7 @@ 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()] (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; @@ -1185,14 +1143,14 @@ 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)] (offs_t offset, input_t data, std::make_unsigned_t<input_t> 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); }; } @@ -1235,14 +1193,14 @@ 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()] (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) { devcb_write::invoke_write<Input>(cb, offset, (data ^ exor) & mask, mem_mask & mask); }; } }; @@ -1273,11 +1231,15 @@ private: that.built(); } - void validity_check(validity_checker &valid) const + bool validity_check(validity_checker &valid) const { 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).c_str(), m_delegate.name()); + { + 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() @@ -1286,7 +1248,7 @@ private: this->built(); m_delegate.resolve(); return - [cb = std::move(this->m_delegate)] (offs_t offset, input_t data, std::make_unsigned_t<input_t> 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); }; } @@ -1339,11 +1301,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(), in_mask, out_mask); } - void validity_check(validity_checker &valid) const + bool validity_check(validity_checker &valid) const { 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).c_str(), m_delegate.name()); + { + 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() @@ -1352,7 +1318,7 @@ private: this->built(); m_delegate.resolve(); return - [cb = std::move(this->m_delegate), exor = this->exor(), mask = this->mask()] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_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); }; } }; @@ -1388,16 +1354,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() @@ -1479,16 +1452,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() @@ -1543,16 +1523,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() @@ -1638,16 +1625,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() @@ -1696,15 +1690,15 @@ 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] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) { port.write(data); }; @@ -1754,15 +1748,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(); - 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()] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) { port.write((data ^ exor) & mask); }; @@ -1796,15 +1790,15 @@ 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] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) { membank.set_entry(data); }; @@ -1854,15 +1848,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(); - 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()] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) { membank.set_entry((data ^ exor) & mask); }; @@ -1896,14 +1890,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)] (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); }; } @@ -1951,111 +1945,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()] (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)] (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()] (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: @@ -2093,6 +1994,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) { @@ -2237,38 +2145,6 @@ private: return set_output(std::forward<Params>(args)...); } - template <typename... Params> - log_builder set_log(device_t &devbase, Params &&... args) - { - set_used(); - return log_builder(m_target, m_append, devbase, std::string(std::forward<Params>(args)...)); - } - - template <typename T, typename... Params> - std::enable_if_t<emu::detail::is_device_implementation<std::remove_reference_t<T> >::value, log_builder> set_log(T &devbase, Params &&... args) - { - return set_log(static_cast<device_t &>(devbase), std::forward<Params>(args)...); - } - - template <typename T, typename... Params> - std::enable_if_t<emu::detail::is_device_interface<std::remove_reference_t<T> >::value, log_builder> set_log(T &devbase, Params &&... args) - { - return set_log(devbase.device(), std::forward<Params>(args)...); - } - - template <typename... Params> - log_builder set_log(Params &&... args) - { - return set_log(m_target.owner().mconfig().current_device(), std::forward<Params>(args)...); - } - - template <typename... Params> - log_builder append_log(Params &&... args) - { - m_append = true; - return set_log(std::forward<Params>(args)...); - } - void set_nop() { set_used(); @@ -2286,18 +2162,20 @@ 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: - using devcb_write_base::array<devcb_write<Input, DefaultMask>, Count>::array; - - void resolve_all_safe() + array(device_t &owner) + : devcb_write_base::array<devcb_write<Input, DefaultMask>, Count>::array(owner) { - for (devcb_write<Input, DefaultMask> &elem : *this) - elem.resolve_safe(); } }; @@ -2306,16 +2184,10 @@ public: binder bind(); void reset(); - virtual void validity_check(validity_checker &valid) const override; - - void resolve(); - void resolve_safe(); - 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> @@ -2327,6 +2199,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); } @@ -2338,29 +2211,38 @@ 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()); - 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()); - 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([] (offs_t offset, Input data, std::make_unsigned_t<Input> mem_mask) { }); } template <typename Input, std::make_unsigned_t<Input> DefaultMask> @@ -2641,7 +2523,6 @@ 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<write8s_delegate> >; extern template class devcb_write16::creator_impl<devcb_write16::delegate_builder<write16s_delegate> >; @@ -2661,7 +2542,6 @@ 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<write8s_delegate> >; extern template class devcb_write32::creator_impl<devcb_write32::delegate_builder<write16s_delegate> >; @@ -2681,7 +2561,6 @@ 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<write8s_delegate> >; extern template class devcb_write64::creator_impl<devcb_write64::delegate_builder<write16s_delegate> >; @@ -2701,7 +2580,6 @@ 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<write8s_delegate> >; extern template class devcb_write_line::creator_impl<devcb_write_line::delegate_builder<write16s_delegate> >; @@ -2721,6 +2599,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 |