Merge branch 'master' into refactoring/frame_manager
83
.vscode/c_cpp_properties.json
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Mac",
|
||||
"includePath": [
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1",
|
||||
"/usr/local/include",
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/9.0.0/include",
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include",
|
||||
"/usr/include",
|
||||
"${workspaceRoot}",
|
||||
"${workspaceRoot}/src/common",
|
||||
"${workspaceRoot}/src/common/tv_filters",
|
||||
"${workspaceRoot}/src/gui",
|
||||
"${workspaceRoot}/src/emucore",
|
||||
"${workspaceRoot}/src/emucore/tia",
|
||||
"${workspaceRoot}/src/unix",
|
||||
"${workspaceRoot}/src/debugger",
|
||||
"${workspaceRoot}/src/debugger/gui",
|
||||
"${workspaceRoot}/src/cheat",
|
||||
"/usr/local/include/SDL2"
|
||||
],
|
||||
"defines": ["DEBUGGER_SUPPORT"],
|
||||
"intelliSenseMode": "clang-x64",
|
||||
"browse": {
|
||||
"path": [
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1",
|
||||
"/usr/local/include",
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/9.0.0/include",
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include",
|
||||
"/usr/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": ""
|
||||
},
|
||||
"macFrameworkPath": [
|
||||
"/System/Library/Frameworks",
|
||||
"/Library/Frameworks"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"/usr/include",
|
||||
"/usr/local/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"defines": [],
|
||||
"intelliSenseMode": "clang-x64",
|
||||
"browse": {
|
||||
"path": [
|
||||
"/usr/include",
|
||||
"/usr/local/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Win32",
|
||||
"includePath": [
|
||||
"C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"defines": [
|
||||
"_DEBUG",
|
||||
"UNICODE"
|
||||
],
|
||||
"intelliSenseMode": "msvc-x64",
|
||||
"browse": {
|
||||
"path": [
|
||||
"C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include/*",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"version": 3
|
||||
}
|
35
.vscode/settings.json
vendored
@ -1,23 +1,16 @@
|
||||
// Platzieren Sie Ihre Einstellungen in dieser Datei, um Standard- und Benutzereinstellungen zu überschreiben.
|
||||
{
|
||||
"clang.cxxflags": [
|
||||
"-std=c++11",
|
||||
"-I/home/cnspeckn/git/stella/src/common",
|
||||
"-I/home/cnspeckn/git/stella/src/emucore",
|
||||
"-I/home/cnspeckn/git/stella/src/emucore/tia",
|
||||
"-I/home/cnspeckn/git/stella/src/debugger",
|
||||
"-I/home/cnspeckn/git/stella/src/debugger/gui",
|
||||
"-I/home/cnspeckn/git/stella/src/gui"
|
||||
],
|
||||
"editor.tabSize": 2,
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"files.exclude": {
|
||||
"**/.git": true,
|
||||
"**/.svn": true,
|
||||
"**/.hg": true,
|
||||
"**/.DS_Store": true,
|
||||
"src/**/*.o": true
|
||||
},
|
||||
"editor.trimAutoWhitespace": true,
|
||||
"editor.useTabStops": false
|
||||
}
|
||||
"editor.tabSize": 2,
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"files.exclude": {
|
||||
"**/.git": true,
|
||||
"**/.svn": true,
|
||||
"**/.hg": true,
|
||||
"**/.DS_Store": true,
|
||||
"src/**/*.o": true
|
||||
},
|
||||
"editor.trimAutoWhitespace": true,
|
||||
"editor.useTabStops": false,
|
||||
"C_Cpp.intelliSenseEngine": "Default",
|
||||
"files.insertFinalNewline": true
|
||||
}
|
||||
|
22
Announce.txt
@ -9,7 +9,7 @@
|
||||
SSSS ttt eeeee llll llll aaaaa
|
||||
|
||||
===========================================================================
|
||||
Release 5.0.1 for Linux, MacOSX and Windows
|
||||
Release 5.0.2 for Linux, MacOSX and Windows
|
||||
===========================================================================
|
||||
|
||||
The Atari 2600 Video Computer System (VCS), introduced in 1977, was the
|
||||
@ -21,30 +21,30 @@ all of your favourite Atari 2600 games again! Stella was originally
|
||||
developed for Linux by Bradford W. Mott, however, it has been ported to a
|
||||
number of other platforms and is currently maintained by Stephen Anthony.
|
||||
|
||||
This is the 5.0.1 release of Stella for Linux, Mac OSX and Windows. The
|
||||
This is the 5.0.2 release of Stella for Linux, Mac OSX and Windows. The
|
||||
distributions currently available are:
|
||||
|
||||
* Binaries for Windows XP_SP3(*)/Vista/7/8/10 :
|
||||
Stella-5.0.1-win32.exe (32-bit EXE installer)
|
||||
Stella-5.0.1-x64.exe (64-bit EXE installer)
|
||||
Stella-5.0.1-windows.zip (32/64 bit versions)
|
||||
Stella-5.0.2-win32.exe (32-bit EXE installer)
|
||||
Stella-5.0.2-x64.exe (64-bit EXE installer)
|
||||
Stella-5.0.2-windows.zip (32/64 bit versions)
|
||||
|
||||
(*) Note: Support for Windows XP is problematic on some systems,
|
||||
and will probably be discontinued in a future release.
|
||||
|
||||
* Binary distribution for MacOS X 10.7 and above :
|
||||
Stella-5.0.1-macosx.dmg (64-bit Intel)
|
||||
Stella-5.0.2-macosx.dmg (64-bit Intel)
|
||||
|
||||
* Binary distribution in 32-bit & 64-bit Ubuntu DEB format :
|
||||
stella_5.0.1-1_i386.deb
|
||||
stella_5.0.1-1_amd64.deb
|
||||
stella_5.0.2-1_i386.deb
|
||||
stella_5.0.2-1_amd64.deb
|
||||
|
||||
* Binary distribution in 32-bit & 64-bit RPM format :
|
||||
stella-5.0.1-2.i386.rpm
|
||||
stella-5.0.1-2.x86_64.rpm
|
||||
stella-5.0.2-2.i386.rpm
|
||||
stella-5.0.2-2.x86_64.rpm
|
||||
|
||||
* Source code distribution for all platforms :
|
||||
stella-5.0.1-src.tar.xz
|
||||
stella-5.0.2-src.tar.xz
|
||||
|
||||
|
||||
Distribution Site
|
||||
|
100
Changes.txt
@ -9,9 +9,105 @@
|
||||
SSSS ttt eeeee llll llll aaaaa
|
||||
|
||||
===========================================================================
|
||||
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)
|
||||
|
||||
* Fixed issues in keypad, Genesis and various other controllers that use
|
||||
@ -25,8 +121,6 @@
|
||||
|
||||
* Codebase now uses C++14 features.
|
||||
|
||||
-Have fun!
|
||||
|
||||
|
||||
4.7.3 to 5.0: (July 16, 2017)
|
||||
|
||||
|
2
Makefile
@ -27,7 +27,7 @@
|
||||
srcdir ?= .
|
||||
|
||||
DEFINES := -D_GLIBCXX_USE_CXX11_ABI=1
|
||||
LDFLAGS :=
|
||||
LDFLAGS := -pthread
|
||||
INCLUDES :=
|
||||
LIBS :=
|
||||
OBJS :=
|
||||
|
75
configure
vendored
@ -378,31 +378,54 @@ echocheck "compiler version"
|
||||
|
||||
have_clang=no
|
||||
cc_check_define __clang_version__ && have_clang=yes
|
||||
if test $have_clang = no; then
|
||||
cc_check_define __clang__ && have_clang=yes
|
||||
fi
|
||||
have_gcc=no
|
||||
cc_check_define __GNUC__ && have_gcc=yes
|
||||
|
||||
if test "$have_clang" = yes; then
|
||||
cxx_name=`( $cc -v ) 2>&1 | tail -n 1 | cut -d ' ' -f 1`
|
||||
cxx_version=$( $CXX -dM -E -x c /dev/null | grep __clang_version__ | sed 's/^.*[^0-9]\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*$/\1/g' 2>&1)
|
||||
if test "$?" -gt 0; then
|
||||
cxx_version="not found"
|
||||
fi
|
||||
|
||||
case $cxx_version in
|
||||
[3].[4-9]|[3].[4-9].[0-9]|[3].[4-9].[0-9][-.]*|[4-9].[0-9].[0-9])
|
||||
_cxx_major=`echo $cxx_version | cut -d '.' -f 1`
|
||||
_cxx_minor=`echo $cxx_version | cut -d '.' -f 2`
|
||||
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
|
||||
;;
|
||||
'not found')
|
||||
cxx_verc_fail=yes
|
||||
;;
|
||||
*)
|
||||
else
|
||||
cxx_version="$cxx_version, bad"
|
||||
cxx_verc_fail=yes
|
||||
;;
|
||||
esac
|
||||
cxx_verc_fail=bad
|
||||
fi
|
||||
else
|
||||
cxx_name=`( $cc -v ) 2>&1 | tail -n 1 | cut -d ' ' -f 1`
|
||||
cxx_version=$( $CXX -dM -E -x c /dev/null | grep __clang_version__ | sed 's/^.*[^0-9]\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*$/\1/g' 2>&1)
|
||||
if test "$?" -gt 0; then
|
||||
cxx_version="not found"
|
||||
fi
|
||||
|
||||
case $cxx_version in
|
||||
[3].[4-9]|[3].[4-9].[0-9]|[3].[4-9].[0-9][-.]*|[4-9].[0-9].[0-9])
|
||||
_cxx_major=`echo $cxx_version | cut -d '.' -f 1`
|
||||
_cxx_minor=`echo $cxx_version | cut -d '.' -f 2`
|
||||
cxx_version="$cxx_version, ok"
|
||||
cxx_verc_fail=no
|
||||
;;
|
||||
'not found')
|
||||
cxx_verc_fail=yes
|
||||
;;
|
||||
*)
|
||||
cxx_version="$cxx_version, bad"
|
||||
cxx_verc_fail=yes
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
CXXFLAGS="$CXXFLAGS"
|
||||
_make_def_HAVE_GCC3='HAVE_GCC3 = 1'
|
||||
add_line_to_config_mk 'CXX_UPDATE_DEP_FLAG = -MMD -MF "$(*D)/$(DEPDIR)/$(*F).d" -MQ "$@" -MP'
|
||||
@ -516,6 +539,10 @@ else
|
||||
DEFINES="$DEFINES -DUNIX"
|
||||
_host_os=unix
|
||||
;;
|
||||
darwin*)
|
||||
DEFINES="$DEFINES -DUNIX -DDARWIN"
|
||||
_host_os=darwin
|
||||
;;
|
||||
irix*)
|
||||
DEFINES="$DEFINES -DUNIX"
|
||||
_ranlib=:
|
||||
@ -695,12 +722,18 @@ fi
|
||||
|
||||
LIBS="$LIBS `$_sdlconfig $_sdl_conf_libs`"
|
||||
LD=$CXX
|
||||
|
||||
case $_host_os in
|
||||
unix)
|
||||
DEFINES="$DEFINES -DBSPF_UNIX -DHAVE_GETTIMEOFDAY"
|
||||
MODULES="$MODULES $SRC/unix"
|
||||
INCLUDES="$INCLUDES -I$SRC/unix"
|
||||
;;
|
||||
darwin)
|
||||
DEFINES="$DEFINES -DBSPF_UNIX -DHAVE_GETTIMEOFDAY -DOSX_KEYS"
|
||||
MODULES="$MODULES $SRC/unix"
|
||||
INCLUDES="$INCLUDES -I$SRC/unix"
|
||||
;;
|
||||
win32)
|
||||
DEFINES="$DEFINES -DBSPF_WINDOWS -DHAVE_GETTIMEOFDAY"
|
||||
MODULES="$MODULES $SRC/windows"
|
||||
@ -803,3 +836,11 @@ EOF
|
||||
|
||||
# This should be taken care of elsewhere, but I'm not sure where
|
||||
rm -f stella-conf*
|
||||
|
||||
if test "$_host_os" = darwin; then
|
||||
cat <<EOI
|
||||
|
||||
WARNING: plain UNIX-style builds on OSX without XCode have degraded functionality
|
||||
and are unsupported. Continue on your own risk...
|
||||
EOI
|
||||
fi
|
||||
|
7
debian/changelog
vendored
@ -1,3 +1,10 @@
|
||||
stella (5.0.2-1) stable; urgency=high
|
||||
|
||||
* Version 5.0.2 release
|
||||
|
||||
-- Stephen Anthony <stephena@users.sf.net> Sun, 20 Aug 2017 17:09:59 -0230
|
||||
|
||||
|
||||
stella (5.0.1-1) stable; urgency=high
|
||||
|
||||
* Version 5.0.1 release
|
||||
|
@ -541,12 +541,13 @@ that holds 'number of scanlines' on an actual console).</p>
|
||||
<table border="1" cellpadding="3">
|
||||
<tr><th>Function</th><th>Description</th></tr>
|
||||
<tr><td> _bank</td><td> Currently selected bank</td></tr>
|
||||
<tr><td> _rwport</td><td> Last address to attempt a read from the cart write port</td></tr>
|
||||
<tr><td> _fcount</td><td> Number of frames since emulation started</td></tr>
|
||||
<tr><td> _cclocks</td><td> Color clocks on a scanline</td></tr>
|
||||
<tr><td> _fcount</td><td> Number of frames since emulation started</td></tr>
|
||||
<tr><td> _fcycles</td><td> Number of cycles since frame started</td></tr>
|
||||
<tr><td> _rwport</td><td> Last address to attempt a read from the cart write port</td></tr>
|
||||
<tr><td> _scan</td><td> Current scanline count</td></tr>
|
||||
<tr><td> _vsync</td><td> Whether vertical sync is enabled (1 or 0)</td></tr>
|
||||
<tr><td> _vblank</td><td> Whether vertical blank is enabled (1 or 0)</td></tr>
|
||||
<tr><td> _vsync</td><td> Whether vertical sync is enabled (1 or 0)</td></tr>
|
||||
</table>
|
||||
|
||||
<p><b>_scan</b> always contains the current scanline count. You can use
|
||||
@ -646,7 +647,7 @@ Type "help 'cmd'" to see extended information about the given command.</p>
|
||||
delfunction - Delete function with label xx
|
||||
delwatch - Delete watch <xx>
|
||||
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>
|
||||
exitrom - Exit emulator, return to ROM launcher
|
||||
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
|
||||
s - Set Stack Pointer to value xx
|
||||
save - Save breaks, watches, traps to file xx
|
||||
saveconfig - Save Distella config file
|
||||
savedis - Save Distella disassembly
|
||||
saverom - Save (possibly patched) ROM
|
||||
saveconfig - Save Distella config file (with default name)
|
||||
savedis - Save Distella disassembly (with default name)
|
||||
saverom - Save (possibly patched) ROM (with default name)
|
||||
saveses - Save console session to file xx
|
||||
savesnap - Save current TIA image to PNG file
|
||||
savestate - Save emulator state xx (valid args 0-9)
|
||||
|
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>
|
||||
<center><h2><b>A multi-platform Atari 2600 VCS emulator</b></h2></center>
|
||||
|
||||
<center><h4><b>Release 5.0.1</b></h4></center>
|
||||
<center><h4><b>Release 5.0.2</b></h4></center>
|
||||
<br><br>
|
||||
|
||||
<center><h2><b>User's Guide</b></h2></center>
|
||||
@ -2039,14 +2039,21 @@
|
||||
<td><pre>-dsense <number></pre></td>
|
||||
<td>Sensitivity for emulation of paddles when using a digital device
|
||||
(ie, joystick digital axis or button, keyboard key, etc).
|
||||
Valid range of values is from 1 to 10, with larger numbers causing
|
||||
Valid range of values is from 1 to 20, with larger numbers causing
|
||||
faster movement.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><pre>-msense <number></pre></td>
|
||||
<td>Sensitivity for emulation of paddles when using a mouse.
|
||||
Valid range of values is from 1 to 15, with larger numbers causing
|
||||
Valid range of values is from 1 to 20, with larger numbers causing
|
||||
faster movement.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><pre>-tsense <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>
|
||||
</tr>
|
||||
|
||||
@ -2082,6 +2089,11 @@
|
||||
<td>Disable Supercharger BIOS progress loading bars.</td>
|
||||
</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>
|
||||
<td><pre>-snapsavedir <path></pre></td>
|
||||
<td>The directory to save snapshot files to.</td>
|
||||
@ -2284,23 +2296,29 @@
|
||||
<tr>
|
||||
<td><pre>-holdjoy0 <U,D,L,R,F></pre></td>
|
||||
<td>Start the emulator with the left joystick direction/button held down
|
||||
(ie, use 'UF' for up and fire).</td>
|
||||
(ie, use 'UF' for up and fire). After entering the emulation, you will
|
||||
have to press and release the direction again to release the event.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><pre>-holdjoy1 <U,D,L,R,F></pre></td>
|
||||
<td>Start the emulator with the right joystick direction/button held down
|
||||
(ie, use 'UF' for up and fire).</td>
|
||||
(ie, use 'UF' for up and fire). After entering the emulation, you will
|
||||
have to press and release the direction again to release the event.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><pre>-holdselect</pre></td>
|
||||
<td>Start the emulator with the Game Select switch held down.</td>
|
||||
<td>Start the emulator with the Game Select switch held down. After entering
|
||||
the emulation, you will have to press and release 'Select' to release the
|
||||
event.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><pre>-holdreset</pre></td>
|
||||
<td>Start the emulator with the Game Reset switch held down.</td>
|
||||
<td>Start the emulator with the Game Reset switch held down. After entering
|
||||
the emulation, you will have to press and release 'Reset' to release the
|
||||
event.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
@ -2456,6 +2474,7 @@
|
||||
<tr><td>Fast SC/AR BIOS</td><td>skip progress loading bars for SuperCharger ROMs</td><td>-fastscbios</td></tr>
|
||||
<tr><td>Show UI messages</td><td>overlay UI messages onscreen</td><td>-uimessages</td></tr>
|
||||
<tr><td>Center window</td><td>attempt to center application window</td><td>-center</td></tr>
|
||||
<tr><td>Use multi-threading</td><td>enable multi-threaded rendering</td><td>-threads</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
@ -2527,7 +2546,7 @@
|
||||
<p><b>Input Settings</b> dialog:</p>
|
||||
<table border="5" cellpadding="2" frame="box" rules="none">
|
||||
<tr>
|
||||
<td><img src="graphics/options_input.png"></td>
|
||||
<td><img src="graphics/eventmapping.png"></td>
|
||||
<td> </td>
|
||||
<td valign="top"><br>This dialog is described in further detail in
|
||||
<b>Advanced Configuration - <a href="#Remapping">Event Remapping</a></b>.</td>
|
||||
@ -2588,7 +2607,7 @@
|
||||
<tr><td>Save snapshots according to</td><td>specifies how to name saved snapshots</td><td>-snapname</td></tr>
|
||||
<tr><td>Continuous snapshot interval</td><td>interval (in seconds) between snapshot</td><td>-ssinterval</td></tr>
|
||||
<tr><td>Overwrite existing files</td><td>whether to overwrite old snapshots</td><td>-sssingle</td></tr>
|
||||
<tr><td>Disable image filtering (1x mode)</td><td>save snapshot in 1x mode, without filtering</td><td>-ss1x</td></tr>
|
||||
<tr><td>Ignore scaling (1x mode)</td><td>save snapshot in 1x mode, without scaling</td><td>-ss1x</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
@ -2696,6 +2715,7 @@
|
||||
<tr><td>Joy deadzone size</td><td>Deadzone area for axes on joysticks/gamepads</td><td>-joydeadzone</td></tr>
|
||||
<tr><td>Digital paddle sensitivity</td><td>Sensitivity used when emulating a paddle using a digital device</td><td>-dsense</td></tr>
|
||||
<tr><td>Mouse paddle sensitivity</td><td>Sensitivity used when emulating a paddle using a mouse</td><td>-msense</td></tr>
|
||||
<tr><td>Trackball sensitivity</td><td>Sensitivity used when emulating a trackball device using a mouse</td><td>-tsense</td></tr>
|
||||
<tr><td>Allow all 4 ...</td><td>Allow all 4 joystick directions to be pressed simultaneously</td><td>-joyallow4</td></tr>
|
||||
<tr><td>Grab mouse ...</td><td>Keep mouse in window in emulation mode</td><td>-grabmouse</td></tr>
|
||||
<tr><td>Use Control key combos</td><td>Enable using Control key in keyboard actions</td><td>-ctrlcombo</td></tr>
|
||||
|
70
src/common/RewindManager.cxx
Normal file
@ -0,0 +1,70 @@
|
||||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2017 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#include "OSystem.hxx"
|
||||
#include "Serializer.hxx"
|
||||
#include "StateManager.hxx"
|
||||
#include "TIA.hxx"
|
||||
|
||||
#include "RewindManager.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
RewindManager::RewindManager(OSystem& system, StateManager& statemgr)
|
||||
: myOSystem(system),
|
||||
myStateManager(statemgr)
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool RewindManager::addState(const string& message)
|
||||
{
|
||||
RewindPtr state = make_unique<RewindState>(); // TODO: get this from object pool
|
||||
Serializer& s = state->data;
|
||||
|
||||
s.reset(); // rewind Serializer internal buffers
|
||||
if(myStateManager.saveState(s) && myOSystem.console().tia().saveDisplay(s))
|
||||
{
|
||||
state->message = "Rewind " + message;
|
||||
|
||||
// Add to the list TODO: should check against current size
|
||||
myStateList.emplace_front(std::move(state));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool RewindManager::rewindState()
|
||||
{
|
||||
if(myStateList.size() > 0)
|
||||
{
|
||||
RewindPtr state = std::move(myStateList.front());
|
||||
myStateList.pop_front(); // TODO: add 'state' to object pool
|
||||
Serializer& s = state->data;
|
||||
|
||||
s.reset(); // rewind Serializer internal buffers
|
||||
myStateManager.loadState(s);
|
||||
myOSystem.console().tia().loadDisplay(s);
|
||||
|
||||
// Show message indicating the rewind state
|
||||
myOSystem.frameBuffer().showMessage(state->message);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
84
src/common/RewindManager.hxx
Normal file
@ -0,0 +1,84 @@
|
||||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2017 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#ifndef REWIND_MANAGER_HXX
|
||||
#define REWIND_MANAGER_HXX
|
||||
|
||||
class OSystem;
|
||||
class StateManager;
|
||||
|
||||
#include <list>
|
||||
#include "bspf.hxx"
|
||||
|
||||
/**
|
||||
This class is used to save (and later 'rewind') system save states.
|
||||
|
||||
TODO: This will eventually be converted to use object pools
|
||||
Currently, it uses a C++ doubly-linked list as a stack, with
|
||||
add/remove happening at the front of the list
|
||||
Also, the additions are currently unbounded
|
||||
|
||||
@author Stephen Anthony
|
||||
*/
|
||||
class RewindManager
|
||||
{
|
||||
public:
|
||||
RewindManager(OSystem& system, StateManager& statemgr);
|
||||
|
||||
public:
|
||||
/**
|
||||
Add a new state file with the given message; this message will be
|
||||
displayed when the state is rewound.
|
||||
|
||||
@param message Message to display when rewinding to this state
|
||||
*/
|
||||
bool addState(const string& message);
|
||||
|
||||
/**
|
||||
Rewind one level of the state list, and display the message associated
|
||||
with that state.
|
||||
*/
|
||||
bool rewindState();
|
||||
|
||||
bool empty() const { return myStateList.size() == 0; }
|
||||
void clear() { myStateList.clear(); }
|
||||
|
||||
private:
|
||||
// Maximum number of states to save
|
||||
static constexpr uInt32 MAX_SIZE = 100; // FIXME: use this
|
||||
|
||||
OSystem& myOSystem;
|
||||
StateManager& myStateManager;
|
||||
|
||||
struct RewindState {
|
||||
Serializer data;
|
||||
string message;
|
||||
};
|
||||
|
||||
using RewindPtr = unique_ptr<RewindState>;
|
||||
std::list<RewindPtr> myStateList;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
RewindManager() = delete;
|
||||
RewindManager(const RewindManager&) = delete;
|
||||
RewindManager(RewindManager&&) = delete;
|
||||
RewindManager& operator=(const RewindManager&) = delete;
|
||||
RewindManager& operator=(RewindManager&&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
@ -56,14 +56,6 @@ class SoundNull : public Sound
|
||||
*/
|
||||
void setEnabled(bool enable) override { }
|
||||
|
||||
/**
|
||||
The system cycle counter is being adjusting by the specified amount. Any
|
||||
members using the system cycle counter should be adjusted as needed.
|
||||
|
||||
@param amount The amount the cycle counter is being adjusted by
|
||||
*/
|
||||
void adjustCycleCounter(Int32 amount) override { }
|
||||
|
||||
/**
|
||||
Sets the number of channels (mono or stereo sound).
|
||||
|
||||
@ -110,7 +102,7 @@ class SoundNull : public Sound
|
||||
@param value The value to save into the register
|
||||
@param cycle The system cycle at which the register is being updated
|
||||
*/
|
||||
void set(uInt16 addr, uInt8 value, Int32 cycle) override { }
|
||||
void set(uInt16 addr, uInt8 value, uInt64 cycle) override { }
|
||||
|
||||
/**
|
||||
Sets the volume of the sound device to the specified level. The
|
||||
|
@ -226,12 +226,6 @@ void SoundSDL2::adjustVolume(Int8 direction)
|
||||
myOSystem.frameBuffer().showMessage(message);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL2::adjustCycleCounter(Int32 amount)
|
||||
{
|
||||
myLastRegisterSetCycle += amount;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL2::setChannels(uInt32 channels)
|
||||
{
|
||||
@ -249,7 +243,7 @@ void SoundSDL2::setFrameRate(float framerate)
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL2::set(uInt16 addr, uInt8 value, Int32 cycle)
|
||||
void SoundSDL2::set(uInt16 addr, uInt8 value, uInt64 cycle)
|
||||
{
|
||||
SDL_LockAudio();
|
||||
|
||||
@ -261,11 +255,7 @@ void SoundSDL2::set(uInt16 addr, uInt8 value, Int32 cycle)
|
||||
// the sound to "scale" correctly, we have to know the games real frame
|
||||
// rate (e.g., 50 or 60) and the currently emulated frame rate. We use these
|
||||
// values to "scale" the time before the register change occurs.
|
||||
RegWrite info;
|
||||
info.addr = addr;
|
||||
info.value = value;
|
||||
info.delta = delta;
|
||||
myRegWriteQueue.enqueue(info);
|
||||
myRegWriteQueue.enqueue(addr, value, delta);
|
||||
|
||||
// Update last cycle counter to the current cycle
|
||||
myLastRegisterSetCycle = cycle;
|
||||
@ -390,7 +380,7 @@ bool SoundSDL2::save(Serializer& out) const
|
||||
for(int i = 0; i < 6; ++i)
|
||||
out.putByte(0);
|
||||
|
||||
out.putInt(myLastRegisterSetCycle);
|
||||
out.putLong(myLastRegisterSetCycle);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
@ -427,7 +417,7 @@ bool SoundSDL2::load(Serializer& in)
|
||||
for(int i = 0; i < 6; ++i)
|
||||
in.getByte();
|
||||
|
||||
myLastRegisterSetCycle = in.getInt();
|
||||
myLastRegisterSetCycle = in.getLong();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
@ -476,14 +466,17 @@ double SoundSDL2::RegWriteQueue::duration() const
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL2::RegWriteQueue::enqueue(const RegWrite& info)
|
||||
void SoundSDL2::RegWriteQueue::enqueue(uInt16 addr, uInt8 value, double delta)
|
||||
{
|
||||
// If an attempt is made to enqueue more than the queue can hold then
|
||||
// we'll enlarge the queue's capacity.
|
||||
if(mySize == myCapacity)
|
||||
grow();
|
||||
|
||||
myBuffer[myTail] = info;
|
||||
RegWrite& reg = myBuffer[myTail];
|
||||
reg.addr = addr;
|
||||
reg.value = value;
|
||||
reg.delta = delta;
|
||||
myTail = (myTail + 1) % myCapacity;
|
||||
++mySize;
|
||||
}
|
||||
|
@ -55,14 +55,6 @@ class SoundSDL2 : public Sound
|
||||
*/
|
||||
void setEnabled(bool state) override;
|
||||
|
||||
/**
|
||||
The system cycle counter is being adjusting by the specified amount. Any
|
||||
members using the system cycle counter should be adjusted as needed.
|
||||
|
||||
@param amount The amount the cycle counter is being adjusted by
|
||||
*/
|
||||
void adjustCycleCounter(Int32 amount) override;
|
||||
|
||||
/**
|
||||
Sets the number of channels (mono or stereo sound). Note that this
|
||||
determines how the emulation should 'mix' the channels of the TIA sound
|
||||
@ -113,7 +105,7 @@ class SoundSDL2 : public Sound
|
||||
@param value The value to save into the register
|
||||
@param cycle The system cycle at which the register is being updated
|
||||
*/
|
||||
void set(uInt16 addr, uInt8 value, Int32 cycle) override;
|
||||
void set(uInt16 addr, uInt8 value, uInt64 cycle) override;
|
||||
|
||||
/**
|
||||
Sets the volume of the sound device to the specified level. The
|
||||
@ -174,6 +166,9 @@ class SoundSDL2 : public Sound
|
||||
uInt16 addr;
|
||||
uInt8 value;
|
||||
double delta;
|
||||
|
||||
RegWrite(uInt16 a = 0, uInt8 v = 0, double d = 0.0)
|
||||
: addr(a), value(v), delta(d) { }
|
||||
};
|
||||
|
||||
/**
|
||||
@ -209,7 +204,7 @@ class SoundSDL2 : public Sound
|
||||
/**
|
||||
Enqueue the specified object.
|
||||
*/
|
||||
void enqueue(const RegWrite& info);
|
||||
void enqueue(uInt16 addr, uInt8 value, double delta);
|
||||
|
||||
/**
|
||||
Return the item at the front on the queue.
|
||||
@ -255,7 +250,7 @@ class SoundSDL2 : public Sound
|
||||
bool myIsInitializedFlag;
|
||||
|
||||
// Indicates the cycle when a sound register was last set
|
||||
Int32 myLastRegisterSetCycle;
|
||||
uInt64 myLastRegisterSetCycle;
|
||||
|
||||
// Indicates the number of channels (mono or stereo)
|
||||
uInt32 myNumChannels;
|
||||
|
@ -28,22 +28,23 @@
|
||||
|
||||
#include "StateManager.hxx"
|
||||
|
||||
#define STATE_HEADER "05000000state"
|
||||
#define STATE_HEADER "05000302state"
|
||||
#define MOVIE_HEADER "03030000movie"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
StateManager::StateManager(OSystem& osystem)
|
||||
: myOSystem(osystem),
|
||||
myCurrentSlot(0),
|
||||
myActiveMode(kOffMode)
|
||||
myActiveMode(Mode::Off)
|
||||
{
|
||||
myRewindManager = make_unique<RewindManager>(myOSystem, *this);
|
||||
reset();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool StateManager::toggleRecordMode()
|
||||
{
|
||||
#if 0
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void StateManager::toggleRecordMode()
|
||||
{
|
||||
if(myActiveMode != kMovieRecordMode) // Turn on movie record mode
|
||||
{
|
||||
myActiveMode = kOffMode;
|
||||
@ -80,15 +81,8 @@ bool StateManager::toggleRecordMode()
|
||||
}
|
||||
|
||||
return myActiveMode == kMovieRecordMode;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool StateManager::toggleRewindMode()
|
||||
{
|
||||
// FIXME - For now, I'm going to use this to activate movie playback
|
||||
#if 0
|
||||
////////////////////////////////////////////////////////
|
||||
// FIXME - For now, I'm going to use this to activate movie playback
|
||||
// Close the writer, since we're about to re-open in read mode
|
||||
myMovieWriter.close();
|
||||
|
||||
@ -127,34 +121,44 @@ bool StateManager::toggleRewindMode()
|
||||
myMovieReader.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
return myActiveMode == kMoviePlaybackMode;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void StateManager::toggleRewindMode()
|
||||
{
|
||||
myActiveMode = myActiveMode == Mode::Rewind ? Mode::Off : Mode::Rewind;
|
||||
if(myActiveMode == Mode::Rewind)
|
||||
myOSystem.frameBuffer().showMessage("Continuous rewind enabled");
|
||||
else
|
||||
myOSystem.frameBuffer().showMessage("Continuous rewind disabled");
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void StateManager::update()
|
||||
{
|
||||
#if 0
|
||||
switch(myActiveMode)
|
||||
{
|
||||
case kMovieRecordMode:
|
||||
case Mode::Rewind:
|
||||
myRewindManager->addState("1 frame");
|
||||
break;
|
||||
|
||||
#if 0
|
||||
case Mode::MovieRecord:
|
||||
myOSystem.console().controller(Controller::Left).save(myMovieWriter);
|
||||
myOSystem.console().controller(Controller::Right).save(myMovieWriter);
|
||||
myOSystem.console().switches().save(myMovieWriter);
|
||||
break;
|
||||
|
||||
case kMoviePlaybackMode:
|
||||
case Mode::MoviePlayback:
|
||||
myOSystem.console().controller(Controller::Left).load(myMovieReader);
|
||||
myOSystem.console().controller(Controller::Right).load(myMovieReader);
|
||||
myOSystem.console().switches().load(myMovieReader);
|
||||
break;
|
||||
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
@ -20,6 +20,7 @@
|
||||
|
||||
class OSystem;
|
||||
|
||||
#include "RewindManager.hxx"
|
||||
#include "Serializer.hxx"
|
||||
|
||||
/**
|
||||
@ -32,41 +33,58 @@ class OSystem;
|
||||
class StateManager
|
||||
{
|
||||
public:
|
||||
enum class Mode {
|
||||
Off,
|
||||
Rewind,
|
||||
MovieRecord,
|
||||
MoviePlayback
|
||||
};
|
||||
|
||||
/**
|
||||
Create a new statemananger class
|
||||
Create a new statemananger class.
|
||||
*/
|
||||
StateManager(OSystem& osystem);
|
||||
|
||||
public:
|
||||
/**
|
||||
Answers whether the manager is in record or playback mode
|
||||
Answers whether the manager is in record or playback mode.
|
||||
*/
|
||||
bool isActive() const { return myActiveMode != kOffMode; }
|
||||
Mode mode() const { return myActiveMode; }
|
||||
|
||||
bool toggleRecordMode();
|
||||
bool toggleRewindMode();
|
||||
#if 0
|
||||
/**
|
||||
Toggle movie recording mode (FIXME - currently disabled)
|
||||
*/
|
||||
void toggleRecordMode();
|
||||
#endif
|
||||
|
||||
/**
|
||||
Updates the state of the system based on the currently active mode
|
||||
Toggle state rewind recording mode; this uses the RewindManager
|
||||
for its functionality.
|
||||
*/
|
||||
void toggleRewindMode();
|
||||
|
||||
/**
|
||||
Updates the state of the system based on the currently active mode.
|
||||
*/
|
||||
void update();
|
||||
|
||||
/**
|
||||
Load a state into the current system
|
||||
Load a state into the current system.
|
||||
|
||||
@param slot The state 'slot' to load state from
|
||||
*/
|
||||
void loadState(int slot = -1);
|
||||
|
||||
/**
|
||||
Save the current state from the system
|
||||
Save the current state from the system.
|
||||
|
||||
@param slot The state 'slot' to save into
|
||||
*/
|
||||
void saveState(int slot = -1);
|
||||
|
||||
/**
|
||||
Switches to the next higher state slot (circular queue style)
|
||||
Switches to the next higher state slot (circular queue style).
|
||||
*/
|
||||
void changeState();
|
||||
|
||||
@ -91,19 +109,16 @@ class StateManager
|
||||
bool saveState(Serializer& out);
|
||||
|
||||
/**
|
||||
Resets manager to defaults
|
||||
Resets manager to defaults.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
private:
|
||||
enum Mode {
|
||||
kOffMode,
|
||||
kMoviePlaybackMode,
|
||||
kMovieRecordMode,
|
||||
kRewindPlaybackMode,
|
||||
kRewindRecordMode
|
||||
};
|
||||
/**
|
||||
The rewind facility for the state manager
|
||||
*/
|
||||
RewindManager& rewindManager() const { return *myRewindManager; }
|
||||
|
||||
private:
|
||||
enum {
|
||||
kVersion = 001
|
||||
};
|
||||
@ -124,6 +139,9 @@ class StateManager
|
||||
Serializer myMovieWriter;
|
||||
Serializer myMovieReader;
|
||||
|
||||
// Stored savestates to be later rewound
|
||||
unique_ptr<RewindManager> myRewindManager;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
StateManager() = delete;
|
@ -18,7 +18,7 @@
|
||||
#ifndef VERSION_HXX
|
||||
#define VERSION_HXX
|
||||
|
||||
#define STELLA_VERSION "5.0.1"
|
||||
#define STELLA_BUILD "3487"
|
||||
#define STELLA_VERSION "5.0.3_pre"
|
||||
#define STELLA_BUILD "3535"
|
||||
|
||||
#endif
|
||||
|
@ -111,9 +111,13 @@ namespace BSPF
|
||||
|
||||
// Combines 'max' and 'min', and clamps value to the upper/lower value
|
||||
// if it is outside the specified range
|
||||
template<typename T> inline T clamp(T a, T l, T u)
|
||||
template<class T> inline T clamp(T val, T lower, T upper)
|
||||
{
|
||||
return (a<l) ? l : (a>u) ? u : a;
|
||||
return (val < lower) ? lower : (val > upper) ? upper : val;
|
||||
}
|
||||
template<class T> inline void clamp(T& val, T lower, T upper, T setVal)
|
||||
{
|
||||
if(val < lower || val > upper) val = setVal;
|
||||
}
|
||||
|
||||
// Compare two strings, ignoring case
|
||||
|
@ -10,10 +10,12 @@ MODULE_OBJS := \
|
||||
src/common/FSNodeZIP.o \
|
||||
src/common/PNGLibrary.o \
|
||||
src/common/MouseControl.o \
|
||||
src/common/RewindManager.o \
|
||||
src/common/StateManager.o \
|
||||
src/common/ZipHandler.o
|
||||
|
||||
MODULE_DIRS += \
|
||||
src/common
|
||||
|
||||
# Include common rules
|
||||
# Include common rules
|
||||
include $(srcdir)/common.rules
|
||||
|
@ -15,6 +15,7 @@
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#include <thread>
|
||||
#include "AtariNTSC.hxx"
|
||||
|
||||
// blitter related
|
||||
@ -66,52 +67,252 @@ void AtariNTSC::initializePalette(const uInt8* palette)
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void AtariNTSC::render(const uInt8* atari_in, uInt32 in_width,
|
||||
uInt32 in_height, void* rgb_out, uInt32 out_pitch)
|
||||
void AtariNTSC::enableThreading(bool enable)
|
||||
{
|
||||
uInt32 systemThreads = enable ? std::thread::hardware_concurrency() : 0;
|
||||
if(systemThreads <= 1)
|
||||
{
|
||||
myWorkerThreads = 0;
|
||||
myTotalThreads = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
systemThreads = std::min(4u, systemThreads);
|
||||
|
||||
myWorkerThreads = systemThreads - 1;
|
||||
myTotalThreads = systemThreads;
|
||||
|
||||
myThreads = make_unique<std::thread[]>(myWorkerThreads);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void AtariNTSC::render(const uInt8* atari_in, const uInt32 in_width, const uInt32 in_height,
|
||||
void* rgb_out, const uInt32 out_pitch, uInt32* rgb_in)
|
||||
{
|
||||
// Spawn the threads...
|
||||
for(uInt32 i = 0; i < myWorkerThreads; ++i)
|
||||
{
|
||||
myThreads[i] = std::thread([=] {
|
||||
rgb_in == nullptr ?
|
||||
renderThread(atari_in, in_width, in_height, myTotalThreads, i+1, rgb_out, out_pitch) :
|
||||
renderWithPhosphorThread(atari_in, in_width, in_height, myTotalThreads, i+1, rgb_in, rgb_out, out_pitch);
|
||||
});
|
||||
}
|
||||
// Make the main thread busy too
|
||||
rgb_in == nullptr ?
|
||||
renderThread(atari_in, in_width, in_height, myTotalThreads, 0, rgb_out, out_pitch) :
|
||||
renderWithPhosphorThread(atari_in, in_width, in_height, myTotalThreads, 0, rgb_in, rgb_out, out_pitch);
|
||||
// ...and make them join again
|
||||
for(uInt32 i = 0; i < myWorkerThreads; ++i)
|
||||
myThreads[i].join();
|
||||
|
||||
// Copy phosphor values into out buffer
|
||||
if(rgb_in != nullptr)
|
||||
memcpy(rgb_out, rgb_in, in_height * out_pitch);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void AtariNTSC::renderThread(const uInt8* atari_in, const uInt32 in_width,
|
||||
const uInt32 in_height, const uInt32 numThreads, const uInt32 threadNum,
|
||||
void* rgb_out, const uInt32 out_pitch)
|
||||
{
|
||||
// Adapt parameters to thread number
|
||||
const uInt32 yStart = in_height * threadNum / numThreads;
|
||||
const uInt32 yEnd = in_height * (threadNum + 1) / numThreads;
|
||||
atari_in += in_width * yStart;
|
||||
rgb_out = static_cast<char*>(rgb_out) + out_pitch * yStart;
|
||||
|
||||
uInt32 const chunk_count = (in_width - 1) / PIXEL_in_chunk;
|
||||
while ( in_height-- )
|
||||
|
||||
for(uInt32 y = yStart; y < yEnd; ++y)
|
||||
{
|
||||
const uInt8* line_in = atari_in;
|
||||
ATARI_NTSC_BEGIN_ROW( NTSC_black, line_in[0] );
|
||||
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 )
|
||||
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] );
|
||||
// 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] );
|
||||
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_in += 2;
|
||||
line_out += 7;
|
||||
}
|
||||
|
||||
/* finish final pixels */
|
||||
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] );
|
||||
// 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] );
|
||||
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
|
||||
|
||||
atari_in += in_width;
|
||||
rgb_out = static_cast<char*>(rgb_out) + out_pitch;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void AtariNTSC::renderWithPhosphorThread(const uInt8* atari_in, const uInt32 in_width,
|
||||
const uInt32 in_height, const uInt32 numThreads, const uInt32 threadNum,
|
||||
uInt32* rgb_in, void* rgb_out, const uInt32 out_pitch)
|
||||
{
|
||||
// Adapt parameters to thread number
|
||||
const uInt32 yStart = in_height * threadNum / numThreads;
|
||||
const uInt32 yEnd = in_height * (threadNum + 1) / numThreads;
|
||||
uInt32 bufofs = AtariNTSC::outWidth(in_width) * yStart;
|
||||
uInt32* out = static_cast<uInt32*>(rgb_out);
|
||||
atari_in += in_width * yStart;
|
||||
rgb_out = static_cast<char*>(rgb_out) + out_pitch * yStart;
|
||||
|
||||
uInt32 const chunk_count = (in_width - 1) / PIXEL_in_chunk;
|
||||
|
||||
for(uInt32 y = yStart; y < yEnd; ++y)
|
||||
{
|
||||
const uInt8* line_in = atari_in;
|
||||
ATARI_NTSC_BEGIN_ROW(NTSC_black, line_in[0]);
|
||||
uInt32* restrict line_out = static_cast<uInt32*>(rgb_out);
|
||||
++line_in;
|
||||
|
||||
for(uInt32 n = chunk_count; n; --n)
|
||||
{
|
||||
// order of input and output pixels must not be altered
|
||||
ATARI_NTSC_COLOR_IN(0, line_in[0]);
|
||||
ATARI_NTSC_RGB_OUT_8888(0, line_out[0]);
|
||||
ATARI_NTSC_RGB_OUT_8888(1, line_out[1]);
|
||||
ATARI_NTSC_RGB_OUT_8888(2, line_out[2]);
|
||||
ATARI_NTSC_RGB_OUT_8888(3, line_out[3]);
|
||||
|
||||
ATARI_NTSC_COLOR_IN(1, line_in[1]);
|
||||
ATARI_NTSC_RGB_OUT_8888(4, line_out[4]);
|
||||
ATARI_NTSC_RGB_OUT_8888(5, line_out[5]);
|
||||
ATARI_NTSC_RGB_OUT_8888(6, line_out[6]);
|
||||
|
||||
line_in += 2;
|
||||
line_out += 7;
|
||||
}
|
||||
|
||||
// finish final pixels
|
||||
ATARI_NTSC_COLOR_IN(0, line_in[0]);
|
||||
ATARI_NTSC_RGB_OUT_8888(0, line_out[0]);
|
||||
ATARI_NTSC_RGB_OUT_8888(1, line_out[1]);
|
||||
ATARI_NTSC_RGB_OUT_8888(2, line_out[2]);
|
||||
ATARI_NTSC_RGB_OUT_8888(3, line_out[3]);
|
||||
|
||||
ATARI_NTSC_COLOR_IN(1, NTSC_black);
|
||||
ATARI_NTSC_RGB_OUT_8888(4, line_out[4]);
|
||||
ATARI_NTSC_RGB_OUT_8888(5, line_out[5]);
|
||||
ATARI_NTSC_RGB_OUT_8888(6, line_out[6]);
|
||||
|
||||
line_in += 2;
|
||||
line_out += 7;
|
||||
|
||||
ATARI_NTSC_COLOR_IN(0, NTSC_black);
|
||||
ATARI_NTSC_RGB_OUT_8888(0, line_out[0]);
|
||||
ATARI_NTSC_RGB_OUT_8888(1, line_out[1]);
|
||||
ATARI_NTSC_RGB_OUT_8888(2, line_out[2]);
|
||||
ATARI_NTSC_RGB_OUT_8888(3, line_out[3]);
|
||||
|
||||
ATARI_NTSC_COLOR_IN(1, NTSC_black);
|
||||
ATARI_NTSC_RGB_OUT_8888(4, line_out[4]);
|
||||
#if 0
|
||||
ATARI_NTSC_RGB_OUT_8888(5, line_out[5]);
|
||||
ATARI_NTSC_RGB_OUT_8888(6, line_out[6]);
|
||||
#endif
|
||||
|
||||
// Do phosphor mode (blend the resulting frames)
|
||||
// Note: The code assumes that AtariNTSC::outWidth(kTIAW) == outPitch == 565
|
||||
for (uInt32 x = AtariNTSC::outWidth(in_width) / 8; x; --x)
|
||||
{
|
||||
// Store back into displayed frame buffer (for next frame)
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
}
|
||||
// finish final pixels
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
#if 0
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
#endif
|
||||
|
||||
atari_in += in_width;
|
||||
rgb_out = static_cast<char*>(rgb_out) + out_pitch;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
inline uInt32 AtariNTSC::getRGBPhosphor(const uInt32 c, const uInt32 p) const
|
||||
{
|
||||
#define TO_RGB(color, red, green, blue) \
|
||||
const uInt8 red = color >> 16; const uInt8 green = color >> 8; const uInt8 blue = color;
|
||||
|
||||
TO_RGB(c, rc, gc, bc);
|
||||
TO_RGB(p, rp, gp, bp);
|
||||
|
||||
// Mix current calculated frame with previous displayed frame
|
||||
const uInt8 rn = myPhosphorPalette[rc][rp];
|
||||
const uInt8 gn = myPhosphorPalette[gc][gp];
|
||||
const uInt8 bn = myPhosphorPalette[bc][bp];
|
||||
|
||||
return (rn << 16) | (gn << 8) | bn;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void AtariNTSC::init(init_t& impl, const Setup& setup)
|
||||
{
|
||||
|
@ -51,6 +51,9 @@ class AtariNTSC
|
||||
entry_size = 2 * 14,
|
||||
};
|
||||
|
||||
// By default, threading is turned off
|
||||
AtariNTSC() { enableThreading(false); }
|
||||
|
||||
// Image parameters, ranging from -1.0 to 1.0. Actual internal values shown
|
||||
// in parenthesis and should remain fairly stable in future versions.
|
||||
struct Setup
|
||||
@ -80,27 +83,52 @@ class AtariNTSC
|
||||
void initialize(const Setup& setup, const uInt8* palette);
|
||||
void initializePalette(const uInt8* palette);
|
||||
|
||||
// Set up threading
|
||||
void enableThreading(bool enable);
|
||||
|
||||
// Set phosphor palette, for use in Blargg + phosphor mode
|
||||
void setPhosphorPalette(uInt8 palette[256][256]) {
|
||||
memcpy(myPhosphorPalette, palette, 256 * 256);
|
||||
}
|
||||
|
||||
// Filters one or more rows of pixels. Input pixels are 8-bit Atari
|
||||
// palette colors.
|
||||
// In_row_width is the number of pixels to get to the next input row.
|
||||
// Out_pitch is the number of *bytes* to get to the next output row.
|
||||
void render(const uInt8* atari_in, uInt32 in_width, uInt32 in_height,
|
||||
void* rgb_out, uInt32 out_pitch);
|
||||
void render(const uInt8* atari_in, const uInt32 in_width, const uInt32 in_height,
|
||||
void* rgb_out, const uInt32 out_pitch, uInt32* rgb_in = nullptr);
|
||||
|
||||
// Number of input pixels that will fit within given output width.
|
||||
// Might be rounded down slightly; use outWidth() on result to find
|
||||
// rounded value.
|
||||
static constexpr uInt32 inWidth( uInt32 out_width ) {
|
||||
return (((out_width) / PIXEL_out_chunk - 1) * PIXEL_in_chunk + 1);
|
||||
return (((out_width-5) / PIXEL_out_chunk - 1) * PIXEL_in_chunk + 1);
|
||||
}
|
||||
|
||||
// Number of output pixels written by blitter for given input width.
|
||||
// Width might be rounded down slightly; use inWidth() on result to
|
||||
// find rounded value. Guaranteed not to round 160 down at all.
|
||||
static constexpr uInt32 outWidth(uInt32 in_width) {
|
||||
return ((((in_width) - 1) / PIXEL_in_chunk + 1)* PIXEL_out_chunk);
|
||||
return ((((in_width) - 1) / PIXEL_in_chunk + 1)* PIXEL_out_chunk) + 5;
|
||||
}
|
||||
|
||||
private:
|
||||
// Threaded rendering
|
||||
void renderThread(const uInt8* atari_in, const uInt32 in_width,
|
||||
const uInt32 in_height, const uInt32 numThreads, const uInt32 threadNum, void* rgb_out, const uInt32 out_pitch);
|
||||
void renderWithPhosphorThread(const uInt8* atari_in, const uInt32 in_width,
|
||||
const uInt32 in_height, const uInt32 numThreads, const uInt32 threadNum, uInt32* rgb_in, void* rgb_out, const uInt32 out_pitch);
|
||||
|
||||
/**
|
||||
Used to calculate an averaged color for the 'phosphor' effect.
|
||||
|
||||
@param c RGB Color 1 (current frame)
|
||||
@param p RGB Color 2 (previous frame)
|
||||
|
||||
@return Averaged value of the two RGB colors
|
||||
*/
|
||||
uInt32 getRGBPhosphor(const uInt32 c, const uInt32 cp) const;
|
||||
|
||||
private:
|
||||
enum {
|
||||
PIXEL_in_chunk = 2, // number of input pixels read per chunk
|
||||
@ -138,6 +166,12 @@ class AtariNTSC
|
||||
#define LUMA_CUTOFF 0.20
|
||||
|
||||
uInt32 myColorTable[palette_size][entry_size];
|
||||
uInt8 myPhosphorPalette[256][256];
|
||||
|
||||
// Rendering threads
|
||||
unique_ptr<std::thread[]> myThreads;
|
||||
// Number of rendering and total threads
|
||||
uInt32 myWorkerThreads, myTotalThreads;
|
||||
|
||||
struct init_t
|
||||
{
|
||||
|
@ -72,6 +72,10 @@ class NTSCFilter
|
||||
myNTSC.initializePalette(myTIAPalette);
|
||||
}
|
||||
|
||||
inline void setPhosphorPalette(uInt8 palette[256][256]) {
|
||||
myNTSC.setPhosphorPalette(palette);
|
||||
}
|
||||
|
||||
// The following are meant to be used strictly for toggling from the GUI
|
||||
string setPreset(Preset preset);
|
||||
|
||||
@ -110,6 +114,17 @@ class NTSCFilter
|
||||
{
|
||||
myNTSC.render(src_buf, src_width, src_height, dest_buf, dest_pitch);
|
||||
}
|
||||
inline void render(uInt8* src_buf, uInt32 src_width, uInt32 src_height,
|
||||
uInt32* dest_buf, uInt32 dest_pitch, uInt32* prev_buf)
|
||||
{
|
||||
myNTSC.render(src_buf, src_width, src_height, dest_buf, dest_pitch, prev_buf);
|
||||
}
|
||||
|
||||
// Enable threading for the NTSC rendering
|
||||
inline void enableThreading(bool enable)
|
||||
{
|
||||
myNTSC.enableThreading(enable);
|
||||
}
|
||||
|
||||
private:
|
||||
// Convert from atari_ntsc_setup_t values to equivalent adjustables
|
||||
|
@ -70,11 +70,11 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem)
|
||||
// Banksizes greater than 4096 indicate multi-bank ROMs, but we handle only
|
||||
// 4K pieces at a time
|
||||
// Banksizes less than 4K use the actual value
|
||||
int banksize = 0;
|
||||
uInt32 banksize = 0;
|
||||
myConsole.cartridge().getImage(banksize);
|
||||
|
||||
BankInfo info;
|
||||
info.size = std::min(banksize, 4096);
|
||||
info.size = std::min(banksize, 4096u);
|
||||
for(int i = 0; i < myConsole.cartridge().bankCount(); ++i)
|
||||
myBankInfo.push_back(info);
|
||||
|
||||
@ -82,9 +82,9 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem)
|
||||
myBankInfo.push_back(info);
|
||||
|
||||
// We know the address for the startup bank right now
|
||||
myBankInfo[myConsole.cartridge().startBank()].addressList.push_back(myDebugger.dpeek(0xfffc));
|
||||
addLabel("START", myDebugger.dpeek(0xfffc));
|
||||
|
||||
myBankInfo[myConsole.cartridge().startBank()].addressList.push_front(myDebugger.dpeek(0xfffc));
|
||||
addLabel("Start", myDebugger.dpeek(0xfffc, DATA));
|
||||
|
||||
// Add system equates
|
||||
for(uInt16 addr = 0x00; addr <= 0x0F; ++addr)
|
||||
{
|
||||
@ -114,16 +114,17 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem)
|
||||
myDisassembly.list.reserve(2048);
|
||||
|
||||
// Add settings for Distella
|
||||
DiStella::settings.gfx_format =
|
||||
DiStella::settings.gfxFormat =
|
||||
myOSystem.settings().getInt("dis.gfxformat") == 16 ? Base::F_16 : Base::F_2;
|
||||
DiStella::settings.resolve_code =
|
||||
DiStella::settings.resolveCode =
|
||||
myOSystem.settings().getBool("dis.resolve");
|
||||
DiStella::settings.show_addresses =
|
||||
DiStella::settings.showAddresses =
|
||||
myOSystem.settings().getBool("dis.showaddr");
|
||||
DiStella::settings.aflag = false; // Not currently configurable
|
||||
DiStella::settings.fflag = true; // Not currently configurable
|
||||
DiStella::settings.rflag = myOSystem.settings().getBool("dis.relocate");
|
||||
DiStella::settings.bwidth = 9; // TODO - configure based on window size
|
||||
DiStella::settings.aFlag = false; // Not currently configurable
|
||||
DiStella::settings.fFlag = true; // Not currently configurable
|
||||
DiStella::settings.rFlag = myOSystem.settings().getBool("dis.relocate");
|
||||
DiStella::settings.bFlag = true; // Not currently configurable
|
||||
DiStella::settings.bytesWidth = 8+1; // TODO - configure based on window size
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@ -263,34 +264,28 @@ bool CartDebug::disassemble(bool force)
|
||||
|
||||
// Only add addresses when absolutely necessary, to cut down on the
|
||||
// work that Distella has to do
|
||||
// Distella expects the addresses to be unique and in sorted order
|
||||
if(bankChanged || !pcfound)
|
||||
{
|
||||
AddressList::const_iterator i;
|
||||
for(i = addresses.cbegin(); i != addresses.cend(); ++i)
|
||||
{
|
||||
if(PC < *i)
|
||||
{
|
||||
addresses.insert(i, PC);
|
||||
break;
|
||||
}
|
||||
else if(PC == *i) // already present
|
||||
if (PC == *i) // already present
|
||||
break;
|
||||
}
|
||||
// Otherwise, add the item at the end
|
||||
if(i == addresses.end())
|
||||
addresses.push_back(PC);
|
||||
if (i == addresses.end())
|
||||
addresses.push_back(PC);
|
||||
}
|
||||
|
||||
// Always attempt to resolve code sections unless it's been
|
||||
// specifically disabled
|
||||
bool found = fillDisassemblyList(info, PC);
|
||||
if(!found && DiStella::settings.resolve_code)
|
||||
if(!found && DiStella::settings.resolveCode)
|
||||
{
|
||||
// Temporarily turn off code resolution
|
||||
DiStella::settings.resolve_code = false;
|
||||
DiStella::settings.resolveCode = false;
|
||||
fillDisassemblyList(info, PC);
|
||||
DiStella::settings.resolve_code = true;
|
||||
DiStella::settings.resolveCode = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -690,6 +685,9 @@ string CartDebug::loadListFile()
|
||||
// The default naming/location for list files is the ROM dir based on the
|
||||
// actual ROM filename
|
||||
|
||||
myUserAddresses.clear();
|
||||
myUserLabels.clear();
|
||||
|
||||
if(myListFile == "")
|
||||
{
|
||||
FilesystemNode lst(myOSystem.romFile().getPathWithExt("") + ".lst");
|
||||
@ -704,7 +702,7 @@ string CartDebug::loadListFile()
|
||||
if(!in.is_open())
|
||||
return DebuggerParser::red("list file '" + node.getShortPath() + "' not readable");
|
||||
|
||||
myUserCLabels.clear();
|
||||
//myUserCLabels.clear();
|
||||
|
||||
while(!in.eof())
|
||||
{
|
||||
@ -736,7 +734,8 @@ string CartDebug::loadListFile()
|
||||
char eq = '\0';
|
||||
buf >> hex >> xx >> hex >> yy >> line >> eq;
|
||||
if(xx >= 0 && yy >= 0 && eq == '=')
|
||||
myUserCLabels.emplace(xx*256+yy, line);
|
||||
//myUserCLabels.emplace(xx*256+yy, line);
|
||||
addLabel(line, xx * 256 + yy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -765,8 +764,8 @@ string CartDebug::loadSymbolFile()
|
||||
if(!in.is_open())
|
||||
return DebuggerParser::red("symbol file '" + node.getShortPath() + "' not readable");
|
||||
|
||||
myUserAddresses.clear();
|
||||
myUserLabels.clear();
|
||||
//myUserAddresses.clear();
|
||||
//myUserLabels.clear();
|
||||
|
||||
while(!in.eof())
|
||||
{
|
||||
@ -781,8 +780,10 @@ string CartDebug::loadSymbolFile()
|
||||
{
|
||||
// Make sure the value doesn't represent a constant
|
||||
// For now, we simply ignore constants completely
|
||||
const auto& iter = myUserCLabels.find(value);
|
||||
if(iter == myUserCLabels.end() || !BSPF::equalsIgnoreCase(label, iter->second))
|
||||
//const auto& iter = myUserCLabels.find(value);
|
||||
//if(iter == myUserCLabels.end() || !BSPF::equalsIgnoreCase(label, iter->second))
|
||||
const auto& iter = myUserLabels.find(value);
|
||||
if (iter == myUserLabels.end() || !BSPF::equalsIgnoreCase(label, iter->second))
|
||||
{
|
||||
// Check for period, and strip leading number
|
||||
if(string::size_type pos = label.find_first_of(".", 0) != string::npos)
|
||||
@ -955,20 +956,12 @@ string CartDebug::saveDisassembly()
|
||||
if(myConsole.cartridge().bankCount() > 1)
|
||||
return DebuggerParser::red("disassembly for multi-bank ROM not yet supported");
|
||||
|
||||
// Currently, the default naming/location for disassembly files is:
|
||||
// 1) ROM dir based on properties entry name
|
||||
|
||||
if(myDisasmFile == "")
|
||||
{
|
||||
const string& propsname =
|
||||
myConsole.properties().get(Cartridge_Name) + ".asm";
|
||||
|
||||
FilesystemNode case0(myOSystem.romFile().getParent().getPath() + propsname);
|
||||
if(case0.getParent().isWritable())
|
||||
myDisasmFile = case0.getPath();
|
||||
else
|
||||
return DebuggerParser::red("disassembly file not writable:\n " +
|
||||
case0.getShortPath());
|
||||
myDisasmFile = FilesystemNode(myOSystem.defaultSaveDir() + propsname).getPath();
|
||||
}
|
||||
|
||||
FilesystemNode node(myDisasmFile);
|
||||
@ -981,20 +974,23 @@ string CartDebug::saveDisassembly()
|
||||
// We can't print the header to the disassembly until it's actually
|
||||
// been processed; therefore buffer output to a string first
|
||||
ostringstream buf;
|
||||
buf << "\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;\n"
|
||||
<< "; MAIN PROGRAM\n"
|
||||
<< ";\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n";
|
||||
buf << "\n\n;***********************************************************\n"
|
||||
<< "; Bank " << myConsole.cartridge().getBank();
|
||||
if (myConsole.cartridge().bankCount() > 1)
|
||||
buf << " / 0.." << myConsole.cartridge().bankCount() - 1;
|
||||
buf << "\n;***********************************************************\n\n";
|
||||
|
||||
// Use specific settings for disassembly output
|
||||
// This will most likely differ from what you see in the debugger
|
||||
DiStella::Settings settings;
|
||||
settings.gfx_format = DiStella::settings.gfx_format;
|
||||
settings.resolve_code = true;
|
||||
settings.show_addresses = false;
|
||||
settings.aflag = false; // Otherwise DASM gets confused
|
||||
settings.fflag = DiStella::settings.fflag;
|
||||
settings.rflag = DiStella::settings.rflag;
|
||||
settings.bwidth = 17; // default from Distella
|
||||
settings.gfxFormat = DiStella::settings.gfxFormat;
|
||||
settings.resolveCode = true;
|
||||
settings.showAddresses = false;
|
||||
settings.aFlag = false; // Otherwise DASM gets confused
|
||||
settings.fFlag = DiStella::settings.fFlag;
|
||||
settings.rFlag = DiStella::settings.rFlag;
|
||||
settings.bytesWidth = 8+1; // same as Stella debugger
|
||||
settings.bFlag = DiStella::settings.bFlag;; // process break routine (TODO)
|
||||
|
||||
Disassembly disasm;
|
||||
disasm.list.reserve(2048);
|
||||
@ -1009,9 +1005,12 @@ string CartDebug::saveDisassembly()
|
||||
disasm.list.clear();
|
||||
DiStella distella(*this, disasm.list, info, settings,
|
||||
myDisLabels, myDisDirectives, myReserved);
|
||||
|
||||
if (myReserved.breakFound)
|
||||
addLabel("Break", myDebugger.dpeek(0xfffe));
|
||||
|
||||
buf << " SEG CODE\n"
|
||||
<< " ORG $" << Base::HEX4 << info.offset << "\n\n";
|
||||
buf << " SEG CODE\n"
|
||||
<< " ORG $" << Base::HEX4 << info.offset << "\n\n";
|
||||
|
||||
// Format in 'distella' style
|
||||
for(uInt32 i = 0; i < disasm.list.size(); ++i)
|
||||
@ -1020,55 +1019,53 @@ string CartDebug::saveDisassembly()
|
||||
|
||||
// Add label (if any)
|
||||
if(tag.label != "")
|
||||
buf << ALIGN(7) << (tag.label+":") << endl;
|
||||
buf << " ";
|
||||
buf << ALIGN(4) << (tag.label) << "\n";
|
||||
buf << " ";
|
||||
|
||||
switch(tag.type)
|
||||
{
|
||||
case CartDebug::CODE:
|
||||
{
|
||||
buf << ALIGN(25) << tag.disasm << tag.ccount << "\n";
|
||||
break;
|
||||
}
|
||||
case CartDebug::NONE:
|
||||
{
|
||||
buf << "\n";
|
||||
buf << ALIGN(32) << tag.disasm << tag.ccount.substr(0, 5) << tag.ctotal << tag.ccount.substr(5, 2);
|
||||
if (tag.disasm.find("WSYNC") != std::string::npos)
|
||||
buf << "\n;---------------------------------------";
|
||||
break;
|
||||
}
|
||||
case CartDebug::ROW:
|
||||
{
|
||||
buf << tag.disasm << "\n";
|
||||
buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 8*4-1) << "; $" << Base::HEX4 << tag.address << " (*)";
|
||||
break;
|
||||
}
|
||||
case CartDebug::GFX:
|
||||
{
|
||||
buf << ".byte " << (settings.gfx_format == Base::F_2 ? "%" : "$")
|
||||
buf << ".byte " << (settings.gfxFormat == Base::F_2 ? "%" : "$")
|
||||
<< tag.bytes << " ; |";
|
||||
for(int c = 12; c < 20; ++c)
|
||||
buf << ((tag.disasm[c] == '\x1e') ? "#" : " ");
|
||||
buf << "| $" << Base::HEX4 << tag.address << " (G)\n";
|
||||
buf << ALIGN(13) << "|" << "$" << Base::HEX4 << tag.address << " (G)";
|
||||
break;
|
||||
}
|
||||
case CartDebug::PGFX:
|
||||
{
|
||||
buf << ".byte " << (settings.gfx_format == Base::F_2 ? "%" : "$")
|
||||
buf << ".byte " << (settings.gfxFormat == Base::F_2 ? "%" : "$")
|
||||
<< tag.bytes << " ; |";
|
||||
for(int c = 12; c < 20; ++c)
|
||||
buf << ((tag.disasm[c] == '\x1f') ? "*" : " ");
|
||||
buf << "| $" << Base::HEX4 << tag.address << " (P)\n";
|
||||
buf << ALIGN(13) << "|" << "$" << Base::HEX4 << tag.address << " (P)";
|
||||
break;
|
||||
}
|
||||
case CartDebug::DATA:
|
||||
{
|
||||
buf << tag.disasm.substr(0, 9) << " ; $" << Base::HEX4 << tag.address << " (D)\n";
|
||||
{
|
||||
buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 8 * 4 - 1) << "; $" << Base::HEX4 << tag.address << " (D)";
|
||||
break;
|
||||
}
|
||||
case CartDebug::NONE:
|
||||
default:
|
||||
{
|
||||
buf << "\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // switch
|
||||
buf << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
@ -1084,73 +1081,117 @@ string CartDebug::saveDisassembly()
|
||||
<< "; Legend: * = CODE not yet run (tentative code)\n"
|
||||
<< "; D = DATA directive (referenced in some way)\n"
|
||||
<< "; G = GFX directive, shown as '#' (stored in player, missile, ball)\n"
|
||||
<< "; P = PGFX directive, shown as '*' (stored in playfield)\n\n"
|
||||
<< " processor 6502\n\n";
|
||||
<< "; P = PGFX directive, shown as '*' (stored in playfield)\n"
|
||||
<< "; i = indexed accessed only\n"
|
||||
<< "; c = used by code executed in RAM\n"
|
||||
<< "; s = used by stack\n"
|
||||
<< "; ! = page crossed, 1 cycle penalty\n"
|
||||
<< "\n processor 6502\n\n";
|
||||
|
||||
bool addrUsed = false;
|
||||
for(uInt16 addr = 0x00; addr <= 0x0F; ++addr)
|
||||
addrUsed = addrUsed || myReserved.TIARead[addr];
|
||||
addrUsed = addrUsed || myReserved.TIARead[addr] || (mySystem.getAccessFlags(addr) & WRITE);
|
||||
for(uInt16 addr = 0x00; addr <= 0x3F; ++addr)
|
||||
addrUsed = addrUsed || myReserved.TIAWrite[addr];
|
||||
addrUsed = addrUsed || myReserved.TIAWrite[addr] || (mySystem.getAccessFlags(addr) & DATA);
|
||||
for(uInt16 addr = 0x00; addr <= 0x17; ++addr)
|
||||
addrUsed = addrUsed || myReserved.IOReadWrite[addr];
|
||||
if(addrUsed)
|
||||
{
|
||||
out << ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"
|
||||
<< "; TIA AND IO CONSTANTS\n"
|
||||
<< ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n";
|
||||
out << "\n;-----------------------------------------------------------\n"
|
||||
<< "; TIA and IO constants accessed\n"
|
||||
<< ";-----------------------------------------------------------\n\n";
|
||||
|
||||
// TIA read access
|
||||
for(uInt16 addr = 0x00; addr <= 0x0F; ++addr)
|
||||
if(myReserved.TIARead[addr] && ourTIAMnemonicR[addr])
|
||||
out << ALIGN(6) << ourTIAMnemonicR[addr] << " = $"
|
||||
<< Base::HEX2 << right << addr << " ; (R)\n";
|
||||
out << ALIGN(16) << ourTIAMnemonicR[addr] << "= $"
|
||||
<< Base::HEX2 << right << addr << " ; (R)\n";
|
||||
else if (mySystem.getAccessFlags(addr) & DATA)
|
||||
out << ";" << ALIGN(16-1) << ourTIAMnemonicR[addr] << "= $"
|
||||
<< Base::HEX2 << right << addr << " ; (Ri)\n";
|
||||
out << "\n";
|
||||
|
||||
// TIA write access
|
||||
for(uInt16 addr = 0x00; addr <= 0x3F; ++addr)
|
||||
if(myReserved.TIAWrite[addr] && ourTIAMnemonicW[addr])
|
||||
out << ALIGN(6) << ourTIAMnemonicW[addr] << " = $"
|
||||
<< Base::HEX2 << right << addr << " ; (W)\n";
|
||||
out << ALIGN(16) << ourTIAMnemonicW[addr] << "= $"
|
||||
<< Base::HEX2 << right << addr << " ; (W)\n";
|
||||
else if (mySystem.getAccessFlags(addr) & WRITE)
|
||||
out << ";" << ALIGN(16-1) << ourTIAMnemonicW[addr] << "= $"
|
||||
<< Base::HEX2 << right << addr << " ; (Wi)\n";
|
||||
out << "\n";
|
||||
|
||||
// RIOT IO access
|
||||
for(uInt16 addr = 0x00; addr <= 0x17; ++addr)
|
||||
if(myReserved.IOReadWrite[addr] && ourIOMnemonic[addr])
|
||||
out << ALIGN(6) << ourIOMnemonic[addr] << " = $"
|
||||
out << ALIGN(16) << ourIOMnemonic[addr] << "= $"
|
||||
<< Base::HEX4 << right << (addr+0x280) << "\n";
|
||||
}
|
||||
|
||||
addrUsed = false;
|
||||
for(uInt16 addr = 0x80; addr <= 0xFF; ++addr)
|
||||
addrUsed = addrUsed || myReserved.ZPRAM[addr-0x80];
|
||||
for(uInt16 addr = 0x80; addr <= 0xFF; ++addr)
|
||||
addrUsed = addrUsed || myReserved.ZPRAM[addr-0x80]
|
||||
|| (mySystem.getAccessFlags(addr) & (DATA | WRITE))
|
||||
|| (mySystem.getAccessFlags(addr|0x100) & (DATA | WRITE));
|
||||
if(addrUsed)
|
||||
{
|
||||
out << "\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"
|
||||
<< "; RIOT RAM (zero-page)\n"
|
||||
<< ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n";
|
||||
for(uInt16 addr = 0x80; addr <= 0xFF; ++addr)
|
||||
{
|
||||
if(myReserved.ZPRAM[addr-0x80] &&
|
||||
myUserLabels.find(addr) == myUserLabels.end())
|
||||
{
|
||||
out << ALIGN(6) << ourZPMnemonic[addr-0x80] << " = $"
|
||||
<< Base::HEX2 << right << (addr) << "\n";
|
||||
}
|
||||
bool addLine = false;
|
||||
out << "\n\n;-----------------------------------------------------------\n"
|
||||
<< "; RIOT RAM (zero-page) labels\n"
|
||||
<< ";-----------------------------------------------------------\n\n";
|
||||
|
||||
for (uInt16 addr = 0x80; addr <= 0xFF; ++addr) {
|
||||
bool ramUsed = (mySystem.getAccessFlags(addr) & (DATA | WRITE));
|
||||
bool codeUsed = (mySystem.getAccessFlags(addr) & CODE);
|
||||
bool stackUsed = (mySystem.getAccessFlags(addr|0x100) & (DATA | WRITE));
|
||||
|
||||
if (myReserved.ZPRAM[addr - 0x80] &&
|
||||
myUserLabels.find(addr) == myUserLabels.end()) {
|
||||
if (addLine)
|
||||
out << "\n";
|
||||
out << ALIGN(16) << ourZPMnemonic[addr - 0x80] << "= $"
|
||||
<< Base::HEX2 << right << (addr)
|
||||
<< (stackUsed|codeUsed ? "; (" : "")
|
||||
<< (codeUsed ? "c" : "")
|
||||
<< (stackUsed ? "s" : "")
|
||||
<< (stackUsed | codeUsed ? ")" : "")
|
||||
<< "\n";
|
||||
addLine = false;
|
||||
} else if (ramUsed|codeUsed|stackUsed) {
|
||||
if (addLine)
|
||||
out << "\n";
|
||||
out << ALIGN(18) << ";" << "$"
|
||||
<< Base::HEX2 << right << (addr)
|
||||
<< " ("
|
||||
<< (ramUsed ? "i" : "")
|
||||
<< (codeUsed ? "c" : "")
|
||||
<< (stackUsed ? "s" : "")
|
||||
<< ")\n";
|
||||
addLine = false;
|
||||
} else
|
||||
addLine = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(myReserved.Label.size() > 0)
|
||||
{
|
||||
out << "\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"
|
||||
<< "; NON LOCATABLE\n"
|
||||
<< ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n";
|
||||
out << "\n\n;-----------------------------------------------------------\n"
|
||||
<< "; Non Locatable Labels\n"
|
||||
<< ";-----------------------------------------------------------\n\n";
|
||||
for(const auto& iter: myReserved.Label)
|
||||
out << ALIGN(10) << iter.second << " = $" << iter.first << "\n";
|
||||
out << ALIGN(16) << iter.second << "= $" << iter.first << "\n";
|
||||
}
|
||||
|
||||
if(myUserLabels.size() > 0)
|
||||
{
|
||||
out << "\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"
|
||||
<< "; USER DEFINED\n"
|
||||
<< ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n";
|
||||
int max_len = 0;
|
||||
out << "\n\n;-----------------------------------------------------------\n"
|
||||
<< "; User Defined Labels\n"
|
||||
<< ";-----------------------------------------------------------\n\n";
|
||||
int max_len = 16;
|
||||
for(const auto& iter: myUserLabels)
|
||||
max_len = std::max(max_len, int(iter.second.size()));
|
||||
for(const auto& iter: myUserLabels)
|
||||
out << ALIGN(max_len) << iter.second << " = $" << iter.first << "\n";
|
||||
out << ALIGN(max_len) << iter.second << "= $" << iter.first << "\n";
|
||||
}
|
||||
|
||||
// And finally, output the disassembly
|
||||
@ -1162,10 +1203,9 @@ string CartDebug::saveDisassembly()
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string CartDebug::saveRom()
|
||||
{
|
||||
const string& path = string("~") + BSPF::PATH_SEPARATOR +
|
||||
myConsole.properties().get(Cartridge_Name) + ".a26";
|
||||
const string& rom = myConsole.properties().get(Cartridge_Name) + ".a26";
|
||||
|
||||
FilesystemNode node(path);
|
||||
FilesystemNode node(myOSystem.defaultSaveDir() + "ROMs\\" + rom);
|
||||
ofstream out(node.getPath(), std::ios::binary);
|
||||
if(out && myConsole.cartridge().saveROM(out))
|
||||
return "saved ROM as " + node.getShortPath();
|
||||
@ -1404,7 +1444,7 @@ void CartDebug::disasmTypeAsString(ostream& buf, uInt8 flags) const
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const char* const CartDebug::ourTIAMnemonicR[16] = {
|
||||
"CXM0P", "CXM1P", "CXP0FB", "CXP1FB", "CXM0FB", "CXM1FB", "CXBLPF", "CXPPMM",
|
||||
"INPT0", "INPT1", "INPT2", "INPT3", "INPT4", "INPT5", 0, 0
|
||||
"INPT0", "INPT1", "INPT2", "INPT3", "INPT4", "INPT5", "$1e", "$1f"
|
||||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@ -1414,8 +1454,9 @@ const char* const CartDebug::ourTIAMnemonicW[64] = {
|
||||
"RESP0", "RESP1", "RESM0", "RESM1", "RESBL", "AUDC0", "AUDC1", "AUDF0",
|
||||
"AUDF1", "AUDV0", "AUDV1", "GRP0", "GRP1", "ENAM0", "ENAM1", "ENABL",
|
||||
"HMP0", "HMP1", "HMM0", "HMM1", "HMBL", "VDELP0", "VDELP1", "VDELBL",
|
||||
"RESMP0", "RESMP1", "HMOVE", "HMCLR", "CXCLR", 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
"RESMP0", "RESMP1", "HMOVE", "HMCLR", "CXCLR", "$2d", "$2e", "$2f",
|
||||
"$30", "$31", "$32", "$33", "$34", "$35", "$36", "$37",
|
||||
"$38", "$39", "$3a", "$3b", "$3c", "$3d", "$3e", "$3f"
|
||||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -52,9 +52,9 @@ class CartDebug : public DebuggerSystem
|
||||
public:
|
||||
enum DisasmType {
|
||||
NONE = 0,
|
||||
REFERENCED = 1 << 0, /* code somewhere in the program references it,
|
||||
REFERENCED = 1 << 0, /* 0x01, code somewhere in the program references it,
|
||||
i.e. LDA $F372 referenced $F372 */
|
||||
VALID_ENTRY = 1 << 1, /* addresses that can have a label placed in front of it.
|
||||
VALID_ENTRY = 1 << 1, /* 0x02, addresses that can have a label placed in front of it.
|
||||
A good counterexample would be "FF00: LDA $FE00"; $FF01
|
||||
would be in the middle of a multi-byte instruction, and
|
||||
therefore cannot be labelled. */
|
||||
@ -63,12 +63,14 @@ class CartDebug : public DebuggerSystem
|
||||
// debugger, or specified in a Distella cfg file, and are listed in order
|
||||
// of decreasing hierarchy
|
||||
//
|
||||
CODE = 1 << 7, // disassemble-able code segments
|
||||
TCODE = 1 << 6, // (tentative) disassemble-able code segments
|
||||
GFX = 1 << 5, // addresses loaded into GRPx registers
|
||||
PGFX = 1 << 4, // addresses loaded into PFx registers
|
||||
DATA = 1 << 3, // addresses loaded into registers other than GRPx / PFx
|
||||
ROW = 1 << 2 // all other addresses
|
||||
CODE = 1 << 7, // 0x80, disassemble-able code segments
|
||||
TCODE = 1 << 6, // 0x40, (tentative) disassemble-able code segments
|
||||
GFX = 1 << 5, // 0x20, addresses loaded into GRPx registers
|
||||
PGFX = 1 << 4, // 0x10, addresses loaded into PFx registers
|
||||
DATA = 1 << 3, // 0x08, addresses loaded into registers other than GRPx / PFx
|
||||
ROW = 1 << 2, // 0x04, all other addresses
|
||||
// special type for poke()
|
||||
WRITE = TCODE // 0x40, address written to
|
||||
};
|
||||
struct DisassemblyTag {
|
||||
DisasmType type;
|
||||
@ -76,6 +78,7 @@ class CartDebug : public DebuggerSystem
|
||||
string label;
|
||||
string disasm;
|
||||
string ccount;
|
||||
string ctotal;
|
||||
string bytes;
|
||||
bool hllabel;
|
||||
};
|
||||
@ -316,6 +319,7 @@ class CartDebug : public DebuggerSystem
|
||||
bool IOReadWrite[24];
|
||||
bool ZPRAM[128];
|
||||
AddrToLabel Label;
|
||||
bool breakFound;
|
||||
};
|
||||
ReservedEquates myReserved;
|
||||
|
||||
@ -362,7 +366,7 @@ class CartDebug : public DebuggerSystem
|
||||
|
||||
// Mappings from label to address (and vice versa) for constants
|
||||
// defined through a DASM lst file
|
||||
AddrToLabel myUserCLabels;
|
||||
// AddrToLabel myUserCLabels;
|
||||
// LabelToAddr myUserCAddresses;
|
||||
|
||||
// Mappings for labels to addresses for system-defined equates
|
||||
|
@ -96,12 +96,15 @@ static const char* const pseudo_registers[][2] = {
|
||||
// { "name", "help text" }
|
||||
|
||||
{ "_bank", "Currently selected bank" },
|
||||
{ "_cclocks", "Color clocks on current scanline" },
|
||||
{ "_fcount", "Number of frames since emulation started" },
|
||||
{ "_fcycles", "Number of cycles since frame started" },
|
||||
{ "_cyclesLo", "Lower 32 bits of number of cycles since emulation started"},
|
||||
{ "_cyclesHi", "Higher 32 bits of number of cycles since emulation started"},
|
||||
{ "_rwport", "Address at which a read from a write port occurred" },
|
||||
{ "_scan", "Current scanline count" },
|
||||
{ "_fcount", "Number of frames since emulation started" },
|
||||
{ "_cclocks", "Color clocks on current scanline" },
|
||||
{ "_vsync", "Whether vertical sync is enabled (1 or 0)" },
|
||||
{ "_vblank", "Whether vertical blank is enabled (1 or 0)" },
|
||||
{ "_vsync", "Whether vertical sync is enabled (1 or 0)" },
|
||||
|
||||
// empty string marks end of list, do not remove
|
||||
{ 0, 0 }
|
||||
@ -152,7 +155,6 @@ void Debugger::initialize()
|
||||
myDialog = new DebuggerDialog(myOSystem, *this, 0, 0, myWidth, myHeight);
|
||||
myBaseDialog = myDialog;
|
||||
|
||||
myRewindManager = make_unique<RewindManager>(myOSystem, myDialog->rewindButton());
|
||||
myCartDebug->setDebugWidget(&(myDialog->cartDebug()));
|
||||
}
|
||||
|
||||
@ -300,20 +302,19 @@ void Debugger::loadState(int state)
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
int Debugger::step()
|
||||
{
|
||||
saveOldState();
|
||||
saveOldState("1 step");
|
||||
mySystem.clearDirtyPages();
|
||||
|
||||
int cyc = mySystem.cycles();
|
||||
uInt64 startCycle = mySystem.cycles();
|
||||
|
||||
unlockBankswitchState();
|
||||
myOSystem.console().tia().updateScanlineByStep().flushLineCache();
|
||||
lockBankswitchState();
|
||||
|
||||
return mySystem.cycles() - cyc;
|
||||
return int(mySystem.cycles() - startCycle);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
// trace is just like step, except it treats a subroutine call as one
|
||||
// instruction.
|
||||
|
||||
@ -328,17 +329,17 @@ int Debugger::trace()
|
||||
// 32 is the 6502 JSR instruction:
|
||||
if(mySystem.peek(myCpuDebug->pc()) == 32)
|
||||
{
|
||||
saveOldState();
|
||||
saveOldState("1 trace");
|
||||
mySystem.clearDirtyPages();
|
||||
|
||||
int cyc = mySystem.cycles();
|
||||
uInt64 startCycle = mySystem.cycles();
|
||||
int targetPC = myCpuDebug->pc() + 3; // return address
|
||||
|
||||
unlockBankswitchState();
|
||||
myOSystem.console().tia().updateScanlineByTrace(targetPC).flushLineCache();
|
||||
lockBankswitchState();
|
||||
|
||||
return mySystem.cycles() - cyc;
|
||||
return int(mySystem.cycles() - startCycle);
|
||||
}
|
||||
else
|
||||
return step();
|
||||
@ -401,7 +402,12 @@ bool Debugger::writeTrap(uInt16 t)
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::nextScanline(int lines)
|
||||
{
|
||||
saveOldState();
|
||||
ostringstream buf;
|
||||
buf << lines << " scanline";
|
||||
if(lines > 1)
|
||||
buf << "s";
|
||||
|
||||
saveOldState(buf.str());
|
||||
mySystem.clearDirtyPages();
|
||||
|
||||
unlockBankswitchState();
|
||||
@ -418,7 +424,12 @@ void Debugger::nextScanline(int lines)
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::nextFrame(int frames)
|
||||
{
|
||||
saveOldState();
|
||||
ostringstream buf;
|
||||
buf << frames << " frame";
|
||||
if(frames > 1)
|
||||
buf << "s";
|
||||
|
||||
saveOldState(buf.str());
|
||||
mySystem.clearDirtyPages();
|
||||
|
||||
unlockBankswitchState();
|
||||
@ -433,12 +444,16 @@ void Debugger::nextFrame(int frames)
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Debugger::rewindState()
|
||||
{
|
||||
RewindManager& r = myOSystem.state().rewindManager();
|
||||
|
||||
mySystem.clearDirtyPages();
|
||||
|
||||
unlockBankswitchState();
|
||||
bool result = myRewindManager->rewindState();
|
||||
bool result = r.rewindState();
|
||||
lockBankswitchState();
|
||||
|
||||
myDialog->rewindButton().setEnabled(!r.empty());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -468,7 +483,7 @@ bool Debugger::patchROM(uInt16 addr, uInt8 value)
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::saveOldState(bool addrewind)
|
||||
void Debugger::saveOldState(string rewindMsg)
|
||||
{
|
||||
myCartDebug->saveOldState();
|
||||
myCpuDebug->saveOldState();
|
||||
@ -476,7 +491,12 @@ void Debugger::saveOldState(bool addrewind)
|
||||
myTiaDebug->saveOldState();
|
||||
|
||||
// Add another rewind level to the Undo list
|
||||
if(addrewind) myRewindManager->addState();
|
||||
if(rewindMsg != "")
|
||||
{
|
||||
RewindManager& r = myOSystem.state().rewindManager();
|
||||
r.addState(rewindMsg);
|
||||
myDialog->rewindButton().setEnabled(!r.empty());
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@ -485,11 +505,14 @@ void Debugger::setStartState()
|
||||
// Lock the bus each time the debugger is entered, so we don't disturb anything
|
||||
lockBankswitchState();
|
||||
|
||||
// Start a new rewind list
|
||||
myRewindManager->clear();
|
||||
// If rewinding is not enabled, always start the debugger with a clean list
|
||||
RewindManager& r = myOSystem.state().rewindManager();
|
||||
if(myOSystem.state().mode() == StateManager::Mode::Off)
|
||||
r.clear();
|
||||
myDialog->rewindButton().setEnabled(!r.empty());
|
||||
|
||||
// Save initial state, but don't add it to the rewind list
|
||||
saveOldState(false);
|
||||
saveOldState();
|
||||
|
||||
// Set the 're-disassemble' flag, but don't do it until the next scheduled time
|
||||
myDialog->rom().invalidate(false);
|
||||
@ -634,90 +657,3 @@ void Debugger::unlockBankswitchState()
|
||||
mySystem.unlockDataBus();
|
||||
myConsole.cartridge().unlockBank();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Debugger::RewindManager::RewindManager(OSystem& system, ButtonWidget& button)
|
||||
: myOSystem(system),
|
||||
myRewindButton(button),
|
||||
mySize(0),
|
||||
myTop(0)
|
||||
{
|
||||
for(int i = 0; i < MAX_SIZE; ++i)
|
||||
myStateList[i] = nullptr;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Debugger::RewindManager::~RewindManager()
|
||||
{
|
||||
for(int i = 0; i < MAX_SIZE; ++i)
|
||||
delete myStateList[i];
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Debugger::RewindManager::addState()
|
||||
{
|
||||
// Create a new Serializer object if we need one
|
||||
if(myStateList[myTop] == nullptr)
|
||||
myStateList[myTop] = new Serializer();
|
||||
Serializer& s = *(myStateList[myTop]);
|
||||
|
||||
if(s)
|
||||
{
|
||||
s.reset();
|
||||
if(myOSystem.state().saveState(s) && myOSystem.console().tia().saveDisplay(s))
|
||||
{
|
||||
// Are we still within the allowable size, or are we overwriting an item?
|
||||
mySize++; if(mySize > MAX_SIZE) mySize = MAX_SIZE;
|
||||
|
||||
myTop = (myTop + 1) % MAX_SIZE;
|
||||
myRewindButton.setEnabled(true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Debugger::RewindManager::rewindState()
|
||||
{
|
||||
if(mySize > 0)
|
||||
{
|
||||
mySize--;
|
||||
myTop = myTop == 0 ? MAX_SIZE - 1 : myTop - 1;
|
||||
Serializer& s = *(myStateList[myTop]);
|
||||
|
||||
s.reset();
|
||||
myOSystem.state().loadState(s);
|
||||
myOSystem.console().tia().loadDisplay(s);
|
||||
|
||||
if(mySize == 0)
|
||||
myRewindButton.setEnabled(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Debugger::RewindManager::empty()
|
||||
{
|
||||
return mySize == 0;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::RewindManager::clear()
|
||||
{
|
||||
for(int i = 0; i < MAX_SIZE; ++i)
|
||||
if(myStateList[i] != nullptr)
|
||||
myStateList[i]->reset();
|
||||
|
||||
myTop = mySize = 0;
|
||||
|
||||
// We use Widget::clearFlags here instead of Widget::setEnabled(),
|
||||
// since the latter implies an immediate draw/update, but this method
|
||||
// might be called before any UI exists
|
||||
// TODO - fix this deficiency in the UI core; we shouldn't have to worry
|
||||
// about such things at this level
|
||||
myRewindButton.clearFlags(WIDGET_ENABLED);
|
||||
}
|
||||
|
@ -26,7 +26,6 @@ class TiaZoomWidget;
|
||||
class EditTextWidget;
|
||||
class RomWidget;
|
||||
class Expression;
|
||||
class Serializer;
|
||||
class PackedBitArray;
|
||||
class PromptWidget;
|
||||
class ButtonWidget;
|
||||
@ -154,11 +153,6 @@ class Debugger : public DialogContainer
|
||||
*/
|
||||
const string run(const string& command);
|
||||
|
||||
/**
|
||||
The current cycle count of the System.
|
||||
*/
|
||||
int cycles() const { return int(mySystem.cycles()); }
|
||||
|
||||
string autoExec();
|
||||
|
||||
string showWatches();
|
||||
@ -212,8 +206,8 @@ class Debugger : public DialogContainer
|
||||
static Debugger& debugger() { return *myStaticDebugger; }
|
||||
|
||||
/* These are now exposed so Expressions can use them. */
|
||||
int peek(int addr) { return mySystem.peek(addr); }
|
||||
int dpeek(int addr) { return mySystem.peek(addr) | (mySystem.peek(addr+1) << 8); }
|
||||
int peek(int addr, uInt8 flags = 0) { return mySystem.peek(addr, flags); }
|
||||
int dpeek(int addr, uInt8 flags = 0) { return mySystem.peek(addr, flags) | (mySystem.peek(addr+1, flags) << 8); }
|
||||
int getAccessFlags(uInt16 addr) const
|
||||
{ return mySystem.getAccessFlags(addr); }
|
||||
void setAccessFlags(uInt16 addr, uInt8 flags)
|
||||
@ -237,8 +231,11 @@ class Debugger : public DialogContainer
|
||||
private:
|
||||
/**
|
||||
Save state of each debugger subsystem.
|
||||
|
||||
If a message is provided, we assume that a rewind state should
|
||||
be saved with the given message.
|
||||
*/
|
||||
void saveOldState(bool addrewind = true);
|
||||
void saveOldState(string rewindMsg = "");
|
||||
|
||||
/**
|
||||
Set initial state before entering the debugger.
|
||||
@ -295,38 +292,6 @@ class Debugger : public DialogContainer
|
||||
uInt32 myWidth;
|
||||
uInt32 myHeight;
|
||||
|
||||
// Class holding all rewind state functionality in the debugger
|
||||
// Essentially, it's a modified circular array-based stack
|
||||
// that cleverly deals with allocation/deallocation of memory
|
||||
class RewindManager
|
||||
{
|
||||
public:
|
||||
RewindManager(OSystem& system, ButtonWidget& button);
|
||||
virtual ~RewindManager();
|
||||
|
||||
public:
|
||||
bool addState();
|
||||
bool rewindState();
|
||||
bool empty();
|
||||
void clear();
|
||||
|
||||
private:
|
||||
enum { MAX_SIZE = 100 };
|
||||
OSystem& myOSystem;
|
||||
ButtonWidget& myRewindButton;
|
||||
Serializer* myStateList[MAX_SIZE];
|
||||
uInt32 mySize, myTop;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
RewindManager() = delete;
|
||||
RewindManager(const RewindManager&) = delete;
|
||||
RewindManager(RewindManager&&) = delete;
|
||||
RewindManager& operator=(const RewindManager&) = delete;
|
||||
RewindManager& operator=(RewindManager&&) = delete;
|
||||
};
|
||||
unique_ptr<RewindManager> myRewindManager;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
Debugger() = delete;
|
||||
|
@ -284,16 +284,16 @@ int DebuggerParser::decipher_arg(const string& str)
|
||||
string DebuggerParser::showWatches()
|
||||
{
|
||||
ostringstream buf;
|
||||
for(uInt32 i = 0; i < watches.size(); i++)
|
||||
for(uInt32 i = 0; i < myWatches.size(); ++i)
|
||||
{
|
||||
if(watches[i] != "")
|
||||
if(myWatches[i] != "")
|
||||
{
|
||||
// Clear the args, since we're going to pass them to eval()
|
||||
argStrings.clear();
|
||||
args.clear();
|
||||
|
||||
argCount = 1;
|
||||
argStrings.push_back(watches[i]);
|
||||
argStrings.push_back(myWatches[i]);
|
||||
args.push_back(decipher_arg(argStrings[0]));
|
||||
if(args[0] < 0)
|
||||
buf << "BAD WATCH " << (i+1) << ": " << argStrings[0] << endl;
|
||||
@ -534,13 +534,14 @@ string DebuggerParser::eval()
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string DebuggerParser::trapStatus(int addr)
|
||||
string DebuggerParser::trapStatus(uInt32 addr, bool& enabled)
|
||||
{
|
||||
string result;
|
||||
result += Base::toString(addr);
|
||||
result += ": ";
|
||||
bool r = debugger.readTrap(addr);
|
||||
bool w = debugger.writeTrap(addr);
|
||||
enabled = r || w;
|
||||
if(r && w)
|
||||
result += "read|write";
|
||||
else if(r)
|
||||
@ -550,8 +551,7 @@ string DebuggerParser::trapStatus(int addr)
|
||||
else
|
||||
result += "none";
|
||||
|
||||
// TODO - technically, we should determine if the label is read or write
|
||||
const string& l = debugger.cartDebug().getLabel(addr, true);
|
||||
const string& l = debugger.cartDebug().getLabel(addr, !w);
|
||||
if(l != "") {
|
||||
result += " (";
|
||||
result += l;
|
||||
@ -570,11 +570,11 @@ bool DebuggerParser::saveScriptFile(string file)
|
||||
ofstream out(file);
|
||||
|
||||
FunctionDefMap funcs = debugger.getFunctionDefMap();
|
||||
for(const auto& i: funcs)
|
||||
out << "function " << i.first << " { " << i.second << " }" << endl;
|
||||
for(const auto& f: funcs)
|
||||
out << "function " << f.first << " { " << f.second << " }" << endl;
|
||||
|
||||
for(const auto& i: watches)
|
||||
out << "watch " << i << endl;
|
||||
for(const auto& w: myWatches)
|
||||
out << "watch " << w << endl;
|
||||
|
||||
for(uInt32 i = 0; i < 0x10000; ++i)
|
||||
if(debugger.breakPoint(i))
|
||||
@ -735,6 +735,7 @@ void DebuggerParser::executeClearconfig()
|
||||
// "cleartraps"
|
||||
void DebuggerParser::executeCleartraps()
|
||||
{
|
||||
myTraps.clear();
|
||||
debugger.clearAllTraps();
|
||||
commandResult << "all traps cleared";
|
||||
}
|
||||
@ -743,7 +744,7 @@ void DebuggerParser::executeCleartraps()
|
||||
// "clearwatches"
|
||||
void DebuggerParser::executeClearwatches()
|
||||
{
|
||||
watches.clear();
|
||||
myWatches.clear();
|
||||
commandResult << "all watches cleared";
|
||||
}
|
||||
|
||||
@ -856,9 +857,9 @@ void DebuggerParser::executeDelfunction()
|
||||
void DebuggerParser::executeDelwatch()
|
||||
{
|
||||
int which = args[0] - 1;
|
||||
if(which >= 0 && which < int(watches.size()))
|
||||
if(which >= 0 && which < int(myWatches.size()))
|
||||
{
|
||||
Vec::removeAt(watches, which);
|
||||
Vec::removeAt(myWatches, which);
|
||||
commandResult << "removed watch";
|
||||
}
|
||||
else
|
||||
@ -890,16 +891,37 @@ void DebuggerParser::executeDisasm()
|
||||
// "dump"
|
||||
void DebuggerParser::executeDump()
|
||||
{
|
||||
for(int i = 0; i < 8; ++i)
|
||||
auto dump = [&](int start, int end)
|
||||
{
|
||||
int start = args[0] + i*16;
|
||||
commandResult << Base::toString(start) << ": ";
|
||||
for(int j = 0; j < 16; ++j)
|
||||
for(int i = start; i <= end; i += 16)
|
||||
{
|
||||
commandResult << Base::toString(debugger.peek(start+j)) << " ";
|
||||
if(j == 7) commandResult << "- ";
|
||||
// Print label every 16 bytes
|
||||
commandResult << Base::toString(i) << ": ";
|
||||
|
||||
for(int j = i; j < i+16 && j <= end; ++j)
|
||||
{
|
||||
commandResult << Base::toString(debugger.peek(j)) << " ";
|
||||
if(j == i+7 && j != end) commandResult << "- ";
|
||||
}
|
||||
commandResult << endl;
|
||||
}
|
||||
if(i != 7) commandResult << endl;
|
||||
};
|
||||
|
||||
// Error checking
|
||||
if(argCount > 1 && args[1] < args[0])
|
||||
{
|
||||
commandResult << red("Start address must be <= end address");
|
||||
return;
|
||||
}
|
||||
|
||||
if(argCount == 1)
|
||||
dump(args[0], args[0] + 127);
|
||||
else if(argCount == 2)
|
||||
dump(args[0], args[1]);
|
||||
else
|
||||
{
|
||||
commandResult << "wrong number of arguments";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1096,19 +1118,13 @@ void DebuggerParser::executeListfunctions()
|
||||
// "listtraps"
|
||||
void DebuggerParser::executeListtraps()
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for(uInt32 i = 0; i <= 0xffff; ++i)
|
||||
if(myTraps.size() > 0)
|
||||
{
|
||||
if(debugger.readTrap(i) || debugger.writeTrap(i))
|
||||
{
|
||||
commandResult << trapStatus(i) << " + mirrors" << endl;
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
bool enabled = true;
|
||||
for(const auto& trap: myTraps)
|
||||
commandResult << trapStatus(trap, enabled) << " + mirrors" << endl;
|
||||
}
|
||||
|
||||
if(!count)
|
||||
else
|
||||
commandResult << "no traps set";
|
||||
}
|
||||
|
||||
@ -1388,10 +1404,20 @@ void DebuggerParser::executeSaverom()
|
||||
// "saveses"
|
||||
void DebuggerParser::executeSaveses()
|
||||
{
|
||||
if(debugger.prompt().saveBuffer(argStrings[0]))
|
||||
commandResult << "saved session to file " << argStrings[0];
|
||||
// Create a file named with the current date and time
|
||||
time_t currtime;
|
||||
struct tm* timeinfo;
|
||||
char buffer[80];
|
||||
|
||||
time(&currtime);
|
||||
timeinfo = localtime(&currtime);
|
||||
strftime(buffer, 80, "session_%F_%H-%M-%S.txt", timeinfo);
|
||||
|
||||
FilesystemNode file(debugger.myOSystem.defaultSaveDir() + buffer);
|
||||
if(debugger.prompt().saveBuffer(file))
|
||||
commandResult << "saved " + file.getShortPath() + " OK";
|
||||
else
|
||||
commandResult << red("I/O error");
|
||||
commandResult << "Unable to save session";
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@ -1570,7 +1596,12 @@ void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write)
|
||||
}
|
||||
}
|
||||
|
||||
commandResult << trapStatus(addr) << " + mirrors" << endl;
|
||||
bool trapEnabled = false;
|
||||
const string& result = trapStatus(addr, trapEnabled);
|
||||
if(trapEnabled) myTraps.insert(addr);
|
||||
else myTraps.erase(addr);
|
||||
|
||||
commandResult << result << " + mirrors" << endl;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@ -1629,7 +1660,7 @@ void DebuggerParser::executeV()
|
||||
// "watch"
|
||||
void DebuggerParser::executeWatch()
|
||||
{
|
||||
watches.push_back(argStrings[0]);
|
||||
myWatches.push_back(argStrings[0]);
|
||||
commandResult << "added watch \"" << argStrings[0] << "\"";
|
||||
}
|
||||
|
||||
@ -1875,11 +1906,13 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||
|
||||
{
|
||||
"dump",
|
||||
"Dump 128 bytes of memory at address <xx>",
|
||||
"Example: dump f000",
|
||||
"Dump data at address <xx> [to yy]",
|
||||
"Examples:\n"
|
||||
" dump f000 - dumps 128 bytes @ f000\n"
|
||||
" dump f000 f0ff - dumps all bytes from f000 to f0ff",
|
||||
true,
|
||||
false,
|
||||
{ kARG_WORD, kARG_END_ARGS },
|
||||
{ kARG_WORD, kARG_MULTI_BYTE },
|
||||
std::mem_fn(&DebuggerParser::executeDump)
|
||||
},
|
||||
|
||||
@ -2179,8 +2212,8 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||
|
||||
{
|
||||
"saveconfig",
|
||||
"Save Distella config file",
|
||||
"Example: saveconfig file.cfg",
|
||||
"Save Distella config file (with default name)",
|
||||
"Example: saveconfig",
|
||||
false,
|
||||
false,
|
||||
{ kARG_END_ARGS },
|
||||
@ -2189,8 +2222,9 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||
|
||||
{
|
||||
"savedis",
|
||||
"Save Distella disassembly",
|
||||
"Example: savedis file.asm",
|
||||
"Save Distella disassembly (with default name)",
|
||||
"Example: savedis\n"
|
||||
"NOTE: saves to default save location",
|
||||
false,
|
||||
false,
|
||||
{ kARG_END_ARGS },
|
||||
@ -2199,8 +2233,9 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||
|
||||
{
|
||||
"saverom",
|
||||
"Save (possibly patched) ROM",
|
||||
"Example: savedrom file.bin",
|
||||
"Save (possibly patched) ROM (with default name)",
|
||||
"Example: saverom\n"
|
||||
"NOTE: saves to default save location",
|
||||
false,
|
||||
false,
|
||||
{ kARG_END_ARGS },
|
||||
@ -2209,11 +2244,12 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||
|
||||
{
|
||||
"saveses",
|
||||
"Save console session to file xx",
|
||||
"Example: saveses session.txt",
|
||||
true,
|
||||
"Save console session",
|
||||
"Example: saveses\n"
|
||||
"NOTE: saves to default save location",
|
||||
false,
|
||||
{ kARG_FILE, kARG_END_ARGS },
|
||||
false,
|
||||
{ kARG_END_ARGS },
|
||||
std::mem_fn(&DebuggerParser::executeSaveses)
|
||||
},
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include <functional>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
|
||||
class Debugger;
|
||||
class FilesystemNode;
|
||||
@ -64,7 +65,6 @@ class DebuggerParser
|
||||
bool getArgs(const string& command, string& verb);
|
||||
bool validateArgs(int cmd);
|
||||
string eval();
|
||||
string trapStatus(int addr);
|
||||
bool saveScriptFile(string file);
|
||||
|
||||
private:
|
||||
@ -114,7 +114,11 @@ class DebuggerParser
|
||||
StringList argStrings;
|
||||
uInt32 argCount;
|
||||
|
||||
StringList watches;
|
||||
StringList myWatches;
|
||||
|
||||
// Keep track of traps (read and/or write)
|
||||
std::set<uInt32> myTraps;
|
||||
string trapStatus(uInt32 addr, bool& enabled);
|
||||
|
||||
// List of available command methods
|
||||
void executeA();
|
||||
|
@ -33,7 +33,8 @@
|
||||
All 7800-related stuff has been removed, as well as some commandline options.
|
||||
Over time, some of the configurability of Distella may be added again.
|
||||
|
||||
@author Stephen Anthony
|
||||
@authors Stephen Anthony and Thomas Jentzsch
|
||||
Original distella developers (http://distella.sf.net)
|
||||
*/
|
||||
class DiStella
|
||||
{
|
||||
@ -41,14 +42,15 @@ class DiStella
|
||||
// A list of options that can be applied to the disassembly
|
||||
// This will eventually grow to include all options supported by
|
||||
// standalone Distella
|
||||
struct Settings{
|
||||
Common::Base::Format gfx_format;
|
||||
bool resolve_code; // Attempt to detect code vs. data sections
|
||||
bool show_addresses; // Show PC addresses (always off for external output)
|
||||
bool aflag; // Turns 'A' off in accumulator instructions (-a in Distella)
|
||||
bool fflag; // Forces correct address length (-f in Distella)
|
||||
bool rflag; // Relocate calls out of address range (-r in Distella)
|
||||
int bwidth; // Number of bytes to use per line (with .byte xxx)
|
||||
struct Settings {
|
||||
Common::Base::Format gfxFormat;
|
||||
bool resolveCode; // Attempt to detect code vs. data sections
|
||||
bool showAddresses; // Show PC addresses (always off for external output)
|
||||
bool aFlag; // Turns 'A' off in accumulator instructions (-a in Distella)
|
||||
bool fFlag; // Forces correct address length (-f in Distella)
|
||||
bool rFlag; // Relocate calls out of address range (-r in Distella)
|
||||
bool bFlag; // Process break routine (-b in Distella)
|
||||
int bytesWidth; // Number of bytes to use per line (with .byte xxx)
|
||||
};
|
||||
static Settings settings; // Default settings
|
||||
|
||||
@ -81,9 +83,16 @@ class DiStella
|
||||
|
||||
// These functions are part of the original Distella code
|
||||
void disasm(uInt32 distart, int pass);
|
||||
void disasmPass1(CartDebug::AddressList& debuggerAddresses);
|
||||
void disasmFromAddress(uInt32 distart);
|
||||
|
||||
bool check_range(uInt16 start, uInt16 end) const;
|
||||
int mark(uInt32 address, uInt8 mask, bool directive = false);
|
||||
bool check_bit(uInt16 address, uInt8 mask) const;
|
||||
bool checkBit(uInt16 address, uInt8 mask, bool useDebugger = true) const;
|
||||
|
||||
bool checkBits(uInt16 address, uInt8 mask, uInt8 notMask, bool useDebugger = true) const;
|
||||
void outputGraphics();
|
||||
void outputBytes(CartDebug::DisasmType type);
|
||||
|
||||
// Convenience methods to generate appropriate labels
|
||||
inline void labelA12High(stringstream& buf, uInt8 op, uInt16 addr, int labfound)
|
||||
@ -115,6 +124,7 @@ class DiStella
|
||||
stringstream myDisasmBuf;
|
||||
std::queue<uInt16> myAddressQueue;
|
||||
uInt16 myOffset, myPC, myPCEnd;
|
||||
uInt16 mySegType;
|
||||
|
||||
struct resource {
|
||||
uInt16 start;
|
||||
@ -179,6 +189,7 @@ class DiStella
|
||||
AccessMode source;
|
||||
ReadWriteMode rw_mode;
|
||||
uInt8 cycles;
|
||||
uInt8 bytes;
|
||||
};
|
||||
static const Instruction_tag ourLookup[256];
|
||||
|
||||
|
@ -40,10 +40,6 @@ TIADebug::TIADebug(Debugger& dbg, Console& console)
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const DebuggerState& TIADebug::getState()
|
||||
{
|
||||
myState.ram.clear();
|
||||
for(int i = 0; i < 0x010; ++i)
|
||||
myState.ram.push_back(myTIA.peek(i));
|
||||
|
||||
// Color registers
|
||||
myState.coluRegs.clear();
|
||||
myState.coluRegs.push_back(coluP0());
|
||||
@ -117,10 +113,6 @@ const DebuggerState& TIADebug::getState()
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TIADebug::saveOldState()
|
||||
{
|
||||
myOldState.ram.clear();
|
||||
for(int i = 0; i < 0x010; ++i)
|
||||
myOldState.ram.push_back(myTIA.peek(i));
|
||||
|
||||
// Color registers
|
||||
myOldState.coluRegs.clear();
|
||||
myOldState.coluRegs.push_back(coluP0());
|
||||
@ -699,7 +691,25 @@ void TIADebug::setENABLOld(bool b)
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
int TIADebug::frameCount() const
|
||||
{
|
||||
return myTIA.myFrameManager.frameCount();
|
||||
return myTIA.frameCount();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
int TIADebug::frameCycles() const
|
||||
{
|
||||
return myTIA.frameCycles();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
int TIADebug::cyclesLo() const
|
||||
{
|
||||
return (int)myTIA.cycles();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
int TIADebug::cyclesHi() const
|
||||
{
|
||||
return (int)(myTIA.cycles() >> 32);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -38,7 +38,6 @@ enum {
|
||||
class TiaState : public DebuggerState
|
||||
{
|
||||
public:
|
||||
IntArray ram;
|
||||
IntArray coluRegs;
|
||||
IntArray fixedCols;
|
||||
IntArray gr;
|
||||
@ -160,6 +159,9 @@ class TIADebug : public DebuggerSystem
|
||||
int scanlines() const;
|
||||
int scanlinesLastFrame() const;
|
||||
int frameCount() const;
|
||||
int frameCycles() const;
|
||||
int cyclesLo() const;
|
||||
int cyclesHi() const;
|
||||
int clocksThisLine() const;
|
||||
bool vsync() const;
|
||||
bool vblank() const;
|
||||
|
@ -59,14 +59,14 @@ Cartridge0840Widget::Cartridge0840Widget(
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Cartridge0840Widget::loadConfig()
|
||||
{
|
||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
||||
myBank->setSelectedIndex(myCart.getBank());
|
||||
|
||||
CartDebugWidget::loadConfig();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Cartridge0840Widget::handleCommand(CommandSender* sender,
|
||||
int cmd, int data, int id)
|
||||
int cmd, int data, int id)
|
||||
{
|
||||
if(cmd == kBankChanged)
|
||||
{
|
||||
@ -83,8 +83,8 @@ string Cartridge0840Widget::bankState()
|
||||
ostringstream& buf = buffer();
|
||||
|
||||
static const char* const spot[] = { "$800", "$840" };
|
||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
||||
buf << "Bank = " << std::dec << myCart.getBank()
|
||||
<< ", hotspot = " << spot[myCart.getBank()];
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ void CartridgeBFSCWidget::saveOldState()
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeBFSCWidget::loadConfig()
|
||||
{
|
||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
||||
myBank->setSelectedIndex(myCart.getBank());
|
||||
|
||||
CartDebugWidget::loadConfig();
|
||||
}
|
||||
@ -167,8 +167,8 @@ string CartridgeBFSCWidget::bankState()
|
||||
"$FFB0", "$FFB1", "$FFB2", "$FFB3", "$FFB4", "$FFB5", "$FFB6", "$FFB7",
|
||||
"$FFB8", "$FFB9", "$FFBA", "$FFBB", "$FFBC", "$FFBD", "$FFBE", "$FFBF"
|
||||
};
|
||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
||||
buf << "Bank = " << std::dec << myCart.getBank()
|
||||
<< ", hotspot = " << spot[myCart.getBank()];
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ CartridgeBFWidget::CartridgeBFWidget(
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeBFWidget::loadConfig()
|
||||
{
|
||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
||||
myBank->setSelectedIndex(myCart.getBank());
|
||||
|
||||
CartDebugWidget::loadConfig();
|
||||
}
|
||||
@ -154,8 +154,8 @@ string CartridgeBFWidget::bankState()
|
||||
"$FFB0", "$FFB1", "$FFB2", "$FFB3", "$FFB4", "$FFB5", "$FFB6", "$FFB7",
|
||||
"$FFB8", "$FFB9", "$FFBA", "$FFBB", "$FFBC", "$FFBD", "$FFBE", "$FFBF"
|
||||
};
|
||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
||||
buf << "Bank = " << std::dec << myCart.getBank()
|
||||
<< ", hotspot = " << spot[myCart.getBank()];
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
@ -252,7 +252,7 @@ void CartridgeBUSWidget::saveOldState()
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeBUSWidget::loadConfig()
|
||||
{
|
||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
||||
myBank->setSelectedIndex(myCart.getBank());
|
||||
|
||||
// Get registers, using change tracking
|
||||
IntArray alist;
|
||||
@ -397,8 +397,8 @@ string CartridgeBUSWidget::bankState()
|
||||
static const char* const spot[] = {
|
||||
"$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB"
|
||||
};
|
||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
||||
buf << "Bank = " << std::dec << myCart.getBank()
|
||||
<< ", hotspot = " << spot[myCart.getBank()];
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ CartridgeCDFWidget::CartridgeCDFWidget(
|
||||
uInt16 size = 8 * 4096;
|
||||
|
||||
ostringstream info;
|
||||
info << "CDF cartridge\n"
|
||||
info << "CDF cartridge (version " << cart.myVersion << ")\n"
|
||||
<< "32K ROM, seven 4K banks are accessible to 2600\n"
|
||||
<< "8K CDF RAM\n"
|
||||
<< "CDF registers accessible @ $FFF0 - $FFF3\n"
|
||||
@ -230,7 +230,7 @@ void CartridgeCDFWidget::saveOldState()
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeCDFWidget::loadConfig()
|
||||
{
|
||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
||||
myBank->setSelectedIndex(myCart.getBank());
|
||||
|
||||
// Get registers, using change tracking
|
||||
IntArray alist;
|
||||
@ -360,8 +360,8 @@ string CartridgeCDFWidget::bankState()
|
||||
static const char* const spot[] = {
|
||||
"$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB"
|
||||
};
|
||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
||||
buf << "Bank = " << std::dec << myCart.getBank()
|
||||
<< ", hotspot = " << spot[myCart.getBank()];
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ void CartridgeCMWidget::saveOldState()
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeCMWidget::loadConfig()
|
||||
{
|
||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
||||
myBank->setSelectedIndex(myCart.getBank());
|
||||
|
||||
RiotDebug& riot = Debugger::debugger().riotDebug();
|
||||
const RiotState& state = static_cast<const RiotState&>(riot.getState());
|
||||
@ -219,7 +219,7 @@ string CartridgeCMWidget::bankState()
|
||||
{
|
||||
ostringstream& buf = buffer();
|
||||
|
||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
||||
buf << "Bank = " << std::dec << myCart.getBank()
|
||||
<< ", RAM is" << (myCart.mySWCHA & 0x10 ? " Inactive" :
|
||||
myCart.mySWCHA & 0x20 ? " Read-only" : " Write-only");
|
||||
|
||||
|
@ -102,7 +102,7 @@ void CartridgeDFSCWidget::saveOldState()
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeDFSCWidget::loadConfig()
|
||||
{
|
||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
||||
myBank->setSelectedIndex(myCart.getBank());
|
||||
|
||||
CartDebugWidget::loadConfig();
|
||||
}
|
||||
@ -131,8 +131,8 @@ string CartridgeDFSCWidget::bankState()
|
||||
"$FFD0", "$FFD1", "$FFD2", "$FFD3", "$FFD4", "$FFD5", "$FFD6", "$FFE7",
|
||||
"$FFD8", "$FFD9", "$FFDA", "$FFDB", "$FFDC", "$FFDD", "$FFDE", "$FFDF"
|
||||
};
|
||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
||||
buf << "Bank = " << std::dec << myCart.getBank()
|
||||
<< ", hotspot = " << spot[myCart.getBank()];
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ CartridgeDFWidget::CartridgeDFWidget(
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeDFWidget::loadConfig()
|
||||
{
|
||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
||||
myBank->setSelectedIndex(myCart.getBank());
|
||||
|
||||
CartDebugWidget::loadConfig();
|
||||
}
|
||||
@ -118,8 +118,8 @@ string CartridgeDFWidget::bankState()
|
||||
"$FFD0", "$FFD1", "$FFD2", "$FFD3", "$FFD4", "$FFD5", "$FFD6", "$FFD7",
|
||||
"$FFD8", "$FFD9", "$FFDA", "$FFDB", "$FFDC", "$FFDD", "$FFDE", "$FFDF"
|
||||
};
|
||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
||||
buf << "Bank = " << std::dec << myCart.getBank()
|
||||
<< ", hotspot = " << spot[myCart.getBank()];
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
@ -218,7 +218,7 @@ void CartridgeDPCPlusWidget::saveOldState()
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeDPCPlusWidget::loadConfig()
|
||||
{
|
||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
||||
myBank->setSelectedIndex(myCart.getBank());
|
||||
|
||||
// Get registers, using change tracking
|
||||
IntArray alist;
|
||||
@ -327,8 +327,8 @@ string CartridgeDPCPlusWidget::bankState()
|
||||
static const char* const spot[] = {
|
||||
"$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB"
|
||||
};
|
||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
||||
buf << "Bank = " << std::dec << myCart.getBank()
|
||||
<< ", hotspot = " << spot[myCart.getBank()];
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
@ -156,7 +156,7 @@ void CartridgeDPCWidget::saveOldState()
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeDPCWidget::loadConfig()
|
||||
{
|
||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
||||
myBank->setSelectedIndex(myCart.getBank());
|
||||
|
||||
// Get registers, using change tracking
|
||||
IntArray alist;
|
||||
@ -228,8 +228,8 @@ string CartridgeDPCWidget::bankState()
|
||||
ostringstream& buf = buffer();
|
||||
|
||||
static const char* const spot[] = { "$FFF8", "$FFF9" };
|
||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
||||
buf << "Bank = " << std::dec << myCart.getBank()
|
||||
<< ", hotspot = " << spot[myCart.getBank()];
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ void CartridgeEFSCWidget::saveOldState()
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeEFSCWidget::loadConfig()
|
||||
{
|
||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
||||
myBank->setSelectedIndex(myCart.getBank());
|
||||
|
||||
CartDebugWidget::loadConfig();
|
||||
}
|
||||
@ -113,8 +113,8 @@ string CartridgeEFSCWidget::bankState()
|
||||
"$FFE0", "$FFE1", "$FFE2", "$FFE3", "$FFE4", "$FFE5", "$FFE6", "$FFE7",
|
||||
"$FFE8", "$FFE9", "$FFEA", "$FFEB", "$FFEC", "$FFED", "$FFEE", "$FFEF"
|
||||
};
|
||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
||||
buf << "Bank = " << std::dec << myCart.getBank()
|
||||
<< ", hotspot = " << spot[myCart.getBank()];
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ CartridgeEFWidget::CartridgeEFWidget(
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeEFWidget::loadConfig()
|
||||
{
|
||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
||||
myBank->setSelectedIndex(myCart.getBank());
|
||||
|
||||
CartDebugWidget::loadConfig();
|
||||
}
|
||||
@ -100,8 +100,8 @@ string CartridgeEFWidget::bankState()
|
||||
"$FFE0", "$FFE1", "$FFE2", "$FFE3", "$FFE4", "$FFE5", "$FFE6", "$FFE7",
|
||||
"$FFE8", "$FFE9", "$FFEA", "$FFEB", "$FFEC", "$FFED", "$FFEE", "$FFEF"
|
||||
};
|
||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
||||
buf << "Bank = " << std::dec << myCart.getBank()
|
||||
<< ", hotspot = " << spot[myCart.getBank()];
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ CartridgeF0Widget::CartridgeF0Widget(
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeF0Widget::loadConfig()
|
||||
{
|
||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
||||
myBank->setSelectedIndex(myCart.getBank());
|
||||
|
||||
CartDebugWidget::loadConfig();
|
||||
}
|
||||
@ -97,7 +97,7 @@ string CartridgeF0Widget::bankState()
|
||||
{
|
||||
ostringstream& buf = buffer();
|
||||
|
||||
buf << "Bank = " << std::dec << myCart.myCurrentBank << ", hotspot = $FFF0";
|
||||
buf << "Bank = " << std::dec << myCart.getBank() << ", hotspot = $FFF0";
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ void CartridgeF4SCWidget::saveOldState()
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeF4SCWidget::loadConfig()
|
||||
{
|
||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
||||
myBank->setSelectedIndex(myCart.getBank());
|
||||
|
||||
CartDebugWidget::loadConfig();
|
||||
}
|
||||
@ -103,8 +103,8 @@ string CartridgeF4SCWidget::bankState()
|
||||
static const char* const spot[] = {
|
||||
"$FFF4", "$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB"
|
||||
};
|
||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
||||
buf << "Bank = " << std::dec << myCart.getBank()
|
||||
<< ", hotspot = " << spot[myCart.getBank()];
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ CartridgeF4Widget::CartridgeF4Widget(
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeF4Widget::loadConfig()
|
||||
{
|
||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
||||
myBank->setSelectedIndex(myCart.getBank());
|
||||
|
||||
CartDebugWidget::loadConfig();
|
||||
}
|
||||
@ -90,8 +90,8 @@ string CartridgeF4Widget::bankState()
|
||||
static const char* const spot[] = {
|
||||
"$FFF4", "$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB"
|
||||
};
|
||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
||||
buf << "Bank = " << std::dec << myCart.getBank()
|
||||
<< ", hotspot = " << spot[myCart.getBank()];
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ void CartridgeF6SCWidget::saveOldState()
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeF6SCWidget::loadConfig()
|
||||
{
|
||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
||||
myBank->setSelectedIndex(myCart.getBank());
|
||||
|
||||
CartDebugWidget::loadConfig();
|
||||
}
|
||||
@ -97,8 +97,8 @@ string CartridgeF6SCWidget::bankState()
|
||||
ostringstream& buf = buffer();
|
||||
|
||||
static const char* const spot[] = { "$FFF6", "$FFF7", "$FFF8", "$FFF9" };
|
||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
||||
buf << "Bank = " << std::dec << myCart.getBank()
|
||||
<< ", hotspot = " << spot[myCart.getBank()];
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|