diff options
Diffstat (limited to 'src/emu')
42 files changed, 3215 insertions, 1595 deletions
diff --git a/src/emu/addrmap.cpp b/src/emu/addrmap.cpp index 0d8d7bc4eef..5f717f3f79a 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); } @@ -609,8 +605,8 @@ 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 datawidth = spaceconfig.m_data_width; + int alignunit = spaceconfig.alignment(); bool detected_overlap = DETECT_OVERLAPPING_MEMORY ? false : true; @@ -624,16 +620,13 @@ void address_map::map_validity_check(validity_checker &valid, int spacenum) cons if (m_databits != datawidth) osd_printf_error("Wrong memory handlers provided for %s space! (width = %d, memory = %08x)\n", spaceconfig.m_name, datawidth, m_databits); - offs_t globalmask = 0xffffffffUL >> (32 - spaceconfig.m_addrbus_width); + offs_t globalmask = 0xffffffffUL >> (32 - spaceconfig.m_addr_width); if (m_globalmask != 0) globalmask = m_globalmask; // 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..bd24f475340 --- /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->addr_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..38bff17b8c4 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" @@ -99,15 +100,15 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu , m_cpu(cpu) , m_console(console) { - m_global_array = auto_alloc_array_clear(m_machine, global_entry, MAX_GLOBALS); + m_global_array = std::make_unique<global_entry []>(MAX_GLOBALS); symbol_table *symtable = m_cpu.get_global_symtable(); /* add a few simple global functions */ using namespace std::placeholders; - symtable->add("min", nullptr, 2, 2, std::bind(&debugger_commands::execute_min, this, _1, _2, _3, _4)); - symtable->add("max", nullptr, 2, 2, std::bind(&debugger_commands::execute_max, this, _1, _2, _3, _4)); - symtable->add("if", nullptr, 3, 3, std::bind(&debugger_commands::execute_if, this, _1, _2, _3, _4)); + symtable->add("min", 2, 2, std::bind(&debugger_commands::execute_min, this, _1, _2, _3)); + symtable->add("max", 2, 2, std::bind(&debugger_commands::execute_max, this, _1, _2, _3)); + symtable->add("if", 3, 3, std::bind(&debugger_commands::execute_if, this, _1, _2, _3)); /* add all single-entry save state globals */ for (int itemnum = 0; itemnum < MAX_GLOBALS; itemnum++) @@ -127,7 +128,10 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu sprintf(symname, ".%s", strrchr(name, '/') + 1); m_global_array[itemnum].base = base; m_global_array[itemnum].size = valsize; - symtable->add(symname, &m_global_array, std::bind(&debugger_commands::global_get, this, _1, _2), std::bind(&debugger_commands::global_set, this, _1, _2, _3)); + symtable->add( + symname, + std::bind(&debugger_commands::global_get, this, _1, &m_global_array[itemnum]), + std::bind(&debugger_commands::global_set, this, _1, &m_global_array[itemnum], _2)); } } @@ -292,7 +296,7 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu execute_min - return the minimum of two values -------------------------------------------------*/ -u64 debugger_commands::execute_min(symbol_table &table, void *ref, int params, const u64 *param) +u64 debugger_commands::execute_min(symbol_table &table, int params, const u64 *param) { return (param[0] < param[1]) ? param[0] : param[1]; } @@ -302,7 +306,7 @@ u64 debugger_commands::execute_min(symbol_table &table, void *ref, int params, c execute_max - return the maximum of two values -------------------------------------------------*/ -u64 debugger_commands::execute_max(symbol_table &table, void *ref, int params, const u64 *param) +u64 debugger_commands::execute_max(symbol_table &table, int params, const u64 *param) { return (param[0] > param[1]) ? param[0] : param[1]; } @@ -312,7 +316,7 @@ u64 debugger_commands::execute_max(symbol_table &table, void *ref, int params, c execute_if - if (a) return b; else return c; -------------------------------------------------*/ -u64 debugger_commands::execute_if(symbol_table &table, void *ref, int params, const u64 *param) +u64 debugger_commands::execute_if(symbol_table &table, int params, const u64 *param) { return param[0] ? param[1] : param[2]; } @@ -327,9 +331,8 @@ u64 debugger_commands::execute_if(symbol_table &table, void *ref, int params, co global_get - symbol table getter for globals -------------------------------------------------*/ -u64 debugger_commands::global_get(symbol_table &table, void *ref) +u64 debugger_commands::global_get(symbol_table &table, global_entry *global) { - global_entry *global = (global_entry *)ref; switch (global->size) { case 1: return *(u8 *)global->base; @@ -345,9 +348,8 @@ u64 debugger_commands::global_get(symbol_table &table, void *ref) global_set - symbol table setter for globals -------------------------------------------------*/ -void debugger_commands::global_set(symbol_table &table, void *ref, u64 value) +void debugger_commands::global_set(symbol_table &table, global_entry *global, u64 value) { - global_entry *global = (global_entry *)ref; switch (global->size) { case 1: *(u8 *)global->base = value; break; @@ -760,7 +762,7 @@ void debugger_commands::execute_tracesym(int ref, const std::vector<std::string> void debugger_commands::execute_quit(int ref, const std::vector<std::string> ¶ms) { - osd_printf_error("Exited via the debugger\n"); + osd_printf_warning("Exited via the debugger\n"); m_machine.schedule_exit(); } @@ -1644,7 +1646,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 +1656,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 +1669,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->addr_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 +1725,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 +1749,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->addr_shift() < 0) + length >>= -space->addr_shift(); + else if (space->addr_shift() > 0) + length <<= space->addr_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->addr_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 +1851,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->addr_shift(); + u64 granularity = shift > 0 ? 2 : 1 << -shift; + /* further validation */ if (width == 0) width = space->data_width() / 8; @@ -1777,14 +1864,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 +1889,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 +1914,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 +1948,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 +2052,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 +2076,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 +2452,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->addr_shift() > 0 ? 2 : 1 << -space->addr_shift(); if (cur_data_size == 0) cur_data_size = 1; @@ -2403,10 +2535,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 +2546,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 +2554,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 +2733,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 +2754,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 +2965,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 +2973,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/debugcmd.h b/src/emu/debug/debugcmd.h index 7eca669908e..98b6d8ae03d 100644 --- a/src/emu/debug/debugcmd.h +++ b/src/emu/debug/debugcmd.h @@ -37,8 +37,10 @@ public: private: struct global_entry { - void * base; - u32 size; + global_entry() { } + + void * base = nullptr; + u32 size = 0; }; @@ -79,12 +81,12 @@ private: u64 cheat_byte_swap(const cheat_system *cheatsys, u64 value); u64 cheat_read_extended(const cheat_system *cheatsys, address_space &space, offs_t address); - u64 execute_min(symbol_table &table, void *ref, int params, const u64 *param); - u64 execute_max(symbol_table &table, void *ref, int params, const u64 *param); - u64 execute_if(symbol_table &table, void *ref, int params, const u64 *param); + u64 execute_min(symbol_table &table, int params, const u64 *param); + u64 execute_max(symbol_table &table, int params, const u64 *param); + u64 execute_if(symbol_table &table, int params, const u64 *param); - u64 global_get(symbol_table &table, void *ref); - void global_set(symbol_table &table, void *ref, u64 value); + u64 global_get(symbol_table &table, global_entry *global); + void global_set(symbol_table &table, global_entry *global, u64 value); int mini_printf(char *buffer, const char *format, int params, u64 *param); @@ -162,7 +164,7 @@ private: debugger_cpu& m_cpu; debugger_console& m_console; - global_entry *m_global_array; + std::unique_ptr<global_entry []> m_global_array; cheat_system m_cheat; static const size_t MAX_GLOBALS; diff --git a/src/emu/debug/debugcpu.cpp b/src/emu/debug/debugcpu.cpp index 0289ef7f664..eab6f7771e7 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" @@ -48,6 +49,7 @@ debugger_cpu::debugger_cpu(running_machine &machine) , m_breakcpu(nullptr) , m_symtable(nullptr) , m_execution_state(EXECUTION_STATE_STOPPED) + , m_stop_when_not_device(nullptr) , m_bpindex(1) , m_wpindex(1) , m_rpindex(1) @@ -71,10 +73,10 @@ debugger_cpu::debugger_cpu(running_machine &machine) m_symtable->add("wpdata", symbol_table::READ_ONLY, &m_wpdata); using namespace std::placeholders; - m_symtable->add("cpunum", nullptr, std::bind(&debugger_cpu::get_cpunum, this, _1, _2)); - m_symtable->add("beamx", (void *)first_screen, std::bind(&debugger_cpu::get_beamx, this, _1, _2)); - m_symtable->add("beamy", (void *)first_screen, std::bind(&debugger_cpu::get_beamy, this, _1, _2)); - m_symtable->add("frame", (void *)first_screen, std::bind(&debugger_cpu::get_frame, this, _1, _2)); + m_symtable->add("cpunum", std::bind(&debugger_cpu::get_cpunum, this, _1)); + m_symtable->add("beamx", std::bind(&debugger_cpu::get_beamx, this, _1, first_screen)); + m_symtable->add("beamy", std::bind(&debugger_cpu::get_beamy, this, _1, first_screen)); + m_symtable->add("frame", std::bind(&debugger_cpu::get_frame, this, _1, first_screen)); /* add the temporary variables to the global symbol table */ for (int regnum = 0; regnum < NUM_TEMP_VARIABLES; regnum++) @@ -363,7 +365,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 +390,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 +431,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 +471,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 +533,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 +555,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 +598,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 +641,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 +705,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 +725,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) @@ -1340,9 +1342,8 @@ expression_error::error_code debugger_cpu::expression_validate(void *param, cons get_beamx - get beam horizontal position -------------------------------------------------*/ -u64 debugger_cpu::get_beamx(symbol_table &table, void *ref) +u64 debugger_cpu::get_beamx(symbol_table &table, screen_device *screen) { - screen_device *screen = reinterpret_cast<screen_device *>(ref); return (screen != nullptr) ? screen->hpos() : 0; } @@ -1351,9 +1352,8 @@ u64 debugger_cpu::get_beamx(symbol_table &table, void *ref) get_beamy - get beam vertical position -------------------------------------------------*/ -u64 debugger_cpu::get_beamy(symbol_table &table, void *ref) +u64 debugger_cpu::get_beamy(symbol_table &table, screen_device *screen) { - screen_device *screen = reinterpret_cast<screen_device *>(ref); return (screen != nullptr) ? screen->vpos() : 0; } @@ -1362,9 +1362,8 @@ u64 debugger_cpu::get_beamy(symbol_table &table, void *ref) get_frame - get current frame number -------------------------------------------------*/ -u64 debugger_cpu::get_frame(symbol_table &table, void *ref) +u64 debugger_cpu::get_frame(symbol_table &table, screen_device *screen) { - screen_device *screen = reinterpret_cast<screen_device *>(ref); return (screen != nullptr) ? screen->frame_number() : 0; } @@ -1374,7 +1373,7 @@ u64 debugger_cpu::get_frame(symbol_table &table, void *ref) 'cpunum' symbol -------------------------------------------------*/ -u64 debugger_cpu::get_cpunum(symbol_table &table, void *ref) +u64 debugger_cpu::get_cpunum(symbol_table &table) { execute_interface_iterator iter(m_machine.root_device()); return iter.indexof(m_visiblecpu->execute()); @@ -1537,22 +1536,34 @@ device_debug::device_debug(device_t &device) // add global symbol for cycles and totalcycles if (m_exec != nullptr) { - m_symtable.add("cycles", nullptr, get_cycles); - m_symtable.add("totalcycles", nullptr, get_totalcycles); - m_symtable.add("lastinstructioncycles", nullptr, get_lastinstructioncycles); + m_symtable.add("cycles", get_cycles); + m_symtable.add("totalcycles", get_totalcycles); + m_symtable.add("lastinstructioncycles", get_lastinstructioncycles); } // add entries to enable/disable unmap reporting for each space if (m_memory != nullptr) { if (m_memory->has_space(AS_PROGRAM)) - m_symtable.add("logunmap", (void *)&m_memory->space(AS_PROGRAM), get_logunmap, set_logunmap); + m_symtable.add( + "logunmap", + [&space = m_memory->space(AS_PROGRAM)] (symbol_table &table) { return space.log_unmap(); }, + [&space = m_memory->space(AS_PROGRAM)] (symbol_table &table, u64 value) { return space.set_log_unmap(bool(value)); }); if (m_memory->has_space(AS_DATA)) - m_symtable.add("logunmapd", (void *)&m_memory->space(AS_DATA), get_logunmap, set_logunmap); + m_symtable.add( + "logunmap", + [&space = m_memory->space(AS_DATA)] (symbol_table &table) { return space.log_unmap(); }, + [&space = m_memory->space(AS_DATA)] (symbol_table &table, u64 value) { return space.set_log_unmap(bool(value)); }); if (m_memory->has_space(AS_IO)) - m_symtable.add("logunmapi", (void *)&m_memory->space(AS_IO), get_logunmap, set_logunmap); + m_symtable.add( + "logunmap", + [&space = m_memory->space(AS_IO)] (symbol_table &table) { return space.log_unmap(); }, + [&space = m_memory->space(AS_IO)] (symbol_table &table, u64 value) { return space.set_log_unmap(bool(value)); }); if (m_memory->has_space(AS_OPCODES)) - m_symtable.add("logunmapo", (void *)&m_memory->space(AS_OPCODES), get_logunmap, set_logunmap); + m_symtable.add( + "logunmap", + [&space = m_memory->space(AS_OPCODES)] (symbol_table &table) { return space.log_unmap(); }, + [&space = m_memory->space(AS_OPCODES)] (symbol_table &table, u64 value) { return space.set_log_unmap(bool(value)); }); } // add all registers into it @@ -1562,8 +1573,13 @@ device_debug::device_debug(device_t &device) // TODO: floating point registers if (!entry->is_float()) { + using namespace std::placeholders; 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()); + m_symtable.add( + tempstr.c_str(), + std::bind(&device_debug::get_state, _1, entry->index()), + entry->writeable() ? std::bind(&device_debug::set_state, _1, entry->index(), _2) : symbol_table::setter_func(nullptr), + entry->format_string()); } } } @@ -1574,8 +1590,8 @@ device_debug::device_debug(device_t &device) m_flags = DEBUG_FLAG_OBSERVING | DEBUG_FLAG_HISTORY; // if no curpc, add one - if (m_state != nullptr && m_symtable.find("curpc") == nullptr) - m_symtable.add("curpc", nullptr, get_current_pc); + if (m_state && !m_symtable.find("curpc")) + m_symtable.add("curpc", get_current_pc); } // set up trace @@ -2487,33 +2503,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); + std::vector<u8> opbuf; + debug_disasm_buffer buffer(device()); - // 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); - } - - 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()); } @@ -2593,26 +2591,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; @@ -2885,43 +2886,11 @@ 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 //------------------------------------------------- -u64 device_debug::get_current_pc(symbol_table &table, void *ref) +u64 device_debug::get_current_pc(symbol_table &table) { device_t *device = reinterpret_cast<device_t *>(table.globalref()); return device->safe_pcbase(); @@ -2933,7 +2902,7 @@ u64 device_debug::get_current_pc(symbol_table &table, void *ref) // 'cycles' symbol //------------------------------------------------- -u64 device_debug::get_cycles(symbol_table &table, void *ref) +u64 device_debug::get_cycles(symbol_table &table) { device_t *device = reinterpret_cast<device_t *>(table.globalref()); return device->debug()->m_exec->cycles_remaining(); @@ -2945,7 +2914,7 @@ u64 device_debug::get_cycles(symbol_table &table, void *ref) // 'totalcycles' symbol //------------------------------------------------- -u64 device_debug::get_totalcycles(symbol_table &table, void *ref) +u64 device_debug::get_totalcycles(symbol_table &table) { device_t *device = reinterpret_cast<device_t *>(table.globalref()); return device->debug()->m_total_cycles; @@ -2957,7 +2926,7 @@ u64 device_debug::get_totalcycles(symbol_table &table, void *ref) // 'lastinstructioncycles' symbol //------------------------------------------------- -u64 device_debug::get_lastinstructioncycles(symbol_table &table, void *ref) +u64 device_debug::get_lastinstructioncycles(symbol_table &table) { device_t *device = reinterpret_cast<device_t *>(table.globalref()); device_debug *debug = device->debug(); @@ -2966,38 +2935,14 @@ u64 device_debug::get_lastinstructioncycles(symbol_table &table, void *ref) //------------------------------------------------- -// get_logunmap - getter callback for the logumap -// symbols -//------------------------------------------------- - -u64 device_debug::get_logunmap(symbol_table &table, void *ref) -{ - address_space &space = *reinterpret_cast<address_space *>(table.globalref()); - return space.log_unmap(); -} - - -//------------------------------------------------- -// set_logunmap - setter callback for the logumap -// symbols -//------------------------------------------------- - -void device_debug::set_logunmap(symbol_table &table, void *ref, u64 value) -{ - address_space &space = *reinterpret_cast<address_space *>(table.globalref()); - space.set_log_unmap(value ? true : false); -} - - -//------------------------------------------------- // get_state - getter callback for a device's // state symbols //------------------------------------------------- -u64 device_debug::get_state(symbol_table &table, void *ref) +u64 device_debug::get_state(symbol_table &table, int index) { device_t *device = reinterpret_cast<device_t *>(table.globalref()); - return device->debug()->m_state->state_int(reinterpret_cast<uintptr_t>(ref)); + return device->debug()->m_state->state_int(index); } @@ -3006,10 +2951,10 @@ u64 device_debug::get_state(symbol_table &table, void *ref) // state symbols //------------------------------------------------- -void device_debug::set_state(symbol_table &table, void *ref, u64 value) +void device_debug::set_state(symbol_table &table, int index, u64 value) { device_t *device = reinterpret_cast<device_t *>(table.globalref()); - device->debug()->m_state->set_state_int(reinterpret_cast<uintptr_t>(ref), value); + device->debug()->m_state->set_state_int(index, value); } @@ -3094,8 +3039,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 : "") { @@ -3257,35 +3202,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..388e497cb0a 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 @@ -289,14 +288,12 @@ private: void hotspot_check(address_space &space, offs_t address); // symbol get/set callbacks - static u64 get_current_pc(symbol_table &table, void *ref); - static u64 get_cycles(symbol_table &table, void *ref); - static u64 get_totalcycles(symbol_table &table, void *ref); - static u64 get_lastinstructioncycles(symbol_table &table, void *ref); - static u64 get_logunmap(symbol_table &table, void *ref); - static void set_logunmap(symbol_table &table, void *ref, u64 value); - static u64 get_state(symbol_table &table, void *ref); - static void set_state(symbol_table &table, void *ref, u64 value); + static u64 get_current_pc(symbol_table &table); + static u64 get_cycles(symbol_table &table); + static u64 get_totalcycles(symbol_table &table); + static u64 get_lastinstructioncycles(symbol_table &table); + static u64 get_state(symbol_table &table, int index); + static void set_state(symbol_table &table, int index, u64 value); // basic device information device_t & m_device; // device we are attached to @@ -586,10 +583,10 @@ private: device_t* expression_get_device(const char *tag); /* variable getters/setters */ - u64 get_cpunum(symbol_table &table, void *ref); - u64 get_beamx(symbol_table &table, void *ref); - u64 get_beamy(symbol_table &table, void *ref); - u64 get_frame(symbol_table &table, void *ref); + u64 get_cpunum(symbol_table &table); + u64 get_beamx(symbol_table &table, screen_device *screen); + u64 get_beamy(symbol_table &table, screen_device *screen); + u64 get_frame(symbol_table &table, screen_device *screen); /* internal helpers */ void on_vblank(screen_device &device, bool vblank_state); diff --git a/src/emu/debug/debugvw.h b/src/emu/debug/debugvw.h index d456eacdbeb..374af7f384e 100644 --- a/src/emu/debug/debugvw.h +++ b/src/emu/debug/debugvw.h @@ -158,7 +158,7 @@ public: void set_visible_position(debug_view_xy pos); void set_cursor_position(debug_view_xy pos); void set_cursor_visible(bool visible = true); - void set_source(const debug_view_source &source); + virtual void set_source(const debug_view_source &source); // helpers void process_char(int character) { view_char(character); } diff --git a/src/emu/debug/dvdisasm.cpp b/src/emu/debug/dvdisasm.cpp index 1051365c561..2292e766132 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.addr_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; + // determine how many characters we need for an address and set the divider + int m_divider1 = 1 + m_dasm[0].m_tadr.size() + 1; - recompute(backpc, 0, m_total.y); - } - recomputed_this_time = true; - } + // assume a fixed number of characters for the disassembly + int m_divider2 = m_divider1 + 1 + m_dasm_width + 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; - } - - // 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,12 +551,21 @@ 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; } } + +//------------------------------------------------- +// set_source - set the current subview +//------------------------------------------------- + +void debug_view_disasm::set_source(const debug_view_source &source) +{ + debug_view::set_source(source); + m_dasm.clear(); +} diff --git a/src/emu/debug/dvdisasm.h b/src/emu/debug/dvdisasm.h index 85ebd7cfef2..ef9e4209f1b 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 }; @@ -80,6 +80,7 @@ public: void set_backward_steps(u32 steps); void set_disasm_width(u32 width); void set_selected_address(offs_t address); + virtual void set_source(const debug_view_source &source) override; protected: // view overrides @@ -90,49 +91,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/debug/express.cpp b/src/emu/debug/express.cpp index 9661d80a35a..06e12e09800 100644 --- a/src/emu/debug/express.cpp +++ b/src/emu/debug/express.cpp @@ -114,7 +114,7 @@ public: // construction/destruction integer_symbol_entry(symbol_table &table, const char *name, symbol_table::read_write rw, u64 *ptr = nullptr); integer_symbol_entry(symbol_table &table, const char *name, u64 constval); - integer_symbol_entry(symbol_table &table, const char *name, void *ref, symbol_table::getter_func getter, symbol_table::setter_func setter, const std::string &format); + integer_symbol_entry(symbol_table &table, const char *name, symbol_table::getter_func getter, symbol_table::setter_func setter, const std::string &format); // symbol access virtual bool is_lval() const override; @@ -122,10 +122,6 @@ public: virtual void set_value(u64 newvalue) override; private: - // internal helpers - static u64 internal_getter(symbol_table &table, void *symref); - static void internal_setter(symbol_table &table, void *symref, u64 value); - // internal state symbol_table::getter_func m_getter; symbol_table::setter_func m_setter; @@ -138,7 +134,7 @@ class function_symbol_entry : public symbol_entry { public: // construction/destruction - function_symbol_entry(symbol_table &table, const char *name, void *ref, int minparams, int maxparams, symbol_table::execute_func execute); + function_symbol_entry(symbol_table &table, const char *name, int minparams, int maxparams, symbol_table::execute_func execute); // symbol access virtual bool is_lval() const override; @@ -203,13 +199,12 @@ const char *expression_error::code_string() const // symbol_entry - constructor //------------------------------------------------- -symbol_entry::symbol_entry(symbol_table &table, symbol_type type, const char *name, const std::string &format, void *ref) +symbol_entry::symbol_entry(symbol_table &table, symbol_type type, const char *name, const std::string &format) : m_next(nullptr), m_table(table), m_type(type), m_name(name), - m_format(format), - m_ref(ref) + m_format(format) { } @@ -233,25 +228,31 @@ symbol_entry::~symbol_entry() //------------------------------------------------- integer_symbol_entry::integer_symbol_entry(symbol_table &table, const char *name, symbol_table::read_write rw, u64 *ptr) - : symbol_entry(table, SMT_INTEGER, name, "", (ptr == nullptr) ? &m_value : ptr), - m_getter(internal_getter), - m_setter((rw == symbol_table::READ_ONLY) ? nullptr : internal_setter), + : symbol_entry(table, SMT_INTEGER, name, ""), + m_getter(ptr + ? symbol_table::getter_func([ptr] (symbol_table &table) { return *ptr; }) + : symbol_table::getter_func([this] (symbol_table &table) { return m_value; })), + m_setter((rw == symbol_table::READ_ONLY) + ? symbol_table::setter_func(nullptr) + : ptr + ? symbol_table::setter_func([ptr] (symbol_table &table, u64 value) { *ptr = value; }) + : symbol_table::setter_func([this] (symbol_table &table, u64 value) { m_value = value; })), m_value(0) { } integer_symbol_entry::integer_symbol_entry(symbol_table &table, const char *name, u64 constval) - : symbol_entry(table, SMT_INTEGER, name, "", &m_value), - m_getter(internal_getter), + : symbol_entry(table, SMT_INTEGER, name, ""), + m_getter([this] (symbol_table &table) { return m_value; }), m_setter(nullptr), m_value(constval) { } -integer_symbol_entry::integer_symbol_entry(symbol_table &table, const char *name, void *ref, symbol_table::getter_func getter, symbol_table::setter_func setter, const std::string &format) - : symbol_entry(table, SMT_INTEGER, name, format, ref), +integer_symbol_entry::integer_symbol_entry(symbol_table &table, const char *name, symbol_table::getter_func getter, symbol_table::setter_func setter, const std::string &format) + : symbol_entry(table, SMT_INTEGER, name, format), m_getter(getter), m_setter(setter), m_value(0) @@ -275,7 +276,7 @@ bool integer_symbol_entry::is_lval() const u64 integer_symbol_entry::value() const { - return m_getter(m_table, m_ref); + return m_getter(m_table); } @@ -286,34 +287,12 @@ u64 integer_symbol_entry::value() const void integer_symbol_entry::set_value(u64 newvalue) { if (m_setter != nullptr) - m_setter(m_table, m_ref, newvalue); + m_setter(m_table, newvalue); else throw emu_fatalerror("Symbol '%s' is read-only", m_name.c_str()); } -//------------------------------------------------- -// internal_getter - internal helper for -// returning the value of a variable -//------------------------------------------------- - -u64 integer_symbol_entry::internal_getter(symbol_table &table, void *symref) -{ - return *(u64 *)symref; -} - - -//------------------------------------------------- -// internal_setter - internal helper for setting -// the value of a variable -//------------------------------------------------- - -void integer_symbol_entry::internal_setter(symbol_table &table, void *symref, u64 value) -{ - *(u64 *)symref = value; -} - - //************************************************************************** // FUNCTION SYMBOL ENTRY @@ -323,8 +302,8 @@ void integer_symbol_entry::internal_setter(symbol_table &table, void *symref, u6 // function_symbol_entry - constructor //------------------------------------------------- -function_symbol_entry::function_symbol_entry(symbol_table &table, const char *name, void *ref, int minparams, int maxparams, symbol_table::execute_func execute) - : symbol_entry(table, SMT_FUNCTION, name, "", ref), +function_symbol_entry::function_symbol_entry(symbol_table &table, const char *name, int minparams, int maxparams, symbol_table::execute_func execute) + : symbol_entry(table, SMT_FUNCTION, name, ""), m_minparams(minparams), m_maxparams(maxparams), m_execute(execute) @@ -372,7 +351,7 @@ u64 function_symbol_entry::execute(int numparams, const u64 *paramlist) throw emu_fatalerror("Function '%s' requires at least %d parameters", m_name.c_str(), m_minparams); if (numparams > m_maxparams) throw emu_fatalerror("Function '%s' accepts no more than %d parameters", m_name.c_str(), m_maxparams); - return m_execute(m_table, m_ref, numparams, paramlist); + return m_execute(m_table, numparams, paramlist); } @@ -435,10 +414,10 @@ void symbol_table::add(const char *name, u64 value) // add - add a new register symbol //------------------------------------------------- -void symbol_table::add(const char *name, void *ref, getter_func getter, setter_func setter, const std::string &format_string) +void symbol_table::add(const char *name, getter_func getter, setter_func setter, const std::string &format_string) { m_symlist.erase(name); - m_symlist.emplace(name, std::make_unique<integer_symbol_entry>(*this, name, ref, getter, setter, format_string)); + m_symlist.emplace(name, std::make_unique<integer_symbol_entry>(*this, name, getter, setter, format_string)); } @@ -446,10 +425,10 @@ void symbol_table::add(const char *name, void *ref, getter_func getter, setter_f // add - add a new function symbol //------------------------------------------------- -void symbol_table::add(const char *name, void *ref, int minparams, int maxparams, execute_func execute) +void symbol_table::add(const char *name, int minparams, int maxparams, execute_func execute) { m_symlist.erase(name); - m_symlist.emplace(name, std::make_unique<function_symbol_entry>(*this, name, ref, minparams, maxparams, execute)); + m_symlist.emplace(name, std::make_unique<function_symbol_entry>(*this, name, minparams, maxparams, execute)); } diff --git a/src/emu/debug/express.h b/src/emu/debug/express.h index 19381786d1b..8084cf84e8f 100644 --- a/src/emu/debug/express.h +++ b/src/emu/debug/express.h @@ -114,7 +114,7 @@ protected: }; // construction/destruction - symbol_entry(symbol_table &table, symbol_type type, const char *name, const std::string &format, void *ref); + symbol_entry(symbol_table &table, symbol_type type, const char *name, const std::string &format); public: virtual ~symbol_entry(); @@ -138,7 +138,6 @@ protected: symbol_type m_type; // type of symbol std::string m_name; // name of the symbol std::string m_format; // format of symbol (or empty if unspecified) - void * m_ref; // internal reference }; @@ -150,11 +149,11 @@ class symbol_table { public: // callback functions for getting/setting a symbol value - typedef std::function<u64(symbol_table &table, void *symref)> getter_func; - typedef std::function<void(symbol_table &table, void *symref, u64 value)> setter_func; + typedef std::function<u64(symbol_table &table)> getter_func; + typedef std::function<void(symbol_table &table, u64 value)> setter_func; // callback functions for function execution - typedef std::function<u64(symbol_table &table, void *symref, int numparams, const u64 *paramlist)> execute_func; + typedef std::function<u64(symbol_table &table, int numparams, const u64 *paramlist)> execute_func; // callback functions for memory reads/writes typedef std::function<expression_error::error_code(void *cbparam, const char *name, expression_space space)> valid_func; @@ -181,8 +180,8 @@ public: // symbol access void add(const char *name, read_write rw, u64 *ptr = nullptr); void add(const char *name, u64 constvalue); - void add(const char *name, void *ref, getter_func getter, setter_func setter = nullptr, const std::string &format_string = ""); - void add(const char *name, void *ref, int minparams, int maxparams, execute_func execute); + void add(const char *name, getter_func getter, setter_func setter = nullptr, const std::string &format_string = ""); + void add(const char *name, int minparams, int maxparams, execute_func execute); symbol_entry *find(const char *name) const { if (name) { auto search = m_symlist.find(name); if (search != m_symlist.end()) return search->second.get(); else return nullptr; } else return nullptr; } symbol_entry *find_deep(const char *name); 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/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/dimemory.cpp b/src/emu/dimemory.cpp index 43f05f6019c..9a78f88d6c4 100644 --- a/src/emu/dimemory.cpp +++ b/src/emu/dimemory.cpp @@ -30,9 +30,9 @@ address_space_config::address_space_config() : m_name("unknown"), m_endianness(ENDIANNESS_NATIVE), - m_databus_width(0), - m_addrbus_width(0), - m_addrbus_shift(0), + m_data_width(0), + m_addr_width(0), + m_addr_shift(0), m_logaddr_width(0), m_page_shift(0), m_is_octal(false), @@ -53,9 +53,9 @@ address_space_config::address_space_config() address_space_config::address_space_config(const char *name, endianness_t endian, u8 datawidth, u8 addrwidth, s8 addrshift, address_map_constructor internal, address_map_constructor defmap) : m_name(name), m_endianness(endian), - m_databus_width(datawidth), - m_addrbus_width(addrwidth), - m_addrbus_shift(addrshift), + m_data_width(datawidth), + m_addr_width(addrwidth), + m_addr_shift(addrshift), m_logaddr_width(addrwidth), m_page_shift(0), m_is_octal(false), @@ -67,9 +67,9 @@ address_space_config::address_space_config(const char *name, endianness_t endian address_space_config::address_space_config(const char *name, endianness_t endian, u8 datawidth, u8 addrwidth, s8 addrshift, u8 logwidth, u8 pageshift, address_map_constructor internal, address_map_constructor defmap) : m_name(name), m_endianness(endian), - m_databus_width(datawidth), - m_addrbus_width(addrwidth), - m_addrbus_shift(addrshift), + m_data_width(datawidth), + m_addr_width(addrwidth), + m_addr_shift(addrshift), m_logaddr_width(logwidth), m_page_shift(pageshift), m_is_octal(false), @@ -81,9 +81,9 @@ address_space_config::address_space_config(const char *name, endianness_t endian address_space_config::address_space_config(const char *name, endianness_t endian, u8 datawidth, u8 addrwidth, s8 addrshift, address_map_delegate internal, address_map_delegate defmap) : m_name(name), m_endianness(endian), - m_databus_width(datawidth), - m_addrbus_width(addrwidth), - m_addrbus_shift(addrshift), + m_data_width(datawidth), + m_addr_width(addrwidth), + m_addr_shift(addrshift), m_logaddr_width(addrwidth), m_page_shift(0), m_is_octal(false), @@ -97,9 +97,9 @@ address_space_config::address_space_config(const char *name, endianness_t endian address_space_config::address_space_config(const char *name, endianness_t endian, u8 datawidth, u8 addrwidth, s8 addrshift, u8 logwidth, u8 pageshift, address_map_delegate internal, address_map_delegate defmap) : m_name(name), m_endianness(endian), - m_databus_width(datawidth), - m_addrbus_width(addrwidth), - m_addrbus_shift(addrshift), + m_data_width(datawidth), + m_addr_width(addrwidth), + m_addr_shift(addrshift), m_logaddr_width(logwidth), m_page_shift(pageshift), m_is_octal(false), 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/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 7f8d48a9257..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 //************************************************************************** diff --git a/src/emu/driver.h b/src/emu/driver.h index 467a261cedf..2b4d3088a1f 100644 --- a/src/emu/driver.h +++ b/src/emu/driver.h @@ -130,10 +130,6 @@ 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 ); @@ -196,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 8729e8e7ec3..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, @@ -92,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 */ @@ -124,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 */ @@ -151,12 +158,16 @@ 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 */ @@ -167,6 +178,7 @@ enum 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) */ @@ -177,8 +189,10 @@ enum 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 */ @@ -191,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 */ @@ -205,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 */ @@ -220,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 */ @@ -238,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 */ @@ -257,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 */ @@ -265,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 1461dcbb272..1782ac8726d 100644 --- a/src/emu/emucore.h +++ b/src/emu/emucore.h @@ -431,4 +431,12 @@ inline u64 d2u(double d) return u.vv; } + +// constexpr absolute value of an integer +template <typename T> +constexpr std::enable_if_t<std::is_signed<T>::value, T> iabs(T v) +{ + return (v < T(0)) ? -v : 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..2b63aa4952b 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 @@ -411,8 +414,8 @@ private: u64 read_stub_64(address_space &space, offs_t offset, u64 mask); // stubs for reading I/O ports - template<typename _UintType> - _UintType read_stub_ioport(address_space &space, offs_t offset, _UintType mask) { return m_ioport->read(); } + template<typename UintType> + UintType read_stub_ioport(address_space &space, offs_t offset, UintType mask) { return m_ioport->read(); } // internal helper virtual void remove_subunit(int entry) override; @@ -474,8 +477,8 @@ private: void write_stub_64(address_space &space, offs_t offset, u64 data, u64 mask); // stubs for writing I/O ports - template<typename _UintType> - void write_stub_ioport(address_space &space, offs_t offset, _UintType data, _UintType mask) { m_ioport->write(data, mask); } + template<typename UintType> + void write_stub_ioport(address_space &space, offs_t offset, UintType data, UintType mask) { m_ioport->write(data, mask); } // internal helper virtual void remove_subunit(int entry) override; @@ -518,15 +521,15 @@ private: // A proxy class that contains an handler_entry_read or _write and forwards the setter calls -template<typename _HandlerEntry> +template<typename HandlerEntry> class handler_entry_proxy { public: - handler_entry_proxy(std::list<_HandlerEntry *> _handlers, u64 _mask) : handlers(std::move(_handlers)), mask(_mask) {} - handler_entry_proxy(const handler_entry_proxy<_HandlerEntry> &hep) : handlers(hep.handlers), mask(hep.mask) {} + handler_entry_proxy(std::list<HandlerEntry *> _handlers, u64 _mask) : handlers(std::move(_handlers)), mask(_mask) {} + handler_entry_proxy(const handler_entry_proxy<HandlerEntry> &hep) : handlers(hep.handlers), mask(hep.mask) {} // forward delegate callbacks configuration - template<typename _delegate> void set_delegate(_delegate delegate) const { + template<typename Delegate> void set_delegate(Delegate delegate) const { for (const auto & elem : handlers) (elem)->set_delegate(delegate, mask); } @@ -538,7 +541,7 @@ public: } private: - std::list<_HandlerEntry *> handlers; + std::list<HandlerEntry *> handlers; u64 mask; }; @@ -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)); @@ -711,8 +714,8 @@ public: private: // internal unmapped handler - template<typename _UintType> - _UintType unmap_r(address_space &space, offs_t offset, _UintType mask) + template<typename UintType> + UintType unmap_r(address_space &space, offs_t offset, UintType mask) { if (m_space.log_unmap() && !m_space.machine().side_effect_disabled()) { @@ -721,32 +724,32 @@ private: ? "%s: unmapped %s memory read from %0*o & %0*o\n" : "%s: unmapped %s memory read from %0*X & %0*X\n", m_space.machine().describe_context(), m_space.name(), - m_space.addrchars(), m_space.byte_to_address(offset * sizeof(_UintType)), - 2 * sizeof(_UintType), mask); + m_space.addrchars(), m_space.byte_to_address(offset * sizeof(UintType)), + 2 * sizeof(UintType), mask); } return m_space.unmap(); } // internal no-op handler - template<typename _UintType> - _UintType nop_r(address_space &space, offs_t offset, _UintType mask) + template<typename UintType> + UintType nop_r(address_space &space, offs_t offset, UintType mask) { return m_space.unmap(); } // internal watchpoint handler - template<typename _UintType> - _UintType watchpoint_r(address_space &space, offs_t offset, _UintType mask) + template<typename UintType> + UintType watchpoint_r(address_space &space, offs_t offset, UintType mask) { - m_space.device().debug()->memory_read_hook(m_space, offset * sizeof(_UintType), mask); + m_space.device().debug()->memory_read_hook(m_space, offset * sizeof(UintType), mask); u16 *oldtable = m_live_lookup; m_live_lookup = &m_table[0]; - _UintType result; - if (sizeof(_UintType) == 1) result = m_space.read_byte(offset); - if (sizeof(_UintType) == 2) result = m_space.read_word(offset << 1, mask); - if (sizeof(_UintType) == 4) result = m_space.read_dword(offset << 2, mask); - if (sizeof(_UintType) == 8) result = m_space.read_qword(offset << 3, mask); + UintType result; + if (sizeof(UintType) == 1) result = m_space.read_byte(offset); + if (sizeof(UintType) == 2) result = m_space.read_word(offset << 1, mask); + if (sizeof(UintType) == 4) result = m_space.read_dword(offset << 2, mask); + if (sizeof(UintType) == 8) result = m_space.read_qword(offset << 3, mask); m_live_lookup = oldtable; return result; } @@ -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)); @@ -782,8 +785,8 @@ public: private: // internal handlers - template<typename _UintType> - void unmap_w(address_space &space, offs_t offset, _UintType data, _UintType mask) + template<typename UintType> + void unmap_w(address_space &space, offs_t offset, UintType data, UintType mask) { if (m_space.log_unmap() && !m_space.machine().side_effect_disabled()) { @@ -792,28 +795,28 @@ private: ? "%s: unmapped %s memory write to %0*o = %0*o & %0*o\n" : "%s: unmapped %s memory write to %0*X = %0*X & %0*X\n", m_space.machine().describe_context(), m_space.name(), - m_space.addrchars(), m_space.byte_to_address(offset * sizeof(_UintType)), - 2 * sizeof(_UintType), data, - 2 * sizeof(_UintType), mask); + m_space.addrchars(), m_space.byte_to_address(offset * sizeof(UintType)), + 2 * sizeof(UintType), data, + 2 * sizeof(UintType), mask); } } - template<typename _UintType> - void nop_w(address_space &space, offs_t offset, _UintType data, _UintType mask) + template<typename UintType> + void nop_w(address_space &space, offs_t offset, UintType data, UintType mask) { } - template<typename _UintType> - void watchpoint_w(address_space &space, offs_t offset, _UintType data, _UintType mask) + template<typename UintType> + void watchpoint_w(address_space &space, offs_t offset, UintType data, UintType mask) { - m_space.device().debug()->memory_write_hook(m_space, offset * sizeof(_UintType), data, mask); + m_space.device().debug()->memory_write_hook(m_space, offset * sizeof(UintType), data, mask); u16 *oldtable = m_live_lookup; m_live_lookup = &m_table[0]; - if (sizeof(_UintType) == 1) m_space.write_byte(offset, data); - if (sizeof(_UintType) == 2) m_space.write_word(offset << 1, data, mask); - if (sizeof(_UintType) == 4) m_space.write_dword(offset << 2, data, mask); - if (sizeof(_UintType) == 8) m_space.write_qword(offset << 3, data, mask); + if (sizeof(UintType) == 1) m_space.write_byte(offset, data); + if (sizeof(UintType) == 2) m_space.write_word(offset << 1, data, mask); + if (sizeof(UintType) == 4) m_space.write_dword(offset << 2, data, mask); + if (sizeof(UintType) == 8) m_space.write_qword(offset << 3, data, mask); m_live_lookup = oldtable; } @@ -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,28 +878,31 @@ 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 AddrShift, bool Large> class address_space_specific : public address_space { - typedef address_space_specific<_NativeType, _Endian, _Large> this_type; + typedef address_space_specific<NativeType, Endian, AddrShift, 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_BITS = 8 * NATIVE_BYTES; + static constexpr u32 NATIVE_BYTES = sizeof(NativeType); + static constexpr u32 NATIVE_STEP = AddrShift >= 0 ? NATIVE_BYTES << iabs(AddrShift) : NATIVE_BYTES >> iabs(AddrShift); + static constexpr u32 NATIVE_MASK = NATIVE_STEP - 1; + static constexpr 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 constexpr offs_t offset_to_byte(offs_t offset) { return AddrShift < 0 ? offset << iabs(AddrShift) : offset >> iabs(AddrShift); } public: // construction/destruction address_space_specific(memory_manager &manager, device_memory_interface &memory, int spacenum) - : address_space(manager, memory, spacenum, _Large), - m_read(*this, _Large), - m_write(*this, _Large), - m_setoffset(*this, _Large) + : address_space(manager, memory, spacenum, Large), + m_read(*this, Large), + m_write(*this, Large), + m_setoffset(*this, Large) { #if (TEST_HANDLER) // test code to verify the read/write handlers are touching the correct bits @@ -905,25 +911,25 @@ public: // install some dummy RAM for the first 16 bytes with well-known values u8 buffer[16]; for (int index = 0; index < 16; index++) - buffer[index ^ ((_Endian == ENDIANNESS_NATIVE) ? 0 : (data_width()/8 - 1))] = index * 0x11; + buffer[index ^ ((Endian == ENDIANNESS_NATIVE) ? 0 : (data_width()/8 - 1))] = index * 0x11; install_ram_generic(0x00, 0x0f, 0x0f, 0, read_or_write::READWRITE, buffer); - printf("\n\naddress_space(%d, %s, %s)\n", NATIVE_BITS, (_Endian == ENDIANNESS_LITTLE) ? "little" : "big", _Large ? "large" : "small"); + printf("\n\naddress_space(%d, %s, %s)\n", NATIVE_BITS, (Endian == ENDIANNESS_LITTLE) ? "little" : "big", Large ? "large" : "small"); // walk through the first 8 addresses for (int address = 0; address < 8; address++) { // determine expected values - u64 expected64 = (u64((address + ((_Endian == ENDIANNESS_LITTLE) ? 7 : 0)) * 0x11) << 56) | - (u64((address + ((_Endian == ENDIANNESS_LITTLE) ? 6 : 1)) * 0x11) << 48) | - (u64((address + ((_Endian == ENDIANNESS_LITTLE) ? 5 : 2)) * 0x11) << 40) | - (u64((address + ((_Endian == ENDIANNESS_LITTLE) ? 4 : 3)) * 0x11) << 32) | - (u64((address + ((_Endian == ENDIANNESS_LITTLE) ? 3 : 4)) * 0x11) << 24) | - (u64((address + ((_Endian == ENDIANNESS_LITTLE) ? 2 : 5)) * 0x11) << 16) | - (u64((address + ((_Endian == ENDIANNESS_LITTLE) ? 1 : 6)) * 0x11) << 8) | - (u64((address + ((_Endian == ENDIANNESS_LITTLE) ? 0 : 7)) * 0x11) << 0); - u32 expected32 = (_Endian == ENDIANNESS_LITTLE) ? expected64 : (expected64 >> 32); - u16 expected16 = (_Endian == ENDIANNESS_LITTLE) ? expected32 : (expected32 >> 16); - u8 expected8 = (_Endian == ENDIANNESS_LITTLE) ? expected16 : (expected16 >> 8); + u64 expected64 = (u64((address + ((Endian == ENDIANNESS_LITTLE) ? 7 : 0)) * 0x11) << 56) | + (u64((address + ((Endian == ENDIANNESS_LITTLE) ? 6 : 1)) * 0x11) << 48) | + (u64((address + ((Endian == ENDIANNESS_LITTLE) ? 5 : 2)) * 0x11) << 40) | + (u64((address + ((Endian == ENDIANNESS_LITTLE) ? 4 : 3)) * 0x11) << 32) | + (u64((address + ((Endian == ENDIANNESS_LITTLE) ? 3 : 4)) * 0x11) << 24) | + (u64((address + ((Endian == ENDIANNESS_LITTLE) ? 2 : 5)) * 0x11) << 16) | + (u64((address + ((Endian == ENDIANNESS_LITTLE) ? 1 : 6)) * 0x11) << 8) | + (u64((address + ((Endian == ENDIANNESS_LITTLE) ? 0 : 7)) * 0x11) << 0); + u32 expected32 = (Endian == ENDIANNESS_LITTLE) ? expected64 : (expected64 >> 32); + u16 expected16 = (Endian == ENDIANNESS_LITTLE) ? expected32 : (expected32 >> 16); + u8 expected8 = (Endian == ENDIANNESS_LITTLE) ? expected16 : (expected16 >> 8); u64 result64; u32 result32; @@ -1064,170 +1070,170 @@ 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 - _NativeType read_native(offs_t offset, _NativeType mask) + NativeType read_native(offs_t offset, NativeType mask) { g_profiler.start(PROFILER_MEMREAD); - if (TEST_HANDLER) printf("[r%X,%s]", offset, core_i64_hex_format(mask, sizeof(_NativeType) * 2)); + 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); - _NativeType result; - if (entry <= STATIC_BANKMAX) result = *reinterpret_cast<_NativeType *>(handler.ramptr(offset)); - else if (sizeof(_NativeType) == 1) result = handler.read8(*this, offset, mask); - else if (sizeof(_NativeType) == 2) result = handler.read16(*this, offset >> 1, mask); - else if (sizeof(_NativeType) == 4) result = handler.read32(*this, offset >> 2, mask); - else if (sizeof(_NativeType) == 8) result = handler.read64(*this, offset >> 3, mask); + 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); + else if (sizeof(NativeType) == 2) result = handler.read16(*this, offset >> 1, mask); + else if (sizeof(NativeType) == 4) result = handler.read32(*this, offset >> 2, mask); + else if (sizeof(NativeType) == 8) result = handler.read64(*this, offset >> 3, mask); g_profiler.stop(); return result; } // mask-less native read - _NativeType read_native(offs_t offset) + NativeType read_native(offs_t offset) { g_profiler.start(PROFILER_MEMREAD); 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); - _NativeType result; - if (entry <= STATIC_BANKMAX) result = *reinterpret_cast<_NativeType *>(handler.ramptr(offset)); - else if (sizeof(_NativeType) == 1) result = handler.read8(*this, offset, 0xff); - else if (sizeof(_NativeType) == 2) result = handler.read16(*this, offset >> 1, 0xffff); - else if (sizeof(_NativeType) == 4) result = handler.read32(*this, offset >> 2, 0xffffffff); - else if (sizeof(_NativeType) == 8) result = handler.read64(*this, offset >> 3, 0xffffffffffffffffU); + 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); + else if (sizeof(NativeType) == 2) result = handler.read16(*this, offset >> 1, 0xffff); + else if (sizeof(NativeType) == 4) result = handler.read32(*this, offset >> 2, 0xffffffff); + else if (sizeof(NativeType) == 8) result = handler.read64(*this, offset >> 3, 0xffffffffffffffffU); g_profiler.stop(); return result; } // native write - void write_native(offs_t offset, _NativeType data, _NativeType mask) + void write_native(offs_t offset, NativeType data, NativeType mask) { 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)); + NativeType *dest = reinterpret_cast<NativeType *>(handler.ramptr(offset)); *dest = (*dest & ~mask) | (data & mask); } - else if (sizeof(_NativeType) == 1) handler.write8(*this, offset, data, mask); - else if (sizeof(_NativeType) == 2) handler.write16(*this, offset >> 1, data, mask); - else if (sizeof(_NativeType) == 4) handler.write32(*this, offset >> 2, data, mask); - else if (sizeof(_NativeType) == 8) handler.write64(*this, offset >> 3, data, mask); + else if (sizeof(NativeType) == 1) handler.write8(*this, offset, data, mask); + else if (sizeof(NativeType) == 2) handler.write16(*this, offset >> 1, data, mask); + else if (sizeof(NativeType) == 4) handler.write32(*this, offset >> 2, data, mask); + else if (sizeof(NativeType) == 8) handler.write64(*this, offset >> 3, data, mask); g_profiler.stop(); } // mask-less native write - void write_native(offs_t offset, _NativeType data) + void write_native(offs_t offset, NativeType data) { 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); - 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); - else if (sizeof(_NativeType) == 4) handler.write32(*this, offset >> 2, data, 0xffffffff); - else if (sizeof(_NativeType) == 8) handler.write64(*this, offset >> 3, data, 0xffffffffffffffffU); + 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); + else if (sizeof(NativeType) == 4) handler.write32(*this, offset >> 2, data, 0xffffffff); + else if (sizeof(NativeType) == 8) handler.write64(*this, offset >> 3, data, 0xffffffffffffffffU); g_profiler.stop(); } // generic direct read - template<typename _TargetType, bool _Aligned> - _TargetType read_direct(offs_t address, _TargetType mask) + template<typename TargetType, bool Aligned> + TargetType read_direct(offs_t address, TargetType mask) { - const u32 TARGET_BYTES = sizeof(_TargetType); + const u32 TARGET_BYTES = sizeof(TargetType); const u32 TARGET_BITS = 8 * TARGET_BYTES; // equal to native size and aligned; simple pass-through to the native reader - if (NATIVE_BYTES == TARGET_BYTES && (_Aligned || (address & NATIVE_MASK) == 0)) + if (NATIVE_BYTES == TARGET_BYTES && (Aligned || (address & NATIVE_MASK) == 0)) return read_native(address & ~NATIVE_MASK, mask); // 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))); - if (_Aligned || (offsbits + TARGET_BITS <= NATIVE_BITS)) + 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; - return read_native(address & ~NATIVE_MASK, (_NativeType)mask << offsbits) >> offsbits; + if (Endian != ENDIANNESS_LITTLE) offsbits = NATIVE_BITS - TARGET_BITS - offsbits; + return read_native(address & ~NATIVE_MASK, (NativeType)mask << offsbits) >> offsbits; } } // 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 if (NATIVE_BYTES >= TARGET_BYTES) { // little-endian case - if (_Endian == ENDIANNESS_LITTLE) + if (Endian == ENDIANNESS_LITTLE) { // read lower bits from lower address - _TargetType result = 0; - _NativeType curmask = (_NativeType)mask << offsbits; + TargetType result = 0; + NativeType curmask = (NativeType)mask << offsbits; if (curmask != 0) result = read_native(address, curmask) >> offsbits; // 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; } @@ -1236,9 +1242,9 @@ public: { // left-justify the mask to the target type const u32 LEFT_JUSTIFY_TARGET_TO_NATIVE_SHIFT = ((NATIVE_BITS >= TARGET_BITS) ? (NATIVE_BITS - TARGET_BITS) : 0); - _NativeType result = 0; - _NativeType ljmask = (_NativeType)mask << LEFT_JUSTIFY_TARGET_TO_NATIVE_SHIFT; - _NativeType curmask = ljmask >> offsbits; + NativeType result = 0; + NativeType ljmask = (NativeType)mask << LEFT_JUSTIFY_TARGET_TO_NATIVE_SHIFT; + NativeType curmask = ljmask >> offsbits; // read upper bits from lower address if (curmask != 0) result = read_native(address, curmask) << offsbits; @@ -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; @@ -1259,30 +1265,30 @@ public: // compute the maximum number of loops; we do it this way so that there are // a fixed number of loops for the compiler to unroll if it desires const u32 MAX_SPLITS_MINUS_ONE = TARGET_BYTES / NATIVE_BYTES - 1; - _TargetType result = 0; + TargetType result = 0; // little-endian case - if (_Endian == ENDIANNESS_LITTLE) + if (Endian == ENDIANNESS_LITTLE) { // read lowest bits from first address - _NativeType curmask = mask << offsbits; + NativeType curmask = mask << offsbits; if (curmask != 0) result = read_native(address, curmask) >> offsbits; // read middle bits from subsequent addresses 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; + if (curmask != 0) result |= (TargetType)read_native(address, curmask) << offsbits; offsbits += NATIVE_BITS; } // if we're not aligned and we still have bits left, read uppermost bits from last address - if (!_Aligned && offsbits < TARGET_BITS) + 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; } } @@ -1291,24 +1297,24 @@ public: { // read highest bits from first address offsbits = TARGET_BITS - (NATIVE_BITS - offsbits); - _NativeType curmask = mask >> offsbits; - if (curmask != 0) result = (_TargetType)read_native(address, curmask) << offsbits; + NativeType curmask = mask >> offsbits; + if (curmask != 0) result = (TargetType)read_native(address, curmask) << offsbits; // read middle bits from subsequent addresses 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; + if (curmask != 0) result |= (TargetType)read_native(address, curmask) << offsbits; } // if we're not aligned and we still have bits left, read lowermost bits from the last address - if (!_Aligned && offsbits != 0) + if (!Aligned && offsbits != 0) { 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; @@ -1316,45 +1322,45 @@ public: } // generic direct write - template<typename _TargetType, bool _Aligned> - void write_direct(offs_t address, _TargetType data, _TargetType mask) + template<typename TargetType, bool Aligned> + void write_direct(offs_t address, TargetType data, TargetType mask) { - const u32 TARGET_BYTES = sizeof(_TargetType); + const u32 TARGET_BYTES = sizeof(TargetType); const u32 TARGET_BITS = 8 * TARGET_BYTES; // equal to native size and aligned; simple pass-through to the native writer - if (NATIVE_BYTES == TARGET_BYTES && (_Aligned || (address & NATIVE_MASK) == 0)) + if (NATIVE_BYTES == TARGET_BYTES && (Aligned || (address & NATIVE_MASK) == 0)) return write_native(address & ~NATIVE_MASK, data, mask); // 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))); - if (_Aligned || (offsbits + TARGET_BITS <= NATIVE_BITS)) + 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; - return write_native(address & ~NATIVE_MASK, (_NativeType)data << offsbits, (_NativeType)mask << offsbits); + if (Endian != ENDIANNESS_LITTLE) offsbits = NATIVE_BITS - TARGET_BITS - offsbits; + return write_native(address & ~NATIVE_MASK, (NativeType)data << offsbits, (NativeType)mask << offsbits); } } // 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 if (NATIVE_BYTES >= TARGET_BYTES) { // little-endian case - if (_Endian == ENDIANNESS_LITTLE) + if (Endian == ENDIANNESS_LITTLE) { // write lower bits to lower address - _NativeType curmask = (_NativeType)mask << offsbits; - if (curmask != 0) write_native(address, (_NativeType)data << offsbits, curmask); + NativeType curmask = (NativeType)mask << offsbits; + if (curmask != 0) write_native(address, (NativeType)data << offsbits, curmask); // 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 @@ -1362,17 +1368,17 @@ public: { // left-justify the mask and data to the target type const u32 LEFT_JUSTIFY_TARGET_TO_NATIVE_SHIFT = ((NATIVE_BITS >= TARGET_BITS) ? (NATIVE_BITS - TARGET_BITS) : 0); - _NativeType ljdata = (_NativeType)data << LEFT_JUSTIFY_TARGET_TO_NATIVE_SHIFT; - _NativeType ljmask = (_NativeType)mask << LEFT_JUSTIFY_TARGET_TO_NATIVE_SHIFT; + NativeType ljdata = (NativeType)data << LEFT_JUSTIFY_TARGET_TO_NATIVE_SHIFT; + NativeType ljmask = (NativeType)mask << LEFT_JUSTIFY_TARGET_TO_NATIVE_SHIFT; // write upper bits to lower address - _NativeType curmask = ljmask >> offsbits; + NativeType curmask = ljmask >> offsbits; if (curmask != 0) write_native(address, ljdata >> offsbits, curmask); // 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); } } @@ -1384,27 +1390,27 @@ public: const u32 MAX_SPLITS_MINUS_ONE = TARGET_BYTES / NATIVE_BYTES - 1; // little-endian case - if (_Endian == ENDIANNESS_LITTLE) + if (Endian == ENDIANNESS_LITTLE) { // write lowest bits to first address - _NativeType curmask = mask << offsbits; + NativeType curmask = mask << offsbits; if (curmask != 0) write_native(address, data << offsbits, curmask); // write middle bits to subsequent addresses 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; } // if we're not aligned and we still have bits left, write uppermost bits to last address - if (!_Aligned && offsbits < TARGET_BITS) + 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); } } @@ -1413,24 +1419,24 @@ public: { // write highest bits to first address offsbits = TARGET_BITS - (NATIVE_BITS - offsbits); - _NativeType curmask = mask >> offsbits; + NativeType curmask = mask >> offsbits; if (curmask != 0) write_native(address, data >> offsbits, curmask); // write middle bits to subsequent addresses 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); } // if we're not aligned and we still have bits left, write lowermost bits to the last address - if (!_Aligned && offsbits != 0) + if (!Aligned && offsbits != 0) { 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,12 +1447,12 @@ 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); - handler.setoffset(*this, offset / sizeof(_NativeType)); + offs_t offset = handler.offset(address); + handler.setoffset(*this, offset / sizeof(NativeType)); } // virtual access to these functions @@ -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; @@ -1566,7 +1601,7 @@ void memory_manager::allocate(device_memory_interface &memory) if (spaceconfig) { // allocate one of the appropriate type - bool const large(spaceconfig->addr2byte_end(0xffffffffUL >> (32 - spaceconfig->m_addrbus_width)) >= (1 << 18)); + bool const large(spaceconfig->addr2byte_end(0xffffffffUL >> (32 - spaceconfig->m_addr_width)) >= (1 << 18)); switch (spaceconfig->data_width()) { @@ -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->addr_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->addr_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->addr_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()); } } } @@ -1785,20 +1954,25 @@ void memory_manager::bank_reattach() address_space::address_space(memory_manager &manager, device_memory_interface &memory, int spacenum, bool large) : 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_addrmask(0xffffffffUL >> (32 - m_config.m_addr_width)), 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_addrchars((m_config.m_addr_width + 3) / 4), m_logaddrchars((m_config.m_logaddr_width + 3) / 4), m_manager(manager), m_machine(memory.device().machine()) { + switch(m_config.addr_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.addr_shift()); + } } @@ -1808,6 +1982,13 @@ address_space::address_space(memory_manager &manager, device_memory_interface &m address_space::~address_space() { + switch(m_config.addr_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) @@ -1839,7 +2014,7 @@ void address_space::check_optimize_all(const char *function, offs_t addrstart, o if (addrend & ~m_addrmask) fatalerror("%s: In range %x-%x mask %x mirror %x select %x, end address is outside of the global address mask %x, did you mean %x ?\n", function, addrstart, addrend, addrmask, addrmirror, addrselect, m_addrmask, addrend & m_addrmask); - offs_t lowbits_mask = (m_config.data_width() >> (3 - m_config.m_addrbus_shift)) - 1; + offs_t lowbits_mask = (m_config.data_width() >> (3 - m_config.m_addr_shift)) - 1; if (addrstart & lowbits_mask) fatalerror("%s: In range %x-%x mask %x mirror %x select %x, start address has low bits set, did you mean %x ?\n", function, addrstart, addrend, addrmask, addrmirror, addrselect, addrstart & ~lowbits_mask); if ((~addrend) & lowbits_mask) @@ -1900,7 +2075,7 @@ void address_space::check_optimize_mirror(const char *function, offs_t addrstart if (addrend & ~m_addrmask) fatalerror("%s: In range %x-%x mirror %x, end address is outside of the global address mask %x, did you mean %x ?\n", function, addrstart, addrend, addrmirror, m_addrmask, addrend & m_addrmask); - offs_t lowbits_mask = (m_config.data_width() >> (3 - m_config.m_addrbus_shift)) - 1; + offs_t lowbits_mask = (m_config.data_width() >> (3 - m_config.m_addr_shift)) - 1; if (addrstart & lowbits_mask) fatalerror("%s: In range %x-%x mirror %x, start address has low bits set, did you mean %x ?\n", function, addrstart, addrend, addrmirror, addrstart & ~lowbits_mask); if ((~addrend) & lowbits_mask) @@ -1950,7 +2125,7 @@ void address_space::check_address(const char *function, offs_t addrstart, offs_t if (addrend & ~m_addrmask) fatalerror("%s: In range %x-%x, end address is outside of the global address mask %x, did you mean %x ?\n", function, addrstart, addrend, m_addrmask, addrend & m_addrmask); - offs_t lowbits_mask = (m_config.data_width() >> (3 - m_config.m_addrbus_shift)) - 1; + offs_t lowbits_mask = (m_config.data_width() >> (3 - m_config.m_addr_shift)) - 1; if (addrstart & lowbits_mask) fatalerror("%s: In range %x-%x, start address has low bits set, did you mean %x ?\n", function, addrstart, addrend, addrstart & ~lowbits_mask); if ((~addrend) & lowbits_mask) @@ -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, address_to_byte(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)); } @@ -2341,19 +2509,19 @@ void address_space::dump_map(FILE *file, read_or_write readorwrite) const address_table &table = (readorwrite == read_or_write::READ) ? static_cast<address_table &>(read()) : static_cast<address_table &>(write()); // 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 bits = %d\n", m_config.m_addr_width); + fprintf(file, " Data bits = %d\n", m_config.m_data_width); + 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.addr_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.addr_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.addr_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 AddrShift> direct_read_data<AddrShift>::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 AddrShift> direct_read_data<AddrShift>::~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 AddrShift> bool direct_read_data<AddrShift>::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(AddrShift < 0) + delta = delta << iabs(AddrShift); + else if(AddrShift > 0) + delta = delta >> iabs(AddrShift); + + 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 AddrShift> typename direct_read_data<AddrShift>::direct_range *direct_read_data<AddrShift>::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 AddrShift> void direct_read_data<AddrShift>::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..70f44385d58 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 AddrShift> class direct_read_data { friend class address_table; public: + using direct_update_delegate = delegate<offs_t (direct_read_data<AddrShift> &, 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,34 @@ 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); + + static constexpr offs_t offset_to_byte(offs_t offset) { return AddrShift < 0 ? offset << iabs(AddrShift) : offset >> iabs(AddrShift); } 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 }; @@ -183,21 +196,27 @@ public: // getters const char *name() const { return m_name; } endianness_t endianness() const { return m_endianness; } - int data_width() const { return m_databus_width; } - int addr_width() const { return m_addrbus_width; } + int data_width() const { return m_data_width; } + int addr_width() const { return m_addr_width; } + int addr_shift() const { return m_addr_shift; } + + // Actual alignment of the bus addresses + int alignment() const { int bytes = m_data_width / 8; return m_addr_shift < 0 ? bytes >> -m_addr_shift : bytes << m_addr_shift; } + + // Address delta to byte delta helpers + inline offs_t addr2byte(offs_t address) const { return (m_addr_shift < 0) ? (address << -m_addr_shift) : (address >> m_addr_shift); } + inline offs_t byte2addr(offs_t address) const { return (m_addr_shift > 0) ? (address << m_addr_shift) : (address >> -m_addr_shift); } // address-to-byte conversion 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); } - 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); } + inline offs_t addr2byte_end(offs_t address) const { return (m_addr_shift < 0) ? ((address << -m_addr_shift) | ((1 << -m_addr_shift) - 1)) : (address >> m_addr_shift); } + inline offs_t byte2addr_end(offs_t address) const { return (m_addr_shift > 0) ? ((address << m_addr_shift) | ((1 << m_addr_shift) - 1)) : (address >> -m_addr_shift); } // state const char * m_name; endianness_t m_endianness; - u8 m_databus_width; - u8 m_addrbus_width; - s8 m_addrbus_shift; + u8 m_data_width; + u8 m_addr_width; + s8 m_addr_shift; u8 m_logaddr_width; u8 m_page_shift; bool m_is_octal; // to determine if messages/debugger will show octal or hex @@ -218,7 +237,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 +258,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 AddrShift> direct_read_data<AddrShift> *direct() const { + static_assert(AddrShift == 3 || AddrShift == 0 || AddrShift == -1 || AddrShift == -2 || AddrShift == -3, "Unsupported AddrShift in direct()"); + if(AddrShift != m_config.addr_shift()) + fatalerror("Requesing direct() with address shift %d while the config says %d\n", AddrShift, m_config.addr_shift()); + return static_cast<direct_read_data<AddrShift> *>(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 addr_shift() const { return m_config.addr_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 +290,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 +414,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 +444,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 +470,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 +532,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 +540,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 +573,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 +821,10 @@ private: // backing that address //------------------------------------------------- -inline void *direct_read_data::read_ptr(offs_t byteaddress, offs_t directxor) +template<int AddrShift> inline void *direct_read_data<AddrShift>::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)) + return &m_ptr[offset_to_byte(((address ^ directxor) & m_addrmask))]; return nullptr; } @@ -804,11 +834,13 @@ 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 AddrShift> inline u8 direct_read_data<AddrShift>::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(AddrShift <= -1) + fatalerror("Can't direct_read_data::read_byte on a memory space with address shift %d", AddrShift); + if (address_is_valid(address)) + return m_ptr[offset_to_byte((address ^ directxor) & m_addrmask)]; + return m_space.read_byte(address); } @@ -817,11 +849,13 @@ 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 AddrShift> inline u16 direct_read_data<AddrShift>::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(AddrShift <= -2) + fatalerror("Can't direct_read_data::read_word on a memory space with address shift %d", AddrShift); + if (address_is_valid(address)) + return *reinterpret_cast<u16 *>(&m_ptr[offset_to_byte((address ^ directxor) & m_addrmask)]); + return m_space.read_word(address); } @@ -830,11 +864,13 @@ 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 AddrShift> inline u32 direct_read_data<AddrShift>::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(AddrShift <= -3) + fatalerror("Can't direct_read_data::read_dword on a memory space with address shift %d", AddrShift); + if (address_is_valid(address)) + return *reinterpret_cast<u32 *>(&m_ptr[offset_to_byte((address ^ directxor) & m_addrmask)]); + return m_space.read_dword(address); } @@ -843,11 +879,11 @@ 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 AddrShift> inline u64 direct_read_data<AddrShift>::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)) + return *reinterpret_cast<u64 *>(&m_ptr[offset_to_byte((address ^ directxor) & m_addrmask)]); + return m_space.read_qword(address); } #endif /* MAME_EMU_EMUMEM_H */ diff --git a/src/emu/ioport.cpp b/src/emu/ioport.cpp index 82f4c4d8030..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); } @@ -3346,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; @@ -3416,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; } @@ -3447,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); } @@ -3470,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 @@ -3488,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; } @@ -3499,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/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/romload.cpp b/src/emu/romload.cpp index 659e6b6c210..6d2dcfec2e9 100644 --- a/src/emu/romload.cpp +++ b/src/emu/romload.cpp @@ -1275,7 +1275,7 @@ void rom_load_manager::normalize_flags_for_device(running_machine &machine, cons endian = ENDIANNESS_BIG; /* set the width */ - buswidth = spaceconfig->m_databus_width; + buswidth = spaceconfig->m_data_width; if (buswidth <= 8) width = 1; else if (buswidth <= 16) 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 dd70af41506..ff29b1b7442 100644 --- a/src/emu/validity.cpp +++ b/src/emu/validity.cpp @@ -514,9 +514,13 @@ void validity_checker::validate_inlines() testi32a = (testi32a & 0x0000ffff) | 0x400000; if (count_leading_zeros(testi32a) != 9) osd_printf_error("Error testing count_leading_zeros\n"); + if (count_leading_zeros(0) != 32) + osd_printf_error("Error testing count_leading_zeros\n"); testi32a = (testi32a | 0xffff0000) & ~0x400000; if (count_leading_ones(testi32a) != 9) osd_printf_error("Error testing count_leading_ones\n"); + if (count_leading_ones(0xffffffff) != 32) + osd_printf_error("Error testing count_leading_ones\n"); } @@ -1921,7 +1925,8 @@ void validity_checker::validate_devices() validate_tag(device.basetag()); // look for duplicates - if (!device_map.insert(device.tag()).second) + bool duplicate = !device_map.insert(device.tag()).second; + if (duplicate) osd_printf_error("Multiple devices with the same tag defined\n"); // check for device-specific validity check @@ -1932,7 +1937,7 @@ void validity_checker::validate_devices() // if it's a slot, iterate over possible cards (don't recurse, or you'll stack infinite tee connectors) device_slot_interface *const slot = dynamic_cast<device_slot_interface *>(&device); - if (slot != nullptr && !slot->fixed()) + if (slot != nullptr && !slot->fixed() && !duplicate) { for (auto &option : slot->option_list()) { |