diff options
Diffstat (limited to 'src/emu/debug/dvmemory.cpp')
-rw-r--r-- | src/emu/debug/dvmemory.cpp | 655 |
1 files changed, 390 insertions, 265 deletions
diff --git a/src/emu/debug/dvmemory.cpp b/src/emu/debug/dvmemory.cpp index 947c387800b..7c10407822b 100644 --- a/src/emu/debug/dvmemory.cpp +++ b/src/emu/debug/dvmemory.cpp @@ -2,7 +2,7 @@ // copyright-holders:Aaron Giles /********************************************************************* - dvmemory.c + dvmemory.cpp Memory debugger view. @@ -12,35 +12,51 @@ #include "dvmemory.h" #include "debugcpu.h" -#include "debugger.h" #include <algorithm> -#include <ctype.h> +#include <cctype> #include <tuple> //************************************************************************** +// HELPER FUNCTIONS +//************************************************************************** + +namespace { + +constexpr u8 sanitise_character(u8 ch) +{ + // assume ISO-8859-1 (low 256 Unicode codepoints) - tab, soft hyphen, C0 and C1 cause problems + return ('\t' == ch) ? ' ' : (0xadU == ch) ? '-' : ((' ' > ch) || (('~' < ch) && (0xa0U > ch))) ? '.' : ch; +} + +} // anonymous namespace + +//************************************************************************** // GLOBAL VARIABLES //************************************************************************** -const debug_view_memory::memory_view_pos debug_view_memory::s_memory_pos_table[12] = +const debug_view_memory::memory_view_pos debug_view_memory::s_memory_pos_table[16] = { - /* 0 bytes per chunk: */ { 0, { 0 } }, - /* 1 byte per chunk: 00 11 22 33 44 55 66 77 */ { 3, { 0x04, 0x00, 0x80 } }, - /* 2 bytes per chunk: 0011 2233 4455 6677 */ { 6, { 0x8c, 0x0c, 0x08, 0x04, 0x00, 0x80 } }, - /* 3 bytes per chunk: */ { 0, { 0 } }, - /* 4 bytes per chunk: 00112233 44556677 */ { 12, { 0x9c, 0x9c, 0x1c, 0x18, 0x14, 0x10, 0x0c, 0x08, 0x04, 0x00, 0x80, 0x80 } }, - /* 5 bytes per chunk: */ { 0, { 0 } }, - /* 6 bytes per chunk: */ { 0, { 0 } }, - /* 7 bytes per chunk: */ { 0, { 0 } }, - /* 8 bytes per chunk: 0011223344556677 */ { 24, { 0xbc, 0xbc, 0xbc, 0xbc, 0x3c, 0x38, 0x34, 0x30, 0x2c, 0x28, 0x24, 0x20, 0x1c, 0x18, 0x14, 0x10, 0x0c, 0x08, 0x04, 0x00, 0x80, 0x80, 0x80, 0x80 } }, - /* 32 bit floating point: */ { 16, { 0 } }, - /* 64 bit floating point: */ { 32, { 0 } }, - /* 80 bit floating point: */ { 32, { 0 } }, + /* 0 bytes per chunk: */ { 0, 0, { 0 } }, + /* 1 byte per chunk: 00 11 22 33 44 55 66 77 */ { 1, 3, { 0x04, 0x00, 0x80 } }, + /* 2 bytes per chunk: 0011 2233 4455 6677 */ { 2, 6, { 0x8c, 0x0c, 0x08, 0x04, 0x00, 0x80 } }, + /* 3 bytes per chunk: */ { 0, 0, { 0 } }, + /* 4 bytes per chunk: 00112233 44556677 */ { 4, 12, { 0x9c, 0x9c, 0x1c, 0x18, 0x14, 0x10, 0x0c, 0x08, 0x04, 0x00, 0x80, 0x80 } }, + /* 5 bytes per chunk: */ { 0, 0, { 0 } }, + /* 6 bytes per chunk: */ { 0, 0, { 0 } }, + /* 7 bytes per chunk: */ { 0, 0, { 0 } }, + /* 8 bytes per chunk: 0011223344556677 */ { 8, 24, { 0xbc, 0xbc, 0xbc, 0xbc, 0x3c, 0x38, 0x34, 0x30, 0x2c, 0x28, 0x24, 0x20, 0x1c, 0x18, 0x14, 0x10, 0x0c, 0x08, 0x04, 0x00, 0x80, 0x80, 0x80, 0x80 } }, + /* 32 bit floating point: */ { 4, 16, { 0 } }, + /* 64 bit floating point: */ { 8, 32, { 0 } }, + /* 80 bit floating point: */ { 10, 32, { 0 } }, + /* 8 bit octal: */ { 1, 4, { 0x06, 0x03, 0x00, 0x80 } }, + /* 16 bit octal: */ { 2, 8, { 0x8f, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x00, 0x80 } }, + /* 32 bit octal: */ { 4, 15, { 0x9e, 0x9e, 0x1e, 0x1b, 0x18, 0x15, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x00, 0x80, 0x80 } }, + /* 64 bit octal: */ { 8, 28, { 0xbf, 0xbf, 0xbf, 0x3f, 0x3c, 0x39, 0x36, 0x33, 0x30, 0x2d, 0x2a, 0x27, 0x24, 0x21, 0x1e, 0x1b, 0x18, 0x15, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x00, 0x80, 0x80, 0x80 } }, }; - //************************************************************************** // DEBUG VIEW MEMORY SOURCE //************************************************************************** @@ -49,39 +65,45 @@ const debug_view_memory::memory_view_pos debug_view_memory::s_memory_pos_table[1 // debug_view_memory_source - constructors //------------------------------------------------- -debug_view_memory_source::debug_view_memory_source(const char *name, address_space &space) - : debug_view_source(name, &space.device()), - m_space(&space), - m_memintf(dynamic_cast<device_memory_interface *>(&space.device())), - m_base(nullptr), - m_length(0), - m_offsetxor(0), - m_endianness(space.endianness()), - m_prefsize(space.data_width() / 8) +debug_view_memory_source::debug_view_memory_source(std::string &&name, address_space &space) + : debug_view_source(std::move(name), &space.device()) + , m_space(&space) + , m_memintf(dynamic_cast<device_memory_interface *>(&space.device())) + , m_base(nullptr) + , m_blocklength(0) + , m_numblocks(0) + , m_blockstride(0) + , m_offsetxor(0) + , m_endianness(space.endianness()) + , m_prefsize(space.data_width() / 8) { } -debug_view_memory_source::debug_view_memory_source(const char *name, memory_region ®ion) - : debug_view_source(name), - m_space(nullptr), - m_memintf(nullptr), - m_base(region.base()), - m_length(region.bytes()), - m_offsetxor(ENDIAN_VALUE_NE_NNE(region.endianness(), 0, region.bytewidth() - 1)), - m_endianness(region.endianness()), - m_prefsize(std::min<u8>(region.bytewidth(), 8)) +debug_view_memory_source::debug_view_memory_source(std::string &&name, memory_region ®ion) + : debug_view_source(std::move(name)) + , m_space(nullptr) + , m_memintf(nullptr) + , m_base(region.base()) + , m_blocklength(region.bytes()) + , m_numblocks(1) + , m_blockstride(0) + , m_offsetxor(region.endianness() == ENDIANNESS_NATIVE ? 0 : region.bytewidth() - 1) + , m_endianness(region.endianness()) + , m_prefsize(std::min<u8>(region.bytewidth(), 8)) { } -debug_view_memory_source::debug_view_memory_source(const char *name, void *base, int element_size, int num_elements) - : debug_view_source(name), - m_space(nullptr), - m_memintf(nullptr), - m_base(base), - m_length(element_size * num_elements), - m_offsetxor(0), - m_endianness(ENDIANNESS_NATIVE), - m_prefsize(std::min(element_size, 8)) +debug_view_memory_source::debug_view_memory_source(std::string &&name, void *base, int element_size, int num_elements, int num_blocks, int block_stride) + : debug_view_source(std::move(name)) + , m_space(nullptr) + , m_memintf(nullptr) + , m_base(base) + , m_blocklength(element_size * num_elements) + , m_numblocks(num_blocks) + , m_blockstride(block_stride) + , m_offsetxor(0) + , m_endianness(ENDIANNESS_NATIVE) + , m_prefsize(std::min(element_size, 8)) { } @@ -101,11 +123,13 @@ debug_view_memory::debug_view_memory(running_machine &machine, debug_view_osd_up m_chunks_per_row(16), m_bytes_per_chunk(1), m_steps_per_chunk(1), - m_data_format(1), + m_data_format(data_format::HEX_8BIT), m_reverse_view(false), m_ascii_view(true), m_no_translation(false), m_edit_enabled(true), + m_shift_bits(4), + m_address_radix(16), m_maxaddr(0), m_bytes_per_row(16), m_byte_offset(0) @@ -119,7 +143,7 @@ debug_view_memory::debug_view_memory(running_machine &machine, debug_view_osd_up // fail if no available sources enumerate_sources(); - if (m_source_list.count() == 0) + if (m_source_list.empty()) throw std::bad_alloc(); // configure the view @@ -135,49 +159,56 @@ debug_view_memory::debug_view_memory(running_machine &machine, debug_view_osd_up void debug_view_memory::enumerate_sources() { // start with an empty list - m_source_list.reset(); - std::string name; + m_source_list.clear(); + m_source_list.reserve(machine().save().registration_count()); // first add all the devices' address spaces - for (device_memory_interface &memintf : memory_interface_iterator(machine().root_device())) + for (device_memory_interface &memintf : memory_interface_enumerator(machine().root_device())) + { for (int spacenum = 0; spacenum < memintf.max_space_count(); ++spacenum) + { if (memintf.has_space(spacenum)) { - address_space &space = memintf.space(spacenum); - name = string_format("%s '%s' %s space memory", memintf.device().name(), memintf.device().tag(), space.name()); - m_source_list.append(*global_alloc(debug_view_memory_source(name.c_str(), space))); + address_space &space(memintf.space(spacenum)); + m_source_list.emplace_back( + std::make_unique<debug_view_memory_source>( + util::string_format("%s '%s' %s space memory", memintf.device().name(), memintf.device().tag(), space.name()), + space)); } + } + } // then add all the memory regions for (auto ®ion : machine().memory().regions()) { - name = string_format("Region '%s'", region.second->name()); - m_source_list.append(*global_alloc(debug_view_memory_source(name.c_str(), *region.second.get()))); + m_source_list.emplace_back( + std::make_unique<debug_view_memory_source>( + util::string_format("Region '%s'", region.second->name()), + *region.second.get())); } - // finally add all global array symbols in alphabetical order - std::vector<std::tuple<std::string, void *, u32, u32> > itemnames; - itemnames.reserve(machine().save().registration_count()); - + // finally add all global array symbols in ASCII order + std::string name; + std::size_t const firstsave = m_source_list.size(); for (int itemnum = 0; itemnum < machine().save().registration_count(); itemnum++) { - u32 valsize, valcount; + u32 valsize, valcount, blockcount, stride; void *base; - std::string name_string(machine().save().indexed_item(itemnum, base, valsize, valcount)); + name = machine().save().indexed_item(itemnum, base, valsize, valcount, blockcount, stride); // add pretty much anything that's not a timer (we may wish to cull other items later) // also, don't trim the front of the name, it's important to know which VIA6522 we're looking at, e.g. - if (strncmp(name_string.c_str(), "timer/", 6)) - itemnames.emplace_back(std::move(name_string), base, valsize, valcount); + if (strncmp(name.c_str(), "timer/", 6)) + m_source_list.emplace_back(std::make_unique<debug_view_memory_source>(std::move(name), base, valsize, valcount, blockcount, stride)); } - - std::sort(itemnames.begin(), itemnames.end(), [] (auto const &x, auto const &y) { return std::get<0>(x) < std::get<0>(y); }); - - for (auto const &item : itemnames) - m_source_list.append(*global_alloc(debug_view_memory_source(std::get<0>(item).c_str(), std::get<1>(item), std::get<2>(item), std::get<3>(item)))); + std::sort( + std::next(m_source_list.begin(), firstsave), + m_source_list.end(), + [] (auto const &x, auto const &y) { return 0 > std::strcmp(x->name(), y->name()); }); // reset the source to a known good entry - set_source(*m_source_list.first()); + if (!m_source_list.empty()) + set_source(*m_source_list[0]); } @@ -201,12 +232,33 @@ void debug_view_memory::view_notify(debug_view_notification type) m_bytes_per_chunk = source.m_prefsize; if (m_bytes_per_chunk > 8) m_bytes_per_chunk = 8; - m_data_format = m_bytes_per_chunk; + bool octal = source.m_space != nullptr && source.m_space->is_octal(); + switch (m_bytes_per_chunk) + { + case 1: + m_data_format = octal ? data_format::OCTAL_8BIT : data_format::HEX_8BIT; + break; + + case 2: + m_data_format = octal ? data_format::OCTAL_16BIT : data_format::HEX_16BIT; + break; + + case 4: + m_data_format = octal ? data_format::OCTAL_32BIT : data_format::HEX_32BIT; + break; + + case 8: + m_data_format = octal ? data_format::OCTAL_64BIT : data_format::HEX_64BIT; + break; + } + m_shift_bits = octal ? 3 : 4; m_steps_per_chunk = source.m_space ? source.m_space->byte_to_address(m_bytes_per_chunk) : m_bytes_per_chunk; if (source.m_space != nullptr) m_expression.set_context(&source.m_space->device().debug()->symtable()); else m_expression.set_context(nullptr); + m_address_radix = octal ? 8 : 16; + m_expression.set_default_base(m_address_radix); } } @@ -244,6 +296,122 @@ static inline float u64_to_double(u64 value) } //------------------------------------------------- +// generate_row - read one row of data and make a +// text representation of the chunks +//------------------------------------------------- + +void debug_view_memory::generate_row(debug_view_char *destmin, debug_view_char *destmax, debug_view_char *destrow, offs_t address) +{ + // get positional data + const memory_view_pos &posdata = get_posdata(m_data_format); + int spacing = posdata.m_spacing; + + // generate the address + char addrtext[20]; + snprintf(addrtext, 20, m_addrformat.c_str(), address); + debug_view_char *dest = destrow + m_section[0].m_pos + 1; + for (int ch = 0; addrtext[ch] != 0 && ch < m_section[0].m_width - 1; ch++, dest++) + if (dest >= destmin && dest < destmax) + dest->byte = addrtext[ch]; + + // generate the data and the ASCII string + std::string chunkascii; + if (m_shift_bits != 0) + { + for (int chunknum = 0; chunknum < m_chunks_per_row; chunknum++) + { + u64 chunkdata; + bool ismapped = read_chunk(address, chunknum, chunkdata); + + int chunkindex = m_reverse_view ? (m_chunks_per_row - 1 - chunknum) : chunknum; + dest = destrow + m_section[1].m_pos + 1 + chunkindex * spacing; + for (int ch = 0; ch < spacing; ch++, dest++) + if (dest >= destmin && dest < destmax) + { + u8 shift = posdata.m_shift[ch]; + if (shift < 64) + dest->byte = ismapped ? "0123456789ABCDEF"[BIT(chunkdata, shift, m_shift_bits)] : '*'; + } + + for (int i = 0; i < m_bytes_per_chunk; i++) + { + u8 chval = chunkdata >> (8 * (m_bytes_per_chunk - i - 1)); + chunkascii += char(ismapped ? sanitise_character(chval) : '.'); + } + } + } + else + { + for (int chunknum = 0; chunknum < m_chunks_per_row; chunknum++) + { + char valuetext[64]; + u64 chunkdata = 0; + extFloat80_t chunkdata80 = { 0, 0 }; + bool ismapped; + + if (m_data_format != data_format::FLOAT_80BIT) + ismapped = read(m_bytes_per_chunk, address + chunknum * m_steps_per_chunk, chunkdata); + else + ismapped = read(m_bytes_per_chunk, address + chunknum * m_steps_per_chunk, chunkdata80); + + if (ismapped) + switch (m_data_format) + { + case data_format::FLOAT_32BIT: + snprintf(valuetext, 64, "%.8g", u32_to_float(u32(chunkdata))); + break; + case data_format::FLOAT_64BIT: + snprintf(valuetext, 64, "%.24g", u64_to_double(chunkdata)); + break; + case data_format::FLOAT_80BIT: + { + float64_t f64 = extF80M_to_f64(&chunkdata80); + snprintf(valuetext, 64, "%.24g", u64_to_double(f64.v)); + break; + } + default: + break; + } + else + { + valuetext[0] = '*'; + valuetext[1] = 0; + } + + int ch; + int chunkindex = m_reverse_view ? (m_chunks_per_row - 1 - chunknum) : chunknum; + dest = destrow + m_section[1].m_pos + 1 + chunkindex * spacing; + // first copy the text + for (ch = 0; (ch < spacing) && (valuetext[ch] != 0); ch++, dest++) + if (dest >= destmin && dest < destmax) + dest->byte = valuetext[ch]; + // then fill with spaces + for (; ch < spacing; ch++, dest++) + if (dest >= destmin && dest < destmax) + dest->byte = ' '; + + for (int i = 0; i < m_bytes_per_chunk; i++) + { + u8 chval = chunkdata >> (8 * (m_bytes_per_chunk - i - 1)); + chunkascii += char(ismapped ? sanitise_character(chval) : '.'); + } + } + } + + // generate the ASCII data, but follow the chunks + if (m_section[2].m_width > 0) + { + dest = destrow + m_section[2].m_pos + 1; + for (size_t i = 0; i != chunkascii.size(); i++) + { + if (dest >= destmin && dest < destmax) + dest->byte = chunkascii[i]; + dest++; + } + } +} + +//------------------------------------------------- // view_update - update the contents of the // memory view //------------------------------------------------- @@ -256,9 +424,6 @@ void debug_view_memory::view_update() if (needs_recompute()) recompute(); - // get positional data - const memory_view_pos &posdata = s_memory_pos_table[m_data_format]; - // loop over visible rows for (u32 row = 0; row < m_visible.y; row++) { @@ -268,10 +433,9 @@ void debug_view_memory::view_update() u32 effrow = m_topleft.y + row; // reset the line of data; section 1 is normal, others are ancillary, cursor is selected - debug_view_char *dest = destmin; - for (int ch = 0; ch < m_visible.x; ch++, dest++) + u32 effcol = m_topleft.x; + for (debug_view_char *dest = destmin; dest != destmax; dest++, effcol++) { - u32 effcol = m_topleft.x + ch; dest->byte = ' '; dest->attrib = DCA_ANCILLARY; if (m_section[1].contains(effcol)) @@ -287,96 +451,7 @@ void debug_view_memory::view_update() { offs_t addrbyte = m_byte_offset + effrow * m_bytes_per_row; offs_t address = (source.m_space != nullptr) ? source.m_space->byte_to_address(addrbyte) : addrbyte; - char addrtext[20]; - - // generate the address - sprintf(addrtext, m_addrformat.c_str(), address); - dest = destrow + m_section[0].m_pos + 1; - for (int ch = 0; addrtext[ch] != 0 && ch < m_section[0].m_width - 1; ch++, dest++) - if (dest >= destmin && dest < destmax) - dest->byte = addrtext[ch]; - - // generate the data and the ascii string - std::string chunkascii; - for (int chunknum = 0; chunknum < m_chunks_per_row; chunknum++) - { - int chunkindex = m_reverse_view ? (m_chunks_per_row - 1 - chunknum) : chunknum; - int spacing = posdata.m_spacing; - - if (m_data_format <= 8) { - u64 chunkdata; - bool ismapped = read_chunk(address, chunknum, chunkdata); - dest = destrow + m_section[1].m_pos + 1 + chunkindex * spacing; - for (int ch = 0; ch < posdata.m_spacing; ch++, dest++) - if (dest >= destmin && dest < destmax) - { - u8 shift = posdata.m_shift[ch]; - if (shift < 64) - dest->byte = ismapped ? "0123456789ABCDEF"[(chunkdata >> shift) & 0x0f] : '*'; - } - for (int i=0; i < m_bytes_per_chunk; i++) { - u8 chval = chunkdata >> (8 * (m_bytes_per_chunk - i - 1)); - chunkascii += char((ismapped && isprint(chval)) ? chval : '.'); - } - } - else { - int ch; - char valuetext[64]; - u64 chunkdata = 0; - floatx80 chunkdata80 = { 0, 0 }; - bool ismapped; - - if (m_data_format != 11) - ismapped = read(m_bytes_per_chunk, address + chunknum * m_steps_per_chunk, chunkdata); - else - ismapped = read(m_bytes_per_chunk, address + chunknum * m_steps_per_chunk, chunkdata80); - - if (ismapped) - switch (m_data_format) - { - case 9: - sprintf(valuetext, "%.8g", u32_to_float(u32(chunkdata))); - break; - case 10: - sprintf(valuetext, "%.24g", u64_to_double(chunkdata)); - break; - case 11: - float64 f64 = floatx80_to_float64(chunkdata80); - sprintf(valuetext, "%.24g", u64_to_double(f64)); - break; - } - else { - valuetext[0] = '*'; - valuetext[1] = 0; - } - - dest = destrow + m_section[1].m_pos + 1 + chunkindex * spacing; - // first copy the text - for (ch = 0; (ch < spacing) && (valuetext[ch] != 0); ch++, dest++) - if (dest >= destmin && dest < destmax) - dest->byte = valuetext[ch]; - // then fill with spaces - for (; ch < spacing; ch++, dest++) - if (dest >= destmin && dest < destmax) - dest->byte = ' '; - - for (int i=0; i < m_bytes_per_chunk; i++) { - u8 chval = chunkdata >> (8 * (m_bytes_per_chunk - i - 1)); - chunkascii += char((ismapped && isprint(chval)) ? chval : '.'); - } - } - } - - // generate the ASCII data, but follow the chunks - if (m_section[2].m_width > 0) - { - dest = destrow + m_section[2].m_pos + 1; - for (size_t i = 0; i != chunkascii.size(); i++) { - if (dest >= destmin && dest < destmax) - dest->byte = chunkascii[i]; - dest++; - } - } + generate_row(destmin, destmax, destrow, address); } } } @@ -429,12 +504,12 @@ void debug_view_memory::view_char(int chval) case DCH_HOME: pos.m_address -= pos.m_address % m_bytes_per_row; - pos.m_shift = (m_bytes_per_chunk * 8) - 4; + pos.m_shift = get_posdata(m_data_format).m_shift[0] & 0x7f; break; case DCH_CTRLHOME: pos.m_address = m_byte_offset; - pos.m_shift = (m_bytes_per_chunk * 8) - 4; + pos.m_shift = get_posdata(m_data_format).m_shift[0] & 0x7f; break; case DCH_END: @@ -458,43 +533,35 @@ void debug_view_memory::view_char(int chval) break; default: - { - static const char hexvals[] = "0123456789abcdef"; - char *hexchar = (char *)strchr(hexvals, tolower(chval)); - if (hexchar == nullptr) - break; - - const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source); - offs_t address = (source.m_space != nullptr) ? source.m_space->byte_to_address(pos.m_address) : pos.m_address; - u64 data; - bool ismapped = read(m_bytes_per_chunk, address, data); - if (!ismapped) - break; + { + static const char hexvals[] = "0123456789abcdef"; + char *hexchar = (char *)strchr(hexvals, tolower(chval)); + if (hexchar == nullptr || (m_shift_bits == 3 && chval >= '8')) + break; - data &= ~(u64(0x0f) << pos.m_shift); - data |= u64(hexchar - hexvals) << pos.m_shift; - write(m_bytes_per_chunk, address, data); + if (!write_digit(pos.m_address, pos.m_shift, hexchar - hexvals)) + break; // TODO: alert OSD? + } // fall through to the right-arrow press - } - + [[fallthrough]]; case DCH_RIGHT: - if (pos.m_shift == 0 && pos.m_address != m_maxaddr) + if (pos.m_shift != 0) + pos.m_shift -= m_shift_bits; + else if (pos.m_address != m_maxaddr) { - pos.m_shift = m_bytes_per_chunk * 8 - 4; + pos.m_shift = get_posdata(m_data_format).m_shift[0] & 0x7f; pos.m_address += m_bytes_per_chunk; } - else - pos.m_shift -= 4; break; case DCH_LEFT: - if (pos.m_shift == m_bytes_per_chunk * 8 - 4 && pos.m_address != m_byte_offset) + if (pos.m_shift != (get_posdata(m_data_format).m_shift[0] & 0x7f)) + pos.m_shift += m_shift_bits; + else if (pos.m_address != m_byte_offset) { pos.m_shift = 0; pos.m_address -= m_bytes_per_chunk; } - else - pos.m_shift += 4; break; } @@ -551,19 +618,42 @@ void debug_view_memory::recompute() { m_maxaddr = m_no_translation ? source.m_space->addrmask() : source.m_space->logaddrmask(); maxbyte = source.m_space->address_to_byte_end(m_maxaddr); - addrchars = m_no_translation ? source.m_space->addrchars() : source.m_space->logaddrchars(); + if (m_address_radix == 8) + addrchars = ((m_no_translation ? source.m_space->addr_width() : source.m_space->logaddr_width()) + 2) / 3; + else + addrchars = m_no_translation ? source.m_space->addrchars() : source.m_space->logaddrchars(); } else { - maxbyte = m_maxaddr = source.m_length - 1; - addrchars = string_format("%X", m_maxaddr).size(); + maxbyte = m_maxaddr = (source.m_blocklength * source.m_numblocks) - 1; + if (m_address_radix == 8) + addrchars = string_format("%o", m_maxaddr).size(); + else + addrchars = string_format("%X", m_maxaddr).size(); } // generate an 8-byte aligned format for the address - if (!m_reverse_view) - m_addrformat = string_format("%*s%%0%dX", 8 - addrchars, "", addrchars); - else - m_addrformat = string_format("%%0%dX%*s", addrchars, 8 - addrchars, ""); + switch (m_address_radix) + { + case 8: + if (!m_reverse_view) + m_addrformat = string_format("%*s%%0%do", 11 - addrchars, "", addrchars); + else + m_addrformat = string_format("%%0%do%*s", addrchars, 11 - addrchars, ""); + break; + + case 10: + // omit leading zeros for decimal addresses + m_addrformat = m_reverse_view ? "%-10d" : "%10d"; + break; + + case 16: + if (!m_reverse_view) + m_addrformat = string_format("%*s%%0%dX", 8 - addrchars, "", addrchars); + else + m_addrformat = string_format("%%0%dX%*s", addrchars, 8 - addrchars, ""); + break; + } // if we are viewing a space with a minimum chunk size, clamp the bytes per chunk // BAD @@ -588,14 +678,21 @@ void debug_view_memory::recompute() m_byte_offset = val % m_bytes_per_row; // compute the section widths - m_section[0].m_width = 1 + 8 + 1; - if (m_data_format <= 8) - m_section[1].m_width = 1 + 3 * m_bytes_per_row + 1; - else { - const memory_view_pos &posdata = s_memory_pos_table[m_data_format]; + switch (m_address_radix) + { + case 8: + m_section[0].m_width = 1 + 11 + 1; + break; - m_section[1].m_width = 1 + posdata.m_spacing * m_chunks_per_row + 1; + case 10: + m_section[0].m_width = 1 + 10 + 1; + break; + + case 16: + m_section[0].m_width = 1 + 8 + 1; + break; } + m_section[1].m_width = 1 + get_posdata(m_data_format).m_spacing * m_chunks_per_row + 1; m_section[2].m_width = m_ascii_view ? (1 + m_bytes_per_row + 1) : 0; // compute the section positions @@ -661,11 +758,11 @@ debug_view_memory::cursor_pos debug_view_memory::get_cursor_pos(const debug_view { // start with the base address for this row cursor_pos pos; - const memory_view_pos &posdata = s_memory_pos_table[m_data_format]; + const memory_view_pos &posdata = get_posdata(m_data_format); pos.m_address = m_byte_offset + cursor.y * m_bytes_per_chunk * m_chunks_per_row; // determine the X position within the middle section, clamping as necessary - if (m_data_format <= 8) { + if (posdata.m_shift[0] != 0) { int xposition = cursor.x - m_section[1].m_pos - 1; if (xposition < 0) xposition = 0; @@ -712,7 +809,7 @@ debug_view_memory::cursor_pos debug_view_memory::get_cursor_pos(const debug_view void debug_view_memory::set_cursor_pos(cursor_pos pos) { - const memory_view_pos &posdata = s_memory_pos_table[m_data_format]; + const memory_view_pos &posdata = get_posdata(m_data_format); // offset the address by the byte offset if (pos.m_address < m_byte_offset) @@ -727,7 +824,7 @@ void debug_view_memory::set_cursor_pos(cursor_pos pos) if (m_reverse_view) chunknum = m_chunks_per_row - 1 - chunknum; - if (m_data_format <= 8) { + if (posdata.m_shift[0] != 0) { // scan within the chunk to find the shift for (m_cursor.x = 0; m_cursor.x < posdata.m_spacing; m_cursor.x++) if (posdata.m_shift[m_cursor.x] == pos.m_shift) @@ -764,22 +861,17 @@ bool debug_view_memory::read(u8 size, offs_t offs, u64 &data) auto dis = machine().disable_side_effects(); bool ismapped = offs <= m_maxaddr; + address_space *tspace; if (ismapped && !m_no_translation) { offs_t dummyaddr = offs; - ismapped = source.m_memintf->translate(source.m_space->spacenum(), TRANSLATE_READ_DEBUG, dummyaddr); + ismapped = source.m_memintf->translate(source.m_space->spacenum(), device_memory_interface::TR_READ, dummyaddr, tspace); } + else + tspace = source.m_space; data = ~u64(0); if (ismapped) - { - switch (size) - { - case 1: data = machine().debugger().cpu().read_byte(*source.m_space, offs, !m_no_translation); break; - case 2: data = machine().debugger().cpu().read_word(*source.m_space, offs, !m_no_translation); break; - case 4: data = machine().debugger().cpu().read_dword(*source.m_space, offs, !m_no_translation); break; - case 8: data = machine().debugger().cpu().read_qword(*source.m_space, offs, !m_no_translation); break; - } - } + data = m_expression.context().read_memory(*tspace, offs, size, !m_no_translation); return ismapped; } @@ -801,9 +893,9 @@ bool debug_view_memory::read(u8 size, offs_t offs, u64 &data) // all 0xff if out of bounds offs ^= source.m_offsetxor; - if (offs >= source.m_length) + if (offs >= (source.m_blocklength * source.m_numblocks)) return false; - data = *((u8 *)source.m_base + offs); + data = *(reinterpret_cast<const u8 *>(source.m_base) + (offs / source.m_blocklength * source.m_blockstride) + (offs % source.m_blocklength)); return true; } @@ -812,21 +904,21 @@ bool debug_view_memory::read(u8 size, offs_t offs, u64 &data) // read - read a 80 bit value //------------------------------------------------- -bool debug_view_memory::read(u8 size, offs_t offs, floatx80 &data) +bool debug_view_memory::read(u8 size, offs_t offs, extFloat80_t &data) { u64 t; bool mappedhi, mappedlo; const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source); if (source.m_endianness == ENDIANNESS_LITTLE) { - mappedlo = read(8, offs, data.low); + mappedlo = read(8, offs, data.signif); mappedhi = read(2, offs+8, t); - data.high = (bits16)t; + data.signExp = u16(t); } else { mappedhi = read(2, offs, t); - data.high = (bits16)t; - mappedlo = read(8, offs + 2, data.low); + data.signExp = u16(t); + mappedlo = read(8, offs + 2, data.signif); } return mappedhi && mappedlo; @@ -870,14 +962,7 @@ void debug_view_memory::write(u8 size, offs_t offs, u64 data) if (source.m_space) { auto dis = machine().disable_side_effects(); - - switch (size) - { - case 1: machine().debugger().cpu().write_byte(*source.m_space, offs, data, !m_no_translation); break; - case 2: machine().debugger().cpu().write_word(*source.m_space, offs, data, !m_no_translation); break; - case 4: machine().debugger().cpu().write_dword(*source.m_space, offs, data, !m_no_translation); break; - case 8: machine().debugger().cpu().write_qword(*source.m_space, offs, data, !m_no_translation); break; - } + m_expression.context().write_memory(*source.m_space, offs, data, size, !m_no_translation); return; } @@ -900,18 +985,44 @@ void debug_view_memory::write(u8 size, offs_t offs, u64 data) // ignore if out of bounds offs ^= source.m_offsetxor; - if (offs >= source.m_length) + if (offs >= (source.m_blocklength * source.m_numblocks)) return; - *((u8 *)source.m_base + offs) = data; + *(reinterpret_cast<u8 *>(source.m_base) + (offs / source.m_blocklength * source.m_blockstride) + (offs % source.m_blocklength)) = data; +} + + +//------------------------------------------------- +// write_digit - write one hex or octal digit +// at the given address and bit position +//------------------------------------------------- + +bool debug_view_memory::write_digit(offs_t offs, u8 pos, u8 digit) +{ + const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source); + offs_t address = (source.m_space != nullptr) ? source.m_space->byte_to_address(offs) : offs; + u64 data; + bool ismapped = read(m_bytes_per_chunk, address, data); + if (!ismapped) + return false; -// hack for FD1094 editing -#ifdef FD1094_HACK - if (source.m_base == machine().root_device().memregion("user2")) + // clamp to chunk size + if (m_bytes_per_chunk * 8 < pos + m_shift_bits) { - extern void fd1094_regenerate_key(running_machine &machine); - fd1094_regenerate_key(machine()); + assert(m_bytes_per_chunk * 8 > pos); + digit &= util::make_bitmask<u8>(m_bytes_per_chunk * 8 - pos); } -#endif + + u64 write_data = (data & ~(util::make_bitmask<u64>(m_shift_bits) << pos)) | (u64(digit) << pos); + write(m_bytes_per_chunk, address, write_data); + + // verify that data reads back as it was written + if (source.m_space != nullptr) + { + read(m_bytes_per_chunk, address, data); + return data == write_data; + } + else + return true; } @@ -948,15 +1059,15 @@ void debug_view_memory::set_chunks_per_row(u32 rowchunks) //------------------------------------------------- // set_data_format - specify what kind of values -// are shown, 1-8 8-64 bits, 9 32bit floating point +// are shown //------------------------------------------------- -void debug_view_memory::set_data_format(int format) +void debug_view_memory::set_data_format(data_format format) { cursor_pos pos; // should never be - if ((format <= 0) || (format > 11)) + if (!is_valid_format(format)) return; // no need to change if (format == m_data_format) @@ -964,47 +1075,42 @@ void debug_view_memory::set_data_format(int format) pos = begin_update_and_get_cursor_pos(); const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source); - if ((format <= 8) && (m_data_format <= 8)) { - + if (is_hex_format(format) && is_hex_format(m_data_format)) { pos.m_address += (pos.m_shift / 8) ^ ((source.m_endianness == ENDIANNESS_LITTLE) ? 0 : (m_bytes_per_chunk - 1)); pos.m_shift %= 8; - m_bytes_per_chunk = format; + m_bytes_per_chunk = get_posdata(format).m_bytes; m_steps_per_chunk = source.m_space ? source.m_space->byte_to_address(m_bytes_per_chunk) : m_bytes_per_chunk; - m_chunks_per_row = m_bytes_per_row / format; + m_chunks_per_row = m_bytes_per_row / m_bytes_per_chunk; if (m_chunks_per_row < 1) m_chunks_per_row = 1; pos.m_shift += 8 * ((pos.m_address % m_bytes_per_chunk) ^ ((source.m_endianness == ENDIANNESS_LITTLE) ? 0 : (m_bytes_per_chunk - 1))); pos.m_address -= pos.m_address % m_bytes_per_chunk; } else { - if (format <= 8) { + if (is_hex_format(format)) { m_supports_cursor = true; m_edit_enabled = true; - - m_bytes_per_chunk = format; + m_shift_bits = 4; + } + else if (is_octal_format(format)) { + m_supports_cursor = true; + m_edit_enabled = true; + m_shift_bits = 3; } else { m_supports_cursor = false; m_edit_enabled = false; m_cursor_visible = false; - - switch (format) - { - case 9: - m_bytes_per_chunk = 4; - break; - case 10: - m_bytes_per_chunk = 8; - break; - case 11: - m_bytes_per_chunk = 10; - break; - } + m_shift_bits = 0; } + + m_bytes_per_chunk = get_posdata(format).m_bytes; m_chunks_per_row = m_bytes_per_row / m_bytes_per_chunk; + if (m_chunks_per_row < 1) + m_chunks_per_row = 1; m_steps_per_chunk = source.m_space ? source.m_space->byte_to_address(m_bytes_per_chunk) : m_bytes_per_chunk; - pos.m_shift = 0; + pos.m_shift = get_posdata(format).m_shift[0] & 0x7f; pos.m_address -= pos.m_address % m_bytes_per_chunk; } m_recompute = m_update_pending = true; @@ -1053,3 +1159,22 @@ void debug_view_memory::set_physical(bool physical) m_recompute = m_update_pending = true; end_update_and_set_cursor_pos(pos); } + + +//------------------------------------------------- +// set_address_radix - specify whether the memory +// view should display addresses in base 8, base +// 10 or base 16 +//------------------------------------------------- + +void debug_view_memory::set_address_radix(int radix) +{ + if (radix != 8 && radix != 10 && radix != 16) + return; + + cursor_pos pos = begin_update_and_get_cursor_pos(); + m_address_radix = radix; + m_expression.set_default_base(radix); + m_recompute = m_update_pending = true; + end_update_and_set_cursor_pos(pos); +} |