Still more user experience improvements:

Changed the default mapping for UI select to not trigger on Alt+Enter
fullscreen toggle.  (Fullscreen toggle still doesn't work in menus -
actually fixing that is complicated.)

frontend: Made the about box wrap text properly, made the title and
backtrack menu item always visible, and added a footer with the VCS
revision.

frontend: Don't highlight the favourites and info toolbar buttons if
there's no selection (can happen if filters produce no results).  Also
made the info viewer appear even if no info is available - it's less
confusing to see an empty menu than wonder why clicking the button does
nothing.

debugger: Added a register points view to the GUI debuggers, to go with
the breakpoints and watchpoints views.

debugger: Extended [brw]p(clear|(en|dis)able) commands to accept
multiple arguments to perform the same action on multiple
(break|watch|register)points at once.  Also made rplist accept a CPU for
showing a single CPU's register points ([bw]plist already support this).

docs: Updated registerpoints debugger commands page, and updated other
pages for latest extensions to syntax.
This commit is contained in:
Vas Crabb 2021-10-18 08:22:21 +11:00
parent 0a82b82684
commit 40a30af10f
34 changed files with 1125 additions and 426 deletions

View File

@ -75,10 +75,10 @@ Back to :ref:`debugger-breakpoint-list`
bpclear
-------
**bpclear [<bpnum>]**
**bpclear [<bpnum>[,…]]**
Clear breakpoints. If **<bpnum>** is specified, the breakpoint it
refers to will be cleared. If **<bpnum>** is not specified, all
Clear breakpoints. If **<bpnum>** is specified, the breakpoints
referred to will be cleared. If **<bpnum>** is not specified, all
breakpoints will be cleared.
Examples:
@ -96,10 +96,10 @@ Back to :ref:`debugger-breakpoint-list`
bpdisable
---------
**bpdisable [<bpnum>]**
**bpdisable [<bpnum>[,…]]**
Disable breakpoints. If **<bpnum>** is specified, the breakpoint it
refers to will be disabled. If **<bpnum>** is not specified, all
Disable breakpoints. If **<bpnum>** is specified, the breakpoints
referred to will be disabled. If **<bpnum>** is not specified, all
breakpoints will be disabled.
Note that disabling a breakpoint does not delete it, it just temporarily
@ -122,10 +122,10 @@ Back to :ref:`debugger-breakpoint-list`
bpenable
--------
**bpenable [<bpnum>]**
**bpenable [<bpnum>[,…]]**
Enable breakpoints. If **<bpnum>** is specified, the breakpoint it
refers to will be enabled. If **<bpnum>** is not specified, all
Enable breakpoints. If **<bpnum>** is specified, the breakpoint
referred to will be enabled. If **<bpnum>** is not specified, all
breakpoints will be enabled.
Examples:

View File

@ -285,7 +285,7 @@ Back to :ref:`debugger-execution-list`
ignore
------
**ignore [<CPU>[,<CPU>[,...]]]**
**ignore [<CPU>[,<CPU>[,]]]**
Ignores the specified CPUs in the debugger. CPUs can be specified by
tag or debugger CPU number (see :ref:`debugger-devicespec` for details).
@ -316,7 +316,7 @@ Back to :ref:`debugger-execution-list`
observe
-------
**observe [<CPU>[,<CPU>[,...]]]**
**observe [<CPU>[,<CPU>[,]]]**
Allow interaction with the specified CPUs in the debugger. CPUs can be
specified by tag or debugger CPU number (see :ref:`debugger-devicespec`

View File

@ -159,7 +159,7 @@ Back to :ref:`debugger-general-list`
print
-----
**print <item>[,...]**
**print <item>[,]**
The **print** command prints the results of one or more expressions to
the debugger console as hexadecimal numbers.
@ -180,7 +180,7 @@ Back to :ref:`debugger-general-list`
printf
------
**printf <format>[,<argument>[,...]]**
**printf <format>[,<argument>[,]]**
Prints a C-style formatted message to the debugger console. Only a
very limited subset of format specifiers and escape sequences are
@ -223,7 +223,7 @@ Back to :ref:`debugger-general-list`
logerror
--------
**logerror <format>[,<argument>[,...]]**
**logerror <format>[,<argument>[,]]**
Prints a C-style formatted message to the error log. See
:ref:`debugger-command-printf` for details about the limited set of
@ -246,7 +246,7 @@ Back to :ref:`debugger-general-list`
tracelog
--------
**tracelog <format>[,<argument>[,...]]**
**tracelog <format>[,<argument>[,]]**
Prints a C-style formatted message to the currently open trace file (see
:ref:`debugger-command-trace` for more information). If no trace file
@ -272,7 +272,7 @@ Back to :ref:`debugger-general-list`
tracesym
--------
**tracesym <item>[,...]**
**tracesym <item>[,]**
Prints the specified symbols to the currently open trace file (see
:ref:`debugger-command-trace` for more information). If no trace file

View File

@ -64,7 +64,7 @@ Back to :ref:`debugger-memory-list`
find
----
**f[ind][{d|i|o}] <address>[:<space>],<length>[,<data>[,...]]**
**f[ind][{d|i|o}] <address>[:<space>],<length>[,<data>[,]]**
Search through memory for the specified sequence of data. The
**<address>** is the address to begin searching from, optionally
@ -113,7 +113,7 @@ Back to :ref:`debugger-memory-list`
fill
----
**fill[{d|i|o}] <address>[:<space>],<length>[,<data>[,...]]**
**fill[{d|i|o}] <address>[:<space>],<length>[,<data>[,]]**
Overwrite a block of memory with copies of the supplied data sequence.
The **<address>** specifies the address to begin writing at, optionally

View File

@ -1,120 +1,146 @@
.. _debugger-registerpoints-list:
Registerpoints Debugger Commands
Registerpoint Debugger Commands
================================
You can also type **help <command>** for further details on each command in the MAME Debugger interface.
| :ref:`debugger-command-rpset` -- sets a registerpoint to trigger on <condition>
| :ref:`debugger-command-rpclear` -- clears a given registerpoint or all if no <rpnum> specified
| :ref:`debugger-command-rpdisable` -- disabled a given registerpoint or all if no <rpnum> specified
| :ref:`debugger-command-rpenable` -- enables a given registerpoint or all if no <rpnum> specified
| :ref:`debugger-command-rplist` -- lists all the registerpoints
:ref:`debugger-command-rpset`
sets a registerpoint to trigger on a condition
:ref:`debugger-command-rpclear`
clears registerpoints
:ref:`debugger-command-rpdisable`
disables a registerpoint
:ref:`debugger-command-rpenable`
enables registerpoints
:ref:`debugger-command-rplist`
lists registerpoints
.. _debugger-command-rpset:
.. _debugger-command-rpset:
rpset
-----
| **rp[set] {<condition>}[,<action>]]**
|
| Sets a new registerpoint which will be triggered when <condition> is met. The condition must be specified between curly braces to prevent the condition from being evaluated as an assignment.
| The optional <action> parameter provides a command that is executed whenever the registerpoint is hit. Note that you may need to embed the action within braces { } in order to prevent commas and semicolons from being interpreted as applying to the rpset command itself.
| Each registerpoint that is set is assigned an index which can be used in other registerpoint commands to reference this registerpoint.
|
| Examples:
|
| rp {PC==0150}
|
| Set a registerpoint that will halt execution whenever the PC register equals 0x150.
|
| temp0=0; rp {PC==0150},{temp0++; g}
|
| Set a registerpoint that will increment the variable temp0 whenever the PC register equals 0x0150.
|
| rp {temp0==5}
|
| Set a registerpoint that will halt execution whenever the temp0 variable equals 5.
|
| Back to :ref:`debugger-registerpoints-list`
**rp[set] <condition>[,<action>]**
Sets a new registerpoint which will be triggered when the expression
supplied as the **<condition>** evaluates to true (non-zero). Note that
the condition may need to be surrounded with braces ``{ }`` to prevent
it from being interpreted as an assignment. The optional **<action>**
parameter provides a command to be executed whenever the registerpoint
is triggered. Note that you may need to surround the action with braces
``{ }`` to ensure commas and semicolons within the command are not
interpreted in the context of the ``rpset`` command itself.
Each registerpoint that is set is assigned a numeric index which can be
used to refer to it in other registerpoint commands. Registerpoint
indices are unique throughout a session.
Examples:
``rp {PC==150}``
Set a registerpoint that will halt execution whenever the **PC**
register equals 150.
``temp0=0; rp {PC==150},{temp0++; g}``
Set a registerpoint that will increment the variable **temp0**
whenever the **PC** register equals 150.
``rp {temp0==5}``
Set a registerpoint that will halt execution whenever the **temp0**
variable equals 5.
Back to :ref:`debugger-registerpoints-list`
.. _debugger-command-rpclear:
.. _debugger-command-rpclear:
rpclear
-------
| **rpclear [<rpnum>]**
|
| The rpclear command clears a registerpoint. If <rpnum> is specified, only the requested registerpoint is cleared, otherwise all registerpoints are cleared.
|
| Examples:
|
| rpclear 3
|
| Clear registerpoint index 3.
|
| rpclear
|
| Clear all registerpoints.
|
| Back to :ref:`debugger-registerpoints-list`
**rpclear [<rpnum>,[,…]]**
Clears registerpoints. If **<rpnum>** is specified, the registerpoints
referred to will be cleared. If **<rpnum>** is not specified, all
registerpoints will be cleared.
Examples:
``rpclear 3``
Clear the registerpoint with index 3.
``rpclear``
Clear all registerpoints.
Back to :ref:`debugger-registerpoints-list`
.. _debugger-command-rpdisable:
.. _debugger-command-rpdisable:
rpdisable
---------
| **rpdisable [<rpnum>]**
|
| The rpdisable command disables a registerpoint. If <rpnum> is specified, only the requested registerpoint is disabled, otherwise all registerpoints are disabled. Note that disabling a registerpoint does not delete it, it just temporarily marks the registerpoint as inactive.
|
| Examples:
|
| rpdisable 3
|
| Disable registerpoint index 3.
|
| rpdisable
|
| Disable all registerpoints.
|
| Back to :ref:`debugger-registerpoints-list`
**rpdisable [<rpnum>[,…]]**
Disables registerpoints. If **<rpnum>** is specified, the
registerpoints referred to will be disabled. If **<rpnum>** is not
specified, all registerpoints will be disabled.
Note that disabling a registerpoint does not delete it, it just
temporarily marks the registerpoint as inactive. Disabled
registerpoints will not cause execution to halt, their condition
expressions will not be evaluated, and their associated commands will
not be executed.
Examples:
``rpdisable 3``
Disable the registerpoint with index 3.
``rpdisable``
Disable all registerpoints.
Back to :ref:`debugger-registerpoints-list`
.. _debugger-command-rpenable:
.. _debugger-command-rpenable:
rpenable
--------
| **rpenable [<rpnum>]**
|
| The rpenable command enables a registerpoint. If <rpnum> is specified, only the requested registerpoint is enabled, otherwise all registerpoints are enabled.
|
| Examples:
|
| rpenable 3
|
| Enable registerpoint index 3.
|
| rpenable
|
| Enable all registerpoints.
|
| Back to :ref:`debugger-registerpoints-list`
**rpenable [<rpnum>[,…]]**
Enables registerpoints. If **<rpnum>** is specified, the registerpoints
referred to will be enabled. If **<rpnum>** is not specified, all
registerpoints will be enabled.
Examples:
``rpenable 3``
Enable the registerpoint with index 3.
``rpenable``
Enable all registerpoints.
Back to :ref:`debugger-registerpoints-list`
.. _debugger-command-rplist:
.. _debugger-command-rplist:
rplist
------
| **rplist**
|
| The rplist command lists all the current registerpoints, along with their index and any actions attached to them.
|
| Back to :ref:`debugger-registerpoints-list`
**rplist [<CPU>]**
List current registerpoints, along with their indices and conditions,
and any associated actions actions. If no **<CPU>** is specified,
registerpoints for all CPUs in the system will be listed; if a **<CPU>**
is specified, only registerpoints for that CPU will be listed. The
**<CPU>** can be specified by tag or by debugger CPU number (see
:ref:`debugger-devicespec` for details).
Examples:
``rplist``
List all registerpoints.
``rplist .``
List all registerpoints for the visible CPU.
``rplist maincpu``
List all registerpoints for the CPU with the absolute tag path
``:maincpu``.
Back to :ref:`debugger-registerpoints-list`

