Merge branch 'master' into refactoring/frame_manager
|
@ -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
|
||||||
|
}
|
|
@ -1,14 +1,5 @@
|
||||||
// Platzieren Sie Ihre Einstellungen in dieser Datei, um Standard- und Benutzereinstellungen zu überschreiben.
|
// 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,
|
"editor.tabSize": 2,
|
||||||
"files.trimTrailingWhitespace": true,
|
"files.trimTrailingWhitespace": true,
|
||||||
"files.exclude": {
|
"files.exclude": {
|
||||||
|
@ -19,5 +10,7 @@
|
||||||
"src/**/*.o": true
|
"src/**/*.o": true
|
||||||
},
|
},
|
||||||
"editor.trimAutoWhitespace": true,
|
"editor.trimAutoWhitespace": true,
|
||||||
"editor.useTabStops": false
|
"editor.useTabStops": false,
|
||||||
|
"C_Cpp.intelliSenseEngine": "Default",
|
||||||
|
"files.insertFinalNewline": true
|
||||||
}
|
}
|
22
Announce.txt
|
@ -9,7 +9,7 @@
|
||||||
SSSS ttt eeeee llll llll aaaaa
|
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
|
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
|
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.
|
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:
|
distributions currently available are:
|
||||||
|
|
||||||
* Binaries for Windows XP_SP3(*)/Vista/7/8/10 :
|
* Binaries for Windows XP_SP3(*)/Vista/7/8/10 :
|
||||||
Stella-5.0.1-win32.exe (32-bit EXE installer)
|
Stella-5.0.2-win32.exe (32-bit EXE installer)
|
||||||
Stella-5.0.1-x64.exe (64-bit EXE installer)
|
Stella-5.0.2-x64.exe (64-bit EXE installer)
|
||||||
Stella-5.0.1-windows.zip (32/64 bit versions)
|
Stella-5.0.2-windows.zip (32/64 bit versions)
|
||||||
|
|
||||||
(*) Note: Support for Windows XP is problematic on some systems,
|
(*) Note: Support for Windows XP is problematic on some systems,
|
||||||
and will probably be discontinued in a future release.
|
and will probably be discontinued in a future release.
|
||||||
|
|
||||||
* Binary distribution for MacOS X 10.7 and above :
|
* 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 :
|
* Binary distribution in 32-bit & 64-bit Ubuntu DEB format :
|
||||||
stella_5.0.1-1_i386.deb
|
stella_5.0.2-1_i386.deb
|
||||||
stella_5.0.1-1_amd64.deb
|
stella_5.0.2-1_amd64.deb
|
||||||
|
|
||||||
* Binary distribution in 32-bit & 64-bit RPM format :
|
* Binary distribution in 32-bit & 64-bit RPM format :
|
||||||
stella-5.0.1-2.i386.rpm
|
stella-5.0.2-2.i386.rpm
|
||||||
stella-5.0.1-2.x86_64.rpm
|
stella-5.0.2-2.x86_64.rpm
|
||||||
|
|
||||||
* Source code distribution for all platforms :
|
* Source code distribution for all platforms :
|
||||||
stella-5.0.1-src.tar.xz
|
stella-5.0.2-src.tar.xz
|
||||||
|
|
||||||
|
|
||||||
Distribution Site
|
Distribution Site
|
||||||
|
|
98
Changes.txt
|
@ -12,6 +12,102 @@
|
||||||
Release History
|
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)
|
5.0 to 5.0.1: (July 23, 2017)
|
||||||
|
|
||||||
* Fixed issues in keypad, Genesis and various other controllers that use
|
* Fixed issues in keypad, Genesis and various other controllers that use
|
||||||
|
@ -25,8 +121,6 @@
|
||||||
|
|
||||||
* Codebase now uses C++14 features.
|
* Codebase now uses C++14 features.
|
||||||
|
|
||||||
-Have fun!
|
|
||||||
|
|
||||||
|
|
||||||
4.7.3 to 5.0: (July 16, 2017)
|
4.7.3 to 5.0: (July 16, 2017)
|
||||||
|
|
||||||
|
|
2
Makefile
|
@ -27,7 +27,7 @@
|
||||||
srcdir ?= .
|
srcdir ?= .
|
||||||
|
|
||||||
DEFINES := -D_GLIBCXX_USE_CXX11_ABI=1
|
DEFINES := -D_GLIBCXX_USE_CXX11_ABI=1
|
||||||
LDFLAGS :=
|
LDFLAGS := -pthread
|
||||||
INCLUDES :=
|
INCLUDES :=
|
||||||
LIBS :=
|
LIBS :=
|
||||||
OBJS :=
|
OBJS :=
|
||||||
|
|
|
@ -378,10 +378,32 @@ echocheck "compiler version"
|
||||||
|
|
||||||
have_clang=no
|
have_clang=no
|
||||||
cc_check_define __clang_version__ && have_clang=yes
|
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
|
have_gcc=no
|
||||||
cc_check_define __GNUC__ && have_gcc=yes
|
cc_check_define __GNUC__ && have_gcc=yes
|
||||||
|
|
||||||
if test "$have_clang" = yes; then
|
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_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)
|
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
|
if test "$?" -gt 0; then
|
||||||
|
@ -403,6 +425,7 @@ if test "$have_clang" = yes; then
|
||||||
cxx_verc_fail=yes
|
cxx_verc_fail=yes
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
fi
|
||||||
CXXFLAGS="$CXXFLAGS"
|
CXXFLAGS="$CXXFLAGS"
|
||||||
_make_def_HAVE_GCC3='HAVE_GCC3 = 1'
|
_make_def_HAVE_GCC3='HAVE_GCC3 = 1'
|
||||||
add_line_to_config_mk 'CXX_UPDATE_DEP_FLAG = -MMD -MF "$(*D)/$(DEPDIR)/$(*F).d" -MQ "$@" -MP'
|
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"
|
DEFINES="$DEFINES -DUNIX"
|
||||||
_host_os=unix
|
_host_os=unix
|
||||||
;;
|
;;
|
||||||
|
darwin*)
|
||||||
|
DEFINES="$DEFINES -DUNIX -DDARWIN"
|
||||||
|
_host_os=darwin
|
||||||
|
;;
|
||||||
irix*)
|
irix*)
|
||||||
DEFINES="$DEFINES -DUNIX"
|
DEFINES="$DEFINES -DUNIX"
|
||||||
_ranlib=:
|
_ranlib=:
|
||||||
|
@ -695,12 +722,18 @@ fi
|
||||||
|
|
||||||
LIBS="$LIBS `$_sdlconfig $_sdl_conf_libs`"
|
LIBS="$LIBS `$_sdlconfig $_sdl_conf_libs`"
|
||||||
LD=$CXX
|
LD=$CXX
|
||||||
|
|
||||||
case $_host_os in
|
case $_host_os in
|
||||||
unix)
|
unix)
|
||||||
DEFINES="$DEFINES -DBSPF_UNIX -DHAVE_GETTIMEOFDAY"
|
DEFINES="$DEFINES -DBSPF_UNIX -DHAVE_GETTIMEOFDAY"
|
||||||
MODULES="$MODULES $SRC/unix"
|
MODULES="$MODULES $SRC/unix"
|
||||||
INCLUDES="$INCLUDES -I$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)
|
win32)
|
||||||
DEFINES="$DEFINES -DBSPF_WINDOWS -DHAVE_GETTIMEOFDAY"
|
DEFINES="$DEFINES -DBSPF_WINDOWS -DHAVE_GETTIMEOFDAY"
|
||||||
MODULES="$MODULES $SRC/windows"
|
MODULES="$MODULES $SRC/windows"
|
||||||
|
@ -803,3 +836,11 @@ EOF
|
||||||
|
|
||||||
# This should be taken care of elsewhere, but I'm not sure where
|
# This should be taken care of elsewhere, but I'm not sure where
|
||||||
rm -f stella-conf*
|
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
|
||||||
|
|
|
@ -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
|
stella (5.0.1-1) stable; urgency=high
|
||||||
|
|
||||||
* Version 5.0.1 release
|
* Version 5.0.1 release
|
||||||
|
|
|
@ -541,12 +541,13 @@ that holds 'number of scanlines' on an actual console).</p>
|
||||||
<table border="1" cellpadding="3">
|
<table border="1" cellpadding="3">
|
||||||
<tr><th>Function</th><th>Description</th></tr>
|
<tr><th>Function</th><th>Description</th></tr>
|
||||||
<tr><td> _bank</td><td> Currently selected bank</td></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> _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> _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> _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>
|
</table>
|
||||||
|
|
||||||
<p><b>_scan</b> always contains the current scanline count. You can use
|
<p><b>_scan</b> always contains the current scanline count. You can use
|
||||||
|
@ -646,7 +647,7 @@ Type "help 'cmd'" to see extended information about the given command.</p>
|
||||||
delfunction - Delete function with label xx
|
delfunction - Delete function with label xx
|
||||||
delwatch - Delete watch <xx>
|
delwatch - Delete watch <xx>
|
||||||
disasm - Disassemble address xx [yy lines] (default=PC)
|
disasm - Disassemble address xx [yy lines] (default=PC)
|
||||||
dump - Dump 128 bytes of memory at address <xx>
|
dump - Dump data at address <xx> [to yy]
|
||||||
exec - Execute script file <xx>
|
exec - Execute script file <xx>
|
||||||
exitrom - Exit emulator, return to ROM launcher
|
exitrom - Exit emulator, return to ROM launcher
|
||||||
frame - Advance emulation by <xx> frames (default=1)
|
frame - Advance emulation by <xx> frames (default=1)
|
||||||
|
@ -676,9 +677,9 @@ listfunctions - List user-defined functions
|
||||||
runtopc - Run until PC is set to value xx
|
runtopc - Run until PC is set to value xx
|
||||||
s - Set Stack Pointer to value xx
|
s - Set Stack Pointer to value xx
|
||||||
save - Save breaks, watches, traps to file xx
|
save - Save breaks, watches, traps to file xx
|
||||||
saveconfig - Save Distella config file
|
saveconfig - Save Distella config file (with default name)
|
||||||
savedis - Save Distella disassembly
|
savedis - Save Distella disassembly (with default name)
|
||||||
saverom - Save (possibly patched) ROM
|
saverom - Save (possibly patched) ROM (with default name)
|
||||||
saveses - Save console session to file xx
|
saveses - Save console session to file xx
|
||||||
savesnap - Save current TIA image to PNG file
|
savesnap - Save current TIA image to PNG file
|
||||||
savestate - Save emulator state xx (valid args 0-9)
|
savestate - Save emulator state xx (valid args 0-9)
|
||||||
|
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 469 B After Width: | Height: | Size: 334 B |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 783 B After Width: | Height: | Size: 509 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 780 B |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 9.0 KiB |
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 7.0 KiB |
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 2.7 KiB |
|
@ -10,7 +10,7 @@
|
||||||
<br><br>
|
<br><br>
|
||||||
<center><h2><b>A multi-platform Atari 2600 VCS emulator</b></h2></center>
|
<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>
|
<br><br>
|
||||||
|
|
||||||
<center><h2><b>User's Guide</b></h2></center>
|
<center><h2><b>User's Guide</b></h2></center>
|
||||||
|
@ -2039,14 +2039,21 @@
|
||||||
<td><pre>-dsense <number></pre></td>
|
<td><pre>-dsense <number></pre></td>
|
||||||
<td>Sensitivity for emulation of paddles when using a digital device
|
<td>Sensitivity for emulation of paddles when using a digital device
|
||||||
(ie, joystick digital axis or button, keyboard key, etc).
|
(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>
|
faster movement.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><pre>-msense <number></pre></td>
|
<td><pre>-msense <number></pre></td>
|
||||||
<td>Sensitivity for emulation of paddles when using a mouse.
|
<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 <number></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>
|
faster movement.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
@ -2082,6 +2089,11 @@
|
||||||
<td>Disable Supercharger BIOS progress loading bars.</td>
|
<td>Disable Supercharger BIOS progress loading bars.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td><pre>-threads <1|0></pre></td>
|
||||||
|
<td>Enable multi-threaded video rendering (may not improve performance on all systems).</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><pre>-snapsavedir <path></pre></td>
|
<td><pre>-snapsavedir <path></pre></td>
|
||||||
<td>The directory to save snapshot files to.</td>
|
<td>The directory to save snapshot files to.</td>
|
||||||
|
@ -2284,23 +2296,29 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td><pre>-holdjoy0 <U,D,L,R,F></pre></td>
|
<td><pre>-holdjoy0 <U,D,L,R,F></pre></td>
|
||||||
<td>Start the emulator with the left joystick direction/button held down
|
<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>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><pre>-holdjoy1 <U,D,L,R,F></pre></td>
|
<td><pre>-holdjoy1 <U,D,L,R,F></pre></td>
|
||||||
<td>Start the emulator with the right joystick direction/button held down
|
<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>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><pre>-holdselect</pre></td>
|
<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>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><pre>-holdreset</pre></td>
|
<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>
|
||||||
|
|
||||||
<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>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>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>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>
|
</table>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -2527,7 +2546,7 @@
|
||||||
<p><b>Input Settings</b> dialog:</p>
|
<p><b>Input Settings</b> dialog:</p>
|
||||||
<table border="5" cellpadding="2" frame="box" rules="none">
|
<table border="5" cellpadding="2" frame="box" rules="none">
|
||||||
<tr>
|
<tr>
|
||||||
<td><img src="graphics/options_input.png"></td>
|
<td><img src="graphics/eventmapping.png"></td>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
<td valign="top"><br>This dialog is described in further detail in
|
<td valign="top"><br>This dialog is described in further detail in
|
||||||
<b>Advanced Configuration - <a href="#Remapping">Event Remapping</a></b>.</td>
|
<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>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>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>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>
|
</table>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</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>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>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>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>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>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>
|
<tr><td>Use Control key combos</td><td>Enable using Control key in keyboard actions</td><td>-ctrlcombo</td></tr>
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -56,14 +56,6 @@ class SoundNull : public Sound
|
||||||
*/
|
*/
|
||||||
void setEnabled(bool enable) override { }
|
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).
|
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 value The value to save into the register
|
||||||
@param cycle The system cycle at which the register is being updated
|
@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
|
Sets the volume of the sound device to the specified level. The
|
||||||
|
|
|
@ -226,12 +226,6 @@ void SoundSDL2::adjustVolume(Int8 direction)
|
||||||
myOSystem.frameBuffer().showMessage(message);
|
myOSystem.frameBuffer().showMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
void SoundSDL2::adjustCycleCounter(Int32 amount)
|
|
||||||
{
|
|
||||||
myLastRegisterSetCycle += amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void SoundSDL2::setChannels(uInt32 channels)
|
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();
|
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
|
// 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
|
// 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.
|
// values to "scale" the time before the register change occurs.
|
||||||
RegWrite info;
|
myRegWriteQueue.enqueue(addr, value, delta);
|
||||||
info.addr = addr;
|
|
||||||
info.value = value;
|
|
||||||
info.delta = delta;
|
|
||||||
myRegWriteQueue.enqueue(info);
|
|
||||||
|
|
||||||
// Update last cycle counter to the current cycle
|
// Update last cycle counter to the current cycle
|
||||||
myLastRegisterSetCycle = cycle;
|
myLastRegisterSetCycle = cycle;
|
||||||
|
@ -390,7 +380,7 @@ bool SoundSDL2::save(Serializer& out) const
|
||||||
for(int i = 0; i < 6; ++i)
|
for(int i = 0; i < 6; ++i)
|
||||||
out.putByte(0);
|
out.putByte(0);
|
||||||
|
|
||||||
out.putInt(myLastRegisterSetCycle);
|
out.putLong(myLastRegisterSetCycle);
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
|
@ -427,7 +417,7 @@ bool SoundSDL2::load(Serializer& in)
|
||||||
for(int i = 0; i < 6; ++i)
|
for(int i = 0; i < 6; ++i)
|
||||||
in.getByte();
|
in.getByte();
|
||||||
|
|
||||||
myLastRegisterSetCycle = in.getInt();
|
myLastRegisterSetCycle = in.getLong();
|
||||||
}
|
}
|
||||||
catch(...)
|
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
|
// If an attempt is made to enqueue more than the queue can hold then
|
||||||
// we'll enlarge the queue's capacity.
|
// we'll enlarge the queue's capacity.
|
||||||
if(mySize == myCapacity)
|
if(mySize == myCapacity)
|
||||||
grow();
|
grow();
|
||||||
|
|
||||||
myBuffer[myTail] = info;
|
RegWrite& reg = myBuffer[myTail];
|
||||||
|
reg.addr = addr;
|
||||||
|
reg.value = value;
|
||||||
|
reg.delta = delta;
|
||||||
myTail = (myTail + 1) % myCapacity;
|
myTail = (myTail + 1) % myCapacity;
|
||||||
++mySize;
|
++mySize;
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,14 +55,6 @@ class SoundSDL2 : public Sound
|
||||||
*/
|
*/
|
||||||
void setEnabled(bool state) override;
|
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
|
Sets the number of channels (mono or stereo sound). Note that this
|
||||||
determines how the emulation should 'mix' the channels of the TIA sound
|
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 value The value to save into the register
|
||||||
@param cycle The system cycle at which the register is being updated
|
@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
|
Sets the volume of the sound device to the specified level. The
|
||||||
|
@ -174,6 +166,9 @@ class SoundSDL2 : public Sound
|
||||||
uInt16 addr;
|
uInt16 addr;
|
||||||
uInt8 value;
|
uInt8 value;
|
||||||
double delta;
|
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.
|
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.
|
Return the item at the front on the queue.
|
||||||
|
@ -255,7 +250,7 @@ class SoundSDL2 : public Sound
|
||||||
bool myIsInitializedFlag;
|
bool myIsInitializedFlag;
|
||||||
|
|
||||||
// Indicates the cycle when a sound register was last set
|
// Indicates the cycle when a sound register was last set
|
||||||
Int32 myLastRegisterSetCycle;
|
uInt64 myLastRegisterSetCycle;
|
||||||
|
|
||||||
// Indicates the number of channels (mono or stereo)
|
// Indicates the number of channels (mono or stereo)
|
||||||
uInt32 myNumChannels;
|
uInt32 myNumChannels;
|
||||||
|
|
|
@ -28,22 +28,23 @@
|
||||||
|
|
||||||
#include "StateManager.hxx"
|
#include "StateManager.hxx"
|
||||||
|
|
||||||
#define STATE_HEADER "05000000state"
|
#define STATE_HEADER "05000302state"
|
||||||
#define MOVIE_HEADER "03030000movie"
|
#define MOVIE_HEADER "03030000movie"
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
StateManager::StateManager(OSystem& osystem)
|
StateManager::StateManager(OSystem& osystem)
|
||||||
: myOSystem(osystem),
|
: myOSystem(osystem),
|
||||||
myCurrentSlot(0),
|
myCurrentSlot(0),
|
||||||
myActiveMode(kOffMode)
|
myActiveMode(Mode::Off)
|
||||||
{
|
{
|
||||||
|
myRewindManager = make_unique<RewindManager>(myOSystem, *this);
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
bool StateManager::toggleRecordMode()
|
|
||||||
{
|
|
||||||
#if 0
|
#if 0
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void StateManager::toggleRecordMode()
|
||||||
|
{
|
||||||
if(myActiveMode != kMovieRecordMode) // Turn on movie record mode
|
if(myActiveMode != kMovieRecordMode) // Turn on movie record mode
|
||||||
{
|
{
|
||||||
myActiveMode = kOffMode;
|
myActiveMode = kOffMode;
|
||||||
|
@ -80,15 +81,8 @@ bool StateManager::toggleRecordMode()
|
||||||
}
|
}
|
||||||
|
|
||||||
return myActiveMode == kMovieRecordMode;
|
return myActiveMode == kMovieRecordMode;
|
||||||
#endif
|
////////////////////////////////////////////////////////
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
bool StateManager::toggleRewindMode()
|
|
||||||
{
|
|
||||||
// FIXME - For now, I'm going to use this to activate movie playback
|
// 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
|
// Close the writer, since we're about to re-open in read mode
|
||||||
myMovieWriter.close();
|
myMovieWriter.close();
|
||||||
|
|
||||||
|
@ -127,34 +121,44 @@ bool StateManager::toggleRewindMode()
|
||||||
myMovieReader.close();
|
myMovieReader.close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return myActiveMode == kMoviePlaybackMode;
|
|
||||||
#endif
|
#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()
|
void StateManager::update()
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
switch(myActiveMode)
|
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::Left).save(myMovieWriter);
|
||||||
myOSystem.console().controller(Controller::Right).save(myMovieWriter);
|
myOSystem.console().controller(Controller::Right).save(myMovieWriter);
|
||||||
myOSystem.console().switches().save(myMovieWriter);
|
myOSystem.console().switches().save(myMovieWriter);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kMoviePlaybackMode:
|
case Mode::MoviePlayback:
|
||||||
myOSystem.console().controller(Controller::Left).load(myMovieReader);
|
myOSystem.console().controller(Controller::Left).load(myMovieReader);
|
||||||
myOSystem.console().controller(Controller::Right).load(myMovieReader);
|
myOSystem.console().controller(Controller::Right).load(myMovieReader);
|
||||||
myOSystem.console().switches().load(myMovieReader);
|
myOSystem.console().switches().load(myMovieReader);
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
class OSystem;
|
class OSystem;
|
||||||
|
|
||||||
|
#include "RewindManager.hxx"
|
||||||
#include "Serializer.hxx"
|
#include "Serializer.hxx"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,41 +33,58 @@ class OSystem;
|
||||||
class StateManager
|
class StateManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
enum class Mode {
|
||||||
|
Off,
|
||||||
|
Rewind,
|
||||||
|
MovieRecord,
|
||||||
|
MoviePlayback
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Create a new statemananger class
|
Create a new statemananger class.
|
||||||
*/
|
*/
|
||||||
StateManager(OSystem& osystem);
|
StateManager(OSystem& osystem);
|
||||||
|
|
||||||
public:
|
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();
|
#if 0
|
||||||
bool toggleRewindMode();
|
/**
|
||||||
|
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();
|
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
|
@param slot The state 'slot' to load state from
|
||||||
*/
|
*/
|
||||||
void loadState(int slot = -1);
|
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
|
@param slot The state 'slot' to save into
|
||||||
*/
|
*/
|
||||||
void saveState(int slot = -1);
|
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();
|
void changeState();
|
||||||
|
|
||||||
|
@ -91,19 +109,16 @@ class StateManager
|
||||||
bool saveState(Serializer& out);
|
bool saveState(Serializer& out);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Resets manager to defaults
|
Resets manager to defaults.
|
||||||
*/
|
*/
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
private:
|
/**
|
||||||
enum Mode {
|
The rewind facility for the state manager
|
||||||
kOffMode,
|
*/
|
||||||
kMoviePlaybackMode,
|
RewindManager& rewindManager() const { return *myRewindManager; }
|
||||||
kMovieRecordMode,
|
|
||||||
kRewindPlaybackMode,
|
|
||||||
kRewindRecordMode
|
|
||||||
};
|
|
||||||
|
|
||||||
|
private:
|
||||||
enum {
|
enum {
|
||||||
kVersion = 001
|
kVersion = 001
|
||||||
};
|
};
|
||||||
|
@ -124,6 +139,9 @@ class StateManager
|
||||||
Serializer myMovieWriter;
|
Serializer myMovieWriter;
|
||||||
Serializer myMovieReader;
|
Serializer myMovieReader;
|
||||||
|
|
||||||
|
// Stored savestates to be later rewound
|
||||||
|
unique_ptr<RewindManager> myRewindManager;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Following constructors and assignment operators not supported
|
// Following constructors and assignment operators not supported
|
||||||
StateManager() = delete;
|
StateManager() = delete;
|
|
@ -18,7 +18,7 @@
|
||||||
#ifndef VERSION_HXX
|
#ifndef VERSION_HXX
|
||||||
#define VERSION_HXX
|
#define VERSION_HXX
|
||||||
|
|
||||||
#define STELLA_VERSION "5.0.1"
|
#define STELLA_VERSION "5.0.3_pre"
|
||||||
#define STELLA_BUILD "3487"
|
#define STELLA_BUILD "3535"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -111,9 +111,13 @@ namespace BSPF
|
||||||
|
|
||||||
// Combines 'max' and 'min', and clamps value to the upper/lower value
|
// Combines 'max' and 'min', and clamps value to the upper/lower value
|
||||||
// if it is outside the specified range
|
// 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
|
// Compare two strings, ignoring case
|
||||||
|
|
|
@ -10,6 +10,8 @@ MODULE_OBJS := \
|
||||||
src/common/FSNodeZIP.o \
|
src/common/FSNodeZIP.o \
|
||||||
src/common/PNGLibrary.o \
|
src/common/PNGLibrary.o \
|
||||||
src/common/MouseControl.o \
|
src/common/MouseControl.o \
|
||||||
|
src/common/RewindManager.o \
|
||||||
|
src/common/StateManager.o \
|
||||||
src/common/ZipHandler.o
|
src/common/ZipHandler.o
|
||||||
|
|
||||||
MODULE_DIRS += \
|
MODULE_DIRS += \
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
#include "AtariNTSC.hxx"
|
#include "AtariNTSC.hxx"
|
||||||
|
|
||||||
// blitter related
|
// blitter related
|
||||||
|
@ -66,11 +67,65 @@ void AtariNTSC::initializePalette(const uInt8* palette)
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void AtariNTSC::render(const uInt8* atari_in, uInt32 in_width,
|
void AtariNTSC::enableThreading(bool enable)
|
||||||
uInt32 in_height, void* rgb_out, uInt32 out_pitch)
|
|
||||||
{
|
{
|
||||||
|
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;
|
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;
|
const uInt8* line_in = atari_in;
|
||||||
ATARI_NTSC_BEGIN_ROW(NTSC_black, line_in[0]);
|
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)
|
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_COLOR_IN(0, line_in[0]);
|
||||||
ATARI_NTSC_RGB_OUT_8888(0, line_out[0]);
|
ATARI_NTSC_RGB_OUT_8888(0, line_out[0]);
|
||||||
ATARI_NTSC_RGB_OUT_8888(1, line_out[1]);
|
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;
|
line_out += 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* finish final pixels */
|
// finish final pixels
|
||||||
ATARI_NTSC_COLOR_IN( 0, NTSC_black );
|
ATARI_NTSC_COLOR_IN(0, line_in[0]);
|
||||||
ATARI_NTSC_RGB_OUT_8888(0, line_out[0]);
|
ATARI_NTSC_RGB_OUT_8888(0, line_out[0]);
|
||||||
ATARI_NTSC_RGB_OUT_8888(1, line_out[1]);
|
ATARI_NTSC_RGB_OUT_8888(1, line_out[1]);
|
||||||
ATARI_NTSC_RGB_OUT_8888(2, line_out[2]);
|
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(5, line_out[5]);
|
||||||
ATARI_NTSC_RGB_OUT_8888(6, line_out[6]);
|
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;
|
atari_in += in_width;
|
||||||
rgb_out = static_cast<char*>(rgb_out) + out_pitch;
|
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)
|
void AtariNTSC::init(init_t& impl, const Setup& setup)
|
||||||
{
|
{
|
||||||
|
|
|
@ -51,6 +51,9 @@ class AtariNTSC
|
||||||
entry_size = 2 * 14,
|
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
|
// Image parameters, ranging from -1.0 to 1.0. Actual internal values shown
|
||||||
// in parenthesis and should remain fairly stable in future versions.
|
// in parenthesis and should remain fairly stable in future versions.
|
||||||
struct Setup
|
struct Setup
|
||||||
|
@ -80,27 +83,52 @@ class AtariNTSC
|
||||||
void initialize(const Setup& setup, const uInt8* palette);
|
void initialize(const Setup& setup, const uInt8* palette);
|
||||||
void initializePalette(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
|
// Filters one or more rows of pixels. Input pixels are 8-bit Atari
|
||||||
// palette colors.
|
// palette colors.
|
||||||
// In_row_width is the number of pixels to get to the next input row.
|
// 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.
|
// 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 render(const uInt8* atari_in, const uInt32 in_width, const uInt32 in_height,
|
||||||
void* rgb_out, uInt32 out_pitch);
|
void* rgb_out, const uInt32 out_pitch, uInt32* rgb_in = nullptr);
|
||||||
|
|
||||||
// Number of input pixels that will fit within given output width.
|
// Number of input pixels that will fit within given output width.
|
||||||
// Might be rounded down slightly; use outWidth() on result to find
|
// Might be rounded down slightly; use outWidth() on result to find
|
||||||
// rounded value.
|
// rounded value.
|
||||||
static constexpr uInt32 inWidth( uInt32 out_width ) {
|
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.
|
// Number of output pixels written by blitter for given input width.
|
||||||
// Width might be rounded down slightly; use inWidth() on result to
|
// Width might be rounded down slightly; use inWidth() on result to
|
||||||
// find rounded value. Guaranteed not to round 160 down at all.
|
// find rounded value. Guaranteed not to round 160 down at all.
|
||||||
static constexpr uInt32 outWidth(uInt32 in_width) {
|
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:
|
private:
|
||||||
enum {
|
enum {
|
||||||
PIXEL_in_chunk = 2, // number of input pixels read per chunk
|
PIXEL_in_chunk = 2, // number of input pixels read per chunk
|
||||||
|
@ -138,6 +166,12 @@ class AtariNTSC
|
||||||
#define LUMA_CUTOFF 0.20
|
#define LUMA_CUTOFF 0.20
|
||||||
|
|
||||||
uInt32 myColorTable[palette_size][entry_size];
|
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
|
struct init_t
|
||||||
{
|
{
|
||||||
|
|
|
@ -72,6 +72,10 @@ class NTSCFilter
|
||||||
myNTSC.initializePalette(myTIAPalette);
|
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
|
// The following are meant to be used strictly for toggling from the GUI
|
||||||
string setPreset(Preset preset);
|
string setPreset(Preset preset);
|
||||||
|
|
||||||
|
@ -110,6 +114,17 @@ class NTSCFilter
|
||||||
{
|
{
|
||||||
myNTSC.render(src_buf, src_width, src_height, dest_buf, dest_pitch);
|
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:
|
private:
|
||||||
// Convert from atari_ntsc_setup_t values to equivalent adjustables
|
// Convert from atari_ntsc_setup_t values to equivalent adjustables
|
||||||
|
|
|
@ -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
|
// Banksizes greater than 4096 indicate multi-bank ROMs, but we handle only
|
||||||
// 4K pieces at a time
|
// 4K pieces at a time
|
||||||
// Banksizes less than 4K use the actual value
|
// Banksizes less than 4K use the actual value
|
||||||
int banksize = 0;
|
uInt32 banksize = 0;
|
||||||
myConsole.cartridge().getImage(banksize);
|
myConsole.cartridge().getImage(banksize);
|
||||||
|
|
||||||
BankInfo info;
|
BankInfo info;
|
||||||
info.size = std::min(banksize, 4096);
|
info.size = std::min(banksize, 4096u);
|
||||||
for(int i = 0; i < myConsole.cartridge().bankCount(); ++i)
|
for(int i = 0; i < myConsole.cartridge().bankCount(); ++i)
|
||||||
myBankInfo.push_back(info);
|
myBankInfo.push_back(info);
|
||||||
|
|
||||||
|
@ -82,8 +82,8 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem)
|
||||||
myBankInfo.push_back(info);
|
myBankInfo.push_back(info);
|
||||||
|
|
||||||
// We know the address for the startup bank right now
|
// We know the address for the startup bank right now
|
||||||
myBankInfo[myConsole.cartridge().startBank()].addressList.push_back(myDebugger.dpeek(0xfffc));
|
myBankInfo[myConsole.cartridge().startBank()].addressList.push_front(myDebugger.dpeek(0xfffc));
|
||||||
addLabel("START", myDebugger.dpeek(0xfffc));
|
addLabel("Start", myDebugger.dpeek(0xfffc, DATA));
|
||||||
|
|
||||||
// Add system equates
|
// Add system equates
|
||||||
for(uInt16 addr = 0x00; addr <= 0x0F; ++addr)
|
for(uInt16 addr = 0x00; addr <= 0x0F; ++addr)
|
||||||
|
@ -114,16 +114,17 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem)
|
||||||
myDisassembly.list.reserve(2048);
|
myDisassembly.list.reserve(2048);
|
||||||
|
|
||||||
// Add settings for Distella
|
// Add settings for Distella
|
||||||
DiStella::settings.gfx_format =
|
DiStella::settings.gfxFormat =
|
||||||
myOSystem.settings().getInt("dis.gfxformat") == 16 ? Base::F_16 : Base::F_2;
|
myOSystem.settings().getInt("dis.gfxformat") == 16 ? Base::F_16 : Base::F_2;
|
||||||
DiStella::settings.resolve_code =
|
DiStella::settings.resolveCode =
|
||||||
myOSystem.settings().getBool("dis.resolve");
|
myOSystem.settings().getBool("dis.resolve");
|
||||||
DiStella::settings.show_addresses =
|
DiStella::settings.showAddresses =
|
||||||
myOSystem.settings().getBool("dis.showaddr");
|
myOSystem.settings().getBool("dis.showaddr");
|
||||||
DiStella::settings.aflag = false; // Not currently configurable
|
DiStella::settings.aFlag = false; // Not currently configurable
|
||||||
DiStella::settings.fflag = true; // Not currently configurable
|
DiStella::settings.fFlag = true; // Not currently configurable
|
||||||
DiStella::settings.rflag = myOSystem.settings().getBool("dis.relocate");
|
DiStella::settings.rFlag = myOSystem.settings().getBool("dis.relocate");
|
||||||
DiStella::settings.bwidth = 9; // TODO - configure based on window size
|
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
|
// Only add addresses when absolutely necessary, to cut down on the
|
||||||
// work that Distella has to do
|
// work that Distella has to do
|
||||||
// Distella expects the addresses to be unique and in sorted order
|
|
||||||
if(bankChanged || !pcfound)
|
if(bankChanged || !pcfound)
|
||||||
{
|
{
|
||||||
AddressList::const_iterator i;
|
AddressList::const_iterator i;
|
||||||
for(i = addresses.cbegin(); i != addresses.cend(); ++i)
|
for(i = addresses.cbegin(); i != addresses.cend(); ++i)
|
||||||
{
|
{
|
||||||
if(PC < *i)
|
if (PC == *i) // already present
|
||||||
{
|
|
||||||
addresses.insert(i, PC);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if(PC == *i) // already present
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Otherwise, add the item at the end
|
// 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
|
// Always attempt to resolve code sections unless it's been
|
||||||
// specifically disabled
|
// specifically disabled
|
||||||
bool found = fillDisassemblyList(info, PC);
|
bool found = fillDisassemblyList(info, PC);
|
||||||
if(!found && DiStella::settings.resolve_code)
|
if(!found && DiStella::settings.resolveCode)
|
||||||
{
|
{
|
||||||
// Temporarily turn off code resolution
|
// Temporarily turn off code resolution
|
||||||
DiStella::settings.resolve_code = false;
|
DiStella::settings.resolveCode = false;
|
||||||
fillDisassemblyList(info, PC);
|
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
|
// The default naming/location for list files is the ROM dir based on the
|
||||||
// actual ROM filename
|
// actual ROM filename
|
||||||
|
|
||||||
|
myUserAddresses.clear();
|
||||||
|
myUserLabels.clear();
|
||||||
|
|
||||||
if(myListFile == "")
|
if(myListFile == "")
|
||||||
{
|
{
|
||||||
FilesystemNode lst(myOSystem.romFile().getPathWithExt("") + ".lst");
|
FilesystemNode lst(myOSystem.romFile().getPathWithExt("") + ".lst");
|
||||||
|
@ -704,7 +702,7 @@ string CartDebug::loadListFile()
|
||||||
if(!in.is_open())
|
if(!in.is_open())
|
||||||
return DebuggerParser::red("list file '" + node.getShortPath() + "' not readable");
|
return DebuggerParser::red("list file '" + node.getShortPath() + "' not readable");
|
||||||
|
|
||||||
myUserCLabels.clear();
|
//myUserCLabels.clear();
|
||||||
|
|
||||||
while(!in.eof())
|
while(!in.eof())
|
||||||
{
|
{
|
||||||
|
@ -736,7 +734,8 @@ string CartDebug::loadListFile()
|
||||||
char eq = '\0';
|
char eq = '\0';
|
||||||
buf >> hex >> xx >> hex >> yy >> line >> eq;
|
buf >> hex >> xx >> hex >> yy >> line >> eq;
|
||||||
if(xx >= 0 && yy >= 0 && 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())
|
if(!in.is_open())
|
||||||
return DebuggerParser::red("symbol file '" + node.getShortPath() + "' not readable");
|
return DebuggerParser::red("symbol file '" + node.getShortPath() + "' not readable");
|
||||||
|
|
||||||
myUserAddresses.clear();
|
//myUserAddresses.clear();
|
||||||
myUserLabels.clear();
|
//myUserLabels.clear();
|
||||||
|
|
||||||
while(!in.eof())
|
while(!in.eof())
|
||||||
{
|
{
|
||||||
|
@ -781,8 +780,10 @@ string CartDebug::loadSymbolFile()
|
||||||
{
|
{
|
||||||
// Make sure the value doesn't represent a constant
|
// Make sure the value doesn't represent a constant
|
||||||
// For now, we simply ignore constants completely
|
// For now, we simply ignore constants completely
|
||||||
const auto& iter = myUserCLabels.find(value);
|
//const auto& iter = myUserCLabels.find(value);
|
||||||
if(iter == myUserCLabels.end() || !BSPF::equalsIgnoreCase(label, iter->second))
|
//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
|
// Check for period, and strip leading number
|
||||||
if(string::size_type pos = label.find_first_of(".", 0) != string::npos)
|
if(string::size_type pos = label.find_first_of(".", 0) != string::npos)
|
||||||
|
@ -955,20 +956,12 @@ string CartDebug::saveDisassembly()
|
||||||
if(myConsole.cartridge().bankCount() > 1)
|
if(myConsole.cartridge().bankCount() > 1)
|
||||||
return DebuggerParser::red("disassembly for multi-bank ROM not yet supported");
|
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 == "")
|
if(myDisasmFile == "")
|
||||||
{
|
{
|
||||||
const string& propsname =
|
const string& propsname =
|
||||||
myConsole.properties().get(Cartridge_Name) + ".asm";
|
myConsole.properties().get(Cartridge_Name) + ".asm";
|
||||||
|
|
||||||
FilesystemNode case0(myOSystem.romFile().getParent().getPath() + propsname);
|
myDisasmFile = FilesystemNode(myOSystem.defaultSaveDir() + propsname).getPath();
|
||||||
if(case0.getParent().isWritable())
|
|
||||||
myDisasmFile = case0.getPath();
|
|
||||||
else
|
|
||||||
return DebuggerParser::red("disassembly file not writable:\n " +
|
|
||||||
case0.getShortPath());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FilesystemNode node(myDisasmFile);
|
FilesystemNode node(myDisasmFile);
|
||||||
|
@ -981,20 +974,23 @@ string CartDebug::saveDisassembly()
|
||||||
// We can't print the header to the disassembly until it's actually
|
// We can't print the header to the disassembly until it's actually
|
||||||
// been processed; therefore buffer output to a string first
|
// been processed; therefore buffer output to a string first
|
||||||
ostringstream buf;
|
ostringstream buf;
|
||||||
buf << "\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;\n"
|
buf << "\n\n;***********************************************************\n"
|
||||||
<< "; MAIN PROGRAM\n"
|
<< "; Bank " << myConsole.cartridge().getBank();
|
||||||
<< ";\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n";
|
if (myConsole.cartridge().bankCount() > 1)
|
||||||
|
buf << " / 0.." << myConsole.cartridge().bankCount() - 1;
|
||||||
|
buf << "\n;***********************************************************\n\n";
|
||||||
|
|
||||||
// Use specific settings for disassembly output
|
// Use specific settings for disassembly output
|
||||||
// This will most likely differ from what you see in the debugger
|
// This will most likely differ from what you see in the debugger
|
||||||
DiStella::Settings settings;
|
DiStella::Settings settings;
|
||||||
settings.gfx_format = DiStella::settings.gfx_format;
|
settings.gfxFormat = DiStella::settings.gfxFormat;
|
||||||
settings.resolve_code = true;
|
settings.resolveCode = true;
|
||||||
settings.show_addresses = false;
|
settings.showAddresses = false;
|
||||||
settings.aflag = false; // Otherwise DASM gets confused
|
settings.aFlag = false; // Otherwise DASM gets confused
|
||||||
settings.fflag = DiStella::settings.fflag;
|
settings.fFlag = DiStella::settings.fFlag;
|
||||||
settings.rflag = DiStella::settings.rflag;
|
settings.rFlag = DiStella::settings.rFlag;
|
||||||
settings.bwidth = 17; // default from Distella
|
settings.bytesWidth = 8+1; // same as Stella debugger
|
||||||
|
settings.bFlag = DiStella::settings.bFlag;; // process break routine (TODO)
|
||||||
|
|
||||||
Disassembly disasm;
|
Disassembly disasm;
|
||||||
disasm.list.reserve(2048);
|
disasm.list.reserve(2048);
|
||||||
|
@ -1010,6 +1006,9 @@ string CartDebug::saveDisassembly()
|
||||||
DiStella distella(*this, disasm.list, info, settings,
|
DiStella distella(*this, disasm.list, info, settings,
|
||||||
myDisLabels, myDisDirectives, myReserved);
|
myDisLabels, myDisDirectives, myReserved);
|
||||||
|
|
||||||
|
if (myReserved.breakFound)
|
||||||
|
addLabel("Break", myDebugger.dpeek(0xfffe));
|
||||||
|
|
||||||
buf << " SEG CODE\n"
|
buf << " SEG CODE\n"
|
||||||
<< " ORG $" << Base::HEX4 << info.offset << "\n\n";
|
<< " ORG $" << Base::HEX4 << info.offset << "\n\n";
|
||||||
|
|
||||||
|
@ -1020,55 +1019,53 @@ string CartDebug::saveDisassembly()
|
||||||
|
|
||||||
// Add label (if any)
|
// Add label (if any)
|
||||||
if(tag.label != "")
|
if(tag.label != "")
|
||||||
buf << ALIGN(7) << (tag.label+":") << endl;
|
buf << ALIGN(4) << (tag.label) << "\n";
|
||||||
buf << " ";
|
buf << " ";
|
||||||
|
|
||||||
switch(tag.type)
|
switch(tag.type)
|
||||||
{
|
{
|
||||||
case CartDebug::CODE:
|
case CartDebug::CODE:
|
||||||
{
|
{
|
||||||
buf << ALIGN(25) << tag.disasm << tag.ccount << "\n";
|
buf << ALIGN(32) << tag.disasm << tag.ccount.substr(0, 5) << tag.ctotal << tag.ccount.substr(5, 2);
|
||||||
break;
|
if (tag.disasm.find("WSYNC") != std::string::npos)
|
||||||
}
|
buf << "\n;---------------------------------------";
|
||||||
case CartDebug::NONE:
|
|
||||||
{
|
|
||||||
buf << "\n";
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CartDebug::ROW:
|
case CartDebug::ROW:
|
||||||
{
|
{
|
||||||
buf << tag.disasm << "\n";
|
buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 8*4-1) << "; $" << Base::HEX4 << tag.address << " (*)";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CartDebug::GFX:
|
case CartDebug::GFX:
|
||||||
{
|
{
|
||||||
buf << ".byte " << (settings.gfx_format == Base::F_2 ? "%" : "$")
|
buf << ".byte " << (settings.gfxFormat == Base::F_2 ? "%" : "$")
|
||||||
<< tag.bytes << " ; |";
|
<< tag.bytes << " ; |";
|
||||||
for(int c = 12; c < 20; ++c)
|
for(int c = 12; c < 20; ++c)
|
||||||
buf << ((tag.disasm[c] == '\x1e') ? "#" : " ");
|
buf << ((tag.disasm[c] == '\x1e') ? "#" : " ");
|
||||||
buf << "| $" << Base::HEX4 << tag.address << " (G)\n";
|
buf << ALIGN(13) << "|" << "$" << Base::HEX4 << tag.address << " (G)";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CartDebug::PGFX:
|
case CartDebug::PGFX:
|
||||||
{
|
{
|
||||||
buf << ".byte " << (settings.gfx_format == Base::F_2 ? "%" : "$")
|
buf << ".byte " << (settings.gfxFormat == Base::F_2 ? "%" : "$")
|
||||||
<< tag.bytes << " ; |";
|
<< tag.bytes << " ; |";
|
||||||
for(int c = 12; c < 20; ++c)
|
for(int c = 12; c < 20; ++c)
|
||||||
buf << ((tag.disasm[c] == '\x1f') ? "*" : " ");
|
buf << ((tag.disasm[c] == '\x1f') ? "*" : " ");
|
||||||
buf << "| $" << Base::HEX4 << tag.address << " (P)\n";
|
buf << ALIGN(13) << "|" << "$" << Base::HEX4 << tag.address << " (P)";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CartDebug::DATA:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
case CartDebug::NONE:
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
buf << "\n";
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
} // switch
|
||||||
|
buf << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1084,69 +1081,113 @@ string CartDebug::saveDisassembly()
|
||||||
<< "; Legend: * = CODE not yet run (tentative code)\n"
|
<< "; Legend: * = CODE not yet run (tentative code)\n"
|
||||||
<< "; D = DATA directive (referenced in some way)\n"
|
<< "; D = DATA directive (referenced in some way)\n"
|
||||||
<< "; G = GFX directive, shown as '#' (stored in player, missile, ball)\n"
|
<< "; G = GFX directive, shown as '#' (stored in player, missile, ball)\n"
|
||||||
<< "; P = PGFX directive, shown as '*' (stored in playfield)\n\n"
|
<< "; P = PGFX directive, shown as '*' (stored in playfield)\n"
|
||||||
<< " processor 6502\n\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;
|
bool addrUsed = false;
|
||||||
for(uInt16 addr = 0x00; addr <= 0x0F; ++addr)
|
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)
|
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)
|
for(uInt16 addr = 0x00; addr <= 0x17; ++addr)
|
||||||
addrUsed = addrUsed || myReserved.IOReadWrite[addr];
|
addrUsed = addrUsed || myReserved.IOReadWrite[addr];
|
||||||
if(addrUsed)
|
if(addrUsed)
|
||||||
{
|
{
|
||||||
out << ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"
|
out << "\n;-----------------------------------------------------------\n"
|
||||||
<< "; TIA AND IO CONSTANTS\n"
|
<< "; TIA and IO constants accessed\n"
|
||||||
<< ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n";
|
<< ";-----------------------------------------------------------\n\n";
|
||||||
|
|
||||||
|
// TIA read access
|
||||||
for(uInt16 addr = 0x00; addr <= 0x0F; ++addr)
|
for(uInt16 addr = 0x00; addr <= 0x0F; ++addr)
|
||||||
if(myReserved.TIARead[addr] && ourTIAMnemonicR[addr])
|
if(myReserved.TIARead[addr] && ourTIAMnemonicR[addr])
|
||||||
out << ALIGN(6) << ourTIAMnemonicR[addr] << " = $"
|
out << ALIGN(16) << ourTIAMnemonicR[addr] << "= $"
|
||||||
<< Base::HEX2 << right << addr << " ; (R)\n";
|
<< 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)
|
for(uInt16 addr = 0x00; addr <= 0x3F; ++addr)
|
||||||
if(myReserved.TIAWrite[addr] && ourTIAMnemonicW[addr])
|
if(myReserved.TIAWrite[addr] && ourTIAMnemonicW[addr])
|
||||||
out << ALIGN(6) << ourTIAMnemonicW[addr] << " = $"
|
out << ALIGN(16) << ourTIAMnemonicW[addr] << "= $"
|
||||||
<< Base::HEX2 << right << addr << " ; (W)\n";
|
<< 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)
|
for(uInt16 addr = 0x00; addr <= 0x17; ++addr)
|
||||||
if(myReserved.IOReadWrite[addr] && ourIOMnemonic[addr])
|
if(myReserved.IOReadWrite[addr] && ourIOMnemonic[addr])
|
||||||
out << ALIGN(6) << ourIOMnemonic[addr] << " = $"
|
out << ALIGN(16) << ourIOMnemonic[addr] << "= $"
|
||||||
<< Base::HEX4 << right << (addr+0x280) << "\n";
|
<< Base::HEX4 << right << (addr+0x280) << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
addrUsed = false;
|
addrUsed = false;
|
||||||
for(uInt16 addr = 0x80; addr <= 0xFF; ++addr)
|
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)
|
if(addrUsed)
|
||||||
{
|
{
|
||||||
out << "\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"
|
bool addLine = false;
|
||||||
<< "; RIOT RAM (zero-page)\n"
|
out << "\n\n;-----------------------------------------------------------\n"
|
||||||
<< ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n";
|
<< "; RIOT RAM (zero-page) labels\n"
|
||||||
for(uInt16 addr = 0x80; addr <= 0xFF; ++addr)
|
<< ";-----------------------------------------------------------\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] &&
|
if (myReserved.ZPRAM[addr - 0x80] &&
|
||||||
myUserLabels.find(addr) == myUserLabels.end())
|
myUserLabels.find(addr) == myUserLabels.end()) {
|
||||||
{
|
if (addLine)
|
||||||
out << ALIGN(6) << ourZPMnemonic[addr-0x80] << " = $"
|
out << "\n";
|
||||||
<< Base::HEX2 << right << (addr) << "\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)
|
if(myReserved.Label.size() > 0)
|
||||||
{
|
{
|
||||||
out << "\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"
|
out << "\n\n;-----------------------------------------------------------\n"
|
||||||
<< "; NON LOCATABLE\n"
|
<< "; Non Locatable Labels\n"
|
||||||
<< ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n";
|
<< ";-----------------------------------------------------------\n\n";
|
||||||
for(const auto& iter: myReserved.Label)
|
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)
|
if(myUserLabels.size() > 0)
|
||||||
{
|
{
|
||||||
out << "\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"
|
out << "\n\n;-----------------------------------------------------------\n"
|
||||||
<< "; USER DEFINED\n"
|
<< "; User Defined Labels\n"
|
||||||
<< ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n";
|
<< ";-----------------------------------------------------------\n\n";
|
||||||
int max_len = 0;
|
int max_len = 16;
|
||||||
for(const auto& iter: myUserLabels)
|
for(const auto& iter: myUserLabels)
|
||||||
max_len = std::max(max_len, int(iter.second.size()));
|
max_len = std::max(max_len, int(iter.second.size()));
|
||||||
for(const auto& iter: myUserLabels)
|
for(const auto& iter: myUserLabels)
|
||||||
|
@ -1162,10 +1203,9 @@ string CartDebug::saveDisassembly()
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
string CartDebug::saveRom()
|
string CartDebug::saveRom()
|
||||||
{
|
{
|
||||||
const string& path = string("~") + BSPF::PATH_SEPARATOR +
|
const string& rom = myConsole.properties().get(Cartridge_Name) + ".a26";
|
||||||
myConsole.properties().get(Cartridge_Name) + ".a26";
|
|
||||||
|
|
||||||
FilesystemNode node(path);
|
FilesystemNode node(myOSystem.defaultSaveDir() + "ROMs\\" + rom);
|
||||||
ofstream out(node.getPath(), std::ios::binary);
|
ofstream out(node.getPath(), std::ios::binary);
|
||||||
if(out && myConsole.cartridge().saveROM(out))
|
if(out && myConsole.cartridge().saveROM(out))
|
||||||
return "saved ROM as " + node.getShortPath();
|
return "saved ROM as " + node.getShortPath();
|
||||||
|
@ -1404,7 +1444,7 @@ void CartDebug::disasmTypeAsString(ostream& buf, uInt8 flags) const
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
const char* const CartDebug::ourTIAMnemonicR[16] = {
|
const char* const CartDebug::ourTIAMnemonicR[16] = {
|
||||||
"CXM0P", "CXM1P", "CXP0FB", "CXP1FB", "CXM0FB", "CXM1FB", "CXBLPF", "CXPPMM",
|
"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",
|
"RESP0", "RESP1", "RESM0", "RESM1", "RESBL", "AUDC0", "AUDC1", "AUDF0",
|
||||||
"AUDF1", "AUDV0", "AUDV1", "GRP0", "GRP1", "ENAM0", "ENAM1", "ENABL",
|
"AUDF1", "AUDV0", "AUDV1", "GRP0", "GRP1", "ENAM0", "ENAM1", "ENABL",
|
||||||
"HMP0", "HMP1", "HMM0", "HMM1", "HMBL", "VDELP0", "VDELP1", "VDELBL",
|
"HMP0", "HMP1", "HMM0", "HMM1", "HMBL", "VDELP0", "VDELP1", "VDELBL",
|
||||||
"RESMP0", "RESMP1", "HMOVE", "HMCLR", "CXCLR", 0, 0, 0,
|
"RESMP0", "RESMP1", "HMOVE", "HMCLR", "CXCLR", "$2d", "$2e", "$2f",
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
"$30", "$31", "$32", "$33", "$34", "$35", "$36", "$37",
|
||||||
|
"$38", "$39", "$3a", "$3b", "$3c", "$3d", "$3e", "$3f"
|
||||||
};
|
};
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
|
@ -52,9 +52,9 @@ class CartDebug : public DebuggerSystem
|
||||||
public:
|
public:
|
||||||
enum DisasmType {
|
enum DisasmType {
|
||||||
NONE = 0,
|
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 */
|
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
|
A good counterexample would be "FF00: LDA $FE00"; $FF01
|
||||||
would be in the middle of a multi-byte instruction, and
|
would be in the middle of a multi-byte instruction, and
|
||||||
therefore cannot be labelled. */
|
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
|
// debugger, or specified in a Distella cfg file, and are listed in order
|
||||||
// of decreasing hierarchy
|
// of decreasing hierarchy
|
||||||
//
|
//
|
||||||
CODE = 1 << 7, // disassemble-able code segments
|
CODE = 1 << 7, // 0x80, disassemble-able code segments
|
||||||
TCODE = 1 << 6, // (tentative) disassemble-able code segments
|
TCODE = 1 << 6, // 0x40, (tentative) disassemble-able code segments
|
||||||
GFX = 1 << 5, // addresses loaded into GRPx registers
|
GFX = 1 << 5, // 0x20, addresses loaded into GRPx registers
|
||||||
PGFX = 1 << 4, // addresses loaded into PFx registers
|
PGFX = 1 << 4, // 0x10, addresses loaded into PFx registers
|
||||||
DATA = 1 << 3, // addresses loaded into registers other than GRPx / PFx
|
DATA = 1 << 3, // 0x08, addresses loaded into registers other than GRPx / PFx
|
||||||
ROW = 1 << 2 // all other addresses
|
ROW = 1 << 2, // 0x04, all other addresses
|
||||||
|
// special type for poke()
|
||||||
|
WRITE = TCODE // 0x40, address written to
|
||||||
};
|
};
|
||||||
struct DisassemblyTag {
|
struct DisassemblyTag {
|
||||||
DisasmType type;
|
DisasmType type;
|
||||||
|
@ -76,6 +78,7 @@ class CartDebug : public DebuggerSystem
|
||||||
string label;
|
string label;
|
||||||
string disasm;
|
string disasm;
|
||||||
string ccount;
|
string ccount;
|
||||||
|
string ctotal;
|
||||||
string bytes;
|
string bytes;
|
||||||
bool hllabel;
|
bool hllabel;
|
||||||
};
|
};
|
||||||
|
@ -316,6 +319,7 @@ class CartDebug : public DebuggerSystem
|
||||||
bool IOReadWrite[24];
|
bool IOReadWrite[24];
|
||||||
bool ZPRAM[128];
|
bool ZPRAM[128];
|
||||||
AddrToLabel Label;
|
AddrToLabel Label;
|
||||||
|
bool breakFound;
|
||||||
};
|
};
|
||||||
ReservedEquates myReserved;
|
ReservedEquates myReserved;
|
||||||
|
|
||||||
|
@ -362,7 +366,7 @@ class CartDebug : public DebuggerSystem
|
||||||
|
|
||||||
// Mappings from label to address (and vice versa) for constants
|
// Mappings from label to address (and vice versa) for constants
|
||||||
// defined through a DASM lst file
|
// defined through a DASM lst file
|
||||||
AddrToLabel myUserCLabels;
|
// AddrToLabel myUserCLabels;
|
||||||
// LabelToAddr myUserCAddresses;
|
// LabelToAddr myUserCAddresses;
|
||||||
|
|
||||||
// Mappings for labels to addresses for system-defined equates
|
// Mappings for labels to addresses for system-defined equates
|
||||||
|
|
|
@ -96,12 +96,15 @@ static const char* const pseudo_registers[][2] = {
|
||||||
// { "name", "help text" }
|
// { "name", "help text" }
|
||||||
|
|
||||||
{ "_bank", "Currently selected bank" },
|
{ "_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" },
|
{ "_rwport", "Address at which a read from a write port occurred" },
|
||||||
{ "_scan", "Current scanline count" },
|
{ "_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)" },
|
{ "_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
|
// empty string marks end of list, do not remove
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
|
@ -152,7 +155,6 @@ void Debugger::initialize()
|
||||||
myDialog = new DebuggerDialog(myOSystem, *this, 0, 0, myWidth, myHeight);
|
myDialog = new DebuggerDialog(myOSystem, *this, 0, 0, myWidth, myHeight);
|
||||||
myBaseDialog = myDialog;
|
myBaseDialog = myDialog;
|
||||||
|
|
||||||
myRewindManager = make_unique<RewindManager>(myOSystem, myDialog->rewindButton());
|
|
||||||
myCartDebug->setDebugWidget(&(myDialog->cartDebug()));
|
myCartDebug->setDebugWidget(&(myDialog->cartDebug()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,20 +302,19 @@ void Debugger::loadState(int state)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
int Debugger::step()
|
int Debugger::step()
|
||||||
{
|
{
|
||||||
saveOldState();
|
saveOldState("1 step");
|
||||||
mySystem.clearDirtyPages();
|
mySystem.clearDirtyPages();
|
||||||
|
|
||||||
int cyc = mySystem.cycles();
|
uInt64 startCycle = mySystem.cycles();
|
||||||
|
|
||||||
unlockBankswitchState();
|
unlockBankswitchState();
|
||||||
myOSystem.console().tia().updateScanlineByStep().flushLineCache();
|
myOSystem.console().tia().updateScanlineByStep().flushLineCache();
|
||||||
lockBankswitchState();
|
lockBankswitchState();
|
||||||
|
|
||||||
return mySystem.cycles() - cyc;
|
return int(mySystem.cycles() - startCycle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
// trace is just like step, except it treats a subroutine call as one
|
// trace is just like step, except it treats a subroutine call as one
|
||||||
// instruction.
|
// instruction.
|
||||||
|
|
||||||
|
@ -328,17 +329,17 @@ int Debugger::trace()
|
||||||
// 32 is the 6502 JSR instruction:
|
// 32 is the 6502 JSR instruction:
|
||||||
if(mySystem.peek(myCpuDebug->pc()) == 32)
|
if(mySystem.peek(myCpuDebug->pc()) == 32)
|
||||||
{
|
{
|
||||||
saveOldState();
|
saveOldState("1 trace");
|
||||||
mySystem.clearDirtyPages();
|
mySystem.clearDirtyPages();
|
||||||
|
|
||||||
int cyc = mySystem.cycles();
|
uInt64 startCycle = mySystem.cycles();
|
||||||
int targetPC = myCpuDebug->pc() + 3; // return address
|
int targetPC = myCpuDebug->pc() + 3; // return address
|
||||||
|
|
||||||
unlockBankswitchState();
|
unlockBankswitchState();
|
||||||
myOSystem.console().tia().updateScanlineByTrace(targetPC).flushLineCache();
|
myOSystem.console().tia().updateScanlineByTrace(targetPC).flushLineCache();
|
||||||
lockBankswitchState();
|
lockBankswitchState();
|
||||||
|
|
||||||
return mySystem.cycles() - cyc;
|
return int(mySystem.cycles() - startCycle);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return step();
|
return step();
|
||||||
|
@ -401,7 +402,12 @@ bool Debugger::writeTrap(uInt16 t)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Debugger::nextScanline(int lines)
|
void Debugger::nextScanline(int lines)
|
||||||
{
|
{
|
||||||
saveOldState();
|
ostringstream buf;
|
||||||
|
buf << lines << " scanline";
|
||||||
|
if(lines > 1)
|
||||||
|
buf << "s";
|
||||||
|
|
||||||
|
saveOldState(buf.str());
|
||||||
mySystem.clearDirtyPages();
|
mySystem.clearDirtyPages();
|
||||||
|
|
||||||
unlockBankswitchState();
|
unlockBankswitchState();
|
||||||
|
@ -418,7 +424,12 @@ void Debugger::nextScanline(int lines)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Debugger::nextFrame(int frames)
|
void Debugger::nextFrame(int frames)
|
||||||
{
|
{
|
||||||
saveOldState();
|
ostringstream buf;
|
||||||
|
buf << frames << " frame";
|
||||||
|
if(frames > 1)
|
||||||
|
buf << "s";
|
||||||
|
|
||||||
|
saveOldState(buf.str());
|
||||||
mySystem.clearDirtyPages();
|
mySystem.clearDirtyPages();
|
||||||
|
|
||||||
unlockBankswitchState();
|
unlockBankswitchState();
|
||||||
|
@ -433,12 +444,16 @@ void Debugger::nextFrame(int frames)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool Debugger::rewindState()
|
bool Debugger::rewindState()
|
||||||
{
|
{
|
||||||
|
RewindManager& r = myOSystem.state().rewindManager();
|
||||||
|
|
||||||
mySystem.clearDirtyPages();
|
mySystem.clearDirtyPages();
|
||||||
|
|
||||||
unlockBankswitchState();
|
unlockBankswitchState();
|
||||||
bool result = myRewindManager->rewindState();
|
bool result = r.rewindState();
|
||||||
lockBankswitchState();
|
lockBankswitchState();
|
||||||
|
|
||||||
|
myDialog->rewindButton().setEnabled(!r.empty());
|
||||||
|
|
||||||
return result;
|
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();
|
myCartDebug->saveOldState();
|
||||||
myCpuDebug->saveOldState();
|
myCpuDebug->saveOldState();
|
||||||
|
@ -476,7 +491,12 @@ void Debugger::saveOldState(bool addrewind)
|
||||||
myTiaDebug->saveOldState();
|
myTiaDebug->saveOldState();
|
||||||
|
|
||||||
// Add another rewind level to the Undo list
|
// 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
|
// Lock the bus each time the debugger is entered, so we don't disturb anything
|
||||||
lockBankswitchState();
|
lockBankswitchState();
|
||||||
|
|
||||||
// Start a new rewind list
|
// If rewinding is not enabled, always start the debugger with a clean list
|
||||||
myRewindManager->clear();
|
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
|
// 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
|
// Set the 're-disassemble' flag, but don't do it until the next scheduled time
|
||||||
myDialog->rom().invalidate(false);
|
myDialog->rom().invalidate(false);
|
||||||
|
@ -634,90 +657,3 @@ void Debugger::unlockBankswitchState()
|
||||||
mySystem.unlockDataBus();
|
mySystem.unlockDataBus();
|
||||||
myConsole.cartridge().unlockBank();
|
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);
|
|
||||||
}
|
|
||||||
|
|
|
@ -26,7 +26,6 @@ class TiaZoomWidget;
|
||||||
class EditTextWidget;
|
class EditTextWidget;
|
||||||
class RomWidget;
|
class RomWidget;
|
||||||
class Expression;
|
class Expression;
|
||||||
class Serializer;
|
|
||||||
class PackedBitArray;
|
class PackedBitArray;
|
||||||
class PromptWidget;
|
class PromptWidget;
|
||||||
class ButtonWidget;
|
class ButtonWidget;
|
||||||
|
@ -154,11 +153,6 @@ class Debugger : public DialogContainer
|
||||||
*/
|
*/
|
||||||
const string run(const string& command);
|
const string run(const string& command);
|
||||||
|
|
||||||
/**
|
|
||||||
The current cycle count of the System.
|
|
||||||
*/
|
|
||||||
int cycles() const { return int(mySystem.cycles()); }
|
|
||||||
|
|
||||||
string autoExec();
|
string autoExec();
|
||||||
|
|
||||||
string showWatches();
|
string showWatches();
|
||||||
|
@ -212,8 +206,8 @@ class Debugger : public DialogContainer
|
||||||
static Debugger& debugger() { return *myStaticDebugger; }
|
static Debugger& debugger() { return *myStaticDebugger; }
|
||||||
|
|
||||||
/* These are now exposed so Expressions can use them. */
|
/* These are now exposed so Expressions can use them. */
|
||||||
int peek(int addr) { return mySystem.peek(addr); }
|
int peek(int addr, uInt8 flags = 0) { return mySystem.peek(addr, flags); }
|
||||||
int dpeek(int addr) { return mySystem.peek(addr) | (mySystem.peek(addr+1) << 8); }
|
int dpeek(int addr, uInt8 flags = 0) { return mySystem.peek(addr, flags) | (mySystem.peek(addr+1, flags) << 8); }
|
||||||
int getAccessFlags(uInt16 addr) const
|
int getAccessFlags(uInt16 addr) const
|
||||||
{ return mySystem.getAccessFlags(addr); }
|
{ return mySystem.getAccessFlags(addr); }
|
||||||
void setAccessFlags(uInt16 addr, uInt8 flags)
|
void setAccessFlags(uInt16 addr, uInt8 flags)
|
||||||
|
@ -237,8 +231,11 @@ class Debugger : public DialogContainer
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
Save state of each debugger subsystem.
|
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.
|
Set initial state before entering the debugger.
|
||||||
|
@ -295,38 +292,6 @@ class Debugger : public DialogContainer
|
||||||
uInt32 myWidth;
|
uInt32 myWidth;
|
||||||
uInt32 myHeight;
|
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:
|
private:
|
||||||
// Following constructors and assignment operators not supported
|
// Following constructors and assignment operators not supported
|
||||||
Debugger() = delete;
|
Debugger() = delete;
|
||||||
|
|
|
@ -284,16 +284,16 @@ int DebuggerParser::decipher_arg(const string& str)
|
||||||
string DebuggerParser::showWatches()
|
string DebuggerParser::showWatches()
|
||||||
{
|
{
|
||||||
ostringstream buf;
|
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()
|
// Clear the args, since we're going to pass them to eval()
|
||||||
argStrings.clear();
|
argStrings.clear();
|
||||||
args.clear();
|
args.clear();
|
||||||
|
|
||||||
argCount = 1;
|
argCount = 1;
|
||||||
argStrings.push_back(watches[i]);
|
argStrings.push_back(myWatches[i]);
|
||||||
args.push_back(decipher_arg(argStrings[0]));
|
args.push_back(decipher_arg(argStrings[0]));
|
||||||
if(args[0] < 0)
|
if(args[0] < 0)
|
||||||
buf << "BAD WATCH " << (i+1) << ": " << argStrings[0] << endl;
|
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;
|
string result;
|
||||||
result += Base::toString(addr);
|
result += Base::toString(addr);
|
||||||
result += ": ";
|
result += ": ";
|
||||||
bool r = debugger.readTrap(addr);
|
bool r = debugger.readTrap(addr);
|
||||||
bool w = debugger.writeTrap(addr);
|
bool w = debugger.writeTrap(addr);
|
||||||
|
enabled = r || w;
|
||||||
if(r && w)
|
if(r && w)
|
||||||
result += "read|write";
|
result += "read|write";
|
||||||
else if(r)
|
else if(r)
|
||||||
|
@ -550,8 +551,7 @@ string DebuggerParser::trapStatus(int addr)
|
||||||
else
|
else
|
||||||
result += "none";
|
result += "none";
|
||||||
|
|
||||||
// TODO - technically, we should determine if the label is read or write
|
const string& l = debugger.cartDebug().getLabel(addr, !w);
|
||||||
const string& l = debugger.cartDebug().getLabel(addr, true);
|
|
||||||
if(l != "") {
|
if(l != "") {
|
||||||
result += " (";
|
result += " (";
|
||||||
result += l;
|
result += l;
|
||||||
|
@ -570,11 +570,11 @@ bool DebuggerParser::saveScriptFile(string file)
|
||||||
ofstream out(file);
|
ofstream out(file);
|
||||||
|
|
||||||
FunctionDefMap funcs = debugger.getFunctionDefMap();
|
FunctionDefMap funcs = debugger.getFunctionDefMap();
|
||||||
for(const auto& i: funcs)
|
for(const auto& f: funcs)
|
||||||
out << "function " << i.first << " { " << i.second << " }" << endl;
|
out << "function " << f.first << " { " << f.second << " }" << endl;
|
||||||
|
|
||||||
for(const auto& i: watches)
|
for(const auto& w: myWatches)
|
||||||
out << "watch " << i << endl;
|
out << "watch " << w << endl;
|
||||||
|
|
||||||
for(uInt32 i = 0; i < 0x10000; ++i)
|
for(uInt32 i = 0; i < 0x10000; ++i)
|
||||||
if(debugger.breakPoint(i))
|
if(debugger.breakPoint(i))
|
||||||
|
@ -735,6 +735,7 @@ void DebuggerParser::executeClearconfig()
|
||||||
// "cleartraps"
|
// "cleartraps"
|
||||||
void DebuggerParser::executeCleartraps()
|
void DebuggerParser::executeCleartraps()
|
||||||
{
|
{
|
||||||
|
myTraps.clear();
|
||||||
debugger.clearAllTraps();
|
debugger.clearAllTraps();
|
||||||
commandResult << "all traps cleared";
|
commandResult << "all traps cleared";
|
||||||
}
|
}
|
||||||
|
@ -743,7 +744,7 @@ void DebuggerParser::executeCleartraps()
|
||||||
// "clearwatches"
|
// "clearwatches"
|
||||||
void DebuggerParser::executeClearwatches()
|
void DebuggerParser::executeClearwatches()
|
||||||
{
|
{
|
||||||
watches.clear();
|
myWatches.clear();
|
||||||
commandResult << "all watches cleared";
|
commandResult << "all watches cleared";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -856,9 +857,9 @@ void DebuggerParser::executeDelfunction()
|
||||||
void DebuggerParser::executeDelwatch()
|
void DebuggerParser::executeDelwatch()
|
||||||
{
|
{
|
||||||
int which = args[0] - 1;
|
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";
|
commandResult << "removed watch";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -890,16 +891,37 @@ void DebuggerParser::executeDisasm()
|
||||||
// "dump"
|
// "dump"
|
||||||
void DebuggerParser::executeDump()
|
void DebuggerParser::executeDump()
|
||||||
{
|
{
|
||||||
for(int i = 0; i < 8; ++i)
|
auto dump = [&](int start, int end)
|
||||||
{
|
{
|
||||||
int start = args[0] + i*16;
|
for(int i = start; i <= end; i += 16)
|
||||||
commandResult << Base::toString(start) << ": ";
|
|
||||||
for(int j = 0; j < 16; ++j)
|
|
||||||
{
|
{
|
||||||
commandResult << Base::toString(debugger.peek(start+j)) << " ";
|
// Print label every 16 bytes
|
||||||
if(j == 7) commandResult << "- ";
|
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"
|
// "listtraps"
|
||||||
void DebuggerParser::executeListtraps()
|
void DebuggerParser::executeListtraps()
|
||||||
{
|
{
|
||||||
int count = 0;
|
if(myTraps.size() > 0)
|
||||||
|
|
||||||
for(uInt32 i = 0; i <= 0xffff; ++i)
|
|
||||||
{
|
{
|
||||||
if(debugger.readTrap(i) || debugger.writeTrap(i))
|
bool enabled = true;
|
||||||
{
|
for(const auto& trap: myTraps)
|
||||||
commandResult << trapStatus(i) << " + mirrors" << endl;
|
commandResult << trapStatus(trap, enabled) << " + mirrors" << endl;
|
||||||
count++;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
|
||||||
if(!count)
|
|
||||||
commandResult << "no traps set";
|
commandResult << "no traps set";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1388,10 +1404,20 @@ void DebuggerParser::executeSaverom()
|
||||||
// "saveses"
|
// "saveses"
|
||||||
void DebuggerParser::executeSaveses()
|
void DebuggerParser::executeSaveses()
|
||||||
{
|
{
|
||||||
if(debugger.prompt().saveBuffer(argStrings[0]))
|
// Create a file named with the current date and time
|
||||||
commandResult << "saved session to file " << argStrings[0];
|
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
|
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"
|
// "watch"
|
||||||
void DebuggerParser::executeWatch()
|
void DebuggerParser::executeWatch()
|
||||||
{
|
{
|
||||||
watches.push_back(argStrings[0]);
|
myWatches.push_back(argStrings[0]);
|
||||||
commandResult << "added watch \"" << argStrings[0] << "\"";
|
commandResult << "added watch \"" << argStrings[0] << "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1875,11 +1906,13 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||||
|
|
||||||
{
|
{
|
||||||
"dump",
|
"dump",
|
||||||
"Dump 128 bytes of memory at address <xx>",
|
"Dump data at address <xx> [to yy]",
|
||||||
"Example: dump f000",
|
"Examples:\n"
|
||||||
|
" dump f000 - dumps 128 bytes @ f000\n"
|
||||||
|
" dump f000 f0ff - dumps all bytes from f000 to f0ff",
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
{ kARG_WORD, kARG_END_ARGS },
|
{ kARG_WORD, kARG_MULTI_BYTE },
|
||||||
std::mem_fn(&DebuggerParser::executeDump)
|
std::mem_fn(&DebuggerParser::executeDump)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -2179,8 +2212,8 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||||
|
|
||||||
{
|
{
|
||||||
"saveconfig",
|
"saveconfig",
|
||||||
"Save Distella config file",
|
"Save Distella config file (with default name)",
|
||||||
"Example: saveconfig file.cfg",
|
"Example: saveconfig",
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
{ kARG_END_ARGS },
|
{ kARG_END_ARGS },
|
||||||
|
@ -2189,8 +2222,9 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||||
|
|
||||||
{
|
{
|
||||||
"savedis",
|
"savedis",
|
||||||
"Save Distella disassembly",
|
"Save Distella disassembly (with default name)",
|
||||||
"Example: savedis file.asm",
|
"Example: savedis\n"
|
||||||
|
"NOTE: saves to default save location",
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
{ kARG_END_ARGS },
|
{ kARG_END_ARGS },
|
||||||
|
@ -2199,8 +2233,9 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||||
|
|
||||||
{
|
{
|
||||||
"saverom",
|
"saverom",
|
||||||
"Save (possibly patched) ROM",
|
"Save (possibly patched) ROM (with default name)",
|
||||||
"Example: savedrom file.bin",
|
"Example: saverom\n"
|
||||||
|
"NOTE: saves to default save location",
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
{ kARG_END_ARGS },
|
{ kARG_END_ARGS },
|
||||||
|
@ -2209,11 +2244,12 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||||
|
|
||||||
{
|
{
|
||||||
"saveses",
|
"saveses",
|
||||||
"Save console session to file xx",
|
"Save console session",
|
||||||
"Example: saveses session.txt",
|
"Example: saveses\n"
|
||||||
true,
|
"NOTE: saves to default save location",
|
||||||
false,
|
false,
|
||||||
{ kARG_FILE, kARG_END_ARGS },
|
false,
|
||||||
|
{ kARG_END_ARGS },
|
||||||
std::mem_fn(&DebuggerParser::executeSaveses)
|
std::mem_fn(&DebuggerParser::executeSaveses)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
class Debugger;
|
class Debugger;
|
||||||
class FilesystemNode;
|
class FilesystemNode;
|
||||||
|
@ -64,7 +65,6 @@ class DebuggerParser
|
||||||
bool getArgs(const string& command, string& verb);
|
bool getArgs(const string& command, string& verb);
|
||||||
bool validateArgs(int cmd);
|
bool validateArgs(int cmd);
|
||||||
string eval();
|
string eval();
|
||||||
string trapStatus(int addr);
|
|
||||||
bool saveScriptFile(string file);
|
bool saveScriptFile(string file);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -114,7 +114,11 @@ class DebuggerParser
|
||||||
StringList argStrings;
|
StringList argStrings;
|
||||||
uInt32 argCount;
|
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
|
// List of available command methods
|
||||||
void executeA();
|
void executeA();
|
||||||
|
|
|
@ -33,7 +33,8 @@
|
||||||
All 7800-related stuff has been removed, as well as some commandline options.
|
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.
|
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
|
class DiStella
|
||||||
{
|
{
|
||||||
|
@ -42,13 +43,14 @@ class DiStella
|
||||||
// This will eventually grow to include all options supported by
|
// This will eventually grow to include all options supported by
|
||||||
// standalone Distella
|
// standalone Distella
|
||||||
struct Settings {
|
struct Settings {
|
||||||
Common::Base::Format gfx_format;
|
Common::Base::Format gfxFormat;
|
||||||
bool resolve_code; // Attempt to detect code vs. data sections
|
bool resolveCode; // Attempt to detect code vs. data sections
|
||||||
bool show_addresses; // Show PC addresses (always off for external output)
|
bool showAddresses; // Show PC addresses (always off for external output)
|
||||||
bool aflag; // Turns 'A' off in accumulator instructions (-a in Distella)
|
bool aFlag; // Turns 'A' off in accumulator instructions (-a in Distella)
|
||||||
bool fflag; // Forces correct address length (-f in Distella)
|
bool fFlag; // Forces correct address length (-f in Distella)
|
||||||
bool rflag; // Relocate calls out of address range (-r 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)
|
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
|
static Settings settings; // Default settings
|
||||||
|
|
||||||
|
@ -81,9 +83,16 @@ class DiStella
|
||||||
|
|
||||||
// These functions are part of the original Distella code
|
// These functions are part of the original Distella code
|
||||||
void disasm(uInt32 distart, int pass);
|
void disasm(uInt32 distart, int pass);
|
||||||
|
void disasmPass1(CartDebug::AddressList& debuggerAddresses);
|
||||||
|
void disasmFromAddress(uInt32 distart);
|
||||||
|
|
||||||
bool check_range(uInt16 start, uInt16 end) const;
|
bool check_range(uInt16 start, uInt16 end) const;
|
||||||
int mark(uInt32 address, uInt8 mask, bool directive = false);
|
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
|
// Convenience methods to generate appropriate labels
|
||||||
inline void labelA12High(stringstream& buf, uInt8 op, uInt16 addr, int labfound)
|
inline void labelA12High(stringstream& buf, uInt8 op, uInt16 addr, int labfound)
|
||||||
|
@ -115,6 +124,7 @@ class DiStella
|
||||||
stringstream myDisasmBuf;
|
stringstream myDisasmBuf;
|
||||||
std::queue<uInt16> myAddressQueue;
|
std::queue<uInt16> myAddressQueue;
|
||||||
uInt16 myOffset, myPC, myPCEnd;
|
uInt16 myOffset, myPC, myPCEnd;
|
||||||
|
uInt16 mySegType;
|
||||||
|
|
||||||
struct resource {
|
struct resource {
|
||||||
uInt16 start;
|
uInt16 start;
|
||||||
|
@ -179,6 +189,7 @@ class DiStella
|
||||||
AccessMode source;
|
AccessMode source;
|
||||||
ReadWriteMode rw_mode;
|
ReadWriteMode rw_mode;
|
||||||
uInt8 cycles;
|
uInt8 cycles;
|
||||||
|
uInt8 bytes;
|
||||||
};
|
};
|
||||||
static const Instruction_tag ourLookup[256];
|
static const Instruction_tag ourLookup[256];
|
||||||
|
|
||||||
|
|
|
@ -40,10 +40,6 @@ TIADebug::TIADebug(Debugger& dbg, Console& console)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
const DebuggerState& TIADebug::getState()
|
const DebuggerState& TIADebug::getState()
|
||||||
{
|
{
|
||||||
myState.ram.clear();
|
|
||||||
for(int i = 0; i < 0x010; ++i)
|
|
||||||
myState.ram.push_back(myTIA.peek(i));
|
|
||||||
|
|
||||||
// Color registers
|
// Color registers
|
||||||
myState.coluRegs.clear();
|
myState.coluRegs.clear();
|
||||||
myState.coluRegs.push_back(coluP0());
|
myState.coluRegs.push_back(coluP0());
|
||||||
|
@ -117,10 +113,6 @@ const DebuggerState& TIADebug::getState()
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void TIADebug::saveOldState()
|
void TIADebug::saveOldState()
|
||||||
{
|
{
|
||||||
myOldState.ram.clear();
|
|
||||||
for(int i = 0; i < 0x010; ++i)
|
|
||||||
myOldState.ram.push_back(myTIA.peek(i));
|
|
||||||
|
|
||||||
// Color registers
|
// Color registers
|
||||||
myOldState.coluRegs.clear();
|
myOldState.coluRegs.clear();
|
||||||
myOldState.coluRegs.push_back(coluP0());
|
myOldState.coluRegs.push_back(coluP0());
|
||||||
|
@ -699,7 +691,25 @@ void TIADebug::setENABLOld(bool b)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
int TIADebug::frameCount() const
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
|
@ -38,7 +38,6 @@ enum {
|
||||||
class TiaState : public DebuggerState
|
class TiaState : public DebuggerState
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
IntArray ram;
|
|
||||||
IntArray coluRegs;
|
IntArray coluRegs;
|
||||||
IntArray fixedCols;
|
IntArray fixedCols;
|
||||||
IntArray gr;
|
IntArray gr;
|
||||||
|
@ -160,6 +159,9 @@ class TIADebug : public DebuggerSystem
|
||||||
int scanlines() const;
|
int scanlines() const;
|
||||||
int scanlinesLastFrame() const;
|
int scanlinesLastFrame() const;
|
||||||
int frameCount() const;
|
int frameCount() const;
|
||||||
|
int frameCycles() const;
|
||||||
|
int cyclesLo() const;
|
||||||
|
int cyclesHi() const;
|
||||||
int clocksThisLine() const;
|
int clocksThisLine() const;
|
||||||
bool vsync() const;
|
bool vsync() const;
|
||||||
bool vblank() const;
|
bool vblank() const;
|
||||||
|
|
|
@ -59,7 +59,7 @@ Cartridge0840Widget::Cartridge0840Widget(
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Cartridge0840Widget::loadConfig()
|
void Cartridge0840Widget::loadConfig()
|
||||||
{
|
{
|
||||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
myBank->setSelectedIndex(myCart.getBank());
|
||||||
|
|
||||||
CartDebugWidget::loadConfig();
|
CartDebugWidget::loadConfig();
|
||||||
}
|
}
|
||||||
|
@ -83,8 +83,8 @@ string Cartridge0840Widget::bankState()
|
||||||
ostringstream& buf = buffer();
|
ostringstream& buf = buffer();
|
||||||
|
|
||||||
static const char* const spot[] = { "$800", "$840" };
|
static const char* const spot[] = { "$800", "$840" };
|
||||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
buf << "Bank = " << std::dec << myCart.getBank()
|
||||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
<< ", hotspot = " << spot[myCart.getBank()];
|
||||||
|
|
||||||
return buf.str();
|
return buf.str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,7 +134,7 @@ void CartridgeBFSCWidget::saveOldState()
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void CartridgeBFSCWidget::loadConfig()
|
void CartridgeBFSCWidget::loadConfig()
|
||||||
{
|
{
|
||||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
myBank->setSelectedIndex(myCart.getBank());
|
||||||
|
|
||||||
CartDebugWidget::loadConfig();
|
CartDebugWidget::loadConfig();
|
||||||
}
|
}
|
||||||
|
@ -167,8 +167,8 @@ string CartridgeBFSCWidget::bankState()
|
||||||
"$FFB0", "$FFB1", "$FFB2", "$FFB3", "$FFB4", "$FFB5", "$FFB6", "$FFB7",
|
"$FFB0", "$FFB1", "$FFB2", "$FFB3", "$FFB4", "$FFB5", "$FFB6", "$FFB7",
|
||||||
"$FFB8", "$FFB9", "$FFBA", "$FFBB", "$FFBC", "$FFBD", "$FFBE", "$FFBF"
|
"$FFB8", "$FFB9", "$FFBA", "$FFBB", "$FFBC", "$FFBD", "$FFBE", "$FFBF"
|
||||||
};
|
};
|
||||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
buf << "Bank = " << std::dec << myCart.getBank()
|
||||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
<< ", hotspot = " << spot[myCart.getBank()];
|
||||||
|
|
||||||
return buf.str();
|
return buf.str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,7 +121,7 @@ CartridgeBFWidget::CartridgeBFWidget(
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void CartridgeBFWidget::loadConfig()
|
void CartridgeBFWidget::loadConfig()
|
||||||
{
|
{
|
||||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
myBank->setSelectedIndex(myCart.getBank());
|
||||||
|
|
||||||
CartDebugWidget::loadConfig();
|
CartDebugWidget::loadConfig();
|
||||||
}
|
}
|
||||||
|
@ -154,8 +154,8 @@ string CartridgeBFWidget::bankState()
|
||||||
"$FFB0", "$FFB1", "$FFB2", "$FFB3", "$FFB4", "$FFB5", "$FFB6", "$FFB7",
|
"$FFB0", "$FFB1", "$FFB2", "$FFB3", "$FFB4", "$FFB5", "$FFB6", "$FFB7",
|
||||||
"$FFB8", "$FFB9", "$FFBA", "$FFBB", "$FFBC", "$FFBD", "$FFBE", "$FFBF"
|
"$FFB8", "$FFB9", "$FFBA", "$FFBB", "$FFBC", "$FFBD", "$FFBE", "$FFBF"
|
||||||
};
|
};
|
||||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
buf << "Bank = " << std::dec << myCart.getBank()
|
||||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
<< ", hotspot = " << spot[myCart.getBank()];
|
||||||
|
|
||||||
return buf.str();
|
return buf.str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -252,7 +252,7 @@ void CartridgeBUSWidget::saveOldState()
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void CartridgeBUSWidget::loadConfig()
|
void CartridgeBUSWidget::loadConfig()
|
||||||
{
|
{
|
||||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
myBank->setSelectedIndex(myCart.getBank());
|
||||||
|
|
||||||
// Get registers, using change tracking
|
// Get registers, using change tracking
|
||||||
IntArray alist;
|
IntArray alist;
|
||||||
|
@ -397,8 +397,8 @@ string CartridgeBUSWidget::bankState()
|
||||||
static const char* const spot[] = {
|
static const char* const spot[] = {
|
||||||
"$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB"
|
"$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB"
|
||||||
};
|
};
|
||||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
buf << "Bank = " << std::dec << myCart.getBank()
|
||||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
<< ", hotspot = " << spot[myCart.getBank()];
|
||||||
|
|
||||||
return buf.str();
|
return buf.str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ CartridgeCDFWidget::CartridgeCDFWidget(
|
||||||
uInt16 size = 8 * 4096;
|
uInt16 size = 8 * 4096;
|
||||||
|
|
||||||
ostringstream info;
|
ostringstream info;
|
||||||
info << "CDF cartridge\n"
|
info << "CDF cartridge (version " << cart.myVersion << ")\n"
|
||||||
<< "32K ROM, seven 4K banks are accessible to 2600\n"
|
<< "32K ROM, seven 4K banks are accessible to 2600\n"
|
||||||
<< "8K CDF RAM\n"
|
<< "8K CDF RAM\n"
|
||||||
<< "CDF registers accessible @ $FFF0 - $FFF3\n"
|
<< "CDF registers accessible @ $FFF0 - $FFF3\n"
|
||||||
|
@ -230,7 +230,7 @@ void CartridgeCDFWidget::saveOldState()
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void CartridgeCDFWidget::loadConfig()
|
void CartridgeCDFWidget::loadConfig()
|
||||||
{
|
{
|
||||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
myBank->setSelectedIndex(myCart.getBank());
|
||||||
|
|
||||||
// Get registers, using change tracking
|
// Get registers, using change tracking
|
||||||
IntArray alist;
|
IntArray alist;
|
||||||
|
@ -360,8 +360,8 @@ string CartridgeCDFWidget::bankState()
|
||||||
static const char* const spot[] = {
|
static const char* const spot[] = {
|
||||||
"$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB"
|
"$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB"
|
||||||
};
|
};
|
||||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
buf << "Bank = " << std::dec << myCart.getBank()
|
||||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
<< ", hotspot = " << spot[myCart.getBank()];
|
||||||
|
|
||||||
return buf.str();
|
return buf.str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,7 +158,7 @@ void CartridgeCMWidget::saveOldState()
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void CartridgeCMWidget::loadConfig()
|
void CartridgeCMWidget::loadConfig()
|
||||||
{
|
{
|
||||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
myBank->setSelectedIndex(myCart.getBank());
|
||||||
|
|
||||||
RiotDebug& riot = Debugger::debugger().riotDebug();
|
RiotDebug& riot = Debugger::debugger().riotDebug();
|
||||||
const RiotState& state = static_cast<const RiotState&>(riot.getState());
|
const RiotState& state = static_cast<const RiotState&>(riot.getState());
|
||||||
|
@ -219,7 +219,7 @@ string CartridgeCMWidget::bankState()
|
||||||
{
|
{
|
||||||
ostringstream& buf = buffer();
|
ostringstream& buf = buffer();
|
||||||
|
|
||||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
buf << "Bank = " << std::dec << myCart.getBank()
|
||||||
<< ", RAM is" << (myCart.mySWCHA & 0x10 ? " Inactive" :
|
<< ", RAM is" << (myCart.mySWCHA & 0x10 ? " Inactive" :
|
||||||
myCart.mySWCHA & 0x20 ? " Read-only" : " Write-only");
|
myCart.mySWCHA & 0x20 ? " Read-only" : " Write-only");
|
||||||
|
|
||||||
|
|
|
@ -102,7 +102,7 @@ void CartridgeDFSCWidget::saveOldState()
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void CartridgeDFSCWidget::loadConfig()
|
void CartridgeDFSCWidget::loadConfig()
|
||||||
{
|
{
|
||||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
myBank->setSelectedIndex(myCart.getBank());
|
||||||
|
|
||||||
CartDebugWidget::loadConfig();
|
CartDebugWidget::loadConfig();
|
||||||
}
|
}
|
||||||
|
@ -131,8 +131,8 @@ string CartridgeDFSCWidget::bankState()
|
||||||
"$FFD0", "$FFD1", "$FFD2", "$FFD3", "$FFD4", "$FFD5", "$FFD6", "$FFE7",
|
"$FFD0", "$FFD1", "$FFD2", "$FFD3", "$FFD4", "$FFD5", "$FFD6", "$FFE7",
|
||||||
"$FFD8", "$FFD9", "$FFDA", "$FFDB", "$FFDC", "$FFDD", "$FFDE", "$FFDF"
|
"$FFD8", "$FFD9", "$FFDA", "$FFDB", "$FFDC", "$FFDD", "$FFDE", "$FFDF"
|
||||||
};
|
};
|
||||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
buf << "Bank = " << std::dec << myCart.getBank()
|
||||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
<< ", hotspot = " << spot[myCart.getBank()];
|
||||||
|
|
||||||
return buf.str();
|
return buf.str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,7 @@ CartridgeDFWidget::CartridgeDFWidget(
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void CartridgeDFWidget::loadConfig()
|
void CartridgeDFWidget::loadConfig()
|
||||||
{
|
{
|
||||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
myBank->setSelectedIndex(myCart.getBank());
|
||||||
|
|
||||||
CartDebugWidget::loadConfig();
|
CartDebugWidget::loadConfig();
|
||||||
}
|
}
|
||||||
|
@ -118,8 +118,8 @@ string CartridgeDFWidget::bankState()
|
||||||
"$FFD0", "$FFD1", "$FFD2", "$FFD3", "$FFD4", "$FFD5", "$FFD6", "$FFD7",
|
"$FFD0", "$FFD1", "$FFD2", "$FFD3", "$FFD4", "$FFD5", "$FFD6", "$FFD7",
|
||||||
"$FFD8", "$FFD9", "$FFDA", "$FFDB", "$FFDC", "$FFDD", "$FFDE", "$FFDF"
|
"$FFD8", "$FFD9", "$FFDA", "$FFDB", "$FFDC", "$FFDD", "$FFDE", "$FFDF"
|
||||||
};
|
};
|
||||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
buf << "Bank = " << std::dec << myCart.getBank()
|
||||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
<< ", hotspot = " << spot[myCart.getBank()];
|
||||||
|
|
||||||
return buf.str();
|
return buf.str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -218,7 +218,7 @@ void CartridgeDPCPlusWidget::saveOldState()
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void CartridgeDPCPlusWidget::loadConfig()
|
void CartridgeDPCPlusWidget::loadConfig()
|
||||||
{
|
{
|
||||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
myBank->setSelectedIndex(myCart.getBank());
|
||||||
|
|
||||||
// Get registers, using change tracking
|
// Get registers, using change tracking
|
||||||
IntArray alist;
|
IntArray alist;
|
||||||
|
@ -327,8 +327,8 @@ string CartridgeDPCPlusWidget::bankState()
|
||||||
static const char* const spot[] = {
|
static const char* const spot[] = {
|
||||||
"$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB"
|
"$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB"
|
||||||
};
|
};
|
||||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
buf << "Bank = " << std::dec << myCart.getBank()
|
||||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
<< ", hotspot = " << spot[myCart.getBank()];
|
||||||
|
|
||||||
return buf.str();
|
return buf.str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,7 +156,7 @@ void CartridgeDPCWidget::saveOldState()
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void CartridgeDPCWidget::loadConfig()
|
void CartridgeDPCWidget::loadConfig()
|
||||||
{
|
{
|
||||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
myBank->setSelectedIndex(myCart.getBank());
|
||||||
|
|
||||||
// Get registers, using change tracking
|
// Get registers, using change tracking
|
||||||
IntArray alist;
|
IntArray alist;
|
||||||
|
@ -228,8 +228,8 @@ string CartridgeDPCWidget::bankState()
|
||||||
ostringstream& buf = buffer();
|
ostringstream& buf = buffer();
|
||||||
|
|
||||||
static const char* const spot[] = { "$FFF8", "$FFF9" };
|
static const char* const spot[] = { "$FFF8", "$FFF9" };
|
||||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
buf << "Bank = " << std::dec << myCart.getBank()
|
||||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
<< ", hotspot = " << spot[myCart.getBank()];
|
||||||
|
|
||||||
return buf.str();
|
return buf.str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,7 @@ void CartridgeEFSCWidget::saveOldState()
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void CartridgeEFSCWidget::loadConfig()
|
void CartridgeEFSCWidget::loadConfig()
|
||||||
{
|
{
|
||||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
myBank->setSelectedIndex(myCart.getBank());
|
||||||
|
|
||||||
CartDebugWidget::loadConfig();
|
CartDebugWidget::loadConfig();
|
||||||
}
|
}
|
||||||
|
@ -113,8 +113,8 @@ string CartridgeEFSCWidget::bankState()
|
||||||
"$FFE0", "$FFE1", "$FFE2", "$FFE3", "$FFE4", "$FFE5", "$FFE6", "$FFE7",
|
"$FFE0", "$FFE1", "$FFE2", "$FFE3", "$FFE4", "$FFE5", "$FFE6", "$FFE7",
|
||||||
"$FFE8", "$FFE9", "$FFEA", "$FFEB", "$FFEC", "$FFED", "$FFEE", "$FFEF"
|
"$FFE8", "$FFE9", "$FFEA", "$FFEB", "$FFEC", "$FFED", "$FFEE", "$FFEF"
|
||||||
};
|
};
|
||||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
buf << "Bank = " << std::dec << myCart.getBank()
|
||||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
<< ", hotspot = " << spot[myCart.getBank()];
|
||||||
|
|
||||||
return buf.str();
|
return buf.str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ CartridgeEFWidget::CartridgeEFWidget(
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void CartridgeEFWidget::loadConfig()
|
void CartridgeEFWidget::loadConfig()
|
||||||
{
|
{
|
||||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
myBank->setSelectedIndex(myCart.getBank());
|
||||||
|
|
||||||
CartDebugWidget::loadConfig();
|
CartDebugWidget::loadConfig();
|
||||||
}
|
}
|
||||||
|
@ -100,8 +100,8 @@ string CartridgeEFWidget::bankState()
|
||||||
"$FFE0", "$FFE1", "$FFE2", "$FFE3", "$FFE4", "$FFE5", "$FFE6", "$FFE7",
|
"$FFE0", "$FFE1", "$FFE2", "$FFE3", "$FFE4", "$FFE5", "$FFE6", "$FFE7",
|
||||||
"$FFE8", "$FFE9", "$FFEA", "$FFEB", "$FFEC", "$FFED", "$FFEE", "$FFEF"
|
"$FFE8", "$FFE9", "$FFEA", "$FFEB", "$FFEC", "$FFED", "$FFEE", "$FFEF"
|
||||||
};
|
};
|
||||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
buf << "Bank = " << std::dec << myCart.getBank()
|
||||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
<< ", hotspot = " << spot[myCart.getBank()];
|
||||||
|
|
||||||
return buf.str();
|
return buf.str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ CartridgeF0Widget::CartridgeF0Widget(
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void CartridgeF0Widget::loadConfig()
|
void CartridgeF0Widget::loadConfig()
|
||||||
{
|
{
|
||||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
myBank->setSelectedIndex(myCart.getBank());
|
||||||
|
|
||||||
CartDebugWidget::loadConfig();
|
CartDebugWidget::loadConfig();
|
||||||
}
|
}
|
||||||
|
@ -97,7 +97,7 @@ string CartridgeF0Widget::bankState()
|
||||||
{
|
{
|
||||||
ostringstream& buf = buffer();
|
ostringstream& buf = buffer();
|
||||||
|
|
||||||
buf << "Bank = " << std::dec << myCart.myCurrentBank << ", hotspot = $FFF0";
|
buf << "Bank = " << std::dec << myCart.getBank() << ", hotspot = $FFF0";
|
||||||
|
|
||||||
return buf.str();
|
return buf.str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ void CartridgeF4SCWidget::saveOldState()
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void CartridgeF4SCWidget::loadConfig()
|
void CartridgeF4SCWidget::loadConfig()
|
||||||
{
|
{
|
||||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
myBank->setSelectedIndex(myCart.getBank());
|
||||||
|
|
||||||
CartDebugWidget::loadConfig();
|
CartDebugWidget::loadConfig();
|
||||||
}
|
}
|
||||||
|
@ -103,8 +103,8 @@ string CartridgeF4SCWidget::bankState()
|
||||||
static const char* const spot[] = {
|
static const char* const spot[] = {
|
||||||
"$FFF4", "$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB"
|
"$FFF4", "$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB"
|
||||||
};
|
};
|
||||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
buf << "Bank = " << std::dec << myCart.getBank()
|
||||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
<< ", hotspot = " << spot[myCart.getBank()];
|
||||||
|
|
||||||
return buf.str();
|
return buf.str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ CartridgeF4Widget::CartridgeF4Widget(
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void CartridgeF4Widget::loadConfig()
|
void CartridgeF4Widget::loadConfig()
|
||||||
{
|
{
|
||||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
myBank->setSelectedIndex(myCart.getBank());
|
||||||
|
|
||||||
CartDebugWidget::loadConfig();
|
CartDebugWidget::loadConfig();
|
||||||
}
|
}
|
||||||
|
@ -90,8 +90,8 @@ string CartridgeF4Widget::bankState()
|
||||||
static const char* const spot[] = {
|
static const char* const spot[] = {
|
||||||
"$FFF4", "$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB"
|
"$FFF4", "$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB"
|
||||||
};
|
};
|
||||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
buf << "Bank = " << std::dec << myCart.getBank()
|
||||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
<< ", hotspot = " << spot[myCart.getBank()];
|
||||||
|
|
||||||
return buf.str();
|
return buf.str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ void CartridgeF6SCWidget::saveOldState()
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void CartridgeF6SCWidget::loadConfig()
|
void CartridgeF6SCWidget::loadConfig()
|
||||||
{
|
{
|
||||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
myBank->setSelectedIndex(myCart.getBank());
|
||||||
|
|
||||||
CartDebugWidget::loadConfig();
|
CartDebugWidget::loadConfig();
|
||||||
}
|
}
|
||||||
|
@ -97,8 +97,8 @@ string CartridgeF6SCWidget::bankState()
|
||||||
ostringstream& buf = buffer();
|
ostringstream& buf = buffer();
|
||||||
|
|
||||||
static const char* const spot[] = { "$FFF6", "$FFF7", "$FFF8", "$FFF9" };
|
static const char* const spot[] = { "$FFF6", "$FFF7", "$FFF8", "$FFF9" };
|
||||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
buf << "Bank = " << std::dec << myCart.getBank()
|
||||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
<< ", hotspot = " << spot[myCart.getBank()];
|
||||||
|
|
||||||
return buf.str();
|
return buf.str();
|
||||||
}
|
}
|
||||||
|
|