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}]
[:],[,[,…]]**
+**f[ind] :.{m|s},[,[,…]]**
Search through memory for the specified sequence of data. The
**** is the address to begin searching from, optionally
@@ -114,6 +115,7 @@ fill
----
**fill[{d|i|o}] [:],[,[,…]]**
+**fill :.{m|s},[,[,…]]**
Overwrite a block of memory with copies of the supplied data sequence.
The **** specifies the address to begin writing at, optionally
@@ -146,6 +148,7 @@ dump
----
**dump[{d|i|o}] ,[:],[,[,[,]]]**
+**dump ,:.{m|s},[,[,[,]]]**
Dump memory to the text file specified by the **** parameter.
The **** specifies the address to start dumping from,
@@ -190,6 +193,7 @@ strdump
-------
**strdump[{d|i|o}] ,[:],[,]**
+**strdump ,:.{m|s},[,]**
Dump memory to the text file specified by the **** parameter.
The **** specifies the address to start dumping from,
@@ -216,6 +220,7 @@ save
----
**save[{d|i|o}] ,[:],**
+**save ,:.{m|s},**
Save raw memory to the binary file specified by the ****
parameter. The **** specifies the address to start saving
@@ -260,6 +265,9 @@ start saving from, and the **** specifies how much memory to
save. The range **** through **+-1**,
inclusive, will be output to the file.
+Alternetevely use :ref:`debugger-command-save` syntax:
+``save ,:.m,``
+
Examples:
``saver data.bin,200,100,:monitor``
@@ -278,6 +286,7 @@ load
----
**load[{d|i|o}] ,[:][,]**
+**load ,:.{m|s}[,]**
Load raw memory from the binary file specified by the ****
parameter. The **** specifies the address to start loading to,
@@ -334,6 +343,9 @@ through **+-1**, inclusive, will be read in from the
file. If the **** 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 ,:.m[,]``
+
Examples:
``loadr data.bin,200,100,:monitor``
diff --git a/src/emu/debug/debugcmd.cpp b/src/emu/debug/debugcmd.cpp
index 76a6053477f9c..3e1a158d3920f 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
#include
@@ -2007,6 +2008,9 @@ void debugger_commands::execute_rewind(const std::vector ¶
void debugger_commands::execute_save(int spacenum, const std::vector ¶ms)
{
+ if (execute_save_try_memory(params))
+ return;
+
u64 offset, endoffset, length;
address_space *space;
@@ -2093,31 +2097,42 @@ void debugger_commands::execute_save(int spacenum, const std::vector ¶ms)
+bool debugger_commands::execute_save_try_memory(const std::vector ¶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
- // 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;
+ u64 length;
+ 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(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]);
@@ -2125,12 +2140,24 @@ void debugger_commands::execute_saveregion(const std::vector &
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 ¶ms)
+{
+ execute_save(-1, std::vector{ params[0], std::string(params[1]) + std::string(params[3]) + ".m", params[2] });
}
@@ -2140,6 +2167,9 @@ void debugger_commands::execute_saveregion(const std::vector &
void debugger_commands::execute_load(int spacenum, const std::vector ¶ms)
{
+ if (execute_load_try_memory(params))
+ return;
+
u64 offset, endoffset, length = 0;
address_space *space;
@@ -2247,31 +2277,43 @@ void debugger_commands::execute_load(int spacenum, const std::vector ¶ms)
+bool debugger_commands::execute_load_try_memory(const std::vector ¶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(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]);
@@ -2279,7 +2321,7 @@ void debugger_commands::execute_loadregion(const std::vector &
if (!f)
{
m_console.printf("Error opening file '%s'\n", params[0]);
- return;
+ return true;
}
fseek(f, 0L, SEEK_END);
@@ -2290,10 +2332,22 @@ void debugger_commands::execute_loadregion(const std::vector &
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 ¶ms)
+{
+ execute_load(-1, std::vector{ params[0], std::string(params[1]) + std::string(params[3]) + ".m", params[2] });
}
@@ -2303,6 +2357,9 @@ void debugger_commands::execute_loadregion(const std::vector &
void debugger_commands::execute_dump(int spacenum, const std::vector ¶ms)
{
+ if (execute_dump_try_memory(params))
+ return;
+
// validate parameters
address_space *space;
u64 offset;
@@ -2460,6 +2517,172 @@ void debugger_commands::execute_dump(int spacenum, const std::vector ¶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;
+
+ 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(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;
+}
//-------------------------------------------------
// execute_strdump - execute the strdump command
@@ -2467,6 +2690,9 @@ void debugger_commands::execute_dump(int spacenum, const std::vector ¶ms)
{
+ if (execute_strdump_try_memory(params))
+ return;
+
// validate parameters
u64 offset;
if (!m_console.validate_number_parameter(params[1], offset))
@@ -2637,6 +2863,187 @@ void debugger_commands::execute_strdump(int spacenum, const std::vector ¶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;
+
+ 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(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;
+}
+
/*-------------------------------------------------
execute_cheatrange - add a range to search for
@@ -3139,6 +3546,9 @@ void debugger_commands::execute_cheatundo(const std::vector &p
void debugger_commands::execute_find(int spacenum, const std::vector ¶ms)
{
+ if (execute_find_try_memory(params))
+ return;
+
u64 offset, length;
address_space *space;
@@ -3262,6 +3672,140 @@ void debugger_commands::execute_find(int spacenum, const std::vector ¶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;
+
+ u32 msize;
+ u8 *base;
+ bool be;
+ if (region != nullptr)
+ {
+ msize = region->bytes();
+ base = region->base();
+ be = region->endianness() == ENDIANNESS_BIG;
+ }
+ else // if (share != nullptr)
+ {
+ msize = share->bytes();
+ base = reinterpret_cast(share->ptr());
+ be = share->endianness() == ENDIANNESS_BIG;
+ }
+
+ 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]) == (be ? get_u16be(&base[address]) : get_u16le(&base[address]));
+ break;
+
+ case 4:
+ match = u32(data_to_find[j]) == (be ? get_u32be(&base[address]) : get_u32le(&base[address]));
+ break;
+
+ case 8:
+ match = u64(data_to_find[j]) == (be ? get_u64be(&base[address]) : get_u64le(&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;
+}
+
//-------------------------------------------------
// execute_fill - execute the fill command
@@ -3269,6 +3813,9 @@ void debugger_commands::execute_find(int spacenum, const std::vector ¶ms)
{
+ if (execute_fill_try_memory(params))
+ return;
+
u64 offset, length;
address_space *space;
@@ -3371,6 +3918,139 @@ void debugger_commands::execute_fill(int spacenum, const std::vector ¶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;
+
+ u32 msize;
+ u8 *base;
+ bool be;
+ if (region != nullptr)
+ {
+ msize = region->bytes();
+ base = region->base();
+ be = region->endianness() == ENDIANNESS_BIG;
+ }
+ else // if (share != nullptr)
+ {
+ msize = share->bytes();
+ base = reinterpret_cast(share->ptr());
+ be = share->endianness() == ENDIANNESS_BIG;
+ }
+
+ 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 (be)
+ put_u16be(&base[address], u16(fill_data[j]));
+ else
+ put_u16le(&base[address], u16(fill_data[j]));
+ break;
+
+ case 4:
+ if (be)
+ put_u32be(&base[address], u32(fill_data[j]));
+ else
+ put_u32le(&base[address], u32(fill_data[j]));
+ break;
+
+ case 8:
+ if (be)
+ put_u64be(&base[address], u64(fill_data[j]));
+ else
+ put_u64le(&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;
+}
+
/*-------------------------------------------------
execute_dasm - execute the dasm command
diff --git a/src/emu/debug/debugcmd.h b/src/emu/debug/debugcmd.h
index cf38c6d903a27..0836790e404a3 100644
--- a/src/emu/debug/debugcmd.h
+++ b/src/emu/debug/debugcmd.h
@@ -127,18 +127,24 @@ class debugger_commands
void execute_stateload(const std::vector ¶ms);
void execute_rewind(const std::vector ¶ms);
void execute_save(int spacenum, const std::vector ¶ms);
+ bool execute_save_try_memory(const std::vector ¶ms);
void execute_saveregion(const std::vector ¶ms);
void execute_load(int spacenum, const std::vector ¶ms);
+ bool execute_load_try_memory(const std::vector ¶ms);
void execute_loadregion(const std::vector ¶ms);
void execute_dump(int spacenum, const std::vector ¶ms);
+ bool execute_dump_try_memory(const std::vector ¶ms);
void execute_strdump(int spacenum, const std::vector ¶ms);
+ bool execute_strdump_try_memory(const std::vector ¶ms);
void execute_cheatrange(bool init, const std::vector ¶ms);
void execute_cheatnext(bool initial, const std::vector ¶ms);
void execute_cheatlist(const std::vector ¶ms);
void execute_cheatundo(const std::vector ¶ms);
void execute_dasm(const std::vector ¶ms);
void execute_find(int spacenum, const std::vector ¶ms);
+ bool execute_find_try_memory(const std::vector ¶ms);
void execute_fill(int spacenum, const std::vector ¶ms);
+ bool execute_fill_try_memory(const std::vector ¶ms);
void execute_trace(const std::vector ¶ms, bool trace_over);
void execute_traceflush(const std::vector ¶ms);
void execute_history(const std::vector ¶ms);
diff --git a/src/emu/debug/debugcon.cpp b/src/emu/debug/debugcon.cpp
index ec5bc15475101..f9076dda5235e 100644
--- a/src/emu/debug/debugcon.cpp
+++ b/src/emu/debug/debugcon.cpp
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
/***************************************************************************
@@ -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,40 @@ 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. 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)
+{
+ 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
@@ -944,6 +979,34 @@ bool debugger_console::validate_memory_region_parameter(std::string_view param,
}
+/// \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)
+{
+ 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
+ {
+ printf("No matching memory share found for '%s'\n", param);
+ return false;
+ }
+}
+
+
/// \brief Get search base for device or address space parameter
///
/// Handles prefix prefixes used to indicate that a device tag should be
diff --git a/src/emu/debug/debugcon.h b/src/emu/debug/debugcon.h
index 37b2e235348cc..b1cef0f7c847d 100644
--- a/src/emu/debug/debugcon.h
+++ b/src/emu/debug/debugcon.h
@@ -130,9 +130,15 @@ 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 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
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);
+
// 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 ,,[,[,]] -- disassemble to the given file\n"
" f[ind] ,[,[,...]] -- search memory for data\n"
+ " f[ind] :.{m|s},[,[,...]] -- search memory region or share for data\n"
" f[ind]d ,[,[,...]] -- search data memory for data\n"
" f[ind]i ,[,[,...]] -- search I/O memory for data\n"
" fill ,[,[,...]] -- fill memory with data\n"
+ " fill :.{m|s},[,[,...]] -- fill memory region or share with data\n"
" filld [:],[,[,...]] -- fill data memory with data\n"
" filli [:],[,[,...][ -- fill I/O memory with data\n"
" fillo [:],[,[,...][ -- fill opcode memory with data\n"
" dump ,[:],[,[,[,]]] -- dump memory as text\n"
+ " dump ,:.{m|s},[,[,[,]]] -- dump memory region or share as text\n"
" dumpd ,[:],[,[,[,]]] -- dump data memory as text\n"
" dumpi ,[:],[,[,[,]]] -- dump I/O memory as text\n"
" dumpo ,[:],[,[,[,]]] -- dump opcodes memory as text\n"
" strdump ,[:],[,] -- dump ASCII strings from memory\n"
+ " strdump ,:.{m|s},[,] -- dump ASCII strings from memory region or share\n"
" strdumpd ,[:],[,] -- dump ASCII strings from data memory\n"
" strdumpi ,[:],[,] -- dump ASCII strings from I/O memory\n"
" strdumpo ,[:],[,] -- dump ASCII strings from opcodes memory\n"
" save ,[:], -- save binary memory to the given file\n"
+ " save ,:.{m|s}, -- load binary memory region or share to the given file\n"
" saved ,[:], -- save binary data memory to the given file\n"
" savei ,[: