From aac1eab8a241973d2be91ae0e883587e43de6c9a Mon Sep 17 00:00:00 2001 From: Andrei Holub <andrei.holub@gmail.com> Date: Sun, 1 Jun 2025 20:57:16 -0400 Subject: [PATCH 1/5] emu/debug: Replaced saver/loadr with more generic savem/loadm which handels both region and share memory --- src/emu/debug/debugcmd.cpp | 150 ++++++++++++++++++++++++++++++++++++- src/emu/debug/debugcmd.h | 5 ++ src/emu/debug/debugcon.cpp | 34 ++++++++- src/emu/debug/debugcon.h | 5 +- 4 files changed, 189 insertions(+), 5 deletions(-) diff --git a/src/emu/debug/debugcmd.cpp b/src/emu/debug/debugcmd.cpp index 76a6053477f9c..f23e3238a9c00 100644 --- a/src/emu/debug/debugcmd.cpp +++ b/src/emu/debug/debugcmd.cpp @@ -274,13 +274,15 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu m_console.register_command("saved", CMDFLAG_NONE, 3, 3, std::bind(&debugger_commands::execute_save, this, AS_DATA, _1)); m_console.register_command("savei", CMDFLAG_NONE, 3, 3, std::bind(&debugger_commands::execute_save, this, AS_IO, _1)); m_console.register_command("saveo", CMDFLAG_NONE, 3, 3, std::bind(&debugger_commands::execute_save, this, AS_OPCODES, _1)); - m_console.register_command("saver", CMDFLAG_NONE, 4, 4, std::bind(&debugger_commands::execute_saveregion, this, _1)); + m_console.register_command("saver", CMDFLAG_NONE, 4, 4, std::bind(&debugger_commands::execute_region_deprecated, this, _1)); + m_console.register_command("savem", CMDFLAG_NONE, 4, 4, std::bind(&debugger_commands::execute_savememory, this, _1)); m_console.register_command("load", CMDFLAG_NONE, 2, 3, std::bind(&debugger_commands::execute_load, this, -1, _1)); m_console.register_command("loadd", CMDFLAG_NONE, 2, 3, std::bind(&debugger_commands::execute_load, this, AS_DATA, _1)); m_console.register_command("loadi", CMDFLAG_NONE, 2, 3, std::bind(&debugger_commands::execute_load, this, AS_IO, _1)); m_console.register_command("loado", CMDFLAG_NONE, 2, 3, std::bind(&debugger_commands::execute_load, this, AS_OPCODES, _1)); - m_console.register_command("loadr", CMDFLAG_NONE, 4, 4, std::bind(&debugger_commands::execute_loadregion, this, _1)); + m_console.register_command("loadr", CMDFLAG_NONE, 4, 4, std::bind(&debugger_commands::execute_region_deprecated, this, _1)); + m_console.register_command("loadm", CMDFLAG_NONE, 4, 4, std::bind(&debugger_commands::execute_loadmemory, this, _1)); m_console.register_command("dump", CMDFLAG_NONE, 3, 6, std::bind(&debugger_commands::execute_dump, this, -1, _1)); m_console.register_command("dumpd", CMDFLAG_NONE, 3, 6, std::bind(&debugger_commands::execute_dump, this, AS_DATA, _1)); @@ -2094,6 +2096,12 @@ void debugger_commands::execute_save(int spacenum, const std::vector<std::string } +void debugger_commands::execute_region_deprecated(const std::vector<std::string_view> ¶ms) +{ + m_console.printf("saver/loadr is deprecated, use savem/loadm instead.\n"); +} + + /*------------------------------------------------- execute_saveregion - execute the save command on region memory -------------------------------------------------*/ @@ -2133,6 +2141,70 @@ void debugger_commands::execute_saveregion(const std::vector<std::string_view> & m_console.printf("Data saved successfully\n"); } +/*------------------------------------------------- + execute_saveshare - execute the save command on share memory +-------------------------------------------------*/ + +void debugger_commands::execute_saveshare(const std::vector<std::string_view> ¶ms) +{ + u64 offset, length; + memory_share *share; + + // validate parameters + if (!m_console.validate_number_parameter(params[1], offset)) + return; + if (!m_console.validate_number_parameter(params[2], length)) + return; + if (!m_console.validate_memory_share_parameter(params[3], share)) + return; + + if (offset >= share->bytes()) + { + m_console.printf("Invalid offset\n"); + return; + } + if ((length <= 0) || ((length + offset) >= share->bytes())) + length = share->bytes() - offset; + + /* open the file */ + std::string const filename(params[0]); + FILE *f = fopen(filename.c_str(), "wb"); + if (!f) + { + m_console.printf("Error opening file '%s'\n", params[0]); + return; + } + fwrite(reinterpret_cast<u8 *>(share->ptr()) + offset, 1, length, f); + + fclose(f); + m_console.printf("Data saved successfully\n"); +} + + +/*------------------------------------------------- + execute_savememory - execute the save command on memory +-------------------------------------------------*/ + +void debugger_commands::execute_savememory(const std::vector<std::string_view> ¶ms) +{ + u64 offset, length; + + // validate parameters + if (!m_console.validate_number_parameter(params[1], offset)) + return; + if (!m_console.validate_number_parameter(params[2], length)) + return; + + memory_region *region; + memory_share *share; + if (m_console.validate_memory_region_parameter(params[3], region, false)) + execute_saveregion(params); + else if (m_console.validate_memory_share_parameter(params[3], share, false)) + execute_saveshare(params); + else + m_console.printf("No matching memory found for '%s'\n", params[3]); +} + /*------------------------------------------------- execute_load - execute the load command @@ -2297,6 +2369,80 @@ void debugger_commands::execute_loadregion(const std::vector<std::string_view> & } +/*------------------------------------------------- + execute_loadshare - execute the load command on share memory +-------------------------------------------------*/ + +void debugger_commands::execute_loadshare(const std::vector<std::string_view> ¶ms) +{ + u64 offset, length; + memory_share *share; + + // validate parameters + if (!m_console.validate_number_parameter(params[1], offset)) + return; + if (!m_console.validate_number_parameter(params[2], length)) + return; + if (!m_console.validate_memory_share_parameter(params[3], share)) + return; + + if (offset >= share->bytes()) + { + m_console.printf("Invalid offset\n"); + return; + } + if ((length <= 0) || ((length + offset) >= share->bytes())) + length = share->bytes() - offset; + + // open the file + std::string filename(params[0]); + FILE *const f = fopen(filename.c_str(), "rb"); + if (!f) + { + m_console.printf("Error opening file '%s'\n", params[0]); + return; + } + + fseek(f, 0L, SEEK_END); + u64 size = ftell(f); + rewind(f); + + // check file size + if (length >= size) + length = size; + + fread(reinterpret_cast<u8 *>(share->ptr()) + offset, 1, length, f); + + fclose(f); + m_console.printf("Data loaded successfully to memory : 0x%X to 0x%X\n", offset, offset + length - 1); +} + + +/*------------------------------------------------- + execute_loadregion - execute the load command on memory +-------------------------------------------------*/ + +void debugger_commands::execute_loadmemory(const std::vector<std::string_view> ¶ms) +{ + u64 offset, length; + + // validate parameters + if (!m_console.validate_number_parameter(params[1], offset)) + return; + if (!m_console.validate_number_parameter(params[2], length)) + return; + + memory_region *region; + memory_share *share; + if (m_console.validate_memory_region_parameter(params[3], region, false)) + execute_loadregion(params); + else if (m_console.validate_memory_share_parameter(params[3], share, false)) + execute_loadshare(params); + else + m_console.printf("No matching memory found for '%s'\n", params[3]); +} + + /*------------------------------------------------- execute_dump - execute the dump command -------------------------------------------------*/ diff --git a/src/emu/debug/debugcmd.h b/src/emu/debug/debugcmd.h index cf38c6d903a27..08770b51e2efe 100644 --- a/src/emu/debug/debugcmd.h +++ b/src/emu/debug/debugcmd.h @@ -127,9 +127,14 @@ class debugger_commands void execute_stateload(const std::vector<std::string_view> ¶ms); void execute_rewind(const std::vector<std::string_view> ¶ms); void execute_save(int spacenum, const std::vector<std::string_view> ¶ms); + void execute_region_deprecated(const std::vector<std::string_view> ¶ms); void execute_saveregion(const std::vector<std::string_view> ¶ms); + void execute_saveshare(const std::vector<std::string_view> ¶ms); + void execute_savememory(const std::vector<std::string_view> ¶ms); void execute_load(int spacenum, const std::vector<std::string_view> ¶ms); void execute_loadregion(const std::vector<std::string_view> ¶ms); + void execute_loadshare(const std::vector<std::string_view> ¶ms); + void execute_loadmemory(const std::vector<std::string_view> ¶ms); void execute_dump(int spacenum, const std::vector<std::string_view> ¶ms); void execute_strdump(int spacenum, const std::vector<std::string_view> ¶ms); void execute_cheatrange(bool init, const std::vector<std::string_view> ¶ms); diff --git a/src/emu/debug/debugcon.cpp b/src/emu/debug/debugcon.cpp index ec5bc15475101..1f50399f8952e 100644 --- a/src/emu/debug/debugcon.cpp +++ b/src/emu/debug/debugcon.cpp @@ -925,7 +925,7 @@ bool debugger_console::validate_target_address_parameter(std::string_view param, /// failure. /// \return true if the parameter refers to a memory region in the /// current system, or false otherwise. -bool debugger_console::validate_memory_region_parameter(std::string_view param, memory_region *&result) +bool debugger_console::validate_memory_region_parameter(std::string_view param, memory_region *&result, bool print_error) { auto const ®ions = m_machine.memory().regions(); std::string_view relative = param; @@ -938,7 +938,37 @@ bool debugger_console::validate_memory_region_parameter(std::string_view param, } else { - printf("No matching memory region found for '%s'\n", param); + if (print_error) + printf("No matching memory region found for '%s'\n", param); + return false; + } +} + + +/// \brief Validate a parameter as a memory share +/// +/// Validates a parameter as a memory share tag and retrieves the +/// specified memory share. +/// \param [in] The parameter string. +/// \param [out] result The memory share on success, or unchanged on +/// failure. +/// \return true if the parameter refers to a memory share in the +/// current system, or false otherwise. +bool debugger_console::validate_memory_share_parameter(std::string_view param, memory_share *&result, bool print_error) +{ + auto const &shares = m_machine.memory().shares(); + std::string_view relative = param; + device_t &base = get_device_search_base(relative); + auto const iter = shares.find(base.subtag(strmakelower(relative))); + if (shares.end() != iter) + { + result = iter->second.get(); + return true; + } + else + { + if (print_error) + printf("No matching memory share found for '%s'\n", param); return false; } } diff --git a/src/emu/debug/debugcon.h b/src/emu/debug/debugcon.h index 37b2e235348cc..13ba7deef60bc 100644 --- a/src/emu/debug/debugcon.h +++ b/src/emu/debug/debugcon.h @@ -131,7 +131,10 @@ class debugger_console bool validate_target_address_parameter(std::string_view param, int spacenum, address_space *&space, u64 &addr); // validates a parameter as a memory region name and retrieves the given region - bool validate_memory_region_parameter(std::string_view param, memory_region *&result); + bool validate_memory_region_parameter(std::string_view param, memory_region *&result, bool print_error = true); + + // validates a parameter as a memory region name and retrieves the given share + bool validate_memory_share_parameter(std::string_view param, memory_share *&result, bool print_error = true); // validates a parameter as a debugger expression bool validate_expression_parameter(std::string_view param, parsed_expression &result); From 098c604234e70c73b290bd3afe7ab218a1826134 Mon Sep 17 00:00:00 2001 From: Andrei Holub <andrei.holub@gmail.com> Date: Wed, 4 Jun 2025 11:56:12 -0400 Subject: [PATCH 2/5] stubs, no implementation --- docs/source/debugger/index.rst | 5 + docs/source/debugger/memory.rst | 12 ++ src/emu/debug/debugcmd.cpp | 188 ++++++++------------------------ src/emu/debug/debugcmd.h | 11 +- src/emu/debug/debugcon.cpp | 10 +- src/emu/debug/debugcon.h | 4 +- src/emu/debug/debughlp.cpp | 18 +++ src/emu/debug/express.cpp | 135 ++++++++++++++++++++++- src/emu/debug/express.h | 5 +- 9 files changed, 229 insertions(+), 159 deletions(-) diff --git a/docs/source/debugger/index.rst b/docs/source/debugger/index.rst index 2947d0253acfb..a035a7e13c022 100644 --- a/docs/source/debugger/index.rst +++ b/docs/source/debugger/index.rst @@ -158,6 +158,10 @@ Examples: Address 9660 in the default address space of the device with the absolute tag ``:ram``, or the ``ram`` space of the root machine device. +``1883:vram.m`` + Address 1883 in the memory region with the absolute tag ``:vram``. +``1923:sprites.s`` + Address 1923 in the memory share with the absolute tag ``:sprites``. The examples here include a lot of corner cases, but in general the debugger should take the most likely meaning for a device or address @@ -327,6 +331,7 @@ The size may optionally be preceded by an access type specification: * ``o`` specifies direct read/write pointer access defaulting to space 3 (opcodes) * ``m`` specifies a memory region +* ``s`` specifies a memory share Finally, this may be preceded by a tag and/or address space name followed by a dot (``.``). diff --git a/docs/source/debugger/memory.rst b/docs/source/debugger/memory.rst index dfb5914b5a9dd..b32273a40c609 100644 --- a/docs/source/debugger/memory.rst +++ b/docs/source/debugger/memory.rst @@ -65,6 +65,7 @@ find ---- **f[ind][{d|i|o}] <address>[:<space>],<length>[,<data>[,…]]** +**f[ind] <address>:<memory>.{m|s},<length>[,<data>[,…]]** Search through memory for the specified sequence of data. The **<address>** is the address to begin searching from, optionally @@ -114,6 +115,7 @@ fill ---- **fill[{d|i|o}] <address>[:<space>],<length>[,<data>[,…]]** +**fill <address>:<memory>.{m|s},<length>[,<data>[,…]]** Overwrite a block of memory with copies of the supplied data sequence. The **<address>** specifies the address to begin writing at, optionally @@ -146,6 +148,7 @@ dump ---- **dump[{d|i|o}] <filename>,<address>[:<space>],<length>[,<group>[,<ascii>[,<rowsize>]]]** +**dump <filename>,<address>:<memory>.{m|s},<length>[,<group>[,<ascii>[,<rowsize>]]]** Dump memory to the text file specified by the **<filename>** parameter. The **<address>** specifies the address to start dumping from, @@ -190,6 +193,7 @@ strdump ------- **strdump[{d|i|o}] <filename>,<address>[:<space>],<length>[,<term>]** +**strdump <filename>,<address>:<memory>.{m|s},<length>[,<term>]** Dump memory to the text file specified by the **<filename>** parameter. The **<address>** specifies the address to start dumping from, @@ -216,6 +220,7 @@ save ---- **save[{d|i|o}] <filename>,<address>[:<space>],<length>** +**save <filename>,<address>:<memory>.{m|s},<length>** Save raw memory to the binary file specified by the **<filename>** parameter. The **<address>** specifies the address to start saving @@ -260,6 +265,9 @@ start saving from, and the **<length>** specifies how much memory to save. The range **<address>** through **<address>+<length>-1**, inclusive, will be output to the file. +Alternetevely use :ref:`debugger-command-save` syntax: +``save <filename>,<address>:<region>.m,<length>`` + Examples: ``saver data.bin,200,100,:monitor`` @@ -278,6 +286,7 @@ load ---- **load[{d|i|o}] <filename>,<address>[:<space>][,<length>]** +**load <filename>,<address>:<memory>.{m|s}[,<length>]** Load raw memory from the binary file specified by the **<filename>** parameter. The **<address>** specifies the address to start loading to, @@ -334,6 +343,9 @@ through **<address>+<length>-1**, inclusive, will be read in from the file. If the **<length>** is zero, or is greater than the total length of the file, the entire contents of the file will be loaded but no more. +Alternetevely use :ref:`debugger-command-load` syntax: +``load <filename>,<address>:<region>.m[,<length>]`` + Examples: ``loadr data.bin,200,100,:monitor`` diff --git a/src/emu/debug/debugcmd.cpp b/src/emu/debug/debugcmd.cpp index f23e3238a9c00..d8807fe7299ed 100644 --- a/src/emu/debug/debugcmd.cpp +++ b/src/emu/debug/debugcmd.cpp @@ -274,15 +274,13 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu m_console.register_command("saved", CMDFLAG_NONE, 3, 3, std::bind(&debugger_commands::execute_save, this, AS_DATA, _1)); m_console.register_command("savei", CMDFLAG_NONE, 3, 3, std::bind(&debugger_commands::execute_save, this, AS_IO, _1)); m_console.register_command("saveo", CMDFLAG_NONE, 3, 3, std::bind(&debugger_commands::execute_save, this, AS_OPCODES, _1)); - m_console.register_command("saver", CMDFLAG_NONE, 4, 4, std::bind(&debugger_commands::execute_region_deprecated, this, _1)); - m_console.register_command("savem", CMDFLAG_NONE, 4, 4, std::bind(&debugger_commands::execute_savememory, this, _1)); + m_console.register_command("saver", CMDFLAG_NONE, 4, 4, std::bind(&debugger_commands::execute_saveregion, this, _1)); m_console.register_command("load", CMDFLAG_NONE, 2, 3, std::bind(&debugger_commands::execute_load, this, -1, _1)); m_console.register_command("loadd", CMDFLAG_NONE, 2, 3, std::bind(&debugger_commands::execute_load, this, AS_DATA, _1)); m_console.register_command("loadi", CMDFLAG_NONE, 2, 3, std::bind(&debugger_commands::execute_load, this, AS_IO, _1)); m_console.register_command("loado", CMDFLAG_NONE, 2, 3, std::bind(&debugger_commands::execute_load, this, AS_OPCODES, _1)); - m_console.register_command("loadr", CMDFLAG_NONE, 4, 4, std::bind(&debugger_commands::execute_region_deprecated, this, _1)); - m_console.register_command("loadm", CMDFLAG_NONE, 4, 4, std::bind(&debugger_commands::execute_loadmemory, this, _1)); + m_console.register_command("loadr", CMDFLAG_NONE, 4, 4, std::bind(&debugger_commands::execute_loadregion, this, _1)); m_console.register_command("dump", CMDFLAG_NONE, 3, 6, std::bind(&debugger_commands::execute_dump, this, -1, _1)); m_console.register_command("dumpd", CMDFLAG_NONE, 3, 6, std::bind(&debugger_commands::execute_dump, this, AS_DATA, _1)); @@ -2095,10 +2093,12 @@ void debugger_commands::execute_save(int spacenum, const std::vector<std::string m_console.printf("Data saved successfully\n"); } +/*------------------------------------------------- + execute_savememory - execute the save command on memory +-------------------------------------------------*/ -void debugger_commands::execute_region_deprecated(const std::vector<std::string_view> ¶ms) +void debugger_commands::execute_savememory(const std::vector<std::string_view> ¶ms) { - m_console.printf("saver/loadr is deprecated, use savem/loadm instead.\n"); } @@ -2141,70 +2141,6 @@ void debugger_commands::execute_saveregion(const std::vector<std::string_view> & m_console.printf("Data saved successfully\n"); } -/*------------------------------------------------- - execute_saveshare - execute the save command on share memory --------------------------------------------------*/ - -void debugger_commands::execute_saveshare(const std::vector<std::string_view> ¶ms) -{ - u64 offset, length; - memory_share *share; - - // validate parameters - if (!m_console.validate_number_parameter(params[1], offset)) - return; - if (!m_console.validate_number_parameter(params[2], length)) - return; - if (!m_console.validate_memory_share_parameter(params[3], share)) - return; - - if (offset >= share->bytes()) - { - m_console.printf("Invalid offset\n"); - return; - } - if ((length <= 0) || ((length + offset) >= share->bytes())) - length = share->bytes() - offset; - - /* open the file */ - std::string const filename(params[0]); - FILE *f = fopen(filename.c_str(), "wb"); - if (!f) - { - m_console.printf("Error opening file '%s'\n", params[0]); - return; - } - fwrite(reinterpret_cast<u8 *>(share->ptr()) + offset, 1, length, f); - - fclose(f); - m_console.printf("Data saved successfully\n"); -} - - -/*------------------------------------------------- - execute_savememory - execute the save command on memory --------------------------------------------------*/ - -void debugger_commands::execute_savememory(const std::vector<std::string_view> ¶ms) -{ - u64 offset, length; - - // validate parameters - if (!m_console.validate_number_parameter(params[1], offset)) - return; - if (!m_console.validate_number_parameter(params[2], length)) - return; - - memory_region *region; - memory_share *share; - if (m_console.validate_memory_region_parameter(params[3], region, false)) - execute_saveregion(params); - else if (m_console.validate_memory_share_parameter(params[3], share, false)) - execute_saveshare(params); - else - m_console.printf("No matching memory found for '%s'\n", params[3]); -} - /*------------------------------------------------- execute_load - execute the load command @@ -2319,6 +2255,14 @@ void debugger_commands::execute_load(int spacenum, const std::vector<std::string m_console.printf("Data loaded successfully to memory : 0x%X to 0x%X\n", offset, i-1); } +/*------------------------------------------------- + execute_loadmemory - execute the load command on memory +-------------------------------------------------*/ + +void debugger_commands::execute_loadmemory(const std::vector<std::string_view> ¶ms) +{ +} + /*------------------------------------------------- execute_loadregion - execute the load command on region memory @@ -2369,80 +2313,6 @@ void debugger_commands::execute_loadregion(const std::vector<std::string_view> & } -/*------------------------------------------------- - execute_loadshare - execute the load command on share memory --------------------------------------------------*/ - -void debugger_commands::execute_loadshare(const std::vector<std::string_view> ¶ms) -{ - u64 offset, length; - memory_share *share; - - // validate parameters - if (!m_console.validate_number_parameter(params[1], offset)) - return; - if (!m_console.validate_number_parameter(params[2], length)) - return; - if (!m_console.validate_memory_share_parameter(params[3], share)) - return; - - if (offset >= share->bytes()) - { - m_console.printf("Invalid offset\n"); - return; - } - if ((length <= 0) || ((length + offset) >= share->bytes())) - length = share->bytes() - offset; - - // open the file - std::string filename(params[0]); - FILE *const f = fopen(filename.c_str(), "rb"); - if (!f) - { - m_console.printf("Error opening file '%s'\n", params[0]); - return; - } - - fseek(f, 0L, SEEK_END); - u64 size = ftell(f); - rewind(f); - - // check file size - if (length >= size) - length = size; - - fread(reinterpret_cast<u8 *>(share->ptr()) + offset, 1, length, f); - - fclose(f); - m_console.printf("Data loaded successfully to memory : 0x%X to 0x%X\n", offset, offset + length - 1); -} - - -/*------------------------------------------------- - execute_loadregion - execute the load command on memory --------------------------------------------------*/ - -void debugger_commands::execute_loadmemory(const std::vector<std::string_view> ¶ms) -{ - u64 offset, length; - - // validate parameters - if (!m_console.validate_number_parameter(params[1], offset)) - return; - if (!m_console.validate_number_parameter(params[2], length)) - return; - - memory_region *region; - memory_share *share; - if (m_console.validate_memory_region_parameter(params[3], region, false)) - execute_loadregion(params); - else if (m_console.validate_memory_share_parameter(params[3], share, false)) - execute_loadshare(params); - else - m_console.printf("No matching memory found for '%s'\n", params[3]); -} - - /*------------------------------------------------- execute_dump - execute the dump command -------------------------------------------------*/ @@ -2606,6 +2476,13 @@ void debugger_commands::execute_dump(int spacenum, const std::vector<std::string m_console.printf("Data dumped successfully\n"); } +/*------------------------------------------------- + execute_dumpmemory - execute the dump command on memory +-------------------------------------------------*/ + +void debugger_commands::execute_dumpmemory(const std::vector<std::string_view> ¶ms) +{ +} //------------------------------------------------- // execute_strdump - execute the strdump command @@ -2782,6 +2659,13 @@ void debugger_commands::execute_strdump(int spacenum, const std::vector<std::str fclose(f); m_console.printf("Data dumped successfully\n"); } +/*------------------------------------------------- + execute_strdumpmemory - execute the strdump command on memory +-------------------------------------------------*/ + +void debugger_commands::execute_strdumpmemory(const std::vector<std::string_view> ¶ms) +{ +} /*------------------------------------------------- @@ -3408,6 +3292,14 @@ void debugger_commands::execute_find(int spacenum, const std::vector<std::string m_console.printf("Not found\n"); } +/*------------------------------------------------- + execute_findmemory - execute the find command on memory +-------------------------------------------------*/ + +void debugger_commands::execute_findmemory(const std::vector<std::string_view> ¶ms) +{ +} + //------------------------------------------------- // execute_fill - execute the fill command @@ -3517,6 +3409,14 @@ void debugger_commands::execute_fill(int spacenum, const std::vector<std::string } } +/*------------------------------------------------- + execute_fillmemory - execute the fill command on memory +-------------------------------------------------*/ + +void debugger_commands::execute_fillmemory(const std::vector<std::string_view> ¶ms) +{ +} + /*------------------------------------------------- execute_dasm - execute the dasm command diff --git a/src/emu/debug/debugcmd.h b/src/emu/debug/debugcmd.h index 08770b51e2efe..b9a5eaeda8862 100644 --- a/src/emu/debug/debugcmd.h +++ b/src/emu/debug/debugcmd.h @@ -127,23 +127,24 @@ class debugger_commands void execute_stateload(const std::vector<std::string_view> ¶ms); void execute_rewind(const std::vector<std::string_view> ¶ms); void execute_save(int spacenum, const std::vector<std::string_view> ¶ms); - void execute_region_deprecated(const std::vector<std::string_view> ¶ms); - void execute_saveregion(const std::vector<std::string_view> ¶ms); - void execute_saveshare(const std::vector<std::string_view> ¶ms); void execute_savememory(const std::vector<std::string_view> ¶ms); + void execute_saveregion(const std::vector<std::string_view> ¶ms); void execute_load(int spacenum, const std::vector<std::string_view> ¶ms); - void execute_loadregion(const std::vector<std::string_view> ¶ms); - void execute_loadshare(const std::vector<std::string_view> ¶ms); void execute_loadmemory(const std::vector<std::string_view> ¶ms); + void execute_loadregion(const std::vector<std::string_view> ¶ms); void execute_dump(int spacenum, const std::vector<std::string_view> ¶ms); + void execute_dumpmemory(const std::vector<std::string_view> ¶ms); void execute_strdump(int spacenum, const std::vector<std::string_view> ¶ms); + void execute_strdumpmemory(const std::vector<std::string_view> ¶ms); void execute_cheatrange(bool init, const std::vector<std::string_view> ¶ms); void execute_cheatnext(bool initial, const std::vector<std::string_view> ¶ms); void execute_cheatlist(const std::vector<std::string_view> ¶ms); void execute_cheatundo(const std::vector<std::string_view> ¶ms); void execute_dasm(const std::vector<std::string_view> ¶ms); void execute_find(int spacenum, const std::vector<std::string_view> ¶ms); + void execute_findmemory(const std::vector<std::string_view> ¶ms); void execute_fill(int spacenum, const std::vector<std::string_view> ¶ms); + void execute_fillmemory(const std::vector<std::string_view> ¶ms); void execute_trace(const std::vector<std::string_view> ¶ms, bool trace_over); void execute_traceflush(const std::vector<std::string_view> ¶ms); void execute_history(const std::vector<std::string_view> ¶ms); diff --git a/src/emu/debug/debugcon.cpp b/src/emu/debug/debugcon.cpp index 1f50399f8952e..1042766aa8721 100644 --- a/src/emu/debug/debugcon.cpp +++ b/src/emu/debug/debugcon.cpp @@ -925,7 +925,7 @@ bool debugger_console::validate_target_address_parameter(std::string_view param, /// failure. /// \return true if the parameter refers to a memory region in the /// current system, or false otherwise. -bool debugger_console::validate_memory_region_parameter(std::string_view param, memory_region *&result, bool print_error) +bool debugger_console::validate_memory_region_parameter(std::string_view param, memory_region *&result) { auto const ®ions = m_machine.memory().regions(); std::string_view relative = param; @@ -938,8 +938,7 @@ bool debugger_console::validate_memory_region_parameter(std::string_view param, } else { - if (print_error) - printf("No matching memory region found for '%s'\n", param); + printf("No matching memory region found for '%s'\n", param); return false; } } @@ -954,7 +953,7 @@ bool debugger_console::validate_memory_region_parameter(std::string_view param, /// failure. /// \return true if the parameter refers to a memory share in the /// current system, or false otherwise. -bool debugger_console::validate_memory_share_parameter(std::string_view param, memory_share *&result, bool print_error) +bool debugger_console::validate_memory_share_parameter(std::string_view param, memory_share *&result) { auto const &shares = m_machine.memory().shares(); std::string_view relative = param; @@ -967,8 +966,7 @@ bool debugger_console::validate_memory_share_parameter(std::string_view param, m } else { - if (print_error) - printf("No matching memory share found for '%s'\n", param); + printf("No matching memory share found for '%s'\n", param); return false; } } diff --git a/src/emu/debug/debugcon.h b/src/emu/debug/debugcon.h index 13ba7deef60bc..78ee1d9bb8dd2 100644 --- a/src/emu/debug/debugcon.h +++ b/src/emu/debug/debugcon.h @@ -131,10 +131,10 @@ class debugger_console bool validate_target_address_parameter(std::string_view param, int spacenum, address_space *&space, u64 &addr); // validates a parameter as a memory region name and retrieves the given region - bool validate_memory_region_parameter(std::string_view param, memory_region *&result, bool print_error = true); + bool validate_memory_region_parameter(std::string_view param, memory_region *&result); // validates a parameter as a memory region name and retrieves the given share - bool validate_memory_share_parameter(std::string_view param, memory_share *&result, bool print_error = true); + bool validate_memory_share_parameter(std::string_view param, memory_share *&result); // validates a parameter as a debugger expression bool validate_expression_parameter(std::string_view param, parsed_expression &result); diff --git a/src/emu/debug/debughlp.cpp b/src/emu/debug/debughlp.cpp index 8e5fa1b9c64f2..e78a31d7568fd 100644 --- a/src/emu/debug/debughlp.cpp +++ b/src/emu/debug/debughlp.cpp @@ -94,26 +94,32 @@ const help_item f_static_help_list[] = "\n" " dasm <filename>,<address>,<length>[,<opcodes>[,<CPU>]] -- disassemble to the given file\n" " f[ind] <address>,<length>[,<data>[,...]] -- search memory for data\n" + " f[ind] <address>:<memory>.{m|s},<length>[,<data>[,...]] -- search memory region or share for data\n" " f[ind]d <address>,<length>[,<data>[,...]] -- search data memory for data\n" " f[ind]i <address>,<length>[,<data>[,...]] -- search I/O memory for data\n" " fill <address>,<length>[,<data>[,...]] -- fill memory with data\n" + " fill <address>:<memory>.{m|s},<length>[,<data>[,...]] -- fill memory region or share with data\n" " filld <address>[:<space>],<length>[,<data>[,...]] -- fill data memory with data\n" " filli <address>[:<space>],<length>[,<data>[,...][ -- fill I/O memory with data\n" " fillo <address>[:<space>],<length>[,<data>[,...][ -- fill opcode memory with data\n" " dump <filename>,<address>[:<space>],<length>[,<group>[,<ascii>[,<rowsize>]]] -- dump memory as text\n" + " dump <filename>,<address>:<memory>.{m|s},<length>[,<group>[,<ascii>[,<rowsize>]]] -- dump memory region or share as text\n" " dumpd <filename>,<address>[:<space>],<length>[,<group>[,<ascii>[,<rowsize>]]] -- dump data memory as text\n" " dumpi <filename>,<address>[:<space>],<length>[,<group>[,<ascii>[,<rowsize>]]] -- dump I/O memory as text\n" " dumpo <filename>,<address>[:<space>],<length>[,<group>[,<ascii>[,<rowsize>]]] -- dump opcodes memory as text\n" " strdump <filename>,<address>[:<space>],<length>[,<term>] -- dump ASCII strings from memory\n" + " strdump <filename>,<address>:<memory>.{m|s},<length>[,<term>] -- dump ASCII strings from memory region or share\n" " strdumpd <filename>,<address>[:<space>],<length>[,<term>] -- dump ASCII strings from data memory\n" " strdumpi <filename>,<address>[:<space>],<length>[,<term>] -- dump ASCII strings from I/O memory\n" " strdumpo <filename>,<address>[:<space>],<length>[,<term>] -- dump ASCII strings from opcodes memory\n" " save <filename>,<address>[:<space>],<length> -- save binary memory to the given file\n" + " save <filename>,<address>:<memory>.{m|s},<length> -- load binary memory region or share to the given file\n" " saved <filename>,<address>[:<space>],<length> -- save binary data memory to the given file\n" " savei <filename>,<address>[:<space>],<length> -- save binary I/O memory to the given file\n" " saveo <filename>,<address>[:<space>],<length> -- save binary opcode memory to the given file\n" " saver <filename>,<address>[:<space>],<length>,<region> -- save binary memory region to the given file\n" " load <filename>,<address>[:<space>][,<length>] -- load binary memory from the given file\n" + " load <filename>,<address>:<memory>.{m|s}[,<length>] -- load binary memory region or share from the given file\n" " loadd <filename>,<address>[:<space>][,<length>] -- load binary data memory from the given file\n" " loadi <filename>,<address>[:<space>][,<length>] -- load binary I/O memory from the given file\n" " loado <filename>,<address>[:<space>][,<length>] -- load binary opcode memory from the given file\n" @@ -633,6 +639,7 @@ const help_item f_static_help_list[] = "find", "\n" " f[ind][{d|i|o}] <address>[:<space>],<length>[,<data>[,...]]\n" + " f[ind] <address>:<memory>.{m|s},<length>[,<data>[,...]]\n" "\n" "The find commands search through memory for the specified sequence of data. The <address> " "is the address to begin searching from, optionally followed by a device and/or address " @@ -674,6 +681,7 @@ const help_item f_static_help_list[] = "fill", "\n" " fill[{d|i|o}] <address>[:<space>],<length>[,<data>[,...]]\n" + " fill <address>:<memory>.{m|s},<length>[,<data>[,...]]\n" "\n" "The fill commands overwrite a block of memory with copies of the supplied data sequence. " "The <address> specifies the address to begin writing at, optionally followed by a device " @@ -700,6 +708,7 @@ const help_item f_static_help_list[] = "dump", "\n" " dump[{d|i|o}] <filename>,<address>[:<space>],<length>[,<group>[,<ascii>[,<rowsize>]]]\n" + " dump <filename>,<address>:<memory>.{m|s},<length>[,<group>[,<ascii>[,<rowsize>]]]\n" "\n" "The dump commands dump memory to the text file specified in the <filename> parameter. The " "<address> specifies the address to start dumping from, optionally followed by a device " @@ -739,6 +748,7 @@ const help_item f_static_help_list[] = "strdump", "\n" " strdump[{d|i|o}] <filename>,<address>[:<space>],<length>[,<term>]\n" + " strdump <filename>,<address>:<memory>.{m|s},<length>[,<term>]\n" "\n" "The strdump commands dump memory to the text file specified in the <filename> parameter. " "The <address> specifies the address to start dumping from, optionally followed by a device " @@ -761,6 +771,7 @@ const help_item f_static_help_list[] = "save", "\n" " save[{d|i|o}] <filename>,<address>[:<space>],<length>\n" + " save <filename>,<address>:<memory>.{m|s},<length>\n" "\n" "The save commands save raw memory to the binary file specified in the <filename> " "parameter. The <address> specifies the address to start saving from, optionally followed " @@ -798,6 +809,9 @@ const help_item f_static_help_list[] = "saving from, and the <length> specifies how much memory to save. The range <address> " "through <address>+<length>-1, inclusive, will be output to the file.\n" "\n" + "Alternetevely use 'save' syntax:\n" + " save <filename>,<address>:<region>.m,<length>\n" + "\n" "Examples:\n" "\n" "saver data.bin,200,100,:monitor\n" @@ -811,6 +825,7 @@ const help_item f_static_help_list[] = "load", "\n" " load[{d|i|o}] <filename>,<address>[:<space>][,<length>]\n" + " load <filename>,<address>:<memory>.{m|s}[,<length>]\n" "\n" "The load commands load raw memory from the binary file specified in the <filename> " "parameter. The <address> specifies the address to start loading to, optionally followed " @@ -857,6 +872,9 @@ const help_item f_static_help_list[] = "is zero, or is greater than the total length of the file, the entire contents of the file " "will be loaded but no more.\n" "\n" + "Alternetevely use 'load' syntax:\n" + " load <filename>,<address>:<region>.m[,<length>]\n" + "\n" "Examples:\n" "\n" "loadr data.bin,200,100,:monitor\n" diff --git a/src/emu/debug/express.cpp b/src/emu/debug/express.cpp index 219ed6a89ef9a..4408d62146076 100644 --- a/src/emu/debug/express.cpp +++ b/src/emu/debug/express.cpp @@ -319,7 +319,7 @@ std::string expression_error::code_string() const case TOO_MANY_STRINGS: return "too many strings"; case INVALID_MEMORY_SIZE: return "invalid memory size (b/w/d/q expected)"; case NO_SUCH_MEMORY_SPACE: return "non-existent memory space"; - case INVALID_MEMORY_SPACE: return "invalid memory space (p/d/i/o/r/m expected)"; + case INVALID_MEMORY_SPACE: return "invalid memory space (p/d/i/o/r/m/s expected)"; case INVALID_MEMORY_NAME: return "invalid memory name"; case MISSING_MEMORY_NAME: return "missing memory name"; default: return "unknown error"; @@ -673,6 +673,11 @@ u64 symbol_table::memory_value(const char *name, expression_space spacenum, u32 return read_memory_region(name, address, size); break; + case EXPSPACE_SHARE: + if (name) + return read_memory_share(name, address, size); + break; + default: break; } @@ -782,6 +787,55 @@ u64 symbol_table::read_memory_region(const char *rgntag, offs_t address, int siz } +//------------------------------------------------- +// read_memory_share - read memory from a +// memory share +//------------------------------------------------- + +u64 symbol_table::read_memory_share(const char *shatag, offs_t address, int size) +{ + auto search = get_device_search(m_machine, m_memintf, shatag); + memory_share *const share = search.first.memshare(search.second); + u64 result = ~u64(0) >> (64 - 8*size); + + // make sure we get a valid base before proceeding + if (share) + { + // call ourself recursively until we are byte-sized + if (size > 1) + { + int halfsize = size / 2; + u64 r0, r1; + + // read each half, from lower address to upper address + r0 = read_memory_share(shatag, address + 0, halfsize); + r1 = read_memory_share(shatag, address + halfsize, halfsize); + + // assemble based on the target endianness + if (share->endianness() == ENDIANNESS_LITTLE) + result = r0 | (r1 << (8 * halfsize)); + else + result = r1 | (r0 << (8 * halfsize)); + } + + // only process if we're within range + else if (address < share->bytes()) + { + // lowmask specified which address bits are within the databus width + u32 lowmask = share->bytewidth() - 1; + u8 *base = reinterpret_cast<u8 *>(share->ptr()) + (address & ~lowmask); + + // if we have a valid base, return the appropriate byte + if (share->endianness() == ENDIANNESS_LITTLE) + result = base[BYTE8_XOR_LE(address) & lowmask]; + else + result = base[BYTE8_XOR_BE(address) & lowmask]; + } + } + return result; +} + + //------------------------------------------------- // set_memory_value - write 1,2,4 or 8 bytes at // the given offset in the given address space @@ -831,6 +885,11 @@ void symbol_table::set_memory_value(const char *name, expression_space spacenum, write_memory_region(name, address, size, data); break; + case EXPSPACE_SHARE: + if (name) + write_memory_share(name, address, size, data); + break; + default: break; } @@ -953,6 +1012,65 @@ void symbol_table::write_memory_region(const char *rgntag, offs_t address, int s } +//------------------------------------------------- +// write_memory_share - write memory to a +// memory share +//------------------------------------------------- + +void symbol_table::write_memory_share(const char *shatag, offs_t address, int size, u64 data) +{ + auto search = get_device_search(m_machine, m_memintf, shatag); + memory_share *const share = search.first.memshare(search.second); + + // make sure we get a valid base before proceeding + if (share) + { + // call ourself recursively until we are byte-sized + if (size > 1) + { + int halfsize = size / 2; + + // break apart based on the target endianness + u64 halfmask = ~u64(0) >> (64 - 8 * halfsize); + u64 r0, r1; + if (share->endianness() == ENDIANNESS_LITTLE) + { + r0 = data & halfmask; + r1 = (data >> (8 * halfsize)) & halfmask; + } + else + { + r0 = (data >> (8 * halfsize)) & halfmask; + r1 = data & halfmask; + } + + // write each half, from lower address to upper address + write_memory_share(shatag, address + 0, halfsize, r0); + write_memory_share(shatag, address + halfsize, halfsize, r1); + } + + // only process if we're within range + else if (address < share->bytes()) + { + // lowmask specified which address bits are within the databus width + u32 lowmask = share->bytewidth() - 1; + u8 *base = reinterpret_cast<u8 *>(share->ptr()) + (address & ~lowmask); + + // if we have a valid base, set the appropriate byte + if (share->endianness() == ENDIANNESS_LITTLE) + { + base[BYTE8_XOR_LE(address) & lowmask] = data; + } + else + { + base[BYTE8_XOR_BE(address) & lowmask] = data; + } + notify_memory_modified(); + } + } +} + + //------------------------------------------------- // memory_valid - return true if the given // memory name/space/offset combination is valid @@ -998,6 +1116,20 @@ expression_error::error_code symbol_table::memory_valid(const char *name, expres } break; + case EXPSPACE_SHARE: + if (!name) + { + return expression_error::MISSING_MEMORY_NAME; + } + else + { + auto search = get_device_search(m_machine, m_memintf, name); + memory_share *const share = search.first.memshare(search.second); + if (!share || !share->ptr()) + return expression_error::INVALID_MEMORY_NAME; + } + break; + default: return expression_error::NO_SUCH_MEMORY_SPACE; } @@ -1618,6 +1750,7 @@ void parsed_expression::parse_memory_operator(parse_token &token, const char *st case 'r': memspace = EXPSPACE_PRGDIRECT; break; case 'o': memspace = EXPSPACE_OPDIRECT; break; case 'm': memspace = EXPSPACE_REGION; break; + case 's': memspace = EXPSPACE_SHARE; break; default: throw expression_error(expression_error::INVALID_MEMORY_SPACE, token.offset() + (string - startstring)); } diff --git a/src/emu/debug/express.h b/src/emu/debug/express.h index 33ab9c3b472b9..f9e3983c053fc 100644 --- a/src/emu/debug/express.h +++ b/src/emu/debug/express.h @@ -41,7 +41,8 @@ enum expression_space EXPSPACE_OPCODE_PHYSICAL, EXPSPACE_PRGDIRECT, EXPSPACE_OPDIRECT, - EXPSPACE_REGION + EXPSPACE_REGION, + EXPSPACE_SHARE }; @@ -215,8 +216,10 @@ class symbol_table // memory helpers u64 read_program_direct(address_space &space, int opcode, offs_t address, int size); u64 read_memory_region(const char *rgntag, offs_t address, int size); + u64 read_memory_share(const char *shatag, offs_t address, int size); void write_program_direct(address_space &space, int opcode, offs_t address, int size, u64 data); void write_memory_region(const char *rgntag, offs_t address, int size, u64 data); + void write_memory_share(const char *shatag, offs_t address, int size, u64 data); expression_error expression_get_space(const char *tag, int &spacenum, device_memory_interface *&memory); void notify_memory_modified(); From 366a39ce83d5bdaaa77796f61659b87574611341 Mon Sep 17 00:00:00 2001 From: Andrei Holub <andrei.holub@gmail.com> Date: Fri, 6 Jun 2025 12:03:09 -0400 Subject: [PATCH 3/5] implement load/save --- src/emu/debug/debugcmd.cpp | 207 +++++++++++++++++++++++++++---------- src/emu/debug/debugcmd.h | 12 +-- src/emu/debug/debugcon.cpp | 34 +++++- src/emu/debug/debugcon.h | 3 + 4 files changed, 196 insertions(+), 60 deletions(-) diff --git a/src/emu/debug/debugcmd.cpp b/src/emu/debug/debugcmd.cpp index d8807fe7299ed..04585fce3b1e8 100644 --- a/src/emu/debug/debugcmd.cpp +++ b/src/emu/debug/debugcmd.cpp @@ -2007,6 +2007,9 @@ void debugger_commands::execute_rewind(const std::vector<std::string_view> ¶ void debugger_commands::execute_save(int spacenum, const std::vector<std::string_view> ¶ms) { + if (execute_save_try_memory(params)) + return; + u64 offset, endoffset, length; address_space *space; @@ -2097,35 +2100,38 @@ void debugger_commands::execute_save(int spacenum, const std::vector<std::string execute_savememory - execute the save command on memory -------------------------------------------------*/ -void debugger_commands::execute_savememory(const std::vector<std::string_view> ¶ms) +bool debugger_commands::execute_save_try_memory(const std::vector<std::string_view> ¶ms) { -} - + u64 offset = u64(-1); + memory_region *region = nullptr; + memory_share *share = nullptr; + if (!m_console.validate_address_with_memory_parameter(params[1], offset, region, share)) + return false; // not memory case -/*------------------------------------------------- - execute_saveregion - execute the save command on region memory --------------------------------------------------*/ - -void debugger_commands::execute_saveregion(const std::vector<std::string_view> ¶ms) -{ - u64 offset, length; - memory_region *region; + u64 length; + if (offset == u64(-1) || !m_console.validate_number_parameter(params[2], length) || (region == nullptr && share == nullptr)) + return true; - // validate parameters - if (!m_console.validate_number_parameter(params[1], offset)) - return; - if (!m_console.validate_number_parameter(params[2], length)) - return; - if (!m_console.validate_memory_region_parameter(params[3], region)) - return; + u32 msize; + u8 *base; + if (region != nullptr) + { + msize = region->bytes(); + base = region->base(); + } + else // if (share != nullptr) + { + msize = share->bytes(); + base = reinterpret_cast<u8 *>(share->ptr()); + } - if (offset >= region->bytes()) + if (offset >= msize) { m_console.printf("Invalid offset\n"); - return; + return true; } - if ((length <= 0) || ((length + offset) >= region->bytes())) - length = region->bytes() - offset; + if ((length <= 0) || ((length + offset) >= msize)) + length = msize - offset; /* open the file */ std::string const filename(params[0]); @@ -2133,12 +2139,24 @@ void debugger_commands::execute_saveregion(const std::vector<std::string_view> & if (!f) { m_console.printf("Error opening file '%s'\n", params[0]); - return; + return true; } - fwrite(region->base() + offset, 1, length, f); + fwrite(base + offset, 1, length, f); fclose(f); m_console.printf("Data saved successfully\n"); + + return true; +} + + +/*------------------------------------------------- + execute_saveregion - execute the save command on region memory +-------------------------------------------------*/ + +void debugger_commands::execute_saveregion(const std::vector<std::string_view> ¶ms) +{ + execute_save(-1, std::vector<std::string_view>{ params[0], std::string(params[1]) + std::string(params[3]) + ".m", params[2] }); } @@ -2148,6 +2166,9 @@ void debugger_commands::execute_saveregion(const std::vector<std::string_view> & void debugger_commands::execute_load(int spacenum, const std::vector<std::string_view> ¶ms) { + if (execute_load_try_memory(params)) + return; + u64 offset, endoffset, length = 0; address_space *space; @@ -2259,35 +2280,39 @@ void debugger_commands::execute_load(int spacenum, const std::vector<std::string execute_loadmemory - execute the load command on memory -------------------------------------------------*/ -void debugger_commands::execute_loadmemory(const std::vector<std::string_view> ¶ms) +bool debugger_commands::execute_load_try_memory(const std::vector<std::string_view> ¶ms) { -} - - -/*------------------------------------------------- - execute_loadregion - execute the load command on region memory --------------------------------------------------*/ - -void debugger_commands::execute_loadregion(const std::vector<std::string_view> ¶ms) -{ - u64 offset, length; - memory_region *region; + u64 offset = u64(-1); + memory_region *region = nullptr; + memory_share *share = nullptr; + if (!m_console.validate_address_with_memory_parameter(params[1], offset, region, share)) + return false; // not memory case + u64 length; // validate parameters - if (!m_console.validate_number_parameter(params[1], offset)) - return; - if (!m_console.validate_number_parameter(params[2], length)) - return; - if (!m_console.validate_memory_region_parameter(params[3], region)) - return; + if (offset == u64(-1) || !m_console.validate_number_parameter(params[2], length) || (region == nullptr && share == nullptr)) + return true; + + u32 msize; + u8 *base; + if (region != nullptr) + { + msize = region->bytes(); + base = region->base(); + } + else // if (share != nullptr) + { + msize = share->bytes(); + base = reinterpret_cast<u8 *>(share->ptr()); + } - if (offset >= region->bytes()) + if (offset >= msize) { m_console.printf("Invalid offset\n"); - return; + return true; } - if ((length <= 0) || ((length + offset) >= region->bytes())) - length = region->bytes() - offset; + if ((length <= 0) || ((length + offset) >= msize)) + length = msize - offset; // open the file std::string filename(params[0]); @@ -2295,7 +2320,7 @@ void debugger_commands::execute_loadregion(const std::vector<std::string_view> & if (!f) { m_console.printf("Error opening file '%s'\n", params[0]); - return; + return true; } fseek(f, 0L, SEEK_END); @@ -2306,10 +2331,22 @@ void debugger_commands::execute_loadregion(const std::vector<std::string_view> & if (length >= size) length = size; - fread(region->base() + offset, 1, length, f); + fread(base + offset, 1, length, f); fclose(f); m_console.printf("Data loaded successfully to memory : 0x%X to 0x%X\n", offset, offset + length - 1); + + return true; +} + + +/*------------------------------------------------- + execute_loadregion - execute the load command on region memory +-------------------------------------------------*/ + +void debugger_commands::execute_loadregion(const std::vector<std::string_view> ¶ms) +{ + execute_load(-1, std::vector<std::string_view>{ params[0], std::string(params[1]) + std::string(params[3]) + ".m", params[2] }); } @@ -2319,7 +2356,10 @@ void debugger_commands::execute_loadregion(const std::vector<std::string_view> & void debugger_commands::execute_dump(int spacenum, const std::vector<std::string_view> ¶ms) { - // validate parameters + if (execute_dump_try_memory(params)) + return; + + // validate parameters address_space *space; u64 offset; if (!m_console.validate_target_address_parameter(params[1], spacenum, space, offset)) @@ -2480,8 +2520,21 @@ void debugger_commands::execute_dump(int spacenum, const std::vector<std::string execute_dumpmemory - execute the dump command on memory -------------------------------------------------*/ -void debugger_commands::execute_dumpmemory(const std::vector<std::string_view> ¶ms) +bool debugger_commands::execute_dump_try_memory(const std::vector<std::string_view> ¶ms) { + u64 offset = u64(-1); + memory_region *region = nullptr; + memory_share *share = nullptr; + if (!m_console.validate_address_with_memory_parameter(params[1], offset, region, share)) + return false; + + u64 length; + if (offset == u64(-1) || !m_console.validate_number_parameter(params[2], length) || (region == nullptr && share == nullptr)) + return true; // not memory case + + // ... + + return true; } //------------------------------------------------- @@ -2490,6 +2543,9 @@ void debugger_commands::execute_dumpmemory(const std::vector<std::string_view> & void debugger_commands::execute_strdump(int spacenum, const std::vector<std::string_view> ¶ms) { + if (execute_strdump_try_memory(params)) + return; + // validate parameters u64 offset; if (!m_console.validate_number_parameter(params[1], offset)) @@ -2663,8 +2719,21 @@ void debugger_commands::execute_strdump(int spacenum, const std::vector<std::str execute_strdumpmemory - execute the strdump command on memory -------------------------------------------------*/ -void debugger_commands::execute_strdumpmemory(const std::vector<std::string_view> ¶ms) +bool debugger_commands::execute_strdump_try_memory(const std::vector<std::string_view> ¶ms) { + u64 offset = u64(-1); + memory_region *region = nullptr; + memory_share *share = nullptr; + if (!m_console.validate_address_with_memory_parameter(params[1], offset, region, share)) + return false; // not memory case + + u64 length; + if (offset == u64(-1) || !m_console.validate_number_parameter(params[2], length) || (region == nullptr && share == nullptr)) + return true; + + // ... + + return true; } @@ -3169,6 +3238,9 @@ void debugger_commands::execute_cheatundo(const std::vector<std::string_view> &p void debugger_commands::execute_find(int spacenum, const std::vector<std::string_view> ¶ms) { + if (execute_find_try_memory(params)) + return; + u64 offset, length; address_space *space; @@ -3296,8 +3368,21 @@ void debugger_commands::execute_find(int spacenum, const std::vector<std::string execute_findmemory - execute the find command on memory -------------------------------------------------*/ -void debugger_commands::execute_findmemory(const std::vector<std::string_view> ¶ms) +bool debugger_commands::execute_find_try_memory(const std::vector<std::string_view> ¶ms) { + u64 offset = u64(-1); + memory_region *region = nullptr; + memory_share *share = nullptr; + if (!m_console.validate_address_with_memory_parameter(params[0], offset, region, share)) + return false; // not memory case + + u64 length; + if (offset == u64(-1) || !m_console.validate_number_parameter(params[1], length) || (region == nullptr && share == nullptr)) + return true; + + // ... + + return true; } @@ -3307,6 +3392,9 @@ void debugger_commands::execute_findmemory(const std::vector<std::string_view> & void debugger_commands::execute_fill(int spacenum, const std::vector<std::string_view> ¶ms) { + if (execute_fill_try_memory(params)) + return; + u64 offset, length; address_space *space; @@ -3413,8 +3501,21 @@ void debugger_commands::execute_fill(int spacenum, const std::vector<std::string execute_fillmemory - execute the fill command on memory -------------------------------------------------*/ -void debugger_commands::execute_fillmemory(const std::vector<std::string_view> ¶ms) +bool debugger_commands::execute_fill_try_memory(const std::vector<std::string_view> ¶ms) { + u64 offset = u64(-1); + memory_region *region = nullptr; + memory_share *share = nullptr; + if (!m_console.validate_address_with_memory_parameter(params[0], offset, region, share)) + return false; // not memory case + + u64 length; + if (offset == u64(-1) || !m_console.validate_number_parameter(params[1], length) || (region == nullptr && share == nullptr)) + return true; + + // ... + + return true; } diff --git a/src/emu/debug/debugcmd.h b/src/emu/debug/debugcmd.h index b9a5eaeda8862..0836790e404a3 100644 --- a/src/emu/debug/debugcmd.h +++ b/src/emu/debug/debugcmd.h @@ -127,24 +127,24 @@ class debugger_commands void execute_stateload(const std::vector<std::string_view> ¶ms); void execute_rewind(const std::vector<std::string_view> ¶ms); void execute_save(int spacenum, const std::vector<std::string_view> ¶ms); - void execute_savememory(const std::vector<std::string_view> ¶ms); + bool execute_save_try_memory(const std::vector<std::string_view> ¶ms); void execute_saveregion(const std::vector<std::string_view> ¶ms); void execute_load(int spacenum, const std::vector<std::string_view> ¶ms); - void execute_loadmemory(const std::vector<std::string_view> ¶ms); + bool execute_load_try_memory(const std::vector<std::string_view> ¶ms); void execute_loadregion(const std::vector<std::string_view> ¶ms); void execute_dump(int spacenum, const std::vector<std::string_view> ¶ms); - void execute_dumpmemory(const std::vector<std::string_view> ¶ms); + bool execute_dump_try_memory(const std::vector<std::string_view> ¶ms); void execute_strdump(int spacenum, const std::vector<std::string_view> ¶ms); - void execute_strdumpmemory(const std::vector<std::string_view> ¶ms); + bool execute_strdump_try_memory(const std::vector<std::string_view> ¶ms); void execute_cheatrange(bool init, const std::vector<std::string_view> ¶ms); void execute_cheatnext(bool initial, const std::vector<std::string_view> ¶ms); void execute_cheatlist(const std::vector<std::string_view> ¶ms); void execute_cheatundo(const std::vector<std::string_view> ¶ms); void execute_dasm(const std::vector<std::string_view> ¶ms); void execute_find(int spacenum, const std::vector<std::string_view> ¶ms); - void execute_findmemory(const std::vector<std::string_view> ¶ms); + bool execute_find_try_memory(const std::vector<std::string_view> ¶ms); void execute_fill(int spacenum, const std::vector<std::string_view> ¶ms); - void execute_fillmemory(const std::vector<std::string_view> ¶ms); + bool execute_fill_try_memory(const std::vector<std::string_view> ¶ms); void execute_trace(const std::vector<std::string_view> ¶ms, bool trace_over); void execute_traceflush(const std::vector<std::string_view> ¶ms); void execute_history(const std::vector<std::string_view> ¶ms); diff --git a/src/emu/debug/debugcon.cpp b/src/emu/debug/debugcon.cpp index 1042766aa8721..245ed7b66f02a 100644 --- a/src/emu/debug/debugcon.cpp +++ b/src/emu/debug/debugcon.cpp @@ -24,6 +24,7 @@ #include <cctype> #include <fstream> #include <iterator> +#include <regex> /*************************************************************************** @@ -883,7 +884,7 @@ bool debugger_console::validate_device_space_parameter(std::string_view param, i /// optionally followed by a colon and a device identifier. If the /// device identifier is not presnt, the current CPU with debugger focus /// is assumed. See #validate_device_parameter for information on how -/// device parametersare interpreted. +/// device parameters are interpreted. /// \param [in] The parameter string. /// \param [in] spacenum The default address space index. If negative, /// the first address space exposed by the device (i.e. the address @@ -916,6 +917,37 @@ bool debugger_console::validate_target_address_parameter(std::string_view param, } +/// \brief Validate a parameter as a address with memory region or share name +/// +/// Validates a parameter as a address with memory region or share tag and +// ... . +/// \param [in] The parameter string. +/// \param [out] addr The address on success, or unchanged on failure. +/// \return true if the parameter refers to a memory region in the +/// current system, or false otherwise. +bool debugger_console::validate_address_with_memory_parameter(std::string_view param, u64 &addr, memory_region *®ion, memory_share *&share) +{ + std::string str(param); + std::regex re("^([^:]+)(:.+)\\.([ms])$"); + std::smatch m; + if (std::regex_match(str, m, re)) + { + if ('m' == m[3]) + validate_memory_region_parameter(m.str(2), region); + else if ('s' == m[3]) + validate_memory_share_parameter(m.str(2), share); + else + return false; + + validate_number_parameter(m.str(1), addr); + + return true; + } + + return false; +} + + /// \brief Validate a parameter as a memory region /// /// Validates a parameter as a memory region tag and retrieves the diff --git a/src/emu/debug/debugcon.h b/src/emu/debug/debugcon.h index 78ee1d9bb8dd2..09fea9fbfe781 100644 --- a/src/emu/debug/debugcon.h +++ b/src/emu/debug/debugcon.h @@ -130,6 +130,9 @@ class debugger_console // validates a parameter as a target address and retrieves the given address space and address bool validate_target_address_parameter(std::string_view param, int spacenum, address_space *&space, u64 &addr); + // validates a parameter as a address with memory region or share name and ... + bool validate_address_with_memory_parameter(std::string_view param, u64 &addr, memory_region *®ion, memory_share *&share); + // validates a parameter as a memory region name and retrieves the given region bool validate_memory_region_parameter(std::string_view param, memory_region *&result); From 35f67f807d8e68787881fa1a1dbc0af1ed79725a Mon Sep 17 00:00:00 2001 From: Andrei Holub <andrei.holub@gmail.com> Date: Sat, 7 Jun 2025 10:36:41 -0400 Subject: [PATCH 4/5] implement fill/find --- src/emu/debug/debugcmd.cpp | 235 ++++++++++++++++++++++++++++++++++++- 1 file changed, 231 insertions(+), 4 deletions(-) diff --git a/src/emu/debug/debugcmd.cpp b/src/emu/debug/debugcmd.cpp index 04585fce3b1e8..35b6cfe060c91 100644 --- a/src/emu/debug/debugcmd.cpp +++ b/src/emu/debug/debugcmd.cpp @@ -28,6 +28,7 @@ #include "softlist.h" #include "corestr.h" +#include "multibyte.h" #include <algorithm> #include <cctype> @@ -2526,11 +2527,11 @@ bool debugger_commands::execute_dump_try_memory(const std::vector<std::string_vi memory_region *region = nullptr; memory_share *share = nullptr; if (!m_console.validate_address_with_memory_parameter(params[1], offset, region, share)) - return false; + return false; // not memory case u64 length; if (offset == u64(-1) || !m_console.validate_number_parameter(params[2], length) || (region == nullptr && share == nullptr)) - return true; // not memory case + return true; // ... @@ -2715,6 +2716,7 @@ void debugger_commands::execute_strdump(int spacenum, const std::vector<std::str fclose(f); m_console.printf("Data dumped successfully\n"); } + /*------------------------------------------------- execute_strdumpmemory - execute the strdump command on memory -------------------------------------------------*/ @@ -3380,7 +3382,120 @@ bool debugger_commands::execute_find_try_memory(const std::vector<std::string_vi if (offset == u64(-1) || !m_console.validate_number_parameter(params[1], length) || (region == nullptr && share == nullptr)) return true; - // ... + u32 msize; + u8 *base; + bool is_le; + if (region != nullptr) + { + msize = region->bytes(); + base = region->base(); + is_le = region->endianness() == ENDIANNESS_LITTLE; + } + else // if (share != nullptr) + { + msize = share->bytes(); + base = reinterpret_cast<u8 *>(share->ptr()); + is_le = share->endianness() == ENDIANNESS_LITTLE; + } + + if (offset >= msize) + { + m_console.printf("Invalid offset\n"); + return true; + } + if ((length <= 0) || ((length + offset) >= msize)) + length = msize - offset; + + // further validation + u64 const endoffset = offset + length - 1; + int cur_data_size = 1; + + // parse the data parameters + u64 data_to_find[256]; + u8 data_size[256]; + int data_count = 0; + for (int i = 2; i < params.size(); i++) + { + std::string_view pdata = params[i]; + + if (!pdata.empty() && pdata.front() == '"' && pdata.back() == '"') // check for a string + { + auto const pdatalen = params[i].length() - 1; + for (int j = 1; j < pdatalen; j++) + { + data_to_find[data_count] = pdata[j]; + data_size[data_count++] = 1; + } + } + else // otherwise, validate as a number + { + // check for a 'b','w','d',or 'q' prefix + data_size[data_count] = cur_data_size; + if (pdata.length() >= 2) + { + if (tolower(u8(pdata[0])) == 'b' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 1; pdata.remove_prefix(2); } + if (tolower(u8(pdata[0])) == 'w' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 2; pdata.remove_prefix(2); } + if (tolower(u8(pdata[0])) == 'd' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 4; pdata.remove_prefix(2); } + if (tolower(u8(pdata[0])) == 'q' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 8; pdata.remove_prefix(2); } + } + + // look for a wildcard + if (pdata == "?") + data_size[data_count++] |= 0x10; + + // otherwise, validate as a number + else if (!m_console.validate_number_parameter(pdata, data_to_find[data_count++])) + return true; + } + } + + // now search + int found = 0; + for (u64 i = offset; i <= endoffset; i += data_size[0]) + { + int suboffset = 0; + bool match = true; + + // find the entire string + for (int j = 0; j < data_count && match; j++) + { + offs_t address = i + suboffset; + switch (data_size[j]) + { + case 1: + match = u8(data_to_find[j]) == base[address]; + break; + + case 2: + match = u16(data_to_find[j]) == (is_le ? get_u16le(&base[address]) : get_u16be(&base[address])); + break; + + case 4: + match = u32(data_to_find[j]) == (is_le ? get_u32le(&base[address]) : get_u32be(&base[address])); + break; + + case 8: + match = u64(data_to_find[j]) == (is_le ? get_u64le(&base[address]) : get_u64be(&base[address])); + break; + + default: + // all other cases are wildcards + break; + } + suboffset += data_size[j] & 0x0f; + } + + // did we find it? + if (match) + { + found++; + m_console.printf("Found at %04X\n", i); + } + } + + // print something if not found + if (found == 0) + m_console.printf("Not found\n"); return true; } @@ -3513,7 +3628,119 @@ bool debugger_commands::execute_fill_try_memory(const std::vector<std::string_vi if (offset == u64(-1) || !m_console.validate_number_parameter(params[1], length) || (region == nullptr && share == nullptr)) return true; - // ... + u32 msize; + u8 *base; + bool is_le; + if (region != nullptr) + { + msize = region->bytes(); + base = region->base(); + is_le = region->endianness() == ENDIANNESS_LITTLE; + } + else // if (share != nullptr) + { + msize = share->bytes(); + base = reinterpret_cast<u8 *>(share->ptr()); + is_le = share->endianness() == ENDIANNESS_LITTLE; + } + + if (offset >= msize) + { + m_console.printf("Invalid offset\n"); + return true; + } + if ((length <= 0) || ((length + offset) >= msize)) + length = msize - offset; + + // further validation + int cur_data_size = 1; + + // parse the data parameters + u64 fill_data[256]; + u8 fill_data_size[256]; + int data_count = 0; + for (int i = 2; i < params.size(); i++) + { + std::string_view pdata = params[i]; + + // check for a string + if (!pdata.empty() && pdata.front() == '"' && pdata.back() == '"') + { + auto const pdatalen = pdata.length() - 1; + for (int j = 1; j < pdatalen; j++) + { + fill_data[data_count] = pdata[j]; + fill_data_size[data_count++] = 1; + } + } + + // otherwise, validate as a number + else + { + // check for a 'b','w','d',or 'q' prefix + fill_data_size[data_count] = cur_data_size; + if (pdata.length() >= 2) + { + if (tolower(u8(pdata[0])) == 'b' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 1; pdata.remove_prefix(2); } + if (tolower(u8(pdata[0])) == 'w' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 2; pdata.remove_prefix(2); } + if (tolower(u8(pdata[0])) == 'd' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 4; pdata.remove_prefix(2); } + if (tolower(u8(pdata[0])) == 'q' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 8; pdata.remove_prefix(2); } + } + + // validate as a number + if (!m_console.validate_number_parameter(pdata, fill_data[data_count++])) + return true; + } + } + if (data_count == 0) + return true; + + // now fill memory + u64 count = length; + while (count != 0) + { + // write the entire string + for (int j = 0; j < data_count; j++) + { + offs_t address = offset; + switch (fill_data_size[j]) + { + case 1: + base[address] = u8(fill_data[j]); + break; + + case 2: + if (is_le) + put_u16le(&base[address], u16(fill_data[j])); + else + put_u16be(&base[address], u16(fill_data[j])); + break; + + case 4: + if (is_le) + put_u32le(&base[address], u32(fill_data[j])); + else + put_u32be(&base[address], u32(fill_data[j])); + break; + + case 8: + if (is_le) + put_u64le(&base[address], u64(fill_data[j])); + else + put_u64be(&base[address], u64(fill_data[j])); + break; + } + + offset += fill_data_size[j]; + if (count <= fill_data_size[j]) + { + count = 0; + break; + } + else + count -= fill_data_size[j]; + } + } return true; } From 4b2232119c705ba450aa20937ba8d0e54c0b9e38 Mon Sep 17 00:00:00 2001 From: Andrei Holub <andrei.holub@gmail.com> Date: Sat, 7 Jun 2025 21:30:48 -0400 Subject: [PATCH 5/5] implement dump/strdump --- src/emu/debug/debugcmd.cpp | 348 ++++++++++++++++++++++++++++++++++--- src/emu/debug/debugcon.cpp | 7 +- src/emu/debug/debugcon.h | 2 +- 3 files changed, 333 insertions(+), 24 deletions(-) diff --git a/src/emu/debug/debugcmd.cpp b/src/emu/debug/debugcmd.cpp index 35b6cfe060c91..3e1a158d3920f 100644 --- a/src/emu/debug/debugcmd.cpp +++ b/src/emu/debug/debugcmd.cpp @@ -2360,7 +2360,7 @@ void debugger_commands::execute_dump(int spacenum, const std::vector<std::string if (execute_dump_try_memory(params)) return; - // validate parameters + // validate parameters address_space *space; u64 offset; if (!m_console.validate_target_address_parameter(params[1], spacenum, space, offset)) @@ -2533,7 +2533,153 @@ bool debugger_commands::execute_dump_try_memory(const std::vector<std::string_vi if (offset == u64(-1) || !m_console.validate_number_parameter(params[2], length) || (region == nullptr && share == nullptr)) return true; - // ... + u64 width = 0; + if (params.size() > 3 && !m_console.validate_number_parameter(params[3], width)) + return true; + + bool ascii = true; + if (params.size() > 4 && !m_console.validate_boolean_parameter(params[4], ascii)) + return true; + + u64 rowsize = 16; + if (params.size() > 5 && !m_console.validate_number_parameter(params[5], rowsize)) + return true; + + int shift = 0; + u64 granularity = shift >= 0 ? 1 : 1 << -shift; + + u32 msize; + u8 *base; + bool be; + if (region != nullptr) + { + msize = region->bytes(); + base = region->base(); + be = region->endianness() == ENDIANNESS_BIG; + if (width == 0) + width = region->bytewidth(); + } + else // if (share != nullptr) + { + msize = share->bytes(); + base = reinterpret_cast<u8 *>(share->ptr()); + be = share->endianness() == ENDIANNESS_BIG; + if (width == 0) + width = share->bytewidth(); + } + + if (offset >= msize) + { + m_console.printf("Invalid offset\n"); + return true; + } + if ((length <= 0) || ((length + offset) >= msize)) + length = msize - offset; + + // further validation + if (width != 1 && width != 2 && width != 4 && width != 8) + { + m_console.printf("Invalid width! (must be 1,2,4 or 8)\n"); + return true; + } + if (width < granularity) + { + m_console.printf("Invalid width! (must be at least %d)\n", granularity); + return true; + } + if (rowsize == 0 || (rowsize % width) != 0) + { + m_console.printf("Invalid row size! (must be a positive multiple of %d)\n", width); + return true; + } + + u64 endoffset = offset + length - 1; + + // open the file + std::string filename(params[0]); + FILE *const f = fopen(filename.c_str(), "w"); + if (!f) + { + m_console.printf("Error opening file '%s'\n", params[0]); + return true; + } + + // now write the data out + util::ovectorstream output; + output.reserve(200); + + const unsigned delta = (shift >= 0) ? (width << shift) : (width >> -shift); + + for (u64 i = offset; i <= endoffset; i += rowsize) + { + output.clear(); + output.rdbuf()->clear(); + + // print the address + util::stream_format(output, "%0*X: ", 8, i); + + // print the bytes + for (u64 j = 0; j < rowsize; j += delta) + { + if (i + j <= endoffset) + { + switch (width) + { + case 8: + util::stream_format(output, " %016X", get_u64be(&base[i+j])); + break; + case 4: + util::stream_format(output, " %08X", get_u32be(&base[i+j])); + break; + case 2: + util::stream_format(output, " %04X", get_u16be(&base[i+j])); + break; + case 1: + util::stream_format(output, " %02X", base[i+j]); + break; + } + } + else + util::stream_format(output, " %*s", width * 2, ""); + } + + // print the ASCII + if (ascii) + { + util::stream_format(output, " "); + for (u64 j = 0; j < rowsize && (i + j) <= endoffset; j += delta) + { + u64 data = 0; + switch (width) + { + case 8: + data = get_u64be(&base[i+j]); + break; + case 4: + data = get_u32be(&base[i+j]); + break; + case 2: + data = get_u16be(&base[i+j]); + break; + case 1: + data = base[i+j]; + break; + } + for (unsigned int b = 0; b != width; b++) { + u8 byte = data >> (8 * (be ? (width-1-b) : b)); + util::stream_format(output, "%c", (byte >= 32 && byte < 127) ? byte : '.'); + } + } + } + + // 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"); return true; } @@ -2733,7 +2879,167 @@ bool debugger_commands::execute_strdump_try_memory(const std::vector<std::string if (offset == u64(-1) || !m_console.validate_number_parameter(params[2], length) || (region == nullptr && share == nullptr)) return true; - // ... + u64 term = 0; + if (params.size() > 3 && !m_console.validate_number_parameter(params[3], term)) + return true; + + // further validation + if (term >= 0x100 && term != u64(-0x80)) + { + m_console.printf("Invalid termination character\n"); + return true; + } + + // open the file + std::string filename(params[0]); + FILE *f = fopen(filename.c_str(), "w"); + if (!f) + { + m_console.printf("Error opening file '%s'\n", params[0]); + return true; + } + + u32 msize; + u8 *base; + bool be; + u64 width; + if (region != nullptr) + { + msize = region->bytes(); + base = region->base(); + be = region->endianness() == ENDIANNESS_BIG; + width = region->bytewidth(); + } + else // if (share != nullptr) + { + msize = share->bytes(); + base = reinterpret_cast<u8 *>(share->ptr()); + be = share->endianness() == ENDIANNESS_BIG; + width = share->bytewidth(); + } + + if (offset >= msize) + { + m_console.printf("Invalid offset\n"); + return true; + } + if ((length <= 0) || ((length + offset) >= msize)) + length = msize - offset; + + // now write the data out + util::ovectorstream output; + output.reserve(200); + + bool terminated = true; + while (length-- != 0) + { + if (terminated) + { + terminated = false; + output.clear(); + output.rdbuf()->clear(); + + // print the address + util::stream_format(output, "%0*X: \"", 8, offset); + } + + // get the character data + u64 data = 0; + offs_t curaddr = offset; + switch (width) + { + case 1: + data = base[curaddr]; + break; + + case 2: + data = be ? get_u16be(&base[curaddr]) : get_u16le(&base[curaddr]); + break; + + case 4: + data = be ? get_u32be(&base[curaddr]) : get_u32le(&base[curaddr]); + break; + + case 8: + data = be ? get_u64be(&base[curaddr]) : get_u64le(&base[curaddr]); + break; + } + + // print the characters + for (int n = 0; n < width; n++) + { + // check for termination within word + if (terminated) + { + terminated = false; + + // output the result + auto const &text = output.vec(); + fprintf(f, "%.*s\"\n", int(unsigned(text.size())), &text[0]); + output.clear(); + output.rdbuf()->clear(); + + // print the address + util::stream_format(output, "%0*X.%d: \"", 8, offset, n); + } + + u8 ch = data & 0xff; + data >>= 8; + + // check for termination + if (term == u64(-0x80)) + { + if (BIT(ch, 7)) + { + terminated = true; + ch &= 0x7f; + } + } + else if (ch == term) + { + terminated = true; + continue; + } + + // check for non-ASCII characters + if (ch < 0x20 || ch >= 0x7f) + { + // use special or octal escape + if (ch >= 0x07 && ch <= 0x0d) + util::stream_format(output, "\\%c", "abtnvfr"[ch - 0x07]); + else + util::stream_format(output, "\\%03o", ch); + } + else + { + if (ch == '"' || ch == '\\') + output << '\\'; + output << char(ch); + } + } + + if (terminated) + { + // output the result + auto const &text = output.vec(); + fprintf(f, "%.*s\"\n", int(unsigned(text.size())), &text[0]); + output.clear(); + output.rdbuf()->clear(); + } + + offset += width; + } + + if (!terminated) + { + // 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"); return true; } @@ -3384,18 +3690,18 @@ bool debugger_commands::execute_find_try_memory(const std::vector<std::string_vi u32 msize; u8 *base; - bool is_le; + bool be; if (region != nullptr) { msize = region->bytes(); base = region->base(); - is_le = region->endianness() == ENDIANNESS_LITTLE; + be = region->endianness() == ENDIANNESS_BIG; } else // if (share != nullptr) { msize = share->bytes(); base = reinterpret_cast<u8 *>(share->ptr()); - is_le = share->endianness() == ENDIANNESS_LITTLE; + be = share->endianness() == ENDIANNESS_BIG; } if (offset >= msize) @@ -3467,15 +3773,15 @@ bool debugger_commands::execute_find_try_memory(const std::vector<std::string_vi break; case 2: - match = u16(data_to_find[j]) == (is_le ? get_u16le(&base[address]) : get_u16be(&base[address])); + match = u16(data_to_find[j]) == (be ? get_u16be(&base[address]) : get_u16le(&base[address])); break; case 4: - match = u32(data_to_find[j]) == (is_le ? get_u32le(&base[address]) : get_u32be(&base[address])); + match = u32(data_to_find[j]) == (be ? get_u32be(&base[address]) : get_u32le(&base[address])); break; case 8: - match = u64(data_to_find[j]) == (is_le ? get_u64le(&base[address]) : get_u64be(&base[address])); + match = u64(data_to_find[j]) == (be ? get_u64be(&base[address]) : get_u64le(&base[address])); break; default: @@ -3630,18 +3936,18 @@ bool debugger_commands::execute_fill_try_memory(const std::vector<std::string_vi u32 msize; u8 *base; - bool is_le; + bool be; if (region != nullptr) { msize = region->bytes(); base = region->base(); - is_le = region->endianness() == ENDIANNESS_LITTLE; + be = region->endianness() == ENDIANNESS_BIG; } else // if (share != nullptr) { msize = share->bytes(); base = reinterpret_cast<u8 *>(share->ptr()); - is_le = share->endianness() == ENDIANNESS_LITTLE; + be = share->endianness() == ENDIANNESS_BIG; } if (offset >= msize) @@ -3710,24 +4016,24 @@ bool debugger_commands::execute_fill_try_memory(const std::vector<std::string_vi break; case 2: - if (is_le) - put_u16le(&base[address], u16(fill_data[j])); - else + if (be) put_u16be(&base[address], u16(fill_data[j])); + else + put_u16le(&base[address], u16(fill_data[j])); break; case 4: - if (is_le) - put_u32le(&base[address], u32(fill_data[j])); - else + if (be) put_u32be(&base[address], u32(fill_data[j])); + else + put_u32le(&base[address], u32(fill_data[j])); break; case 8: - if (is_le) - put_u64le(&base[address], u64(fill_data[j])); - else + if (be) put_u64be(&base[address], u64(fill_data[j])); + else + put_u64le(&base[address], u64(fill_data[j])); break; } diff --git a/src/emu/debug/debugcon.cpp b/src/emu/debug/debugcon.cpp index 245ed7b66f02a..f9076dda5235e 100644 --- a/src/emu/debug/debugcon.cpp +++ b/src/emu/debug/debugcon.cpp @@ -919,10 +919,13 @@ bool debugger_console::validate_target_address_parameter(std::string_view param, /// \brief Validate a parameter as a address with memory region or share name /// -/// Validates a parameter as a address with memory region or share tag and -// ... . +/// Validates a parameter as a address with memory region or share tag. addres +/// parameters stays unchanged if invalid and requires additional validation on +/// the caller side. /// \param [in] The parameter string. /// \param [out] addr The address on success, or unchanged on failure. +/// \param [out] region The region on success, or unchanged on failure. +/// \param [out] share The share on success, or unchanged on failure. /// \return true if the parameter refers to a memory region in the /// current system, or false otherwise. bool debugger_console::validate_address_with_memory_parameter(std::string_view param, u64 &addr, memory_region *®ion, memory_share *&share) diff --git a/src/emu/debug/debugcon.h b/src/emu/debug/debugcon.h index 09fea9fbfe781..b1cef0f7c847d 100644 --- a/src/emu/debug/debugcon.h +++ b/src/emu/debug/debugcon.h @@ -130,7 +130,7 @@ class debugger_console // validates a parameter as a target address and retrieves the given address space and address bool validate_target_address_parameter(std::string_view param, int spacenum, address_space *&space, u64 &addr); - // validates a parameter as a address with memory region or share name and ... + // validates a parameter as a address with memory region or share name and retrieves the given address and region or share bool validate_address_with_memory_parameter(std::string_view param, u64 &addr, memory_region *®ion, memory_share *&share); // validates a parameter as a memory region name and retrieves the given region