summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author holub <andrei.holub@gmail.com>2025-08-30 10:25:16 -0400
committer GitHub <noreply@github.com>2025-08-30 16:25:16 +0200
commit095418aec533e21727421dbf5a3ab4cedf90c135 (patch)
treee55aa8a6f9245c676f3a52b2cd64a9ab0b392ab0
parentc745d0bce07097aea0659fd10bff3077105efeee (diff)
emu/debug: Extended memory commands for region and space (#13767)
-rw-r--r--docs/source/debugger/index.rst5
-rw-r--r--docs/source/debugger/memory.rst12
-rw-r--r--src/emu/debug/debugcmd.cpp750
-rw-r--r--src/emu/debug/debugcmd.h6
-rw-r--r--src/emu/debug/debugcon.cpp65
-rw-r--r--src/emu/debug/debugcon.h6
-rw-r--r--src/emu/debug/debughlp.cpp18
-rw-r--r--src/emu/debug/express.cpp135
-rw-r--r--src/emu/debug/express.h5
9 files changed, 964 insertions, 38 deletions
diff --git a/docs/source/debugger/index.rst b/docs/source/debugger/index.rst
index 2947d0253ac..a035a7e13c0 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 dfb5914b5a9..b32273a40c6 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 97b4ce0afb9..9ca407cec3f 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>
@@ -2011,6 +2012,9 @@ void debugger_commands::execute_rewind(const std::vector<std::string_view> &para
void debugger_commands::execute_save(int spacenum, const std::vector<std::string_view> &params)
{
+ if (execute_save_try_memory(params))
+ return;
+
u64 offset, endoffset, length;
address_space *space;
@@ -2097,31 +2101,42 @@ void debugger_commands::execute_save(int spacenum, const std::vector<std::string
m_console.printf("Data saved successfully\n");
}
-
/*-------------------------------------------------
- execute_saveregion - execute the save command on region memory
+ execute_savememory - execute the save command on memory
-------------------------------------------------*/
-void debugger_commands::execute_saveregion(const std::vector<std::string_view> &params)
+bool debugger_commands::execute_save_try_memory(const std::vector<std::string_view> &params)
{
- 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<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]);
@@ -2129,12 +2144,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> &params)
+{
+ execute_save(-1, std::vector<std::string_view>{ params[0], std::string(params[1]) + std::string(params[3]) + ".m", params[2] });
}
@@ -2144,6 +2171,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> &params)
{
+ if (execute_load_try_memory(params))
+ return;
+
u64 offset, endoffset, length = 0;
address_space *space;
@@ -2251,31 +2281,43 @@ 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_loadregion - execute the load command on region memory
+ execute_loadmemory - execute the load command on memory
-------------------------------------------------*/
-void debugger_commands::execute_loadregion(const std::vector<std::string_view> &params)
+bool debugger_commands::execute_load_try_memory(const std::vector<std::string_view> &params)
{
- 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]);
@@ -2283,7 +2325,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);
@@ -2294,10 +2336,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> &params)
+{
+ execute_load(-1, std::vector<std::string_view>{ params[0], std::string(params[1]) + std::string(params[3]) + ".m", params[2] });
}
@@ -2307,6 +2361,9 @@ void debugger_commands::execute_loadregion(const std::vector<std::string_view> &
void debugger_commands::execute_dump(int spacenum, const std::vector<std::string_view> &params)
{
+ if (execute_dump_try_memory(params))
+ return;
+
// validate parameters
address_space *space;
u64 offset;
@@ -2464,6 +2521,172 @@ 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
+-------------------------------------------------*/
+
+bool debugger_commands::execute_dump_try_memory(const std::vector<std::string_view> &params)
+{
+ 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<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;
+}
//-------------------------------------------------
// execute_strdump - execute the strdump command
@@ -2471,6 +2694,9 @@ void debugger_commands::execute_dump(int spacenum, const std::vector<std::string
void debugger_commands::execute_strdump(int spacenum, const std::vector<std::string_view> &params)
{
+ if (execute_strdump_try_memory(params))
+ return;
+
// validate parameters
u64 offset;
if (!m_console.validate_number_parameter(params[1], offset))
@@ -2641,6 +2867,187 @@ void debugger_commands::execute_strdump(int spacenum, const std::vector<std::str
m_console.printf("Data dumped successfully\n");
}
+/*-------------------------------------------------
+ execute_strdumpmemory - execute the strdump command on memory
+-------------------------------------------------*/
+
+bool debugger_commands::execute_strdump_try_memory(const std::vector<std::string_view> &params)
+{
+ 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<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;
+}
+
/*-------------------------------------------------
execute_cheatrange - add a range to search for
@@ -3143,6 +3550,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> &params)
{
+ if (execute_find_try_memory(params))
+ return;
+
u64 offset, length;
address_space *space;
@@ -3266,6 +3676,140 @@ 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
+-------------------------------------------------*/
+
+bool debugger_commands::execute_find_try_memory(const std::vector<std::string_view> &params)
+{
+ 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<u8 *>(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
@@ -3273,6 +3817,9 @@ void debugger_commands::execute_find(int spacenum, const std::vector<std::string
void debugger_commands::execute_fill(int spacenum, const std::vector<std::string_view> &params)
{
+ if (execute_fill_try_memory(params))
+ return;
+
u64 offset, length;
address_space *space;
@@ -3375,6 +3922,139 @@ void debugger_commands::execute_fill(int spacenum, const std::vector<std::string
}
}
+/*-------------------------------------------------
+ execute_fillmemory - execute the fill command on memory
+-------------------------------------------------*/
+
+bool debugger_commands::execute_fill_try_memory(const std::vector<std::string_view> &params)
+{
+ 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<u8 *>(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 cf38c6d903a..0836790e404 100644
--- a/src/emu/debug/debugcmd.h
+++ b/src/emu/debug/debugcmd.h
@@ -127,18 +127,24 @@ private:
void execute_stateload(const std::vector<std::string_view> &params);
void execute_rewind(const std::vector<std::string_view> &params);
void execute_save(int spacenum, const std::vector<std::string_view> &params);
+ bool execute_save_try_memory(const std::vector<std::string_view> &params);
void execute_saveregion(const std::vector<std::string_view> &params);
void execute_load(int spacenum, const std::vector<std::string_view> &params);
+ bool execute_load_try_memory(const std::vector<std::string_view> &params);
void execute_loadregion(const std::vector<std::string_view> &params);
void execute_dump(int spacenum, const std::vector<std::string_view> &params);
+ bool execute_dump_try_memory(const std::vector<std::string_view> &params);
void execute_strdump(int spacenum, const std::vector<std::string_view> &params);
+ bool execute_strdump_try_memory(const std::vector<std::string_view> &params);
void execute_cheatrange(bool init, const std::vector<std::string_view> &params);
void execute_cheatnext(bool initial, const std::vector<std::string_view> &params);
void execute_cheatlist(const std::vector<std::string_view> &params);
void execute_cheatundo(const std::vector<std::string_view> &params);
void execute_dasm(const std::vector<std::string_view> &params);
void execute_find(int spacenum, const std::vector<std::string_view> &params);
+ bool execute_find_try_memory(const std::vector<std::string_view> &params);
void execute_fill(int spacenum, const std::vector<std::string_view> &params);
+ bool execute_fill_try_memory(const std::vector<std::string_view> &params);
void execute_trace(const std::vector<std::string_view> &params, bool trace_over);
void execute_traceflush(const std::vector<std::string_view> &params);
void execute_history(const std::vector<std::string_view> &params);
diff --git a/src/emu/debug/debugcon.cpp b/src/emu/debug/debugcon.cpp
index ec5bc154751..f9076dda523 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,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 *&region, 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 37b2e235348..b1cef0f7c84 100644
--- a/src/emu/debug/debugcon.h
+++ b/src/emu/debug/debugcon.h
@@ -130,9 +130,15 @@ public:
// 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 *&region, 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 8e5fa1b9c64..e78a31d7568 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 219ed6a89ef..4408d621460 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;
}
@@ -783,6 +788,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;
}
@@ -954,6 +1013,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 33ab9c3b472..f9e3983c053 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 @@ private:
// 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();