-debugger: Finished updating commands and documentation.

* Updated cheat commands to work with arbitrary devices and address
  spaces.  You can still only search RAM areas in a single address space
  at a time, but any address space of any device can be used now.
* Made the cheatinit/cheatrange commands not affect current state if the
  arguments are invalid.  Also fixed some bugs in the cheat commands.
* Updated documentation for cheat commands, and added a simple worked
  example.  Also added single-sentence descriptions of what
  (break|watch|register)points are to the top of the relevant pages.

-frontend improvements:

* Added a bit more info to the about box, moved the VCS revision to the
  heading.
* Don't show "not" codes in prompts - they're not helpful.
This commit is contained in:
Vas Crabb 2021-10-19 05:35:30 +11:00
parent 5bea4a6292
commit 08ee39da70
11 changed files with 555 additions and 450 deletions

View File

@ -14,6 +14,9 @@ Breakpoint Debugger Commands
:ref:`debugger-command-bplist` :ref:`debugger-command-bplist`
lists breakpoints lists breakpoints
Breakpoints halt execution and activate the debugger before a CPU
executes an instruction at a particular address.
.. _debugger-command-bpset: .. _debugger-command-bpset:

View File

@ -3,144 +3,192 @@
Cheat Debugger Commands Cheat Debugger Commands
======================= =======================
:ref:`debugger-command-cheatinit`
initialize the cheat search to the selected memory area
:ref:`debugger-command-cheatrange`
add selected memory area to cheat search
:ref:`debugger-command-cheatnext`
filter cheat candidates by comparing to previous values
:ref:`debugger-command-cheatnextf`
filter cheat candidates by comparing to initial value
:ref:`debugger-command-cheatlist`
show the list of cheat search matches or save them to a file
:ref:`debugger-command-cheatundo`
undo the last cheat search (state only)
You can also type **help <command>** for further details on each command in the MAME Debugger interface. The debugger includes basic cheat search functionality, which works
by saving the contents of memory, and then filtering locations according
to how the values change.
| :ref:`debugger-command-cheatinit` -- initialize the cheat search to the selected memory area Well demonstrate use of the cheat search functionality to make an
| :ref:`debugger-command-cheatrange` -- add to the cheat search the selected memory area infinite lives cheat for Raiden (``raiden``):
| :ref:`debugger-command-cheatnext` -- continue cheat search comparing with the last value
| :ref:`debugger-command-cheatnextf` -- continue cheat search comparing with the first value
| :ref:`debugger-command-cheatlist` -- show the list of cheat search matches or save them to <filename>
| :ref:`debugger-command-cheatundo` -- undo the last cheat search (state only)
.. _debugger-command-cheatinit: * Start the game with the debugger active. Allow the game to run,
insert a coin, and start a game, then break into the debugger.
* Ensure the main CPU is visible, and start a search for 8-bit unsigned
values using the
:ref:`cheatinit command <debugger-command-cheatinit>`::
>cheatinit ub
MAME debugger version 0.236 (mame0236-190-gf7a8ad4fc7d-dirty)
36928 cheat locations initialized for NEC V30 ':maincpu' program space
* Allow the game to run, lose a life and break into the debugger.
* Use the :ref:`cheatnext command <debugger-command-cheatnext>` to
filter locations that have decreased by 1::
>cheatnext -,1
12 cheats found
* Allow the game to run, lose another life, break into the
debugger, and filter locations that have decreased by 1 again::
>cheatnext -,1
Address=0B85 Start=03 Current=01
1 cheat found
* Use the :ref:`cheatlist command <debugger-command-cheatlist>` to save
the cheat candidate to a file::
>cheatlist raiden-p1-lives.xml
* The file now contains an XML fragment with cheat to set the candidate
location to the initial value:
.. code-block:: XML
<cheat desc="Possibility 1: 00B85 (01)">
<script state="run">
<action>:maincpu.ppb@00B85=03</action>
</script>
</cheat>
.. _debugger-command-cheatinit:
cheatinit cheatinit
--------- ---------
| **cheatinit [<sign><width><swap>,[<address>,<length>[,<cpu>]]]** **cheatinit [[<sign>[<width>[<swap>]]],[<address>,<length>[,<space>]]]**
|
| The cheatinit command initializes the cheat search to the selected memory area. Initialize the cheat search to writable RAM areas in the specified
| address space. May be abbreviated to ``ci``.
| If no parameter is specified the cheat search is initialized to all changeable memory of the main CPU.
| The first argument specifies the data format to search for. The
| <sign> can be s(signed) or u(unsigned) **<sign>** may be **u** for unsigned or **s** for signed, the
| <width> can be b(8 bit), w(16 bit), d(32 bit) or q(64 bit) **<width>** may be **b** for 8-bit (byte), **w** for 16-bit (word),
| <swap> append s for swapped search **d** for 32-bit (double word), or **q** for 64-bit (quadruple word);
| **<swap>** may be **s** for reversed byte order. If the first argument
| Examples: is omitted or empty, the data format from the previous cheat search is
| used, or unsigned 8-bit format if this is the first cheat search.
| cheatinit ub,0x1000,0x10
| The **<address>** specifies the address to start searching from, and the
| Initialize the cheat search from 0x1000 to 0x1010 of the first CPU. **<length>** specifies how much memory to search. If specified,
| writable RAM in the range **<address>** through
| cheatinit sw,0x2000,0x1000,1 **<address>+<length>-1**, inclusive, will be searched; otherwise, all
| writable RAM in the address space will be searched.
| Initialize the cheat search with width of 2 byte in signed mode from 0x2000 to 0x3000 of the second CPU.
| See :ref:`debugger-devicespec` for details on specifying address spaces.
| cheatinit uds,0x0000,0x1000 If the address space is not specified, it defaults to the first address
| space exposed by the visible CPU.
| Initialize the cheat search with width of 4 byte swapped from 0x0000 to 0x1000.
| Examples:
| Back to :ref:`debugger-cheats-list`
``cheatinit ub,0x1000,0x10``
Initialize the cheat search for unsigned 8-bit values in addresses
0x1000-0x100f in the program space of the visible CPU.
``cheatinit sw,0x2000,0x1000,1``
Initialize the cheat search for signed 16-bit values in addresses
0x2000-0x2fff in the program space of the second CPU in the system
(zero-based index).
``cheatinit uds,0x0000,0x1000``
Initialize the cheat search for unsigned 64-bit values with reverse
byte order in addresses 0x0000-0x0fff in the program space of the
visible CPU.
Back to :ref:`debugger-cheats-list`
.. _debugger-command-cheatrange: .. _debugger-command-cheatrange:
cheatrange cheatrange
---------- ----------
| **cheatrange <address>,<length>** **cheatrange <address>,<length>**
|
| The cheatrange command adds the selected memory area to the cheat search. Add writable RAM areas to the cheat search. May be abbreviated to
| ``cr``. Before using this command, the
| Before using cheatrange it is necessary to initialize the cheat search with cheatinit. :ref:`cheatinit command <debugger-command-cheatinit>` must be used to
| initialize the cheat search and set the address space and data format.
| Examples:
| The **<address>** specifies the address to start searching from, and the
| cheatrange 0x1000,0x10 **<length>** specifies how much memory to search. Writable RAM in the
| range **<address>** through **<address>+<length>-1**, inclusive, will be
| Add the bytes from 0x1000 to 0x1010 to the cheat search. added to the areas to search.
|
| Back to :ref:`debugger-cheats-list` Examples:
``cheatrange 0x1000,0x10``
Add addresses 0x1000-0x100f to the areas to search for cheats.
Back to :ref:`debugger-cheats-list`
.. _debugger-command-cheatnext: .. _debugger-command-cheatnext:
cheatnext cheatnext
--------- ---------
| **cheatnext <condition>[,<comparisonvalue>]** **cheatnext <condition>[,<comparisonvalue>]**
|
| The cheatnext command will make comparisons with the last search matches. Filter candidates by comparing to the previous search values. If five
| or fewer candidates remain, they will be shown in the debugger console.
| Possible <condition>: May be abbreviated to ``cn``.
|
| **all** Possible **<condition>** arguments:
|
| No <comparisonvalue> needed. ``all``
| Use to update the last value without changing the current matches
| Use to update the last value without changing the current matches. (the **<comparisonvalue>** is not used).
| ``equal`` (``eq``)
| **equal [eq]** Without **<comparisonvalue>**, search for values that are equal to
| the previous search; with **<comparisonvalue>**, search for values
| Without <comparisonvalue> search for all bytes that are equal to the last search. that are equal to the **<comparisonvalue>**.
| With <comparisonvalue> search for all bytes that are equal to the <comparisonvalue>. ``notequal`` (``ne``)
| Without **<comparisonvalue>**, search for values that are not equal
| **notequal [ne]** to the previous search; with **<comparisonvalue>**, search for
| values that are not equal to the **<comparisonvalue>**.
| Without <comparisonvalue> search for all bytes that are not equal to the last search. ``decrease`` (``de``, ``-``)
| With <comparisonvalue> search for all bytes that are not equal to the <comparisonvalue>. Without **<comparisonvalue>**, search for values that have decreased
| since the previous search; with **<comparisonvalue>**, search for
| **decrease [de, +]** values that have decreased by the **<comparisonvalue>** since the
| previous search.
| Without <comparisonvalue> search for all bytes that have decreased since the last search. ``increase`` (``in``, ``+``)
| With <comparisonvalue> search for all bytes that have decreased by the <comparisonvalue> since the last search. Without **<comparisonvalue>**, search for values that have increased
| since the previous search; with **<comparisonvalue>**, search for
| **increase [in, -]** values that have increased by the **<comparisonvalue>** since the
| previous search.
| Without <comparisonvalue> search for all bytes that have increased since the last search. ``decreaseorequal`` (``deeq``)
| With <comparisonvalue> search for all bytes that have increased by the <comparisonvalue> since the last search. Search for values that have decreased or are unchanged since the
| previous search (the **<comparisonvalue>** is not used).
| **decreaseorequal [deeq]** ``increaseorequal`` (``ineq``)
| Search for values that have increased or are unchanged since the
| No <comparisonvalue> needed. previous search (the **<comparisonvalue>** is not used).
| ``smallerof`` (``lt``, ``<``)
| Search for all bytes that have decreased or have same value since the last search. Search for values that are less than the **<comparisonvalue>** (the
| **<comparisonvalue>** is required).
| **increaseorequal [ineq]** ``greaterof`` (``gt``, ``>``)
| Search for values that are greater than the **<comparisonvalue>**
| No <comparisonvalue> needed. (the **<comparisonvalue>** is required).
| ``changedby`` (``ch``, ``~``)
| Search for all bytes that have decreased or have same value since the last search. Search for values that have changed by the **<comparisonvalue>**
| since the previous search (the **<comparisonvalue>** is required).
| **smallerof [lt]**
| Examples:
| Without <comparisonvalue> this condition is invalid
| With <comparisonvalue> search for all bytes that are smaller than the <comparisonvalue>. ``cheatnext increase``
| Search for all values that have increased since the previous search.
| **greaterof [gt]** ``cheatnext decrease,1``
| Search for all values that have decreased by 1 since the previous
| Without <comparisonvalue> this condition is invalid search.
| With <comparisonvalue> search for all bytes that are larger than the <comparisonvalue>.
| Back to :ref:`debugger-cheats-list`
| **changedby [ch, ~]**
|
| Without <comparisonvalue> this condition is invalid
| With <comparisonvalue> search for all bytes that have changed by the <comparisonvalue> since the last search.
|
|
| Examples:
|
| cheatnext increase
|
| Search for all bytes that have increased since the last search.
|
| cheatnext decrease, 1
|
| Search for all bytes that have decreased by 1 since the last search.
|
| Back to :ref:`debugger-cheats-list`
.. _debugger-command-cheatnextf: .. _debugger-command-cheatnextf:
@ -148,120 +196,100 @@ cheatnext
cheatnextf cheatnextf
---------- ----------
| **cheatnextf <condition>[,<comparisonvalue>]** **cheatnextf <condition>[,<comparisonvalue>]**
|
| The cheatnextf command will make comparisons with the initial search. Filter candidates by comparing to the initial search values. If five or
| fewer candidates remain, they will be shown in the debugger console.
| Possible <condition>: May be abbreviated to ``cn``.
|
| **all** Possible **<condition>** arguments:
|
| No <comparisonvalue> needed. ``all``
| Use to update the last value without changing the current matches
| Use to update the last value without changing the current matches. (the **<comparisonvalue>** is not used).
| ``equal`` (``eq``)
| **equal [eq]** Without **<comparisonvalue>**, search for values that are equal to
| the initial search; with **<comparisonvalue>**, search for values
| Without <comparisonvalue> search for all bytes that are equal to the initial search. that are equal to the **<comparisonvalue>**.
| With <comparisonvalue> search for all bytes that are equal to the <comparisonvalue>. ``notequal`` (``ne``)
| Without **<comparisonvalue>**, search for values that are not equal
| **notequal [ne]** to the initial search; with **<comparisonvalue>**, search for values
| that are not equal to the **<comparisonvalue>**.
| Without <comparisonvalue> search for all bytes that are not equal to the initial search. ``decrease`` (``de``, ``-``)
| With <comparisonvalue> search for all bytes that are not equal to the <comparisonvalue>. Without **<comparisonvalue>**, search for values that have decreased
| since the initial search; with **<comparisonvalue>**, search for
| **decrease [de, +]** values that have decreased by the **<comparisonvalue>** since the
| initial search.
| Without <comparisonvalue> search for all bytes that have decreased since the initial search. ``increase`` (``in``, ``+``)
| With <comparisonvalue> search for all bytes that have decreased by the <comparisonvalue> since the initial search. Without **<comparisonvalue>**, search for values that have increased
| since the initial search; with **<comparisonvalue>**, search for
| **increase [in, -]** values that have increased by the **<comparisonvalue>** since the
| initial search.
| Without <comparisonvalue> search for all bytes that have increased since the initial search. ``decreaseorequal`` (``deeq``)
| Search for values that have decreased or are unchanged since the
| With <comparisonvalue> search for all bytes that have increased by the <comparisonvalue> since the initial search. initial search (the **<comparisonvalue>** is not used).
| ``increaseorequal`` (``ineq``)
| **decreaseorequal [deeq]** Search for values that have increased or are unchanged since the
| initial search (the **<comparisonvalue>** is not used).
| No <comparisonvalue> needed. ``smallerof`` (``lt``, ``<``)
| Search for values that are less than the **<comparisonvalue>** (the
| Search for all bytes that have decreased or have same value since the initial search. **<comparisonvalue>** is required).
| ``greaterof`` (``gt``, ``>``)
| **increaseorequal [ineq]** Search for values that are greater than the **<comparisonvalue>**
| (the **<comparisonvalue>** is required).
| No <comparisonvalue> needed. ``changedby`` (``ch``, ``~``)
| Search for values that have changed by the **<comparisonvalue>**
| Search for all bytes that have decreased or have same value since the initial search. since the initial search (the **<comparisonvalue>** is required).
|
| **smallerof [lt]** Examples:
|
| Without <comparisonvalue> this condition is invalid. ``cheatnextf increase``
| With <comparisonvalue> search for all bytes that are smaller than the <comparisonvalue>. Search for all values that have increased since the initial search.
| ``cheatnextf decrease,1``
| **greaterof [gt]** Search for all values that have decreased by 1 since the initial
| search.
| Without <comparisonvalue> this condition is invalid.
| With <comparisonvalue> search for all bytes that are larger than the <comparisonvalue>. Back to :ref:`debugger-cheats-list`
|
| **changedby [ch, ~]**
|
| Without <comparisonvalue> this condition is invalid
| With <comparisonvalue> search for all bytes that have changed by the <comparisonvalue> since the initial search.
|
|
| Examples:
|
| cheatnextf increase
|
| Search for all bytes that have increased since the initial search.
|
| cheatnextf decrease, 1
|
| Search for all bytes that have decreased by 1 since the initial search.
|
| Back to :ref:`debugger-cheats-list`
.. _debugger-command-cheatlist: .. _debugger-command-cheatlist:
cheatlist cheatlist
--------- ---------
| **cheatlist [<filename>]** **cheatlist [<filename>]**
|
| Without <filename> show the list of matches in the debug console. Without **<filename>**, show the current cheat matches in the debugger
| With <filename> save the list of matches in basic XML format to <filename>. console; with **<filename>**, save the current cheat matches in basic
| XML format to the specified file. May be abbreviated to ``cl``.
| Examples:
| Examples:
| cheatlist
| ``cheatlist``
| Show the current matches in the debug console. Show the current matches in the console.
| ``cheatlist cheat.xml``
| cheatlist cheat.txt Save the current matches to the file **cheat.xml** in XML format.
|
| Save the current matches in XML format to cheat.txt. Back to :ref:`debugger-cheats-list`
|
| Back to :ref:`debugger-cheats-list`
.. _debugger-command-cheatundo: .. _debugger-command-cheatundo:
cheatundo cheatundo
--------- ---------
| **cheatundo** **cheatundo**
|
| Undo the results of the last search.
|
| The undo command has no effect on the last value.
|
|
| Examples:
|
| cheatundo
|
| Undo the last search (state only).
|
| Back to :ref:`debugger-cheats-list`
Undo filtering of cheat candidates by the most recent
:ref:`cheatnext <debugger-command-cheatnext>` or
:ref:`cheatnextf <debugger-command-cheatnextf>` command. Note that the
previous values *are not* rolled back. May be abbreviated to ``cu``.
Examples:
``cheatundo``
Restore cheat candidates filtered out by the most recent
:ref:`cheatnext <debugger-command-cheatnext>` or
:ref:`cheatnextf <debugger-command-cheatnextf>` command.
Back to :ref:`debugger-cheats-list`

