Merge branch 'master' into refactoring/frame_manager

This commit is contained in:
Christian Speckner 2017-09-27 23:27:44 +02:00
commit 7965b84553
303 changed files with 6364 additions and 5657 deletions

83
.vscode/c_cpp_properties.json vendored Normal file
View File

@ -0,0 +1,83 @@
{
"configurations": [
{
"name": "Mac",
"includePath": [
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1",
"/usr/local/include",
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/9.0.0/include",
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include",
"/usr/include",
"${workspaceRoot}",
"${workspaceRoot}/src/common",
"${workspaceRoot}/src/common/tv_filters",
"${workspaceRoot}/src/gui",
"${workspaceRoot}/src/emucore",
"${workspaceRoot}/src/emucore/tia",
"${workspaceRoot}/src/unix",
"${workspaceRoot}/src/debugger",
"${workspaceRoot}/src/debugger/gui",
"${workspaceRoot}/src/cheat",
"/usr/local/include/SDL2"
],
"defines": ["DEBUGGER_SUPPORT"],
"intelliSenseMode": "clang-x64",
"browse": {
"path": [
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1",
"/usr/local/include",
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/9.0.0/include",
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include",
"/usr/include",
"${workspaceRoot}"
],
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": ""
},
"macFrameworkPath": [
"/System/Library/Frameworks",
"/Library/Frameworks"
]
},
{
"name": "Linux",
"includePath": [
"/usr/include",
"/usr/local/include",
"${workspaceRoot}"
],
"defines": [],
"intelliSenseMode": "clang-x64",
"browse": {
"path": [
"/usr/include",
"/usr/local/include",
"${workspaceRoot}"
],
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": ""
}
},
{
"name": "Win32",
"includePath": [
"C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include",
"${workspaceRoot}"
],
"defines": [
"_DEBUG",
"UNICODE"
],
"intelliSenseMode": "msvc-x64",
"browse": {
"path": [
"C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include/*",
"${workspaceRoot}"
],
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": ""
}
}
],
"version": 3
}

13
.vscode/settings.json vendored
View File

@ -1,14 +1,5 @@
// Platzieren Sie Ihre Einstellungen in dieser Datei, um Standard- und Benutzereinstellungen zu überschreiben.
{
"clang.cxxflags": [
"-std=c++11",
"-I/home/cnspeckn/git/stella/src/common",
"-I/home/cnspeckn/git/stella/src/emucore",
"-I/home/cnspeckn/git/stella/src/emucore/tia",
"-I/home/cnspeckn/git/stella/src/debugger",
"-I/home/cnspeckn/git/stella/src/debugger/gui",
"-I/home/cnspeckn/git/stella/src/gui"
],
"editor.tabSize": 2,
"files.trimTrailingWhitespace": true,
"files.exclude": {
@ -19,5 +10,7 @@
"src/**/*.o": true
},
"editor.trimAutoWhitespace": true,
"editor.useTabStops": false
"editor.useTabStops": false,
"C_Cpp.intelliSenseEngine": "Default",
"files.insertFinalNewline": true
}

View File

@ -9,7 +9,7 @@
SSSS ttt eeeee llll llll aaaaa
===========================================================================
Release 5.0.1 for Linux, MacOSX and Windows
Release 5.0.2 for Linux, MacOSX and Windows
===========================================================================
The Atari 2600 Video Computer System (VCS), introduced in 1977, was the
@ -21,30 +21,30 @@ all of your favourite Atari 2600 games again! Stella was originally
developed for Linux by Bradford W. Mott, however, it has been ported to a
number of other platforms and is currently maintained by Stephen Anthony.
This is the 5.0.1 release of Stella for Linux, Mac OSX and Windows. The
This is the 5.0.2 release of Stella for Linux, Mac OSX and Windows. The
distributions currently available are:
* Binaries for Windows XP_SP3(*)/Vista/7/8/10 :
Stella-5.0.1-win32.exe (32-bit EXE installer)
Stella-5.0.1-x64.exe (64-bit EXE installer)
Stella-5.0.1-windows.zip (32/64 bit versions)
Stella-5.0.2-win32.exe (32-bit EXE installer)
Stella-5.0.2-x64.exe (64-bit EXE installer)
Stella-5.0.2-windows.zip (32/64 bit versions)
(*) Note: Support for Windows XP is problematic on some systems,
and will probably be discontinued in a future release.
* Binary distribution for MacOS X 10.7 and above :
Stella-5.0.1-macosx.dmg (64-bit Intel)
Stella-5.0.2-macosx.dmg (64-bit Intel)
* Binary distribution in 32-bit & 64-bit Ubuntu DEB format :
stella_5.0.1-1_i386.deb
stella_5.0.1-1_amd64.deb
stella_5.0.2-1_i386.deb
stella_5.0.2-1_amd64.deb
* Binary distribution in 32-bit & 64-bit RPM format :
stella-5.0.1-2.i386.rpm
stella-5.0.1-2.x86_64.rpm
stella-5.0.2-2.i386.rpm
stella-5.0.2-2.x86_64.rpm
* Source code distribution for all platforms :
stella-5.0.1-src.tar.xz
stella-5.0.2-src.tar.xz
Distribution Site

View File

@ -12,6 +12,102 @@
Release History
===========================================================================
5.0.2 to 5.0.3: (August xx, 2017)
* Huge improvements to the disassembly view in the debugger:
- TODO: add items ...
* Fixed Genesis controller autodetect (Stay Frosty 2, Scramble, etc).
* Fixed a bug in ystart autodetection that could cause screen jumps.
* Fixed several bugs in holdselect, holdreset and holdjoyX commandline
arguments; these now work as expected.
* Fixed bug in TIA collision handling; it is now disabled in VBlank.
* Fixed wrong display of HM values in debugger after 'HMCLR' has been
executed.
* Fixed bug with the debugger 'savedis' command in Windows; it wasn't
actually saving the files at all. This has never been reported
before, so I guess it shows how many people use that functionality.
* The debugger 'savedis', 'saverom' and 'saveses' now save files in
a default, user-visible directory (see the documentation for more
information). In the case of 'saveses', the filename is now named
based on the date and time of when the command was entered.
* Fixed bug with saving snapshots in 1x mode; there was graphical
corruption in some cases. Such snapshots also now include any TV
effects / phosphor blending currently in use.
* Fixed regular-sized snapshots when phosphor effect was enabled;
sometimes the image was 'double-blended', resulting in a snapshot that
was too dark.
* Added debugger pseudo-register '_fcycles', which gives the number of
CPU cycles that have occurred since the frame started.
* Extended debugger 'dump' command to take a second argument, indicating
the end of the range to dump data.
* Improved emulation of 'FE' bankswitch scheme (no user-visible changes,
but internally the emulation is much more accurate compared to the
real thing). Related to this, improved the debugger support for this
scheme (you can now switch banks in the debugger view).
* Added ROM properties for 'Scramble' ROMs, and updated info for all
"Champ Games" ROMs.
* Added ROM properties for 'Zippy the Porcupine' ROMs, and updated
info for all "Chris Spry (Sprybug)" ROMs.
* Fix error when building with uClibc-ng for ARM (thanks to Sergio Prado).
* Updated included PNG library to latest stable version.
-Have fun!
5.0.1 to 5.0.2: (August 20, 2017)
* Improved emulation of Trakball controller, eliminating bias in left/
right directions. Thanks to Thomas Jentzsch for the idea and code.
Related to this, added 'tsense' commandline argument and associated
UI item, to allow changing sensitivity of mouse trackball emulation.
* Added preliminary support for multi-threading in the Blargg TV effects
code. This is still a WIP; more improvements are coming. Related to
this, further optimized the TIA rendering code. Also added 'threads'
commandline argument and associated UI item to enable/disable
multi-threading. Thanks to Thomas Jentzsch for the bulk of the work
in this area.
* Blargg TV effects now no longer cut off the right side of the image
(by several pixels) in certain cases.
* Updated CDF scheme to latest version from Spiceware. In addition,
this scheme now supports versioning, so older and newer ROMs will
continue to work.
* Fixed an annoying bug in Linux, where Alt-Tab'ing out of a window and
then back again would pass a 'Tab' key event to the app, which in
most cases would navigate to the next UI element.
* Fixed potential issue with state file saving and the debugger; under
certain circumstances a rewind would give a different state than
before (note that the state file format has changed because of this).
* Fixed lockups when entering the debugger under certain circumstances.
* The debugger 'listtraps' command now shows all traps set, not just
the first one(s).
* Reverted joystick changes for Decathlon ROMs from last release, as
it was added by mistake.
5.0 to 5.0.1: (July 23, 2017)
* Fixed issues in keypad, Genesis and various other controllers that use
@ -25,8 +121,6 @@
* Codebase now uses C++14 features.
-Have fun!
4.7.3 to 5.0: (July 16, 2017)

View File

@ -27,7 +27,7 @@
srcdir ?= .
DEFINES := -D_GLIBCXX_USE_CXX11_ABI=1
LDFLAGS :=
LDFLAGS := -pthread
INCLUDES :=
LIBS :=
OBJS :=

41
configure vendored
View File

@ -378,10 +378,32 @@ echocheck "compiler version"
have_clang=no
cc_check_define __clang_version__ && have_clang=yes
if test $have_clang = no; then
cc_check_define __clang__ && have_clang=yes
fi
have_gcc=no
cc_check_define __GNUC__ && have_gcc=yes
if test "$have_clang" = yes; then
is_xcode=$( $CXX -dM -E -x c /dev/null | grep __apple_build_version__ )
if test -n "$is_xcode"; then
clang_minor=$( $CXX -dM -E -x c /dev/null | grep __clang_minor__ | sed 's/.*\([0-9][0-9]*\).*/\1/' )
clang_patch=$( $CXX -dM -E -x c /dev/null | grep __clang_patchlevel__ | sed 's/.*\([0-9][0-9]*\).*/\1/' )
clang_major=$( $CXX -dM -E -x c /dev/null | grep __clang_major__ | sed 's/.*\([0-9][0-9]*\).*/\1/' )
cxx_version="$clang_major.$clang_minor.$clang_patch"
cxx_name="XCode $cxx_version"
if test $clang_major -ge 8; then
cxx_version="$cxx_version, ok"
cxx_verc_fail=no
else
cxx_version="$cxx_version, bad"
cxx_verc_fail=bad
fi
else
cxx_name=`( $cc -v ) 2>&1 | tail -n 1 | cut -d ' ' -f 1`
cxx_version=$( $CXX -dM -E -x c /dev/null | grep __clang_version__ | sed 's/^.*[^0-9]\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*$/\1/g' 2>&1)
if test "$?" -gt 0; then
@ -403,6 +425,7 @@ if test "$have_clang" = yes; then
cxx_verc_fail=yes
;;
esac
fi
CXXFLAGS="$CXXFLAGS"
_make_def_HAVE_GCC3='HAVE_GCC3 = 1'
add_line_to_config_mk 'CXX_UPDATE_DEP_FLAG = -MMD -MF "$(*D)/$(DEPDIR)/$(*F).d" -MQ "$@" -MP'
@ -516,6 +539,10 @@ else
DEFINES="$DEFINES -DUNIX"
_host_os=unix
;;
darwin*)
DEFINES="$DEFINES -DUNIX -DDARWIN"
_host_os=darwin
;;
irix*)
DEFINES="$DEFINES -DUNIX"
_ranlib=:
@ -695,12 +722,18 @@ fi
LIBS="$LIBS `$_sdlconfig $_sdl_conf_libs`"
LD=$CXX
case $_host_os in
unix)
DEFINES="$DEFINES -DBSPF_UNIX -DHAVE_GETTIMEOFDAY"
MODULES="$MODULES $SRC/unix"
INCLUDES="$INCLUDES -I$SRC/unix"
;;
darwin)
DEFINES="$DEFINES -DBSPF_UNIX -DHAVE_GETTIMEOFDAY -DOSX_KEYS"
MODULES="$MODULES $SRC/unix"
INCLUDES="$INCLUDES -I$SRC/unix"
;;
win32)
DEFINES="$DEFINES -DBSPF_WINDOWS -DHAVE_GETTIMEOFDAY"
MODULES="$MODULES $SRC/windows"
@ -803,3 +836,11 @@ EOF
# This should be taken care of elsewhere, but I'm not sure where
rm -f stella-conf*
if test "$_host_os" = darwin; then
cat <<EOI
WARNING: plain UNIX-style builds on OSX without XCode have degraded functionality
and are unsupported. Continue on your own risk...
EOI
fi

7
debian/changelog vendored
View File

@ -1,3 +1,10 @@
stella (5.0.2-1) stable; urgency=high
* Version 5.0.2 release
-- Stephen Anthony <stephena@users.sf.net> Sun, 20 Aug 2017 17:09:59 -0230
stella (5.0.1-1) stable; urgency=high
* Version 5.0.1 release

View File

