summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/devcb.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/devcb.h')
-rw-r--r--src/emu/devcb.h631
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