View File

@ -415,6 +415,8 @@ Loads the most recent RAM-based saved state. When enabled, rewind
states are saved when :ref:`debugger-command-step`, states are saved when :ref:`debugger-command-step`,
:ref:`debugger-command-over` and :ref:`debugger-command-out` commands :ref:`debugger-command-over` and :ref:`debugger-command-out` commands
are used, storing the machine state as of the moment before stepping. are used, storing the machine state as of the moment before stepping.
May be abbreviated to ``rw``.
Consecutively loading rewind states can work like reverse execution. Consecutively loading rewind states can work like reverse execution.
Depending on which steps forward were taken previously, the behavior can Depending on which steps forward were taken previously, the behavior can
be similar to GDB's **reverse-stepi** and **reverse-next** commands. be similar to GDB's **reverse-stepi** and **reverse-next** commands.
@ -445,7 +447,7 @@ Creates a save state at the current moment in emulated time. The state
file is written to the configured save state directory (see the file is written to the configured save state directory (see the
:ref:`state_directory <mame-commandline-statedirectory>` option), and :ref:`state_directory <mame-commandline-statedirectory>` option), and
the **.sta** extension is automatically appended to the specified file the **.sta** extension is automatically appended to the specified file
name. name. May be abbreviates to ``ss``.
All output from this command is currently echoed into the running machine All output from this command is currently echoed into the running machine
window. window.
@ -473,6 +475,7 @@ Restores a saved state file from disk. The specified state file is read
from the configured save state directory (see the from the configured save state directory (see the
:ref:`state_directory <mame-commandline-statedirectory>` option), and the :ref:`state_directory <mame-commandline-statedirectory>` option), and the
**.sta** extension is automatically appended to the specified file name. **.sta** extension is automatically appended to the specified file name.
May be abbreviated to ``sl``.
All output for this command is currently echoed into the running machine All output for this command is currently echoed into the running machine
window. Previous memory and PC tracking statistics are cleared. window. Previous memory and PC tracking statistics are cleared.

