Merge branch 'master' into feature/lodefmode-moviecart

This commit is contained in:
Stephen Anthony 2021-08-26 19:42:43 -02:30
commit 4716079954
142 changed files with 5952 additions and 3337 deletions

View File

@ -12,6 +12,17 @@
Release History
===========================================================================
6.5.3 to 6.6 (??? ??, 202?)
* Added web links for many games
* Debugger: added optional logging of breaks and traps
* Debugger: enhanced prompt's auto complete and history
-Have fun!
6.5.2 to 6.5.3 (April 20, 2021)
* Added context-sensitive help.
@ -26,8 +37,6 @@
* Fixed immediate disassembling when switching options in debugger.
-Have fun!
6.5.1 to 6.5.2 (February 25, 2021)

View File

@ -102,10 +102,10 @@ feature that no other 2600 debugger has; it's <b>completely</b> cross-platform.<
breakpoints as you want.</li>
<li>Conditional breakpoints - Break running program when some arbitrary
condition is true (e.g. "breakif {a == $7f &amp;&amp; c}" will break when the Accumulator value is $7f and the Carry flag is true, no matter where
condition is true (e.g. "breakIf {a == $7f &amp;&amp; c}" will break when the Accumulator value is $7f and the Carry flag is true, no matter where
in the program this happens). Unlike the cond breaks in PCAE, Stella's
are *fast*: the emulation will run at full speed unless you use lots
of breakif's at the same time, or have a slow CPU.</li>
of breakIf's at the same time, or have a slow CPU.</li>
<li>Watches - View contents of a location/register before every
debugger prompt.</li>
@ -172,7 +172,7 @@ feature that no other 2600 debugger has; it's <b>completely</b> cross-platform.<
<li>Data sources for the CPU SP/A/X/Y registers, showing the resolved/source
address of of load operands.</li>
<li>Scanline advance (like frame advance, break at beginning
of next scanline).</li>
of next scanLine).</li>
<li>TIA display is updated during step/trace, so we can see our
scanlines being drawn as it happens. This isn't 100% perfect: unlike
a real TIA, the one in Stella only updates when it's written to.</li>
@ -183,7 +183,7 @@ feature that no other 2600 debugger has; it's <b>completely</b> cross-platform.<
named after the ROM image.</li>
<li>Saving the current debugger state to a script file (including
breakpoints, traps, etc).</li>
<li>Built-in functions for use with "breakif", to support common conditions
<li>Built-in functions for use with "breakIf", to support common conditions
(such as breaking when the user presses Game Select...)</li>
<li>Patching ROM in-place.</li>
<li>Save patched ROM</li>
@ -251,9 +251,9 @@ command on the command line, or alternatively within the ROM launcher in
</p>
<p>Using the ` key will always enter the debugger at the end of
the frame (for NTSC games usually scanline 262). This is because Stella only checks
the frame (for NTSC games usually scanLine 262). This is because Stella only checks
for keystrokes once per frame. Once in the debugger, you can control
execution by stepping one instruction, scanline, or frame at a time
execution by stepping one instruction, scanLine, or frame at a time
(or more than one at a time, using commands in the prompt). You can
also set breakpoints or traps, which will cause the emulator to enter
the debugger when they are triggered, even if it happens in mid-frame.</p>
@ -345,52 +345,52 @@ size can be configured e.g. in the
<p>
<table BORDER=1 cellpadding=4>
<tr>
<th>Key</th>
<th>Function</th>
<th>Key</th>
</tr>
<tr>
<td>Control + S</td>
<td>Step</td>
<td>Control + S</td>
</tr>
<tr>
<td>Control + T</td>
<td>Trace</td>
<td>Control + T</td>
</tr>
<tr>
<td>Control + L</td>
<td>Scan +1</td>
<td>Control + L</td>
</tr>
<tr>
<td>Control + F</td>
<td>Frame +1</td>
<td>Control + F</td>
</tr>
<tr>
<td>Alt + Left arrow</td>
<td>Rewind 1</td>
<td>Alt + Left arrow</td>
</tr>
<tr>
<td>Shift-Alt + Left arrow</td>
<td>Rewind 10</td>
<td>Shift-Alt + Left arrow</td>
</tr>
<tr>
<td>Alt + Down arrow</td>
<td>Rewind all</td>
<td>Alt + Down arrow</td>
</tr>
<tr>
<td>Alt + Right arrow</td>
<td>Unwind 1</td>
<td>Alt + Right arrow</td>
</tr>
<tr>
<td>Shift-Alt + Right arrow</td>
<td>Unwind 10</td>
<td>Shift-Alt + Right arrow</td>
</tr>
<tr>
<td>Alt + Up arrow</td>
<td>Unwind all</td>
<td>Alt + Up arrow</td>
</tr>
<tr>
<td>Backquote (`)</td>
<td>Run, exits debugger</td>
<td>Backquote (`)</td>
</tr>
</table>
</p>
@ -408,7 +408,7 @@ in detail in the <a href="index.html">User's Guide</a>.</p>
<p>The debugger tracks changes to the CPU, TIA and RIOT registers and RAM by
displaying changed locations or registers with a red background after each step,
trace, scanline, or frame advance. This sounds simple, and it is, but
trace, scanLine, or frame advance. This sounds simple, and it is, but
it's also amazingly useful.</p>
<p>One clarification about the change tracking: it only tracks when values
@ -428,25 +428,28 @@ or Supermon for the C=64.</p>
Bash-style commands are also supported:</p>
<table border="1" cellpadding=4>
<tr><th>Key</th><th>Function</th></tr>
<tr><td>Home</td><td>Move cursor to beginning of line</td></tr>
<tr><td>End</td><td>Move cursor to end of line</td></tr>
<tr><td>Delete</td><td>Remove character to right of cursor</td></tr>
<tr><td>Backspace</td><td>Remove character to left of cursor</td></tr>
<tr><td>Control + A</td><td>Same function as 'Home'</td></tr>
<tr><td>Control + E</td><td>Same function as 'End'</td></tr>
<tr><td>Control + D</td><td>Same function as 'Delete'</td></tr>
<tr><td>Control + K</td><td>Remove all characters from cursor to end of line</td></tr>
<tr><td>Control + U</td><td>Remove all characters from cursor to beginning of line</td></tr>
<tr><td>Control + W</td><td>Remove entire word to left of cursor</td></tr>
<tr><td>Shift + PgUp</td><td>Scroll up through previous commands one screen/page</td></tr>
<tr><td>Shift + PgDown</td><td>Scroll down through previous commands one screen/page</td></tr>
<tr><td>Shift + Up</td><td>Scroll up through previous commands one line</td></tr>
<tr><td>Shift + Down</td><td>Scroll down through previous commands one line</td></tr>
<tr><td>Shift + Home</td><td>Scroll to beginning of commands</td></tr>
<tr><td>Shift + End</td><td>Scroll to end of commands</td></tr>
<tr><th>Function</th><th>Key</th></tr>
<tr><td>Move cursor to beginning of line</td><td>Home</td></tr>
<tr><td>Move cursor to end of line</td><td>End</td></tr>
<tr><td>Remove character to right of cursor</td><td>Delete</td></tr>
<tr><td>Remove character to left of cursor</td><td>Backspace</td></tr>
<tr><td>Same function as 'Home'</td><td>Control + A</td></tr>
<tr><td>Same function as 'End'</td><td>Control + E</td></tr>
<tr><td>Same function as 'Delete'</td><td>Control + D</td></tr>
<tr><td>Remove all characters from cursor to end of line</td><td>Control + K</td></tr>
<tr><td>Remove all characters from cursor to beginning of line</td><td>Control + U</td></tr>
<tr><td>Remove entire word to left of cursor</td><td>Control + W</td></tr>
<tr><td>Copy current line</td><td>Control + C</td></tr>
<tr><td>Cut current line</td><td>Control + X</td></tr>
<tr><td>Paste over current line</td><td>Control + V</td></tr>
<tr><td>Scroll up through previous commands one screen/page</td><td>Shift + PgUp</td></tr>
<tr><td>Scroll down through previous commands one screen/page</td><td>Shift + PgDown</td></tr>
<tr><td>Scroll up through previous commands one line</td><td>Shift + Up</td></tr>
<tr><td>Scroll down through previous commands one line</td><td>Shift + Down</td></tr>
<tr><td>Scroll to beginning of commands</td><td>Shift + Home</td></tr>
<tr><td>Scroll to end of commands</td><td>Shift + End</td></tr>
</table>
<p>You can also scroll with the mouse. Copy and paste is not yet supported.</p>
<p>You can also scroll with the mouse. Copy and paste is currently only supported for a complete line.</p>
<p>To see the available commands, enter "help". For extended help, type "help cmd",
where 'cmd' is the command you wish to know about. The available commands are listed
@ -467,16 +470,16 @@ just by re-running the relevant commands in the prompt.</p>
<h3><a name="TabCompletion">Tab Key Auto-Complete</a></h3>
<p>While entering a command, label or function, you can type a partial name and
press the Tab key to attempt to auto-complete it. If you've ever used
press the (Shift +) Tab key to attempt to auto-complete it. If you've ever used
"bash", this will be immediately familiar. If not, try it: load up
a ROM, go to the debugger, type "g" (but don't press Enter),
then hit Tab. The "g" will change to "gfx" (since this is the only
built-in command starting with a "g"). If there are multiple possible
completions (try with "tr" instead of "g"), you'll see a list of them,
and your partial name will be completed as far as possible.
completions (try with "tr" instead of "g"), you can tab through them.
After the first character, the autocompletion considers all
characters in the right order as a match (e.g. "twf" will be completed to
"trapwriteif").</p>
"trapWriteIf"). Alternatively you can make use of the camel case names and type
e.g. "tWI" ("trapWriteIf") or "lAS" ("LoadAllStates").</p>
<p>Tab completion works on all labels: built-in, loaded from a symbol file,
or set during debugging with the "define" command. It also works with
@ -609,7 +612,7 @@ command that takes arguments.</p>
<h4><a name="Breakpoints">Breakpoints</a></h4>
<p>A breakpoint is a "hotspot" in your program that causes the emulator
to stop emulating and jump into the debugger. You can set as many
to stop emulating and jump into the debugger &#185;. You can set as many
breakpoints as you like. The command is "break xx yy" where xx is any
expression and yy a bank number. Both arguments are optional. If you have
created a symbol file, you can use labels for the expression.</p>
@ -630,8 +633,11 @@ set it. In the example, "break kernel" will remove the breakpoint.
The "break" command can be thought of as a *toggle*: it turns the
breakpoint on &amp; off, like a light switch.</p>
<p>You could also use "clearbreaks" to remove all the breakpoints. Also,
there is a "listbreaks" command that will list them all.</p>
<p>You could also use "clearBreaks" to remove all the breakpoints. Also,
there is a "listBreaks" command that will list them all.</p>
<p>&#185; By enabling "logBreaks" you can log the current state into
the System Log and continue emulation instead.</p>
<h4><a name="ConditionalBreaks">Conditional Breaks</a></h4>
@ -661,10 +667,10 @@ is the "!" operator): !(*SWCHB&amp;1). The parentheses are necessary as
we want to apply the ! to the result of the &amp;, not just the first term
(the "*SWCHB").</p>
<p>"breakif !(*SWCHB&amp;1)" will do the job for us. However, it's an ugly mess
<p>"breakIf !(*SWCHB&amp;1)" will do the job for us. However, it's an ugly mess
of letters, numbers, and punctuation. We can do a little better:</p>
<p>"breakif { !(*SWCHB &amp; 1 ) }" is a lot more readable, isn't it? If
<p>"breakIf { !(*SWCHB &amp; 1 ) }" is a lot more readable, isn't it? If
you're going to use readable expressions with spaces in them,
enclose the entire expression in curly braces.</p>
@ -673,9 +679,9 @@ condition that depends on input (like SWCHB) will always happen at the
end of a frame. This is different from how a real 2600 works, but most
ROMs only check for input once per frame anyway.</p>
<p>Conditional breaks appear in "listbreaks", numbered starting from
zero. You can remove a cond-break with "delbreakif number", where
the number comes from "listbreaks" or by entering the same conditional break again.</p>
<p>Conditional breaks appear in "listBreaks", numbered starting from
zero. You can remove a cond-break with "delBreakIf number", where
the number comes from "listBreaks" or by entering the same conditional break again.</p>
<p>Any time the debugger is entered due to a trap, breakpoint, or
conditional break, the reason will be displayed in the
@ -684,16 +690,16 @@ conditional break, the reason will be displayed in the
<h4><a name="Functions">Functions</a></h4>
<p>There is one annoyance about complex expressions: once we
remove the conditional break with "delbreakif" or "clearbreaks",
remove the conditional break with "delBreakIf" or "clearBreaks",
we'd have to retype it (or search backwards with the up-arrow key)
if we wanted to use it again.</p>
<p>We can avoid this by defining the expression as a function, then using
"breakif function_name":</p>
"breakIf function_name":</p>
<pre>
function gameReset { !(*SWCHB &amp; 1 ) }
breakif gameReset
breakIf gameReset
</pre>
<p>Now we have a meaningful name for the condition, so we can use it again.
@ -703,16 +709,16 @@ if the Game Select switch is pressed. We want to break when the user
presses both Select and Reset:</p>
<pre>
breakif { gameReset &amp;&amp; gameSelect }
breakIf { gameReset &amp;&amp; gameSelect }
</pre>
<p>User-defined functions appear in "listfunctions", which shows the label
<p>User-defined functions appear in "listFunctions", which shows the label
and expression for each function. Functions can be removed with
"delfunction label", where the labels come from "listfunctions".</p>
"delFunction label", where the labels come from "listFunctions".</p>
<h4><a name="BuiltInFunctions">Built-in Functions</a></h4>
<p>Stella has some pre-defined functions for use with the "breakif"
<p>Stella has some pre-defined functions for use with the "breakIf"
command. These allow you to break and enter the debugger on various
conditions without having to define the conditions yourself.</p>
@ -723,24 +729,24 @@ Stella debugger.</p>
<table border="1" cellpadding=4>
<tr><th>Function</th><th>Definition</th><th>Description</th></tr>
<tr><td> _joy0left</td><td> !(*SWCHA &amp; $40)</td><td> Left joystick moved left</td></tr>
<tr><td> _joy0right</td><td> !(*SWCHA &amp; $80)</td><td> Left joystick moved right</td></tr>
<tr><td> _joy0up</td><td> !(*SWCHA &amp; $10)</td><td> Left joystick moved up</td></tr>
<tr><td> _joy0down</td><td> !(*SWCHA &amp; $20)</td><td> Left joystick moved down</td></tr>
<tr><td> _joy0button</td><td> !(*INPT4 &amp; $80)</td><td> Left joystick button pressed</td></tr>
<tr><td> _joy1left</td><td> !(*SWCHA &amp; $04)</td><td> Right joystick moved left</td></tr>
<tr><td> _joy1right</td><td> !(*SWCHA &amp; $08)</td><td> Right joystick moved right</td></tr>
<tr><td> _joy1up</td><td> !(*SWCHA &amp; $01)</td><td> Right joystick moved up</td></tr>
<tr><td> _joy1down</td><td> !(*SWCHA &amp; $02)</td><td> Right joystick moved down</td></tr>
<tr><td> _joy1button</td><td> !(*INPT5 &amp; $80)</td><td> Right joystick button pressed</td></tr>
<tr><td> _joy0Left</td><td> !(*SWCHA &amp; $40)</td><td> Left joystick moved left</td></tr>
<tr><td> _joy0Right</td><td> !(*SWCHA &amp; $80)</td><td> Left joystick moved right</td></tr>
<tr><td> _joy0Up</td><td> !(*SWCHA &amp; $10)</td><td> Left joystick moved up</td></tr>
<tr><td> _joy0Down</td><td> !(*SWCHA &amp; $20)</td><td> Left joystick moved down</td></tr>
<tr><td> _joy0Fire</td><td> !(*INPT4 &amp; $80)</td><td> Left joystick fire button pressed</td></tr>
<tr><td> _joy1Left</td><td> !(*SWCHA &amp; $04)</td><td> Right joystick moved left</td></tr>
<tr><td> _joy1Right</td><td> !(*SWCHA &amp; $08)</td><td> Right joystick moved right</td></tr>
<tr><td> _joy1Up</td><td> !(*SWCHA &amp; $01)</td><td> Right joystick moved up</td></tr>
<tr><td> _joy1Down</td><td> !(*SWCHA &amp; $02)</td><td> Right joystick moved down</td></tr>
<tr><td> _joy1Fire</td><td> !(*INPT5 &amp; $80)</td><td> Right joystick fire button pressed</td></tr>
<tr><td> _select</td><td> !(*SWCHB &amp; $02)</td><td> Game Select pressed</td></tr>
<tr><td> _reset</td><td> !(*SWCHB &amp; $01)</td><td> Game Reset pressed</td></tr>
<tr><td> _color</td><td> *SWCHB &amp; $08</td><td> Color/BW set to Color</td></tr>
<tr><td> _bw</td><td> !(*SWCHB &amp; $08)</td><td> Color/BW set to BW</td></tr>
<tr><td> _diff0b</td><td> !(*SWCHB &amp; $40)</td><td> Left difficulty set to B (easy)</td></tr>
<tr><td> _diff0a</td><td> *SWCHB &amp; $40</td><td> Left difficulty set to A (hard)</td></tr>
<tr><td> _diff1b</td><td> !(*SWCHB &amp; $80)</td><td> Right difficulty set to B (easy)</td></tr>
<tr><td> _diff1a</td><td> *SWCHB &amp; $80</td><td> Right difficulty set to A (hard)</td></tr>
<tr><td> _diff0B</td><td> !(*SWCHB &amp; $40)</td><td> Left difficulty set to B (easy)</td></tr>
<tr><td> _diff0A</td><td> *SWCHB &amp; $40</td><td> Left difficulty set to A (hard)</td></tr>
<tr><td> _diff1B</td><td> !(*SWCHB &amp; $80)</td><td> Right difficulty set to B (easy)</td></tr>
<tr><td> _diff1A</td><td> *SWCHB &amp; $80</td><td> Right difficulty set to A (hard)</td></tr>
</table>
<p>Don't worry about memorizing them all: the Prompt "help" command
@ -756,36 +762,36 @@ that holds 'number of scanlines' on an actual console).</p>
<table border="1" cellpadding=4>
<tr><th>Function</th><th>Description</th></tr>
<tr><td> _bank</td><td> Currently selected bank</td></tr>
<tr><td> _cclocks</td><td> Color clocks on a scanline</td></tr>
<tr><td> _cycleshi</td><td> Higher 32 bits of number of cycles since emulation started</td></tr>
<tr><td> _cycleslo</td><td> Lower 32 bits of number of cycles since emulation started</td></tr>
<tr><td> _fcount</td><td> Number of frames since emulation started</td></tr>
<tr><td> _fcycles</td><td> Number of cycles since frame started</td></tr>
<tr><td> _ftimreadcycles</td><td>Number of cycles used by timer reads since frame started</td></tr>
<tr><td> _fwsynccycles</td><td>Number of cycles skipped by WSYNC since frame started</td></tr>
<tr><td> _icycles</td><td> Number of cycles of last instruction</td></tr>
<tr><td> _scan</td><td> Current scanline count</td></tr>
<tr><td> _scanend</td><td> Scanline count at end of last frame</td></tr>
<tr><td> _scycles</td><td> Number of cycles in current scanline</td></tr>
<tr><td> _timwrapread</td><td> Timer read wrapped on this cycle</td></tr>
<tr><td> _timwrapwrite</td><td> Timer write wrapped on this cycle</td></tr>
<tr><td> _vblank</td><td> Whether vertical blank is enabled (1 or 0)</td></tr>
<tr><td> _vsync</td><td> Whether vertical sync is enabled (1 or 0)</td></tr>
<tr><td> _cClocks</td><td> Color clocks on a scanLine</td></tr>
<tr><td> _cyclesHi</td><td> Higher 32 bits of number of cycles since emulation started</td></tr>
<tr><td> _cyclesLo</td><td> Lower 32 bits of number of cycles since emulation started</td></tr>
<tr><td> _fCount</td><td> Number of frames since emulation started</td></tr>
<tr><td> _fCycles</td><td> Number of cycles since frame started</td></tr>
<tr><td> _fTimReadCycles</td><td>Number of cycles used by timer reads since frame started</td></tr>
<tr><td> _fWsyncCycles</td><td>Number of cycles skipped by WSYNC since frame started</td></tr>
<tr><td> _iCycles</td><td> Number of cycles of last instruction</td></tr>
<tr><td> _scan</td><td> Current scanLine count</td></tr>
<tr><td> _scanEnd</td><td> Scanline count at end of last frame</td></tr>
<tr><td> _sCycles</td><td> Number of cycles in current scanLine</td></tr>
<tr><td> _timWrapRead</td><td> Timer read wrapped on this cycle</td></tr>
<tr><td> _timWrapWrite</td><td> Timer write wrapped on this cycle</td></tr>
<tr><td> _vBlank</td><td> Whether vertical blank is enabled (1 or 0)</td></tr>
<tr><td> _vSync</td><td> Whether vertical sync is enabled (1 or 0)</td></tr>
</table>
<p><b>_scan</b> always contains the current scanline count. You can use
<p><b>_scan</b> always contains the current scanLine count. You can use
this to break your program in the middle of your kernel. Example:</p>
<pre>
breakif _scan==#64
breakIf _scan==#64
</pre>
<p>This will cause Stella to enter the debugger when the TIA reaches the
beginning of the 64th scanline.</p>
beginning of the 64th scanLine.</p>
<p><b>_bank</b> always contains the currently selected bank. For 2K or 4K
(non-bankswitched) ROMs, it will always contain 0. One useful use is:</p>
<pre>
breakif { pc==myLabel &amp;&amp; _bank==1 }
breakIf { pc==myLabel &amp;&amp; _bank==1 }
</pre>
<p>This is similar to setting a regular breakpoint, but it will only trigger
@ -804,8 +810,8 @@ pointed to by the Y register, even if the Y register changes.</p>
<p>The watches are numbered. The numbers are printed along with the
watches, so you can tell which is which. To delete a watch use the
"delwatch" command with the watch number (1 to whatever). You can
also delete them all with the "clearwatches" command.</p>
"delWatch" command with the watch number (1 to whatever). You can
also delete them all with the "clearWatches" command.</p>
<p>Note that there's no real point in watching a label or CPU register
without dereferencing it: Labels are constants, and CPU registers
@ -818,7 +824,7 @@ accesses to a memory address, rather than specific location in the
program. They're useful for finding code that modifies TIA registers
or memory.</p>
<p>Traps can also combined with a condition ("trapif"). If an access
<p>Traps can also combined with a condition ("trapIf"). If an access
to a memory address is caught, the condition is evaluated additionally.
Only if the condition is true too, the emulations stops. For details
about conditions see <a href="#ConditionalBreaks"><b>Conditional Breaks</b></a> described above.</p>
@ -842,12 +848,12 @@ so the best we can do is stop before the next instruction runs.</p>
<p>Traps come in two varieties: read access traps and write access traps.
It is possible to set both types of trap on the same address (that's
what the plain "trap" command does). To set a read or write only trap,
use "trapread(if)" or "trapwrite(if)".
use "trapRead(if)" or "trapWrite(if)".
<p>All traps appear in "listtraps", numbered starting from zero. You
can remove a trap with "deltrap number", where the number comes from
"listtraps" or by entering the identical trap again. You can get rid of
all traps at once with the "cleartraps" command.</p></p>
<p>All traps appear in "listTraps", numbered starting from zero. You
can remove a trap with "delTrap number", where the number comes from
"listTraps" or by entering the identical trap again. You can get rid of
all traps at once with the "clearTraps" command.</p></p>
</br>
<h3><a name="SaveWork">Save your work!</a></h3>
@ -856,58 +862,61 @@ later re-use.</p>
<ul>
<li>
<b><a name="savecmd">save</a></b>: If you've defined a lot of complex functions, you probably will
want to re-use them in future runs of the debugger. You can save all
your functions, breakpoints, conditional breaks, traps and watches with the
"save" command. If you name your saved file the same as the ROM filename
and place it in the ROM directory, it will be auto-loaded next time you
load the same ROM in Stella. The saved file is just a plain text file
called "&lt;rom_filename&gt;.script", so you can edit it and add new functions, etc.
<b><a name="savecmd">save</a></b>: If you've defined a lot of complex
functions, you probably will want to re-use them in future runs of the
debugger. You can save all your functions, breakpoints, conditional breaks,
traps and watches with the "save" command. By default it is saved in the
user directory with the same as the ROM filename. In this case it will be
auto-loaded next time you load the same ROM in Stella. The saved file is
just a plain text file called "&lt;rom_filename&gt;.script", so you can
edit it and add more functions, etc.
<p>Use "autoSave" to automatically execute the "save" command when
exiting the debugger.</p>
<p>Note: While "save" is ROM specific, you can also create a file called
"autoexec.script" which will be loaded when the debugger starts, no matter
what ROM you have loaded.<p>
See <a href="#Startup"><b>Startup</b></a> for details.
</li>
<li>
<b>saveconfig</b>: The "saveconfig" command creates a
<b>saveConfig</b>: The "saveConfig" command creates a
<a href="#DistellaConfiguration"><b>DiStella Configuration File</b></a> which is
based on Stella's dynamic and static analysis of the current ROM.
<p>This will be automatically loaded the next time your start the debugger.
From there on, you can continue analyzing the ROM and then use "saveconfig"
again to update the configuration. You can also use "loadconfig" to load it
From there on, you can continue analyzing the ROM and then use "saveConfig"
again to update the configuration. You can also use "loadConfig" to load it
manually.
<p>Note that this is not tested for multi-banked ROMs.</p>
</li>
<li>
<b>savedis</b>:
<b>saveDis</b>:
While your are playing or debugging a game, Stella will gather dynamic
information about the ROM. It can then use that information together with
a static analysis of the ROM and therefore create a better disassembly
than DiStella alone. "savedis" allows you to save that disassembly as the
than DiStella alone. "saveDis" allows you to save that disassembly as the
result of this combined analysis.
<p>Note that this currently only works for single banked ROMs. For larger
ROMs, the created disassembly is incomplete.</p>
</li>
<li>
<p><b>saverom</b>:
If you have manipulated a ROM, you can save it with "saverom". The file is
<p><b>saveRom</b>:
If you have manipulated a ROM, you can save it with "saveRom". The file is
named "&lt;rom_filename&gt;.a26".</p>
</li>
<li>
<p><b>saveses</b>:
The "saveses" command dumps the whole prompt session into a file named
<p><b>saveSes</b>:
The "saveSes" command dumps the whole prompt session into a file named
"&lt;YYYY-MM-DD_HH-mm-ss&gt;.txt". So you can later lookup what you did exactly
when you were debugging at that time.</p>
</li>
<li>
<p><b>saveallstates</b>:
<p><b>saveAllStates</b>:
This command works identical to the save all states hotkey (Alt + F9) during emulation.
The saved states can be loaded with "loadallstates".</p>
The saved states can be loaded with "loadAllStates".</p>
</li>
<li>
<p><b>savestate</b>:
<p><b>saveState</b>:
This command works identical to the save state hotkey (F9) during emulation.
Any previously saved state can be loaded with "loadstate" plus the slot
Any previously saved state can be loaded with "loadState" plus the slot
number (0-9).</p>
</li>
</ul>
@ -921,63 +930,66 @@ Type "help 'cmd'" to see extended information about the given command.</p>
<pre>
a - Set Accumulator to &lt;value&gt;
aud - Mark 'AUD' range in disassembly
autoSave - Automatically execute "save" when exiting the debugger
base - Set default number base to &lt;base&gt; (bin, dec, hex)
bcol - Mark 'BCOL' range in disassembly
bCol - Mark 'BCOL' range in disassembly
break - Set/clear breakpoint at &lt;address&gt; and &lt;bank&gt;
breakif - Set/clear breakpoint on &lt;condition&gt;
breaklabel - Set/clear breakpoint on &lt;address&gt; (no mirrors, all banks)
breakIf - Set/clear breakpoint on &lt;condition&gt;
breakLabel - Set/clear breakpoint on &lt;address&gt; (no mirrors, all banks)
c - Carry Flag: set (0 or 1), or toggle (no arg)
cheat - Use a cheat code (see manual for cheat types)
clearbreaks - Clear all breakpoints
clearconfig - Clear DiStella config directives [bank xx]
clearsavestateifs - Clear all savestate points
cleartraps - Clear all traps
clearwatches - Clear all watches
clearBreaks - Clear all breakpoints
clearConfig - Clear DiStella config directives [bank xx]
clearHistory - Clear the prompt history
clearSaveStateIfs - Clear all saveState points
clearTraps - Clear all traps
clearWatches - Clear all watches
cls - Clear prompt area of text
code - Mark 'CODE' range in disassembly
col - Mark 'COL' range in disassembly
colortest - Show value xx as TIA color
colorTest - Show value xx as TIA color
d - Decimal Mode Flag: set (0 or 1), or toggle (no arg)
data - Mark 'DATA' range in disassembly
debugcolors - Show Fixed Debug Colors information
debugColors - Show Fixed Debug Colors information
define - Define label xx for address yy
delbreakif - Delete conditional breakif &lt;xx&gt;
delfunction - Delete function with label xx
delsavestateif - Delete conditional savestate point &lt;xx&gt;
deltrap - Delete trap &lt;xx&gt;
delwatch - Delete watch &lt;xx&gt;
disasm - Disassemble address xx [yy lines] (default=PC)
delBreakIf - Delete conditional breakIf &lt;xx&gt;
delFunction - Delete function with label xx
delSaveStateIf - Delete conditional saveState point &lt;xx&gt;
delTrap - Delete trap &lt;xx&gt;
delWatch - Delete watch &lt;xx&gt;
disAsm - Disassemble address xx [yy lines] (default=PC)
dump - Dump data at address &lt;xx&gt; [to yy] [1: memory; 2: CPU state; 4: input regs] [?]
exec - Execute script file &lt;xx&gt; [prefix]
exitrom - Exit emulator, return to ROM launcher
exitRom - Exit emulator, return to ROM launcher
frame - Advance emulation by &lt;xx&gt; frames (default=1)
function - Define function name xx for expression yy
gfx - Mark 'GFX' range in disassembly
help - help &lt;command&gt;
joy0up - Set joystick 0 up direction to value &lt;x&gt; (0 or 1), or toggle (no arg)
joy0down - Set joystick 0 down direction to value &lt;x&gt; (0 or 1), or toggle (no arg)
joy0left - Set joystick 0 left direction to value &lt;x&gt; (0 or 1), or toggle (no arg)
joy0right - Set joystick 0 right direction to value <x> (0 or 1), or toggle (no arg)
joy0fire - Set joystick 0 fire button to value &lt;x&gt; (0 or 1), or toggle (no arg)
joy1up - Set joystick 1 up direction to value &lt;x&gt; (0 or 1), or toggle (no arg)
joy1down - Set joystick 1 down direction to value &lt;x&gt; (0 or 1), or toggle (no arg)
joy1left - Set joystick 1 left direction to value &lt;x&gt; (0 or 1), or toggle (no arg)
joy1right - Set joystick 1 right direction to value &lt;x&gt; (0 or 1), or toggle (no arg)
joy1fire - Set joystick 1 fire button to value &lt;x&gt; (0 or 1), or toggle (no arg)
joy0Up - Set joystick 0 up direction to value &lt;x&gt; (0 or 1), or toggle (no arg)
joy0Down - Set joystick 0 down direction to value &lt;x&gt; (0 or 1), or toggle (no arg)
joy0Left - Set joystick 0 left direction to value &lt;x&gt; (0 or 1), or toggle (no arg)
joy0Right - Set joystick 0 right direction to value <x> (0 or 1), or toggle (no arg)
joy0Fire - Set joystick 0 fire button to value &lt;x&gt; (0 or 1), or toggle (no arg)
joy1Up - Set joystick 1 up direction to value &lt;x&gt; (0 or 1), or toggle (no arg)
joy1Down - Set joystick 1 down direction to value &lt;x&gt; (0 or 1), or toggle (no arg)
joy1Left - Set joystick 1 left direction to value &lt;x&gt; (0 or 1), or toggle (no arg)
joy1Right - Set joystick 1 right direction to value &lt;x&gt; (0 or 1), or toggle (no arg)
joy1Fire - Set joystick 1 fire button to value &lt;x&gt; (0 or 1), or toggle (no arg)
jump - Scroll disassembly to address xx
listbreaks - List breakpoints
listconfig - List DiStella config directives [bank xx]
listfunctions - List user-defined functions
listsavestateifs - List savestate points
listtraps - List traps
loadconfig - Load DiStella config file
loadallstates - Load all emulator states
loadstate - Load emulator state xx (0-9)
listBreaks - List breakpoints
listConfig - List DiStella config directives [bank xx]
listFunctions - List user-defined functions
listSaveStateIfs - List saveState points
listTraps - List traps
loadConfig - Load DiStella config file
loadAllStates - Load all emulator states
loadState - Load emulator state xx (0-9)
logBreaks - Logs breaks and traps and continues emulation
n - Negative Flag: set (0 or 1), or toggle (no arg)
palette - Show current TIA palette
pc - Set Program Counter to address xx
pcol - Mark 'PCOL' range in disassembly
pgfx - Mark 'PGFX' range in disassembly
pCol - Mark 'PCOL' range in disassembly
pGfx - Mark 'PGFX' range in disassembly
print - Evaluate/print expression xx in hex/dec/binary
ram - Show ZP RAM, or set address xx to yy1 [yy2 ...]
reset - Reset system to power-on state
@ -986,32 +998,32 @@ clearsavestateifs - Clear all savestate points
rom - Set ROM address xx to yy1 [yy2 ...]
row - Mark 'ROW' range in disassembly
run - Exit debugger, return to emulator
runto - Run until string xx in disassembly
runtopc - Run until PC is set to value xx
runTo - Run until string xx in disassembly
runToPc - Run until PC is set to value xx
s - Set Stack Pointer to value xx
save - Save breaks, watches, traps and functions to file <xx or ?>
saveaccess - Save access counters to CSV file [?]
saveconfig - Save DiStella config file (with default name)
savedis - Save DiStella disassembly to file [?]
saverom - Save (possibly patched) ROM to file [?]
saveses - Save console session to file [?]
savesnap - Save current TIA image to PNG file
saveallstates - Save all emulator states
savestate - Save emulator state xx (valid args 0-9)
savestateif - Create savestate on &lt;condition&gt;
scanline - Advance emulation by &lt;xx&gt; scanlines (default=1)
save - Save breaks, watches, traps and functions to file [xx or ?]
saveAccess - Save access counters to CSV file [?]
saveConfig - Save DiStella config file (with default name)
saveDis - Save DiStella disassembly to file [?]
saveRom - Save (possibly patched) ROM to file [?]
saveSes - Save console session to file [?]
saveSnap - Save current TIA image to PNG file
saveAllStates - Save all emulator states
saveState - Save emulator state xx (valid args 0-9)
saveStateIf - Create saveState on &lt;condition&gt;
scanLine - Advance emulation by &lt;xx&gt; scanlines (default=1)
step - Single step CPU [with count xx]
stepwhile - Single step CPU while &lt;condition&gt; is true
stepWhile - Single step CPU while &lt;condition&gt; is true
tia - Show TIA state
trace - Single step CPU over subroutines [with count xx]
trap - Trap read/write access to address(es) xx [yy]
trapif - On &lt;condition&gt; trap R/W access to address(es) xx [yy]
trapread - Trap read access to address(es) xx [yy]
trapreadif - On &lt;condition&gt; trap read access to address(es) xx [yy]
trapwrite - Trap write access to address(es) xx [yy]
trapwriteif - On &lt;condition&gt; trap write access to address(es) xx [yy]
trapIf - On &lt;condition&gt; trap R/W access to address(es) xx [yy]
trapRead - Trap read access to address(es) xx [yy]
trapReadIf - On &lt;condition&gt; trap read access to address(es) xx [yy]
trapWrite - Trap write access to address(es) xx [yy]
trapWriteIf - On &lt;condition&gt; trap write access to address(es) xx [yy]
type - Show disassembly type for address xx [yy]
uhex - Toggle upper/lowercase HEX display
uHex - Toggle upper/lowercase HEX display
undef - Undefine label xx (if defined)
unwind - Unwind state state by one or [xx] steps/traces/scanlines/frames...
v - Overflow Flag: set (0 or 1), or toggle (no arg)
@ -1111,12 +1123,12 @@ volume resulting from the two channel volumes.</p>
<p>In the upper left of the debugger, you'll see the current frame of
video as generated by the TIA. If a complete frame hasn't been drawn,
the partial contents of the current frame will be displayed up to the
current scanline, with the contents of the old frame (in black &amp;
current scanLine, with the contents of the old frame (in black &amp;
white) filling the rest of the display. Note that if 'phosphor mode'
or TV effects are enabled, you won't see the effects here; this shows the
<b>raw</b> TIA image only.</p>
<p>To e.g. watch the TIA draw the frame one scanline at a time, you can
<p>To e.g. watch the TIA draw the frame one scanLine at a time, you can
use the 'Scan+1' button, the prompt "scan" command or the Control-L key.</p>
<p>You can also right-click anywhere in this window to show a context menu,
@ -1124,10 +1136,10 @@ as illustrated:</p>
<p><img src="graphics/debugger_tiaoutcmenu.png"></p>
<p>The options are as follows:</p>
<ul>
<li><b>Fill to scanline</b>: This option will draw all scanlines up to the
<li><b>Fill to scanLine</b>: This option will draw all scanlines up to the
vertical position where the mouse was clicked (see also <a href="#TIAZoom"><b>TIA Zoom</b></a>).</li>
<li><b>Toggle breakpoint</b>: Will toggle a conditional breakpoint at the
scanline where the mouse was clicked. You can also use a left-click or
scanLine where the mouse was clicked. You can also use a left-click or
the Prompt Tab commands to list and turn off the breakpoint
(see also <a href="#TIAZoom"><b>TIA Zoom</b></a>).</li>
<li><b>Set zoom position</b>: Influences what is shown in the TIA
@ -1148,27 +1160,27 @@ as illustrated:</p>
<p>The indicators are as follows (note that all these are read-only):</p>
<ul>
<li><b>Frame Cycls</b>: The number of CPU cycles that have been executed this frame since
VSYNC was cleared at scanline 0.</li>
VSYNC was cleared at scanLine 0.</li>
<li><b>WSync Cycls</b>: The number of CPU cycles that have been skipped by WSYNC this frame since
VSYNC was cleared at scanline 0.</li>
VSYNC was cleared at scanLine 0.</li>
<li><b>Timer Cycls</b>: The number of CPU cycles (approximately) that have been used by timer read loops since
VSYNC was cleared at scanline 0.</li>
VSYNC was cleared at scanLine 0.</li>
<li><b>Total</b>: The total number of CPU cycles since this ROM was loaded or reset.</li>
<li><b>Delta</b>: The number of CPU cycles that have been executed since the last debugger
interrupt.</li>
<li><b>Frame Cnt.</b>: The number of frames since this ROM was loaded or reset.</li>
<li><b>Scanline</b>: The scanline that's currently being drawn, and the count from the
<li><b>Scanline</b>: The scanLine that's currently being drawn, and the count from the
previous frame. Scanline 0 is the one on which VSYNC is cleared (after being set for
3 scanlines, as per the Stella Programmer's Guide).</li>
<li><b>Scan Cycle</b>: The number of CPU cycles that have been executed since the beginning
of the current scanline.</li>
of the current scanLine.</li>
<li><b>Pixel Pos</b>: The current number of visible color clocks that have been displayed on
the current scanline, starting from the beginning of the Horizontal Blank period.
the current scanLine, starting from the beginning of the Horizontal Blank period.
During HBLANK, this value will be negative (representing the number of clocks
until the first visible one). Since there are 68 color clocks per HBLANK and
160 visible clocks per scanline, the Pixel Position will range from -68 to 159.</li>
160 visible clocks per scanLine, the Pixel Position will range from -68 to 159.</li>
<li><b>Color Clock</b>: The current number of total color clocks since the beginning of this
scanline's HBLANK. This counter starts at zero, but otherwise displays the same
scanLine's HBLANK. This counter starts at zero, but otherwise displays the same
information as the Pixel Position (so Color Clock will always be 68 more than Pixel
Position, and will range from 0 to 228).</li>
</ul>
@ -1186,10 +1198,10 @@ as illustrated:</p>
<p><img src="graphics/debugger_tiazoomcmenu.png"></p>
<p>These options allow you to:</p>
<ul>
<li><b>Fill to scanline</b>: This option will draw all scanlines up to the
<li><b>Fill to scanLine</b>: This option will draw all scanlines up to the
vertical position where the mouse was clicked.</li>
<li><b>Toggle breakpoint</b>: Will toggle a conditional breakpoint at the
scanline where the mouse was clicked. You can also
scanLine where the mouse was clicked. You can also
the Prompt Tab commands to list and turn off the breakpoint.</li>
<li><b>2x|4x|8x zoom</b>: Zoom in on the image for even greater detail.</li>
</ul>
@ -1375,7 +1387,7 @@ labels. Normally there will be nothing there: this indicates that there's
no breakpoint set at that address. You can set and clear breakpoints by
clicking in this area. When a breakpoint is set, there will be a
red circle in this area. These are the same breakpoints as used
by the <a href="#Breakpoints">break</a> command, <b>not</b> the conditional "breakif" breakpoints
by the <a href="#Breakpoints">break</a> command, <b>not</b> the conditional "breakIf" breakpoints
(which makes sense: conditional breaks can break on any condition, the Program
Counter isn't necessarily involved).</li>
<li><b>Labels</b>: Any labels assigned to the given address, either generated
@ -1473,7 +1485,7 @@ or lowercase for "illegal" 6502 instructions (like "dcp"). If automatic resolvin
of code sections has been disabled for any reason, you'll likely see a lot
of illegal opcodes if you scroll to a data table in ROM. This can also
occur if the disassembler hasn't yet encountered addresses in the PC.
If you step/trace/scanline/frame advance into such an area, the disassembler
If you step/trace/scanLine/frame advance into such an area, the disassembler
will make note of it, and disassemble it correctly from that point on.</p>
<!-- TODO - is this true any longer?
@ -1541,7 +1553,7 @@ Note: The code will continue to run fine, but the ROM image will be altered.</li
<li>The ROM Widget only works on ROM or zero-page RAM separately. If your game runs
code from zero-page RAM, the disassembly will show addresses $80 to $FF (zero-page
RAM address space) only. Once your RAM routine returns, the ROM Widget will switch
back to ROM space ($1000 - $1FFF and mirrors). The same is true of the "disasm"
back to ROM space ($1000 - $1FFF and mirrors). The same is true of the "disAsm"
command; it will show either ROM or RAM space, not both at the same time.</li>
<li>The standard VCS memory map has the cartridge port at locations
@ -1610,13 +1622,13 @@ space with the appropriate directive, there are times when it will fail. There a
several options in this case:</p>
<ol>
<li><b>Manually set the directives</b>: Directives can be set in the debugger
prompt with the aud/code/col/bcol/gfx/pcol/pgfx/data/row commands. These accept an address range
prompt with the aud/code/col/bcol/gfx/pCol/pGfx/data/row commands. These accept an address range
for the given directive type. Setting a range with the same type a second time
will remove that directive from the range.</li>
<li><b>Use configuration files</b>: Configuration files can be used to automatically
load a list of directives when a ROM is loaded. These files can be generated with the
'saveconfig' command, and loaded with the 'loadconfig' command. There are also
'listconfig' and 'clearconfig' commands to show and erase (respectively) the current
'saveConfig' command, and loaded with the 'loadConfig' command. There are also
'listConfig' and 'clearConfig' commands to show and erase (respectively) the current
directive listing. Upon opening the debugger for the first time, Stella attempts
to load a configuration file from the folder containing the ROM. Assuming a ROM named "rr.a26" exists, the config file must be named <i>rr.cfg</i>.
</ul>
@ -1689,7 +1701,7 @@ but it helps to know at least a little about 6502 programming.</p>
(for that, we have to disable the collision checking code, which means
we have to find and understand it first!)</li>
<li>Set a Write Trap on the lives counter address: "trapwrite $ba"
<li>Set a Write Trap on the lives counter address: "trapWrite $ba"
in the Prompt. Exit the debugger and play until you get killed. When
you die, the trap will cause the emulator to enter the debugger with the
Program Counter pointing to the instruction *after* the one that wrote
@ -1737,7 +1749,7 @@ but it helps to know at least a little about 6502 programming.</p>
will *still* see 3 lives: Success! We've hacked Battlezone to give us
infinite lives.</li>
<li>Save your work. In the prompt: "saverom". You now
<li>Save your work. In the prompt: "saveRom". You now
have your very own infinite-lives version of Battlezone. The file will
be saved in your HOME directory (NOT your ROM directory), so you might
want to move it to your ROM directory if it isn't the current directory.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

View File

@ -629,7 +629,7 @@
The tables below show the default settings.<br/><br/>
Note: All key names are based on the US QWERTY <a href="https://en.wikipedia.org/wiki/Keyboard_layout">
keyboard layout.</a>. If you use a different layout some keys may differ. You can use the
keyboard layout</a>. If you use a different layout some keys may differ. You can use the
following layout image as reference where to find the US keys on your keyboard.
</p>
<p><img src="graphics/qwertz.png"></p>
@ -785,8 +785,8 @@
<table BORDER=2>
<tr>
<th>Left Joystick (Joy0)</th>
<th>Right Joystick (Joy1)</th>
<th>Left Joystick</th>
<th>Right Joystick</th>
</tr>
<tr>
@ -898,32 +898,32 @@
<tr>
<td>Pad Up</td>
<td>Same as 'Joy0 Up'</td>
<td>Same as Left Joystick 'Up'</td>
</tr>
<tr>
<td>Pad Down</td>
<td>Same as 'Joy0 Down'</td>
<td>Same as Left Joystick 'Down'</td>
</tr>
<tr>
<td>Pad Left</td>
<td>Same as 'Joy0 Left'</td>
<td>Same as Left Joystick 'Left'</td>
</tr>
<tr>
<td>Pad Right</td>
<td>Same as 'Joy0 Right'</td>
<td>Same as Left Joystick 'Right'</td>
</tr>
<tr>
<td>Button 'B'</td>
<td>Same as 'Joy0 Fire'</td>
<td>Same as Left Joystick 'Fire'</td>
</tr>
<tr>
<td>Button 'C'</td>
<td>Same as 'Joy0 Top Booster Button'</td>
<td>Same as Left Joystick 'Top Booster Button'</td>
</tr>
</table>
</td>
@ -937,32 +937,32 @@
<tr>
<td>Pad Up</td>
<td>Same as 'Joy1 Up'</td>
<td>Same as Right Joystick 'Up'</td>
</tr>
<tr>
<td>Pad Down</td>
<td>Same as 'Joy1 Down'</td>
<td>Same as Right Joystick 'Down'</td>
</tr>
<tr>
<td>Pad Left</td>
<td>Same as 'Joy1 Left'</td>
<td>Same as Right Joystick 'Left'</td>
</tr>
<tr>
<td>Pad Right</td>
<td>Same as 'Joy1 Right'</td>
<td>Same as Right Joystick 'Right'</td>
</tr>
<tr>
<td>Button 'B'</td>
<td>Same as 'Joy1 Fire'</td>
<td>Same as Right Joystick 'Fire'</td>
</tr>
<tr>
<td>Button 'C'</td>
<td>Same as 'Joy1 Top Booster Button'</td>
<td>Same as Right Joystick 'Top Booster Button'</td>
</tr>
</table>
</td>
@ -987,17 +987,17 @@
<tr>
<td>Left Direction</td>
<td>Same as 'Joy0 Left'</td>
<td>Same as Left Joystick 'Left'</td>
</tr>
<tr>
<td>Right Direction</td>
<td>Same as 'Joy0 Right'</td>
<td>Same as Left Joystick 'Right'</td>
</tr>
<tr>
<td>Fire Button</td>
<td>Same as 'Joy0 Fire'</td>
<td>Same as Left Joystick 'Fire'</td>
</tr>
</table>
</td>
@ -1011,17 +1011,17 @@
<tr>
<td>Left Direction</td>
<td>Same as 'Joy1 Left'</td>
<td>Same as Right Joystick 'Left'</td>
</tr>
<tr>
<td>Right Direction</td>
<td>Same as 'Joy1 Right'</td>
<td>Same as Right Joystick 'Right'</td>
</tr>
<tr>
<td>Fire Button</td>
<td>Same as 'Joy1 Fire'</td>
<td>Same as Right Joystick 'Fire'</td>
</tr>
</table>
</td>
@ -1043,7 +1043,7 @@
</tr>
<tr>
<td>Fire Button</td>
<td>Same as 'Joy0 Fire'</td>
<td>Same as Left Joystick 'Fire'</td>
</tr>
</table>
</td>
@ -1065,7 +1065,7 @@
</tr>
<tr>
<td>Fire Button</td>
<td>Same as 'Joy0 Fire'</td>
<td>Same as Left Joystick 'Fire'</td>
</tr>
</table>
</td>
@ -1089,32 +1089,32 @@
</tr>
<tr>
<td>Paddle 0 Turn Left</td>
<td>Paddle A Turn Left</td>
<td>Left arrow</td>
</tr>
<tr>
<td>Paddle 0 Turn Right</td>
<td>Paddle A Turn Right</td>
<td>Right arrow</td>
</tr>
<tr>
<td>Paddle 0 Fire</td>
<td>Paddle A Fire</td>
<td>Left Control, Space</td>
</tr>
<tr>
<td>Paddle 1 Turn Left</td>
<td>Paddle B Turn Left</td>
<td>Up arrow</td>
</tr>
<tr>
<td>Paddle 1 Turn Right</td>
<td>Paddle B Turn Right</td>
<td>Down arrow</td>
</tr>
<tr>
<td>Paddle 1 Fire</td>
<td>Paddle B Fire</td>
<td>4</td>
</tr>
</table>
@ -1128,32 +1128,32 @@
</tr>
<tr>
<td>Paddle 2 Turn Left</td>
<td>Paddle A Turn Left</td>
<td>G</td>
</tr>
<tr>
<td>Paddle 2 Turn Right</td>
<td>Paddle A Turn Right</td>
<td>J</td>
</tr>
<tr>
<td>Paddle 2 Fire</td>
<td>Paddle A Fire</td>
<td>F</td>
</tr>
<tr>
<td>Paddle 3 Turn Left</td>
<td>Paddle B Turn Left</td>
<td>Y</td>
</tr>
<tr>
<td>Paddle 3 Turn Right</td>
<td>Paddle B Turn Right</td>
<td>H</td>
</tr>
<tr>
<td>Paddle 3 Fire</td>
<td>Paddle B Fire</td>
<td>6</td>
</tr>
</table>
@ -1161,12 +1161,12 @@
</tr>
</table>
<p><b>Keypad Controller (can be remapped)</b></p>
<p><b>Keyboard Controller (can be remapped)</b></p>
<table BORDER=2>
<tr>
<th>Left Keypad</th>
<th>Right Keypad</th>
<th>Left Keyboard</th>
<th>Right Keyboard</th>
</tr>
<tr>
@ -3541,6 +3541,25 @@
fatal errors are simply logged, and emulation continues. Do not use this
unless you know exactly what you're doing, as it changes the behaviour as
compared to real hardware.</td>
</tr><tr>
<td><pre>-dev.thumb.incycles &lt;1|0&gt;</pre></td>
<td>When enabled, ARM emulation cycles are added to 6507 system cycles. This
allows detecting timer overruns, but will also distort audio.</br>
Note: The ARM emulation cycles are only a coarse approximation.
</td>
</tr><tr>
<td><pre>-dev.thumb.cyclefactor &lt;float&gt;</pre></td>
<td>Defines the ARM cycle count correction factor (default = 0.95).</td>
</tr><tr>
<td><pre>-dev.thumb.chiptype &lt;0|1&gt;</pre></td>
<td>Selects the emulated chip type (0 = LPC2103, 1 = LPC2104 family). This
setting affects the CPU clock, the Flash memory access clock cycles and
the number of Flash banks.</td>
</tr><tr>
<td><pre>-dev.thumb.mammode &lt;0..3&gt;</pre></td>
<td>Selects the Memory Accelerator Module (MAM) mode.</br>
Note: Mode X (3) is for testing only. It reduces Flash memory access
clock cycles to always 1.</td>
</tr><tr>
<td><pre>-&lt;plr.|dev.&gt;eepromaccess &lt;1|0&gt;</pre></td>
<td>When enabled, each read or write access to the AtariVox/SaveKey EEPROM is
@ -3654,8 +3673,7 @@
<table border="1" cellpadding="4">
<tr><th>Item</th><th>Brief description</th><th>For more information,<br>see <a href="#CommandLine">Command Line</a></th></tr>
<tr><td>Palette</td><td>Palette used for emulation mode</td><td>-palette</td></tr>
<tr><td>NTSC phase</td><td>Adjust phase shift of 'Custom' NTSC palette</td><td>-pal.phase_ntsc</td></tr>
<tr><td>PAL phase</td><td>Adjust phase shift of 'Custom' PAL palette</td><td>-pal.phase_pal</td></tr>
<tr><td>NTSC/PAL phase</td><td>Adjust phase shift of 'Custom' NTSC or PAL (depends on game) palette. </td><td>-pal.phase_ntsc, -pal.phase_pal</td></tr>
<tr><td>R</td><td>Adjust red scale and shift of 'Custom' palette</td><td>-pal.red_scale, -pal.red_shift</td></tr>
<tr><td>G</td><td>Adjust green scale and shift of 'Custom' palette</td><td>-pal.green_scale, -pal.green_shift</td></tr>
<tr><td>B</td><td>Adjust blue scale and shift of 'Custom' palette</td><td>-pal.blue_scale, -pal.blue_shift</td></tr>
@ -3899,16 +3917,13 @@
while in emulation mode, the left arrow could mean 'joystick 0 left', while in UI
mode it could mean 'move cursor left'. Emulation mode occurs whenever you're
actually playing a game. UI mode occurs whenever a user interface is present
(ROM launcher, debugger, settings menu, etc.). Because of these different modes,
there are two separate mapping areas.
(ROM launcher, debugger, settings menu, etc.).
<p>To remap an event:
<ol>
<li>Enter <b>Options Menu</b> and click the <b>Input Settings</b> button.</li>
<li>If you wish to remap emulation events, click the 'Emulation Events' tab. Here
you can also filter for the type of events.
Otherwise, click the 'UI Events' tab for user interface events.</li>
<li>Select event you want to remap and click the 'Map' button.</li>
<li>Click the 'Event Mappings' tab. Here you can also filter the list of events by type.
<li>Select the event you want to remap and click the 'Map' button.</li>
<li>Now define the input:
<ul>
<li>Either press a key, a modifier key (Control, Shift...) or a modifier+key combination.</li>
@ -3917,7 +3932,7 @@
Notes:<ul>
<li>If nothing seems to happen, either Stella can't see the input device, or the
selected event doesn't support being remapped to the input device.</li>
<li>The same input can be used for multiple controller types (e.g. 'Right' for 'P0 Joystick Right' and 'Paddle 0 Turn Right').</li>
<li>The same input can be used for multiple controller types (e.g. 'Right' for 'Left Joystick Right' and 'Left Paddle A Turn Right').</li>
<li>If the same input is used again for the same controller type, the old mapping will be removed.</li>
<li>Events which are available in both event modes can be remapped individually.</li>
<li>Left and right modifiers are mapped separately when used alone.</li>
@ -3965,7 +3980,7 @@
<tr><td>Allow all 4 directions ...</td><td>Allow all 4 joystick directions to be pressed simultaneously</td><td>-joyallow4</td></tr>
<tr><td>Use modifier key combos</td><td>Enable using modifier keys in keyboard actions</td><td>-modcombo</td></tr>
<tr><td>Swap Stelladaptor ports</td><td>Swap the order of the detected Stelladaptors/2600-daptors (see <b>Advanced Configuration - <a href="#Adaptor">Stelladaptor/2600-daptor Support</a></b>)</td><td>-saport</td></tr>
<tr><td>Joystick Database</td><td>Show all joysticks that Stella knows about, with the option to remove them</td><td>&nbsp;</td></tr>
<tr><td>Controller Database</td><td>Show all controllers that Stella knows about, with the option to remove them</td><td>&nbsp;</td></tr>
<tr><td>Erase EEPROM</td><td>Erase the whole AtariVox/SaveKey flash memory</td><td>&nbsp;</td></tr>
<tr><td>AtariVox serial port</td><td>Described in further detail in <b>Advanced Configuration - <a href="#AtariVox">AtariVox/SaveKey Support</a></b> </td><td>-avoxport</td></tr>
</table>
@ -4140,7 +4155,7 @@
<h2><b><a name="Adaptor">Stelladaptor/2600-daptor Support</a></b></h2>
<blockquote> H
<blockquote>
<p>Stella supports real Atari 2600 joysticks, paddles, driving controllers
and trackballs (CX22/CX80 'Trak-Ball', Atari and Amiga mouse) using the
<a href="http://www.grandideastudio.com/stelladaptor-2600">Stelladaptor</a> and
@ -4156,13 +4171,13 @@
<ul>
<li>The first device found will act as the <b>left game port</b>
on a real Atari. Depending on the device, Stella will detect it as
either the left joystick, paddles 0 & 1, the left driving controller,
left keypad, etc.</li>
either the left joystick, left paddles A & B, the left driving controller,
left keyboard, etc.</li>
<li>The second device found will act as the <b>right game port</b>
on a real Atari. Depending on the device, Stella will detect it as
either the right joystick, paddles 2 & 3, the right driving controller,
right keypad, etc.</li>
either the right joystick, right paddles A & B, the right driving controller,
right keyboard, etc.</li>
<li>Any other devices will be ignored.</li>
@ -4874,7 +4889,7 @@ Ms Pac-Man (Stella extended codes):
<td VALIGN="TOP"><i>Console.SwapPorts</i></td>
<td>Indicates that the left and right ports should be
swapped internally. This is used for ROMs like 'Raiders of the Lost Ark' where the
Player 0 joystick is plugged into the right joystick port.
1st player's joystick is plugged into the right joystick port.
The value must be <b>Yes</b> or <b>No</b>.</td>
</tr>
@ -4882,8 +4897,8 @@ Ms Pac-Man (Stella extended codes):
<td VALIGN="TOP"><i>Controller.SwapPaddles</i></td>
<td>Indicates that the left and right paddles in
a particular port should be swapped. This is used for ROMs like
'Demons to Diamonds' where the default paddle is paddle 1, not
paddle 0. Other ROMs such as 'Tac-Scan' default to paddle 3,
'Demons to Diamonds' where the default paddle is left paddle B, not
left paddle A. Other ROMs such as 'Tac-Scan' default to right paddle B,
which can be set using both 'Controller.SwapPaddles' and
'Console.SwapPorts'. The value must be <b>Yes</b> or <b>No</b>.</td>
</tr>
@ -4907,14 +4922,14 @@ Ms Pac-Man (Stella extended codes):
Y-axis and right button. The value must be <b>Auto</b> or <b>XY</b>, as follows:
<table cellpadding="2" border="1">
<tr><th>&nbsp;Id&nbsp;</th><th>Controller</th></tr>
<tr><td>0 </td><td>Paddle 0</td></tr>
<tr><td>1 </td><td>Paddle 1</td></tr>
<tr><td>2 </td><td>Paddle 2</td></tr>
<tr><td>3 </td><td>Paddle 3</td></tr>
<tr><td>4 </td><td>Driving 0</td></tr>
<tr><td>5 </td><td>Driving 1</td></tr>
<tr><td>6 </td><td>MindLink 0</td></tr>
<tr><td>7 </td><td>MindLink 1</td></tr>
<tr><td>0 </td><td>Left Paddle A</td></tr>
<tr><td>1 </td><td>Left Paddle B</td></tr>
<tr><td>2 </td><td>Right Paddle A</td></tr>
<tr><td>3 </td><td>Right Paddle B</td></tr>
<tr><td>4 </td><td>Left Driving</td></tr>
<tr><td>5 </td><td>Right Driving</td></tr>
<tr><td>6 </td><td>Left MindLink</td></tr>
<tr><td>7 </td><td>Right MindLink</td></tr>
</table>
An <I>optional</I> second parameter (default of 100) indicates how much
of the paddle range the mouse should emulate.

View File

@ -71,6 +71,8 @@ FBBackendSDL2::~FBBackendSDL2()
myWindow = nullptr;
}
SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_TIMER);
cerr << "~FBBackendSDL2()" << endl;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -40,6 +40,8 @@ namespace {
}
}
static int REF_COUNT = 0;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FBSurfaceSDL2::FBSurfaceSDL2(FBBackendSDL2& backend,
uInt32 width, uInt32 height,
@ -48,6 +50,7 @@ FBSurfaceSDL2::FBSurfaceSDL2(FBBackendSDL2& backend,
: myBackend{backend},
myInterpolationMode{inter}
{
REF_COUNT++;
createSurface(width, height, staticData);
}
@ -58,6 +61,8 @@ FBSurfaceSDL2::~FBSurfaceSDL2()
if(mySurface)
{
REF_COUNT--;
cerr << " ~FBSurfaceSDL2(): " << this << " " << REF_COUNT << endl;
SDL_FreeSurface(mySurface);
mySurface = nullptr;
}

View File

@ -218,7 +218,7 @@ json JoyMap::saveMapping(const EventMode mode) const
json eventMappings = json::array();
for (const auto& [_mapping, _event]: sortedMap) {
if (_mapping.mode != mode) continue;
if(_mapping.mode != mode || _event == Event::NoType) continue;
json eventMapping = json::object();
@ -255,6 +255,10 @@ int JoyMap::loadMapping(const json& eventMappings, const EventMode mode)
JoyHatDir hatDirection = eventMapping.contains("hat") ? eventMapping.at("hatDirection").get<JoyHatDir>() : JoyHatDir::CENTER;
try {
// avoid blocking mappings for NoType events
if(eventMapping.at("event").get<Event::Type>() == Event::NoType)
continue;
add(
eventMapping.at("event").get<Event::Type>(),
mode,

View File

@ -241,7 +241,7 @@ json KeyMap::saveMapping(const EventMode mode) const
json mappings = json::array();
for (const auto& [_mapping, _event]: sortedMap) {
if (_mapping.mode != mode) continue;
if (_mapping.mode != mode || _event == Event::NoType) continue;
json mapping = json::object();
@ -264,6 +264,10 @@ int KeyMap::loadMapping(const json& mappings, const EventMode mode) {
for(const json& mapping : mappings)
{
try {
// avoid blocking mappings for NoType events
if(mapping.at("event").get<Event::Type>() == Event::NoType)
continue;
add(
mapping.at("event").get<Event::Type>(),
mode,

View File

@ -56,7 +56,8 @@ void Logger::logMessage(const string& message, Level level)
cout << message << endl << std::flush;
myLogMessages += message + "\n";
}
else if(static_cast<int>(level) <= myLogLevel)
else if(static_cast<int>(level) <= myLogLevel ||
level == Logger::Level::ALWAYS)
{
if(myLogToConsole)
cout << message << endl << std::flush;

View File

@ -30,6 +30,7 @@ class Logger {
ERR = 0, // cannot use ERROR???
INFO = 1,
DEBUG = 2,
ALWAYS = 3,
MIN = ERR,
MAX = DEBUG
};
@ -38,7 +39,7 @@ class Logger {
static Logger& instance();
static void log(const string& message, Level level);
static void log(const string& message, Level level = Level::ALWAYS);
static void error(const string& message);

View File

@ -54,45 +54,45 @@ MouseControl::MouseControl(Console& console, const string& mode)
case MouseControl::Type::NoControl:
msg << "not used";
break;
case MouseControl::Type::Paddle0:
case MouseControl::Type::LeftPaddleA:
type = Controller::Type::Paddles;
id = 0;
msg << "Paddle 0";
msg << "Left Paddle A";
break;
case MouseControl::Type::Paddle1:
case MouseControl::Type::LeftPaddleB:
type = Controller::Type::Paddles;
id = 1;
msg << "Paddle 1";
msg << "Left Paddle B";
break;
case MouseControl::Type::Paddle2:
case MouseControl::Type::RightPaddleA:
type = Controller::Type::Paddles;
id = 2;
msg << "Paddle 2";
msg << "Right Paddle A";
break;
case MouseControl::Type::Paddle3:
case MouseControl::Type::RightPaddleB:
type = Controller::Type::Paddles;
id = 3;
msg << "Paddle 3";
msg << "Right Paddle B";
break;
case MouseControl::Type::Driving0:
case MouseControl::Type::LeftDriving:
type = Controller::Type::Driving;
id = 0;
msg << "Driving 0";
msg << "Left Driving";
break;
case MouseControl::Type::Driving1:
case MouseControl::Type::RightDriving:
type = Controller::Type::Driving;
id = 1;
msg << "Driving 1";
msg << "Right Driving";
break;
case MouseControl::Type::MindLink0:
case MouseControl::Type::LeftMindLink:
type = Controller::Type::MindLink;
id = 0;
msg << "MindLink 0";
msg << "Left MindLink";
break;
case MouseControl::Type::MindLink1:
case MouseControl::Type::RightMindLink:
type = Controller::Type::MindLink;
id = 1;
msg << "MindLink 1";
msg << "Right MindLink";
break;
}
};

View File

@ -43,8 +43,8 @@ class MouseControl
*/
enum class Type
{
Paddle0 = 0, Paddle1, Paddle2, Paddle3,
Driving0, Driving1, MindLink0, MindLink1,
LeftPaddleA = 0, LeftPaddleB, RightPaddleA, RightPaddleB,
LeftDriving, RightDriving, LeftMindLink, RightMindLink,
NoControl
};

View File

@ -98,27 +98,12 @@ int PhysicalJoystickHandler::add(const PhysicalJoystickPtr& stick)
return -1;
// Figure out what type of joystick this is
bool specialAdaptor = false;
bool isAdaptor = false;
if(BSPF::containsIgnoreCase(stick->name, "2600-daptor"))
if(BSPF::containsIgnoreCase(stick->name, "Stelladaptor")
|| BSPF::containsIgnoreCase(stick->name, "2600-daptor"))
{
specialAdaptor = true;
if(stick->numAxes == 4)
{
// TODO - detect controller type based on z-axis
stick->name = "2600-daptor D9";
}
else if(stick->numAxes == 3)
{
stick->name = "2600-daptor II";
}
else
stick->name = "2600-daptor";
}
else if(BSPF::containsIgnoreCase(stick->name, "Stelladaptor"))
{
stick->name = "Stelladaptor";
specialAdaptor = true;
isAdaptor = true;
}
else
{
@ -141,11 +126,40 @@ int PhysicalJoystickHandler::add(const PhysicalJoystickPtr& stick)
// The stick *must* be inserted here, since it may be used below
mySticks[stick->ID] = stick;
// Map the stelladaptors we've found according to the specified ports
// The 'type' is also set there
if(specialAdaptor)
mapStelladaptors(myOSystem.settings().getString("saport"));
bool erased = false;
if(isAdaptor)
{
// Map the Stelladaptors we've found according to the specified ports
// The 'type' is also set there
erased = mapStelladaptors(myOSystem.settings().getString("saport"), stick->ID);
}
if(erased)
// We have to add all Stelladaptors again, because they have changed
// name due to being reordered when mapping them
for(auto& [_id, _stick] : mySticks)
{
if(_stick->name.find(" (emulates ") != std::string::npos)
addToDatabase(_stick);
}
else
addToDatabase(stick);
// We're potentially swapping out an input device behind the back of
// the Event system, so we make sure all Stelladaptor-generated events
// are reset
for(int port = 0; port < NUM_PORTS; ++port)
{
for(int axis = 0; axis < NUM_SA_AXIS; ++axis)
myEvent.set(SA_Axis[port][axis], 0);
}
return stick->ID;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalJoystickHandler::addToDatabase(const PhysicalJoystickPtr& stick)
{
// Add stick to database
auto it = myDatabase.find(stick->name);
if(it != myDatabase.end()) // already present
@ -162,16 +176,10 @@ int PhysicalJoystickHandler::add(const PhysicalJoystickPtr& stick)
setStickDefaultMapping(stick->ID, Event::NoType, EventMode::kMenuMode);
}
// We're potentially swapping out an input device behind the back of
// the Event system, so we make sure all Stelladaptor-generated events
// are reset
for(int port = 0; port < NUM_PORTS; ++port)
{
for(int axis = 0; axis < NUM_SA_AXIS; ++axis)
myEvent.set(SA_Axis[port][axis], 0);
}
return stick->ID;
ostringstream buf;
buf << "Added joystick " << stick->ID << ":" << endl
<< " " << stick->about() << endl;
Logger::info(buf.str());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -223,8 +231,9 @@ bool PhysicalJoystickHandler::remove(const string& name)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalJoystickHandler::mapStelladaptors(const string& saport)
bool PhysicalJoystickHandler::mapStelladaptors(const string& saport, int ID)
{
bool erased = false;
// saport will have two values:
// 'lr' means treat first valid adaptor as left port, second as right port
// 'rl' means treat first valid adaptor as right port, second as left port
@ -238,44 +247,55 @@ void PhysicalJoystickHandler::mapStelladaptors(const string& saport)
saOrder[0] = 2; saOrder[1] = 1;
}
for(auto& [_id, _joyptr]: mySticks)
for(auto& [_id, _stick]: mySticks)
{
bool found = false;
// remove previously added emulated ports
size_t pos = _joyptr->name.find(" (emulates ");
size_t pos = _stick->name.find(" (emulates ");
if(pos != std::string::npos)
_joyptr->name.erase(pos);
if(pos != std::string::npos && ID != -1 && ID < _stick->ID)
{
// Erase a previously added Stelladapter with a higher ID
ostringstream buf;
buf << "Erased joystick " << _stick->ID << ":" << endl
<< " " << _stick->about() << endl;
Logger::info(buf.str());
if(BSPF::startsWithIgnoreCase(_joyptr->name, "Stelladaptor"))
_stick->name.erase(pos);
erased = true;
}
//if(BSPF::startsWithIgnoreCase(_stick->name, "Stelladaptor"))
if(BSPF::containsIgnoreCase(_stick->name, "Stelladaptor"))
{
if(saOrder[saCount] == 1)
_joyptr->type = PhysicalJoystick::Type::LEFT_STELLADAPTOR;
_stick->type = PhysicalJoystick::Type::LEFT_STELLADAPTOR;
else if(saOrder[saCount] == 2)
_joyptr->type = PhysicalJoystick::Type::RIGHT_STELLADAPTOR;
_stick->type = PhysicalJoystick::Type::RIGHT_STELLADAPTOR;
found = true;
}
else if(BSPF::startsWithIgnoreCase(_joyptr->name, "2600-daptor"))
else //if(BSPF::startsWithIgnoreCase(_stick->name, "2600-daptor"))
if(BSPF::containsIgnoreCase(_stick->name, "2600-daptor"))
{
if(saOrder[saCount] == 1)
_joyptr->type = PhysicalJoystick::Type::LEFT_2600DAPTOR;
_stick->type = PhysicalJoystick::Type::LEFT_2600DAPTOR;
else if(saOrder[saCount] == 2)
_joyptr->type = PhysicalJoystick::Type::RIGHT_2600DAPTOR;
_stick->type = PhysicalJoystick::Type::RIGHT_2600DAPTOR;
found = true;
}
if(found)
{
if(saOrder[saCount] == 1)
_joyptr->name += " (emulates left joystick port)";
_stick->name += " (emulates left joystick port)";
else if(saOrder[saCount] == 2)
_joyptr->name += " (emulates right joystick port)";
_stick->name += " (emulates right joystick port)";
saCount++;
// always map Stelladaptor/2600-daptor to emulation mode defaults
setStickDefaultMapping(_joyptr->ID, Event::NoType, EventMode::kEmulationMode);
setStickDefaultMapping(_stick->ID, Event::NoType, EventMode::kEmulationMode);
}
}
myOSystem.settings().setValue("saport", saport);
return erased;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -361,8 +381,8 @@ void PhysicalJoystickHandler::setStickDefaultMapping(int stick, Event::Type even
setDefaultAction(stick, item, event, EventMode::kJoystickMode, updateDefaults);
for (const auto& item : DefaultLeftPaddlesMapping)
setDefaultAction(stick, item, event, EventMode::kPaddlesMode, updateDefaults);
for (const auto& item : DefaultLeftKeypadMapping)
setDefaultAction(stick, item, event, EventMode::kKeypadMode, updateDefaults);
for (const auto& item : DefaultLeftKeyboardMapping)
setDefaultAction(stick, item, event, EventMode::kKeyboardMode, updateDefaults);
}
else
{
@ -371,8 +391,8 @@ void PhysicalJoystickHandler::setStickDefaultMapping(int stick, Event::Type even
setDefaultAction(stick, item, event, EventMode::kJoystickMode, updateDefaults);
for (const auto& item : DefaultRightPaddlesMapping)
setDefaultAction(stick, item, event, EventMode::kPaddlesMode, updateDefaults);
for (const auto& item : DefaultRightKeypadMapping)
setDefaultAction(stick, item, event, EventMode::kKeypadMode, updateDefaults);
for (const auto& item : DefaultRightKeyboardMapping)
setDefaultAction(stick, item, event, EventMode::kKeyboardMode, updateDefaults);
}
for(const auto& item : DefaultCommonMapping)
setDefaultAction(stick, item, event, EventMode::kCommonMode, updateDefaults);
@ -409,9 +429,9 @@ void PhysicalJoystickHandler::defineControllerMappings(const Controller::Type ty
case Controller::Type::Keyboard:
case Controller::Type::KidVid:
if(port == Controller::Jack::Left)
myLeftMode = EventMode::kKeypadMode;
myLeftMode = EventMode::kKeyboardMode;
else
myRightMode = EventMode::kKeypadMode;
myRightMode = EventMode::kKeyboardMode;
break;
case Controller::Type::Paddles:
@ -456,8 +476,8 @@ void PhysicalJoystickHandler::enableEmulationMappings()
enableMappings(RightPaddlesEvents, EventMode::kPaddlesMode);
break;
case EventMode::kKeypadMode:
enableMappings(RightKeypadEvents, EventMode::kKeypadMode);
case EventMode::kKeyboardMode:
enableMappings(RightKeyboardEvents, EventMode::kKeyboardMode);
break;
default:
@ -471,8 +491,8 @@ void PhysicalJoystickHandler::enableEmulationMappings()
enableMappings(LeftPaddlesEvents, EventMode::kPaddlesMode);
break;
case EventMode::kKeypadMode:
enableMappings(LeftKeypadEvents, EventMode::kKeypadMode);
case EventMode::kKeyboardMode:
enableMappings(LeftKeyboardEvents, EventMode::kKeyboardMode);
break;
default:
@ -527,8 +547,8 @@ EventMode PhysicalJoystickHandler::getEventMode(const Event::Type event, const E
if(isPaddleEvent(event))
return EventMode::kPaddlesMode;
if(isKeypadEvent(event))
return EventMode::kKeypadMode;
if(isKeyboardEvent(event))
return EventMode::kKeyboardMode;
if(isCommonEvent(event))
return EventMode::kCommonMode;
@ -552,16 +572,16 @@ bool PhysicalJoystickHandler::isPaddleEvent(const Event::Type event) const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PhysicalJoystickHandler::isKeypadEvent(const Event::Type event) const
bool PhysicalJoystickHandler::isKeyboardEvent(const Event::Type event) const
{
return LeftKeypadEvents.find(event) != LeftKeypadEvents.end()
|| RightKeypadEvents.find(event) != RightKeypadEvents.end();
return LeftKeyboardEvents.find(event) != LeftKeyboardEvents.end()
|| RightKeyboardEvents.find(event) != RightKeyboardEvents.end();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PhysicalJoystickHandler::isCommonEvent(const Event::Type event) const
{
return !(isJoystickEvent(event) || isPaddleEvent(event) || isKeypadEvent(event));
return !(isJoystickEvent(event) || isPaddleEvent(event) || isKeyboardEvent(event));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -579,7 +599,7 @@ void PhysicalJoystickHandler::eraseMapping(Event::Type event, EventMode mode)
_joyptr->eraseMap(EventMode::kCommonMode);
_joyptr->eraseMap(EventMode::kJoystickMode);
_joyptr->eraseMap(EventMode::kPaddlesMode);
_joyptr->eraseMap(EventMode::kKeypadMode);
_joyptr->eraseMap(EventMode::kKeyboardMode);
}
}
}
@ -656,7 +676,7 @@ bool PhysicalJoystickHandler::addJoyMapping(Event::Type event, EventMode mode, i
// erase identical mappings for all controller modes
j->joyMap.erase(EventMode::kJoystickMode, button, axis, adir);
j->joyMap.erase(EventMode::kPaddlesMode, button, axis, adir);
j->joyMap.erase(EventMode::kKeypadMode, button, axis, adir);
//j->joyMap.erase(EventMode::kKeyboardMode, button, axis, adir); // no common buttons in keyboard mode!
j->joyMap.erase(EventMode::kCompuMateMode, button, axis, adir);
}
else if (evMode != EventMode::kMenuMode)
@ -691,7 +711,7 @@ bool PhysicalJoystickHandler::addJoyHatMapping(Event::Type event, EventMode mode
// erase identical mappings for all controller modes
j->joyMap.erase(EventMode::kJoystickMode, button, hat, hdir);
j->joyMap.erase(EventMode::kPaddlesMode, button, hat, hdir);
j->joyMap.erase(EventMode::kKeypadMode, button, hat, hdir);
j->joyMap.erase(EventMode::kKeyboardMode, button, hat, hdir);
j->joyMap.erase(EventMode::kCompuMateMode, button, hat, hdir);
}
else if (evMode != EventMode::kMenuMode)
@ -1068,113 +1088,113 @@ void PhysicalJoystickHandler::changeDrivingSensitivity(int direction)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultLeftJoystickMapping = {
// Left joystick (assume buttons zero..two)
{Event::JoystickZeroFire, 0},
{Event::JoystickZeroFire5, 1},
{Event::JoystickZeroFire9, 2},
{Event::LeftJoystickFire, 0},
{Event::LeftJoystickFire5, 1},
{Event::LeftJoystickFire9, 2},
// Left joystick left/right directions
{Event::JoystickZeroLeft, JOY_CTRL_NONE, JoyAxis::X, JoyDir::NEG},
{Event::JoystickZeroRight, JOY_CTRL_NONE, JoyAxis::X, JoyDir::POS},
{Event::LeftJoystickLeft, JOY_CTRL_NONE, JoyAxis::X, JoyDir::NEG},
{Event::LeftJoystickRight, JOY_CTRL_NONE, JoyAxis::X, JoyDir::POS},
// Left joystick up/down directions
{Event::JoystickZeroUp, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::NEG},
{Event::JoystickZeroDown, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::POS},
{Event::LeftJoystickUp, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::NEG},
{Event::LeftJoystickDown, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::POS},
// Left joystick left/right directions (assume hat 0)
{Event::JoystickZeroLeft, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHatDir::LEFT},
{Event::JoystickZeroRight, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHatDir::RIGHT},
{Event::LeftJoystickLeft, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHatDir::LEFT},
{Event::LeftJoystickRight, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHatDir::RIGHT},
// Left joystick up/down directions (assume hat 0)
{Event::JoystickZeroUp, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHatDir::UP},
{Event::JoystickZeroDown, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHatDir::DOWN},
{Event::LeftJoystickUp, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHatDir::UP},
{Event::LeftJoystickDown, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHatDir::DOWN},
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultRightJoystickMapping = {
// Right joystick (assume buttons zero..two)
{Event::JoystickOneFire, 0},
{Event::JoystickOneFire5, 1},
{Event::JoystickOneFire9, 2},
{Event::RightJoystickFire, 0},
{Event::RightJoystickFire5, 1},
{Event::RightJoystickFire9, 2},
// Right joystick left/right directions
{Event::JoystickOneLeft, JOY_CTRL_NONE, JoyAxis::X, JoyDir::NEG},
{Event::JoystickOneRight, JOY_CTRL_NONE, JoyAxis::X, JoyDir::POS},
{Event::RightJoystickLeft, JOY_CTRL_NONE, JoyAxis::X, JoyDir::NEG},
{Event::RightJoystickRight, JOY_CTRL_NONE, JoyAxis::X, JoyDir::POS},
// Right joystick up/down directions
{Event::JoystickOneUp, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::NEG},
{Event::JoystickOneDown, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::POS},
{Event::RightJoystickUp, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::NEG},
{Event::RightJoystickDown, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::POS},
// Right joystick left/right directions (assume hat 0)
{Event::JoystickOneLeft, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHatDir::LEFT},
{Event::JoystickOneRight, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHatDir::RIGHT},
{Event::RightJoystickLeft, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHatDir::LEFT},
{Event::RightJoystickRight, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHatDir::RIGHT},
// Right joystick up/down directions (assume hat 0)
{Event::JoystickOneUp, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHatDir::UP},
{Event::JoystickOneDown, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHatDir::DOWN},
{Event::RightJoystickUp, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHatDir::UP},
{Event::RightJoystickDown, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHatDir::DOWN},
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultLeftPaddlesMapping = {
{Event::PaddleZeroAnalog, JOY_CTRL_NONE, JoyAxis::X, JoyDir::ANALOG},
{Event::LeftPaddleAAnalog, JOY_CTRL_NONE, JoyAxis::X, JoyDir::ANALOG},
#if defined(RETRON77)
{Event::PaddleZeroAnalog, JOY_CTRL_NONE, JoyAxis::Z, JoyDir::ANALOG},
{Event::LeftPaddleAAnalog, JOY_CTRL_NONE, JoyAxis::Z, JoyDir::ANALOG},
#endif
// Current code does NOT allow digital and anlog events on the same axis at the same time
//{Event::PaddleZeroDecrease, JOY_CTRL_NONE, JoyAxis::X, JoyDir::POS},
//{Event::PaddleZeroIncrease, JOY_CTRL_NONE, JoyAxis::X, JoyDir::NEG},
{Event::PaddleZeroFire, 0},
{Event::PaddleOneAnalog, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::ANALOG},
//{Event::LeftPaddleADecrease, JOY_CTRL_NONE, JoyAxis::X, JoyDir::POS},
//{Event::LeftPaddleAIncrease, JOY_CTRL_NONE, JoyAxis::X, JoyDir::NEG},
{Event::LeftPaddleAFire, 0},
{Event::LeftPaddleBAnalog, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::ANALOG},
#if defined(RETRON77)
{Event::PaddleOneAnalog, JOY_CTRL_NONE, JoyAxis::A3, JoyDir::ANALOG},
{Event::LeftPaddleBAnalog, JOY_CTRL_NONE, JoyAxis::A3, JoyDir::ANALOG},
#endif
// Current code does NOT allow digital and anlog events on the same axis at the same
//{Event::PaddleOneDecrease, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::POS},
//{Event::PaddleOneIncrease, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::NEG},
{Event::PaddleOneFire, 1},
//{Event::LeftPaddleBDecrease, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::POS},
//{Event::LeftPaddleBIncrease, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::NEG},
{Event::LeftPaddleBFire, 1},
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultRightPaddlesMapping = {
{Event::PaddleTwoAnalog, JOY_CTRL_NONE, JoyAxis::X, JoyDir::ANALOG},
{Event::RightPaddleAAnalog, JOY_CTRL_NONE, JoyAxis::X, JoyDir::ANALOG},
#if defined(RETRON77)
{Event::PaddleTwoAnalog, JOY_CTRL_NONE, JoyAxis::Z, JoyDir::ANALOG},
{Event::RightPaddleAAnalog, JOY_CTRL_NONE, JoyAxis::Z, JoyDir::ANALOG},
#endif
// Current code does NOT allow digital and anlog events on the same axis at the same
//{Event::PaddleTwoDecrease, JOY_CTRL_NONE, JoyAxis::X, JoyDir::POS},
//{Event::PaddleTwoIncrease, JOY_CTRL_NONE, JoyAxis::X, JoyDir::NEG},
{Event::PaddleTwoFire, 0},
{Event::PaddleThreeAnalog, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::ANALOG},
//{Event::RightPaddleADecrease, JOY_CTRL_NONE, JoyAxis::X, JoyDir::POS},
//{Event::RightPaddleAIncrease, JOY_CTRL_NONE, JoyAxis::X, JoyDir::NEG},
{Event::RightPaddleAFire, 0},
{Event::RightPaddleBAnalog, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::ANALOG},
#if defined(RETRON77)
{Event::PaddleThreeAnalog, JOY_CTRL_NONE, JoyAxis::A3, JoyDir::ANALOG},
{Event::RightPaddleBAnalog, JOY_CTRL_NONE, JoyAxis::A3, JoyDir::ANALOG},
#endif
// Current code does NOT allow digital and anlog events on the same axis at the same
//{Event::PaddleThreeDecrease,JOY_CTRL_NONE, JoyAxis::Y, JoyDir::POS},
//{Event::PaddleThreeIncrease,JOY_CTRL_NONE, JoyAxis::Y, JoyDir::NEG},
{Event::PaddleThreeFire, 1},
//{Event::RightPaddleBDecrease,JOY_CTRL_NONE, JoyAxis::Y, JoyDir::POS},
//{Event::RightPaddleBIncrease,JOY_CTRL_NONE, JoyAxis::Y, JoyDir::NEG},
{Event::RightPaddleBFire, 1},
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultLeftKeypadMapping = {
{Event::KeyboardZero1, 0},
{Event::KeyboardZero2, 1},
{Event::KeyboardZero3, 2},
{Event::KeyboardZero4, 3},
{Event::KeyboardZero5, 4},
{Event::KeyboardZero6, 5},
{Event::KeyboardZero7, 6},
{Event::KeyboardZero8, 7},
{Event::KeyboardZero9, 8},
{Event::KeyboardZeroStar, 9},
{Event::KeyboardZero0, 10},
{Event::KeyboardZeroPound, 11},
PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultLeftKeyboardMapping = {
{Event::LeftKeyboard1, 0},
{Event::LeftKeyboard2, 1},
{Event::LeftKeyboard3, 2},
{Event::LeftKeyboard4, 3},
{Event::LeftKeyboard5, 4},
{Event::LeftKeyboard6, 5},
{Event::LeftKeyboard7, 6},
{Event::LeftKeyboard8, 7},
{Event::LeftKeyboard9, 8},
{Event::LeftKeyboardStar, 9},
{Event::LeftKeyboard0, 10},
{Event::LeftKeyboardPound, 11},
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultRightKeypadMapping = {
{Event::KeyboardOne1, 0},
{Event::KeyboardOne2, 1},
{Event::KeyboardOne3, 2},
{Event::KeyboardOne4, 3},
{Event::KeyboardOne5, 4},
{Event::KeyboardOne6, 5},
{Event::KeyboardOne7, 6},
{Event::KeyboardOne8, 7},
{Event::KeyboardOne9, 8},
{Event::KeyboardOneStar, 9},
{Event::KeyboardOne0, 10},
{Event::KeyboardOnePound, 11},
PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultRightKeyboardMapping = {
{Event::RightKeyboard1, 0},
{Event::RightKeyboard2, 1},
{Event::RightKeyboard3, 2},
{Event::RightKeyboard4, 3},
{Event::RightKeyboard5, 4},
{Event::RightKeyboard6, 5},
{Event::RightKeyboard7, 6},
{Event::RightKeyboard8, 7},
{Event::RightKeyboard9, 8},
{Event::RightKeyboardStar, 9},
{Event::RightKeyboard0, 10},
{Event::RightKeyboardPound, 11},
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -70,7 +70,7 @@ class PhysicalJoystickHandler
int add(const PhysicalJoystickPtr& stick);
bool remove(int id);
bool remove(const string& name);
void mapStelladaptors(const string& saport);
bool mapStelladaptors(const string& saport, int ID = -1);
bool hasStelladaptors() const;
void setDefaultMapping(Event::Type type, EventMode mode);
@ -140,6 +140,9 @@ class PhysicalJoystickHandler
return i != mySticks.cend() ? i->second : nullptr;
}
// Add stick to stick database
void addToDatabase(const PhysicalJoystickPtr& stick);
// Set default mapping for given joystick when no mappings already exist
void setStickDefaultMapping(int stick, Event::Type type, EventMode mode,
bool updateDefaults = false);
@ -175,7 +178,7 @@ class PhysicalJoystickHandler
/** Checks event type. */
bool isJoystickEvent(const Event::Type event) const;
bool isPaddleEvent(const Event::Type event) const;
bool isKeypadEvent(const Event::Type event) const;
bool isKeyboardEvent(const Event::Type event) const;
bool isCommonEvent(const Event::Type event) const;
void enableCommonMappings();
@ -195,8 +198,8 @@ class PhysicalJoystickHandler
static EventMappingArray DefaultRightJoystickMapping;
static EventMappingArray DefaultLeftPaddlesMapping;
static EventMappingArray DefaultRightPaddlesMapping;
static EventMappingArray DefaultLeftKeypadMapping;
static EventMappingArray DefaultRightKeypadMapping;
static EventMappingArray DefaultLeftKeyboardMapping;
static EventMappingArray DefaultRightKeyboardMapping;
static constexpr int NUM_PORTS = 2;
static constexpr int NUM_SA_AXIS = 2;

View File

@ -53,7 +53,7 @@ PhysicalKeyboardHandler::PhysicalKeyboardHandler(OSystem& system, EventHandler&
loadSerializedMappings(myOSystem.settings().getString("keymap_emu"), EventMode::kCommonMode);
loadSerializedMappings(myOSystem.settings().getString("keymap_joy"), EventMode::kJoystickMode);
loadSerializedMappings(myOSystem.settings().getString("keymap_pad"), EventMode::kPaddlesMode);
loadSerializedMappings(myOSystem.settings().getString("keymap_key"), EventMode::kKeypadMode);
loadSerializedMappings(myOSystem.settings().getString("keymap_key"), EventMode::kKeyboardMode);
loadSerializedMappings(myOSystem.settings().getString("keymap_ui"), EventMode::kMenuMode);
updateDefaults = true;
@ -65,7 +65,10 @@ PhysicalKeyboardHandler::PhysicalKeyboardHandler(OSystem& system, EventHandler&
setDefaultMapping(Event::NoType, EventMode::kMenuMode, updateDefaults);
#ifdef GUI_SUPPORT
setDefaultMapping(Event::NoType, EventMode::kEditMode, updateDefaults);
#endif // DEBUG
#endif
#ifdef DEBUGGER_SUPPORT
setDefaultMapping(Event::NoType, EventMode::kPromptMode, updateDefaults);
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -109,7 +112,7 @@ bool PhysicalKeyboardHandler::isMappingUsed(EventMode mode, const EventMapping&
return myKeyMap.check(EventMode::kCommonMode, map.key, map.mod)
|| myKeyMap.check(EventMode::kJoystickMode, map.key, map.mod)
|| myKeyMap.check(EventMode::kPaddlesMode, map.key, map.mod)
|| myKeyMap.check(EventMode::kKeypadMode, map.key, map.mod)
|| myKeyMap.check(EventMode::kKeyboardMode, map.key, map.mod)
|| myKeyMap.check(EventMode::kCompuMateMode, map.key, map.mod);
}
@ -177,8 +180,8 @@ void PhysicalKeyboardHandler::setDefaultMapping(Event::Type event, EventMode mod
setDefaultKey(item, event, EventMode::kJoystickMode, updateDefaults);
for (const auto& item: DefaultPaddleMapping)
setDefaultKey(item, event, EventMode::kPaddlesMode, updateDefaults);
for (const auto& item: DefaultKeypadMapping)
setDefaultKey(item, event, EventMode::kKeypadMode, updateDefaults);
for (const auto& item: DefaultKeyboardMapping)
setDefaultKey(item, event, EventMode::kKeyboardMode, updateDefaults);
for (const auto& item : CompuMateMapping)
setDefaultKey(item, event, EventMode::kCompuMateMode, updateDefaults);
break;
@ -195,6 +198,13 @@ void PhysicalKeyboardHandler::setDefaultMapping(Event::Type event, EventMode mod
setDefaultKey(item, event, EventMode::kEditMode);
break;
#endif
#ifdef DEBUGGER_SUPPORT
case EventMode::kPromptMode:
// Edit mode events are always set because they are not saved
for(const auto& item : FixedPromptMapping)
setDefaultKey(item, event, EventMode::kPromptMode);
break;
#endif
default:
break;
@ -254,7 +264,7 @@ EventMode PhysicalKeyboardHandler::getMode(const Controller::Type type)
{
case Controller::Type::Keyboard:
case Controller::Type::KidVid:
return EventMode::kKeypadMode;
return EventMode::kKeyboardMode;
case Controller::Type::Paddles:
case Controller::Type::PaddlesIAxDr:
@ -282,28 +292,28 @@ void PhysicalKeyboardHandler::enableEmulationMappings()
switch(myRight2ndMode)
{
case EventMode::kPaddlesMode:
enableMappings(Right2PaddlesEvents, EventMode::kPaddlesMode);
enableMappings(QTPaddles4Events, EventMode::kPaddlesMode);
break;
case EventMode::kEmulationMode: // no QuadTari
break;
default:
enableMappings(Right2JoystickEvents, EventMode::kJoystickMode);
enableMappings(QTJoystick4Events, EventMode::kJoystickMode);
break;
}
switch(myLeft2ndMode)
{
case EventMode::kPaddlesMode:
enableMappings(Left2PaddlesEvents, EventMode::kPaddlesMode);
enableMappings(QTPaddles3Events, EventMode::kPaddlesMode);
break;
case EventMode::kEmulationMode: // no QuadTari
break;
default:
enableMappings(Left2JoystickEvents, EventMode::kJoystickMode);
enableMappings(QTJoystick3Events, EventMode::kJoystickMode);
break;
}
@ -313,8 +323,8 @@ void PhysicalKeyboardHandler::enableEmulationMappings()
enableMappings(RightPaddlesEvents, EventMode::kPaddlesMode);
break;
case EventMode::kKeypadMode:
enableMappings(RightKeypadEvents, EventMode::kKeypadMode);
case EventMode::kKeyboardMode:
enableMappings(RightKeyboardEvents, EventMode::kKeyboardMode);
break;
case EventMode::kCompuMateMode:
@ -332,8 +342,8 @@ void PhysicalKeyboardHandler::enableEmulationMappings()
enableMappings(LeftPaddlesEvents, EventMode::kPaddlesMode);
break;
case EventMode::kKeypadMode:
enableMappings(LeftKeypadEvents, EventMode::kKeypadMode);
case EventMode::kKeyboardMode:
enableMappings(LeftKeyboardEvents, EventMode::kKeyboardMode);
break;
case EventMode::kCompuMateMode:
@ -390,8 +400,8 @@ EventMode PhysicalKeyboardHandler::getEventMode(const Event::Type event,
if (isPaddleEvent(event))
return EventMode::kPaddlesMode;
if (isKeypadEvent(event))
return EventMode::kKeypadMode;
if (isKeyboardEvent(event))
return EventMode::kKeyboardMode;
if (isCommonEvent(event))
return EventMode::kCommonMode;
@ -404,31 +414,31 @@ EventMode PhysicalKeyboardHandler::getEventMode(const Event::Type event,
bool PhysicalKeyboardHandler::isJoystickEvent(const Event::Type event) const
{
return LeftJoystickEvents.find(event) != LeftJoystickEvents.end()
|| Left2JoystickEvents.find(event) != Left2JoystickEvents.end()
|| QTJoystick3Events.find(event) != QTJoystick3Events.end()
|| RightJoystickEvents.find(event) != RightJoystickEvents.end()
|| Right2JoystickEvents.find(event) != Right2JoystickEvents.end();
|| QTJoystick4Events.find(event) != QTJoystick4Events.end();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PhysicalKeyboardHandler::isPaddleEvent(const Event::Type event) const
{
return LeftPaddlesEvents.find(event) != LeftPaddlesEvents.end()
|| Left2PaddlesEvents.find(event) != Left2PaddlesEvents.end()
|| QTPaddles3Events.find(event) != QTPaddles3Events.end()
|| RightPaddlesEvents.find(event) != RightPaddlesEvents.end()
|| Right2PaddlesEvents.find(event) != Right2PaddlesEvents.end();
|| QTPaddles4Events.find(event) != QTPaddles4Events.end();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PhysicalKeyboardHandler::isKeypadEvent(const Event::Type event) const
bool PhysicalKeyboardHandler::isKeyboardEvent(const Event::Type event) const
{
return LeftKeypadEvents.find(event) != LeftKeypadEvents.end()
|| RightKeypadEvents.find(event) != RightKeypadEvents.end();
return LeftKeyboardEvents.find(event) != LeftKeyboardEvents.end()
|| RightKeyboardEvents.find(event) != RightKeyboardEvents.end();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PhysicalKeyboardHandler::isCommonEvent(const Event::Type event) const
{
return !(isJoystickEvent(event) || isPaddleEvent(event) || isKeypadEvent(event));
return !(isJoystickEvent(event) || isPaddleEvent(event) || isKeyboardEvent(event));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -445,7 +455,7 @@ void PhysicalKeyboardHandler::saveMapping()
myOSystem.settings().setValue("keymap_emu", myKeyMap.saveMapping(EventMode::kCommonMode).dump(2));
myOSystem.settings().setValue("keymap_joy", myKeyMap.saveMapping(EventMode::kJoystickMode).dump(2));
myOSystem.settings().setValue("keymap_pad", myKeyMap.saveMapping(EventMode::kPaddlesMode).dump(2));
myOSystem.settings().setValue("keymap_key", myKeyMap.saveMapping(EventMode::kKeypadMode).dump(2));
myOSystem.settings().setValue("keymap_key", myKeyMap.saveMapping(EventMode::kKeyboardMode).dump(2));
myOSystem.settings().setValue("keymap_ui", myKeyMap.saveMapping(EventMode::kMenuMode).dump(2));
enableEmulationMappings();
}
@ -467,10 +477,12 @@ bool PhysicalKeyboardHandler::addMapping(Event::Type event, EventMode mode,
// erase identical mappings for all controller modes
myKeyMap.erase(EventMode::kJoystickMode, key, mod);
myKeyMap.erase(EventMode::kPaddlesMode, key, mod);
myKeyMap.erase(EventMode::kKeypadMode, key, mod);
myKeyMap.erase(EventMode::kKeyboardMode, key, mod);
myKeyMap.erase(EventMode::kCompuMateMode, key, mod);
}
else if(evMode != EventMode::kMenuMode && evMode != EventMode::kEditMode)
else if(evMode != EventMode::kMenuMode
&& evMode != EventMode::kEditMode
&& evMode != EventMode::kPromptMode)
{
// erase identical mapping for kCommonMode
myKeyMap.erase(EventMode::kCommonMode, key, mod);
@ -899,111 +911,132 @@ PhysicalKeyboardHandler::FixedEditMapping = {
{Event::EndEdit, KBDK_KP_ENTER},
{Event::AbortEdit, KBDK_ESCAPE},
};
#endif
#endif // GUI_SUPPORT
#ifdef DEBUGGER_SUPPORT
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PhysicalKeyboardHandler::EventMappingArray
PhysicalKeyboardHandler::FixedPromptMapping = {
{Event::UINavNext, KBDK_TAB},
{Event::UINavPrev, KBDK_TAB, KBDM_SHIFT},
{Event::UIPgUp, KBDK_PAGEUP},
{Event::UIPgUp, KBDK_PAGEUP, KBDM_SHIFT},
{Event::UIPgDown, KBDK_PAGEDOWN},
{Event::UIPgDown, KBDK_PAGEDOWN, KBDM_SHIFT},
{Event::UIHome, KBDK_HOME, KBDM_SHIFT},
{Event::UIEnd, KBDK_END, KBDM_SHIFT},
{Event::UIUp, KBDK_UP, KBDM_SHIFT},
{Event::UIDown, KBDK_DOWN, KBDM_SHIFT},
{Event::UILeft, KBDK_DOWN},
{Event::UIRight, KBDK_UP},
};
#endif // DEBUGGER_SUPPORT
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultJoystickMapping = {
{Event::JoystickZeroUp, KBDK_UP},
{Event::JoystickZeroDown, KBDK_DOWN},
{Event::JoystickZeroLeft, KBDK_LEFT},
{Event::JoystickZeroRight, KBDK_RIGHT},
{Event::JoystickZeroUp, KBDK_KP_8},
{Event::JoystickZeroDown, KBDK_KP_2},
{Event::JoystickZeroLeft, KBDK_KP_4},
{Event::JoystickZeroRight, KBDK_KP_6},
{Event::JoystickZeroFire, KBDK_SPACE},
{Event::JoystickZeroFire, KBDK_LCTRL},
{Event::JoystickZeroFire, KBDK_KP_5},
{Event::JoystickZeroFire5, KBDK_4},
{Event::JoystickZeroFire5, KBDK_RSHIFT},
{Event::JoystickZeroFire5, KBDK_KP_9},
{Event::JoystickZeroFire9, KBDK_5},
{Event::JoystickZeroFire9, KBDK_RCTRL},
{Event::JoystickZeroFire9, KBDK_KP_3},
{Event::LeftJoystickUp, KBDK_UP},
{Event::LeftJoystickDown, KBDK_DOWN},
{Event::LeftJoystickLeft, KBDK_LEFT},
{Event::LeftJoystickRight, KBDK_RIGHT},
{Event::LeftJoystickUp, KBDK_KP_8},
{Event::LeftJoystickDown, KBDK_KP_2},
{Event::LeftJoystickLeft, KBDK_KP_4},
{Event::LeftJoystickRight, KBDK_KP_6},
{Event::LeftJoystickFire, KBDK_SPACE},
{Event::LeftJoystickFire, KBDK_LCTRL},
{Event::LeftJoystickFire, KBDK_KP_5},
{Event::LeftJoystickFire5, KBDK_4},
{Event::LeftJoystickFire5, KBDK_RSHIFT},
{Event::LeftJoystickFire5, KBDK_KP_9},
{Event::LeftJoystickFire9, KBDK_5},
{Event::LeftJoystickFire9, KBDK_RCTRL},
{Event::LeftJoystickFire9, KBDK_KP_3},
{Event::JoystickOneUp, KBDK_Y},
{Event::JoystickOneDown, KBDK_H},
{Event::JoystickOneLeft, KBDK_G},
{Event::JoystickOneRight, KBDK_J},
{Event::JoystickOneFire, KBDK_F},
{Event::JoystickOneFire5, KBDK_6},
{Event::JoystickOneFire9, KBDK_7},
{Event::RightJoystickUp, KBDK_Y},
{Event::RightJoystickDown, KBDK_H},
{Event::RightJoystickLeft, KBDK_G},
{Event::RightJoystickRight, KBDK_J},
{Event::RightJoystickFire, KBDK_F},
{Event::RightJoystickFire5, KBDK_6},
{Event::RightJoystickFire9, KBDK_7},
// Same as Joysticks Zero & One + SHIFT
{Event::JoystickTwoUp, KBDK_UP, KBDM_SHIFT},
{Event::JoystickTwoDown, KBDK_DOWN, KBDM_SHIFT},
{Event::JoystickTwoLeft, KBDK_LEFT, KBDM_SHIFT},
{Event::JoystickTwoRight, KBDK_RIGHT, KBDM_SHIFT},
{Event::JoystickTwoUp, KBDK_KP_8, KBDM_SHIFT},
{Event::JoystickTwoDown, KBDK_KP_2, KBDM_SHIFT},
{Event::JoystickTwoLeft, KBDK_KP_4, KBDM_SHIFT},
{Event::JoystickTwoRight, KBDK_KP_6, KBDM_SHIFT},
{Event::JoystickTwoFire, KBDK_SPACE, KBDM_SHIFT},
{Event::QTJoystickThreeUp, KBDK_UP, KBDM_SHIFT},
{Event::QTJoystickThreeDown, KBDK_DOWN, KBDM_SHIFT},
{Event::QTJoystickThreeLeft, KBDK_LEFT, KBDM_SHIFT},
{Event::QTJoystickThreeRight, KBDK_RIGHT, KBDM_SHIFT},
{Event::QTJoystickThreeUp, KBDK_KP_8, KBDM_SHIFT},
{Event::QTJoystickThreeDown, KBDK_KP_2, KBDM_SHIFT},
{Event::QTJoystickThreeLeft, KBDK_KP_4, KBDM_SHIFT},
{Event::QTJoystickThreeRight, KBDK_KP_6, KBDM_SHIFT},
{Event::QTJoystickThreeFire, KBDK_SPACE, KBDM_SHIFT},
{Event::JoystickThreeUp, KBDK_Y, KBDM_SHIFT},
{Event::JoystickThreeDown, KBDK_H, KBDM_SHIFT},
{Event::JoystickThreeLeft, KBDK_G, KBDM_SHIFT},
{Event::JoystickThreeRight, KBDK_J, KBDM_SHIFT},
{Event::JoystickThreeFire, KBDK_F, KBDM_SHIFT},
{Event::QTJoystickFourUp, KBDK_Y, KBDM_SHIFT},
{Event::QTJoystickFourDown, KBDK_H, KBDM_SHIFT},
{Event::QTJoystickFourLeft, KBDK_G, KBDM_SHIFT},
{Event::QTJoystickFourRight, KBDK_J, KBDM_SHIFT},
{Event::QTJoystickFourFire, KBDK_F, KBDM_SHIFT},
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PhysicalKeyboardHandler::EventMappingArray
PhysicalKeyboardHandler::DefaultPaddleMapping = {
{Event::PaddleZeroDecrease, KBDK_RIGHT},
{Event::PaddleZeroIncrease, KBDK_LEFT},
{Event::PaddleZeroFire, KBDK_SPACE},
{Event::PaddleZeroFire, KBDK_LCTRL},
{Event::PaddleZeroFire, KBDK_KP_5},
{Event::LeftPaddleADecrease, KBDK_RIGHT},
{Event::LeftPaddleAIncrease, KBDK_LEFT},
{Event::LeftPaddleAFire, KBDK_SPACE},
{Event::LeftPaddleAFire, KBDK_LCTRL},
{Event::LeftPaddleAFire, KBDK_KP_5},
{Event::PaddleOneDecrease, KBDK_DOWN},
{Event::PaddleOneIncrease, KBDK_UP},
{Event::PaddleOneFire, KBDK_4},
{Event::PaddleOneFire, KBDK_RCTRL},
{Event::LeftPaddleBDecrease, KBDK_DOWN},
{Event::LeftPaddleBIncrease, KBDK_UP},
{Event::LeftPaddleBFire, KBDK_4},
{Event::LeftPaddleBFire, KBDK_RCTRL},
{Event::PaddleTwoDecrease, KBDK_J},
{Event::PaddleTwoIncrease, KBDK_G},
{Event::PaddleTwoFire, KBDK_F},
{Event::RightPaddleADecrease, KBDK_J},
{Event::RightPaddleAIncrease, KBDK_G},
{Event::RightPaddleAFire, KBDK_F},
{Event::PaddleThreeDecrease, KBDK_H},
{Event::PaddleThreeIncrease, KBDK_Y},
{Event::PaddleThreeFire, KBDK_6},
{Event::RightPaddleBDecrease, KBDK_H},
{Event::RightPaddleBIncrease, KBDK_Y},
{Event::RightPaddleBFire, KBDK_6},
// Same as Paddles Zero..Three Fire + SHIFT
{Event::PaddleFourFire, KBDK_SPACE, KBDM_SHIFT},
{Event::PaddleFiveFire, KBDK_4, KBDM_SHIFT},
{Event::PaddleSixFire, KBDK_F, KBDM_SHIFT},
{Event::PaddleSevenFire, KBDK_6, KBDM_SHIFT},
{Event::QTPaddle3AFire, KBDK_SPACE, KBDM_SHIFT},
{Event::QTPaddle3BFire, KBDK_4, KBDM_SHIFT},
{Event::QTPaddle4AFire, KBDK_F, KBDM_SHIFT},
{Event::QTPaddle4BFire, KBDK_6, KBDM_SHIFT},
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PhysicalKeyboardHandler::EventMappingArray
PhysicalKeyboardHandler::DefaultKeypadMapping = {
{Event::KeyboardZero1, KBDK_1},
{Event::KeyboardZero2, KBDK_2},
{Event::KeyboardZero3, KBDK_3},
{Event::KeyboardZero4, KBDK_Q},
{Event::KeyboardZero5, KBDK_W},
{Event::KeyboardZero6, KBDK_E},
{Event::KeyboardZero7, KBDK_A},
{Event::KeyboardZero8, KBDK_S},
{Event::KeyboardZero9, KBDK_D},
{Event::KeyboardZeroStar, KBDK_Z},
{Event::KeyboardZero0, KBDK_X},
{Event::KeyboardZeroPound, KBDK_C},
PhysicalKeyboardHandler::DefaultKeyboardMapping = {
{Event::LeftKeyboard1, KBDK_1},
{Event::LeftKeyboard2, KBDK_2},
{Event::LeftKeyboard3, KBDK_3},
{Event::LeftKeyboard4, KBDK_Q},
{Event::LeftKeyboard5, KBDK_W},
{Event::LeftKeyboard6, KBDK_E},
{Event::LeftKeyboard7, KBDK_A},
{Event::LeftKeyboard8, KBDK_S},
{Event::LeftKeyboard9, KBDK_D},
{Event::LeftKeyboardStar, KBDK_Z},
{Event::LeftKeyboard0, KBDK_X},
{Event::LeftKeyboardPound, KBDK_C},
{Event::KeyboardOne1, KBDK_8},
{Event::KeyboardOne2, KBDK_9},
{Event::KeyboardOne3, KBDK_0},
{Event::KeyboardOne4, KBDK_I},
{Event::KeyboardOne5, KBDK_O},
{Event::KeyboardOne6, KBDK_P},
{Event::KeyboardOne7, KBDK_K},
{Event::KeyboardOne8, KBDK_L},
{Event::KeyboardOne9, KBDK_SEMICOLON},
{Event::KeyboardOneStar, KBDK_COMMA},
{Event::KeyboardOne0, KBDK_PERIOD},
{Event::KeyboardOnePound, KBDK_SLASH},
{Event::RightKeyboard1, KBDK_8},
{Event::RightKeyboard2, KBDK_9},
{Event::RightKeyboard3, KBDK_0},
{Event::RightKeyboard4, KBDK_I},
{Event::RightKeyboard5, KBDK_O},
{Event::RightKeyboard6, KBDK_P},
{Event::RightKeyboard7, KBDK_K},
{Event::RightKeyboard8, KBDK_L},
{Event::RightKeyboard9, KBDK_SEMICOLON},
{Event::RightKeyboardStar, KBDK_COMMA},
{Event::RightKeyboard0, KBDK_PERIOD},
{Event::RightKeyboardPound, KBDK_SLASH},
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -104,7 +104,7 @@ class PhysicalKeyboardHandler
/** Checks event type. */
bool isJoystickEvent(const Event::Type event) const;
bool isPaddleEvent(const Event::Type event) const;
bool isKeypadEvent(const Event::Type event) const;
bool isKeyboardEvent(const Event::Type event) const;
bool isCommonEvent(const Event::Type event) const;
void enableCommonMappings();
@ -149,12 +149,15 @@ class PhysicalKeyboardHandler
static EventMappingArray DefaultMenuMapping;
#ifdef GUI_SUPPORT
static EventMappingArray FixedEditMapping;
#endif
#ifdef DEBUGGER_SUPPORT
static EventMappingArray FixedPromptMapping;
#endif
static EventMappingArray DefaultCommonMapping;
// Controller specific mappings
static EventMappingArray DefaultJoystickMapping;
static EventMappingArray DefaultPaddleMapping;
static EventMappingArray DefaultKeypadMapping;
static EventMappingArray DefaultKeyboardMapping;
static EventMappingArray CompuMateMapping;
};

View File

@ -26,8 +26,6 @@
PaletteHandler::PaletteHandler(OSystem& system)
: myOSystem{system}
{
// Load user-defined palette for this ROM
loadUserPalette();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -315,6 +313,10 @@ void PaletteHandler::setPalette()
{
const string& name = myOSystem.settings().getString("palette");
// Load user-defined palette for this ROM
if(name == SETTING_USER)
loadUserPalette();
// Look at all the palettes, since we don't know which one is
// currently active
static constexpr BSPF::array2D<const PaletteArray*, PaletteType::NumTypes, int(ConsoleTiming::numTimings)> palettes = {{

View File

@ -58,7 +58,7 @@ void PhysicalJoystick::initialize(int index, const string& desc,
eraseMap(EventMode::kMenuMode);
eraseMap(EventMode::kJoystickMode);
eraseMap(EventMode::kPaddlesMode);
eraseMap(EventMode::kKeypadMode);
eraseMap(EventMode::kKeyboardMode);
eraseMap(EventMode::kCommonMode);
}
@ -70,7 +70,7 @@ json PhysicalJoystick::getMap() const
mapping["name"] = name;
for (auto& mode: {
EventMode::kMenuMode, EventMode::kJoystickMode, EventMode::kPaddlesMode, EventMode::kKeypadMode, EventMode::kCommonMode
EventMode::kMenuMode, EventMode::kJoystickMode, EventMode::kPaddlesMode, EventMode::kKeyboardMode, EventMode::kCommonMode
})
mapping[jsonName(mode)] = joyMap.saveMapping(mode);

View File

@ -30,6 +30,7 @@
#pragma clang diagnostic ignored "-Wdocumentation-unknown-command"
#pragma clang diagnostic ignored "-Wimplicit-fallthrough"
#pragma clang diagnostic ignored "-Wreserved-id-macro"
#pragma clang diagnostic ignored "-Wold-style-cast"
#include <SDL.h>
#pragma clang diagnostic pop
#else

View File

@ -284,7 +284,7 @@ void ZipHandler::ZipFile::readEcd()
// Find the ECD signature
Int32 offset;
for(offset = Int32(buflen - EcdReader::minimumLength()); offset >= 0; --offset)
for(offset = Int32(buflen - EcdReader::minimumLength()); offset >= 0; --offset)
{
EcdReader reader(buffer.get() + offset);
if(reader.signatureCorrect() && ((reader.totalLength() + offset) <= buflen))
@ -445,13 +445,13 @@ void ZipHandler::ZipFile::decompressDataType8(
uInt64 input_remaining = myHeader.compressedLength;
// Reset the stream
z_stream stream;
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
stream.opaque = Z_NULL;
stream.avail_in = 0;
stream.next_out = reinterpret_cast<Bytef *>(out.get());
stream.avail_out = uInt32(length); // TODO - use zip64
z_stream stream;
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
stream.opaque = Z_NULL;
stream.avail_in = 0;
stream.next_out = reinterpret_cast<Bytef *>(out.get());
stream.avail_out = uInt32(length); // TODO - use zip64
// Initialize the decompressor
int zerr = inflateInit2(&stream, -MAX_WBITS);

View File

@ -260,7 +260,7 @@ namespace BSPF
// Test whether the first string matches the second one (case insensitive)
// - the first character must match
// - the following characters must appear in the order of the first string
inline bool matches(string_view s1, string_view s2)
inline bool matchesIgnoreCase(string_view s1, string_view s2)
{
if(startsWithIgnoreCase(s1, s2.substr(0, 1)))
{
@ -277,6 +277,50 @@ namespace BSPF
return false;
}
// Test whether the first string matches the second one
// (case sensitive for upper case characters in second string, except first one)
// - the first character must match
// - the following characters must appear in the order of the first string
inline bool matchesCamelCase(const string_view s1, const string_view s2)
{
// skip leading '_' for matching
uInt32 ofs = (s1[0] == '_' && s2[0] == '_') ? 1 : 0;
if(startsWithIgnoreCase(s1.substr(ofs), s2.substr(ofs, 1)))
{
size_t lastUpper = ofs, pos = 1;
for(uInt32 j = 1 + ofs; j < s2.size(); ++j)
{
if(std::isupper(s2[j]))
{
size_t found = s1.find_first_of(s2[j], pos + ofs);
if(found == string::npos)
return false;
// make sure no upper case characters are skipped
for(size_t k = lastUpper + 1; k < found; ++k)
if(isupper(s1[k]))
return false;
pos = found + 1;
lastUpper = found;
}
else
{
size_t found = findIgnoreCase(s1, s2.substr(j, 1), pos + ofs);
if(found == string::npos)
return false;
pos += found + 1;
}
}
return true;
}
return false;
}
// Modify 'str', replacing all occurrences of 'from' with 'to'
inline void replaceAll(string& str, const string& from, const string& to)
{

View File

@ -48,11 +48,12 @@ NLOHMANN_JSON_SERIALIZE_ENUM(JoyHatDir, {
NLOHMANN_JSON_SERIALIZE_ENUM(EventMode, {
{EventMode::kEditMode, "kEditMode"},
{EventMode::kPromptMode, "kPromptMode"},
{EventMode::kMenuMode, "kMenuMode"},
{EventMode::kEmulationMode, "kEmulationMode"},
{EventMode::kJoystickMode, "kJoystickMode"},
{EventMode::kPaddlesMode, "kPaddlesMode"},
{EventMode::kKeypadMode, "kKeypadMode"},
{EventMode::kKeyboardMode, "kKeyboardMode"},
{EventMode::kCompuMateMode, "kCompuMateMode"},
{EventMode::kCommonMode, "kCommonMode"},
{EventMode::kNumModes, "kNumModes"},
@ -72,74 +73,74 @@ NLOHMANN_JSON_SERIALIZE_ENUM(Event::Type, {
{Event::ConsoleRightDiffToggle, "ConsoleRightDiffToggle"},
{Event::ConsoleSelect, "ConsoleSelect"},
{Event::ConsoleReset, "ConsoleReset"},
{Event::JoystickZeroUp, "JoystickZeroUp"},
{Event::JoystickZeroDown, "JoystickZeroDown"},
{Event::JoystickZeroLeft, "JoystickZeroLeft"},
{Event::JoystickZeroRight, "JoystickZeroRight"},
{Event::JoystickZeroFire, "JoystickZeroFire"},
{Event::JoystickZeroFire5, "JoystickZeroFire5"},
{Event::JoystickZeroFire9, "JoystickZeroFire9"},
{Event::JoystickOneUp, "JoystickOneUp"},
{Event::JoystickOneDown, "JoystickOneDown"},
{Event::JoystickOneLeft, "JoystickOneLeft"},
{Event::JoystickOneRight, "JoystickOneRight"},
{Event::JoystickOneFire, "JoystickOneFire"},
{Event::JoystickOneFire5, "JoystickOneFire5"},
{Event::JoystickOneFire9, "JoystickOneFire9"},
{Event::JoystickTwoUp, "JoystickTwoUp"},
{Event::JoystickTwoDown, "JoystickTwoDown"},
{Event::JoystickTwoLeft, "JoystickTwoLeft"},
{Event::JoystickTwoRight, "JoystickTwoRight"},
{Event::JoystickTwoFire, "JoystickTwoFire"},
{Event::JoystickThreeUp, "JoystickThreeUp"},
{Event::JoystickThreeDown, "JoystickThreeDown"},
{Event::JoystickThreeLeft, "JoystickThreeLeft"},
{Event::JoystickThreeRight, "JoystickThreeRight"},
{Event::JoystickThreeFire, "JoystickThreeFire"},
{Event::PaddleZeroDecrease, "PaddleZeroDecrease"},
{Event::PaddleZeroIncrease, "PaddleZeroIncrease"},
{Event::PaddleZeroAnalog, "PaddleZeroAnalog"},
{Event::PaddleZeroFire, "PaddleZeroFire"},
{Event::PaddleOneDecrease, "PaddleOneDecrease"},
{Event::PaddleOneIncrease, "PaddleOneIncrease"},
{Event::PaddleOneAnalog, "PaddleOneAnalog"},
{Event::PaddleOneFire, "PaddleOneFire"},
{Event::PaddleTwoDecrease, "PaddleTwoDecrease"},
{Event::PaddleTwoIncrease, "PaddleTwoIncrease"},
{Event::PaddleTwoAnalog, "PaddleTwoAnalog"},
{Event::PaddleTwoFire, "PaddleTwoFire"},
{Event::PaddleThreeDecrease, "PaddleThreeDecrease"},
{Event::PaddleThreeIncrease, "PaddleThreeIncrease"},
{Event::PaddleThreeAnalog, "PaddleThreeAnalog"},
{Event::PaddleThreeFire, "PaddleThreeFire"},
{Event::PaddleFourFire, "PaddleFourFire"},
{Event::PaddleFiveFire, "PaddleFiveFire"},
{Event::PaddleSixFire, "PaddleSixFire"},
{Event::PaddleSevenFire, "PaddleSevenFire"},
{Event::KeyboardZero1, "KeyboardZero1"},
{Event::KeyboardZero2, "KeyboardZero2"},
{Event::KeyboardZero3, "KeyboardZero3"},
{Event::KeyboardZero4, "KeyboardZero4"},
{Event::KeyboardZero5, "KeyboardZero5"},
{Event::KeyboardZero6, "KeyboardZero6"},
{Event::KeyboardZero7, "KeyboardZero7"},
{Event::KeyboardZero8, "KeyboardZero8"},
{Event::KeyboardZero9, "KeyboardZero9"},
{Event::KeyboardZeroStar, "KeyboardZeroStar"},
{Event::KeyboardZero0, "KeyboardZero0"},
{Event::KeyboardZeroPound, "KeyboardZeroPound"},
{Event::KeyboardOne1, "KeyboardOne1"},
{Event::KeyboardOne2, "KeyboardOne2"},
{Event::KeyboardOne3, "KeyboardOne3"},
{Event::KeyboardOne4, "KeyboardOne4"},
{Event::KeyboardOne5, "KeyboardOne5"},
{Event::KeyboardOne6, "KeyboardOne6"},
{Event::KeyboardOne7, "KeyboardOne7"},
{Event::KeyboardOne8, "KeyboardOne8"},
{Event::KeyboardOne9, "KeyboardOne9"},
{Event::KeyboardOneStar, "KeyboardOneStar"},
{Event::KeyboardOne0, "KeyboardOne0"},
{Event::KeyboardOnePound, "KeyboardOnePound"},
{Event::LeftJoystickUp, "LeftJoystickUp"},
{Event::LeftJoystickDown, "LeftJoystickDown"},
{Event::LeftJoystickLeft, "LeftJoystickLeft"},
{Event::LeftJoystickRight, "LeftJoystickRight"},
{Event::LeftJoystickFire, "LeftJoystickFire"},
{Event::LeftJoystickFire5, "LeftJoystickFire5"},
{Event::LeftJoystickFire9, "LeftJoystickFire9"},
{Event::RightJoystickUp, "RightJoystickUp"},
{Event::RightJoystickDown, "RightJoystickDown"},
{Event::RightJoystickLeft, "RightJoystickLeft"},
{Event::RightJoystickRight, "RightJoystickRight"},
{Event::RightJoystickFire, "RightJoystickFire"},
{Event::RightJoystickFire5, "RightJoystickFire5"},
{Event::RightJoystickFire9, "RightJoystickFire9"},
{Event::QTJoystickThreeUp, "QTJoystickThreeUp"},
{Event::QTJoystickThreeDown, "QTJoystickThreeDown"},
{Event::QTJoystickThreeLeft, "QTJoystickThreeLeft"},
{Event::QTJoystickThreeRight, "QTJoystickThreeRight"},
{Event::QTJoystickThreeFire, "QTJoystickThreeFire"},
{Event::QTJoystickFourUp, "QTJoystickFourUp"},
{Event::QTJoystickFourDown, "QTJoystickFourDown"},
{Event::QTJoystickFourLeft, "QTJoystickFourLeft"},
{Event::QTJoystickFourRight, "QTJoystickFourRight"},
{Event::QTJoystickFourFire, "QTJoystickFourFire"},
{Event::LeftPaddleADecrease, "LeftPaddleADecrease"},
{Event::LeftPaddleAIncrease, "LeftPaddleAIncrease"},
{Event::LeftPaddleAAnalog, "LeftPaddleAAnalog"},
{Event::LeftPaddleAFire, "LeftPaddleAFire"},
{Event::LeftPaddleBDecrease, "LeftPaddleBDecrease"},
{Event::LeftPaddleBIncrease, "LeftPaddleBIncrease"},
{Event::LeftPaddleBAnalog, "LeftPaddleBAnalog"},
{Event::LeftPaddleBFire, "LeftPaddleBFire"},
{Event::RightPaddleADecrease, "RightPaddleADecrease"},
{Event::RightPaddleAIncrease, "RightPaddleAIncrease"},
{Event::RightPaddleAAnalog, "RightPaddleAAnalog"},
{Event::RightPaddleAFire, "RightPaddleAFire"},
{Event::RightPaddleBDecrease, "RightPaddleBDecrease"},
{Event::RightPaddleBIncrease, "RightPaddleBIncrease"},
{Event::RightPaddleBAnalog, "RightPaddleBAnalog"},
{Event::RightPaddleBFire, "RightPaddleBFire"},
{Event::QTPaddle3AFire, "QTPaddle3AFire"},
{Event::QTPaddle3BFire, "QTPaddle3BFire"},
{Event::QTPaddle4AFire, "QTPaddle4AFire"},
{Event::QTPaddle4BFire, "QTPaddle4BFire"},
{Event::LeftKeyboard1, "LeftKeyboard1"},
{Event::LeftKeyboard2, "LeftKeyboard2"},
{Event::LeftKeyboard3, "LeftKeyboard3"},
{Event::LeftKeyboard4, "LeftKeyboard4"},
{Event::LeftKeyboard5, "LeftKeyboard5"},
{Event::LeftKeyboard6, "LeftKeyboard6"},
{Event::LeftKeyboard7, "LeftKeyboard7"},
{Event::LeftKeyboard8, "LeftKeyboard8"},
{Event::LeftKeyboard9, "LeftKeyboard9"},
{Event::LeftKeyboardStar, "LeftKeyboardStar"},
{Event::LeftKeyboard0, "LeftKeyboard0"},
{Event::LeftKeyboardPound, "LeftKeyboardPound"},
{Event::RightKeyboard1, "RightKeyboard1"},
{Event::RightKeyboard2, "RightKeyboard2"},
{Event::RightKeyboard3, "RightKeyboard3"},
{Event::RightKeyboard4, "RightKeyboard4"},
{Event::RightKeyboard5, "RightKeyboard5"},
{Event::RightKeyboard6, "RightKeyboard6"},
{Event::RightKeyboard7, "RightKeyboard7"},
{Event::RightKeyboard8, "RightKeyboard8"},
{Event::RightKeyboard9, "RightKeyboard9"},
{Event::RightKeyboardStar, "RightKeyboardStar"},
{Event::RightKeyboard0, "RightKeyboard0"},
{Event::RightKeyboardPound, "RightKeyboardPound"},
{Event::CompuMateFunc, "CompuMateFunc"},
{Event::CompuMateShift, "CompuMateShift"},
{Event::CompuMate0, "CompuMate0"},

View File

@ -206,7 +206,7 @@ int main(int ac, char* av[])
// Create the full OSystem after the settings, since settings are
// probably needed for defaults
Logger::debug("Creating the OSystem ...");
Logger::log("Creating the OSystem ...");
if(!theOSystem->initialize(globalOpts))
{
Logger::error("ERROR: Couldn't create OSystem");

View File

@ -1493,23 +1493,23 @@ void CartDebug::getCompletions(const char* in, StringList& completions) const
{
// First scan system equates
for(uInt16 addr = 0x00; addr <= 0x0F; ++addr)
if(ourTIAMnemonicR[addr] && BSPF::matches(ourTIAMnemonicR[addr], in))
if(ourTIAMnemonicR[addr] && BSPF::matchesIgnoreCase(ourTIAMnemonicR[addr], in))
completions.push_back(ourTIAMnemonicR[addr]);
for(uInt16 addr = 0x00; addr <= 0x3F; ++addr)
if(ourTIAMnemonicW[addr] && BSPF::matches(ourTIAMnemonicW[addr], in))
if(ourTIAMnemonicW[addr] && BSPF::matchesIgnoreCase(ourTIAMnemonicW[addr], in))
completions.push_back(ourTIAMnemonicW[addr]);
for(uInt16 addr = 0; addr <= 0x297-0x280; ++addr)
if(ourIOMnemonic[addr] && BSPF::matches(ourIOMnemonic[addr], in))
if(ourIOMnemonic[addr] && BSPF::matchesIgnoreCase(ourIOMnemonic[addr], in))
completions.push_back(ourIOMnemonic[addr]);
for(uInt16 addr = 0; addr <= 0x7F; ++addr)
if(ourZPMnemonic[addr] && BSPF::matches(ourZPMnemonic[addr], in))
if(ourZPMnemonic[addr] && BSPF::matchesIgnoreCase(ourZPMnemonic[addr], in))
completions.push_back(ourZPMnemonic[addr]);
// Now scan user-defined labels
for(const auto& iter: myUserAddresses)
{
const char* l = iter.first.c_str();
if(BSPF::matches(l, in))
if(BSPF::matchesCamelCase(l, in))
completions.push_back(l);
}
}

View File

@ -26,6 +26,7 @@
#include "FSNode.hxx"
#include "Settings.hxx"
#include "DebuggerDialog.hxx"
#include "PromptWidget.hxx"
#include "DebuggerParser.hxx"
#include "StateManager.hxx"
#include "RewindManager.hxx"
@ -123,6 +124,7 @@ bool Debugger::start(const string& message, int address, bool read,
{
if(myOSystem.eventHandler().enterDebugMode())
{
myFirstLog = true;
// This must be done *after* we enter debug mode,
// so the message isn't erased
ostringstream buf;
@ -150,7 +152,15 @@ bool Debugger::startWithFatalError(const string& message)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::quit(bool exitrom)
void Debugger::quit()
{
if(myOSystem.settings().getBool("dbg.autosave")
&& myDialog->prompt().isLoaded())
myParser->run("save");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::exit(bool exitrom)
{
if(exitrom)
myOSystem.eventHandler().handleEvent(Event::ExitGame);
@ -172,7 +182,8 @@ string Debugger::autoExec(StringList* history)
<< myParser->exec(autoexec, history) << endl;
// Also, "romname.script" if present
FilesystemNode romname(myOSystem.romFile().getPathWithExt(".script"));
const string path = myOSystem.userDir().getPath() + myOSystem.romFile().getNameWithExt(".script");
FilesystemNode romname(path);
buf << myParser->exec(romname, history) << endl;
// Init builtins
@ -442,6 +453,82 @@ bool Debugger::writeTrap(uInt16 t)
return writeTraps().isInitialized() && writeTraps().isSet(t);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::log(const string& triggerMsg)
{
const CartDebug::Disassembly& disasm = myCartDebug->disassembly();
int pc = myCpuDebug->pc();
if(myFirstLog)
{
ostringstream msg;
msg << "Trigger: Frame Scn Cy Pxl | PS A X Y SP | ";
if(myCartDebug->romBankCount() > 1)
{
if(myCartDebug->romBankCount() > 9)
msg << "Bk/";
else
msg << "B/";
}
msg << "Addr Code Disam";
Logger::log(msg.str());
myFirstLog = false;
}
// First find the lines in the range, and determine the longest string
uInt16 start = pc & 0xFFF;
uInt32 list_size = uInt32(disasm.list.size());
uInt32 pos;
for(pos = 0; pos < list_size; ++pos)
{
const CartDebug::DisassemblyTag& tag = disasm.list[pos];
if((tag.address & 0xfff) >= start)
break;
}
const CartDebug::DisassemblyTag& tag = disasm.list[pos];
ostringstream msg;
msg << std::left << std::setw(10) << std::setfill(' ') << triggerMsg;
msg << Base::toString(myTiaDebug->frameCount(), Base::Fmt::_10_5) << " "
<< Base::toString(myTiaDebug->scanlines(), Base::Fmt::_10_3) << " "
<< Base::toString(myTiaDebug->clocksThisLine() / 3, Base::Fmt::_10_02) << " "
<< Base::toString(myTiaDebug->clocksThisLine() - 68, Base::Fmt::_10_3) << " | ";
msg << (myCpuDebug->n() ? "N" : "n")
<< (myCpuDebug->v() ? "V" : "v") << "-"
<< (myCpuDebug->b() ? "B" : "b")
<< (myCpuDebug->d() ? "D" : "d")
<< (myCpuDebug->i() ? "I" : "i")
<< (myCpuDebug->z() ? "Z" : "z")
<< (myCpuDebug->c() ? "C" : "c") << " "
<< Base::HEX2 << myCpuDebug->a() << " "
<< Base::HEX2 << myCpuDebug->x() << " "
<< Base::HEX2 << myCpuDebug->y() << " "
<< Base::HEX2 << myCpuDebug->sp() << " |";
if(myCartDebug->romBankCount() > 1)
{
if(myCartDebug->romBankCount() > 9)
msg << Base::toString(myCartDebug->getBank(pc), Base::Fmt::_10) << "/";
else
msg << " " << myCartDebug->getBank(pc) << "/";
}
else
msg << " ";
msg << Base::HEX4 << pc << " "
<< std::left << std::setw(8) << std::setfill(' ') << tag.bytes << " "
<< tag.disasm.substr(0, 7);
if(tag.disasm.length() > 8)
msg << tag.disasm.substr(8);
Logger::log(msg.str());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 Debugger::peek(uInt16 addr, Device::AccessFlags flags)
{
@ -816,12 +903,12 @@ void Debugger::getCompletions(const char* in, StringList& list) const
for(const auto& iter : myFunctions)
{
const char* l = iter.first.c_str();
if(BSPF::matches(l, in))
if(BSPF::matchesCamelCase(l, in))
list.push_back(l);
}
for(const auto& reg: ourPseudoRegisters)
if(BSPF::matches(reg.name, in))
if(BSPF::matchesCamelCase(reg.name, in))
list.push_back(reg.name);
}
}
@ -849,28 +936,28 @@ bool Debugger::canExit() const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
std::array<Debugger::BuiltinFunction, 18> Debugger::ourBuiltinFunctions = { {
// left joystick:
{ "_joy0left", "!(*SWCHA & $40)", "Left joystick moved left" },
{ "_joy0right", "!(*SWCHA & $80)", "Left joystick moved right" },
{ "_joy0up", "!(*SWCHA & $10)", "Left joystick moved up" },
{ "_joy0down", "!(*SWCHA & $20)", "Left joystick moved down" },
{ "_joy0button", "!(*INPT4 & $80)", "Left joystick button pressed" },
{ "_joy0Left", "!(*SWCHA & $40)", "Left joystick moved left" },
{ "_joy0Right", "!(*SWCHA & $80)", "Left joystick moved right" },
{ "_joy0Up", "!(*SWCHA & $10)", "Left joystick moved up" },
{ "_joy0Down", "!(*SWCHA & $20)", "Left joystick moved down" },
{ "_joy0Fire", "!(*INPT4 & $80)", "Left joystick fire button pressed" },
// right joystick:
{ "_joy1left", "!(*SWCHA & $04)", "Right joystick moved left" },
{ "_joy1right", "!(*SWCHA & $08)", "Right joystick moved right" },
{ "_joy1up", "!(*SWCHA & $01)", "Right joystick moved up" },
{ "_joy1down", "!(*SWCHA & $02)", "Right joystick moved down" },
{ "_joy1button", "!(*INPT5 & $80)", "Right joystick button pressed" },
{ "_joy1Left", "!(*SWCHA & $04)", "Right joystick moved left" },
{ "_joy1Right", "!(*SWCHA & $08)", "Right joystick moved right" },
{ "_joy1Up", "!(*SWCHA & $01)", "Right joystick moved up" },
{ "_joy1Down", "!(*SWCHA & $02)", "Right joystick moved down" },
{ "_joy1Fire", "!(*INPT5 & $80)", "Right joystick fire button pressed" },
// console switches:
{ "_select", "!(*SWCHB & $02)", "Game Select pressed" },
{ "_reset", "!(*SWCHB & $01)", "Game Reset pressed" },
{ "_color", "*SWCHB & $08", "Color/BW set to Color" },
{ "_bw", "!(*SWCHB & $08)", "Color/BW set to BW" },
{ "_diff0b", "!(*SWCHB & $40)", "Left diff. set to B (easy)" },
{ "_diff0a", "*SWCHB & $40", "Left diff. set to A (hard)" },
{ "_diff1b", "!(*SWCHB & $80)", "Right diff. set to B (easy)" },
{ "_diff1a", "*SWCHB & $80", "Right diff. set to A (hard)" }
{ "_diff0B", "!(*SWCHB & $40)", "Left diff. set to B (easy)" },
{ "_diff0A", "*SWCHB & $40", "Left diff. set to A (hard)" },
{ "_diff1B", "!(*SWCHB & $80)", "Right diff. set to B (easy)" },
{ "_diff1A", "*SWCHB & $80", "Right diff. set to A (hard)" }
} };
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -878,25 +965,25 @@ std::array<Debugger::BuiltinFunction, 18> Debugger::ourBuiltinFunctions = { {
std::array<Debugger::PseudoRegister, 16> Debugger::ourPseudoRegisters = { {
// Debugger::PseudoRegister Debugger::ourPseudoRegisters[NUM_PSEUDO_REGS] = {
{ "_bank", "Currently selected bank" },
{ "_cclocks", "Color clocks on current scanline" },
{ "_cycleshi", "Higher 32 bits of number of cycles since emulation started" },
{ "_cycleslo", "Lower 32 bits of number of cycles since emulation started" },
{ "_fcount", "Number of frames since emulation started" },
{ "_fcycles", "Number of cycles since frame started" },
{ "_ftimreadcycles","Number of cycles used by timer reads since frame started" },
{ "_fwsynccycles", "Number of cycles skipped by WSYNC since frame started" },
{ "_icycles", "Number of cycles of last instruction" },
{ "_cClocks", "Color clocks on current scanline" },
{ "_cyclesHi", "Higher 32 bits of number of cycles since emulation started" },
{ "_cyclesLo", "Lower 32 bits of number of cycles since emulation started" },
{ "_fCount", "Number of frames since emulation started" },
{ "_fCycles", "Number of cycles since frame started" },
{ "_fTimReadCycles","Number of cycles used by timer reads since frame started" },
{ "_fWsyncCycles", "Number of cycles skipped by WSYNC since frame started" },
{ "_iCycles", "Number of cycles of last instruction" },
{ "_scan", "Current scanline count" },
{ "_scanend", "Scanline count at end of last frame" },
{ "_scycles", "Number of cycles in current scanline" },
{ "_timwrapread", "Timer read wrapped on this cycle" },
{ "_timwrapwrite", "Timer write wrapped on this cycle" },
{ "_vblank", "Whether vertical blank is enabled (1 or 0)" },
{ "_vsync", "Whether vertical sync is enabled (1 or 0)" }
{ "_scanEnd", "Scanline count at end of last frame" },
{ "_sCycles", "Number of cycles in current scanline" },
{ "_timWrapRead", "Timer read wrapped on this cycle" },
{ "_timWrapWrite", "Timer write wrapped on this cycle" },
{ "_vBlank", "Whether vertical blank is enabled (1 or 0)" },
{ "_vSync", "Whether vertical sync is enabled (1 or 0)" }
// CPU address access functions:
/*{ "_lastread", "last CPU read address" },
{ "_lastwrite", "last CPU write address" },
{ "__lastbaseread", "last CPU read base address" },
{ "__lastbasewrite", "last CPU write base address" }*/
/*{ "_lastRead", "last CPU read address" },
{ "_lastWrite", "last CPU write address" },
{ "__lastBaseRead", "last CPU read base address" },
{ "__lastBaseWrite", "last CPU write base address" }*/
} };
//

View File

@ -102,7 +102,12 @@ class Debugger : public DialogContainer
Wrapper method for EventHandler::leaveDebugMode() for those classes
that don't have access to EventHandler.
*/
void quit(bool exitrom);
void exit(bool exitrom);
/**
Executed when debugger is quit.
*/
void quit();
bool addFunction(const string& name, const string& def,
Expression* exp, bool builtin = false);
@ -321,6 +326,7 @@ class Debugger : public DialogContainer
bool readTrap(uInt16 t);
bool writeTrap(uInt16 t);
void clearAllTraps();
void log(const string& triggerMsg);
// Set a bunch of RAM locations at once
string setRAM(IntArray& args);
@ -363,6 +369,7 @@ class Debugger : public DialogContainer
static std::array<PseudoRegister, 16> ourPseudoRegisters;
static constexpr Int8 ANY_BANK = -1;
bool myFirstLog{true};
private:
// rewind/unwind n states

File diff suppressed because it is too large Load Diff

View File

@ -101,7 +101,8 @@ class DebuggerParser
std::array<Parameters, 10> parms;
std::function<void (DebuggerParser*)> executor;
};
static std::array<Command, 100> commands;
using CommandArray = std::array<Command, 103>;
static CommandArray commands;
struct Trap
{
@ -149,32 +150,34 @@ class DebuggerParser
// List of available command methods
void executeA();
void executeAud();
void executeAutoSave();
void executeBase();
void executeBCol();
void executeBreak();
void executeBreakif();
void executeBreaklabel();
void executeBreakIf();
void executeBreakLabel();
void executeC();
void executeCheat();
void executeClearbreaks();
void executeClearconfig();
void executeClearsavestateifs();
void executeCleartraps();
void executeClearwatches();
void executeClearBreaks();
void executeClearConfig();
void executeClearHistory();
void executeClearSaveStateIfs();
void executeClearTraps();
void executeClearWatches();
void executeCls();
void executeCode();
void executeCol();
void executeColortest();
void executeColorTest();
void executeD();
void executeData();
void executeDebugColors();
void executeDefine();
void executeDelbreakif();
void executeDelfunction();
void executeDelsavestateif();
void executeDeltrap();
void executeDelwatch();
void executeDisasm();
void executeDelBreakIf();
void executeDelFunction();
void executeDelSaveStateIf();
void executeDelTrap();
void executeDelWatch();
void executeDisAsm();
void executeDump();
void executeExec();
void executeExitRom();
@ -193,14 +196,15 @@ class DebuggerParser
void executeJoy1Right();
void executeJoy1Fire();
void executeJump();
void executeListbreaks();
void executeListconfig();
void executeListfunctions();
void executeListsavestateifs();
void executeListtraps();
void executeLoadallstates();
void executeLoadconfig();
void executeLoadstate();
void executeListBreaks();
void executeListConfig();
void executeListFunctions();
void executeListSaveStateIfs();
void executeListTraps();
void executeLoadAllStates();
void executeLoadConfig();
void executeLoadState();
void executeLogBreaks();
void executeN();
void executePalette();
void executePc();
@ -219,25 +223,25 @@ class DebuggerParser
void executeS();
void executeSave();
void executeSaveAccess();
void executeSaveallstates();
void executeSaveconfig();
void executeSavedisassembly();
void executeSaverom();
void executeSaveses();
void executeSavesnap();
void executeSavestate();
void executeSavestateif();
void executeScanline();
void executeSaveAllStates();
void executeSaveConfig();
void executeSaveDisassembly();
void executeSaveRom();
void executeSaveSes();
void executeSaveSnap();
void executeSaveState();
void executeSaveStateIf();
void executeScanLine();
void executeStep();
void executeStepwhile();
void executeStepWhile();
void executeTia();
void executeTrace();
void executeTrap();
void executeTrapif();
void executeTrapread();
void executeTrapreadif();
void executeTrapwrite();
void executeTrapwriteif();
void executeTrapIf();
void executeTrapRead();
void executeTrapReadIf();
void executeTrapWrite();
void executeTrapWriteIf();
void executeTraps(bool read, bool write, const string& command, bool cond = false);
void executeTrapRW(uInt32 addr, bool read, bool write, bool add = true); // not exposed by debugger
void executeType();

View File

@ -0,0 +1,286 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2021 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include <cmath>
#include "OSystem.hxx"
//#include "EditTextWidget.hxx"
#include "PopUpWidget.hxx"
#include "DataGridWidget.hxx"
#include "CartARMWidget.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeARMWidget::CartridgeARMWidget(
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
int x, int y, int w, int h, CartridgeARM& cart)
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
myCart{cart}
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeARMWidget::addCycleWidgets(int xpos, int ypos)
{
const int INDENT = 20;
const int VGAP = 4;
VariantList items;
new StaticTextWidget(_boss, _font, xpos, ypos + 1, "ARM emulation cycles:");
xpos += INDENT; ypos += myLineHeight + VGAP;
myIncCycles = new CheckboxWidget(_boss, _font, xpos, ypos + 1, "Increase 6507 cycles",
kIncCyclesChanged);
myIncCycles->setToolTip("Increase 6507 cycles with approximated ARM cycles.");
myIncCycles->setTarget(this);
myCycleFactor = new SliderWidget(_boss, _font, myIncCycles->getRight() + _fontWidth * 2, ypos - 1,
_fontWidth * 10, _lineHeight, "Cycle factor", _fontWidth * 14,
kFactorChanged, _fontWidth * 4, "%");
myCycleFactor->setMinValue(90); myCycleFactor->setMaxValue(110);
myCycleFactor->setTickmarkIntervals(4);
myCycleFactor->setToolTip("Correct approximated ARM cycles by factor.");
myCycleFactor->setTarget(this);
ypos += (myLineHeight + VGAP) * 2;
myCyclesLabel = new StaticTextWidget(_boss, _font, xpos, ypos + 1, "Cycles #");
myPrevThumbCycles = new DataGridWidget(_boss, _font, myCyclesLabel->getRight(), ypos - 1,
1, 1, 6, 32, Common::Base::Fmt::_10_6);
myPrevThumbCycles->setEditable(false);
myPrevThumbCycles->setToolTip("Approximated CPU cycles of last but one ARM run.\n");
myThumbCycles = new DataGridWidget(_boss, _font,
myPrevThumbCycles->getRight() + _fontWidth / 2, ypos - 1,
1, 1, 6, 32, Common::Base::Fmt::_10_6);
myThumbCycles->setEditable(false);
myThumbCycles->setToolTip("Approximated CPU cycles of last ARM run.\n");
StaticTextWidget* s = new StaticTextWidget(_boss, _font, myCycleFactor->getLeft(), ypos + 1,
"Instructions #");
myPrevThumbInstructions = new DataGridWidget(_boss, _font, s->getRight(), ypos - 1,
1, 1, 6, 32, Common::Base::Fmt::_10_6);
myPrevThumbInstructions->setEditable(false);
myPrevThumbInstructions->setToolTip("Instructions of last but one ARM run.\n");
myThumbInstructions = new DataGridWidget(_boss, _font,
myPrevThumbInstructions->getRight() + _fontWidth / 2, ypos - 1,
1, 1, 6, 32, Common::Base::Fmt::_10_6);
myThumbInstructions->setEditable(false);
myThumbInstructions->setToolTip("Instructions of last ARM run.\n");
// add later to allow aligning
ypos -= myLineHeight + VGAP;
int pwidth = myThumbCycles->getRight() - myPrevThumbCycles->getLeft()
- PopUpWidget::dropDownWidth(_font);
items.clear();
VarList::push_back(items, "LPC2101" + ELLIPSIS + "3", static_cast<uInt32>(Thumbulator::ChipType::LPC2101));
VarList::push_back(items, "LPC2104" + ELLIPSIS + "6 OC", static_cast<uInt32>(Thumbulator::ChipType::LPC2104_OC));
VarList::push_back(items, "LPC2104" + ELLIPSIS + "6", static_cast<uInt32>(Thumbulator::ChipType::LPC2104));
VarList::push_back(items, "LPC213x", static_cast<uInt32>(Thumbulator::ChipType::LPC213x));
myChipType = new PopUpWidget(_boss, _font, xpos, ypos, pwidth, myLineHeight, items,
"Chip ", 0, kChipChanged);
myChipType->setToolTip("Select emulated ARM chip.");
myChipType->setTarget(this);
myLockMamMode = new CheckboxWidget(_boss, _font, myCycleFactor->getLeft(), ypos + 1, "MAM Mode",
kMamLockChanged);
myLockMamMode->setToolTip("Check to lock Memory Accelerator Module (MAM) mode.");
myLockMamMode->setTarget(this);
pwidth = myThumbInstructions->getRight() - myPrevThumbInstructions->getLeft()
- PopUpWidget::dropDownWidth(_font);
items.clear();
VarList::push_back(items, "Off (0)", static_cast<uInt32>(Thumbulator::MamModeType::mode0));
VarList::push_back(items, "Partial (1)", static_cast<uInt32>(Thumbulator::MamModeType::mode1));
VarList::push_back(items, "Full (2)", static_cast<uInt32>(Thumbulator::MamModeType::mode2));
VarList::push_back(items, "1 Cycle (X)", static_cast<uInt32>(Thumbulator::MamModeType::modeX));
myMamMode = new PopUpWidget(_boss, _font, myPrevThumbInstructions->getLeft(), ypos,
pwidth, myLineHeight, items, "", 0, kMamModeChanged);
myMamMode->setToolTip("Select emulated Memory Accelerator Module (MAM) mode.");
myMamMode->setTarget(this);
// define the tab order
addFocusWidget(myIncCycles);
addFocusWidget(myCycleFactor);
addFocusWidget(myChipType);
addFocusWidget(myLockMamMode);
addFocusWidget(myMamMode);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeARMWidget::saveOldState()
{
myOldState.armPrevRun.clear();
myOldState.armRun.clear();
myOldState.mamMode = static_cast<uInt32>(myCart.mamMode());
myOldState.armPrevRun.push_back(myCart.prevCycles());
myOldState.armPrevRun.push_back(myCart.prevStats().instructions);
myOldState.armRun.push_back(myCart.cycles());
myOldState.armRun.push_back(myCart.stats().instructions);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeARMWidget::loadConfig()
{
bool isChanged;
bool devSettings = instance().settings().getBool("dev.settings");
IntArray alist;
IntArray vlist;
BoolArray changed;
myChipType->setSelectedIndex(static_cast<uInt32>(instance().settings().getInt("dev.thumb.chiptype")));
handleChipType();
isChanged = static_cast<uInt32>(myCart.mamMode()) != myOldState.mamMode;
myMamMode->setSelectedIndex(static_cast<uInt32>(myCart.mamMode()), isChanged);
myMamMode->setEnabled(devSettings && myLockMamMode->getState());
myLockMamMode->setEnabled(devSettings);
// ARM cycles
myIncCycles->setState(instance().settings().getBool("dev.thumb.inccycles"));
myCycleFactor->setValue(std::round(instance().settings().getFloat("dev.thumb.cyclefactor") * 100.F));
handleArmCycles();
alist.clear(); vlist.clear(); changed.clear();
alist.push_back(0); vlist.push_back(myCart.prevCycles());
changed.push_back(myCart.prevCycles() != uInt32(myOldState.armPrevRun[0]));
myPrevThumbCycles->setList(alist, vlist, changed);
alist.clear(); vlist.clear(); changed.clear();
alist.push_back(0); vlist.push_back(myCart.prevStats().instructions);
changed.push_back(myCart.prevStats().instructions != uInt32(myOldState.armPrevRun[1]));
myPrevThumbInstructions->setList(alist, vlist, changed);
alist.clear(); vlist.clear(); changed.clear();
alist.push_back(0); vlist.push_back(myCart.cycles());
changed.push_back(myCart.cycles() != uInt32(myOldState.armRun[0]));
myThumbCycles->setList(alist, vlist, changed);
alist.clear(); vlist.clear(); changed.clear();
alist.push_back(0); vlist.push_back(myCart.stats().instructions);
changed.push_back(myCart.stats().instructions != uInt32(myOldState.armRun[1]));
myThumbInstructions->setList(alist, vlist, changed);
CartDebugWidget::loadConfig();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeARMWidget::handleCommand(CommandSender* sender,
int cmd, int data, int id)
{
switch(cmd)
{
case kChipChanged:
handleChipType();
break;
case kMamLockChanged:
handleMamLock();
break;
case kMamModeChanged:
handleMamMode();
break;
case kIncCyclesChanged:
case kFactorChanged:
handleArmCycles();
break;
default:
break;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeARMWidget::handleChipType()
{
bool devSettings = instance().settings().getBool("dev.settings");
if(devSettings)
{
instance().settings().setValue("dev.thumb.chiptype", myChipType->getSelectedTag().toInt());
}
myChipType->setEnabled(devSettings);
Thumbulator::ChipPropsType chipProps = myCart.setChipType(static_cast<Thumbulator::ChipType>(myChipType->getSelectedTag().toInt()));
// update tooltip with currently selecte chip's properties
string tip = myChipType->getToolTip(Common::Point(0, 0));
ostringstream buf;
tip = tip.substr(0, 25);
buf << tip << "\nCurrent:\n"
<< chipProps.MHz << " MHz, "
<< chipProps.flashBanks << " flash bank"
<< (chipProps.flashBanks > 1 ? "s" : "") << ", "
<< chipProps.flashCycles - 1 << " wait states";
myChipType->setToolTip(buf.str());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeARMWidget::handleMamLock()
{
bool checked = myLockMamMode->getState();
myMamMode->setEnabled(checked);
myCart.lockMamMode(checked);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeARMWidget::handleMamMode()
{
// override MAM mode set by ROM
Int32 mode = myMamMode->getSelected();
string name = myMamMode->getSelectedName();
myMamMode->setSelectedName(name + "XXX");
instance().settings().setValue("dev.thumb.mammode", mode);
myCart.setMamMode(static_cast<Thumbulator::MamModeType>(mode));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeARMWidget::handleArmCycles()
{
bool devSettings = instance().settings().getBool("dev.settings");
bool enable = myIncCycles->getState();
double factor = static_cast<double>(myCycleFactor->getValue()) / 100.0;
if(devSettings)
{
instance().settings().setValue("dev.thumb.inccycles", enable);
instance().settings().setValue("dev.thumb.cyclefactor", factor);
}
myIncCycles->setEnabled(devSettings);
myCycleFactor->setEnabled(devSettings);
myCyclesLabel->setEnabled(devSettings);
myThumbCycles->setEnabled(devSettings);
myPrevThumbCycles->setEnabled(devSettings);
myCart.incCycles(devSettings && enable);
myCart.cycleFactor(factor);
myCart.enableCycleCount(devSettings);
}

View File

@ -0,0 +1,96 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2021 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#ifndef CARTRIDGE_ARM_WIDGET_HXX
#define CARTRIDGE_ARM_WIDGET_HXX
#include "CartARM.hxx"
#include "CartDebugWidget.hxx"
class CheckboxWidget;
class SliderWidget;
class PopUpWidget;
class DataGridWidget;
/**
Abstract base class for ARM cart widgets.
@author Thomas Jentzsch
*/
class CartridgeARMWidget : public CartDebugWidget
{
public:
CartridgeARMWidget(GuiObject* boss, const GUI::Font& lfont,
const GUI::Font& nfont,
int x, int y, int w, int h,
CartridgeARM& cart);
~CartridgeARMWidget() override = default;
protected:
void addCycleWidgets(int xpos, int ypos);
void saveOldState() override;
void loadConfig() override;
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
private:
void handleChipType();
void handleMamLock();
void handleMamMode();
void handleArmCycles();
private:
struct CartState {
uInt32 mamMode{0};
uIntArray armRun;
uIntArray armPrevRun;
};
CartridgeARM& myCart;
CheckboxWidget* myIncCycles{nullptr};
SliderWidget* myCycleFactor{nullptr};
PopUpWidget* myChipType{nullptr};
CheckboxWidget* myLockMamMode{nullptr};
PopUpWidget* myMamMode{nullptr};
StaticTextWidget* myCyclesLabel{nullptr};
DataGridWidget* myPrevThumbCycles{nullptr};
DataGridWidget* myPrevThumbInstructions{nullptr};
DataGridWidget* myThumbCycles{nullptr};
DataGridWidget* myThumbInstructions{nullptr};
CartState myOldState;
enum {
kChipChanged = 'chCh',
kMamLockChanged = 'mlCh',
kMamModeChanged = 'mmCh',
kIncCyclesChanged = 'inCH',
kFactorChanged = 'fcCH'
};
private:
// Following constructors and assignment operators not supported
CartridgeARMWidget() = delete;
CartridgeARMWidget(const CartridgeARMWidget&) = delete;
CartridgeARMWidget(CartridgeARMWidget&&) = delete;
CartridgeARMWidget& operator=(const CartridgeARMWidget&) = delete;
CartridgeARMWidget& operator=(CartridgeARMWidget&&) = delete;
};
#endif

View File

@ -25,7 +25,7 @@
CartridgeBUSWidget::CartridgeBUSWidget(
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
int x, int y, int w, int h, CartridgeBUS& cart)
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
: CartridgeARMWidget(boss, lfont, nfont, x, y, w, h, cart),
myCart{cart}
{
uInt16 size = 8 * 4096;
@ -186,32 +186,7 @@ CartridgeBUSWidget::CartridgeBUSWidget(
myDigitalSample->setEditable(false);
xpos = 10; ypos += myLineHeight + 4 * 2;
new StaticTextWidget(boss, _font, xpos, ypos + 1, "Last ARM run stats:");
xpos = 10 + _font.getMaxCharWidth() * 2; ypos += myLineHeight + 4;
StaticTextWidget* s = new StaticTextWidget(boss, _font, xpos, ypos + 1, "Mem. cycles ");
myThumbMemCycles = new EditTextWidget(boss, _font, s->getRight(), ypos - 1,
EditTextWidget::calcWidth(_font, 6), myLineHeight, "");
myThumbMemCycles->setEditable(false);
myThumbMemCycles->setToolTip("Number of memory cycles of last ARM run.");
s = new StaticTextWidget(boss, _font, myThumbMemCycles->getRight() + _fontWidth * 2, ypos + 1, "Fetches ");
myThumbFetches = new EditTextWidget(boss, _font, s->getRight(), ypos - 1,
EditTextWidget::calcWidth(_font, 6), myLineHeight, "");
myThumbFetches->setEditable(false);
myThumbFetches->setToolTip("Number of fetches/instructions of last ARM run.");
ypos += myLineHeight + 4;
s = new StaticTextWidget(boss, _font, xpos, ypos + 1, "Reads ");
myThumbReads = new EditTextWidget(boss, _font, myThumbMemCycles->getLeft(), ypos - 1,
EditTextWidget::calcWidth(_font, 6), myLineHeight, "");
myThumbReads->setEditable(false);
myThumbReads->setToolTip("Number of reads of last ARM run.");
s = new StaticTextWidget(boss, _font, myThumbReads->getRight() + _fontWidth * 2, ypos + 1, "Writes ");
myThumbWrites = new EditTextWidget(boss, _font, myThumbFetches->getLeft(), ypos - 1,
EditTextWidget::calcWidth(_font, 6), myLineHeight, "");
myThumbWrites->setEditable(false);
myThumbWrites->setToolTip("Number of write of last ARM run.");
addCycleWidgets(xpos, ypos);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -268,6 +243,8 @@ void CartridgeBUSWidget::saveOldState()
myOldState.internalram.push_back(myCart.myRAM[i]);
myOldState.samplepointer.push_back(myCart.getSample());
CartridgeARMWidget::saveOldState();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -394,17 +371,7 @@ void CartridgeBUSWidget::loadConfig()
mySamplePointer->setCrossed(true);
}
myThumbMemCycles->setText(Common::Base::toString(myCart.stats().fetches
+ myCart.stats().reads + myCart.stats().writes,
Common::Base::Fmt::_10_6));
myThumbFetches->setText(Common::Base::toString(myCart.stats().fetches,
Common::Base::Fmt::_10_6));
myThumbReads->setText(Common::Base::toString(myCart.stats().reads,
Common::Base::Fmt::_10_6));
myThumbWrites->setText(Common::Base::toString(myCart.stats().writes,
Common::Base::Fmt::_10_6));
CartDebugWidget::loadConfig();
CartridgeARMWidget::loadConfig();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -418,6 +385,8 @@ void CartridgeBUSWidget::handleCommand(CommandSender* sender,
myCart.lockBank();
invalidate();
}
else
CartridgeARMWidget::handleCommand(sender, cmd, data, id);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -24,9 +24,9 @@ class CheckboxWidget;
class DataGridWidget;
class EditTextWidget;
#include "CartDebugWidget.hxx"
#include "CartARMWidget.hxx"
class CartridgeBUSWidget : public CartDebugWidget
class CartridgeBUSWidget : public CartridgeARMWidget
{
public:
CartridgeBUSWidget(GuiObject* boss, const GUI::Font& lfont,
@ -66,10 +66,6 @@ class CartridgeBUSWidget : public CartDebugWidget
DataGridWidget* mySamplePointer{nullptr};
CheckboxWidget* myBusOverdrive{nullptr};
CheckboxWidget* myDigitalSample{nullptr};
EditTextWidget* myThumbMemCycles{nullptr};
EditTextWidget* myThumbFetches{nullptr};
EditTextWidget* myThumbReads{nullptr};
EditTextWidget* myThumbWrites{nullptr};
std::array<StaticTextWidget*, 6> myDatastreamLabels{nullptr};
CartState myOldState;

View File

@ -15,6 +15,7 @@
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include "OSystem.hxx"
#include "DataGridWidget.hxx"
#include "PopUpWidget.hxx"
#include "EditTextWidget.hxx"
@ -24,7 +25,7 @@
CartridgeCDFWidget::CartridgeCDFWidget(
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
int x, int y, int w, int h, CartridgeCDF& cart)
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
: CartridgeARMWidget(boss, lfont, nfont, x, y, w, h, cart),
myCart{cart}
{
const int VBORDER = 8;
@ -56,7 +57,7 @@ CartridgeCDFWidget::CartridgeCDFWidget(
myLineHeight, items,
"Set bank ", 0, kBankChanged);
myBank->setTarget(this);
//addFocusWidget(myBank);
addFocusWidget(myBank);
// Fast Fetch flag
myFastFetch = new CheckboxWidget(boss, _font, myBank->getRight() + 24, ypos + 1,
@ -69,7 +70,7 @@ CartridgeCDFWidget::CartridgeCDFWidget(
// Datastream Pointers
#define DS_X (HBORDER + _font.getStringWidth("xx "))
xpos = DS_X;
ypos += myLineHeight + VGAP * 3;
ypos += myLineHeight + VGAP * 2;
new StaticTextWidget(boss, _font, xpos, ypos, "Datastream Pointers");
myDatastreamPointers = new DataGridWidget(boss, _nfont, DS_X,
@ -136,7 +137,7 @@ CartridgeCDFWidget::CartridgeCDFWidget(
Common::Base::Fmt::_16_2_2);
myJumpStreamIncrements->setTarget(this);
myJumpStreamIncrements->setEditable(false);
xpos = HBORDER; ypos += myLineHeight * 11 + VGAP * 3;
xpos = HBORDER; ypos += myLineHeight * 11 + VGAP * 2;
lwidth = _font.getStringWidth("Waveform Sizes ");
@ -201,32 +202,7 @@ CartridgeCDFWidget::CartridgeCDFWidget(
mySamplePointer->setEditable(false);
xpos = HBORDER; ypos += myLineHeight + VGAP * 2;
new StaticTextWidget(boss, _font, xpos, ypos + 1, "Last ARM run stats:");
xpos = HBORDER + INDENT; ypos += myLineHeight + VGAP;
StaticTextWidget* s = new StaticTextWidget(boss, _font, xpos, ypos + 1, "Mem. cycles ");
myThumbMemCycles = new EditTextWidget(boss, _font, s->getRight(), ypos - 1,
EditTextWidget::calcWidth(_font, 6), myLineHeight, "");
myThumbMemCycles->setEditable(false);
myThumbMemCycles->setToolTip("Number of memory cycles of last ARM run.");
s = new StaticTextWidget(boss, _font, myThumbMemCycles->getRight() + _fontWidth * 2, ypos + 1, "Fetches ");
myThumbFetches = new EditTextWidget(boss, _font, s->getRight(), ypos - 1,
EditTextWidget::calcWidth(_font, 6), myLineHeight, "");
myThumbFetches->setEditable(false);
myThumbFetches->setToolTip("Number of fetches/instructions of last ARM run.");
ypos += myLineHeight + VGAP;
s = new StaticTextWidget(boss, _font, xpos, ypos + 1, "Reads ");
myThumbReads = new EditTextWidget(boss, _font, myThumbMemCycles->getLeft(), ypos - 1,
EditTextWidget::calcWidth(_font, 6), myLineHeight, "");
myThumbReads->setEditable(false);
myThumbReads->setToolTip("Number of reads of last ARM run.");
s = new StaticTextWidget(boss, _font, myThumbReads->getRight() + _fontWidth * 2, ypos + 1, "Writes ");
myThumbWrites = new EditTextWidget(boss, _font, myThumbFetches->getLeft(), ypos - 1,
EditTextWidget::calcWidth(_font, 6), myLineHeight, "");
myThumbWrites->setEditable(false);
myThumbWrites->setToolTip("Number of write of last ARM run.");
addCycleWidgets(xpos, ypos);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -274,6 +250,8 @@ void CartridgeCDFWidget::saveOldState()
myOldState.internalram.push_back(myCart.myRAM[i]);
myOldState.samplepointer.push_back(myCart.getSample());
CartridgeARMWidget::saveOldState();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -405,17 +383,8 @@ void CartridgeCDFWidget::loadConfig()
mySamplePointer->setCrossed(true);
}
myThumbMemCycles->setText(Common::Base::toString(myCart.stats().fetches
+ myCart.stats().reads + myCart.stats().writes,
Common::Base::Fmt::_10_6));
myThumbFetches->setText(Common::Base::toString(myCart.stats().fetches,
Common::Base::Fmt::_10_6));
myThumbReads->setText(Common::Base::toString(myCart.stats().reads,
Common::Base::Fmt::_10_6));
myThumbWrites->setText(Common::Base::toString(myCart.stats().writes,
Common::Base::Fmt::_10_6));
CartDebugWidget::loadConfig();
// ARM cycles
CartridgeARMWidget::loadConfig();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -429,6 +398,8 @@ void CartridgeCDFWidget::handleCommand(CommandSender* sender,
myCart.lockBank();
invalidate();
}
else
CartridgeARMWidget::handleCommand(sender, cmd, data, id);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -23,11 +23,12 @@ class CheckboxWidget;
class DataGridWidget;
class StaticTextWidget;
class EditTextWidget;
class SliderWidget;
#include "CartCDF.hxx"
#include "CartDebugWidget.hxx"
#include "CartARMWidget.hxx"
class CartridgeCDFWidget : public CartDebugWidget
class CartridgeCDFWidget : public CartridgeARMWidget
{
public:
CartridgeCDFWidget(GuiObject* boss, const GUI::Font& lfont,
@ -70,10 +71,6 @@ class CartridgeCDFWidget : public CartDebugWidget
CheckboxWidget* myFastFetch{nullptr};
CheckboxWidget* myDigitalSample{nullptr};
EditTextWidget* myThumbMemCycles{nullptr};
EditTextWidget* myThumbFetches{nullptr};
EditTextWidget* myThumbReads{nullptr};
EditTextWidget* myThumbWrites{nullptr};
CartState myOldState;
@ -86,8 +83,8 @@ class CartridgeCDFWidget : public CartDebugWidget
static string describeCDFVersion(CartridgeCDF::CDFSubtype subtype);
void saveOldState() override;
void loadConfig() override;
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
string bankState() override;

View File

@ -25,7 +25,7 @@
CartridgeDPCPlusWidget::CartridgeDPCPlusWidget(
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
int x, int y, int w, int h, CartridgeDPCPlus& cart)
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
: CartridgeARMWidget(boss, lfont, nfont, x, y, w, h, cart),
myCart{cart}
{
size_t size = cart.mySize;
@ -181,33 +181,7 @@ CartridgeDPCPlusWidget::CartridgeDPCPlusWidget(
myIMLDA->setEditable(false);
xpos = 2; ypos += myLineHeight + 4 * 1;
new StaticTextWidget(boss, _font, xpos, ypos + 1, "Last ARM run stats:");
xpos = 2 + _font.getMaxCharWidth() * 2; ypos += myLineHeight + 4;
StaticTextWidget* s = new StaticTextWidget(boss, _font, xpos, ypos + 1, "Mem. cycles ");
myThumbMemCycles = new EditTextWidget(boss, _font, s->getRight(), ypos - 1,
EditTextWidget::calcWidth(_font, 6), myLineHeight, "");
myThumbMemCycles->setEditable(false);
myThumbMemCycles->setToolTip("Number of memory cycles of last ARM run.");
s = new StaticTextWidget(boss, _font, myThumbMemCycles->getRight() + _fontWidth * 2, ypos + 1, "Fetches ");
myThumbFetches = new EditTextWidget(boss, _font, s->getRight(), ypos - 1,
EditTextWidget::calcWidth(_font, 6), myLineHeight, "");
myThumbFetches->setEditable(false);
myThumbFetches->setToolTip("Number of fetches/instructions of last ARM run.");
ypos += myLineHeight + 4;
s = new StaticTextWidget(boss, _font, xpos, ypos + 1, "Reads ");
myThumbReads = new EditTextWidget(boss, _font, myThumbMemCycles->getLeft(), ypos - 1,
EditTextWidget::calcWidth(_font, 6), myLineHeight, "");
myThumbReads->setEditable(false);
myThumbReads->setToolTip("Number of reads of last ARM run.");
s = new StaticTextWidget(boss, _font, myThumbReads->getRight() + _fontWidth * 2, ypos + 1, "Writes ");
myThumbWrites = new EditTextWidget(boss, _font, myThumbFetches->getLeft(), ypos - 1,
EditTextWidget::calcWidth(_font, 6), myLineHeight, "");
myThumbWrites->setEditable(false);
myThumbWrites->setToolTip("Number of write of last ARM run.");
addCycleWidgets(xpos, ypos);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -246,6 +220,8 @@ void CartridgeDPCPlusWidget::saveOldState()
myOldState.internalram.push_back(myCart.myDisplayImage[i]);
myOldState.bank = myCart.getBank();
CartridgeARMWidget::saveOldState();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -336,17 +312,7 @@ void CartridgeDPCPlusWidget::loadConfig()
myFastFetch->setState(myCart.myFastFetch);
myIMLDA->setState(myCart.myLDAimmediate);
myThumbMemCycles->setText(Common::Base::toString(myCart.stats().fetches
+ myCart.stats().reads + myCart.stats().writes,
Common::Base::Fmt::_10_6));
myThumbFetches->setText(Common::Base::toString(myCart.stats().fetches,
Common::Base::Fmt::_10_6));
myThumbReads->setText(Common::Base::toString(myCart.stats().reads,
Common::Base::Fmt::_10_6));
myThumbWrites->setText(Common::Base::toString(myCart.stats().writes,
Common::Base::Fmt::_10_6));
CartDebugWidget::loadConfig();
CartridgeARMWidget::loadConfig();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -360,6 +326,8 @@ void CartridgeDPCPlusWidget::handleCommand(CommandSender* sender,
myCart.lockBank();
invalidate();
}
else
CartridgeARMWidget::handleCommand(sender, cmd, data, id);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -24,9 +24,9 @@ class CheckboxWidget;
class DataGridWidget;
class EditTextWidget;
#include "CartDebugWidget.hxx"
#include "CartARMWidget.hxx"
class CartridgeDPCPlusWidget : public CartDebugWidget
class CartridgeDPCPlusWidget : public CartridgeARMWidget
{
public:
CartridgeDPCPlusWidget(GuiObject* boss, const GUI::Font& lfont,
@ -66,10 +66,6 @@ class CartridgeDPCPlusWidget : public CartDebugWidget
CheckboxWidget* myFastFetch{nullptr};
CheckboxWidget* myIMLDA{nullptr};
DataGridWidget* myRandom{nullptr};
EditTextWidget* myThumbMemCycles{nullptr};
EditTextWidget* myThumbFetches{nullptr};
EditTextWidget* myThumbReads{nullptr};
EditTextWidget* myThumbWrites{nullptr};
CartState myOldState;

View File

@ -337,7 +337,7 @@ bool DataGridWidget::handleKeyDown(StellaKey key, StellaMod mod)
{
// Ignore all mod keys
if(StellaModTest::isControl(mod) || StellaModTest::isAlt(mod))
return true;
return false;
bool handled = true;
bool dirty = false;
@ -737,6 +737,7 @@ void DataGridWidget::startEditMode()
dialog().tooltip().hide();
enableEditMode(true);
setText("", true); // Erase current entry when starting editing
backupString() = "@@"; // dummy value to process Escape correctly key when nothing is entered
}
}
@ -782,6 +783,7 @@ void DataGridWidget::endEditMode()
}
setSelectedValue(value);
commit();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -789,6 +791,7 @@ void DataGridWidget::abortEditMode()
{
if(_editMode)
{
abort();
// Undo any changes made
assert(_selectedItem >= 0);
enableEditMode(false);

View File

@ -111,6 +111,10 @@ void DebuggerDialog::handleKeyDown(StellaKey key, StellaMod mod, bool repeated)
instance().eventHandler().enableTextEvents(false);
}
// Process widget keys first
if(_focusedWidget && _focusedWidget->handleKeyDown(key, mod))
return;
// special debugger keys first (cannot be remapped)
if (StellaModTest::isControl(mod))
{
@ -186,7 +190,7 @@ void DebuggerDialog::handleKeyDown(StellaKey key, StellaMod mod, bool repeated)
// events which need special handling in debugger
case Event::TakeSnapshot:
if(!repeated)
instance().debugger().parser().run("savesnap");
instance().debugger().parser().run("saveSnap");
return;
case Event::Rewind1Menu:
@ -319,7 +323,7 @@ void DebuggerDialog::doAdvance()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::doScanlineAdvance()
{
instance().debugger().parser().run("scanline #1");
instance().debugger().parser().run("scanLine #1");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -367,7 +371,7 @@ void DebuggerDialog::doExitDebugger()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::doExitRom()
{
instance().debugger().parser().run("exitrom");
instance().debugger().parser().run("exitRom");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -33,16 +33,16 @@ class KeyboardWidget : public ControllerWidget
const Event::Type* myEvent{nullptr};
static constexpr std::array<Event::Type, 12> ourLeftEvents = {{
Event::KeyboardZero1, Event::KeyboardZero2, Event::KeyboardZero3,
Event::KeyboardZero4, Event::KeyboardZero5, Event::KeyboardZero6,
Event::KeyboardZero7, Event::KeyboardZero8, Event::KeyboardZero9,
Event::KeyboardZeroStar, Event::KeyboardZero0, Event::KeyboardZeroPound
Event::LeftKeyboard1, Event::LeftKeyboard2, Event::LeftKeyboard3,
Event::LeftKeyboard4, Event::LeftKeyboard5, Event::LeftKeyboard6,
Event::LeftKeyboard7, Event::LeftKeyboard8, Event::LeftKeyboard9,
Event::LeftKeyboardStar, Event::LeftKeyboard0, Event::LeftKeyboardPound
}};
static constexpr std::array<Event::Type, 12> ourRightEvents = {{
Event::KeyboardOne1, Event::KeyboardOne2, Event::KeyboardOne3,
Event::KeyboardOne4, Event::KeyboardOne5, Event::KeyboardOne6,
Event::KeyboardOne7, Event::KeyboardOne8, Event::KeyboardOne9,
Event::KeyboardOneStar, Event::KeyboardOne0, Event::KeyboardOnePound
Event::RightKeyboard1, Event::RightKeyboard2, Event::RightKeyboard3,
Event::RightKeyboard4, Event::RightKeyboard5, Event::RightKeyboard6,
Event::RightKeyboard7, Event::RightKeyboard8, Event::RightKeyboard9,
Event::RightKeyboardStar, Event::RightKeyboard0, Event::RightKeyboardPound
}};
private:

View File

@ -40,13 +40,7 @@
PromptWidget::PromptWidget(GuiObject* boss, const GUI::Font& font,
int x, int y, int w, int h)
: Widget(boss, font, x, y, w - ScrollBarWidget::scrollBarWidth(font), h),
CommandSender(boss),
_historySize{0},
_historyIndex{0},
_historyLine{0},
_makeDirty{false},
_firstTime{true},
_exitedEarly{false}
CommandSender(boss)
{
_flags = Widget::FLAG_ENABLED | Widget::FLAG_CLEARBG | Widget::FLAG_RETAIN_FOCUS |
Widget::FLAG_WANTS_TAB | Widget::FLAG_WANTS_RAWDATA;
@ -68,9 +62,6 @@ PromptWidget::PromptWidget(GuiObject* boss, const GUI::Font& font,
ScrollBarWidget::scrollBarWidth(_font), _h);
_scrollBar->setTarget(this);
// Init colors
_inverse = false;
clearScreen();
addFocusWidget(this);
@ -137,6 +128,8 @@ void PromptWidget::printPrompt()
print(PROMPT);
_promptStartPos = _promptEndPos = _currentPos;
resetFunctions();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -150,6 +143,8 @@ bool PromptWidget::handleText(char text)
_promptEndPos++;
putcharIntern(text);
scrollToCurrent();
resetFunctions();
}
return true;
}
@ -157,323 +152,171 @@ bool PromptWidget::handleText(char text)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PromptWidget::handleKeyDown(StellaKey key, StellaMod mod)
{
bool handled = true;
bool dirty = false;
bool handled = true,
dirty = true,
changeInput = false,
resetAutoComplete = true,
resetHistoryScroll = true;
switch(key)
// Uses normal edit events + special prompt events
Event::Type event = instance().eventHandler().eventForKey(EventMode::kEditMode, key, mod);
if(event == Event::NoType)
event = instance().eventHandler().eventForKey(EventMode::kPromptMode, key, mod);
switch(event)
{
case KBDK_RETURN:
case KBDK_KP_ENTER:
case Event::EndEdit:
{
nextLine();
assert(_promptEndPos >= _promptStartPos);
int len = _promptEndPos - _promptStartPos;
if (len > 0)
{
// Copy the user input to command
string command;
for (int i = 0; i < len; i++)
command += buffer(_promptStartPos + i) & 0x7f;
// Add the input to the history
addToHistory(command.c_str());
// Pass the command to the debugger, and print the result
string result = instance().debugger().run(command);
// This is a bit of a hack
// Certain commands remove the debugger dialog from underneath us,
// so we shouldn't print any messages
// Those commands will return '_EXIT_DEBUGGER' as their result
if(result == "_EXIT_DEBUGGER")
{
_exitedEarly = true;
return true;
}
else if(result == "_NO_PROMPT")
return true;
else if(result != "")
print(result + "\n");
}
if(execute())
return true;
printPrompt();
dirty = true;
break;
}
case KBDK_TAB:
{
// Tab completion: we complete either commands or labels, but not
// both at once.
if(_currentPos <= _promptStartPos)
break;
scrollToCurrent();
int len = _promptEndPos - _promptStartPos;
if(len > 255) len = 255;
int lastDelimPos = -1;
char delimiter = '\0';
char inputStr[256]; // NOLINT (will be rewritten soon)
for (int i = 0; i < len; i++)
{
inputStr[i] = buffer(_promptStartPos + i) & 0x7f;
// whitespace characters
if(strchr("{*@<> =[]()+-/&|!^~%", inputStr[i]))
{
lastDelimPos = i;
delimiter = inputStr[i];
}
}
inputStr[len] = '\0';
size_t strLen = len - lastDelimPos - 1;
StringList list;
string completionList;
string prefix;
if(lastDelimPos < 0)
{
// no delimiters, do only command completion:
const DebuggerParser& parser = instance().debugger().parser();
parser.getCompletions(inputStr, list);
if(list.size() < 1)
break;
sort(list.begin(), list.end());
completionList = list[0];
for(uInt32 i = 1; i < list.size(); ++i)
completionList += " " + list[i];
prefix = getCompletionPrefix(list);
}
else
{
// Special case for 'help' command
if(BSPF::startsWithIgnoreCase(inputStr, "help"))
{
instance().debugger().parser().getCompletions(inputStr + lastDelimPos + 1, list);
}
else
{
// do not show ALL labels without any filter as it makes no sense
if(strLen > 0)
{
// we got a delimiter, so this must be a label or a function
const Debugger& dbg = instance().debugger();
dbg.cartDebug().getCompletions(inputStr + lastDelimPos + 1, list);
dbg.getCompletions(inputStr + lastDelimPos + 1, list);
}
}
if(list.size() < 1)
break;
sort(list.begin(), list.end());
completionList = list[0];
for(uInt32 i = 1; i < list.size(); ++i)
completionList += " " + list[i];
prefix = getCompletionPrefix(list);
}
// TODO: tab through list
if(list.size() == 1)
{
// add to buffer as though user typed it (plus a space)
_currentPos = _promptStartPos + lastDelimPos + 1;
const char* clptr = completionList.c_str();
while(*clptr != '\0')
putcharIntern(*clptr++);
putcharIntern(' ');
_promptEndPos = _currentPos;
}
else
{
nextLine();
// add to buffer as-is, then add PROMPT plus whatever we have so far
_currentPos = _promptStartPos + lastDelimPos + 1;
print("\n");
print(completionList);
print("\n");
print(PROMPT);
_promptStartPos = _currentPos;
if(prefix.length() < strLen)
{
for(int i = 0; i < len; i++)
putcharIntern(inputStr[i]);
}
else
{
for(int i = 0; i < lastDelimPos; i++)
putcharIntern(inputStr[i]);
if(lastDelimPos > 0)
putcharIntern(delimiter);
print(prefix);
}
_promptEndPos = _currentPos;
}
dirty = true;
// special events (auto complete & history scrolling)
case Event::UINavNext:
dirty = changeInput = autoComplete(+1);
resetAutoComplete = false;
break;
}
case KBDK_BACKSPACE:
if (_currentPos > _promptStartPos)
case Event::UINavPrev:
dirty = changeInput = autoComplete(-1);
resetAutoComplete = false;
break;
case Event::UILeft: // mapped to KBDK_DOWN by default
dirty = changeInput = historyScroll(-1);
resetHistoryScroll = false;
break;
case Event::UIRight: // mapped to KBDK_UP by default
dirty = changeInput = historyScroll(+1);
resetHistoryScroll = false;
break;
// input modifying events
case Event::Backspace:
if(_currentPos > _promptStartPos)
{
killChar(-1);
changeInput = true;
}
scrollToCurrent();
dirty = true;
break;
case KBDK_DELETE:
case KBDK_KP_PERIOD: // actually the num delete
if(StellaModTest::isShift(mod))
textCut();
else
killChar(+1);
dirty = true;
case Event::Delete:
killChar(+1);
changeInput = true;
break;
case KBDK_PAGEUP:
if (StellaModTest::isShift(mod))
{
// Don't scroll up when at top of buffer
if(_scrollLine < _linesPerPage)
break;
_scrollLine -= _linesPerPage - 1;
if (_scrollLine < _firstLineInBuffer + _linesPerPage - 1)
_scrollLine = _firstLineInBuffer + _linesPerPage - 1;
updateScrollBuffer();
dirty = true;
}
case Event::DeleteEnd:
killLine(+1);
changeInput = true;
break;
case KBDK_PAGEDOWN:
if (StellaModTest::isShift(mod))
{
// Don't scroll down when at bottom of buffer
if(_scrollLine >= _promptEndPos / _lineWidth)
break;
_scrollLine += _linesPerPage - 1;
if (_scrollLine > _promptEndPos / _lineWidth)
_scrollLine = _promptEndPos / _lineWidth;
updateScrollBuffer();
dirty = true;
}
case Event::DeleteHome:
killLine(-1);
changeInput = true;
break;
case KBDK_HOME:
if (StellaModTest::isShift(mod))
{
_scrollLine = _firstLineInBuffer + _linesPerPage - 1;
updateScrollBuffer();
}
else
_currentPos = _promptStartPos;
dirty = true;
case Event::DeleteLeftWord:
killWord();
changeInput = true;
break;
case KBDK_END:
if (StellaModTest::isShift(mod))
{
_scrollLine = _promptEndPos / _lineWidth;
if (_scrollLine < _linesPerPage - 1)
_scrollLine = _linesPerPage - 1;
updateScrollBuffer();
}
else
_currentPos = _promptEndPos;
dirty = true;
case Event::Cut:
textCut();
changeInput = true;
break;
case KBDK_UP:
if (StellaModTest::isShift(mod))
{
if(_scrollLine <= _firstLineInBuffer + _linesPerPage - 1)
break;
_scrollLine -= 1;
updateScrollBuffer();
dirty = true;
}
else
historyScroll(+1);
case Event::Copy:
textCopy();
break;
case KBDK_DOWN:
if (StellaModTest::isShift(mod))
{
// Don't scroll down when at bottom of buffer
if(_scrollLine >= _promptEndPos / _lineWidth)
break;
_scrollLine += 1;
updateScrollBuffer();
dirty = true;
}
else
historyScroll(-1);
case Event::Paste:
textPaste();
changeInput = true;
break;
case KBDK_RIGHT:
if (_currentPos < _promptEndPos)
// cursor events
case Event::MoveHome:
_currentPos = _promptStartPos;
break;
case Event::MoveEnd:
_currentPos = _promptEndPos;
break;
case Event::MoveRightChar:
if(_currentPos < _promptEndPos)
_currentPos++;
dirty = true;
break;
case KBDK_LEFT:
if (_currentPos > _promptStartPos)
_currentPos--;
dirty = true;
break;
case KBDK_INSERT:
if(StellaModTest::isShift(mod))
{
textPaste();
dirty = true;
}
else if(StellaModTest::isControl(mod))
{
textCopy();
dirty = true;
}
else
handled = false;
break;
case Event::MoveLeftChar:
if(_currentPos > _promptStartPos)
_currentPos--;
else
handled = false;
break;
// scrolling events
case Event::UIUp:
if(_scrollLine <= _firstLineInBuffer + _linesPerPage - 1)
break;
_scrollLine -= 1;
updateScrollBuffer();
break;
case Event::UIDown:
// Don't scroll down when at bottom of buffer
if(_scrollLine >= _promptEndPos / _lineWidth)
break;
_scrollLine += 1;
updateScrollBuffer();
break;
case Event::UIPgUp:
// Don't scroll up when at top of buffer
if(_scrollLine < _linesPerPage)
break;
_scrollLine -= _linesPerPage - 1;
if(_scrollLine < _firstLineInBuffer + _linesPerPage - 1)
_scrollLine = _firstLineInBuffer + _linesPerPage - 1;
updateScrollBuffer();
break;
case Event::UIPgDown:
// Don't scroll down when at bottom of buffer
if(_scrollLine >= _promptEndPos / _lineWidth)
break;
_scrollLine += _linesPerPage - 1;
if(_scrollLine > _promptEndPos / _lineWidth)
_scrollLine = _promptEndPos / _lineWidth;
updateScrollBuffer();
break;
case Event::UIHome:
_scrollLine = _firstLineInBuffer + _linesPerPage - 1;
updateScrollBuffer();
break;
case Event::UIEnd:
_scrollLine = _promptEndPos / _lineWidth;
if(_scrollLine < _linesPerPage - 1)
_scrollLine = _linesPerPage - 1;
updateScrollBuffer();
break;
default:
if (StellaModTest::isControl(mod))
{
specialKeys(key);
}
else if (StellaModTest::isAlt(mod))
{
// Placeholder only - this will never be reached
}
else
handled = false;
handled = false;
dirty = false;
break;
}
@ -481,19 +324,12 @@ bool PromptWidget::handleKeyDown(StellaKey key, StellaMod mod)
if(dirty)
setDirty();
// There are times when we want the prompt and scrollbar to be marked
// as dirty *after* they've been drawn above. One such occurrence is
// when we issue a command that indirectly redraws the entire parent
// dialog (such as 'scanline' or 'frame').
// In those cases, the return code of the command must be shown, but the
// entire dialog contents are redrawn at a later time. So the prompt and
// scrollbar won't be redrawn unless they're dirty again.
if(_makeDirty)
{
setDirty();
_scrollBar->setDirty();
_makeDirty = false;
}
// Reset special event handling if input has changed
// We assume that non-handled events will modify the input too
if(!handled || (resetAutoComplete && changeInput))
_tabCount = -1;
if(!handled || (resetHistoryScroll && changeInput))
_historyLine = 0;
return handled;
}
@ -532,9 +368,6 @@ void PromptWidget::handleCommand(CommandSender* sender, int cmd,
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptWidget::loadConfig()
{
// See logic at the end of handleKeyDown for an explanation of this
_makeDirty = true;
// Show the prompt the first time we draw this widget
if(_firstTime)
{
@ -557,6 +390,22 @@ void PromptWidget::loadConfig()
print(instance().debugger().cartDebug().loadConfigFile() + "\n");
print(instance().debugger().cartDebug().loadListFile() + "\n");
print(instance().debugger().cartDebug().loadSymbolFile() + "\n");
bool extra = false;
if(instance().settings().getBool("dbg.autosave"))
{
print(DebuggerParser::inverse(" autoSave enabled "));
print("\177 "); // must switch inverse here!
extra = true;
}
if(instance().settings().getBool("dbg.logbreaks"))
{
print(DebuggerParser::inverse(" logBreaks enabled "));
extra = true;
}
if(extra)
print("\n");
print(PROMPT);
_promptStartPos = _promptEndPos = _currentPos;
@ -575,46 +424,6 @@ int PromptWidget::getWidth() const
return _w + ScrollBarWidget::scrollBarWidth(_font);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptWidget::specialKeys(StellaKey key)
{
bool handled = true;
switch(key)
{
case KBDK_D:
killChar(+1);
break;
case KBDK_K:
killLine(+1);
break;
case KBDK_U:
killLine(-1);
break;
case KBDK_W:
killWord();
break;
case KBDK_A:
textSelectAll();
break;
case KBDK_X:
textCut();
break;
case KBDK_C:
textCopy();
break;
case KBDK_V:
textPaste();
break;
default:
handled = false;
break;
}
if(handled)
setDirty();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptWidget::killChar(int direction)
{
@ -692,22 +501,16 @@ void PromptWidget::killWord()
_promptEndPos -= cnt;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptWidget::textSelectAll()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string PromptWidget::getLine()
{
#if defined(PSEUDO_CUT_COPY_PASTE)
assert(_promptEndPos >= _promptStartPos);
int len = _promptEndPos - _promptStartPos;
string text;
// Copy current line to text
for(int i = 0; i < len; i++)
text += buffer(_promptStartPos + i) & 0x7f;
for(int i = _promptStartPos; i < _promptEndPos; i++)
text += buffer(i) & 0x7f;
return text;
#endif
@ -717,14 +520,14 @@ string PromptWidget::getLine()
void PromptWidget::textCut()
{
#if defined(PSEUDO_CUT_COPY_PASTE)
string text = getLine();
instance().eventHandler().copyText(text);
textCopy();
// Remove the current line
_currentPos = _promptStartPos;
killLine(1); // to end of line
_promptEndPos = _currentPos;
resetFunctions();
#endif
}
@ -751,65 +554,95 @@ void PromptWidget::textPaste()
instance().eventHandler().pasteText(text);
print(text);
_promptEndPos = _currentPos;
resetFunctions();
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int PromptWidget::historyDir(int& index, int direction)
{
index += direction;
if(index < 0)
index += int(_history.size());
else
index %= int(_history.size());
return index;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptWidget::historyAdd(const string& entry)
{
if(_historyIndex >= int(_history.size()))
_history.push_back(entry);
else
_history[_historyIndex] = entry;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptWidget::addToHistory(const char* str)
{
#if defined(BSPF_WINDOWS)
strncpy_s(_history[_historyIndex], kLineBufferSize, str, kLineBufferSize - 1);
#else
strncpy(_history[_historyIndex], str, kLineBufferSize - 1);
#endif
_historyIndex = (_historyIndex + 1) % kHistorySize;
_historyLine = 0;
if (_historySize < kHistorySize)
_historySize++;
}
#if 0 // FIXME
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int PromptWidget::compareHistory(const char *histLine)
{
return 1;
}
#endif
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptWidget::historyScroll(int direction)
{
if (_historySize == 0)
return;
if (_historyLine == 0 && direction > 0)
// Do not add duplicates, remove old duplicate
if(_history.size())
{
int i;
for (i = 0; i < _promptEndPos - _promptStartPos; i++)
_history[_historyIndex][i] = buffer(_promptStartPos + i); //FIXME: int to char??
int i = _historyIndex;
int historyEnd = _historyIndex % _history.size();
_history[_historyIndex][i] = '\0';
}
do
{
historyDir(i, -1);
// Advance to the next line in the history
int line = _historyLine + direction;
if(line < 0)
line += _historySize + 1;
line %= (_historySize + 1);
if(!BSPF::compareIgnoreCase(_history[i], str))
{
int j = i, prevJ;
// If they press arrow-up with anything in the buffer, search backwards
// in the history.
/*
if(direction < 0 && _currentPos > _promptStartPos) {
for(;line > 0; line--) {
if(compareHistory(_history[line]) == 0)
do
{
prevJ = j;
historyDir(j, +1);
_history[prevJ] = _history[j];
}
while(j != historyEnd);
historyDir(_historyIndex, -1);
break;
}
}
while(i != historyEnd);
}
*/
historyAdd(str);
_historyLine = 0; // reset history scroll
_historyIndex = (_historyIndex + 1) % kHistorySize;
}
_historyLine = line;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PromptWidget::historyScroll(int direction)
{
if(_history.size() == 0)
return false;
// add current input temporarily to history
if(_historyLine == 0)
historyAdd(getLine());
// Advance to the next/prev line in the history
historyDir(_historyLine, direction);
// Search the history using the original input
do
{
int idx = _historyLine
? (_historyIndex - _historyLine + _history.size()) % int(_history.size())
: _historyIndex;
if(BSPF::startsWithIgnoreCase(_history[idx], _history[_historyIndex]))
break;
// Advance to the next/prev line in the history
historyDir(_historyLine, direction);
}
while(_historyLine); // If _historyLine == 0, nothing was found
// Remove the current user text
_currentPos = _promptStartPos;
@ -819,21 +652,145 @@ void PromptWidget::historyScroll(int direction)
scrollToCurrent();
// Print the text from the history
int idx;
if (_historyLine > 0)
idx = (_historyIndex - _historyLine + _historySize) % _historySize;
else
idx = _historyIndex;
int idx = _historyLine
? (_historyIndex - _historyLine + _history.size()) % int(_history.size())
: _historyIndex;
for (int i = 0; i < kLineBufferSize && _history[idx][i] != '\0'; i++)
for(int i = 0; i < kLineBufferSize && _history[idx][i] != '\0'; i++)
putcharIntern(_history[idx][i]);
_promptEndPos = _currentPos;
// Ensure once more the caret is visible (in case of very long history entries)
scrollToCurrent();
setDirty();
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PromptWidget::execute()
{
nextLine();
assert(_promptEndPos >= _promptStartPos);
int len = _promptEndPos - _promptStartPos;
if(len > 0)
{
// Copy the user input to command
string command = getLine();
// Add the input to the history
addToHistory(command.c_str());
// Pass the command to the debugger, and print the result
string result = instance().debugger().run(command);
// This is a bit of a hack
// Certain commands remove the debugger dialog from underneath us,
// so we shouldn't print any messages
// Those commands will return '_EXIT_DEBUGGER' as their result
if(result == "_EXIT_DEBUGGER")
{
_exitedEarly = true;
return true;
}
else if(result == "_NO_PROMPT")
return true;
else if(result != "")
print(result + "\n");
}
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PromptWidget::autoComplete(int direction)
{
// Tab completion: we complete either commands or labels, but not
// both at once.
if(_currentPos <= _promptStartPos)
return false; // no input
scrollToCurrent();
int len = _promptEndPos - _promptStartPos;
if(_tabCount != -1)
len = int(strlen(_inputStr));
if(len > kLineBufferSize - 1)
len = kLineBufferSize - 1;
int lastDelimPos = -1;
char delimiter = '\0';
for(int i = 0; i < len; i++)
{
// copy the input at first tab press only
if(_tabCount == -1)
_inputStr[i] = buffer(_promptStartPos + i) & 0x7f;
// whitespace characters
if(strchr("{*@<> =[]()+-/&|!^~%", _inputStr[i]))
{
lastDelimPos = i;
delimiter = _inputStr[i];
}
}
if(_tabCount == -1)
_inputStr[len] = '\0';
StringList list;
if(lastDelimPos == -1)
// no delimiters, do only command completion:
instance().debugger().parser().getCompletions(_inputStr, list);
else
{
size_t strLen = len - lastDelimPos - 1;
// do not show ALL commands/labels without any filter as it makes no sense
if(strLen > 0)
{
// Special case for 'help' command
if(BSPF::startsWithIgnoreCase(_inputStr, "help"))
instance().debugger().parser().getCompletions(_inputStr + lastDelimPos + 1, list);
else
{
// we got a delimiter, so this must be a label or a function
const Debugger& dbg = instance().debugger();
dbg.cartDebug().getCompletions(_inputStr + lastDelimPos + 1, list);
dbg.getCompletions(_inputStr + lastDelimPos + 1, list);
}
}
}
if(list.size() < 1)
return false;
sort(list.begin(), list.end());
if(direction < 0)
{
if(--_tabCount < 0)
_tabCount = int(list.size()) - 1;
}
else
_tabCount = (_tabCount + 1) % list.size();
nextLine();
_currentPos = _promptStartPos;
killLine(1); // kill whole line
// start with-autocompleted, fixed string...
for(int i = 0; i < lastDelimPos; i++)
putcharIntern(_inputStr[i]);
if(lastDelimPos > 0)
putcharIntern(delimiter);
// ...and add current autocompletion string
print(list[_tabCount]);
putcharIntern(' ');
_promptEndPos = _currentPos;
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1000,30 +957,6 @@ string PromptWidget::saveBuffer(const FilesystemNode& file)
return "unable to save session";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string PromptWidget::getCompletionPrefix(const StringList& completions)
{
// Find the number of characters matching for each of the completions provided
for(uInt32 len = 1;; ++len)
{
for(uInt32 i = 0; i < completions.size(); ++i)
{
string s1 = completions[i];
if(s1.length() < len)
{
return s1.substr(0, len - 1);
}
string find = s1.substr(0, len);
for(uInt32 j = i + 1; j < completions.size(); ++j)
{
if(!BSPF::startsWithIgnoreCase(completions[j], find))
return s1.substr(0, len - 1);
}
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptWidget::clearScreen()
{
@ -1036,4 +969,21 @@ void PromptWidget::clearScreen()
if(!_firstTime)
updateScrollBuffer();
resetFunctions();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptWidget::clearHistory()
{
_history.clear();
_historyIndex = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptWidget::resetFunctions()
{
// reset special functions
_tabCount = -1;
_historyLine = 0;
}

View File

@ -42,18 +42,22 @@ class PromptWidget : public Widget, public CommandSender
~PromptWidget() override = default;
public:
ATTRIBUTE_FMT_PRINTF int printf(const char* format, ...);
ATTRIBUTE_FMT_PRINTF int vprintf(const char* format, va_list argptr);
void print(const string& str);
void printPrompt();
string saveBuffer(const FilesystemNode& file);
// Clear screen and erase all history
// Clear screen
void clearScreen();
// Erase all history
void clearHistory();
void addToHistory(const char *str);
bool isLoaded() const { return !_firstTime; }
protected:
ATTRIBUTE_FMT_PRINTF int printf(const char* format, ...);
ATTRIBUTE_FMT_PRINTF int vprintf(const char* format, va_list argptr);
int& buffer(int idx) { return _buffer[idx % kBufferSize]; }
void drawWidget(bool hilite) override;
@ -64,21 +68,22 @@ class PromptWidget : public Widget, public CommandSender
void scrollToCurrent();
// Line editing
void specialKeys(StellaKey key);
void nextLine();
void killChar(int direction);
void killLine(int direction);
void killWord();
// Clipboard
void textSelectAll();
string getLine();
void textCut();
void textCopy();
void textPaste();
// History
void historyScroll(int direction);
bool historyScroll(int direction);
bool execute();
bool autoComplete(int direction);
void handleMouseDown(int x, int y, MouseButton b, int clickCount) override;
void handleMouseWheel(int x, int y, int direction) override;
@ -92,15 +97,13 @@ class PromptWidget : public Widget, public CommandSender
bool wantsFocus() const override { return true; }
void loadConfig() override;
private:
// Get the longest prefix (initially 's') that is in every string in the list
string getCompletionPrefix(const StringList& completions);
void resetFunctions();
private:
enum {
kBufferSize = 32768,
kBufferSize = 32768,
kLineBufferSize = 256,
kHistorySize = 20
kHistorySize = 1000
};
int _buffer[kBufferSize]; // NOLINT (will be rewritten soon)
@ -118,19 +121,20 @@ class PromptWidget : public Widget, public CommandSender
ScrollBarWidget* _scrollBar;
char _history[kHistorySize][kLineBufferSize]; // NOLINT (will be rewritten soon)
int _historySize;
int _historyIndex;
int _historyLine;
std::vector<string> _history;
int _historyIndex{0};
int _historyLine{0};
int _tabCount{-1};
char _inputStr[kLineBufferSize];
int _kConsoleCharWidth, _kConsoleCharHeight, _kConsoleLineHeight;
bool _inverse;
bool _makeDirty;
bool _firstTime;
bool _exitedEarly;
bool _inverse{false};
bool _firstTime{true};
bool _exitedEarly{false};
// int compareHistory(const char *histLine);
int historyDir(int& index, int direction);
void historyAdd(const string& entry);
private:
// Following constructors and assignment operators not supported

View File

@ -90,14 +90,14 @@ RiotWidget::RiotWidget(GuiObject* boss, const GUI::Font& lfont,
// SWCHA bits in 'peek' mode
xpos = 10; ypos += lineHeight + 5;
labels.clear();
labels.push_back("P0 right");
labels.push_back("P0 left");
labels.push_back("P0 down");
labels.push_back("P0 up");
labels.push_back("P1 right");
labels.push_back("P1 left");
labels.push_back("P1 down");
labels.push_back("P1 up");
labels.push_back("Left right");
labels.push_back("Left left");
labels.push_back("Left down");
labels.push_back("Left up");
labels.push_back("Right right");
labels.push_back("Right left");
labels.push_back("Right down");
labels.push_back("Right up");
CREATE_IO_REGS("SWCHA(R)", mySWCHAReadBits, kSWCHARBitsID, true)
// SWCHB bits in 'poke' mode
@ -112,8 +112,8 @@ RiotWidget::RiotWidget(GuiObject* boss, const GUI::Font& lfont,
// SWCHB bits in 'peek' mode
xpos = 10; ypos += lineHeight + 5;
labels.clear();
labels.push_back("P1 difficulty");
labels.push_back("P0 difficulty");
labels.push_back("Right difficulty");
labels.push_back("Left difficulty");
labels.push_back("");
labels.push_back("");
labels.push_back("Color/B+W");
@ -210,19 +210,19 @@ RiotWidget::RiotWidget(GuiObject* boss, const GUI::Font& lfont,
// PO & P1 difficulty switches
int pwidth = lfont.getStringWidth("B/easy");
lwidth = lfont.getStringWidth("P0 Diff ");
lwidth = lfont.getStringWidth("Right Diff ");
xpos = col; ypos += 2 * lineHeight;
int col2_ypos = ypos;
items.clear();
VarList::push_back(items, "B/easy", "b");
VarList::push_back(items, "A/hard", "a");
myP0Diff = new PopUpWidget(boss, lfont, xpos, ypos, pwidth, lineHeight, items,
"P0 Diff ", lwidth, kP0DiffChanged);
"Left Diff ", lwidth, kP0DiffChanged);
myP0Diff->setTarget(this);
addFocusWidget(myP0Diff);
ypos += myP0Diff->getHeight() + 5;
myP1Diff = new PopUpWidget(boss, lfont, xpos, ypos, pwidth, lineHeight, items,
"P1 Diff ", lwidth, kP1DiffChanged);
"Right Diff ", lwidth, kP1DiffChanged);
myP1Diff->setTarget(this);
addFocusWidget(myP1Diff);

View File

@ -304,7 +304,7 @@ bool RomListWidget::handleKeyDown(StellaKey key, StellaMod mod)
{
// Ignore all Alt-mod keys
if(StellaModTest::isAlt(mod))
return true;
return false;
bool handled = true;
int oldSelectedItem = _selectedItem;

View File

@ -137,7 +137,7 @@ void TiaOutputWidget::handleCommand(CommandSender* sender, int cmd, int data, in
lines += instance().console().tia().scanlinesLastFrame();
if(lines > 0)
{
command << "scanline #" << lines;
command << "scanLine #" << lines;
string message = instance().debugger().parser().run(command.str());
instance().frameBuffer().showTextMessage(message);
}
@ -146,7 +146,7 @@ void TiaOutputWidget::handleCommand(CommandSender* sender, int cmd, int data, in
{
ostringstream command;
int scanline = myClickY + startLine;
command << "breakif _scan==#" << scanline;
command << "breakIf _scan==#" << scanline;
string message = instance().debugger().parser().run(command.str());
instance().frameBuffer().showTextMessage(message);
}
@ -157,7 +157,7 @@ void TiaOutputWidget::handleCommand(CommandSender* sender, int cmd, int data, in
}
else if(rmb == "snap")
{
instance().debugger().parser().run("savesnap");
instance().debugger().parser().run("saveSnap");
}
}
}

View File

@ -92,7 +92,7 @@ bool ToggleWidget::handleKeyDown(StellaKey key, StellaMod mod)
{
// Ignore all mod keys
if(StellaModTest::isControl(mod) || StellaModTest::isAlt(mod))
return true;
return false;
bool handled = true;
bool dirty = false, toggle = false;

View File

@ -14,6 +14,7 @@ MODULE_OBJS := \
src/debugger/gui/Cart4A50Widget.o \
src/debugger/gui/Cart4KSCWidget.o \
src/debugger/gui/Cart4KWidget.o \
src/debugger/gui/CartARMWidget.o \
src/debugger/gui/CartARWidget.o \
src/debugger/gui/CartBFSCWidget.o \
src/debugger/gui/CartBFWidget.o \

View File

@ -23,13 +23,13 @@ BoosterGrip::BoosterGrip(Jack jack, const Event& event, const System& system)
{
if(myJack == Jack::Left)
{
myTriggerEvent = Event::JoystickZeroFire5;
myBoosterEvent = Event::JoystickZeroFire9;
myTriggerEvent = Event::LeftJoystickFire5;
myBoosterEvent = Event::LeftJoystickFire9;
}
else
{
myTriggerEvent = Event::JoystickOneFire5;
myBoosterEvent = Event::JoystickOneFire9;
myTriggerEvent = Event::RightJoystickFire5;
myBoosterEvent = Event::RightJoystickFire9;
}
setPin(AnalogPin::Five, AnalogReadout::disconnect());

View File

@ -125,6 +125,12 @@ class Cartridge3EPlus: public Cartridge3E
#endif
private:
/**
Checks if startup bank randomization is enabled. For this scheme,
randomization is not supported (see above).
*/
bool randomStartBank() const override { return false; }
bool checkSwitchBank(uInt16 address, uInt8 value) override;
private:

127
src/emucore/CartARM.cxx Normal file
View File

@ -0,0 +1,127 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2021 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include "System.hxx"
#include "Settings.hxx"
#include "CartARM.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeARM::CartridgeARM(const string& md5, const Settings& settings)
: Cartridge(settings, md5)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeARM::setInitialState()
{
bool devSettings = mySettings.getBool("dev.settings");
if(devSettings)
{
myIncCycles = mySettings.getBool("dev.thumb.inccycles");
myThumbEmulator->setChipType(static_cast<Thumbulator::ChipType>(mySettings.getInt("dev.thumb.chiptype")));
myThumbEmulator->setMamMode(static_cast<Thumbulator::MamModeType>(mySettings.getInt("dev.thumb.mammode")));
}
else
{
myIncCycles = false;
}
enableCycleCount(devSettings);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeARM::consoleChanged(ConsoleTiming timing)
{
myThumbEmulator->setConsoleTiming(timing);
constexpr double NTSC = 1193191.66666667; // NTSC 6507 clock rate
constexpr double PAL = 1182298; // PAL 6507 clock rate
constexpr double SECAM = 1187500; // SECAM 6507 clock rate
switch(timing)
{
case ConsoleTiming::ntsc: myClockRate = NTSC; break;
case ConsoleTiming::pal: myClockRate = PAL; break;
case ConsoleTiming::secam: myClockRate = SECAM; break;
default: break; // satisfy compiler
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeARM::updateCycles(int cycles)
{
if(myIncCycles)
mySystem->incrementCycles(cycles);
#ifdef DEBUGGER_SUPPORT
myPrevStats = myStats;
myStats = myThumbEmulator->stats();
myPrevCycles = myCycles;
myCycles = myThumbEmulator->cycles();
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeARM::incCycles(bool enable)
{
myIncCycles = enable;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeARM::cycleFactor(double factor)
{
myThumbEmulator->cycleFactor(factor);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeARM::save(Serializer& out) const
{
#ifdef DEBUGGER_SUPPORT
try
{
out.putInt(myPrevCycles);
out.putInt(myPrevStats.instructions);
out.putInt(myCycles);
out.putInt(myStats.instructions);
}
catch(...)
{
cerr << "ERROR: CartridgeARM::save" << endl;
return false;
}
#endif
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeARM::load(Serializer& in)
{
#ifdef DEBUGGER_SUPPORT
try
{
myPrevCycles = in.getInt();
myPrevStats.instructions = in.getInt();
myCycles = in.getInt();
myStats.instructions = in.getInt();
}
catch(...)
{
cerr << "ERROR: CartridgeARM::load" << endl;
return false;
}
#endif
return true;
}

113
src/emucore/CartARM.hxx Normal file
View File

@ -0,0 +1,113 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2021 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#ifndef CARTRIDGE_ARM_HXX
#define CARTRIDGE_ARM_HXX
#include "Thumbulator.hxx"
#include "Cart.hxx"
/**
Abstract base class for ARM carts.
@author Thomas Jentzsch
*/
class CartridgeARM : public Cartridge
{
friend class CartridgeARMWidget;
public:
CartridgeARM(const string& md5, const Settings& settings);
~CartridgeARM() override = default;
protected:
/**
Notification method invoked by the system when the console type
has changed. We need this to inform the Thumbulator that the
timing has changed.
@param timing Enum representing the new console type
*/
void consoleChanged(ConsoleTiming timing) override;
/**
Save the current state of this cart to the given Serializer.
@param out The Serializer object to use
@return False on any errors, else true
*/
bool save(Serializer& out) const override;
/**
Load the current state of this cart from the given Serializer.
@param in The Serializer object to use
@return False on any errors, else true
*/
bool load(Serializer& in) override;
/**
Sets the initial state of the MAM mode
*/
virtual void setInitialState();
void enableCycleCount(bool enable) const { myThumbEmulator->enableCycleCount(enable); }
// Get number of memory accesses of last and last but one ARM runs.
void updateCycles(int cycles);
#ifdef DEBUGGER_SUPPORT
const Thumbulator::Stats& stats() const { return myStats; }
const Thumbulator::Stats& prevStats() const { return myPrevStats; }
uInt32 cycles() const { return myCycles; }
uInt32 prevCycles() const { return myPrevCycles; }
#endif
void incCycles(bool enable);
void cycleFactor(double factor);
double cycleFactor() const { return myThumbEmulator->cycleFactor(); }
Thumbulator::ChipPropsType setChipType(Thumbulator::ChipType chipType) {
return myThumbEmulator->setChipType(chipType);
}
void lockMamMode(bool lock) { myThumbEmulator->lockMamMode(lock); }
void setMamMode(Thumbulator::MamModeType mamMode) { myThumbEmulator->setMamMode(mamMode); }
Thumbulator::MamModeType mamMode() const { return myThumbEmulator->mamMode(); }
protected:
// Pointer to the Thumb ARM emulator object
unique_ptr<Thumbulator> myThumbEmulator;
// ARM code increases 6507 cycles
bool myIncCycles{false};
// Console clock rate
double myClockRate{1193191.66666667};
#ifdef DEBUGGER_SUPPORT
Thumbulator::Stats myStats{0};
Thumbulator::Stats myPrevStats{0};
uInt32 myCycles{0};
uInt32 myPrevCycles{0};
#endif
private:
// Following constructors and assignment operators not supported
CartridgeARM() = delete;
CartridgeARM(const CartridgeARM&) = delete;
CartridgeARM(CartridgeARM&&) = delete;
CartridgeARM& operator=(const CartridgeARM&) = delete;
CartridgeARM& operator=(CartridgeARM&&) = delete;
};
#endif

View File

@ -23,7 +23,6 @@
#include "System.hxx"
#include "M6532.hxx"
#include "TIA.hxx"
#include "Thumbulator.hxx"
#include "CartBUS.hxx"
#include "exception/FatalEmulationError.hxx"
@ -43,7 +42,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeBUS::CartridgeBUS(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: Cartridge(settings, md5),
: CartridgeARM(md5, settings),
myImage{make_unique<uInt8[]>(32_KB)}
{
// Copy the ROM image into my buffer
@ -72,6 +71,7 @@ CartridgeBUS::CartridgeBUS(const ByteBuffer& image, size_t size,
0x00000808,
0x40001FDC,
devSettings ? settings.getBool("dev.thumb.trapfatal") : false,
devSettings ? settings.getFloat("dev.thumb.cyclefactor") : 1.0,
Thumbulator::ConfigureFor::BUS,
this);
@ -112,12 +112,8 @@ void CartridgeBUS::setInitialState()
mySTYZeroPageAddress = myJMPoperandAddress = 0;
myFastJumpActive = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeBUS::consoleChanged(ConsoleTiming timing)
{
myThumbEmulator->setConsoleTiming(timing);
CartridgeARM::setInitialState();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -147,7 +143,7 @@ inline void CartridgeBUS::updateMusicModeDataFetchers()
myAudioCycles = mySystem->cycles();
// Calculate the number of BUS OSC clocks since the last update
double clocks = ((20000.0 * cycles) / 1193191.66666667) + myFractionalClocks;
double clocks = ((20000.0 * cycles) / myClockRate) + myFractionalClocks;
uInt32 wholeClocks = uInt32(clocks);
myFractionalClocks = clocks - double(wholeClocks);
@ -167,10 +163,11 @@ inline void CartridgeBUS::callFunction(uInt8 value)
// time for Stella as ARM code "runs in zero 6507 cycles".
case 255: // call without IRQ driven audio
try {
Int32 cycles = Int32(mySystem->cycles() - myARMCycles);
myARMCycles = mySystem->cycles();
uInt32 cycles = uInt32(mySystem->cycles() - myARMCycles);
myThumbEmulator->run(cycles);
myARMCycles = mySystem->cycles();
myThumbEmulator->run(cycles, value == 254);
updateCycles(cycles);
}
catch(const runtime_error& e) {
if(!mySystem->autodetectMode())
@ -588,6 +585,8 @@ bool CartridgeBUS::save(Serializer& out) const
// Indicates if in the middle of a fast jump
out.putByte(myFastJumpActive);
CartridgeARM::save(out);
}
catch(...)
{
@ -629,6 +628,8 @@ bool CartridgeBUS::load(Serializer& in)
// Indicates if in the middle of a fast jump
myFastJumpActive = in.getByte();
CartridgeARM::load(in);
}
catch(...)
{

View File

@ -19,14 +19,13 @@
#define CARTRIDGE_BUS_HXX
class System;
class Thumbulator;
#ifdef DEBUGGER_SUPPORT
#include "CartBUSWidget.hxx"
#endif
#include "bspf.hxx"
#include "Thumbulator.hxx"
#include "Cart.hxx"
#include "CartARM.hxx"
/**
Cartridge class used for BUS.
@ -41,7 +40,7 @@ class Thumbulator;
@authors: Darrell Spice Jr, Chris Walton, Fred Quimby,
Stephen Anthony, Bradford W. Mott
*/
class CartridgeBUS : public Cartridge
class CartridgeBUS : public CartridgeARM
{
friend class CartridgeBUSWidget;
friend class CartridgeRamBUSWidget;
@ -65,15 +64,6 @@ class CartridgeBUS : public Cartridge
*/
void reset() override;
/**
Notification method invoked by the system when the console type
has changed. We need this to inform the Thumbulator that the
timing has changed.
@param timing Enum representing the new console type
*/
void consoleChanged(ConsoleTiming timing) override;
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@ -206,7 +196,7 @@ class CartridgeBUS : public Cartridge
/**
Sets the initial state of the DPC pointers and RAM
*/
void setInitialState();
void setInitialState() override;
/**
Updates any data fetchers in music mode based on the number of
@ -233,9 +223,6 @@ class CartridgeBUS : public Cartridge
uInt32 getWaveformSize(uInt8 index) const;
uInt32 getSample();
// Get number of memory accesses of last ARM run.
const Thumbulator::Stats& stats() const { return myThumbEmulator->stats(); }
private:
// The 32K ROM image of the cartridge
ByteBuffer myImage;
@ -255,9 +242,6 @@ class CartridgeBUS : public Cartridge
// $1800 - 2K C Variable & Stack
std::array<uInt8, 8_KB> myRAM;
// Pointer to the Thumb ARM emulator object
unique_ptr<Thumbulator> myThumbEmulator;
// Indicates the offset into the ROM image (aligns to current bank)
uInt16 myBankOffset{0};

View File

@ -24,7 +24,6 @@
#endif
#include "System.hxx"
#include "Thumbulator.hxx"
#include "CartCDF.hxx"
#include "TIA.hxx"
#include "exception/FatalEmulationError.hxx"
@ -65,7 +64,7 @@ namespace {
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeCDF::CartridgeCDF(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: Cartridge(settings, md5)
: CartridgeARM(md5, settings)
{
// Copy the ROM image into my buffer
mySize = std::min(size, 512_KB);
@ -108,6 +107,8 @@ CartridgeCDF::CartridgeCDF(const ByteBuffer& image, size_t size,
static_cast<uInt32>(mySize),
cBase, cStart, cStack,
devSettings ? settings.getBool("dev.thumb.trapfatal") : false,
devSettings ? static_cast<double>(
settings.getFloat("dev.thumb.cyclefactor")) : 1.0,
thumulatorConfiguration(myCDFSubtype),
this);
@ -145,12 +146,8 @@ void CartridgeCDF::setInitialState()
myBankOffset = myLDAimmediateOperandAddress = myJMPoperandAddress = 0;
myFastJumpActive = myFastJumpStream = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeCDF::consoleChanged(ConsoleTiming timing)
{
myThumbEmulator->setConsoleTiming(timing);
CartridgeARM::setInitialState();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -175,7 +172,7 @@ inline void CartridgeCDF::updateMusicModeDataFetchers()
myAudioCycles = mySystem->cycles();
// Calculate the number of CDF OSC clocks since the last update
double clocks = ((20000.0 * cycles) / 1193191.66666667) + myFractionalClocks;
double clocks = ((20000.0 * cycles) / myClockRate) + myFractionalClocks;
uInt32 wholeClocks = uInt32(clocks);
myFractionalClocks = clocks - double(wholeClocks);
@ -195,10 +192,11 @@ inline void CartridgeCDF::callFunction(uInt8 value)
// time for Stella as ARM code "runs in zero 6507 cycles".
case 255: // call without IRQ driven audio
try {
Int32 cycles = Int32(mySystem->cycles() - myARMCycles);
myARMCycles = mySystem->cycles();
uInt32 cycles = uInt32(mySystem->cycles() - myARMCycles);
myThumbEmulator->run(cycles);
myARMCycles = mySystem->cycles();
myThumbEmulator->run(cycles, value == 254);
updateCycles(cycles);
}
catch(const runtime_error& e) {
if(!mySystem->autodetectMode())
@ -560,6 +558,8 @@ bool CartridgeCDF::save(Serializer& out) const
out.putLong(myAudioCycles);
out.putDouble(myFractionalClocks);
out.putLong(myARMCycles);
CartridgeARM::save(out);
}
catch(...)
{
@ -600,6 +600,8 @@ bool CartridgeCDF::load(Serializer& in)
myAudioCycles = in.getLong();
myFractionalClocks = in.getDouble();
myARMCycles = in.getLong();
CartridgeARM::load(in);
}
catch(...)
{

View File

@ -21,8 +21,7 @@
class System;
#include "bspf.hxx"
#include "Thumbulator.hxx"
#include "Cart.hxx"
#include "CartARM.hxx"
/**
Cartridge class used for CDF/CDFJ/CDFJ+.
@ -52,7 +51,7 @@ class System;
@authors: Darrell Spice Jr, Chris Walton, Fred Quimby, John Champeau
Thomas Jentzsch, Stephen Anthony, Bradford W. Mott
*/
class CartridgeCDF : public Cartridge
class CartridgeCDF : public CartridgeARM
{
friend class CartridgeCDFWidget;
friend class CartridgeCDFInfoWidget;
@ -86,15 +85,6 @@ class CartridgeCDF : public Cartridge
*/
void reset() override;
/**
Notification method invoked by the system when the console type
has changed. We need this to inform the Thumbulator that the
timing has changed.
@param timing Enum representing the new console type
*/
void consoleChanged(ConsoleTiming timing) override;
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@ -238,7 +228,7 @@ class CartridgeCDF : public Cartridge
/**
Sets the initial state of the DPC pointers and RAM
*/
void setInitialState();
void setInitialState() override;
/**
Updates any data fetchers in music mode based on the number of
@ -263,9 +253,6 @@ class CartridgeCDF : public Cartridge
uInt32 getSample();
void setupVersion();
// Get number of memory accesses of last ARM run.
const Thumbulator::Stats& stats() const { return myThumbEmulator->stats(); }
private:
// The ROM image of the cartridge
ByteBuffer myImage{nullptr};
@ -291,9 +278,6 @@ class CartridgeCDF : public Cartridge
// $0800 - Display Data, C Variables & Stack
std::array<uInt8, 32_KB> myRAM;
// Pointer to the Thumb ARM emulator object
unique_ptr<Thumbulator> myThumbEmulator;
// Indicates the offset into the ROM image (aligns to current bank)
uInt16 myBankOffset{0};

View File

@ -64,6 +64,22 @@ void CartridgeCTY::reset()
bank(startBank());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeCTY::consoleChanged(ConsoleTiming timing)
{
constexpr double NTSC = 1193191.66666667; // NTSC 6507 clock rate
constexpr double PAL = 1182298.0; // PAL 6507 clock rate
constexpr double SECAM = 1187500.0; // SECAM 6507 clock rate
switch(timing)
{
case ConsoleTiming::ntsc: myClockRate = NTSC; break;
case ConsoleTiming::pal: myClockRate = PAL; break;
case ConsoleTiming::secam: myClockRate = SECAM; break;
default: break; // satisfy compiler
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeCTY::install(System& system)
{
@ -573,7 +589,7 @@ inline void CartridgeCTY::updateMusicModeDataFetchers()
myAudioCycles = mySystem->cycles();
// Calculate the number of CTY OSC clocks since the last update
double clocks = ((20000.0 * cycles) / 1193191.66666667) + myFractionalClocks;
double clocks = ((20000.0 * cycles) / myClockRate) + myFractionalClocks;
uInt32 wholeClocks = uInt32(clocks);
myFractionalClocks = clocks - double(wholeClocks);

View File

@ -128,6 +128,15 @@ class CartridgeCTY : public Cartridge
*/
void reset() override;
/**
Notification method invoked by the system when the console type
has changed. We need this to inform the Thumbulator that the
timing has changed.
@param timing Enum representing the new console type
*/
void consoleChanged(ConsoleTiming timing) override;
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@ -271,6 +280,9 @@ class CartridgeCTY : public Cartridge
// The 64 bytes of RAM accessible at $1000 - $1080
std::array<uInt8, 64> myRAM;
// Console clock rate
double myClockRate{1193191.66666667};
// Operation type (written to $1000, used by hotspot $1FF4)
uInt8 myOperationType{0};

View File

@ -38,6 +38,22 @@ void CartridgeDPC::reset()
myDpcPitch = mySettings.getInt(AudioSettings::SETTING_DPC_PITCH);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeDPC::consoleChanged(ConsoleTiming timing)
{
constexpr double NTSC = 1193191.66666667; // NTSC 6507 clock rate
constexpr double PAL = 1182298.0; // PAL 6507 clock rate
constexpr double SECAM = 1187500.0; // SECAM 6507 clock rate
switch(timing)
{
case ConsoleTiming::ntsc: myClockRate = NTSC; break;
case ConsoleTiming::pal: myClockRate = PAL; break;
case ConsoleTiming::secam: myClockRate = SECAM; break;
default: break; // satisfy compiler
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeDPC::install(System& system)
{
@ -82,7 +98,7 @@ inline void CartridgeDPC::updateMusicModeDataFetchers()
myAudioCycles = mySystem->cycles();
// Calculate the number of DPC OSC clocks since the last update
double clocks = ((myDpcPitch * cycles) / 1193191.66666667) + myFractionalClocks;
double clocks = ((myDpcPitch * cycles) / myClockRate) + myFractionalClocks;
uInt32 wholeClocks = uInt32(clocks);
myFractionalClocks = clocks - double(wholeClocks);

View File

@ -53,18 +53,28 @@ class CartridgeDPC : public CartridgeF8
~CartridgeDPC() override = default;
public:
/**
Reset device to its power-on state
*/
void reset() override;
/**
Notification method invoked by the system when the console type
has changed. We need this to inform the Thumbulator that the
timing has changed.
@param timing Enum representing the new console type
*/
void consoleChanged(ConsoleTiming timing) override;
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@param system The system the device should install itself in
*/
void install(System& system) override;
/**
Reset device to its power-on state
*/
void reset() override;
void install(System& system) override;
/**
Patch the cartridge ROM.
@ -147,6 +157,9 @@ class CartridgeDPC : public CartridgeF8
void updateMusicModeDataFetchers();
private:
// Console clock rate
double myClockRate{1193191.66666667};
// Pointer to the 2K display ROM image of the cartridge
uInt8* myDisplayImage{nullptr};

View File

@ -20,7 +20,6 @@
#endif
#include "MD5.hxx"
#include "System.hxx"
#include "Thumbulator.hxx"
#include "CartDPCPlus.hxx"
#include "TIA.hxx"
#include "exception/FatalEmulationError.hxx"
@ -28,7 +27,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeDPCPlus::CartridgeDPCPlus(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: Cartridge(settings, md5),
: CartridgeARM(md5, settings),
myImage{make_unique<uInt8[]>(32_KB)},
mySize{std::min(size, 32_KB)}
{
@ -58,6 +57,8 @@ CartridgeDPCPlus::CartridgeDPCPlus(const ByteBuffer& image, size_t size,
0x00000C08,
0x40001FDC,
devSettings ? settings.getBool("dev.thumb.trapfatal") : false,
devSettings ? static_cast<double>(
settings.getFloat("dev.thumb.cyclefactor")) : 1.0,
Thumbulator::ConfigureFor::DPCplus,
this);
@ -118,12 +119,8 @@ void CartridgeDPCPlus::setInitialState()
myFastFetch = myLDAimmediate = false;
myAudioCycles = myARMCycles = 0;
myFractionalClocks = 0.0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeDPCPlus::consoleChanged(ConsoleTiming timing)
{
myThumbEmulator->setConsoleTiming(timing);
CartridgeARM::setInitialState();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -165,7 +162,7 @@ inline void CartridgeDPCPlus::updateMusicModeDataFetchers()
myAudioCycles = mySystem->cycles();
// Calculate the number of DPC+ OSC clocks since the last update
double clocks = ((20000.0 * cycles) / 1193191.66666667) + myFractionalClocks;
double clocks = ((20000.0 * cycles) / myClockRate) + myFractionalClocks;
uInt32 wholeClocks = uInt32(clocks);
myFractionalClocks = clocks - double(wholeClocks);
@ -200,10 +197,11 @@ inline void CartridgeDPCPlus::callFunction(uInt8 value)
// time for Stella as ARM code "runs in zero 6507 cycles".
case 255: // call without IRQ driven audio
try {
Int32 cycles = Int32(mySystem->cycles() - myARMCycles);
myARMCycles = mySystem->cycles();
uInt32 cycles = uInt32(mySystem->cycles() - myARMCycles);
myThumbEmulator->run(cycles);
myARMCycles = mySystem->cycles();
myThumbEmulator->run(cycles, value == 254);
updateCycles(cycles);
}
catch(const runtime_error& e) {
if(!mySystem->autodetectMode())
@ -710,6 +708,8 @@ bool CartridgeDPCPlus::save(Serializer& out) const
// Clock info for Thumbulator
out.putLong(myARMCycles);
CartridgeARM::save(out);
}
catch(...)
{
@ -771,6 +771,8 @@ bool CartridgeDPCPlus::load(Serializer& in)
// Clock info for Thumbulator
myARMCycles = in.getLong();
CartridgeARM::load(in);
}
catch(...)
{

View File

@ -20,13 +20,12 @@
class System;
#include "Thumbulator.hxx"
#ifdef DEBUGGER_SUPPORT
#include "CartDPCPlusWidget.hxx"
#endif
#include "bspf.hxx"
#include "Cart.hxx"
#include "CartARM.hxx"
/**
Cartridge class used for DPC+, derived from Pitfall II. There are six 4K
@ -42,7 +41,7 @@ class System;
@authors Darrell Spice Jr, Fred Quimby, Stephen Anthony, Bradford W. Mott
*/
class CartridgeDPCPlus : public Cartridge
class CartridgeDPCPlus : public CartridgeARM
{
friend class CartridgeDPCPlusWidget;
friend class CartridgeRamDPCPlusWidget;
@ -66,15 +65,6 @@ class CartridgeDPCPlus : public Cartridge
*/
void reset() override;
/**
Notification method invoked by the system when the console type
has changed. We need this to inform the Thumbulator that the
timing has changed.
@param timing Enum representing the new console type
*/
void consoleChanged(ConsoleTiming timing) override;
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@ -200,7 +190,7 @@ class CartridgeDPCPlus : public Cartridge
/**
Sets the initial state of the DPC pointers and RAM
*/
void setInitialState();
void setInitialState() override;
/**
Clocks the random number generator to move it to its next state
@ -223,9 +213,6 @@ class CartridgeDPCPlus : public Cartridge
*/
void callFunction(uInt8 value);
// Get number of memory accesses of last ARM run.
const Thumbulator::Stats& stats() const { return myThumbEmulator->stats(); }
private:
// The ROM image and size
ByteBuffer myImage;
@ -243,9 +230,6 @@ class CartridgeDPCPlus : public Cartridge
// 1K Frequency Data
std::array<uInt8, 8_KB> myDPCRAM;
// Pointer to the Thumb ARM emulator object
unique_ptr<Thumbulator> myThumbEmulator;
// Pointer to the 1K frequency table
uInt8* myFrequencyImage{nullptr};

View File

@ -134,6 +134,10 @@ Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t si
{
if (isProbablyCTY(image, size))
type = Bankswitch::Type::_CTY;
else if(isProbablyCDF(image, size))
type = Bankswitch::Type::_CDF;
else if(isProbablyDPCplus(image, size))
type = Bankswitch::Type::_DPCP;
else if(isProbablySC(image, size))
type = Bankswitch::Type::_F4SC;
else if(isProbably3EX(image, size))
@ -144,10 +148,6 @@ Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t si
type = Bankswitch::Type::_3F;
else if (isProbablyBUS(image, size))
type = Bankswitch::Type::_BUS;
else if (isProbablyCDF(image, size))
type = Bankswitch::Type::_CDF;
else if(isProbablyDPCplus(image, size))
type = Bankswitch::Type::_DPCP;
else if(isProbablyFA2(image, size))
type = Bankswitch::Type::_FA2;
else if (isProbablyFC(image, size))
@ -166,12 +166,12 @@ Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t si
{
if(isProbably3EX(image, size))
type = Bankswitch::Type::_3EX;
else if (isProbablyCDF(image, size))
type = Bankswitch::Type::_CDF;
else if(isProbably3E(image, size))
type = Bankswitch::Type::_3E;
else if(isProbably3F(image, size))
type = Bankswitch::Type::_3F;
else if (isProbablyCDF(image, size))
type = Bankswitch::Type::_CDF;
else if(isProbably4A50(image, size))
type = Bankswitch::Type::_4A50;
else if(isProbablyEF(image, size, type))
@ -195,6 +195,8 @@ Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t si
type = Bankswitch::Type::_CDF;
else if(isProbably4A50(image, size))
type = Bankswitch::Type::_4A50;
else if(isProbablyCDF(image, size))
type = Bankswitch::Type::_CDF;
else /*if(isProbablySB(image, size))*/
type = Bankswitch::Type::_SB;
}

File diff suppressed because it is too large Load Diff

View File

@ -25,15 +25,15 @@ Driving::Driving(Jack jack, const Event& event, const System& system, bool altma
{
if(!altmap)
{
myCCWEvent = Event::JoystickZeroLeft;
myCWEvent = Event::JoystickZeroRight;
myFireEvent = Event::JoystickZeroFire;
myCCWEvent = Event::LeftJoystickLeft;
myCWEvent = Event::LeftJoystickRight;
myFireEvent = Event::LeftJoystickFire;
}
else
{
myCCWEvent = Event::JoystickTwoLeft;
myCWEvent = Event::JoystickTwoRight;
myFireEvent = Event::JoystickTwoFire;
myCCWEvent = Event::QTJoystickThreeLeft;
myCWEvent = Event::QTJoystickThreeRight;
myFireEvent = Event::QTJoystickThreeFire;
}
myXAxisValue = Event::SALeftAxis0Value; // joystick input
myYAxisValue = Event::SALeftAxis1Value; // driving controller input
@ -42,15 +42,15 @@ Driving::Driving(Jack jack, const Event& event, const System& system, bool altma
{
if(!altmap)
{
myCCWEvent = Event::JoystickOneLeft;
myCWEvent = Event::JoystickOneRight;
myFireEvent = Event::JoystickOneFire;
myCCWEvent = Event::RightJoystickLeft;
myCWEvent = Event::RightJoystickRight;
myFireEvent = Event::RightJoystickFire;
}
else
{
myCCWEvent = Event::JoystickThreeLeft;
myCWEvent = Event::JoystickThreeRight;
myFireEvent = Event::JoystickThreeFire;
myCCWEvent = Event::QTJoystickFourLeft;
myCWEvent = Event::QTJoystickFourRight;
myFireEvent = Event::QTJoystickFourFire;
}
myXAxisValue = Event::SARightAxis0Value; // joystick input
myYAxisValue = Event::SARightAxis1Value; // driving controller input

View File

@ -42,25 +42,25 @@ class Event
ConsoleRightDiffA, ConsoleRightDiffB, ConsoleRightDiffToggle,
ConsoleSelect, ConsoleReset,
JoystickZeroUp, JoystickZeroDown, JoystickZeroLeft, JoystickZeroRight,
JoystickZeroFire, JoystickZeroFire5, JoystickZeroFire9,
JoystickOneUp, JoystickOneDown, JoystickOneLeft, JoystickOneRight,
JoystickOneFire, JoystickOneFire5, JoystickOneFire9,
LeftJoystickUp, LeftJoystickDown, LeftJoystickLeft, LeftJoystickRight,
LeftJoystickFire, LeftJoystickFire5, LeftJoystickFire9,
RightJoystickUp, RightJoystickDown, RightJoystickLeft, RightJoystickRight,
RightJoystickFire, RightJoystickFire5, RightJoystickFire9,
PaddleZeroDecrease, PaddleZeroIncrease, PaddleZeroAnalog, PaddleZeroFire,
PaddleOneDecrease, PaddleOneIncrease, PaddleOneAnalog, PaddleOneFire,
PaddleTwoDecrease, PaddleTwoIncrease, PaddleTwoAnalog, PaddleTwoFire,
PaddleThreeDecrease, PaddleThreeIncrease, PaddleThreeAnalog, PaddleThreeFire,
LeftPaddleADecrease, LeftPaddleAIncrease, LeftPaddleAAnalog, LeftPaddleAFire,
LeftPaddleBDecrease, LeftPaddleBIncrease, LeftPaddleBAnalog, LeftPaddleBFire,
RightPaddleADecrease, RightPaddleAIncrease, RightPaddleAAnalog, RightPaddleAFire,
RightPaddleBDecrease, RightPaddleBIncrease, RightPaddleBAnalog, RightPaddleBFire,
KeyboardZero1, KeyboardZero2, KeyboardZero3,
KeyboardZero4, KeyboardZero5, KeyboardZero6,
KeyboardZero7, KeyboardZero8, KeyboardZero9,
KeyboardZeroStar, KeyboardZero0, KeyboardZeroPound,
LeftKeyboard1, LeftKeyboard2, LeftKeyboard3,
LeftKeyboard4, LeftKeyboard5, LeftKeyboard6,
LeftKeyboard7, LeftKeyboard8, LeftKeyboard9,
LeftKeyboardStar, LeftKeyboard0, LeftKeyboardPound,
KeyboardOne1, KeyboardOne2, KeyboardOne3,
KeyboardOne4, KeyboardOne5, KeyboardOne6,
KeyboardOne7, KeyboardOne8, KeyboardOne9,
KeyboardOneStar, KeyboardOne0, KeyboardOnePound,
RightKeyboard1, RightKeyboard2, RightKeyboard3,
RightKeyboard4, RightKeyboard5, RightKeyboard6,
RightKeyboard7, RightKeyboard8, RightKeyboard9,
RightKeyboardStar, RightKeyboard0, RightKeyboardPound,
CompuMateFunc, CompuMateShift,
CompuMate0, CompuMate1, CompuMate2, CompuMate3, CompuMate4,
@ -129,10 +129,10 @@ class Event
DecreaseAutoFire, IncreaseAutoFire,
DecreaseSpeed, IncreaseSpeed,
JoystickTwoUp, JoystickTwoDown, JoystickTwoLeft, JoystickTwoRight,
JoystickTwoFire,
JoystickThreeUp, JoystickThreeDown, JoystickThreeLeft, JoystickThreeRight,
JoystickThreeFire,
QTJoystickThreeUp, QTJoystickThreeDown, QTJoystickThreeLeft, QTJoystickThreeRight,
QTJoystickThreeFire,
QTJoystickFourUp, QTJoystickFourDown, QTJoystickFourLeft, QTJoystickFourRight,
QTJoystickFourFire,
ToggleCorrectAspectRatio,
@ -167,7 +167,7 @@ class Event
DecreaseMouseAxesRange, IncreaseMouseAxesRange,
SALeftAxis0Value, SALeftAxis1Value, SARightAxis0Value, SARightAxis1Value,
PaddleFourFire, PaddleFiveFire, PaddleSixFire, PaddleSevenFire,
QTPaddle3AFire, QTPaddle3BFire, QTPaddle4AFire, QTPaddle4BFire,
UIHelp,
LastType
};
@ -229,10 +229,10 @@ class Event
{
switch(type)
{
case Event::PaddleZeroAnalog:
case Event::PaddleOneAnalog:
case Event::PaddleTwoAnalog:
case Event::PaddleThreeAnalog:
case Event::LeftPaddleAAnalog:
case Event::LeftPaddleBAnalog:
case Event::RightPaddleAAnalog:
case Event::RightPaddleBAnalog:
return true;
default:
return false;
@ -256,62 +256,62 @@ class Event
// Hold controller related events
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static const Event::EventSet LeftJoystickEvents = {
Event::JoystickZeroUp, Event::JoystickZeroDown, Event::JoystickZeroLeft, Event::JoystickZeroRight,
Event::JoystickZeroFire, Event::JoystickZeroFire5, Event::JoystickZeroFire9,
Event::LeftJoystickUp, Event::LeftJoystickDown, Event::LeftJoystickLeft, Event::LeftJoystickRight,
Event::LeftJoystickFire, Event::LeftJoystickFire5, Event::LeftJoystickFire9,
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static const Event::EventSet Left2JoystickEvents = {
Event::JoystickTwoUp, Event::JoystickTwoDown, Event::JoystickTwoLeft, Event::JoystickTwoRight,
Event::JoystickTwoFire
static const Event::EventSet QTJoystick3Events = {
Event::QTJoystickThreeUp, Event::QTJoystickThreeDown, Event::QTJoystickThreeLeft, Event::QTJoystickThreeRight,
Event::QTJoystickThreeFire
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static const Event::EventSet RightJoystickEvents = {
Event::JoystickOneUp, Event::JoystickOneDown, Event::JoystickOneLeft, Event::JoystickOneRight,
Event::JoystickOneFire, Event::JoystickOneFire5, Event::JoystickOneFire9,
Event::RightJoystickUp, Event::RightJoystickDown, Event::RightJoystickLeft, Event::RightJoystickRight,
Event::RightJoystickFire, Event::RightJoystickFire5, Event::RightJoystickFire9,
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static const Event::EventSet Right2JoystickEvents = {
Event::JoystickThreeUp, Event::JoystickThreeDown, Event::JoystickThreeLeft, Event::JoystickThreeRight,
Event::JoystickThreeFire
static const Event::EventSet QTJoystick4Events = {
Event::QTJoystickFourUp, Event::QTJoystickFourDown, Event::QTJoystickFourLeft, Event::QTJoystickFourRight,
Event::QTJoystickFourFire
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static const Event::EventSet LeftPaddlesEvents = {
Event::PaddleZeroDecrease, Event::PaddleZeroIncrease, Event::PaddleZeroAnalog, Event::PaddleZeroFire,
Event::PaddleOneDecrease, Event::PaddleOneIncrease, Event::PaddleOneAnalog, Event::PaddleOneFire,
Event::LeftPaddleADecrease, Event::LeftPaddleAIncrease, Event::LeftPaddleAAnalog, Event::LeftPaddleAFire,
Event::LeftPaddleBDecrease, Event::LeftPaddleBIncrease, Event::LeftPaddleBAnalog, Event::LeftPaddleBFire,
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static const Event::EventSet Left2PaddlesEvents = {
static const Event::EventSet QTPaddles3Events = {
// Only fire buttons supported by QuadTari
Event::PaddleFourFire, Event::PaddleFiveFire
Event::QTPaddle3AFire, Event::QTPaddle3BFire
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static const Event::EventSet RightPaddlesEvents = {
Event::PaddleTwoDecrease, Event::PaddleTwoIncrease, Event::PaddleTwoAnalog, Event::PaddleTwoFire,
Event::PaddleThreeDecrease, Event::PaddleThreeIncrease, Event::PaddleThreeAnalog, Event::PaddleThreeFire,
Event::RightPaddleADecrease, Event::RightPaddleAIncrease, Event::RightPaddleAAnalog, Event::RightPaddleAFire,
Event::RightPaddleBDecrease, Event::RightPaddleBIncrease, Event::RightPaddleBAnalog, Event::RightPaddleBFire,
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static const Event::EventSet Right2PaddlesEvents = {
static const Event::EventSet QTPaddles4Events = {
// Only fire buttons supported by QuadTari
Event::PaddleSixFire, Event::PaddleSevenFire
Event::QTPaddle4AFire, Event::QTPaddle4BFire
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static const Event::EventSet LeftKeypadEvents = {
Event::KeyboardZero1, Event::KeyboardZero2, Event::KeyboardZero3,
Event::KeyboardZero4, Event::KeyboardZero5, Event::KeyboardZero6,
Event::KeyboardZero7, Event::KeyboardZero8, Event::KeyboardZero9,
Event::KeyboardZeroStar, Event::KeyboardZero0, Event::KeyboardZeroPound,
static const Event::EventSet LeftKeyboardEvents = {
Event::LeftKeyboard1, Event::LeftKeyboard2, Event::LeftKeyboard3,
Event::LeftKeyboard4, Event::LeftKeyboard5, Event::LeftKeyboard6,
Event::LeftKeyboard7, Event::LeftKeyboard8, Event::LeftKeyboard9,
Event::LeftKeyboardStar, Event::LeftKeyboard0, Event::LeftKeyboardPound,
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static const Event::EventSet RightKeypadEvents = {
Event::KeyboardOne1, Event::KeyboardOne2, Event::KeyboardOne3,
Event::KeyboardOne4, Event::KeyboardOne5, Event::KeyboardOne6,
Event::KeyboardOne7, Event::KeyboardOne8, Event::KeyboardOne9,
Event::KeyboardOneStar, Event::KeyboardOne0, Event::KeyboardOnePound,
static const Event::EventSet RightKeyboardEvents = {
Event::RightKeyboard1, Event::RightKeyboard2, Event::RightKeyboard3,
Event::RightKeyboard4, Event::RightKeyboard5, Event::RightKeyboard6,
Event::RightKeyboard7, Event::RightKeyboard8, Event::RightKeyboard9,
Event::RightKeyboardStar, Event::RightKeyboard0, Event::RightKeyboardPound,
};
#endif

View File

@ -54,6 +54,7 @@
#endif
#ifdef DEBUGGER_SUPPORT
#include "Debugger.hxx"
#include "DebuggerParser.hxx"
#endif
#ifdef GUI_SUPPORT
#include "Menu.hxx"
@ -68,6 +69,7 @@
#endif
using namespace std::placeholders;
using json = nlohmann::json;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EventHandler::EventHandler(OSystem& osystem)
@ -89,11 +91,6 @@ void EventHandler::initialize()
// Create joystick handler (to handle all physical joystick functionality)
myPJoyHandler = make_unique<PhysicalJoystickHandler>(myOSystem, *this, myEvent);
// Erase the 'combo' array
for(int i = 0; i < COMBO_SIZE; ++i)
for(int j = 0; j < EVENTS_PER_COMBO; ++j)
myComboTable[i][j] = Event::NoType;
// Make sure the event/action mappings are correctly set,
// and fill the ActionList structure with valid values
setComboMap();
@ -163,11 +160,6 @@ void EventHandler::addPhysicalJoystick(const PhysicalJoystickPtr& joy)
setActionMappings(EventMode::kEmulationMode);
setActionMappings(EventMode::kMenuMode);
ostringstream buf;
buf << "Added joystick " << ID << ":" << endl
<< " " << joy->about() << endl;
Logger::info(buf.str());
#endif
}
@ -758,84 +750,84 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated)
////////////////////////////////////////////////////////////////////////
// If enabled, make sure 'impossible' joystick directions aren't allowed
case Event::JoystickZeroUp:
case Event::LeftJoystickUp:
if(!myAllowAllDirectionsFlag && pressed)
myEvent.set(Event::JoystickZeroDown, 0);
myEvent.set(Event::LeftJoystickDown, 0);
break;
case Event::JoystickZeroDown:
case Event::LeftJoystickDown:
if(!myAllowAllDirectionsFlag && pressed)
myEvent.set(Event::JoystickZeroUp, 0);
myEvent.set(Event::LeftJoystickUp, 0);
break;
case Event::JoystickZeroLeft:
case Event::LeftJoystickLeft:
if(!myAllowAllDirectionsFlag && pressed)
myEvent.set(Event::JoystickZeroRight, 0);
myEvent.set(Event::LeftJoystickRight, 0);
break;
case Event::JoystickZeroRight:
case Event::LeftJoystickRight:
if(!myAllowAllDirectionsFlag && pressed)
myEvent.set(Event::JoystickZeroLeft, 0);
myEvent.set(Event::LeftJoystickLeft, 0);
break;
case Event::JoystickOneUp:
case Event::RightJoystickUp:
if(!myAllowAllDirectionsFlag && pressed)
myEvent.set(Event::JoystickOneDown, 0);
myEvent.set(Event::RightJoystickDown, 0);
break;
case Event::JoystickOneDown:
case Event::RightJoystickDown:
if(!myAllowAllDirectionsFlag && pressed)
myEvent.set(Event::JoystickOneUp, 0);
myEvent.set(Event::RightJoystickUp, 0);
break;
case Event::JoystickOneLeft:
case Event::RightJoystickLeft:
if(!myAllowAllDirectionsFlag && pressed)
myEvent.set(Event::JoystickOneRight, 0);
myEvent.set(Event::RightJoystickRight, 0);
break;
case Event::JoystickOneRight:
case Event::RightJoystickRight:
if(!myAllowAllDirectionsFlag && pressed)
myEvent.set(Event::JoystickOneLeft, 0);
myEvent.set(Event::RightJoystickLeft, 0);
break;
case Event::JoystickTwoUp:
case Event::QTJoystickThreeUp:
if(!myAllowAllDirectionsFlag && pressed)
myEvent.set(Event::JoystickTwoDown, 0);
myEvent.set(Event::QTJoystickThreeDown, 0);
break;
case Event::JoystickTwoDown:
case Event::QTJoystickThreeDown:
if(!myAllowAllDirectionsFlag && pressed)
myEvent.set(Event::JoystickTwoUp, 0);
myEvent.set(Event::QTJoystickThreeUp, 0);
break;
case Event::JoystickTwoLeft:
case Event::QTJoystickThreeLeft:
if(!myAllowAllDirectionsFlag && pressed)
myEvent.set(Event::JoystickTwoRight, 0);
myEvent.set(Event::QTJoystickThreeRight, 0);
break;
case Event::JoystickTwoRight:
case Event::QTJoystickThreeRight:
if(!myAllowAllDirectionsFlag && pressed)
myEvent.set(Event::JoystickTwoLeft, 0);
myEvent.set(Event::QTJoystickThreeLeft, 0);
break;
case Event::JoystickThreeUp:
case Event::QTJoystickFourUp:
if(!myAllowAllDirectionsFlag && pressed)
myEvent.set(Event::JoystickThreeDown, 0);
myEvent.set(Event::QTJoystickFourDown, 0);
break;
case Event::JoystickThreeDown:
case Event::QTJoystickFourDown:
if(!myAllowAllDirectionsFlag && pressed)
myEvent.set(Event::JoystickThreeUp, 0);
myEvent.set(Event::QTJoystickFourUp, 0);
break;
case Event::JoystickThreeLeft:
case Event::QTJoystickFourLeft:
if(!myAllowAllDirectionsFlag && pressed)
myEvent.set(Event::JoystickThreeRight, 0);
myEvent.set(Event::QTJoystickFourRight, 0);
break;
case Event::JoystickThreeRight:
case Event::QTJoystickFourRight:
if(!myAllowAllDirectionsFlag && pressed)
myEvent.set(Event::JoystickThreeLeft, 0);
myEvent.set(Event::QTJoystickFourLeft, 0);
break;
///////////////////////////////////////////////////////////////////////////
@ -2087,27 +2079,27 @@ void EventHandler::handleConsoleStartupEvents()
const string& holdjoy0 = myOSystem.settings().getString("holdjoy0");
if(BSPF::containsIgnoreCase(holdjoy0, "U"))
handleEvent(Event::JoystickZeroUp);
handleEvent(Event::LeftJoystickUp);
if(BSPF::containsIgnoreCase(holdjoy0, "D"))
handleEvent(Event::JoystickZeroDown);
handleEvent(Event::LeftJoystickDown);
if(BSPF::containsIgnoreCase(holdjoy0, "L"))
handleEvent(Event::JoystickZeroLeft);
handleEvent(Event::LeftJoystickLeft);
if(BSPF::containsIgnoreCase(holdjoy0, "R"))
handleEvent(Event::JoystickZeroRight);
handleEvent(Event::LeftJoystickRight);
if(BSPF::containsIgnoreCase(holdjoy0, "F"))
handleEvent(Event::JoystickZeroFire);
handleEvent(Event::LeftJoystickFire);
const string& holdjoy1 = myOSystem.settings().getString("holdjoy1");
if(BSPF::containsIgnoreCase(holdjoy1, "U"))
handleEvent(Event::JoystickOneUp);
handleEvent(Event::RightJoystickUp);
if(BSPF::containsIgnoreCase(holdjoy1, "D"))
handleEvent(Event::JoystickOneDown);
handleEvent(Event::RightJoystickDown);
if(BSPF::containsIgnoreCase(holdjoy1, "L"))
handleEvent(Event::JoystickOneLeft);
handleEvent(Event::RightJoystickLeft);
if(BSPF::containsIgnoreCase(holdjoy1, "R"))
handleEvent(Event::JoystickOneRight);
handleEvent(Event::RightJoystickRight);
if(BSPF::containsIgnoreCase(holdjoy1, "F"))
handleEvent(Event::JoystickOneFire);
handleEvent(Event::RightJoystickFire);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -2263,12 +2255,19 @@ void EventHandler::setActionMappings(EventMode mode)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::setComboMap()
{
// Since istringstream swallows whitespace, we have to make the
// delimiters be spaces
string list = myOSystem.settings().getString("combomap");
replace(list.begin(), list.end(), ':', ' ');
istringstream buf(list);
const Int32 version = myOSystem.settings().getInt("event_ver");
const string serializedMapping = myOSystem.settings().getString("combomap");
json mapping;
try
{
mapping = json::parse(serializedMapping);
}
catch(const json::exception&)
{
Logger::info("converting legacy combo mapping");
mapping = convertLegacyComboMapping(serializedMapping);
}
// Erase the 'combo' array
auto ERASE_ALL = [&]() {
@ -2277,48 +2276,84 @@ void EventHandler::setComboMap()
myComboTable[i][j] = Event::NoType;
};
ERASE_ALL();
// Compare if event list version has changed so that combo maps became invalid
if(version != Event::VERSION || !buf.good())
ERASE_ALL();
else
if(version == Event::VERSION)
{
// Get combo count, which should be the first int in the list
// If it isn't, then we treat the entire list as invalid
try
{
string key;
buf >> key;
if(BSPF::stringToInt(key) == COMBO_SIZE)
for(const json& combo : mapping)
{
// Fill the combomap table with events for as long as they exist
int combocount = 0;
while(buf >> key && combocount < COMBO_SIZE)
{
// Each event in a comboevent is separated by a comma
replace(key.begin(), key.end(), ',', ' ');
istringstream buf2(key);
int i = combo.at("combo").get<Event::Type>() - Event::Combo1,
j = 0;
json events = combo.at("events");
int eventcount = 0;
while(buf2 >> key && eventcount < EVENTS_PER_COMBO)
{
myComboTable[combocount][eventcount] = Event::Type(BSPF::stringToInt(key));
++eventcount;
}
++combocount;
}
for(const json& event : events)
myComboTable[i][j++] = event;
}
else
ERASE_ALL();
}
catch(...)
catch(const json::exception&)
{
Logger::error("ignoring bad combo mapping");
ERASE_ALL();
}
}
saveComboMapping();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
json EventHandler::convertLegacyComboMapping(string list)
{
json convertedMapping = json::array();
// Since istringstream swallows whitespace, we have to make the
// delimiters be spaces
std::replace(list.begin(), list.end(), ':', ' ');
std::replace(list.begin(), list.end(), ',', ' ');
istringstream buf(list);
try
{
int numCombos;
// Get combo count, which should be the first int in the list
// If it isn't, then we treat the entire list as invalid
buf >> numCombos;
if(numCombos == COMBO_SIZE)
{
for(int i = 0; i < COMBO_SIZE; ++i)
{
json events = json::array();
for(int j = 0; j < EVENTS_PER_COMBO; ++j)
{
int event;
buf >> event;
// skip all NoType events
if(event != Event::NoType)
events.push_back(Event::Type(event));
}
// only store if there are any NoType events
if(events.size())
{
json combo;
combo["combo"] = Event::Type(Event::Combo1 + i);
combo["events"] = events;
convertedMapping.push_back(combo);
}
}
}
}
catch(...)
{
Logger::error("Legacy combo map conversion failed!");
}
return convertedMapping;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::removePhysicalJoystickFromDatabase(const string& name)
{
@ -2423,18 +2458,32 @@ void EventHandler::saveJoyMapping()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::saveComboMapping()
{
// Iterate through the combomap table and create a colon-separated list
// For each combo event, create a comma-separated list of its events
// Prepend the event count, so we can check it on next load
ostringstream buf;
buf << COMBO_SIZE;
json mapping = json::array();
// Iterate through the combomap table and convert into json format
for(int i = 0; i < COMBO_SIZE; ++i)
{
buf << ":" << myComboTable[i][0];
for(int j = 1; j < EVENTS_PER_COMBO; ++j)
buf << "," << myComboTable[i][j];
json events = json::array();
for(int j = 0; j < EVENTS_PER_COMBO; ++j)
{
int event = myComboTable[i][j];
// skip all NoType events
if(event != Event::NoType)
events.push_back(Event::Type(event));
}
// only store if there are any NoType events
if(events.size())
{
json combo;
combo["combo"] = Event::Type(Event::Combo1 + i);
combo["events"] = events;
mapping.push_back(combo);
}
}
myOSystem.settings().setValue("combomap", buf.str());
myOSystem.settings().setValue("combomap", mapping.dump(2));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -2535,7 +2584,7 @@ StringList EventHandler::getActionList(const Event::EventSet& events, EventMode
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
VariantList EventHandler::getComboList(EventMode /**/) const
VariantList EventHandler::getComboList() const
{
// For now, this only works in emulation mode
VariantList l;
@ -2589,9 +2638,9 @@ void EventHandler::setComboListForEvent(Event::Type event, const StringList& eve
{
if(event >= Event::Combo1 && event <= Event::Combo16)
{
assert(events.size() == 8);
assert(events.size() == EVENTS_PER_COMBO);
const int combo = event - Event::Combo1;
for(uInt32 i = 0; i < 8; ++i)
for(uInt32 i = 0; i < EVENTS_PER_COMBO; ++i)
{
uInt32 idx = BSPF::stringToInt(events[i]);
if(idx < ourEmulActionList.size())
@ -2996,12 +3045,15 @@ void EventHandler::exitEmulation(bool checkLauncher)
const bool activeTM = myOSystem.settings().getBool(
myOSystem.settings().getBool("dev.settings") ? "dev.timemachine" : "plr.timemachine");
if (saveOnExit == "all" && activeTM)
handleEvent(Event::SaveAllStates);
else if (saveOnExit == "current")
handleEvent(Event::SaveState);
#if DEBUGGER_SUPPORT
myOSystem.debugger().quit();
#endif
if (checkLauncher)
{
// Go back to the launcher, or immediately quit
@ -3036,12 +3088,12 @@ EventHandler::EmulActionList EventHandler::ourEmulActionList = { {
{ Event::ConsoleBlackWhite, "Black & White TV", "" },
{ Event::ConsoleColorToggle, "Toggle Color / B&W TV", "" },
{ Event::Console7800Pause, "7800 Pause Key", "" },
{ Event::ConsoleLeftDiffA, "P0 Difficulty A", "" },
{ Event::ConsoleLeftDiffB, "P0 Difficulty B", "" },
{ Event::ConsoleLeftDiffToggle, "P0 Toggle Difficulty", "" },
{ Event::ConsoleRightDiffA, "P1 Difficulty A", "" },
{ Event::ConsoleRightDiffB, "P1 Difficulty B", "" },
{ Event::ConsoleRightDiffToggle, "P1 Toggle Difficulty", "" },
{ Event::ConsoleLeftDiffA, "Left Difficulty A", "" },
{ Event::ConsoleLeftDiffB, "Left Difficulty B", "" },
{ Event::ConsoleLeftDiffToggle, "Toggle Left Difficulty", "" },
{ Event::ConsoleRightDiffA, "Right Difficulty A", "" },
{ Event::ConsoleRightDiffB, "Right Difficulty B", "" },
{ Event::ConsoleRightDiffToggle, "Toggle Right Difficulty", "" },
{ Event::SaveState, "Save state", "" },
{ Event::SaveAllStates, "Save all TM states of current game", "" },
{ Event::PreviousState, "Change to previous state slot", "" },
@ -3056,84 +3108,84 @@ EventHandler::EmulActionList EventHandler::ourEmulActionList = { {
{ Event::ToggleContSnapshotsFrame,"Save continuous snapsh. (every frame)", "" },
#endif
{ Event::JoystickZeroUp, "P0 Joystick Up", "" },
{ Event::JoystickZeroDown, "P0 Joystick Down", "" },
{ Event::JoystickZeroLeft, "P0 Joystick Left", "" },
{ Event::JoystickZeroRight, "P0 Joystick Right", "" },
{ Event::JoystickZeroFire, "P0 Joystick Fire", "" },
{ Event::JoystickZeroFire5, "P0 Booster Top Booster Button", "" },
{ Event::JoystickZeroFire9, "P0 Booster Handle Grip Trigger", "" },
{ Event::LeftJoystickUp, "Left Joystick Up", "" },
{ Event::LeftJoystickDown, "Left Joystick Down", "" },
{ Event::LeftJoystickLeft, "Left Joystick Left", "" },
{ Event::LeftJoystickRight, "Left Joystick Right", "" },
{ Event::LeftJoystickFire, "Left Joystick Fire", "" },
{ Event::LeftJoystickFire5, "Left Booster Top Booster Button", "" },
{ Event::LeftJoystickFire9, "Left Booster Handle Grip Trigger", "" },
{ Event::JoystickOneUp, "P1 Joystick Up", "" },
{ Event::JoystickOneDown, "P1 Joystick Down", "" },
{ Event::JoystickOneLeft, "P1 Joystick Left", "" },
{ Event::JoystickOneRight, "P1 Joystick Right", "" },
{ Event::JoystickOneFire, "P1 Joystick Fire", "" },
{ Event::JoystickOneFire5, "P1 Booster Top Booster Button", "" },
{ Event::JoystickOneFire9, "P1 Booster Handle Grip Trigger", "" },
{ Event::RightJoystickUp, "Right Joystick Up", "" },
{ Event::RightJoystickDown, "Right Joystick Down", "" },
{ Event::RightJoystickLeft, "Right Joystick Left", "" },
{ Event::RightJoystickRight, "Right Joystick Right", "" },
{ Event::RightJoystickFire, "Right Joystick Fire", "" },
{ Event::RightJoystickFire5, "Right Booster Top Booster Button", "" },
{ Event::RightJoystickFire9, "Right Booster Handle Grip Trigger", "" },
{ Event::JoystickTwoUp, "P2 Joystick Up", "" },
{ Event::JoystickTwoDown, "P2 Joystick Down", "" },
{ Event::JoystickTwoLeft, "P2 Joystick Left", "" },
{ Event::JoystickTwoRight, "P2 Joystick Right", "" },
{ Event::JoystickTwoFire, "P2 Joystick Fire", "" },
{ Event::QTJoystickThreeUp, "QuadTari Joystick 3 Up", "" },
{ Event::QTJoystickThreeDown, "QuadTari Joystick 3 Down", "" },
{ Event::QTJoystickThreeLeft, "QuadTari Joystick 3 Left", "" },
{ Event::QTJoystickThreeRight, "QuadTari Joystick 3 Right", "" },
{ Event::QTJoystickThreeFire, "QuadTari Joystick 3 Fire", "" },
{ Event::JoystickThreeUp, "P3 Joystick Up", "" },
{ Event::JoystickThreeDown, "P3 Joystick Down", "" },
{ Event::JoystickThreeLeft, "P3 Joystick Left", "" },
{ Event::JoystickThreeRight, "P3 Joystick Right", "" },
{ Event::JoystickThreeFire, "P3 Joystick Fire", "" },
{ Event::QTJoystickFourUp, "QuadTari Joystick 4 Up", "" },
{ Event::QTJoystickFourDown, "QuadTari Joystick 4 Down", "" },
{ Event::QTJoystickFourLeft, "QuadTari Joystick 4 Left", "" },
{ Event::QTJoystickFourRight, "QuadTari Joystick 4 Right", "" },
{ Event::QTJoystickFourFire, "QuadTari Joystick 4 Fire", "" },
{ Event::PaddleZeroAnalog, "Paddle 0 Analog", "" },
{ Event::PaddleZeroIncrease, "Paddle 0 Turn Left", "" },
{ Event::PaddleZeroDecrease, "Paddle 0 Turn Right", "" },
{ Event::PaddleZeroFire, "Paddle 0 Fire", "" },
{ Event::LeftPaddleAAnalog, "Left Paddle A Analog", "" },
{ Event::LeftPaddleAIncrease, "Left Paddle A Turn Left", "" },
{ Event::LeftPaddleADecrease, "Left Paddle A Turn Right", "" },
{ Event::LeftPaddleAFire, "Left Paddle A Fire", "" },
{ Event::PaddleOneAnalog, "Paddle 1 Analog", "" },
{ Event::PaddleOneIncrease, "Paddle 1 Turn Left", "" },
{ Event::PaddleOneDecrease, "Paddle 1 Turn Right", "" },
{ Event::PaddleOneFire, "Paddle 1 Fire", "" },
{ Event::LeftPaddleBAnalog, "Left Paddle B Analog", "" },
{ Event::LeftPaddleBIncrease, "Left Paddle B Turn Left", "" },
{ Event::LeftPaddleBDecrease, "Left Paddle B Turn Right", "" },
{ Event::LeftPaddleBFire, "Left Paddle B Fire", "" },
{ Event::PaddleTwoAnalog, "Paddle 2 Analog", "" },
{ Event::PaddleTwoIncrease, "Paddle 2 Turn Left", "" },
{ Event::PaddleTwoDecrease, "Paddle 2 Turn Right", "" },
{ Event::PaddleTwoFire, "Paddle 2 Fire", "" },
{ Event::RightPaddleAAnalog, "Right Paddle A Analog", "" },
{ Event::RightPaddleAIncrease, "Right Paddle A Turn Left", "" },
{ Event::RightPaddleADecrease, "Right Paddle A Turn Right", "" },
{ Event::RightPaddleAFire, "Right Paddle A Fire", "" },
{ Event::PaddleThreeAnalog, "Paddle 3 Analog", "" },
{ Event::PaddleThreeIncrease, "Paddle 3 Turn Left", "" },
{ Event::PaddleThreeDecrease, "Paddle 3 Turn Right", "" },
{ Event::PaddleThreeFire, "Paddle 3 Fire", "" },
{ Event::RightPaddleBAnalog, "Right Paddle B Analog", "" },
{ Event::RightPaddleBIncrease, "Right Paddle B Turn Left", "" },
{ Event::RightPaddleBDecrease, "Right Paddle B Turn Right", "" },
{ Event::RightPaddleBFire, "Right Paddle B Fire", "" },
{ Event::PaddleFourFire, "Paddle 4 Fire", "" },
{ Event::PaddleFiveFire, "Paddle 5 Fire", "" },
{ Event::PaddleSixFire, "Paddle 6 Fire", "" },
{ Event::PaddleSevenFire, "Paddle 7 Fire", "" },
{ Event::QTPaddle3AFire, "QuadTari Paddle 3A Fire", "" },
{ Event::QTPaddle3BFire, "QuadTari Paddle 3B Fire", "" },
{ Event::QTPaddle4AFire, "QuadTari Paddle 4A Fire", "" },
{ Event::QTPaddle4BFire, "QuadTari Paddle 4B Fire", "" },
{ Event::KeyboardZero1, "P0 Keyboard 1", "" },
{ Event::KeyboardZero2, "P0 Keyboard 2", "" },
{ Event::KeyboardZero3, "P0 Keyboard 3", "" },
{ Event::KeyboardZero4, "P0 Keyboard 4", "" },
{ Event::KeyboardZero5, "P0 Keyboard 5", "" },
{ Event::KeyboardZero6, "P0 Keyboard 6", "" },
{ Event::KeyboardZero7, "P0 Keyboard 7", "" },
{ Event::KeyboardZero8, "P0 Keyboard 8", "" },
{ Event::KeyboardZero9, "P0 Keyboard 9", "" },
{ Event::KeyboardZeroStar, "P0 Keyboard *", "" },
{ Event::KeyboardZero0, "P0 Keyboard 0", "" },
{ Event::KeyboardZeroPound, "P0 Keyboard #", "" },
{ Event::LeftKeyboard1, "Left Keyboard 1", "" },
{ Event::LeftKeyboard2, "Left Keyboard 2", "" },
{ Event::LeftKeyboard3, "Left Keyboard 3", "" },
{ Event::LeftKeyboard4, "Left Keyboard 4", "" },
{ Event::LeftKeyboard5, "Left Keyboard 5", "" },
{ Event::LeftKeyboard6, "Left Keyboard 6", "" },
{ Event::LeftKeyboard7, "Left Keyboard 7", "" },
{ Event::LeftKeyboard8, "Left Keyboard 8", "" },
{ Event::LeftKeyboard9, "Left Keyboard 9", "" },
{ Event::LeftKeyboardStar, "Left Keyboard *", "" },
{ Event::LeftKeyboard0, "Left Keyboard 0", "" },
{ Event::LeftKeyboardPound, "Left Keyboard #", "" },
{ Event::KeyboardOne1, "P1 Keyboard 1", "" },
{ Event::KeyboardOne2, "P1 Keyboard 2", "" },
{ Event::KeyboardOne3, "P1 Keyboard 3", "" },
{ Event::KeyboardOne4, "P1 Keyboard 4", "" },
{ Event::KeyboardOne5, "P1 Keyboard 5", "" },
{ Event::KeyboardOne6, "P1 Keyboard 6", "" },
{ Event::KeyboardOne7, "P1 Keyboard 7", "" },
{ Event::KeyboardOne8, "P1 Keyboard 8", "" },
{ Event::KeyboardOne9, "P1 Keyboard 9", "" },
{ Event::KeyboardOneStar, "P1 Keyboard *", "" },
{ Event::KeyboardOne0, "P1 Keyboard 0", "" },
{ Event::KeyboardOnePound, "P1 Keyboard #", "" },
{ Event::RightKeyboard1, "Right Keyboard 1", "" },
{ Event::RightKeyboard2, "Right Keyboard 2", "" },
{ Event::RightKeyboard3, "Right Keyboard 3", "" },
{ Event::RightKeyboard4, "Right Keyboard 4", "" },
{ Event::RightKeyboard5, "Right Keyboard 5", "" },
{ Event::RightKeyboard6, "Right Keyboard 6", "" },
{ Event::RightKeyboard7, "Right Keyboard 7", "" },
{ Event::RightKeyboard8, "Right Keyboard 8", "" },
{ Event::RightKeyboard9, "Right Keyboard 9", "" },
{ Event::RightKeyboardStar, "Right Keyboard *", "" },
{ Event::RightKeyboard0, "Right Keyboard 0", "" },
{ Event::RightKeyboardPound, "Right Keyboard #", "" },
// Video
{ Event::ToggleFullScreen, "Toggle fullscreen", "" },
#ifdef ADAPTABLE_REFRESH_SUPPORT
@ -3234,7 +3286,7 @@ EventHandler::EmulActionList EventHandler::ourEmulActionList = { {
{ Event::DecreaseDrivingSense, "Decrease driving sensitivity", "" },
{ Event::IncreaseDrivingSense, "Increase driving sensitivity", "" },
{ Event::PreviousCursorVisbility, "Select prev. cursor visibility mode", "" },
{ Event::NextCursorVisbility, "Select next cursor visibility mode" ,"" },
{ Event::NextCursorVisbility, "Select next cursor visibility mode", "" },
{ Event::ToggleGrabMouse, "Toggle grab mouse", "" },
{ Event::PreviousLeftPort, "Select previous left controller", "" },
{ Event::NextLeftPort, "Select next left controller", "" },
@ -3363,35 +3415,35 @@ const Event::EventSet EventHandler::ConsoleEvents = {
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const Event::EventSet EventHandler::JoystickEvents = {
Event::JoystickZeroUp, Event::JoystickZeroDown, Event::JoystickZeroLeft, Event::JoystickZeroRight,
Event::JoystickZeroFire, Event::JoystickZeroFire5, Event::JoystickZeroFire9,
Event::JoystickOneUp, Event::JoystickOneDown, Event::JoystickOneLeft, Event::JoystickOneRight,
Event::JoystickOneFire, Event::JoystickOneFire5, Event::JoystickOneFire9,
Event::JoystickTwoUp, Event::JoystickTwoDown, Event::JoystickTwoLeft, Event::JoystickTwoRight,
Event::JoystickTwoFire,
Event::JoystickThreeUp, Event::JoystickThreeDown, Event::JoystickThreeLeft, Event::JoystickThreeRight,
Event::JoystickThreeFire,
Event::LeftJoystickUp, Event::LeftJoystickDown, Event::LeftJoystickLeft, Event::LeftJoystickRight,
Event::LeftJoystickFire, Event::LeftJoystickFire5, Event::LeftJoystickFire9,
Event::RightJoystickUp, Event::RightJoystickDown, Event::RightJoystickLeft, Event::RightJoystickRight,
Event::RightJoystickFire, Event::RightJoystickFire5, Event::RightJoystickFire9,
Event::QTJoystickThreeUp, Event::QTJoystickThreeDown, Event::QTJoystickThreeLeft, Event::QTJoystickThreeRight,
Event::QTJoystickThreeFire,
Event::QTJoystickFourUp, Event::QTJoystickFourDown, Event::QTJoystickFourLeft, Event::QTJoystickFourRight,
Event::QTJoystickFourFire,
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const Event::EventSet EventHandler::PaddlesEvents = {
Event::PaddleZeroDecrease, Event::PaddleZeroIncrease, Event::PaddleZeroAnalog, Event::PaddleZeroFire,
Event::PaddleOneDecrease, Event::PaddleOneIncrease, Event::PaddleOneAnalog, Event::PaddleOneFire,
Event::PaddleTwoDecrease, Event::PaddleTwoIncrease, Event::PaddleTwoAnalog, Event::PaddleTwoFire,
Event::PaddleThreeDecrease, Event::PaddleThreeIncrease, Event::PaddleThreeAnalog, Event::PaddleThreeFire,
Event::PaddleFourFire, Event::PaddleFiveFire,Event::PaddleSixFire,Event::PaddleSevenFire,
Event::LeftPaddleADecrease, Event::LeftPaddleAIncrease, Event::LeftPaddleAAnalog, Event::LeftPaddleAFire,
Event::LeftPaddleBDecrease, Event::LeftPaddleBIncrease, Event::LeftPaddleBAnalog, Event::LeftPaddleBFire,
Event::RightPaddleADecrease, Event::RightPaddleAIncrease, Event::RightPaddleAAnalog, Event::RightPaddleAFire,
Event::RightPaddleBDecrease, Event::RightPaddleBIncrease, Event::RightPaddleBAnalog, Event::RightPaddleBFire,
Event::QTPaddle3AFire, Event::QTPaddle3BFire,Event::QTPaddle4AFire,Event::QTPaddle4BFire,
};
const Event::EventSet EventHandler::KeyboardEvents = {
Event::KeyboardZero1, Event::KeyboardZero2, Event::KeyboardZero3,
Event::KeyboardZero4, Event::KeyboardZero5, Event::KeyboardZero6,
Event::KeyboardZero7, Event::KeyboardZero8, Event::KeyboardZero9,
Event::KeyboardZeroStar, Event::KeyboardZero0, Event::KeyboardZeroPound,
Event::LeftKeyboard1, Event::LeftKeyboard2, Event::LeftKeyboard3,
Event::LeftKeyboard4, Event::LeftKeyboard5, Event::LeftKeyboard6,
Event::LeftKeyboard7, Event::LeftKeyboard8, Event::LeftKeyboard9,
Event::LeftKeyboardStar, Event::LeftKeyboard0, Event::LeftKeyboardPound,
Event::KeyboardOne1, Event::KeyboardOne2, Event::KeyboardOne3,
Event::KeyboardOne4, Event::KeyboardOne5, Event::KeyboardOne6,
Event::KeyboardOne7, Event::KeyboardOne8, Event::KeyboardOne9,
Event::KeyboardOneStar, Event::KeyboardOne0, Event::KeyboardOnePound,
Event::RightKeyboard1, Event::RightKeyboard2, Event::RightKeyboard3,
Event::RightKeyboard4, Event::RightKeyboard5, Event::RightKeyboard6,
Event::RightKeyboard7, Event::RightKeyboard8, Event::RightKeyboard9,
Event::RightKeyboardStar, Event::RightKeyboard0, Event::RightKeyboardPound,
};
const Event::EventSet EventHandler::DevicesEvents = {
@ -3436,8 +3488,3 @@ const Event::EventSet EventHandler::DebugEvents = {
Event::ToggleColorLoss,
Event::ToggleJitter,
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const Event::EventSet EventHandler::EditEvents = {
};

View File

@ -175,7 +175,7 @@ class EventHandler
bool frying() const { return myFryingFlag; }
StringList getActionList(Event::Group group) const;
VariantList getComboList(EventMode mode) const;
VariantList getComboList() const;
/** Used to access the list of events assigned to a specific combo event. */
StringList getComboListForEvent(Event::Type event) const;
@ -296,11 +296,6 @@ class EventHandler
*/
void setDefaultMapping(Event::Type event, EventMode mode);
/**
Sets the combo event mappings to those in the 'combomap' setting
*/
void setComboMap();
/**
Joystick emulates 'impossible' directions (ie, left & right
at the same time).
@ -378,6 +373,11 @@ class EventHandler
bool myQwertz{false};
#endif
/**
Sets the combo event mappings to those in the 'combomap' setting
*/
void setComboMap();
/**
Methods which are called by derived classes to handle specific types
of input.
@ -548,7 +548,6 @@ class EventHandler
static const Event::EventSet DevicesEvents;
static const Event::EventSet ComboEvents;
static const Event::EventSet DebugEvents;
static const Event::EventSet EditEvents;
/**
The following methods take care of assigning action mappings.
@ -556,6 +555,7 @@ class EventHandler
void setActionMappings(EventMode mode);
void setDefaultKeymap(Event::Type, EventMode mode);
void setDefaultJoymap(Event::Type, EventMode mode);
static nlohmann::json convertLegacyComboMapping(string list);
void saveComboMapping();
StringList getActionList(EventMode mode) const;

View File

@ -80,10 +80,11 @@ enum class EventMode {
kMenuMode, // mapping used for dialogs
kJoystickMode, // 4 extra modes for mapping controller keys separately for emulation mode
kPaddlesMode,
kKeypadMode,
kKeyboardMode,
kCompuMateMode, // cannot be remapped
kCommonMode, // mapping common between controllers
kEditMode, // mapping used in editable widgets
kPromptMode, // extra mappings used in debugger's prompt widget
kNumModes
};

View File

@ -347,9 +347,10 @@ bool FBSurface::isWhiteSpace(const char s) const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int FBSurface::drawString(const GUI::Font& font, const string& s,
int x, int y, int w, int h,
ColorId color, TextAlign align,
int deltax, bool useEllipsis, ColorId shadowColor)
int x, int y, int w, int h,
ColorId color, TextAlign align,
int deltax, bool useEllipsis, ColorId shadowColor,
size_t linkStart, size_t linkLen, bool underline)
{
int lines = 0;
@ -357,14 +358,17 @@ int FBSurface::drawString(const GUI::Font& font, const string& s,
string inStr = s;
// draw multiline string
//while (font.getStringWidth(inStr) > w && h >= font.getFontHeight() * 2)
while(inStr.length() && h >= font.getFontHeight() * 2)
{
// String is too wide.
string leftStr, rightStr;
splitString(font, inStr, w, leftStr, rightStr);
drawString(font, leftStr, x, y, w, color, align, deltax, false, shadowColor);
drawString(font, leftStr, x, y, w, color, align, deltax, false, shadowColor,
linkStart, linkLen, underline);
if(linkStart != string::npos)
linkStart = std::max(0, int(linkStart - leftStr.length()));
h -= font.getFontHeight();
y += font.getFontHeight();
inStr = rightStr;
@ -372,7 +376,8 @@ int FBSurface::drawString(const GUI::Font& font, const string& s,
}
if(inStr.length())
{
drawString(font, inStr, x, y, w, color, align, deltax, useEllipsis, shadowColor);
drawString(font, inStr, x, y, w, color, align, deltax, useEllipsis, shadowColor,
linkStart, linkLen, underline);
lines++;
}
#endif
@ -383,7 +388,8 @@ int FBSurface::drawString(const GUI::Font& font, const string& s,
void FBSurface::drawString(const GUI::Font& font, const string& s,
int x, int y, int w,
ColorId color, TextAlign align,
int deltax, bool useEllipsis, ColorId shadowColor)
int deltax, bool useEllipsis, ColorId shadowColor,
size_t linkStart, size_t linkLen, bool underline)
{
#ifdef GUI_SUPPORT
const string ELLIPSIS = "\x1d"; // "..."
@ -424,16 +430,30 @@ void FBSurface::drawString(const GUI::Font& font, const string& s,
x = x + w - width;
x += deltax;
int x0 = x, x1 = 0;
for(i = 0; i < str.size(); ++i)
{
w = font.getCharWidth(str[i]);
if(x+w > rightX)
if(x + w > rightX)
break;
if(x >= leftX)
drawChar(font, str[i], x, y, color, shadowColor);
{
if(i == linkStart)
x0 = x;
else if(i < linkStart + linkLen)
x1 = x + w;
drawChar(font, str[i], x, y,
(i >= linkStart && i < linkStart + linkLen) ? kTextColorLink : color,
shadowColor);
}
x += w;
}
if(underline && x1 > 0)
hLine(x0, y + font.getFontHeight() - 1, x1, kTextColorLink);
#endif
}

View File

@ -211,41 +211,52 @@ class FBSurface
/**
This method should be called to draw the specified string.
@param font The font to draw the string with
@param s The string to draw
@param x The x coordinate
@param y The y coordinate
@param w The width of the string area
@param h The height of the string area (for multi line strings)
@param color The color of the text
@param align The alignment of the text in the string width area
@param deltax FIXME
@param font The font to draw the string with
@param s The string to draw
@param x The x coordinate
@param y The y coordinate
@param w The width of the string area
@param h The height of the string area (for multi line strings)
@param color The color of the text
@param align The alignment of the text in the string width area
@param deltax The horizontal scroll offset
@param useEllipsis Whether to use '...' when the string is too long
@param shadowColor The shadow color of the text
@param linkStart The start position of a link in drawn string
@param linkLen The length of a link in drawn string
@param underline Whether to underline the link
@return Number of lines drawn
*/
virtual int drawString(
const GUI::Font& font, const string& s, int x, int y, int w, int h,
ColorId color, TextAlign align = TextAlign::Left,
int deltax = 0, bool useEllipsis = true, ColorId shadowColor = kNone);
virtual int drawString(const GUI::Font& font, const string& s, int x, int y, int w, int h,
ColorId color, TextAlign align = TextAlign::Left,
int deltax = 0, bool useEllipsis = true, ColorId shadowColor = kNone,
size_t linkStart = string::npos, size_t linkLen = string::npos,
bool underline = false);
/**
This method should be called to draw the specified string.
@param font The font to draw the string with
@param s The string to draw
@param x The x coordinate
@param y The y coordinate
@param w The width of the string area
@param color The color of the text
@param align The alignment of the text in the string width area
@param deltax FIXME
@param font The font to draw the string with
@param s The string to draw
@param x The x coordinate
@param y The y coordinate
@param w The width of the string area
@param color The color of the text
@param align The alignment of the text in the string width area
@param deltax The horizontal scroll offset
@param useEllipsis Whether to use '...' when the string is too long
@param shadowColor The shadow color of the text
@param linkStart The start position of a link in drawn string
@param linkLen The length of a link in drawn string
@param underline Whether to underline the link
*/
virtual void drawString(
const GUI::Font& font, const string& s, int x, int y, int w,
ColorId color, TextAlign align = TextAlign::Left,
int deltax = 0, bool useEllipsis = true, ColorId shadowColor = kNone);
virtual void drawString(const GUI::Font& font, const string& s, int x, int y, int w,
ColorId color, TextAlign align = TextAlign::Left,
int deltax = 0, bool useEllipsis = true, ColorId shadowColor = kNone,
size_t linkStart = string::npos, size_t linkLen = string::npos,
bool underline = false);
/**
Splits a given string to a given width considering whitespaces.

View File

@ -67,6 +67,7 @@ FrameBuffer::FrameBuffer(OSystem& osystem)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FrameBuffer::~FrameBuffer()
{
cerr << "~FrameBuffer()\n";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -885,63 +886,28 @@ void FrameBuffer::setPauseDelay()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unique_ptr<FBSurface> FrameBuffer::allocateSurface(
shared_ptr<FBSurface> FrameBuffer::allocateSurface(
int w, int h, ScalingInterpolation inter, const uInt32* data)
{
return myBackend->createSurface(w, h, inter, data);
mySurfaceList.push_back(myBackend->createSurface(w, h, inter, data));
return mySurfaceList.back();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBuffer::deallocateSurface(shared_ptr<FBSurface> surface)
{
if(surface)
{
cerr << "deallocateSurface: " << surface << endl;
mySurfaceList.remove(surface);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBuffer::resetSurfaces()
{
switch(myOSystem.eventHandler().state())
{
case EventHandlerState::NONE:
case EventHandlerState::EMULATION:
case EventHandlerState::PAUSE:
case EventHandlerState::PLAYBACK:
#ifdef GUI_SUPPORT
myMsg.surface->reload();
myStatsMsg.surface->reload();
#endif
myTIASurface->resetSurfaces();
break;
#ifdef GUI_SUPPORT
case EventHandlerState::OPTIONSMENU:
myOSystem.menu().resetSurfaces();
break;
case EventHandlerState::CMDMENU:
myOSystem.commandMenu().resetSurfaces();
break;
case EventHandlerState::HIGHSCORESMENU:
myOSystem.highscoresMenu().resetSurfaces();
break;
case EventHandlerState::MESSAGEMENU:
myOSystem.messageMenu().resetSurfaces();
break;
case EventHandlerState::TIMEMACHINE:
myOSystem.timeMachine().resetSurfaces();
break;
case EventHandlerState::LAUNCHER:
myOSystem.launcher().resetSurfaces();
break;
#endif
#ifdef DEBUGGER_SUPPORT
case EventHandlerState::DEBUGGER:
myOSystem.debugger().resetSurfaces();
break;
#endif
default:
break;
}
for(auto& surface: mySurfaceList)
surface->reload();
update(UpdateMode::REDRAW); // force full update
}
@ -1419,6 +1385,7 @@ void FrameBuffer::toggleGrabMouse(bool toggle)
kTextColorHi Highlighted text color
kTextColorEm Emphasized text color
kTextColorInv Color for selected text
kTextColorLink Color for links
*** UI elements (dialog and widgets) ***
kDlgColor Dialog background
kWidColor Widget background
@ -1454,7 +1421,7 @@ void FrameBuffer::toggleGrabMouse(bool toggle)
*/
UIPaletteArray FrameBuffer::ourStandardUIPalette = {
{ 0x686868, 0x000000, 0xa38c61, 0xdccfa5, 0x404040, // base
0x000000, 0xac3410, 0x9f0000, 0xf0f0cf, // text
0x000000, 0xac3410, 0x9f0000, 0xf0f0cf, 0xac3410, // text
0xc9af7c, 0xf0f0cf, 0xd55941, 0xc80000, // UI elements
0xac3410, 0xd55941, 0x686868, 0xdccfa5, 0xf0f0cf, 0xf0f0cf, // buttons
0xac3410, // checkbox
@ -1467,7 +1434,7 @@ UIPaletteArray FrameBuffer::ourStandardUIPalette = {
UIPaletteArray FrameBuffer::ourClassicUIPalette = {
{ 0x686868, 0x000000, 0x404040, 0x404040, 0x404040, // base
0x20a020, 0x00ff00, 0xc80000, 0x000000, // text
0x20a020, 0x00ff00, 0xc80000, 0x000000, 0x00ff00, // text
0x000000, 0x000000, 0x00ff00, 0xc80000, // UI elements
0x000000, 0x000000, 0x686868, 0x00ff00, 0x20a020, 0x00ff00, // buttons
0x20a020, // checkbox
@ -1480,7 +1447,7 @@ UIPaletteArray FrameBuffer::ourClassicUIPalette = {
UIPaletteArray FrameBuffer::ourLightUIPalette = {
{ 0x808080, 0x000000, 0xc0c0c0, 0xe1e1e1, 0x333333, // base
0x000000, 0xBDDEF9, 0x0078d7, 0x000000, // text
0x000000, 0xBDDEF9, 0x0078d7, 0x000000, 0x005aa1, // text
0xf0f0f0, 0xffffff, 0x0078d7, 0x0f0f0f, // UI elements
0xe1e1e1, 0xe5f1fb, 0x808080, 0x0078d7, 0x000000, 0x000000, // buttons
0x333333, // checkbox
@ -1493,7 +1460,7 @@ UIPaletteArray FrameBuffer::ourLightUIPalette = {
UIPaletteArray FrameBuffer::ourDarkUIPalette = {
{ 0x646464, 0xc0c0c0, 0x3c3c3c, 0x282828, 0x989898, // base
0xc0c0c0, 0x1567a5, 0x0059a3, 0xc0c0c0, // text
0xc0c0c0, 0x1567a5, 0x0064b7, 0xc0c0c0, 0x1d92e0, // text
0x202020, 0x000000, 0x0059a3, 0xb0b0b0, // UI elements
0x282828, 0x00467f, 0x646464, 0x0059a3, 0xc0c0c0, 0xc0c0c0, // buttons
0x989898, // checkbox

View File

@ -18,7 +18,7 @@
#ifndef FRAMEBUFFER_HXX
#define FRAMEBUFFER_HXX
#include <map>
#include <list>
class OSystem;
class Console;
@ -158,13 +158,21 @@ class FrameBuffer
@return A pointer to a valid surface object, or nullptr
*/
unique_ptr<FBSurface> allocateSurface(
shared_ptr<FBSurface> allocateSurface(
int w,
int h,
ScalingInterpolation inter = ScalingInterpolation::none,
const uInt32* data = nullptr
);
/**
Deallocate a previously allocated surface. If no such surface exists,
this method does nothing.
@param surface The surface to remove/deallocate
*/
void deallocateSurface(shared_ptr<FBSurface> surface);
/**
Set up the TIA/emulation palette. Due to the way the palette is stored,
a call to this method implicitly calls setUIPalette() too.
@ -521,7 +529,7 @@ class FrameBuffer
int x{0}, y{0}, w{0}, h{0};
MessagePosition position{MessagePosition::BottomCenter};
ColorId color{kNone};
unique_ptr<FBSurface> surface;
shared_ptr<FBSurface> surface;
bool enabled{false};
bool dirty{false};
bool showGauge{false};
@ -540,6 +548,9 @@ class FrameBuffer
// Minimum TIA zoom level that can be used for this framebuffer
float myTIAMinZoom{2.F};
// Holds a reference to all the surfaces that have been created
std::list<shared_ptr<FBSurface>> mySurfaceList;
// Maximum message width [chars]
static constexpr int MESSAGE_WIDTH = 56;
// Maximum gauge bar width [chars]

View File

@ -77,39 +77,40 @@ static constexpr ColorId
kTextColorHi = 262,
kTextColorEm = 263,
kTextColorInv = 264,
kTextColorLink = 265,
// *** UI elements(dialog and widgets) ***
kDlgColor = 265,
kWidColor = 266,
kWidColorHi = 267,
kWidFrameColor = 268,
kDlgColor = 266,
kWidColor = 267,
kWidColorHi = 268,
kWidFrameColor = 269,
// *** Button colors ***
kBtnColor = 269,
kBtnColorHi = 270,
kBtnBorderColor = 271,
kBtnBorderColorHi = 272,
kBtnTextColor = 273,
kBtnTextColorHi = 274,
kBtnColor = 270,
kBtnColorHi = 271,
kBtnBorderColor = 272,
kBtnBorderColorHi = 273,
kBtnTextColor = 274,
kBtnTextColorHi = 275,
// *** Checkbox colors ***
kCheckColor = 275,
kCheckColor = 276,
// *** Scrollbar colors ***
kScrollColor = 276,
kScrollColorHi = 277,
kScrollColor = 277,
kScrollColorHi = 278,
// *** Debugger colors ***
kDbgChangedColor = 278,
kDbgChangedTextColor = 279,
kDbgColorHi = 280,
kDbgColorRed = 281, // Note: this must be < 0x11e (286)! (see PromptWidget::putcharIntern)
kDbgChangedColor = 279,
kDbgChangedTextColor = 280,
kDbgColorHi = 281,
kDbgColorRed = 282, // Note: this must be < 0x11e (286)! (see PromptWidget::putcharIntern)
// *** Slider colors ***
kSliderColor = 282,
kSliderColorHi = 283,
kSliderBGColor = 284,
kSliderBGColorHi = 285,
kSliderBGColorLo = 286,
kSliderColor = 283,
kSliderColorHi = 284,
kSliderBGColor = 285,
kSliderBGColorHi = 286,
kSliderBGColorLo = 287,
// *** Other colors ***
kColorInfo = 287,
kColorTitleBar = 288,
kColorTitleText = 289,
kNumColors = 290,
kColorInfo = 288,
kColorTitleBar = 289,
kColorTitleText = 290,
kNumColors = 291,
kNone = 0 // placeholder to represent default/no color
;

View File

@ -22,11 +22,12 @@ Genesis::Genesis(Jack jack, const Event& event, const System& system)
: Joystick(jack, event, system, Controller::Type::Genesis)
{
if(myJack == Jack::Left)
myButtonCEvent = Event::JoystickZeroFire5;
myButtonCEvent = Event::LeftJoystickFire5;
else
myButtonCEvent = Event::JoystickOneFire5;
myButtonCEvent = Event::RightJoystickFire5;
setPin(AnalogPin::Five, AnalogReadout::connectToVcc());
setPin(AnalogPin::Nine, AnalogReadout::connectToVcc());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -32,38 +32,38 @@ Joystick::Joystick(Jack jack, const Event& event, const System& system,
{
if(!altmap)
{
myUpEvent = Event::JoystickZeroUp;
myDownEvent = Event::JoystickZeroDown;
myLeftEvent = Event::JoystickZeroLeft;
myRightEvent = Event::JoystickZeroRight;
myFireEvent = Event::JoystickZeroFire;
myUpEvent = Event::LeftJoystickUp;
myDownEvent = Event::LeftJoystickDown;
myLeftEvent = Event::LeftJoystickLeft;
myRightEvent = Event::LeftJoystickRight;
myFireEvent = Event::LeftJoystickFire;
}
else
{
myUpEvent = Event::JoystickTwoUp;
myDownEvent = Event::JoystickTwoDown;
myLeftEvent = Event::JoystickTwoLeft;
myRightEvent = Event::JoystickTwoRight;
myFireEvent = Event::JoystickTwoFire;
myUpEvent = Event::QTJoystickThreeUp;
myDownEvent = Event::QTJoystickThreeDown;
myLeftEvent = Event::QTJoystickThreeLeft;
myRightEvent = Event::QTJoystickThreeRight;
myFireEvent = Event::QTJoystickThreeFire;
}
}
else
{
if(!altmap)
{
myUpEvent = Event::JoystickOneUp;
myDownEvent = Event::JoystickOneDown;
myLeftEvent = Event::JoystickOneLeft;
myRightEvent = Event::JoystickOneRight;
myFireEvent = Event::JoystickOneFire;
myUpEvent = Event::RightJoystickUp;
myDownEvent = Event::RightJoystickDown;
myLeftEvent = Event::RightJoystickLeft;
myRightEvent = Event::RightJoystickRight;
myFireEvent = Event::RightJoystickFire;
}
else
{
myUpEvent = Event::JoystickThreeUp;
myDownEvent = Event::JoystickThreeDown;
myLeftEvent = Event::JoystickThreeLeft;
myRightEvent = Event::JoystickThreeRight;
myFireEvent = Event::JoystickThreeFire;
myUpEvent = Event::QTJoystickFourUp;
myDownEvent = Event::QTJoystickFourDown;
myLeftEvent = Event::QTJoystickFourLeft;
myRightEvent = Event::QTJoystickFourRight;
myFireEvent = Event::QTJoystickFourFire;
}
}
}

View File

@ -24,33 +24,33 @@ Keyboard::Keyboard(Jack jack, const Event& event, const System& system)
{
if(myJack == Jack::Left)
{
myOneEvent = Event::KeyboardZero1;
myTwoEvent = Event::KeyboardZero2;
myThreeEvent = Event::KeyboardZero3;
myFourEvent = Event::KeyboardZero4;
myFiveEvent = Event::KeyboardZero5;
mySixEvent = Event::KeyboardZero6;
mySevenEvent = Event::KeyboardZero7;
myEightEvent = Event::KeyboardZero8;
myNineEvent = Event::KeyboardZero9;
myStarEvent = Event::KeyboardZeroStar;
myZeroEvent = Event::KeyboardZero0;
myPoundEvent = Event::KeyboardZeroPound;
myOneEvent = Event::LeftKeyboard1;
myTwoEvent = Event::LeftKeyboard2;
myThreeEvent = Event::LeftKeyboard3;
myFourEvent = Event::LeftKeyboard4;
myFiveEvent = Event::LeftKeyboard5;
mySixEvent = Event::LeftKeyboard6;
mySevenEvent = Event::LeftKeyboard7;
myEightEvent = Event::LeftKeyboard8;
myNineEvent = Event::LeftKeyboard9;
myStarEvent = Event::LeftKeyboardStar;
myZeroEvent = Event::LeftKeyboard0;
myPoundEvent = Event::LeftKeyboardPound;
}
else
{
myOneEvent = Event::KeyboardOne1;
myTwoEvent = Event::KeyboardOne2;
myThreeEvent = Event::KeyboardOne3;
myFourEvent = Event::KeyboardOne4;
myFiveEvent = Event::KeyboardOne5;
mySixEvent = Event::KeyboardOne6;
mySevenEvent = Event::KeyboardOne7;
myEightEvent = Event::KeyboardOne8;
myNineEvent = Event::KeyboardOne9;
myStarEvent = Event::KeyboardOneStar;
myZeroEvent = Event::KeyboardOne0;
myPoundEvent = Event::KeyboardOnePound;
myOneEvent = Event::RightKeyboard1;
myTwoEvent = Event::RightKeyboard2;
myThreeEvent = Event::RightKeyboard3;
myFourEvent = Event::RightKeyboard4;
myFiveEvent = Event::RightKeyboard5;
mySixEvent = Event::RightKeyboard6;
mySevenEvent = Event::RightKeyboard7;
myEightEvent = Event::RightKeyboard8;
myNineEvent = Event::RightKeyboard9;
myStarEvent = Event::RightKeyboardStar;
myZeroEvent = Event::RightKeyboard0;
myPoundEvent = Event::RightKeyboardPound;
}
}

View File

@ -52,7 +52,7 @@ void KidVid::update()
myTape = 0; // rewind Kid Vid tape
closeSampleFile();
}
if(myEvent.get(Event::KeyboardOne1))
if(myEvent.get(Event::RightKeyboard1))
{
myTape = 2;
myIdx = myGame == KVBBEARS ? KVBLOCKBITS : 0;
@ -61,7 +61,7 @@ void KidVid::update()
openSampleFile();
//cerr << "myTape = " << myTape << endl;
}
else if(myEvent.get(Event::KeyboardOne2))
else if(myEvent.get(Event::RightKeyboard2))
{
myTape = 3;
myIdx = myGame == KVBBEARS ? KVBLOCKBITS : 0;
@ -70,7 +70,7 @@ void KidVid::update()
openSampleFile();
//cerr << "myTape = " << myTape << endl;
}
else if(myEvent.get(Event::KeyboardOne3))
else if(myEvent.get(Event::RightKeyboard3))
{
if(myGame == KVBBEARS) /* Berenstain Bears ? */
{

View File

@ -116,7 +116,7 @@ bool Lightgun::read(DigitalPin pin)
void Lightgun::update()
{
// Digital events (from keyboard or joystick hats & buttons)
bool firePressed = myEvent.get(Event::JoystickZeroFire) != 0;
bool firePressed = myEvent.get(Event::LeftJoystickFire) != 0;
// We allow left and right mouse buttons for fire button
firePressed = firePressed

View File

@ -93,6 +93,7 @@ void M6502::reset()
myGhostReadsTrap = mySettings.getBool("dbg.ghostreadstrap");
myReadFromWritePortBreak = devSettings ? mySettings.getBool("dev.rwportbreak") : false;
myWriteToReadPortBreak = devSettings ? mySettings.getBool("dev.wrportbreak") : false;
myLogBreaks = mySettings.getBool("dbg.logbreaks");
myLastBreakCycle = ULLONG_MAX;
}
@ -162,7 +163,7 @@ inline void M6502::poke(uInt16 address, uInt8 value, Device::AccessFlags flags)
{
myJustHitWriteTrapFlag = true;
stringstream msg;
msg << "WTrap[" << Common::Base::HEX2 << cond << "]" << (myTrapCondNames[cond].empty() ? ": " : "If: {" + myTrapCondNames[cond] + "} ");
msg << "WTrap[" << Common::Base::HEX2 << cond << "]" << (myTrapCondNames[cond].empty() ? ":" : "If: {" + myTrapCondNames[cond] + "}");
myHitTrapInfo.message = msg.str();
myHitTrapInfo.address = address;
}
@ -243,10 +244,16 @@ inline void M6502::_execute(uInt64 cycles, DispatchResult& result)
myJustHitReadTrapFlag = myJustHitWriteTrapFlag = false;
myLastBreakCycle = mySystem->cycles();
result.setDebugger(currentCycles, myHitTrapInfo.message,
read ? "Read trap" : "Write trap",
myHitTrapInfo.address, read);
return;
if(myLogBreaks)
myDebugger->log(myHitTrapInfo.message);
else
{
result.setDebugger(currentCycles, myHitTrapInfo.message + " ",
read ? "Read trap" : "Write trap",
myHitTrapInfo.address, read);
return;
}
}
if(myBreakPoints.isInitialized())
@ -260,15 +267,21 @@ inline void M6502::_execute(uInt64 cycles, DispatchResult& result)
if(myBreakPoints.get(PC, bank) & BreakpointMap::ONE_SHOT)
{
myBreakPoints.erase(PC, bank);
return;
}
else
{
ostringstream msg;
if(myLogBreaks)
myDebugger->log("BP:");
else
{
ostringstream msg;
msg << "BP: $" << Common::Base::HEX4 << PC << ", bank #" << std::dec << int(bank);
result.setDebugger(currentCycles, msg.str(), "Breakpoint");
msg << "BP: $" << Common::Base::HEX4 << PC << ", bank #" << std::dec << int(bank);
result.setDebugger(currentCycles, msg.str(), "Breakpoint");
return;
}
}
return;
}
}
@ -277,11 +290,19 @@ inline void M6502::_execute(uInt64 cycles, DispatchResult& result)
{
ostringstream msg;
msg << "CBP[" << Common::Base::HEX2 << cond << "]: " << myCondBreakNames[cond];
myLastBreakCycle = mySystem->cycles();
result.setDebugger(currentCycles, msg.str(), "Conditional breakpoint");
return;
if(myLogBreaks)
{
msg << "CBP[" << Common::Base::HEX2 << cond << "]:";
myDebugger->log(msg.str());
}
else
{
msg << "CBP[" << Common::Base::HEX2 << cond << "]: " << myCondBreakNames[cond];
result.setDebugger(currentCycles, msg.str(), "Conditional breakpoint");
return;
}
}
}

View File

@ -255,6 +255,8 @@ class M6502 : public Serializable
void setGhostReadsTrap(bool enable) { myGhostReadsTrap = enable; }
void setReadFromWritePortBreak(bool enable) { myReadFromWritePortBreak = enable; }
void setWriteToReadPortBreak(bool enable) { myWriteToReadPortBreak = enable; }
void setLogBreaks(bool enable) { myLogBreaks = enable; }
bool getLogBreaks() { return myLogBreaks; }
#endif // DEBUGGER_SUPPORT
private:
@ -469,6 +471,7 @@ class M6502 : public Serializable
bool myReadFromWritePortBreak{false}; // trap on reads from write ports
bool myWriteToReadPortBreak{false}; // trap on writes to read ports
bool myStepStateByInstruction{false};
bool myLogBreaks{false}; // log breaks/taps and continue emulation
private:
// Following constructors and assignment operators not supported

View File

@ -111,6 +111,7 @@ OSystem::OSystem()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
OSystem::~OSystem()
{
cerr << "~OSystem()\n";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -103,6 +103,7 @@ class OSystem
@return The frame buffer
*/
FrameBuffer& frameBuffer() const { return *myFrameBuffer; }
bool hasFrameBuffer() const { return myFrameBuffer.get() != nullptr; }
/**
Get the sound object of the system.

View File

@ -49,65 +49,65 @@ Paddles::Paddles(Jack jack, const Event& event, const System& system,
{
if(!altmap)
{
// First paddle is 0, second is 1
myP0AxisValue = Event::PaddleZeroAnalog;
myP1AxisValue = Event::PaddleOneAnalog;
myP0FireEvent = Event::PaddleZeroFire;
myP1FireEvent = Event::PaddleOneFire;
// First paddle is left A, second is left B
myAAxisValue = Event::LeftPaddleAAnalog;
myBAxisValue = Event::LeftPaddleBAnalog;
myLeftAFireEvent = Event::LeftPaddleAFire;
myLeftBFireEvent = Event::LeftPaddleBFire;
// These can be affected by changes in axis orientation
myP0DecEvent = Event::PaddleZeroDecrease;
myP0IncEvent = Event::PaddleZeroIncrease;
myP1DecEvent = Event::PaddleOneDecrease;
myP1IncEvent = Event::PaddleOneIncrease;
myLeftADecEvent = Event::LeftPaddleADecrease;
myLeftAIncEvent = Event::LeftPaddleAIncrease;
myLeftBDecEvent = Event::LeftPaddleBDecrease;
myLeftBIncEvent = Event::LeftPaddleBIncrease;
}
else
{
// First paddle is 4, second is 5 (fire buttons only)
myP0FireEvent = Event::PaddleFourFire;
myP1FireEvent = Event::PaddleFiveFire;
// First paddle is QT 3A, second is QT 3B (fire buttons only)
myLeftAFireEvent = Event::QTPaddle3AFire;
myLeftBFireEvent = Event::QTPaddle3BFire;
myP0AxisValue = myP1AxisValue =
myP0DecEvent = myP0IncEvent =
myP1DecEvent = myP1IncEvent = Event::NoType;
myAAxisValue = myBAxisValue =
myLeftADecEvent = myLeftAIncEvent =
myLeftBDecEvent = myLeftBIncEvent = Event::NoType;
}
}
else // Jack is right port
{
if(!altmap)
{
// First paddle is 2, second is 3
myP0AxisValue = Event::PaddleTwoAnalog;
myP1AxisValue = Event::PaddleThreeAnalog;
myP0FireEvent = Event::PaddleTwoFire;
myP1FireEvent = Event::PaddleThreeFire;
// First paddle is right A, second is right B
myAAxisValue = Event::RightPaddleAAnalog;
myBAxisValue = Event::RightPaddleBAnalog;
myLeftAFireEvent = Event::RightPaddleAFire;
myLeftBFireEvent = Event::RightPaddleBFire;
// These can be affected by changes in axis orientation
myP0DecEvent = Event::PaddleTwoDecrease;
myP0IncEvent = Event::PaddleTwoIncrease;
myP1DecEvent = Event::PaddleThreeDecrease;
myP1IncEvent = Event::PaddleThreeIncrease;
myLeftADecEvent = Event::RightPaddleADecrease;
myLeftAIncEvent = Event::RightPaddleAIncrease;
myLeftBDecEvent = Event::RightPaddleBDecrease;
myLeftBIncEvent = Event::RightPaddleBIncrease;
}
else
{
// First paddle is 6, second is 7 (fire buttons only)
myP0FireEvent = Event::PaddleSixFire;
myP1FireEvent = Event::PaddleSevenFire;
// First paddle is QT 4A, second is QT 4B (fire buttons only)
myLeftAFireEvent = Event::QTPaddle4AFire;
myLeftBFireEvent = Event::QTPaddle4BFire;
myP0AxisValue = myP1AxisValue =
myP0DecEvent = myP0IncEvent =
myP1DecEvent = myP1IncEvent = Event::NoType;
myAAxisValue = myBAxisValue =
myLeftADecEvent = myLeftAIncEvent =
myLeftBDecEvent = myLeftBIncEvent = Event::NoType;
}
}
// Some games swap the paddles
if(swappaddle)
{
// First paddle is 1|3, second is 0|2
swapEvents(myP0AxisValue, myP1AxisValue);
swapEvents(myP0FireEvent, myP1FireEvent);
swapEvents(myP0DecEvent, myP1DecEvent);
swapEvents(myP0IncEvent, myP1IncEvent);
// First paddle is right A|B, second is left A|B
swapEvents(myAAxisValue, myBAxisValue);
swapEvents(myLeftAFireEvent, myLeftBFireEvent);
swapEvents(myLeftADecEvent, myLeftBDecEvent);
swapEvents(myLeftAIncEvent, myLeftBIncEvent);
}
// Direction of movement can be swapped
@ -115,8 +115,8 @@ Paddles::Paddles(Jack jack, const Event& event, const System& system,
// result in either increasing or decreasing paddle movement
if(swapdir)
{
swapEvents(myP0DecEvent, myP0IncEvent);
swapEvents(myP1DecEvent, myP1IncEvent);
swapEvents(myLeftADecEvent, myLeftAIncEvent);
swapEvents(myLeftBDecEvent, myLeftBIncEvent);
}
// The following are independent of whether or not the port
@ -159,8 +159,8 @@ void Paddles::update()
setPin(DigitalPin::Four, true);
// Digital events (from keyboard or joystick hats & buttons)
bool firePressedP0 = myEvent.get(myP0FireEvent) != 0;
bool firePressedP1 = myEvent.get(myP1FireEvent) != 0;
bool firePressedA = myEvent.get(myLeftAFireEvent) != 0;
bool firePressedB = myEvent.get(myLeftBFireEvent) != 0;
// Paddle movement is a very difficult thing to accurately emulate,
// since it originally came from an analog device that had very
@ -175,7 +175,7 @@ void Paddles::update()
if(!updateAnalogAxes())
{
updateMouse(firePressedP0, firePressedP1);
updateMouse(firePressedA, firePressedB);
updateDigitalAxes();
// Only change state if the charge has actually changed
@ -191,8 +191,8 @@ void Paddles::update()
}
}
setPin(DigitalPin::Four, !getAutoFireState(firePressedP0));
setPin(DigitalPin::Three, !getAutoFireStateP1(firePressedP1));
setPin(DigitalPin::Four, !getAutoFireState(firePressedA));
setPin(DigitalPin::Three, !getAutoFireStateP1(firePressedB));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -221,8 +221,8 @@ bool Paddles::updateAnalogAxes()
const double baseFactor = bFac[DEJITTER_BASE];
const double diffFactor = dFac[DEJITTER_DIFF];
int sa_xaxis = myEvent.get(myP0AxisValue);
int sa_yaxis = myEvent.get(myP1AxisValue);
int sa_xaxis = myEvent.get(myAAxisValue);
int sa_yaxis = myEvent.get(myBAxisValue);
bool sa_changed = false;
if(abs(myLastAxisX - sa_xaxis) > 10)
@ -261,7 +261,7 @@ bool Paddles::updateAnalogAxes()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Paddles::updateMouse(bool& firePressedP0, bool& firePressedP1)
void Paddles::updateMouse(bool& firePressedA, bool& firePressedB)
{
// Mouse motion events give relative movement
// That is, they're only relevant if they're non-zero
@ -272,11 +272,11 @@ void Paddles::updateMouse(bool& firePressedP0, bool& firePressedP1)
(myEvent.get(myAxisMouseMotion) * MOUSE_SENSITIVITY),
TRIGMIN, TRIGRANGE);
if(myMPaddleID == 0)
firePressedP0 = firePressedP0
firePressedA = firePressedA
|| myEvent.get(Event::MouseButtonLeftValue)
|| myEvent.get(Event::MouseButtonRightValue);
else
firePressedP1 = firePressedP1
firePressedB = firePressedB
|| myEvent.get(Event::MouseButtonLeftValue)
|| myEvent.get(Event::MouseButtonRightValue);
}
@ -290,10 +290,10 @@ void Paddles::updateMouse(bool& firePressedP0, bool& firePressedP1)
(myEvent.get(Event::MouseAxisXMove) * MOUSE_SENSITIVITY),
TRIGMIN, TRIGRANGE);
if(myMPaddleIDX == 0)
firePressedP0 = firePressedP0
firePressedA = firePressedA
|| myEvent.get(Event::MouseButtonLeftValue);
else
firePressedP1 = firePressedP1
firePressedB = firePressedB
|| myEvent.get(Event::MouseButtonLeftValue);
}
if(myMPaddleIDY > -1)
@ -302,10 +302,10 @@ void Paddles::updateMouse(bool& firePressedP0, bool& firePressedP1)
(myEvent.get(Event::MouseAxisYMove) * MOUSE_SENSITIVITY),
TRIGMIN, TRIGRANGE);
if(myMPaddleIDY == 0)
firePressedP0 = firePressedP0
firePressedA = firePressedA
|| myEvent.get(Event::MouseButtonRightValue);
else
firePressedP1 = firePressedP1
firePressedB = firePressedB
|| myEvent.get(Event::MouseButtonRightValue);
}
}
@ -316,45 +316,45 @@ void Paddles::updateDigitalAxes()
{
// Finally, consider digital input, where movement happens
// until a digital event is released
if(myKeyRepeat0)
if(myKeyRepeatA)
{
myPaddleRepeat0++;
if(myPaddleRepeat0 > DIGITAL_SENSITIVITY)
myPaddleRepeat0 = DIGITAL_DISTANCE;
myPaddleRepeatA++;
if(myPaddleRepeatA > DIGITAL_SENSITIVITY)
myPaddleRepeatA = DIGITAL_DISTANCE;
}
if(myKeyRepeat1)
if(myKeyRepeatB)
{
myPaddleRepeat1++;
if(myPaddleRepeat1 > DIGITAL_SENSITIVITY)
myPaddleRepeat1 = DIGITAL_DISTANCE;
myPaddleRepeatB++;
if(myPaddleRepeatB > DIGITAL_SENSITIVITY)
myPaddleRepeatB = DIGITAL_DISTANCE;
}
myKeyRepeat0 = false;
myKeyRepeat1 = false;
myKeyRepeatA = false;
myKeyRepeatB = false;
if(myEvent.get(myP0DecEvent))
if(myEvent.get(myLeftADecEvent))
{
myKeyRepeat0 = true;
if(myCharge[myAxisDigitalZero] > myPaddleRepeat0)
myCharge[myAxisDigitalZero] -= myPaddleRepeat0;
myKeyRepeatA = true;
if(myCharge[myAxisDigitalZero] > myPaddleRepeatA)
myCharge[myAxisDigitalZero] -= myPaddleRepeatA;
}
if(myEvent.get(myP0IncEvent))
if(myEvent.get(myLeftAIncEvent))
{
myKeyRepeat0 = true;
if((myCharge[myAxisDigitalZero] + myPaddleRepeat0) < TRIGRANGE)
myCharge[myAxisDigitalZero] += myPaddleRepeat0;
myKeyRepeatA = true;
if((myCharge[myAxisDigitalZero] + myPaddleRepeatA) < TRIGRANGE)
myCharge[myAxisDigitalZero] += myPaddleRepeatA;
}
if(myEvent.get(myP1DecEvent))
if(myEvent.get(myLeftBDecEvent))
{
myKeyRepeat1 = true;
if(myCharge[myAxisDigitalOne] > myPaddleRepeat1)
myCharge[myAxisDigitalOne] -= myPaddleRepeat1;
myKeyRepeatB = true;
if(myCharge[myAxisDigitalOne] > myPaddleRepeatB)
myCharge[myAxisDigitalOne] -= myPaddleRepeatB;
}
if(myEvent.get(myP1IncEvent))
if(myEvent.get(myLeftBIncEvent))
{
myKeyRepeat1 = true;
if((myCharge[myAxisDigitalOne] + myPaddleRepeat1) < TRIGRANGE)
myCharge[myAxisDigitalOne] += myPaddleRepeat1;
myKeyRepeatB = true;
if((myCharge[myAxisDigitalOne] + myPaddleRepeatB) < TRIGRANGE)
myCharge[myAxisDigitalOne] += myPaddleRepeatB;
}
}

View File

@ -174,18 +174,18 @@ class Paddles : public Controller
// Pre-compute the events we care about based on given port
// This will eliminate test for left or right port in update()
Event::Type myP0AxisValue, myP1AxisValue,
myP0DecEvent, myP0IncEvent,
myP1DecEvent, myP1IncEvent,
myP0FireEvent, myP1FireEvent,
Event::Type myAAxisValue, myBAxisValue,
myLeftADecEvent, myLeftAIncEvent,
myLeftBDecEvent, myLeftBIncEvent,
myLeftAFireEvent, myLeftBFireEvent,
myAxisMouseMotion;
// The following are used for the various mouse-axis modes
int myMPaddleID{-1}; // paddle to emulate in 'automatic' mode
int myMPaddleIDX{-1}, myMPaddleIDY{-1}; // paddles to emulate in 'specific axis' mode
bool myKeyRepeat0{false}, myKeyRepeat1{false};
int myPaddleRepeat0{0}, myPaddleRepeat1{0};
bool myKeyRepeatA{false}, myKeyRepeatB{false};
int myPaddleRepeatA{0}, myPaddleRepeatB{0};
std::array<int, 2> myCharge{TRIGRANGE/2, TRIGRANGE/2}, myLastCharge{0};
int myLastAxisX{0}, myLastAxisY{0};
int myAxisDigitalZero{0}, myAxisDigitalOne{0};
@ -211,7 +211,7 @@ class Paddles : public Controller
/**
Update the entire state according to mouse events currently set.
*/
void updateMouse(bool& firePressedP0, bool& firePressedP1);
void updateMouse(bool& firePressedA, bool& firePressedB);
/**
Update the axes pin state according to the keyboard events currently set.

View File

@ -90,7 +90,7 @@ void PointingDevice::update()
myTrackBallDown, myTrackBallLinesV, myScanCountV, myFirstScanOffsetV);
// We allow left and right mouse buttons for fire button
setPin(DigitalPin::Six, !getAutoFireState(myEvent.get(Event::JoystickZeroFire) ||
setPin(DigitalPin::Six, !getAutoFireState(myEvent.get(Event::LeftJoystickFire) ||
myEvent.get(Event::MouseButtonLeftValue) || myEvent.get(Event::MouseButtonRightValue)));
}

View File

@ -188,6 +188,8 @@ Settings::Settings()
setPermanent("dbg.fontstyle", "0");
setPermanent("dbg.uhex", "false");
setPermanent("dbg.ghostreadstrap", "true");
setPermanent("dbg.logbreaks", "false");
setPermanent("dbg.autosave", "false");
setPermanent("dis.resolve", "true");
setPermanent("dis.gfxformat", "2");
setPermanent("dis.showaddr", "true");
@ -240,10 +242,16 @@ Settings::Settings()
setPermanent("dev.tm.uncompressed", 600);
setPermanent("dev.tm.interval", "1f"); // = 1 frame
setPermanent("dev.tm.horizon", "30s"); // = ~30 seconds
// Thumb ARM emulation options
setPermanent("dev.thumb.trapfatal", "true");
setPermanent("dev.detectedinfo", "true");
setPermanent("dev.eepromaccess", "true");
// Thumb ARM emulation options
setPermanent("dev.thumb.trapfatal", "true");
#ifdef DEBUGGER_SUPPORT
setPermanent("dev.thumb.inccycles", "true");
setPermanent("dev.thumb.cyclefactor", "1.05");
setPermanent("dev.thumb.chiptype", "0"); // = LPC2103
setPermanent("dev.thumb.mammode", "2");
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -613,7 +621,9 @@ void Settings::usage() const
<< " -dbg.fontstyle <0-3> Font style to use in debugger window (bold vs.\n"
<< " normal)\n"
<< " -dbg.ghostreadstrap <1|0> Debugger traps on 'ghost' reads\n"
<< " -dbg.uhex <0|1> lower-/uppercase HEX display\n"
<< " -dbg.uhex <0|1> Lower-/uppercase HEX display\n"
<< " -dbg.logbreaks <0|1> Log breaks and traps and continue emulation\n"
<< " -dbg.autosave <0|1> Automatically save breaks, traps etc.\n"
<< " -break <address> Set a breakpoint at 'address'\n"
<< " -debug Start in debugger mode\n"
<< endl
@ -674,12 +684,19 @@ void Settings::usage() const
<< " -dev.tiadriven <1|0> Drive unused TIA pins randomly on a\n"
<< " read/peek\n"
#ifdef DEBUGGER_SUPPORT
<< " -dev.rwportbreak <1|0> Debugger breaks on reads from write ports\n"
<< " -dev.wrportbreak <1|0> Debugger breaks on writes to read ports\n"
<< " -dev.rwportbreak <1|0> Debugger breaks on reads from write ports\n"
<< " -dev.wrportbreak <1|0> Debugger breaks on writes to read ports\n"
#endif
<< " -dev.thumb.trapfatal <1|0> Determines whether errors in ARM emulation\n"
<< " -dev.thumb.trapfatal <1|0> Determines whether errors in ARM emulation\n"
<< " throw an exception\n"
<< " -dev.eepromaccess <1|0> Enable messages for AtariVox/SaveKey access\n"
#ifdef DEBUGGER_SUPPORT
<< " -dev.thumb.inccycles <1|0> Determines whether ARM emulation cycles\n"
<< " increase system cycles\n"
<< " -dev.thumb.cyclefactor <float> Sets the ARM cycles correction multiplier\n"
<< " -dev.thumb.chiptype <0|1> Selects the ARM chip type\n"
<< " -dev.thumb.mammode <0-3> Selects the LPC's MAM mode\n"
#endif
<< " -dev.eepromaccess <1|0> Enable messages for AtariVox/SaveKey access\n"
<< " messages\n"
<< " -dev.tia.type <standard|custom| Selects a TIA type\n"
<< " koolaidman|\n"

View File

@ -541,12 +541,3 @@ bool TIASurface::correctAspect() const
{
return myOSystem.settings().getBool("tia.correct_aspect");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIASurface::resetSurfaces()
{
myTiaSurface->reload();
mySLineSurface->reload();
myBaseTiaSurface->reload();
myShadeSurface->reload();
}

View File

@ -49,7 +49,7 @@ class TIASurface
Creates a new TIASurface object
*/
explicit TIASurface(OSystem& system);
virtual ~TIASurface();
~TIASurface();
/**
Set the TIA object, which is needed for actually rendering the TIA image.
@ -183,11 +183,6 @@ class TIASurface
*/
void updateSurfaceSettings();
/**
Issue a 'reload' to each surface.
*/
void resetSurfaces();
private:
/**
Average current calculated buffer's pixel with previous calculated buffer's pixel (50:50).
@ -213,7 +208,8 @@ class TIASurface
FrameBuffer& myFB;
TIA* myTIA{nullptr};
unique_ptr<FBSurface> myTiaSurface, mySLineSurface, myBaseTiaSurface, myShadeSurface;
shared_ptr<FBSurface> myTiaSurface, mySLineSurface,
myBaseTiaSurface, myShadeSurface;
// NTSC object to use in TIA rendering mode
NTSCFilter myNTSCFilter;

File diff suppressed because it is too large Load Diff

View File

@ -32,7 +32,6 @@ class Cartridge;
#ifdef RETRON77
#define UNSAFE_OPTIMIZATIONS
#define NO_THUMB_STATS
#endif
#define ROMADDMASK 0x7FFFF
@ -46,6 +45,17 @@ class Cartridge;
#define CPSR_C (1u<<29)
#define CPSR_V (1u<<28)
#ifdef DEBUGGER_SUPPORT
#define THUMB_CYCLE_COUNT
//#define COUNT_OPS
#define THUMB_STATS
#endif
#ifdef THUMB_CYCLE_COUNT
//#define EMULATE_PIPELINE // enable coarse ARM pipeline emulation (TODO)
#define TIMER_0 // enable timer 0 support (e.g. for measuring cycle count)
#endif
class Thumbulator
{
public:
@ -59,16 +69,37 @@ class Thumbulator
CDFJplus, // cartridges of type CDFJ+
DPCplus // cartridges of type DPC+
};
enum class ChipType {
LPC2101, // Harmony (includes LPC2103)
LPC2104_OC, // Dev cart overclocked (includes LPC2105)
LPC2104, // Dev cart (includes LPC2105)
LPC213x, // future use (includes LPC2132)
numTypes
};
enum class MamModeType {
mode0, mode1, mode2, modeX
};
struct ChipPropsType {
double MHz;
uInt32 flashCycles;
uInt32 flashBanks;
};
struct Stats {
#ifndef NO_THUMB_STATS
uInt32 fetches{0}, reads{0}, writes{0};
uInt32 instructions{0};
#ifdef THUMB_STATS
uInt32 reads{0}, writes{0};
uInt32 nCylces{0}, sCylces{0}, iCylces{0};
uInt32 branches{0}, taken{0};
uInt32 mamPrefetchHits{0}, mamPrefetchMisses{0};
uInt32 mamBranchHits{0}, mamBranchMisses{0};
uInt32 mamDataHits{0}, mamDataMisses{0};
#endif
};
Thumbulator(const uInt16* rom_ptr, uInt16* ram_ptr, uInt32 rom_size,
const uInt32 c_base, const uInt32 c_start, const uInt32 c_stack,
bool traponfatal, Thumbulator::ConfigureFor configurefor,
bool traponfatal, double cyclefactor,
Thumbulator::ConfigureFor configurefor,
Cartridge* cartridge);
/**
@ -79,11 +110,24 @@ class Thumbulator
@return The results of any debugging output (if enabled),
otherwise an empty string
*/
string run();
string run(uInt32 cycles);
string run(uInt32& cycles, bool irqDrivenAudio);
void enableCycleCount(bool enable) { _countCycles = enable; }
const Stats& stats() const { return _stats; }
uInt32 cycles() const { return _totalCycles; }
ChipPropsType setChipType(ChipType type);
void setMamMode(MamModeType mode) { mamcr = mode; }
void lockMamMode(bool lock) { _lockMamcr = lock; }
MamModeType mamMode() const { return static_cast<MamModeType>(mamcr); }
#ifndef UNSAFE_OPTIMIZATIONS
#ifdef THUMB_CYCLE_COUNT
void cycleFactor(double factor) { _armCyclesFactor = factor; }
double cycleFactor() const { return _armCyclesFactor; }
#else
void cycleFactor(double) { }
double cycleFactor() const { return 1.0; }
#endif
#ifndef UNSAFE_OPTIMIZATIONS
/**
Normally when a fatal error is encountered, the ARM emulation
immediately throws an exception and exits. This method allows execution
@ -96,8 +140,8 @@ class Thumbulator
@param enable Enable (the default) or disable exceptions on fatal errors
*/
static void trapFatalErrors(bool enable) { trapOnFatal = enable; }
#endif
void trapFatalErrors(bool enable) { trapOnFatal = enable; }
#endif
/**
Inform the Thumbulator class about the console currently in use,
@ -155,18 +199,35 @@ class Thumbulator
sxth,
tst,
uxtb,
uxth
uxth,
numOps
};
#ifdef THUMB_CYCLE_COUNT
enum class CycleType {
S, N, I // Sequential, Non-sequential, Internal
};
enum class AccessType {
prefetch, branch, data
};
#endif
const std::array<ChipPropsType, uInt32(ChipType::numTypes)> ChipProps =
{{
{ 70.0, 4, 1 }, // LPC2101_02_03
{ 70.0, 4, 2 }, // LPC2104_05_06 Overclocked
{ 60.0, 3, 2 }, // LPC2104_05_06
{ 60.0, 3, 1 }, // LPC2132..
}};
private:
string doRun(uInt32& cycles, bool irqDrivenAudio);
uInt32 read_register(uInt32 reg);
void write_register(uInt32 reg, uInt32 data);
void write_register(uInt32 reg, uInt32 data, bool isFlowBreak = true);
uInt32 fetch16(uInt32 addr);
uInt32 read16(uInt32 addr);
uInt32 read32(uInt32 addr);
#ifndef UNSAFE_OPTIMIZATIONS
#ifndef UNSAFE_OPTIMIZATIONS
bool isProtected(uInt32 addr);
#endif
#endif
void write16(uInt32 addr, uInt32 data);
void write32(uInt32 addr, uInt32 data);
void updateTimer(uInt32 cycles);
@ -180,7 +241,7 @@ class Thumbulator
void do_cflag_bit(uInt32 x);
void do_vflag_bit(uInt32 x);
#ifndef UNSAFE_OPTIMIZATIONS
#ifndef UNSAFE_OPTIMIZATIONS
// Throw a runtime_error exception containing an error referencing the
// given message and variables
// Note that the return value is never used in these methods
@ -189,10 +250,18 @@ class Thumbulator
void dump_counters();
void dump_regs();
#endif
#endif
int execute();
int reset();
#ifdef THUMB_CYCLE_COUNT
bool isMamBuffered(uInt32 addr, AccessType = AccessType::data);
void incCycles(AccessType accessType, uInt32 cycles);
void incSCycles(uInt32 addr, AccessType = AccessType::data);
void incNCycles(uInt32 addr, AccessType = AccessType::data);
void incICycles(uInt32 m = 1);
#endif
private:
const uInt16* rom{nullptr};
uInt32 romSize{0};
@ -202,26 +271,58 @@ class Thumbulator
const unique_ptr<Op[]> decodedRom; // NOLINT
uInt16* ram{nullptr};
std::array<uInt32, 16> reg_norm; // normal execution mode, do not have a thread mode
uInt32 cpsr{0}, mamcr{0};
uInt32 cpsr{0};
MamModeType mamcr{MamModeType::mode0};
bool handler_mode{false};
uInt32 systick_ctrl{0}, systick_reload{0}, systick_count{0}, systick_calibrate{0};
#ifndef UNSAFE_OPTIMIZATIONS
uInt32 instructions{0};
#endif
Stats _stats;
ChipType _chipType{ChipType::LPC2101};
ConsoleTiming _consoleTiming{ConsoleTiming::ntsc};
double _MHz{70.0};
uInt32 _flashCycles{4};
uInt32 _flashBanks{1};
Stats _stats{0};
bool _irqDrivenAudio{false};
uInt32 _totalCycles{0};
// For emulation of LPC2103's timer 1, used for NTSC/PAL/SECAM detection.
// Register names from documentation:
// http://www.nxp.com/documents/user_manual/UM10161.pdf
uInt32 T1TCR{0}; // Timer 1 Timer Control Register
uInt32 T1TC{0}; // Timer 1 Timer Counter
#ifdef TIMER_0
uInt32 T0TCR{0}; // Timer 0 Timer Control Register
uInt32 T0TC{0}; // Timer 0 Timer Counter
uInt32 tim0Start{0}; // _totalCycles when Timer 0 got started last time
uInt32 tim0Total{0}; // total cycles of Timer 0
#endif
uInt32 T1TCR{0}; // Timer 1 Timer Control Register
uInt32 T1TC{0}; // Timer 1 Timer Counter
uInt32 tim1Start{0}; // _totalCycles when Timer 1 got started last time
uInt32 tim1Total{0}; // total cycles of Timer 1
double timing_factor{0.0};
#ifndef UNSAFE_OPTIMIZATIONS
#ifndef UNSAFE_OPTIMIZATIONS
ostringstream statusMsg;
bool trapOnFatal{true};
#endif
bool _countCycles{false};
bool _lockMamcr{false};
static bool trapOnFatal;
#endif
#ifdef THUMB_CYCLE_COUNT
double _armCyclesFactor{1.05};
uInt32 _pipeIdx{0};
CycleType _prefetchCycleType[3]{CycleType::S};
CycleType _lastCycleType[3]{CycleType::S};
AccessType _prefetchAccessType[3]{AccessType::data};
#ifdef EMULATE_PIPELINE
uInt32 _fetchPipeline{0}; // reserve fetch cycles resulting from pipelining (execution stage)
uInt32 _memory0Pipeline{0}, _memory1Pipeline{0};
#endif
uInt32 _prefetchBufferAddr[2]{0};
uInt32 _branchBufferAddr[2]{0};
uInt32 _dataBufferAddr{0};
#endif
#ifdef COUNT_OPS
uInt32 opCount[size_t(Op::numOps)]{0};
#endif
ConfigureFor configuration;

View File

@ -5,6 +5,7 @@ MODULE_OBJS := \
src/emucore/Bankswitch.o \
src/emucore/Booster.o \
src/emucore/Cart.o \
src/emucore/CartARM.o \
src/emucore/CartCreator.o \
src/emucore/CartDetector.o \
src/emucore/CartEnhanced.o \

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,7 @@
#include "Widget.hxx"
#include "Font.hxx"
#include "WhatsNewDialog.hxx"
#include "MediaFactory.hxx"
#include "AboutDialog.hxx"
@ -80,8 +81,10 @@ AboutDialog::AboutDialog(OSystem& osystem, DialogContainer& parent,
xpos = HBORDER * 2; ypos += lineHeight + VGAP * 2;
for(int i = 0; i < myLinesPerPage; i++)
{
myDesc.push_back(new StaticTextWidget(this, font, xpos, ypos, _w - xpos * 2,
fontHeight, "", TextAlign::Left));
StaticTextWidget* s = new StaticTextWidget(this, font, xpos, ypos, _w - xpos * 2,
fontHeight, "", TextAlign::Left, kNone);
s->setID(i);
myDesc.push_back(s);
myDescStr.emplace_back("");
ypos += fontHeight;
}
@ -160,9 +163,8 @@ void AboutDialog::updateStrings(int page, int lines, string& title)
case 4:
title = "Cast of thousands";
ADD_ATEXT("\\L\\c0""Special thanks to AtariAge for introducing the");
ADD_ATEXT("\\L\\c0""Special thanks to <AtariAge> for introducing the");
ADD_ATEXT("\\L\\c0""Atari 2600 to a whole new generation.");
ADD_ATEXT("\\L\\c2"" http://www.atariage.com");
ADD_ALINE();
ADD_ATEXT("\\L\\c0""Finally, a huge thanks to the original Atari 2600");
ADD_ATEXT("\\L\\c0""VCS team for giving us the magic, and to the");
@ -242,6 +244,24 @@ void AboutDialog::displayInfo()
myDesc[i]->setAlign(align);
myDesc[i]->setTextColor(color);
myDesc[i]->setLabel(str);
// add some labeled links
if(BSPF::containsIgnoreCase(str, "see manual"))
myDesc[i]->setUrl("https://stella-emu.github.io/docs/index.html#License", "manual");
else if(BSPF::containsIgnoreCase(str, "Stephen Anthony"))
myDesc[i]->setUrl("http://minbar.org", "Stephen Anthony");
else if(BSPF::containsIgnoreCase(str, "Bradford W. Mott"))
myDesc[i]->setUrl("www.intellimedia.ncsu.edu/people/bwmott", "Bradford W. Mott");
else if(BSPF::containsIgnoreCase(str, "ScummVM project"))
myDesc[i]->setUrl("www.scummvm.org", "ScummVM");
else if(BSPF::containsIgnoreCase(str, "Ian Bogost"))
myDesc[i]->setUrl("http://bogost.com", "Ian Bogost");
else if(BSPF::containsIgnoreCase(str, "CRT Simulation"))
myDesc[i]->setUrl("http://blargg.8bitalley.com/libs/ntsc.html", "CRT Simulation effects");
else if(BSPF::containsIgnoreCase(str, "<AtariAge>"))
myDesc[i]->setUrl("www.atariage.com", "AtariAge", "<AtariAge>");
else
// extract URL from label
myDesc[i]->setUrl();
}
// Redraw entire dialog
@ -280,7 +300,52 @@ void AboutDialog::handleCommand(CommandSender* sender, int cmd, int data, int id
myWhatsNewDialog->open();
break;
case StaticTextWidget::kOpenUrlCmd:
{
const string url = myDesc[id]->getUrl();
if(url != EmptyString)
MediaFactory::openURL(url);
break;
}
default:
Dialog::handleCommand(sender, cmd, data, 0);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const string AboutDialog::getUrl(const string& str) const
{
bool isUrl = false;
size_t start = 0, len = 0;
for(size_t i = 0; i < str.size(); ++i)
{
string remainder = str.substr(i);
char ch = str[i];
if(!isUrl
&& (BSPF::startsWithIgnoreCase(remainder, "http://")
|| BSPF::startsWithIgnoreCase(remainder, "https://")
|| BSPF::startsWithIgnoreCase(remainder, "www.")))
{
isUrl = true;
start = i;
}
// hack, change mode without changing string length
if(isUrl)
{
if((ch == ' ' || ch == ')' || ch == '>'))
isUrl = false;
else
len++;
}
}
if(len)
return str.substr(start, len);
else
return EmptyString;
}

View File

@ -38,6 +38,7 @@ class AboutDialog : public Dialog
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
void updateStrings(int page, int lines, string& title);
void displayInfo();
const string getUrl(const string& text) const;
void loadConfig() override { displayInfo(); }

View File

@ -31,7 +31,7 @@ ColorWidget::ColorWidget(GuiObject* boss, const GUI::Font& font,
_framed{framed},
_cmd{cmd}
{
_flags = Widget::FLAG_ENABLED | Widget::FLAG_CLEARBG | Widget::FLAG_RETAIN_FOCUS;
_flags = Widget::FLAG_ENABLED | Widget::FLAG_CLEARBG;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -45,6 +45,8 @@ class ColorWidget : public Widget, public CommandSender
void setCrossed(bool enable);
protected:
void handleMouseEntered() override { }
void handleMouseLeft() override { }
void drawWidget(bool hilite) override;
protected:

View File

@ -168,6 +168,13 @@ const string& ContextMenu::getSelectedName() const
return (_selectedItem >= 0) ? _entries[_selectedItem].first : EmptyString;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ContextMenu::setSelectedName(const string& name)
{
if(_selectedItem >= 0)
_entries[_selectedItem].first = name;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const Variant& ContextMenu::getSelectedTag() const
{

Some files were not shown because too many files have changed in this diff Show More