summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/devcb.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/devcb.cpp')
-rw-r--r--src/emu/devcb.cpp555
1 files changed, 555 insertions, 0 deletions
diff --git a/src/emu/devcb.cpp b/src/emu/devcb.cpp
new file mode 100644
index 00000000000..5a0b4d69e44
--- /dev/null
+++ b/src/emu/devcb.cpp
@@ -0,0 +1,555 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+/***************************************************************************
+
+ devcb.c
+
+ Device callback interface helpers.
+
+***************************************************************************/
+
+#include "emu.h"
+
+
+
+//**************************************************************************
+// DEVCB BASE CLASS
+//**************************************************************************
+
+//-------------------------------------------------
+// devcb_base - constructor
+//-------------------------------------------------
+
+devcb_base::devcb_base(device_t &device, UINT64 defmask)
+ : m_device(device),
+ m_rshift(0),
+ m_mask(defmask),
+ m_xor(0)
+{
+ reset();
+}
+
+
+//-------------------------------------------------
+// reset - reset/initialize state
+//-------------------------------------------------
+
+void devcb_base::reset(callback_type type)
+{
+ m_type = type;
+ m_target_tag = NULL;
+ m_target_int = 0;
+ m_space_tag = NULL;
+ m_space_num = AS_0;
+ m_space = NULL;
+ m_target.ptr = NULL;
+ m_rshift = 0;
+ m_mask = ~U64(0);
+}
+
+
+//-------------------------------------------------
+// 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 != NULL) ? m_device.owner()->ioport(m_target_tag) : NULL;
+ if (m_target.ioport == NULL)
+ throw emu_fatalerror("Unable to resolve I/O port callback reference to '%s' in device '%s'\n", m_target_tag, m_device.tag());
+}
+
+
+//-------------------------------------------------
+// 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 != NULL) ? m_device.owner()->subdevice(m_target_tag) : NULL;
+ if (m_target.device == NULL)
+ throw emu_fatalerror("Unable to resolve device reference to '%s' in device '%s'\n", m_target_tag, m_device.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_device.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 *spacedev = (m_space_tag != NULL) ? m_device.owner()->subdevice(m_space_tag) : NULL;
+ if (spacedev == NULL)
+ throw emu_fatalerror("Unable to resolve device reference to '%s' in device '%s'\n", m_space_tag, m_device.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_device.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, UINT64 defmask)
+ : devcb_base(device, defmask)
+{
+}
+
+
+//-------------------------------------------------
+// reset - reset/initialize state
+//-------------------------------------------------
+
+void devcb_read_base::reset(callback_type type)
+{
+ // parent first
+ devcb_base::reset(type);
+
+ // local stuff
+ 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;
+}
+
+
+//-------------------------------------------------
+// resolve - resolve the specified callback to
+// its final form
+//-------------------------------------------------
+
+void devcb_read_base::resolve()
+{
+ // first resolve any address spaces
+ if (m_space_tag != NULL)
+ resolve_space();
+ else
+ m_space = &downcast<driver_device &>(m_device.machine().root_device()).generic_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_device.owner());
+ m_target_int = 0;
+ m_adapter = m_readline.isnull() ? &devcb_read_base::read_constant_adapter : &devcb_read_base::read_line_adapter;
+ break;
+
+ case CALLBACK_8:
+ name = m_read8.name();
+ m_read8.bind_relative_to(*m_device.owner());
+ m_target_int = 0;
+ m_adapter = m_read8.isnull() ? &devcb_read_base::read_constant_adapter : &devcb_read_base::read8_adapter;
+ break;
+
+ case CALLBACK_16:
+ name = m_read16.name();
+ m_read16.bind_relative_to(*m_device.owner());
+ m_target_int = 0;
+ m_adapter = m_read16.isnull() ? &devcb_read_base::read_constant_adapter : &devcb_read_base::read16_adapter;
+ break;
+
+ case CALLBACK_32:
+ name = m_read32.name();
+ m_read32.bind_relative_to(*m_device.owner());
+ m_target_int = 0;
+ m_adapter = m_read32.isnull() ? &devcb_read_base::read_constant_adapter : &devcb_read_base::read32_adapter;
+ break;
+
+ case CALLBACK_64:
+ name = m_read64.name();
+ m_read64.bind_relative_to(*m_device.owner());
+ m_target_int = 0;
+ m_adapter = m_read64.isnull() ? &devcb_read_base::read_constant_adapter : &devcb_read_base::read64_adapter;
+ break;
+
+ case CALLBACK_IOPORT:
+ resolve_ioport();
+ m_target_int = 0;
+ m_adapter = (m_target.ioport == NULL) ? &devcb_read_base::read_constant_adapter : &devcb_read_base::read_ioport_adapter;
+ break;
+
+ case CALLBACK_LOG:
+ m_adapter = &devcb_read_base::read_logged_adapter;
+ break;
+
+ case CALLBACK_CONSTANT:
+ m_adapter = &devcb_read_base::read_constant_adapter;
+ break;
+
+ case CALLBACK_INPUTLINE:
+ throw emu_fatalerror("Device read callbacks can't be connected to input lines\n");
+ }
+ }
+ catch (binding_type_exception &binderr)
+ {
+ 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);
+ }
+}
+
+
+//-------------------------------------------------
+// resolve_safe - resolve the callback; if not
+// specified, resolve to a constant callback with
+// the given value
+//-------------------------------------------------
+
+void devcb_read_base::resolve_safe(UINT64 none_constant_value)
+{
+ // convert to a constant if none specified
+ if (m_type == CALLBACK_NONE)
+ {
+ m_target_int = none_constant_value;
+ m_type = CALLBACK_CONSTANT;
+ }
+ resolve();
+}
+
+
+//-------------------------------------------------
+// read_unresolved_adapter - error-generating
+// unresolved adapter
+//-------------------------------------------------
+
+UINT64 devcb_read_base::read_unresolved_adapter(address_space &space, offs_t offset, UINT64 mask)
+{
+ throw emu_fatalerror("Attempted to read through an unresolved devcb item");
+}
+
+
+//-------------------------------------------------
+// read_line_adapter - read from a line delegate
+//-------------------------------------------------
+
+UINT64 devcb_read_base::read_line_adapter(address_space &space, offs_t offset, UINT64 mask)
+{
+ return shift_mask_xor(m_readline() & 1);
+}
+
+
+//-------------------------------------------------
+// read8_adapter - read from an 8-bit delegate
+//-------------------------------------------------
+
+UINT64 devcb_read_base::read8_adapter(address_space &space, offs_t offset, UINT64 mask)
+{
+ return shift_mask_xor(m_read8(space, offset, unshift_mask(mask)));
+}
+
+
+//-------------------------------------------------
+// read16_adapter - read from a 16-bit delegate
+//-------------------------------------------------
+
+UINT64 devcb_read_base::read16_adapter(address_space &space, offs_t offset, UINT64 mask)
+{
+ return shift_mask_xor(m_read16(space, offset, unshift_mask(mask)));
+}
+
+
+//-------------------------------------------------
+// read32_adapter - read from a 32-bit delegate
+//-------------------------------------------------
+
+UINT64 devcb_read_base::read32_adapter(address_space &space, offs_t offset, UINT64 mask)
+{
+ return shift_mask_xor(m_read32(space, offset, unshift_mask(mask)));
+}
+
+
+//-------------------------------------------------
+// read64_adapter - read from a 64-bit delegate
+//-------------------------------------------------
+
+UINT64 devcb_read_base::read64_adapter(address_space &space, offs_t offset, UINT64 mask)
+{
+ return shift_mask_xor(m_read64(space, offset, unshift_mask(mask)));
+}
+
+
+//-------------------------------------------------
+// read_ioport - read from an I/O port
+//-------------------------------------------------
+
+UINT64 devcb_read_base::read_ioport_adapter(address_space &space, offs_t offset, UINT64 mask)
+{
+ return shift_mask_xor(m_target.ioport->read());
+}
+
+
+//-------------------------------------------------
+// read_logged_adapter - log a read and return a
+// constant
+//-------------------------------------------------
+
+UINT64 devcb_read_base::read_logged_adapter(address_space &space, offs_t offset, UINT64 mask)
+{
+ m_device.logerror("%s: read %s\n", m_device.machine().describe_context(), m_target_tag);
+ return shift_mask_xor(m_target_int);
+}
+
+
+//-------------------------------------------------
+// read_constant - read from a constant
+//-------------------------------------------------
+
+UINT64 devcb_read_base::read_constant_adapter(address_space &space, offs_t offset, UINT64 mask)
+{
+ return shift_mask_xor(m_target_int);
+}
+
+
+
+//**************************************************************************
+// DEVCB WRITE CLASS
+//**************************************************************************
+
+//-------------------------------------------------
+// devcb_write_base - constructor
+//-------------------------------------------------
+
+devcb_write_base::devcb_write_base(device_t &device, UINT64 defmask)
+ : devcb_base(device, defmask)
+{
+}
+
+
+//-------------------------------------------------
+// reset - reset/initialize state
+//-------------------------------------------------
+
+void devcb_write_base::reset(callback_type type)
+{
+ // parent first
+ devcb_base::reset(type);
+
+ // local stuff
+ 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;
+}
+
+
+//-------------------------------------------------
+// resolve - resolve the specified callback to
+// its final form
+//-------------------------------------------------
+
+void devcb_write_base::resolve()
+{
+ // first resolve any address spaces
+ if (m_space_tag != NULL)
+ resolve_space();
+ else
+ m_space = &downcast<driver_device &>(m_device.machine().root_device()).generic_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_device.owner());
+ 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_device.owner());
+ 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_device.owner());
+ 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_device.owner());
+ 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_device.owner());
+ 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 == NULL) ? &devcb_write_base::write_noop_adapter : &devcb_write_base::write_ioport_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;
+ }
+ }
+ 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_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();
+}
+
+
+//-------------------------------------------------
+// write_unresolved_adapter - error-generating
+// unresolved adapter
+//-------------------------------------------------
+
+void devcb_write_base::write_unresolved_adapter(address_space &space, offs_t offset, UINT64 data, UINT64 mask)
+{
+ throw emu_fatalerror("Attempted to write through an unresolved devcb item");
+}
+
+
+//-------------------------------------------------
+// write_line_adapter - write from a line delegate
+//-------------------------------------------------
+
+void devcb_write_base::write_line_adapter(address_space &space, offs_t offset, UINT64 data, UINT64 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, UINT64 data, UINT64 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, UINT64 data, UINT64 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, UINT64 data, UINT64 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, UINT64 data, UINT64 mask)
+{
+ m_write64(space, offset, unshift_mask_xor(data), unshift_mask(mask));
+}
+
+
+//-------------------------------------------------
+// write_ioport - write from an I/O port
+//-------------------------------------------------
+
+void devcb_write_base::write_ioport_adapter(address_space &space, offs_t offset, UINT64 data, UINT64 mask)
+{
+ if (m_target.ioport)
+ m_target.ioport->write(unshift_mask_xor(data));
+}
+
+
+//-------------------------------------------------
+// write_logged_adapter - logging unresolved
+// adapter
+//-------------------------------------------------
+
+void devcb_write_base::write_logged_adapter(address_space &space, offs_t offset, UINT64 data, UINT64 mask)
+{
+ m_device.logerror("%s: unresolved devcb write\n", m_device.machine().describe_context());
+}
+
+
+//-------------------------------------------------
+// write_constant - write from a constant
+//-------------------------------------------------
+
+void devcb_write_base::write_noop_adapter(address_space &space, offs_t offset, UINT64 data, UINT64 mask)
+{
+ // constant for writes is a no-op
+}
+
+
+//-------------------------------------------------
+// write_inputline_adapter - write to an device's
+// input line
+//-------------------------------------------------
+
+void devcb_write_base::write_inputline_adapter(address_space &space, offs_t offset, UINT64 data, UINT64 mask)
+{
+ m_target.device->execute().set_input_line(m_target_int, unshift_mask_xor(data) & 1);
+}