View File

@ -14,6 +14,10 @@ Registerpoint Debugger Commands
:ref:`debugger-command-rplist` :ref:`debugger-command-rplist`
lists registerpoints lists registerpoints
Registerpoints evaluate an expression each time a CPU executes an
instruction and halt execution and activate the debugger if the result
is true (non-zero).
.. _debugger-command-rpset: .. _debugger-command-rpset:

View File

@ -14,6 +14,10 @@ Watchpoint Debugger Commands
:ref:`debugger-command-wplist` :ref:`debugger-command-wplist`
lists watchpoints lists watchpoints
Watchpoints halt execution and activate the debugger when a CPU accesses
a location in a particular memory range.
.. _debugger-command-wpset: .. _debugger-command-wpset:
wpset wpset

View File

@ -378,7 +378,7 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu
if (name[0] != 0) if (name[0] != 0)
m_console.source_script(name); m_console.source_script(name);
m_cheat.cpu[0] = m_cheat.cpu[1] = 0; m_cheat.space = nullptr;
} }
@ -2859,82 +2859,84 @@ void debugger_commands::execute_strdump(int spacenum, const std::vector<std::str
void debugger_commands::execute_cheatrange(bool init, const std::vector<std::string> &params) void debugger_commands::execute_cheatrange(bool init, const std::vector<std::string> &params)
{ {
cheat_region_map cheat_region[100]; address_space *space = m_cheat.space;
memset(cheat_region, 0, sizeof(cheat_region)); if (!space && !init)
{
// validate parameters m_console.printf("Use cheatinit before cheatrange\n");
address_space *space;
if (!validate_device_space_parameter((params.size() > 3) ? params[3] : std::string_view(), -1, space))
return; return;
}
u8 width = (space || !init) ? m_cheat.width : 1;
bool signed_cheat = (space || !init) ? m_cheat.signed_cheat : false;
bool swapped_cheat = (space || !init) ? m_cheat.swapped_cheat : false;
if (init) if (init)
{ {
m_cheat.width = 1; // first argument is sign/size/swap flags
m_cheat.signed_cheat = false;
m_cheat.swapped_cheat = false;
if (!params.empty()) if (!params.empty())
{ {
char const *srtpnt = params[0].c_str(); std::string const &srtpnt = params[0];
if (!srtpnt.empty())
char sspec = std::tolower((unsigned char)*srtpnt);
if (sspec == 's')
m_cheat.signed_cheat = true;
else if (sspec == 'u')
m_cheat.signed_cheat = false;
else
{ {
m_console.printf("Invalid sign: expected s or u\n"); width = 1;
return; signed_cheat = false;
swapped_cheat = false;
} }
char wspec = std::tolower((unsigned char)*(++srtpnt)); if (srtpnt.length() >= 1)
if (wspec == 'b')
m_cheat.width = 1;
else if (wspec == 'w')
m_cheat.width = 2;
else if (wspec == 'd')
m_cheat.width = 4;
else if (wspec == 'q')
m_cheat.width = 8;
else
{ {
m_console.printf("Invalid width: expected b, w, d or q\n"); char const sspec = std::tolower((unsigned char)srtpnt[0]);
return; if (sspec == 's')
signed_cheat = true;
else if (sspec == 'u')
signed_cheat = false;
else
{
m_console.printf("Invalid sign: expected s or u\n");
return;
}
} }
if (std::tolower((unsigned char)*(++srtpnt)) == 's') if (srtpnt.length() >= 2)
m_cheat.swapped_cheat = true; {
else char const wspec = std::tolower((unsigned char)srtpnt[1]);
m_cheat.swapped_cheat = false; if (wspec == 'b')
width = 1;
else if (wspec == 'w')
width = 2;
else if (wspec == 'd')
width = 4;
else if (wspec == 'q')
width = 8;
else
{
m_console.printf("Invalid width: expected b, w, d or q\n");
return;
}
}
if (srtpnt.length() >= 3)
{
if (std::tolower((unsigned char)srtpnt[2]) == 's')
swapped_cheat = true;
else
{
m_console.printf("Invalid swap: expected s\n");
return;
}
}
} }
// fourth argument is device/space
if (!validate_device_space_parameter((params.size() > 3) ? params[3] : std::string_view(), -1, space))
return;
} }
// initialize entire memory by default cheat_region_map cheat_region[100]; // FIXME: magic number
u64 length = 0; unsigned region_count = 0;
u8 region_count = 0; if (params.size() >= (init ? 3 : 2))
if (params.size() <= 1)
{
for (address_map_entry &entry : space->map()->m_entrylist)
{
cheat_region[region_count].offset = entry.m_addrstart & space->addrmask();
cheat_region[region_count].endoffset = entry.m_addrend & space->addrmask();
cheat_region[region_count].share = entry.m_share;
cheat_region[region_count].disabled = (entry.m_write.m_type == AMH_RAM) ? false : true;
// disable double share regions
if (entry.m_share != nullptr)
for (u8 i = 0; i < region_count; i++)
if (cheat_region[i].share != nullptr)
if (strcmp(cheat_region[i].share, entry.m_share) == 0)
cheat_region[region_count].disabled = true;
region_count++;
}
}
else
{ {
// validate parameters // validate parameters
u64 offset; u64 offset, length;
if (!validate_number_parameter(params[init ? 1 : 0], offset)) if (!validate_number_parameter(params[init ? 1 : 0], offset))
return; return;
if (!validate_number_parameter(params[init ? 2 : 1], length)) if (!validate_number_parameter(params[init ? 2 : 1], length))
@ -2947,61 +2949,76 @@ void debugger_commands::execute_cheatrange(bool init, const std::vector<std::str
cheat_region[region_count].disabled = false; cheat_region[region_count].disabled = false;
region_count++; region_count++;
} }
else
{
// initialize to entire memory by default
for (address_map_entry &entry : space->map()->m_entrylist)
{
cheat_region[region_count].offset = entry.m_addrstart & space->addrmask();
cheat_region[region_count].endoffset = entry.m_addrend & space->addrmask();
cheat_region[region_count].share = entry.m_share;
cheat_region[region_count].disabled = entry.m_write.m_type != AMH_RAM;
// disable duplicate share regions
if (entry.m_share)
for (unsigned i = 0; i < region_count; i++)
if (cheat_region[i].share && !strcmp(cheat_region[i].share, entry.m_share))
cheat_region[region_count].disabled = true;
if (!cheat_region[region_count].disabled)
region_count++;
}
}
// determine the writable extent of each region in total // determine the writable extent of each region in total
u64 real_length = 0; u64 real_length = 0;
for (u8 i = 0; i < region_count; i++) for (unsigned i = 0; i < region_count; i++)
if (!cheat_region[i].disabled) for (u64 curaddr = cheat_region[i].offset; curaddr <= cheat_region[i].endoffset; curaddr += width)
for (u64 curaddr = cheat_region[i].offset; curaddr <= cheat_region[i].endoffset; curaddr += m_cheat.width) if (cheat_address_is_valid(*space, curaddr))
if (cheat_address_is_valid(*space, curaddr)) real_length++;
real_length++;
if (real_length == 0) if (!real_length)
{ {
m_console.printf("No writable bytes found in this area\n"); m_console.printf("No writable bytes found in this area\n");
return; return;
} }
u32 active_cheat = 0; size_t active_cheat = 0;
if (init) if (init)
{ {
// initialize new cheat system // initialize new cheat system
m_cheat.cheatmap.resize(real_length); m_cheat.space = space;
m_cheat.width = width;
m_cheat.undo = 0; m_cheat.undo = 0;
m_cheat.cpu[0] = params.size() > 3 ? params[3][0] : '0'; m_cheat.signed_cheat = signed_cheat;
m_cheat.swapped_cheat = swapped_cheat;
} }
else else
{ {
// add range to cheat system
if (m_cheat.cpu[0] == 0)
{
m_console.printf("Use cheatinit before cheatrange\n");
return;
}
if (!validate_device_space_parameter(m_cheat.cpu, -1, space))
return;
active_cheat = m_cheat.cheatmap.size(); active_cheat = m_cheat.cheatmap.size();
m_cheat.cheatmap.resize(m_cheat.cheatmap.size() + real_length);
} }
m_cheat.cheatmap.resize(active_cheat + real_length);
// initialize cheatmap in the selected space // initialize cheatmap in the selected space
for (u8 i = 0; i < region_count; i++) for (unsigned i = 0; i < region_count; i++)
if (!cheat_region[i].disabled) for (u64 curaddr = cheat_region[i].offset; curaddr <= cheat_region[i].endoffset; curaddr += width)
for (u64 curaddr = cheat_region[i].offset; curaddr <= cheat_region[i].endoffset; curaddr += m_cheat.width) if (cheat_address_is_valid(*space, curaddr))
if (cheat_address_is_valid(*space, curaddr)) {
{ m_cheat.cheatmap[active_cheat].previous_value = cheat_read_extended(&m_cheat, *space, curaddr);
m_cheat.cheatmap[active_cheat].previous_value = cheat_read_extended(&m_cheat, *space, curaddr); m_cheat.cheatmap[active_cheat].first_value = m_cheat.cheatmap[active_cheat].previous_value;
m_cheat.cheatmap[active_cheat].first_value = m_cheat.cheatmap[active_cheat].previous_value; m_cheat.cheatmap[active_cheat].offset = curaddr;
m_cheat.cheatmap[active_cheat].offset = curaddr; m_cheat.cheatmap[active_cheat].state = 1;
m_cheat.cheatmap[active_cheat].state = 1; m_cheat.cheatmap[active_cheat].undo = 0;
m_cheat.cheatmap[active_cheat].undo = 0; active_cheat++;
active_cheat++; }
}
// give a detailed init message to avoid searches being mistakingly carried out on the wrong CPU // give a detailed init message to avoid searches being mistakenly carried out on the wrong CPU
m_console.printf("%u cheat initialized for CPU index %s ( aka %s )\n", active_cheat, m_cheat.cpu, space->device().tag()); m_console.printf(
"%u cheat locations initialized for %s '%s' %s space\n",
active_cheat,
space->device().type().fullname(),
space->device().tag(),
space->name());
} }
@ -3029,16 +3046,13 @@ void debugger_commands::execute_cheatnext(bool initial, const std::vector<std::s
CHEAT_CHANGEDBY CHEAT_CHANGEDBY
}; };
if (m_cheat.cpu[0] == 0) address_space *const space = m_cheat.space;
if (!space)
{ {
m_console.printf("Use cheatinit before cheatnext\n"); m_console.printf("Use cheatinit before cheatnext\n");
return; return;
} }
address_space *space;
if (!validate_device_space_parameter(m_cheat.cpu, AS_PROGRAM, space))
return;
u64 comp_value = 0; u64 comp_value = 0;
if (params.size() > 1 && !validate_number_parameter(params[1], comp_value)) if (params.size() > 1 && !validate_number_parameter(params[1], comp_value))
return; return;
@ -3186,30 +3200,36 @@ void debugger_commands::execute_cheatnext(bool initial, const std::vector<std::s
void debugger_commands::execute_cheatlist(const std::vector<std::string> &params) void debugger_commands::execute_cheatlist(const std::vector<std::string> &params)
{ {
if (m_cheat.cpu[0] == 0) address_space *const space = m_cheat.space;
if (!space)
{ {
m_console.printf("Use cheatinit before cheatlist\n"); m_console.printf("Use cheatinit before cheatlist\n");
return; return;
} }
address_space *space;
if (!validate_device_space_parameter(m_cheat.cpu, -1, space))
return;
device_t &cpu = space->device();
FILE *f = nullptr; FILE *f = nullptr;
if (params.size() > 0) if (params.size() > 0)
{
f = fopen(params[0].c_str(), "w"); f = fopen(params[0].c_str(), "w");
if (!f)
{
m_console.printf("Error opening file '%s'\n", params[0]);
return;
}
}
std::string tag(space->device().tag());
char spaceletter; char spaceletter;
switch (space->spacenum()) switch (space->spacenum())
{ {
default:
case AS_PROGRAM: spaceletter = 'p'; break; case AS_PROGRAM: spaceletter = 'p'; break;
case AS_DATA: spaceletter = 'd'; break; case AS_DATA: spaceletter = 'd'; break;
case AS_IO: spaceletter = 'i'; break; case AS_IO: spaceletter = 'i'; break;
case AS_OPCODES: spaceletter = 'o'; break; case AS_OPCODES: spaceletter = '3'; break;
default:
tag.append(1, ':');
tag.append(space->name());
spaceletter = 'p';
} }
char sizeletter; char sizeletter;
@ -3240,13 +3260,13 @@ void debugger_commands::execute_cheatlist(const std::vector<std::string> &params
output.rdbuf()->clear(); output.rdbuf()->clear();
stream_format( stream_format(
output, output,
" <cheat desc=\"Possibility %d : %0*X (%0*X)\">\n" " <cheat desc=\"Possibility %d: %0*X (%0*X)\">\n"
" <script state=\"run\">\n" " <script state=\"run\">\n"
" <action>%s.p%c%c@%0*X=%0*X</action>\n" " <action>%s.p%c%c@%0*X=%0*X</action>\n"
" </script>\n" " </script>\n"
" </cheat>\n\n", " </cheat>\n\n",
active_cheat, space->logaddrchars(), address, m_cheat.width * 2, value, active_cheat, space->logaddrchars(), address, m_cheat.width * 2, value,
cpu.tag(), spaceletter, sizeletter, space->logaddrchars(), address, m_cheat.width * 2, cheat_byte_swap(&m_cheat, m_cheat.cheatmap[cheatindex].first_value) & sizemask); tag, spaceletter, sizeletter, space->logaddrchars(), address, m_cheat.width * 2, cheat_byte_swap(&m_cheat, m_cheat.cheatmap[cheatindex].first_value) & sizemask);
auto const &text(output.vec()); auto const &text(output.vec());
fprintf(f, "%.*s", int(unsigned(text.size())), &text[0]); fprintf(f, "%.*s", int(unsigned(text.size())), &text[0]);
} }
@ -3273,7 +3293,7 @@ void debugger_commands::execute_cheatundo(const std::vector<std::string> &params
{ {
if (m_cheat.undo > 0) if (m_cheat.undo > 0)
{ {
u32 undo_count = 0; u64 undo_count = 0;
for (u64 cheatindex = 0; cheatindex < m_cheat.cheatmap.size(); cheatindex += 1) for (u64 cheatindex = 0; cheatindex < m_cheat.cheatmap.size(); cheatindex += 1)
{ {
if (m_cheat.cheatmap[cheatindex].undo == m_cheat.undo) if (m_cheat.cheatmap[cheatindex].undo == m_cheat.undo)
@ -3288,7 +3308,9 @@ void debugger_commands::execute_cheatundo(const std::vector<std::string> &params
m_console.printf("%u cheat reactivated\n", undo_count); m_console.printf("%u cheat reactivated\n", undo_count);
} }
else else
{
m_console.printf("Maximum undo reached\n"); m_console.printf("Maximum undo reached\n");
}
} }
@ -4013,7 +4035,7 @@ void debugger_commands::execute_memdump(const std::vector<std::string> &params)
sp.dump_maps(entries[0], entries[1]); sp.dump_maps(entries[0], entries[1]);
for (int mode = 0; mode < 2; mode ++) for (int mode = 0; mode < 2; mode ++)
{ {
fprintf(file, " device %s space %s %s:\n", memory.device().tag(), sp.name(), mode ? "write" : "read"); fprintf(file, " %s '%s' space %s %s:\n", memory.device().type().fullname(), memory.device().tag(), sp.name(), mode ? "write" : "read");
for (memory_entry &entry : entries[mode]) for (memory_entry &entry : entries[mode])
{ {
if (octal) if (octal)

View File

@ -67,20 +67,20 @@ private:
// TODO [RH 31 May 2016]: Move this cheat stuff into its own class // TODO [RH 31 May 2016]: Move this cheat stuff into its own class
struct cheat_system struct cheat_system
{ {
char cpu[2]; address_space *space;
u8 width; u8 width;
std::vector<cheat_map> cheatmap;
u8 undo;
u8 signed_cheat; u8 signed_cheat;
u8 swapped_cheat; u8 swapped_cheat;
std::vector<cheat_map> cheatmap;
u8 undo;
}; };
struct cheat_region_map struct cheat_region_map
{ {
u64 offset; u64 offset = 0U;
u64 endoffset; u64 endoffset = 0U;
const char *share; const char *share = nullptr;
u8 disabled; u8 disabled = 0U;
}; };
device_t &get_device_search_base(std::string_view &param); device_t &get_device_search_base(std::string_view &param);

View File

@ -246,8 +246,8 @@ const help_item f_static_help_list[] =
"Cheat Commands\n" "Cheat Commands\n"
"Type help <command> for further details on each command\n" "Type help <command> for further details on each command\n"
"\n" "\n"
" cheatinit [<sign><width>[<swap>],[<address>,<length>[,<CPU>]]] -- initialize the cheat search to the selected memory area\n" " cheatinit [[<sign>[<width>[<swap>]]],[<address>,<length>[,<space>]]] -- initialize the cheat search to the selected memory area\n"
" cheatrange <address>,<length> -- add to the cheat search the selected memory area\n" " cheatrange <address>,<length> -- add selected memory area to the cheat search\n"
" cheatnext <condition>[,<comparisonvalue>] -- continue cheat search comparing with the previous value\n" " cheatnext <condition>[,<comparisonvalue>] -- continue cheat search comparing with the previous value\n"
" cheatnextf <condition>[,<comparisonvalue>] -- continue cheat search comparing with the first value\n" " cheatnextf <condition>[,<comparisonvalue>] -- continue cheat search comparing with the first value\n"
" cheatlist [<filename>] -- show the list of cheat search matches or save them to <filename>\n" " cheatlist [<filename>] -- show the list of cheat search matches or save them to <filename>\n"
@ -1611,157 +1611,184 @@ const help_item f_static_help_list[] =
{ {
"cheatinit", "cheatinit",
"\n" "\n"
" cheatinit [<sign><width>[<swap>],[<address>,<length>[,<CPU>]]]\n" " cheatinit [[<sign>[<width>[<swap>]]],[<address>,<length>[,<space>]]]\n"
"\n" "\n"
"The cheatinit command initializes the cheat search to the selected memory area.\n" "The cheatinit command initializes the cheat search to writable RAM areas in the specified "
"If no parameter is specified the cheat search is initialized to all changeable memory of the main CPU.\n" "address space. The device may be specified as a tag or a debugger CPU number; if no "
"<sign> can be s(signed) or u(unsigned)\n" "device is specified, the CPU currently visible in the debugger is assumed. If an address "
"<width> can be b(8 bit), w(16 bit), d(32 bit) or q(64 bit)\n" "space is not specified, the first address space exposed by the device is used.\n"
"<swap> append s for swapped search\n" "\n"
"The first argument specifies the data format to search for:\n"
" <sign>: 's' (signed), 'u' (unsigned)\n"
" <width>: 'b' (8-bit), 'w' (16-bit), 'd' (32-bit), 'q' (64-bit)\n"
" <swap>: 's' (reverse byte order)\n"
"If the first argument is omitted or empty, the format from the previous cheat search is "
"used, or unsigned 8-bit for the first cheat search.\n"
"\n"
"The <address> specifies the address to start searching from, and the <length> specifies "
"how much memory to search. If specified, writable RAM in the range <address> through "
"<address>+<length>-1, inclusive, will be searched; otherwise, all writable RAM in the "
"address space will be searched.\n"
"\n" "\n"
"Examples:\n" "Examples:\n"
"\n" "\n"
"cheatinit ub,0x1000,0x10\n" "cheatinit ub,0x1000,0x10\n"
" Initialize the cheat search from 0x1000 to 0x1010 of the first CPU.\n" " Initialize the cheat search for unsigned 8-bit values in addresses 0x1000-0x100f in the "
"program space of the visible CPU.\n"
"\n" "\n"
"cheatinit sw,0x2000,0x1000,1\n" "cheatinit sw,0x2000,0x1000,1\n"
" Initialize the cheat search with width of 2 byte in signed mode from 0x2000 to 0x3000 of the second CPU.\n" " Initialize the cheat search for signed 16-bit values in addresses 0x2000-0x3000 in the "
"program space of CPU #1.\n"
"\n" "\n"
"cheatinit uds,0x0000,0x1000\n" "cheatinit uds,0x0000,0x1000\n"
" Initialize the cheat search with width of 4 byte swapped from 0x0000 to 0x1000.\n" " Initialize the cheat search for unsigned 32-bit values with reverse byte order in "
"addresses 0x0000-0x0fff of the program space of the visible CPU.\n"
}, },
{ {
"cheatrange", "cheatrange",
"\n" "\n"
" cheatrange <address>,<length>\n" " cheatrange <address>,<length>\n"
"\n" "\n"
"The cheatrange command adds the selected memory area to the cheat search.\n" "The cheatrange command adds writable RAM areas in the range <address> through "
"Before using cheatrange it is necessary to initialize the cheat search with cheatinit.\n" "through <address>+<length>-1, inclusive, to the cheat search. Before using cheatrange, "
"the cheatinit command must be used to initialize the cheat search.\n"
"\n" "\n"
"Examples:\n" "Examples:\n"
"\n" "\n"
"cheatrange 0x1000,0x10\n" "cheatrange 0x1000,0x10\n"
" Add the bytes from 0x1000 to 0x1010 to the cheat search.\n" " Add addresses 0x1000-0x100f to the cheat search.\n"
}, },
{ {
"cheatnext", "cheatnext",
"\n" "\n"
" cheatnext <condition>[,<comparisonvalue>]\n" " cheatnext <condition>[,<comparisonvalue>]\n"
"\n" "\n"
"The cheatnext command will make comparisons with the previous search matches.\n" "The cheatnext command makes comparisons with the previous search matches.\n"
"Possible <condition>:\n" "Possible <condition>:\n"
" all\n" " all\n"
" no <comparisonvalue> needed.\n" " Use to update the last value without changing the current matches.\n"
" use to update the previous value without changing the current matches.\n" " The <comparisonvalue> is not used.\n"
" equal [eq]\n" " equal (eq)\n"
" without <comparisonvalue> search for all bytes that are equal to the previous search.\n" " Without <comparisonvalue>**, search for values that are equal to the previous "
" with <comparisonvalue> search for all bytes that are equal to the <comparisonvalue>.\n" "search.\n"
" notequal [ne]\n" " With <comparisonvalue>, search for values that are equal to the <comparisonvalue>.\n"
" without <comparisonvalue> search for all bytes that are not equal to the previous search.\n" " notequal (ne)\n"
" with <comparisonvalue> search for all bytes that are not equal to the <comparisonvalue>.\n" " Without <comparisonvalue>, search for values that are not equal to the previous "
" decrease [de, +]\n" "search.\n"
" without <comparisonvalue> search for all bytes that have decreased since the previous search.\n" " With <comparisonvalue>, search for values that are not equal to the <comparisonvalue>.\n"
" with <comparisonvalue> search for all bytes that have decreased by the <comparisonvalue> since the previous search.\n" " decrease (de, -)\n"
" increase [in, -]\n" " Without <comparisonvalue>, search for values that have decreased since the previous "
" without <comparisonvalue> search for all bytes that have increased since the previous search.\n" "search.\n"
" with <comparisonvalue> search for all bytes that have increased by the <comparisonvalue> since the previous search.\n" " With <comparisonvalue>, search for values that have decreased by the <comparisonvalue> "
" decreaseorequal [deeq]\n" "since the previous search.\n"
" no <comparisonvalue> needed.\n" " increase (in, +)\n"
" search for all bytes that have decreased or have same value since the previous search.\n" " Without <comparisonvalue>, search for values that have increased since the previous "
" increaseorequal [ineq]\n" "search.\n"
" no <comparisonvalue> needed.\n" " With <comparisonvalue>, search for values that have increased by the <comparisonvalue> "
" search for all bytes that have decreased or have same value since the previous search.\n" "since the previous search.\n"
" smallerof [lt]\n" " decreaseorequal (deeq)\n"
" without <comparisonvalue> this condition is invalid\n" " Search for values that have decreased or are unchanged since the previous search.\n"
" with <comparisonvalue> search for all bytes that are smaller than the <comparisonvalue>.\n" " The <comparisonvalue> is not used.\n"
" greaterof [gt]\n" " increaseorequal (ineq)\n"
" without <comparisonvalue> this condition is invalid\n" " Search for values that have increased or are unchanged since the previous search.\n"
" with <comparisonvalue> search for all bytes that are larger than the <comparisonvalue>.\n" " The <comparisonvalue> is not used.\n"
" changedby [ch, ~]\n" " smallerof (lt, <)\n"
" without <comparisonvalue> this condition is invalid\n" " Search for values that are less than the <comparisonvalue>.\n"
" with <comparisonvalue> search for all bytes that have changed by the <comparisonvalue> since the previous search.\n" " The <comparisonvalue> is required.\n"
" greaterof (gt, >)\n"
" Search for values that are greater than the <comparisonvalue>.\n"
" The <comparisonvalue> is required.\n"
" changedby (ch, ~)\n"
" Search for values that have changed by the <comparisonvalue> since the previous "
"search.\n"
" The <comparisonvalue> is required.\n"
"\n" "\n"
"Examples:\n" "Examples:\n"
"\n" "\n"
"cheatnext increase\n" "cheatnext increase\n"
" search for all bytes that have increased since the previous search.\n" " Search for all values that have increased since the previous search.\n"
"\n" "\n"
"cheatnext decrease, 1\n" "cheatnext decrease,1\n"
" search for all bytes that have decreased by 1 since the previous search.\n" " Search for all values that have decreased by 1 since the previous search.\n"
}, },
{ {
"cheatnextf", "cheatnextf",
"\n" "\n"
" cheatnextf <condition>[,<comparisonvalue>]\n" " cheatnextf <condition>[,<comparisonvalue>]\n"
"\n" "\n"
"The cheatnextf command will make comparisons with the initial search.\n" "The cheatnextf command makes comparisons with the initial search matches.\n"
"Possible <condition>:\n" "Possible <condition>:\n"
" all\n" " all\n"
" no <comparisonvalue> needed.\n" " Use to update the last value without changing the current matches.\n"
" use to update the previous value without changing the current matches.\n" " The <comparisonvalue> is not used.\n"
" equal [eq]\n" " equal (eq)\n"
" without <comparisonvalue> search for all bytes that are equal to the initial search.\n" " Without <comparisonvalue>**, search for values that are equal to the initial search.\n"
" with <comparisonvalue> search for all bytes that are equal to the <comparisonvalue>.\n" " With <comparisonvalue>, search for values that are equal to the <comparisonvalue>.\n"
" notequal [ne]\n" " notequal (ne)\n"
" without <comparisonvalue> search for all bytes that are not equal to the initial search.\n" " Without <comparisonvalue>, search for values that are not equal to the initial search.\n"
" with <comparisonvalue> search for all bytes that are not equal to the <comparisonvalue>.\n" " With <comparisonvalue>, search for values that are not equal to the <comparisonvalue>.\n"
" decrease [de, +]\n" " decrease (de, -)\n"
" without <comparisonvalue> search for all bytes that have decreased since the initial search.\n" " Without <comparisonvalue>, search for values that have decreased since the initial "
" with <comparisonvalue> search for all bytes that have decreased by the <comparisonvalue> since the initial search.\n" "search.\n"
" increase [in, -]\n" " With <comparisonvalue>, search for values that have decreased by the <comparisonvalue> "
" without <comparisonvalue> search for all bytes that have increased since the initial search.\n" "since the initial search.\n"
" with <comparisonvalue> search for all bytes that have increased by the <comparisonvalue> since the initial search.\n" " increase (in, +)\n"
" decreaseorequal [deeq]\n" " Without <comparisonvalue>, search for values that have increased since the initial "
" no <comparisonvalue> needed.\n" "search.\n"
" search for all bytes that have decreased or have same value since the initial search.\n" " With <comparisonvalue>, search for values that have increased by the <comparisonvalue> "
" increaseorequal [ineq]\n" "since the initial search.\n"
" no <comparisonvalue> needed.\n" " decreaseorequal (deeq)\n"
" search for all bytes that have decreased or have same value since the initial search.\n" " Search for values that have decreased or are unchanged since the initial search.\n"
" smallerof [lt]\n" " The <comparisonvalue> is not used.\n"
" without <comparisonvalue> this condition is invalid.\n" " increaseorequal (ineq)\n"
" with <comparisonvalue> search for all bytes that are smaller than the <comparisonvalue>.\n" " Search for values that have increased or are unchanged since the initial search.\n"
" greaterof [gt]\n" " The <comparisonvalue> is not used.\n"
" without <comparisonvalue> this condition is invalid.\n" " smallerof (lt, <)\n"
" with <comparisonvalue> search for all bytes that are larger than the <comparisonvalue>.\n" " Search for values that are less than the <comparisonvalue>.\n"
" changedby [ch, ~]\n" " The <comparisonvalue> is required.\n"
" without <comparisonvalue> this condition is invalid\n" " greaterof (gt, >)\n"
" with <comparisonvalue> search for all bytes that have changed by the <comparisonvalue> since the initial search.\n" " Search for values that are greater than the <comparisonvalue>.\n"
" The <comparisonvalue> is required.\n"
" changedby (ch, ~)\n"
" Search for values that have changed by the <comparisonvalue> since the initial search.\n"
" The <comparisonvalue> is required.\n"
"\n" "\n"
"Examples:\n" "Examples:\n"
"\n" "\n"
"cheatnextf increase\n" "cheatnextf increase\n"
" search for all bytes that have increased since the initial search.\n" " Search for all values that have increased since the initial search.\n"
"\n" "\n"
"cheatnextf decrease, 1\n" "cheatnextf decrease,1\n"
" search for all bytes that have decreased by 1 since the initial search.\n" " Search for all values that have decreased by 1 since the initial search.\n"
}, },
{ {
"cheatlist", "cheatlist",
"\n" "\n"
" cheatlist [<filename>]\n" " cheatlist [<filename>]\n"
"\n" "\n"
"Without <filename> show the list of matches in the debug console.\n" "Without <filename>, show the current cheat matches in the debugger console; with "
"With <filename> save the list of matches in basic xml format to <filename>.\n" "<filename>, save the current cheat matches in basic XML format to the specified file.\n"
"\n" "\n"
"Examples:\n" "Examples:\n"
"\n" "\n"
"cheatlist\n" "cheatlist\n"
" Show the current matches in the debug console.\n" " Show the current matches in the console.\n"
"cheatlist cheat.txt\n" "cheatlist cheat.xml\n"
" Save the current matches to cheat.txt.\n" " Save the current matches to cheat.xml in XML format.\n"
}, },
{ {
"cheatundo", "cheatundo",
"\n" "\n"
" cheatundo\n" " cheatundo\n"
"\n" "\n"
"Undo the results of the last search.\n" "Undo filtering of cheat candidates by the most recent cheatnext or cheatnextf command.\n"
"The undo command has no effect on the last value.\n" "Note that the previous values ARE NOT rolled back.\n"
"\n" "\n"
"Examples:\n" "Examples:\n"
"\n" "\n"
"cheatundo\n" "cheatundo\n"
" Undo the last search (state only).\n" " Restore cheat candidates filtered out by the most recent cheatnext or cheatnextf "
"command.\n"
}, },
{ {
"images", "images",

View File

@ -39,8 +39,19 @@ namespace {
menu_about::menu_about(mame_ui_manager &mui, render_container &container) menu_about::menu_about(mame_ui_manager &mui, render_container &container)
: menu(mui, container) : menu(mui, container)
, m_title(util::string_format(_("%1$s %2$s"), emulator_info::get_appname(), bare_build_version)) , m_header{
, m_footer(util::string_format(_("Revision: %1$s"), bare_vcs_revision)) util::string_format(
#ifdef MAME_DEBUG
_("%1$s %2$s (%3$s%4$sP%5$s, debug)"),
#else
_("%1$s %2$s (%3$s%4$sP%5$s)"),
#endif
emulator_info::get_appname(),
bare_build_version,
(sizeof(int) == sizeof(void *)) ? "I" : "",
(sizeof(long) == sizeof(void *)) ? "L" : (sizeof(long long) == sizeof(void *)) ? "LL" : "",
sizeof(void *) * 8),
util::string_format(_("Revision: %1$s"), bare_vcs_revision) }
{ {
} }
@ -60,23 +71,12 @@ menu_about::~menu_about()
void menu_about::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2) void menu_about::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
{ {
std::string_view tempbuf[1];
// draw the title // draw the title
tempbuf[0] = m_title;
draw_text_box( draw_text_box(
std::begin(tempbuf), std::end(tempbuf), std::begin(m_header), std::end(m_header),
origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(), origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(),
text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false, text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false,
ui().colors().text_color(), UI_GREEN_COLOR, 1.0f); ui().colors().text_color(), UI_GREEN_COLOR, 1.0f);
// draw the footer
tempbuf[0] = m_footer;
draw_text_box(
std::begin(tempbuf), std::end(tempbuf),
origx1, origx2, origy2 + ui().box_tb_border(), origy2 + bottom,
text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, false,
ui().colors().text_color(), ui().colors().background_color(), 1.0f);
} }
@ -221,8 +221,7 @@ void menu_about::draw(uint32_t flags)
void menu_about::populate(float &customtop, float &custombottom) void menu_about::populate(float &customtop, float &custombottom)
{ {
// make space for the title and revision // make space for the title and revision
customtop = ui().get_line_height() + 3.0f * ui().box_tb_border(); customtop = (ui().get_line_height() * m_header.size()) + (ui().box_tb_border() * 3.0f);
custombottom = ui().get_line_height() + 3.0f * ui().box_tb_border();
} }

View File

@ -16,6 +16,7 @@
#include <optional> #include <optional>
#include <string> #include <string>
#include <vector>
namespace ui { namespace ui {
@ -34,8 +35,7 @@ private:
virtual void populate(float &customtop, float &custombottom) override; virtual void populate(float &customtop, float &custombottom) override;
virtual void handle() override; virtual void handle() override;
std::string const m_title; std::vector<std::string> const m_header;
std::string const m_footer;
std::optional<text_layout> m_layout; std::optional<text_layout> m_layout;
}; };

View File

@ -2268,7 +2268,22 @@ void mame_ui_manager::menu_reset()
std::string mame_ui_manager::get_general_input_setting(ioport_type type, int player, input_seq_type seqtype) std::string mame_ui_manager::get_general_input_setting(ioport_type type, int player, input_seq_type seqtype)
{ {
return machine().input().seq_name(machine().ioport().type_seq(type, player, seqtype)); input_seq seq(machine().ioport().type_seq(type, player, seqtype));
input_code codes[16]; // TODO: remove magic number
unsigned len(0U);
for (unsigned i = 0U; std::size(codes) > i; ++i)
{
if (input_seq::not_code == seq[i])
++i;
else
codes[len++] = seq[i];
if (input_seq::end_code == seq[i])
break;
}
seq.reset();
for (unsigned i = 0U; len > i; ++i)
seq += codes[i];
return machine().input().seq_name(seq);
} }