@ -541,12 +541,13 @@ that holds 'number of scanlines' on an actual console).</p>
<table border="1" cellpadding="3">
<tr><th>Function</th><th>Description</th></tr>
<tr><td> _bank</td><td> Currently selected bank</td></tr>
<tr><td> _rwport</td><td> Last address to attempt a read from the cart write port</td></tr>
<tr><td> _fcount</td><td> Number of frames since emulation started</td></tr>
<tr><td> _cclocks</td><td> Color clocks on a scanline</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> _rwport</td><td> Last address to attempt a read from the cart write port</td></tr>
<tr><td> _scan</td><td> Current scanline count</td></tr>
<tr><td> _vsync</td><td> Whether vertical sync is enabled (1 or 0)</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
@ -646,7 +647,7 @@ Type "help 'cmd'" to see extended information about the given command.</p>
delfunction - Delete function with label xx
delwatch - Delete watch &lt;xx&gt;
disasm - Disassemble address xx [yy lines] (default=PC)
dump - Dump 128 bytes of memory at address &lt;xx&gt;
dump - Dump data at address &lt;xx&gt; [to yy]
exec - Execute script file &lt;xx&gt;
exitrom - Exit emulator, return to ROM launcher
frame - Advance emulation by &lt;xx&gt; frames (default=1)
@ -676,9 +677,9 @@ listfunctions - List user-defined functions
runtopc - Run until PC is set to value xx
s - Set Stack Pointer to value xx
save - Save breaks, watches, traps to file xx
saveconfig - Save Distella config file
savedis - Save Distella disassembly
saverom - Save (possibly patched) ROM
saveconfig - Save Distella config file (with default name)
savedis - Save Distella disassembly (with default name)
saverom - Save (possibly patched) ROM (with default name)
saveses - Save console session to file xx
savesnap - Save current TIA image to PNG file
savestate - Save emulator state xx (valid args 0-9)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 469 B

After

Width:  |  Height:  |  Size: 334 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 783 B

After

Width:  |  Height:  |  Size: 509 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 780 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -10,7 +10,7 @@
<br><br>
<center><h2><b>A multi-platform Atari 2600 VCS emulator</b></h2></center>
<center><h4><b>Release 5.0.1</b></h4></center>
<center><h4><b>Release 5.0.2</b></h4></center>
<br><br>
<center><h2><b>User's Guide</b></h2></center>
@ -2039,14 +2039,21 @@
<td><pre>-dsense &lt;number&gt;</pre></td>
<td>Sensitivity for emulation of paddles when using a digital device
(ie, joystick digital axis or button, keyboard key, etc).
Valid range of values is from 1 to 10, with larger numbers causing
Valid range of values is from 1 to 20, with larger numbers causing
faster movement.</td>
</tr>
<tr>
<td><pre>-msense &lt;number&gt;</pre></td>
<td>Sensitivity for emulation of paddles when using a mouse.
Valid range of values is from 1 to 15, with larger numbers causing
Valid range of values is from 1 to 20, with larger numbers causing
faster movement.</td>
</tr>
<tr>
<td><pre>-tsense &lt;number&gt;</pre></td>
<td>Sensitivity for emulation of trackball controllers when using a mouse.
Valid range of values is from 1 to 20, with larger numbers causing
faster movement.</td>
</tr>
@ -2082,6 +2089,11 @@
<td>Disable Supercharger BIOS progress loading bars.</td>
</tr>
<tr>
<td><pre>-threads &lt;1|0&gt;</pre></td>
<td>Enable multi-threaded video rendering (may not improve performance on all systems).</td>
</tr>
<tr>
<td><pre>-snapsavedir &lt;path&gt;</pre></td>
<td>The directory to save snapshot files to.</td>
@ -2284,23 +2296,29 @@
<tr>
<td><pre>-holdjoy0 &lt;U,D,L,R,F&gt;</pre></td>
<td>Start the emulator with the left joystick direction/button held down
(ie, use 'UF' for up and fire).</td>
(ie, use 'UF' for up and fire). After entering the emulation, you will
have to press and release the direction again to release the event.</td>
</tr>
<tr>
<td><pre>-holdjoy1 &lt;U,D,L,R,F&gt;</pre></td>
<td>Start the emulator with the right joystick direction/button held down
(ie, use 'UF' for up and fire).</td>
(ie, use 'UF' for up and fire). After entering the emulation, you will
have to press and release the direction again to release the event.</td>
</tr>
<tr>
<td><pre>-holdselect</pre></td>
<td>Start the emulator with the Game Select switch held down.</td>
<td>Start the emulator with the Game Select switch held down. After entering
the emulation, you will have to press and release 'Select' to release the
event.</td>
</tr>
<tr>
<td><pre>-holdreset</pre></td>
<td>Start the emulator with the Game Reset switch held down.</td>
<td>Start the emulator with the Game Reset switch held down. After entering
the emulation, you will have to press and release 'Reset' to release the
event.</td>
</tr>
<tr>
@ -2456,6 +2474,7 @@
<tr><td>Fast SC/AR BIOS</td><td>skip progress loading bars for SuperCharger ROMs</td><td>-fastscbios</td></tr>
<tr><td>Show UI messages</td><td>overlay UI messages onscreen</td><td>-uimessages</td></tr>
<tr><td>Center window</td><td>attempt to center application window</td><td>-center</td></tr>
<tr><td>Use multi-threading</td><td>enable multi-threaded rendering</td><td>-threads</td></tr>
</table>
</td>
</tr>
@ -2527,7 +2546,7 @@
<p><b>Input Settings</b> dialog:</p>
<table border="5" cellpadding="2" frame="box" rules="none">
<tr>
<td><img src="graphics/options_input.png"></td>
<td><img src="graphics/eventmapping.png"></td>
<td>&nbsp;&nbsp;&nbsp;&nbsp;</td>
<td valign="top"><br>This dialog is described in further detail in
<b>Advanced Configuration - <a href="#Remapping">Event Remapping</a></b>.</td>
@ -2588,7 +2607,7 @@
<tr><td>Save snapshots according to</td><td>specifies how to name saved snapshots</td><td>-snapname</td></tr>
<tr><td>Continuous snapshot interval</td><td>interval (in seconds) between snapshot</td><td>-ssinterval</td></tr>
<tr><td>Overwrite existing files</td><td>whether to overwrite old snapshots</td><td>-sssingle</td></tr>
<tr><td>Disable image filtering (1x mode)</td><td>save snapshot in 1x mode, without filtering</td><td>-ss1x</td></tr>
<tr><td>Ignore scaling (1x mode)</td><td>save snapshot in 1x mode, without scaling</td><td>-ss1x</td></tr>
</table>
</td>
</tr>
@ -2696,6 +2715,7 @@
<tr><td>Joy deadzone size</td><td>Deadzone area for axes on joysticks/gamepads</td><td>-joydeadzone</td></tr>
<tr><td>Digital paddle sensitivity</td><td>Sensitivity used when emulating a paddle using a digital device</td><td>-dsense</td></tr>
<tr><td>Mouse paddle sensitivity</td><td>Sensitivity used when emulating a paddle using a mouse</td><td>-msense</td></tr>
<tr><td>Trackball sensitivity</td><td>Sensitivity used when emulating a trackball device using a mouse</td><td>-tsense</td></tr>
<tr><td>Allow all 4 ...</td><td>Allow all 4 joystick directions to be pressed simultaneously</td><td>-joyallow4</td></tr>
<tr><td>Grab mouse ...</td><td>Keep mouse in window in emulation mode</td><td>-grabmouse</td></tr>
<tr><td>Use Control key combos</td><td>Enable using Control key in keyboard actions</td><td>-ctrlcombo</td></tr>

View File

