Merge branch 'master' into feature/lodefmode-moviecart
13
Changes.txt
|
@ -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)
|
||||
|
||||
|
|
|
@ -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 && 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 && 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 ¹. 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 & 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>¹ 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&1). The parentheses are necessary as
|
|||
we want to apply the ! to the result of the &, not just the first term
|
||||
(the "*SWCHB").</p>
|
||||
|
||||
<p>"breakif !(*SWCHB&1)" will do the job for us. However, it's an ugly mess
|
||||
<p>"breakIf !(*SWCHB&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 & 1 ) }" is a lot more readable, isn't it? If
|
||||
<p>"breakIf { !(*SWCHB & 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 & 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 && gameSelect }
|
||||
breakIf { gameReset && 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 & $40)</td><td> Left joystick moved left</td></tr>
|
||||
<tr><td> _joy0right</td><td> !(*SWCHA & $80)</td><td> Left joystick moved right</td></tr>
|
||||
<tr><td> _joy0up</td><td> !(*SWCHA & $10)</td><td> Left joystick moved up</td></tr>
|
||||
<tr><td> _joy0down</td><td> !(*SWCHA & $20)</td><td> Left joystick moved down</td></tr>
|
||||
<tr><td> _joy0button</td><td> !(*INPT4 & $80)</td><td> Left joystick button pressed</td></tr>
|
||||
<tr><td> _joy1left</td><td> !(*SWCHA & $04)</td><td> Right joystick moved left</td></tr>
|
||||
<tr><td> _joy1right</td><td> !(*SWCHA & $08)</td><td> Right joystick moved right</td></tr>
|
||||
<tr><td> _joy1up</td><td> !(*SWCHA & $01)</td><td> Right joystick moved up</td></tr>
|
||||
<tr><td> _joy1down</td><td> !(*SWCHA & $02)</td><td> Right joystick moved down</td></tr>
|
||||
<tr><td> _joy1button</td><td> !(*INPT5 & $80)</td><td> Right joystick button pressed</td></tr>
|
||||
<tr><td> _joy0Left</td><td> !(*SWCHA & $40)</td><td> Left joystick moved left</td></tr>
|
||||
<tr><td> _joy0Right</td><td> !(*SWCHA & $80)</td><td> Left joystick moved right</td></tr>
|
||||
<tr><td> _joy0Up</td><td> !(*SWCHA & $10)</td><td> Left joystick moved up</td></tr>
|
||||
<tr><td> _joy0Down</td><td> !(*SWCHA & $20)</td><td> Left joystick moved down</td></tr>
|
||||
<tr><td> _joy0Fire</td><td> !(*INPT4 & $80)</td><td> Left joystick fire button pressed</td></tr>
|
||||
<tr><td> _joy1Left</td><td> !(*SWCHA & $04)</td><td> Right joystick moved left</td></tr>
|
||||
<tr><td> _joy1Right</td><td> !(*SWCHA & $08)</td><td> Right joystick moved right</td></tr>
|
||||
<tr><td> _joy1Up</td><td> !(*SWCHA & $01)</td><td> Right joystick moved up</td></tr>
|
||||
<tr><td> _joy1Down</td><td> !(*SWCHA & $02)</td><td> Right joystick moved down</td></tr>
|
||||
<tr><td> _joy1Fire</td><td> !(*INPT5 & $80)</td><td> Right joystick fire button pressed</td></tr>
|
||||
<tr><td> _select</td><td> !(*SWCHB & $02)</td><td> Game Select pressed</td></tr>
|
||||
<tr><td> _reset</td><td> !(*SWCHB & $01)</td><td> Game Reset pressed</td></tr>
|
||||
<tr><td> _color</td><td> *SWCHB & $08</td><td> Color/BW set to Color</td></tr>
|
||||
<tr><td> _bw</td><td> !(*SWCHB & $08)</td><td> Color/BW set to BW</td></tr>
|
||||
<tr><td> _diff0b</td><td> !(*SWCHB & $40)</td><td> Left difficulty set to B (easy)</td></tr>
|
||||
<tr><td> _diff0a</td><td> *SWCHB & $40</td><td> Left difficulty set to A (hard)</td></tr>
|
||||
<tr><td> _diff1b</td><td> !(*SWCHB & $80)</td><td> Right difficulty set to B (easy)</td></tr>
|
||||
<tr><td> _diff1a</td><td> *SWCHB & $80</td><td> Right difficulty set to A (hard)</td></tr>
|
||||
<tr><td> _diff0B</td><td> !(*SWCHB & $40)</td><td> Left difficulty set to B (easy)</td></tr>
|
||||
<tr><td> _diff0A</td><td> *SWCHB & $40</td><td> Left difficulty set to A (hard)</td></tr>
|
||||
<tr><td> _diff1B</td><td> !(*SWCHB & $80)</td><td> Right difficulty set to B (easy)</td></tr>
|
||||
<tr><td> _diff1A</td><td> *SWCHB & $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 && _bank==1 }
|
||||
breakIf { pc==myLabel && _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 "<rom_filename>.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 "<rom_filename>.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 "<rom_filename>.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
|
||||
"<YYYY-MM-DD_HH-mm-ss>.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 <value>
|
||||
aud - Mark 'AUD' range in disassembly
|
||||
autoSave - Automatically execute "save" when exiting the debugger
|
||||
base - Set default number base to <base> (bin, dec, hex)
|
||||
bcol - Mark 'BCOL' range in disassembly
|
||||
bCol - Mark 'BCOL' range in disassembly
|
||||
break - Set/clear breakpoint at <address> and <bank>
|
||||
breakif - Set/clear breakpoint on <condition>
|
||||
breaklabel - Set/clear breakpoint on <address> (no mirrors, all banks)
|
||||
breakIf - Set/clear breakpoint on <condition>
|
||||
breakLabel - Set/clear breakpoint on <address> (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 <xx>
|
||||
delfunction - Delete function with label xx
|
||||
delsavestateif - Delete conditional savestate point <xx>
|
||||
deltrap - Delete trap <xx>
|
||||
delwatch - Delete watch <xx>
|
||||
disasm - Disassemble address xx [yy lines] (default=PC)
|
||||
delBreakIf - Delete conditional breakIf <xx>
|
||||
delFunction - Delete function with label xx
|
||||
delSaveStateIf - Delete conditional saveState point <xx>
|
||||
delTrap - Delete trap <xx>
|
||||
delWatch - Delete watch <xx>
|
||||
disAsm - Disassemble address xx [yy lines] (default=PC)
|
||||
dump - Dump data at address <xx> [to yy] [1: memory; 2: CPU state; 4: input regs] [?]
|
||||
exec - Execute script file <xx> [prefix]
|
||||
exitrom - Exit emulator, return to ROM launcher
|
||||
exitRom - Exit emulator, return to ROM launcher
|
||||
frame - Advance emulation by <xx> frames (default=1)
|
||||
function - Define function name xx for expression yy
|
||||
gfx - Mark 'GFX' range in disassembly
|
||||
help - help <command>
|
||||
joy0up - Set joystick 0 up direction to value <x> (0 or 1), or toggle (no arg)
|
||||
joy0down - Set joystick 0 down direction to value <x> (0 or 1), or toggle (no arg)
|
||||
joy0left - Set joystick 0 left direction to value <x> (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 <x> (0 or 1), or toggle (no arg)
|
||||
joy1up - Set joystick 1 up direction to value <x> (0 or 1), or toggle (no arg)
|
||||
joy1down - Set joystick 1 down direction to value <x> (0 or 1), or toggle (no arg)
|
||||
joy1left - Set joystick 1 left direction to value <x> (0 or 1), or toggle (no arg)
|
||||
joy1right - Set joystick 1 right direction to value <x> (0 or 1), or toggle (no arg)
|
||||
joy1fire - Set joystick 1 fire button to value <x> (0 or 1), or toggle (no arg)
|
||||
joy0Up - Set joystick 0 up direction to value <x> (0 or 1), or toggle (no arg)
|
||||
joy0Down - Set joystick 0 down direction to value <x> (0 or 1), or toggle (no arg)
|
||||
joy0Left - Set joystick 0 left direction to value <x> (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 <x> (0 or 1), or toggle (no arg)
|
||||
joy1Up - Set joystick 1 up direction to value <x> (0 or 1), or toggle (no arg)
|
||||
joy1Down - Set joystick 1 down direction to value <x> (0 or 1), or toggle (no arg)
|
||||
joy1Left - Set joystick 1 left direction to value <x> (0 or 1), or toggle (no arg)
|
||||
joy1Right - Set joystick 1 right direction to value <x> (0 or 1), or toggle (no arg)
|
||||
joy1Fire - Set joystick 1 fire button to value <x> (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 <condition>
|
||||
scanline - Advance emulation by <xx> 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 <condition>
|
||||
scanLine - Advance emulation by <xx> scanlines (default=1)
|
||||
step - Single step CPU [with count xx]
|
||||
stepwhile - Single step CPU while <condition> is true
|
||||
stepWhile - Single step CPU while <condition> 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 <condition> trap R/W access to address(es) xx [yy]
|
||||
trapread - Trap read access to address(es) xx [yy]
|
||||
trapreadif - On <condition> trap read access to address(es) xx [yy]
|
||||
trapwrite - Trap write access to address(es) xx [yy]
|
||||
trapwriteif - On <condition> trap write access to address(es) xx [yy]
|
||||
trapIf - On <condition> trap R/W access to address(es) xx [yy]
|
||||
trapRead - Trap read access to address(es) xx [yy]
|
||||
trapReadIf - On <condition> trap read access to address(es) xx [yy]
|
||||
trapWrite - Trap write access to address(es) xx [yy]
|
||||
trapWriteIf - On <condition> 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 &
|
||||
current scanLine, with the contents of the old frame (in black &
|
||||
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.
|
||||
|
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 9.1 KiB |
143
docs/index.html
|
@ -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 <1|0></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 <float></pre></td>
|
||||
<td>Defines the ARM cycle count correction factor (default = 0.95).</td>
|
||||
</tr><tr>
|
||||
<td><pre>-dev.thumb.chiptype <0|1></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 <0..3></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>-<plr.|dev.>eepromaccess <1|0></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> </td></tr>
|
||||
<tr><td>Controller Database</td><td>Show all controllers that Stella knows about, with the option to remove them</td><td> </td></tr>
|
||||
<tr><td>Erase EEPROM</td><td>Erase the whole AtariVox/SaveKey flash memory</td><td> </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> Id </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.
|
||||
|
|
|
@ -71,6 +71,8 @@ FBBackendSDL2::~FBBackendSDL2()
|
|||
myWindow = nullptr;
|
||||
}
|
||||
SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_TIMER);
|
||||
|
||||
cerr << "~FBBackendSDL2()" << endl;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
bool erased = false;
|
||||
if(isAdaptor)
|
||||
{
|
||||
// Map the Stelladaptors we've found according to the specified ports
|
||||
// The 'type' is also set there
|
||||
if(specialAdaptor)
|
||||
mapStelladaptors(myOSystem.settings().getString("saport"));
|
||||
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},
|
||||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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},
|
||||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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 = {{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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"},
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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" }*/
|
||||
} };
|
||||
//
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,197 +152,135 @@ 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;
|
||||
if(execute())
|
||||
return true;
|
||||
}
|
||||
else if(result == "_NO_PROMPT")
|
||||
return true;
|
||||
else if(result != "")
|
||||
print(result + "\n");
|
||||
}
|
||||
|
||||
printPrompt();
|
||||
dirty = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case KBDK_TAB:
|
||||
{
|
||||
// Tab completion: we complete either commands or labels, but not
|
||||
// both at once.
|
||||
|
||||
if(_currentPos <= _promptStartPos)
|
||||
// special events (auto complete & history scrolling)
|
||||
case Event::UINavNext:
|
||||
dirty = changeInput = autoComplete(+1);
|
||||
resetAutoComplete = false;
|
||||
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)
|
||||
case Event::UINavPrev:
|
||||
dirty = changeInput = autoComplete(-1);
|
||||
resetAutoComplete = false;
|
||||
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)
|
||||
case Event::UILeft: // mapped to KBDK_DOWN by default
|
||||
dirty = changeInput = historyScroll(-1);
|
||||
resetHistoryScroll = false;
|
||||
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;
|
||||
case Event::UIRight: // mapped to KBDK_UP by default
|
||||
dirty = changeInput = historyScroll(+1);
|
||||
resetHistoryScroll = false;
|
||||
break;
|
||||
}
|
||||
|
||||
case KBDK_BACKSPACE:
|
||||
// input modifying events
|
||||
case Event::Backspace:
|
||||
if(_currentPos > _promptStartPos)
|
||||
killChar(-1);
|
||||
|
||||
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;
|
||||
break;
|
||||
|
||||
case KBDK_PAGEUP:
|
||||
if (StellaModTest::isShift(mod))
|
||||
{
|
||||
killChar(-1);
|
||||
changeInput = true;
|
||||
}
|
||||
scrollToCurrent();
|
||||
break;
|
||||
|
||||
case Event::Delete:
|
||||
killChar(+1);
|
||||
changeInput = true;
|
||||
break;
|
||||
|
||||
case Event::DeleteEnd:
|
||||
killLine(+1);
|
||||
changeInput = true;
|
||||
break;
|
||||
|
||||
case Event::DeleteHome:
|
||||
killLine(-1);
|
||||
changeInput = true;
|
||||
break;
|
||||
|
||||
case Event::DeleteLeftWord:
|
||||
killWord();
|
||||
changeInput = true;
|
||||
break;
|
||||
|
||||
case Event::Cut:
|
||||
textCut();
|
||||
changeInput = true;
|
||||
break;
|
||||
|
||||
case Event::Copy:
|
||||
textCopy();
|
||||
break;
|
||||
|
||||
case Event::Paste:
|
||||
textPaste();
|
||||
changeInput = true;
|
||||
break;
|
||||
|
||||
// cursor events
|
||||
case Event::MoveHome:
|
||||
_currentPos = _promptStartPos;
|
||||
break;
|
||||
|
||||
case Event::MoveEnd:
|
||||
_currentPos = _promptEndPos;
|
||||
break;
|
||||
|
||||
case Event::MoveRightChar:
|
||||
if(_currentPos < _promptEndPos)
|
||||
_currentPos++;
|
||||
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;
|
||||
|
@ -356,14 +289,9 @@ bool PromptWidget::handleKeyDown(StellaKey key, StellaMod mod)
|
|||
if(_scrollLine < _firstLineInBuffer + _linesPerPage - 1)
|
||||
_scrollLine = _firstLineInBuffer + _linesPerPage - 1;
|
||||
updateScrollBuffer();
|
||||
|
||||
dirty = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case KBDK_PAGEDOWN:
|
||||
if (StellaModTest::isShift(mod))
|
||||
{
|
||||
case Event::UIPgDown:
|
||||
// Don't scroll down when at bottom of buffer
|
||||
if(_scrollLine >= _promptEndPos / _lineWidth)
|
||||
break;
|
||||
|
@ -372,108 +300,23 @@ bool PromptWidget::handleKeyDown(StellaKey key, StellaMod mod)
|
|||
if(_scrollLine > _promptEndPos / _lineWidth)
|
||||
_scrollLine = _promptEndPos / _lineWidth;
|
||||
updateScrollBuffer();
|
||||
|
||||
dirty = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case KBDK_HOME:
|
||||
if (StellaModTest::isShift(mod))
|
||||
{
|
||||
case Event::UIHome:
|
||||
_scrollLine = _firstLineInBuffer + _linesPerPage - 1;
|
||||
updateScrollBuffer();
|
||||
}
|
||||
else
|
||||
_currentPos = _promptStartPos;
|
||||
|
||||
dirty = true;
|
||||
break;
|
||||
|
||||
case KBDK_END:
|
||||
if (StellaModTest::isShift(mod))
|
||||
{
|
||||
case Event::UIEnd:
|
||||
_scrollLine = _promptEndPos / _lineWidth;
|
||||
if(_scrollLine < _linesPerPage - 1)
|
||||
_scrollLine = _linesPerPage - 1;
|
||||
updateScrollBuffer();
|
||||
}
|
||||
else
|
||||
_currentPos = _promptEndPos;
|
||||
|
||||
dirty = true;
|
||||
break;
|
||||
|
||||
case KBDK_UP:
|
||||
if (StellaModTest::isShift(mod))
|
||||
{
|
||||
if(_scrollLine <= _firstLineInBuffer + _linesPerPage - 1)
|
||||
break;
|
||||
|
||||
_scrollLine -= 1;
|
||||
updateScrollBuffer();
|
||||
|
||||
dirty = true;
|
||||
}
|
||||
else
|
||||
historyScroll(+1);
|
||||
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);
|
||||
break;
|
||||
|
||||
case KBDK_RIGHT:
|
||||
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;
|
||||
|
||||
default:
|
||||
if (StellaModTest::isControl(mod))
|
||||
{
|
||||
specialKeys(key);
|
||||
}
|
||||
else if (StellaModTest::isAlt(mod))
|
||||
{
|
||||
// Placeholder only - this will never be reached
|
||||
}
|
||||
else
|
||||
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)
|
||||
// Do not add duplicates, remove old duplicate
|
||||
if(_history.size())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
int i = _historyIndex;
|
||||
int historyEnd = _historyIndex % _history.size();
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PromptWidget::historyScroll(int direction)
|
||||
do
|
||||
{
|
||||
if (_historySize == 0)
|
||||
return;
|
||||
historyDir(i, -1);
|
||||
|
||||
if (_historyLine == 0 && direction > 0)
|
||||
if(!BSPF::compareIgnoreCase(_history[i], str))
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < _promptEndPos - _promptStartPos; i++)
|
||||
_history[_historyIndex][i] = buffer(_promptStartPos + i); //FIXME: int to char??
|
||||
int j = i, prevJ;
|
||||
|
||||
_history[_historyIndex][i] = '\0';
|
||||
do
|
||||
{
|
||||
prevJ = j;
|
||||
historyDir(j, +1);
|
||||
_history[prevJ] = _history[j];
|
||||
}
|
||||
while(j != historyEnd);
|
||||
|
||||
// Advance to the next line in the history
|
||||
int line = _historyLine + direction;
|
||||
if(line < 0)
|
||||
line += _historySize + 1;
|
||||
line %= (_historySize + 1);
|
||||
|
||||
// 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)
|
||||
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++)
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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(...)
|
||||
{
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
|
@ -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(...)
|
||||
{
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
|
@ -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(...)
|
||||
{
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,46 +2276,82 @@ void EventHandler::setComboMap()
|
|||
myComboTable[i][j] = Event::NoType;
|
||||
};
|
||||
|
||||
// Compare if event list version has changed so that combo maps became invalid
|
||||
if(version != Event::VERSION || !buf.good())
|
||||
ERASE_ALL();
|
||||
else
|
||||
|
||||
// Compare if event list version has changed so that combo maps became invalid
|
||||
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)
|
||||
for(const json& event : events)
|
||||
myComboTable[i][j++] = event;
|
||||
}
|
||||
}
|
||||
catch(const json::exception&)
|
||||
{
|
||||
myComboTable[combocount][eventcount] = Event::Type(BSPF::stringToInt(key));
|
||||
++eventcount;
|
||||
}
|
||||
++combocount;
|
||||
}
|
||||
}
|
||||
else
|
||||
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(...)
|
||||
{
|
||||
ERASE_ALL();
|
||||
Logger::error("Legacy combo map conversion failed!");
|
||||
}
|
||||
}
|
||||
|
||||
saveComboMapping();
|
||||
return convertedMapping;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -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));
|
||||
}
|
||||
myOSystem.settings().setValue("combomap", buf.str());
|
||||
// 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", 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
|
||||
|
@ -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 = {
|
||||
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -349,7 +349,8 @@ 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 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)
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -219,15 +219,20 @@ class FBSurface
|
|||
@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 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,
|
||||
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);
|
||||
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.
|
||||
|
@ -239,13 +244,19 @@ class FBSurface
|
|||
@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 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,
|
||||
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);
|
||||
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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
;
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 ? */
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
@ -243,11 +244,17 @@ inline void M6502::_execute(uInt64 cycles, DispatchResult& result)
|
|||
myJustHitReadTrapFlag = myJustHitWriteTrapFlag = false;
|
||||
|
||||
myLastBreakCycle = mySystem->cycles();
|
||||
result.setDebugger(currentCycles, myHitTrapInfo.message,
|
||||
|
||||
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,30 +267,44 @@ inline void M6502::_execute(uInt64 cycles, DispatchResult& result)
|
|||
if(myBreakPoints.get(PC, bank) & BreakpointMap::ONE_SHOT)
|
||||
{
|
||||
myBreakPoints.erase(PC, bank);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
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");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int cond = evalCondBreaks();
|
||||
if(cond > -1)
|
||||
{
|
||||
ostringstream msg;
|
||||
|
||||
msg << "CBP[" << Common::Base::HEX2 << cond << "]: " << myCondBreakNames[cond];
|
||||
|
||||
myLastBreakCycle = mySystem->cycles();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int cond = evalCondSaveStates();
|
||||
if(cond > -1)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -111,6 +111,7 @@ OSystem::OSystem()
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
OSystem::~OSystem()
|
||||
{
|
||||
cerr << "~OSystem()\n";
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -679,6 +689,13 @@ void Settings::usage() const
|
|||
#endif
|
||||
<< " -dev.thumb.trapfatal <1|0> Determines whether errors in ARM emulation\n"
|
||||
<< " throw an exception\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"
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,9 +110,22 @@ 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); }
|
||||
|
||||
#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
|
||||
/**
|
||||
|
@ -96,7 +140,7 @@ class Thumbulator
|
|||
|
||||
@param enable Enable (the default) or disable exceptions on fatal errors
|
||||
*/
|
||||
static void trapFatalErrors(bool enable) { trapOnFatal = enable; }
|
||||
void trapFatalErrors(bool enable) { trapOnFatal = enable; }
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
@ -155,12 +199,29 @@ 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);
|
||||
|
@ -193,6 +254,14 @@ class Thumbulator
|
|||
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,25 +271,57 @@ 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
|
||||
#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
|
||||
ostringstream statusMsg;
|
||||
bool trapOnFatal{true};
|
||||
#endif
|
||||
bool _countCycles{false};
|
||||
bool _lockMamcr{false};
|
||||
|
||||
static bool trapOnFatal;
|
||||
#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;
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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(); }
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -71,6 +71,7 @@ class ContextMenu : public Dialog, public CommandSender
|
|||
/** Accessor methods for the currently selected item. */
|
||||
int getSelected() const;
|
||||
const string& getSelectedName() const;
|
||||
void setSelectedName(const string& name);
|
||||
const Variant& getSelectedTag() const;
|
||||
|
||||
/** This dialog uses its own positioning, so we override Dialog::setPosition() */
|
||||
|
|