summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2021-10-14 08:00:04 +1100
committer Vas Crabb <vas@vastheman.com>2021-10-14 08:00:04 +1100
commit96ca1dbd965df08ed4ab1f23053690c9ce540f94 (patch)
tree7c357aa9efe72e7e9c8b6e7084cec9fa859e214a /src
parent75f9660fa29d3d68a522fa96dbc92ef02baff2b8 (diff)
More user experience improvements:
frontend: Allow clicking the adjuster arrows on menu items. This allows things like video options and DIP switches to be configured using a mouse only. Also fixed a bug preventing paging menus with a mouse if the first item scrolled off the bottom is not selectable. debugger: Allow wplist and bplist to accept a CPU argument to list breakpoints/watchpoints for a single CPU only. debugger: Fixed some corner cases in address space syntax in memory accesses, and allowed memory region accesses to use tags relative to the visible CPU. emu/softlist.cpp: Ignore notes elements when loading software lists. It's effectively a comment that isn't a comment syntactically, it's being used for things that are not useful to display in the internal UI, and it slows down startup. docs: Updated three more pages of debugger documentation. Also updated more of the built-in debugger help. minimaws: Fixed up schema for software list notes, made sofware list notes display initially collapsed.
Diffstat (limited to 'src')
-rw-r--r--src/emu/debug/debugcmd.cpp160
-rw-r--r--src/emu/debug/debugcmd.h5
-rw-r--r--src/emu/debug/debughlp.cpp257
-rw-r--r--src/emu/debug/express.cpp292
-rw-r--r--src/emu/softlist.cpp30
-rw-r--r--src/emu/softlist.h3
-rw-r--r--src/emu/softlist_dev.cpp6
-rw-r--r--src/emu/softlist_dev.h2
-rw-r--r--src/frontend/mame/clifront.cpp4
-rw-r--r--src/frontend/mame/ui/menu.cpp65
-rw-r--r--src/frontend/mame/ui/submenu.cpp26
-rw-r--r--src/frontend/mame/ui/submenu.h3
12 files changed, 472 insertions, 381 deletions
diff --git a/src/emu/debug/debugcmd.cpp b/src/emu/debug/debugcmd.cpp
index 1d2bf4e13b6..e7ca864988d 100644
--- a/src/emu/debug/debugcmd.cpp
+++ b/src/emu/debug/debugcmd.cpp
@@ -252,7 +252,7 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu
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("bplist", CMDFLAG_NONE, 0, 0, std::bind(&debugger_commands::execute_bplist, this, _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));
m_console.register_command("wp", CMDFLAG_NONE, 3, 5, std::bind(&debugger_commands::execute_wpset, this, -1, _1));
@@ -265,7 +265,7 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu
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("wplist", CMDFLAG_NONE, 0, 0, std::bind(&debugger_commands::execute_wplist, this, _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));
@@ -337,8 +337,8 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu
m_console.register_command("dasm", CMDFLAG_NONE, 3, 5, std::bind(&debugger_commands::execute_dasm, this, _1));
- m_console.register_command("trace", CMDFLAG_NONE, 1, 4, std::bind(&debugger_commands::execute_trace, this, _1));
- m_console.register_command("traceover", CMDFLAG_NONE, 1, 4, std::bind(&debugger_commands::execute_traceover, this, _1));
+ m_console.register_command("trace", CMDFLAG_NONE, 1, 4, std::bind(&debugger_commands::execute_trace, this, _1, false));
+ m_console.register_command("traceover", CMDFLAG_NONE, 1, 4, std::bind(&debugger_commands::execute_trace, this, _1, true));
m_console.register_command("traceflush",CMDFLAG_NONE, 0, 0, std::bind(&debugger_commands::execute_traceflush, this, _1));
m_console.register_command("history", CMDFLAG_NONE, 0, 2, std::bind(&debugger_commands::execute_history, this, _1));
@@ -1816,29 +1816,45 @@ void debugger_commands::execute_bplist(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()->breakpoint_list().empty())
- {
- m_console.printf("Device '%s' breakpoints:\n", device.tag());
-
- /* loop over the breakpoints */
- for (const auto &bpp : device.debug()->breakpoint_list())
+ auto const apply =
+ [this, &printed, &buffer] (device_t &device)
{
- debug_breakpoint &bp = *bpp.second;
- buffer = string_format("%c%4X @ %0*X", bp.enabled() ? ' ' : 'D', bp.index(), device.debug()->logaddrchars(), bp.address());
- if (std::string(bp.condition()).compare("1") != 0)
- buffer.append(string_format(" if %s", bp.condition()));
- if (std::string(bp.action()).compare("") != 0)
- buffer.append(string_format(" do %s", bp.action()));
- m_console.printf("%s\n", buffer);
- printed++;
- }
- }
+ if (!device.debug()->breakpoint_list().empty())
+ {
+ m_console.printf("Device '%s' breakpoints:\n", device.tag());
- if (printed == 0)
- m_console.printf("No breakpoints currently installed\n");
+ // loop over the breakpoints
+ for (const auto &bpp : device.debug()->breakpoint_list())
+ {
+ debug_breakpoint &bp = *bpp.second;
+ buffer = string_format("%c%4X @ %0*X", bp.enabled() ? ' ' : 'D', bp.index(), device.debug()->logaddrchars(), bp.address());
+ if (std::string(bp.condition()).compare("1") != 0)
+ buffer.append(string_format(" if %s", bp.condition()));
+ if (std::string(bp.action()).compare("") != 0)
+ buffer.append(string_format(" do %s", bp.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 breakpoints 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 breakpoints currently installed\n");
+ }
}
@@ -1977,35 +1993,57 @@ void debugger_commands::execute_wplist(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()))
- for (int spacenum = 0; spacenum < device.debug()->watchpoint_space_count(); ++spacenum)
- if (!device.debug()->watchpoint_vector(spacenum).empty())
+ auto const apply =
+ [this, &printed, &buffer] (device_t &device)
{
- static const char *const types[] = { "unkn ", "read ", "write", "r/w " };
+ for (int spacenum = 0; spacenum < device.debug()->watchpoint_space_count(); ++spacenum)
+ {
+ if (!device.debug()->watchpoint_vector(spacenum).empty())
+ {
+ static const char *const types[] = { "unkn ", "read ", "write", "r/w " };
- m_console.printf("Device '%s' %s space watchpoints:\n", device.tag(),
- device.debug()->watchpoint_vector(spacenum).front()->space().name());
+ m_console.printf(
+ "Device '%s' %s space watchpoints:\n",
+ device.tag(),
+ device.debug()->watchpoint_vector(spacenum).front()->space().name());
- /* loop over the watchpoints */
- for (const auto &wp : device.debug()->watchpoint_vector(spacenum))
- {
- buffer = string_format("%c%4X @ %0*X-%0*X %s", wp->enabled() ? ' ' : 'D', wp->index(),
- wp->space().addrchars(), wp->address(),
- wp->space().addrchars(), wp->address() + wp->length() - 1,
- types[int(wp->type())]);
- if (std::string(wp->condition()).compare("1") != 0)
- buffer.append(string_format(" if %s", wp->condition()));
- if (std::string(wp->action()).compare("") != 0)
- buffer.append(string_format(" do %s", wp->action()));
- m_console.printf("%s\n", buffer);
- printed++;
+ // loop over the watchpoints
+ for (const auto &wp : device.debug()->watchpoint_vector(spacenum))
+ {
+ buffer = string_format(
+ "%c%4X @ %0*X-%0*X %s",
+ wp->enabled() ? ' ' : 'D', wp->index(),
+ wp->space().addrchars(), wp->address(),
+ wp->space().addrchars(), wp->address() + wp->length() - 1,
+ types[int(wp->type())]);
+ if (std::string(wp->condition()).compare("1") != 0)
+ buffer.append(string_format(" if %s", wp->condition()));
+ if (std::string(wp->action()).compare("") != 0)
+ buffer.append(string_format(" do %s", wp->action()));
+ m_console.printf("%s\n", buffer);
+ printed++;
+ }
+ }
}
- }
+ };
- if (printed == 0)
- m_console.printf("No watchpoints currently installed\n");
+ if (!params.empty())
+ {
+ device_t *cpu;
+ if (!validate_cpu_parameter(params[0], cpu))
+ return;
+ apply(*cpu);
+ if (!printed)
+ m_console.printf("No watchpoints 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 watchpoints currently installed\n");
+ }
}
@@ -3576,11 +3614,11 @@ void debugger_commands::execute_dasm(const std::vector<std::string> &params)
/*-------------------------------------------------
- execute_trace_internal - functionality for
+ execute_trace - functionality for
trace over and trace info
-------------------------------------------------*/
-void debugger_commands::execute_trace_internal(const std::vector<std::string> &params, bool trace_over)
+void debugger_commands::execute_trace(const std::vector<std::string> &params, bool trace_over)
{
const char *action = nullptr;
bool detect_loops = true;
@@ -3648,26 +3686,6 @@ void debugger_commands::execute_trace_internal(const std::vector<std::string> &p
/*-------------------------------------------------
- execute_trace - execute the trace command
--------------------------------------------------*/
-
-void debugger_commands::execute_trace(const std::vector<std::string> &params)
-{
- execute_trace_internal(params, false);
-}
-
-
-/*-------------------------------------------------
- execute_traceover - execute the trace over command
--------------------------------------------------*/
-
-void debugger_commands::execute_traceover(const std::vector<std::string> &params)
-{
- execute_trace_internal(params, true);
-}
-
-
-/*-------------------------------------------------
execute_traceflush - execute the trace flush command
-------------------------------------------------*/
diff --git a/src/emu/debug/debugcmd.h b/src/emu/debug/debugcmd.h
index 6c389644df2..09e4b7ed7a1 100644
--- a/src/emu/debug/debugcmd.h
+++ b/src/emu/debug/debugcmd.h
@@ -100,8 +100,6 @@ private:
int mini_printf(char *buffer, const char *format, int params, u64 *param);
- void execute_trace_internal(const std::vector<std::string> &params, bool trace_over);
-
void execute_help(const std::vector<std::string> &params);
void execute_print(const std::vector<std::string> &params);
void execute_printf(const std::vector<std::string> &params);
@@ -160,8 +158,7 @@ private:
void execute_dasm(const std::vector<std::string> &params);
void execute_find(int spacenum, const std::vector<std::string> &params);
void execute_fill(int spacenum, const std::vector<std::string> &params);
- void execute_trace(const std::vector<std::string> &params);
- void execute_traceover(const std::vector<std::string> &params);
+ void execute_trace(const std::vector<std::string> &params, bool trace_over);
void execute_traceflush(const std::vector<std::string> &params);
void execute_history(const std::vector<std::string> &params);
void execute_trackpc(const std::vector<std::string> &params);
diff --git a/src/emu/debug/debughlp.cpp b/src/emu/debug/debughlp.cpp
index 322c760bbbb..13a0b2d1216 100644
--- a/src/emu/debug/debughlp.cpp
+++ b/src/emu/debug/debughlp.cpp
@@ -157,7 +157,7 @@ const help_item f_static_help_list[] =
" 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"
- " bplist -- lists all the breakpoints\n"
+ " bplist [<CPU>] -- lists all the breakpoints\n"
},
{
"watchpoints",
@@ -172,7 +172,7 @@ const help_item f_static_help_list[] =
" 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"
- " wplist -- lists all the watchpoints\n"
+ " wplist [<CPU>] -- lists all the watchpoints\n"
},
{
"registerpoints",
@@ -896,7 +896,7 @@ const help_item f_static_help_list[] =
"Note that the step out functionality may not be implemented on all CPU types. If it is not "
"implemented, then 'out' will behave exactly like 'step'.\n"
"\n"
- "Examples:\n"
+ "Example:\n"
"\n"
"out\n"
" Steps until the current subroutine or exception handler returns.\n"
@@ -920,35 +920,45 @@ const help_item f_static_help_list[] =
" Resume execution, stopping at address 1234 unless something else stops us first.\n"
},
{
- "gvblank",
+ "gex",
"\n"
- " gv[blank]\n"
+ " ge[x] [<exception>,[<condition>]]\n"
"\n"
- "The gvblank command resumes execution of the current code. Control will not be returned to "
- "the debugger until a breakpoint or watchpoint is hit, or until the next VBLANK occurs in the "
- "emulator.\n"
+ "The gex command resumes execution of the current code. Control will not be returned to "
+ "the debugger until a breakpoint or watchpoint is hit, or until an exception condition "
+ "is raised on the current CPU. You can specify <exception> if you wish to stop execution "
+ "only on a particular exception condition occurring. If <exception> is omitted, then any "
+ "exception condition will stop execution. The optional <condition> parameter lets you "
+ "specify an expression that will be evaluated each time the specified exception condition "
+ "is raised. If the result of the expression is true (non-zero), the exception will halt "
+ "execution; otherwise, execution will continue with no notification.\n"
"\n"
"Examples:\n"
"\n"
- "gv\n"
- " Resume execution until the next break/watchpoint or until the next VBLANK.\n"
+ "gex\n"
+ " Resume execution until the next break/watchpoint or until any exception condition is "
+ "raised on the current CPU.\n"
+ "\n"
+ "ge 2\n"
+ " Resume execution until the next break/watchpoint or until exception condition 2 is "
+ "raised on the current CPU.\n"
},
{
"gint",
"\n"
" gi[nt] [<irqline>]\n"
"\n"
- "The gint command resumes execution of the current code. Control will not be returned to the "
- "debugger until a breakpoint or watchpoint is hit, or until an IRQ is asserted and acknowledged "
- "on the current CPU. You can specify <irqline> if you wish to stop execution only on a particular "
- "IRQ line being asserted and acknowledged. If <irqline> is omitted, then any IRQ line will stop "
- "execution.\n"
+ "The gint command resumes execution of the current code. Control will not be returned to "
+ "the debugger until a breakpoint or watchpoint is hit, or until an IRQ is asserted and "
+ "acknowledged on the current CPU. You can specify <irqline> if you wish to stop execution "
+ "only on a particular IRQ line being asserted and acknowledged. If <irqline> is omitted, "
+ "then any IRQ line will stop execution.\n"
"\n"
"Examples:\n"
"\n"
"gi\n"
- " Resume execution until the next break/watchpoint or until any IRQ is asserted and acknowledged "
- "on the current CPU.\n"
+ " Resume execution until the next break/watchpoint or until any IRQ is asserted and "
+ "acknowledged on the current CPU.\n"
"\n"
"gint 4\n"
" Resume execution until the next break/watchpoint or until IRQ line 4 is asserted and "
@@ -968,13 +978,32 @@ const help_item f_static_help_list[] =
" Resume execution for ten seconds\n"
},
{
+ "gvblank",
+ "\n"
+ " gv[blank]\n"
+ "\n"
+ "The gvblank command resumes execution of the current code. Control will not be returned to "
+ "the debugger until a breakpoint or watchpoint is hit, or until the beginning of the "
+ " vertical blanking interval for an emulated screen.\n"
+ "\n"
+ "Example:\n"
+ "\n"
+ "gv\n"
+ " Resume execution until the next break/watchpoint or until the next VBLANK.\n"
+ },
+ {
"next",
"\n"
" n[ext]\n"
"\n"
"The next command resumes execution and continues executing until the next time a different "
- "CPU is scheduled. Note that if you have used 'ignore' to ignore certain CPUs, you will not "
- "stop until a non-'ignore'd CPU is scheduled.\n"
+ "CPU is scheduled. Note that if you have used 'focus' or 'ignore' to ignore certain CPUs, "
+ "execution will continue until a non-'ignore'd CPU is scheduled.\n"
+ "\n"
+ "Example:\n"
+ "\n"
+ "n\n"
+ " Resume execution, stopping when a different CPU that is not ignored is scheduled.\n"
},
{
"focus",
@@ -988,21 +1017,25 @@ const help_item f_static_help_list[] =
"\n"
"focus 1\n"
" Focus exclusively CPU #1 while ignoring all other CPUs when using the debugger.\n"
+ "\n"
+ "focus audiopcb:melodycpu\n"
+ " Focus exclusively on the CPU ':audiopcb:melodycpu'.\n"
},
{
"ignore",
"\n"
" ignore [<CPU>[,<CPU>[,...]]]\n"
"\n"
- "Ignores the specified <CPU> in the debugger. This means that you won't ever see execution "
- "on that CPU, nor will you be able to set breakpoints on that CPU. To undo this change use "
- "the 'observe' command. You can specify multiple <CPU>s in a single command. Note also that "
- "you are not permitted to ignore all CPUs; at least one must be active at all times.\n"
+ "Ignores the specified CPUs in the debugger. CPUs can be specified by tag or debugger CPU "
+ "number. The debugger never shows execution for ignored CPUs, and breakpoints or "
+ "watchpoints on ignored CPUs have no effect. If no CPUs are specified, currently ignored "
+ "CPUs will be listed. Use the 'observe' command to stop ignoring a CPU. Note that you "
+ "cannot ignore all CPUs; at least CPU must be observed at all times.\n"
"\n"
"Examples:\n"
"\n"
- "ignore 1\n"
- " Ignore CPU #1 when using the debugger.\n"
+ "ignore audiocpu\n"
+ " Ignore the CPU ':audiocpu' when using the debugger.\n"
"\n"
"ignore 2,3,4\n"
" Ignore CPU #2, #3 and #4 when using the debugger.\n"
@@ -1020,8 +1053,8 @@ const help_item f_static_help_list[] =
"\n"
"Examples:\n"
"\n"
- "observe 1\n"
- " Stop ignoring CPU #1 when using the debugger.\n"
+ "observe audiocpu\n"
+ " Stop ignoring the CPU ':audiocpu' when using the debugger.\n"
"\n"
"observe 2,3,4\n"
" Stop ignoring CPU #2, #3 and #4 when using the debugger.\n"
@@ -1032,91 +1065,101 @@ const help_item f_static_help_list[] =
{
"trace",
"\n"
- " trace {<filename>|OFF}[,<CPU>[,[noloop|logerror][,<action>]]]\n"
+ " trace {<filename>|off}[,<CPU>[,[noloop|logerror][,<action>]]]\n"
+ "\n"
+ "Starts or stops tracing of the execution of the specified <CPU>, or the currently visible "
+ "CPU if no CPU is specified. To enable tracing, specify the trace log file name in the "
+ "<filename> parameter. To disable tracing, use the keyword 'off' for <filename> "
+ "parameter. If the **<filename>** begins with two right angle brackets (>>), it is treated "
+ "as a directive to open the file for appending rather than overwriting.\n"
"\n"
- "Starts or stops tracing of the execution of the specified <CPU>. If <CPU> is omitted, "
- "the currently active CPU is specified. When enabling tracing, specify the filename in the "
- "<filename> parameter. To disable tracing, substitute the keyword 'off' for <filename>. "
- "<detectloops> should be either true or false. If 'noloop' is omitted, the trace "
- "will have loops detected and condensed to a single line. If 'noloop' is specified, the trace "
- "will contain every opcode as it is executed. If 'logerror' is specified, logerror output "
- "will augment the trace. If you "
- "wish to log additional information on each trace, you can append an <action> parameter which "
- "is a command that is executed before each trace is logged. Generally, this is used to include "
- "a 'tracelog' command. 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 trace command "
- "itself.\n"
+ "The optional third parameter is a flags field. The supported flags are 'noloop' and "
+ "'logerror'. Multiple flags must be separated by | (pipe) characters. By default, loops "
+ "are detected and condensed to a single line. If the 'noloop' flag is specified, loops "
+ "will not be detected and every instruction will be logged as executed. If the 'logerror' "
+ "flag is specified, error log output will be included in the trace log.\n"
+ "\n"
+ "The optional <action> parameter is a debugger command to execute before each trace message "
+ "is logged. Generally, this will include a 'tracelog' or 'tracesym' command to include "
+ "additional information in the trace log. 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 trace command itself.\n"
"\n"
"Examples:\n"
"\n"
"trace joust.tr\n"
- " Begin tracing the currently active CPU, logging output to joust.tr.\n"
+ " Begin tracing the execution of the currently visible CPU, logging output to joust.tr.\n"
"\n"
- "trace dribling.tr,0\n"
- " Begin tracing the execution of CPU #0, logging output to dribling.tr.\n"
+ "trace dribling.tr,maincpu\n"
+ " Begin tracing the execution of the CPU ':maincpu', logging output to dribling.tr.\n"
"\n"
- "trace starswep.tr,0,noloop\n"
- " Begin tracing the execution of CPU #0, logging output to starswep.tr, with loop detection disabled.\n"
+ "trace starswep.tr,,noloop\n"
+ " Begin tracing the execution of the currently visible CPU, logging output to starswep.tr, "
+ "with loop detection disabled.\n"
"\n"
- "trace starswep.tr,0,logerror\n"
- " Begin tracing the execution of CPU #0, logging output (along with logerror output) to starswep.tr.\n"
+ "trace starswep.tr,1,logerror\n"
+ " Begin tracing the execution of CPU #1, logging output (along with logerror output) to "
+ "starswep.tr.\n"
"\n"
"trace starswep.tr,0,logerror|noloop\n"
- " Begin tracing the execution of CPU #0, logging output (along with logerror output) to starswep.tr, with loop detection disabled.\n"
+ " Begin tracing the execution of CPU #0, logging output (along with logerror output) to "
+ "starswep.tr, with loop detection disabled.\n"
"\n"
"trace >>pigskin.tr\n"
- " Begin tracing the currently active CPU, appending log output to pigskin.tr.\n"
+ " Begin tracing execution of the currently visible CPU, appending log output to "
+ "pigskin.tr.\n"
"\n"
"trace off,0\n"
" Turn off tracing on CPU #0.\n"
"\n"
- "trace asteroid.tr,0,,{tracelog \"A=%02X \",a}\n"
- " Begin tracing the execution of CPU #0, logging output to asteroid.tr. Before each line, "
- "output A=<aval> to the tracelog.\n"
+ "trace asteroid.tr,,,{tracelog \"A=%02X \",a}\n"
+ " Begin tracing the execution of the currently visible CPU, logging output to asteroid.tr. "
+ "Before each line, output A=<aval> to the trace log.\n"
},
{
"traceover",
"\n"
- " traceover {<filename>|OFF}[,<CPU>[,<detectloops>[,<action>]]]\n"
- "\n"
- "Starts or stops tracing of the execution of the specified <CPU>. When tracing reaches "
- "a subroutine or call, tracing will skip over the subroutine. The same algorithm is used as is "
- "used in the step over command. This means that traceover will not work properly when calls "
- "are recusive or the return address is not immediately following the call instruction. If "
- "<detectloops> should be either true or false. If <detectloops> is true or omitted, the trace "
- "will have loops detected and condensed to a single line. If it is false, the trace will contain "
- "every opcode as it is executed. If <CPU> is omitted, the currently active CPU is specified. When "
- "enabling tracing, specify the filename in the <filename> parameter. To disable tracing, substitute "
- "the keyword 'off' for <filename>. If you wish to log additional information on each trace, you can "
- "append an <action> parameter which is a command that is executed before each trace is logged. "
- "Generally, this is used to include a 'tracelog' command. 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 trace command itself.\n"
+ " traceover {<filename>|off}[,<CPU>[,[noloop|logerror][,<action>]]]\n"
+ "\n"
+ "Starts or stops tracing for execution of the specified **<CPU>**, or the currently visible "
+ "CPU if no CPU is specified. When a subroutine call is encountered, tracing will skip over "
+ "the subroutine. The same algorithm is used as is used in the step over command. It will "
+ "not work properly with recursive functions, or if the return address does not immediately "
+ "follow the call instruction.\n"
+ "\n"
+ "This command accepts the same parameters as the 'trace' command. Please refer to the "
+ "corresponding section for a detailed description of options and more examples.\n"
"\n"
"Examples:\n"
"\n"
"traceover joust.tr\n"
- " Begin tracing the currently active CPU, logging output to joust.tr.\n"
+ " Begin tracing the execution of the currently visible CPU, logging output to joust.tr.\n"
"\n"
- "traceover dribling.tr,0\n"
- " Begin tracing the execution of CPU #0, logging output to dribling.tr.\n"
+ "traceover dribling.tr,maincpu\n"
+ " Begin tracing the execution of the CPU ':maincpu', logging output to dribling.tr.\n"
"\n"
- "traceover starswep.tr,0,false\n"
- " Begin tracing the execution of CPU #0, logging output to starswep.tr, with loop detection disabled.\n"
+ "traceover starswep.tr,,noloop\n"
+ " Begin tracing the execution of the currently visible CPU, logging output to starswep.tr, "
+ "with loop detection disabled.\n"
"\n"
"traceover off,0\n"
" Turn off tracing on CPU #0.\n"
"\n"
- "traceover asteroid.tr,0,true,{tracelog \"A=%02X \",a}\n"
- " Begin tracing the execution of CPU #0, logging output to asteroid.tr. Before each line, "
- "output A=<aval> to the tracelog.\n"
+ "traceover asteroid.tr,,,{tracelog \"A=%02X \",a}\n"
+ " Begin tracing the execution of the currently visible CPU, logging output to "
+ "asteroid.tr. Before each line, output A=<aval> to the trace log.\n"
},
{
"traceflush",
"\n"
" traceflush\n"
"\n"
- "Flushes all open trace files.\n"
+ "Flushes all open trace log files to disk.\n"
+ "\n"
+ "Example:\n"
+ "\n"
+ "traceflush\n"
+ " Flush trace log files.\n"
},
{
"bpset",
@@ -1124,15 +1167,15 @@ const help_item f_static_help_list[] =
" bp[set] <address>[:<CPU>][,<condition>[,<action>]]\n"
"\n"
"Sets a new execution breakpoint at the specified <address>. The <address> may optionally "
- "be followed by a colon and the tag or debuggers CPU number to specify a CPU explicitly. "
- "If no CPU is specified, the CPU currently visible in the debugger is assumed. The "
- "optional <condition> parameter lets you specify an expression that will be evaluated each "
- "time the breakpoint is hit. If the result of the expression is true (non-zero), the "
- "breakpoint will halt execution; otherwise, execution will continue with no notification. "
- "The optional <action> parameter provides a command that is executed whenever the "
- "breakpoint is hit and the <condition> is true. 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 'bpset' command itself.\n"
+ "be followed by a colon and a tag or debugger CPU number to specify a CPU explicitly. If "
+ "no CPU is specified, the CPU currently visible in the debugger is assumed. The optional "
+ "<condition> parameter lets you specify an expression that will be evaluated each time the "
+ "breakpoint is hit. If the result of the expression is true (non-zero), the breakpoint "
+ "will halt execution; otherwise, execution will continue with no notification. The "
+ "optional <action> parameter provides a command that is executed whenever the breakpoint is "
+ "hit and the <condition> is true. 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 "
+ "'bpset' command itself.\n"
"\n"
"Each breakpoint that is set is assigned an index which can be used to refer to it in other "
"breakpoint commands.\n"
@@ -1212,10 +1255,23 @@ const help_item f_static_help_list[] =
{
"bplist",
"\n"
- " bplist\n"
+ " bplist [<CPU>]\n"
+ "\n"
+ "The bplist list current breakpoints, along with their indices and any associated "
+ "conditions or actions. If no <CPU> is specified, breakpoints for all CPUs in the system "
+ "will be listed; if a <CPU> is specified, only breakpoints for that CPU will be listed. "
+ "The <CPU> can be specified by tag or by debugger CPU number.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "bplist\n"
+ " List all breakpoints.\n"
+ "\n"
+ "bplist .\n"
+ " List all breakpoints for the visible CPU.\n"
"\n"
- "The bplist command lists all the current breakpoints, along with their indices and any "
- "conditions or actions attached to them.\n"
+ "bplist maincpu\n"
+ " List all breakpoints for the CPU ':maincpu'.\n"
},
{
"wpset",
@@ -1230,8 +1286,8 @@ const help_item f_static_help_list[] =
"suffix sets the address space: 'wpset' defaults to the first address space exposed by the "
"CPU, 'wpdset' defaults to the data space, 'wpiset' defaults to the I/O space, and 'wposet' "
"defaults to the opcodes space. The <type> parameter specifies the access types to trap "
- "on - it can be one of three values: 'r' for read accesses, 'w' for write accesses, and "
- "'rw' for both read and write accesses.\n"
+ "on - it can be one of three values: 'r' for read accesses, 'w' for write accesses, or 'rw' "
+ "for both read and write accesses.\n"
"\n"
"The optional <condition> parameter lets you specify an expression that will be evaluated "
"each time the watchpoint is triggered. If the result of the expression is true "
@@ -1246,7 +1302,7 @@ const help_item f_static_help_list[] =
"\n"
"To make <condition> expressions more useful, two variables are available: for all "
"watchpoints, the variable 'wpaddr' is set to the access address that triggered the "
- "watchpoint; for write watchpoints, the variable 'wpdata' is set to the data that is being "
+ "watchpoint; for write watchpoints, the variable 'wpdata' is set to the data being "
"written.\n"
"\n"
"Examples:\n"
@@ -1324,10 +1380,23 @@ const help_item f_static_help_list[] =
{
"wplist",
"\n"
- " wplist\n"
+ " wplist [<CPU>]\n"
+ "\n"
+ "The wplist list current watchpoints, along with their indices and any associated "
+ "conditions or actions. If no <CPU> is specified, watchpoints for all CPUs in the system "
+ "will be listed; if a <CPU> is specified, only watchpoints for that CPU will be listed. "
+ "The <CPU> can be specified by tag or by debugger CPU number.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "wplist\n"
+ " List all watchpoints.\n"
+ "\n"
+ "wplist .\n"
+ " List all watchpoints for the visible CPU.\n"
"\n"
- "The wplist command lists all the current watchpoints, along with their indices and any "
- "conditions or actions attached to them.\n"
+ "wplist maincpu\n"
+ " List all watchpoints for the CPU ':maincpu'.\n"
},
{
"rpset",
diff --git a/src/emu/debug/express.cpp b/src/emu/debug/express.cpp
index bc90ddaf52e..3e15ba29a5b 100644
--- a/src/emu/debug/express.cpp
+++ b/src/emu/debug/express.cpp
@@ -46,6 +46,7 @@
#include "logmacro.h"
+namespace {
/***************************************************************************
CONSTANTS
@@ -103,7 +104,7 @@ enum
//**************************************************************************
-// TYPE DEFINITIONS
+// REGISTER SYMBOL ENTRY
//**************************************************************************
// a symbol entry representing a register, with read/write callbacks
@@ -116,8 +117,8 @@ public:
integer_symbol_entry(symbol_table &table, const char *name, symbol_table::getter_func getter, symbol_table::setter_func setter, const std::string &format);
// symbol access
- virtual bool is_lval() const override;
- virtual u64 value() const override;
+ virtual bool is_lval() const override { return m_setter != nullptr; }
+ virtual u64 value() const override { return m_getter(); }
virtual void set_value(u64 newvalue) override;
private:
@@ -128,105 +129,6 @@ private:
};
-// a symbol entry representing a function
-class function_symbol_entry : public symbol_entry
-{
-public:
- // construction/destruction
- function_symbol_entry(symbol_table &table, const char *name, int minparams, int maxparams, symbol_table::execute_func execute);
-
- // getters
- u16 minparams() const { return m_minparams; }
- u16 maxparams() const { return m_maxparams; }
-
- // symbol access
- virtual bool is_lval() const override;
- virtual u64 value() const override;
- virtual void set_value(u64 newvalue) override;
-
- // execution helper
- virtual u64 execute(int numparams, const u64 *paramlist);
-
-private:
- // internal state
- u16 m_minparams;
- u16 m_maxparams;
- symbol_table::execute_func m_execute;
-};
-
-
-
-//**************************************************************************
-// EXPRESSION ERROR
-//**************************************************************************
-
-//-------------------------------------------------
-// code_string - return a friendly string for a
-// given expression error
-//-------------------------------------------------
-
-std::string expression_error::code_string() const
-{
- switch (m_code)
- {
- case NOT_LVAL: return "not an lvalue";
- case NOT_RVAL: return "not an rvalue";
- case SYNTAX: return "syntax error";
- case UNKNOWN_SYMBOL: return "unknown symbol";
- case INVALID_NUMBER: return "invalid number";
- case INVALID_TOKEN: return "invalid token";
- case STACK_OVERFLOW: return "stack overflow";
- case STACK_UNDERFLOW: return "stack underflow";
- case UNBALANCED_PARENS: return "unbalanced parentheses";
- case DIVIDE_BY_ZERO: return "divide by zero";
- case OUT_OF_MEMORY: return "out of memory";
- case INVALID_PARAM_COUNT: return "invalid number of parameters";
- case TOO_FEW_PARAMS: return util::string_format("too few parameters (at least %d required)", m_num);
- case TOO_MANY_PARAMS: return util::string_format("too many parameters (no more than %d accepted)", m_num);
- case UNBALANCED_QUOTES: return "unbalanced quotes";
- case TOO_MANY_STRINGS: return "too many strings";
- case INVALID_MEMORY_SIZE: return "invalid memory size (b/w/d/q expected)";
- case NO_SUCH_MEMORY_SPACE: return "non-existent memory space";
- case INVALID_MEMORY_SPACE: return "invalid memory space (p/d/i/o/r/m expected)";
- case INVALID_MEMORY_NAME: return "invalid memory name";
- case MISSING_MEMORY_NAME: return "missing memory name";
- default: return "unknown error";
- }
-}
-
-
-
-//**************************************************************************
-// SYMBOL ENTRY
-//**************************************************************************
-
-//-------------------------------------------------
-// symbol_entry - constructor
-//-------------------------------------------------
-
-symbol_entry::symbol_entry(symbol_table &table, symbol_type type, const char *name, const std::string &format)
- : m_table(table),
- m_type(type),
- m_name(name),
- m_format(format)
-{
-}
-
-
-//-------------------------------------------------
-// ~symbol_entry - destructor
-//-------------------------------------------------
-
-symbol_entry::~symbol_entry()
-{
-}
-
-
-
-//**************************************************************************
-// REGISTER SYMBOL ENTRY
-//**************************************************************************
-
//-------------------------------------------------
// integer_symbol_entry - constructor
//-------------------------------------------------
@@ -265,26 +167,6 @@ integer_symbol_entry::integer_symbol_entry(symbol_table &table, const char *name
//-------------------------------------------------
-// is_lval - is this symbol allowable as an lval?
-//-------------------------------------------------
-
-bool integer_symbol_entry::is_lval() const
-{
- return (m_setter != nullptr);
-}
-
-
-//-------------------------------------------------
-// value - return the value of this symbol
-//-------------------------------------------------
-
-u64 integer_symbol_entry::value() const
-{
- return m_getter();
-}
-
-
-//-------------------------------------------------
// set_value - set the value of this symbol
//-------------------------------------------------
@@ -302,6 +184,33 @@ void integer_symbol_entry::set_value(u64 newvalue)
// FUNCTION SYMBOL ENTRY
//**************************************************************************
+// a symbol entry representing a function
+class function_symbol_entry : public symbol_entry
+{
+public:
+ // construction/destruction
+ function_symbol_entry(symbol_table &table, const char *name, int minparams, int maxparams, symbol_table::execute_func execute);
+
+ // getters
+ u16 minparams() const { return m_minparams; }
+ u16 maxparams() const { return m_maxparams; }
+
+ // symbol access
+ virtual bool is_lval() const override { return false; }
+ virtual u64 value() const override;
+ virtual void set_value(u64 newvalue) override;
+
+ // execution helper
+ virtual u64 execute(int numparams, const u64 *paramlist);
+
+private:
+ // internal state
+ u16 m_minparams;
+ u16 m_maxparams;
+ symbol_table::execute_func m_execute;
+};
+
+
//-------------------------------------------------
// function_symbol_entry - constructor
//-------------------------------------------------
@@ -316,16 +225,6 @@ function_symbol_entry::function_symbol_entry(symbol_table &table, const char *na
//-------------------------------------------------
-// is_lval - is this symbol allowable as an lval?
-//-------------------------------------------------
-
-bool function_symbol_entry::is_lval() const
-{
- return false;
-}
-
-
-//-------------------------------------------------
// value - return the value of this symbol
//-------------------------------------------------
@@ -360,6 +259,102 @@ u64 function_symbol_entry::execute(int numparams, const u64 *paramlist)
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+inline std::pair<device_t &, char const *> get_device_search(running_machine &machine, device_memory_interface *memintf, char const *tag)
+{
+ if (tag)
+ {
+ if (('.' == tag[0]) && (!tag[1] || (':' == tag[1]) || ('^' == tag[1])))
+ return std::pair<device_t &, char const *>(memintf ? memintf->device() : machine.root_device(), tag + ((':' == tag[1]) ? 2 : 1));
+ else if (('^' == tag[0]) && memintf)
+ return std::pair<device_t &, char const *>(memintf->device(), tag);
+ else
+ return std::pair<device_t &, char const *>(machine.root_device(), tag);
+ }
+ else if (memintf)
+ {
+ return std::pair<device_t &, char const *>(memintf->device(), "");
+ }
+ else
+ {
+ return std::pair<device_t &, char const *>(machine.root_device(), "");
+ }
+}
+
+} // anonymous namespace
+
+
+
+//**************************************************************************
+// EXPRESSION ERROR
+//**************************************************************************
+
+//-------------------------------------------------
+// code_string - return a friendly string for a
+// given expression error
+//-------------------------------------------------
+
+std::string expression_error::code_string() const
+{
+ switch (m_code)
+ {
+ case NOT_LVAL: return "not an lvalue";
+ case NOT_RVAL: return "not an rvalue";
+ case SYNTAX: return "syntax error";
+ case UNKNOWN_SYMBOL: return "unknown symbol";
+ case INVALID_NUMBER: return "invalid number";
+ case INVALID_TOKEN: return "invalid token";
+ case STACK_OVERFLOW: return "stack overflow";
+ case STACK_UNDERFLOW: return "stack underflow";
+ case UNBALANCED_PARENS: return "unbalanced parentheses";
+ case DIVIDE_BY_ZERO: return "divide by zero";
+ case OUT_OF_MEMORY: return "out of memory";
+ case INVALID_PARAM_COUNT: return "invalid number of parameters";
+ case TOO_FEW_PARAMS: return util::string_format("too few parameters (at least %d required)", m_num);
+ case TOO_MANY_PARAMS: return util::string_format("too many parameters (no more than %d accepted)", m_num);
+ case UNBALANCED_QUOTES: return "unbalanced quotes";
+ case TOO_MANY_STRINGS: return "too many strings";
+ case INVALID_MEMORY_SIZE: return "invalid memory size (b/w/d/q expected)";
+ case NO_SUCH_MEMORY_SPACE: return "non-existent memory space";
+ case INVALID_MEMORY_SPACE: return "invalid memory space (p/d/i/o/r/m expected)";
+ case INVALID_MEMORY_NAME: return "invalid memory name";
+ case MISSING_MEMORY_NAME: return "missing memory name";
+ default: return "unknown error";
+ }
+}
+
+
+
+//**************************************************************************
+// SYMBOL ENTRY
+//**************************************************************************
+
+//-------------------------------------------------
+// symbol_entry - constructor
+//-------------------------------------------------
+
+symbol_entry::symbol_entry(symbol_table &table, symbol_type type, const char *name, const std::string &format)
+ : m_table(table),
+ m_type(type),
+ m_name(name),
+ m_format(format)
+{
+}
+
+
+//-------------------------------------------------
+// ~symbol_entry - destructor
+//-------------------------------------------------
+
+symbol_entry::~symbol_entry()
+{
+}
+
+
+
//**************************************************************************
// SYMBOL TABLE
//**************************************************************************
@@ -551,17 +546,13 @@ expression_error symbol_table::expression_get_space(const char *tag, int &spacen
if (tag)
{
// convert to lowercase then lookup the name (tags are enforced to be all lower case)
- device_t *base;
- if ((('^' == tag[0]) || (('.' == tag[0]) && ((':' == tag[1]) || !tag[1]))) && m_memintf)
- base = &m_memintf->device();
- else
- base = &m_machine.root_device();
- device = base->subdevice(strmakelower(tag));
+ auto base = get_device_search(m_machine, m_memintf, tag);
+ device = base.first.subdevice(strmakelower(base.second));
// if that failed, treat the last component as an address space
if (!device)
{
- std::string_view t = tag;
+ std::string_view t = base.second;
auto const delimiter = t.find_last_of(":^");
bool const found = std::string_view::npos != delimiter;
if (!found || (':' == t[delimiter]))
@@ -569,7 +560,7 @@ expression_error symbol_table::expression_get_space(const char *tag, int &spacen
spacename = strmakelower(t.substr(found ? (delimiter + 1) : 0));
t = t.substr(0, !found ? 0 : !delimiter ? 1 : delimiter);
if (!t.empty())
- device = base->subdevice(strmakelower(t));
+ device = base.first.subdevice(strmakelower(t));
else
device = m_memintf ? &m_memintf->device() : &m_machine.root_device();
}
@@ -740,11 +731,12 @@ u64 symbol_table::read_program_direct(address_space &space, int opcode, offs_t a
u64 symbol_table::read_memory_region(const char *rgntag, offs_t address, int size)
{
- memory_region *region = m_machine.root_device().memregion(rgntag);
+ auto search = get_device_search(m_machine, m_memintf, rgntag);
+ memory_region *const region = search.first.memregion(search.second);
u64 result = ~u64(0) >> (64 - 8*size);
// make sure we get a valid base before proceeding
- if (region != nullptr)
+ if (region)
{
// call ourself recursively until we are byte-sized
if (size > 1)
@@ -900,10 +892,11 @@ void symbol_table::write_program_direct(address_space &space, int opcode, offs_t
void symbol_table::write_memory_region(const char *rgntag, offs_t address, int size, u64 data)
{
- memory_region *region = m_machine.root_device().memregion(rgntag);
+ auto search = get_device_search(m_machine, m_memintf, rgntag);
+ memory_region *const region = search.first.memregion(search.second);
// make sure we get a valid base before proceeding
- if (region != nullptr)
+ if (region)
{
// call ourself recursively until we are byte-sized
if (size > 1)
@@ -984,9 +977,16 @@ expression_error::error_code symbol_table::memory_valid(const char *name, expres
case EXPSPACE_REGION:
if (!name)
+ {
return expression_error::MISSING_MEMORY_NAME;
- if (!m_machine.root_device().memregion(name) || !m_machine.root_device().memregion(name)->base())
- return expression_error::INVALID_MEMORY_NAME;
+ }
+ else
+ {
+ auto search = get_device_search(m_machine, m_memintf, name);
+ memory_region *const region = search.first.memregion(search.second);
+ if (!region || !region->base())
+ return expression_error::INVALID_MEMORY_NAME;
+ }
break;
default:
diff --git a/src/emu/softlist.cpp b/src/emu/softlist.cpp
index fe9d862ef1f..72f299c4c29 100644
--- a/src/emu/softlist.cpp
+++ b/src/emu/softlist.cpp
@@ -190,7 +190,6 @@ public:
std::string_view filename,
std::string &listname,
std::string &description,
- std::string &notes,
std::list<software_info> &infolist,
std::ostream &errors);
@@ -241,8 +240,8 @@ private:
struct XML_ParserStruct * m_parser;
std::string & m_listname;
std::string & m_description;
- std::string & m_notes;
bool m_data_accum_expected;
+ bool m_ignore_cdata;
std::string m_data_accum;
software_info * m_current_info;
software_part * m_current_part;
@@ -259,7 +258,6 @@ softlist_parser::softlist_parser(
std::string_view filename,
std::string &listname,
std::string &description,
- std::string &notes,
std::list<software_info> &infolist,
std::ostream &errors) :
m_filename(filename),
@@ -267,8 +265,8 @@ softlist_parser::softlist_parser(
m_errors(errors),
m_listname(listname),
m_description(description),
- m_notes(notes),
m_data_accum_expected(false),
+ m_ignore_cdata(false),
m_current_info(nullptr),
m_current_part(nullptr),
m_pos(POS_ROOT)
@@ -488,6 +486,7 @@ void softlist_parser::end_handler(void *data, const char *name)
// stop accumulating
state->m_data_accum_expected = false;
+ state->m_ignore_cdata = false;
state->m_data_accum.clear();
}
@@ -500,7 +499,11 @@ void softlist_parser::data_handler(void *data, const char *s, int len)
{
softlist_parser *state = reinterpret_cast<softlist_parser *>(data);
- if (state->m_data_accum_expected)
+ if (state->m_ignore_cdata)
+ {
+ // allowed, but we don't use it
+ }
+ else if (state->m_data_accum_expected)
{
// if we have an std::string to accumulate data in, do it
state->m_data_accum.append(s, len);
@@ -548,9 +551,9 @@ void softlist_parser::parse_root_start(const char *tagname, const char **attribu
void softlist_parser::parse_main_start(const char *tagname, const char **attributes)
{
- // <software name='' cloneof='' supported=''>
if (strcmp(tagname, "software") == 0)
{
+ // <software name='' cloneof='' supported=''>
static char const *const attrnames[] = { "name", "cloneof", "supported" };
auto attrvalues = parse_attributes(attributes, attrnames);
@@ -562,10 +565,10 @@ void softlist_parser::parse_main_start(const char *tagname, const char **attribu
else
parse_error("No name defined for item");
}
- // <notes>
else if (strcmp(tagname, "notes") == 0)
{
- m_data_accum_expected = true;
+ // <notes>
+ m_ignore_cdata = true;
}
else
unknown_tag(tagname);
@@ -574,8 +577,6 @@ void softlist_parser::parse_main_start(const char *tagname, const char **attribu
void softlist_parser::parse_main_end(const char *tagname)
{
- if (strcmp(tagname, "notes") == 0)
- m_notes = std::move(m_data_accum);
}
@@ -607,7 +608,7 @@ void softlist_parser::parse_soft_start(const char *tagname, const char **attribu
// <notes>
else if (strcmp(tagname, "notes") == 0)
- m_data_accum_expected = true;
+ m_ignore_cdata = true;
// <info name='' value=''>
else if (strcmp(tagname, "info") == 0)
@@ -884,10 +885,6 @@ void softlist_parser::parse_soft_end(const char *tagname)
else if (strcmp(tagname, "publisher") == 0)
m_current_info->m_publisher = std::move(m_data_accum);
- // <notes>
- else if (strcmp(tagname, "notes") == 0)
- m_current_info->m_notes = std::move(m_data_accum);
-
// </part>
else if (strcmp(tagname, "part") == 0)
{
@@ -915,11 +912,10 @@ void parse_software_list(
std::string_view filename,
std::string &listname,
std::string &description,
- std::string &notes,
std::list<software_info> &infolist,
std::ostream &errors)
{
- detail::softlist_parser(file, filename, listname, description, notes, infolist, errors);
+ detail::softlist_parser(file, filename, listname, description, infolist, errors);
}
diff --git a/src/emu/softlist.h b/src/emu/softlist.h
index e8587dd4505..2fd755c29cc 100644
--- a/src/emu/softlist.h
+++ b/src/emu/softlist.h
@@ -133,7 +133,6 @@ public:
const std::string &parentname() const { return m_parentname; }
const std::string &year() const { return m_year; }
const std::string &publisher() const { return m_publisher; }
- const std::string &notes() const { return m_notes; }
const std::list<software_info_item> &info() const { return m_info; }
const software_info_item::set &shared_features() const { return m_shared_features; }
software_support supported() const { return m_supported; }
@@ -151,7 +150,6 @@ private:
std::string m_parentname;
std::string m_year; // Copyright year on title screen, actual release dates can be tracked in external resources
std::string m_publisher;
- std::string m_notes;
std::list<software_info_item> m_info; // Here we store info like developer, serial #, etc. which belong to the software entry as a whole
software_info_item::set m_shared_features; // Here we store info like TV standard compatibility, or add-on requirements, etc. which get inherited
// by each part of this software entry (after loading these are stored in partdata->features)
@@ -167,7 +165,6 @@ void parse_software_list(
std::string_view filename,
std::string &listname,
std::string &description,
- std::string &notes,
std::list<software_info> &infolist,
std::ostream &errors);
diff --git a/src/emu/softlist_dev.cpp b/src/emu/softlist_dev.cpp
index 7d7e1930089..7d25dd17013 100644
--- a/src/emu/softlist_dev.cpp
+++ b/src/emu/softlist_dev.cpp
@@ -89,8 +89,7 @@ software_list_device::software_list_device(const machine_config &mconfig, const
m_list_type(softlist_type::ORIGINAL_SYSTEM),
m_filter(nullptr),
m_parsed(false),
- m_description(""),
- m_notes("")
+ m_description("")
{
}
@@ -181,7 +180,6 @@ void software_list_device::release()
m_filename.clear();
m_shortname.clear();
m_description.clear();
- m_notes.clear();
m_errors.clear();
m_infolist.clear();
}
@@ -296,7 +294,7 @@ void software_list_device::parse()
{
// parse if no error
std::ostringstream errs;
- parse_software_list(file, m_filename, m_shortname, m_description, m_notes, m_infolist, errs);
+ parse_software_list(file, m_filename, m_shortname, m_description, m_infolist, errs);
file.close();
m_errors = errs.str();
}
diff --git a/src/emu/softlist_dev.h b/src/emu/softlist_dev.h
index 2de72bd3b8f..e0e912a67f1 100644
--- a/src/emu/softlist_dev.h
+++ b/src/emu/softlist_dev.h
@@ -116,7 +116,6 @@ public:
// getters that may trigger a parse
const std::string &description() { if (!m_parsed) parse(); return m_description; }
- const std::string &notes() { if (!m_parsed) parse(); return m_notes; }
bool valid() { if (!m_parsed) parse(); return !m_infolist.empty(); }
const char *errors_string() { if (!m_parsed) parse(); return m_errors.c_str(); }
const std::list<software_info> &get_info() { if (!m_parsed) parse(); return m_infolist; }
@@ -153,7 +152,6 @@ private:
std::string m_filename;
std::string m_shortname;
std::string m_description;
- std::string m_notes;
std::string m_errors;
std::list<software_info> m_infolist;
};
diff --git a/src/frontend/mame/clifront.cpp b/src/frontend/mame/clifront.cpp
index 191ae747a4c..19160cc9784 100644
--- a/src/frontend/mame/clifront.cpp
+++ b/src/frontend/mame/clifront.cpp
@@ -1118,8 +1118,6 @@ const char cli_frontend::s_softlist_xml_dtd[] =
void cli_frontend::output_single_softlist(std::ostream &out, software_list_device &swlistdev)
{
util::stream_format(out, "\t<softwarelist name=\"%s\" description=\"%s\">\n", swlistdev.list_name(), util::xml::normalize_string(swlistdev.description().c_str()));
- if (!swlistdev.notes().empty())
- util::stream_format(out, "\t\t<notes>%s</notes>\n", util::xml::normalize_string(swlistdev.notes().c_str()));
for (const software_info &swinfo : swlistdev.get_info())
{
util::stream_format(out, "\t\t<software name=\"%s\"", util::xml::normalize_string(swinfo.shortname().c_str()));
@@ -1133,8 +1131,6 @@ void cli_frontend::output_single_softlist(std::ostream &out, software_list_devic
util::stream_format(out, "\t\t\t<description>%s</description>\n", util::xml::normalize_string(swinfo.longname().c_str()));
util::stream_format(out, "\t\t\t<year>%s</year>\n", util::xml::normalize_string(swinfo.year().c_str()));
util::stream_format(out, "\t\t\t<publisher>%s</publisher>\n", util::xml::normalize_string(swinfo.publisher().c_str()));
- if (!swinfo.notes().empty())
- util::stream_format(out, "\t\t\t<notes>%s</notes>\n", util::xml::normalize_string(swinfo.notes().c_str()));
for (const auto &flist : swinfo.info())
util::stream_format(out, "\t\t\t<info name=\"%s\" value=\"%s\"/>\n", flist.name(), util::xml::normalize_string(flist.value().c_str()));
diff --git a/src/frontend/mame/ui/menu.cpp b/src/frontend/mame/ui/menu.cpp
index 14a5c4ae0c1..d3caec1b2c2 100644
--- a/src/frontend/mame/ui/menu.cpp
+++ b/src/frontend/mame/ui/menu.cpp
@@ -556,20 +556,31 @@ void menu::draw(uint32_t flags)
float const line_y0 = visible_top + (float)linenum * line_height;
float const line_y1 = line_y0 + line_height;
+ // work out what we're dealing with
+ bool const uparrow = !linenum && show_top_arrow;
+ bool const downarrow = (linenum == (m_visible_lines - 1)) && show_bottom_arrow;
+
// set the hover if this is our item
- if (mouse_in_rect(line_x0, line_y0, line_x1, line_y1) && is_selectable(pitem))
- m_hover = itemnum;
+ bool const hovered = mouse_in_rect(line_x0, line_y0, line_x1, line_y1);
+ if (hovered)
+ {
+ if (uparrow)
+ m_hover = HOVER_ARROW_UP;
+ else if (downarrow)
+ m_hover = HOVER_ARROW_DOWN;
+ else if (is_selectable(pitem))
+ m_hover = itemnum;
+ }
- // if we're selected, draw with a different background
if (is_selected(itemnum))
{
+ // if we're selected, draw with a different background
fgcolor = fgcolor2 = fgcolor3 = ui().colors().selected_color();
bgcolor = ui().colors().selected_bg_color();
}
-
- // else if the mouse is over this item, draw with a different background
- else if (itemnum == m_hover)
+ else if (hovered && (uparrow || downarrow || is_selectable(pitem)))
{
+ // else if the mouse is over this item, draw with a different background
fgcolor = fgcolor2 = fgcolor3 = ui().colors().mouseover_color();
bgcolor = ui().colors().mouseover_bg_color();
}
@@ -578,7 +589,7 @@ void menu::draw(uint32_t flags)
if (bgcolor != ui().colors().text_bg_color())
highlight(line_x0, line_y0, line_x1, line_y1, bgcolor);
- if (linenum == 0 && show_top_arrow)
+ if (uparrow)
{
// if we're on the top line, display the up arrow
draw_arrow(
@@ -588,10 +599,8 @@ void menu::draw(uint32_t flags)
line_y0 + 0.75f * line_height,
fgcolor,
ROT0);
- if (m_hover == itemnum)
- m_hover = HOVER_ARROW_UP;
}
- else if (linenum == m_visible_lines - 1 && show_bottom_arrow)
+ else if (downarrow)
{
// if we're on the bottom line, display the down arrow
draw_arrow(
@@ -601,8 +610,6 @@ void menu::draw(uint32_t flags)
line_y0 + 0.75f * line_height,
fgcolor,
ROT0 ^ ORIENTATION_FLIP_Y);
- if (m_hover == itemnum)
- m_hover = HOVER_ARROW_DOWN;
}
else if (pitem.type == menu_item_type::SEPARATOR)
{
@@ -677,23 +684,25 @@ void menu::draw(uint32_t flags)
// apply arrows
if (is_selected(itemnum) && (pitem.flags & FLAG_LEFT_ARROW))
{
+ float const l = effective_left + effective_width - subitem_width - gutter_width;
+ float const r = l + lr_arrow_width;
draw_arrow(
- effective_left + effective_width - subitem_width - gutter_width,
- line_y0 + 0.1f * line_height,
- effective_left + effective_width - subitem_width - gutter_width + lr_arrow_width,
- line_y0 + 0.9f * line_height,
+ l, line_y0 + 0.1f * line_height, r, line_y0 + 0.9f * line_height,
fgcolor,
ROT90 ^ ORIENTATION_FLIP_X);
+ if (mouse_in_rect(l, line_y0 + 0.1f * line_height, r, line_y0 + 0.9f * line_height))
+ m_hover = HOVER_UI_LEFT;
}
if (is_selected(itemnum) && (pitem.flags & FLAG_RIGHT_ARROW))
{
+ float const r = effective_left + effective_width + gutter_width;
+ float const l = r - lr_arrow_width;
draw_arrow(
- effective_left + effective_width + gutter_width - lr_arrow_width,
- line_y0 + 0.1f * line_height,
- effective_left + effective_width + gutter_width,
- line_y0 + 0.9f * line_height,
+ l, line_y0 + 0.1f * line_height, r, line_y0 + 0.9f * line_height,
fgcolor,
ROT90);
+ if (mouse_in_rect(l, line_y0 + 0.1f * line_height, r, line_y0 + 0.9f * line_height))
+ m_hover = HOVER_UI_RIGHT;
}
}
}
@@ -856,13 +865,15 @@ void menu::handle_events(uint32_t flags, event &ev)
if (custom_mouse_down())
return;
- if ((flags & PROCESS_ONLYCHAR) == 0)
+ if (!(flags & PROCESS_ONLYCHAR))
{
if (m_hover >= 0 && m_hover < m_items.size())
+ {
m_selected = m_hover;
+ }
else if (m_hover == HOVER_ARROW_UP)
{
- if ((flags & FLAG_UI_DATS) != 0)
+ if (flags & FLAG_UI_DATS)
{
top_line -= m_visible_items - (last_item_visible() ? 1 : 0);
return;
@@ -884,6 +895,16 @@ void menu::handle_events(uint32_t flags, event &ev)
m_selected = m_items.size() - 1;
top_line += m_visible_lines - 2;
}
+ else if (m_hover == HOVER_UI_LEFT)
+ {
+ ev.iptkey = IPT_UI_LEFT;
+ stop = true;
+ }
+ else if (m_hover == HOVER_UI_RIGHT)
+ {
+ ev.iptkey = IPT_UI_RIGHT;
+ stop = true;
+ }
}
break;
diff --git a/src/frontend/mame/ui/submenu.cpp b/src/frontend/mame/ui/submenu.cpp
index d6d237cabd3..382524b636c 100644
--- a/src/frontend/mame/ui/submenu.cpp
+++ b/src/frontend/mame/ui/submenu.cpp
@@ -152,9 +152,9 @@ submenu::submenu(mame_ui_manager &mui, render_container &container, std::vector<
{
core_options *opts = nullptr;
if (m_driver == nullptr)
- opts = dynamic_cast<core_options*>(&mui.machine().options());
+ opts = dynamic_cast<core_options *>(&mui.machine().options());
else
- opts = dynamic_cast<core_options*>(options);
+ opts = dynamic_cast<core_options *>(options);
for (option & sm_option : m_options)
{
@@ -358,9 +358,9 @@ void submenu::populate(float &customtop, float &custombottom)
{
case OPTION_BOOLEAN:
item_append_on_off(_(sm_option->description),
- sm_option->options->bool_value(sm_option->name),
- 0,
- static_cast<void*>(&(*sm_option)));
+ sm_option->options->bool_value(sm_option->name),
+ 0,
+ static_cast<void*>(&(*sm_option)));
break;
case OPTION_INTEGER:
{
@@ -378,9 +378,9 @@ void submenu::populate(float &customtop, float &custombottom)
}
arrow_flags = get_arrow_flags(i_min, i_max, i_cur);
item_append(_(sm_option->description),
- sm_option->entry->value(),
- arrow_flags,
- static_cast<void*>(&(*sm_option)));
+ sm_option->entry->value(),
+ arrow_flags,
+ static_cast<void*>(&(*sm_option)));
}
break;
case OPTION_FLOAT:
@@ -400,9 +400,9 @@ void submenu::populate(float &customtop, float &custombottom)
arrow_flags = get_arrow_flags(f_min, f_max, f_cur);
std::string tmptxt = string_format("%g", f_cur);
item_append(_(sm_option->description),
- tmptxt,
- arrow_flags,
- static_cast<void*>(&(*sm_option)));
+ tmptxt,
+ arrow_flags,
+ static_cast<void*>(&(*sm_option)));
}
break;
case OPTION_STRING:
@@ -418,8 +418,8 @@ void submenu::populate(float &customtop, float &custombottom)
default:
arrow_flags = FLAG_RIGHT_ARROW;
item_append(_(sm_option->description),
- sm_option->options->value(sm_option->name),
- arrow_flags, static_cast<void*>(&(*sm_option)));
+ sm_option->options->value(sm_option->name),
+ arrow_flags, static_cast<void*>(&(*sm_option)));
break;
}
break;
diff --git a/src/frontend/mame/ui/submenu.h b/src/frontend/mame/ui/submenu.h
index 8c7744de391..f5c26c7eecb 100644
--- a/src/frontend/mame/ui/submenu.h
+++ b/src/frontend/mame/ui/submenu.h
@@ -12,9 +12,10 @@
#pragma once
-#include "emuopts.h"
#include "ui/menu.h"
+#include "emuopts.h"
+
#include <string>
#include <vector>