diff options
author | 2016-12-29 14:34:59 -0800 | |
---|---|---|
committer | 2016-12-29 14:34:59 -0800 | |
commit | 1fafe7706cbfcfc6e39c23c3c713fbb102557cbe (patch) | |
tree | e717407aa8f98f192a2095f28909c89f3af3a8e5 /src/emu/devcb.cpp | |
parent | f7a98c4a969478fca51faf30f588d59631394bd9 (diff) | |
parent | 2b74e4c0be91b86b408fca518af7518c1ea994c9 (diff) |
Merge https://github.com/mamedev/mame
Diffstat (limited to 'src/emu/devcb.cpp')
-rw-r--r-- | src/emu/devcb.cpp | 188 |
1 files changed, 162 insertions, 26 deletions
diff --git a/src/emu/devcb.cpp b/src/emu/devcb.cpp index 3d851ee8e2a..12f84a01f5f 100644 --- a/src/emu/devcb.cpp +++ b/src/emu/devcb.cpp @@ -22,11 +22,27 @@ devcb_base::devcb_base(device_t &device, u64 defmask) : m_device(device), + m_type(CALLBACK_NONE), + m_target_tag(nullptr), + m_target_int(0), + m_space_tag(nullptr), + m_space_num(AS_0), + m_space(nullptr), m_rshift(0), m_mask(defmask), + m_defmask(defmask), m_xor(0) { - reset(); + m_target.ptr = nullptr; +} + + +//------------------------------------------------- +// devcb_base - destructor +//------------------------------------------------- + +devcb_base::~devcb_base() +{ } @@ -45,6 +61,8 @@ void devcb_base::reset(callback_type type) m_target.ptr = nullptr; m_rshift = 0; m_mask = ~u64(0); + m_xor = 0; + devcb_reset(); } @@ -59,6 +77,26 @@ void devcb_base::resolve_ioport() m_target.ioport = (m_target_tag != nullptr) ? m_device.owner()->ioport(m_target_tag) : nullptr; if (m_target.ioport == nullptr) throw emu_fatalerror("Unable to resolve I/O port callback reference to '%s' in device '%s'\n", m_target_tag, m_device.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 != nullptr) ? m_device.owner()->membank(m_target_tag) : nullptr; + if (m_target.membank == nullptr) + throw emu_fatalerror("Unable to resolve memory bank callback reference to '%s' in device '%s'\n", m_target_tag, m_device.tag()); } @@ -109,27 +147,37 @@ void devcb_base::resolve_space() devcb_read_base::devcb_read_base(device_t &device, u64 defmask) : devcb_base(device, defmask), - m_adapter(nullptr) + m_adapter(&devcb_read_base::read_unresolved_adapter) { } //------------------------------------------------- -// reset - reset/initialize state +// devcb_reset - reset/initialize local state //------------------------------------------------- -void devcb_read_base::reset(callback_type type) +void devcb_read_base::devcb_reset() { - // 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; + 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_device, m_defmask)); + return *m_chain; } @@ -160,6 +208,7 @@ void devcb_read_base::resolve() 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; + m_mask = shift_mask(1); break; case CALLBACK_8: @@ -167,6 +216,7 @@ void devcb_read_base::resolve() 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; + m_mask = shift_mask(0xff); break; case CALLBACK_16: @@ -174,6 +224,7 @@ void devcb_read_base::resolve() 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; + m_mask = shift_mask(0xffff); break; case CALLBACK_32: @@ -181,6 +232,7 @@ void devcb_read_base::resolve() 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; + m_mask = shift_mask(0xffffffff); break; case CALLBACK_64: @@ -191,20 +243,30 @@ void devcb_read_base::resolve() break; case CALLBACK_IOPORT: + name = m_target_tag; resolve_ioport(); m_target_int = 0; - m_adapter = (m_target.ioport == nullptr) ? &devcb_read_base::read_constant_adapter : &devcb_read_base::read_ioport_adapter; + 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_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: throw emu_fatalerror("Device read callbacks can't be connected to input lines\n"); } } @@ -212,6 +274,15 @@ void devcb_read_base::resolve() { 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 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_device.tag(), name, (unsigned long)m_mask, (unsigned long)chained_cb->m_mask); } @@ -305,14 +376,14 @@ u64 devcb_read_base::read_ioport_adapter(address_space &space, offs_t offset, u6 //------------------------------------------------- -// read_logged_adapter - log a read and return a -// constant +// 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_device.logerror("%s: read %s\n", m_device.machine().describe_context(), m_target_tag); - return shift_mask_xor(m_target_int); + m_device.logerror("%s: %s\n", m_device.machine().describe_context(), m_target_tag); + return 0; } @@ -322,7 +393,7 @@ u64 devcb_read_base::read_logged_adapter(address_space &space, offs_t offset, u6 u64 devcb_read_base::read_constant_adapter(address_space &space, offs_t offset, u64 mask) { - return shift_mask_xor(m_target_int); + return shift_mask(m_target_int); } @@ -337,27 +408,37 @@ u64 devcb_read_base::read_constant_adapter(address_space &space, offs_t offset, devcb_write_base::devcb_write_base(device_t &device, u64 defmask) : devcb_base(device, defmask), - m_adapter(nullptr) + m_adapter(&devcb_write_base::write_unresolved_adapter) { } //------------------------------------------------- -// reset - reset/initialize state +// devcb_reset - reset/initialize local state //------------------------------------------------- -void devcb_write_base::reset(callback_type type) +void devcb_write_base::devcb_reset() { - // 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; + 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_device, m_defmask)); + return *m_chain; } @@ -418,6 +499,11 @@ void devcb_write_base::resolve() m_adapter = (m_target.ioport == nullptr) ? &devcb_write_base::write_noop_adapter : &devcb_write_base::write_ioport_adapter; break; + case CALLBACK_MEMBANK: + resolve_membank(); + m_adapter = (m_target.membank == nullptr) ? &devcb_write_base::write_noop_adapter : &devcb_write_base::write_membank_adapter; + break; + case CALLBACK_LOG: m_adapter = &devcb_write_base::write_logged_adapter; break; @@ -430,12 +516,26 @@ void devcb_write_base::resolve() 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; } } 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 != nullptr) + m_chain->resolve(); } @@ -515,7 +615,7 @@ void devcb_write_base::write64_adapter(address_space &space, offs_t offset, u64 //------------------------------------------------- -// write_ioport - write from an I/O port +// 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) @@ -526,13 +626,25 @@ void devcb_write_base::write_ioport_adapter(address_space &space, offs_t offset, //------------------------------------------------- -// write_logged_adapter - logging unresolved -// adapter +// 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_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) { - m_device.logerror("%s: unresolved devcb write\n", m_device.machine().describe_context()); + if (unshift_mask_xor(data) != 0) + m_device.logerror("%s: %s\n", m_device.machine().describe_context(), m_target_tag); } @@ -547,7 +659,7 @@ void devcb_write_base::write_noop_adapter(address_space &space, offs_t offset, u //------------------------------------------------- -// write_inputline_adapter - write to an device's +// write_inputline_adapter - write to a device's // input line //------------------------------------------------- @@ -555,3 +667,27 @@ void devcb_write_base::write_inputline_adapter(address_space &space, offs_t offs { 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) +{ + if (unshift_mask_xor(data) & 1) + m_target.device->execute().set_input_line(m_target_int, CLEAR_LINE); +} |