View File

@ -83,10 +83,10 @@ Back to :ref:`debugger-watchpoints-list`
wpclear
-------
**wpclear [<wpnum>]**
**wpclear [<wpnum>[,…]]**
Clear watchpoints. If **<wpnum>** is specified, the watchpoint it
refers to will be cleared. If **<wpnum>** is not specified, all
Clear watchpoints. If **<wpnum>** is specified, the watchpoints
referred to will be cleared. If **<wpnum>** is not specified, all
watchpoints will be cleared.
Examples:
@ -104,10 +104,10 @@ Back to :ref:`debugger-watchpoints-list`
wpdisable
---------
**wpdisable [<wpnum>]**
**wpdisable [<wpnum>[,…]]**
Disable watchpoints. If **<wpnum>** is specified, the watchpoint it
refers to will be disabled. If **<wpnum>** is not specified, all
Disable watchpoints. If **<wpnum>** is specified, the watchpoints
referred to will be disabled. If **<wpnum>** is not specified, all
watchpoints will be disabled.
Note that disabling a watchpoint does not delete it, it just temporarily
@ -130,10 +130,10 @@ Back to :ref:`debugger-watchpoints-list`
wpenable
--------
**wpenable [<wpnum>]**
**wpenable [<wpnum>[,…]]**
Enable watchpoints. If **<wpnum>** is specified, the watchpoint it
refers to will be enabled. If **<wpnum>** is not specified, all
Enable watchpoints. If **<wpnum>** is specified, the watchpoints
referred to will be enabled. If **<wpnum>** is not specified, all
watchpoints will be enabled.
Examples:

View File

