summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/devcb.cpp
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2018-07-07 02:40:29 +1000
committer Vas Crabb <vas@vastheman.com>2018-07-07 02:40:29 +1000
commitc3fb11c2c98a5c28ece6a27093a0f9def350ac64 (patch)
treec68b38f05ed1d32358add721fda7f45e8803479f /src/emu/devcb.cpp
parent5d9e33b786d7ef452317439359f3cbd8cc920513 (diff)
devcb3
There are multiple issues with the current device callbacks: * They always dispatch through a pointer-to-member * Chained callbacks are a linked list so the branch unit can't predict the early * There's a runtime decision made on the left/right shift direction * There are runtime NULL checks on various objects * Binding a lambda isn't practical * Arbitrary transformations are not supported * When chaining callbacks it isn't clear what the MCFG_DEVCB_ modifiers apply to * It isn't possible to just append to a callback in derived configuration * The macros need a magic, hidden local called devcb * Moving code that uses the magic locals around is error-prone * Writing the MCFG_ macros to make a device usable is a pain * You can't discover applicable MCFG_ macros with intellisense * Macros are not scoped * Using an inappropriate macro isn't detected at compile time * Lots of other things This changeset overcomes the biggest obstacle to remving MCFG_ macros altogether. Essentially, to allow a devcb to be configured, call .bind() and expose the result (a bind target for the callback). Bind target methods starting with "set" repace the current callbacks; methods starting with "append" append to them. You can't reconfigure a callback after resolving it. There's no need to use a macro matching the handler signatures - use FUNC for everything. Current device is implied if no tag/finder is supplied (no need for explicit this). Lambdas are supported, and the memory space and offset are optional. These kinds of things work: * .read_cb().set([this] () { return something; }); * .read_cb().set([this] (offs_t offset) { return ~offset; }); * .write_cb().set([this] (offs_t offset, u8 data) { m_array[offset] = data; }); * .write_cb().set([this] (int state) { some_var = state; }); Arbitrary transforms are allowed, and they can modify offset/mask for example: * .read_cb().set(FUNC(my_state::handler)).transform([] (u8 data) { return bitswap<4>(data, 1, 3, 0, 2); }); * .read_cb().set(m_dev, FUNC(some_device::member)).transform([] (offs_t &offset, u8 data) { offset ^= 3; return data; }); It's possible to stack arbitrary transforms, at the cost of compile time (the whole transform stack gets inlined at compile time). Shifts count as an arbitrary transform, but mask/exor does not. Order of mask/shift/exor now matters. Modifications are applied in the specified order. These are NOT EQUIVALENT: * .read_cb().set(FUNC(my_state::handler)).mask(0x06).lshift(2); * .read_cb().set(FUNC(my_state::handler)).lshift(2).mask(0x06); The bit helper no longer reverses its behaviour for read callbacks, and I/O ports are no longer aware of the field mask. Binding a read callback to no-op is not supported - specify a constant. The GND and VCC aliases have been removed intentionally - they're TTL-centric, and were already being abused. Other quirks have been preserved, including write logger only logging when the data is non-zero (quite unhelpful in many of the cases where it's used). Legacy syntax is still supported for simple cases, but will be phased out. New devices should not have MCFG_ macros. I don't think I've missed any fundamental issues, but if I've broken something, let me know.
Diffstat (limited to 'src/emu/devcb.cpp')
-rw-r--r--src/emu/devcb.cpp1031
1 files changed, 192 insertions, 839 deletions
diff --git a/src/emu/devcb.cpp b/src/emu/devcb.cpp
index d22a9667e81..75e43ad606e 100644
--- a/src/emu/devcb.cpp
+++ b/src/emu/devcb.cpp
@@ -1,875 +1,228 @@
// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
+// copyright-holders:Vas Crabb
/***************************************************************************
- devcb.c
+ devcb.cpp
Device callback interface helpers.
***************************************************************************/
#include "emu.h"
-
-
-
-//**************************************************************************
-// DEVCB BASE CLASS
-//**************************************************************************
-
-//-------------------------------------------------
-// devcb_base - constructor
-//-------------------------------------------------
-
-devcb_base::devcb_base(device_t &device, u64 defmask)
- : m_owner(device)
- , m_base(device)
- , m_type(CALLBACK_NONE)
- , m_target_tag(nullptr)
- , m_target_int(0)
- , m_space_tag(nullptr)
- , m_space_num(0)
- , m_space(nullptr)
- , m_rshift(0)
- , m_mask(defmask)
- , m_defmask(defmask)
- , m_xor(0)
-{
- m_target.ptr = nullptr;
+#include "devcb.h"
+
+template class devcb_read<u8>;
+template class devcb_read<u16>;
+template class devcb_read<u32>;
+template class devcb_read<u64>;
+template class devcb_read<int, 1U>;
+
+template class devcb_read8::delegate_builder<read8_delegate>;
+template class devcb_read8::delegate_builder<read16_delegate>;
+template class devcb_read8::delegate_builder<read32_delegate>;
+template class devcb_read8::delegate_builder<read64_delegate>;
+template class devcb_read8::delegate_builder<read_line_delegate>;
+
+template class devcb_read16::delegate_builder<read8_delegate>;
+template class devcb_read16::delegate_builder<read16_delegate>;
+template class devcb_read16::delegate_builder<read32_delegate>;
+template class devcb_read16::delegate_builder<read64_delegate>;
+template class devcb_read16::delegate_builder<read_line_delegate>;
+
+template class devcb_read32::delegate_builder<read8_delegate>;
+template class devcb_read32::delegate_builder<read16_delegate>;
+template class devcb_read32::delegate_builder<read32_delegate>;
+template class devcb_read32::delegate_builder<read64_delegate>;
+template class devcb_read32::delegate_builder<read_line_delegate>;
+
+template class devcb_read64::delegate_builder<read8_delegate>;
+template class devcb_read64::delegate_builder<read16_delegate>;
+template class devcb_read64::delegate_builder<read32_delegate>;
+template class devcb_read64::delegate_builder<read64_delegate>;
+template class devcb_read64::delegate_builder<read_line_delegate>;
+
+template class devcb_read_line::delegate_builder<read8_delegate>;
+template class devcb_read_line::delegate_builder<read16_delegate>;
+template class devcb_read_line::delegate_builder<read32_delegate>;
+template class devcb_read_line::delegate_builder<read64_delegate>;
+template class devcb_read_line::delegate_builder<read_line_delegate>;
+
+template class devcb_read8::creator_impl<devcb_read8::delegate_builder<read8_delegate> >;
+template class devcb_read8::creator_impl<devcb_read8::delegate_builder<read16_delegate> >;
+template class devcb_read8::creator_impl<devcb_read8::delegate_builder<read32_delegate> >;
+template class devcb_read8::creator_impl<devcb_read8::delegate_builder<read64_delegate> >;
+template class devcb_read8::creator_impl<devcb_read8::delegate_builder<read_line_delegate> >;
+template class devcb_read8::creator_impl<devcb_read8::ioport_builder>;
+
+template class devcb_read16::creator_impl<devcb_read16::delegate_builder<read8_delegate> >;
+template class devcb_read16::creator_impl<devcb_read16::delegate_builder<read16_delegate> >;
+template class devcb_read16::creator_impl<devcb_read16::delegate_builder<read32_delegate> >;
+template class devcb_read16::creator_impl<devcb_read16::delegate_builder<read64_delegate> >;
+template class devcb_read16::creator_impl<devcb_read16::delegate_builder<read_line_delegate> >;
+template class devcb_read16::creator_impl<devcb_read16::ioport_builder>;
+
+template class devcb_read32::creator_impl<devcb_read32::delegate_builder<read8_delegate> >;
+template class devcb_read32::creator_impl<devcb_read32::delegate_builder<read16_delegate> >;
+template class devcb_read32::creator_impl<devcb_read32::delegate_builder<read32_delegate> >;
+template class devcb_read32::creator_impl<devcb_read32::delegate_builder<read64_delegate> >;
+template class devcb_read32::creator_impl<devcb_read32::delegate_builder<read_line_delegate> >;
+template class devcb_read32::creator_impl<devcb_read32::ioport_builder>;
+
+template class devcb_read64::creator_impl<devcb_read64::delegate_builder<read8_delegate> >;
+template class devcb_read64::creator_impl<devcb_read64::delegate_builder<read16_delegate> >;
+template class devcb_read64::creator_impl<devcb_read64::delegate_builder<read32_delegate> >;
+template class devcb_read64::creator_impl<devcb_read64::delegate_builder<read64_delegate> >;
+template class devcb_read64::creator_impl<devcb_read64::delegate_builder<read_line_delegate> >;
+template class devcb_read64::creator_impl<devcb_read64::ioport_builder>;
+
+template class devcb_read_line::creator_impl<devcb_read_line::delegate_builder<read8_delegate> >;
+template class devcb_read_line::creator_impl<devcb_read_line::delegate_builder<read16_delegate> >;
+template class devcb_read_line::creator_impl<devcb_read_line::delegate_builder<read32_delegate> >;
+template class devcb_read_line::creator_impl<devcb_read_line::delegate_builder<read64_delegate> >;
+template class devcb_read_line::creator_impl<devcb_read_line::delegate_builder<read_line_delegate> >;
+template class devcb_read_line::creator_impl<devcb_read_line::ioport_builder>;
+
+template class devcb_write<u8>;
+template class devcb_write<u16>;
+template class devcb_write<u32>;
+template class devcb_write<u64>;
+template class devcb_write<int, 1U>;
+
+template class devcb_write8::delegate_builder<write8_delegate>;
+template class devcb_write8::delegate_builder<write16_delegate>;
+template class devcb_write8::delegate_builder<write32_delegate>;
+template class devcb_write8::delegate_builder<write64_delegate>;
+template class devcb_write8::delegate_builder<write_line_delegate>;
+
+template class devcb_write16::delegate_builder<write8_delegate>;
+template class devcb_write16::delegate_builder<write16_delegate>;
+template class devcb_write16::delegate_builder<write32_delegate>;
+template class devcb_write16::delegate_builder<write64_delegate>;
+template class devcb_write16::delegate_builder<write_line_delegate>;
+
+template class devcb_write32::delegate_builder<write8_delegate>;
+template class devcb_write32::delegate_builder<write16_delegate>;
+template class devcb_write32::delegate_builder<write32_delegate>;
+template class devcb_write32::delegate_builder<write64_delegate>;
+template class devcb_write32::delegate_builder<write_line_delegate>;
+
+template class devcb_write64::delegate_builder<write8_delegate>;
+template class devcb_write64::delegate_builder<write16_delegate>;
+template class devcb_write64::delegate_builder<write32_delegate>;
+template class devcb_write64::delegate_builder<write64_delegate>;
+template class devcb_write64::delegate_builder<write_line_delegate>;
+
+template class devcb_write_line::delegate_builder<write8_delegate>;
+template class devcb_write_line::delegate_builder<write16_delegate>;
+template class devcb_write_line::delegate_builder<write32_delegate>;
+template class devcb_write_line::delegate_builder<write64_delegate>;
+template class devcb_write_line::delegate_builder<write_line_delegate>;
+
+template class devcb_write8::creator_impl<devcb_write8::delegate_builder<write8_delegate> >;
+template class devcb_write8::creator_impl<devcb_write8::delegate_builder<write16_delegate> >;
+template class devcb_write8::creator_impl<devcb_write8::delegate_builder<write32_delegate> >;
+template class devcb_write8::creator_impl<devcb_write8::delegate_builder<write64_delegate> >;
+template class devcb_write8::creator_impl<devcb_write8::delegate_builder<write_line_delegate> >;
+template class devcb_write8::creator_impl<devcb_write8::inputline_builder>;
+template class devcb_write8::creator_impl<devcb_write8::latched_inputline_builder>;
+template class devcb_write8::creator_impl<devcb_write8::ioport_builder>;
+template class devcb_write8::creator_impl<devcb_write8::membank_builder>;
+template class devcb_write8::creator_impl<devcb_write8::output_builder>;
+template class devcb_write8::creator_impl<devcb_write8::log_builder>;
+
+template class devcb_write16::creator_impl<devcb_write16::delegate_builder<write8_delegate> >;
+template class devcb_write16::creator_impl<devcb_write16::delegate_builder<write16_delegate> >;
+template class devcb_write16::creator_impl<devcb_write16::delegate_builder<write32_delegate> >;
+template class devcb_write16::creator_impl<devcb_write16::delegate_builder<write64_delegate> >;
+template class devcb_write16::creator_impl<devcb_write16::delegate_builder<write_line_delegate> >;
+template class devcb_write16::creator_impl<devcb_write16::inputline_builder>;
+template class devcb_write16::creator_impl<devcb_write16::latched_inputline_builder>;
+template class devcb_write16::creator_impl<devcb_write16::ioport_builder>;
+template class devcb_write16::creator_impl<devcb_write16::membank_builder>;
+template class devcb_write16::creator_impl<devcb_write16::output_builder>;
+template class devcb_write16::creator_impl<devcb_write16::log_builder>;
+
+template class devcb_write32::creator_impl<devcb_write32::delegate_builder<write8_delegate> >;
+template class devcb_write32::creator_impl<devcb_write32::delegate_builder<write16_delegate> >;
+template class devcb_write32::creator_impl<devcb_write32::delegate_builder<write32_delegate> >;
+template class devcb_write32::creator_impl<devcb_write32::delegate_builder<write64_delegate> >;
+template class devcb_write32::creator_impl<devcb_write32::delegate_builder<write_line_delegate> >;
+template class devcb_write32::creator_impl<devcb_write32::inputline_builder>;
+template class devcb_write32::creator_impl<devcb_write32::latched_inputline_builder>;
+template class devcb_write32::creator_impl<devcb_write32::ioport_builder>;
+template class devcb_write32::creator_impl<devcb_write32::membank_builder>;
+template class devcb_write32::creator_impl<devcb_write32::output_builder>;
+template class devcb_write32::creator_impl<devcb_write32::log_builder>;
+
+template class devcb_write64::creator_impl<devcb_write64::delegate_builder<write8_delegate> >;
+template class devcb_write64::creator_impl<devcb_write64::delegate_builder<write16_delegate> >;
+template class devcb_write64::creator_impl<devcb_write64::delegate_builder<write32_delegate> >;
+template class devcb_write64::creator_impl<devcb_write64::delegate_builder<write64_delegate> >;
+template class devcb_write64::creator_impl<devcb_write64::delegate_builder<write_line_delegate> >;
+template class devcb_write64::creator_impl<devcb_write64::inputline_builder>;
+template class devcb_write64::creator_impl<devcb_write64::latched_inputline_builder>;
+template class devcb_write64::creator_impl<devcb_write64::ioport_builder>;
+template class devcb_write64::creator_impl<devcb_write64::membank_builder>;
+template class devcb_write64::creator_impl<devcb_write64::output_builder>;
+template class devcb_write64::creator_impl<devcb_write64::log_builder>;
+
+template class devcb_write_line::creator_impl<devcb_write_line::delegate_builder<write8_delegate> >;
+template class devcb_write_line::creator_impl<devcb_write_line::delegate_builder<write16_delegate> >;
+template class devcb_write_line::creator_impl<devcb_write_line::delegate_builder<write32_delegate> >;
+template class devcb_write_line::creator_impl<devcb_write_line::delegate_builder<write64_delegate> >;
+template class devcb_write_line::creator_impl<devcb_write_line::delegate_builder<write_line_delegate> >;
+template class devcb_write_line::creator_impl<devcb_write_line::inputline_builder>;
+template class devcb_write_line::creator_impl<devcb_write_line::latched_inputline_builder>;
+template class devcb_write_line::creator_impl<devcb_write_line::ioport_builder>;
+template class devcb_write_line::creator_impl<devcb_write_line::membank_builder>;
+template class devcb_write_line::creator_impl<devcb_write_line::output_builder>;
+template class devcb_write_line::creator_impl<devcb_write_line::log_builder>;
+
+
+devcb_base::devcb_base(device_t &owner)
+ : m_owner(owner)
+ , m_dflt_space_finder(owner, finder_base::DUMMY_TAG)
+ , m_dflt_space_index(-1)
+ , m_dflt_space(nullptr)
+{
+ owner.register_callback(*this);
}
-//-------------------------------------------------
-// devcb_base - destructor
-//-------------------------------------------------
-
devcb_base::~devcb_base()
{
}
-//-------------------------------------------------
-// reset - reset/initialize state
-//-------------------------------------------------
-
-void devcb_base::reset(callback_type type)
-{
- reset(m_owner.mconfig().current_device(), type);
-}
-
-void devcb_base::reset(device_t &base, callback_type type)
-{
- m_base = base;
- m_type = type;
- m_target_tag = nullptr;
- m_target_int = 0;
- m_space_tag = nullptr;
- m_space_num = 0;
- m_space = nullptr;
- m_target.ptr = nullptr;
- m_rshift = 0;
- m_mask = m_defmask;
- m_xor = 0;
- devcb_reset();
-}
-
-
-//-------------------------------------------------
-// resolve_ioport - resolve an I/O port or fatal
-// error if we can't find it
-//-------------------------------------------------
-
-void devcb_base::resolve_ioport()
-{
- // attempt to resolve, fatal error if fail
- m_target.ioport = m_target_tag ? m_base.get().ioport(m_target_tag) : nullptr;
- if (!m_target.ioport)
- throw emu_fatalerror("Unable to resolve I/O port callback reference to '%s' in device '%s'\n", m_target_tag, m_base.get().tag());
-
- // adjust the mask to match the port bits
- u64 port_mask = 0;
- for (const ioport_field &field : m_target.ioport->fields())
- port_mask |= field.mask();
- m_mask = shift_mask(port_mask);
-}
-
-
-//-------------------------------------------------
-// resolve_membank - resolve a memory bank or
-// fatal error if we can't find it
-//-------------------------------------------------
-
-void devcb_base::resolve_membank()
-{
- // attempt to resolve, fatal error if fail
- m_target.membank = m_target_tag ? m_base.get().membank(m_target_tag) : nullptr;
- if (!m_target.membank)
- throw emu_fatalerror("Unable to resolve memory bank callback reference to '%s' in device '%s'\n", m_target_tag, m_base.get().tag());
-}
-
-
-//-------------------------------------------------
-// resolve_output - resolve an output item
-//-------------------------------------------------
-
-void devcb_base::resolve_output()
-{
- assert(m_target_tag);
- m_target.item = &m_base.get().machine().output().find_or_create_item(m_target_tag, 0);
-}
-
-
-//-------------------------------------------------
-// resolve_inputline - resolve a device and input
-// number or fatal error if we can't find it
-//-------------------------------------------------
-
-void devcb_base::resolve_inputline()
-{
- // attempt to resolve, fatal error if fail
- m_target.device = m_target_tag ? m_base.get().subdevice(m_target_tag) : nullptr;
- if (!m_target.device)
- throw emu_fatalerror("Unable to resolve device reference to '%s' in device '%s'\n", m_target_tag, m_base.get().tag());
-
- // make sure we have an execute interface
- device_execute_interface *exec;
- if (!m_target.device->interface(exec))
- throw emu_fatalerror("No execute interface found for device reference to '%s' in device '%s'\n", m_target_tag, m_base.get().tag());
-}
-
-
-//-------------------------------------------------
-// resolve_space - resolve an address space or
-// fatal error if we can't find it
-//-------------------------------------------------
-
-void devcb_base::resolve_space()
-{
- // attempt to resolve, fatal error if fail
- device_t *const spacedev(m_space_tag ? m_base.get().subdevice(m_space_tag) : nullptr);
- if (!spacedev)
- throw emu_fatalerror("Unable to resolve device reference to '%s' in device '%s'\n", m_space_tag, m_base.get().tag());
- if (!spacedev->memory().has_space(m_space_num))
- throw emu_fatalerror("Unable to resolve device address space %d on '%s' in device '%s'\n", m_space_num, m_space_tag, m_base.get().tag());
- m_space = &spacedev->memory().space(m_space_num);
-}
-
-
-
-//**************************************************************************
-// DEVCB READ CLASS
-//**************************************************************************
-
-//-------------------------------------------------
-// devcb_read_base - constructor
-//-------------------------------------------------
-
-devcb_read_base::devcb_read_base(device_t &device, u64 defmask, bool chained)
- : devcb_base(device, defmask),
- m_adapter(&devcb_read_base::read_unresolved_adapter)
-{
- if (!chained)
- device.m_input_callbacks.push_back(this);
-}
-
-
-//-------------------------------------------------
-// devcb_reset - reset/initialize local state
-//-------------------------------------------------
-
-void devcb_read_base::devcb_reset()
-{
- m_readline = read_line_delegate();
- m_read8 = read8_delegate();
- m_read16 = read16_delegate();
- m_read32 = read32_delegate();
- m_read64 = read64_delegate();
- m_adapter = &devcb_read_base::read_unresolved_adapter;
- m_chain = nullptr;
-}
-
-
-//-------------------------------------------------
-// chain_alloc - add another callback to the
-// input chain
-//-------------------------------------------------
-
-devcb_read_base &devcb_read_base::chain_alloc()
-{
- // set up the chained callback pointer
- m_chain.reset(new devcb_read_base(m_owner, m_defmask, true));
- return *m_chain;
-}
-
-
-//-------------------------------------------------
-// resolve - resolve the specified callback to
-// its final form
-//-------------------------------------------------
-
-void devcb_read_base::resolve()
+void devcb_base::validity_check(validity_checker &valid) const
{
- // first resolve any address spaces
- if (m_space_tag)
- resolve_space();
- else
- m_space = &m_owner.machine().dummy_space();
-
- // then handle the various types
- const char *name = "unknown";
- try
- {
- switch (m_type)
- {
- case CALLBACK_NONE:
- break;
-
- case CALLBACK_LINE:
- name = m_readline.name();
- m_readline.bind_relative_to(m_base);
- m_target_int = 0;
- m_adapter = m_readline.isnull() ? &devcb_read_base::read_constant_adapter : &devcb_read_base::read_line_adapter;
- m_mask = shift_mask(1);
- break;
-
- case CALLBACK_8:
- name = m_read8.name();
- m_read8.bind_relative_to(m_base);
- m_target_int = 0;
- m_adapter = m_read8.isnull() ? &devcb_read_base::read_constant_adapter : &devcb_read_base::read8_adapter;
- m_mask = shift_mask(0xff);
- break;
-
- case CALLBACK_16:
- name = m_read16.name();
- m_read16.bind_relative_to(m_base);
- m_target_int = 0;
- m_adapter = m_read16.isnull() ? &devcb_read_base::read_constant_adapter : &devcb_read_base::read16_adapter;
- m_mask = shift_mask(0xffff);
- break;
-
- case CALLBACK_32:
- name = m_read32.name();
- m_read32.bind_relative_to(m_base);
- m_target_int = 0;
- m_adapter = m_read32.isnull() ? &devcb_read_base::read_constant_adapter : &devcb_read_base::read32_adapter;
- m_mask = shift_mask(0xffffffff);
- break;
-
- case CALLBACK_64:
- name = m_read64.name();
- m_read64.bind_relative_to(m_base);
- m_target_int = 0;
- m_adapter = m_read64.isnull() ? &devcb_read_base::read_constant_adapter : &devcb_read_base::read64_adapter;
- break;
-
- case CALLBACK_IOPORT:
- name = m_target_tag;
- resolve_ioport();
- m_target_int = 0;
- m_adapter = &devcb_read_base::read_ioport_adapter;
- break;
-
- case CALLBACK_MEMBANK:
- throw emu_fatalerror("Device read callbacks can't be connected to bank switches\n");
-
- case CALLBACK_OUTPUT:
- throw emu_fatalerror("Device read callbacks can't be connected to output items\n");
-
- case CALLBACK_LOG:
- m_adapter = &devcb_read_base::read_logged_adapter;
- m_mask = 0;
- break;
-
- case CALLBACK_CONSTANT:
- if (m_xor != 0)
- throw emu_fatalerror("devcb_read: Attempt to invert constant value (%lX ^ %lX)\n", (unsigned long)shift_mask(m_target_int), (unsigned long)m_xor);
- m_adapter = &devcb_read_base::read_constant_adapter;
- m_mask = shift_mask(m_target_int);
- break;
-
- case CALLBACK_INPUTLINE:
- case CALLBACK_ASSERTLINE:
- case CALLBACK_CLEARLINE:
- case CALLBACK_HOLDLINE:
- throw emu_fatalerror("Device read callbacks can't be connected to input lines\n");
- }
- }
- catch (binding_type_exception &binderr)
+ // if a default address space is configured, ensure it exists
+ if (m_dflt_space_finder)
{
- throw emu_fatalerror("devcb_read: Error performing a late bind of type %s to %s (name=%s)\n", binderr.m_actual_type.name(), binderr.m_target_type.name(), name);
+ if (!m_dflt_space_finder->has_space(m_dflt_space_index))
+ osd_printf_error("Callback references non-existent memory space %d of device %s (%s)\n", m_dflt_space_index, m_dflt_space_finder->device().tag(), m_dflt_space_finder->device().name());
}
-
- // resolve callback chain recursively
- if (m_chain != nullptr)
- m_chain->resolve();
-
- // protect against bus contention (the masks must not overlap)
- for (const devcb_read_base *chained_cb = m_chain.get(); chained_cb != nullptr; chained_cb = chained_cb->m_chain.get())
- if ((m_mask & chained_cb->m_mask) != 0)
- throw emu_fatalerror("Device %s read callback (name=%s) overlaps with chained callback (%lX & %lX)", m_owner.tag(), name, (unsigned long)m_mask, (unsigned long)chained_cb->m_mask);
-}
-
-
-//-------------------------------------------------
-// resolve_safe - resolve the callback; if not
-// specified, resolve to a constant callback with
-// the given value
-//-------------------------------------------------
-
-void devcb_read_base::resolve_safe(u64 none_constant_value)
-{
- // convert to a constant if none specified
- if (m_type == CALLBACK_NONE)
+ else if (m_dflt_space_finder.finder_tag() != finder_base::DUMMY_TAG)
{
- m_target_int = none_constant_value;
- m_type = CALLBACK_CONSTANT;
+ osd_printf_error("Callback references non-existent memory space device tag %s\n", m_dflt_space_finder.finder_tag());
}
- resolve();
-}
-
-
-//-------------------------------------------------
-// read_unresolved_adapter - error-generating
-// unresolved adapter
-//-------------------------------------------------
-
-u64 devcb_read_base::read_unresolved_adapter(address_space &space, offs_t offset, u64 mask)
-{
- throw emu_fatalerror("Attempted to read through an unresolved devcb item");
-}
-
-
-//-------------------------------------------------
-// read_line_adapter - read from a line delegate
-//-------------------------------------------------
-
-u64 devcb_read_base::read_line_adapter(address_space &space, offs_t offset, u64 mask)
-{
- return shift_mask_xor(m_readline() & 1);
-}
-
-
-//-------------------------------------------------
-// read8_adapter - read from an 8-bit delegate
-//-------------------------------------------------
-
-u64 devcb_read_base::read8_adapter(address_space &space, offs_t offset, u64 mask)
-{
- return shift_mask_xor(m_read8(space, offset, unshift_mask(mask)));
-}
-
-
-//-------------------------------------------------
-// read16_adapter - read from a 16-bit delegate
-//-------------------------------------------------
-
-u64 devcb_read_base::read16_adapter(address_space &space, offs_t offset, u64 mask)
-{
- return shift_mask_xor(m_read16(space, offset, unshift_mask(mask)));
-}
-
-
-//-------------------------------------------------
-// read32_adapter - read from a 32-bit delegate
-//-------------------------------------------------
-
-u64 devcb_read_base::read32_adapter(address_space &space, offs_t offset, u64 mask)
-{
- return shift_mask_xor(m_read32(space, offset, unshift_mask(mask)));
-}
-
-
-//-------------------------------------------------
-// read64_adapter - read from a 64-bit delegate
-//-------------------------------------------------
-
-u64 devcb_read_base::read64_adapter(address_space &space, offs_t offset, u64 mask)
-{
- return shift_mask_xor(m_read64(space, offset, unshift_mask(mask)));
-}
-
-
-//-------------------------------------------------
-// read_ioport - read from an I/O port
-//-------------------------------------------------
-
-u64 devcb_read_base::read_ioport_adapter(address_space &space, offs_t offset, u64 mask)
-{
- return shift_mask_xor(m_target.ioport->read());
-}
-
-
-//-------------------------------------------------
-// read_logged_adapter - log a read and return
-// zero
-//-------------------------------------------------
-
-u64 devcb_read_base::read_logged_adapter(address_space &space, offs_t offset, u64 mask)
-{
- m_owner.logerror("%s: %s\n", m_base.get().machine().describe_context(), m_target_tag);
- return 0;
}
-//-------------------------------------------------
-// read_constant - read from a constant
-//-------------------------------------------------
-
-u64 devcb_read_base::read_constant_adapter(address_space &space, offs_t offset, u64 mask)
+void devcb_base::resolve()
{
- return shift_mask(m_target_int);
-}
-
-
-//-------------------------------------------------
-// validity_check - check the validity of the
-// callback object
-//-------------------------------------------------
-
-void devcb_read_base::validity_check(validity_checker &valid) const
-{
- switch (m_type)
- {
- case CALLBACK_NONE:
- case CALLBACK_CONSTANT:
- case CALLBACK_LOG:
- case CALLBACK_IOPORT:
- break;
-
- case CALLBACK_LINE:
- if (!m_base.get().subdevice(m_readline.device_name()))
- osd_printf_error("Device %s not found for READLINE callback (%s)\n", m_readline.device_name(), m_readline.name());
- break;
-
- case CALLBACK_8:
- if (!m_base.get().subdevice(m_read8.device_name()))
- osd_printf_error("Device %s not found for READ8 callback (%s)\n", m_read8.device_name(), m_read8.name());
- break;
-
- case CALLBACK_16:
- if (!m_base.get().subdevice(m_read16.device_name()))
- osd_printf_error("Device %s not found for READ16 callback (%s)\n", m_read16.device_name(), m_read16.name());
- break;
-
- case CALLBACK_32:
- if (!m_base.get().subdevice(m_read32.device_name()))
- osd_printf_error("Device %s not found for READ32 callback (%s)\n", m_read32.device_name(), m_read32.name());
- break;
-
- case CALLBACK_64:
- if (!m_base.get().subdevice(m_read64.device_name()))
- osd_printf_error("Device %s not found for READ64 callback (%s)\n", m_read64.device_name(), m_read64.name());
- break;
-
- case CALLBACK_MEMBANK:
- osd_printf_error("Device read callbacks can't be connected to bank switches\n");
- break;
-
- case CALLBACK_OUTPUT:
- osd_printf_error("Device read callbacks can't be connected to output items\n");
- break;
-
- case CALLBACK_INPUTLINE:
- case CALLBACK_ASSERTLINE:
- case CALLBACK_CLEARLINE:
- case CALLBACK_HOLDLINE:
- throw emu_fatalerror("Device read callbacks can't be connected to input lines\n");
- }
-
- if (m_chain)
- m_chain->validity_check(valid);
-}
-
-
-
-//**************************************************************************
-// DEVCB WRITE CLASS
-//**************************************************************************
-
-//-------------------------------------------------
-// devcb_write_base - constructor
-//-------------------------------------------------
-
-devcb_write_base::devcb_write_base(device_t &device, u64 defmask, bool chained)
- : devcb_base(device, defmask),
- m_adapter(&devcb_write_base::write_unresolved_adapter)
-{
- if (!chained)
- device.m_output_callbacks.push_back(this);
-}
-
-
-//-------------------------------------------------
-// devcb_reset - reset/initialize local state
-//-------------------------------------------------
-
-void devcb_write_base::devcb_reset()
-{
- m_writeline = write_line_delegate();
- m_write8 = write8_delegate();
- m_write16 = write16_delegate();
- m_write32 = write32_delegate();
- m_write64 = write64_delegate();
- m_adapter = &devcb_write_base::write_unresolved_adapter;
- m_chain = nullptr;
-}
-
-
-//-------------------------------------------------
-// chain_alloc - add another callback to the
-// output chain
-//-------------------------------------------------
-
-devcb_write_base &devcb_write_base::chain_alloc()
-{
- // set up the chained callback pointer
- m_chain.reset(new devcb_write_base(m_owner, m_defmask, true));
- return *m_chain;
-}
-
-
-//-------------------------------------------------
-// resolve - resolve the specified callback to
-// its final form
-//-------------------------------------------------
-
-void devcb_write_base::resolve()
-{
- // first resolve any address spaces
- if (m_space_tag)
- resolve_space();
+ if (m_dflt_space_finder && m_dflt_space_finder->has_space(m_dflt_space_index))
+ m_dflt_space = &m_dflt_space_finder->space(m_dflt_space_index);
else
- m_space = &m_owner.machine().dummy_space();
-
- // then handle the various types
- const char *name = "unknown";
- try
- {
- switch (m_type)
- {
- case CALLBACK_NONE:
- break;
-
- case CALLBACK_LINE:
- name = m_writeline.name();
- m_writeline.bind_relative_to(m_base);
- m_adapter = m_writeline.isnull() ? &devcb_write_base::write_noop_adapter : &devcb_write_base::write_line_adapter;
- break;
-
- case CALLBACK_8:
- name = m_write8.name();
- m_write8.bind_relative_to(m_base);
- m_adapter = m_write8.isnull() ? &devcb_write_base::write_noop_adapter : &devcb_write_base::write8_adapter;
- break;
-
- case CALLBACK_16:
- name = m_write16.name();
- m_write16.bind_relative_to(m_base);
- m_adapter = m_write16.isnull() ? &devcb_write_base::write_noop_adapter : &devcb_write_base::write16_adapter;
- break;
-
- case CALLBACK_32:
- name = m_write32.name();
- m_write32.bind_relative_to(m_base);
- m_adapter = m_write32.isnull() ? &devcb_write_base::write_noop_adapter : &devcb_write_base::write32_adapter;
- break;
-
- case CALLBACK_64:
- name = m_write64.name();
- m_write64.bind_relative_to(m_base);
- m_adapter = m_write64.isnull() ? &devcb_write_base::write_noop_adapter : &devcb_write_base::write64_adapter;
- break;
-
- case CALLBACK_IOPORT:
- resolve_ioport();
- m_adapter = !m_target.ioport ? &devcb_write_base::write_noop_adapter : &devcb_write_base::write_ioport_adapter;
- break;
-
- case CALLBACK_MEMBANK:
- resolve_membank();
- m_adapter = !m_target.membank ? &devcb_write_base::write_noop_adapter : &devcb_write_base::write_membank_adapter;
- break;
-
- case CALLBACK_OUTPUT:
- resolve_output();
- m_adapter = !m_target.item ? &devcb_write_base::write_noop_adapter : &devcb_write_base::write_output_adapter;
- break;
-
- case CALLBACK_LOG:
- m_adapter = &devcb_write_base::write_logged_adapter;
- break;
-
- case CALLBACK_CONSTANT:
- m_adapter = &devcb_write_base::write_noop_adapter;
- break;
-
- case CALLBACK_INPUTLINE:
- resolve_inputline();
- m_adapter = &devcb_write_base::write_inputline_adapter;
- break;
-
- case CALLBACK_ASSERTLINE:
- resolve_inputline();
- m_adapter = &devcb_write_base::write_assertline_adapter;
- break;
-
- case CALLBACK_CLEARLINE:
- resolve_inputline();
- m_adapter = &devcb_write_base::write_clearline_adapter;
- break;
-
- case CALLBACK_HOLDLINE:
- resolve_inputline();
- m_adapter = &devcb_write_base::write_holdline_adapter;
- break;
- }
- }
- catch (binding_type_exception &binderr)
- {
- throw emu_fatalerror("devcb_write: Error performing a late bind of type %s to %s (name=%s)\n", binderr.m_actual_type.name(), binderr.m_target_type.name(), name);
- }
-
- // resolve callback chain recursively
- if (m_chain)
- m_chain->resolve();
-}
-
-
-//-------------------------------------------------
-// resolve_safe - resolve the callback; if not
-// specified, resolve to a no-op
-//-------------------------------------------------
-
-void devcb_write_base::resolve_safe()
-{
- // convert to a constant if none specified
- if (m_type == CALLBACK_NONE)
- m_type = CALLBACK_CONSTANT;
- resolve();
-}
-
-
-//-------------------------------------------------
-// validity_check - check the validity of the
-// callback object
-//-------------------------------------------------
-
-void devcb_write_base::validity_check(validity_checker &valid) const
-{
- switch (m_type)
- {
- case CALLBACK_NONE:
- break;
-
- case CALLBACK_CONSTANT:
- case CALLBACK_LOG:
- case CALLBACK_IOPORT:
- case CALLBACK_MEMBANK:
- case CALLBACK_OUTPUT:
- break;
-
- case CALLBACK_LINE:
- if (!m_base.get().subdevice(m_writeline.device_name()))
- osd_printf_error("Device %s not found for WRITELINE callback (%s)\n", m_writeline.device_name(), m_writeline.name());
- break;
-
- case CALLBACK_8:
- if (!m_base.get().subdevice(m_write8.device_name()))
- osd_printf_error("Device %s not found for WRITE8 callback (%s)\n", m_write8.device_name(), m_write8.name());
- break;
-
- case CALLBACK_16:
- if (!m_base.get().subdevice(m_write16.device_name()))
- osd_printf_error("Device %s not found for WRITE16 callback (%s)\n", m_write16.device_name(), m_write16.name());
- break;
-
- case CALLBACK_32:
- if (!m_base.get().subdevice(m_write32.device_name()))
- osd_printf_error("Device %s not found for WRITE32 callback (%s)\n", m_write32.device_name(), m_write32.name());
- break;
-
- case CALLBACK_64:
- if (!m_base.get().subdevice(m_write64.device_name()))
- osd_printf_error("Device %s not found for WRITE64 callback (%s)\n", m_write64.device_name(), m_write64.name());
- break;
-
- case CALLBACK_INPUTLINE:
- case CALLBACK_ASSERTLINE:
- case CALLBACK_CLEARLINE:
- case CALLBACK_HOLDLINE:
- {
- device_t *const device = m_base.get().subdevice(m_target_tag);
- device_execute_interface *execute;
- if (!device)
- osd_printf_error("Device %s not found for INPUTLINE callback (%d)\n", m_target_tag, int(m_target_int));
- else if (!device->interface(execute))
- osd_printf_error("Device %s has no interface for INPUTLINE callback (%d)\n", m_target_tag, int(m_target_int));
- }
- break;
- }
-
- if (m_chain)
- m_chain->validity_check(valid);
-}
-
-
-//-------------------------------------------------
-// write_unresolved_adapter - error-generating
-// unresolved adapter
-//-------------------------------------------------
-
-void devcb_write_base::write_unresolved_adapter(address_space &space, offs_t offset, u64 data, u64 mask)
-{
- throw emu_fatalerror("Attempted to write through an unresolved devcb item");
+ m_dflt_space = &m_owner.machine().dummy_space();
}
-//-------------------------------------------------
-// write_line_adapter - write from a line delegate
-//-------------------------------------------------
-
-void devcb_write_base::write_line_adapter(address_space &space, offs_t offset, u64 data, u64 mask)
-{
- m_writeline(unshift_mask_xor(data) & 1);
-}
-
-
-//-------------------------------------------------
-// write8_adapter - write from an 8-bit delegate
-//-------------------------------------------------
-
-void devcb_write_base::write8_adapter(address_space &space, offs_t offset, u64 data, u64 mask)
-{
- m_write8(space, offset, unshift_mask_xor(data), unshift_mask(mask));
-}
-
-
-//-------------------------------------------------
-// write16_adapter - write from a 16-bit delegate
-//-------------------------------------------------
-
-void devcb_write_base::write16_adapter(address_space &space, offs_t offset, u64 data, u64 mask)
-{
- m_write16(space, offset, unshift_mask_xor(data), unshift_mask(mask));
-}
-
-
-//-------------------------------------------------
-// write32_adapter - write from a 32-bit delegate
-//-------------------------------------------------
-
-void devcb_write_base::write32_adapter(address_space &space, offs_t offset, u64 data, u64 mask)
-{
- m_write32(space, offset, unshift_mask_xor(data), unshift_mask(mask));
-}
-
-
-//-------------------------------------------------
-// write64_adapter - write from a 64-bit delegate
-//-------------------------------------------------
-
-void devcb_write_base::write64_adapter(address_space &space, offs_t offset, u64 data, u64 mask)
-{
- m_write64(space, offset, unshift_mask_xor(data), unshift_mask(mask));
-}
-
-
-//-------------------------------------------------
-// write_ioport_adapter - write to an I/O port
-//-------------------------------------------------
-
-void devcb_write_base::write_ioport_adapter(address_space &space, offs_t offset, u64 data, u64 mask)
-{
- if (m_target.ioport)
- m_target.ioport->write(unshift_mask_xor(data));
-}
-
-
-//-------------------------------------------------
-// write_membank_adapter - switch a memory bank
-//-------------------------------------------------
-
-void devcb_write_base::write_membank_adapter(address_space &space, offs_t offset, u64 data, u64 mask)
-{
- if (m_target.membank)
- m_target.membank->set_entry(unshift_mask_xor(data));
-}
-
-
-//-------------------------------------------------
-// write_output_adapter - set an output item
-//-------------------------------------------------
-
-void devcb_write_base::write_output_adapter(address_space &space, offs_t offset, u64 data, u64 mask)
-{
- if (m_target.item)
- m_target.item->set(unshift_mask_xor(data));
-}
-
-
-//-------------------------------------------------
-// write_logged_adapter - log write if masked
-// value is nonzero
-//-------------------------------------------------
-
-void devcb_write_base::write_logged_adapter(address_space &space, offs_t offset, u64 data, u64 mask)
-{
- if (unshift_mask_xor(data) != 0)
- m_owner.logerror("%s: %s\n", m_owner.machine().describe_context(), m_target_tag);
-}
-
-
-//-------------------------------------------------
-// write_constant - write from a constant
-//-------------------------------------------------
-
-void devcb_write_base::write_noop_adapter(address_space &space, offs_t offset, u64 data, u64 mask)
-{
- // constant for writes is a no-op
-}
-
-
-//-------------------------------------------------
-// write_inputline_adapter - write to a device's
-// input line
-//-------------------------------------------------
-
-void devcb_write_base::write_inputline_adapter(address_space &space, offs_t offset, u64 data, u64 mask)
-{
- m_target.device->execute().set_input_line(m_target_int, unshift_mask_xor(data) & 1);
-}
-
-
-//-------------------------------------------------
-// write_assertline_adapter - write to a device's
-// input line
-//-------------------------------------------------
-
-void devcb_write_base::write_assertline_adapter(address_space &space, offs_t offset, u64 data, u64 mask)
-{
- if (unshift_mask_xor(data) & 1)
- m_target.device->execute().set_input_line(m_target_int, ASSERT_LINE);
-}
-
-
-//-------------------------------------------------
-// write_clearline_adapter - write to a device's
-// input line
-//-------------------------------------------------
-
-void devcb_write_base::write_clearline_adapter(address_space &space, offs_t offset, u64 data, u64 mask)
+devcb_read_base::~devcb_read_base()
{
- if (unshift_mask_xor(data) & 1)
- m_target.device->execute().set_input_line(m_target_int, CLEAR_LINE);
}
-//-------------------------------------------------
-// write_clearline_adapter - write to a device's
-// input line
-//-------------------------------------------------
-void devcb_write_base::write_holdline_adapter(address_space &space, offs_t offset, u64 data, u64 mask)
+devcb_write_base::~devcb_write_base()
{
- if (unshift_mask_xor(data) & 1)
- m_target.device->execute().set_input_line(m_target_int, HOLD_LINE);
}