diff options
author | 2017-05-10 17:13:54 +0200 | |
---|---|---|
committer | 2017-11-29 10:32:31 +0100 | |
commit | c46e1007a8c0b42b7c50dce9b8bc9dff0db328e5 (patch) | |
tree | aa08023cdf065d10dbe9633c845496447c953484 /src/emu/debug/debugcmd.cpp | |
parent | 5676444d8cf9da4b27ceba2efd0a2d82a343cc57 (diff) |
emumem: API change [O. Galibert]
* direct_read_data is now a template which takes the address bus shift
as a parameter.
* address_space::direct<shift>() is now a template method that takes
the shift as a parameter and returns a pointer instead of a
reference
* the address to give to {read|write}_* on address_space or
direct_read_data is now the address one wants to access
Longer explanation:
Up until now, the {read|write}_* methods required the caller to give
the byte offset instead of the actual address. That's the same on
byte-addressing CPUs, e.g. the ones everyone knows, but it's different
on the word/long/quad addressing ones (tms, sharc, etc...) or the
bit-addressing one (tms340x0). Changing that required templatizing
the direct access interface on the bus addressing granularity,
historically called address bus shift. Also, since everybody was
taking the address of the reference returned by direct(), and
structurally didn't have much choice in the matter, it got changed to
return a pointer directly.
Longest historical explanation:
In a cpu core, the hottest memory access, by far, is the opcode
fetching. It's also an access with very good locality (doesn't move
much, tends to stay in the same rom/ram zone even when jumping around,
tends not to hit handlers), which makes efficient caching worthwhile
(as in, 30-50% faster core iirc on something like the 6502, but that
was 20 years ago and a number of things changed since then). In fact,
opcode fetching was, in the distant past, just an array lookup indexed
by pc on an offset pointer, which was updated on branches. It didn't
stay that way because more elaborate access is often needed (handlers,
banking with instructions crossing a bank...) but it still ends up with
a frontend of "if the address is still in the current range read from
pointer+address otherwise do the slowpath", e.g. two usually correctly
predicted branches plus the read most of the time.
Then the >8 bits cpus arrived. That was ok, it just required to do
the add to a u8 *, then convert to a u16/u32 * and do the read. At
the asm level, it was all identical except for the final read, and
read_byte/word/long being separate there was no test (and associated
overhead) added in the path.
Then the word-addressing CPUs arrived with, iirc, the tms cpus used in
atari games. They require, to read from the pointer, to shift the
address, either explicitely, or implicitely through indexing a u16 *.
There were three possibilities:
1- create a new read_* method for each size and granularity. That
amounts to a lot of copy/paste in the end, and functions with
identical prototypes so the compiler can't detect you're using the
wrong one.
2- put a variable shift in the read path. That was too expensive
especially since the most critical cpus are byte-addressing (68000 at
the time was the key). Having bit-adressing cpus which means the
shift can either be right or left depending on the variable makes
things even worse.
3- require the caller to do the shift himself when needed.
The last solution was chosen, and starting that day the address was a
byte offset and not the real address. Which is, actually, quite
surprising when writing a new cpu core or, worse, when using the
read/write methods from the driver code.
But since then, C++ happened. And, in particular, templates with
non-type parameters. Suddendly, solution 1 can be done without the
copy/paste and with different types allowing to detect (at runtime,
but systematically and at startup) if you got it wrong, while still
generating optimal code. So it was time to switch to that solution
and makes the address parameter sane again. Especially since it makes
mucking in the rest of the memory subsystem code a lot more
understandable.
Diffstat (limited to 'src/emu/debug/debugcmd.cpp')
-rw-r--r-- | src/emu/debug/debugcmd.cpp | 193 |
1 files changed, 161 insertions, 32 deletions
diff --git a/src/emu/debug/debugcmd.cpp b/src/emu/debug/debugcmd.cpp index c5afe1b366c..bc43182b2b1 100644 --- a/src/emu/debug/debugcmd.cpp +++ b/src/emu/debug/debugcmd.cpp @@ -1645,7 +1645,6 @@ void debugger_commands::execute_save(int ref, const std::vector<std::string> &pa u64 offset, endoffset, length; address_space *space; FILE *f; - u64 i; /* validate parameters */ if (!validate_number_parameter(params[1], offset)) @@ -1656,8 +1655,8 @@ 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(); /* open the file */ f = fopen(params[0].c_str(), "wb"); @@ -1668,10 +1667,46 @@ void debugger_commands::execute_save(int ref, const std::vector<std::string> &pa } /* now write the data out */ - for (i = offset; i <= endoffset; i++) + auto dis = space->machine().disable_side_effect(); + switch (space->addrbus_shift()) { - u8 byte = m_cpu.read_byte(*space, i, true); - fwrite(&byte, 1, 1, f); + case -3: + for (offs_t i = offset; i != endoffset; i++) + { + u64 data = space->read_qword(i); + fwrite(&data, 8, 1, f); + } + break; + case -2: + for (offs_t i = offset; i != endoffset; i++) + { + u32 data = space->read_dword(i); + fwrite(&data, 4, 1, f); + } + break; + case -1: + for (offs_t i = offset; i != endoffset; i++) + { + u16 byte = space->read_word(i); + fwrite(&byte, 2, 1, f); + } + break; + case 0: + for (offs_t i = offset; i != endoffset; i++) + { + u8 byte = space->read_word(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 */ @@ -1688,7 +1723,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)) @@ -1713,19 +1747,66 @@ void debugger_commands::execute_load(int ref, const std::vector<std::string> &pa f.seekg(0, std::ios::end); length = f.tellg(); f.seekg(0); + if (space->addrbus_shift() < 0) + length >>= -space->addrbus_shift(); + else if (space->addrbus_shift() > 0) + length <<= space->addrbus_shift(); } // determine the addresses to read - endoffset = space->address_to_byte(offset + length - 1) & space->bytemask(); - offset = space->address_to_byte(offset) & space->bytemask(); - + endoffset = (offset + length - 1) & space->addrmask(); + offset = offset & space->addrmask(); + offs_t i = 0; // now read the data in, ignore endoffset and load entire file if length has been set to zero (offset-1) - for (i = offset; f.good() && (i <= endoffset || endoffset == offset - 1); i++) + switch (space->addrbus_shift()) { - char byte; - f.read(&byte, 1); - if (f) - m_cpu.write_byte(*space, i, byte, true); + case -3: + for (i = offset; f.good() && (i <= endoffset || endoffset == offset - 1); i++) + { + u64 data; + f.read((char *)&data, 8); + if (f) + space->write_qword(i, data); + } + break; + case -2: + for (i = offset; f.good() && (i <= endoffset || endoffset == offset - 1); i++) + { + u32 data; + f.read((char *)&data, 4); + if (f) + space->write_dword(i, data); + } + break; + case -1: + for (i = offset; f.good() && (i <= endoffset || endoffset == offset - 1); i++) + { + u16 data; + f.read((char *)&data, 2); + if (f) + space->write_word(i, data); + } + break; + case 0: + for (i = offset; f.good() && (i <= endoffset || endoffset == offset - 1); i++) + { + u8 data; + f.read((char *)&data, 1); + if (f) + space->write_byte(i, data); + } + break; + case 3: + offset &= ~15; + endoffset &= ~15; + for (i = offset; f.good() && (i <= endoffset || endoffset == offset - 16); i+=16) + { + u16 data; + f.read((char *)&data, 2); + if (f) + space->write_word(i >> 4, data); + } + break; } if (!f.good()) @@ -1768,6 +1849,9 @@ void debugger_commands::execute_dump(int ref, const std::vector<std::string> &pa if (!validate_cpu_space_parameter((params.size() > 6) ? params[6].c_str() : nullptr, ref, space)) return; + int shift = space->addrbus_shift(); + u64 granularity = shift > 0 ? 2 : 1 << -shift; + /* further validation */ if (width == 0) width = space->data_width() / 8; @@ -1778,14 +1862,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"); @@ -1798,13 +1887,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) @@ -1814,8 +1912,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 { @@ -1835,8 +1946,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 { @@ -1921,8 +2050,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; @@ -1945,8 +2074,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++; @@ -2321,9 +2450,9 @@ void debugger_commands::execute_find(int ref, const std::vector<std::string> &pa return; /* further validation */ - endoffset = space->address_to_byte(offset + length - 1) & space->bytemask(); - offset = space->address_to_byte(offset) & space->bytemask(); - cur_data_size = space->address_to_byte(1); + endoffset = (offset + length - 1) & space->addrmask(); + offset = offset & space->addrmask(); + cur_data_size = space->addrbus_shift() > 0 ? 2 : 1 << -space->addrbus_shift(); if (cur_data_size == 0) cur_data_size = 1; @@ -2834,7 +2963,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); @@ -2842,7 +2971,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 |