diff options
Diffstat (limited to 'src/emu')
52 files changed, 3482 insertions, 1525 deletions
diff --git a/src/emu/addrmap.cpp b/src/emu/addrmap.cpp index 0d8d7bc4eef..9eee69f986f 100644 --- a/src/emu/addrmap.cpp +++ b/src/emu/addrmap.cpp @@ -41,11 +41,7 @@ address_map_entry::address_map_entry(device_t &device, address_map &map, offs_t m_region(nullptr), m_rgnoffs(0), m_submap_bits(0), - m_memory(nullptr), - m_bytestart(0), - m_byteend(0), - m_bytemirror(0), - m_bytemask(0) + m_memory(nullptr) { } @@ -404,7 +400,7 @@ address_map::address_map(const address_space &space, offs_t start, offs_t end, i m_device(&device), m_databits(space.data_width()), m_unmapval(space.unmap()), - m_globalmask(space.bytemask()) + m_globalmask(space.addrmask()) { range(start, end).set_submap(DEVICE_SELF, submap_delegate, bits, unitmask); } @@ -610,7 +606,7 @@ void address_map::map_validity_check(validity_checker &valid, int spacenum) cons // it's safe to assume here that the device has a memory interface and a config for this space const address_space_config &spaceconfig = *m_device->memory().space_config(spacenum); int datawidth = spaceconfig.m_databus_width; - int alignunit = datawidth / 8; + int alignunit = spaceconfig.alignment(); bool detected_overlap = DETECT_OVERLAPPING_MEMORY ? false : true; @@ -631,9 +627,6 @@ void address_map::map_validity_check(validity_checker &valid, int spacenum) cons // loop over entries and look for errors for (address_map_entry &entry : m_entrylist) { - u32 bytestart = spaceconfig.addr2byte(entry.m_addrstart); - u32 byteend = spaceconfig.addr2byte_end(entry.m_addrend); - // look for overlapping entries if (!detected_overlap) { @@ -653,7 +646,7 @@ void address_map::map_validity_check(validity_checker &valid, int spacenum) cons } // look for inverted start/end pairs - if (byteend < bytestart) + if (entry.m_addrend < entry.m_addrstart) osd_printf_error("Wrong %s memory read handler start = %08x > end = %08x\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend); // look for ranges outside the global mask @@ -663,7 +656,7 @@ void address_map::map_validity_check(validity_checker &valid, int spacenum) cons osd_printf_error("In %s memory range %x-%x, end address is outside of the global address mask %x\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, globalmask); // look for misaligned entries - if ((bytestart & (alignunit - 1)) != 0 || (byteend & (alignunit - 1)) != (alignunit - 1)) + if ((entry.m_addrstart & (alignunit - 1)) != 0 || (entry.m_addrend & (alignunit - 1)) != (alignunit - 1)) osd_printf_error("Wrong %s memory read handler start = %08x, end = %08x ALIGN = %d\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, alignunit); // verify mask/mirror/select @@ -715,7 +708,7 @@ void address_map::map_validity_check(validity_checker &valid, int spacenum) cons { // verify the address range is within the region's bounds offs_t const length = region.get_length(); - if (entry.m_rgnoffs + (byteend - bytestart + 1) > length) + if (entry.m_rgnoffs + spaceconfig.addr2byte(entry.m_addrend - entry.m_addrstart + 1) > length) osd_printf_error("%s space memory map entry %X-%X extends beyond region '%s' size (%X)\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_region, length); found = true; } diff --git a/src/emu/addrmap.h b/src/emu/addrmap.h index c56c9257d47..587f9a16e33 100644 --- a/src/emu/addrmap.h +++ b/src/emu/addrmap.h @@ -154,10 +154,6 @@ public: // information used during processing void * m_memory; // pointer to memory backing this entry - offs_t m_bytestart; // byte-adjusted start address - offs_t m_byteend; // byte-adjusted end address - offs_t m_bytemirror; // byte-adjusted mirror bits - offs_t m_bytemask; // byte-adjusted mask bits // handler setters for 8-bit functions address_map_entry &set_handler(read8_delegate func, u64 mask = 0); diff --git a/src/emu/debug/debugbuf.cpp b/src/emu/debug/debugbuf.cpp new file mode 100644 index 00000000000..779b91f84ac --- /dev/null +++ b/src/emu/debug/debugbuf.cpp @@ -0,0 +1,1379 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +// Buffering interface for the disassembly windows + +#include "emu.h" +#include "debugbuf.h" + +debug_disasm_buffer::debug_data_buffer::debug_data_buffer(util::disasm_interface *intf) : m_intf(intf) +{ + m_space = nullptr; + m_back = nullptr; + m_opcode = true; + m_lstart = m_lend = 0; + m_wrapped = false; +} + +bool debug_disasm_buffer::debug_data_buffer::active() const +{ + return m_space || m_back; +} + +void debug_disasm_buffer::debug_data_buffer::set_source(address_space &space) +{ + m_space = &space; + setup_methods(); +} + +void debug_disasm_buffer::debug_data_buffer::set_source(debug_data_buffer &back, bool opcode) +{ + m_back = &back; + m_opcode = opcode; + setup_methods(); +} + +u8 debug_disasm_buffer::debug_data_buffer::r8 (offs_t pc) const +{ + return m_do_r8(pc & m_pc_mask); +} + +u16 debug_disasm_buffer::debug_data_buffer::r16(offs_t pc) const +{ + return m_do_r16(pc & m_pc_mask); +} + +u32 debug_disasm_buffer::debug_data_buffer::r32(offs_t pc) const +{ + return m_do_r32(pc & m_pc_mask); +} + +u64 debug_disasm_buffer::debug_data_buffer::r64(offs_t pc) const +{ + return m_do_r64(pc & m_pc_mask); +} + +address_space *debug_disasm_buffer::debug_data_buffer::get_underlying_space() const +{ + return m_space; +} + +void debug_disasm_buffer::debug_data_buffer::fill(offs_t lstart, offs_t size) const +{ + offs_t lend = (lstart + size) & m_pc_mask; + if(m_page_mask) { + if((lstart ^ lend) & ~m_page_mask) { + lstart = lstart & ~m_page_mask; + lend = (((lend - 1) | m_page_mask) + 1) & m_pc_mask; + } + } + + if(!m_buffer.empty()) { + if(m_lstart == m_lend) + return; + if(m_wrapped) { + if(lstart >= m_lstart && (lend > m_lstart || lend <= m_lend)) + return; + if(lstart < m_lend && lend <= m_lend) + return; + } else { + if(lstart < lend && lstart >= m_lstart && lend <= m_lend) + return; + } + } + + if(m_buffer.empty()) { + m_lstart = lstart; + m_lend = lend; + m_wrapped = lend < lstart; + offs_t size = m_pc_delta_to_bytes((lend - lstart) & m_pc_mask); + m_buffer.resize(size); + m_do_fill(lstart, lend); + + } else { + offs_t n_lstart, n_lend; + if(lstart > lend) { + if(m_wrapped) { + // Old is wrapped, new is wrapped, just extend + n_lstart = std::min(m_lstart, lstart); + n_lend = std::max(m_lend, lend); + } else { + // Old is unwrapped, new is wrapped. Reduce the amount of "useless" data. + offs_t gap_post = m_lend >= lstart ? 0 : lstart - m_lend; + offs_t gap_pre = m_lstart <= lend ? 0 : m_lstart - lend; + if(gap_post < gap_pre) { + // extend the old one end until it reaches the new one + n_lstart = std::min(m_lstart, lstart); + n_lend = lend; + } else { + // extend the old one start until it reaches the new one + n_lstart = lstart; + n_lend = std::max(m_lend, lend); + } + m_wrapped = true; + } + } else if(m_wrapped) { + // Old is wrapped, new is unwrapped. Reduce the amount of "useless" data. + offs_t gap_post = m_lend >= lstart ? 0 : lstart - m_lend; + offs_t gap_pre = m_lstart <= lend ? 0 : m_lstart - lend; + if(gap_post < gap_pre) { + // extend the old one end until it reaches the new one + n_lstart = m_lstart; + n_lend = lend; + } else { + // extend the old one start until it reaches the new one + n_lstart = lstart; + n_lend = m_lend; + } + } else { + // Both are unwrapped, decide whether to wrap. + // If there's overlap, don't wrap, just extend + if(lend >= m_lstart && lstart < m_lend) { + n_lstart = std::min(m_lstart, lstart); + n_lend = std::max(m_lend, lend); + } else { + // If there's no overlap, compute the gap with wrapping or without + offs_t gap_unwrapped = lstart > m_lstart ? lstart - m_lend : m_lstart - lend; + offs_t gap_wrapped = lstart > m_lstart ? (m_lstart - lend) & m_pc_mask : (lstart - m_lend) & m_pc_mask; + if(gap_unwrapped < gap_wrapped) { + n_lstart = std::min(m_lstart, lstart); + n_lend = std::max(m_lend, lend); + } else { + n_lstart = std::max(m_lstart, lstart); + n_lend = std::min(m_lend, lend); + m_wrapped = true; + } + } + } + + if(n_lstart != m_lstart) { + offs_t size = m_pc_delta_to_bytes((m_lstart - n_lstart) & m_pc_mask); + m_buffer.insert(m_buffer.begin(), size, 0); + offs_t old_lstart = m_lstart; + m_lstart = n_lstart; + m_do_fill(m_lstart, old_lstart); + } + if(n_lend != m_lend) { + offs_t size = m_pc_delta_to_bytes((n_lend - m_lstart) & m_pc_mask); + m_buffer.resize(size); + offs_t old_lend = m_lend; + m_lend = n_lend; + m_do_fill(old_lend, m_lend); + } + } +} + +std::string debug_disasm_buffer::debug_data_buffer::data_to_string(offs_t pc, offs_t size) const +{ + return m_data_to_string(pc, size); +} + +void debug_disasm_buffer::debug_data_buffer::data_get(offs_t pc, offs_t size, std::vector<u8> &data) const +{ + return m_data_get(pc, size, data); +} + +void debug_disasm_buffer::debug_data_buffer::setup_methods() +{ + address_space *space = m_space ? m_space : m_back->get_underlying_space(); + int shift = space->addrbus_shift(); + int alignment = m_intf->opcode_alignment(); + endianness_t endian = space->endianness(); + + m_pc_mask = space->logaddrmask(); + + if(m_intf->interface_flags() & util::disasm_interface::PAGED) + m_page_mask = (1 << m_intf->page_address_bits()) - 1; + else + m_page_mask = 0; + + // Define the byte counter + switch(shift) { + case -3: m_pc_delta_to_bytes = [](offs_t delta) { return delta << 3; }; break; + case -2: m_pc_delta_to_bytes = [](offs_t delta) { return delta << 2; }; break; + case -1: m_pc_delta_to_bytes = [](offs_t delta) { return delta << 1; }; break; + case 0: m_pc_delta_to_bytes = [](offs_t delta) { return delta; }; break; + case 3: m_pc_delta_to_bytes = [](offs_t delta) { return delta >> 3; }; break; + default: throw emu_fatalerror("debug_disasm_buffer::debug_data_buffer::setup_methods: Abnormal address buf shift\n"); + } + + // Define the filler + if(m_space) { + // get the data from given space + if(m_intf->interface_flags() & util::disasm_interface::NONLINEAR_PC) { + switch(shift) { + case -1: + m_do_fill = [this](offs_t lstart, offs_t lend) { + auto dis = m_space->machine().disable_side_effect(); + u16 *dest = get_ptr<u16>(lstart); + for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) { + offs_t tpc = m_intf->pc_linear_to_real(lpc); + if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc)) + *dest++ = m_space->read_word(tpc); + else + *dest++ = 0; + } + }; + break; + case 0: + m_do_fill = [this](offs_t lstart, offs_t lend) { + auto dis = m_space->machine().disable_side_effect(); + u8 *dest = get_ptr<u8>(lstart); + u32 steps = 0; + for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) { + offs_t tpc = m_intf->pc_linear_to_real(lpc); + if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc)) + *dest++ = m_space->read_byte(tpc); + else + *dest++ = 0; + steps++; + } + }; + break; + } + + } else { + switch(shift) { + case -3: // bus granularity 64 + m_do_fill = [this](offs_t lstart, offs_t lend) { + auto dis = m_space->machine().disable_side_effect(); + u64 *dest = get_ptr<u64>(lstart); + for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) { + offs_t tpc = lpc; + if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc)) + *dest++ = m_space->read_qword(tpc); + else + *dest++ = 0; + } + }; + break; + + case -2: // bus granularity 32 + m_do_fill = [this](offs_t lstart, offs_t lend) { + auto dis = m_space->machine().disable_side_effect(); + u32 *dest = get_ptr<u32>(lstart); + for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) { + offs_t tpc = lpc; + if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc)) + *dest++ = m_space->read_dword(tpc); + else + *dest++ = 0; + } + }; + break; + + case -1: // bus granularity 16 + m_do_fill = [this](offs_t lstart, offs_t lend) { + auto dis = m_space->machine().disable_side_effect(); + u16 *dest = get_ptr<u16>(lstart); + for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) { + offs_t tpc = lpc; + if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc)) + *dest++ = m_space->read_word(tpc); + else + *dest++ = 0; + } + }; + break; + + case 0: // bus granularity 8 + m_do_fill = [this](offs_t lstart, offs_t lend) { + auto dis = m_space->machine().disable_side_effect(); + u8 *dest = get_ptr<u8>(lstart); + for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) { + offs_t tpc = lpc; + if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc)) + *dest++ = m_space->read_byte(tpc); + else + *dest++ = 0; + } + }; + break; + + case 3: // bus granularity 1, stored as u16 + m_do_fill = [this](offs_t lstart, offs_t lend) { + auto dis = m_space->machine().disable_side_effect(); + u16 *dest = reinterpret_cast<u16 *>(&m_buffer[0]) + ((lstart - m_lstart) >> 4); + for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 0x10) & m_pc_mask) { + offs_t tpc = lpc; + if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc)) + *dest++ = m_space->read_word(tpc); + else + *dest++ = 0; + } + }; + break; + } + } + } else { + // get the data from a back buffer and decrypt it through the device + // size chosen is alignment * granularity + assert(!(m_intf->interface_flags() & util::disasm_interface::NONLINEAR_PC)); + + switch(shift) { + case -3: // bus granularity 64, endianness irrelevant + m_do_fill = [this](offs_t lstart, offs_t lend) { + u64 *dest = get_ptr<u64>(lstart); + for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) + *dest++ = m_intf->decrypt64(m_back->r64(lpc), lpc, m_opcode); + }; + break; + + case -2: // bus granularity 32 + switch(alignment) { + case 1: // bus granularity 32, alignment 32, endianness irrelevant + m_do_fill = [this](offs_t lstart, offs_t lend) { + u32 *dest = get_ptr<u32>(lstart); + for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) + *dest++ = m_intf->decrypt32(m_back->r32(lpc), lpc, m_opcode); + }; + break; + + case 2: // bus granularity 32, alignment 64 + switch(endian) { + case ENDIANNESS_LITTLE: // bus granularity 32, alignment 64, little endian + m_do_fill = [this](offs_t lstart, offs_t lend) { + u32 *dest = get_ptr<u32>(lstart); + for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 2) & m_pc_mask) { + u64 val = m_intf->decrypt64(m_back->r64(lpc), lpc, m_opcode); + *dest++ = val; + *dest++ = val >> 32; + } + }; + break; + + case ENDIANNESS_BIG: // bus granularity 32, bus width 64, big endian + m_do_fill = [this](offs_t lstart, offs_t lend) { + u32 *dest = get_ptr<u32>(lstart); + for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 2) & m_pc_mask) { + u64 val = m_intf->decrypt64(m_back->r64(lpc), lpc, m_opcode); + *dest++ = val >> 32; + *dest++ = val; + } + }; + break; + } + break; + } + break; + + case -1: // bus granularity 16 + switch(alignment) { + case 1: // bus granularity 16, alignment 16, endianness irrelevant + m_do_fill = [this](offs_t lstart, offs_t lend) { + u16 *dest = get_ptr<u16>(lstart); + for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) + *dest++ = m_intf->decrypt16(m_back->r16(lpc), lpc, m_opcode); + }; + break; + + case 2: // bus granularity 16, alignment 32 + switch(endian) { + case ENDIANNESS_LITTLE: // bus granularity 16, alignment 32, little endian + m_do_fill = [this](offs_t lstart, offs_t lend) { + u16 *dest = get_ptr<u16>(lstart); + for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 2) & m_pc_mask) { + u32 val = m_intf->decrypt32(m_back->r32(lpc), lpc, m_opcode); + *dest++ = val; + *dest++ = val >> 16; + } + }; + break; + + case ENDIANNESS_BIG: // bus granularity 16, alignment 32, big endian + m_do_fill = [this](offs_t lstart, offs_t lend) { + u16 *dest = get_ptr<u16>(lstart); + for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 2) & m_pc_mask) { + u32 val = m_intf->decrypt32(m_back->r32(lpc), lpc, m_opcode); + *dest++ = val >> 16; + *dest++ = val; + } + }; + break; + } + break; + + case 4: // bus granularity 16, alignment 64 + switch(endian) { + case ENDIANNESS_LITTLE: // bus granularity 16, alignment 64, little endian + m_do_fill = [this](offs_t lstart, offs_t lend) { + u16 *dest = get_ptr<u16>(lstart); + for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 4) & m_pc_mask) { + u64 val = m_intf->decrypt64(m_back->r64(lpc), lpc, m_opcode); + *dest++ = val; + *dest++ = val >> 16; + *dest++ = val >> 32; + *dest++ = val >> 48; + } + }; + break; + + case ENDIANNESS_BIG: // bus granularity 16, alignment 64, big endian + m_do_fill = [this](offs_t lstart, offs_t lend) { + u16 *dest = get_ptr<u16>(lstart); + for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 4) & m_pc_mask) { + u64 val = m_intf->decrypt64(m_back->r64(lpc), lpc, m_opcode); + *dest++ = val >> 48; + *dest++ = val >> 32; + *dest++ = val >> 16; + *dest++ = val; + } + }; + break; + } + break; + } + break; + + case 0: // bus granularity 8 + switch(alignment) { + case 1: // bus granularity 8, alignment 8, endianness irrelevant + m_do_fill = [this](offs_t lstart, offs_t lend) { + u8 *dest = get_ptr<u8>(lstart); + for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) + *dest++ = m_intf->decrypt8(m_back->r8(lpc), lpc, m_opcode); + }; + break; + + case 2: // bus granularity 8, alignment 16 + switch(endian) { + case ENDIANNESS_LITTLE: // bus granularity 8, alignment 16, little endian + m_do_fill = [this](offs_t lstart, offs_t lend) { + u8 *dest = get_ptr<u8>(lstart); + for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 2) & m_pc_mask) { + u16 val = m_intf->decrypt16(m_back->r16(lpc), lpc, m_opcode); + *dest++ = val; + *dest++ = val >> 8; + } + }; + break; + + case ENDIANNESS_BIG: // bus granularity 16, alignment 16, big endian + m_do_fill = [this](offs_t lstart, offs_t lend) { + u8 *dest = get_ptr<u8>(lstart); + for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 2) & m_pc_mask) { + u16 val = m_intf->decrypt16(m_back->r16(lpc), lpc, m_opcode); + *dest++ = val >> 8; + *dest++ = val; + } + }; + break; + } + break; + + case 4: // bus granularity 8, alignment 32 + switch(endian) { + case ENDIANNESS_LITTLE: // bus granularity 8, alignment 16, little endian + m_do_fill = [this](offs_t lstart, offs_t lend) { + u8 *dest = get_ptr<u8>(lstart); + for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 4) & m_pc_mask) { + u32 val = m_intf->decrypt32(m_back->r32(lpc), lpc, m_opcode); + *dest++ = val; + *dest++ = val >> 8; + *dest++ = val >> 16; + *dest++ = val >> 24; + } + }; + break; + + case ENDIANNESS_BIG: // bus granularity 16, alignment 32, big endian + m_do_fill = [this](offs_t lstart, offs_t lend) { + u8 *dest = get_ptr<u8>(lstart); + for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 4) & m_pc_mask) { + u32 val = m_intf->decrypt32(m_back->r32(lpc), lpc, m_opcode); + *dest++ = val >> 24; + *dest++ = val >> 16; + *dest++ = val >> 8; + *dest++ = val; + } + }; + break; + } + break; + + + case 8: // bus granularity 8, alignment 64 + switch(endian) { + case ENDIANNESS_LITTLE: // bus granularity 8, alignment 64, little endian + m_do_fill = [this](offs_t lstart, offs_t lend) { + u8 *dest = get_ptr<u8>(lstart); + for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 8) & m_pc_mask) { + u64 val = m_intf->decrypt64(m_back->r64(lpc), lpc, m_opcode); + *dest++ = val; + *dest++ = val >> 8; + *dest++ = val >> 16; + *dest++ = val >> 24; + *dest++ = val >> 32; + *dest++ = val >> 40; + *dest++ = val >> 48; + *dest++ = val >> 56; + } + }; + break; + + case ENDIANNESS_BIG: // bus granularity 8, alignment 64, big endian + m_do_fill = [this](offs_t lstart, offs_t lend) { + u8 *dest = get_ptr<u8>(lstart); + for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 2) & m_pc_mask) { + u64 val = m_intf->decrypt64(m_back->r64(lpc), lpc, m_opcode); + *dest++ = val >> 56; + *dest++ = val >> 48; + *dest++ = val >> 40; + *dest++ = val >> 32; + *dest++ = val >> 24; + *dest++ = val >> 16; + *dest++ = val >> 8; + *dest++ = val; + } + }; + break; + } + break; + } + break; + + case 3: // bus granularity 1, alignment 16, little endian (bit addressing, stored as u16, tms3401x) + assert(alignment == 16); + assert(endian == ENDIANNESS_LITTLE); + m_do_fill = [this](offs_t lstart, offs_t lend) { + u16 *dest = reinterpret_cast<u16 *>(&m_buffer[0]) + ((lstart - m_lstart) >> 4); + for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 0x10) & m_pc_mask) + *dest++ = m_intf->decrypt16(m_back->r16(lpc), lpc, m_opcode); + }; + break; + } + } + + // Define the accessors + if(m_intf->interface_flags() & util::disasm_interface::NONLINEAR_PC) { + switch(shift) { + case -1: + m_do_r8 = [](offs_t pc) -> u8 { throw emu_fatalerror("debug_disasm_buffer::debug_data_buffer: r8 access on 16-bits granularity bus\n"); }; + m_do_r16 = [this](offs_t pc) -> u16 { + offs_t lpc = m_intf->pc_real_to_linear(pc); + fill(lpc, 1); + const u16 *src = get_ptr<u16>(lpc); + return src[0]; + }; + + switch(endian) { + case ENDIANNESS_LITTLE: + m_do_r32 = [this](offs_t pc) -> u32 { + offs_t lpc = m_intf->pc_real_to_linear(pc); + fill(lpc, 2); + u32 r = 0; + for(int j=0; j != 2; j++) { + r |= get<u16>(lpc) << (j*16); + lpc = (lpc & ~m_page_mask) | ((lpc + 1) & m_page_mask); + } + return r; + }; + m_do_r64 = [this](offs_t pc) -> u64 { + offs_t lpc = m_intf->pc_real_to_linear(pc); + fill(lpc, 4); + u64 r = 0; + for(int j=0; j != 4; j++) { + r |= u64(get<u16>(lpc)) << (j*16); + lpc = (lpc & ~m_page_mask) | ((lpc + 1) & m_page_mask); + } + return r; + }; + break; + + case ENDIANNESS_BIG: + m_do_r32 = [this](offs_t pc) -> u32 { + offs_t lpc = m_intf->pc_real_to_linear(pc); + fill(lpc, 2); + u32 r = 0; + for(int j=0; j != 2; j++) { + r |= get<u16>(lpc) << ((1-j)*16); + lpc = (lpc & ~m_page_mask) | ((lpc + 1) & m_page_mask); + } + return r; + }; + m_do_r64 = [this](offs_t pc) -> u64 { + offs_t lpc = m_intf->pc_real_to_linear(pc); + fill(lpc, 4); + u64 r = 0; + for(int j=0; j != 4; j++) { + r |= u64(get<u16>(lpc)) << ((3-j)*16); + lpc = (lpc & ~m_page_mask) | ((lpc + 1) & m_page_mask); + } + return r; + }; + break; + } + break; + + case 0: + m_do_r8 = [this](offs_t pc) -> u8 { + offs_t lpc = m_intf->pc_real_to_linear(pc); + fill(lpc, 1); + const u8 *src = get_ptr<u8>(lpc); + return src[0]; + }; + + switch(endian) { + case ENDIANNESS_LITTLE: + m_do_r16 = [this](offs_t pc) -> u16 { + offs_t lpc = m_intf->pc_real_to_linear(pc); + fill(lpc, 2); + u16 r = 0; + for(int j=0; j != 2; j++) { + r |= get<u8>(lpc) << (j*8); + lpc = (lpc & ~m_page_mask) | ((lpc + 1) & m_page_mask); + } + return r; + }; + m_do_r32 = [this](offs_t pc) -> u32 { + offs_t lpc = m_intf->pc_real_to_linear(pc); + fill(lpc, 4); + u32 r = 0; + for(int j=0; j != 2; j++) { + r |= get<u8>(lpc) << (j*8); + lpc = (lpc & ~m_page_mask) | ((lpc + 1) & m_page_mask); + } + return r; + }; + m_do_r64 = [this](offs_t pc) -> u64 { + offs_t lpc = m_intf->pc_real_to_linear(pc); + fill(lpc, 8); + u64 r = 0; + for(int j=0; j != 8; j++) { + r |= u64(get<u8>(lpc)) << (j*8); + lpc = (lpc & ~m_page_mask) | ((lpc + 1) & m_page_mask); + } + return r; + }; + break; + + case ENDIANNESS_BIG: + m_do_r16 = [this](offs_t pc) -> u16 { + offs_t lpc = m_intf->pc_real_to_linear(pc); + fill(lpc, 2); + u16 r = 0; + for(int j=0; j != 2; j++) { + r |= get<u8>(lpc) << ((1-j)*8); + lpc = (lpc & ~m_page_mask) | ((lpc + 1) & m_page_mask); + } + return r; + }; + m_do_r32 = [this](offs_t pc) -> u32 { + offs_t lpc = m_intf->pc_real_to_linear(pc); + fill(lpc, 4); + u32 r = 0; + for(int j=0; j != 2; j++) { + r |= get<u8>(lpc) << ((3-j)*8); + lpc = (lpc & ~m_page_mask) | ((lpc + 1) & m_page_mask); + } + return r; + }; + m_do_r64 = [this](offs_t pc) -> u64 { + offs_t lpc = m_intf->pc_real_to_linear(pc); + fill(lpc, 8); + u64 r = 0; + for(int j=0; j != 8; j++) { + r |= u64(get<u8>(lpc)) << ((7-j)*8); + lpc = (lpc & ~m_page_mask) | ((lpc + 1) & m_page_mask); + } + return r; + }; + break; + } + break; + } + } else { + switch(shift) { + case -3: // bus granularity 64 + m_do_r8 = [](offs_t pc) -> u8 { throw emu_fatalerror("debug_disasm_buffer::debug_data_buffer: r8 access on 64-bits granularity bus\n"); }; + m_do_r16 = [](offs_t pc) -> u16 { throw emu_fatalerror("debug_disasm_buffer::debug_data_buffer: r16 access on 64-bits granularity bus\n"); }; + m_do_r32 = [](offs_t pc) -> u32 { throw emu_fatalerror("debug_disasm_buffer::debug_data_buffer: r32 access on 64-bits granularity bus\n"); }; + m_do_r64 = [this](offs_t pc) -> u64 { + fill(pc, 1); + const u64 *src = get_ptr<u64>(pc); + return src[0]; + }; + break; + + case -2: // bus granularity 32 + m_do_r8 = [](offs_t pc) -> u8 { throw emu_fatalerror("debug_disasm_buffer::debug_data_buffer: r8 access on 32-bits granularity bus\n"); }; + m_do_r16 = [](offs_t pc) -> u16 { throw emu_fatalerror("debug_disasm_buffer::debug_data_buffer: r16 access on 32-bits granularity bus\n"); }; + m_do_r32 = [this](offs_t pc) -> u32 { + fill(pc, 1); + const u32 *src = get_ptr<u32>(pc); + return src[0]; + }; + switch(endian) { + case ENDIANNESS_LITTLE: + if(m_page_mask) { + m_do_r64 = [this](offs_t pc) -> u64 { + fill(pc, 2); + u64 r = 0; + for(int j=0; j != 2; j++) { + r |= u64(get<u32>(pc)) << (j*32); + pc = (pc & ~m_page_mask) | ((pc + 1) & m_page_mask); + } + return r; + }; + } else { + m_do_r64 = [this](offs_t pc) -> u64 { + fill(pc, 2); + const u32 *src = get_ptr<u32>(pc); + return src[0] | (u64(src[1]) << 32); + }; + } + break; + case ENDIANNESS_BIG: + if(m_page_mask) { + m_do_r64 = [this](offs_t pc) -> u64 { + fill(pc, 2); + u64 r = 0; + for(int j=0; j != 2; j++) { + r |= u64(get<u32>(pc)) << ((1-j)*32); + pc = (pc & ~m_page_mask) | ((pc + 1) & m_page_mask); + } + return r; + }; + } else { + m_do_r64 = [this](offs_t pc) -> u64 { + fill(pc, 2); + const u32 *src = get_ptr<u32>(pc); + return (u64(src[0]) << 32) | u64(src[1]); + }; + } + break; + } + break; + + case -1: // bus granularity 16 + m_do_r8 = [](offs_t pc) -> u8 { throw emu_fatalerror("debug_disasm_buffer::debug_data_buffer: r8 access on 16-bits granularity bus\n"); }; + m_do_r16 = [this](offs_t pc) -> u16 { + fill(pc, 1); + const u16 *src = get_ptr<u16>(pc); + return src[0]; + }; + switch(endian) { + case ENDIANNESS_LITTLE: + if(m_page_mask) { + m_do_r32 = [this](offs_t pc) -> u32 { + fill(pc, 2); + u32 r = 0; + for(int j=0; j != 2; j++) { + r |= get<u16>(pc) << (j*16); + pc = (pc & ~m_page_mask) | ((pc + 1) & m_page_mask); + } + return r; + }; + m_do_r64 = [this](offs_t pc) -> u64 { + fill(pc, 4); + u64 r = 0; + for(int j=0; j != 4; j++) { + r |= u64(get<u16>(pc)) << (j*16); + pc = (pc & ~m_page_mask) | ((pc + 1) & m_page_mask); + } + return r; + }; + } else { + m_do_r32 = [this](offs_t pc) -> u32 { + fill(pc, 2); + const u16 *src = get_ptr<u16>(pc); + return src[0] | (src[1] << 16); + }; + m_do_r64 = [this](offs_t pc) -> u64 { + fill(pc, 4); + const u16 *src = get_ptr<u16>(pc); + return src[0] | (src[1] << 16) | (u64(src[2]) << 32) | (u64(src[3]) << 48); + }; + } + break; + case ENDIANNESS_BIG: + if(m_page_mask) { + m_do_r32 = [this](offs_t pc) -> u32 { + fill(pc, 2); + u32 r = 0; + for(int j=0; j != 2; j++) { + r |= get<u16>(pc) << ((1-j)*16); + pc = (pc & ~m_page_mask) | ((pc + 1) & m_page_mask); + } + return r; + }; + m_do_r64 = [this](offs_t pc) -> u64 { + fill(pc, 4); + u64 r = 0; + for(int j=0; j != 4; j++) { + r |= u64(get<u16>(pc)) << ((3-j)*16); + pc = (pc & ~m_page_mask) | ((pc + 1) & m_page_mask); + } + return r; + }; + } else { + m_do_r32 = [this](offs_t pc) -> u32 { + fill(pc, 2); + const u16 *src = get_ptr<u16>(pc); + return (src[0] << 16) | src[1]; + }; + m_do_r64 = [this](offs_t pc) -> u64 { + fill(pc, 4); + const u16 *src = get_ptr<u16>(pc); + return (u64(src[0]) << 48) | (u64(src[1]) << 32) | u32(src[2] << 16) | src[3]; + }; + } + break; + } + break; + + case 0: // bus granularity 8 + m_do_r8 = [this](offs_t pc) -> u8 { + fill(pc, 1); + const u8 *src = get_ptr<u8>(pc); + return src[0]; + }; + switch(endian) { + case ENDIANNESS_LITTLE: + if(m_page_mask) { + m_do_r16 = [this](offs_t pc) -> u16 { + fill(pc, 2); + u16 r = 0; + for(int j=0; j != 2; j++) { + r |= get<u8>(pc) << (j*8); + pc = (pc & ~m_page_mask) | ((pc + 1) & m_page_mask); + } + return r; + }; + m_do_r32 = [this](offs_t pc) -> u32 { + fill(pc, 4); + u32 r = 0; + for(int j=0; j != 4; j++) { + r |= get<u8>(pc) << (j*8); + pc = (pc & ~m_page_mask) | ((pc + 1) & m_page_mask); + } + return r; + }; + m_do_r64 = [this](offs_t pc) -> u64 { + fill(pc, 8); + u64 r = 0; + for(int j=0; j != 8; j++) { + r |= u64(get<u8>(pc)) << (j*8); + pc = (pc & ~m_page_mask) | ((pc + 1) & m_page_mask); + } + return r; + }; + } else { + m_do_r16 = [this](offs_t pc) -> u16 { + fill(pc, 2); + const u8 *src = get_ptr<u8>(pc); + return src[0] | (src[1] << 8); + }; + m_do_r32 = [this](offs_t pc) -> u32 { + fill(pc, 4); + const u8 *src = get_ptr<u8>(pc); + return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24); + }; + m_do_r64 = [this](offs_t pc) -> u64 { + fill(pc, 8); + const u8 *src = get_ptr<u8>(pc); + return src[0] | (src[1] << 8) | (src[2] << 16) | u32(src[3] << 24) | + (u64(src[4]) << 32) | (u64(src[5]) << 40) | (u64(src[6]) << 48) | (u64(src[7]) << 56); + }; + } + break; + case ENDIANNESS_BIG: + if(m_page_mask) { + m_do_r16 = [this](offs_t pc) -> u16 { + fill(pc, 2); + u16 r = 0; + for(int j=0; j != 2; j++) { + r |= get<u8>(pc) << ((1-j)*8); + pc = (pc & ~m_page_mask) | ((pc + 1) & m_page_mask); + } + return r; + }; + m_do_r32 = [this](offs_t pc) -> u32 { + fill(pc, 4); + u32 r = 0; + for(int j=0; j != 4; j++) { + r |= get<u8>(pc) << ((3-j)*8); + pc = (pc & ~m_page_mask) | ((pc + 1) & m_page_mask); + } + return r; + }; + m_do_r64 = [this](offs_t pc) -> u64 { + fill(pc, 8); + u64 r = 0; + for(int j=0; j != 8; j++) { + r |= u64(get<u8>(pc)) << ((7-j)*8); + pc = (pc & ~m_page_mask) | ((pc + 1) & m_page_mask); + } + return r; + }; + } else { + m_do_r16 = [this](offs_t pc) -> u16 { + fill(pc, 2); + const u8 *src = get_ptr<u8>(pc); + return (src[0] << 8) | src[1]; + }; + m_do_r32 = [this](offs_t pc) -> u32 { + fill(pc, 4); + const u8 *src = get_ptr<u8>(pc); + return (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3]; + }; + m_do_r64 = [this](offs_t pc) -> u64 { + fill(pc, 8); + const u8 *src = get_ptr<u8>(pc); + return (u64(src[0]) << 56) | (u64(src[1]) << 32) | (u64(src[2]) << 40) | (u64(src[3]) << 32) | + (src[4] << 24) | (src[5] << 16) | (src[6] << 8) | src[7]; + }; + } + break; + } + break; + + case 3: // bus granularity 1, u16 storage, no paging + assert(endian == ENDIANNESS_LITTLE); + assert(!m_page_mask); + m_do_r8 = [](offs_t pc) -> u8 { throw emu_fatalerror("debug_disasm_buffer::debug_data_buffer: r8 access on 1-bit/16 wide granularity bus\n"); }; + m_do_r16 = [this](offs_t pc) -> u16 { + fill(pc, 16); + const u16 *src = reinterpret_cast<u16 *>(&m_buffer[0]) + ((pc - m_lstart) >> 4); + return src[0]; + }; + m_do_r32 = [this](offs_t pc) -> u32 { + fill(pc, 32); + const u16 *src = reinterpret_cast<u16 *>(&m_buffer[0]) + ((pc - m_lstart) >> 4); + return src[0] | (src[1] << 16); + }; + m_do_r64 = [this](offs_t pc) -> u64 { + fill(pc, 64); + const u16 *src = reinterpret_cast<u16 *>(&m_buffer[0]) + ((pc - m_lstart) >> 4); + return src[0] | (src[1] << 16) | (u64(src[2]) << 32) | (u64(src[3]) << 48); + }; + break; + } + } + + // Define the data -> string conversion + switch(shift) { + case -3: + m_data_to_string = [this](offs_t pc, offs_t size) { + std::ostringstream out; + for(offs_t i=0; i != size; i++) { + if(i) + out << ' '; + util::stream_format(out, "%016x", r64(pc)); + pc = m_next_pc_wrap(pc, 1); + } + return out.str(); + }; + break; + + case -2: + switch(alignment) { + case 1: + m_data_to_string = [this](offs_t pc, offs_t size) { + std::ostringstream out; + for(offs_t i=0; i != size; i++) { + if(i) + out << ' '; + util::stream_format(out, "%08x", r32(pc)); + pc = m_next_pc_wrap(pc, 1); + } + return out.str(); + }; + break; + + case 2: + m_data_to_string = [this](offs_t pc, offs_t size) { + std::ostringstream out; + for(offs_t i=0; i != size; i += 2) { + if(i) + out << ' '; + util::stream_format(out, "%016x", r64(pc)); + pc = m_next_pc_wrap(pc, 2); + } + return out.str(); + }; + break; + } + break; + + case -1: + switch(alignment) { + case 1: + m_data_to_string = [this](offs_t pc, offs_t size) { + std::ostringstream out; + for(offs_t i=0; i != size; i++) { + if(i) + out << ' '; + util::stream_format(out, "%04x", r16(pc)); + pc = m_next_pc_wrap(pc, 1); + } + return out.str(); + }; + break; + + case 2: + m_data_to_string = [this](offs_t pc, offs_t size) { + std::ostringstream out; + for(offs_t i=0; i != size; i += 2) { + if(i) + out << ' '; + util::stream_format(out, "%08x", r32(pc)); + pc = m_next_pc_wrap(pc, 2); + } + return out.str(); + }; + break; + + case 4: + m_data_to_string = [this](offs_t pc, offs_t size) { + std::ostringstream out; + for(offs_t i=0; i != size; i += 4) { + if(i) + out << ' '; + util::stream_format(out, "%016x", r64(pc)); + pc = m_next_pc_wrap(pc, 4); + } + return out.str(); + }; + break; + } + break; + + case 0: + switch(alignment) { + case 1: + m_data_to_string = [this](offs_t pc, offs_t size) { + std::ostringstream out; + for(offs_t i=0; i != size; i++) { + if(i) + out << ' '; + util::stream_format(out, "%02x", r8(pc)); + pc = m_next_pc_wrap(pc, 1); + } + return out.str(); + }; + break; + + case 2: + m_data_to_string = [this](offs_t pc, offs_t size) { + std::ostringstream out; + for(offs_t i=0; i != size; i += 2) { + if(i) + out << ' '; + util::stream_format(out, "%04x", r16(pc)); + pc = m_next_pc_wrap(pc, 2); + } + return out.str(); + }; + break; + + case 4: + m_data_to_string = [this](offs_t pc, offs_t size) { + std::ostringstream out; + for(offs_t i=0; i != size; i += 4) { + if(i) + out << ' '; + util::stream_format(out, "%08x", r32(pc)); + pc = m_next_pc_wrap(pc, 4); + } + return out.str(); + }; + break; + + case 8: + m_data_to_string = [this](offs_t pc, offs_t size) { + std::ostringstream out; + for(offs_t i=0; i != size; i += 8) { + if(i) + out << ' '; + util::stream_format(out, "%016x", r64(pc)); + pc = m_next_pc_wrap(pc, 8); + } + return out.str(); + }; + break; + } + break; + + case 3: + m_data_to_string = [this](offs_t pc, offs_t size) { + std::ostringstream out; + for(offs_t i=0; i != size; i += 16) { + if(i) + out << ' '; + util::stream_format(out, "%04x", r16(pc)); + pc = m_next_pc_wrap(pc, 16); + } + return out.str(); + }; + break; + } + + // Define the data extraction + switch(shift) { + case -3: + m_data_get = [this](offs_t pc, offs_t size, std::vector<u8> &data) { + for(offs_t i=0; i != size; i++) { + u64 r = r64(pc); + for(int j=0; j != 8; j++) + data.push_back(r >> (8*j)); + pc = m_next_pc_wrap(pc, 1); + } + }; + break; + + case -2: + m_data_get = [this](offs_t pc, offs_t size, std::vector<u8> &data) { + for(offs_t i=0; i != size; i++) { + u32 r = r32(pc); + for(int j=0; j != 4; j++) + data.push_back(r >> (8*j)); + pc = m_next_pc_wrap(pc, 1); + } + }; + break; + + case -1: + m_data_get = [this](offs_t pc, offs_t size, std::vector<u8> &data) { + for(offs_t i=0; i != size; i++) { + u16 r = r16(pc); + for(int j=0; j != 2; j++) + data.push_back(r >> (8*j)); + pc = m_next_pc_wrap(pc, 1); + } + }; + break; + + case 0: + m_data_get = [this](offs_t pc, offs_t size, std::vector<u8> &data) { + for(offs_t i=0; i != size; i++) { + data.push_back(r8(pc)); + pc = m_next_pc_wrap(pc, 1); + } + }; + break; + + case 3: + m_data_get = [this](offs_t pc, offs_t size, std::vector<u8> &data) { + for(offs_t i=0; i != size >> 4; i++) { + u16 r = r16(pc); + for(int j=0; j != 2; j++) + data.push_back(r >> (8*j)); + pc = m_next_pc_wrap(pc, 16); + } + }; + break; + } + + // Wrapped next pc computation + if(m_intf->interface_flags() & util::disasm_interface::NONLINEAR_PC) { + // lfsr pc is always paged + m_next_pc_wrap = [this](offs_t pc, offs_t size) { + offs_t lpc = m_intf->pc_real_to_linear(pc); + offs_t lpce = (lpc & ~m_page_mask) | ((lpc + size) & m_page_mask); + return m_intf->pc_linear_to_real(lpce); + }; + } else if(m_intf->interface_flags() & util::disasm_interface::PAGED) { + m_next_pc_wrap = [this](offs_t pc, offs_t size) { + offs_t pce = (pc & ~m_page_mask) | ((pc + size) & m_page_mask); + return pce; + }; + } else { + m_next_pc_wrap = [this](offs_t pc, offs_t size) { + return (pc + size) & m_pc_mask; + }; + } +} + +debug_disasm_buffer::debug_disasm_buffer(device_t &device) : + m_buf_raw(dynamic_cast<device_disasm_interface &>(device).get_disassembler()), + m_buf_opcodes(dynamic_cast<device_disasm_interface &>(device).get_disassembler()), + m_buf_params(dynamic_cast<device_disasm_interface &>(device).get_disassembler()) +{ + m_dintf = dynamic_cast<device_disasm_interface *>(&device)->get_disassembler(); + m_mintf = dynamic_cast<device_memory_interface *>(&device); + + m_flags = m_dintf->interface_flags(); + + if(m_flags & util::disasm_interface::INTERNAL_DECRYPTION) { + m_buf_raw.set_source(m_mintf->space(AS_PROGRAM)); + m_buf_opcodes.set_source(m_buf_raw, true); + if((m_flags & util::disasm_interface::SPLIT_DECRYPTION) == util::disasm_interface::SPLIT_DECRYPTION) + m_buf_params.set_source(m_buf_raw, false); + } else { + if(m_mintf->has_space(AS_OPCODES)) { + m_buf_opcodes.set_source(m_mintf->space(AS_OPCODES)); + m_buf_params.set_source(m_mintf->space(AS_PROGRAM)); + } else + m_buf_opcodes.set_source(m_mintf->space(AS_PROGRAM)); + } + + m_pc_mask = m_mintf->space(AS_PROGRAM).logaddrmask(); + + if(m_flags & util::disasm_interface::PAGED) + m_page_mask = (1 << m_dintf->page_address_bits()) - 1; + else + m_page_mask = 0; + + // Next pc computation + if(m_flags & util::disasm_interface::NONLINEAR_PC) { + // lfsr pc is always paged + m_next_pc = [this](offs_t pc, offs_t size) { + offs_t lpc = m_dintf->pc_real_to_linear(pc); + offs_t lpce = lpc + size; + if((lpc ^ lpce) & ~m_page_mask) + lpce = (lpc | m_page_mask) + 1; + lpce &= m_pc_mask; + return m_dintf->pc_linear_to_real(lpce); + }; + m_next_pc_wrap = [this](offs_t pc, offs_t size) { + offs_t lpc = m_dintf->pc_real_to_linear(pc); + offs_t lpce = (lpc & ~m_page_mask) | ((lpc + size) & m_page_mask); + return m_dintf->pc_linear_to_real(lpce); + }; + + } else if(m_flags & util::disasm_interface::PAGED) { + m_next_pc = [this](offs_t pc, offs_t size) { + offs_t pce = pc + size; + if((pc ^ pce) & ~m_page_mask) + pce = (pc | m_page_mask) + 1; + pce &= m_pc_mask; + return pce; + }; + m_next_pc_wrap = [this](offs_t pc, offs_t size) { + offs_t pce = (pc & ~m_page_mask) | ((pc + size) & m_page_mask); + return pce; + }; + + } else { + m_next_pc = [this](offs_t pc, offs_t size) { + return (pc + size) & m_pc_mask; + }; + m_next_pc_wrap = [this](offs_t pc, offs_t size) { + return (pc + size) & m_pc_mask; + }; + } + + // pc to string conversion + int aw = m_mintf->space(AS_PROGRAM).addr_width(); + bool is_octal = m_mintf->space(AS_PROGRAM).is_octal(); + if((m_flags & util::disasm_interface::PAGED2LEVEL) == util::disasm_interface::PAGED2LEVEL) { + int bits1 = m_dintf->page_address_bits(); + int bits2 = m_dintf->page2_address_bits(); + int bits3 = aw - bits1 - bits2; + offs_t sm1 = (1 << bits1) - 1; + int sh2 = bits1; + offs_t sm2 = (1 << bits2) - 1; + int sh3 = bits1+bits2; + + if(is_octal) { + int nc1 = (bits1+2)/3; + int nc2 = (bits2+2)/3; + int nc3 = (bits3+2)/3; + m_pc_to_string = [nc1, nc2, nc3, sm1, sm2, sh2, sh3](offs_t pc) -> std::string { + return util::string_format("%0*o:%0*o:%0*o", + nc3, pc >> sh3, + nc2, (pc >> sh2) & sm2, + nc1, pc & sm1); + }; + } else { + int nc1 = (bits1+3)/4; + int nc2 = (bits2+3)/4; + int nc3 = (bits3+3)/4; + m_pc_to_string = [nc1, nc2, nc3, sm1, sm2, sh2, sh3](offs_t pc) -> std::string { + return util::string_format("%0*x:%0*x:%0*x", + nc3, pc >> sh3, + nc2, (pc >> sh2) & sm2, + nc1, pc & sm1); + }; + } + + } else if(m_flags & util::disasm_interface::PAGED) { + int bits1 = m_dintf->page_address_bits(); + int bits2 = aw - bits1; + offs_t sm1 = (1 << bits1) - 1; + int sh2 = bits1; + + if(is_octal) { + int nc1 = (bits1+2)/3; + int nc2 = (bits2+2)/3; + m_pc_to_string = [nc1, nc2, sm1, sh2](offs_t pc) -> std::string { + return util::string_format("%0*o:%0*o", + nc2, pc >> sh2, + nc1, pc & sm1); + }; + } else { + int nc1 = (bits1+3)/4; + int nc2 = (bits2+3)/4; + m_pc_to_string = [nc1, nc2, sm1, sh2](offs_t pc) -> std::string { + return util::string_format("%0*x:%0*x", + nc2, pc >> sh2, + nc1, pc & sm1); + }; + } + + } else { + int bits1 = aw; + + if(is_octal) { + int nc1 = (bits1+2)/3; + m_pc_to_string = [nc1](offs_t pc) -> std::string { + return util::string_format("%0*o", + nc1, pc); + }; + } else { + int nc1 = (bits1+3)/4; + m_pc_to_string = [nc1](offs_t pc) -> std::string { + return util::string_format("%0*x", + nc1, pc); + }; + } + } +} + +void debug_disasm_buffer::disassemble(offs_t pc, std::string &instruction, offs_t &next_pc, offs_t &size, u32 &info) const +{ + std::ostringstream out; + u32 result = m_dintf->disassemble(out, pc, m_buf_opcodes, m_buf_params.active() ? m_buf_params : m_buf_opcodes); + instruction = out.str(); + size = result & util::disasm_interface::LENGTHMASK; + next_pc = m_next_pc(pc, size); + info = result; +} + + +u32 debug_disasm_buffer::disassemble_info(offs_t pc) const +{ + std::ostringstream out; + return m_dintf->disassemble(out, pc, m_buf_opcodes, m_buf_params.active() ? m_buf_params : m_buf_opcodes); +} + +std::string debug_disasm_buffer::pc_to_string(offs_t pc) const +{ + return m_pc_to_string(pc); +} + +std::string debug_disasm_buffer::data_to_string(offs_t pc, offs_t size, bool opcode) const +{ + if(!opcode && !m_buf_params.active()) + return std::string(); + return (opcode ? m_buf_opcodes : m_buf_params).data_to_string(pc, size); +} + +void debug_disasm_buffer::data_get(offs_t pc, offs_t size, bool opcode, std::vector<u8> &data) const +{ + data.clear(); + if(!opcode && !m_buf_params.active()) + return; + (opcode ? m_buf_opcodes : m_buf_params).data_get(pc, size, data); +} + +offs_t debug_disasm_buffer::next_pc(offs_t pc, offs_t step) const +{ + return m_next_pc(pc, step); +} + +offs_t debug_disasm_buffer::next_pc_wrap(offs_t pc, offs_t step) const +{ + return m_next_pc_wrap(pc, step); +} diff --git a/src/emu/debug/debugbuf.h b/src/emu/debug/debugbuf.h new file mode 100644 index 00000000000..46ec8286417 --- /dev/null +++ b/src/emu/debug/debugbuf.h @@ -0,0 +1,93 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +// Buffering interface for the disassembly windows + +#ifndef MAME_EMU_DEBUG_DEBUGBUF_H +#define MAME_EMU_DEBUG_DEBUGBUF_H + +#pragma once + +class debug_disasm_buffer +{ +public: + debug_disasm_buffer(device_t &device); + + void disassemble(offs_t pc, std::string &instruction, offs_t &next_pc, offs_t &size, u32 &info) const; + u32 disassemble_info(offs_t pc) const; + std::string pc_to_string(offs_t pc) const; + std::string data_to_string(offs_t pc, offs_t size, bool opcode) const; + void data_get(offs_t pc, offs_t size, bool opcode, std::vector<u8> &data) const; + + offs_t next_pc(offs_t pc, offs_t step) const; + offs_t next_pc_wrap(offs_t pc, offs_t step) const; + +private: + class debug_data_buffer : public util::disasm_interface::data_buffer + { + public: + debug_data_buffer(util::disasm_interface *intf); + ~debug_data_buffer() = default; + + virtual u8 r8 (offs_t pc) const override; + virtual u16 r16(offs_t pc) const override; + virtual u32 r32(offs_t pc) const override; + virtual u64 r64(offs_t pc) const override; + + void set_source(address_space &space); + void set_source(debug_data_buffer &back, bool opcode); + + bool active() const; + + address_space *get_underlying_space() const; + std::string data_to_string(offs_t pc, offs_t size) const; + void data_get(offs_t pc, offs_t size, std::vector<u8> &data) const; + + private: + util::disasm_interface *m_intf; + + std::function<offs_t (offs_t)> m_pc_delta_to_bytes; + std::function<void (offs_t, offs_t)> m_do_fill; + std::function<u8 (offs_t)> m_do_r8; + std::function<u16 (offs_t)> m_do_r16; + std::function<u32 (offs_t)> m_do_r32; + std::function<u64 (offs_t)> m_do_r64; + std::function<std::string (offs_t, offs_t)> m_data_to_string; + std::function<void (offs_t, offs_t, std::vector<u8> &)> m_data_get; + std::function<offs_t (offs_t, offs_t)> m_next_pc_wrap; + + address_space *m_space; + debug_data_buffer *m_back; + bool m_opcode; + offs_t m_page_mask, m_pc_mask; + mutable offs_t m_lstart, m_lend; + mutable bool m_wrapped; + mutable std::vector<u8> m_buffer; + + template<typename T> T *get_ptr(offs_t lpc) { + return reinterpret_cast<T *>(&m_buffer[0]) + ((lpc - m_lstart) & m_pc_mask); + } + + template<typename T> T get(offs_t lpc) const { + return reinterpret_cast<const T *>(&m_buffer[0])[(lpc - m_lstart) & m_pc_mask]; + } + + void setup_methods(); + void fill(offs_t lstart, offs_t size) const; + + }; + + util::disasm_interface *m_dintf; + device_memory_interface *m_mintf; + + std::function<offs_t (offs_t, offs_t)> m_next_pc; + std::function<offs_t (offs_t, offs_t)> m_next_pc_wrap; + std::function<std::string (offs_t)> m_pc_to_string; + + debug_data_buffer m_buf_raw, m_buf_opcodes, m_buf_params; + u32 m_flags; + offs_t m_page_mask, m_pc_mask; +}; + +#endif + diff --git a/src/emu/debug/debugcmd.cpp b/src/emu/debug/debugcmd.cpp index c1e96054164..0c7715b523b 100644 --- a/src/emu/debug/debugcmd.cpp +++ b/src/emu/debug/debugcmd.cpp @@ -14,6 +14,7 @@ #include "debugcmd.h" #include "debugcon.h" #include "debugcpu.h" +#include "debugbuf.h" #include "express.h" #include "debughlp.h" #include "debugvw.h" @@ -1644,7 +1645,6 @@ void debugger_commands::execute_save(int ref, const std::vector<std::string> &pa u64 offset, endoffset, length; address_space *space; FILE *f; - u64 i; /* validate parameters */ if (!validate_number_parameter(params[1], offset)) @@ -1655,8 +1655,9 @@ void debugger_commands::execute_save(int ref, const std::vector<std::string> &pa return; /* determine the addresses to write */ - endoffset = space->address_to_byte(offset + length - 1) & space->bytemask(); - offset = space->address_to_byte(offset) & space->bytemask(); + endoffset = (offset + length - 1) & space->addrmask(); + offset = offset & space->addrmask(); + endoffset ++; /* open the file */ f = fopen(params[0].c_str(), "wb"); @@ -1667,10 +1668,46 @@ void debugger_commands::execute_save(int ref, const std::vector<std::string> &pa } /* now write the data out */ - for (i = offset; i <= endoffset; i++) + auto dis = space->machine().disable_side_effect(); + switch (space->addrbus_shift()) { - u8 byte = m_cpu.read_byte(*space, i, true); - fwrite(&byte, 1, 1, f); + case -3: + for (offs_t i = offset; i != endoffset; i++) + { + u64 data = space->read_qword(i); + fwrite(&data, 8, 1, f); + } + break; + case -2: + for (offs_t i = offset; i != endoffset; i++) + { + u32 data = space->read_dword(i); + fwrite(&data, 4, 1, f); + } + break; + case -1: + for (offs_t i = offset; i != endoffset; i++) + { + u16 byte = space->read_word(i); + fwrite(&byte, 2, 1, f); + } + break; + case 0: + for (offs_t i = offset; i != endoffset; i++) + { + u8 byte = space->read_byte(i); + fwrite(&byte, 1, 1, f); + } + break; + case 3: + offset &= ~15; + endoffset &= ~15; + for (offs_t i = offset; i != endoffset; i+=16) + { + u16 byte = space->read_word(i >> 4); + fwrite(&byte, 2, 1, f); + } + break; } /* close the file */ @@ -1687,7 +1724,6 @@ void debugger_commands::execute_load(int ref, const std::vector<std::string> &pa { u64 offset, endoffset, length = 0; address_space *space; - u64 i; // validate parameters if (!validate_number_parameter(params[1], offset)) @@ -1712,19 +1748,66 @@ void debugger_commands::execute_load(int ref, const std::vector<std::string> &pa f.seekg(0, std::ios::end); length = f.tellg(); f.seekg(0); + if (space->addrbus_shift() < 0) + length >>= -space->addrbus_shift(); + else if (space->addrbus_shift() > 0) + length <<= space->addrbus_shift(); } // determine the addresses to read - endoffset = space->address_to_byte(offset + length - 1) & space->bytemask(); - offset = space->address_to_byte(offset) & space->bytemask(); - + endoffset = (offset + length - 1) & space->addrmask(); + offset = offset & space->addrmask(); + offs_t i = 0; // now read the data in, ignore endoffset and load entire file if length has been set to zero (offset-1) - for (i = offset; f.good() && (i <= endoffset || endoffset == offset - 1); i++) + switch (space->addrbus_shift()) { - char byte; - f.read(&byte, 1); - if (f) - m_cpu.write_byte(*space, i, byte, true); + case -3: + for (i = offset; f.good() && (i <= endoffset || endoffset == offset - 1); i++) + { + u64 data; + f.read((char *)&data, 8); + if (f) + space->write_qword(i, data); + } + break; + case -2: + for (i = offset; f.good() && (i <= endoffset || endoffset == offset - 1); i++) + { + u32 data; + f.read((char *)&data, 4); + if (f) + space->write_dword(i, data); + } + break; + case -1: + for (i = offset; f.good() && (i <= endoffset || endoffset == offset - 1); i++) + { + u16 data; + f.read((char *)&data, 2); + if (f) + space->write_word(i, data); + } + break; + case 0: + for (i = offset; f.good() && (i <= endoffset || endoffset == offset - 1); i++) + { + u8 data; + f.read((char *)&data, 1); + if (f) + space->write_byte(i, data); + } + break; + case 3: + offset &= ~15; + endoffset &= ~15; + for (i = offset; f.good() && (i <= endoffset || endoffset == offset - 16); i+=16) + { + u16 data; + f.read((char *)&data, 2); + if (f) + space->write_word(i >> 4, data); + } + break; } if (!f.good()) @@ -1767,6 +1850,9 @@ void debugger_commands::execute_dump(int ref, const std::vector<std::string> &pa if (!validate_cpu_space_parameter((params.size() > 6) ? params[6].c_str() : nullptr, ref, space)) return; + int shift = space->addrbus_shift(); + u64 granularity = shift > 0 ? 2 : 1 << -shift; + /* further validation */ if (width == 0) width = space->data_width() / 8; @@ -1777,14 +1863,19 @@ void debugger_commands::execute_dump(int ref, const std::vector<std::string> &pa m_console.printf("Invalid width! (must be 1,2,4 or 8)\n"); return; } + if (width < granularity) + { + m_console.printf("Invalid width! (must be at least %d)\n", granularity); + return; + } if (rowsize == 0 || (rowsize % width) != 0) { m_console.printf("Invalid row size! (must be a positive multiple of %d)\n", width); return; } - u64 endoffset = space->address_to_byte(offset + length - 1) & space->bytemask(); - offset = space->address_to_byte(offset) & space->bytemask(); + u64 endoffset = (offset + length - 1) & space->addrmask(); + offset = offset & space->addrmask(); /* open the file */ FILE* f = fopen(params[0].c_str(), "w"); @@ -1797,13 +1888,22 @@ void debugger_commands::execute_dump(int ref, const std::vector<std::string> &pa /* now write the data out */ util::ovectorstream output; output.reserve(200); - for (u64 i = offset; i <= endoffset; i += rowsize) + + if (shift > 0) + width <<= shift; + else if(shift < 0) + width >>= -shift; + + auto dis = space->machine().disable_side_effect(); + bool be = space->endianness() == ENDIANNESS_BIG; + + for (offs_t i = offset; i <= endoffset; i += rowsize) { output.clear(); output.rdbuf()->clear(); /* print the address */ - util::stream_format(output, "%0*X: ", space->logaddrchars(), u32(space->byte_to_address(i))); + util::stream_format(output, "%0*X: ", space->logaddrchars(), i); /* print the bytes */ for (u64 j = 0; j < rowsize; j += width) @@ -1813,8 +1913,21 @@ void debugger_commands::execute_dump(int ref, const std::vector<std::string> &pa offs_t curaddr = i + j; if (space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, curaddr)) { - u64 value = m_cpu.read_memory(*space, i + j, width, true); - util::stream_format(output, " %0*X", width * 2, value); + switch (width) + { + case 8: + util::stream_format(output, " %016X", space->read_qword(i+j)); + break; + case 4: + util::stream_format(output, " %08X", space->read_dword(i+j)); + break; + case 2: + util::stream_format(output, " %04X", space->read_word(i+j)); + break; + case 1: + util::stream_format(output, " %02X", space->read_byte(i+j)); + break; + } } else { @@ -1834,8 +1947,26 @@ void debugger_commands::execute_dump(int ref, const std::vector<std::string> &pa offs_t curaddr = i + j; if (space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, curaddr)) { - u8 byte = m_cpu.read_byte(*space, i + j, true); - util::stream_format(output, "%c", (byte >= 32 && byte < 127) ? byte : '.'); + u64 data = 0; + switch (width) + { + case 8: + data = space->read_qword(i+j); + break; + case 4: + data = space->read_dword(i+j); + break; + case 2: + data = space->read_word(i+j); + break; + case 1: + data = space->read_byte(i+j); + break; + } + for (unsigned int b = 0; b != width; b++) { + u8 byte = data >> (8 * (be ? (width-i-b) : b)); + util::stream_format(output, "%c", (byte >= 32 && byte < 127) ? byte : '.'); + } } else { @@ -1920,8 +2051,8 @@ void debugger_commands::execute_cheatinit(int ref, const std::vector<std::string { for (address_map_entry &entry : space->map()->m_entrylist) { - cheat_region[region_count].offset = space->address_to_byte(entry.m_addrstart) & space->bytemask(); - cheat_region[region_count].endoffset = space->address_to_byte(entry.m_addrend) & space->bytemask(); + cheat_region[region_count].offset = entry.m_addrstart & space->addrmask(); + cheat_region[region_count].endoffset = entry.m_addrend & space->addrmask(); cheat_region[region_count].share = entry.m_share; cheat_region[region_count].disabled = (entry.m_write.m_type == AMH_RAM) ? false : true; @@ -1944,8 +2075,8 @@ void debugger_commands::execute_cheatinit(int ref, const std::vector<std::string return; /* force region to the specified range */ - cheat_region[region_count].offset = space->address_to_byte(offset) & space->bytemask(); - cheat_region[region_count].endoffset = space->address_to_byte(offset + length - 1) & space->bytemask(); + cheat_region[region_count].offset = offset & space->addrmask(); + cheat_region[region_count].endoffset = (offset + length - 1) & space->addrmask(); cheat_region[region_count].share = nullptr; cheat_region[region_count].disabled = false; region_count++; @@ -2320,9 +2451,9 @@ void debugger_commands::execute_find(int ref, const std::vector<std::string> &pa return; /* further validation */ - endoffset = space->address_to_byte(offset + length - 1) & space->bytemask(); - offset = space->address_to_byte(offset) & space->bytemask(); - cur_data_size = space->address_to_byte(1); + endoffset = (offset + length - 1) & space->addrmask(); + offset = offset & space->addrmask(); + cur_data_size = space->addrbus_shift() > 0 ? 2 : 1 << -space->addrbus_shift(); if (cur_data_size == 0) cur_data_size = 1; @@ -2403,10 +2534,7 @@ void debugger_commands::execute_find(int ref, const std::vector<std::string> &pa void debugger_commands::execute_dasm(int ref, const std::vector<std::string> ¶ms) { u64 offset, length, bytes = 1; - int minbytes, maxbytes, byteswidth; - address_space *space, *decrypted_space; - FILE *f; - int j; + address_space *space; /* validate parameters */ if (!validate_number_parameter(params[1], offset)) @@ -2417,10 +2545,6 @@ void debugger_commands::execute_dasm(int ref, const std::vector<std::string> &pa return; if (!validate_cpu_space_parameter(params.size() > 4 ? params[4].c_str() : nullptr, AS_PROGRAM, space)) return; - if (space->device().memory().has_space(AS_OPCODES)) - decrypted_space = &space->device().memory().space(AS_OPCODES); - else - decrypted_space = space; /* determine the width of the bytes */ device_disasm_interface *dasmintf; @@ -2429,104 +2553,72 @@ void debugger_commands::execute_dasm(int ref, const std::vector<std::string> &pa m_console.printf("No disassembler available for %s\n", space->device().name()); return; } - minbytes = dasmintf->min_opcode_bytes(); - maxbytes = dasmintf->max_opcode_bytes(); - byteswidth = 0; - if (bytes) - { - byteswidth = (maxbytes + (minbytes - 1)) / minbytes; - byteswidth *= (2 * minbytes) + 1; - } - /* open the file */ - f = fopen(params[0].c_str(), "w"); - if (!f) - { - m_console.printf("Error opening file '%s'\n", params[0].c_str()); - return; - } + /* build the data, check the maximum size of the opcodes and disasm */ + std::vector<offs_t> pcs; + std::vector<std::string> instructions; + std::vector<std::string> tpc; + std::vector<std::string> topcodes; + int max_opcodes_size = 0; + int max_disasm_size = 0; + + debug_disasm_buffer buffer(space->device()); - /* now write the data out */ - util::ovectorstream output; - util::ovectorstream disasm; - output.reserve(512); for (u64 i = 0; i < length; ) { - int pcbyte = space->address_to_byte(offset + i) & space->bytemask(); - const char *comment; - offs_t tempaddr; - int numbytes = 0; - output.clear(); - output.rdbuf()->clear(); - disasm.clear(); - disasm.seekp(0); + std::string instruction; + offs_t next_offset; + offs_t size; + u32 info; + buffer.disassemble(offset, instruction, next_offset, size, info); + pcs.push_back(offset); + instructions.emplace_back(instruction); + tpc.emplace_back(buffer.pc_to_string(offset)); + topcodes.emplace_back(buffer.data_to_string(offset, size, true)); - /* print the address */ - stream_format(output, "%0*X: ", space->logaddrchars(), u32(space->byte_to_address(pcbyte))); + int osize = topcodes.back().size(); + if(osize > max_opcodes_size) + max_opcodes_size = osize; - /* make sure we can translate the address */ - tempaddr = pcbyte; - if (space->device().memory().translate(space->spacenum(), TRANSLATE_FETCH_DEBUG, tempaddr)) - { - { - u8 opbuf[64], argbuf[64]; + int dsize = instructions.back().size(); + if(dsize > max_disasm_size) + max_disasm_size = dsize; - /* fetch the bytes up to the maximum */ - for (numbytes = 0; numbytes < maxbytes; numbytes++) - { - opbuf[numbytes] = m_cpu.read_opcode(*decrypted_space, pcbyte + numbytes, 1); - argbuf[numbytes] = m_cpu.read_opcode(*space, pcbyte + numbytes, 1); - } + i += size; + offset = next_offset; + } - /* disassemble the result */ - i += numbytes = dasmintf->disassemble(disasm, offset + i, opbuf, argbuf) & DASMFLAG_LENGTHMASK; - } + /* write the data */ + std::ofstream f(params[0]); + if (!f.good()) + { + m_console.printf("Error opening file '%s'\n", params[0]); + return; + } - /* print the bytes */ - if (bytes) - { - auto const startdex = output.tellp(); - numbytes = space->address_to_byte(numbytes); - for (j = 0; j < numbytes; j += minbytes) - stream_format(output, "%0*X ", minbytes * 2, m_cpu.read_opcode(*decrypted_space, pcbyte + j, minbytes)); - if ((output.tellp() - startdex) < byteswidth) - stream_format(output, "%*s", byteswidth - (output.tellp() - startdex), ""); - stream_format(output, " "); - } - } - else + if (bytes) + { + for(unsigned int i=0; i != pcs.size(); i++) { - disasm << "<unmapped>"; - i += minbytes; + const char *comment = space->device().debug()->comment_text(pcs[i]); + if (comment) + util::stream_format(f, "%s: %-*s %-*s // %s\n", tpc[i], max_opcodes_size, topcodes[i], max_disasm_size, instructions[i], comment); + else + util::stream_format(f, "%s: %-*s %s\n", tpc[i], max_opcodes_size, topcodes[i], instructions[i]); } - - /* add the disassembly */ - disasm.put('\0'); - stream_format(output, "%s", &disasm.vec()[0]); - - /* attempt to add the comment */ - comment = space->device().debug()->comment_text(tempaddr); - if (comment != nullptr) + } + else + { + for(unsigned int i=0; i != pcs.size(); i++) { - /* somewhat arbitrary guess as to how long most disassembly lines will be [column 60] */ - if (output.tellp() < 60) - { - /* pad the comment space out to 60 characters and null-terminate */ - while (output.tellp() < 60) output.put(' '); - - stream_format(output, "// %s", comment); - } + const char *comment = space->device().debug()->comment_text(pcs[i]); + if (comment) + util::stream_format(f, "%s: %-*s // %s\n", tpc[i], max_disasm_size, instructions[i], comment); else - stream_format(output, "\t// %s", comment); + util::stream_format(f, "%s: %s\n", tpc[i], instructions[i]); } - - /* output the result */ - auto const &text(output.vec()); - fprintf(f, "%.*s\n", int(unsigned(text.size())), &text[0]); } - /* close the file */ - fclose(f); m_console.printf("Data dumped successfully\n"); } @@ -2640,13 +2732,9 @@ void debugger_commands::execute_traceflush(int ref, const std::vector<std::strin void debugger_commands::execute_history(int ref, const std::vector<std::string> ¶ms) { /* validate parameters */ - address_space *space, *decrypted_space; + address_space *space; if (!validate_cpu_space_parameter(!params.empty() ? params[0].c_str() : nullptr, AS_PROGRAM, space)) return; - if (space->device().memory().has_space(AS_OPCODES)) - decrypted_space = &space->device().memory().space(AS_OPCODES); - else - decrypted_space = space; u64 count = device_debug::HISTORY_SIZE; if (params.size() > 1 && !validate_number_parameter(params[1], count)) @@ -2665,25 +2753,19 @@ void debugger_commands::execute_history(int ref, const std::vector<std::string> m_console.printf("No disassembler available for %s\n", space->device().name()); return; } - int maxbytes = dasmintf->max_opcode_bytes(); + + debug_disasm_buffer buffer(space->device()); + for (int index = 0; index < (int) count; index++) { offs_t pc = debug->history_pc(-index); + std::string instruction; + offs_t next_offset; + offs_t size; + u32 info; + buffer.disassemble(pc, instruction, next_offset, size, info); - /* fetch the bytes up to the maximum */ - offs_t pcbyte = space->address_to_byte(pc) & space->bytemask(); - u8 opbuf[64], argbuf[64]; - for (int numbytes = 0; numbytes < maxbytes; numbytes++) - { - opbuf[numbytes] = m_cpu.read_opcode(*decrypted_space, pcbyte + numbytes, 1); - argbuf[numbytes] = m_cpu.read_opcode(*space, pcbyte + numbytes, 1); - } - - util::ovectorstream buffer; - dasmintf->disassemble(buffer, pc, opbuf, argbuf); - buffer.put('\0'); - - m_console.printf("%0*X: %s\n", space->logaddrchars(), pc, &buffer.vec()[0]); + m_console.printf("%s: %s\n", buffer.pc_to_string(pc), instruction); } } @@ -2882,7 +2964,7 @@ void debugger_commands::execute_map(int ref, const std::vector<std::string> &par for (intention = TRANSLATE_READ_DEBUG; intention <= TRANSLATE_FETCH_DEBUG; intention++) { static const char *const intnames[] = { "Read", "Write", "Fetch" }; - taddress = space->address_to_byte(address) & space->bytemask(); + taddress = address & space->addrmask(); if (space->device().memory().translate(space->spacenum(), intention, taddress)) { const char *mapname = space->get_handler_string((intention == TRANSLATE_WRITE_DEBUG) ? read_or_write::WRITE : read_or_write::READ, taddress); @@ -2890,7 +2972,7 @@ void debugger_commands::execute_map(int ref, const std::vector<std::string> &par "%7s: %0*X logical == %0*X physical -> %s\n", intnames[intention & 3], space->logaddrchars(), address, - space->addrchars(), space->byte_to_address(taddress), + space->addrchars(), taddress, mapname); } else diff --git a/src/emu/debug/debugcon.cpp b/src/emu/debug/debugcon.cpp index 8b0cd786bff..3b0f2e98b6b 100644 --- a/src/emu/debug/debugcon.cpp +++ b/src/emu/debug/debugcon.cpp @@ -344,7 +344,7 @@ CMDERR debugger_console::execute_command(const std::string &command, bool echo) if (!echo) printf(">%s\n", command.c_str()); printf(" %*s^\n", CMDERR_ERROR_OFFSET(result), ""); - printf("%s\n", cmderr_to_string(result)); + printf("%s\n", cmderr_to_string(result).c_str()); } /* update all views */ @@ -404,8 +404,9 @@ void debugger_console::register_command(const char *command, u32 flags, int ref, for a given command error -------------------------------------------------*/ -const char *debugger_console::cmderr_to_string(CMDERR error) +std::string debugger_console::cmderr_to_string(CMDERR error) { + int offset = CMDERR_ERROR_OFFSET(error); switch (CMDERR_ERROR_CLASS(error)) { case CMDERR_UNKNOWN_COMMAND: return "unknown command"; @@ -414,7 +415,8 @@ const char *debugger_console::cmderr_to_string(CMDERR error) case CMDERR_UNBALANCED_QUOTES: return "unbalanced quotes"; case CMDERR_NOT_ENOUGH_PARAMS: return "not enough parameters for command"; case CMDERR_TOO_MANY_PARAMS: return "too many parameters for command"; - case CMDERR_EXPRESSION_ERROR: return "error in assignment expression"; + case CMDERR_EXPRESSION_ERROR: return string_format("error in assignment expression: %s", + expression_error(static_cast<expression_error::error_code>(offset)).code_string()); default: return "unknown error"; } } diff --git a/src/emu/debug/debugcon.h b/src/emu/debug/debugcon.h index 54bc3bf6772..7cc1231d4c9 100644 --- a/src/emu/debug/debugcon.h +++ b/src/emu/debug/debugcon.h @@ -104,7 +104,7 @@ public: vprintf_wrap(wrapcol, util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...)); } - static const char * cmderr_to_string(CMDERR error); + static std::string cmderr_to_string(CMDERR error); private: void exit(); diff --git a/src/emu/debug/debugcpu.cpp b/src/emu/debug/debugcpu.cpp index 46ad9e04683..c5f5a532599 100644 --- a/src/emu/debug/debugcpu.cpp +++ b/src/emu/debug/debugcpu.cpp @@ -10,6 +10,7 @@ #include "emu.h" #include "debugcpu.h" +#include "debugbuf.h" #include "express.h" #include "debugcon.h" @@ -363,7 +364,7 @@ u8 debugger_cpu::read_byte(address_space &space, offs_t address, bool apply_tran device_memory_interface &memory = space.device().memory(); /* mask against the logical byte mask */ - address &= space.logbytemask(); + address &= space.logaddrmask(); /* translate if necessary; if not mapped, return 0xff */ u8 result; @@ -388,7 +389,7 @@ u8 debugger_cpu::read_byte(address_space &space, offs_t address, bool apply_tran u16 debugger_cpu::read_word(address_space &space, offs_t address, bool apply_translation) { /* mask against the logical byte mask */ - address &= space.logbytemask(); + address &= space.logaddrmask(); u16 result; if (!WORD_ALIGNED(address)) @@ -429,7 +430,7 @@ u16 debugger_cpu::read_word(address_space &space, offs_t address, bool apply_tra u32 debugger_cpu::read_dword(address_space &space, offs_t address, bool apply_translation) { /* mask against the logical byte mask */ - address &= space.logbytemask(); + address &= space.logaddrmask(); u32 result; if (!DWORD_ALIGNED(address)) @@ -469,7 +470,7 @@ u32 debugger_cpu::read_dword(address_space &space, offs_t address, bool apply_tr u64 debugger_cpu::read_qword(address_space &space, offs_t address, bool apply_translation) { /* mask against the logical byte mask */ - address &= space.logbytemask(); + address &= space.logaddrmask(); u64 result; if (!QWORD_ALIGNED(address)) @@ -531,7 +532,7 @@ void debugger_cpu::write_byte(address_space &space, offs_t address, u8 data, boo device_memory_interface &memory = space.device().memory(); /* mask against the logical byte mask */ - address &= space.logbytemask(); + address &= space.logaddrmask(); /* translate if necessary; if not mapped, we're done */ if (apply_translation && !memory.translate(space.spacenum(), TRANSLATE_WRITE_DEBUG, address)) @@ -553,7 +554,7 @@ void debugger_cpu::write_byte(address_space &space, offs_t address, u8 data, boo void debugger_cpu::write_word(address_space &space, offs_t address, u16 data, bool apply_translation) { /* mask against the logical byte mask */ - address &= space.logbytemask(); + address &= space.logaddrmask(); /* if this is a misaligned write, or if there are no word writers, just read two bytes */ if (!WORD_ALIGNED(address)) @@ -596,7 +597,7 @@ void debugger_cpu::write_word(address_space &space, offs_t address, u16 data, bo void debugger_cpu::write_dword(address_space &space, offs_t address, u32 data, bool apply_translation) { /* mask against the logical byte mask */ - address &= space.logbytemask(); + address &= space.logaddrmask(); /* if this is a misaligned write, or if there are no dword writers, just read two words */ if (!DWORD_ALIGNED(address)) @@ -639,7 +640,7 @@ void debugger_cpu::write_dword(address_space &space, offs_t address, u32 data, b void debugger_cpu::write_qword(address_space &space, offs_t address, u64 data, bool apply_translation) { /* mask against the logical byte mask */ - address &= space.logbytemask(); + address &= space.logaddrmask(); /* if this is a misaligned write, or if there are no qword writers, just read two dwords */ if (!QWORD_ALIGNED(address)) @@ -703,7 +704,7 @@ u64 debugger_cpu::read_opcode(address_space &space, offs_t address, int size) u64 result = ~u64(0) & (~u64(0) >> (64 - 8*size)); /* keep in logical range */ - address &= space.logbytemask(); + address &= space.logaddrmask(); /* if we're bigger than the address bus, break into smaller pieces */ if (size > space.data_width() / 8) @@ -723,7 +724,7 @@ u64 debugger_cpu::read_opcode(address_space &space, offs_t address, int size) return result; /* keep in physical range */ - address &= space.bytemask(); + address &= space.addrmask(); /* switch off the size and handle unaligned accesses */ switch (size) @@ -1559,8 +1560,12 @@ device_debug::device_debug(device_t &device) std::string tempstr; for (const auto &entry : m_state->state_entries()) { - strmakelower(tempstr.assign(entry->symbol())); - m_symtable.add(tempstr.c_str(), (void *)(uintptr_t)entry->index(), get_state, set_state, entry->format_string()); + // TODO: floating point registers + if (!entry->is_float()) + { + strmakelower(tempstr.assign(entry->symbol())); + m_symtable.add(tempstr.c_str(), (void *)(uintptr_t)entry->index(), get_state, entry->writeable() ? set_state : nullptr, entry->format_string()); + } } } @@ -2483,33 +2488,15 @@ bool device_debug::comment_import(util::xml::data_node const &cpunode, bool is_i u32 device_debug::compute_opcode_crc32(offs_t pc) const { - // Basically the same thing as dasm_wrapped, but with some tiny savings - assert(m_memory != nullptr); - - // determine the adjusted PC - address_space &decrypted_space = m_memory->has_space(AS_OPCODES) ? m_memory->space(AS_OPCODES) : m_memory->space(AS_PROGRAM); - address_space &space = m_memory->space(AS_PROGRAM); - offs_t pcbyte = space.address_to_byte(pc) & space.bytemask(); - - // fetch the bytes up to the maximum - u8 opbuf[64], argbuf[64]; - int maxbytes = (m_disasm != nullptr) ? m_disasm->max_opcode_bytes() : 1; - for (int numbytes = 0; numbytes < maxbytes; numbytes++) - { - opbuf[numbytes] = m_device.machine().debugger().cpu().read_opcode(decrypted_space, pcbyte + numbytes, 1); - argbuf[numbytes] = m_device.machine().debugger().cpu().read_opcode(space, pcbyte + numbytes, 1); - } + std::vector<u8> opbuf; + debug_disasm_buffer buffer(device()); - u32 numbytes = maxbytes; - if (m_disasm != nullptr) - { - // disassemble to our buffer - std::ostringstream diasmbuf; - numbytes = m_disasm->disassemble(diasmbuf, pc, opbuf, argbuf) & DASMFLAG_LENGTHMASK; - } + // disassemble the current instruction and get the flags + u32 dasmresult = buffer.disassemble_info(pc); + buffer.data_get(pc, dasmresult & util::disasm_interface::LENGTHMASK, true, opbuf); // return a CRC of the exact count of opcode bytes - return core_crc32(0, opbuf, numbytes); + return core_crc32(0, &opbuf[0], opbuf.size()); } @@ -2589,26 +2576,29 @@ void device_debug::compute_debug_flags() void device_debug::prepare_for_step_overout(offs_t pc) { + debug_disasm_buffer buffer(device()); + // disassemble the current instruction and get the flags - std::string dasmbuffer; - offs_t dasmresult = dasm_wrapped(dasmbuffer, pc); + u32 dasmresult = buffer.disassemble_info(pc); // if flags are supported and it's a call-style opcode, set a temp breakpoint after that instruction - if ((dasmresult & DASMFLAG_SUPPORTED) != 0 && (dasmresult & DASMFLAG_STEP_OVER) != 0) + if ((dasmresult & util::disasm_interface::SUPPORTED) != 0 && (dasmresult & util::disasm_interface::STEP_OVER) != 0) { - int extraskip = (dasmresult & DASMFLAG_OVERINSTMASK) >> DASMFLAG_OVERINSTSHIFT; - pc += dasmresult & DASMFLAG_LENGTHMASK; + int extraskip = (dasmresult & util::disasm_interface::OVERINSTMASK) >> util::disasm_interface::OVERINSTSHIFT; + pc = buffer.next_pc_wrap(pc, dasmresult & util::disasm_interface::LENGTHMASK); // if we need to skip additional instructions, advance as requested - while (extraskip-- > 0) - pc += dasm_wrapped(dasmbuffer, pc) & DASMFLAG_LENGTHMASK; + while (extraskip-- > 0) { + u32 result = buffer.disassemble_info(pc); + pc += buffer.next_pc_wrap(pc, result & util::disasm_interface::LENGTHMASK); + } m_stepaddr = pc; } // if we're stepping out and this isn't a step out instruction, reset the steps until stop to a high number if ((m_flags & DEBUG_FLAG_STEPPING_OUT) != 0) { - if ((dasmresult & DASMFLAG_SUPPORTED) != 0 && (dasmresult & DASMFLAG_STEP_OUT) == 0) + if ((dasmresult & util::disasm_interface::SUPPORTED) != 0 && (dasmresult & util::disasm_interface::STEP_OUT) == 0) m_stepsleft = 100; else m_stepsleft = 1; @@ -2881,38 +2871,6 @@ void device_debug::hotspot_check(address_space &space, offs_t address) //------------------------------------------------- -// dasm_wrapped - wraps calls to the disassembler -// by fetching the opcode bytes to a temporary -// buffer and then disassembling them -//------------------------------------------------- - -u32 device_debug::dasm_wrapped(std::string &buffer, offs_t pc) -{ - assert(m_memory != nullptr && m_disasm != nullptr); - - // determine the adjusted PC - address_space &decrypted_space = m_memory->has_space(AS_OPCODES) ? m_memory->space(AS_OPCODES) : m_memory->space(AS_PROGRAM); - address_space &space = m_memory->space(AS_PROGRAM); - offs_t pcbyte = space.address_to_byte(pc) & space.bytemask(); - - // fetch the bytes up to the maximum - u8 opbuf[64], argbuf[64]; - int maxbytes = m_disasm->max_opcode_bytes(); - for (int numbytes = 0; numbytes < maxbytes; numbytes++) - { - opbuf[numbytes] = m_device.machine().debugger().cpu().read_opcode(decrypted_space, pcbyte + numbytes, 1); - argbuf[numbytes] = m_device.machine().debugger().cpu().read_opcode(space, pcbyte + numbytes, 1); - } - - // disassemble to our buffer - std::ostringstream stream; - uint32_t result = m_disasm->disassemble(stream, pc, opbuf, argbuf); - buffer = stream.str(); - return result; -} - - -//------------------------------------------------- // get_current_pc - getter callback for a device's // current instruction pointer //------------------------------------------------- @@ -3090,8 +3048,8 @@ device_debug::watchpoint::watchpoint(device_debug* debugInterface, m_index(index), m_enabled(true), m_type(type), - m_address(space.address_to_byte(address) & space.bytemask()), - m_length(space.address_to_byte(length)), + m_address(address & space.addrmask()), + m_length(length), m_condition(&symbols, (condition != nullptr) ? condition : "1"), m_action((action != nullptr) ? action : "") { @@ -3253,35 +3211,24 @@ void device_debug::tracer::update(offs_t pc) if (!m_action.empty()) m_debug.m_device.machine().debugger().console().execute_command(m_action, false); - // print the address - std::string buffer; - int logaddrchars = m_debug.logaddrchars(); - if (m_debug.is_octal()) - { - buffer = string_format("%0*o: ", logaddrchars*3/2, pc); - } - else - { - buffer = string_format("%0*X: ", logaddrchars, pc); - } - - // print the disassembly - std::string dasm; - offs_t dasmresult = m_debug.dasm_wrapped(dasm, pc); - buffer.append(dasm); + debug_disasm_buffer buffer(m_debug.device()); + std::string instruction; + offs_t next_pc, size; + u32 dasmresult; + buffer.disassemble(pc, instruction, next_pc, size, dasmresult); // output the result - fprintf(&m_file, "%s\n", buffer.c_str()); + fprintf(&m_file, "%s: %s\n", buffer.pc_to_string(pc).c_str(), instruction.c_str()); // do we need to step the trace over this instruction? - if (m_trace_over && (dasmresult & DASMFLAG_SUPPORTED) != 0 && (dasmresult & DASMFLAG_STEP_OVER) != 0) + if (m_trace_over && (dasmresult & util::disasm_interface::SUPPORTED) != 0 && (dasmresult & util::disasm_interface::STEP_OVER) != 0) { - int extraskip = (dasmresult & DASMFLAG_OVERINSTMASK) >> DASMFLAG_OVERINSTSHIFT; - offs_t trace_over_target = pc + (dasmresult & DASMFLAG_LENGTHMASK); + int extraskip = (dasmresult & util::disasm_interface::OVERINSTMASK) >> util::disasm_interface::OVERINSTSHIFT; + offs_t trace_over_target = buffer.next_pc_wrap(pc, dasmresult & util::disasm_interface::LENGTHMASK); // if we need to skip additional instructions, advance as requested while (extraskip-- > 0) - trace_over_target += m_debug.dasm_wrapped(dasm, trace_over_target) & DASMFLAG_LENGTHMASK; + trace_over_target = buffer.next_pc_wrap(trace_over_target, buffer.disassemble_info(trace_over_target) & util::disasm_interface::LENGTHMASK); m_trace_over_target = trace_over_target; } diff --git a/src/emu/debug/debugcpu.h b/src/emu/debug/debugcpu.h index 2ea78c3fe20..e00ac9576cc 100644 --- a/src/emu/debug/debugcpu.h +++ b/src/emu/debug/debugcpu.h @@ -278,7 +278,6 @@ private: // internal helpers void prepare_for_step_overout(offs_t pc); - u32 dasm_wrapped(std::string &buffer, offs_t pc); void errorlog_write_line(const char *line); // breakpoint and watchpoint helpers diff --git a/src/emu/debug/dvdisasm.cpp b/src/emu/debug/dvdisasm.cpp index 1051365c561..9ad6cb968c2 100644 --- a/src/emu/debug/dvdisasm.cpp +++ b/src/emu/debug/dvdisasm.cpp @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Aaron Giles +// copyright-holders:Aaron Giles, Olivier Galibert /********************************************************************* dvdisasm.c @@ -14,7 +14,6 @@ #include "debugcpu.h" #include "debugger.h" - //************************************************************************** // DEBUG VIEW DISASM SOURCE //************************************************************************** @@ -25,7 +24,6 @@ debug_view_disasm_source::debug_view_disasm_source(const char *name, device_t &device) : debug_view_source(name, &device), - m_disasmintf(dynamic_cast<device_disasm_interface *>(&device)), m_space(device.memory().space(AS_PROGRAM)), m_decrypted_space(device.memory().has_space(AS_OPCODES) ? device.memory().space(AS_OPCODES) : device.memory().space(AS_PROGRAM)) { @@ -49,23 +47,17 @@ debug_view_disasm::debug_view_disasm(running_machine &machine, debug_view_osd_up m_right_column(DASM_RIGHTCOL_RAW), m_backwards_steps(3), m_dasm_width(DEFAULT_DASM_WIDTH), - m_last_direct_raw(nullptr), - m_last_direct_decrypted(nullptr), - m_last_change_count(0), - m_last_pcbyte(0), - m_divider1(0), - m_divider2(0), - m_divider3(0), + m_previous_pc(1), m_expression(machine) { // fail if no available sources enumerate_sources(); - if (m_source_list.count() == 0) + if(m_source_list.count() == 0) throw std::bad_alloc(); // count the number of comments int total_comments = 0; - for (const debug_view_source &source : m_source_list) + for(const debug_view_source &source : m_source_list) { const debug_view_disasm_source &dasmsource = downcast<const debug_view_disasm_source &>(source); total_comments += dasmsource.device()->debug()->comment_count(); @@ -98,10 +90,10 @@ void debug_view_disasm::enumerate_sources() // iterate over devices with disassembly interfaces std::string name; - for (device_disasm_interface &dasm : disasm_interface_iterator(machine().root_device())) + for(device_disasm_interface &dasm : disasm_interface_iterator(machine().root_device())) { name = string_format("%s '%s'", dasm.device().name(), dasm.device().tag()); - if (dasm.device().memory().space_config(AS_PROGRAM)!=nullptr) + if(dasm.device().memory().space_config(AS_PROGRAM)!=nullptr) m_source_list.append(*global_alloc(debug_view_disasm_source(name.c_str(), dasm.device()))); } @@ -117,10 +109,10 @@ void debug_view_disasm::enumerate_sources() void debug_view_disasm::view_notify(debug_view_notification type) { - if (type == VIEW_NOTIFY_CURSOR_CHANGED) + if(type == VIEW_NOTIFY_CURSOR_CHANGED) adjust_visible_y_for_cursor(); - else if (type == VIEW_NOTIFY_SOURCE_CHANGED) + else if(type == VIEW_NOTIFY_SOURCE_CHANGED) m_expression.set_context(&downcast<const debug_view_disasm_source *>(m_source)->device()->debug()->symtable()); } @@ -136,29 +128,29 @@ void debug_view_disasm::view_char(int chval) u8 end_buffer = 3; s32 temp; - switch (chval) + switch(chval) { case DCH_UP: - if (m_cursor.y > 0) + if(m_cursor.y > 0) m_cursor.y--; break; case DCH_DOWN: - if (m_cursor.y < m_total.y - 1) + if(m_cursor.y < m_total.y - 1) m_cursor.y++; break; case DCH_PUP: - temp = m_cursor.y - (m_visible.y - end_buffer); - if (temp < 0) + temp = m_cursor.y -(m_visible.y - end_buffer); + if(temp < 0) m_cursor.y = 0; else m_cursor.y = temp; break; case DCH_PDOWN: - temp = m_cursor.y + (m_visible.y - end_buffer); - if (temp > m_total.y - 1) + temp = m_cursor.y +(m_visible.y - end_buffer); + if(temp > m_total.y - 1) m_cursor.y = m_total.y - 1; else m_cursor.y = temp; @@ -167,11 +159,11 @@ void debug_view_disasm::view_char(int chval) case DCH_HOME: // set the active column to the PC { const debug_view_disasm_source &source = downcast<const debug_view_disasm_source &>(*m_source); - offs_t pc = source.m_space.address_to_byte(source.device()->safe_pcbase()) & source.m_space.logbytemask(); + offs_t pc = source.device()->safe_pcbase() & source.m_space.logaddrmask(); // figure out which row the pc is on - for (unsigned int curline = 0; curline < m_dasm.size(); curline++) - if (m_dasm[curline].m_byteaddress == pc) + for(unsigned int curline = 0; curline < m_dasm.size(); curline++) + if(m_dasm[curline].m_address == pc) m_cursor.y = curline; break; } @@ -186,7 +178,7 @@ void debug_view_disasm::view_char(int chval) } /* send a cursor changed notification */ - if (m_cursor.y != origcursor.y) + if(m_cursor.y != origcursor.y) { begin_update(); view_notify(VIEW_NOTIFY_CURSOR_CHANGED); @@ -208,7 +200,7 @@ void debug_view_disasm::view_click(const int button, const debug_view_xy& pos) /* cursor popup|toggle */ bool cursorVisible = true; - if (m_cursor.y == origcursor.y) + if(m_cursor.y == origcursor.y) { cursorVisible = !m_cursor_visible; } @@ -221,218 +213,174 @@ void debug_view_disasm::view_click(const int button, const debug_view_xy& pos) end_update(); } +void debug_view_disasm::generate_from_address(debug_disasm_buffer &buffer, offs_t address) +{ + m_dasm.clear(); + for(int i=0; i != m_total.y; i++) { + std::string dasm; + offs_t size; + offs_t next_address; + u32 info; + buffer.disassemble(address, dasm, next_address, size, info); + m_dasm.emplace_back(address, size, dasm); + address = next_address; + } +} -//------------------------------------------------- -// find_pc_backwards - back up the specified -// number of instructions from the given PC -//------------------------------------------------- - -offs_t debug_view_disasm::find_pc_backwards(offs_t targetpc, int numinstrs) +bool debug_view_disasm::generate_with_pc(debug_disasm_buffer &buffer, offs_t pc) { - auto dis = machine().disable_side_effect(); + // Consider that instructions are 64 bytes max const debug_view_disasm_source &source = downcast<const debug_view_disasm_source &>(*m_source); + int shift = source.m_space.addrbus_shift(); - // compute the increment - int minlen = source.m_space.byte_to_address(source.m_disasmintf->min_opcode_bytes()); - if (minlen == 0) minlen = 1; - int maxlen = source.m_space.byte_to_address(source.m_disasmintf->max_opcode_bytes()); - if (maxlen == 0) maxlen = 1; - - // start off numinstrs back - offs_t curpc = targetpc - minlen * numinstrs; - if (curpc > targetpc) - curpc = 0; - - /* loop until we find what we are looking for */ - offs_t targetpcbyte = source.m_space.address_to_byte(targetpc) & source.m_space.logbytemask(); - offs_t fillpcbyte = targetpcbyte; - offs_t lastgoodpc = targetpc; - while (1) - { - // fill the buffer up to the target - offs_t curpcbyte = source.m_space.address_to_byte(curpc) & source.m_space.logbytemask(); - u8 opbuf[1024], argbuf[1024]; - while (curpcbyte < fillpcbyte) - { - fillpcbyte--; - opbuf[1000 + fillpcbyte - targetpcbyte] = machine().debugger().cpu().read_opcode(source.m_decrypted_space, fillpcbyte, 1); - argbuf[1000 + fillpcbyte - targetpcbyte] = machine().debugger().cpu().read_opcode(source.m_space, fillpcbyte, 1); + offs_t backwards_offset; + if(shift < 0) + backwards_offset = 64 >> -shift; + else if(shift == 0) + backwards_offset = 64; + else + backwards_offset = 64 << shift; + + m_dasm.clear(); + offs_t address = (pc - m_backwards_steps*backwards_offset) & source.m_space.logaddrmask(); + // Handle wrap at 0 + if(address > pc) + address = 0; + + util::disasm_interface *intf = dynamic_cast<device_disasm_interface &>(*source.device()).get_disassembler(); + if(intf->interface_flags() & util::disasm_interface::NONLINEAR_PC) { + offs_t lpc = intf->pc_real_to_linear(pc); + while(intf->pc_real_to_linear(address) < lpc) { + std::string dasm; + offs_t size; + offs_t next_address; + u32 info; + buffer.disassemble(address, dasm, next_address, size, info); + m_dasm.emplace_back(address, size, dasm); + if(intf->pc_real_to_linear(address) > intf->pc_real_to_linear(next_address)) + return false; + address = next_address; } - // loop until we get past the target instruction - int instcount = 0; - int instlen; - offs_t scanpc; - for (scanpc = curpc; scanpc < targetpc; scanpc += instlen) - { - offs_t scanpcbyte = source.m_space.address_to_byte(scanpc) & source.m_space.logbytemask(); - offs_t physpcbyte = scanpcbyte; - - // get the disassembly, but only if mapped - instlen = 1; - if (source.m_space.device().memory().translate(source.m_space.spacenum(), TRANSLATE_FETCH, physpcbyte)) - { - std::ostringstream dasmbuffer; - instlen = source.m_disasmintf->disassemble(dasmbuffer, scanpc, &opbuf[1000 + scanpcbyte - targetpcbyte], &argbuf[1000 + scanpcbyte - targetpcbyte]) & DASMFLAG_LENGTHMASK; - } - - // count this one - instcount++; + } else { + while(address < pc) { + std::string dasm; + offs_t size; + offs_t next_address; + u32 info; + buffer.disassemble(address, dasm, next_address, size, info); + m_dasm.emplace_back(address, size, dasm); + if(address > next_address) + return false; + address = next_address; } + } - // if we ended up right on targetpc, this is a good candidate - if (scanpc == targetpc && instcount <= numinstrs) - lastgoodpc = curpc; - - // we're also done if we go back too far - if (targetpc - curpc >= numinstrs * maxlen) - break; + if(address != pc) + return false; - // and if we hit 0, we're done - if (curpc == 0) - break; + if(m_dasm.size() > m_backwards_steps) + m_dasm.erase(m_dasm.begin(), m_dasm.begin() + (m_dasm.size() - m_backwards_steps)); - // back up one more and try again - curpc -= minlen; - if (curpc > targetpc) - curpc = 0; + while(m_dasm.size() < m_total.y) { + std::string dasm; + offs_t size; + offs_t next_address; + u32 info; + buffer.disassemble(address, dasm, next_address, size, info); + m_dasm.emplace_back(address, size, dasm); + address = next_address; } - - return lastgoodpc; + return true; } - -//------------------------------------------------- -// generate_bytes - generate the opcode byte -// values -//------------------------------------------------- - -std::string debug_view_disasm::generate_bytes(offs_t pcbyte, int numbytes, int granularity, bool encrypted) +int debug_view_disasm::address_position(offs_t pc) const { - const debug_view_disasm_source &source = downcast<const debug_view_disasm_source &>(*m_source); - const int char_num = source.m_space.is_octal() ? 3 : 2; - std::ostringstream ostr; - - for (int byte = 0; byte < numbytes; byte += granularity) { - if (byte) - ostr << ' '; - util::stream_format(ostr, source.m_space.is_octal() ? "%0*o" : "%0*X", granularity * char_num, machine().debugger().cpu().read_opcode(encrypted ? source.m_space : source.m_decrypted_space, pcbyte + byte, granularity)); - } - - return ostr.str(); + for(int i=0; i != int(m_dasm.size()); i++) + if(m_dasm[i].m_address == pc) + return i; + return -1; } - -//------------------------------------------------- -// recompute - recompute selected info for the -// disassembly view -//------------------------------------------------- - -bool debug_view_disasm::recompute(offs_t pc, int startline, int lines) +void debug_view_disasm::generate_dasm(debug_disasm_buffer &buffer, offs_t pc) { - auto dis = machine().disable_side_effect(); - - bool changed = false; - const debug_view_disasm_source &source = downcast<const debug_view_disasm_source &>(*m_source); - const int char_num = source.m_space.is_octal() ? 3 : 2; - - // determine how many characters we need for an address and set the divider - m_divider1 = 1 + (source.m_space.logaddrchars()/2*char_num) + 1; + bool pc_changed = pc != m_previous_pc; + m_previous_pc = pc; + if(strcmp(m_expression.string(), "curpc")) { + if(m_expression.dirty()) { + m_topleft.x = 0; + m_topleft.y = 0; + } + generate_from_address(buffer, m_expression.value()); + return; + } - // assume a fixed number of characters for the disassembly - m_divider2 = m_divider1 + 1 + m_dasm_width + 1; + if(address_position(pc) != -1) { + generate_from_address(buffer, m_dasm[0].m_address); + int pos = address_position(pc); + if(pos != -1) { + if(!pc_changed) + return; + if(pos >= m_topleft.y && pos < m_topleft.y + m_visible.y) + return; + if(pos < m_total.y - m_visible.y) { + m_topleft.x = 0; + m_topleft.y = pos - m_backwards_steps; + return; + } + } + } - // determine how many bytes we might need to display - const int minbytes = source.m_disasmintf->min_opcode_bytes(); - const int maxbytes = source.m_disasmintf->max_opcode_bytes(); + m_topleft.x = 0; + m_topleft.y = 0; - // ensure that the PC is aligned to the minimum opcode size - pc &= ~source.m_space.byte_to_address_end(minbytes - 1); + if(generate_with_pc(buffer, pc)) + return; - // set the width of the third column according to display mode - if (m_right_column == DASM_RIGHTCOL_RAW || m_right_column == DASM_RIGHTCOL_ENCRYPTED) - { - int const maxbytes_clamped = (std::min)(maxbytes, DASM_MAX_BYTES); - m_total.x = m_divider2 + 1 + char_num * maxbytes_clamped + (maxbytes_clamped / minbytes - 1) + 1; - } - else if (m_right_column == DASM_RIGHTCOL_COMMENTS) - m_total.x = m_divider2 + 1 + 50; // DEBUG_COMMENT_MAX_LINE_LENGTH - else - m_total.x = m_divider2 + 1; + generate_from_address(buffer, pc); +} - // allocate dasm array - m_dasm.resize(m_total.y); +void debug_view_disasm::complete_information(const debug_view_disasm_source &source, debug_disasm_buffer &buffer, offs_t pc) +{ + for(auto &dasm : m_dasm) { + offs_t adr = dasm.m_address; - // comparison buffer to detect whether data changed when doing only one line - dasm_line comparison_buffer; + dasm.m_tadr = buffer.pc_to_string(adr); + dasm.m_topcodes = buffer.data_to_string(adr, dasm.m_size, true); + dasm.m_tparams = buffer.data_to_string(adr, dasm.m_size, false); - // iterate over lines - for (int line = 0; line < lines; line++) - { - // convert PC to a byte offset - const offs_t pcbyte = source.m_space.address_to_byte(pc) & source.m_space.logbytemask(); - - // save a copy of the previous line as a backup if we're only doing one line - const auto instr = startline + line; - if (lines == 1) - comparison_buffer = m_dasm[instr]; - - // convert back and set the address of this instruction - std::ostringstream oadr; - m_dasm[instr].m_byteaddress = pcbyte; - util::stream_format(oadr, - source.m_space.is_octal() ? " %0*o " : " %0*X ", - source.m_space.logaddrchars()/2*char_num, source.m_space.byte_to_address(pcbyte)); - m_dasm[instr].m_adr = oadr.str(); - - // make sure we can translate the address, and then disassemble the result - std::ostringstream dasm; - int numbytes = 0; - offs_t physpcbyte = pcbyte; - if (source.m_space.device().memory().translate(source.m_space.spacenum(), TRANSLATE_FETCH_DEBUG, physpcbyte)) - { - u8 opbuf[64], argbuf[64]; + dasm.m_is_pc = adr == pc; - // fetch the bytes up to the maximum - for (numbytes = 0; numbytes < maxbytes; numbytes++) - { - opbuf[numbytes] = machine().debugger().cpu().read_opcode(source.m_decrypted_space, pcbyte + numbytes, 1); - argbuf[numbytes] = machine().debugger().cpu().read_opcode(source.m_space, pcbyte + numbytes, 1); + dasm.m_is_bp = false; + for(device_debug::breakpoint *bp = source.device()->debug()->breakpoint_first(); bp != nullptr; bp = bp->next()) + if(adr ==(bp->address() & source.m_space.logaddrmask())) { + dasm.m_is_bp = true; + break; } - // disassemble the result - pc += numbytes = source.m_disasmintf->disassemble(dasm, pc & source.m_space.logaddrmask(), opbuf, argbuf) & DASMFLAG_LENGTHMASK; - } - else - dasm << "<unmapped>"; - - m_dasm[instr].m_dasm = dasm.str(); + dasm.m_is_visited = source.device()->debug()->track_pc_visited(adr); - // generate the byte views - std::ostringstream bytes_raw; - numbytes = source.m_space.address_to_byte(numbytes) & source.m_space.logbytemask(); - m_dasm[instr].m_rawdata = generate_bytes(pcbyte, numbytes, minbytes, false); - m_dasm[instr].m_encdata = generate_bytes(pcbyte, numbytes, minbytes, true); + const char *comment = source.device()->debug()->comment_text(adr); + if(comment) + dasm.m_comment = comment; + } +} - // get and add the comment, if present - const offs_t comment_address = source.m_space.byte_to_address(m_dasm[instr].m_byteaddress); - const char *const text = source.device()->debug()->comment_text(comment_address); - if (text != nullptr) - m_dasm[instr].m_comment = text; +//------------------------------------------------- +// view_update - update the contents of the +// disassembly view +//------------------------------------------------- - // see if the line changed at all - if (lines == 1 && m_dasm[instr] != comparison_buffer) - changed = true; - } +void debug_view_disasm::view_update() +{ + const debug_view_disasm_source &source = downcast<const debug_view_disasm_source &>(*m_source); + debug_disasm_buffer buffer(*source.device()); + offs_t pc = source.device()->safe_pcbase() & source.m_space.logaddrmask(); - // update opcode base information - m_last_direct_decrypted = source.m_decrypted_space.direct().ptr(); - m_last_direct_raw = source.m_space.direct().ptr(); - m_last_change_count = source.device()->debug()->comment_change_count(); + generate_dasm(buffer, pc); - // no longer need to recompute - m_recompute = false; - return changed; + complete_information(source, buffer, pc); + redraw(); } @@ -443,11 +391,11 @@ bool debug_view_disasm::recompute(offs_t pc, int startline, int lines) void debug_view_disasm::print(int row, std::string text, int start, int end, u8 attrib) { int view_end = end - m_topleft.x; - if (view_end < 0) + if(view_end < 0) return; int string_0 = start - m_topleft.x; - if (string_0 >= m_visible.x) + if(string_0 >= m_visible.x) return; int view_start = string_0 > 0 ? string_0 : 0; @@ -458,152 +406,63 @@ void debug_view_disasm::print(int row, std::string text, int start, int end, u8 for(int pos = view_start; pos < view_end; pos++) { int spos = pos - string_0; - if (spos >= int(text.size())) + if(spos >= int(text.size())) *dest++ = { ' ', attrib }; else *dest++ = { u8(text[spos]), attrib }; - } + } } + //------------------------------------------------- -// view_update - update the contents of the -// disassembly view +// redraw - update the view from the data //------------------------------------------------- -void debug_view_disasm::view_update() +void debug_view_disasm::redraw() { - const debug_view_disasm_source &source = downcast<const debug_view_disasm_source &>(*m_source); - - offs_t pc = source.device()->safe_pcbase(); - offs_t pcbyte = source.m_space.address_to_byte(pc) & source.m_space.logbytemask(); - - // update our context; if the expression is dirty, recompute - if (m_expression.dirty()) - m_recompute = true; - - // if we're tracking a value, make sure it is visible - u64 previous = m_expression.last_value(); - u64 result = m_expression.value(); - if (result != previous) - { - offs_t resultbyte = source.m_space.address_to_byte(result) & source.m_space.logbytemask(); - - // see if the new result is an address we already have - u32 row; - for (row = 0; row < m_dasm.size(); row++) - if (m_dasm[row].m_byteaddress == resultbyte) - break; - - // if we didn't find it, or if it's really close to the bottom, recompute - if (row == m_dasm.size() || row >= m_total.y - m_visible.y) - m_recompute = true; - - // otherwise, if it's not visible, adjust the view so it is - else if (row < m_topleft.y || row >= m_topleft.y + m_visible.y - 2) - m_topleft.y = (row > 3) ? row - 3 : 0; - } - - // if the opcode base has changed, rework things - if (source.m_decrypted_space.direct().ptr() != m_last_direct_decrypted || source.m_space.direct().ptr() != m_last_direct_raw) - m_recompute = true; - - // if the comments have changed, redo it - if (m_last_change_count != source.device()->debug()->comment_change_count()) - m_recompute = true; - - // if we need to recompute, do it - bool recomputed_this_time = false; -recompute: - if (m_recompute) - { - // recompute the view - if (!m_dasm.empty() && m_last_change_count != source.device()->debug()->comment_change_count()) - { - // smoosh us against the left column, but not the top row - m_topleft.x = 0; - - // recompute from where we last recomputed! - recompute(source.m_space.byte_to_address(m_dasm[0].m_byteaddress), 0, m_total.y); - } - else - { - // determine the addresses of what we will display - offs_t backpc = find_pc_backwards(u32(m_expression.value()), m_backwards_steps); - - // put ourselves back in the top left - m_topleft.y = 0; - m_topleft.x = 0; - - recompute(backpc, 0, m_total.y); - } - recomputed_this_time = true; - } + // determine how many characters we need for an address and set the divider + int m_divider1 = 1 + m_dasm[0].m_tadr.size() + 1; - // figure out the row where the PC is and recompute the disassembly - if (pcbyte != m_last_pcbyte) - { - // find the row with the PC on it - for (u32 row = 0; row < m_visible.y; row++) - { - u32 effrow = m_topleft.y + row; - if (effrow >= m_dasm.size()) - break; - if (pcbyte == m_dasm[effrow].m_byteaddress) - { - // see if we changed - bool changed = recompute(pc, effrow, 1); - if (changed && !recomputed_this_time) - { - m_recompute = true; - goto recompute; - } + // assume a fixed number of characters for the disassembly + int m_divider2 = m_divider1 + 1 + m_dasm_width + 1; - // set the effective row and PC - m_cursor.y = effrow; - view_notify(VIEW_NOTIFY_CURSOR_CHANGED); - } - } - m_last_pcbyte = pcbyte; - } + // set the width of the third column to max comment length + m_total.x = m_divider2 + 1 + 50; // DEBUG_COMMENT_MAX_LINE_LENGTH // loop over visible rows - for (u32 row = 0; row < m_visible.y; row++) + for(u32 row = 0; row < m_visible.y; row++) { u32 effrow = m_topleft.y + row; // if this visible row is valid, add it to the buffer u8 attrib = DCA_NORMAL; - if (effrow < m_dasm.size()) + if(effrow < m_dasm.size()) { - // if we're on the line with the PC, recompute and hilight it - if (pcbyte == m_dasm[effrow].m_byteaddress) + // if we're on the line with the PC, hilight it + if(m_dasm[effrow].m_is_pc) attrib = DCA_CURRENT; // if we're on a line with a breakpoint, tag it changed - else - { - for (device_debug::breakpoint *bp = source.device()->debug()->breakpoint_first(); bp != nullptr; bp = bp->next()) - if (m_dasm[effrow].m_byteaddress == (source.m_space.address_to_byte(bp->address()) & source.m_space.logbytemask())) - attrib = DCA_CHANGED; - } + else if(m_dasm[effrow].m_is_bp) + attrib = DCA_CHANGED; // if we're on the active column and everything is couth, highlight it - if (m_cursor_visible && effrow == m_cursor.y) + if(m_cursor_visible && effrow == m_cursor.y) attrib |= DCA_SELECTED; // if we've visited this pc, mark it as such - if (source.device()->debug()->track_pc_visited(m_dasm[effrow].m_byteaddress)) + if(m_dasm[effrow].m_is_visited) attrib |= DCA_VISITED; - print(row, m_dasm[effrow].m_adr, 0, m_divider1, attrib | DCA_ANCILLARY); + print(row, ' ' + m_dasm[effrow].m_tadr, 0, m_divider1, attrib | DCA_ANCILLARY); print(row, ' ' + m_dasm[effrow].m_dasm, m_divider1, m_divider2, attrib); - if (m_right_column == DASM_RIGHTCOL_RAW || m_right_column == DASM_RIGHTCOL_ENCRYPTED) { - std::string text = ' ' + (m_right_column == DASM_RIGHTCOL_RAW ? m_dasm[effrow].m_rawdata : m_dasm[effrow].m_encdata); + if(m_right_column == DASM_RIGHTCOL_RAW || m_right_column == DASM_RIGHTCOL_ENCRYPTED) { + std::string text = ' ' +(m_right_column == DASM_RIGHTCOL_RAW ? m_dasm[effrow].m_topcodes : m_dasm[effrow].m_tparams); print(row, text, m_divider2, m_visible.x, attrib | DCA_ANCILLARY); if(int(text.size()) > m_visible.x - m_divider2) { int base = m_total.x - 3; - if (base < m_divider2) + if(base < m_divider2) base = m_divider2; print(row, "...", base, m_visible.x, attrib | DCA_ANCILLARY); } @@ -624,7 +483,7 @@ recompute: offs_t debug_view_disasm::selected_address() { flush_updates(); - return downcast<const debug_view_disasm_source &>(*m_source).m_space.byte_to_address(m_dasm[m_cursor.y].m_byteaddress); + return m_dasm[m_cursor.y].m_address; } @@ -679,7 +538,7 @@ void debug_view_disasm::set_disasm_width(u32 width) { begin_update(); m_dasm_width = width; - m_recompute = m_update_pending = true; + m_update_pending = true; end_update(); } @@ -692,10 +551,9 @@ void debug_view_disasm::set_disasm_width(u32 width) void debug_view_disasm::set_selected_address(offs_t address) { const debug_view_disasm_source &source = downcast<const debug_view_disasm_source &>(*m_source); - offs_t byteaddress = source.m_space.address_to_byte(address) & source.m_space.logbytemask(); - for (int line = 0; line < m_total.y; line++) - if (m_dasm[line].m_byteaddress == byteaddress) - { + address = address & source.m_space.logaddrmask(); + for(int line = 0; line < m_total.y; line++) + if(m_dasm[line].m_address == address) { m_cursor.y = line; set_cursor_position(m_cursor); break; diff --git a/src/emu/debug/dvdisasm.h b/src/emu/debug/dvdisasm.h index 85ebd7cfef2..dcf756117b8 100644 --- a/src/emu/debug/dvdisasm.h +++ b/src/emu/debug/dvdisasm.h @@ -14,6 +14,7 @@ #pragma once #include "debugvw.h" +#include "debugbuf.h" #include "vecstream.h" @@ -51,7 +52,6 @@ public: private: // internal state - device_disasm_interface *m_disasmintf; // disassembly interface address_space & m_space; // address space to display address_space & m_decrypted_space; // address space to display for decrypted opcodes }; @@ -90,49 +90,42 @@ protected: private: // The information of one disassembly line. May become the actual - // external interface at one point + // external interface at one point. struct dasm_line { - offs_t m_byteaddress; // address of the first byte of the instruction - std::string m_adr; // instruction address as a string + offs_t m_address; // address of the instruction + offs_t m_size; // size of the instruction + + std::string m_tadr; // instruction address as a string std::string m_dasm; // disassembly - std::string m_rawdata; // textual representation of the instruction values - std::string m_encdata; // textual representation of encrypted instruction values + std::string m_topcodes; // textual representation of opcode/default values + std::string m_tparams; // textual representation of parameter values std::string m_comment; // comment, when present - bool operator == (const dasm_line &right) const { - return - m_byteaddress == right.m_byteaddress && - m_adr == right.m_adr && - m_dasm == right.m_dasm && - m_rawdata == right.m_rawdata && - m_encdata == right.m_encdata && - m_comment == right.m_comment; - } - - bool operator != (const dasm_line &right) const { - return !(*this == right); - } + bool m_is_pc; // this line's address is PC + bool m_is_bp; // this line's address is a breakpoint + bool m_is_visited; // this line has been visited + + dasm_line(offs_t address, offs_t size, std::string dasm) : m_address(address), m_size(size), m_dasm(dasm), m_is_pc(false), m_is_bp(false), m_is_visited(false) {} }; // internal helpers + void generate_from_address(debug_disasm_buffer &buffer, offs_t address); + bool generate_with_pc(debug_disasm_buffer &buffer, offs_t pc); + int address_position(offs_t pc) const; + void generate_dasm(debug_disasm_buffer &buffer, offs_t pc); + void complete_information(const debug_view_disasm_source &source, debug_disasm_buffer &buffer, offs_t pc); + void enumerate_sources(); - offs_t find_pc_backwards(offs_t targetpc, int numinstrs); - std::string generate_bytes(offs_t pcbyte, int numbytes, int granularity, bool encrypted); - bool recompute(offs_t pc, int startline, int lines); void print(int row, std::string text, int start, int end, u8 attrib); + void redraw(); // internal state - disasm_right_column m_right_column; // right column contents - u32 m_backwards_steps; // number of backwards steps - u32 m_dasm_width; // width of the disassembly area - u8 * m_last_direct_raw; // last direct raw value - u8 * m_last_direct_decrypted;// last direct decrypted value - u32 m_last_change_count; // last comment change count - offs_t m_last_pcbyte; // last PC byte value - int m_divider1, m_divider2; // left and right divider columns - int m_divider3; // comment divider column - debug_view_expression m_expression; // expression-related information - std::vector<dasm_line> m_dasm; // disassembled instructions + disasm_right_column m_right_column; // right column contents + u32 m_backwards_steps; // number of backwards steps + u32 m_dasm_width; // width of the disassembly area + offs_t m_previous_pc; // previous pc, to detect whether it changed + debug_view_expression m_expression; // expression-related information + std::vector<dasm_line> m_dasm; // disassembled instructions // constants static constexpr int DEFAULT_DASM_LINES = 1000; diff --git a/src/emu/debug/dvmemory.cpp b/src/emu/debug/dvmemory.cpp index a5de89adb30..e32d576fa65 100644 --- a/src/emu/debug/dvmemory.cpp +++ b/src/emu/debug/dvmemory.cpp @@ -531,7 +531,7 @@ void debug_view_memory::recompute() int addrchars; if (source.m_space != nullptr) { - m_maxaddr = m_no_translation ? source.m_space->bytemask() : source.m_space->logbytemask(); + m_maxaddr = m_no_translation ? source.m_space->addrmask() : source.m_space->logaddrmask(); addrchars = m_no_translation ? source.m_space->addrchars() : source.m_space->logaddrchars(); } else @@ -547,6 +547,8 @@ void debug_view_memory::recompute() m_addrformat = string_format("%%0%dX%*s", addrchars, 8 - addrchars, ""); // if we are viewing a space with a minimum chunk size, clamp the bytes per chunk + // BAD +#if 0 if (source.m_space != nullptr && source.m_space->byte_to_address(1) > 1) { u32 min_bytes_per_chunk = source.m_space->byte_to_address(1); @@ -557,6 +559,7 @@ void debug_view_memory::recompute() } m_chunks_per_row = std::max(1U, m_chunks_per_row); } +#endif // recompute the byte offset based on the most recent expression result m_bytes_per_row = m_bytes_per_chunk * m_chunks_per_row; @@ -617,7 +620,7 @@ bool debug_view_memory::needs_recompute() const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source); offs_t resultbyte; if (source.m_space != nullptr) - resultbyte = source.m_space->address_to_byte(m_expression.value()) & source.m_space->logbytemask(); + resultbyte = m_expression.value() & source.m_space->logaddrmask(); else resultbyte = m_expression.value(); diff --git a/src/emu/devcpu.h b/src/emu/devcpu.h index 1c4bce13506..35c8c3b2a9e 100644 --- a/src/emu/devcpu.h +++ b/src/emu/devcpu.h @@ -50,15 +50,6 @@ //************************************************************************** -// MACROS -//************************************************************************** - -#define CPU_DISASSEMBLE_NAME(name) cpu_disassemble_##name -#define CPU_DISASSEMBLE(name) offs_t CPU_DISASSEMBLE_NAME(name)(cpu_device *device, std::ostream &stream, offs_t pc, const u8 *oprom, const u8 *opram, int options) -#define CPU_DISASSEMBLE_CALL(name) CPU_DISASSEMBLE_NAME(name)(device, stream, pc, oprom, opram, options) - - -//************************************************************************** // TYPE DEFINITIONS //************************************************************************** @@ -86,7 +77,4 @@ private: }; -typedef offs_t (*cpu_disassemble_func)(cpu_device *device, std::ostream &stream, offs_t pc, const u8 *oprom, const u8 *opram, int options); - - #endif /* MAME_EMU_DEVCPU_H */ diff --git a/src/emu/device.cpp b/src/emu/device.cpp index 5325e506568..e03e09e8dac 100644 --- a/src/emu/device.cpp +++ b/src/emu/device.cpp @@ -450,10 +450,11 @@ bool device_t::findit(bool isvalidation) const } //------------------------------------------------- -// start - start a device +// resolve_objects - find objects referenced in +// configuration //------------------------------------------------- -void device_t::start() +void device_t::resolve_objects() { // prepare the logerror buffer if (m_machine->allow_logging()) @@ -463,6 +464,20 @@ void device_t::start() if (!findit(false)) throw emu_fatalerror("Missing some required objects, unable to proceed"); + // allow implementation to do additional setup + device_resolve_objects(); +} + +//------------------------------------------------- +// start - start a device +//------------------------------------------------- + +void device_t::start() +{ + // prepare the logerror buffer + if (m_machine->allow_logging()) + m_string_buffer.reserve(1024); + // let the interfaces do their pre-work for (device_interface &intf : interfaces()) intf.interface_pre_start(); @@ -681,6 +696,18 @@ void device_t::device_reset_after_children() //------------------------------------------------- +// device_resolve_objects - resolve objects that +// may be needed for other devices to set +// initial conditions at start time +//------------------------------------------------- + +void device_t::device_resolve_objects() +{ + // do nothing by default +} + + +//------------------------------------------------- // device_stop - clean up anything that needs to // happen before the running_machine goes away //------------------------------------------------- diff --git a/src/emu/device.h b/src/emu/device.h index 0a894d20e09..211da59cb38 100644 --- a/src/emu/device.h +++ b/src/emu/device.h @@ -541,6 +541,7 @@ public: protected: // miscellaneous helpers void set_machine(running_machine &machine); + void resolve_objects(); void start(); void stop(); void debug_setup(); @@ -557,6 +558,7 @@ protected: virtual ioport_constructor device_input_ports() const; virtual void device_config_complete(); virtual void device_validity_check(validity_checker &valid) const ATTR_COLD; + virtual void device_resolve_objects() ATTR_COLD; virtual void device_start() ATTR_COLD = 0; virtual void device_stop() ATTR_COLD; virtual void device_reset() ATTR_COLD; diff --git a/src/emu/didisasm.cpp b/src/emu/didisasm.cpp index 95353889a65..51a96915a04 100644 --- a/src/emu/didisasm.cpp +++ b/src/emu/didisasm.cpp @@ -11,82 +11,93 @@ #include "emu.h" -//************************************************************************** -// DEVICE DISASM INTERFACE -//************************************************************************** - -//------------------------------------------------- -// device_disasm_interface - constructor -//------------------------------------------------- - device_disasm_interface::device_disasm_interface(const machine_config &mconfig, device_t &device) : device_interface(device, "disasm") { } +util::disasm_interface *device_disasm_interface::get_disassembler() +{ + if(!m_disasm) { + if(m_dasm_override.isnull()) + m_disasm.reset(create_disassembler()); + else + m_disasm = std::make_unique<device_disasm_indirect>(create_disassembler(), m_dasm_override); + } + return m_disasm.get(); +} -//------------------------------------------------- -// ~device_disasm_interface - destructor -//------------------------------------------------- +void device_disasm_interface::interface_pre_start() +{ + m_dasm_override.bind_relative_to(*device().owner()); +} -device_disasm_interface::~device_disasm_interface() +void device_disasm_interface::set_dasm_override(dasm_override_delegate dasm_override) { + m_dasm_override = dasm_override; } +device_disasm_indirect::device_disasm_indirect(util::disasm_interface *upper, dasm_override_delegate &dasm_override) : m_dasm_override(dasm_override) +{ + m_disasm.reset(upper); +} -//------------------------------------------------- -// interface_pre_start - work to be done prior to -// actually starting a device -//------------------------------------------------- +u32 device_disasm_indirect::interface_flags() const +{ + return m_disasm->interface_flags(); +} -void device_disasm_interface::interface_pre_start() +u32 device_disasm_indirect::page_address_bits() const { - // bind delegate - m_dasm_override.bind_relative_to(*device().owner()); + return m_disasm->page_address_bits(); } +u32 device_disasm_indirect::page2_address_bits() const +{ + return m_disasm->page2_address_bits(); +} -//------------------------------------------------- -// static_set_dasm_override - configuration -// helper to override disassemble function -//------------------------------------------------- +offs_t device_disasm_indirect::pc_linear_to_real(offs_t pc) const +{ + return m_disasm->pc_linear_to_real(pc); +} -void device_disasm_interface::static_set_dasm_override(device_t &device, dasm_override_delegate dasm_override) +offs_t device_disasm_indirect::pc_real_to_linear(offs_t pc) const { - device_disasm_interface *dasm; - if (!device.interface(dasm)) - throw emu_fatalerror("MCFG_DEVICE_DISASSEMBLE_OVERRIDE called on device '%s' with no disasm interface", device.tag()); - dasm->m_dasm_override = dasm_override; + return m_disasm->pc_real_to_linear(pc); } +u8 device_disasm_indirect::decrypt8 (u8 value, offs_t pc, bool opcode) const +{ + return m_disasm->decrypt8(value, pc, opcode); +} -//------------------------------------------------- -// disassemble - interface for disassembly -//------------------------------------------------- +u16 device_disasm_indirect::decrypt16(u16 value, offs_t pc, bool opcode) const +{ + return m_disasm->decrypt16(value, pc, opcode); +} -offs_t device_disasm_interface::disassemble(std::ostream &stream, offs_t pc, const u8 *oprom, const u8 *opram, u32 options) +u32 device_disasm_indirect::decrypt32(u32 value, offs_t pc, bool opcode) const { - offs_t result = 0; + return m_disasm->decrypt32(value, pc, opcode); +} - // check for disassembler override - if (!m_dasm_override.isnull()) - result = m_dasm_override(device(), stream, pc, oprom, opram, options); - if (result == 0) - result = disasm_disassemble(stream, pc, oprom, opram, options); +u64 device_disasm_indirect::decrypt64(u64 value, offs_t pc, bool opcode) const +{ + return m_disasm->decrypt64(value, pc, opcode); +} - // make sure we get good results - assert((result & DASMFLAG_LENGTHMASK) != 0); -#ifdef MAME_DEBUG - device_memory_interface *memory; - if (device().interface(memory)) - { - address_space &space = memory->space(AS_PROGRAM); - int bytes = space.address_to_byte(result & DASMFLAG_LENGTHMASK); - assert(bytes >= min_opcode_bytes()); - assert(bytes <= max_opcode_bytes()); - (void) bytes; // appease compiler - } -#endif +u32 device_disasm_indirect::opcode_alignment() const +{ + return m_disasm->opcode_alignment(); +} +offs_t device_disasm_indirect::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) +{ + offs_t result = m_dasm_override(stream, pc, opcodes, params); + if(!result) + result = m_disasm->disassemble(stream, pc, opcodes, params); return result; } + + diff --git a/src/emu/didisasm.h b/src/emu/didisasm.h index edd56b3352f..9636b67a6db 100644 --- a/src/emu/didisasm.h +++ b/src/emu/didisasm.h @@ -17,79 +17,70 @@ #ifndef MAME_EMU_DIDISASM_H #define MAME_EMU_DIDISASM_H - -//************************************************************************** -// CONSTANTS -//************************************************************************** - -// Disassembler constants -constexpr u32 DASMFLAG_SUPPORTED = 0x80000000; // are disassembly flags supported? -constexpr u32 DASMFLAG_STEP_OUT = 0x40000000; // this instruction should be the end of a step out sequence -constexpr u32 DASMFLAG_STEP_OVER = 0x20000000; // this instruction should be stepped over by setting a breakpoint afterwards -constexpr u32 DASMFLAG_OVERINSTMASK = 0x18000000; // number of extra instructions to skip when stepping over -constexpr u32 DASMFLAG_OVERINSTSHIFT = 27; // bits to shift after masking to get the value -constexpr u32 DASMFLAG_LENGTHMASK = 0x0000ffff; // the low 16-bits contain the actual length - - - -//************************************************************************** -// MACROS -//************************************************************************** - -#define DASMFLAG_STEP_OVER_EXTRA(x) ((x) << DASMFLAG_OVERINSTSHIFT) - - - -//************************************************************************** -// INTERFACE CONFIGURATION MACROS -//************************************************************************** +#include "disasmintf.h" #define MCFG_DEVICE_DISASSEMBLE_OVERRIDE(_class, _func) \ - device_disasm_interface::static_set_dasm_override(*device, dasm_override_delegate(&_class::_func, #_class "::" #_func, nullptr, (_class *)nullptr)); - - + dynamic_cast<device_disasm_interface *>(device)->set_dasm_override(dasm_override_delegate(&_class::_func, #_class "::" #_func, nullptr, (_class *)nullptr)); //************************************************************************** // TYPE DEFINITIONS //************************************************************************** -typedef device_delegate<offs_t (device_t &device, std::ostream &stream, offs_t pc, const u8 *oprom, const u8 *opram, int options)> dasm_override_delegate; +typedef device_delegate<offs_t (std::ostream &stream, offs_t pc, const util::disasm_interface::data_buffer &opcodes, const util::disasm_interface::data_buffer ¶ms)> dasm_override_delegate; // ======================> device_disasm_interface - + // class representing interface-specific live disasm class device_disasm_interface : public device_interface { public: // construction/destruction device_disasm_interface(const machine_config &mconfig, device_t &device); - virtual ~device_disasm_interface(); + virtual ~device_disasm_interface() = default; - // configuration access - u32 min_opcode_bytes() const { return disasm_min_opcode_bytes(); } - u32 max_opcode_bytes() const { return disasm_max_opcode_bytes(); } + // Override + void set_dasm_override(dasm_override_delegate dasm_override); - // static inline configuration helpers - static void static_set_dasm_override(device_t &device, dasm_override_delegate dasm_override); - - // interface for disassembly - offs_t disassemble(std::ostream &stream, offs_t pc, const u8 *oprom, const u8 *opram, u32 options = 0); + // disassembler request + util::disasm_interface *get_disassembler(); protected: - // required operation overrides - virtual u32 disasm_min_opcode_bytes() const = 0; - virtual u32 disasm_max_opcode_bytes() const = 0; - virtual offs_t disasm_disassemble(std::ostream &stream, offs_t pc, const u8 *oprom, const u8 *opram, u32 options) = 0; + // disassembler creation + virtual util::disasm_interface *create_disassembler() = 0; - // interface-level overrides + // delegate resolving virtual void interface_pre_start() override; private: - dasm_override_delegate m_dasm_override; // provided override function + std::unique_ptr<util::disasm_interface> m_disasm; + dasm_override_delegate m_dasm_override; }; // iterator typedef device_interface_iterator<device_disasm_interface> disasm_interface_iterator; +class device_disasm_indirect : public util::disasm_interface +{ +public: + device_disasm_indirect(util::disasm_interface *upper, dasm_override_delegate &dasm_override); + virtual ~device_disasm_indirect() = default; + + virtual u32 interface_flags() const override; + virtual u32 page_address_bits() const override; + virtual u32 page2_address_bits() const override; + virtual offs_t pc_linear_to_real(offs_t pc) const override; + virtual offs_t pc_real_to_linear(offs_t pc) const override; + virtual u8 decrypt8 (u8 value, offs_t pc, bool opcode) const override; + virtual u16 decrypt16(u16 value, offs_t pc, bool opcode) const override; + virtual u32 decrypt32(u32 value, offs_t pc, bool opcode) const override; + virtual u64 decrypt64(u64 value, offs_t pc, bool opcode) const override; + + virtual u32 opcode_alignment() const override; + virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) override; + +private: + std::unique_ptr<util::disasm_interface> m_disasm; + dasm_override_delegate &m_dasm_override; +}; #endif /* MAME_EMU_DIDISASM_H */ diff --git a/src/emu/diexec.cpp b/src/emu/diexec.cpp index e43613b0302..0958108fe42 100644 --- a/src/emu/diexec.cpp +++ b/src/emu/diexec.cpp @@ -695,6 +695,48 @@ TIMER_CALLBACK_MEMBER(device_execute_interface::trigger_periodic_interrupt) } +//------------------------------------------------- +// irq_pulse_clear - clear a "pulsed" input line +//------------------------------------------------- + +TIMER_CALLBACK_MEMBER(device_execute_interface::irq_pulse_clear) +{ + int irqline = param; + set_input_line(irqline, CLEAR_LINE); +} + + +//------------------------------------------------- +// pulse_input_line - "pulse" an input line by +// asserting it and then clearing it later +//------------------------------------------------- + +void device_execute_interface::pulse_input_line(int irqline, const attotime &duration) +{ + assert(duration > attotime::zero); + set_input_line(irqline, ASSERT_LINE); + + attotime target_time = local_time() + duration; + m_scheduler->timer_set(target_time - m_scheduler->time(), timer_expired_delegate(FUNC(device_execute_interface::irq_pulse_clear), this), irqline); +} + + +//------------------------------------------------- +// pulse_input_line_and_vector - "pulse" an +// input line by asserting it and then clearing it +// later, specifying a vector +//------------------------------------------------- + +void device_execute_interface::pulse_input_line_and_vector(int irqline, int vector, const attotime &duration) +{ + assert(duration > attotime::zero); + set_input_line_and_vector(irqline, ASSERT_LINE, vector); + + attotime target_time = local_time() + duration; + m_scheduler->timer_set(target_time - m_scheduler->time(), timer_expired_delegate(FUNC(device_execute_interface::irq_pulse_clear), this), irqline); +} + + //************************************************************************** // DEVICE INPUT diff --git a/src/emu/diexec.h b/src/emu/diexec.h index 8e4c4ce9cc5..c307400dd69 100644 --- a/src/emu/diexec.h +++ b/src/emu/diexec.h @@ -162,6 +162,8 @@ public: void set_input_line_vector(int linenum, int vector) { m_input[linenum].set_vector(vector); } void set_input_line_and_vector(int linenum, int state, int vector) { m_input[linenum].set_state_synced(state, vector); } int input_state(int linenum) const { return m_input[linenum].m_curstate; } + void pulse_input_line(int irqline, const attotime &duration); + void pulse_input_line_and_vector(int irqline, int vector, const attotime &duration); // suspend/resume void suspend(u32 reason, bool eatcycles); @@ -292,9 +294,13 @@ private: void on_vblank(screen_device &screen, bool vblank_state); TIMER_CALLBACK_MEMBER(trigger_periodic_interrupt); + TIMER_CALLBACK_MEMBER(irq_pulse_clear); void suspend_resume_changed(); attoseconds_t minimum_quantum() const; + +public: + attotime minimum_quantum_time() const { return attotime(0, minimum_quantum()); } }; // iterator diff --git a/src/emu/dipalette.cpp b/src/emu/dipalette.cpp index d996ccafe4d..f7d4a6974d4 100644 --- a/src/emu/dipalette.cpp +++ b/src/emu/dipalette.cpp @@ -26,7 +26,7 @@ device_palette_interface::device_palette_interface(const machine_config &mconfig : device_interface(device, "palette"), m_palette(nullptr), m_pens(nullptr), - m_format(), + m_format(BITMAP_FORMAT_RGB32), m_shadow_table(nullptr), m_shadow_group(0), m_hilight_group(0), @@ -57,10 +57,6 @@ void device_palette_interface::interface_validity_check(validity_checker &valid) void device_palette_interface::interface_pre_start() { - // reset all our data - screen_device *screen = device().machine().first_screen(); - m_format = (screen != nullptr) ? screen->format() : BITMAP_FORMAT_INVALID; - // allocate the palette u32 numentries = palette_entries(); allocate_palette(numentries); diff --git a/src/emu/dipalette.h b/src/emu/dipalette.h index eb2979f6118..358d5071b58 100644 --- a/src/emu/dipalette.h +++ b/src/emu/dipalette.h @@ -37,6 +37,8 @@ typedef u16 indirect_pen_t; class device_palette_interface : public device_interface { + friend class screen_device; + static constexpr int MAX_SHADOW_PRESETS = 4; public: diff --git a/src/emu/dirom.cpp b/src/emu/dirom.cpp index 161b7770c75..3a0ed23692f 100644 --- a/src/emu/dirom.cpp +++ b/src/emu/dirom.cpp @@ -85,7 +85,7 @@ void device_rom_interface::set_rom(const void *base, u32 size) void device_rom_interface::interface_pre_start() { - m_rom_direct = &space().direct(); + m_rom_direct = space().direct<0>(); m_bank = nullptr; m_cur_bank = -1; device().save_item(NAME(m_cur_bank)); diff --git a/src/emu/dirom.h b/src/emu/dirom.h index 1e9efcca037..2ea7edca810 100644 --- a/src/emu/dirom.h +++ b/src/emu/dirom.h @@ -42,7 +42,7 @@ protected: private: const char *m_rom_tag; const address_space_config m_rom_config; - direct_read_data *m_rom_direct; + direct_read_data<0> *m_rom_direct; memory_bank *m_bank; int m_cur_bank, m_bank_count; diff --git a/src/emu/diserial.cpp b/src/emu/diserial.cpp index b0a8e40ab6a..db8f726d8c7 100644 --- a/src/emu/diserial.cpp +++ b/src/emu/diserial.cpp @@ -213,6 +213,7 @@ WRITE_LINE_MEMBER(device_serial_interface::rx_w) receive_register_update_bit(state); if(m_rcv_flags & RECEIVE_REGISTER_SYNCHRONISED) { + //device().logerror("Receiver is synchronized\n"); if(m_rcv_clock && !(m_rcv_rate.is_never())) // make start delay just a bit longer to make sure we are called after the sender m_rcv_clock->adjust(((m_rcv_rate*3)/2), 0, m_rcv_rate); @@ -266,6 +267,7 @@ void device_serial_interface::receive_register_update_bit(int bit) else if (m_rcv_flags & RECEIVE_REGISTER_SYNCHRONISED) { + //device().logerror("Received bit %d\n", m_rcv_bit_count_received); m_rcv_bit_count_received++; if (!bit && (m_rcv_bit_count_received > (m_rcv_bit_count - m_df_stop_bit_count))) @@ -279,7 +281,7 @@ void device_serial_interface::receive_register_update_bit(int bit) m_rcv_bit_count_received = 0; m_rcv_flags &=~RECEIVE_REGISTER_SYNCHRONISED; m_rcv_flags |= RECEIVE_REGISTER_WAITING_FOR_START_BIT; - //logerror("receive register full\n"); + //device().logerror("Receive register full\n"); m_rcv_flags |= RECEIVE_REGISTER_FULL; } } diff --git a/src/emu/distate.cpp b/src/emu/distate.cpp index 2a1ed9b9ea9..71462ce3275 100644 --- a/src/emu/distate.cpp +++ b/src/emu/distate.cpp @@ -49,30 +49,18 @@ const u64 device_state_entry::k_decimal_divisor[] = // device_state_entry - constructor //------------------------------------------------- -device_state_entry::device_state_entry(int index, const char *symbol, void *dataptr, u8 size, device_state_interface *dev) +device_state_entry::device_state_entry(int index, const char *symbol, u8 size, u64 sizemask, u8 flags, device_state_interface *dev) : m_device_state(dev), m_index(index), - m_dataptr(dataptr), - m_datamask(0), + m_datamask(sizemask), m_datasize(size), - m_flags(0), + m_flags(flags), m_symbol(symbol), m_default_format(true), - m_sizemask(0) + m_sizemask(sizemask) { - // convert the size to a mask - assert(size == 1 || size == 2 || size == 4 || size == 8); - if (size == 1) - m_sizemask = 0xff; - else if (size == 2) - m_sizemask = 0xffff; - else if (size == 4) - m_sizemask = 0xffffffff; - else - m_sizemask = ~u64(0); - - // default the data mask to the same - m_datamask = m_sizemask; + assert(size == 1 || size == 2 || size == 4 || size == 8 || (flags & DSF_FLOATING_POINT) != 0); + format_from_mask(); // override well-known symbols @@ -87,10 +75,9 @@ device_state_entry::device_state_entry(int index, const char *symbol, void *data device_state_entry::device_state_entry(int index, device_state_interface *dev) : m_device_state(dev), m_index(index), - m_dataptr(nullptr), m_datamask(0), m_datasize(0), - m_flags(DSF_DIVIDER), + m_flags(DSF_DIVIDER | DSF_READONLY), m_symbol(), m_default_format(true), m_sizemask(0) @@ -99,6 +86,15 @@ device_state_entry::device_state_entry(int index, device_state_interface *dev) //------------------------------------------------- +// device_state_entry - destructor +//------------------------------------------------- + +device_state_entry::~device_state_entry() +{ +} + + +//------------------------------------------------- // formatstr - specify a format string //------------------------------------------------- @@ -126,6 +122,12 @@ void device_state_entry::format_from_mask() if (!m_default_format) return; + if (is_float()) + { + m_format = "%12s"; + return; + } + // make up a format based on the mask int width = 0; for (u64 tempmask = m_datamask; tempmask != 0; tempmask >>= 4) @@ -135,22 +137,34 @@ void device_state_entry::format_from_mask() //------------------------------------------------- -// value - return the current value as a u64 +// entry_baseptr - return a pointer to where the +// data lives (if applicable) //------------------------------------------------- -u64 device_state_entry::value() const +void *device_state_entry::entry_baseptr() const { - // pick up the value - u64 result; - switch (m_datasize) - { - default: - case 1: result = *static_cast<u8 *>(m_dataptr); break; - case 2: result = *static_cast<u16 *>(m_dataptr); break; - case 4: result = *static_cast<u32 *>(m_dataptr); break; - case 8: result = *static_cast<u64 *>(m_dataptr); break; - } - return result & m_datamask; + return nullptr; +} + + +//------------------------------------------------- +// entry_value - return the current value as a u64 +//------------------------------------------------- + +u64 device_state_entry::entry_value() const +{ + return 0; +} + + +//------------------------------------------------- +// entry_dvalue - return the current value as a +// double +//------------------------------------------------- + +double device_state_entry::entry_dvalue() const +{ + return 0.0; } @@ -349,6 +363,8 @@ std::string device_state_entry::format(const char *string, bool maxout) const void device_state_entry::set_value(u64 value) const { + assert((m_flags & DSF_READONLY) == 0); + // apply the mask value &= m_datamask; @@ -357,14 +373,39 @@ void device_state_entry::set_value(u64 value) const value |= ~m_datamask; // store the value - switch (m_datasize) - { - default: - case 1: *static_cast<u8 *>(m_dataptr) = value; break; - case 2: *static_cast<u16 *>(m_dataptr) = value; break; - case 4: *static_cast<u32 *>(m_dataptr) = value; break; - case 8: *static_cast<u64 *>(m_dataptr) = value; break; - } + entry_set_value(value); +} + + +//------------------------------------------------- +// set_dvalue - set the value from a double +//------------------------------------------------- + +void device_state_entry::set_dvalue(double value) const +{ + assert((m_flags & DSF_READONLY) == 0); + + // store the value + entry_set_dvalue(value); +} + + +//------------------------------------------------- +// entry_set_value - set the value from a u64 +//------------------------------------------------- + +void device_state_entry::entry_set_value(u64 value) const +{ +} + + +//------------------------------------------------- +// entry_set_dvalue - set the value from a double +//------------------------------------------------- + +void device_state_entry::entry_set_dvalue(double value) const +{ + set_value(u64(value)); } @@ -443,6 +484,8 @@ std::string device_state_interface::state_string(int index) const std::string custom; if (entry->needs_custom_string()) state_string_export(*entry, custom); + else if (entry->is_float()) + custom = string_format("%-12G", entry->dvalue()); // ask the entry to format itself return entry->format(custom.c_str()); @@ -509,38 +552,22 @@ void device_state_interface::set_state_string(int index, const char *string) //------------------------------------------------- -// state_add - return the value of the given -// pieces of indexed state as a u64 +// state_add - add a new piece of indexed state //------------------------------------------------- -device_state_entry &device_state_interface::state_add(int index, const char *symbol, void *data, u8 size) +device_state_entry &device_state_interface::state_add(std::unique_ptr<device_state_entry> &&entry) { - // assert validity of incoming parameters - assert(size == 1 || size == 2 || size == 4 || size == 8); - assert(symbol != nullptr); - // append to the end of the list - m_state_list.push_back(std::make_unique<device_state_entry>(index, symbol, data, size, this)); + m_state_list.push_back(std::move(entry)); + device_state_entry &new_entry = *m_state_list.back(); // set the fast entry if applicable - if (index >= FAST_STATE_MIN && index <= FAST_STATE_MAX) - m_fast_state[index - FAST_STATE_MIN] = m_state_list.back().get(); + if (new_entry.index() >= FAST_STATE_MIN && new_entry.index() <= FAST_STATE_MAX && !new_entry.divider()) + m_fast_state[new_entry.index() - FAST_STATE_MIN] = &new_entry; - return *m_state_list.back().get(); + return new_entry; } -//------------------------------------------------- -// state_add_divider - add a simple divider -// entry -//------------------------------------------------- - -device_state_entry &device_state_interface::state_add_divider(int index) -{ - // append to the end of the list - m_state_list.push_back(std::make_unique<device_state_entry>(index, this)); - - return *m_state_list.back().get(); -} //------------------------------------------------- // state_import - called after new state is diff --git a/src/emu/distate.h b/src/emu/distate.h index 22db6cc22af..a2cfcecb4c5 100644 --- a/src/emu/distate.h +++ b/src/emu/distate.h @@ -46,8 +46,9 @@ class device_state_entry friend class device_state_interface; public: // construction/destruction - device_state_entry(int index, const char *symbol, void *dataptr, u8 size, device_state_interface *dev); + device_state_entry(int index, const char *symbol, u8 size, u64 sizemask, u8 flags, device_state_interface *dev); device_state_entry(int index, device_state_interface *dev); + virtual ~device_state_entry(); public: // post-construction modifiers @@ -57,13 +58,17 @@ public: device_state_entry &callimport() { m_flags |= DSF_IMPORT; return *this; } device_state_entry &callexport() { m_flags |= DSF_EXPORT; return *this; } device_state_entry &noshow() { m_flags |= DSF_NOSHOW; return *this; } + device_state_entry &readonly() { m_flags |= DSF_READONLY; return *this; } // query information int index() const { return m_index; } - void *dataptr() const { return m_dataptr; } + void *dataptr() const { return entry_baseptr(); } + u64 datamask() const { return m_datamask; } const char *symbol() const { return m_symbol.c_str(); } bool visible() const { return ((m_flags & DSF_NOSHOW) == 0); } + bool writeable() const { return ((m_flags & DSF_READONLY) == 0); } bool divider() const { return m_flags & DSF_DIVIDER; } + bool is_float() const { return m_flags & DSF_FLOATING_POINT; } device_state_interface *parent_state() const {return m_device_state;} const std::string &format_string() const { return m_format; } @@ -75,6 +80,8 @@ protected: static constexpr u8 DSF_EXPORT = 0x08; // call the export function prior to fetching the data static constexpr u8 DSF_CUSTOM_STRING = 0x10; // set if the format has a custom string static constexpr u8 DSF_DIVIDER = 0x20; // set if this is a divider entry + static constexpr u8 DSF_READONLY = 0x40; // set if this entry does not permit writes + static constexpr u8 DSF_FLOATING_POINT = 0x80; // set if this entry represents a floating-point value // helpers bool needs_custom_string() const { return ((m_flags & DSF_CUSTOM_STRING) != 0); } @@ -82,21 +89,29 @@ protected: // return the current value -- only for our friends who handle export bool needs_export() const { return ((m_flags & DSF_EXPORT) != 0); } - u64 value() const; + u64 value() const { return entry_value() & m_datamask; } + double dvalue() const { return entry_dvalue(); } std::string format(const char *string, bool maxout = false) const; // set the current value -- only for our friends who handle import bool needs_import() const { return ((m_flags & DSF_IMPORT) != 0); } void set_value(u64 value) const; + void set_dvalue(double value) const; void set_value(const char *string) const; + // overrides + virtual void *entry_baseptr() const; + virtual u64 entry_value() const; + virtual void entry_set_value(u64 value) const; + virtual double entry_dvalue() const; + virtual void entry_set_dvalue(double value) const; + // statics static const u64 k_decimal_divisor[20]; // divisors for outputting decimal values // public state description device_state_interface *m_device_state; // link to parent device state u32 m_index; // index by which this item is referred - void * m_dataptr; // pointer to where the data lives u64 m_datamask; // mask that applies to the data u8 m_datasize; // size of the data u8 m_flags; // flags for this data @@ -107,6 +122,84 @@ protected: }; +// ======================> device_state_register + +// class template representing a state register of a specific width +template<class ItemType> +class device_state_register : public device_state_entry +{ +public: + // construction/destruction + device_state_register(int index, const char *symbol, ItemType &data, device_state_interface *dev) + : device_state_entry(index, symbol, sizeof(ItemType), std::numeric_limits<ItemType>::max(), 0, dev), + m_data(data) + { + static_assert(std::is_integral<ItemType>().value, "Registration of non-integer types is not currently supported"); + } + +protected: + // device_state_entry overrides + virtual void *entry_baseptr() const override { return &m_data; } + virtual u64 entry_value() const override { return m_data; } + virtual void entry_set_value(u64 value) const override { m_data = value; } + +private: + ItemType & m_data; // reference to where the data lives +}; + +// class template representing a floating-point state register +template<> +class device_state_register<double> : public device_state_entry +{ +public: + // construction/destruction + device_state_register(int index, const char *symbol, double &data, device_state_interface *dev) + : device_state_entry(index, symbol, sizeof(double), ~u64(0), DSF_FLOATING_POINT, dev), + m_data(data) + { + } + +protected: + // device_state_entry overrides + virtual void *entry_baseptr() const override { return &m_data; } + virtual u64 entry_value() const override { return u64(m_data); } + virtual void entry_set_value(u64 value) const override { m_data = double(value); } + virtual double entry_dvalue() const override { return m_data; } + virtual void entry_set_dvalue(double value) const override { m_data = value; } + +private: + double & m_data; // reference to where the data lives +}; + + +// ======================> device_state_register + +// class template representing a state register of a specific width +template<class ItemType> +class device_pseudo_state_register : public device_state_entry +{ +public: + typedef typename std::function<ItemType ()> getter_func; + typedef typename std::function<void (ItemType)> setter_func; + + // construction/destruction + device_pseudo_state_register(int index, const char *symbol, getter_func &&getter, setter_func &&setter, device_state_interface *dev) + : device_state_entry(index, symbol, sizeof(ItemType), std::numeric_limits<ItemType>::max(), 0, dev), + m_getter(std::move(getter)), + m_setter(std::move(setter)) + { + } + +protected: + // device_state_entry overrides + virtual u64 entry_value() const override { return m_getter(); } + virtual void entry_set_value(u64 value) const override { m_setter(value); } + +private: + getter_func m_getter; // function to retrieve the data + setter_func m_setter; // function to store the data +}; + // ======================> device_state_interface @@ -143,15 +236,32 @@ public: public: // protected eventually - // add a new state item - template<class _ItemType> device_state_entry &state_add(int index, const char *symbol, _ItemType &data) + // add a new state register item + template<class ItemType> device_state_entry &state_add(int index, const char *symbol, ItemType &data) + { + assert(symbol != nullptr); + return state_add(std::make_unique<device_state_register<ItemType>>(index, symbol, data, this)); + } + + // add a new state pseudo-register item (template argument must be explicit) + template<class ItemType> device_state_entry &state_add(int index, const char *symbol, + typename device_pseudo_state_register<ItemType>::getter_func &&getter, + typename device_pseudo_state_register<ItemType>::setter_func &&setter) { - return state_add(index, symbol, &data, sizeof(data)); + assert(symbol != nullptr); + return state_add(std::make_unique<device_pseudo_state_register<ItemType>>(index, symbol, std::move(getter), std::move(setter), this)); } - device_state_entry &state_add(int index, const char *symbol, void *data, u8 size); + template<class ItemType> device_state_entry &state_add(int index, const char *symbol, + typename device_pseudo_state_register<ItemType>::getter_func &&getter) + { + assert(symbol != nullptr); + return state_add(std::make_unique<device_pseudo_state_register<ItemType>>(index, symbol, std::move(getter), [](ItemType){}, this)).readonly(); + } + + device_state_entry &state_add(std::unique_ptr<device_state_entry> &&entry); // add a new divider entry - device_state_entry &state_add_divider(int index); + device_state_entry &state_add_divider(int index) { return state_add(std::make_unique<device_state_entry>(index, this)); } protected: // derived class overrides diff --git a/src/emu/divideo.cpp b/src/emu/divideo.cpp index 4abe607dab3..7007487ef32 100644 --- a/src/emu/divideo.cpp +++ b/src/emu/divideo.cpp @@ -134,11 +134,8 @@ void device_video_interface::interface_pre_start() throw device_missing_dependencies(); else { - // resolve the palette for the sake of register_screen_bitmap - m_screen->resolve_palette(); - - // no other palette may be specified (FIXME: breaks meritm.cpp) - if (0 && m_screen->has_palette() && palintf != &m_screen->palette()) + // no other palette may be specified + if (m_screen->has_palette() && palintf != &m_screen->palette()) throw emu_fatalerror("Device '%s' cannot control screen '%s' with palette '%s'", device().tag(), m_screen_tag, m_screen->palette().device().tag()); } } diff --git a/src/emu/drawgfx.cpp b/src/emu/drawgfx.cpp index edbfa1ec306..eff4e46f2cf 100644 --- a/src/emu/drawgfx.cpp +++ b/src/emu/drawgfx.cpp @@ -1919,6 +1919,18 @@ void copybitmap_trans(bitmap_rgb32 &dest, const bitmap_rgb32 &src, int flipx, in } +/*------------------------------------------------- + copybitmap_transalphpa - copy from one bitmap + to another, copying all unclipped pixels except + those with an alpha value of zero +-------------------------------------------------*/ + +void copybitmap_transalpha(bitmap_rgb32 &dest, const bitmap_rgb32 &src, int flipx, int flipy, s32 destx, s32 desty, const rectangle &cliprect) +{ + DECLARE_NO_PRIORITY; + COPYBITMAP_CORE(u32, PIXEL_OP_COPY_TRANSALPHA, NO_PRIORITY); +} + /*************************************************************************** COPYSCROLLBITMAP IMPLEMENTATIONS diff --git a/src/emu/drawgfx.h b/src/emu/drawgfx.h index fe5cb7679df..e9833de4a30 100644 --- a/src/emu/drawgfx.h +++ b/src/emu/drawgfx.h @@ -352,6 +352,8 @@ void copybitmap(bitmap_rgb32 &dest, const bitmap_rgb32 &src, int flipx, int flip void copybitmap_trans(bitmap_ind16 &dest, const bitmap_ind16 &src, int flipx, int flipy, s32 destx, s32 desty, const rectangle &cliprect, u32 transpen); void copybitmap_trans(bitmap_rgb32 &dest, const bitmap_rgb32 &src, int flipx, int flipy, s32 destx, s32 desty, const rectangle &cliprect, u32 transpen); +void copybitmap_transalpha(bitmap_rgb32 &dest, const bitmap_rgb32 &src, int flipx, int flipy, s32 destx, s32 desty, const rectangle &cliprect); + /* Copy a bitmap onto another with scroll and wraparound. These functions support multiple independently scrolling rows/columns. @@ -429,7 +431,7 @@ constexpr u32 alpha_blend_r16(u32 d, u32 s, u8 level) //------------------------------------------------- -// alpha_blend_r16 - alpha blend two 32-bit +// alpha_blend_r32 - alpha blend two 32-bit // 8-8-8 RGB pixels //------------------------------------------------- diff --git a/src/emu/drawgfxm.h b/src/emu/drawgfxm.h index 325ce0e974c..1bef8e15237 100644 --- a/src/emu/drawgfxm.h +++ b/src/emu/drawgfxm.h @@ -95,6 +95,21 @@ do while (0) /*------------------------------------------------- + PIXEL_OP_COPY_TRANSALPHA - render all pixels + except those with an alpha of zero, copying + directly +-------------------------------------------------*/ + +#define PIXEL_OP_COPY_TRANSALPHA(DEST, PRIORITY, SOURCE) \ +do \ +{ \ + u32 srcdata = (SOURCE); \ + if ((srcdata & 0xff000000) != 0) \ + (DEST) = SOURCE; \ +} \ +while (0) + +/*------------------------------------------------- PIXEL_OP_REMAP_OPAQUE - render all pixels regardless of pen, mapping the pen via the 'paldata' array diff --git a/src/emu/driver.cpp b/src/emu/driver.cpp index 76756b2bfb0..75e01880fe2 100644 --- a/src/emu/driver.cpp +++ b/src/emu/driver.cpp @@ -260,55 +260,6 @@ void driver_device::device_reset_after_children() //************************************************************************** -// INTERRUPT ENABLE AND VECTOR HELPERS -//************************************************************************** - -//------------------------------------------------- -// irq_pulse_clear - clear a "pulsed" IRQ line -//------------------------------------------------- - -void driver_device::irq_pulse_clear(void *ptr, s32 param) -{ - device_execute_interface *exec = reinterpret_cast<device_execute_interface *>(ptr); - int irqline = param; - exec->set_input_line(irqline, CLEAR_LINE); -} - - -//------------------------------------------------- -// generic_pulse_irq_line - "pulse" an IRQ line by -// asserting it and then clearing it x cycle(s) -// later -//------------------------------------------------- - -void driver_device::generic_pulse_irq_line(device_execute_interface &exec, int irqline, int cycles) -{ - assert(irqline != INPUT_LINE_NMI && irqline != INPUT_LINE_RESET && cycles > 0); - exec.set_input_line(irqline, ASSERT_LINE); - - attotime target_time = exec.local_time() + exec.cycles_to_attotime(cycles * exec.min_cycles()); - machine().scheduler().timer_set(target_time - machine().time(), timer_expired_delegate(FUNC(driver_device::irq_pulse_clear), this), irqline, (void *)&exec); -} - - -//------------------------------------------------- -// generic_pulse_irq_line_and_vector - "pulse" an -// IRQ line by asserting it and then clearing it -// x cycle(s) later, specifying a vector -//------------------------------------------------- - -void driver_device::generic_pulse_irq_line_and_vector(device_execute_interface &exec, int irqline, int vector, int cycles) -{ - assert(irqline != INPUT_LINE_NMI && irqline != INPUT_LINE_RESET && cycles > 0); - exec.set_input_line_and_vector(irqline, ASSERT_LINE, vector); - - attotime target_time = exec.local_time() + exec.cycles_to_attotime(cycles * exec.min_cycles()); - machine().scheduler().timer_set(target_time - machine().time(), timer_expired_delegate(FUNC(driver_device::irq_pulse_clear), this), irqline, (void *)&exec); -} - - - -//************************************************************************** // INTERRUPT GENERATION CALLBACK HELPERS //************************************************************************** @@ -325,35 +276,27 @@ INTERRUPT_GEN_MEMBER( driver_device::nmi_line_assert ) { device.execute().set_i //------------------------------------------------- INTERRUPT_GEN_MEMBER( driver_device::irq0_line_hold ) { device.execute().set_input_line(0, HOLD_LINE); } -INTERRUPT_GEN_MEMBER( driver_device::irq0_line_pulse ) { generic_pulse_irq_line(device.execute(), 0, 1); } INTERRUPT_GEN_MEMBER( driver_device::irq0_line_assert ) { device.execute().set_input_line(0, ASSERT_LINE); } INTERRUPT_GEN_MEMBER( driver_device::irq1_line_hold ) { device.execute().set_input_line(1, HOLD_LINE); } -INTERRUPT_GEN_MEMBER( driver_device::irq1_line_pulse ) { generic_pulse_irq_line(device.execute(), 1, 1); } INTERRUPT_GEN_MEMBER( driver_device::irq1_line_assert ) { device.execute().set_input_line(1, ASSERT_LINE); } INTERRUPT_GEN_MEMBER( driver_device::irq2_line_hold ) { device.execute().set_input_line(2, HOLD_LINE); } -INTERRUPT_GEN_MEMBER( driver_device::irq2_line_pulse ) { generic_pulse_irq_line(device.execute(), 2, 1); } INTERRUPT_GEN_MEMBER( driver_device::irq2_line_assert ) { device.execute().set_input_line(2, ASSERT_LINE); } INTERRUPT_GEN_MEMBER( driver_device::irq3_line_hold ) { device.execute().set_input_line(3, HOLD_LINE); } -INTERRUPT_GEN_MEMBER( driver_device::irq3_line_pulse ) { generic_pulse_irq_line(device.execute(), 3, 1); } INTERRUPT_GEN_MEMBER( driver_device::irq3_line_assert ) { device.execute().set_input_line(3, ASSERT_LINE); } INTERRUPT_GEN_MEMBER( driver_device::irq4_line_hold ) { device.execute().set_input_line(4, HOLD_LINE); } -INTERRUPT_GEN_MEMBER( driver_device::irq4_line_pulse ) { generic_pulse_irq_line(device.execute(), 4, 1); } INTERRUPT_GEN_MEMBER( driver_device::irq4_line_assert ) { device.execute().set_input_line(4, ASSERT_LINE); } INTERRUPT_GEN_MEMBER( driver_device::irq5_line_hold ) { device.execute().set_input_line(5, HOLD_LINE); } -INTERRUPT_GEN_MEMBER( driver_device::irq5_line_pulse ) { generic_pulse_irq_line(device.execute(), 5, 1); } INTERRUPT_GEN_MEMBER( driver_device::irq5_line_assert ) { device.execute().set_input_line(5, ASSERT_LINE); } INTERRUPT_GEN_MEMBER( driver_device::irq6_line_hold ) { device.execute().set_input_line(6, HOLD_LINE); } -INTERRUPT_GEN_MEMBER( driver_device::irq6_line_pulse ) { generic_pulse_irq_line(device.execute(), 6, 1); } INTERRUPT_GEN_MEMBER( driver_device::irq6_line_assert ) { device.execute().set_input_line(6, ASSERT_LINE); } INTERRUPT_GEN_MEMBER( driver_device::irq7_line_hold ) { device.execute().set_input_line(7, HOLD_LINE); } -INTERRUPT_GEN_MEMBER( driver_device::irq7_line_pulse ) { generic_pulse_irq_line(device.execute(), 7, 1); } INTERRUPT_GEN_MEMBER( driver_device::irq7_line_assert ) { device.execute().set_input_line(7, ASSERT_LINE); } diff --git a/src/emu/driver.h b/src/emu/driver.h index 8ac375c218a..2b4d3088a1f 100644 --- a/src/emu/driver.h +++ b/src/emu/driver.h @@ -130,43 +130,31 @@ public: // output heler output_manager &output() const { return machine().output(); } - // generic interrupt generators - void generic_pulse_irq_line(device_execute_interface &exec, int irqline, int cycles); - void generic_pulse_irq_line_and_vector(device_execute_interface &exec, int irqline, int vector, int cycles); - INTERRUPT_GEN_MEMBER( nmi_line_pulse ); INTERRUPT_GEN_MEMBER( nmi_line_assert ); INTERRUPT_GEN_MEMBER( irq0_line_hold ); - INTERRUPT_GEN_MEMBER( irq0_line_pulse ); INTERRUPT_GEN_MEMBER( irq0_line_assert ); INTERRUPT_GEN_MEMBER( irq1_line_hold ); - INTERRUPT_GEN_MEMBER( irq1_line_pulse ); INTERRUPT_GEN_MEMBER( irq1_line_assert ); INTERRUPT_GEN_MEMBER( irq2_line_hold ); - INTERRUPT_GEN_MEMBER( irq2_line_pulse ); INTERRUPT_GEN_MEMBER( irq2_line_assert ); INTERRUPT_GEN_MEMBER( irq3_line_hold ); - INTERRUPT_GEN_MEMBER( irq3_line_pulse ); INTERRUPT_GEN_MEMBER( irq3_line_assert ); INTERRUPT_GEN_MEMBER( irq4_line_hold ); - INTERRUPT_GEN_MEMBER( irq4_line_pulse ); INTERRUPT_GEN_MEMBER( irq4_line_assert ); INTERRUPT_GEN_MEMBER( irq5_line_hold ); - INTERRUPT_GEN_MEMBER( irq5_line_pulse ); INTERRUPT_GEN_MEMBER( irq5_line_assert ); INTERRUPT_GEN_MEMBER( irq6_line_hold ); - INTERRUPT_GEN_MEMBER( irq6_line_pulse ); INTERRUPT_GEN_MEMBER( irq6_line_assert ); INTERRUPT_GEN_MEMBER( irq7_line_hold ); - INTERRUPT_GEN_MEMBER( irq7_line_pulse ); INTERRUPT_GEN_MEMBER( irq7_line_assert ); @@ -204,7 +192,6 @@ protected: private: // helpers - void irq_pulse_clear(void *ptr, s32 param); void updateflip(); // internal state diff --git a/src/emu/drivers/xtal.h b/src/emu/drivers/xtal.h index dfab1af2ee6..8c9fb948510 100644 --- a/src/emu/drivers/xtal.h +++ b/src/emu/drivers/xtal.h @@ -35,6 +35,11 @@ XTAL_3_579545MHz should actually be 3579545.454545...Hz (39375000/11). This is no problem though: see above note about tolerance. + In the "Examples" column, please don't add 1000 examples, this is just + for interest, so two or three examples is enough. + The actual reference where the xtals are used can be found in the + driver files by searching for the frequency (e.g. "XTAL_4_9152MHz") + (Thanks to Guru for starting this documentation.) **************************************************************************/ @@ -53,6 +58,7 @@ enum XTAL_1MHz = 1000000, /* Used to drive OKI M6295 chips */ XTAL_1_2944MHz = 1294400, /* BBN BitGraph PSG */ XTAL_1_75MHz = 1750000, /* RCA CDP1861 */ + XTAL_1_7971MHz = 1797100, /* SWTPC 6800 (with MIKBUG) */ XTAL_1_8432MHz = 1843200, /* Bondwell 12/14 */ XTAL_1_9968MHz = 1996800, /* NEC PC-98xx */ XTAL_2MHz = 2000000, @@ -66,6 +72,7 @@ enum XTAL_3_12MHz = 3120000, /* SP0250 clock on Gottlieb games */ XTAL_3_5MHz = 3500000, /* Reported by Commodore 65 document, true xtal unchecked on PCB */ XTAL_3_52128MHz = 3521280, /* RCA COSMAC VIP */ + XTAL_3_57MHz = 3570000, /* Telmac TMC-600 */ XTAL_3_57864MHz = 3578640, /* Atari Portfolio PCD3311T */ XTAL_3_579545MHz = 3579545, /* NTSC color subcarrier, extremely common, used on 100's of PCBs (Keytronic custom part #48-300-010 is equivalent) */ XTAL_3_6864MHz = 3686400, /* Baud rate clock for MC68681 and similar UARTs */ @@ -91,7 +98,7 @@ enum XTAL_5_911MHz = 5911000, /* Philips Videopac Plus G7400 */ XTAL_5_9904MHz = 5990400, /* Luxor ABC 800 keyboard (Keytronic custom part #48-300-008 is equivalent) */ XTAL_6MHz = 6000000, /* American Poker II, Taito SJ System */ - XTAL_6_144MHz = 6144000, /* Used on Alpha Denshi early 80's games sound board, Casio FP-200 and Namco System 16 */ + XTAL_6_144MHz = 6144000, /* Used on Alpha Denshi early 80's games sound board, Casio FP-200 and Namco Universal System 16 */ XTAL_6_5MHz = 6500000, /* Jupiter Ace */ XTAL_6_9MHz = 6900000, /* BBN BitGraph CPU */ XTAL_7MHz = 7000000, /* Jaleco Mega System PCBs */ @@ -123,6 +130,7 @@ enum XTAL_10_733MHz = 10733000, /* The Fairyland Story */ XTAL_10_738635MHz = 10738635, /* TMS9918 family (3x NTSC subcarrier) */ XTAL_10_816MHz = 10816000, /* Universal 1979-1980 (Cosmic Alien, etc) */ + XTAL_10_920MHz = 10920000, /* ADDS Viewpoint 60, Viewpoint A2 */ XTAL_11MHz = 11000000, /* Mario I8039 sound */ XTAL_11_0592MHz = 11059200, /* Used with MCS-51 to generate common baud rates */ XTAL_11_2MHz = 11200000, /* New York, New York */ @@ -132,6 +140,7 @@ enum XTAL_11_8MHz = 11800000, /* IBM PC Music Feature Card */ XTAL_11_9808MHz = 11980800, /* Luxor ABC 80 */ XTAL_12MHz = 12000000, /* Extremely common, used on 100's of PCBs */ + XTAL_12_0576MHz = 12057600, /* Poly 1 (38400 * 314) */ XTAL_12_096MHz = 12096000, /* Some early 80's Atari games */ XTAL_12_288MHz = 12288000, /* Sega Model 3 digital audio board */ XTAL_12_432MHz = 12432000, /* Kaneko Fly Boy/Fast Freddie Hardware */ @@ -149,32 +158,41 @@ enum XTAL_13_5168MHz = 13516800, /* Kontron KDT6 */ XTAL_14MHz = 14000000, XTAL_14_112MHz = 14112000, /* Timex/Sinclair TS2068 */ + XTAL_14_192640MHz = 14192640, /* Reported by Central Data 2650 document, true xtal unchecked on PCB */ + XTAL_14_218MHz = 14218000, /* Dragon */ XTAL_14_3MHz = 14300000, /* Agat-7 */ XTAL_14_314MHz = 14314000, /* Taito TTL Board */ XTAL_14_31818MHz = 14318181, /* Extremely common, used on 100's of PCBs (4x NTSC subcarrier) */ XTAL_14_705882MHz = 14705882, /* Aleck64 */ XTAL_14_7456MHz = 14745600, /* Namco System 12 & System Super 22/23 for JVS */ + XTAL_14_916MHz = 14916000, /* ADDS Viewpoint 122 */ XTAL_15MHz = 15000000, /* Sinclair QL, Amusco Poker */ + XTAL_15_30072MHz = 15300720, /* Microterm 420 */ XTAL_15_36MHz = 15360000, /* Visual 1050 */ XTAL_15_4MHz = 15400000, /* DVK KSM */ XTAL_15_468MHz = 15468480, /* Bank Panic h/w, Sega G80 */ XTAL_15_8976MHz = 15897600, /* IAI Swyft */ XTAL_15_92MHz = 15920000, /* HP Integral PC */ - XTAL_15_9744MHz = 15974400, /* Osborne 1 */ + XTAL_15_9744MHz = 15974400, /* Osborne 1 (9600 * 52 * 32) */ XTAL_16MHz = 16000000, /* Extremely common, used on 100's of PCBs */ XTAL_16_384MHz = 16384000, XTAL_16_4MHz = 16400000, /* MS 6102 */ XTAL_16_5888MHz = 16588800, /* SM 7238 */ + XTAL_16_6698MHz = 16669800, /* Qume QVT-102 */ XTAL_16_67MHz = 16670000, XTAL_16_777216MHz = 16777216, /* Nintendo Game Boy Advance */ XTAL_16_9344MHz = 16934400, /* Usually used to drive 90's Yamaha OPL/FM chips (44100 * 384) */ + XTAL_17_064MHz = 17064000, /* Memorex 1377 */ XTAL_17_36MHz = 17360000, /* OMTI Series 10 SCSI controller */ XTAL_17_73447MHz = 17734470, /* (~4x PAL subcarrier) */ XTAL_17_734472MHz = 17734472, /* actually ~4x PAL subcarrier */ XTAL_17_9712MHz = 17971200, XTAL_18MHz = 18000000, /* S.A.R, Ikari Warriors 3 */ XTAL_18_432MHz = 18432000, /* Extremely common, used on 100's of PCBs (48000 * 384) */ + XTAL_18_575MHz = 18575000, /* Visual 102 */ XTAL_18_720MHz = 18720000, /* Nokia MikroMikko 1 */ + XTAL_18_8696MHz = 18869600, /* Memorex 2178 */ + XTAL_19_3396MHz = 19339600, /* TeleVideo TVI-955 80-column display clock */ XTAL_19_6MHz = 19600000, /* Universal Mr. Do - Model 8021 PCB */ XTAL_19_6608MHz = 19660800, /* Euro League (bootleg), labeled as "UKI 19.6608 20PF" */ XTAL_19_923MHz = 19923000, /* Cinematronics vectors */ @@ -187,9 +205,11 @@ enum XTAL_21_3MHz = 21300000, XTAL_21_4772MHz = 21477272, /* BMC bowling, some Data East 90's games, Vtech Socrates; (6x NTSC subcarrier) */ XTAL_22MHz = 22000000, + XTAL_22_096MHz = 22096000, /* ADDS Viewpoint 122 */ XTAL_22_1184MHz = 22118400, /* Amusco Poker */ XTAL_22_3210MHz = 22321000, /* Apple LaserWriter II NT */ XTAL_22_656MHz = 22656000, /* Super Pinball Action (~1440x NTSC line rate) */ + XTAL_23_814MHz = 23814000, /* TeleVideo TVI-912C & 950 */ XTAL_23_9616MHz = 23961600, /* Osborne 4 (Vixen) */ XTAL_24MHz = 24000000, /* Mario, 80's Data East games, 80's Konami games */ XTAL_24_0734MHz = 24073400, /* DEC Rainbow 100 */ @@ -201,10 +221,14 @@ enum XTAL_25_447MHz = 25447000, /* Namco EVA3A (Funcube2) */ XTAL_25_590906MHz = 25590906, /* Atari Jaguar NTSC */ XTAL_25_593900MHz = 25593900, /* Atari Jaguar PAL */ + XTAL_25_7715MHz = 25771500, /* HP-2622A */ + XTAL_25_92MHz = 25920000, /* ADDS Viewpoint 60 */ XTAL_26MHz = 26000000, /* Gaelco PCBs */ XTAL_26_601712MHz = 26601712, /* Astro Corp.'s Show Hand, PAL Vtech/Yeno Socrates (6x PAL subcarrier) */ + XTAL_26_666MHz = 26666000, /* Imagetek I4100/I4220/I4300 */ XTAL_26_66666MHz = 26666666, /* Irem M92 but most use 27MHz */ XTAL_26_686MHz = 26686000, /* Typically used on 90's Taito PCBs to drive the custom chips */ + XTAL_26_9892MHz = 26989200, /* TeleVideo 965 */ XTAL_27MHz = 27000000, /* Some Banpresto games macrossp, Irem M92 and 90's Toaplan games */ XTAL_27_164MHz = 27164000, /* Typically used on 90's Taito PCBs to drive the custom chips */ XTAL_27_2109MHz = 27210900, /* LA Girl */ @@ -216,9 +240,11 @@ enum XTAL_28_64MHz = 28640000, /* Fukki FG-1c AI AM-2 PCB */ XTAL_28_7MHz = 28700000, XTAL_29_4912MHz = 29491200, /* Xerox Alto-II system clock (tagged 29.4MHz in the schematics) */ + XTAL_29_876MHz = 29876000, /* Qume QVT-103 */ XTAL_30MHz = 30000000, /* Impera Magic Card */ XTAL_30_4761MHz = 30476100, /* Taito JC */ XTAL_30_8MHz = 30800000, /* 15IE-00-013 */ + XTAL_31_684MHz = 31684000, /* TeleVideo TVI-955 132-column display clock */ XTAL_32MHz = 32000000, XTAL_32_22MHz = 32220000, /* Typically used on 90's Data East PCBs (close to 9x NTSC subcarrier which is 32.215905Mhz*/ XTAL_32_5304MHz = 32530400, /* Seta 2 */ @@ -234,12 +260,18 @@ enum XTAL_40MHz = 40000000, XTAL_42MHz = 42000000, /* BMC A-00211 - Popo Bear */ XTAL_42_9545MHz = 42954545, /* CPS3 (12x NTSC subcarrier)*/ + XTAL_43_320MHz = 43320000, /* DEC VT420 */ XTAL_44_1MHz = 44100000, /* Subsino's Bishou Jan */ + XTAL_44_4528MHz = 44452800, /* TeleVideo 965 */ XTAL_45MHz = 45000000, /* Eolith with Hyperstone CPUs */ XTAL_45_158MHz = 45158000, /* Sega Model 2A video board, Model 3 CPU board */ - XTAL_45_6192Mhz = 45619200, /* DEC VK100 */ + XTAL_45_582MHz = 45582000, /* Zentec Zephyr */ + XTAL_45_6192MHz = 45619200, /* DEC VK100 */ + XTAL_45_8304MHz = 45830400, /* Microterm 5510 */ + XTAL_47_736MHz = 47736000, /* Visual 100 */ XTAL_48MHz = 48000000, /* Williams/Midway Y/Z-unit system / SSV board */ XTAL_48_384MHz = 48384000, /* Namco NB-1 */ + XTAL_48_654MHz = 48654000, /* Qume QVT-201 */ XTAL_48_66MHz = 48660000, /* Zaxxon */ XTAL_49_152MHz = 49152000, /* Used on some Namco PCBs, Baraduke h/w, System 21, Super System 22 */ XTAL_50MHz = 50000000, /* Williams/Midway T/W/V-unit system */ @@ -253,6 +285,7 @@ enum XTAL_55MHz = 55000000, /* Eolith Vega */ XTAL_57_2727MHz = 57272727, /* Psikyo SH2 with /2 divider (16x NTSC subcarrier)*/ XTAL_58MHz = 58000000, /* Magic Reel (Play System) */ + XTAL_59_2920MHz = 59292000, /* Data General D461 */ XTAL_60MHz = 60000000, XTAL_61_44MHz = 61440000, /* dkong */ XTAL_64MHz = 64000000, /* BattleToads */ @@ -261,6 +294,7 @@ enum XTAL_72MHz = 72000000, /* Aristocrat MKV */ XTAL_72_576MHz = 72576000, /* Centipede, Millipede, Missile Command, Let's Go Bowling "Multipede" */ XTAL_73_728MHz = 73728000, /* Ms. Pac-Man/Galaga 20th Anniversary */ + XTAL_87_18336MHz = 87183360, /* AT&T 630 MTG */ XTAL_100MHz = 100000000, /* PSX-based Namco System 12, Vegas, Sony ZN1-2-based */ XTAL_101_4912MHz = 101491200, /* PSX-based Namco System 10 */ XTAL_200MHz = 200000000, /* Base SH4 CPU (Naomi, Hikaru etc.) */ diff --git a/src/emu/emucore.h b/src/emu/emucore.h index 46a5427a4ec..04b67869546 100644 --- a/src/emu/emucore.h +++ b/src/emu/emucore.h @@ -384,19 +384,6 @@ enum_value(T value) noexcept // INLINE FUNCTIONS //************************************************************************** -// population count -#if !defined(__NetBSD__) -inline int popcount(u32 val) -{ - int count; - - for (count = 0; val != 0; count++) - val &= val - 1; - return count; -} -#endif - - // convert a series of 32 bits into a float inline float u2f(u32 v) { @@ -444,4 +431,14 @@ inline u64 d2u(double d) return u.vv; } + +// constexpr absolute value of an integer +inline constexpr int iabs(int v) +{ + if(v < 0) + return -v; + else + return v; +} + #endif /* MAME_EMU_EMUCORE_H */ diff --git a/src/emu/emufwd.h b/src/emu/emufwd.h index cd7de9fecb9..0ab280adbf4 100644 --- a/src/emu/emufwd.h +++ b/src/emu/emufwd.h @@ -130,7 +130,7 @@ class driver_device; // declared in emumem.h class address_space; -class direct_read_data; +template<int addr_shift> class direct_read_data; class memory_bank; class memory_block; class memory_manager; diff --git a/src/emu/emumem.cpp b/src/emu/emumem.cpp index c6ad1349d23..48e43c4acf1 100644 --- a/src/emu/emumem.cpp +++ b/src/emu/emumem.cpp @@ -269,8 +269,9 @@ protected: public: // getters bool populated() const { return m_populated; } - offs_t bytestart() const { return m_bytestart; } - offs_t byteend() const { return m_byteend; } + offs_t addrstart() const { return m_addrstart; } + offs_t addrend() const { return m_addrend; } + offs_t addrmask() const { return m_addrmask; } offs_t bytemask() const { return m_bytemask; } virtual const char *name() const = 0; virtual const char *subunit_name(int entry) const = 0; @@ -279,44 +280,45 @@ public: virtual void copy(handler_entry *entry); // return offset within the range referenced by this handler - offs_t byteoffset(offs_t byteaddress) const { return (byteaddress - m_bytestart) & m_bytemask; } + offs_t offset(offs_t address) const { return (address - m_addrstart) & m_addrmask; } // return a pointer to the backing RAM at the given offset u8 *ramptr(offs_t offset = 0) const { return *m_rambaseptr + offset; } // see if we are an exact match to the given parameters - bool matches_exactly(offs_t bytestart, offs_t byteend, offs_t bytemask) const + bool matches_exactly(offs_t addrstart, offs_t addrend, offs_t addrmask) const { - return (m_populated && m_bytestart == bytestart && m_byteend == byteend && m_bytemask == bytemask); + return (m_populated && m_addrstart == addrstart && m_addrend == addrend && m_addrmask == addrmask); } // get the start/end address with the given mirror - void mirrored_start_end(offs_t byteaddress, offs_t &start, offs_t &end) const + void mirrored_start_end(offs_t address, offs_t &start, offs_t &end) const { - offs_t mirrorbits = (byteaddress - m_bytestart) & ~m_bytemask; - start = m_bytestart | mirrorbits; - end = m_byteend | mirrorbits; + offs_t mirrorbits = (address - m_addrstart) & ~m_addrmask; + start = m_addrstart | mirrorbits; + end = m_addrend | mirrorbits; } // configure the handler addresses, and mark as populated - void configure(offs_t bytestart, offs_t byteend, offs_t bytemask) + void configure(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t bytemask) { if (m_populated && m_subunits) - reconfigure_subunits(bytestart); + reconfigure_subunits(addrstart); m_populated = true; - m_bytestart = bytestart; - m_byteend = byteend; + m_addrstart = addrstart; + m_addrend = addrend; + m_addrmask = addrmask; m_bytemask = bytemask; } - // Re-expand the bytemask after subunit fun + // Re-expand the addrmask after subunit fun void expand_bytemask(offs_t previous_mask) { m_bytemask |= previous_mask; } // reconfigure the subunits on a base address change - void reconfigure_subunits(offs_t bytestart); + void reconfigure_subunits(offs_t addrstart); // depopulate an handler void deconfigure() @@ -326,7 +328,7 @@ public: } // apply a global mask - void apply_mask(offs_t bytemask) { m_bytemask &= bytemask; } + void apply_mask(offs_t addrmask) { m_addrmask &= addrmask; } void clear_conflicting_subunits(u64 handlermask); bool overriden_by_mask(u64 handlermask); @@ -335,7 +337,7 @@ protected: // Subunit description information struct subunit_info { - offs_t m_bytemask; // bytemask for this subunit + offs_t m_addrmask; // addrmask for this subunit u32 m_mask; // mask (ff, ffff or ffffffff) s32 m_offset; // offset to add to the address u32 m_multiplier; // multiplier to the pre-split address @@ -351,9 +353,10 @@ protected: bool m_populated; // populated? u8 m_datawidth; endianness_t m_endianness; - offs_t m_bytestart; // byte-adjusted start address for handler - offs_t m_byteend; // byte-adjusted end address for handler - offs_t m_bytemask; // byte-adjusted mask against the final address + offs_t m_addrstart; // start address for handler + offs_t m_addrend; // end address for handler + offs_t m_addrmask; // mask against the final address + offs_t m_bytemask; // mask against the final address, byte resolution u8 ** m_rambaseptr; // pointer to the bank base u8 m_subunits; // for width stubs, the number of subunits subunit_info m_subunit_infos[8]; // for width stubs, the associated subunit info @@ -568,33 +571,33 @@ public: bool watchpoints_enabled() const { return (m_live_lookup == s_watchpoint_table); } // address lookups - u32 lookup_live(offs_t byteaddress) const { return m_large ? lookup_live_large(byteaddress) : lookup_live_small(byteaddress); } - u32 lookup_live_small(offs_t byteaddress) const { return m_live_lookup[byteaddress]; } + u32 lookup_live(offs_t address) const { return m_large ? lookup_live_large(address) : lookup_live_small(address); } + u32 lookup_live_small(offs_t address) const { return m_live_lookup[address]; } - u32 lookup_live_large(offs_t byteaddress) const + u32 lookup_live_large(offs_t address) const { - u32 entry = m_live_lookup[level1_index_large(byteaddress)]; + u32 entry = m_live_lookup[level1_index_large(address)]; if (entry >= SUBTABLE_BASE) - entry = m_live_lookup[level2_index_large(entry, byteaddress)]; + entry = m_live_lookup[level2_index_large(entry, address)]; return entry; } - u32 lookup_live_nowp(offs_t byteaddress) const { return m_large ? lookup_live_large_nowp(byteaddress) : lookup_live_small_nowp(byteaddress); } - u32 lookup_live_small_nowp(offs_t byteaddress) const { return m_table[byteaddress]; } + u32 lookup_live_nowp(offs_t address) const { return m_large ? lookup_live_large_nowp(address) : lookup_live_small_nowp(address); } + u32 lookup_live_small_nowp(offs_t address) const { return m_table[address]; } - u32 lookup_live_large_nowp(offs_t byteaddress) const + u32 lookup_live_large_nowp(offs_t address) const { - u32 entry = m_table[level1_index_large(byteaddress)]; + u32 entry = m_table[level1_index_large(address)]; if (entry >= SUBTABLE_BASE) - entry = m_table[level2_index_large(entry, byteaddress)]; + entry = m_table[level2_index_large(entry, address)]; return entry; } - u32 lookup(offs_t byteaddress) const + u32 lookup(offs_t address) const { - u32 entry = m_live_lookup[level1_index(byteaddress)]; + u32 entry = m_live_lookup[level1_index(address)]; if (entry >= SUBTABLE_BASE) - entry = m_live_lookup[level2_index(entry, byteaddress)]; + entry = m_live_lookup[level2_index(entry, address)]; return entry; } @@ -602,9 +605,9 @@ public: void enable_watchpoints(bool enable = true) { m_live_lookup = enable ? s_watchpoint_table : &m_table[0]; } // table mapping helpers - void map_range(offs_t bytestart, offs_t byteend, offs_t bytemask, offs_t bytemirror, u16 staticentry); - void setup_range(offs_t bytestart, offs_t byteend, offs_t bytemask, offs_t bytemirror, u64 mask, std::list<u32> &entries); - u16 derive_range(offs_t byteaddress, offs_t &bytestart, offs_t &byteend) const; + void map_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u16 staticentry); + void setup_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 mask, std::list<u32> &entries); + u16 derive_range(offs_t address, offs_t &addrstart, offs_t &addrend) const; // misc helpers void mask_all_handlers(offs_t mask); @@ -618,8 +621,8 @@ protected: u32 level2_index(u16 l1entry, offs_t address) const { return m_large ? level2_index_large(l1entry, address) : 0; } // table population/depopulation - void populate_range_mirrored(offs_t bytestart, offs_t byteend, offs_t bytemirror, u16 handler); - void populate_range(offs_t bytestart, offs_t byteend, u16 handler); + void populate_range_mirrored(offs_t addrstart, offs_t addrend, offs_t addrmirror, u16 handler); + void populate_range(offs_t addrstart, offs_t addrend, u16 handler); // subtable management u16 subtable_alloc(); @@ -700,9 +703,9 @@ public: handler_entry_read &handler_read(u32 index) const { assert(index < ARRAY_LENGTH(m_handlers)); return *m_handlers[index]; } // range getter - handler_entry_proxy<handler_entry_read> handler_map_range(offs_t bytestart, offs_t byteend, offs_t bytemask, offs_t bytemirror, u64 mask = 0) { + handler_entry_proxy<handler_entry_read> handler_map_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 mask = 0) { std::list<u32> entries; - setup_range(bytestart, byteend, bytemask, bytemirror, mask, entries); + setup_range(addrstart, addrend, addrmask, addrmirror, mask, entries); std::list<handler_entry_read *> handlers; for (std::list<u32>::const_iterator i = entries.begin(); i != entries.end(); ++i) handlers.push_back(&handler_read(*i)); @@ -771,9 +774,9 @@ public: handler_entry_write &handler_write(u32 index) const { assert(index < ARRAY_LENGTH(m_handlers)); return *m_handlers[index]; } // range getter - handler_entry_proxy<handler_entry_write> handler_map_range(offs_t bytestart, offs_t byteend, offs_t bytemask, offs_t bytemirror, u64 mask = 0) { + handler_entry_proxy<handler_entry_write> handler_map_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 mask = 0) { std::list<u32> entries; - setup_range(bytestart, byteend, bytemask, bytemirror, mask, entries); + setup_range(addrstart, addrend, addrmask, addrmirror, mask, entries); std::list<handler_entry_write *> handlers; for (std::list<u32>::const_iterator i = entries.begin(); i != entries.end(); ++i) handlers.push_back(&handler_write(*i)); @@ -836,7 +839,7 @@ public: // Watchpoints and unmap states do not make sense for setoffset m_handlers[STATIC_NOP]->set_delegate(setoffset_delegate(FUNC(address_table_setoffset::nop_so), this)); - m_handlers[STATIC_NOP]->configure(0, space.bytemask(), ~0); + m_handlers[STATIC_NOP]->configure(0, space.addrmask(), ~0, ~0); } ~address_table_setoffset() @@ -847,9 +850,9 @@ public: handler_entry_setoffset &handler_setoffset(u32 index) const { assert(index < ARRAY_LENGTH(m_handlers)); return *m_handlers[index]; } // range getter - handler_entry_proxy<handler_entry_setoffset> handler_map_range(offs_t bytestart, offs_t byteend, offs_t bytemask, offs_t bytemirror, u64 mask = 0) { + handler_entry_proxy<handler_entry_setoffset> handler_map_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 mask = 0) { std::list<u32> entries; - setup_range(bytestart, byteend, bytemask, bytemirror, mask, entries); + setup_range(addrstart, addrend, addrmask, addrmirror, mask, entries); std::list<handler_entry_setoffset *> handlers; for (std::list<u32>::const_iterator i = entries.begin(); i != entries.end(); ++i) handlers.push_back(&handler_setoffset(*i)); @@ -875,20 +878,23 @@ private: // ======================> address_space_specific // this is a derived class of address_space with specific width, endianness, and table size -template<typename _NativeType, endianness_t _Endian, bool _Large> +template<typename _NativeType, endianness_t _Endian, int _Shift, bool _Large> class address_space_specific : public address_space { - typedef address_space_specific<_NativeType, _Endian, _Large> this_type; + typedef address_space_specific<_NativeType, _Endian, _Shift, _Large> this_type; // constants describing the native size static const u32 NATIVE_BYTES = sizeof(_NativeType); - static const u32 NATIVE_MASK = NATIVE_BYTES - 1; + static const u32 NATIVE_STEP = _Shift >= 0 ? NATIVE_BYTES << iabs(_Shift) : NATIVE_BYTES >> iabs(_Shift); + static const u32 NATIVE_MASK = NATIVE_STEP - 1; static const u32 NATIVE_BITS = 8 * NATIVE_BYTES; // helpers to simplify core code - u32 read_lookup(offs_t byteaddress) const { return _Large ? m_read.lookup_live_large(byteaddress) : m_read.lookup_live_small(byteaddress); } - u32 write_lookup(offs_t byteaddress) const { return _Large ? m_write.lookup_live_large(byteaddress) : m_write.lookup_live_small(byteaddress); } - u32 setoffset_lookup(offs_t byteaddress) const { return _Large ? m_setoffset.lookup_live_large(byteaddress) : m_setoffset.lookup_live_small(byteaddress); } + u32 read_lookup(offs_t address) const { return _Large ? m_read.lookup_live_large(address) : m_read.lookup_live_small(address); } + u32 write_lookup(offs_t address) const { return _Large ? m_write.lookup_live_large(address) : m_write.lookup_live_small(address); } + u32 setoffset_lookup(offs_t address) const { return _Large ? m_setoffset.lookup_live_large(address) : m_setoffset.lookup_live_small(address); } + + static inline offs_t offset_to_byte(offs_t offset) { return _Shift < 0 ? offset << iabs(_Shift) : offset >> iabs(_Shift); } public: // construction/destruction @@ -1064,31 +1070,31 @@ public: } // return a pointer to the read bank, or nullptr if none - virtual void *get_read_ptr(offs_t byteaddress) override + virtual void *get_read_ptr(offs_t address) override { // perform the lookup - byteaddress &= m_bytemask; - u32 entry = read_lookup(byteaddress); + address &= m_addrmask; + u32 entry = read_lookup(address); const handler_entry_read &handler = m_read.handler_read(entry); // 8-bit case: RAM/ROM if (entry > STATIC_BANKMAX) return nullptr; - return handler.ramptr(handler.byteoffset(byteaddress)); + return handler.ramptr(handler.offset(address)); } // return a pointer to the write bank, or nullptr if none - virtual void *get_write_ptr(offs_t byteaddress) override + virtual void *get_write_ptr(offs_t address) override { // perform the lookup - byteaddress &= m_bytemask; - u32 entry = write_lookup(byteaddress); + address &= m_addrmask; + u32 entry = write_lookup(address); const handler_entry_write &handler = m_write.handler_write(entry); // 8-bit case: RAM/ROM if (entry > STATIC_BANKMAX) return nullptr; - return handler.ramptr(handler.byteoffset(byteaddress)); + return handler.ramptr(handler.offset(address)); } // native read @@ -1099,12 +1105,12 @@ public: if (TEST_HANDLER) printf("[r%X,%s]", offset, core_i64_hex_format(mask, sizeof(_NativeType) * 2)); // look up the handler - offs_t byteaddress = offset & m_bytemask; - u32 entry = read_lookup(byteaddress); + offs_t address = offset & m_addrmask; + u32 entry = read_lookup(address); const handler_entry_read &handler = m_read.handler_read(entry); // either read directly from RAM, or call the delegate - offset = handler.byteoffset(byteaddress); + offset = offset_to_byte(handler.offset(address)); _NativeType result; if (entry <= STATIC_BANKMAX) result = *reinterpret_cast<_NativeType *>(handler.ramptr(offset)); else if (sizeof(_NativeType) == 1) result = handler.read8(*this, offset, mask); @@ -1124,12 +1130,12 @@ public: if (TEST_HANDLER) printf("[r%X]", offset); // look up the handler - offs_t byteaddress = offset & m_bytemask; - u32 entry = read_lookup(byteaddress); + offs_t address = offset & m_addrmask; + u32 entry = read_lookup(address); const handler_entry_read &handler = m_read.handler_read(entry); // either read directly from RAM, or call the delegate - offset = handler.byteoffset(byteaddress); + offset = offset_to_byte(handler.offset(address)); _NativeType result; if (entry <= STATIC_BANKMAX) result = *reinterpret_cast<_NativeType *>(handler.ramptr(offset)); else if (sizeof(_NativeType) == 1) result = handler.read8(*this, offset, 0xff); @@ -1147,12 +1153,12 @@ public: g_profiler.start(PROFILER_MEMWRITE); // look up the handler - offs_t byteaddress = offset & m_bytemask; - u32 entry = write_lookup(byteaddress); + offs_t address = offset & m_addrmask; + u32 entry = write_lookup(address); const handler_entry_write &handler = m_write.handler_write(entry); // either write directly to RAM, or call the delegate - offset = handler.byteoffset(byteaddress); + offset = offset_to_byte(handler.offset(address)); if (entry <= STATIC_BANKMAX) { _NativeType *dest = reinterpret_cast<_NativeType *>(handler.ramptr(offset)); @@ -1172,12 +1178,12 @@ public: g_profiler.start(PROFILER_MEMWRITE); // look up the handler - offs_t byteaddress = offset & m_bytemask; - u32 entry = write_lookup(byteaddress); + offs_t address = offset & m_addrmask; + u32 entry = write_lookup(address); const handler_entry_write &handler = m_write.handler_write(entry); // either write directly to RAM, or call the delegate - offset = handler.byteoffset(byteaddress); + offset = offset_to_byte(handler.offset(address)); if (entry <= STATIC_BANKMAX) *reinterpret_cast<_NativeType *>(handler.ramptr(offset)) = data; else if (sizeof(_NativeType) == 1) handler.write8(*this, offset, data, 0xff); else if (sizeof(_NativeType) == 2) handler.write16(*this, offset >> 1, data, 0xffff); @@ -1201,7 +1207,7 @@ public: // if native size is larger, see if we can do a single masked read (guaranteed if we're aligned) if (NATIVE_BYTES > TARGET_BYTES) { - u32 offsbits = 8 * (address & (NATIVE_BYTES - (_Aligned ? TARGET_BYTES : 1))); + u32 offsbits = 8 * (offset_to_byte(address) & (NATIVE_BYTES - (_Aligned ? TARGET_BYTES : 1))); if (_Aligned || (offsbits + TARGET_BITS <= NATIVE_BITS)) { if (_Endian != ENDIANNESS_LITTLE) offsbits = NATIVE_BITS - TARGET_BITS - offsbits; @@ -1210,7 +1216,7 @@ public: } // determine our alignment against the native boundaries, and mask the address - u32 offsbits = 8 * (address & (NATIVE_BYTES - 1)); + u32 offsbits = 8 * (offset_to_byte(address) & (NATIVE_BYTES - 1)); address &= ~NATIVE_MASK; // if we're here, and native size is larger or equal to the target, we need exactly 2 reads @@ -1227,7 +1233,7 @@ public: // read upper bits from upper address offsbits = NATIVE_BITS - offsbits; curmask = mask >> offsbits; - if (curmask != 0) result |= read_native(address + NATIVE_BYTES, curmask) << offsbits; + if (curmask != 0) result |= read_native(address + NATIVE_STEP, curmask) << offsbits; return result; } @@ -1246,7 +1252,7 @@ public: // read lower bits from upper address curmask = ljmask << offsbits; - if (curmask != 0) result |= read_native(address + NATIVE_BYTES, curmask) >> offsbits; + if (curmask != 0) result |= read_native(address + NATIVE_STEP, curmask) >> offsbits; // return the un-justified result return result >> LEFT_JUSTIFY_TARGET_TO_NATIVE_SHIFT; @@ -1272,7 +1278,7 @@ public: offsbits = NATIVE_BITS - offsbits; for (u32 index = 0; index < MAX_SPLITS_MINUS_ONE; index++) { - address += NATIVE_BYTES; + address += NATIVE_STEP; curmask = mask >> offsbits; if (curmask != 0) result |= (_TargetType)read_native(address, curmask) << offsbits; offsbits += NATIVE_BITS; @@ -1282,7 +1288,7 @@ public: if (!_Aligned && offsbits < TARGET_BITS) { curmask = mask >> offsbits; - if (curmask != 0) result |= (_TargetType)read_native(address + NATIVE_BYTES, curmask) << offsbits; + if (curmask != 0) result |= (_TargetType)read_native(address + NATIVE_STEP, curmask) << offsbits; } } @@ -1298,7 +1304,7 @@ public: for (u32 index = 0; index < MAX_SPLITS_MINUS_ONE; index++) { offsbits -= NATIVE_BITS; - address += NATIVE_BYTES; + address += NATIVE_STEP; curmask = mask >> offsbits; if (curmask != 0) result |= (_TargetType)read_native(address, curmask) << offsbits; } @@ -1308,7 +1314,7 @@ public: { offsbits = NATIVE_BITS - offsbits; curmask = mask << offsbits; - if (curmask != 0) result |= read_native(address + NATIVE_BYTES, curmask) >> offsbits; + if (curmask != 0) result |= read_native(address + NATIVE_STEP, curmask) >> offsbits; } } return result; @@ -1329,7 +1335,7 @@ public: // if native size is larger, see if we can do a single masked write (guaranteed if we're aligned) if (NATIVE_BYTES > TARGET_BYTES) { - u32 offsbits = 8 * (address & (NATIVE_BYTES - (_Aligned ? TARGET_BYTES : 1))); + u32 offsbits = 8 * (offset_to_byte(address) & (NATIVE_BYTES - (_Aligned ? TARGET_BYTES : 1))); if (_Aligned || (offsbits + TARGET_BITS <= NATIVE_BITS)) { if (_Endian != ENDIANNESS_LITTLE) offsbits = NATIVE_BITS - TARGET_BITS - offsbits; @@ -1338,7 +1344,7 @@ public: } // determine our alignment against the native boundaries, and mask the address - u32 offsbits = 8 * (address & (NATIVE_BYTES - 1)); + u32 offsbits = 8 * (offset_to_byte(address) & (NATIVE_BYTES - 1)); address &= ~NATIVE_MASK; // if we're here, and native size is larger or equal to the target, we need exactly 2 writes @@ -1354,7 +1360,7 @@ public: // write upper bits to upper address offsbits = NATIVE_BITS - offsbits; curmask = mask >> offsbits; - if (curmask != 0) write_native(address + NATIVE_BYTES, data >> offsbits, curmask); + if (curmask != 0) write_native(address + NATIVE_STEP, data >> offsbits, curmask); } // big-endian case @@ -1372,7 +1378,7 @@ public: // write lower bits to upper address offsbits = NATIVE_BITS - offsbits; curmask = ljmask << offsbits; - if (curmask != 0) write_native(address + NATIVE_BYTES, ljdata << offsbits, curmask); + if (curmask != 0) write_native(address + NATIVE_STEP, ljdata << offsbits, curmask); } } @@ -1394,7 +1400,7 @@ public: offsbits = NATIVE_BITS - offsbits; for (u32 index = 0; index < MAX_SPLITS_MINUS_ONE; index++) { - address += NATIVE_BYTES; + address += NATIVE_STEP; curmask = mask >> offsbits; if (curmask != 0) write_native(address, data >> offsbits, curmask); offsbits += NATIVE_BITS; @@ -1404,7 +1410,7 @@ public: if (!_Aligned && offsbits < TARGET_BITS) { curmask = mask >> offsbits; - if (curmask != 0) write_native(address + NATIVE_BYTES, data >> offsbits, curmask); + if (curmask != 0) write_native(address + NATIVE_STEP, data >> offsbits, curmask); } } @@ -1420,7 +1426,7 @@ public: for (u32 index = 0; index < MAX_SPLITS_MINUS_ONE; index++) { offsbits -= NATIVE_BITS; - address += NATIVE_BYTES; + address += NATIVE_STEP; curmask = mask >> offsbits; if (curmask != 0) write_native(address, data >> offsbits, curmask); } @@ -1430,7 +1436,7 @@ public: { offsbits = NATIVE_BITS - offsbits; curmask = mask << offsbits; - if (curmask != 0) write_native(address + NATIVE_BYTES, data << offsbits, curmask); + if (curmask != 0) write_native(address + NATIVE_STEP, data << offsbits, curmask); } } } @@ -1441,11 +1447,11 @@ public: // to some particular set_offset operation for an entry in the address map. void set_address(offs_t address) override { - offs_t byteaddress = address & m_bytemask; - u32 entry = setoffset_lookup(byteaddress); + address &= m_addrmask; + u32 entry = setoffset_lookup(address); const handler_entry_setoffset &handler = m_setoffset.handler_setoffset(entry); - offs_t offset = handler.byteoffset(byteaddress); + offs_t offset = handler.offset(address); handler.setoffset(*this, offset / sizeof(_NativeType)); } @@ -1499,23 +1505,52 @@ public: address_table_setoffset m_setoffset; // memory setoffset lookup table }; -typedef address_space_specific<u8, ENDIANNESS_LITTLE, false> address_space_8le_small; -typedef address_space_specific<u8, ENDIANNESS_BIG, false> address_space_8be_small; -typedef address_space_specific<u16, ENDIANNESS_LITTLE, false> address_space_16le_small; -typedef address_space_specific<u16, ENDIANNESS_BIG, false> address_space_16be_small; -typedef address_space_specific<u32, ENDIANNESS_LITTLE, false> address_space_32le_small; -typedef address_space_specific<u32, ENDIANNESS_BIG, false> address_space_32be_small; -typedef address_space_specific<u64, ENDIANNESS_LITTLE, false> address_space_64le_small; -typedef address_space_specific<u64, ENDIANNESS_BIG, false> address_space_64be_small; +typedef address_space_specific<u8, ENDIANNESS_LITTLE, 0, false> address_space_8_8le_small; +typedef address_space_specific<u8, ENDIANNESS_BIG, 0, false> address_space_8_8be_small; +typedef address_space_specific<u16, ENDIANNESS_LITTLE, 3, false> address_space_16_1le_small; +typedef address_space_specific<u16, ENDIANNESS_BIG, 3, false> address_space_16_1be_small; +typedef address_space_specific<u16, ENDIANNESS_LITTLE, 0, false> address_space_16_8le_small; +typedef address_space_specific<u16, ENDIANNESS_BIG, 0, false> address_space_16_8be_small; +typedef address_space_specific<u16, ENDIANNESS_LITTLE, -1, false> address_space_16_16le_small; +typedef address_space_specific<u16, ENDIANNESS_BIG, -1, false> address_space_16_16be_small; +typedef address_space_specific<u32, ENDIANNESS_LITTLE, 0, false> address_space_32_8le_small; +typedef address_space_specific<u32, ENDIANNESS_BIG, 0, false> address_space_32_8be_small; +typedef address_space_specific<u32, ENDIANNESS_LITTLE, -1, false> address_space_32_16le_small; +typedef address_space_specific<u32, ENDIANNESS_BIG, -1, false> address_space_32_16be_small; +typedef address_space_specific<u32, ENDIANNESS_LITTLE, -2, false> address_space_32_32le_small; +typedef address_space_specific<u32, ENDIANNESS_BIG, -2, false> address_space_32_32be_small; +typedef address_space_specific<u64, ENDIANNESS_LITTLE, 0, false> address_space_64_8le_small; +typedef address_space_specific<u64, ENDIANNESS_BIG, 0, false> address_space_64_8be_small; +typedef address_space_specific<u64, ENDIANNESS_LITTLE, -1, false> address_space_64_16le_small; +typedef address_space_specific<u64, ENDIANNESS_BIG, -1, false> address_space_64_16be_small; +typedef address_space_specific<u64, ENDIANNESS_LITTLE, -2, false> address_space_64_32le_small; +typedef address_space_specific<u64, ENDIANNESS_BIG, -2, false> address_space_64_32be_small; +typedef address_space_specific<u64, ENDIANNESS_LITTLE, -3, false> address_space_64_64le_small; +typedef address_space_specific<u64, ENDIANNESS_BIG, -3, false> address_space_64_64be_small; + +typedef address_space_specific<u8, ENDIANNESS_LITTLE, 0, true> address_space_8_8le_large; +typedef address_space_specific<u8, ENDIANNESS_BIG, 0, true> address_space_8_8be_large; +typedef address_space_specific<u16, ENDIANNESS_LITTLE, 3, true> address_space_16_1le_large; +typedef address_space_specific<u16, ENDIANNESS_BIG, 3, true> address_space_16_1be_large; +typedef address_space_specific<u16, ENDIANNESS_LITTLE, 0, true> address_space_16_8le_large; +typedef address_space_specific<u16, ENDIANNESS_BIG, 0, true> address_space_16_8be_large; +typedef address_space_specific<u16, ENDIANNESS_LITTLE, -1, true> address_space_16_16le_large; +typedef address_space_specific<u16, ENDIANNESS_BIG, -1, true> address_space_16_16be_large; +typedef address_space_specific<u32, ENDIANNESS_LITTLE, 0, true> address_space_32_8le_large; +typedef address_space_specific<u32, ENDIANNESS_BIG, 0, true> address_space_32_8be_large; +typedef address_space_specific<u32, ENDIANNESS_LITTLE, -1, true> address_space_32_16le_large; +typedef address_space_specific<u32, ENDIANNESS_BIG, -1, true> address_space_32_16be_large; +typedef address_space_specific<u32, ENDIANNESS_LITTLE, -2, true> address_space_32_32le_large; +typedef address_space_specific<u32, ENDIANNESS_BIG, -2, true> address_space_32_32be_large; +typedef address_space_specific<u64, ENDIANNESS_LITTLE, 0, true> address_space_64_8le_large; +typedef address_space_specific<u64, ENDIANNESS_BIG, 0, true> address_space_64_8be_large; +typedef address_space_specific<u64, ENDIANNESS_LITTLE, -1, true> address_space_64_16le_large; +typedef address_space_specific<u64, ENDIANNESS_BIG, -1, true> address_space_64_16be_large; +typedef address_space_specific<u64, ENDIANNESS_LITTLE, -2, true> address_space_64_32le_large; +typedef address_space_specific<u64, ENDIANNESS_BIG, -2, true> address_space_64_32be_large; +typedef address_space_specific<u64, ENDIANNESS_LITTLE, -3, true> address_space_64_64le_large; +typedef address_space_specific<u64, ENDIANNESS_BIG, -3, true> address_space_64_64be_large; -typedef address_space_specific<u8, ENDIANNESS_LITTLE, true> address_space_8le_large; -typedef address_space_specific<u8, ENDIANNESS_BIG, true> address_space_8be_large; -typedef address_space_specific<u16, ENDIANNESS_LITTLE, true> address_space_16le_large; -typedef address_space_specific<u16, ENDIANNESS_BIG, true> address_space_16be_large; -typedef address_space_specific<u32, ENDIANNESS_LITTLE, true> address_space_32le_large; -typedef address_space_specific<u32, ENDIANNESS_BIG, true> address_space_32be_large; -typedef address_space_specific<u64, ENDIANNESS_LITTLE, true> address_space_64le_large; -typedef address_space_specific<u64, ENDIANNESS_BIG, true> address_space_64be_large; @@ -1574,72 +1609,206 @@ void memory_manager::allocate(device_memory_interface &memory) if (spaceconfig->endianness() == ENDIANNESS_LITTLE) { if (large) - memory.allocate<address_space_8le_large>(*this, spacenum); + memory.allocate<address_space_8_8le_large>(*this, spacenum); else - memory.allocate<address_space_8le_small>(*this, spacenum); + memory.allocate<address_space_8_8le_small>(*this, spacenum); } else { if (large) - memory.allocate<address_space_8be_large>(*this, spacenum); + memory.allocate<address_space_8_8be_large>(*this, spacenum); else - memory.allocate<address_space_8be_small>(*this, spacenum); + memory.allocate<address_space_8_8be_small>(*this, spacenum); } break; - + case 16: - if (spaceconfig->endianness() == ENDIANNESS_LITTLE) + switch (spaceconfig->addrbus_shift()) { - if (large) - memory.allocate<address_space_16le_large>(*this, spacenum); + case 3: + if (spaceconfig->endianness() == ENDIANNESS_LITTLE) + { + if (large) + memory.allocate<address_space_16_1le_large>(*this, spacenum); + else + memory.allocate<address_space_16_1le_small>(*this, spacenum); + } else - memory.allocate<address_space_16le_small>(*this, spacenum); - } - else - { - if (large) - memory.allocate<address_space_16be_large>(*this, spacenum); + { + if (large) + memory.allocate<address_space_16_1be_large>(*this, spacenum); + else + memory.allocate<address_space_16_1be_small>(*this, spacenum); + } + break; + + case 0: + if (spaceconfig->endianness() == ENDIANNESS_LITTLE) + { + if (large) + memory.allocate<address_space_16_8le_large>(*this, spacenum); + else + memory.allocate<address_space_16_8le_small>(*this, spacenum); + } else - memory.allocate<address_space_16be_small>(*this, spacenum); + { + if (large) + memory.allocate<address_space_16_8be_large>(*this, spacenum); + else + memory.allocate<address_space_16_8be_small>(*this, spacenum); + } + break; + + case -1: + if (spaceconfig->endianness() == ENDIANNESS_LITTLE) + { + if (large) + memory.allocate<address_space_16_16le_large>(*this, spacenum); + else + memory.allocate<address_space_16_16le_small>(*this, spacenum); + } + else + { + if (large) + memory.allocate<address_space_16_16be_large>(*this, spacenum); + else + memory.allocate<address_space_16_16be_small>(*this, spacenum); + } + break; } break; - + case 32: - if (spaceconfig->endianness() == ENDIANNESS_LITTLE) + switch (spaceconfig->addrbus_shift()) { - if (large) - memory.allocate<address_space_32le_large>(*this, spacenum); + case 0: + if (spaceconfig->endianness() == ENDIANNESS_LITTLE) + { + if (large) + memory.allocate<address_space_32_8le_large>(*this, spacenum); + else + memory.allocate<address_space_32_8le_small>(*this, spacenum); + } else - memory.allocate<address_space_32le_small>(*this, spacenum); - } - else - { - if (large) - memory.allocate<address_space_32be_large>(*this, spacenum); + { + if (large) + memory.allocate<address_space_32_8be_large>(*this, spacenum); + else + memory.allocate<address_space_32_8be_small>(*this, spacenum); + } + break; + + case -1: + if (spaceconfig->endianness() == ENDIANNESS_LITTLE) + { + if (large) + memory.allocate<address_space_32_16le_large>(*this, spacenum); + else + memory.allocate<address_space_32_16le_small>(*this, spacenum); + } else - memory.allocate<address_space_32be_small>(*this, spacenum); + { + if (large) + memory.allocate<address_space_32_16be_large>(*this, spacenum); + else + memory.allocate<address_space_32_16be_small>(*this, spacenum); + } + break; + + case -2: + if (spaceconfig->endianness() == ENDIANNESS_LITTLE) + { + if (large) + memory.allocate<address_space_32_32le_large>(*this, spacenum); + else + memory.allocate<address_space_32_32le_small>(*this, spacenum); + } + else + { + if (large) + memory.allocate<address_space_32_32be_large>(*this, spacenum); + else + memory.allocate<address_space_32_32be_small>(*this, spacenum); + } + break; } break; - + case 64: - if (spaceconfig->endianness() == ENDIANNESS_LITTLE) + switch (spaceconfig->addrbus_shift()) { - if (large) - memory.allocate<address_space_64le_large>(*this, spacenum); + case 0: + if (spaceconfig->endianness() == ENDIANNESS_LITTLE) + { + if (large) + memory.allocate<address_space_64_8le_large>(*this, spacenum); + else + memory.allocate<address_space_64_8le_small>(*this, spacenum); + } else - memory.allocate<address_space_64le_small>(*this, spacenum); - } - else - { - if (large) - memory.allocate<address_space_64be_large>(*this, spacenum); + { + if (large) + memory.allocate<address_space_64_8be_large>(*this, spacenum); + else + memory.allocate<address_space_64_8be_small>(*this, spacenum); + } + break; + + case -1: + if (spaceconfig->endianness() == ENDIANNESS_LITTLE) + { + if (large) + memory.allocate<address_space_64_16le_large>(*this, spacenum); + else + memory.allocate<address_space_64_16le_small>(*this, spacenum); + } + else + { + if (large) + memory.allocate<address_space_64_16be_large>(*this, spacenum); + else + memory.allocate<address_space_64_16be_small>(*this, spacenum); + } + break; + + case -2: + if (spaceconfig->endianness() == ENDIANNESS_LITTLE) + { + if (large) + memory.allocate<address_space_64_32le_large>(*this, spacenum); + else + memory.allocate<address_space_64_32le_small>(*this, spacenum); + } + else + { + if (large) + memory.allocate<address_space_64_32be_large>(*this, spacenum); + else + memory.allocate<address_space_64_32be_small>(*this, spacenum); + } + break; + + case -3: + if (spaceconfig->endianness() == ENDIANNESS_LITTLE) + { + if (large) + memory.allocate<address_space_64_64le_large>(*this, spacenum); + else + memory.allocate<address_space_64_64le_small>(*this, spacenum); + } else - memory.allocate<address_space_64be_small>(*this, spacenum); + { + if (large) + memory.allocate<address_space_64_64be_large>(*this, spacenum); + else + memory.allocate<address_space_64_64be_small>(*this, spacenum); + } + break; } break; - + default: - throw emu_fatalerror("Invalid width %d specified for memory_manager::allocate", spaceconfig->data_width()); + throw emu_fatalerror("Invalid width %d specified for address_space::allocate", spaceconfig->data_width()); } } } @@ -1786,19 +1955,24 @@ address_space::address_space(memory_manager &manager, device_memory_interface &m : m_config(*memory.space_config(spacenum)), m_device(memory.device()), m_addrmask(0xffffffffUL >> (32 - m_config.m_addrbus_width)), - m_bytemask(address_to_byte_end(m_addrmask)), m_logaddrmask(0xffffffffUL >> (32 - m_config.m_logaddr_width)), - m_logbytemask(address_to_byte_end(m_logaddrmask)), m_unmap(0), m_spacenum(spacenum), m_log_unmap(true), - m_direct(std::make_unique<direct_read_data>(*this)), m_name(memory.space_config(spacenum)->name()), m_addrchars((m_config.m_addrbus_width + 3) / 4), m_logaddrchars((m_config.m_logaddr_width + 3) / 4), m_manager(manager), m_machine(memory.device().machine()) { + switch(m_config.addrbus_shift()) { + case 3: m_direct = static_cast<void *>(new direct_read_data< 3>(*this)); break; + case 0: m_direct = static_cast<void *>(new direct_read_data< 0>(*this)); break; + case -1: m_direct = static_cast<void *>(new direct_read_data<-1>(*this)); break; + case -2: m_direct = static_cast<void *>(new direct_read_data<-2>(*this)); break; + case -3: m_direct = static_cast<void *>(new direct_read_data<-3>(*this)); break; + default: fatalerror("Unsupported address shift %d\n", m_config.addrbus_shift()); + } } @@ -1808,6 +1982,13 @@ address_space::address_space(memory_manager &manager, device_memory_interface &m address_space::~address_space() { + switch(m_config.addrbus_shift()) { + case 3: delete static_cast<direct_read_data< 3> *>(m_direct); break; + case 0: delete static_cast<direct_read_data< 0> *>(m_direct); break; + case -1: delete static_cast<direct_read_data<-1> *>(m_direct); break; + case -2: delete static_cast<direct_read_data<-2> *>(m_direct); break; + case -3: delete static_cast<direct_read_data<-3> *>(m_direct); break; + } } @@ -1822,12 +2003,6 @@ inline void address_space::adjust_addresses(offs_t &start, offs_t &end, offs_t & mask &= m_addrmask; start &= ~mirror & m_addrmask; end &= ~mirror & m_addrmask; - - // adjust to byte values - start = address_to_byte(start); - end = address_to_byte_end(end); - mask = address_to_byte_end(mask); - mirror = address_to_byte(mirror); } void address_space::check_optimize_all(const char *function, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, offs_t &nstart, offs_t &nend, offs_t &nmask, offs_t &nmirror) @@ -1978,20 +2153,13 @@ void address_space::prepare_map() // extract global parameters specified by the map m_unmap = (m_map->m_unmapval == 0) ? 0 : ~0; if (m_map->m_globalmask != 0) - { m_addrmask = m_map->m_globalmask; - m_bytemask = address_to_byte_end(m_addrmask); - } // make a pass over the address map, adjusting for the device and getting memory pointers for (address_map_entry &entry : m_map->m_entrylist) { // computed adjusted addresses first - entry.m_bytestart = entry.m_addrstart; - entry.m_byteend = entry.m_addrend; - entry.m_bytemirror = entry.m_addrmirror; - entry.m_bytemask = entry.m_addrmask ? entry.m_addrmask : ~entry.m_addrmirror; - adjust_addresses(entry.m_bytestart, entry.m_byteend, entry.m_bytemask, entry.m_bytemirror); + adjust_addresses(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror); // if we have a share entry, add it to our map if (entry.m_share != nullptr) @@ -2000,8 +2168,8 @@ void address_space::prepare_map() std::string fulltag = entry.m_devbase.subtag(entry.m_share); if (manager().m_sharelist.find(fulltag.c_str()) == manager().m_sharelist.end()) { - VPRINTF(("Creating share '%s' of length 0x%X\n", fulltag.c_str(), entry.m_byteend + 1 - entry.m_bytestart)); - manager().m_sharelist.emplace(fulltag.c_str(), std::make_unique<memory_share>(m_map->m_databits, entry.m_byteend + 1 - entry.m_bytestart, endianness())); + VPRINTF(("Creating share '%s' of length 0x%X\n", fulltag.c_str(), entry.m_addrend + 1 - entry.m_addrstart)); + manager().m_sharelist.emplace(fulltag.c_str(), std::make_unique<memory_share>(m_map->m_databits, entry.m_addrend + 1 - entry.m_addrstart, endianness())); } } @@ -2009,10 +2177,10 @@ void address_space::prepare_map() if (m_spacenum == 0 && entry.m_read.m_type == AMH_ROM && entry.m_region == nullptr) { // make sure it fits within the memory region before doing so, however - if (entry.m_byteend < devregionsize) + if (entry.m_addrend < devregionsize) { entry.m_region = m_device.tag(); - entry.m_rgnoffs = entry.m_bytestart; + entry.m_rgnoffs = address_to_byte(entry.m_addrstart); } } @@ -2028,7 +2196,7 @@ void address_space::prepare_map() fatalerror("device '%s' %s space memory map entry %X-%X references non-existant region \"%s\"\n", m_device.tag(), m_name, entry.m_addrstart, entry.m_addrend, entry.m_region); // validate the region - if (entry.m_rgnoffs + (entry.m_byteend - entry.m_bytestart + 1) > region->bytes()) + if (entry.m_rgnoffs + m_config.addr2byte(entry.m_addrend - entry.m_addrstart + 1) > region->bytes()) fatalerror("device '%s' %s space memory map entry %X-%X extends beyond region \"%s\" size (%X)\n", m_device.tag(), m_name, entry.m_addrstart, entry.m_addrend, entry.m_region, region->bytes()); } @@ -2044,8 +2212,8 @@ void address_space::prepare_map() } // now loop over all the handlers and enforce the address mask - read().mask_all_handlers(m_bytemask); - write().mask_all_handlers(m_bytemask); + read().mask_all_handlers(m_addrmask); + write().mask_all_handlers(m_addrmask); } @@ -2176,13 +2344,13 @@ void address_space::allocate_memory() int tail = blocklist.size(); for (address_map_entry &entry : m_map->m_entrylist) if (entry.m_memory != nullptr) - blocklist.push_back(std::make_unique<memory_block>(*this, entry.m_bytestart, entry.m_byteend, entry.m_memory)); + blocklist.push_back(std::make_unique<memory_block>(*this, entry.m_addrstart, entry.m_addrend, entry.m_memory)); // loop over all blocks just allocated and assign pointers from them address_map_entry *unassigned = nullptr; for (auto memblock = blocklist.begin() + tail; memblock != blocklist.end(); ++memblock) - unassigned = block_assign_intersecting(memblock->get()->bytestart(), memblock->get()->byteend(), memblock->get()->data()); + unassigned = block_assign_intersecting(memblock->get()->addrstart(), memblock->get()->addrend(), memblock->get()->data()); // if we don't have an unassigned pointer yet, try to find one if (unassigned == nullptr) @@ -2192,8 +2360,8 @@ void address_space::allocate_memory() while (unassigned != nullptr) { // work in MEMORY_BLOCK_CHUNK-sized chunks - offs_t curblockstart = unassigned->m_bytestart / MEMORY_BLOCK_CHUNK; - offs_t curblockend = unassigned->m_byteend / MEMORY_BLOCK_CHUNK; + offs_t curblockstart = unassigned->m_addrstart / MEMORY_BLOCK_CHUNK; + offs_t curblockend = unassigned->m_addrend / MEMORY_BLOCK_CHUNK; // loop while we keep finding unassigned blocks in neighboring MEMORY_BLOCK_CHUNK chunks bool changed; @@ -2206,8 +2374,8 @@ void address_space::allocate_memory() if (entry.m_memory == nullptr && &entry != unassigned && needs_backing_store(entry)) { // get block start/end blocks for this block - offs_t blockstart = entry.m_bytestart / MEMORY_BLOCK_CHUNK; - offs_t blockend = entry.m_byteend / MEMORY_BLOCK_CHUNK; + offs_t blockstart = entry.m_addrstart / MEMORY_BLOCK_CHUNK; + offs_t blockend = entry.m_addrend / MEMORY_BLOCK_CHUNK; // if we intersect or are adjacent, adjust the start/end if (blockstart <= curblockend + 1 && blockend >= curblockstart - 1) @@ -2221,12 +2389,12 @@ void address_space::allocate_memory() } while (changed); // we now have a block to allocate; do it - offs_t curbytestart = curblockstart * MEMORY_BLOCK_CHUNK; - offs_t curbyteend = curblockend * MEMORY_BLOCK_CHUNK + (MEMORY_BLOCK_CHUNK - 1); - auto block = std::make_unique<memory_block>(*this, curbytestart, curbyteend); + offs_t curaddrstart = curblockstart * MEMORY_BLOCK_CHUNK; + offs_t curaddrend = curblockend * MEMORY_BLOCK_CHUNK + (MEMORY_BLOCK_CHUNK - 1); + auto block = std::make_unique<memory_block>(*this, curaddrstart, curaddrend); // assign memory that intersected the new block - unassigned = block_assign_intersecting(curbytestart, curbyteend, block.get()->data()); + unassigned = block_assign_intersecting(curaddrstart, curaddrend, block.get()->data()); blocklist.push_back(std::move(block)); } } @@ -2245,7 +2413,7 @@ void address_space::locate_memory() { // set the initial bank pointer for (address_map_entry &entry : m_map->m_entrylist) - if (entry.m_bytestart == bank.second->bytestart() && entry.m_memory != nullptr) + if (entry.m_addrstart == bank.second->addrstart() && entry.m_memory != nullptr) { bank.second->set_base(entry.m_memory); VPRINTF(("assigned bank '%s' pointer to memory from range %08X-%08X [%p]\n", bank.second->tag(), entry.m_addrstart, entry.m_addrend, entry.m_memory)); @@ -2266,7 +2434,7 @@ void address_space::locate_memory() // intersecting blocks and assign their pointers //------------------------------------------------- -address_map_entry *address_space::block_assign_intersecting(offs_t bytestart, offs_t byteend, u8 *base) +address_map_entry *address_space::block_assign_intersecting(offs_t addrstart, offs_t addrend, u8 *base) { address_map_entry *unassigned = nullptr; @@ -2290,10 +2458,10 @@ address_map_entry *address_space::block_assign_intersecting(offs_t bytestart, of } // otherwise, look for a match in this block - if (entry.m_memory == nullptr && entry.m_bytestart >= bytestart && entry.m_byteend <= byteend) + if (entry.m_memory == nullptr && entry.m_addrstart >= addrstart && entry.m_addrend <= addrend) { - entry.m_memory = base + (entry.m_bytestart - bytestart); - VPRINTF(("memory range %08X-%08X -> found in block from %08X-%08X [%p]\n", entry.m_addrstart, entry.m_addrend, bytestart, byteend, entry.m_memory)); + entry.m_memory = base + m_config.addr2byte(entry.m_addrstart - addrstart); + VPRINTF(("memory range %08X-%08X -> found in block from %08X-%08X [%p]\n", entry.m_addrstart, entry.m_addrend, addrstart, addrend, entry.m_memory)); } // if we're the first match on a shared pointer, assign it now @@ -2322,12 +2490,12 @@ address_map_entry *address_space::block_assign_intersecting(offs_t bytestart, of // describing the handler at a particular offset //------------------------------------------------- -const char *address_space::get_handler_string(read_or_write readorwrite, offs_t byteaddress) +const char *address_space::get_handler_string(read_or_write readorwrite, offs_t address) { if (readorwrite == read_or_write::READ) - return read().handler_name(read().lookup(byteaddress)); + return read().handler_name(read().lookup(address)); else - return write().handler_name(write().lookup(byteaddress)); + return write().handler_name(write().lookup(address)); } @@ -2343,17 +2511,17 @@ void address_space::dump_map(FILE *file, read_or_write readorwrite) // dump generic information fprintf(file, " Address bits = %d\n", m_config.m_addrbus_width); fprintf(file, " Data bits = %d\n", m_config.m_databus_width); - fprintf(file, " Address mask = %X\n", m_bytemask); + fprintf(file, " Address mask = %X\n", m_addrmask); fprintf(file, "\n"); // iterate over addresses - offs_t bytestart, byteend; - for (offs_t byteaddress = 0; byteaddress <= m_bytemask; byteaddress = byteend) + offs_t addrstart, addrend; + for (offs_t address = 0; address <= m_addrmask; address = addrend) { - u16 entry = table.derive_range(byteaddress, bytestart, byteend); + u16 entry = table.derive_range(address, addrstart, addrend); fprintf(file, "%08X-%08X = %02X: %s [offset=%08X]\n", - bytestart, byteend, entry, table.handler_name(entry), table.handler(entry).bytestart()); - if (++byteend == 0) + addrstart, addrend, entry, table.handler_name(entry), table.handler(entry).addrstart()); + if (++addrend == 0) break; } } @@ -2549,7 +2717,7 @@ void address_space::install_ram_generic(offs_t addrstart, offs_t addrend, offs_t { if (machine().phase() >= machine_phase::RESET) fatalerror("Attempted to call install_ram_generic() after initialization time without a baseptr!\n"); - auto block = std::make_unique<memory_block>(*this, address_to_byte(addrstart), address_to_byte_end(addrend)); + auto block = std::make_unique<memory_block>(*this, addrstart, addrend); bank.set_base(block.get()->data()); manager().m_blocklist.push_back(std::move(block)); } @@ -2739,10 +2907,7 @@ void address_space::install_setoffset_handler(offs_t addrstart, offs_t addrend, void *address_space::find_backing_memory(offs_t addrstart, offs_t addrend) { - offs_t bytestart = address_to_byte(addrstart); - offs_t byteend = address_to_byte_end(addrend); - - VPRINTF(("address_space::find_backing_memory('%s',%s,%08X-%08X) -> ", m_device.tag(), m_name, bytestart, byteend)); + VPRINTF(("address_space::find_backing_memory('%s',%s,%08X-%08X) -> ", m_device.tag(), m_name, addrstart, addrend)); if (m_map == nullptr) return nullptr; @@ -2750,21 +2915,19 @@ void *address_space::find_backing_memory(offs_t addrstart, offs_t addrend) // look in the address map first for (address_map_entry &entry : m_map->m_entrylist) { - offs_t maskstart = bytestart & entry.m_bytemask; - offs_t maskend = byteend & entry.m_bytemask; - if (entry.m_memory != nullptr && maskstart >= entry.m_bytestart && maskend <= entry.m_byteend) + if (entry.m_memory != nullptr && addrstart >= entry.m_addrstart && addrend <= entry.m_addrend) { - VPRINTF(("found in entry %08X-%08X [%p]\n", entry.m_addrstart, entry.m_addrend, (u8 *)entry.m_memory + (maskstart - entry.m_bytestart))); - return (u8 *)entry.m_memory + (maskstart - entry.m_bytestart); + VPRINTF(("found in entry %08X-%08X [%p]\n", entry.m_addrstart, entry.m_addrend, (u8 *)entry.m_memory + address_to_byte(addrstart - entry.m_addrstart))); + return (u8 *)entry.m_memory + address_to_byte(addrstart - entry.m_addrstart); } } // if not found there, look in the allocated blocks for (auto &block : manager().m_blocklist) - if (block->contains(*this, bytestart, byteend)) + if (block->contains(*this, addrstart, addrend)) { - VPRINTF(("found in allocated memory block %08X-%08X [%p]\n", block->bytestart(), block->byteend(), block->data() + (bytestart - block->bytestart()))); - return block->data() + bytestart - block->bytestart(); + VPRINTF(("found in allocated memory block %08X-%08X [%p]\n", block->addrstart(), block->addrend(), block->data() + address_to_byte(addrstart - block->addrstart()))); + return block->data() + address_to_byte(addrstart - block->addrstart()); } VPRINTF(("did not find\n")); @@ -2818,11 +2981,8 @@ bool address_space::needs_backing_store(const address_map_entry &entry) memory_bank &address_space::bank_find_or_allocate(const char *tag, offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite) { // adjust the addresses, handling mirrors and such - offs_t bytemirror = addrmirror; - offs_t bytestart = addrstart; - offs_t bytemask = ~addrmirror; - offs_t byteend = addrend; - adjust_addresses(bytestart, byteend, bytemask, bytemirror); + offs_t addrmask = ~addrmirror; + adjust_addresses(addrstart, addrend, addrmask, addrmirror); // look up the bank by name, or else by byte range memory_bank *membank = nullptr; @@ -2832,7 +2992,7 @@ memory_bank &address_space::bank_find_or_allocate(const char *tag, offs_t addrst membank = bank->second.get(); } else { - membank = bank_find_anonymous(bytestart, byteend); + membank = bank_find_anonymous(addrstart, addrend); } // if we don't have a bank yet, find a free one @@ -2845,11 +3005,11 @@ memory_bank &address_space::bank_find_or_allocate(const char *tag, offs_t addrst if (tag != nullptr) throw emu_fatalerror("Unable to allocate new bank '%s'", tag); else - throw emu_fatalerror("Unable to allocate bank for RAM/ROM area %X-%X\n", bytestart, byteend); + throw emu_fatalerror("Unable to allocate bank for RAM/ROM area %X-%X\n", addrstart, addrend); } // if no tag, create a unique one - auto bank = std::make_unique<memory_bank>(*this, banknum, bytestart, byteend, tag); + auto bank = std::make_unique<memory_bank>(*this, banknum, addrstart, addrend, tag); std::string temptag; if (tag == nullptr) { temptag = string_format("anon_%p", bank.get()); @@ -2869,17 +3029,56 @@ memory_bank &address_space::bank_find_or_allocate(const char *tag, offs_t addrst // bank_find_anonymous - try to find an anonymous // bank matching the given byte range //------------------------------------------------- -memory_bank *address_space::bank_find_anonymous(offs_t bytestart, offs_t byteend) const +memory_bank *address_space::bank_find_anonymous(offs_t addrstart, offs_t addrend) const { // try to find an exact match for (auto &bank : manager().banks()) - if (bank.second->anonymous() && bank.second->references_space(*this, read_or_write::READWRITE) && bank.second->matches_exactly(bytestart, byteend)) + if (bank.second->anonymous() && bank.second->references_space(*this, read_or_write::READWRITE) && bank.second->matches_exactly(addrstart, addrend)) return bank.second.get(); // not found return nullptr; } +//------------------------------------------------- +// address_space::invalidate_read_caches -- clear +// the read cache (direct) for a specific entry +// or all of them +//------------------------------------------------- + +void address_space::invalidate_read_caches() +{ + switch(m_config.addrbus_shift()) { + case 3: static_cast<direct_read_data< 3> *>(m_direct)->force_update(); break; + case 0: static_cast<direct_read_data< 0> *>(m_direct)->force_update(); break; + case -1: static_cast<direct_read_data<-1> *>(m_direct)->force_update(); break; + case -2: static_cast<direct_read_data<-2> *>(m_direct)->force_update(); break; + case -3: static_cast<direct_read_data<-3> *>(m_direct)->force_update(); break; + } +} + +void address_space::invalidate_read_caches(u16 entry) +{ + switch(m_config.addrbus_shift()) { + case 3: static_cast<direct_read_data< 3> *>(m_direct)->force_update(entry); break; + case 0: static_cast<direct_read_data< 0> *>(m_direct)->force_update(entry); break; + case -1: static_cast<direct_read_data<-1> *>(m_direct)->force_update(entry); break; + case -2: static_cast<direct_read_data<-2> *>(m_direct)->force_update(entry); break; + case -3: static_cast<direct_read_data<-3> *>(m_direct)->force_update(entry); break; + } +} + +void address_space::invalidate_read_caches(offs_t start, offs_t end) +{ + switch(m_config.addrbus_shift()) { + case 3: static_cast<direct_read_data< 3> *>(m_direct)->remove_intersecting_ranges(start, end); break; + case 0: static_cast<direct_read_data< 0> *>(m_direct)->remove_intersecting_ranges(start, end); break; + case -1: static_cast<direct_read_data<-1> *>(m_direct)->remove_intersecting_ranges(start, end); break; + case -2: static_cast<direct_read_data<-2> *>(m_direct)->remove_intersecting_ranges(start, end); break; + case -3: static_cast<direct_read_data<-3> *>(m_direct)->remove_intersecting_ranges(start, end); break; + } +} + //************************************************************************** // TABLE MANAGEMENT @@ -2935,27 +3134,23 @@ address_table::~address_table() void address_table::map_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u16 entry) { // convert addresses to bytes - offs_t bytestart = addrstart; - offs_t byteend = addrend; - offs_t bytemask = addrmask; - offs_t bytemirror = addrmirror; - m_space.adjust_addresses(bytestart, byteend, bytemask, bytemirror); + m_space.adjust_addresses(addrstart, addrend, addrmask, addrmirror); // validity checks assert_always(addrstart <= addrend, "address_table::map_range called with start greater than end"); - assert_always((bytestart & (m_space.data_width() / 8 - 1)) == 0, "address_table::map_range called with misaligned start address"); - assert_always((byteend & (m_space.data_width() / 8 - 1)) == (m_space.data_width() / 8 - 1), "address_table::map_range called with misaligned end address"); + assert_always((addrstart & (m_space.alignment() - 1)) == 0, "address_table::map_range called with misaligned start address"); + assert_always((addrend & (m_space.alignment() - 1)) == (m_space.alignment() - 1), "address_table::map_range called with misaligned end address"); // configure the entry to our parameters (but not for static non-banked cases) handler_entry &curentry = handler(entry); if (entry <= STATIC_BANKMAX || entry >= STATIC_COUNT) - curentry.configure(bytestart, byteend, bytemask); + curentry.configure(addrstart, addrend, addrmask, m_space.address_to_byte_end(addrmask)); // populate it - populate_range_mirrored(bytestart, byteend, bytemirror, entry); + populate_range_mirrored(addrstart, addrend, addrmirror, entry); // recompute any direct access on this space if it is a read modification - m_space.m_direct->force_update(entry); + m_space.invalidate_read_caches(entry); // verify_reference_counts(); } @@ -3022,16 +3217,14 @@ namespace { void address_table::setup_range_masked(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 mask, std::list<u32> &entries) { // convert addresses to bytes - offs_t bytestart = addrstart; - offs_t byteend = addrend; - offs_t bytemask = addrmask; - offs_t bytemirror = addrmirror; - m_space.adjust_addresses(bytestart, byteend, bytemask, bytemirror); + m_space.adjust_addresses(addrstart, addrend, addrmask, addrmirror); // Validity checks assert_always(addrstart <= addrend, "address_table::setup_range called with start greater than end"); - assert_always((bytestart & (m_space.data_width() / 8 - 1)) == 0, "address_table::setup_range called with misaligned start address"); - assert_always((byteend & (m_space.data_width() / 8 - 1)) == (m_space.data_width() / 8 - 1), "address_table::setup_range called with misaligned end address"); + assert_always((addrstart & (m_space.alignment() - 1)) == 0, "address_table::setup_range called with misaligned start address"); + assert_always((addrend & (m_space.alignment() - 1)) == (m_space.alignment() - 1), "address_table::setup_range called with misaligned end address"); + + offs_t bytemask = m_space.address_to_byte_end(addrmask); // Scan the memory to see what has to be done std::list<subrange> range_override; @@ -3040,8 +3233,8 @@ void address_table::setup_range_masked(offs_t addrstart, offs_t addrend, offs_t offs_t base_mirror = 0; do { - offs_t base_address = base_mirror | bytestart; - offs_t end_address = base_mirror | byteend; + offs_t base_address = base_mirror | addrstart; + offs_t end_address = base_mirror | addrend; do { @@ -3059,7 +3252,7 @@ void address_table::setup_range_masked(offs_t addrstart, offs_t addrend, offs_t while (base_address != end_address + 1); // Efficient method to go to the next range start given a mirroring mask - base_mirror = (base_mirror + 1 + ~bytemirror) & bytemirror; + base_mirror = (base_mirror + 1 + ~addrmirror) & addrmirror; } while (base_mirror); @@ -3071,7 +3264,7 @@ void address_table::setup_range_masked(offs_t addrstart, offs_t addrend, offs_t // configure the entry to our parameters handler_entry &curentry = handler(entry); - curentry.configure(bytestart, byteend, bytemask); + curentry.configure(addrstart, addrend, addrmask, bytemask); // Populate it wherever needed for (std::list<subrange>::const_iterator i = range_override.begin(); i != range_override.end(); ++i) @@ -3081,7 +3274,7 @@ void address_table::setup_range_masked(offs_t addrstart, offs_t addrend, offs_t entries.push_back(entry); // recompute any direct access on this space if it is a read modification - m_space.m_direct->force_update(entry); + m_space.invalidate_read_caches(entry); } // Ranges in range_partial must be duplicated then partially changed @@ -3111,7 +3304,7 @@ void address_table::setup_range_masked(offs_t addrstart, offs_t addrend, offs_t curentry.clear_conflicting_subunits(mask); // Reconfigure the base addresses - curentry.configure(bytestart, byteend, bytemask); + curentry.configure(addrstart, addrend, addrmask, bytemask); // Populate it wherever needed for (const auto & elem : i->second) @@ -3123,7 +3316,7 @@ void address_table::setup_range_masked(offs_t addrstart, offs_t addrend, offs_t entries.push_back(entry); // recompute any direct access on this space if it is a read modification - m_space.m_direct->force_update(entry); + m_space.invalidate_read_caches(entry); } } @@ -3182,16 +3375,16 @@ void address_table::verify_reference_counts() // range of addresses //------------------------------------------------- -void address_table::populate_range(offs_t bytestart, offs_t byteend, u16 handlerindex) +void address_table::populate_range(offs_t addrstart, offs_t addrend, u16 handlerindex) { offs_t l2mask = (1 << level2_bits()) - 1; - offs_t l1start = bytestart >> level2_bits(); - offs_t l2start = bytestart & l2mask; - offs_t l1stop = byteend >> level2_bits(); - offs_t l2stop = byteend & l2mask; + offs_t l1start = addrstart >> level2_bits(); + offs_t l2start = addrstart & l2mask; + offs_t l1stop = addrend >> level2_bits(); + offs_t l2stop = addrend & l2mask; // sanity check - if (bytestart > byteend) + if (addrstart > addrend) return; // handle the starting edge if it's not on a block boundary @@ -3267,19 +3460,19 @@ void address_table::populate_range(offs_t bytestart, offs_t byteend, u16 handler // mirrors //------------------------------------------------- -void address_table::populate_range_mirrored(offs_t bytestart, offs_t byteend, offs_t bytemirror, u16 handlerindex) +void address_table::populate_range_mirrored(offs_t addrstart, offs_t addrend, offs_t addrmirror, u16 handlerindex) { // determine the mirror bits offs_t lmirrorbits = 0; offs_t lmirrorbit[32]; for (int bit = 0; bit < level2_bits(); bit++) - if (bytemirror & (1 << bit)) + if (addrmirror & (1 << bit)) lmirrorbit[lmirrorbits++] = 1 << bit; offs_t hmirrorbits = 0; offs_t hmirrorbit[32]; for (int bit = level2_bits(); bit < 32; bit++) - if (bytemirror & (1 << bit)) + if (addrmirror & (1 << bit)) hmirrorbit[hmirrorbits++] = 1 << bit; // loop over mirrors in the level 2 table @@ -3301,14 +3494,14 @@ void address_table::populate_range_mirrored(offs_t bytestart, offs_t byteend, of for (int bit = 0; bit < lmirrorbits; bit++) if (lmirrorcount & (1 << bit)) lmirrorbase |= lmirrorbit[bit]; - m_space.m_direct->remove_intersecting_ranges(bytestart + lmirrorbase, byteend + lmirrorbase); + m_space.invalidate_read_caches(addrstart + lmirrorbase, addrend + lmirrorbase); } // if this is not our first time through, and the level 2 entry matches the previous // level 2 entry, just do a quick map and get out; note that this only works for entries // which don't span multiple level 1 table entries - int cur_index = level1_index(bytestart + hmirrorbase); - if (cur_index == level1_index(byteend + hmirrorbase)) + int cur_index = level1_index(addrstart + hmirrorbase); + if (cur_index == level1_index(addrend + hmirrorbase)) { if (hmirrorcount != 0 && prev_entry == m_table[cur_index]) { @@ -3344,7 +3537,7 @@ void address_table::populate_range_mirrored(offs_t bytestart, offs_t byteend, of lmirrorbase |= lmirrorbit[bit]; // populate the tables - populate_range(bytestart + lmirrorbase, byteend + lmirrorbase, handlerindex); + populate_range(addrstart + lmirrorbase, addrend + lmirrorbase, handlerindex); } } } @@ -3356,22 +3549,22 @@ void address_table::populate_range_mirrored(offs_t bytestart, offs_t byteend, of // range based on the lookup tables //------------------------------------------------- -u16 address_table::derive_range(offs_t byteaddress, offs_t &bytestart, offs_t &byteend) const +u16 address_table::derive_range(offs_t address, offs_t &addrstart, offs_t &addrend) const { // look up the initial address to get the entry we care about u16 l1entry; - u16 entry = l1entry = m_table[level1_index(byteaddress)]; + u16 entry = l1entry = m_table[level1_index(address)]; if (l1entry >= SUBTABLE_BASE) - entry = m_table[level2_index(l1entry, byteaddress)]; + entry = m_table[level2_index(l1entry, address)]; - // use the bytemask of the entry to set minimum and maximum bounds + // use the addrmask of the entry to set minimum and maximum bounds offs_t minscan, maxscan; - handler(entry).mirrored_start_end(byteaddress, minscan, maxscan); + handler(entry).mirrored_start_end(address, minscan, maxscan); // first scan backwards to find the start address u16 curl1entry = l1entry; u16 curentry = entry; - bytestart = byteaddress; + addrstart = address; while (1) { // if we need to scan the subtable, do it @@ -3381,7 +3574,7 @@ u16 address_table::derive_range(offs_t byteaddress, offs_t &bytestart, offs_t &b u32 index; // scan backwards from the current address, until the previous entry doesn't match - for (index = level2_index(curl1entry, bytestart); index > minindex; index--, bytestart -= 1) + for (index = level2_index(curl1entry, addrstart); index > minindex; index--, addrstart -= 1) if (m_table[index - 1] != entry) break; @@ -3391,25 +3584,25 @@ u16 address_table::derive_range(offs_t byteaddress, offs_t &bytestart, offs_t &b } // move to the beginning of this L1 entry; stop at the minimum address - bytestart &= ~((1 << level2_bits()) - 1); - if (bytestart <= minscan) + addrstart &= ~((1 << level2_bits()) - 1); + if (addrstart <= minscan) break; // look up the entry of the byte at the end of the previous L1 entry; if it doesn't match, stop - curentry = curl1entry = m_table[level1_index(bytestart - 1)]; + curentry = curl1entry = m_table[level1_index(addrstart - 1)]; if (curl1entry >= SUBTABLE_BASE) - curentry = m_table[level2_index(curl1entry, bytestart - 1)]; + curentry = m_table[level2_index(curl1entry, addrstart - 1)]; if (curentry != entry) break; // move into the previous entry and resume searching - bytestart -= 1; + addrstart -= 1; } // then scan forwards to find the end address curl1entry = l1entry; curentry = entry; - byteend = byteaddress; + addrend = address; while (1) { // if we need to scan the subtable, do it @@ -3419,7 +3612,7 @@ u16 address_table::derive_range(offs_t byteaddress, offs_t &bytestart, offs_t &b u32 index; // scan forwards from the current address, until the next entry doesn't match - for (index = level2_index(curl1entry, byteend); index < maxindex; index++, byteend += 1) + for (index = level2_index(curl1entry, addrend); index < maxindex; index++, addrend += 1) if (m_table[index + 1] != entry) break; @@ -3429,19 +3622,19 @@ u16 address_table::derive_range(offs_t byteaddress, offs_t &bytestart, offs_t &b } // move to the end of this L1 entry; stop at the maximum address - byteend |= (1 << level2_bits()) - 1; - if (byteend >= maxscan) + addrend |= (1 << level2_bits()) - 1; + if (addrend >= maxscan) break; // look up the entry of the byte at the start of the next L1 entry; if it doesn't match, stop - curentry = curl1entry = m_table[level1_index(byteend + 1)]; + curentry = curl1entry = m_table[level1_index(addrend + 1)]; if (curl1entry >= SUBTABLE_BASE) - curentry = m_table[level2_index(curl1entry, byteend + 1)]; + curentry = m_table[level2_index(curl1entry, addrend + 1)]; if (curentry != entry) break; // move into the next entry and resume searching - byteend += 1; + addrend += 1; } return entry; @@ -3746,9 +3939,9 @@ address_table_read::address_table_read(address_space &space, bool large) } // reset the byte masks on the special handlers to open up the full address space for proper reporting - m_handlers[STATIC_UNMAP]->configure(0, space.bytemask(), ~0); - m_handlers[STATIC_NOP]->configure(0, space.bytemask(), ~0); - m_handlers[STATIC_WATCHPOINT]->configure(0, space.bytemask(), ~0); + m_handlers[STATIC_UNMAP]->configure(0, space.addrmask(), ~0, ~0); + m_handlers[STATIC_NOP]->configure(0, space.addrmask(), ~0, ~0); + m_handlers[STATIC_WATCHPOINT]->configure(0, space.addrmask(), ~0, ~0); } @@ -3820,9 +4013,9 @@ address_table_write::address_table_write(address_space &space, bool large) } // reset the byte masks on the special handlers to open up the full address space for proper reporting - m_handlers[STATIC_UNMAP]->configure(0, space.bytemask(), ~0); - m_handlers[STATIC_NOP]->configure(0, space.bytemask(), ~0); - m_handlers[STATIC_WATCHPOINT]->configure(0, space.bytemask(), ~0); + m_handlers[STATIC_UNMAP]->configure(0, space.addrmask(), ~0, ~0); + m_handlers[STATIC_NOP]->configure(0, space.addrmask(), ~0, ~0); + m_handlers[STATIC_WATCHPOINT]->configure(0, space.addrmask(), ~0, ~0); } @@ -3856,12 +4049,12 @@ handler_entry &address_table_write::handler(u32 index) const // direct_read_data - constructor //------------------------------------------------- -direct_read_data::direct_read_data(address_space &space) +template<int addr_shift> direct_read_data<addr_shift>::direct_read_data(address_space &space) : m_space(space), m_ptr(nullptr), - m_bytemask(space.bytemask()), - m_bytestart(1), - m_byteend(0), + m_addrmask(space.addrmask()), + m_addrstart(1), + m_addrend(0), m_entry(STATIC_UNMAP) { } @@ -3871,7 +4064,7 @@ direct_read_data::direct_read_data(address_space &space) // ~direct_read_data - destructor //------------------------------------------------- -direct_read_data::~direct_read_data() +template<int addr_shift> direct_read_data<addr_shift>::~direct_read_data() { } @@ -3881,29 +4074,35 @@ direct_read_data::~direct_read_data() // update the opcode base for the given address //------------------------------------------------- -bool direct_read_data::set_direct_region(offs_t byteaddress) +template<int addr_shift> bool direct_read_data<addr_shift>::set_direct_region(offs_t address) { // find or allocate a matching range - direct_range *range = find_range(byteaddress, m_entry); + direct_range *range = find_range(address, m_entry); // if we don't map to a bank, return false if (m_entry < STATIC_BANK1 || m_entry > STATIC_BANKMAX) { // ensure future updates to land here as well until we get back into a bank - m_byteend = 0; - m_bytestart = 1; + m_addrend = 0; + m_addrstart = 1; return false; } u8 *base = *m_space.manager().bank_pointer_addr(m_entry); // compute the adjusted base - offs_t maskedbits = byteaddress & ~m_space.bytemask(); + offs_t maskedbits = address & ~m_space.addrmask(); const handler_entry_read &handler = m_space.read().handler_read(m_entry); - m_bytemask = handler.bytemask(); - m_ptr = base - (handler.bytestart() & m_bytemask); - m_bytestart = maskedbits | range->m_bytestart; - m_byteend = maskedbits | range->m_byteend; + m_addrmask = handler.addrmask(); + u32 delta = handler.addrstart() & m_addrmask; + if(addr_shift < 0) + delta = delta << iabs(addr_shift); + else if(addr_shift > 0) + delta = delta >> iabs(addr_shift); + + m_ptr = base - delta; + m_addrstart = maskedbits | range->m_addrstart; + m_addrend = maskedbits | range->m_addrend; return true; } @@ -3912,20 +4111,20 @@ bool direct_read_data::set_direct_region(offs_t byteaddress) // find_range - find a byte address in a range //------------------------------------------------- -direct_read_data::direct_range *direct_read_data::find_range(offs_t byteaddress, u16 &entry) +template<int addr_shift> typename direct_read_data<addr_shift>::direct_range *direct_read_data<addr_shift>::find_range(offs_t address, u16 &entry) { // determine which entry - byteaddress &= m_space.m_bytemask; - entry = m_space.read().lookup_live_nowp(byteaddress); + address &= m_space.m_addrmask; + entry = m_space.read().lookup_live_nowp(address); // scan our table for (auto &range : m_rangelist[entry]) - if (byteaddress >= range.m_bytestart && byteaddress <= range.m_byteend) + if (address >= range.m_addrstart && address <= range.m_addrend) return ⦥ // didn't find out; create a new one direct_range range; - m_space.read().derive_range(byteaddress, range.m_bytestart, range.m_byteend); + m_space.read().derive_range(address, range.m_addrstart, range.m_addrend); m_rangelist[entry].push_front(range); return &m_rangelist[entry].front(); @@ -3937,7 +4136,7 @@ direct_read_data::direct_range *direct_read_data::find_range(offs_t byteaddress, // ranges that intersect the given address range //------------------------------------------------- -void direct_read_data::remove_intersecting_ranges(offs_t bytestart, offs_t byteend) +template<int addr_shift> void direct_read_data<addr_shift>::remove_intersecting_ranges(offs_t addrstart, offs_t addrend) { // loop over all entries for (auto & elem : m_rangelist) @@ -3946,7 +4145,7 @@ void direct_read_data::remove_intersecting_ranges(offs_t bytestart, offs_t bytee for (auto range = elem.begin(); range!=elem.end();) { // if we intersect, remove - if (bytestart <= range->m_byteend && byteend >= range->m_bytestart) + if (addrstart <= range->m_addrend && addrend >= range->m_addrstart) range = elem.erase(range); else range ++; @@ -3954,6 +4153,12 @@ void direct_read_data::remove_intersecting_ranges(offs_t bytestart, offs_t bytee } } +template class direct_read_data<3>; +template class direct_read_data<0>; +template class direct_read_data<-1>; +template class direct_read_data<-2>; +template class direct_read_data<-3>; + //************************************************************************** // MEMORY BLOCK @@ -3963,15 +4168,15 @@ void direct_read_data::remove_intersecting_ranges(offs_t bytestart, offs_t bytee // memory_block - constructor //------------------------------------------------- -memory_block::memory_block(address_space &space, offs_t bytestart, offs_t byteend, void *memory) +memory_block::memory_block(address_space &space, offs_t addrstart, offs_t addrend, void *memory) : m_machine(space.machine()), m_space(space), - m_bytestart(bytestart), - m_byteend(byteend), + m_addrstart(addrstart), + m_addrend(addrend), m_data(reinterpret_cast<u8 *>(memory)) { - offs_t const length = byteend + 1 - bytestart; - VPRINTF(("block_allocate('%s',%s,%08X,%08X,%p)\n", space.device().tag(), space.name(), bytestart, byteend, memory)); + offs_t const length = space.address_to_byte(addrend + 1 - addrstart); + VPRINTF(("block_allocate('%s',%s,%08X,%08X,%p)\n", space.device().tag(), space.name(), addrstart, addrend, memory)); // allocate a block if needed if (m_data == nullptr) @@ -3996,8 +4201,8 @@ memory_block::memory_block(address_space &space, offs_t bytestart, offs_t byteen else { int bytes_per_element = space.data_width() / 8; - std::string name = string_format("%08x-%08x", bytestart, byteend); - space.machine().save().save_memory(nullptr, "memory", space.device().tag(), space.spacenum(), name.c_str(), m_data, bytes_per_element, (u32)length / bytes_per_element); + std::string name = string_format("%08x-%08x", addrstart, addrend); + space.machine().save().save_memory(&space.device(), "memory", space.device().tag(), space.spacenum(), name.c_str(), m_data, bytes_per_element, (u32)length / bytes_per_element); } } @@ -4020,13 +4225,13 @@ memory_block::~memory_block() // memory_bank - constructor //------------------------------------------------- -memory_bank::memory_bank(address_space &space, int index, offs_t bytestart, offs_t byteend, const char *tag) +memory_bank::memory_bank(address_space &space, int index, offs_t addrstart, offs_t addrend, const char *tag) : m_machine(space.machine()), m_baseptr(space.manager().bank_pointer_addr(index)), m_index(index), m_anonymous(tag == nullptr), - m_bytestart(bytestart), - m_byteend(byteend), + m_addrstart(addrstart), + m_addrend(addrend), m_curentry(BANK_ENTRY_UNSPECIFIED) { // generate an internal tag if we don't have one @@ -4042,7 +4247,7 @@ memory_bank::memory_bank(address_space &space, int index, offs_t bytestart, offs } if (!m_anonymous && space.machine().save().registration_allowed()) - space.machine().save().save_item(nullptr, "memory", m_tag.c_str(), 0, NAME(m_curentry)); + space.machine().save().save_item(&space.device(), "memory", m_tag.c_str(), 0, NAME(m_curentry)); } @@ -4093,7 +4298,7 @@ void memory_bank::invalidate_references() { // invalidate all the direct references to any referenced address spaces for (auto &ref : m_reflist) - ref->space().direct().force_update(); + ref->space().invalidate_read_caches(); } @@ -4218,8 +4423,9 @@ handler_entry::handler_entry(u8 width, endianness_t endianness, u8 **rambaseptr) : m_populated(false), m_datawidth(width), m_endianness(endianness), - m_bytestart(0), - m_byteend(0), + m_addrstart(0), + m_addrend(0), + m_addrmask(~0), m_bytemask(~0), m_rambaseptr(rambaseptr), m_subunits(0), @@ -4253,8 +4459,9 @@ void handler_entry::copy(handler_entry *entry) m_populated = true; m_datawidth = entry->m_datawidth; m_endianness = entry->m_endianness; - m_bytestart = entry->m_bytestart; - m_byteend = entry->m_byteend; + m_addrstart = entry->m_addrstart; + m_addrend = entry->m_addrend; + m_addrmask = entry->m_addrmask; m_bytemask = entry->m_bytemask; m_rambaseptr = nullptr; m_subunits = entry->m_subunits; @@ -4267,9 +4474,9 @@ void handler_entry::copy(handler_entry *entry) // reconfigure_subunits - reconfigure the subunits // to handle a new base address //------------------------------------------------- -void handler_entry::reconfigure_subunits(offs_t bytestart) +void handler_entry::reconfigure_subunits(offs_t addrstart) { - s32 delta = bytestart - m_bytestart; + s32 delta = addrstart - m_addrstart; for (int i=0; i != m_subunits; i++) m_subunit_infos[i].m_offset += delta / (m_subunit_infos[i].m_size / 8); } @@ -4319,7 +4526,7 @@ void handler_entry::configure_subunits(u64 handlermask, int handlerbits, int &st u32 shift = (unitnum^shift_xor_mask) * handlerbits; if (((handlermask >> shift) & unitmask) != 0) { - m_subunit_infos[m_subunits].m_bytemask = m_bytemask / (maxunits / multiplier); + m_subunit_infos[m_subunits].m_addrmask = m_bytemask / (maxunits / multiplier); m_subunit_infos[m_subunits].m_mask = unitmask; m_subunit_infos[m_subunits].m_offset = cur_offset++; m_subunit_infos[m_subunits].m_size = handlerbits; @@ -4413,7 +4620,7 @@ void handler_entry::description(char *buffer) const m_subunit_infos[i].m_shift, m_subunit_infos[i].m_offset, m_subunit_infos[i].m_multiplier, - m_subunit_infos[i].m_bytemask, + m_subunit_infos[i].m_addrmask, subunit_name(i)); } } @@ -4660,7 +4867,7 @@ u16 handler_entry_read::read_stub_16(address_space &space, offs_t offset, u16 ma { offs_t aoffset = offset * si.m_multiplier + si.m_offset; u8 val; - val = m_subread[index].r8(space, aoffset & si.m_bytemask, submask); + val = m_subread[index].r8(space, aoffset & si.m_addrmask, submask); result |= val << si.m_shift; } } @@ -4687,10 +4894,10 @@ u32 handler_entry_read::read_stub_32(address_space &space, offs_t offset, u32 ma switch (si.m_size) { case 8: - val = m_subread[index].r8(space, aoffset & si.m_bytemask, submask); + val = m_subread[index].r8(space, aoffset & si.m_addrmask, submask); break; case 16: - val = m_subread[index].r16(space, aoffset & si.m_bytemask, submask); + val = m_subread[index].r16(space, aoffset & si.m_addrmask, submask); break; } result |= val << si.m_shift; @@ -4719,13 +4926,13 @@ u64 handler_entry_read::read_stub_64(address_space &space, offs_t offset, u64 ma switch (si.m_size) { case 8: - val = m_subread[index].r8(space, aoffset & si.m_bytemask, submask); + val = m_subread[index].r8(space, aoffset & si.m_addrmask, submask); break; case 16: - val = m_subread[index].r16(space, aoffset & si.m_bytemask, submask); + val = m_subread[index].r16(space, aoffset & si.m_addrmask, submask); break; case 32: - val = m_subread[index].r32(space, aoffset & si.m_bytemask, submask); + val = m_subread[index].r32(space, aoffset & si.m_addrmask, submask); break; } result |= u64(val) << si.m_shift; @@ -4953,7 +5160,7 @@ void handler_entry_write::write_stub_16(address_space &space, offs_t offset, u16 { offs_t aoffset = offset * si.m_multiplier + si.m_offset; u8 adata = data >> si.m_shift; - m_subwrite[index].w8(space, aoffset & si.m_bytemask, adata, submask); + m_subwrite[index].w8(space, aoffset & si.m_addrmask, adata, submask); } } } @@ -4977,10 +5184,10 @@ void handler_entry_write::write_stub_32(address_space &space, offs_t offset, u32 switch (si.m_size) { case 8: - m_subwrite[index].w8(space, aoffset & si.m_bytemask, adata, submask); + m_subwrite[index].w8(space, aoffset & si.m_addrmask, adata, submask); break; case 16: - m_subwrite[index].w16(space, aoffset & si.m_bytemask, adata, submask); + m_subwrite[index].w16(space, aoffset & si.m_addrmask, adata, submask); break; } } @@ -5006,13 +5213,13 @@ void handler_entry_write::write_stub_64(address_space &space, offs_t offset, u64 switch (si.m_size) { case 8: - m_subwrite[index].w8(space, aoffset & si.m_bytemask, adata, submask); + m_subwrite[index].w8(space, aoffset & si.m_addrmask, adata, submask); break; case 16: - m_subwrite[index].w16(space, aoffset & si.m_bytemask, adata, submask); + m_subwrite[index].w16(space, aoffset & si.m_addrmask, adata, submask); break; case 32: - m_subwrite[index].w32(space, aoffset & si.m_bytemask, adata, submask); + m_subwrite[index].w32(space, aoffset & si.m_addrmask, adata, submask); break; } } diff --git a/src/emu/emumem.h b/src/emu/emumem.h index 19edc918aaa..45e1a759138 100644 --- a/src/emu/emumem.h +++ b/src/emu/emumem.h @@ -17,6 +17,14 @@ #ifndef MAME_EMU_EMUMEM_H #define MAME_EMU_EMUMEM_H +using s8 = std::int8_t; +using u8 = std::uint8_t; +using s16 = std::int16_t; +using u16 = std::uint16_t; +using s32 = std::int32_t; +using u32 = std::uint32_t; +using s64 = std::int64_t; +using u64 = std::uint64_t; //************************************************************************** @@ -63,21 +71,21 @@ typedef named_delegate<void (address_map &)> address_map_delegate; // struct with function pointers for accessors; use is generally discouraged unless necessary struct data_accessors { - u8 (*read_byte)(address_space &space, offs_t byteaddress); - u16 (*read_word)(address_space &space, offs_t byteaddress); - u16 (*read_word_masked)(address_space &space, offs_t byteaddress, u16 mask); - u32 (*read_dword)(address_space &space, offs_t byteaddress); - u32 (*read_dword_masked)(address_space &space, offs_t byteaddress, u32 mask); - u64 (*read_qword)(address_space &space, offs_t byteaddress); - u64 (*read_qword_masked)(address_space &space, offs_t byteaddress, u64 mask); - - void (*write_byte)(address_space &space, offs_t byteaddress, u8 data); - void (*write_word)(address_space &space, offs_t byteaddress, u16 data); - void (*write_word_masked)(address_space &space, offs_t byteaddress, u16 data, u16 mask); - void (*write_dword)(address_space &space, offs_t byteaddress, u32 data); - void (*write_dword_masked)(address_space &space, offs_t byteaddress, u32 data, u32 mask); - void (*write_qword)(address_space &space, offs_t byteaddress, u64 data); - void (*write_qword_masked)(address_space &space, offs_t byteaddress, u64 data, u64 mask); + u8 (*read_byte)(address_space &space, offs_t address); + u16 (*read_word)(address_space &space, offs_t address); + u16 (*read_word_masked)(address_space &space, offs_t address, u16 mask); + u32 (*read_dword)(address_space &space, offs_t address); + u32 (*read_dword_masked)(address_space &space, offs_t address, u32 mask); + u64 (*read_qword)(address_space &space, offs_t address); + u64 (*read_qword_masked)(address_space &space, offs_t address, u64 mask); + + void (*write_byte)(address_space &space, offs_t address, u8 data); + void (*write_word)(address_space &space, offs_t address, u16 data); + void (*write_word_masked)(address_space &space, offs_t address, u16 data, u16 mask); + void (*write_dword)(address_space &space, offs_t address, u32 data); + void (*write_dword_masked)(address_space &space, offs_t address, u32 data, u32 mask); + void (*write_qword)(address_space &space, offs_t address, u64 data); + void (*write_qword_masked)(address_space &space, offs_t address, u64 data, u64 mask); }; @@ -106,26 +114,28 @@ typedef device_delegate<void (address_space &, offs_t)> setoffset_delegate; // ======================> direct_read_data // direct_read_data contains state data for direct read access -class direct_read_data +template<int addr_shift> class direct_read_data { friend class address_table; public: + using direct_update_delegate = delegate<offs_t (direct_read_data<addr_shift> &, offs_t)>; + // direct_range is an internal class that is part of a list of start/end ranges class direct_range { public: // construction - direct_range(): m_bytestart(0),m_byteend(~0) { } + direct_range(): m_addrstart(0),m_addrend(~0) { } inline bool operator==(direct_range val) noexcept { // return true if _Left and _Right identify the same thread - return (m_bytestart == val.m_bytestart) && (m_byteend == val.m_byteend); + return (m_addrstart == val.m_addrstart) && (m_addrend == val.m_addrend); } // internal state - offs_t m_bytestart; // starting byte offset of the range - offs_t m_byteend; // ending byte offset of the range + offs_t m_addrstart; // starting offset of the range + offs_t m_addrend; // ending offset of the range }; // construction/destruction @@ -137,31 +147,32 @@ public: u8 *ptr() const { return m_ptr; } // see if an address is within bounds, or attempt to update it if not - bool address_is_valid(offs_t byteaddress) { return EXPECTED(byteaddress >= m_bytestart && byteaddress <= m_byteend) || set_direct_region(byteaddress); } + bool address_is_valid(offs_t address) { return EXPECTED(address >= m_addrstart && address <= m_addrend) || set_direct_region(address); } // force a recomputation on the next read - void force_update() { m_byteend = 0; m_bytestart = 1; } + void force_update() { m_addrend = 0; m_addrstart = 1; } void force_update(u16 if_match) { if (m_entry == if_match) force_update(); } // accessor methods - void *read_ptr(offs_t byteaddress, offs_t directxor = 0); - u8 read_byte(offs_t byteaddress, offs_t directxor = 0); - u16 read_word(offs_t byteaddress, offs_t directxor = 0); - u32 read_dword(offs_t byteaddress, offs_t directxor = 0); - u64 read_qword(offs_t byteaddress, offs_t directxor = 0); + void *read_ptr(offs_t address, offs_t directxor = 0); + u8 read_byte(offs_t address, offs_t directxor = 0); + u16 read_word(offs_t address, offs_t directxor = 0); + u32 read_dword(offs_t address, offs_t directxor = 0); + u64 read_qword(offs_t address, offs_t directxor = 0); + + void remove_intersecting_ranges(offs_t start, offs_t end); private: // internal helpers - bool set_direct_region(offs_t byteaddress); - direct_range *find_range(offs_t byteaddress, u16 &entry); - void remove_intersecting_ranges(offs_t bytestart, offs_t byteend); + bool set_direct_region(offs_t address); + direct_range *find_range(offs_t address, u16 &entry); // internal state address_space & m_space; u8 * m_ptr; // direct access data pointer - offs_t m_bytemask; // byte address mask - offs_t m_bytestart; // minimum valid byte address - offs_t m_byteend; // maximum valid byte address + offs_t m_addrmask; // address mask + offs_t m_addrstart; // minimum valid address + offs_t m_addrend; // maximum valid address u16 m_entry; // live entry std::list<direct_range> m_rangelist[TOTAL_MEMORY_BANKS]; // list of ranges for each entry }; @@ -185,11 +196,17 @@ public: endianness_t endianness() const { return m_endianness; } int data_width() const { return m_databus_width; } int addr_width() const { return m_addrbus_width; } + int addrbus_shift() const { return m_addrbus_shift; } - // address-to-byte conversion helpers + // Actual alignment of the bus addresses + int alignment() const { int bytes = m_databus_width / 8; return m_addrbus_shift < 0 ? bytes >> -m_addrbus_shift : bytes << m_addrbus_shift; } + + // Address delta to byte delta helpers inline offs_t addr2byte(offs_t address) const { return (m_addrbus_shift < 0) ? (address << -m_addrbus_shift) : (address >> m_addrbus_shift); } - inline offs_t addr2byte_end(offs_t address) const { return (m_addrbus_shift < 0) ? ((address << -m_addrbus_shift) | ((1 << -m_addrbus_shift) - 1)) : (address >> m_addrbus_shift); } inline offs_t byte2addr(offs_t address) const { return (m_addrbus_shift > 0) ? (address << m_addrbus_shift) : (address >> -m_addrbus_shift); } + + // address-to-byte conversion helpers + inline offs_t addr2byte_end(offs_t address) const { return (m_addrbus_shift < 0) ? ((address << -m_addrbus_shift) | ((1 << -m_addrbus_shift) - 1)) : (address >> m_addrbus_shift); } inline offs_t byte2addr_end(offs_t address) const { return (m_addrbus_shift > 0) ? ((address << m_addrbus_shift) | ((1 << m_addrbus_shift) - 1)) : (address >> -m_addrbus_shift); } // state @@ -218,7 +235,11 @@ class address_space friend class address_table_read; friend class address_table_write; friend class address_table_setoffset; - friend class direct_read_data; + friend class direct_read_data<3>; + friend class direct_read_data<0>; + friend class direct_read_data<-1>; + friend class direct_read_data<-2>; + friend class direct_read_data<-3>; protected: // construction/destruction @@ -235,19 +256,24 @@ public: int spacenum() const { return m_spacenum; } address_map *map() const { return m_map.get(); } - direct_read_data &direct() const { return *m_direct; } + template<int addr_shift> direct_read_data<addr_shift> *direct() const { + static_assert(addr_shift == 3 || addr_shift == 0 || addr_shift == -1 || addr_shift == -2 || addr_shift == -3, "Unsupported addr_shift in direct()"); + if(addr_shift != m_config.addrbus_shift()) + fatalerror("Requesing direct() with address shift %d while the config says %d\n", addr_shift, m_config.addrbus_shift()); + return static_cast<direct_read_data<addr_shift> *>(m_direct); + } int data_width() const { return m_config.data_width(); } int addr_width() const { return m_config.addr_width(); } + int alignment() const { return m_config.alignment(); } endianness_t endianness() const { return m_config.endianness(); } + int addrbus_shift() const { return m_config.addrbus_shift(); } u64 unmap() const { return m_unmap; } bool is_octal() const { return m_config.m_is_octal; } offs_t addrmask() const { return m_addrmask; } - offs_t bytemask() const { return m_bytemask; } u8 addrchars() const { return m_addrchars; } offs_t logaddrmask() const { return m_logaddrmask; } - offs_t logbytemask() const { return m_logbytemask; } u8 logaddrchars() const { return m_logaddrchars; } // debug helpers @@ -262,41 +288,41 @@ public: // general accessors virtual void accessors(data_accessors &accessors) const = 0; - virtual void *get_read_ptr(offs_t byteaddress) = 0; - virtual void *get_write_ptr(offs_t byteaddress) = 0; + virtual void *get_read_ptr(offs_t address) = 0; + virtual void *get_write_ptr(offs_t address) = 0; // read accessors - virtual u8 read_byte(offs_t byteaddress) = 0; - virtual u16 read_word(offs_t byteaddress) = 0; - virtual u16 read_word(offs_t byteaddress, u16 mask) = 0; - virtual u16 read_word_unaligned(offs_t byteaddress) = 0; - virtual u16 read_word_unaligned(offs_t byteaddress, u16 mask) = 0; - virtual u32 read_dword(offs_t byteaddress) = 0; - virtual u32 read_dword(offs_t byteaddress, u32 mask) = 0; - virtual u32 read_dword_unaligned(offs_t byteaddress) = 0; - virtual u32 read_dword_unaligned(offs_t byteaddress, u32 mask) = 0; - virtual u64 read_qword(offs_t byteaddress) = 0; - virtual u64 read_qword(offs_t byteaddress, u64 mask) = 0; - virtual u64 read_qword_unaligned(offs_t byteaddress) = 0; - virtual u64 read_qword_unaligned(offs_t byteaddress, u64 mask) = 0; + virtual u8 read_byte(offs_t address) = 0; + virtual u16 read_word(offs_t address) = 0; + virtual u16 read_word(offs_t address, u16 mask) = 0; + virtual u16 read_word_unaligned(offs_t address) = 0; + virtual u16 read_word_unaligned(offs_t address, u16 mask) = 0; + virtual u32 read_dword(offs_t address) = 0; + virtual u32 read_dword(offs_t address, u32 mask) = 0; + virtual u32 read_dword_unaligned(offs_t address) = 0; + virtual u32 read_dword_unaligned(offs_t address, u32 mask) = 0; + virtual u64 read_qword(offs_t address) = 0; + virtual u64 read_qword(offs_t address, u64 mask) = 0; + virtual u64 read_qword_unaligned(offs_t address) = 0; + virtual u64 read_qword_unaligned(offs_t address, u64 mask) = 0; // write accessors - virtual void write_byte(offs_t byteaddress, u8 data) = 0; - virtual void write_word(offs_t byteaddress, u16 data) = 0; - virtual void write_word(offs_t byteaddress, u16 data, u16 mask) = 0; - virtual void write_word_unaligned(offs_t byteaddress, u16 data) = 0; - virtual void write_word_unaligned(offs_t byteaddress, u16 data, u16 mask) = 0; - virtual void write_dword(offs_t byteaddress, u32 data) = 0; - virtual void write_dword(offs_t byteaddress, u32 data, u32 mask) = 0; - virtual void write_dword_unaligned(offs_t byteaddress, u32 data) = 0; - virtual void write_dword_unaligned(offs_t byteaddress, u32 data, u32 mask) = 0; - virtual void write_qword(offs_t byteaddress, u64 data) = 0; - virtual void write_qword(offs_t byteaddress, u64 data, u64 mask) = 0; - virtual void write_qword_unaligned(offs_t byteaddress, u64 data) = 0; - virtual void write_qword_unaligned(offs_t byteaddress, u64 data, u64 mask) = 0; + virtual void write_byte(offs_t address, u8 data) = 0; + virtual void write_word(offs_t address, u16 data) = 0; + virtual void write_word(offs_t address, u16 data, u16 mask) = 0; + virtual void write_word_unaligned(offs_t address, u16 data) = 0; + virtual void write_word_unaligned(offs_t address, u16 data, u16 mask) = 0; + virtual void write_dword(offs_t address, u32 data) = 0; + virtual void write_dword(offs_t address, u32 data, u32 mask) = 0; + virtual void write_dword_unaligned(offs_t address, u32 data) = 0; + virtual void write_dword_unaligned(offs_t address, u32 data, u32 mask) = 0; + virtual void write_qword(offs_t address, u64 data) = 0; + virtual void write_qword(offs_t address, u64 data, u64 mask) = 0; + virtual void write_qword_unaligned(offs_t address, u64 data) = 0; + virtual void write_qword_unaligned(offs_t address, u64 data, u64 mask) = 0; // Set address. This will invoke setoffset handlers for the respective entries. - virtual void set_address(offs_t byteaddress) = 0; + virtual void set_address(offs_t address) = 0; // address-to-byte conversion helpers offs_t address_to_byte(offs_t address) const { return m_config.addr2byte(address); } @@ -386,6 +412,10 @@ public: void allocate_memory(); void locate_memory(); + void invalidate_read_caches(); + void invalidate_read_caches(u16 entry); + void invalidate_read_caches(offs_t start, offs_t end); + private: // internal helpers virtual address_table_read &read() = 0; @@ -412,15 +442,13 @@ protected: // private state const address_space_config &m_config; // configuration of this space device_t & m_device; // reference to the owning device - std::unique_ptr<address_map> m_map; // original memory map + std::unique_ptr<address_map> m_map; // original memory map offs_t m_addrmask; // physical address mask - offs_t m_bytemask; // byte-converted physical address mask offs_t m_logaddrmask; // logical address mask - offs_t m_logbytemask; // byte-converted logical address mask u64 m_unmap; // unmapped value int m_spacenum; // address space index bool m_log_unmap; // log unmapped accesses in this space? - std::unique_ptr<direct_read_data> m_direct; // fast direct-access read info + void * m_direct; // fast direct-access read info const char * m_name; // friendly name of the address space u8 m_addrchars; // number of characters to use for physical addresses u8 m_logaddrchars; // number of characters to use for logical addresses @@ -440,26 +468,26 @@ class memory_block public: // construction/destruction - memory_block(address_space &space, offs_t bytestart, offs_t byteend, void *memory = nullptr); + memory_block(address_space &space, offs_t start, offs_t end, void *memory = nullptr); ~memory_block(); // getters running_machine &machine() const { return m_machine; } - offs_t bytestart() const { return m_bytestart; } - offs_t byteend() const { return m_byteend; } + offs_t addrstart() const { return m_addrstart; } + offs_t addrend() const { return m_addrend; } u8 *data() const { return m_data; } // is the given range contained by this memory block? - bool contains(address_space &space, offs_t bytestart, offs_t byteend) const + bool contains(address_space &space, offs_t addrstart, offs_t addrend) const { - return (&space == &m_space && m_bytestart <= bytestart && m_byteend >= byteend); + return (&space == &m_space && m_addrstart <= addrstart && m_addrend >= addrend); } private: // internal state running_machine & m_machine; // need the machine to free our memory address_space & m_space; // which address space are we associated with? - offs_t m_bytestart, m_byteend; // byte-normalized start/end for verifying a match + offs_t m_addrstart, m_addrend; // start/end for verifying a match u8 * m_data; // pointer to the data for this block std::vector<u8> m_allocated; // pointer to the actually allocated block }; @@ -502,7 +530,7 @@ class memory_bank public: // construction/destruction - memory_bank(address_space &space, int index, offs_t bytestart, offs_t byteend, const char *tag = nullptr); + memory_bank(address_space &space, int index, offs_t start, offs_t end, const char *tag = nullptr); ~memory_bank(); // getters @@ -510,16 +538,16 @@ public: int index() const { return m_index; } int entry() const { return m_curentry; } bool anonymous() const { return m_anonymous; } - offs_t bytestart() const { return m_bytestart; } + offs_t addrstart() const { return m_addrstart; } void *base() const { return *m_baseptr; } const char *tag() const { return m_tag.c_str(); } const char *name() const { return m_name.c_str(); } // compare a range against our range - bool matches_exactly(offs_t bytestart, offs_t byteend) const { return (m_bytestart == bytestart && m_byteend == byteend); } - bool fully_covers(offs_t bytestart, offs_t byteend) const { return (m_bytestart <= bytestart && m_byteend >= byteend); } - bool is_covered_by(offs_t bytestart, offs_t byteend) const { return (m_bytestart >= bytestart && m_byteend <= byteend); } - bool straddles(offs_t bytestart, offs_t byteend) const { return (m_bytestart < byteend && m_byteend > bytestart); } + bool matches_exactly(offs_t addrstart, offs_t addrend) const { return (m_addrstart == addrstart && m_addrend == addrend); } + bool fully_covers(offs_t addrstart, offs_t addrend) const { return (m_addrstart <= addrstart && m_addrend >= addrend); } + bool is_covered_by(offs_t addrstart, offs_t addrend) const { return (m_addrstart >= addrstart && m_addrend <= addrend); } + bool straddles(offs_t addrstart, offs_t addrend) const { return (m_addrstart < addrend && m_addrend > addrstart); } // track and verify address space references to this bank bool references_space(const address_space &space, read_or_write readorwrite) const; @@ -543,8 +571,8 @@ private: u8 ** m_baseptr; // pointer to our base pointer in the global array u16 m_index; // array index for this handler bool m_anonymous; // are we anonymous or explicit? - offs_t m_bytestart; // byte-adjusted start offset - offs_t m_byteend; // byte-adjusted end offset + offs_t m_addrstart; // start offset + offs_t m_addrend; // end offset int m_curentry; // current entry std::vector<bank_entry> m_entry; // array of entries (dynamically allocated) std::string m_name; // friendly name for this bank @@ -791,10 +819,16 @@ private: // backing that address //------------------------------------------------- -inline void *direct_read_data::read_ptr(offs_t byteaddress, offs_t directxor) +template<int addr_shift> inline void *direct_read_data<addr_shift>::read_ptr(offs_t address, offs_t directxor) { - if (address_is_valid(byteaddress)) - return &m_ptr[(byteaddress ^ directxor) & m_bytemask]; + if (address_is_valid(address)) { + if(addr_shift < 0) + return &m_ptr[((address ^ directxor) & m_addrmask) << iabs(addr_shift)]; + else if(addr_shift == 0) + return &m_ptr[(address ^ directxor) & m_addrmask]; + else + return &m_ptr[((address ^ directxor) & m_addrmask) >> iabs(addr_shift)]; + } return nullptr; } @@ -804,11 +838,17 @@ inline void *direct_read_data::read_ptr(offs_t byteaddress, offs_t directxor) // direct_read_data class //------------------------------------------------- -inline u8 direct_read_data::read_byte(offs_t byteaddress, offs_t directxor) +template<int addr_shift> inline u8 direct_read_data<addr_shift>::read_byte(offs_t address, offs_t directxor) { - if (address_is_valid(byteaddress)) - return m_ptr[(byteaddress ^ directxor) & m_bytemask]; - return m_space.read_byte(byteaddress); + if(addr_shift <= -1) + fatalerror("Can't direct_read_data::read_byte on a memory space with address shift %d", addr_shift); + if (address_is_valid(address)) { + if(addr_shift == 0) + return m_ptr[(address ^ directxor) & m_addrmask]; + else + return m_ptr[((address ^ directxor) & m_addrmask) >> iabs(addr_shift)]; + } + return m_space.read_byte(address); } @@ -817,11 +857,19 @@ inline u8 direct_read_data::read_byte(offs_t byteaddress, offs_t directxor) // direct_read_data class //------------------------------------------------- -inline u16 direct_read_data::read_word(offs_t byteaddress, offs_t directxor) +template<int addr_shift> inline u16 direct_read_data<addr_shift>::read_word(offs_t address, offs_t directxor) { - if (address_is_valid(byteaddress)) - return *reinterpret_cast<u16 *>(&m_ptr[(byteaddress ^ directxor) & m_bytemask]); - return m_space.read_word(byteaddress); + if(addr_shift <= -2) + fatalerror("Can't direct_read_data::read_word on a memory space with address shift %d", addr_shift); + if (address_is_valid(address)) { + if(addr_shift < 0) + return *reinterpret_cast<u16 *>(&m_ptr[((address ^ directxor) & m_addrmask) << iabs(addr_shift)]); + else if(addr_shift == 0) + return *reinterpret_cast<u16 *>(&m_ptr[(address ^ directxor) & m_addrmask]); + else + return *reinterpret_cast<u16 *>(&m_ptr[((address ^ directxor) & m_addrmask) >> iabs(addr_shift)]); + } + return m_space.read_word(address); } @@ -830,11 +878,19 @@ inline u16 direct_read_data::read_word(offs_t byteaddress, offs_t directxor) // direct_read_data class //------------------------------------------------- -inline u32 direct_read_data::read_dword(offs_t byteaddress, offs_t directxor) +template<int addr_shift> inline u32 direct_read_data<addr_shift>::read_dword(offs_t address, offs_t directxor) { - if (address_is_valid(byteaddress)) - return *reinterpret_cast<u32 *>(&m_ptr[(byteaddress ^ directxor) & m_bytemask]); - return m_space.read_dword(byteaddress); + if(addr_shift <= -3) + fatalerror("Can't direct_read_data::read_dword on a memory space with address shift %d", addr_shift); + if (address_is_valid(address)) { + if(addr_shift < 0) + return *reinterpret_cast<u32 *>(&m_ptr[((address ^ directxor) & m_addrmask) << iabs(addr_shift)]); + else if(addr_shift == 0) + return *reinterpret_cast<u32 *>(&m_ptr[(address ^ directxor) & m_addrmask]); + else + return *reinterpret_cast<u32 *>(&m_ptr[((address ^ directxor) & m_addrmask) >> iabs(addr_shift)]); + } + return m_space.read_dword(address); } @@ -843,11 +899,17 @@ inline u32 direct_read_data::read_dword(offs_t byteaddress, offs_t directxor) // direct_read_data class //------------------------------------------------- -inline u64 direct_read_data::read_qword(offs_t byteaddress, offs_t directxor) +template<int addr_shift> inline u64 direct_read_data<addr_shift>::read_qword(offs_t address, offs_t directxor) { - if (address_is_valid(byteaddress)) - return *reinterpret_cast<u64 *>(&m_ptr[(byteaddress ^ directxor) & m_bytemask]); - return m_space.read_qword(byteaddress); + if (address_is_valid(address)) { + if(addr_shift < 0) + return *reinterpret_cast<u64 *>(&m_ptr[((address ^ directxor) & m_addrmask) << iabs(addr_shift)]); + else if(addr_shift == 0) + return *reinterpret_cast<u64 *>(&m_ptr[(address ^ directxor) & m_addrmask]); + else + return *reinterpret_cast<u64 *>(&m_ptr[((address ^ directxor) & m_addrmask) >> iabs(addr_shift)]); + } + return m_space.read_qword(address); } #endif /* MAME_EMU_EMUMEM_H */ diff --git a/src/emu/inpttype.h b/src/emu/inpttype.h index 247eced5037..b58ca37bec6 100644 --- a/src/emu/inpttype.h +++ b/src/emu/inpttype.h @@ -576,16 +576,16 @@ inline void construct_core_types_pedal(simple_list<input_type_entry> &typelist) inline void construct_core_types_pedal2(simple_list<input_type_entry> &typelist) { - INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, PEDAL2, "P1 Pedal 2", input_seq(JOYCODE_Z_POS_ABSOLUTE_INDEXED(0)), input_seq(), input_seq(KEYCODE_LALT, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(0)) ) - INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, PEDAL2, "P2 Pedal 2", input_seq(JOYCODE_Z_POS_ABSOLUTE_INDEXED(1)), input_seq(), input_seq(KEYCODE_S, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(1)) ) - INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, PEDAL2, "P3 Pedal 2", input_seq(JOYCODE_Z_POS_ABSOLUTE_INDEXED(2)), input_seq(), input_seq(KEYCODE_RSHIFT, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(2)) ) - INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, PEDAL2, "P4 Pedal 2", input_seq(JOYCODE_Z_POS_ABSOLUTE_INDEXED(3)), input_seq(), input_seq(KEYCODE_DEL_PAD, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(3)) ) - INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, PEDAL2, "P5 Pedal 2", input_seq(JOYCODE_Z_POS_ABSOLUTE_INDEXED(4)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(4)) ) - INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, PEDAL2, "P6 Pedal 2", input_seq(JOYCODE_Z_POS_ABSOLUTE_INDEXED(5)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(5)) ) - INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, PEDAL2, "P7 Pedal 2", input_seq(JOYCODE_Z_POS_ABSOLUTE_INDEXED(6)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(6)) ) - INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, PEDAL2, "P8 Pedal 2", input_seq(JOYCODE_Z_POS_ABSOLUTE_INDEXED(7)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(7)) ) - INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, PEDAL2, "P9 Pedal 2", input_seq(JOYCODE_Z_POS_ABSOLUTE_INDEXED(8)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(8)) ) - INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, PEDAL2, "P10 Pedal 2", input_seq(JOYCODE_Z_POS_ABSOLUTE_INDEXED(9)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(9)) ) + INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, PEDAL2, "P1 Pedal 2", input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(0)), input_seq(), input_seq(KEYCODE_LALT, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(0)) ) + INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, PEDAL2, "P2 Pedal 2", input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(1)), input_seq(), input_seq(KEYCODE_S, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(1)) ) + INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, PEDAL2, "P3 Pedal 2", input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(2)), input_seq(), input_seq(KEYCODE_RSHIFT, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(2)) ) + INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, PEDAL2, "P4 Pedal 2", input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(3)), input_seq(), input_seq(KEYCODE_DEL_PAD, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(3)) ) + INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, PEDAL2, "P5 Pedal 2", input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(4)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(4)) ) + INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, PEDAL2, "P6 Pedal 2", input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(5)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(5)) ) + INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, PEDAL2, "P7 Pedal 2", input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(6)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(6)) ) + INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, PEDAL2, "P8 Pedal 2", input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(7)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(7)) ) + INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, PEDAL2, "P9 Pedal 2", input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(8)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(8)) ) + INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, PEDAL2, "P10 Pedal 2", input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(9)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(9)) ) } inline void construct_core_types_pedal3(simple_list<input_type_entry> &typelist) @@ -627,7 +627,7 @@ inline void construct_core_types_paddle_v(simple_list<input_type_entry> &typelis INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, PADDLE_V, "Paddle V 7", input_seq(JOYCODE_Y_INDEXED(6), input_seq::or_code, MOUSECODE_Y_INDEXED(6)), input_seq(), input_seq() ) INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, PADDLE_V, "Paddle V 8", input_seq(JOYCODE_Y_INDEXED(7), input_seq::or_code, MOUSECODE_Y_INDEXED(7)), input_seq(), input_seq() ) INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, PADDLE_V, "Paddle V 9", input_seq(JOYCODE_Y_INDEXED(8), input_seq::or_code, MOUSECODE_Y_INDEXED(8)), input_seq(), input_seq() ) - INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, PADDLE_V, "Paddle V 10", input_seq(JOYCODE_Y_INDEXED(9), input_seq::or_code, MOUSECODE_Y_INDEXED(9)), input_seq(), input_seq() ) + INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, PADDLE_V, "Paddle V 10", input_seq(JOYCODE_Y_INDEXED(9), input_seq::or_code, MOUSECODE_Y_INDEXED(9)), input_seq(), input_seq() ) } inline void construct_core_types_positional(simple_list<input_type_entry> &typelist) diff --git a/src/emu/input.h b/src/emu/input.h index f3e061b37bd..47c9a3276d9 100644 --- a/src/emu/input.h +++ b/src/emu/input.h @@ -830,12 +830,14 @@ private: #define JOYCODE_Z_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_ZAXIS) #define JOYCODE_U_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_RXAXIS) #define JOYCODE_V_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_RYAXIS) +#define JOYCODE_W_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_RZAXIS) #define JOYCODE_X JOYCODE_X_INDEXED(0) #define JOYCODE_Y JOYCODE_Y_INDEXED(0) #define JOYCODE_Z JOYCODE_Z_INDEXED(0) #define JOYCODE_U JOYCODE_U_INDEXED(0) #define JOYCODE_V JOYCODE_V_INDEXED(0) +#define JOYCODE_W JOYCODE_W_INDEXED(0) // joystick axes as absolute half-axes #define JOYCODE_X_POS_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_XAXIS) @@ -848,6 +850,8 @@ private: #define JOYCODE_U_NEG_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_RXAXIS) #define JOYCODE_V_POS_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_RYAXIS) #define JOYCODE_V_NEG_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_RYAXIS) +#define JOYCODE_W_POS_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_RZAXIS) +#define JOYCODE_W_NEG_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_RZAXIS) #define JOYCODE_X_POS_ABSOLUTE JOYCODE_X_POS_ABSOLUTE_INDEXED(0) #define JOYCODE_X_NEG_ABSOLUTE JOYCODE_X_NEG_ABSOLUTE_INDEXED(0) @@ -859,6 +863,8 @@ private: #define JOYCODE_U_NEG_ABSOLUTE JOYCODE_U_NEG_ABSOLUTE_INDEXED(0) #define JOYCODE_V_POS_ABSOLUTE JOYCODE_V_POS_ABSOLUTE_INDEXED(0) #define JOYCODE_V_NEG_ABSOLUTE JOYCODE_V_NEG_ABSOLUTE_INDEXED(0) +#define JOYCODE_W_POS_ABSOLUTE JOYCODE_W_POS_ABSOLUTE_INDEXED(0) +#define JOYCODE_W_NEG_ABSOLUTE JOYCODE_W_NEG_ABSOLUTE_INDEXED(0) // joystick axes as switches; X/Y are specially handled for left/right/up/down mapping #define JOYCODE_X_LEFT_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_LEFT, ITEM_ID_XAXIS) @@ -871,6 +877,8 @@ private: #define JOYCODE_U_NEG_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_RXAXIS) #define JOYCODE_V_POS_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_RYAXIS) #define JOYCODE_V_NEG_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_RYAXIS) +#define JOYCODE_W_POS_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_RZAXIS) +#define JOYCODE_W_NEG_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_RZAXIS) #define JOYCODE_X_LEFT_SWITCH JOYCODE_X_LEFT_SWITCH_INDEXED(0) #define JOYCODE_X_RIGHT_SWITCH JOYCODE_X_RIGHT_SWITCH_INDEXED(0) @@ -882,6 +890,8 @@ private: #define JOYCODE_U_NEG_SWITCH JOYCODE_U_NEG_SWITCH_INDEXED(0) #define JOYCODE_V_POS_SWITCH JOYCODE_V_POS_SWITCH_INDEXED(0) #define JOYCODE_V_NEG_SWITCH JOYCODE_V_NEG_SWITCH_INDEXED(0) +#define JOYCODE_W_POS_SWITCH JOYCODE_W_POS_SWITCH_INDEXED(0) +#define JOYCODE_W_NEG_SWITCH JOYCODE_W_NEG_SWITCH_INDEXED(0) // joystick buttons #define JOYCODE_BUTTON1_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON1) diff --git a/src/emu/ioport.cpp b/src/emu/ioport.cpp index bf241f30b57..d76804a9573 100644 --- a/src/emu/ioport.cpp +++ b/src/emu/ioport.cpp @@ -153,7 +153,7 @@ inline s64 recip_scale(s64 scale) inline s32 apply_scale(s32 value, s64 scale) { - return (s64(value) * scale) >> 24; + return (s64(value) * scale) / (1 << 24); } @@ -616,7 +616,9 @@ ioport_field::ioport_field(ioport_port &port, ioport_type type, ioport_value def // reset sequences and chars for (input_seq_type seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; ++seqtype) m_seq[seqtype].set_default(); - std::fill(std::begin(m_chars), std::end(m_chars), char32_t(0)); + + for (int i = 0; i < ARRAY_LENGTH(m_chars); i++) + std::fill(std::begin(m_chars[i]), std::end(m_chars[i]), char32_t(0)); // for DIP switches and configs, look for a default value from the owner if (type == IPT_DIPSWITCH || type == IPT_CONFIG) @@ -755,16 +757,20 @@ ioport_type_class ioport_field::type_class() const //------------------------------------------------- -// keyboard_code - accesses a particular keyboard -// code +// keyboard_codes - accesses a particular keyboard +// code list //------------------------------------------------- -char32_t ioport_field::keyboard_code(int which) const +std::vector<char32_t> ioport_field::keyboard_codes(int which) const { if (which >= ARRAY_LENGTH(m_chars)) throw emu_fatalerror("Tried to access keyboard_code with out-of-range index %d\n", which); - return m_chars[which]; + std::vector<char32_t> result; + for (int i = 0; i < ARRAY_LENGTH(m_chars[which]) && m_chars[which] != 0; i++) + result.push_back(m_chars[which][i]); + + return result; } @@ -774,7 +780,8 @@ char32_t ioport_field::keyboard_code(int which) const std::string ioport_field::key_name(int which) const { - char32_t ch = keyboard_code(which); + std::vector<char32_t> codes = keyboard_codes(which); + char32_t ch = codes.empty() ? 0 : codes[0]; // attempt to get the string from the character info table switch (ch) @@ -1373,8 +1380,8 @@ ioport_field_live::ioport_field_live(ioport_field &field, analog_field *analog) // loop through each character on the field for (int which = 0; which < 4; which++) { - char32_t const ch = field.keyboard_code(which); - if (ch == 0) + std::vector<char32_t> const codes = field.keyboard_codes(which); + if (codes.empty()) break; name.append(string_format("%-*s ", std::max(SPACE_COUNT - 1, 0), field.key_name(which))); } @@ -3059,16 +3066,27 @@ ioport_configurer& ioport_configurer::field_alloc(ioport_type type, ioport_value // field_add_char - add a character to a field //------------------------------------------------- -ioport_configurer& ioport_configurer::field_add_char(char32_t ch) +ioport_configurer& ioport_configurer::field_add_char(std::initializer_list<char32_t> charlist) { for (int index = 0; index < ARRAY_LENGTH(m_curfield->m_chars); index++) - if (m_curfield->m_chars[index] == 0) + if (m_curfield->m_chars[index][0] == 0) { - m_curfield->m_chars[index] = ch; + const size_t char_count = ARRAY_LENGTH(m_curfield->m_chars[index]); + assert(charlist.size() > 0 && charlist.size() <= char_count); + + for (size_t i = 0; i < char_count; i++) + m_curfield->m_chars[index][i] = i < charlist.size() ? *(charlist.begin() + i) : 0; return *this; } - throw emu_fatalerror("PORT_CHAR(%d) could not be added - maximum amount exceeded\n", ch); + std::ostringstream s; + bool is_first = true; + for (char32_t ch : charlist) + { + util::stream_format(s, "%s%d", is_first ? "" : ",", (int)ch); + is_first = false; + } + throw emu_fatalerror("PORT_CHAR(%s) could not be added - maximum amount exceeded\n", s.str().c_str()); } @@ -3328,10 +3346,6 @@ analog_field::analog_field(ioport_field &field) // single axis that increases from default m_scalepos = compute_scale(m_adjmax - m_adjmin, INPUT_ABSOLUTE_MAX - INPUT_ABSOLUTE_MIN); - // move from default - if (m_adjdefvalue == m_adjmax) - m_scalepos = -m_scalepos; - // make the scaling the same for easier coding when we need to scale m_scaleneg = m_scalepos; @@ -3370,7 +3384,13 @@ analog_field::analog_field(ioport_field &field) // relative controls reverse from 1 past their max range if (m_wraps) - m_reverse_val -= INPUT_RELATIVE_PER_PIXEL; + { + // FIXME: positional needs -1, using INPUT_RELATIVE_PER_PIXEL skips a position (and reads outside the table array) + if(field.type() == IPT_POSITIONAL || field.type() == IPT_POSITIONAL_V) + m_reverse_val --; + else + m_reverse_val -= INPUT_RELATIVE_PER_PIXEL; + } } } @@ -3392,25 +3412,11 @@ inline s32 analog_field::apply_min_max(s32 value) const s32 adjmin = apply_inverse_sensitivity(m_minimum); s32 adjmax = apply_inverse_sensitivity(m_maximum); - // for absolute devices, clamp to the bounds absolutely - if (!m_wraps) - { - if (value > adjmax) - value = adjmax; - else if (value < adjmin) - value = adjmin; - } - - // for relative devices, wrap around when we go past the edge - else - { - s32 range = adjmax - adjmin; - // rolls to other end when 1 position past end. - value = (value - adjmin) % range; - if (value < 0) - value += range; - value += adjmin; - } + // clamp to the bounds absolutely + if (value > adjmax) + value = adjmax; + else if (value < adjmin) + value = adjmin; return value; } @@ -3423,7 +3429,7 @@ inline s32 analog_field::apply_min_max(s32 value) const inline s32 analog_field::apply_sensitivity(s32 value) const { - return s32((s64(value) * m_sensitivity) / 100.0 + 0.5); + return lround((s64(value) * m_sensitivity) / 100.0); } @@ -3446,7 +3452,8 @@ inline s32 analog_field::apply_inverse_sensitivity(s32 value) const s32 analog_field::apply_settings(s32 value) const { // apply the min/max and then the sensitivity - value = apply_min_max(value); + if (!m_wraps) + value = apply_min_max(value); value = apply_sensitivity(value); // apply reversal if needed @@ -3464,6 +3471,18 @@ s32 analog_field::apply_settings(s32 value) const value = apply_scale(value, m_scaleneg); value += m_adjdefvalue; + // for relative devices, wrap around when we go past the edge + // (this is done last to prevent rounding errors) + if (m_wraps) + { + s32 range = m_adjmax - m_adjmin; + // rolls to other end when 1 position past end. + value = (value - m_adjmin) % range; + if (value < 0) + value += range; + value += m_adjmin; + } + return value; } @@ -3475,8 +3494,12 @@ s32 analog_field::apply_settings(s32 value) const void analog_field::frame_update(running_machine &machine) { - // clamp the previous value to the min/max range and remember it - m_previous = m_accum = apply_min_max(m_accum); + // clamp the previous value to the min/max range + if (!m_wraps) + m_accum = apply_min_max(m_accum); + + // remember the previous value in case we need to interpolate + m_previous = m_accum; // get the new raw analog value and its type input_item_class itemclass; diff --git a/src/emu/ioport.h b/src/emu/ioport.h index 0e6932e683e..722c028e4dc 100644 --- a/src/emu/ioport.h +++ b/src/emu/ioport.h @@ -1063,7 +1063,7 @@ public: const ioport_value *remap_table() const { return m_remap_table; } u8 way() const { return m_way; } - char32_t keyboard_code(int which) const; + std::vector<char32_t> keyboard_codes(int which) const; std::string key_name(int which) const; ioport_field_live &live() const { assert(m_live != nullptr); return *m_live; } @@ -1149,7 +1149,7 @@ private: // data relevant to other specific types u8 m_way; // digital joystick 2/4/8-way descriptions - char32_t m_chars[1 << (UCHAR_SHIFT_END - UCHAR_SHIFT_BEGIN + 1)]; // unicode key data + char32_t m_chars[1 << (UCHAR_SHIFT_END - UCHAR_SHIFT_BEGIN + 1)][2]; // unicode key data }; @@ -1501,7 +1501,7 @@ public: // field helpers ioport_configurer& field_alloc(ioport_type type, ioport_value defval, ioport_value mask, const char *name = nullptr); - ioport_configurer& field_add_char(char32_t ch); + ioport_configurer& field_add_char(std::initializer_list<char32_t> charlist); ioport_configurer& field_add_code(input_seq_type which, input_code code); ioport_configurer& field_set_way(int way) { m_curfield->m_way = way; return *this; } ioport_configurer& field_set_rotated() { m_curfield->m_flags |= ioport_field::FIELD_FLAG_ROTATED; return *this; } @@ -1746,8 +1746,8 @@ ATTR_COLD void INPUT_PORTS_NAME(_name)(device_t &owner, ioport_list &portlist, s configurer.setting_alloc((_default), (_name)); // keyboard chars -#define PORT_CHAR(_ch) \ - configurer.field_add_char(_ch); +#define PORT_CHAR(...) \ + configurer.field_add_char({ __VA_ARGS__ }); // name of table diff --git a/src/emu/layout/README.md b/src/emu/layout/README.md index ce23c18751a..76dd0e3435e 100644 --- a/src/emu/layout/README.md +++ b/src/emu/layout/README.md @@ -1,6 +1,6 @@ # **Layout** # -Layouts files are definiton files to describe look and fell of emulated machines, and are product -of many different contributors. +Layout files are definition files to describe the look and feel of emulated machines, and are +the product of many different contributors. Licensed under [CC0 1.0 Universal (CC0 1.0)](https://creativecommons.org/publicdomain/zero/1.0/) diff --git a/src/emu/machine.cpp b/src/emu/machine.cpp index 4af765831d6..fa6375ef937 100644 --- a/src/emu/machine.cpp +++ b/src/emu/machine.cpp @@ -974,6 +974,10 @@ void running_machine::logfile_callback(const char *buffer) void running_machine::start_all_devices() { + // resolve objects first to avoid messy start order dependencies + for (device_t &device : device_iterator(root_device())) + device.resolve_objects(); + m_dummy_space.start(); // iterate through the devices diff --git a/src/emu/natkeyboard.cpp b/src/emu/natkeyboard.cpp index 9defa2f0fa1..2c579b6b894 100644 --- a/src/emu/natkeyboard.cpp +++ b/src/emu/natkeyboard.cpp @@ -580,11 +580,14 @@ void natural_keyboard::build_codes(ioport_manager &manager) { if (field.type() == IPT_KEYBOARD) { - char32_t const code = field.keyboard_code(0); - if ((code >= UCHAR_SHIFT_BEGIN) && (code <= UCHAR_SHIFT_END)) + std::vector<char32_t> const codes = field.keyboard_codes(0); + for (char32_t code : codes) { - mask |= 1U << (code - UCHAR_SHIFT_BEGIN); - shift[code - UCHAR_SHIFT_BEGIN] = &field; + if ((code >= UCHAR_SHIFT_BEGIN) && (code <= UCHAR_SHIFT_END)) + { + mask |= 1U << (code - UCHAR_SHIFT_BEGIN); + shift[code - UCHAR_SHIFT_BEGIN] = &field; + } } } } @@ -603,35 +606,38 @@ void natural_keyboard::build_codes(ioport_manager &manager) if (!(curshift & ~mask)) { // fetch the code, ignoring 0 and shiters - char32_t const code = field.keyboard_code(curshift); - if (((code < UCHAR_SHIFT_BEGIN) || (code > UCHAR_SHIFT_END)) && (code != 0)) + std::vector<char32_t> const codes = field.keyboard_codes(curshift); + for (char32_t code : codes) { - // prefer lowest shift state - keycode_map::iterator const found(m_keycode_map.find(code)); - if ((m_keycode_map.end() == found) || (found->second.shift > curshift)) + if (((code < UCHAR_SHIFT_BEGIN) || (code > UCHAR_SHIFT_END)) && (code != 0)) { - keycode_map_entry newcode; - std::fill(std::begin(newcode.field), std::end(newcode.field), nullptr); - newcode.shift = curshift; - - unsigned fieldnum = 0; - for (unsigned i = 0, bits = curshift; (i < SHIFT_COUNT) && bits; ++i, bits >>= 1) - { - if (BIT(bits, 0)) - newcode.field[fieldnum++] = shift[i]; - } - - assert(fieldnum < ARRAY_LENGTH(newcode.field)); - newcode.field[fieldnum] = &field; - if (m_keycode_map.end() == found) - m_keycode_map.emplace(code, newcode); - else - found->second = newcode; - - if (LOG_NATURAL_KEYBOARD) + // prefer lowest shift state + keycode_map::iterator const found(m_keycode_map.find(code)); + if ((m_keycode_map.end() == found) || (found->second.shift > curshift)) { - machine().logerror("natural_keyboard: code=%u (%s) port=%p field.name='%s'\n", + keycode_map_entry newcode; + std::fill(std::begin(newcode.field), std::end(newcode.field), nullptr); + newcode.shift = curshift; + + unsigned fieldnum = 0; + for (unsigned i = 0, bits = curshift; (i < SHIFT_COUNT) && bits; ++i, bits >>= 1) + { + if (BIT(bits, 0)) + newcode.field[fieldnum++] = shift[i]; + } + + assert(fieldnum < ARRAY_LENGTH(newcode.field)); + newcode.field[fieldnum] = &field; + if (m_keycode_map.end() == found) + m_keycode_map.emplace(code, newcode); + else + found->second = newcode; + + if (LOG_NATURAL_KEYBOARD) + { + machine().logerror("natural_keyboard: code=%u (%s) port=%p field.name='%s'\n", code, unicode_to_string(code), (void *)&port, field.name()); + } } } } diff --git a/src/emu/screen.cpp b/src/emu/screen.cpp index 2d5c177f9b9..52e5cefe37c 100644 --- a/src/emu/screen.cpp +++ b/src/emu/screen.cpp @@ -804,6 +804,39 @@ void screen_device::device_validity_check(validity_checker &valid) const //------------------------------------------------- +// device_resolve_objects - resolve objects that +// may be needed for other devices to set +// initial conditions at start time +//------------------------------------------------- + +void screen_device::device_resolve_objects() +{ + // bind our handlers + m_screen_update_ind16.bind_relative_to(*owner()); + m_screen_update_rgb32.bind_relative_to(*owner()); + m_screen_vblank.resolve_safe(); + + // find the specified palette + if (m_palette_tag != nullptr && m_palette == nullptr) + { + // find our palette as a sibling device + device_t *palette = owner()->subdevice(m_palette_tag); + if (palette == nullptr) + fatalerror("Screen '%s' specifies nonexistent device '%s' as palette\n", + tag(), + m_palette_tag); + if (!palette->interface(m_palette)) + fatalerror("Screen '%s' specifies device '%s' as palette, but it has no palette interface\n", + tag(), + m_palette_tag); + + // assign our format to the palette before it starts + m_palette->m_format = format(); + } +} + + +//------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- @@ -826,13 +859,7 @@ void screen_device::device_start() } } - // bind our handlers - m_screen_update_ind16.bind_relative_to(*owner()); - m_screen_update_rgb32.bind_relative_to(*owner()); - m_screen_vblank.resolve_safe(); - // if we have a palette and it's not started, wait for it - resolve_palette(); if (m_palette != nullptr && !m_palette->device().started()) throw device_missing_dependencies(); @@ -1482,28 +1509,6 @@ void screen_device::register_screen_bitmap(bitmap_t &bitmap) //------------------------------------------------- -// resolve_palette - find the specified palette -//------------------------------------------------- - -void screen_device::resolve_palette() -{ - if (m_palette_tag != nullptr && m_palette == nullptr) - { - // find our palette as a sibling device - device_t *palette = owner()->subdevice(m_palette_tag); - if (palette == nullptr) - fatalerror("Screen '%s' specifies nonexistent device '%s' as palette\n", - tag(), - m_palette_tag); - if (!palette->interface(m_palette)) - fatalerror("Screen '%s' specifies device '%s' as palette, but it has no palette interface\n", - tag(), - m_palette_tag); - } -} - - -//------------------------------------------------- // vblank_begin - call any external callbacks to // signal the VBLANK period has begun //------------------------------------------------- diff --git a/src/emu/screen.h b/src/emu/screen.h index 3da146bac1d..c022c573316 100644 --- a/src/emu/screen.h +++ b/src/emu/screen.h @@ -239,7 +239,6 @@ public: // additional helpers void register_vblank_callback(vblank_state_delegate vblank_callback); void register_screen_bitmap(bitmap_t &bitmap); - void resolve_palette(); // internal to the video system bool update_quads(); @@ -263,6 +262,7 @@ private: // device-level overrides virtual void device_validity_check(validity_checker &valid) const override; + virtual void device_resolve_objects() override; virtual void device_start() override; virtual void device_reset() override; virtual void device_stop() override; diff --git a/src/emu/validity.cpp b/src/emu/validity.cpp index b7b6f0d6f90..dd70af41506 100644 --- a/src/emu/validity.cpp +++ b/src/emu/validity.cpp @@ -770,6 +770,38 @@ void validity_checker::validate_rgb() rgb.mul_imm_rgba(actual_a, actual_r, actual_g, actual_b); check_expected("rgbaint_t::mul_imm_rgba"); + // test select alpha element multiplication + expected_a *= actual_a = random_i32(); + expected_r *= actual_a; + expected_g *= actual_a; + expected_b *= actual_a; + rgb.mul(rgbaint_t(actual_a, actual_r, actual_g, actual_b).select_alpha32()); + check_expected("rgbaint_t::mul(select_alpha32)"); + + // test select red element multiplication + expected_a *= actual_r = random_i32(); + expected_r *= actual_r; + expected_g *= actual_r; + expected_b *= actual_r; + rgb.mul(rgbaint_t(actual_a, actual_r, actual_g, actual_b).select_red32()); + check_expected("rgbaint_t::mul(select_red32)"); + + // test select green element multiplication + expected_a *= actual_g = random_i32(); + expected_r *= actual_g; + expected_g *= actual_g; + expected_b *= actual_g; + rgb.mul(rgbaint_t(actual_a, actual_r, actual_g, actual_b).select_green32()); + check_expected("rgbaint_t::mul(select_green32)"); + + // test select blue element multiplication + expected_a *= actual_b = random_i32(); + expected_r *= actual_b; + expected_g *= actual_b; + expected_b *= actual_b; + rgb.mul(rgbaint_t(actual_a, actual_r, actual_g, actual_b).select_blue32()); + check_expected("rgbaint_t::mul(select_blue32)"); + // test RGB and not expected_a &= ~(actual_a = random_i32()); expected_r &= ~(actual_r = random_i32()); @@ -1844,13 +1876,16 @@ void validity_checker::validate_inputs() // verify natural keyboard codes for (int which = 0; which < 1 << (UCHAR_SHIFT_END - UCHAR_SHIFT_BEGIN + 1); which++) { - char32_t code = field.keyboard_code(which); - if (code && !uchar_isvalid(code)) + std::vector<char32_t> codes = field.keyboard_codes(which); + for (char32_t code : codes) { - osd_printf_error("Field '%s' has non-character U+%04X in PORT_CHAR(%d)\n", - name, - (unsigned)code, - (int)code); + if (!uchar_isvalid(code)) + { + osd_printf_error("Field '%s' has non-character U+%04X in PORT_CHAR(%d)\n", + name, + (unsigned)code, + (int)code); + } } } } diff --git a/src/emu/video/rgbgen.cpp b/src/emu/video/rgbgen.cpp index 09b27090887..1882493b698 100644 --- a/src/emu/video/rgbgen.cpp +++ b/src/emu/video/rgbgen.cpp @@ -77,26 +77,6 @@ void rgbaint_t::scale_and_clamp(const rgbaint_t& scale) } -void rgbaint_t::scale_imm_add_and_clamp(s32 scale, const rgbaint_t& other) -{ - m_a = (m_a * scale) >> 8; - m_r = (m_r * scale) >> 8; - m_g = (m_g * scale) >> 8; - m_b = (m_b * scale) >> 8; - m_a |= (m_a & 0x00800000) ? 0xff000000 : 0; - m_r |= (m_r & 0x00800000) ? 0xff000000 : 0; - m_g |= (m_g & 0x00800000) ? 0xff000000 : 0; - m_b |= (m_b & 0x00800000) ? 0xff000000 : 0; - m_a += other.m_a; - m_r += other.m_r; - m_g += other.m_g; - m_b += other.m_b; - if (u32(m_a) > 255) { m_a = (m_a < 0) ? 0 : 255; } - if (u32(m_r) > 255) { m_r = (m_r < 0) ? 0 : 255; } - if (u32(m_g) > 255) { m_g = (m_g < 0) ? 0 : 255; } - if (u32(m_b) > 255) { m_b = (m_b < 0) ? 0 : 255; } -} - void rgbaint_t::scale_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other) { m_a = (m_a * scale.m_a) >> 8; diff --git a/src/emu/video/rgbgen.h b/src/emu/video/rgbgen.h index 197769946a8..e460208d9fd 100644 --- a/src/emu/video/rgbgen.h +++ b/src/emu/video/rgbgen.h @@ -37,6 +37,12 @@ public: m_b = b; } void set(const rgb_t& rgba) { set(rgba.a(), rgba.r(), rgba.g(), rgba.b()); } + // This function sets all elements to the same val + void set_all(const s32& val) { set(val, val, val, val); } + // This function zeros all elements + void zero() { set_all(0); } + // This function zeros only the alpha element + void zero_alpha() { m_a = 0; } rgb_t to_rgba() const { return rgb_t(get_a(), get_r(), get_g(), get_b()); } @@ -49,6 +55,7 @@ public: return rgb_t(a, r, g, b); } + void set_a16(const s32 value) { m_a = value; } void set_a(const s32 value) { m_a = value; } void set_r(const s32 value) { m_r = value; } void set_g(const s32 value) { m_g = value; } @@ -64,6 +71,12 @@ public: s32 get_g32() const { return m_g; } s32 get_b32() const { return m_b; } + // These selects return an rgbaint_t with all fields set to the element choosen (a, r, g, or b) + rgbaint_t select_alpha32() const { return rgbaint_t(get_a32(), get_a32(), get_a32(), get_a32()); } + rgbaint_t select_red32() const { return rgbaint_t(get_r32(), get_r32(), get_r32(), get_r32()); } + rgbaint_t select_green32() const { return rgbaint_t(get_g32(), get_g32(), get_g32(), get_g32()); } + rgbaint_t select_blue32() const { return rgbaint_t(get_b32(), get_b32(), get_b32(), get_b32()); } + inline void add(const rgbaint_t& color) { add_imm_rgba(color.m_a, color.m_r, color.m_g, color.m_b); @@ -304,7 +317,6 @@ public: void scale_imm_and_clamp(const s32 scale); void scale2_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other, const rgbaint_t& scale2); void scale_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other); - void scale_imm_add_and_clamp(const s32 scale, const rgbaint_t& other); void cmpeq(const rgbaint_t& value) { cmpeq_imm_rgba(value.m_a, value.m_r, value.m_g, value.m_b); } void cmpgt(const rgbaint_t& value) { cmpgt_imm_rgba(value.m_a, value.m_r, value.m_g, value.m_b); } @@ -338,6 +350,11 @@ public: m_b = (m_b < b) ? 0xffffffff : 0; } + void merge_alpha16(const rgbaint_t& alpha) + { + m_a = alpha.m_a; + } + void merge_alpha(const rgbaint_t& alpha) { m_a = alpha.m_a; diff --git a/src/emu/video/rgbsse.h b/src/emu/video/rgbsse.h index 68e57bca7fd..0b1a13c0beb 100644 --- a/src/emu/video/rgbsse.h +++ b/src/emu/video/rgbsse.h @@ -41,6 +41,12 @@ public: void set(const u32& rgba) { m_value = _mm_unpacklo_epi16(_mm_unpacklo_epi8(_mm_cvtsi32_si128(rgba), _mm_setzero_si128()), _mm_setzero_si128()); } void set(s32 a, s32 r, s32 g, s32 b) { m_value = _mm_set_epi32(a, r, g, b); } void set(const rgb_t& rgb) { set((const u32&) rgb); } + // This function sets all elements to the same val + void set_all(const s32& val) { m_value = _mm_set1_epi32(val); } + // This function zeros all elements + void zero() { m_value = _mm_xor_si128(m_value, m_value); } + // This function zeros only the alpha element + void zero_alpha() { m_value = _mm_and_si128(m_value, alpha_mask()); } inline rgb_t to_rgba() const { @@ -52,6 +58,7 @@ public: return _mm_cvtsi128_si32(_mm_packus_epi16(_mm_packs_epi32(m_value, _mm_setzero_si128()), _mm_setzero_si128())); } + void set_a16(const s32 value) { m_value = _mm_insert_epi16(m_value, value, 6); } #ifdef __SSE4_1__ void set_a(const s32 value) { m_value = _mm_insert_epi32(m_value, value, 3); } void set_r(const s32 value) { m_value = _mm_insert_epi32(m_value, value, 2); } @@ -67,7 +74,7 @@ public: u8 get_a() const { return u8(unsigned(_mm_extract_epi16(m_value, 6))); } u8 get_r() const { return u8(unsigned(_mm_extract_epi16(m_value, 4))); } u8 get_g() const { return u8(unsigned(_mm_extract_epi16(m_value, 2))); } - u8 get_b() const { return u8(unsigned(_mm_extract_epi16(m_value, 0))); } + u8 get_b() const { return u8(unsigned(_mm_cvtsi128_si32(m_value))); } #ifdef __SSE4_1__ s32 get_a32() const { return _mm_extract_epi32(m_value, 3); } @@ -75,12 +82,18 @@ public: s32 get_g32() const { return _mm_extract_epi32(m_value, 1); } s32 get_b32() const { return _mm_extract_epi32(m_value, 0); } #else - s32 get_a32() const { return (_mm_extract_epi16(m_value, 7) << 16) | _mm_extract_epi16(m_value, 6); } - s32 get_r32() const { return (_mm_extract_epi16(m_value, 5) << 16) | _mm_extract_epi16(m_value, 4); } - s32 get_g32() const { return (_mm_extract_epi16(m_value, 3) << 16) | _mm_extract_epi16(m_value, 2); } - s32 get_b32() const { return (_mm_extract_epi16(m_value, 1) << 16) | _mm_extract_epi16(m_value, 0); } + s32 get_a32() const { return (_mm_cvtsi128_si32(_mm_shuffle_epi32(m_value, _MM_SHUFFLE(0, 0, 0, 3)))); } + s32 get_r32() const { return (_mm_cvtsi128_si32(_mm_shuffle_epi32(m_value, _MM_SHUFFLE(0, 0, 0, 2)))); } + s32 get_g32() const { return (_mm_cvtsi128_si32(_mm_shuffle_epi32(m_value, _MM_SHUFFLE(0, 0, 0, 1)))); } + s32 get_b32() const { return (_mm_cvtsi128_si32(m_value)); } #endif + // These selects return an rgbaint_t with all fields set to the element choosen (a, r, g, or b) + rgbaint_t select_alpha32() const { return (rgbaint_t)_mm_shuffle_epi32(m_value, _MM_SHUFFLE(3, 3, 3, 3)); } + rgbaint_t select_red32() const { return (rgbaint_t)_mm_shuffle_epi32(m_value, _MM_SHUFFLE(2, 2, 2, 2)); } + rgbaint_t select_green32() const { return (rgbaint_t)_mm_shuffle_epi32(m_value, _MM_SHUFFLE(1, 1, 1, 1)); } + rgbaint_t select_blue32() const { return (rgbaint_t)_mm_shuffle_epi32(m_value, _MM_SHUFFLE(0, 0, 0, 0)); } + inline void add(const rgbaint_t& color2) { m_value = _mm_add_epi32(m_value, color2.m_value); @@ -283,37 +296,74 @@ public: void scale_and_clamp(const rgbaint_t& scale); - inline void scale_imm_and_clamp(const s32 scale) - { - mul_imm(scale); - sra_imm(8); - clamp_to_uint8(); - } - - inline void scale_imm_add_and_clamp(const s32 scale, const rgbaint_t& other) - { - mul_imm(scale); - sra_imm(8); - add(other); - clamp_to_uint8(); + // Leave this here in case Model3 blows up... + //inline void scale_imm_and_clamp(const s32 scale) + //{ + // mul_imm(scale); + // sra_imm(8); + // clamp_to_uint8(); + //} + + // This version needs values to be 12 bits or less + inline void scale_imm_and_clamp(const s16 scale) + { + // Set mult a 16 bit inputs to scale + __m128i immv = _mm_set1_epi16(scale); + // Shift up by 4 + immv = _mm_slli_epi16(immv, 4); + // Pack color into mult b 16 bit inputs + m_value = _mm_packs_epi32(m_value, _mm_setzero_si128()); + // Shift up by 4 + m_value = _mm_slli_epi16(m_value, 4); + // Do the 16 bit multiply, bottom 64 bits will contain 16 bit truncated results + m_value = _mm_mulhi_epi16(m_value, immv); + // Clamp to u8 + m_value = _mm_packus_epi16(m_value, _mm_setzero_si128()); + // Unpack up to s32 + m_value = _mm_unpacklo_epi8(m_value, _mm_setzero_si128()); + m_value = _mm_unpacklo_epi16(m_value, _mm_setzero_si128()); } + // This function needs values to be 12 bits or less inline void scale_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other) { - mul(scale); - sra_imm(8); + // Pack scale into mult a 16 bits + __m128i tmp1 = _mm_packs_epi32(scale.m_value, _mm_setzero_si128()); + // Shift up by 4 + tmp1 = _mm_slli_epi16(tmp1, 4); + // Pack color into mult b 16 bit inputs + m_value = _mm_packs_epi32(m_value, _mm_setzero_si128()); + // Shift up by 4 + m_value = _mm_slli_epi16(m_value, 4); + // Do the 16 bit multiply, bottom 64 bits will contain 16 bit truncated results + m_value = _mm_mulhi_epi16(m_value, tmp1); + // Clamp to u8 + m_value = _mm_packus_epi16(m_value, _mm_setzero_si128()); + // Unpack up to s32 + m_value = _mm_unpacklo_epi8(m_value, _mm_setzero_si128()); + m_value = _mm_unpacklo_epi16(m_value, _mm_setzero_si128()); add(other); clamp_to_uint8(); } + // This function needs values to be 12 bits or less inline void scale2_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other, const rgbaint_t& scale2) { - rgbaint_t color2(other); - color2.mul(scale2); - - mul(scale); - add(color2); - sra_imm(8); + // Pack both scale values into mult a 16 bits + __m128i tmp1 = _mm_packs_epi32(scale.m_value, scale2.m_value); + // Shift up by 4 + tmp1 = _mm_slli_epi16(tmp1, 4); + // Pack both color values into mult b 16 bit inputs + m_value = _mm_packs_epi32(m_value, other.m_value); + // Shift up by 4 + m_value = _mm_slli_epi16(m_value, 4); + // Do the 16 bit multiply, top and bottom 64 bits will contain 16 bit truncated results + tmp1 = _mm_mulhi_epi16(m_value, tmp1); + // Unpack the results + m_value = _mm_unpacklo_epi16(tmp1, _mm_setzero_si128()); + tmp1 = _mm_unpackhi_epi16(tmp1, _mm_setzero_si128()); + // Add the results + m_value = _mm_add_epi32(m_value, tmp1); clamp_to_uint8(); } @@ -366,6 +416,11 @@ public: return *this; } + inline void merge_alpha16(const rgbaint_t& alpha) + { + m_value = _mm_insert_epi16(m_value, _mm_extract_epi16(alpha.m_value, 6), 6); + } + inline void merge_alpha(const rgbaint_t& alpha) { #ifdef __SSE4_1__ diff --git a/src/emu/video/rgbutil.h b/src/emu/video/rgbutil.h index e0ccd299a4e..74f425e3417 100644 --- a/src/emu/video/rgbutil.h +++ b/src/emu/video/rgbutil.h @@ -14,6 +14,7 @@ // use SSE on 64-bit implementations, where it can be assumed #if (!defined(MAME_DEBUG) || defined(__OPTIMIZE__)) && (defined(__SSE2__) || defined(_MSC_VER)) && defined(PTR64) + #include "rgbsse.h" #elif defined(__ALTIVEC__) #include "rgbvmx.h" diff --git a/src/emu/video/rgbvmx.h b/src/emu/video/rgbvmx.h index 824e8dd3799..05d26cd9e21 100644 --- a/src/emu/video/rgbvmx.h +++ b/src/emu/video/rgbvmx.h @@ -75,6 +75,13 @@ public: #endif } + // This function sets all elements to the same val + void set_all(const s32& val) { set(val, val, val, val); } + // This function zeros all elements + void zero() { set_all(0); } + // This function zeros only the alpha element + void zero_alpha() { set_a(0); } + inline rgb_t to_rgba() const { VECU32 temp = VECU32(vec_packs(m_value, m_value)); @@ -93,6 +100,12 @@ public: return result; } + void set_a16(const s32 value) + { + const VECS32 temp = { value, value, value, value }; + m_value = vec_perm(m_value, temp, alpha_perm); + } + void set_a(const s32 value) { const VECS32 temp = { value, value, value, value }; @@ -205,6 +218,12 @@ public: return result; } + // These selects return an rgbaint_t with all fields set to the element choosen (a, r, g, or b) + rgbaint_t select_alpha32() const { return rgbaint_t(get_a32(), get_a32(), get_a32(), get_a32()); } + rgbaint_t select_red32() const { return rgbaint_t(get_r32(), get_r32(), get_r32(), get_r32()); } + rgbaint_t select_green32() const { return rgbaint_t(get_g32(), get_g32(), get_g32(), get_g32()); } + rgbaint_t select_blue32() const { return rgbaint_t(get_b32(), get_b32(), get_b32(), get_b32()); } + inline void add(const rgbaint_t& color2) { m_value = vec_add(m_value, color2.m_value); @@ -460,14 +479,6 @@ public: void scale_and_clamp(const rgbaint_t& scale); void scale_imm_and_clamp(const s32 scale); - void scale_imm_add_and_clamp(const s32 scale, const rgbaint_t& other) - { - mul_imm(scale); - sra_imm(8); - add(other); - clamp_to_uint8(); - } - void scale_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other) { mul(scale); @@ -601,6 +612,11 @@ public: return *this; } + inline void merge_alpha16(const rgbaint_t& alpha) + { + m_value = vec_perm(m_value, alpha.m_value, alpha_perm); + } + inline void merge_alpha(const rgbaint_t& alpha) { m_value = vec_perm(m_value, alpha.m_value, alpha_perm); |