@ -0,0 +1,70 @@
//============================================================================
//
// 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-2017 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 "OSystem.hxx"
#include "Serializer.hxx"
#include "StateManager.hxx"
#include "TIA.hxx"
#include "RewindManager.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
RewindManager::RewindManager(OSystem& system, StateManager& statemgr)
: myOSystem(system),
myStateManager(statemgr)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool RewindManager::addState(const string& message)
{
RewindPtr state = make_unique<RewindState>(); // TODO: get this from object pool
Serializer& s = state->data;
s.reset(); // rewind Serializer internal buffers
if(myStateManager.saveState(s) && myOSystem.console().tia().saveDisplay(s))
{
state->message = "Rewind " + message;
// Add to the list TODO: should check against current size
myStateList.emplace_front(std::move(state));
return true;
}
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool RewindManager::rewindState()
{
if(myStateList.size() > 0)
{
RewindPtr state = std::move(myStateList.front());
myStateList.pop_front(); // TODO: add 'state' to object pool
Serializer& s = state->data;
s.reset(); // rewind Serializer internal buffers
myStateManager.loadState(s);
myOSystem.console().tia().loadDisplay(s);
// Show message indicating the rewind state
myOSystem.frameBuffer().showMessage(state->message);
return true;
}
else
return false;
}

View File

@ -0,0 +1,84 @@
//============================================================================
//
// 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-2017 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 REWIND_MANAGER_HXX
#define REWIND_MANAGER_HXX
class OSystem;
class StateManager;
#include <list>
#include "bspf.hxx"
/**
This class is used to save (and later 'rewind') system save states.
TODO: This will eventually be converted to use object pools
Currently, it uses a C++ doubly-linked list as a stack, with
add/remove happening at the front of the list
Also, the additions are currently unbounded
@author Stephen Anthony
*/
class RewindManager
{
public:
RewindManager(OSystem& system, StateManager& statemgr);
public:
/**
Add a new state file with the given message; this message will be
displayed when the state is rewound.
@param message Message to display when rewinding to this state
*/
bool addState(const string& message);
/**
Rewind one level of the state list, and display the message associated
with that state.
*/
bool rewindState();
bool empty() const { return myStateList.size() == 0; }
void clear() { myStateList.clear(); }
private:
// Maximum number of states to save
static constexpr uInt32 MAX_SIZE = 100; // FIXME: use this
OSystem& myOSystem;
StateManager& myStateManager;
struct RewindState {
Serializer data;
string message;
};
using RewindPtr = unique_ptr<RewindState>;
std::list<RewindPtr> myStateList;
private:
// Following constructors and assignment operators not supported
RewindManager() = delete;
RewindManager(const RewindManager&) = delete;
RewindManager(RewindManager&&) = delete;
RewindManager& operator=(const RewindManager&) = delete;
RewindManager& operator=(RewindManager&&) = delete;
};
#endif

View File

@ -56,14 +56,6 @@ class SoundNull : public Sound
*/
void setEnabled(bool enable) override { }
/**
The system cycle counter is being adjusting by the specified amount. Any
members using the system cycle counter should be adjusted as needed.
@param amount The amount the cycle counter is being adjusted by
*/
void adjustCycleCounter(Int32 amount) override { }
/**
Sets the number of channels (mono or stereo sound).
@ -110,7 +102,7 @@ class SoundNull : public Sound
@param value The value to save into the register
@param cycle The system cycle at which the register is being updated
*/
void set(uInt16 addr, uInt8 value, Int32 cycle) override { }
void set(uInt16 addr, uInt8 value, uInt64 cycle) override { }
/**
Sets the volume of the sound device to the specified level. The

View File

@ -226,12 +226,6 @@ void SoundSDL2::adjustVolume(Int8 direction)
myOSystem.frameBuffer().showMessage(message);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL2::adjustCycleCounter(Int32 amount)
{
myLastRegisterSetCycle += amount;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL2::setChannels(uInt32 channels)
{
@ -249,7 +243,7 @@ void SoundSDL2::setFrameRate(float framerate)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL2::set(uInt16 addr, uInt8 value, Int32 cycle)
void SoundSDL2::set(uInt16 addr, uInt8 value, uInt64 cycle)
{
SDL_LockAudio();
@ -261,11 +255,7 @@ void SoundSDL2::set(uInt16 addr, uInt8 value, Int32 cycle)
// the sound to "scale" correctly, we have to know the games real frame
// rate (e.g., 50 or 60) and the currently emulated frame rate. We use these
// values to "scale" the time before the register change occurs.
RegWrite info;
info.addr = addr;
info.value = value;
info.delta = delta;
myRegWriteQueue.enqueue(info);
myRegWriteQueue.enqueue(addr, value, delta);
// Update last cycle counter to the current cycle
myLastRegisterSetCycle = cycle;
@ -390,7 +380,7 @@ bool SoundSDL2::save(Serializer& out) const
for(int i = 0; i < 6; ++i)
out.putByte(0);
out.putInt(myLastRegisterSetCycle);
out.putLong(myLastRegisterSetCycle);
}
catch(...)
{
@ -427,7 +417,7 @@ bool SoundSDL2::load(Serializer& in)
for(int i = 0; i < 6; ++i)
in.getByte();
myLastRegisterSetCycle = in.getInt();
myLastRegisterSetCycle = in.getLong();
}
catch(...)
{
@ -476,14 +466,17 @@ double SoundSDL2::RegWriteQueue::duration() const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL2::RegWriteQueue::enqueue(const RegWrite& info)
void SoundSDL2::RegWriteQueue::enqueue(uInt16 addr, uInt8 value, double delta)
{
// If an attempt is made to enqueue more than the queue can hold then
// we'll enlarge the queue's capacity.
if(mySize == myCapacity)
grow();
myBuffer[myTail] = info;
RegWrite& reg = myBuffer[myTail];
reg.addr = addr;
reg.value = value;
reg.delta = delta;
myTail = (myTail + 1) % myCapacity;
++mySize;
}

View File

@ -55,14 +55,6 @@ class SoundSDL2 : public Sound
*/
void setEnabled(bool state) override;
/**
The system cycle counter is being adjusting by the specified amount. Any
members using the system cycle counter should be adjusted as needed.
@param amount The amount the cycle counter is being adjusted by
*/
void adjustCycleCounter(Int32 amount) override;
/**
Sets the number of channels (mono or stereo sound). Note that this
determines how the emulation should 'mix' the channels of the TIA sound
@ -113,7 +105,7 @@ class SoundSDL2 : public Sound
@param value The value to save into the register
@param cycle The system cycle at which the register is being updated
*/
void set(uInt16 addr, uInt8 value, Int32 cycle) override;
void set(uInt16 addr, uInt8 value, uInt64 cycle) override;
/**
Sets the volume of the sound device to the specified level. The
@ -174,6 +166,9 @@ class SoundSDL2 : public Sound
uInt16 addr;
uInt8 value;
double delta;
RegWrite(uInt16 a = 0, uInt8 v = 0, double d = 0.0)
: addr(a), value(v), delta(d) { }
};
/**
@ -209,7 +204,7 @@ class SoundSDL2 : public Sound
/**
Enqueue the specified object.
*/
void enqueue(const RegWrite& info);
void enqueue(uInt16 addr, uInt8 value, double delta);
/**
Return the item at the front on the queue.
@ -255,7 +250,7 @@ class SoundSDL2 : public Sound
bool myIsInitializedFlag;
// Indicates the cycle when a sound register was last set
Int32 myLastRegisterSetCycle;
uInt64 myLastRegisterSetCycle;
// Indicates the number of channels (mono or stereo)
uInt32 myNumChannels;

View File

@ -28,22 +28,23 @@
#include "StateManager.hxx"
#define STATE_HEADER "05000000state"
#define STATE_HEADER "05000302state"
#define MOVIE_HEADER "03030000movie"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
StateManager::StateManager(OSystem& osystem)
: myOSystem(osystem),
myCurrentSlot(0),
myActiveMode(kOffMode)
myActiveMode(Mode::Off)
{
myRewindManager = make_unique<RewindManager>(myOSystem, *this);
reset();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool StateManager::toggleRecordMode()
{
#if 0
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void StateManager::toggleRecordMode()
{
if(myActiveMode != kMovieRecordMode) // Turn on movie record mode
{
myActiveMode = kOffMode;
@ -80,15 +81,8 @@ bool StateManager::toggleRecordMode()
}
return myActiveMode == kMovieRecordMode;
#endif
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool StateManager::toggleRewindMode()
{
////////////////////////////////////////////////////////
// FIXME - For now, I'm going to use this to activate movie playback
#if 0
// Close the writer, since we're about to re-open in read mode
myMovieWriter.close();
@ -127,34 +121,44 @@ bool StateManager::toggleRewindMode()
myMovieReader.close();
return false;
}
return myActiveMode == kMoviePlaybackMode;
}
#endif
return false;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void StateManager::toggleRewindMode()
{
myActiveMode = myActiveMode == Mode::Rewind ? Mode::Off : Mode::Rewind;
if(myActiveMode == Mode::Rewind)
myOSystem.frameBuffer().showMessage("Continuous rewind enabled");
else
myOSystem.frameBuffer().showMessage("Continuous rewind disabled");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void StateManager::update()
{
#if 0
switch(myActiveMode)
{
case kMovieRecordMode:
case Mode::Rewind:
myRewindManager->addState("1 frame");
break;
#if 0
case Mode::MovieRecord:
myOSystem.console().controller(Controller::Left).save(myMovieWriter);
myOSystem.console().controller(Controller::Right).save(myMovieWriter);
myOSystem.console().switches().save(myMovieWriter);
break;
case kMoviePlaybackMode:
case Mode::MoviePlayback:
myOSystem.console().controller(Controller::Left).load(myMovieReader);
myOSystem.console().controller(Controller::Right).load(myMovieReader);
myOSystem.console().switches().load(myMovieReader);
break;
#endif
default:
break;
}
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -20,6 +20,7 @@
class OSystem;
#include "RewindManager.hxx"
#include "Serializer.hxx"
/**
@ -32,41 +33,58 @@ class OSystem;
class StateManager
{
public:
enum class Mode {
Off,
Rewind,
MovieRecord,
MoviePlayback
};
/**
Create a new statemananger class
Create a new statemananger class.
*/
StateManager(OSystem& osystem);
public:
/**
Answers whether the manager is in record or playback mode
Answers whether the manager is in record or playback mode.
*/
bool isActive() const { return myActiveMode != kOffMode; }
Mode mode() const { return myActiveMode; }
bool toggleRecordMode();
bool toggleRewindMode();
#if 0
/**
Toggle movie recording mode (FIXME - currently disabled)
*/
void toggleRecordMode();
#endif
/**
Updates the state of the system based on the currently active mode
Toggle state rewind recording mode; this uses the RewindManager
for its functionality.
*/
void toggleRewindMode();
/**
Updates the state of the system based on the currently active mode.
*/
void update();
/**
Load a state into the current system
Load a state into the current system.
@param slot The state 'slot' to load state from
*/
void loadState(int slot = -1);
/**
Save the current state from the system
Save the current state from the system.
@param slot The state 'slot' to save into
*/
void saveState(int slot = -1);
/**
Switches to the next higher state slot (circular queue style)
Switches to the next higher state slot (circular queue style).
*/
void changeState();
@ -91,19 +109,16 @@ class StateManager
bool saveState(Serializer& out);
/**
Resets manager to defaults
Resets manager to defaults.
*/
void reset();
private:
enum Mode {
kOffMode,
kMoviePlaybackMode,
kMovieRecordMode,
kRewindPlaybackMode,
kRewindRecordMode
};
/**
The rewind facility for the state manager
*/
RewindManager& rewindManager() const { return *myRewindManager; }
private:
enum {
kVersion = 001
};
@ -124,6 +139,9 @@ class StateManager
Serializer myMovieWriter;
Serializer myMovieReader;
// Stored savestates to be later rewound
unique_ptr<RewindManager> myRewindManager;
private:
// Following constructors and assignment operators not supported
StateManager() = delete;

View File

@ -18,7 +18,7 @@
#ifndef VERSION_HXX
#define VERSION_HXX
#define STELLA_VERSION "5.0.1"
#define STELLA_BUILD "3487"
#define STELLA_VERSION "5.0.3_pre"
#define STELLA_BUILD "3535"
#endif

View File

@ -111,9 +111,13 @@ namespace BSPF
// Combines 'max' and 'min', and clamps value to the upper/lower value
// if it is outside the specified range
template<typename T> inline T clamp(T a, T l, T u)
template<class T> inline T clamp(T val, T lower, T upper)
{
return (a<l) ? l : (a>u) ? u : a;
return (val < lower) ? lower : (val > upper) ? upper : val;
}
template<class T> inline void clamp(T& val, T lower, T upper, T setVal)
{
if(val < lower || val > upper) val = setVal;
}
// Compare two strings, ignoring case

View File

@ -10,6 +10,8 @@ MODULE_OBJS := \
src/common/FSNodeZIP.o \
src/common/PNGLibrary.o \
src/common/MouseControl.o \
src/common/RewindManager.o \
src/common/StateManager.o \
src/common/ZipHandler.o
MODULE_DIRS += \

View File

@ -15,6 +15,7 @@
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include <thread>
#include "AtariNTSC.hxx"
// blitter related
@ -66,11 +67,65 @@ void AtariNTSC::initializePalette(const uInt8* palette)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AtariNTSC::render(const uInt8* atari_in, uInt32 in_width,
uInt32 in_height, void* rgb_out, uInt32 out_pitch)
void AtariNTSC::enableThreading(bool enable)
{
uInt32 systemThreads = enable ? std::thread::hardware_concurrency() : 0;
if(systemThreads <= 1)
{
myWorkerThreads = 0;
myTotalThreads = 1;
}
else
{
systemThreads = std::min(4u, systemThreads);
myWorkerThreads = systemThreads - 1;
myTotalThreads = systemThreads;
myThreads = make_unique<std::thread[]>(myWorkerThreads);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AtariNTSC::render(const uInt8* atari_in, const uInt32 in_width, const uInt32 in_height,
void* rgb_out, const uInt32 out_pitch, uInt32* rgb_in)
{
// Spawn the threads...
for(uInt32 i = 0; i < myWorkerThreads; ++i)
{
myThreads[i] = std::thread([=] {
rgb_in == nullptr ?
renderThread(atari_in, in_width, in_height, myTotalThreads, i+1, rgb_out, out_pitch) :
renderWithPhosphorThread(atari_in, in_width, in_height, myTotalThreads, i+1, rgb_in, rgb_out, out_pitch);
});
}
// Make the main thread busy too
rgb_in == nullptr ?
renderThread(atari_in, in_width, in_height, myTotalThreads, 0, rgb_out, out_pitch) :
renderWithPhosphorThread(atari_in, in_width, in_height, myTotalThreads, 0, rgb_in, rgb_out, out_pitch);
// ...and make them join again
for(uInt32 i = 0; i < myWorkerThreads; ++i)
myThreads[i].join();
// Copy phosphor values into out buffer
if(rgb_in != nullptr)
memcpy(rgb_out, rgb_in, in_height * out_pitch);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AtariNTSC::renderThread(const uInt8* atari_in, const uInt32 in_width,
const uInt32 in_height, const uInt32 numThreads, const uInt32 threadNum,
void* rgb_out, const uInt32 out_pitch)
{
// Adapt parameters to thread number
const uInt32 yStart = in_height * threadNum / numThreads;
const uInt32 yEnd = in_height * (threadNum + 1) / numThreads;
atari_in += in_width * yStart;
rgb_out = static_cast<char*>(rgb_out) + out_pitch * yStart;
uInt32 const chunk_count = (in_width - 1) / PIXEL_in_chunk;
while ( in_height-- )
for(uInt32 y = yStart; y < yEnd; ++y)
{
const uInt8* line_in = atari_in;
ATARI_NTSC_BEGIN_ROW(NTSC_black, line_in[0]);
@ -79,7 +134,7 @@ void AtariNTSC::render(const uInt8* atari_in, uInt32 in_width,
for(uInt32 n = chunk_count; n; --n)
{
/* order of input and output pixels must not be altered */
// order of input and output pixels must not be altered
ATARI_NTSC_COLOR_IN(0, line_in[0]);
ATARI_NTSC_RGB_OUT_8888(0, line_out[0]);
ATARI_NTSC_RGB_OUT_8888(1, line_out[1]);
@ -95,8 +150,8 @@ void AtariNTSC::render(const uInt8* atari_in, uInt32 in_width,
line_out += 7;
}
/* finish final pixels */
ATARI_NTSC_COLOR_IN( 0, NTSC_black );
// finish final pixels
ATARI_NTSC_COLOR_IN(0, line_in[0]);
ATARI_NTSC_RGB_OUT_8888(0, line_out[0]);
ATARI_NTSC_RGB_OUT_8888(1, line_out[1]);
ATARI_NTSC_RGB_OUT_8888(2, line_out[2]);
@ -107,11 +162,157 @@ void AtariNTSC::render(const uInt8* atari_in, uInt32 in_width,
ATARI_NTSC_RGB_OUT_8888(5, line_out[5]);
ATARI_NTSC_RGB_OUT_8888(6, line_out[6]);
line_in += 2;
line_out += 7;
ATARI_NTSC_COLOR_IN(0, NTSC_black);
ATARI_NTSC_RGB_OUT_8888(0, line_out[0]);
ATARI_NTSC_RGB_OUT_8888(1, line_out[1]);
ATARI_NTSC_RGB_OUT_8888(2, line_out[2]);
ATARI_NTSC_RGB_OUT_8888(3, line_out[3]);
ATARI_NTSC_COLOR_IN(1, NTSC_black);
ATARI_NTSC_RGB_OUT_8888(4, line_out[4]);
#if 0
ATARI_NTSC_RGB_OUT_8888(5, line_out[5]);
ATARI_NTSC_RGB_OUT_8888(6, line_out[6]);
#endif
atari_in += in_width;
rgb_out = static_cast<char*>(rgb_out) + out_pitch;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AtariNTSC::renderWithPhosphorThread(const uInt8* atari_in, const uInt32 in_width,
const uInt32 in_height, const uInt32 numThreads, const uInt32 threadNum,
uInt32* rgb_in, void* rgb_out, const uInt32 out_pitch)
{
// Adapt parameters to thread number
const uInt32 yStart = in_height * threadNum / numThreads;
const uInt32 yEnd = in_height * (threadNum + 1) / numThreads;
uInt32 bufofs = AtariNTSC::outWidth(in_width) * yStart;
uInt32* out = static_cast<uInt32*>(rgb_out);
atari_in += in_width * yStart;
rgb_out = static_cast<char*>(rgb_out) + out_pitch * yStart;
uInt32 const chunk_count = (in_width - 1) / PIXEL_in_chunk;
for(uInt32 y = yStart; y < yEnd; ++y)
{
const uInt8* line_in = atari_in;
ATARI_NTSC_BEGIN_ROW(NTSC_black, line_in[0]);
uInt32* restrict line_out = static_cast<uInt32*>(rgb_out);
++line_in;
for(uInt32 n = chunk_count; n; --n)
{
// order of input and output pixels must not be altered
ATARI_NTSC_COLOR_IN(0, line_in[0]);
ATARI_NTSC_RGB_OUT_8888(0, line_out[0]);
ATARI_NTSC_RGB_OUT_8888(1, line_out[1]);
ATARI_NTSC_RGB_OUT_8888(2, line_out[2]);
ATARI_NTSC_RGB_OUT_8888(3, line_out[3]);
ATARI_NTSC_COLOR_IN(1, line_in[1]);
ATARI_NTSC_RGB_OUT_8888(4, line_out[4]);
ATARI_NTSC_RGB_OUT_8888(5, line_out[5]);
ATARI_NTSC_RGB_OUT_8888(6, line_out[6]);
line_in += 2;
line_out += 7;
}
// finish final pixels
ATARI_NTSC_COLOR_IN(0, line_in[0]);
ATARI_NTSC_RGB_OUT_8888(0, line_out[0]);
ATARI_NTSC_RGB_OUT_8888(1, line_out[1]);
ATARI_NTSC_RGB_OUT_8888(2, line_out[2]);
ATARI_NTSC_RGB_OUT_8888(3, line_out[3]);
ATARI_NTSC_COLOR_IN(1, NTSC_black);
ATARI_NTSC_RGB_OUT_8888(4, line_out[4]);
ATARI_NTSC_RGB_OUT_8888(5, line_out[5]);
ATARI_NTSC_RGB_OUT_8888(6, line_out[6]);
line_in += 2;
line_out += 7;
ATARI_NTSC_COLOR_IN(0, NTSC_black);
ATARI_NTSC_RGB_OUT_8888(0, line_out[0]);
ATARI_NTSC_RGB_OUT_8888(1, line_out[1]);
ATARI_NTSC_RGB_OUT_8888(2, line_out[2]);
ATARI_NTSC_RGB_OUT_8888(3, line_out[3]);
ATARI_NTSC_COLOR_IN(1, NTSC_black);
ATARI_NTSC_RGB_OUT_8888(4, line_out[4]);
#if 0
ATARI_NTSC_RGB_OUT_8888(5, line_out[5]);
ATARI_NTSC_RGB_OUT_8888(6, line_out[6]);
#endif
// Do phosphor mode (blend the resulting frames)
// Note: The code assumes that AtariNTSC::outWidth(kTIAW) == outPitch == 565
for (uInt32 x = AtariNTSC::outWidth(in_width) / 8; x; --x)
{
// Store back into displayed frame buffer (for next frame)
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
bufofs++;
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
bufofs++;
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
bufofs++;
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
bufofs++;
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
bufofs++;
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
bufofs++;
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
bufofs++;
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
bufofs++;
}
// finish final pixels
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
bufofs++;
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
bufofs++;
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
bufofs++;
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
bufofs++;
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
bufofs++;
#if 0
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
bufofs++;
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
bufofs++;
#endif
atari_in += in_width;
rgb_out = static_cast<char*>(rgb_out) + out_pitch;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline uInt32 AtariNTSC::getRGBPhosphor(const uInt32 c, const uInt32 p) const
{
#define TO_RGB(color, red, green, blue) \
const uInt8 red = color >> 16; const uInt8 green = color >> 8; const uInt8 blue = color;
TO_RGB(c, rc, gc, bc);
TO_RGB(p, rp, gp, bp);
// Mix current calculated frame with previous displayed frame
const uInt8 rn = myPhosphorPalette[rc][rp];
const uInt8 gn = myPhosphorPalette[gc][gp];
const uInt8 bn = myPhosphorPalette[bc][bp];
return (rn << 16) | (gn << 8) | bn;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AtariNTSC::init(init_t& impl, const Setup& setup)
{

View File

@ -51,6 +51,9 @@ class AtariNTSC
entry_size = 2 * 14,
};
// By default, threading is turned off
AtariNTSC() { enableThreading(false); }
// Image parameters, ranging from -1.0 to 1.0. Actual internal values shown
// in parenthesis and should remain fairly stable in future versions.
struct Setup
@ -80,27 +83,52 @@ class AtariNTSC
void initialize(const Setup& setup, const uInt8* palette);
void initializePalette(const uInt8* palette);
// Set up threading
void enableThreading(bool enable);
// Set phosphor palette, for use in Blargg + phosphor mode
void setPhosphorPalette(uInt8 palette[256][256]) {
memcpy(myPhosphorPalette, palette, 256 * 256);
}
// Filters one or more rows of pixels. Input pixels are 8-bit Atari
// palette colors.
// In_row_width is the number of pixels to get to the next input row.
// Out_pitch is the number of *bytes* to get to the next output row.
void render(const uInt8* atari_in, uInt32 in_width, uInt32 in_height,
void* rgb_out, uInt32 out_pitch);
void render(const uInt8* atari_in, const uInt32 in_width, const uInt32 in_height,
void* rgb_out, const uInt32 out_pitch, uInt32* rgb_in = nullptr);
// Number of input pixels that will fit within given output width.
// Might be rounded down slightly; use outWidth() on result to find
// rounded value.
static constexpr uInt32 inWidth( uInt32 out_width ) {
return (((out_width) / PIXEL_out_chunk - 1) * PIXEL_in_chunk + 1);
return (((out_width-5) / PIXEL_out_chunk - 1) * PIXEL_in_chunk + 1);
}
// Number of output pixels written by blitter for given input width.
// Width might be rounded down slightly; use inWidth() on result to
// find rounded value. Guaranteed not to round 160 down at all.
static constexpr uInt32 outWidth(uInt32 in_width) {
return ((((in_width) - 1) / PIXEL_in_chunk + 1)* PIXEL_out_chunk);
return ((((in_width) - 1) / PIXEL_in_chunk + 1)* PIXEL_out_chunk) + 5;
}
private:
// Threaded rendering
void renderThread(const uInt8* atari_in, const uInt32 in_width,
const uInt32 in_height, const uInt32 numThreads, const uInt32 threadNum, void* rgb_out, const uInt32 out_pitch);
void renderWithPhosphorThread(const uInt8* atari_in, const uInt32 in_width,
const uInt32 in_height, const uInt32 numThreads, const uInt32 threadNum, uInt32* rgb_in, void* rgb_out, const uInt32 out_pitch);
/**
Used to calculate an averaged color for the 'phosphor' effect.
@param c RGB Color 1 (current frame)
@param p RGB Color 2 (previous frame)
@return Averaged value of the two RGB colors
*/
uInt32 getRGBPhosphor(const uInt32 c, const uInt32 cp) const;
private:
enum {
PIXEL_in_chunk = 2, // number of input pixels read per chunk
@ -138,6 +166,12 @@ class AtariNTSC
#define LUMA_CUTOFF 0.20
uInt32 myColorTable[palette_size][entry_size];
uInt8 myPhosphorPalette[256][256];
// Rendering threads
unique_ptr<std::thread[]> myThreads;
// Number of rendering and total threads
uInt32 myWorkerThreads, myTotalThreads;
struct init_t
{

View File

@ -72,6 +72,10 @@ class NTSCFilter
myNTSC.initializePalette(myTIAPalette);
}
inline void setPhosphorPalette(uInt8 palette[256][256]) {
myNTSC.setPhosphorPalette(palette);
}
// The following are meant to be used strictly for toggling from the GUI
string setPreset(Preset preset);
@ -110,6 +114,17 @@ class NTSCFilter
{
myNTSC.render(src_buf, src_width, src_height, dest_buf, dest_pitch);
}
inline void render(uInt8* src_buf, uInt32 src_width, uInt32 src_height,
uInt32* dest_buf, uInt32 dest_pitch, uInt32* prev_buf)
{
myNTSC.render(src_buf, src_width, src_height, dest_buf, dest_pitch, prev_buf);
}
// Enable threading for the NTSC rendering
inline void enableThreading(bool enable)
{
myNTSC.enableThreading(enable);
}
private:
// Convert from atari_ntsc_setup_t values to equivalent adjustables

View File

@ -70,11 +70,11 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem)
// Banksizes greater than 4096 indicate multi-bank ROMs, but we handle only
// 4K pieces at a time
// Banksizes less than 4K use the actual value
int banksize = 0;
uInt32 banksize = 0;
myConsole.cartridge().getImage(banksize);
BankInfo info;
info.size = std::min(banksize, 4096);
info.size = std::min(banksize, 4096u);
for(int i = 0; i < myConsole.cartridge().bankCount(); ++i)
myBankInfo.push_back(info);
@ -82,8 +82,8 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem)
myBankInfo.push_back(info);
// We know the address for the startup bank right now
myBankInfo[myConsole.cartridge().startBank()].addressList.push_back(myDebugger.dpeek(0xfffc));
addLabel("START", myDebugger.dpeek(0xfffc));
myBankInfo[myConsole.cartridge().startBank()].addressList.push_front(myDebugger.dpeek(0xfffc));
addLabel("Start", myDebugger.dpeek(0xfffc, DATA));
// Add system equates
for(uInt16 addr = 0x00; addr <= 0x0F; ++addr)
@ -114,16 +114,17 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem)
myDisassembly.list.reserve(2048);
// Add settings for Distella
DiStella::settings.gfx_format =
DiStella::settings.gfxFormat =
myOSystem.settings().getInt("dis.gfxformat") == 16 ? Base::F_16 : Base::F_2;
DiStella::settings.resolve_code =
DiStella::settings.resolveCode =
myOSystem.settings().getBool("dis.resolve");
DiStella::settings.show_addresses =
DiStella::settings.showAddresses =
myOSystem.settings().getBool("dis.showaddr");
DiStella::settings.aflag = false; // Not currently configurable
DiStella::settings.fflag = true; // Not currently configurable
DiStella::settings.rflag = myOSystem.settings().getBool("dis.relocate");
DiStella::settings.bwidth = 9; // TODO - configure based on window size
DiStella::settings.aFlag = false; // Not currently configurable
DiStella::settings.fFlag = true; // Not currently configurable
DiStella::settings.rFlag = myOSystem.settings().getBool("dis.relocate");
DiStella::settings.bFlag = true; // Not currently configurable
DiStella::settings.bytesWidth = 8+1; // TODO - configure based on window size
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -263,18 +264,12 @@ bool CartDebug::disassemble(bool force)
// Only add addresses when absolutely necessary, to cut down on the
// work that Distella has to do
// Distella expects the addresses to be unique and in sorted order
if(bankChanged || !pcfound)
{
AddressList::const_iterator i;
for(i = addresses.cbegin(); i != addresses.cend(); ++i)
{
if(PC < *i)
{
addresses.insert(i, PC);
break;
}
else if(PC == *i) // already present
if (PC == *i) // already present
break;
}
// Otherwise, add the item at the end
@ -285,12 +280,12 @@ bool CartDebug::disassemble(bool force)
// Always attempt to resolve code sections unless it's been
// specifically disabled
bool found = fillDisassemblyList(info, PC);
if(!found && DiStella::settings.resolve_code)
if(!found && DiStella::settings.resolveCode)
{
// Temporarily turn off code resolution
DiStella::settings.resolve_code = false;
DiStella::settings.resolveCode = false;
fillDisassemblyList(info, PC);
DiStella::settings.resolve_code = true;
DiStella::settings.resolveCode = true;
}
}
@ -690,6 +685,9 @@ string CartDebug::loadListFile()
// The default naming/location for list files is the ROM dir based on the
// actual ROM filename
myUserAddresses.clear();
myUserLabels.clear();
if(myListFile == "")
{
FilesystemNode lst(myOSystem.romFile().getPathWithExt("") + ".lst");
@ -704,7 +702,7 @@ string CartDebug::loadListFile()
if(!in.is_open())
return DebuggerParser::red("list file '" + node.getShortPath() + "' not readable");
myUserCLabels.clear();
//myUserCLabels.clear();
while(!in.eof())
{
@ -736,7 +734,8 @@ string CartDebug::loadListFile()
char eq = '\0';
buf >> hex >> xx >> hex >> yy >> line >> eq;
if(xx >= 0 && yy >= 0 && eq == '=')
myUserCLabels.emplace(xx*256+yy, line);
//myUserCLabels.emplace(xx*256+yy, line);
addLabel(line, xx * 256 + yy);
}
}
}
@ -765,8 +764,8 @@ string CartDebug::loadSymbolFile()
if(!in.is_open())
return DebuggerParser::red("symbol file '" + node.getShortPath() + "' not readable");
myUserAddresses.clear();
myUserLabels.clear();
//myUserAddresses.clear();
//myUserLabels.clear();
while(!in.eof())
{
@ -781,8 +780,10 @@ string CartDebug::loadSymbolFile()
{
// Make sure the value doesn't represent a constant
// For now, we simply ignore constants completely
const auto& iter = myUserCLabels.find(value);
if(iter == myUserCLabels.end() || !BSPF::equalsIgnoreCase(label, iter->second))
//const auto& iter = myUserCLabels.find(value);
//if(iter == myUserCLabels.end() || !BSPF::equalsIgnoreCase(label, iter->second))
const auto& iter = myUserLabels.find(value);
if (iter == myUserLabels.end() || !BSPF::equalsIgnoreCase(label, iter->second))
{
// Check for period, and strip leading number
if(string::size_type pos = label.find_first_of(".", 0) != string::npos)
@ -955,20 +956,12 @@ string CartDebug::saveDisassembly()
if(myConsole.cartridge().bankCount() > 1)
return DebuggerParser::red("disassembly for multi-bank ROM not yet supported");
// Currently, the default naming/location for disassembly files is:
// 1) ROM dir based on properties entry name
if(myDisasmFile == "")
{
const string& propsname =
myConsole.properties().get(Cartridge_Name) + ".asm";
FilesystemNode case0(myOSystem.romFile().getParent().getPath() + propsname);
if(case0.getParent().isWritable())
myDisasmFile = case0.getPath();
else
return DebuggerParser::red("disassembly file not writable:\n " +
case0.getShortPath());
myDisasmFile = FilesystemNode(myOSystem.defaultSaveDir() + propsname).getPath();
}
FilesystemNode node(myDisasmFile);
@ -981,20 +974,23 @@ string CartDebug::saveDisassembly()
// We can't print the header to the disassembly until it's actually
// been processed; therefore buffer output to a string first
ostringstream buf;
buf << "\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;\n"
<< "; MAIN PROGRAM\n"
<< ";\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n";
buf << "\n\n;***********************************************************\n"
<< "; Bank " << myConsole.cartridge().getBank();
if (myConsole.cartridge().bankCount() > 1)
buf << " / 0.." << myConsole.cartridge().bankCount() - 1;
buf << "\n;***********************************************************\n\n";
// Use specific settings for disassembly output
// This will most likely differ from what you see in the debugger
DiStella::Settings settings;
settings.gfx_format = DiStella::settings.gfx_format;
settings.resolve_code = true;
settings.show_addresses = false;
settings.aflag = false; // Otherwise DASM gets confused
settings.fflag = DiStella::settings.fflag;
settings.rflag = DiStella::settings.rflag;
settings.bwidth = 17; // default from Distella
settings.gfxFormat = DiStella::settings.gfxFormat;
settings.resolveCode = true;
settings.showAddresses = false;
settings.aFlag = false; // Otherwise DASM gets confused
settings.fFlag = DiStella::settings.fFlag;
settings.rFlag = DiStella::settings.rFlag;
settings.bytesWidth = 8+1; // same as Stella debugger
settings.bFlag = DiStella::settings.bFlag;; // process break routine (TODO)
Disassembly disasm;
disasm.list.reserve(2048);
@ -1010,6 +1006,9 @@ string CartDebug::saveDisassembly()
DiStella distella(*this, disasm.list, info, settings,
myDisLabels, myDisDirectives, myReserved);
if (myReserved.breakFound)
addLabel("Break", myDebugger.dpeek(0xfffe));
buf << " SEG CODE\n"
<< " ORG $" << Base::HEX4 << info.offset << "\n\n";
@ -1020,55 +1019,53 @@ string CartDebug::saveDisassembly()
// Add label (if any)
if(tag.label != "")
buf << ALIGN(7) << (tag.label+":") << endl;
buf << ALIGN(4) << (tag.label) << "\n";
buf << " ";
switch(tag.type)
{
case CartDebug::CODE:
{
buf << ALIGN(25) << tag.disasm << tag.ccount << "\n";
break;
}
case CartDebug::NONE:
{
buf << "\n";
buf << ALIGN(32) << tag.disasm << tag.ccount.substr(0, 5) << tag.ctotal << tag.ccount.substr(5, 2);
if (tag.disasm.find("WSYNC") != std::string::npos)
buf << "\n;---------------------------------------";
break;
}
case CartDebug::ROW:
{
buf << tag.disasm << "\n";
buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 8*4-1) << "; $" << Base::HEX4 << tag.address << " (*)";
break;
}
case CartDebug::GFX:
{
buf << ".byte " << (settings.gfx_format == Base::F_2 ? "%" : "$")
buf << ".byte " << (settings.gfxFormat == Base::F_2 ? "%" : "$")
<< tag.bytes << " ; |";
for(int c = 12; c < 20; ++c)
buf << ((tag.disasm[c] == '\x1e') ? "#" : " ");
buf << "| $" << Base::HEX4 << tag.address << " (G)\n";
buf << ALIGN(13) << "|" << "$" << Base::HEX4 << tag.address << " (G)";
break;
}
case CartDebug::PGFX:
{
buf << ".byte " << (settings.gfx_format == Base::F_2 ? "%" : "$")
buf << ".byte " << (settings.gfxFormat == Base::F_2 ? "%" : "$")
<< tag.bytes << " ; |";
for(int c = 12; c < 20; ++c)
buf << ((tag.disasm[c] == '\x1f') ? "*" : " ");
buf << "| $" << Base::HEX4 << tag.address << " (P)\n";
buf << ALIGN(13) << "|" << "$" << Base::HEX4 << tag.address << " (P)";
break;
}
case CartDebug::DATA:
{
buf << tag.disasm.substr(0, 9) << " ; $" << Base::HEX4 << tag.address << " (D)\n";
buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 8 * 4 - 1) << "; $" << Base::HEX4 << tag.address << " (D)";
break;
}
case CartDebug::NONE:
default:
{
buf << "\n";
break;
}
}
} // switch
buf << "\n";
}
}
@ -1084,69 +1081,113 @@ string CartDebug::saveDisassembly()
<< "; Legend: * = CODE not yet run (tentative code)\n"
<< "; D = DATA directive (referenced in some way)\n"
<< "; G = GFX directive, shown as '#' (stored in player, missile, ball)\n"
<< "; P = PGFX directive, shown as '*' (stored in playfield)\n\n"
<< " processor 6502\n\n";
<< "; P = PGFX directive, shown as '*' (stored in playfield)\n"
<< "; i = indexed accessed only\n"
<< "; c = used by code executed in RAM\n"
<< "; s = used by stack\n"
<< "; ! = page crossed, 1 cycle penalty\n"
<< "\n processor 6502\n\n";
bool addrUsed = false;
for(uInt16 addr = 0x00; addr <= 0x0F; ++addr)
addrUsed = addrUsed || myReserved.TIARead[addr];
addrUsed = addrUsed || myReserved.TIARead[addr] || (mySystem.getAccessFlags(addr) & WRITE);
for(uInt16 addr = 0x00; addr <= 0x3F; ++addr)
addrUsed = addrUsed || myReserved.TIAWrite[addr];
addrUsed = addrUsed || myReserved.TIAWrite[addr] || (mySystem.getAccessFlags(addr) & DATA);
for(uInt16 addr = 0x00; addr <= 0x17; ++addr)
addrUsed = addrUsed || myReserved.IOReadWrite[addr];
if(addrUsed)
{
out << ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"
<< "; TIA AND IO CONSTANTS\n"
<< ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n";
out << "\n;-----------------------------------------------------------\n"
<< "; TIA and IO constants accessed\n"
<< ";-----------------------------------------------------------\n\n";
// TIA read access
for(uInt16 addr = 0x00; addr <= 0x0F; ++addr)
if(myReserved.TIARead[addr] && ourTIAMnemonicR[addr])
out << ALIGN(6) << ourTIAMnemonicR[addr] << " = $"
out << ALIGN(16) << ourTIAMnemonicR[addr] << "= $"
<< Base::HEX2 << right << addr << " ; (R)\n";
else if (mySystem.getAccessFlags(addr) & DATA)
out << ";" << ALIGN(16-1) << ourTIAMnemonicR[addr] << "= $"
<< Base::HEX2 << right << addr << " ; (Ri)\n";
out << "\n";
// TIA write access
for(uInt16 addr = 0x00; addr <= 0x3F; ++addr)
if(myReserved.TIAWrite[addr] && ourTIAMnemonicW[addr])
out << ALIGN(6) << ourTIAMnemonicW[addr] << " = $"
out << ALIGN(16) << ourTIAMnemonicW[addr] << "= $"
<< Base::HEX2 << right << addr << " ; (W)\n";
else if (mySystem.getAccessFlags(addr) & WRITE)
out << ";" << ALIGN(16-1) << ourTIAMnemonicW[addr] << "= $"
<< Base::HEX2 << right << addr << " ; (Wi)\n";
out << "\n";
// RIOT IO access
for(uInt16 addr = 0x00; addr <= 0x17; ++addr)
if(myReserved.IOReadWrite[addr] && ourIOMnemonic[addr])
out << ALIGN(6) << ourIOMnemonic[addr] << " = $"
out << ALIGN(16) << ourIOMnemonic[addr] << "= $"
<< Base::HEX4 << right << (addr+0x280) << "\n";
}
addrUsed = false;
for(uInt16 addr = 0x80; addr <= 0xFF; ++addr)
addrUsed = addrUsed || myReserved.ZPRAM[addr-0x80];
addrUsed = addrUsed || myReserved.ZPRAM[addr-0x80]
|| (mySystem.getAccessFlags(addr) & (DATA | WRITE))
|| (mySystem.getAccessFlags(addr|0x100) & (DATA | WRITE));
if(addrUsed)
{
out << "\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"
<< "; RIOT RAM (zero-page)\n"
<< ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n";
for(uInt16 addr = 0x80; addr <= 0xFF; ++addr)
{
bool addLine = false;
out << "\n\n;-----------------------------------------------------------\n"
<< "; RIOT RAM (zero-page) labels\n"
<< ";-----------------------------------------------------------\n\n";
for (uInt16 addr = 0x80; addr <= 0xFF; ++addr) {
bool ramUsed = (mySystem.getAccessFlags(addr) & (DATA | WRITE));
bool codeUsed = (mySystem.getAccessFlags(addr) & CODE);
bool stackUsed = (mySystem.getAccessFlags(addr|0x100) & (DATA | WRITE));
if (myReserved.ZPRAM[addr - 0x80] &&
myUserLabels.find(addr) == myUserLabels.end())
{
out << ALIGN(6) << ourZPMnemonic[addr-0x80] << " = $"
<< Base::HEX2 << right << (addr) << "\n";
}
myUserLabels.find(addr) == myUserLabels.end()) {
if (addLine)
out << "\n";
out << ALIGN(16) << ourZPMnemonic[addr - 0x80] << "= $"
<< Base::HEX2 << right << (addr)
<< (stackUsed|codeUsed ? "; (" : "")
<< (codeUsed ? "c" : "")
<< (stackUsed ? "s" : "")
<< (stackUsed | codeUsed ? ")" : "")
<< "\n";
addLine = false;
} else if (ramUsed|codeUsed|stackUsed) {
if (addLine)
out << "\n";
out << ALIGN(18) << ";" << "$"
<< Base::HEX2 << right << (addr)
<< " ("
<< (ramUsed ? "i" : "")
<< (codeUsed ? "c" : "")
<< (stackUsed ? "s" : "")
<< ")\n";
addLine = false;
} else
addLine = true;
}
}
if(myReserved.Label.size() > 0)
{
out << "\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"
<< "; NON LOCATABLE\n"
<< ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n";
out << "\n\n;-----------------------------------------------------------\n"
<< "; Non Locatable Labels\n"
<< ";-----------------------------------------------------------\n\n";
for(const auto& iter: myReserved.Label)
out << ALIGN(10) << iter.second << " = $" << iter.first << "\n";
out << ALIGN(16) << iter.second << "= $" << iter.first << "\n";
}
if(myUserLabels.size() > 0)
{
out << "\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"
<< "; USER DEFINED\n"
<< ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n";
int max_len = 0;
out << "\n\n;-----------------------------------------------------------\n"
<< "; User Defined Labels\n"
<< ";-----------------------------------------------------------\n\n";
int max_len = 16;
for(const auto& iter: myUserLabels)
max_len = std::max(max_len, int(iter.second.size()));
for(const auto& iter: myUserLabels)
@ -1162,10 +1203,9 @@ string CartDebug::saveDisassembly()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string CartDebug::saveRom()
{
const string& path = string("~") + BSPF::PATH_SEPARATOR +
myConsole.properties().get(Cartridge_Name) + ".a26";
const string& rom = myConsole.properties().get(Cartridge_Name) + ".a26";
FilesystemNode node(path);
FilesystemNode node(myOSystem.defaultSaveDir() + "ROMs\\" + rom);
ofstream out(node.getPath(), std::ios::binary);
if(out && myConsole.cartridge().saveROM(out))
return "saved ROM as " + node.getShortPath();
@ -1404,7 +1444,7 @@ void CartDebug::disasmTypeAsString(ostream& buf, uInt8 flags) const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* const CartDebug::ourTIAMnemonicR[16] = {
"CXM0P", "CXM1P", "CXP0FB", "CXP1FB", "CXM0FB", "CXM1FB", "CXBLPF", "CXPPMM",
"INPT0", "INPT1", "INPT2", "INPT3", "INPT4", "INPT5", 0, 0
"INPT0", "INPT1", "INPT2", "INPT3", "INPT4", "INPT5", "$1e", "$1f"
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1414,8 +1454,9 @@ const char* const CartDebug::ourTIAMnemonicW[64] = {
"RESP0", "RESP1", "RESM0", "RESM1", "RESBL", "AUDC0", "AUDC1", "AUDF0",
"AUDF1", "AUDV0", "AUDV1", "GRP0", "GRP1", "ENAM0", "ENAM1", "ENABL",
"HMP0", "HMP1", "HMM0", "HMM1", "HMBL", "VDELP0", "VDELP1", "VDELBL",
"RESMP0", "RESMP1", "HMOVE", "HMCLR", "CXCLR", 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
"RESMP0", "RESMP1", "HMOVE", "HMCLR", "CXCLR", "$2d", "$2e", "$2f",
"$30", "$31", "$32", "$33", "$34", "$35", "$36", "$37",
"$38", "$39", "$3a", "$3b", "$3c", "$3d", "$3e", "$3f"
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -52,9 +52,9 @@ class CartDebug : public DebuggerSystem
public:
enum DisasmType {
NONE = 0,
REFERENCED = 1 << 0, /* code somewhere in the program references it,
REFERENCED = 1 << 0, /* 0x01, code somewhere in the program references it,
i.e. LDA $F372 referenced $F372 */
VALID_ENTRY = 1 << 1, /* addresses that can have a label placed in front of it.
VALID_ENTRY = 1 << 1, /* 0x02, addresses that can have a label placed in front of it.
A good counterexample would be "FF00: LDA $FE00"; $FF01
would be in the middle of a multi-byte instruction, and
therefore cannot be labelled. */
@ -63,12 +63,14 @@ class CartDebug : public DebuggerSystem
// debugger, or specified in a Distella cfg file, and are listed in order
// of decreasing hierarchy
//
CODE = 1 << 7, // disassemble-able code segments
TCODE = 1 << 6, // (tentative) disassemble-able code segments
GFX = 1 << 5, // addresses loaded into GRPx registers
PGFX = 1 << 4, // addresses loaded into PFx registers
DATA = 1 << 3, // addresses loaded into registers other than GRPx / PFx
ROW = 1 << 2 // all other addresses
CODE = 1 << 7, // 0x80, disassemble-able code segments
TCODE = 1 << 6, // 0x40, (tentative) disassemble-able code segments
GFX = 1 << 5, // 0x20, addresses loaded into GRPx registers
PGFX = 1 << 4, // 0x10, addresses loaded into PFx registers
DATA = 1 << 3, // 0x08, addresses loaded into registers other than GRPx / PFx
ROW = 1 << 2, // 0x04, all other addresses
// special type for poke()
WRITE = TCODE // 0x40, address written to
};
struct DisassemblyTag {
DisasmType type;
@ -76,6 +78,7 @@ class CartDebug : public DebuggerSystem
string label;
string disasm;
string ccount;
string ctotal;
string bytes;
bool hllabel;
};
@ -316,6 +319,7 @@ class CartDebug : public DebuggerSystem
bool IOReadWrite[24];
bool ZPRAM[128];
AddrToLabel Label;
bool breakFound;
};
ReservedEquates myReserved;
@ -362,7 +366,7 @@ class CartDebug : public DebuggerSystem
// Mappings from label to address (and vice versa) for constants
// defined through a DASM lst file
AddrToLabel myUserCLabels;
// AddrToLabel myUserCLabels;
// LabelToAddr myUserCAddresses;
// Mappings for labels to addresses for system-defined equates

View File

@ -96,12 +96,15 @@ static const char* const pseudo_registers[][2] = {
// { "name", "help text" }
{ "_bank", "Currently selected bank" },
{ "_cclocks", "Color clocks on current scanline" },
{ "_fcount", "Number of frames since emulation started" },
{ "_fcycles", "Number of cycles since frame started" },
{ "_cyclesLo", "Lower 32 bits of number of cycles since emulation started"},
{ "_cyclesHi", "Higher 32 bits of number of cycles since emulation started"},
{ "_rwport", "Address at which a read from a write port occurred" },
{ "_scan", "Current scanline count" },
{ "_fcount", "Number of frames since emulation started" },
{ "_cclocks", "Color clocks on current scanline" },
{ "_vsync", "Whether vertical sync is enabled (1 or 0)" },
{ "_vblank", "Whether vertical blank is enabled (1 or 0)" },
{ "_vsync", "Whether vertical sync is enabled (1 or 0)" },
// empty string marks end of list, do not remove
{ 0, 0 }
@ -152,7 +155,6 @@ void Debugger::initialize()
myDialog = new DebuggerDialog(myOSystem, *this, 0, 0, myWidth, myHeight);
myBaseDialog = myDialog;
myRewindManager = make_unique<RewindManager>(myOSystem, myDialog->rewindButton());
myCartDebug->setDebugWidget(&(myDialog->cartDebug()));
}
@ -300,20 +302,19 @@ void Debugger::loadState(int state)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int Debugger::step()
{
saveOldState();
saveOldState("1 step");
mySystem.clearDirtyPages();
int cyc = mySystem.cycles();
uInt64 startCycle = mySystem.cycles();
unlockBankswitchState();
myOSystem.console().tia().updateScanlineByStep().flushLineCache();
lockBankswitchState();
return mySystem.cycles() - cyc;
return int(mySystem.cycles() - startCycle);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// trace is just like step, except it treats a subroutine call as one
// instruction.
@ -328,17 +329,17 @@ int Debugger::trace()
// 32 is the 6502 JSR instruction:
if(mySystem.peek(myCpuDebug->pc()) == 32)
{
saveOldState();
saveOldState("1 trace");
mySystem.clearDirtyPages();
int cyc = mySystem.cycles();
uInt64 startCycle = mySystem.cycles();
int targetPC = myCpuDebug->pc() + 3; // return address
unlockBankswitchState();
myOSystem.console().tia().updateScanlineByTrace(targetPC).flushLineCache();
lockBankswitchState();
return mySystem.cycles() - cyc;
return int(mySystem.cycles() - startCycle);
}
else
return step();
@ -401,7 +402,12 @@ bool Debugger::writeTrap(uInt16 t)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::nextScanline(int lines)
{
saveOldState();
ostringstream buf;
buf << lines << " scanline";
if(lines > 1)
buf << "s";
saveOldState(buf.str());
mySystem.clearDirtyPages();
unlockBankswitchState();
@ -418,7 +424,12 @@ void Debugger::nextScanline(int lines)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::nextFrame(int frames)
{
saveOldState();
ostringstream buf;
buf << frames << " frame";
if(frames > 1)
buf << "s";
saveOldState(buf.str());
mySystem.clearDirtyPages();
unlockBankswitchState();
@ -433,12 +444,16 @@ void Debugger::nextFrame(int frames)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Debugger::rewindState()
{
RewindManager& r = myOSystem.state().rewindManager();
mySystem.clearDirtyPages();
unlockBankswitchState();
bool result = myRewindManager->rewindState();
bool result = r.rewindState();
lockBankswitchState();
myDialog->rewindButton().setEnabled(!r.empty());
return result;
}
@ -468,7 +483,7 @@ bool Debugger::patchROM(uInt16 addr, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::saveOldState(bool addrewind)
void Debugger::saveOldState(string rewindMsg)
{
myCartDebug->saveOldState();
myCpuDebug->saveOldState();
@ -476,7 +491,12 @@ void Debugger::saveOldState(bool addrewind)
myTiaDebug->saveOldState();
// Add another rewind level to the Undo list
if(addrewind) myRewindManager->addState();
if(rewindMsg != "")
{
RewindManager& r = myOSystem.state().rewindManager();
r.addState(rewindMsg);
myDialog->rewindButton().setEnabled(!r.empty());
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -485,11 +505,14 @@ void Debugger::setStartState()
// Lock the bus each time the debugger is entered, so we don't disturb anything
lockBankswitchState();
// Start a new rewind list
myRewindManager->clear();
// If rewinding is not enabled, always start the debugger with a clean list
RewindManager& r = myOSystem.state().rewindManager();
if(myOSystem.state().mode() == StateManager::Mode::Off)
r.clear();
myDialog->rewindButton().setEnabled(!r.empty());
// Save initial state, but don't add it to the rewind list
saveOldState(false);
saveOldState();
// Set the 're-disassemble' flag, but don't do it until the next scheduled time
myDialog->rom().invalidate(false);
@ -634,90 +657,3 @@ void Debugger::unlockBankswitchState()
mySystem.unlockDataBus();
myConsole.cartridge().unlockBank();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Debugger::RewindManager::RewindManager(OSystem& system, ButtonWidget& button)
: myOSystem(system),
myRewindButton(button),
mySize(0),
myTop(0)
{
for(int i = 0; i < MAX_SIZE; ++i)
myStateList[i] = nullptr;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Debugger::RewindManager::~RewindManager()
{
for(int i = 0; i < MAX_SIZE; ++i)
delete myStateList[i];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Debugger::RewindManager::addState()
{
// Create a new Serializer object if we need one
if(myStateList[myTop] == nullptr)
myStateList[myTop] = new Serializer();
Serializer& s = *(myStateList[myTop]);
if(s)
{
s.reset();
if(myOSystem.state().saveState(s) && myOSystem.console().tia().saveDisplay(s))
{
// Are we still within the allowable size, or are we overwriting an item?
mySize++; if(mySize > MAX_SIZE) mySize = MAX_SIZE;
myTop = (myTop + 1) % MAX_SIZE;
myRewindButton.setEnabled(true);
return true;
}
}
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Debugger::RewindManager::rewindState()
{
if(mySize > 0)
{
mySize--;
myTop = myTop == 0 ? MAX_SIZE - 1 : myTop - 1;
Serializer& s = *(myStateList[myTop]);
s.reset();
myOSystem.state().loadState(s);
myOSystem.console().tia().loadDisplay(s);
if(mySize == 0)
myRewindButton.setEnabled(false);
return true;
}
else
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Debugger::RewindManager::empty()
{
return mySize == 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::RewindManager::clear()
{
for(int i = 0; i < MAX_SIZE; ++i)
if(myStateList[i] != nullptr)
myStateList[i]->reset();
myTop = mySize = 0;
// We use Widget::clearFlags here instead of Widget::setEnabled(),
// since the latter implies an immediate draw/update, but this method
// might be called before any UI exists
// TODO - fix this deficiency in the UI core; we shouldn't have to worry
// about such things at this level
myRewindButton.clearFlags(WIDGET_ENABLED);
}

View File

@ -26,7 +26,6 @@ class TiaZoomWidget;
class EditTextWidget;
class RomWidget;
class Expression;
class Serializer;
class PackedBitArray;
class PromptWidget;
class ButtonWidget;
@ -154,11 +153,6 @@ class Debugger : public DialogContainer
*/
const string run(const string& command);
/**
The current cycle count of the System.
*/
int cycles() const { return int(mySystem.cycles()); }
string autoExec();
string showWatches();
@ -212,8 +206,8 @@ class Debugger : public DialogContainer
static Debugger& debugger() { return *myStaticDebugger; }
/* These are now exposed so Expressions can use them. */
int peek(int addr) { return mySystem.peek(addr); }
int dpeek(int addr) { return mySystem.peek(addr) | (mySystem.peek(addr+1) << 8); }
int peek(int addr, uInt8 flags = 0) { return mySystem.peek(addr, flags); }
int dpeek(int addr, uInt8 flags = 0) { return mySystem.peek(addr, flags) | (mySystem.peek(addr+1, flags) << 8); }
int getAccessFlags(uInt16 addr) const
{ return mySystem.getAccessFlags(addr); }
void setAccessFlags(uInt16 addr, uInt8 flags)
@ -237,8 +231,11 @@ class Debugger : public DialogContainer
private:
/**
Save state of each debugger subsystem.
If a message is provided, we assume that a rewind state should
be saved with the given message.
*/
void saveOldState(bool addrewind = true);
void saveOldState(string rewindMsg = "");
/**
Set initial state before entering the debugger.
@ -295,38 +292,6 @@ class Debugger : public DialogContainer
uInt32 myWidth;
uInt32 myHeight;
// Class holding all rewind state functionality in the debugger
// Essentially, it's a modified circular array-based stack
// that cleverly deals with allocation/deallocation of memory
class RewindManager
{
public:
RewindManager(OSystem& system, ButtonWidget& button);
virtual ~RewindManager();
public:
bool addState();
bool rewindState();
bool empty();
void clear();
private:
enum { MAX_SIZE = 100 };
OSystem& myOSystem;
ButtonWidget& myRewindButton;
Serializer* myStateList[MAX_SIZE];
uInt32 mySize, myTop;
private:
// Following constructors and assignment operators not supported
RewindManager() = delete;
RewindManager(const RewindManager&) = delete;
RewindManager(RewindManager&&) = delete;
RewindManager& operator=(const RewindManager&) = delete;
RewindManager& operator=(RewindManager&&) = delete;
};
unique_ptr<RewindManager> myRewindManager;
private:
// Following constructors and assignment operators not supported
Debugger() = delete;

View File

@ -284,16 +284,16 @@ int DebuggerParser::decipher_arg(const string& str)
string DebuggerParser::showWatches()
{
ostringstream buf;
for(uInt32 i = 0; i < watches.size(); i++)
for(uInt32 i = 0; i < myWatches.size(); ++i)
{
if(watches[i] != "")
if(myWatches[i] != "")
{
// Clear the args, since we're going to pass them to eval()
argStrings.clear();
args.clear();
argCount = 1;
argStrings.push_back(watches[i]);
argStrings.push_back(myWatches[i]);
args.push_back(decipher_arg(argStrings[0]));
if(args[0] < 0)
buf << "BAD WATCH " << (i+1) << ": " << argStrings[0] << endl;
@ -534,13 +534,14 @@ string DebuggerParser::eval()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string DebuggerParser::trapStatus(int addr)
string DebuggerParser::trapStatus(uInt32 addr, bool& enabled)
{
string result;
result += Base::toString(addr);
result += ": ";
bool r = debugger.readTrap(addr);
bool w = debugger.writeTrap(addr);
enabled = r || w;
if(r && w)
result += "read|write";
else if(r)
@ -550,8 +551,7 @@ string DebuggerParser::trapStatus(int addr)
else
result += "none";
// TODO - technically, we should determine if the label is read or write
const string& l = debugger.cartDebug().getLabel(addr, true);
const string& l = debugger.cartDebug().getLabel(addr, !w);
if(l != "") {
result += " (";
result += l;
@ -570,11 +570,11 @@ bool DebuggerParser::saveScriptFile(string file)
ofstream out(file);
FunctionDefMap funcs = debugger.getFunctionDefMap();
for(const auto& i: funcs)
out << "function " << i.first << " { " << i.second << " }" << endl;
for(const auto& f: funcs)
out << "function " << f.first << " { " << f.second << " }" << endl;
for(const auto& i: watches)
out << "watch " << i << endl;
for(const auto& w: myWatches)
out << "watch " << w << endl;
for(uInt32 i = 0; i < 0x10000; ++i)
if(debugger.breakPoint(i))
@ -735,6 +735,7 @@ void DebuggerParser::executeClearconfig()
// "cleartraps"
void DebuggerParser::executeCleartraps()
{
myTraps.clear();
debugger.clearAllTraps();
commandResult << "all traps cleared";
}
@ -743,7 +744,7 @@ void DebuggerParser::executeCleartraps()
// "clearwatches"
void DebuggerParser::executeClearwatches()
{
watches.clear();
myWatches.clear();
commandResult << "all watches cleared";
}
@ -856,9 +857,9 @@ void DebuggerParser::executeDelfunction()
void DebuggerParser::executeDelwatch()
{
int which = args[0] - 1;
if(which >= 0 && which < int(watches.size()))
if(which >= 0 && which < int(myWatches.size()))
{
Vec::removeAt(watches, which);
Vec::removeAt(myWatches, which);
commandResult << "removed watch";
}
else
@ -890,16 +891,37 @@ void DebuggerParser::executeDisasm()
// "dump"
void DebuggerParser::executeDump()
{
for(int i = 0; i < 8; ++i)
auto dump = [&](int start, int end)
{
int start = args[0] + i*16;
commandResult << Base::toString(start) << ": ";
for(int j = 0; j < 16; ++j)
for(int i = start; i <= end; i += 16)
{
commandResult << Base::toString(debugger.peek(start+j)) << " ";
if(j == 7) commandResult << "- ";
// Print label every 16 bytes
commandResult << Base::toString(i) << ": ";
for(int j = i; j < i+16 && j <= end; ++j)
{
commandResult << Base::toString(debugger.peek(j)) << " ";
if(j == i+7 && j != end) commandResult << "- ";
}
if(i != 7) commandResult << endl;
commandResult << endl;
}
};
// Error checking
if(argCount > 1 && args[1] < args[0])
{
commandResult << red("Start address must be <= end address");
return;
}
if(argCount == 1)
dump(args[0], args[0] + 127);
else if(argCount == 2)
dump(args[0], args[1]);
else
{
commandResult << "wrong number of arguments";
return;
}
}
@ -1096,19 +1118,13 @@ void DebuggerParser::executeListfunctions()
// "listtraps"
void DebuggerParser::executeListtraps()
{
int count = 0;
for(uInt32 i = 0; i <= 0xffff; ++i)
if(myTraps.size() > 0)
{
if(debugger.readTrap(i) || debugger.writeTrap(i))
{
commandResult << trapStatus(i) << " + mirrors" << endl;
count++;
break;
bool enabled = true;
for(const auto& trap: myTraps)
commandResult << trapStatus(trap, enabled) << " + mirrors" << endl;
}
}
if(!count)
else
commandResult << "no traps set";
}
@ -1388,10 +1404,20 @@ void DebuggerParser::executeSaverom()
// "saveses"
void DebuggerParser::executeSaveses()
{
if(debugger.prompt().saveBuffer(argStrings[0]))
commandResult << "saved session to file " << argStrings[0];
// Create a file named with the current date and time
time_t currtime;
struct tm* timeinfo;
char buffer[80];
time(&currtime);
timeinfo = localtime(&currtime);
strftime(buffer, 80, "session_%F_%H-%M-%S.txt", timeinfo);
FilesystemNode file(debugger.myOSystem.defaultSaveDir() + buffer);
if(debugger.prompt().saveBuffer(file))
commandResult << "saved " + file.getShortPath() + " OK";
else
commandResult << red("I/O error");
commandResult << "Unable to save session";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1570,7 +1596,12 @@ void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write)
}
}
commandResult << trapStatus(addr) << " + mirrors" << endl;
bool trapEnabled = false;
const string& result = trapStatus(addr, trapEnabled);
if(trapEnabled) myTraps.insert(addr);
else myTraps.erase(addr);
commandResult << result << " + mirrors" << endl;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1629,7 +1660,7 @@ void DebuggerParser::executeV()
// "watch"
void DebuggerParser::executeWatch()
{
watches.push_back(argStrings[0]);
myWatches.push_back(argStrings[0]);
commandResult << "added watch \"" << argStrings[0] << "\"";
}
@ -1875,11 +1906,13 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
{
"dump",
"Dump 128 bytes of memory at address <xx>",
"Example: dump f000",
"Dump data at address <xx> [to yy]",
"Examples:\n"
" dump f000 - dumps 128 bytes @ f000\n"
" dump f000 f0ff - dumps all bytes from f000 to f0ff",
true,
false,
{ kARG_WORD, kARG_END_ARGS },
{ kARG_WORD, kARG_MULTI_BYTE },
std::mem_fn(&DebuggerParser::executeDump)
},
@ -2179,8 +2212,8 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
{
"saveconfig",
"Save Distella config file",
"Example: saveconfig file.cfg",
"Save Distella config file (with default name)",
"Example: saveconfig",
false,
false,
{ kARG_END_ARGS },
@ -2189,8 +2222,9 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
{
"savedis",
"Save Distella disassembly",
"Example: savedis file.asm",
"Save Distella disassembly (with default name)",
"Example: savedis\n"
"NOTE: saves to default save location",
false,
false,
{ kARG_END_ARGS },
@ -2199,8 +2233,9 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
{
"saverom",
"Save (possibly patched) ROM",
"Example: savedrom file.bin",
"Save (possibly patched) ROM (with default name)",
"Example: saverom\n"
"NOTE: saves to default save location",
false,
false,
{ kARG_END_ARGS },
@ -2209,11 +2244,12 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
{
"saveses",
"Save console session to file xx",
"Example: saveses session.txt",
true,
"Save console session",
"Example: saveses\n"
"NOTE: saves to default save location",
false,
{ kARG_FILE, kARG_END_ARGS },
false,
{ kARG_END_ARGS },
std::mem_fn(&DebuggerParser::executeSaveses)
},

View File

@ -20,6 +20,7 @@
#include <functional>
#include <sstream>
#include <set>
class Debugger;
class FilesystemNode;
@ -64,7 +65,6 @@ class DebuggerParser
bool getArgs(const string& command, string& verb);
bool validateArgs(int cmd);
string eval();
string trapStatus(int addr);
bool saveScriptFile(string file);
private:
@ -114,7 +114,11 @@ class DebuggerParser
StringList argStrings;
uInt32 argCount;
StringList watches;
StringList myWatches;
// Keep track of traps (read and/or write)
std::set<uInt32> myTraps;
string trapStatus(uInt32 addr, bool& enabled);
// List of available command methods
void executeA();

File diff suppressed because it is too large Load Diff

View File

@ -33,7 +33,8 @@
All 7800-related stuff has been removed, as well as some commandline options.
Over time, some of the configurability of Distella may be added again.
@author Stephen Anthony
@authors Stephen Anthony and Thomas Jentzsch
Original distella developers (http://distella.sf.net)
*/
class DiStella
{
@ -42,13 +43,14 @@ class DiStella
// This will eventually grow to include all options supported by
// standalone Distella
struct Settings {
Common::Base::Format gfx_format;
bool resolve_code; // Attempt to detect code vs. data sections
bool show_addresses; // Show PC addresses (always off for external output)
bool aflag; // Turns 'A' off in accumulator instructions (-a in Distella)
bool fflag; // Forces correct address length (-f in Distella)
bool rflag; // Relocate calls out of address range (-r in Distella)
int bwidth; // Number of bytes to use per line (with .byte xxx)
Common::Base::Format gfxFormat;
bool resolveCode; // Attempt to detect code vs. data sections
bool showAddresses; // Show PC addresses (always off for external output)
bool aFlag; // Turns 'A' off in accumulator instructions (-a in Distella)
bool fFlag; // Forces correct address length (-f in Distella)
bool rFlag; // Relocate calls out of address range (-r in Distella)
bool bFlag; // Process break routine (-b in Distella)
int bytesWidth; // Number of bytes to use per line (with .byte xxx)
};
static Settings settings; // Default settings
@ -81,9 +83,16 @@ class DiStella
// These functions are part of the original Distella code
void disasm(uInt32 distart, int pass);
void disasmPass1(CartDebug::AddressList& debuggerAddresses);
void disasmFromAddress(uInt32 distart);
bool check_range(uInt16 start, uInt16 end) const;
int mark(uInt32 address, uInt8 mask, bool directive = false);
bool check_bit(uInt16 address, uInt8 mask) const;
bool checkBit(uInt16 address, uInt8 mask, bool useDebugger = true) const;
bool checkBits(uInt16 address, uInt8 mask, uInt8 notMask, bool useDebugger = true) const;
void outputGraphics();
void outputBytes(CartDebug::DisasmType type);
// Convenience methods to generate appropriate labels
inline void labelA12High(stringstream& buf, uInt8 op, uInt16 addr, int labfound)
@ -115,6 +124,7 @@ class DiStella
stringstream myDisasmBuf;
std::queue<uInt16> myAddressQueue;
uInt16 myOffset, myPC, myPCEnd;
uInt16 mySegType;
struct resource {
uInt16 start;
@ -179,6 +189,7 @@ class DiStella
AccessMode source;
ReadWriteMode rw_mode;
uInt8 cycles;
uInt8 bytes;
};
static const Instruction_tag ourLookup[256];

View File

@ -40,10 +40,6 @@ TIADebug::TIADebug(Debugger& dbg, Console& console)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const DebuggerState& TIADebug::getState()
{
myState.ram.clear();
for(int i = 0; i < 0x010; ++i)
myState.ram.push_back(myTIA.peek(i));
// Color registers
myState.coluRegs.clear();
myState.coluRegs.push_back(coluP0());
@ -117,10 +113,6 @@ const DebuggerState& TIADebug::getState()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIADebug::saveOldState()
{
myOldState.ram.clear();
for(int i = 0; i < 0x010; ++i)
myOldState.ram.push_back(myTIA.peek(i));
// Color registers
myOldState.coluRegs.clear();
myOldState.coluRegs.push_back(coluP0());
@ -699,7 +691,25 @@ void TIADebug::setENABLOld(bool b)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int TIADebug::frameCount() const
{
return myTIA.myFrameManager.frameCount();
return myTIA.frameCount();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int TIADebug::frameCycles() const
{
return myTIA.frameCycles();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int TIADebug::cyclesLo() const
{
return (int)myTIA.cycles();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int TIADebug::cyclesHi() const
{
return (int)(myTIA.cycles() >> 32);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -38,7 +38,6 @@ enum {
class TiaState : public DebuggerState
{
public:
IntArray ram;
IntArray coluRegs;
IntArray fixedCols;
IntArray gr;
@ -160,6 +159,9 @@ class TIADebug : public DebuggerSystem
int scanlines() const;
int scanlinesLastFrame() const;
int frameCount() const;
int frameCycles() const;
int cyclesLo() const;
int cyclesHi() const;
int clocksThisLine() const;
bool vsync() const;
bool vblank() const;

View File

@ -59,7 +59,7 @@ Cartridge0840Widget::Cartridge0840Widget(
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Cartridge0840Widget::loadConfig()
{
myBank->setSelectedIndex(myCart.myCurrentBank);
myBank->setSelectedIndex(myCart.getBank());
CartDebugWidget::loadConfig();
}
@ -83,8 +83,8 @@ string Cartridge0840Widget::bankState()
ostringstream& buf = buffer();
static const char* const spot[] = { "$800", "$840" };
buf << "Bank = " << std::dec << myCart.myCurrentBank
<< ", hotspot = " << spot[myCart.myCurrentBank];
buf << "Bank = " << std::dec << myCart.getBank()
<< ", hotspot = " << spot[myCart.getBank()];
return buf.str();
}

View File

@ -134,7 +134,7 @@ void CartridgeBFSCWidget::saveOldState()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeBFSCWidget::loadConfig()
{
myBank->setSelectedIndex(myCart.myCurrentBank);
myBank->setSelectedIndex(myCart.getBank());
CartDebugWidget::loadConfig();
}
@ -167,8 +167,8 @@ string CartridgeBFSCWidget::bankState()
"$FFB0", "$FFB1", "$FFB2", "$FFB3", "$FFB4", "$FFB5", "$FFB6", "$FFB7",
"$FFB8", "$FFB9", "$FFBA", "$FFBB", "$FFBC", "$FFBD", "$FFBE", "$FFBF"
};
buf << "Bank = " << std::dec << myCart.myCurrentBank
<< ", hotspot = " << spot[myCart.myCurrentBank];
buf << "Bank = " << std::dec << myCart.getBank()
<< ", hotspot = " << spot[myCart.getBank()];
return buf.str();
}

View File

@ -121,7 +121,7 @@ CartridgeBFWidget::CartridgeBFWidget(
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeBFWidget::loadConfig()
{
myBank->setSelectedIndex(myCart.myCurrentBank);
myBank->setSelectedIndex(myCart.getBank());
CartDebugWidget::loadConfig();
}
@ -154,8 +154,8 @@ string CartridgeBFWidget::bankState()
"$FFB0", "$FFB1", "$FFB2", "$FFB3", "$FFB4", "$FFB5", "$FFB6", "$FFB7",
"$FFB8", "$FFB9", "$FFBA", "$FFBB", "$FFBC", "$FFBD", "$FFBE", "$FFBF"
};
buf << "Bank = " << std::dec << myCart.myCurrentBank
<< ", hotspot = " << spot[myCart.myCurrentBank];
buf << "Bank = " << std::dec << myCart.getBank()
<< ", hotspot = " << spot[myCart.getBank()];
return buf.str();
}

View File

@ -252,7 +252,7 @@ void CartridgeBUSWidget::saveOldState()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeBUSWidget::loadConfig()
{
myBank->setSelectedIndex(myCart.myCurrentBank);
myBank->setSelectedIndex(myCart.getBank());
// Get registers, using change tracking
IntArray alist;
@ -397,8 +397,8 @@ string CartridgeBUSWidget::bankState()
static const char* const spot[] = {
"$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB"
};
buf << "Bank = " << std::dec << myCart.myCurrentBank
<< ", hotspot = " << spot[myCart.myCurrentBank];
buf << "Bank = " << std::dec << myCart.getBank()
<< ", hotspot = " << spot[myCart.getBank()];
return buf.str();
}

View File

@ -30,7 +30,7 @@ CartridgeCDFWidget::CartridgeCDFWidget(
uInt16 size = 8 * 4096;
ostringstream info;
info << "CDF cartridge\n"
info << "CDF cartridge (version " << cart.myVersion << ")\n"
<< "32K ROM, seven 4K banks are accessible to 2600\n"
<< "8K CDF RAM\n"
<< "CDF registers accessible @ $FFF0 - $FFF3\n"
@ -230,7 +230,7 @@ void CartridgeCDFWidget::saveOldState()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeCDFWidget::loadConfig()
{
myBank->setSelectedIndex(myCart.myCurrentBank);
myBank->setSelectedIndex(myCart.getBank());
// Get registers, using change tracking
IntArray alist;
@ -360,8 +360,8 @@ string CartridgeCDFWidget::bankState()
static const char* const spot[] = {
"$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB"
};
buf << "Bank = " << std::dec << myCart.myCurrentBank
<< ", hotspot = " << spot[myCart.myCurrentBank];
buf << "Bank = " << std::dec << myCart.getBank()
<< ", hotspot = " << spot[myCart.getBank()];
return buf.str();
}

View File

@ -158,7 +158,7 @@ void CartridgeCMWidget::saveOldState()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeCMWidget::loadConfig()
{
myBank->setSelectedIndex(myCart.myCurrentBank);
myBank->setSelectedIndex(myCart.getBank());
RiotDebug& riot = Debugger::debugger().riotDebug();
const RiotState& state = static_cast<const RiotState&>(riot.getState());
@ -219,7 +219,7 @@ string CartridgeCMWidget::bankState()
{
ostringstream& buf = buffer();
buf << "Bank = " << std::dec << myCart.myCurrentBank
buf << "Bank = " << std::dec << myCart.getBank()
<< ", RAM is" << (myCart.mySWCHA & 0x10 ? " Inactive" :
myCart.mySWCHA & 0x20 ? " Read-only" : " Write-only");

View File

@ -102,7 +102,7 @@ void CartridgeDFSCWidget::saveOldState()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeDFSCWidget::loadConfig()
{
myBank->setSelectedIndex(myCart.myCurrentBank);
myBank->setSelectedIndex(myCart.getBank());
CartDebugWidget::loadConfig();
}
@ -131,8 +131,8 @@ string CartridgeDFSCWidget::bankState()
"$FFD0", "$FFD1", "$FFD2", "$FFD3", "$FFD4", "$FFD5", "$FFD6", "$FFE7",
"$FFD8", "$FFD9", "$FFDA", "$FFDB", "$FFDC", "$FFDD", "$FFDE", "$FFDF"
};
buf << "Bank = " << std::dec << myCart.myCurrentBank
<< ", hotspot = " << spot[myCart.myCurrentBank];
buf << "Bank = " << std::dec << myCart.getBank()
<< ", hotspot = " << spot[myCart.getBank()];
return buf.str();
}

View File

@ -89,7 +89,7 @@ CartridgeDFWidget::CartridgeDFWidget(
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeDFWidget::loadConfig()
{
myBank->setSelectedIndex(myCart.myCurrentBank);
myBank->setSelectedIndex(myCart.getBank());
CartDebugWidget::loadConfig();
}
@ -118,8 +118,8 @@ string CartridgeDFWidget::bankState()
"$FFD0", "$FFD1", "$FFD2", "$FFD3", "$FFD4", "$FFD5", "$FFD6", "$FFD7",
"$FFD8", "$FFD9", "$FFDA", "$FFDB", "$FFDC", "$FFDD", "$FFDE", "$FFDF"
};
buf << "Bank = " << std::dec << myCart.myCurrentBank
<< ", hotspot = " << spot[myCart.myCurrentBank];
buf << "Bank = " << std::dec << myCart.getBank()
<< ", hotspot = " << spot[myCart.getBank()];
return buf.str();
}

View File

@ -218,7 +218,7 @@ void CartridgeDPCPlusWidget::saveOldState()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeDPCPlusWidget::loadConfig()
{
myBank->setSelectedIndex(myCart.myCurrentBank);
myBank->setSelectedIndex(myCart.getBank());
// Get registers, using change tracking
IntArray alist;
@ -327,8 +327,8 @@ string CartridgeDPCPlusWidget::bankState()
static const char* const spot[] = {
"$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB"
};
buf << "Bank = " << std::dec << myCart.myCurrentBank
<< ", hotspot = " << spot[myCart.myCurrentBank];
buf << "Bank = " << std::dec << myCart.getBank()
<< ", hotspot = " << spot[myCart.getBank()];
return buf.str();
}

View File

@ -156,7 +156,7 @@ void CartridgeDPCWidget::saveOldState()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeDPCWidget::loadConfig()
{
myBank->setSelectedIndex(myCart.myCurrentBank);
myBank->setSelectedIndex(myCart.getBank());
// Get registers, using change tracking
IntArray alist;
@ -228,8 +228,8 @@ string CartridgeDPCWidget::bankState()
ostringstream& buf = buffer();
static const char* const spot[] = { "$FFF8", "$FFF9" };
buf << "Bank = " << std::dec << myCart.myCurrentBank
<< ", hotspot = " << spot[myCart.myCurrentBank];
buf << "Bank = " << std::dec << myCart.getBank()
<< ", hotspot = " << spot[myCart.getBank()];
return buf.str();
}

View File

@ -86,7 +86,7 @@ void CartridgeEFSCWidget::saveOldState()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeEFSCWidget::loadConfig()
{
myBank->setSelectedIndex(myCart.myCurrentBank);
myBank->setSelectedIndex(myCart.getBank());
CartDebugWidget::loadConfig();
}
@ -113,8 +113,8 @@ string CartridgeEFSCWidget::bankState()
"$FFE0", "$FFE1", "$FFE2", "$FFE3", "$FFE4", "$FFE5", "$FFE6", "$FFE7",
"$FFE8", "$FFE9", "$FFEA", "$FFEB", "$FFEC", "$FFED", "$FFEE", "$FFEF"
};
buf << "Bank = " << std::dec << myCart.myCurrentBank
<< ", hotspot = " << spot[myCart.myCurrentBank];
buf << "Bank = " << std::dec << myCart.getBank()
<< ", hotspot = " << spot[myCart.getBank()];
return buf.str();
}

View File

@ -73,7 +73,7 @@ CartridgeEFWidget::CartridgeEFWidget(
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeEFWidget::loadConfig()
{
myBank->setSelectedIndex(myCart.myCurrentBank);
myBank->setSelectedIndex(myCart.getBank());
CartDebugWidget::loadConfig();
}
@ -100,8 +100,8 @@ string CartridgeEFWidget::bankState()
"$FFE0", "$FFE1", "$FFE2", "$FFE3", "$FFE4", "$FFE5", "$FFE6", "$FFE7",
"$FFE8", "$FFE9", "$FFEA", "$FFEB", "$FFEC", "$FFED", "$FFEE", "$FFEF"
};
buf << "Bank = " << std::dec << myCart.myCurrentBank
<< ", hotspot = " << spot[myCart.myCurrentBank];
buf << "Bank = " << std::dec << myCart.getBank()
<< ", hotspot = " << spot[myCart.getBank()];
return buf.str();
}

View File

@ -74,7 +74,7 @@ CartridgeF0Widget::CartridgeF0Widget(
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF0Widget::loadConfig()
{
myBank->setSelectedIndex(myCart.myCurrentBank);
myBank->setSelectedIndex(myCart.getBank());
CartDebugWidget::loadConfig();
}
@ -97,7 +97,7 @@ string CartridgeF0Widget::bankState()
{
ostringstream& buf = buffer();
buf << "Bank = " << std::dec << myCart.myCurrentBank << ", hotspot = $FFF0";
buf << "Bank = " << std::dec << myCart.getBank() << ", hotspot = $FFF0";
return buf.str();
}

View File

@ -77,7 +77,7 @@ void CartridgeF4SCWidget::saveOldState()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF4SCWidget::loadConfig()
{
myBank->setSelectedIndex(myCart.myCurrentBank);
myBank->setSelectedIndex(myCart.getBank());
CartDebugWidget::loadConfig();
}
@ -103,8 +103,8 @@ string CartridgeF4SCWidget::bankState()
static const char* const spot[] = {
"$FFF4", "$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB"
};
buf << "Bank = " << std::dec << myCart.myCurrentBank
<< ", hotspot = " << spot[myCart.myCurrentBank];
buf << "Bank = " << std::dec << myCart.getBank()
<< ", hotspot = " << spot[myCart.getBank()];
return buf.str();
}

View File

@ -64,7 +64,7 @@ CartridgeF4Widget::CartridgeF4Widget(
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF4Widget::loadConfig()
{
myBank->setSelectedIndex(myCart.myCurrentBank);
myBank->setSelectedIndex(myCart.getBank());
CartDebugWidget::loadConfig();
}
@ -90,8 +90,8 @@ string CartridgeF4Widget::bankState()
static const char* const spot[] = {
"$FFF4", "$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB"
};
buf << "Bank = " << std::dec << myCart.myCurrentBank
<< ", hotspot = " << spot[myCart.myCurrentBank];
buf << "Bank = " << std::dec << myCart.getBank()
<< ", hotspot = " << spot[myCart.getBank()];
return buf.str();
}

View File

@ -73,7 +73,7 @@ void CartridgeF6SCWidget::saveOldState()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF6SCWidget::loadConfig()
{
myBank->setSelectedIndex(myCart.myCurrentBank);
myBank->setSelectedIndex(myCart.getBank());
CartDebugWidget::loadConfig();
}
@ -97,8 +97,8 @@ string CartridgeF6SCWidget::bankState()
ostringstream& buf = buffer();
static const char* const spot[] = { "$FFF6", "$FFF7", "$FFF8", "$FFF9" };
buf << "Bank = " << std::dec << myCart.myCurrentBank
<< ", hotspot = " << spot[myCart.myCurrentBank];
buf << "Bank = " << std::dec << myCart.getBank()
<< ", hotspot = " << spot[myCart.getBank()];
return buf.str();
}

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