@ -1073,7 +1073,7 @@ endif
ifneq ($(GIT_AVAILABLE),git)
IGNORE_GIT := 1
endif
ifeq ($(wildcard .git/*),)
ifeq ($(filter .git,$(wildcard .*)),)
IGNORE_GIT := 1
endif
@ -1757,17 +1757,23 @@ endif
ifeq (posix,$(SHELLTYPE))
$(GENDIR)/version.cpp: makefile $(GENDIR)/git_desc | $(GEN_FOLDERS)
@echo '#define BARE_BUILD_VERSION "0.236"' > $@
@echo '#define BARE_VCS_REVISION "$(NEW_GIT_VERSION)"' >> $@
@echo 'extern const char bare_build_version[];' >> $@
@echo 'extern const char bare_vcs_revision[];' >> $@
@echo 'extern const char build_version[];' >> $@
@echo 'const char bare_build_version[] = BARE_BUILD_VERSION;' >> $@
@echo 'const char build_version[] = BARE_BUILD_VERSION " ($(NEW_GIT_VERSION))";' >> $@
@echo 'const char bare_vcs_revision[] = BARE_VCS_REVISION;' >> $@
@echo 'const char build_version[] = BARE_BUILD_VERSION " (" BARE_VCS_REVISION ")";' >> $@
else
$(GENDIR)/version.cpp: makefile $(GENDIR)/git_desc | $(GEN_FOLDERS)
@echo #define BARE_BUILD_VERSION "0.236" > $@
@echo #define BARE_VCS_REVISION "$(NEW_GIT_VERSION)" >> $@
@echo extern const char bare_build_version[]; >> $@
@echo extern const char bare_vcs_revision[]; >> $@
@echo extern const char build_version[]; >> $@
@echo const char bare_build_version[] = BARE_BUILD_VERSION; >> $@
@echo const char build_version[] = BARE_BUILD_VERSION " ($(NEW_GIT_VERSION))"; >> $@
@echo const char bare_vcs_revision[] = BARE_VCS_REVISION; >> $@
@echo const char build_version[] = BARE_BUILD_VERSION " (" BARE_VCS_REVISION ")"; >> $@
endif

View File

@ -238,6 +238,8 @@ files {
MAME_DIR .. "src/emu/debug/dvmemory.h",
MAME_DIR .. "src/emu/debug/dvbpoints.cpp",
MAME_DIR .. "src/emu/debug/dvbpoints.h",
MAME_DIR .. "src/emu/debug/dvrpoints.cpp",
MAME_DIR .. "src/emu/debug/dvrpoints.h",
MAME_DIR .. "src/emu/debug/dvwpoints.cpp",
MAME_DIR .. "src/emu/debug/dvwpoints.h",
MAME_DIR .. "src/emu/debug/dvstate.cpp",

View File

@ -108,6 +108,8 @@ project ("osd_" .. _OPTIONS["osd"])
MAME_DIR .. "src/osd/modules/debugger/osx/memoryviewer.h",
MAME_DIR .. "src/osd/modules/debugger/osx/pointsviewer.mm",
MAME_DIR .. "src/osd/modules/debugger/osx/pointsviewer.h",
MAME_DIR .. "src/osd/modules/debugger/osx/registerpointsview.mm",
MAME_DIR .. "src/osd/modules/debugger/osx/registerpointsview.h",
MAME_DIR .. "src/osd/modules/debugger/osx/registersview.mm",
MAME_DIR .. "src/osd/modules/debugger/osx/registersview.h",
MAME_DIR .. "src/osd/modules/debugger/osx/watchpointsview.mm",

View File

@ -250,9 +250,9 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu
m_console.register_command("bpset", CMDFLAG_NONE, 1, 3, std::bind(&debugger_commands::execute_bpset, this, _1));
m_console.register_command("bp", CMDFLAG_NONE, 1, 3, std::bind(&debugger_commands::execute_bpset, this, _1));
m_console.register_command("bpclear", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_bpclear, this, _1));
m_console.register_command("bpdisable", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_bpdisenable, this, false, _1));
m_console.register_command("bpenable", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_bpdisenable, this, true, _1));
m_console.register_command("bpclear", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_bpclear, this, _1));
m_console.register_command("bpdisable", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_bpdisenable, this, false, _1));
m_console.register_command("bpenable", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_bpdisenable, this, true, _1));
m_console.register_command("bplist", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_bplist, this, _1));
m_console.register_command("wpset", CMDFLAG_NONE, 3, 5, std::bind(&debugger_commands::execute_wpset, this, -1, _1));
@ -263,17 +263,17 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu
m_console.register_command("wpi", CMDFLAG_NONE, 3, 5, std::bind(&debugger_commands::execute_wpset, this, AS_IO, _1));
m_console.register_command("wposet", CMDFLAG_NONE, 3, 5, std::bind(&debugger_commands::execute_wpset, this, AS_OPCODES, _1));
m_console.register_command("wpo", CMDFLAG_NONE, 3, 5, std::bind(&debugger_commands::execute_wpset, this, AS_OPCODES, _1));
m_console.register_command("wpclear", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_wpclear, this, _1));
m_console.register_command("wpdisable", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_wpdisenable, this, false, _1));
m_console.register_command("wpenable", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_wpdisenable, this, true, _1));
m_console.register_command("wpclear", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_wpclear, this, _1));
m_console.register_command("wpdisable", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_wpdisenable, this, false, _1));
m_console.register_command("wpenable", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_wpdisenable, this, true, _1));
m_console.register_command("wplist", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_wplist, this, _1));
m_console.register_command("rpset", CMDFLAG_NONE, 1, 2, std::bind(&debugger_commands::execute_rpset, this, _1));
m_console.register_command("rp", CMDFLAG_NONE, 1, 2, std::bind(&debugger_commands::execute_rpset, this, _1));
m_console.register_command("rpclear", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_rpclear, this, _1));
m_console.register_command("rpdisable", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_rpdisenable, this, false, _1));
m_console.register_command("rpenable", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_rpdisenable, this, true, _1));
m_console.register_command("rplist", CMDFLAG_NONE, 0, 0, std::bind(&debugger_commands::execute_rplist, this, _1));
m_console.register_command("rpclear", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_rpclear, this, _1));
m_console.register_command("rpdisable", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_rpdisenable, this, false, _1));
m_console.register_command("rpenable", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_rpdisenable, this, true, _1));
m_console.register_command("rplist", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_rplist, this, _1));
m_console.register_command("statesave", CMDFLAG_NONE, 1, 1, std::bind(&debugger_commands::execute_statesave, this, _1));
m_console.register_command("ss", CMDFLAG_NONE, 1, 1, std::bind(&debugger_commands::execute_statesave, this, _1));
@ -1070,6 +1070,37 @@ int debugger_commands::mini_printf(char *buffer, const char *format, int params,
}
/*-------------------------------------------------
execute_index_command - helper for commands
that take multiple indices as arguments
-------------------------------------------------*/
template <typename T>
void debugger_commands::execute_index_command(std::vector<std::string> const &params, T &&apply, char const *unused_message)
{
std::vector<u64> index(params.size());
for (int paramnum = 0; paramnum < params.size(); paramnum++)
{
if (!validate_number_parameter(params[paramnum], index[paramnum]))
return;
}
for (device_t &device : device_enumerator(m_machine.root_device()))
{
for (auto param = index.begin(); index.end() != param; )
{
if (apply(device, *param))
param = index.erase(param);
else
++param;
}
}
for (auto const &param : index)
m_console.printf(unused_message, param);
}
/*-------------------------------------------------
execute_printf - execute the printf command
-------------------------------------------------*/
@ -1740,31 +1771,24 @@ void debugger_commands::execute_bpset(const std::vector<std::string> &params)
void debugger_commands::execute_bpclear(const std::vector<std::string> &params)
{
u64 bpindex;
if (params.empty()) // if no parameters, clear all
{
for (device_t &device : device_enumerator(m_machine.root_device()))
device.debug()->breakpoint_clear_all();
m_console.printf("Cleared all breakpoints\n");
}
else if (!validate_number_parameter(params[0], bpindex)) // otherwise, clear the specific one
else // otherwise, clear the specific ones
{
return;
}
else
{
bool found = false;
for (device_t &device : device_enumerator(m_machine.root_device()))
if (device.debug()->breakpoint_clear(bpindex))
{
found = true;
break;
}
if (found)
m_console.printf("Breakpoint %X cleared\n", u32(bpindex));
else
m_console.printf("Invalid breakpoint number %X\n", u32(bpindex));
execute_index_command(
params,
[this] (device_t &device, u64 param) -> bool
{
if (!device.debug()->breakpoint_clear(param))
return false;
m_console.printf("Breakpoint %X cleared\n", param);
return true;
},
"Invalid breakpoint number %X\n");
}
}
@ -1776,34 +1800,24 @@ void debugger_commands::execute_bpclear(const std::vector<std::string> &params)
void debugger_commands::execute_bpdisenable(bool enable, const std::vector<std::string> &params)
{
u64 bpindex;
if (params.empty()) // if 0 parameters, disable/enable all
if (params.empty()) // if no parameters, disable/enable all
{
for (device_t &device : device_enumerator(m_machine.root_device()))
device.debug()->breakpoint_enable_all(enable);
if (!enable)
m_console.printf("Disabled all breakpoints\n");
else
m_console.printf("Enabled all breakpoints\n");
m_console.printf(enable ? "Enabled all breakpoints\n" : "Disabled all breakpoints\n");
}
else if (!validate_number_parameter(params[0], bpindex)) // otherwise, disable/enable the specific one
else // otherwise, disable/enable the specific ones
{
return;
}
else
{
bool found = false;
for (device_t &device : device_enumerator(m_machine.root_device()))
if (device.debug()->breakpoint_enable(bpindex, enable))
{
found = true;
break;
}
if (found)
m_console.printf("Breakpoint %X %s\n", u32(bpindex), enable ? "enabled" : "disabled");
else
m_console.printf("Invalid breakpoint number %X\n", u32(bpindex));
execute_index_command(
params,
[this, enable] (device_t &device, u64 param) -> bool
{
if (!device.debug()->breakpoint_enable(param, enable))
return false;
m_console.printf(enable ? "Breakpoint %X enabled\n" : "Breakpoint %X disabled\n", param);
return true;
},
"Invalid breakpoint number %X\n");
}
}
@ -1922,29 +1936,24 @@ void debugger_commands::execute_wpset(int spacenum, const std::vector<std::strin
void debugger_commands::execute_wpclear(const std::vector<std::string> &params)
{
u64 wpindex;
/* if 0 parameters, clear all */
if (params.empty())
if (params.empty()) // if no parameters, clear all
{
for (device_t &device : device_enumerator(m_machine.root_device()))
device.debug()->watchpoint_clear_all();
m_console.printf("Cleared all watchpoints\n");
}
/* otherwise, clear the specific one */
else if (!validate_number_parameter(params[0], wpindex))
return;
else
else // otherwise, clear the specific ones
{
bool found = false;
for (device_t &device : device_enumerator(m_machine.root_device()))
if (device.debug()->watchpoint_clear(wpindex))
found = true;
if (found)
m_console.printf("Watchpoint %X cleared\n", u32(wpindex));
else
m_console.printf("Invalid watchpoint number %X\n", u32(wpindex));
execute_index_command(
params,
[this] (device_t &device, u64 param) -> bool
{
if (!device.debug()->watchpoint_clear(param))
return false;
m_console.printf("Watchpoint %X cleared\n", param);
return true;
},
"Invalid watchpoint number %X\n");
}
}
@ -1956,31 +1965,24 @@ void debugger_commands::execute_wpclear(const std::vector<std::string> &params)
void debugger_commands::execute_wpdisenable(bool enable, const std::vector<std::string> &params)
{
u64 wpindex;
if (params.empty()) // if no parameters, clear all
if (params.empty()) // if no parameters, disable/enable all
{
for (device_t &device : device_enumerator(m_machine.root_device()))
device.debug()->watchpoint_enable_all(enable);
if (!enable)
m_console.printf("Disabled all watchpoints\n");
else
m_console.printf("Enabled all watchpoints\n");
m_console.printf(enable ? "Enabled all watchpoints\n" : "Disabled all watchpoints\n");
}
else if (!validate_number_parameter(params[0], wpindex)) // otherwise, clear the specific one
else // otherwise, disable/enable the specific ones
{
return;
}
else
{
bool found = false;
for (device_t &device : device_enumerator(m_machine.root_device()))
if (device.debug()->watchpoint_enable(wpindex, enable))
found = true;
if (found)
m_console.printf("Watchpoint %X %s\n", u32(wpindex), enable ? "enabled" : "disabled");
else
m_console.printf("Invalid watchpoint number %X\n", u32(wpindex));
execute_index_command(
params,
[this, enable] (device_t &device, u64 param) -> bool
{
if (!device.debug()->watchpoint_enable(param, enable))
return false;
m_console.printf(enable ? "Watchpoint %X enabled\n" : "Watchpoint %X disabled\n", param);
return true;
},
"Invalid watchpoint number %X\n");
}
}
@ -2070,9 +2072,9 @@ void debugger_commands::execute_rpset(const std::vector<std::string> &params)
if (params.size() > 1 && !debug_command_parameter_command(action = params[1].c_str()))
return;
// set the breakpoint
int const bpnum = cpu->debug()->registerpoint_set(condition.original_string(), action);
m_console.printf("Registerpoint %X set\n", bpnum);
// set the registerpoint
int const rpnum = cpu->debug()->registerpoint_set(condition.original_string(), action);
m_console.printf("Registerpoint %X set\n", rpnum);
}
@ -2083,29 +2085,24 @@ void debugger_commands::execute_rpset(const std::vector<std::string> &params)
void debugger_commands::execute_rpclear(const std::vector<std::string> &params)
{
u64 rpindex;
/* if 0 parameters, clear all */
if (params.empty())
if (params.empty()) // if no parameters, clear all
{
for (device_t &device : device_enumerator(m_machine.root_device()))
device.debug()->registerpoint_clear_all();
m_console.printf("Cleared all registerpoints\n");
}
/* otherwise, clear the specific one */
else if (!validate_number_parameter(params[0], rpindex))
return;
else
else // otherwise, clear the specific ones
{
bool found = false;
for (device_t &device : device_enumerator(m_machine.root_device()))
if (device.debug()->registerpoint_clear(rpindex))
found = true;
if (found)
m_console.printf("Registerpoint %X cleared\n", u32(rpindex));
else
m_console.printf("Invalid registerpoint number %X\n", u32(rpindex));
execute_index_command(
params,
[this] (device_t &device, u64 param) -> bool
{
if (!device.debug()->registerpoint_clear(param))
return false;
m_console.printf("Registerpoint %X cleared\n", param);
return true;
},
"Invalid registerpoint number %X\n");
}
}
@ -2117,31 +2114,24 @@ void debugger_commands::execute_rpclear(const std::vector<std::string> &params)
void debugger_commands::execute_rpdisenable(bool enable, const std::vector<std::string> &params)
{
u64 rpindex;
if (params.empty()) // if no parameters, clear all
if (params.empty()) // if no parameters, disable/enable all
{
for (device_t &device : device_enumerator(m_machine.root_device()))
device.debug()->registerpoint_enable_all(enable);
if (!enable)
m_console.printf("Disabled all registerpoints\n");
else
m_console.printf("Enabled all registeroints\n");
m_console.printf(enable ? "Enabled all registerpoints\n" : "Disabled all registerpoints\n");
}
else if (!validate_number_parameter(params[0], rpindex)) // otherwise, clear the specific one
else // otherwise, disable/enable the specific ones
{
return;
}
else
{
bool found = false;
for (device_t &device : device_enumerator(m_machine.root_device()))
if (device.debug()->registerpoint_enable(rpindex, enable))
found = true;
if (found)
m_console.printf("Registerpoint %X %s\n", u32(rpindex), enable ? "enabled" : "disabled");
else
m_console.printf("Invalid registerpoint number %X\n", u32(rpindex));
execute_index_command(
params,
[this, enable] (device_t &device, u64 param) -> bool
{
if (!device.debug()->registerpoint_enable(param, enable))
return false;
m_console.printf(enable ? "Registerpoint %X enabled\n" : "Breakpoint %X disabled\n", param);
return true;
},
"Invalid registerpoint number %X\n");
}
}
@ -2155,26 +2145,42 @@ void debugger_commands::execute_rplist(const std::vector<std::string> &params)
{
int printed = 0;
std::string buffer;
/* loop over all CPUs */
for (device_t &device : device_enumerator(m_machine.root_device()))
if (!device.debug()->registerpoint_list().empty())
{
m_console.printf("Device '%s' registerpoints:\n", device.tag());
/* loop over the breakpoints */
for (const debug_registerpoint &rp : device.debug()->registerpoint_list())
auto const apply =
[this, &printed, &buffer] (device_t &device)
{
buffer = string_format("%c%4X if %s", rp.enabled() ? ' ' : 'D', rp.index(), rp.condition());
if (rp.action() != nullptr)
buffer.append(string_format(" do %s", rp.action()));
m_console.printf("%s\n", buffer);
printed++;
}
}
if (!device.debug()->registerpoint_list().empty())
{
m_console.printf("Device '%s' registerpoints:\n", device.tag());
if (printed == 0)
m_console.printf("No registerpoints currently installed\n");
// loop over the registerpoints
for (const auto &rp : device.debug()->registerpoint_list())
{
buffer = string_format("%c%4X if %s", rp.enabled() ? ' ' : 'D', rp.index(), rp.condition());
if (rp.action() && *rp.action())
buffer.append(string_format(" do %s", rp.action()));
m_console.printf("%s\n", buffer);
printed++;
}
}
};
if (!params.empty())
{
device_t *cpu;
if (!validate_cpu_parameter(params[0], cpu))
return;
apply(*cpu);
if (!printed)
m_console.printf("No registerpoints currently installed for CPU %s\n", cpu->tag());
}
else
{
// loop over all CPUs
for (device_t &device : device_enumerator(m_machine.root_device()))
apply(device);
if (!printed)
m_console.printf("No registerpoints currently installed\n");
}
}

View File

@ -99,6 +99,8 @@ private:
void global_set(global_entry *global, u64 value);
int mini_printf(char *buffer, const char *format, int params, u64 *param);
template <typename T>
void execute_index_command(std::vector<std::string> const &params, T &&apply, char const *unused_message);
void execute_help(const std::vector<std::string> &params);
void execute_print(const std::vector<std::string> &params);

View File

@ -154,9 +154,9 @@ const help_item f_static_help_list[] =
"Type help <command> for further details on each command\n"
"\n"
" bp[set] <address>[:<CPU>][,<condition>[,<action>]] -- sets breakpoint at <address>\n"
" bpclear [<bpnum>] -- clears a given breakpoint or all if no <bpnum> specified\n"
" bpdisable [<bpnum>] -- disables a given breakpoint or all if no <bpnum> specified\n"
" bpenable [<bpnum>] -- enables a given breakpoint or all if no <bpnum> specified\n"
" bpclear [<bpnum>[,...]] -- clears given breakpoints or all if no <bpnum> specified\n"
" bpdisable [<bpnum>[,...]] -- disables given breakpoints or all if no <bpnum> specified\n"
" bpenable [<bpnum>[,...]] -- enables given breakpoints or all if no <bpnum> specified\n"
" bplist [<CPU>] -- lists all the breakpoints\n"
},
{
@ -169,9 +169,9 @@ const help_item f_static_help_list[] =
" wpd[set] <address>[:<space>],<length>,<type>[,<condition>[,<action>]] -- sets data space watchpoint\n"
" wpi[set] <address>[:<space>],<length>,<type>[,<condition>[,<action>]] -- sets I/O space watchpoint\n"
" wpo[set] <address>[:<space>],<length>,<type>[,<condition>[,<action>]] -- sets opcode space watchpoint\n"
" wpclear [<wpnum>] -- clears a given watchpoint or all if no <wpnum> specified\n"
" wpdisable [<wpnum>] -- disables a given watchpoint or all if no <wpnum> specified\n"
" wpenable [<wpnum>] -- enables a given watchpoint or all if no <wpnum> specified\n"
" wpclear [<wpnum>[,...]] -- clears given watchpoints or all if no <wpnum> specified\n"
" wpdisable [<wpnum>[,...]] -- disables given watchpoints or all if no <wpnum> specified\n"
" wpenable [<wpnum>[,...]] -- enables given watchpoints or all if no <wpnum> specified\n"
" wplist [<CPU>] -- lists all the watchpoints\n"
},
{
@ -180,11 +180,11 @@ const help_item f_static_help_list[] =
"Registerpoint Commands\n"
"Type help <command> for further details on each command\n"
"\n"
" rp[set] {<condition>}[,<action>] -- sets a registerpoint to trigger on <condition>\n"
" rpclear [<rpnum>] -- clears a given registerpoint or all if no <rpnum> specified\n"
" rpdisable [<rpnum>] -- disabled a given registerpoint or all if no <rpnum> specified\n"
" rpenable [<rpnum>] -- enables a given registerpoint or all if no <rpnum> specified\n"
" rplist -- lists all the registerpoints\n"
" rp[set] <condition>[,<action>] -- sets a registerpoint to trigger on <condition>\n"
" rpclear [<rpnum>[,...]] -- clears given registerpoints or all if no <rpnum> specified\n"
" rpdisable [<rpnum>[,...]] -- disabled given registerpoints or all if no <rpnum> specified\n"
" rpenable [<rpnum>[,...]] -- enables given registerpoints or all if no <rpnum> specified\n"
" rplist [<CPU>] -- lists all the registerpoints\n"
},
{
"expressions",
@ -1206,10 +1206,10 @@ const help_item f_static_help_list[] =
{
"bpclear",
"\n"
" bpclear [<bpnum>]\n"
" bpclear [<bpnum>[,...]]\n"
"\n"
"The bpclear command clears a breakpoint. If <bpnum> is specified, only the requested "
"breakpoint is cleared; otherwise all breakpoints are cleared.\n"
"The bpclear command clears breakpoints. If <bpnum> is specified, only the requested "
"breakpoints are cleared; otherwise all breakpoints are cleared.\n"
"\n"
"Examples:\n"
"\n"
@ -1222,10 +1222,10 @@ const help_item f_static_help_list[] =
{
"bpdisable",
"\n"
" bpdisable [<bpnum>]\n"
" bpdisable [<bpnum>,[...]]\n"
"\n"
"The bpdisable command disables a breakpoint. If <bpnum> is specified, only the requested "
"breakpoint is disabled; otherwise all breakpoints are disabled. Note that disabling a "
"The bpdisable command disables breakpoints. If <bpnum> is specified, only the requested "
"breakpoints are disabled; otherwise all breakpoints are disabled. Note that disabling a "
"breakpoint does not delete it, it just temporarily marks the breakpoint as inactive.\n"
"\n"
"Examples:\n"
@ -1239,10 +1239,10 @@ const help_item f_static_help_list[] =
{
"bpenable",
"\n"
" bpenable [<bpnum>]\n"
" bpenable [<bpnum>,[...]]\n"
"\n"
"The bpenable command enables a breakpoint. If <bpnum> is specified, only the requested "
"breakpoint is enabled; otherwise all breakpoints are enabled.\n"
"The bpenable command enable breakpoints. If <bpnum> is specified, only the requested "
"breakpoints enabled; otherwise all breakpoints are enabled.\n"
"\n"
"Examples:\n"
"\n"
@ -1331,10 +1331,10 @@ const help_item f_static_help_list[] =
{
"wpclear",
"\n"
" wpclear [<wpnum>]\n"
" wpclear [<wpnum>[,...]]\n"
"\n"
"The wpclear command clears a watchpoint. If <wpnum> is specified, only the requested "
"watchpoint is cleared; otherwise all watchpoints are cleared.\n"
"The wpclear command clears watchpoints. If <wpnum> is specified, only the requested "
"watchpoints are cleared; otherwise all watchpoints are cleared.\n"
"\n"
"Examples:\n"
"\n"
@ -1347,10 +1347,10 @@ const help_item f_static_help_list[] =
{
"wpdisable",
"\n"
" wpdisable [<wpnum>]\n"
" wpdisable [<wpnum>[,...]]\n"
"\n"
"The wpdisable command disables a watchpoint. If <wpnum> is specified, only the requested "
"watchpoint is disabled; otherwise all watchpoints are disabled. Note that disabling a "
"The wpdisable command disables watchpoints. If <wpnum> is specified, only the requested "
"watchpoints are disabled; otherwise all watchpoints are disabled. Note that disabling a "
"watchpoint does not delete it, it just temporarily marks the watchpoint as inactive.\n"
"\n"
"Examples:\n"
@ -1364,10 +1364,10 @@ const help_item f_static_help_list[] =
{
"wpenable",
"\n"
" wpenable [<wpnum>]\n"
" wpenable [<wpnum>[,...]]\n"
"\n"
"The wpenable command enables a watchpoint. If <wpnum> is specified, only the requested "
"watchpoint is enabled; otherwise all watchpoints are enabled.\n"
"The wpenable command enables watchpoints. If <wpnum> is specified, only the requested "
"watchpoints are enabled; otherwise all watchpoints are enabled.\n"
"\n"
"Examples:\n"
"\n"
@ -1401,26 +1401,26 @@ const help_item f_static_help_list[] =
{
"rpset",
"\n"
" rp[set] {<condition>}[,<action>]]\n"
" rp[set] <condition>[,<action>]\n"
"\n"
"Sets a new registerpoint which will be triggered when <condition> is met. The condition must "
"be specified between curly braces to prevent the condition from being evaluated as an "
"assignment.\n"
"Sets a new registerpoint which will be triggered when <condition> is true (evaluates to a "
"non-zero value). The condition must be embedded in braces { } to prevent it from being "
"interpreted as an assignment.\n"
"\n"
"The optional <action> parameter provides a command that is executed whenever the registerpoint "
"is hit. Note that you may need to embed the action within braces { } in "
"order to prevent commas and semicolons from being interpreted as applying to the rpset command "
"itself. Each registerpoint that is set is assigned an index which can be used in other "
"registerpoint commands to reference this registerpoint.\n"
"The optional <action> parameter provides a command that is executed whenever the "
"registerpoint is hit. Note that you may need to embed the action within braces { } in "
"order to prevent commas and semicolons from being interpreted as applying to the rpset "
"command itself. Each registerpoint that is set is assigned an index which can be used in "
"other registerpoint commands to reference this registerpoint.\n"
"\n"
"Examples:\n"
"\n"
"rp {PC==0150}\n"
" Set a registerpoint that will halt execution whenever the PC register equals 0x150.\n"
"rp {PC==150}\n"
" Set a registerpoint that will halt execution whenever the PC register equals 150.\n"
"\n"
"temp0=0; rp {PC==0150},{temp0++; g}\n"
"temp0=0; rp {PC==150},{temp0++; g}\n"
" Set a registerpoint that will increment the variable temp0 whenever the PC register "
"equals 0x0150.\n"
"equals 150.\n"
"\n"
"rp {temp0==5}\n"
" Set a registerpoint that will halt execution whenever the temp0 variable equals 5.\n"
@ -1428,15 +1428,15 @@ const help_item f_static_help_list[] =
{
"rpclear",
"\n"
" rpclear [<rpnum>]\n"
" rpclear [<rpnum>[,...]]\n"
"\n"
"The rpclear command clears a registerpoint. If <rpnum> is specified, only the requested "
"registerpoint is cleared, otherwise all registerpoints are cleared.\n"
"The rpclear command clears registerpoints. If <rpnum> is specified, only the requested "
"registerpoints are cleared, otherwise all registerpoints are cleared.\n"
"\n"
"Examples:\n"
"\n"
"rpclear 3\n"
" Clear registerpoint index 3.\n"
" Clear the registerpoint with index 3.\n"
"\n"
"rpclear\n"
" Clear all registerpoints.\n"
@ -1444,16 +1444,17 @@ const help_item f_static_help_list[] =
{
"rpdisable",
"\n"
" rpdisable [<rpnum>]\n"
" rpdisable [<rpnum>[,...]]\n"
"\n"
"The rpdisable command disables a registerpoint. If <rpnum> is specified, only the requested "
"registerpoint is disabled, otherwise all registerpoints are disabled. Note that disabling a "
"registerpoint does not delete it, it just temporarily marks the registerpoint as inactive.\n"
"The rpdisable command disables registerpoints. If <rpnum> is specified, only the "
"requested registerpoints are disabled, otherwise all registerpoints are disabled. Note "
"that disabling a registerpoint does not delete it, it just temporarily marks the "
"registerpoint as inactive.\n"
"\n"
"Examples:\n"
"\n"
"rpdisable 3\n"
" Disable registerpoint index 3.\n"
" Disable the registerpoint with index 3.\n"
"\n"
"rpdisable\n"
" Disable all registerpoints.\n"
@ -1461,15 +1462,15 @@ const help_item f_static_help_list[] =
{
"rpenable",
"\n"
" rpenable [<rpnum>]\n"
" rpenable [<rpnum>[,...]]\n"
"\n"
"The rpenable command enables a registerpoint. If <rpnum> is specified, only the requested "
"registerpoint is enabled, otherwise all registerpoints are enabled.\n"
"The rpenable command enables registerpoints. If <rpnum> is specified, only the requested "
"registerpoints are enabled, otherwise all registerpoints are enabled.\n"
"\n"
"Examples:\n"
"\n"
"rpenable 3\n"
" Enable registerpoint index 3.\n"
" Enable the registerpoint with index 3.\n"
"\n"
"rpenable\n"
" Enable all registerpoints.\n"

View File

@ -9,16 +9,20 @@
***************************************************************************/
#include "emu.h"
#include "express.h"
#include "debugvw.h"
#include "dvtext.h"
#include "dvstate.h"
#include "debugcpu.h"
#include "dvbpoints.h"
#include "dvdisasm.h"
#include "dvmemory.h"
#include "dvbpoints.h"
#include "dvrpoints.h"
#include "dvstate.h"
#include "dvtext.h"
#include "dvwpoints.h"
#include "debugcpu.h"
#include "express.h"
#include "debugger.h"
#include <cctype>
@ -362,6 +366,9 @@ debug_view *debug_view_manager::alloc_view(debug_view_type type, debug_view_osd_
case DVT_WATCH_POINTS:
return append(new debug_view_watchpoints(machine(), osdupdate, osdprivate));
case DVT_REGISTER_POINTS:
return append(new debug_view_registerpoints(machine(), osdupdate, osdprivate));
default:
fatalerror("Attempt to create invalid debug view type %d\n", type);
}

View File

@ -34,7 +34,8 @@ enum debug_view_type
DVT_MEMORY,
DVT_LOG,
DVT_BREAK_POINTS,
DVT_WATCH_POINTS
DVT_WATCH_POINTS,
DVT_REGISTER_POINTS
};

View File

@ -1,5 +1,5 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
// copyright-holders:Andrew Gardner, Vas Crabb
/*********************************************************************
dvbpoints.cpp

View File

@ -1,5 +1,5 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
// copyright-holders:Andrew Gardner, Vas Crabb
/*********************************************************************
dvbpoints.h
@ -7,19 +7,15 @@
Breakpoint debugger view.
***************************************************************************/
#ifndef MAME_EMU_DEBUG_DVBPOINTS_H
#define MAME_EMU_DEBUG_DVBPOINTS_H
#pragma once
#include "debugvw.h"
#include "debugcpu.h"
#include "debugvw.h"
//**************************************************************************
// CONSTANTS
//**************************************************************************
#include <vector>
//**************************************************************************
@ -46,7 +42,6 @@ private:
void pad_ostream_to_length(std::ostream& str, int len);
void gather_breakpoints();
// internal state
bool (*m_sortType)(const debug_breakpoint *, const debug_breakpoint *);
std::vector<const debug_breakpoint *> m_buffer;

298
src/emu/debug/dvrpoints.cpp Normal file
View File

@ -0,0 +1,298 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/*********************************************************************
dvrpoints.cpp
Registerpoint debugger view.
***************************************************************************/
#include "emu.h"
#include "dvrpoints.h"
#include "debugger.h"
#include "points.h"
#include <algorithm>
#include <iomanip>
namespace {
bool cIndexAscending(std::pair<device_t *, debug_registerpoint const *> const &a, std::pair<device_t *, debug_registerpoint const *> const &b)
{
return a.second->index() < b.second->index();
}
bool cIndexDescending(std::pair<device_t *, debug_registerpoint const *> const &a, std::pair<device_t *, debug_registerpoint const *> const &b)
{
return a.second->index() > b.second->index();
}
bool cEnabledAscending(std::pair<device_t *, debug_registerpoint const *> const &a, std::pair<device_t *, debug_registerpoint const *> const &b)
{
return !a.second->enabled() && b.second->enabled();
}
bool cEnabledDescending(std::pair<device_t *, debug_registerpoint const *> const &a, std::pair<device_t *, debug_registerpoint const *> const &b)
{
return cEnabledAscending(b, a);
}
bool cCpuAscending(std::pair<device_t *, debug_registerpoint const *> const &a, std::pair<device_t *, debug_registerpoint const *> const &b)
{
return strcmp(a.first->tag(), b.first->tag()) < 0;
}
bool cCpuDescending(std::pair<device_t *, debug_registerpoint const *> const &a, std::pair<device_t *, debug_registerpoint const *> const &b)
{
return cCpuAscending(b, a);
}
bool cConditionAscending(std::pair<device_t *, debug_registerpoint const *> const &a, std::pair<device_t *, debug_registerpoint const *> const &b)
{
return strcmp(a.second->condition(), b.second->condition()) < 0;
}
bool cConditionDescending(std::pair<device_t *, debug_registerpoint const *> const &a, std::pair<device_t *, debug_registerpoint const *> const &b)
{
return cConditionAscending(b, a);
}
bool cActionAscending(std::pair<device_t *, debug_registerpoint const *> const &a, std::pair<device_t *, debug_registerpoint const *> const &b)
{
return strcmp(a.second->action(), b.second->action()) < 0;
}
bool cActionDescending(std::pair<device_t *, debug_registerpoint const *> const &a, std::pair<device_t *, debug_registerpoint const *> const &b)
{
return cActionAscending(b, a);
}
constexpr int TABLE_BREAKS[] = { 5, 9, 31, 49, 66 };
} // anonymous namespace
//**************************************************************************
// DEBUG VIEW REGISTER POINTS
//**************************************************************************
//-------------------------------------------------
// debug_view_registerpoints - constructor
//-------------------------------------------------
debug_view_registerpoints::debug_view_registerpoints(running_machine &machine, debug_view_osd_update_func osdupdate, void *osdprivate)
: debug_view(machine, DVT_REGISTER_POINTS, osdupdate, osdprivate)
, m_sort_type(cIndexAscending)
{
// fail if no available sources
enumerate_sources();
if (m_source_list.empty())
throw std::bad_alloc();
}
//-------------------------------------------------
// ~debug_view_registerpoints - destructor
//-------------------------------------------------
debug_view_registerpoints::~debug_view_registerpoints()
{
}
//-------------------------------------------------
// enumerate_sources - enumerate all possible
// sources for a disassembly view
//-------------------------------------------------
void debug_view_registerpoints::enumerate_sources()
{
// start with an empty list
m_source_list.clear();
// iterate over devices with disassembly interfaces
for (device_disasm_interface &dasm : disasm_interface_enumerator(machine().root_device()))
{
m_source_list.emplace_back(
std::make_unique<debug_view_source>(
util::string_format("%s '%s'", dasm.device().name(), dasm.device().tag()),
&dasm.device()));
}
// reset the source to a known good entry
if (!m_source_list.empty())
set_source(*m_source_list[0]);
}
//-------------------------------------------------
// view_click - handle a mouse click within the
// current view
//-------------------------------------------------
void debug_view_registerpoints::view_click(const int button, const debug_view_xy& pos)
{
bool clickedTopRow = (m_topleft.y == pos.y);
if (clickedTopRow)
{
if (pos.x < TABLE_BREAKS[0])
m_sort_type = (m_sort_type == &cIndexAscending) ? &cIndexDescending : &cIndexAscending;
else if (pos.x < TABLE_BREAKS[1])
m_sort_type = (m_sort_type == &cEnabledAscending) ? &cEnabledDescending : &cEnabledAscending;
else if (pos.x < TABLE_BREAKS[2])
m_sort_type = (m_sort_type == &cCpuAscending) ? &cCpuDescending : &cCpuAscending;
else if (pos.x < TABLE_BREAKS[3])
m_sort_type = (m_sort_type == &cConditionAscending) ? &cConditionDescending : &cConditionAscending;
else if (pos.x < TABLE_BREAKS[4])
m_sort_type = (m_sort_type == &cActionAscending) ? &cActionDescending : &cActionAscending;
}
else
{
// Gather a sorted list of all the breakpoints for all the CPUs
gather_registerpoints();
int rpIndex = pos.y - 1;
if ((rpIndex >= m_buffer.size()) || (rpIndex < 0))
return;
// Enable / disable
m_buffer[rpIndex].first->debug()->registerpoint_enable(
m_buffer[rpIndex].second->index(),
!m_buffer[rpIndex].second->enabled());
}
begin_update();
m_update_pending = true;
end_update();
}
void debug_view_registerpoints::pad_ostream_to_length(std::ostream& str, int len)
{
auto const current = str.tellp();
if (current < decltype(current)(len))
str << std::setw(decltype(current)(len) - current) << "";
}
void debug_view_registerpoints::gather_registerpoints()
{
m_buffer.resize(0);
for (auto &source : m_source_list)
{
// Collect
device_debug &debugInterface = *source->device()->debug();
for (const auto &rp : debugInterface.registerpoint_list())
m_buffer.emplace_back(source->device(), &rp);
}
// And now for the sort
if (!m_buffer.empty())
std::stable_sort(m_buffer.begin(), m_buffer.end(), m_sort_type);
}
//-------------------------------------------------
// view_update - update the contents of the
// registerpoints view
//-------------------------------------------------
void debug_view_registerpoints::view_update()
{
// Gather a list of all the registerpoints for all the CPUs
gather_registerpoints();
// Set the view region so the scroll bars update
m_total.x = TABLE_BREAKS[std::size(TABLE_BREAKS) - 1];
m_total.y = m_buffer.size() + 1;
if (m_total.y < 10)
m_total.y = 10;
// Draw
debug_view_char *dest = &m_viewdata[0];
util::ovectorstream linebuf;
linebuf.reserve(std::size(TABLE_BREAKS) - 1);
// Header
if (m_visible.y > 0)
{
linebuf.clear();
linebuf.rdbuf()->clear();
linebuf << "ID";
if (m_sort_type == &cIndexAscending) linebuf.put('\\');
else if (m_sort_type == &cIndexDescending) linebuf.put('/');
pad_ostream_to_length(linebuf, TABLE_BREAKS[0]);
linebuf << "En";
if (m_sort_type == &cEnabledAscending) linebuf.put('\\');
else if (m_sort_type == &cEnabledDescending) linebuf.put('/');
pad_ostream_to_length(linebuf, TABLE_BREAKS[1]);
linebuf << "CPU";
if (m_sort_type == &cCpuAscending) linebuf.put('\\');
else if (m_sort_type == &cCpuDescending) linebuf.put('/');
pad_ostream_to_length(linebuf, TABLE_BREAKS[2]);
linebuf << "Condition";
if (m_sort_type == &cConditionAscending) linebuf.put('\\');
else if (m_sort_type == &cConditionDescending) linebuf.put('/');
pad_ostream_to_length(linebuf, TABLE_BREAKS[3]);
linebuf << "Action";
if (m_sort_type == &cActionAscending) linebuf.put('\\');
else if (m_sort_type == &cActionDescending) linebuf.put('/');
pad_ostream_to_length(linebuf, TABLE_BREAKS[4]);
auto const &text(linebuf.vec());
for (u32 i = m_topleft.x; i < (m_topleft.x + m_visible.x); i++, dest++)
{
dest->byte = (i < text.size()) ? text[i] : ' ';
dest->attrib = DCA_ANCILLARY;
}
}
for (int row = 1; row < m_visible.y; row++)
{
// Breakpoints
int rpi = row + m_topleft.y - 1;
if ((rpi < m_buffer.size()) && (rpi >= 0))
{
point_pair const &rpp = m_buffer[rpi];
linebuf.clear();
linebuf.rdbuf()->clear();
util::stream_format(linebuf, "%2X", rpp.second->index());
pad_ostream_to_length(linebuf, TABLE_BREAKS[0]);
linebuf.put(rpp.second->enabled() ? 'X' : 'O');
pad_ostream_to_length(linebuf, TABLE_BREAKS[1]);
linebuf << rpp.first->tag();
pad_ostream_to_length(linebuf, TABLE_BREAKS[2]);
linebuf << rpp.second->condition();
pad_ostream_to_length(linebuf, TABLE_BREAKS[3]);
linebuf << rpp.second->action();
pad_ostream_to_length(linebuf, TABLE_BREAKS[4]);
auto const &text(linebuf.vec());
for (u32 i = m_topleft.x; i < (m_topleft.x + m_visible.x); i++, dest++)
{
dest->byte = (i < text.size()) ? text[i] : ' ';
dest->attrib = DCA_NORMAL;
// Color disabled breakpoints red
if ((i >= TABLE_BREAKS[0]) && (i < TABLE_BREAKS[1]) && !rpp.second->enabled())
dest->attrib |= DCA_CHANGED;
}
}
else
{
// Fill the remaining vertical space
for (u32 i = m_topleft.x; i < (m_topleft.x + m_visible.x); i++, dest++)
{
dest->byte = ' ';
dest->attrib = DCA_NORMAL;
}
}
}
}

53
src/emu/debug/dvrpoints.h Normal file
View File

@ -0,0 +1,53 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/*********************************************************************
dvrpoints.h
Registerpoint debugger view.
***************************************************************************/
#ifndef MAME_EMU_DEBUG_DVRPOINTS_H
#define MAME_EMU_DEBUG_DVRPOINTS_H
#pragma once
#include "debugcpu.h"
#include "debugvw.h"
#include <utility>
#include <vector>
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// debug view for breakpoints
class debug_view_registerpoints : public debug_view
{
friend class debug_view_manager;
// construction/destruction
debug_view_registerpoints(running_machine &machine, debug_view_osd_update_func osdupdate, void *osdprivate);
virtual ~debug_view_registerpoints();
protected:
// view overrides
virtual void view_update() override;
virtual void view_click(int button, debug_view_xy const &pos) override;
private:
using point_pair = std::pair<device_t *, debug_registerpoint const *>;
// internal helpers
void enumerate_sources();
void pad_ostream_to_length(std::ostream& str, int len);
void gather_registerpoints();
// internal state
bool (*m_sort_type)(point_pair const &, point_pair const &);
std::vector<point_pair> m_buffer;
};
#endif // MAME_EMU_DEBUG_DVBPOINTS_H

View File

@ -1,5 +1,5 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
// copyright-holders:Andrew Gardner, Vas Crabb
/*********************************************************************
dvwpoints.cpp
@ -10,6 +10,7 @@
#include "emu.h"
#include "dvwpoints.h"
#include "points.h"
#include <algorithm>

View File

@ -1,5 +1,5 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
// copyright-holders:Andrew Gardner, Vas Crabb
/*********************************************************************
dvwpoints.h
@ -7,14 +7,13 @@
Watchpoint debugger view.
***************************************************************************/
#ifndef MAME_EMU_DEBUG_DVWPOINTS_H
#define MAME_EMU_DEBUG_DVWPOINTS_H
#pragma once
#include "debugvw.h"
#include "debugcpu.h"
#include "debugvw.h"
//**************************************************************************

View File

@ -838,7 +838,7 @@ namespace {
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PAGE_DOWN, N_p("input-name", "UI Page Down"), input_seq(KEYCODE_PGDN) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FOCUS_NEXT, N_p("input-name", "UI Focus Next"), input_seq(KEYCODE_TAB, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FOCUS_PREV, N_p("input-name", "UI Focus Previous"), input_seq(KEYCODE_TAB, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_TAB, KEYCODE_RSHIFT) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SELECT, N_p("input-name", "UI Select"), input_seq(KEYCODE_ENTER, input_seq::or_code, JOYCODE_BUTTON1_INDEXED(0), input_seq::or_code, KEYCODE_ENTER_PAD) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SELECT, N_p("input-name", "UI Select"), input_seq(KEYCODE_ENTER, input_seq::not_code, KEYCODE_LALT, input_seq::not_code, KEYCODE_RALT, input_seq::or_code, JOYCODE_BUTTON1_INDEXED(0), input_seq::or_code, KEYCODE_ENTER_PAD) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_CANCEL, N_p("input-name", "UI Cancel"), input_seq(KEYCODE_ESC) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_DISPLAY_COMMENT, N_p("input-name", "UI Display Comment"), input_seq(KEYCODE_SPACE) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_CLEAR, N_p("input-name", "UI Clear"), input_seq(KEYCODE_DEL) ) \

View File

@ -92,5 +92,6 @@ private:
extern const char build_version[];
extern const char bare_build_version[];
extern const char bare_vcs_revision[];
#endif // MAME_FRONTEND_MAME_MAME_H

View File

@ -1,21 +1,23 @@
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
// copyright-holders:Vas Crabb
/***************************************************************************
ui/about.cpp
"About" modal
About box
***************************************************************************/
#include "emu.h"
#include "ui/about.h"
#include "ui/ui.h"
#include "ui/utils.h"
#include "mame.h"
#include "osdcore.h"
#include <string_view>
namespace ui {
@ -25,10 +27,9 @@ namespace {
} // anonymous namespace
/**************************************************
ABOUT MODAL
ABOUT BOX
**************************************************/
@ -38,6 +39,8 @@ namespace {
menu_about::menu_about(mame_ui_manager &mui, render_container &container)
: menu(mui, container)
, m_title(util::string_format(_("%1$s %2$s"), emulator_info::get_appname(), bare_build_version))
, m_footer(util::string_format(_("Revision: %1$s"), bare_vcs_revision))
{
}
@ -51,20 +54,175 @@ menu_about::~menu_about()
}
//-------------------------------------------------
// perform our special rendering
//-------------------------------------------------
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
tempbuf[0] = m_title;
draw_text_box(
std::begin(tempbuf), std::end(tempbuf),
origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(),
text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false,
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);
}
//-------------------------------------------------
// draw - draw about
//-------------------------------------------------
void menu_about::draw(uint32_t flags)
{
rgb_t const color = ui().colors().text_color();
float const aspect = machine().render().ui_aspect(&container());
float const line_height = ui().get_line_height();
float const ud_arrow_width = line_height * aspect;
float const gutter_width = 0.52f * line_height * aspect;
float const visible_width = 1.0f - (2.0f * ui().box_lr_border() * aspect);
float const visible_left = (1.0f - visible_width) * 0.5f;
float const extra_height = 2.0f * line_height;
float const visible_extra_menu_height = get_customtop() + get_custombottom() + extra_height;
// determine effective positions taking into account the hilighting arrows
float const maximum_width = visible_width - 2.0f * gutter_width;
draw_background();
map_mouse();
// account for extra space at the top and bottom
float visible_main_menu_height = 1.0f - 2.0f * ui().box_tb_border() - visible_extra_menu_height;
m_visible_lines = int(std::trunc(visible_main_menu_height / line_height));
visible_main_menu_height = float(m_visible_lines) * line_height;
// compute top/left of inner menu area by centering, if the menu is at the bottom of the extra, adjust
float const visible_top = ((1.0f - (visible_main_menu_height + visible_extra_menu_height)) * 0.5f) + get_customtop();
// lay out the text if necessary
if (!m_layout || (m_layout->width() != maximum_width))
{
m_layout.emplace(ui().create_layout(container(), maximum_width));
for (char const *const *line = copying_text; *line; ++line)
{
m_layout->add_text(*line, color);
m_layout->add_text("\n", color);
}
}
float const actual_width = m_layout->actual_width();
// compute text box size
float const x1 = visible_left + ((maximum_width - actual_width) * 0.5f);
float const y1 = visible_top - ui().box_tb_border();
float const x2 = visible_left + visible_width - ((maximum_width - actual_width) * 0.5f);
float const y2 = visible_top + visible_main_menu_height + ui().box_tb_border() + extra_height;
float const effective_left = x1 + gutter_width;
float const line_x0 = x1 + 0.5f * UI_LINE_WIDTH;
float const line_x1 = x2 - 0.5f * UI_LINE_WIDTH;
float const separator = visible_top + float(m_visible_lines) * line_height;
ui().draw_outlined_box(container(), x1, y1, x2, y2, ui().colors().background_color());
int const visible_items = m_layout->lines();
m_visible_lines = (std::min)(visible_items, m_visible_lines);
top_line = (std::max)(0, top_line);
if (top_line + m_visible_lines >= visible_items)
top_line = visible_items - m_visible_lines;
clear_hover();
if (top_line)
{
// if we're on the top line, display the up arrow
rgb_t fgcolor = ui().colors().text_color();
if (mouse_in_rect(line_x0, visible_top, line_x1, visible_top + line_height))
{
fgcolor = ui().colors().mouseover_color();
highlight(
line_x0, visible_top,
line_x1, visible_top + line_height,
ui().colors().mouseover_bg_color());
set_hover(HOVER_ARROW_UP);
}
draw_arrow(
0.5f * (x1 + x2) - 0.5f * ud_arrow_width, visible_top + 0.25f * line_height,
0.5f * (x1 + x2) + 0.5f * ud_arrow_width, visible_top + 0.75f * line_height,
fgcolor, ROT0);
}
if ((top_line + m_visible_lines) < visible_items)
{
// if we're on the bottom line, display the down arrow
float const line_y = visible_top + float(m_visible_lines - 1) * line_height;
rgb_t fgcolor = ui().colors().text_color();
if (mouse_in_rect(line_x0, line_y, line_x1, line_y + line_height))
{
fgcolor = ui().colors().mouseover_color();
highlight(
line_x0, line_y,
line_x1, line_y + line_height,
ui().colors().mouseover_bg_color());
set_hover(HOVER_ARROW_DOWN);
}
draw_arrow(
0.5f * (x1 + x2) - 0.5f * ud_arrow_width, line_y + 0.25f * line_height,
0.5f * (x1 + x2) + 0.5f * ud_arrow_width, line_y + 0.75f * line_height,
fgcolor, ROT0 ^ ORIENTATION_FLIP_Y);
}
// return the number of visible lines, minus 1 for top arrow and 1 for bottom arrow
m_visible_items = m_visible_lines - (top_line ? 1 : 0) - (top_line + m_visible_lines != visible_items);
m_layout->emit(
container(),
top_line ? (top_line + 1) : 0, m_visible_items,
effective_left, visible_top + (top_line ? line_height : 0.0f));
// add visual separator before the "return to prevous menu" item
container().add_line(
x1, separator + (0.5f * line_height),
x2, separator + (0.5f * line_height),
UI_LINE_WIDTH, ui().colors().text_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
menu_item const &pitem = item(0);
std::string_view const itemtext = pitem.text;
float const line_y0 = separator + line_height;
float const line_y1 = line_y0 + line_height;
if (mouse_in_rect(line_x0, line_y0, line_x1, line_y1) && is_selectable(pitem))
set_hover(0);
highlight(line_x0, line_y0, line_x1, line_y1, ui().colors().selected_bg_color());
ui().draw_text_full(
container(), itemtext,
effective_left, line_y0, actual_width,
text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE,
mame_ui_manager::NORMAL,
ui().colors().selected_color(), ui().colors().selected_bg_color(),
nullptr, nullptr);
// if there is something special to add, do it by calling the virtual method
custom_render(get_selection_ref(), get_customtop(), get_custombottom(), x1, y1, x2, y2);
}
//-------------------------------------------------
// populate - populates the about modal
//-------------------------------------------------
void menu_about::populate(float &customtop, float &custombottom)
{
std::string title = string_format(_("%1$s %2$s"), emulator_info::get_appname(), bare_build_version);
item_append(title, 0, nullptr);
item_append(menu_item_type::SEPARATOR);
for (char const *const *line = copying_text; *line; ++line)
item_append(*line, 0, nullptr);
item_append(menu_item_type::SEPARATOR);
// make space for the title and revision
customtop = ui().get_line_height() + 3.0f * ui().box_tb_border();
custombottom = ui().get_line_height() + 3.0f * ui().box_tb_border();
}
@ -74,13 +232,35 @@ void menu_about::populate(float &customtop, float &custombottom)
void menu_about::handle()
{
// process the menu
const event *event = process(0);
// process the event
if (event && (event->iptkey == IPT_UI_SELECT))
const event *event = process(PROCESS_CUSTOM_NAV);
if (event)
{
stack_pop();
switch (event->iptkey)
{
case IPT_UI_UP:
--top_line;
break;
case IPT_UI_DOWN:
++top_line;
break;
case IPT_UI_PAGE_UP:
top_line -= m_visible_lines - 3;
break;
case IPT_UI_PAGE_DOWN:
top_line += m_visible_lines - 3;
break;
case IPT_UI_HOME:
top_line = 0;
break;
case IPT_UI_END:
top_line = m_layout->lines() - m_visible_lines;
break;
}
}
}

View File

@ -1,10 +1,10 @@
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
// copyright-holders:Vas Crabb
/***************************************************************************
ui/about.h
"About" modal
About box
***************************************************************************/
#ifndef MAME_FRONTEND_UI_ABOUT_H
@ -14,7 +14,9 @@
#include "ui/menu.h"
#include <vector>
#include <optional>
#include <string>
namespace ui {
@ -24,9 +26,17 @@ public:
menu_about(mame_ui_manager &mui, render_container &container);
virtual ~menu_about() override;
protected:
virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override;
private:
virtual void draw(uint32_t flags) override;
virtual void populate(float &customtop, float &custombottom) override;
virtual void handle() override;
std::string const m_title;
std::string const m_footer;
std::optional<text_layout> m_layout;
};
} // namespace ui

View File

@ -1,5 +1,5 @@
// license:BSD-3-Clause
// copyright-holders:Maurizio Petrarota
// copyright-holders:Maurizio Petrarota, Vas Crabb
/*********************************************************************
ui/datmenu.cpp
@ -140,7 +140,7 @@ void menu_dats_view::add_info_text(text_layout &layout, std::string_view text, r
if (std::string_view::npos != split)
{
layout.add_text(line.substr(0, split), text_layout::text_justify::LEFT, color, rgb_t::transparent(), size);
layout.add_text(" ", text_layout::text_layout::text_justify::LEFT, color, rgb_t::transparent(), size);
layout.add_text(" ", text_layout::text_justify::LEFT, color, rgb_t::transparent(), size);
layout.add_text(line.substr(split + 1), text_layout::text_justify::RIGHT, color, rgb_t::transparent(), size);
}
else
@ -278,10 +278,13 @@ void menu_dats_view::draw(uint32_t flags)
if (!m_layout || (m_layout->width() != effective_width))
{
std::string buffer;
if (m_issoft)
get_data_sw(buffer);
else
get_data(buffer);
if (!m_items_list.empty())
{
if (m_issoft)
get_data_sw(buffer);
else
get_data(buffer);
}
m_layout.emplace(ui().create_layout(container(), effective_width));
add_info_text(*m_layout, buffer, ui().colors().text_color());
}
@ -339,8 +342,8 @@ void menu_dats_view::draw(uint32_t flags)
// add visual separator before the "return to prevous menu" item
container().add_line(
visible_left, separator + (0.5f * line_height),
visible_left + visible_width, separator + (0.5f * line_height),
x1, separator + (0.5f * line_height),
x2, separator + (0.5f * line_height),
UI_LINE_WIDTH, ui().colors().text_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
menu_item const &pitem = item(0);
@ -471,38 +474,41 @@ void menu_dats_view::custom_render(void *selectedref, float top, float bottom, f
}
// bottom
std::string const revision(util::string_format(_("Revision: %1$s"), m_items_list[m_actual].revision));
ui().draw_text_full(
container(),
revision,
0.0f, 0.0f, 1.0f,
text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE,
mame_ui_manager::NONE, rgb_t::white(), rgb_t::black(),
&width, nullptr);
width += 2 * lr_border;
maxwidth = std::max(origx2 - origx1, width);
if (!m_items_list.empty())
{
std::string const revision(util::string_format(_("Revision: %1$s"), m_items_list[m_actual].revision));
ui().draw_text_full(
container(),
revision,
0.0f, 0.0f, 1.0f,
text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE,
mame_ui_manager::NONE, rgb_t::white(), rgb_t::black(),
&width, nullptr);
width += 2 * lr_border;
maxwidth = std::max(origx2 - origx1, width);
// compute our bounds
x1 = 0.5f - 0.5f * maxwidth;
x2 = x1 + maxwidth;
y1 = origy2 + ui().box_tb_border();
y2 = origy2 + bottom;
// compute our bounds
x1 = 0.5f - 0.5f * maxwidth;
x2 = x1 + maxwidth;
y1 = origy2 + ui().box_tb_border();
y2 = origy2 + bottom;
// draw a box
ui().draw_outlined_box(container(), x1, y1, x2, y2, UI_GREEN_COLOR);
// draw a box
ui().draw_outlined_box(container(), x1, y1, x2, y2, UI_GREEN_COLOR);
// take off the borders
x1 += lr_border;
x2 -= lr_border;
y1 += ui().box_tb_border();
// take off the borders
x1 += lr_border;
x2 -= lr_border;
y1 += ui().box_tb_border();
// draw the text within it
ui().draw_text_full(
container(),
revision,
x1, y1, x2 - x1,
text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE,
mame_ui_manager::NORMAL, ui().colors().text_color(), ui().colors().text_bg_color());
// draw the text within it
ui().draw_text_full(
container(),
revision,
x1, y1, x2 - x1,
text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE,
mame_ui_manager::NORMAL, ui().colors().text_color(), ui().colors().text_bg_color());
}
}
//-------------------------------------------------

View File

@ -1,5 +1,5 @@
// license:BSD-3-Clause
// copyright-holders:Maurizio Petrarota
// copyright-holders:Maurizio Petrarota, Vas Crabb
/***************************************************************************
ui/datmenu.h
@ -76,4 +76,4 @@ private:
} // namespace ui
#endif /* MAME_FRONTEND_UI_DATMENU_H */
#endif // MAME_FRONTEND_UI_DATMENU_H

View File

@ -855,18 +855,10 @@ void menu_select_launch::inkey_dats()
ui_software_info const *software;
ui_system_info const *system;
get_selection(software, system);
if (software)
{
if (software->startempty && mame_machine_manager::instance()->lua()->call_plugin_check<const char *>("data_list", software->driver->name, true))
menu::stack_push<menu_dats_view>(ui(), container(), system);
else if (mame_machine_manager::instance()->lua()->call_plugin_check<const char *>("data_list", std::string(software->shortname).append(1, ',').append(software->listname).c_str()) || !software->infotext.empty())
menu::stack_push<menu_dats_view>(ui(), container(), software);
}
if (software && !software->startempty)
menu::stack_push<menu_dats_view>(ui(), container(), software);
else if (system)
{
if (mame_machine_manager::instance()->lua()->call_plugin_check<const char *>("data_list", system->driver->name, true))
menu::stack_push<menu_dats_view>(ui(), container(), system);
}
menu::stack_push<menu_dats_view>(ui(), container(), system);
}
@ -1299,23 +1291,28 @@ void menu_select_launch::draw_toolbar(float x1, float y1, float x2, float y2)
x1 = (std::min)(backtrack_pos - (float(toolbar_count) * x_spacing), x1 + ((x2 - x1 - total_width) * 0.5f));
for (int z = 0; toolbar_count > z; ++z, x1 += x_spacing)
{
auto const bitmap = toolbar_bitmaps[z];
x2 = x1 + x_size;
color = rgb_t (0xffcccccc);
if (mouse_in_rect(x1, y1, x2, y2))
{
set_hover(HOVER_B_FAV + toolbar_bitmaps[z]);
color = rgb_t::white();
bool const need_selection = (TOOLBAR_BITMAP_FAVORITE == bitmap) || (TOOLBAR_BITMAP_INFO == bitmap);
if (!need_selection || get_selection_ptr())
{
set_hover(HOVER_B_FAV + bitmap);
color = rgb_t::white();
}
float ypos = y2 + ui().get_line_height() + 2.0f * ui().box_tb_border();
ui().draw_text_box(
container(),
_(hover_msg[toolbar_bitmaps[z]]),
_(hover_msg[bitmap]),
text_layout::text_justify::CENTER, (x1 + x2) * 0.5f, ypos,
ui().colors().background_color());
}
container().add_quad(
x1, y1, x2, y2,
color,
m_cache.toolbar_textures()[toolbar_bitmaps[z]].get(),
m_cache.toolbar_textures()[bitmap].get(),
PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
}
}

View File

@ -1,5 +1,5 @@
// copyright-holders:R. Belmont
// license:BSD-3-Clause
// copyright-holders:R. Belmont
/***************************************************************************
apple2e.cpp - Apple IIe/IIc/IIc Plus and clones

View File

@ -10,6 +10,7 @@
#import "pointsviewer.h"
#import "breakpointsview.h"
#import "registerpointsview.h"
#import "watchpointsview.h"
#include "util/xmlfile.h"
@ -18,9 +19,9 @@
@implementation MAMEPointsViewer
- (id)initWithMachine:(running_machine &)m console:(MAMEDebugConsole *)c {
MAMEDebugView *breakView, *watchView;
NSScrollView *breakScroll, *watchScroll;
NSTabViewItem *breakTab, *watchTab;
MAMEDebugView *breakView, *watchView, *registerView;
NSScrollView *breakScroll, *watchScroll, *registerScroll;
NSTabViewItem *breakTab, *watchTab, *registerTab;
NSPopUpButton *actionButton;
NSRect subviewFrame;
@ -44,6 +45,9 @@
[[[subviewButton menu] addItemWithTitle:@"All Watchpoints"
action:NULL
keyEquivalent:@""] setTag:1];
[[[subviewButton menu] addItemWithTitle:@"All Registerpoints"
action:NULL
keyEquivalent:@""] setTag:2];
[subviewButton sizeToFit];
subviewFrame = [subviewButton frame];
subviewFrame.origin.x = subviewFrame.size.height;
@ -82,7 +86,7 @@
[breakTab setView:breakScroll];
[breakScroll release];
// create the breakpoints view
// create the watchpoints view
watchView = [[MAMEWatchpointsView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)
machine:*machine];
watchScroll = [[NSScrollView alloc] initWithFrame:[breakScroll frame]];
@ -98,6 +102,22 @@
[watchTab setView:watchScroll];
[watchScroll release];
// create the registerpoints view
registerView = [[MAMERegisterpointsView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)
machine:*machine];
registerScroll = [[NSScrollView alloc] initWithFrame:[breakScroll frame]];
[registerScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
[registerScroll setHasHorizontalScroller:YES];
[registerScroll setHasVerticalScroller:YES];
[registerScroll setAutohidesScrollers:YES];
[registerScroll setBorderType:NSNoBorder];
[registerScroll setDrawsBackground:NO];
[registerScroll setDocumentView:registerView];
[registerView release];
registerTab = [[NSTabViewItem alloc] initWithIdentifier:@""];
[registerTab setView:registerScroll];
[registerScroll release];
// create a tabless tabview for the two subviews
tabs = [[NSTabView alloc] initWithFrame:[breakScroll frame]];
[tabs setTabViewType:NSNoTabsNoBorder];
@ -106,6 +126,8 @@
[breakTab release];
[tabs addTabViewItem:watchTab];
[watchTab release];
[tabs addTabViewItem:registerTab];
[registerTab release];
[[window contentView] addSubview:tabs];
[tabs release];
@ -124,8 +146,12 @@
hasHorizontalScroller:YES
hasVerticalScroller:YES
borderType:[watchScroll borderType]];
NSSize const desired = NSMakeSize(std::max(breakDesired.width, watchDesired.width),
std::max(breakDesired.height, watchDesired.height));
NSSize const registerDesired = [NSScrollView frameSizeForContentSize:[registerView maximumFrameSize]
hasHorizontalScroller:YES
hasVerticalScroller:YES
borderType:[registerScroll borderType]];
NSSize const desired = NSMakeSize(std::max({ breakDesired.width, watchDesired.width, registerDesired.width }),
std::max({ breakDesired.height, watchDesired.height, registerDesired.height }));
[self cascadeWindowWithDesiredSize:desired forView:tabs];
// don't forget the result

View File

@ -0,0 +1,23 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
//============================================================
//
// registerpointsview.h - MacOS X Cocoa debug window handling
//
//============================================================
#import "debugosx.h"
#import "debugview.h"
#import <Cocoa/Cocoa.h>
@interface MAMERegisterpointsView : MAMEDebugView
{
}
- (id)initWithFrame:(NSRect)f machine:(running_machine &)m;
@end

View File

@ -0,0 +1,27 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
//============================================================
//
// registerpointsview.m - MacOS X Cocoa debug window handling
//
//============================================================
#import "registerpointsview.h"
#include "debug/debugvw.h"
@implementation MAMERegisterpointsView
- (id)initWithFrame:(NSRect)f machine:(running_machine &)m {
if (!(self = [super initWithFrame:f type:DVT_REGISTER_POINTS machine:m wholeLineScroll:YES]))
return nil;
return self;
}
- (void)dealloc {
[super dealloc];
}
@end

View File

@ -5,8 +5,6 @@
#include "debug/debugcon.h"
#include "debug/debugcpu.h"
#include "debug/dvbpoints.h"
#include "debug/dvwpoints.h"
#include <QtWidgets/QActionGroup>
#include <QtWidgets/QHBoxLayout>
@ -48,16 +46,25 @@ BreakpointsWindow::BreakpointsWindow(running_machine &machine, QWidget *parent)
//
QActionGroup *typeGroup = new QActionGroup(this);
typeGroup->setObjectName("typegroup");
QAction *typeBreak = new QAction("Breakpoints", this);
typeBreak->setObjectName("typebreak");
typeBreak->setCheckable(true);
typeBreak->setActionGroup(typeGroup);
typeBreak->setShortcut(QKeySequence("Ctrl+1"));
QAction *typeWatch = new QAction("Watchpoints", this);
typeWatch->setObjectName("typewatch");
typeBreak->setCheckable(true);
typeWatch->setCheckable(true);
typeBreak->setActionGroup(typeGroup);
typeWatch->setActionGroup(typeGroup);
typeBreak->setShortcut(QKeySequence("Ctrl+1"));
typeWatch->setShortcut(QKeySequence("Ctrl+2"));
QAction *typeRegister = new QAction("Registerpoints", this);
typeRegister->setObjectName("typeregister");
typeRegister->setCheckable(true);
typeRegister->setActionGroup(typeGroup);
typeRegister->setShortcut(QKeySequence("Ctrl+3"));
typeBreak->setChecked(true);
connect(typeGroup, &QActionGroup::triggered, this, &BreakpointsWindow::typeChanged);
@ -89,6 +96,11 @@ void BreakpointsWindow::typeChanged(QAction* changedTo)
m_breakpointsView = new DebuggerView(DVT_WATCH_POINTS, m_machine, this);
setWindowTitle("Debug: All Watchpoints");
}
else if (changedTo->text() == "Registerpoints")
{
m_breakpointsView = new DebuggerView(DVT_REGISTER_POINTS, m_machine, this);
setWindowTitle("Debug: All Registerpoints");
}
// Re-register
QVBoxLayout *layout = findChild<QVBoxLayout *>("vlayout");
@ -110,6 +122,8 @@ void BreakpointsWindowQtConfig::buildFromQWidget(QWidget *widget)
m_bwType = 0;
else if (typeGroup->checkedAction()->text() == "Watchpoints")
m_bwType = 1;
else if (typeGroup->checkedAction()->text() == "Registerpoints")
m_bwType = 2;
}

View File

@ -97,6 +97,7 @@ protected:
ID_SHOW_BREAKPOINTS,
ID_SHOW_WATCHPOINTS,
ID_SHOW_REGISTERPOINTS,
ID_CLEAR_LOG,

View File

@ -31,6 +31,7 @@ pointswin_info::pointswin_info(debugger_windows_interface &debugger) :
HMENU const optionsmenu = CreatePopupMenu();
AppendMenu(optionsmenu, MF_ENABLED, ID_SHOW_BREAKPOINTS, TEXT("Breakpoints\tCtrl+1"));
AppendMenu(optionsmenu, MF_ENABLED, ID_SHOW_WATCHPOINTS, TEXT("Watchpoints\tCtrl+2"));
AppendMenu(optionsmenu, MF_ENABLED, ID_SHOW_REGISTERPOINTS, TEXT("Registerpoints\tCtrl+3"));
AppendMenu(GetMenu(window()), MF_ENABLED | MF_POPUP, (UINT_PTR)optionsmenu, TEXT("Options"));
// compute a client rect
@ -69,6 +70,10 @@ bool pointswin_info::handle_key(WPARAM wparam, LPARAM lparam)
case '2':
SendMessage(window(), WM_COMMAND, ID_SHOW_WATCHPOINTS, 0);
return true;
case '3':
SendMessage(window(), WM_COMMAND, ID_SHOW_REGISTERPOINTS, 0);
return true;
}
}
@ -83,6 +88,7 @@ void pointswin_info::update_menu()
HMENU const menu = GetMenu(window());
CheckMenuItem(menu, ID_SHOW_BREAKPOINTS, MF_BYCOMMAND | (m_views[0]->type() == DVT_BREAK_POINTS ? MF_CHECKED : MF_UNCHECKED));
CheckMenuItem(menu, ID_SHOW_WATCHPOINTS, MF_BYCOMMAND | (m_views[0]->type() == DVT_WATCH_POINTS ? MF_CHECKED : MF_UNCHECKED));
CheckMenuItem(menu, ID_SHOW_REGISTERPOINTS, MF_BYCOMMAND | (m_views[0]->type() == DVT_REGISTER_POINTS ? MF_CHECKED : MF_UNCHECKED));
}
@ -111,6 +117,15 @@ bool pointswin_info::handle_command(WPARAM wparam, LPARAM lparam)
win_set_window_text_utf8(window(), "All Watchpoints");
recompute_children();
return true;
case ID_SHOW_REGISTERPOINTS:
m_views[0].reset();
m_views[0].reset(new debugview_info(debugger(), *this, window(), DVT_REGISTER_POINTS));
if (!m_views[0]->is_valid())
m_views[0].reset();
win_set_window_text_utf8(window(), "All Registerpoints");
recompute_children();
return true;
}
break;
}