diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json
new file mode 100644
index 000000000..1a1d89422
--- /dev/null
+++ b/.vscode/c_cpp_properties.json
@@ -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
+}
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 94f1f7797..857d47127 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -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
-}
\ No newline at end of file
+ "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
+}
diff --git a/Announce.txt b/Announce.txt
index 51c7f6b27..76fbbdd16 100644
--- a/Announce.txt
+++ b/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
diff --git a/Changes.txt b/Changes.txt
index 6500823cf..eb541ed7d 100644
--- a/Changes.txt
+++ b/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)
diff --git a/Makefile b/Makefile
index a1284f07b..cc38e4c64 100644
--- a/Makefile
+++ b/Makefile
@@ -27,7 +27,7 @@
srcdir ?= .
DEFINES := -D_GLIBCXX_USE_CXX11_ABI=1
-LDFLAGS :=
+LDFLAGS := -pthread
INCLUDES :=
LIBS :=
OBJS :=
diff --git a/configure b/configure
index c2f304729..090fafc39 100755
--- a/configure
+++ b/configure
@@ -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 < Sun, 20 Aug 2017 17:09:59 -0230
+
+
stella (5.0.1-1) stable; urgency=high
* Version 5.0.1 release
diff --git a/docs/debugger.html b/docs/debugger.html
index de8ec3405..a0531e6cb 100644
--- a/docs/debugger.html
+++ b/docs/debugger.html
@@ -541,12 +541,13 @@ that holds 'number of scanlines' on an actual console).
Function | Description |
_bank | Currently selected bank |
- _rwport | Last address to attempt a read from the cart write port |
- _fcount | Number of frames since emulation started |
_cclocks | Color clocks on a scanline |
+ _fcount | Number of frames since emulation started |
+ _fcycles | Number of cycles since frame started |
+ _rwport | Last address to attempt a read from the cart write port |
_scan | Current scanline count |
- _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) |
_scan always contains the current scanline count. You can use
@@ -646,7 +647,7 @@ Type "help 'cmd'" to see extended information about the given command.
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)
diff --git a/docs/graphics/cheat.png b/docs/graphics/cheat.png
index bdac1abbd..0c34afeec 100644
Binary files a/docs/graphics/cheat.png and b/docs/graphics/cheat.png differ
diff --git a/docs/graphics/commandmenu.png b/docs/graphics/commandmenu.png
index 27c11929f..448fd61be 100644
Binary files a/docs/graphics/commandmenu.png and b/docs/graphics/commandmenu.png differ
diff --git a/docs/graphics/console.png b/docs/graphics/console.png
index 7a4f35a1b..7b8f549a4 100644
Binary files a/docs/graphics/console.png and b/docs/graphics/console.png differ
diff --git a/docs/graphics/debugger_bankcomplex.png b/docs/graphics/debugger_bankcomplex.png
index 549b7df34..b20ad65ac 100644
Binary files a/docs/graphics/debugger_bankcomplex.png and b/docs/graphics/debugger_bankcomplex.png differ
diff --git a/docs/graphics/debugger_banksimple.png b/docs/graphics/debugger_banksimple.png
index 37c48860d..98f09dfe0 100644
Binary files a/docs/graphics/debugger_banksimple.png and b/docs/graphics/debugger_banksimple.png differ
diff --git a/docs/graphics/debugger_bpstatus.png b/docs/graphics/debugger_bpstatus.png
index 2136e3f89..231ecf884 100644
Binary files a/docs/graphics/debugger_bpstatus.png and b/docs/graphics/debugger_bpstatus.png differ
diff --git a/docs/graphics/debugger_cpuregs.png b/docs/graphics/debugger_cpuregs.png
index e69ec6ac1..f8cd3cb55 100644
Binary files a/docs/graphics/debugger_cpuregs.png and b/docs/graphics/debugger_cpuregs.png differ
diff --git a/docs/graphics/debugger_dataops.png b/docs/graphics/debugger_dataops.png
index d3a312ebd..7cfe7c874 100644
Binary files a/docs/graphics/debugger_dataops.png and b/docs/graphics/debugger_dataops.png differ
diff --git a/docs/graphics/debugger_globalbuttons.png b/docs/graphics/debugger_globalbuttons.png
index 8b32294a5..c9527a0da 100644
Binary files a/docs/graphics/debugger_globalbuttons.png and b/docs/graphics/debugger_globalbuttons.png differ
diff --git a/docs/graphics/debugger_iotab.png b/docs/graphics/debugger_iotab.png
index 24014eaa9..1fc409716 100644
Binary files a/docs/graphics/debugger_iotab.png and b/docs/graphics/debugger_iotab.png differ
diff --git a/docs/graphics/debugger_main.png b/docs/graphics/debugger_main.png
index 6826e4ade..709623f33 100644
Binary files a/docs/graphics/debugger_main.png and b/docs/graphics/debugger_main.png differ
diff --git a/docs/graphics/debugger_ram-dpc.png b/docs/graphics/debugger_ram-dpc.png
index 62136b701..fbc42d75c 100644
Binary files a/docs/graphics/debugger_ram-dpc.png and b/docs/graphics/debugger_ram-dpc.png differ
diff --git a/docs/graphics/debugger_ram-f8sc.png b/docs/graphics/debugger_ram-f8sc.png
index 146c11091..b4145c269 100644
Binary files a/docs/graphics/debugger_ram-f8sc.png and b/docs/graphics/debugger_ram-f8sc.png differ
diff --git a/docs/graphics/debugger_ram.png b/docs/graphics/debugger_ram.png
index 0bb5a9f60..0b3e983b8 100644
Binary files a/docs/graphics/debugger_ram.png and b/docs/graphics/debugger_ram.png differ
diff --git a/docs/graphics/debugger_ramsearch.png b/docs/graphics/debugger_ramsearch.png
index b37d5d698..433922fc6 100644
Binary files a/docs/graphics/debugger_ramsearch.png and b/docs/graphics/debugger_ramsearch.png differ
diff --git a/docs/graphics/debugger_rom.png b/docs/graphics/debugger_rom.png
index 2cd5a1f12..3dc88e48b 100644
Binary files a/docs/graphics/debugger_rom.png and b/docs/graphics/debugger_rom.png differ
diff --git a/docs/graphics/debugger_romcmenu.png b/docs/graphics/debugger_romcmenu.png
index 215386847..f702c9766 100644
Binary files a/docs/graphics/debugger_romcmenu.png and b/docs/graphics/debugger_romcmenu.png differ
diff --git a/docs/graphics/debugger_tiainfo.png b/docs/graphics/debugger_tiainfo.png
index 50f817d6f..449d39716 100644
Binary files a/docs/graphics/debugger_tiainfo.png and b/docs/graphics/debugger_tiainfo.png differ
diff --git a/docs/graphics/debugger_tiaoutcmenu.png b/docs/graphics/debugger_tiaoutcmenu.png
index 12d1f1b05..fcfe672e9 100644
Binary files a/docs/graphics/debugger_tiaoutcmenu.png and b/docs/graphics/debugger_tiaoutcmenu.png differ
diff --git a/docs/graphics/debugger_tiatab.png b/docs/graphics/debugger_tiatab.png
index 0f1834e8c..090ce9a9e 100644
Binary files a/docs/graphics/debugger_tiatab.png and b/docs/graphics/debugger_tiatab.png differ
diff --git a/docs/graphics/debugger_tiazoomcmenu.png b/docs/graphics/debugger_tiazoomcmenu.png
index bbaae8b21..06e3dc3ae 100644
Binary files a/docs/graphics/debugger_tiazoomcmenu.png and b/docs/graphics/debugger_tiazoomcmenu.png differ
diff --git a/docs/graphics/developer_stats.png b/docs/graphics/developer_stats.png
index 76217b9c9..fff0b07cd 100644
Binary files a/docs/graphics/developer_stats.png and b/docs/graphics/developer_stats.png differ
diff --git a/docs/graphics/eventmapping.png b/docs/graphics/eventmapping.png
index da13d048f..230e99ef2 100644
Binary files a/docs/graphics/eventmapping.png and b/docs/graphics/eventmapping.png differ
diff --git a/docs/graphics/eventmapping_combo.png b/docs/graphics/eventmapping_combo.png
index e87112e12..96eac8f6d 100644
Binary files a/docs/graphics/eventmapping_combo.png and b/docs/graphics/eventmapping_combo.png differ
diff --git a/docs/graphics/eventmapping_devsports.png b/docs/graphics/eventmapping_devsports.png
index 2fa98cc0c..82b1a603b 100644
Binary files a/docs/graphics/eventmapping_devsports.png and b/docs/graphics/eventmapping_devsports.png differ
diff --git a/docs/graphics/eventmapping_remap.png b/docs/graphics/eventmapping_remap.png
index ca0d9ad41..27742a547 100644
Binary files a/docs/graphics/eventmapping_remap.png and b/docs/graphics/eventmapping_remap.png differ
diff --git a/docs/graphics/jr_pacman.png b/docs/graphics/jr_pacman.png
index 826bd04d2..989a19a78 100644
Binary files a/docs/graphics/jr_pacman.png and b/docs/graphics/jr_pacman.png differ
diff --git a/docs/graphics/launcher.png b/docs/graphics/launcher.png
index c5a04f49d..0c0e3182e 100644
Binary files a/docs/graphics/launcher.png and b/docs/graphics/launcher.png differ
diff --git a/docs/graphics/launcher_filter.png b/docs/graphics/launcher_filter.png
index acf1037a6..e56e8bee6 100644
Binary files a/docs/graphics/launcher_filter.png and b/docs/graphics/launcher_filter.png differ
diff --git a/docs/graphics/launcher_options_files.png b/docs/graphics/launcher_options_files.png
index 6db5fface..e9becf46f 100644
Binary files a/docs/graphics/launcher_options_files.png and b/docs/graphics/launcher_options_files.png differ
diff --git a/docs/graphics/launcher_options_snapshots.png b/docs/graphics/launcher_options_snapshots.png
index 2de169502..de6f9dfa5 100644
Binary files a/docs/graphics/launcher_options_snapshots.png and b/docs/graphics/launcher_options_snapshots.png differ
diff --git a/docs/graphics/launcher_override.png b/docs/graphics/launcher_override.png
index af1d49ba7..a6c3dcfe0 100644
Binary files a/docs/graphics/launcher_override.png and b/docs/graphics/launcher_override.png differ
diff --git a/docs/graphics/logs.png b/docs/graphics/logs.png
index ae6373b5c..acfe013f7 100644
Binary files a/docs/graphics/logs.png and b/docs/graphics/logs.png differ
diff --git a/docs/graphics/options.png b/docs/graphics/options.png
index bb7c35d04..5497cb154 100644
Binary files a/docs/graphics/options.png and b/docs/graphics/options.png differ
diff --git a/docs/graphics/options_audio.png b/docs/graphics/options_audio.png
index 3b624a95e..a8706ba65 100644
Binary files a/docs/graphics/options_audio.png and b/docs/graphics/options_audio.png differ
diff --git a/docs/graphics/options_debugger.png b/docs/graphics/options_debugger.png
index ee6dd4ea6..2605d266c 100644
Binary files a/docs/graphics/options_debugger.png and b/docs/graphics/options_debugger.png differ
diff --git a/docs/graphics/options_gameinfo.png b/docs/graphics/options_gameinfo.png
index 83cf0e820..1c8eb8bb9 100644
Binary files a/docs/graphics/options_gameinfo.png and b/docs/graphics/options_gameinfo.png differ
diff --git a/docs/graphics/options_input.png b/docs/graphics/options_input.png
deleted file mode 100644
index fb9423b2e..000000000
Binary files a/docs/graphics/options_input.png and /dev/null differ
diff --git a/docs/graphics/options_misc.png b/docs/graphics/options_misc.png
index 493402e56..e7e9dacd2 100644
Binary files a/docs/graphics/options_misc.png and b/docs/graphics/options_misc.png differ
diff --git a/docs/graphics/options_ui.png b/docs/graphics/options_ui.png
index 1114cfeac..b16714426 100644
Binary files a/docs/graphics/options_ui.png and b/docs/graphics/options_ui.png differ
diff --git a/docs/graphics/options_video.png b/docs/graphics/options_video.png
index 6bb857b28..c137437b3 100644
Binary files a/docs/graphics/options_video.png and b/docs/graphics/options_video.png differ
diff --git a/docs/graphics/options_video_dbgcolors.png b/docs/graphics/options_video_dbgcolors.png
index 107d83bac..aa7ba44dc 100644
Binary files a/docs/graphics/options_video_dbgcolors.png and b/docs/graphics/options_video_dbgcolors.png differ
diff --git a/docs/graphics/options_video_tv.png b/docs/graphics/options_video_tv.png
index 878cacab0..a5991b3cc 100644
Binary files a/docs/graphics/options_video_tv.png and b/docs/graphics/options_video_tv.png differ
diff --git a/docs/graphics/pacman.png b/docs/graphics/pacman.png
index bcc567895..daa0a505e 100644
Binary files a/docs/graphics/pacman.png and b/docs/graphics/pacman.png differ
diff --git a/docs/graphics/rom_browser.png b/docs/graphics/rom_browser.png
index 76c0cef5d..8232f25de 100644
Binary files a/docs/graphics/rom_browser.png and b/docs/graphics/rom_browser.png differ
diff --git a/docs/graphics/romaudit.png b/docs/graphics/romaudit.png
index 86d867ead..0de9446d2 100644
Binary files a/docs/graphics/romaudit.png and b/docs/graphics/romaudit.png differ
diff --git a/docs/graphics/rominfo_1x_large.png b/docs/graphics/rominfo_1x_large.png
index 76e29a384..97ff18784 100644
Binary files a/docs/graphics/rominfo_1x_large.png and b/docs/graphics/rominfo_1x_large.png differ
diff --git a/docs/graphics/rominfo_1x_small.png b/docs/graphics/rominfo_1x_small.png
index fc1c5b73e..f8fcf087e 100644
Binary files a/docs/graphics/rominfo_1x_small.png and b/docs/graphics/rominfo_1x_small.png differ
diff --git a/docs/graphics/rominfo_2x_small.png b/docs/graphics/rominfo_2x_small.png
index aed5e9fec..b51ee93e7 100644
Binary files a/docs/graphics/rominfo_2x_small.png and b/docs/graphics/rominfo_2x_small.png differ
diff --git a/docs/graphics/secret_quest.png b/docs/graphics/secret_quest.png
index d26cb53a4..57d1a6fe0 100644
Binary files a/docs/graphics/secret_quest.png and b/docs/graphics/secret_quest.png differ
diff --git a/docs/graphics/select_romdir.png b/docs/graphics/select_romdir.png
index 23b740314..1adfcd084 100644
Binary files a/docs/graphics/select_romdir.png and b/docs/graphics/select_romdir.png differ
diff --git a/docs/graphics/space_invaders.png b/docs/graphics/space_invaders.png
index f7ec5eebe..e3aaf8a33 100644
Binary files a/docs/graphics/space_invaders.png and b/docs/graphics/space_invaders.png differ
diff --git a/docs/index.html b/docs/index.html
index c457f08c4..dead10428 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -10,7 +10,7 @@
A multi-platform Atari 2600 VCS emulator
- Release 5.0.1
+ Release 5.0.2
User's Guide
@@ -2039,14 +2039,21 @@
-dsense <number> |
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. |
-msense <number> |
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. |
+
+
+
+ -tsense <number> |
+ 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. |
@@ -2082,6 +2089,11 @@
Disable Supercharger BIOS progress loading bars. |
+
+ -threads <1|0> |
+ Enable multi-threaded video rendering (may not improve performance on all systems). |
+
+
-snapsavedir <path> |
The directory to save snapshot files to. |
@@ -2284,23 +2296,29 @@
-holdjoy0 <U,D,L,R,F> |
Start the emulator with the left joystick direction/button held down
- (ie, use 'UF' for up and fire). |
+ (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.
-holdjoy1 <U,D,L,R,F> |
Start the emulator with the right joystick direction/button held down
- (ie, use 'UF' for up and fire). |
+ (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.
-holdselect |
- Start the emulator with the Game Select switch held down. |
+ 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. |
-holdreset |
- Start the emulator with the Game Reset switch held down. |
+ 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. |
@@ -2456,6 +2474,7 @@
Fast SC/AR BIOS | skip progress loading bars for SuperCharger ROMs | -fastscbios |
Show UI messages | overlay UI messages onscreen | -uimessages |
Center window | attempt to center application window | -center |
+ Use multi-threading | enable multi-threaded rendering | -threads |
@@ -2527,7 +2546,7 @@
Input Settings dialog:
- |
+ |
|
This dialog is described in further detail in
Advanced Configuration - Event Remapping. |
@@ -2588,7 +2607,7 @@
Save snapshots according to | specifies how to name saved snapshots | -snapname |
Continuous snapshot interval | interval (in seconds) between snapshot | -ssinterval |
Overwrite existing files | whether to overwrite old snapshots | -sssingle |
- Disable image filtering (1x mode) | save snapshot in 1x mode, without filtering | -ss1x |
+ Ignore scaling (1x mode) | save snapshot in 1x mode, without scaling | -ss1x |
@@ -2696,6 +2715,7 @@
Joy deadzone size | Deadzone area for axes on joysticks/gamepads | -joydeadzone |
Digital paddle sensitivity | Sensitivity used when emulating a paddle using a digital device | -dsense |
Mouse paddle sensitivity | Sensitivity used when emulating a paddle using a mouse | -msense |
+ Trackball sensitivity | Sensitivity used when emulating a trackball device using a mouse | -tsense |
Allow all 4 ... | Allow all 4 joystick directions to be pressed simultaneously | -joyallow4 |
Grab mouse ... | Keep mouse in window in emulation mode | -grabmouse |
Use Control key combos | Enable using Control key in keyboard actions | -ctrlcombo |
diff --git a/src/common/RewindManager.cxx b/src/common/RewindManager.cxx
new file mode 100644
index 000000000..21a7d2281
--- /dev/null
+++ b/src/common/RewindManager.cxx
@@ -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(); // 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;
+}
diff --git a/src/common/RewindManager.hxx b/src/common/RewindManager.hxx
new file mode 100644
index 000000000..504cea079
--- /dev/null
+++ b/src/common/RewindManager.hxx
@@ -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
+#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;
+ std::list 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
diff --git a/src/common/SoundNull.hxx b/src/common/SoundNull.hxx
index cda9ab671..768da91d5 100644
--- a/src/common/SoundNull.hxx
+++ b/src/common/SoundNull.hxx
@@ -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
diff --git a/src/common/SoundSDL2.cxx b/src/common/SoundSDL2.cxx
index 5451b6147..34fe07b16 100644
--- a/src/common/SoundSDL2.cxx
+++ b/src/common/SoundSDL2.cxx
@@ -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;
}
diff --git a/src/common/SoundSDL2.hxx b/src/common/SoundSDL2.hxx
index 5d186a5c1..faa9a72b9 100644
--- a/src/common/SoundSDL2.hxx
+++ b/src/common/SoundSDL2.hxx
@@ -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;
diff --git a/src/emucore/StateManager.cxx b/src/common/StateManager.cxx
similarity index 92%
rename from src/emucore/StateManager.cxx
rename to src/common/StateManager.cxx
index 8e3101fce..2261f8329 100644
--- a/src/emucore/StateManager.cxx
+++ b/src/common/StateManager.cxx
@@ -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(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
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/src/emucore/StateManager.hxx b/src/common/StateManager.hxx
similarity index 76%
rename from src/emucore/StateManager.hxx
rename to src/common/StateManager.hxx
index 3e846841b..a5c9c2b8a 100644
--- a/src/emucore/StateManager.hxx
+++ b/src/common/StateManager.hxx
@@ -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 myRewindManager;
+
private:
// Following constructors and assignment operators not supported
StateManager() = delete;
diff --git a/src/common/Version.hxx b/src/common/Version.hxx
index 313e78d88..aa3b9ff2e 100644
--- a/src/common/Version.hxx
+++ b/src/common/Version.hxx
@@ -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
diff --git a/src/common/bspf.hxx b/src/common/bspf.hxx
index 13975f056..607c4522b 100644
--- a/src/common/bspf.hxx
+++ b/src/common/bspf.hxx
@@ -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 inline T clamp(T a, T l, T u)
+ template inline T clamp(T val, T lower, T upper)
{
- return (au) ? u : a;
+ return (val < lower) ? lower : (val > upper) ? upper : val;
+ }
+ template inline void clamp(T& val, T lower, T upper, T setVal)
+ {
+ if(val < lower || val > upper) val = setVal;
}
// Compare two strings, ignoring case
diff --git a/src/common/module.mk b/src/common/module.mk
index 8c6238de5..37690f7dd 100644
--- a/src/common/module.mk
+++ b/src/common/module.mk
@@ -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
diff --git a/src/common/tv_filters/AtariNTSC.cxx b/src/common/tv_filters/AtariNTSC.cxx
index 155a3b7bc..a16a3649a 100644
--- a/src/common/tv_filters/AtariNTSC.cxx
+++ b/src/common/tv_filters/AtariNTSC.cxx
@@ -15,6 +15,7 @@
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
+#include
#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(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(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(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(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(rgb_out);
+ atari_in += in_width * yStart;
+ rgb_out = static_cast(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(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(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)
{
diff --git a/src/common/tv_filters/AtariNTSC.hxx b/src/common/tv_filters/AtariNTSC.hxx
index f9c42696f..d5dbecdda 100644
--- a/src/common/tv_filters/AtariNTSC.hxx
+++ b/src/common/tv_filters/AtariNTSC.hxx
@@ -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 myThreads;
+ // Number of rendering and total threads
+ uInt32 myWorkerThreads, myTotalThreads;
struct init_t
{
diff --git a/src/common/tv_filters/NTSCFilter.hxx b/src/common/tv_filters/NTSCFilter.hxx
index cb184337c..987687fc5 100644
--- a/src/common/tv_filters/NTSCFilter.hxx
+++ b/src/common/tv_filters/NTSCFilter.hxx
@@ -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
diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx
index 04f58f09e..79f8abe7a 100644
--- a/src/debugger/CartDebug.cxx
+++ b/src/debugger/CartDebug.cxx
@@ -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"
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/src/debugger/CartDebug.hxx b/src/debugger/CartDebug.hxx
index e4ce65b00..3c178dd44 100644
--- a/src/debugger/CartDebug.hxx
+++ b/src/debugger/CartDebug.hxx
@@ -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
diff --git a/src/debugger/Debugger.cxx b/src/debugger/Debugger.cxx
index 32d018923..ef8119ee6 100644
--- a/src/debugger/Debugger.cxx
+++ b/src/debugger/Debugger.cxx
@@ -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(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);
-}
diff --git a/src/debugger/Debugger.hxx b/src/debugger/Debugger.hxx
index 049306aec..bdefeb719 100644
--- a/src/debugger/Debugger.hxx
+++ b/src/debugger/Debugger.hxx
@@ -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 myRewindManager;
-
private:
// Following constructors and assignment operators not supported
Debugger() = delete;
diff --git a/src/debugger/DebuggerParser.cxx b/src/debugger/DebuggerParser.cxx
index f71bdf078..329ebaf32 100644
--- a/src/debugger/DebuggerParser.cxx
+++ b/src/debugger/DebuggerParser.cxx
@@ -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 ",
- "Example: dump f000",
+ "Dump data at address [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)
},
diff --git a/src/debugger/DebuggerParser.hxx b/src/debugger/DebuggerParser.hxx
index d0bcb5094..f4737487e 100644
--- a/src/debugger/DebuggerParser.hxx
+++ b/src/debugger/DebuggerParser.hxx
@@ -20,6 +20,7 @@
#include
#include
+#include
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 myTraps;
+ string trapStatus(uInt32 addr, bool& enabled);
// List of available command methods
void executeA();
diff --git a/src/debugger/DiStella.cxx b/src/debugger/DiStella.cxx
index a96fef2f7..744d08012 100644
--- a/src/debugger/DiStella.cxx
+++ b/src/debugger/DiStella.cxx
@@ -35,55 +35,22 @@ DiStella::DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list,
myLabels(labels),
myDirectives(directives)
{
- CartDebug::AddressList& addresses = info.addressList;
-
- while(!myAddressQueue.empty())
- myAddressQueue.pop();
-
- bool resolve_code = mySettings.resolve_code;
-
- auto it = addresses.cbegin();
- uInt16 start = *it++;
+ bool resolve_code = mySettings.resolveCode;
+ CartDebug::AddressList& debuggerAddresses = info.addressList;
+ uInt16 start = *debuggerAddresses.cbegin();
myOffset = info.offset;
- if(start & 0x1000)
- {
- if(info.size == 4096) // 4K ROM space
- {
- /*============================================
- The offset is the address where the code segment
- starts. For a 4K game, it is usually 0xf000.
-
- Example:
- Start address = $D973, so therefore
- Offset to code = $D000
- Code range = $D000-$DFFF
- =============================================*/
- info.start = myAppData.start = 0x0000;
- info.end = myAppData.end = 0x0FFF;
-
- // Keep previous offset; it may be different between banks
- if(info.offset == 0)
- info.offset = myOffset = (start - (start % 0x1000));
- }
- else // 2K ROM space (also includes 'Sub2K' ROMs)
- {
- /*============================================
- The offset is the address where the code segment
- starts. For a 2K game, it is usually 0xf800,
- but can also be 0xf000.
- =============================================*/
- info.start = myAppData.start = 0x0000;
- info.end = myAppData.end = info.size - 1;
- info.offset = myOffset = (start - (start % info.size));
- }
- }
- else // ZP RAM
- {
+ if (start & 0x1000) {
+ info.start = myAppData.start = 0x0000;
+ info.end = myAppData.end = info.size - 1;
+ // Keep previous offset; it may be different between banks
+ if (info.offset == 0)
+ info.offset = myOffset = (start - (start % info.size));
+ } else { // ZP RAM
// For now, we assume all accesses below $1000 are zero-page
- info.start = myAppData.start = 0x0080;
- info.end = myAppData.end = 0x00FF;
- info.offset = myOffset = 0;
+ info.start = myAppData.start = 0x0080;
+ info.end = myAppData.end = 0x00FF;
+ info.offset = myOffset = 0;
// Resolve code is never used in ZP RAM mode
resolve_code = false;
@@ -92,126 +59,32 @@ DiStella::DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list,
memset(myLabels, 0, 0x1000);
memset(myDirectives, 0, 0x1000);
- myAddressQueue.push(start);
// Process any directives first, as they override automatic code determination
processDirectives(info.directiveList);
- if(resolve_code)
- {
- // After we've disassembled from all addresses in the address list,
- // use all access points determined by Stella during emulation
- int codeAccessPoint = 0;
+ myReserved.breakFound = false;
- while(!myAddressQueue.empty())
- {
- myPC = myAddressQueue.front();
- uInt16 pcBeg = myPC;
- myAddressQueue.pop();
- disasm(myPC, 1);
- if(pcBeg <= myPCEnd)
- {
- // Tentatively mark all addresses in the range as CODE
- // Note that this is a 'best-effort' approach, since
- // Distella will normally keep going until the end of the
- // range or branch is encountered
- // However, addresses *specifically* marked as DATA/GFX/PGFX
- // in the emulation core indicate that the CODE range has finished
- // Therefore, we stop at the first such address encountered
- for (uInt32 k = pcBeg; k <= myPCEnd; k++)
- {
- if(Debugger::debugger().getAccessFlags(k) &
- (CartDebug::DATA|CartDebug::GFX|CartDebug::PGFX))
- {
- myPCEnd = k - 1;
- break;
- }
- mark(k, CartDebug::CODE);
- }
- }
-
- // When we get to this point, all addresses have been processed
- // starting from the initial one in the address list
- // If so, process the next one in the list that hasn't already
- // been marked as CODE
- // If it *has* been marked, it can be removed from consideration
- // in all subsequent passes
- //
- // Once the address list has been exhausted, we process all addresses
- // determined during emulation to represent code, which *haven't* already
- // been considered
- //
- // Note that we can't simply add all addresses right away, since
- // the processing of a single address can cause others to be added in
- // the ::disasm method
- // All of these have to be exhausted before considering a new address
- if(myAddressQueue.empty())
- {
- while(it != addresses.end())
- {
- uInt16 addr = *it;
- if(!check_bit(addr-myOffset, CartDebug::CODE))
- {
- myAddressQueue.push(addr);
- ++it;
- break;
- }
- else // remove this address, it is redundant
- it = addresses.erase(it);
- }
-
- // Stella itself can provide hints on whether an address has ever
- // been referenced as CODE
- while(it == addresses.end() && codeAccessPoint <= myAppData.end)
- {
- if((Debugger::debugger().getAccessFlags(codeAccessPoint+myOffset) & CartDebug::CODE)
- && !(myLabels[codeAccessPoint & myAppData.end] & CartDebug::CODE))
- {
- myAddressQueue.push(codeAccessPoint+myOffset);
- ++codeAccessPoint;
- break;
- }
- ++codeAccessPoint;
- }
- }
- }
- for (int k = 0; k <= myAppData.end; k++)
- {
- // Let the emulation core know about tentative code
- if(check_bit(k, CartDebug::CODE) &&
- !(Debugger::debugger().getAccessFlags(k+myOffset) & CartDebug::CODE)
- && myOffset != 0)
- {
- Debugger::debugger().setAccessFlags(k+myOffset, CartDebug::TCODE);
- }
-
- // Must be ROW / unused bytes
- if (!check_bit(k, CartDebug::CODE | CartDebug::GFX |
- CartDebug::PGFX | CartDebug::DATA))
- mark(k+myOffset, CartDebug::ROW);
- }
- }
+ if (resolve_code)
+ // First pass
+ disasmPass1(info.addressList);
// Second pass
disasm(myOffset, 2);
// Add reserved line equates
ostringstream reservedLabel;
- for (int k = 0; k <= myAppData.end; k++)
- {
- if ((myLabels[k] & (CartDebug::REFERENCED | CartDebug::VALID_ENTRY)) ==
- CartDebug::REFERENCED)
- {
+ for (int k = 0; k <= myAppData.end; k++) {
+ if ((myLabels[k] & (CartDebug::REFERENCED | CartDebug::VALID_ENTRY)) == CartDebug::REFERENCED) {
// If we have a piece of code referenced somewhere else, but cannot
// locate the label in code (i.e because the address is inside of a
// multi-byte instruction, then we make note of that address for reference
//
// However, we only do this for labels pointing to ROM (above $1000)
- if(myDbg.addressType(k+myOffset) == CartDebug::ADDR_ROM)
- {
+ if (myDbg.addressType(k + myOffset) == CartDebug::ADDR_ROM) {
reservedLabel.str("");
- reservedLabel << "L" << Base::HEX4 << (k+myOffset);
- myReserved.Label.emplace(k+myOffset, reservedLabel.str());
+ reservedLabel << "L" << Base::HEX4 << (k + myOffset);
+ myReserved.Label.emplace(k + myOffset, reservedLabel.str());
}
}
}
@@ -222,185 +95,134 @@ DiStella::DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list,
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DiStella::disasm(uInt32 distart, int pass)
+/*
+// Here we have 3 passes:
+ - pass 1 tries to detect code and data ranges and labels
+ - pass 2 marks valid code
+ - pass 3 generates output
+*/
{
-#define LABEL_A12_HIGH(address) labelA12High(nextline, op, address, labfound)
-#define LABEL_A12_LOW(address) labelA12Low(nextline, op, address, labfound)
+#define LABEL_A12_HIGH(address) labelA12High(nextLine, opcode, address, labelFound)
+#define LABEL_A12_LOW(address) labelA12Low(nextLine, opcode, address, labelFound)
- uInt8 op, d1;
+ uInt8 opcode, d1;
uInt16 ad;
- AddressingMode addr_mode;
- int bytes=0, labfound=0, addbranch=0;
- stringstream nextline, nextlinebytes;
+ uInt32 cycles = 0;
+ AddressingMode addrMode;
+ int labelFound = 0;
+ stringstream nextLine, nextLineBytes;
+
+ mySegType = CartDebug::NONE; // create extra lines between code and data
+
myDisasmBuf.str("");
/* pc=myAppData.start; */
myPC = distart - myOffset;
- while(myPC <= myAppData.end)
- {
- if(check_bit(myPC, CartDebug::GFX|CartDebug::PGFX) && !check_bit(myPC, CartDebug::CODE))
- {
- mark(myPC+myOffset, CartDebug::VALID_ENTRY);
+ while (myPC <= myAppData.end) {
- if (pass == 3)
- {
- if (check_bit(myPC, CartDebug::REFERENCED))
- myDisasmBuf << Base::HEX4 << myPC+myOffset << "'L" << Base::HEX4 << myPC+myOffset << "'";
- else
- myDisasmBuf << Base::HEX4 << myPC+myOffset << "' '";
-
- bool isPGfx = check_bit(myPC, CartDebug::PGFX);
- const string& bit_string = isPGfx ? "\x1f" : "\x1e";
- uInt8 byte = Debugger::debugger().peek(myPC+myOffset);
- myDisasmBuf << ".byte $" << Base::HEX2 << int(byte) << " |";
- for(uInt8 i = 0, c = byte; i < 8; ++i, c <<= 1)
- myDisasmBuf << ((c > 127) ? bit_string : " ");
- myDisasmBuf << "| $" << Base::HEX4 << myPC+myOffset << "'";
- if(mySettings.gfx_format == Base::F_2)
- myDisasmBuf << Base::toString(byte, Base::F_2_8);
- else
- myDisasmBuf << Base::HEX2 << int(byte);
- addEntry(isPGfx ? CartDebug::PGFX : CartDebug::GFX);
- }
- myPC++;
- }
- else if (check_bit(myPC, CartDebug::DATA) &&
- !check_bit(myPC, CartDebug::CODE|CartDebug::GFX|CartDebug::PGFX))
- {
+ if (checkBits(myPC, CartDebug::GFX | CartDebug::PGFX,
+ CartDebug::CODE)) {
if (pass == 2)
- mark(myPC+myOffset, CartDebug::VALID_ENTRY);
- else if (pass == 3)
- {
- if (check_bit(myPC, CartDebug::REFERENCED))
- myDisasmBuf << Base::HEX4 << myPC+myOffset << "'L" << Base::HEX4 << myPC+myOffset << "'";
- else
- myDisasmBuf << Base::HEX4 << myPC+myOffset << "' '";
-
- uInt8 byte = Debugger::debugger().peek(myPC+myOffset);
- myDisasmBuf << ".byte $" << Base::HEX2 << int(byte) << " $"
- << Base::HEX4 << myPC+myOffset << "'"
- << Base::HEX2 << int(byte);
- addEntry(CartDebug::DATA);
- }
- myPC++;
- }
- else if (check_bit(myPC, CartDebug::ROW) &&
- !check_bit(myPC, CartDebug::CODE|CartDebug::DATA|CartDebug::GFX|CartDebug::PGFX))
- {
- if (pass == 2)
- mark(myPC+myOffset, CartDebug::VALID_ENTRY);
-
+ mark(myPC + myOffset, CartDebug::VALID_ENTRY);
if (pass == 3)
- {
- bool row = check_bit(myPC, CartDebug::ROW) &&
- !check_bit(myPC, CartDebug::CODE | CartDebug::DATA |
- CartDebug::GFX | CartDebug::PGFX);
- bool referenced = check_bit(myPC, CartDebug::REFERENCED);
- bool line_empty = true;
- while (row && myPC <= myAppData.end)
- {
- if(referenced) // start a new line with a label
- {
- if(!line_empty)
- addEntry(CartDebug::ROW);
-
- myDisasmBuf << Base::HEX4 << myPC+myOffset << "'L" << Base::HEX4
- << myPC+myOffset << "'.byte " << "$" << Base::HEX2
- << int(Debugger::debugger().peek(myPC+myOffset));
- myPC++;
- bytes = 1;
- line_empty = false;
- }
- else if(line_empty) // start a new line without a label
- {
- myDisasmBuf << " ' '.byte $" << Base::HEX2 << int(Debugger::debugger().peek(myPC+myOffset));
- myPC++;
- bytes = 1;
- line_empty = false;
- }
- // Otherwise, append bytes to the current line, up until the maximum
- else if(++bytes == mySettings.bwidth)
- {
- addEntry(CartDebug::ROW);
- line_empty = true;
- }
- else
- {
- myDisasmBuf << ",$" << Base::HEX2 << int(Debugger::debugger().peek(myPC+myOffset));
- myPC++;
- }
-
- row = check_bit(myPC, CartDebug::ROW) &&
- !check_bit(myPC, CartDebug::CODE | CartDebug::DATA |
- CartDebug::GFX | CartDebug::PGFX);
- referenced = check_bit(myPC, CartDebug::REFERENCED);
- }
- if(!line_empty)
- addEntry(CartDebug::ROW);
- myDisasmBuf << " ' ' ";
- addEntry(CartDebug::NONE);
- }
+ outputGraphics();
+ myPC++;
+ } else if (checkBits(myPC, CartDebug::DATA,
+ CartDebug::CODE | CartDebug::GFX | CartDebug::PGFX)) {
+ if (pass == 2)
+ mark(myPC + myOffset, CartDebug::VALID_ENTRY);
+ if (pass == 3)
+ outputBytes(CartDebug::DATA);
else
myPC++;
- }
- else // The following sections must be CODE
- {
- // Add label (if any)
- //
- op = Debugger::debugger().peek(myPC+myOffset);
+ } else if (checkBits(myPC, CartDebug::ROW,
+ CartDebug::CODE | CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX)) {
+ if (pass == 2)
+ mark(myPC + myOffset, CartDebug::VALID_ENTRY);
+
+ if (pass == 3)
+ outputBytes(CartDebug::ROW);
+ else
+ myPC++;
+ } else {
+ // The following sections must be CODE
+
+ // add extra spacing line when switching from non-code to code
+ if (pass == 3 && mySegType != CartDebug::CODE && mySegType != CartDebug::NONE) {
+ myDisasmBuf << " ' ' ";
+ addEntry(CartDebug::NONE);
+ mark(myPC + myOffset, CartDebug::REFERENCED); // add label when switching
+ }
+ mySegType = CartDebug::CODE;
+
/* version 2.1 bug fix */
if (pass == 2)
- mark(myPC+myOffset, CartDebug::VALID_ENTRY);
- else if (pass == 3)
- {
- if (check_bit(myPC, CartDebug::REFERENCED))
- myDisasmBuf << Base::HEX4 << myPC+myOffset << "'L" << Base::HEX4 << myPC+myOffset << "'";
- else
- myDisasmBuf << Base::HEX4 << myPC+myOffset << "' '";
- }
+ mark(myPC + myOffset, CartDebug::VALID_ENTRY);
- // Add opcode mneumonic
- //
- addr_mode = ourLookup[op].addr_mode;
+ // get opcode
+ opcode = Debugger::debugger().peek(myPC + myOffset);
+ // get address mode for opcode
+ addrMode = ourLookup[opcode].addr_mode;
+
+ if (pass == 3) {
+ if (checkBit(myPC, CartDebug::REFERENCED))
+ myDisasmBuf << Base::HEX4 << myPC + myOffset << "'L" << Base::HEX4 << myPC + myOffset << "'";
+ else
+ myDisasmBuf << Base::HEX4 << myPC + myOffset << "' '";
+ }
myPC++;
+ // detect labels inside instructions (e.g. BIT masks)
+ labelFound = false;
+ for (Uint8 i = 0; i < ourLookup[opcode].bytes - 1; i++) {
+ if (checkBit(myPC + i, CartDebug::REFERENCED)) {
+ labelFound = true;
+ break;
+ }
+ }
+ if (labelFound) {
+ if (myOffset >= 0x1000) {
+ // the opcode's operand address matches a label address
+ if (pass == 3) {
+ // output the byte of the opcode incl. cycles
+ Uint8 nextOpcode = Debugger::debugger().peek(myPC + myOffset);
+
+ cycles += int(ourLookup[opcode].cycles) - int(ourLookup[nextOpcode].cycles);
+ nextLine << ".byte $" << Base::HEX2 << int(opcode) << " ;";
+ nextLine << ourLookup[opcode].mnemonic;
+
+ myDisasmBuf << nextLine.str() << "'" << ";"
+ << std::dec << int(ourLookup[opcode].cycles) << "-"
+ << std::dec << int(ourLookup[nextOpcode].cycles) << " "
+ << "'= " << std::setw(3) << std::setfill(' ') << std::dec << cycles;
+
+ nextLine.str("");
+ cycles = 0;
+ addEntry(CartDebug::CODE); // add the new found CODE entry
+ }
+ // continue with the label's opcode
+ continue;
+ } else {
+ if (pass == 3) {
+ // TODO
+ }
+ }
+ }
+
// Undefined opcodes start with a '.'
// These are undefined wrt DASM
- if (ourLookup[op].mnemonic[0] == '.')
- {
- addr_mode = IMPLIED;
- if (pass == 3)
- nextline << ".byte $" << Base::HEX2 << int(op) << " ;";
+ if (ourLookup[opcode].mnemonic[0] == '.' && pass == 3) {
+ nextLine << ".byte $" << Base::HEX2 << int(opcode) << " ;";
}
- if (pass == 1)
- {
- /* M_REL covers BPL, BMI, BVC, BVS, BCC, BCS, BNE, BEQ
- M_ADDR = JMP $NNNN, JSR $NNNN
- M_AIND = JMP Abs, Indirect */
- switch(ourLookup[op].source)
- {
- case M_REL:
- case M_ADDR:
- case M_AIND:
- addbranch = 1;
- break;
- default:
- addbranch = 0;
- break;
- }
- }
- else if (pass == 3)
- {
- nextline << ourLookup[op].mnemonic;
- nextlinebytes << Base::HEX2 << int(op) << " ";
+ if (pass == 3) {
+ nextLine << ourLookup[opcode].mnemonic;
+ nextLineBytes << Base::HEX2 << int(opcode) << " ";
}
// Add operand(s) for PC values outside the app data range
- //
- if (myPC >= myAppData.end)
- {
- switch(addr_mode)
- {
+ if (myPC >= myAppData.end) {
+ switch (addrMode) {
case ABSOLUTE:
case ABSOLUTE_X:
case ABSOLUTE_Y:
@@ -408,27 +230,25 @@ void DiStella::disasm(uInt32 distart, int pass)
case INDIRECT_Y:
case ABS_INDIRECT:
{
- if (pass == 3)
- {
+ if (pass == 3) {
/* Line information is already printed; append .byte since last
instruction will put recompilable object larger that original
binary file */
- myDisasmBuf << ".byte $" << Base::HEX2 << int(op) << " $"
- << Base::HEX4 << myPC+myOffset << "'"
- << Base::HEX2 << int(op);
+ myDisasmBuf << ".byte $" << Base::HEX2 << int(opcode) << " $"
+ << Base::HEX4 << myPC + myOffset << "'"
+ << Base::HEX2 << int(opcode);
addEntry(CartDebug::DATA);
- if (myPC == myAppData.end)
- {
- if (check_bit(myPC, CartDebug::REFERENCED))
- myDisasmBuf << Base::HEX4 << myPC+myOffset << "'L" << Base::HEX4 << myPC+myOffset << "'";
+ if (myPC == myAppData.end) {
+ if (checkBit(myPC, CartDebug::REFERENCED))
+ myDisasmBuf << Base::HEX4 << myPC + myOffset << "'L" << Base::HEX4 << myPC + myOffset << "'";
else
- myDisasmBuf << Base::HEX4 << myPC+myOffset << "' '";
+ myDisasmBuf << Base::HEX4 << myPC + myOffset << "' '";
- op = Debugger::debugger().peek(myPC+myOffset); myPC++;
- myDisasmBuf << ".byte $" << Base::HEX2 << int(op) << " $"
- << Base::HEX4 << myPC+myOffset << "'"
- << Base::HEX2 << int(op);
+ opcode = Debugger::debugger().peek(myPC + myOffset); myPC++;
+ myDisasmBuf << ".byte $" << Base::HEX2 << int(opcode) << " $"
+ << Base::HEX4 << myPC + myOffset << "'"
+ << Base::HEX2 << int(opcode);
addEntry(CartDebug::DATA);
}
}
@@ -442,21 +262,17 @@ void DiStella::disasm(uInt32 distart, int pass)
case ZERO_PAGE_Y:
case RELATIVE:
{
- if (myPC > myAppData.end)
- {
- if (pass == 3)
- {
- /* Line information is already printed, but we can remove the
- Instruction (i.e. BMI) by simply clearing the buffer to print */
- myDisasmBuf << ".byte $" << Base::HEX2 << int(op);
- addEntry(CartDebug::ROW);
- nextline.str("");
- nextlinebytes.str("");
- }
- myPC++;
- myPCEnd = myAppData.end + myOffset;
- return;
+ if (pass == 3) {
+ /* Line information is already printed, but we can remove the
+ Instruction (i.e. BMI) by simply clearing the buffer to print */
+ myDisasmBuf << ".byte $" << Base::HEX2 << int(opcode);
+ addEntry(CartDebug::ROW);
+ nextLine.str("");
+ nextLineBytes.str("");
}
+ myPC++;
+ myPCEnd = myAppData.end + myOffset;
+ return;
}
default:
@@ -465,77 +281,41 @@ void DiStella::disasm(uInt32 distart, int pass)
}
// Add operand(s)
- //
+ ad = d1 = 0; // not WSYNC by default!
/* Version 2.1 added the extensions to mnemonics */
- switch(addr_mode)
- {
- #if 0
- case IMPLIED:
- {
- if (op == 0x40 || op == 0x60)
- if (pass == 3)
- nextline << "\n";
- break;
- }
- #endif
+ switch (addrMode) {
case ACCUMULATOR:
{
- if (pass == 3 && mySettings.aflag)
- nextline << " A";
+ if (pass == 3 && mySettings.aFlag)
+ nextLine << " A";
break;
}
case ABSOLUTE:
{
- ad = Debugger::debugger().dpeek(myPC+myOffset); myPC+=2;
- labfound = mark(ad, CartDebug::REFERENCED);
- if (pass == 1)
- {
- if (addbranch)
- {
- if (!check_bit(ad & myAppData.end, CartDebug::CODE))
- {
- if (ad > 0xfff)
- myAddressQueue.push((ad & myAppData.end) + myOffset);
-
- mark(ad, CartDebug::CODE);
- }
- }
- else if(ad > 0xfff)
- {
- mark(ad, CartDebug::DATA);
- }
- }
- else if (pass == 3)
- {
- if (ad < 0x100 && mySettings.fflag)
- nextline << ".w ";
+ ad = Debugger::debugger().dpeek(myPC + myOffset); myPC += 2;
+ labelFound = mark(ad, CartDebug::REFERENCED);
+ if (pass == 3) {
+ if (ad < 0x100 && mySettings.fFlag)
+ nextLine << ".w ";
else
- nextline << " ";
+ nextLine << " ";
- if (labfound == 1)
- {
+ if (labelFound == 1) {
LABEL_A12_HIGH(ad);
- nextlinebytes << Base::HEX2 << int(ad&0xff) << " " << Base::HEX2 << int(ad>>8);
- }
- else if (labfound == 4)
- {
- if(mySettings.rflag)
- {
- int tmp = (ad & myAppData.end)+myOffset;
+ nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8);
+ } else if (labelFound == 4) {
+ if (mySettings.rFlag) {
+ int tmp = (ad & myAppData.end) + myOffset;
LABEL_A12_HIGH(tmp);
- nextlinebytes << Base::HEX2 << int(tmp&0xff) << " " << Base::HEX2 << int(tmp>>8);
+ nextLineBytes << Base::HEX2 << int(tmp & 0xff) << " " << Base::HEX2 << int(tmp >> 8);
+ } else {
+ nextLine << "$" << Base::HEX4 << ad;
+ nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8);
}
- else
- {
- nextline << "$" << Base::HEX4 << ad;
- nextlinebytes << Base::HEX2 << int(ad&0xff) << " " << Base::HEX2 << int(ad>>8);
- }
- }
- else
- {
+ } else {
LABEL_A12_LOW(ad);
- nextlinebytes << Base::HEX2 << int(ad&0xff) << " " << Base::HEX2 << int(ad>>8);
+ nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8);
}
}
break;
@@ -543,73 +323,60 @@ void DiStella::disasm(uInt32 distart, int pass)
case ZERO_PAGE:
{
- d1 = Debugger::debugger().peek(myPC+myOffset); myPC++;
- labfound = mark(d1, CartDebug::REFERENCED);
- if (pass == 3)
- {
- nextline << " ";
+ d1 = Debugger::debugger().peek(myPC + myOffset); myPC++;
+ labelFound = mark(d1, CartDebug::REFERENCED);
+ if (pass == 3) {
+ nextLine << " ";
LABEL_A12_LOW(int(d1));
- nextlinebytes << Base::HEX2 << int(d1);
+ nextLineBytes << Base::HEX2 << int(d1);
}
break;
}
case IMMEDIATE:
{
- d1 = Debugger::debugger().peek(myPC+myOffset); myPC++;
- if (pass == 3)
- {
- nextline << " #$" << Base::HEX2 << int(d1) << " ";
- nextlinebytes << Base::HEX2 << int(d1);
+ d1 = Debugger::debugger().peek(myPC + myOffset); myPC++;
+ if (pass == 3) {
+ nextLine << " #$" << Base::HEX2 << int(d1) << " ";
+ nextLineBytes << Base::HEX2 << int(d1);
}
break;
}
case ABSOLUTE_X:
{
- ad = Debugger::debugger().dpeek(myPC+myOffset); myPC+=2;
- labfound = mark(ad, CartDebug::REFERENCED);
- if (pass == 2 && !check_bit(ad & myAppData.end, CartDebug::CODE))
- {
+ ad = Debugger::debugger().dpeek(myPC + myOffset); myPC += 2;
+ labelFound = mark(ad, CartDebug::REFERENCED);
+ if (pass == 2 && !checkBit(ad & myAppData.end, CartDebug::CODE)) {
// Since we can't know what address is being accessed unless we also
// know the current X value, this is marked as ROW instead of DATA
// The processing is left here, however, in case future versions of
// the code can somehow track access to CPU registers
mark(ad, CartDebug::ROW);
- }
- else if (pass == 3)
- {
- if (ad < 0x100 && mySettings.fflag)
- nextline << ".wx ";
+ } else if (pass == 3) {
+ if (ad < 0x100 && mySettings.fFlag)
+ nextLine << ".wx ";
else
- nextline << " ";
+ nextLine << " ";
- if (labfound == 1)
- {
+ if (labelFound == 1) {
LABEL_A12_HIGH(ad);
- nextline << ",X";
- nextlinebytes << Base::HEX2 << int(ad&0xff) << " " << Base::HEX2 << int(ad>>8);
- }
- else if (labfound == 4)
- {
- if(mySettings.rflag)
- {
- int tmp = (ad & myAppData.end)+myOffset;
+ nextLine << ",x";
+ nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8);
+ } else if (labelFound == 4) {
+ if (mySettings.rFlag) {
+ int tmp = (ad & myAppData.end) + myOffset;
LABEL_A12_HIGH(tmp);
- nextline << ",X";
- nextlinebytes << Base::HEX2 << int(tmp&0xff) << " " << Base::HEX2 << int(tmp>>8);
+ nextLine << ",x";
+ nextLineBytes << Base::HEX2 << int(tmp & 0xff) << " " << Base::HEX2 << int(tmp >> 8);
+ } else {
+ nextLine << "$" << Base::HEX4 << ad << ",x";
+ nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8);
}
- else
- {
- nextline << "$" << Base::HEX4 << ad << ",X";
- nextlinebytes << Base::HEX2 << int(ad&0xff) << " " << Base::HEX2 << int(ad>>8);
- }
- }
- else
- {
+ } else {
LABEL_A12_LOW(ad);
- nextline << ",X";
- nextlinebytes << Base::HEX2 << int(ad&0xff) << " " << Base::HEX2 << int(ad>>8);
+ nextLine << ",x";
+ nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8);
}
}
break;
@@ -617,49 +384,38 @@ void DiStella::disasm(uInt32 distart, int pass)
case ABSOLUTE_Y:
{
- ad = Debugger::debugger().dpeek(myPC+myOffset); myPC+=2;
- labfound = mark(ad, CartDebug::REFERENCED);
- if (pass == 2 && !check_bit(ad & myAppData.end, CartDebug::CODE))
- {
+ ad = Debugger::debugger().dpeek(myPC + myOffset); myPC += 2;
+ labelFound = mark(ad, CartDebug::REFERENCED);
+ if (pass == 2 && !checkBit(ad & myAppData.end, CartDebug::CODE)) {
// Since we can't know what address is being accessed unless we also
// know the current Y value, this is marked as ROW instead of DATA
// The processing is left here, however, in case future versions of
// the code can somehow track access to CPU registers
mark(ad, CartDebug::ROW);
- }
- else if (pass == 3)
- {
- if (ad < 0x100 && mySettings.fflag)
- nextline << ".wy ";
+ } else if (pass == 3) {
+ if (ad < 0x100 && mySettings.fFlag)
+ nextLine << ".wy ";
else
- nextline << " ";
+ nextLine << " ";
- if (labfound == 1)
- {
+ if (labelFound == 1) {
LABEL_A12_HIGH(ad);
- nextline << ",Y";
- nextlinebytes << Base::HEX2 << int(ad&0xff) << " " << Base::HEX2 << int(ad>>8);
- }
- else if (labfound == 4)
- {
- if(mySettings.rflag)
- {
- int tmp = (ad & myAppData.end)+myOffset;
+ nextLine << ",y";
+ nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8);
+ } else if (labelFound == 4) {
+ if (mySettings.rFlag) {
+ int tmp = (ad & myAppData.end) + myOffset;
LABEL_A12_HIGH(tmp);
- nextline << ",Y";
- nextlinebytes << Base::HEX2 << int(tmp&0xff) << " " << Base::HEX2 << int(tmp>>8);
+ nextLine << ",y";
+ nextLineBytes << Base::HEX2 << int(tmp & 0xff) << " " << Base::HEX2 << int(tmp >> 8);
+ } else {
+ nextLine << "$" << Base::HEX4 << ad << ",y";
+ nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8);
}
- else
- {
- nextline << "$" << Base::HEX4 << ad << ",Y";
- nextlinebytes << Base::HEX2 << int(ad&0xff) << " " << Base::HEX2 << int(ad>>8);
- }
- }
- else
- {
+ } else {
LABEL_A12_LOW(ad);
- nextline << ",Y";
- nextlinebytes << Base::HEX2 << int(ad&0xff) << " " << Base::HEX2 << int(ad>>8);
+ nextLine << ",y";
+ nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8);
}
}
break;
@@ -667,57 +423,53 @@ void DiStella::disasm(uInt32 distart, int pass)
case INDIRECT_X:
{
- d1 = Debugger::debugger().peek(myPC+myOffset); myPC++;
- if (pass == 3)
- {
- labfound = mark(d1, 0); // dummy call to get address type
- nextline << " (";
+ d1 = Debugger::debugger().peek(myPC + myOffset); myPC++;
+ if (pass == 3) {
+ labelFound = mark(d1, 0); // dummy call to get address type
+ nextLine << " (";
LABEL_A12_LOW(d1);
- nextline << ",X)";
- nextlinebytes << Base::HEX2 << int(d1);
+ nextLine << ",x)";
+ nextLineBytes << Base::HEX2 << int(d1);
}
break;
}
case INDIRECT_Y:
{
- d1 = Debugger::debugger().peek(myPC+myOffset); myPC++;
- if (pass == 3)
- {
- labfound = mark(d1, 0); // dummy call to get address type
- nextline << " (";
+ d1 = Debugger::debugger().peek(myPC + myOffset); myPC++;
+ if (pass == 3) {
+ labelFound = mark(d1, 0); // dummy call to get address type
+ nextLine << " (";
LABEL_A12_LOW(d1);
- nextline << "),Y";
- nextlinebytes << Base::HEX2 << int(d1);
+ nextLine << "),y";
+ nextLineBytes << Base::HEX2 << int(d1);
}
break;
}
case ZERO_PAGE_X:
{
- d1 = Debugger::debugger().peek(myPC+myOffset); myPC++;
- labfound = mark(d1, CartDebug::REFERENCED);
- if (pass == 3)
- {
- nextline << " ";
+ d1 = Debugger::debugger().peek(myPC + myOffset); myPC++;
+ labelFound = mark(d1, CartDebug::REFERENCED);
+ if (pass == 3) {
+ nextLine << " ";
LABEL_A12_LOW(d1);
- nextline << ",X";
+ nextLine << ",x";
}
- nextlinebytes << Base::HEX2 << int(d1);
+ nextLineBytes << Base::HEX2 << int(d1);
break;
}
case ZERO_PAGE_Y:
{
- d1 = Debugger::debugger().peek(myPC+myOffset); myPC++;
- labfound = mark(d1, CartDebug::REFERENCED);
- if (pass == 3)
- {
- nextline << " ";
+ d1 = Debugger::debugger().peek(myPC + myOffset); myPC++;
+ labelFound = mark(d1, CartDebug::REFERENCED);
+ if (pass == 3) {
+ nextLine << " ";
LABEL_A12_LOW(d1);
- nextline << ",Y";
+ nextLine << ",y";
}
- nextlinebytes << Base::HEX2 << int(d1);
+ nextLineBytes << Base::HEX2 << int(d1);
break;
}
@@ -726,67 +478,51 @@ void DiStella::disasm(uInt32 distart, int pass)
// SA - 04-06-2010: there seemed to be a bug in distella,
// where wraparound occurred on a 32-bit int, and subsequent
// indexing into the labels array caused a crash
- d1 = Debugger::debugger().peek(myPC+myOffset); myPC++;
+ d1 = Debugger::debugger().peek(myPC + myOffset); myPC++;
ad = ((myPC + Int8(d1)) & 0xfff) + myOffset;
- labfound = mark(ad, CartDebug::REFERENCED);
- if (pass == 1)
- {
- if ((addbranch) && !check_bit(ad-myOffset, CartDebug::CODE))
- {
- myAddressQueue.push(ad);
- mark(ad, CartDebug::CODE);
- }
- }
- else if (pass == 3)
- {
- if (labfound == 1)
- {
- nextline << " ";
+ labelFound = mark(ad, CartDebug::REFERENCED);
+ if (pass == 3) {
+ if (labelFound == 1) {
+ nextLine << " ";
LABEL_A12_HIGH(ad);
- }
- else
- nextline << " $" << Base::HEX4 << ad;
+ } else
+ nextLine << " $" << Base::HEX4 << ad;
- nextlinebytes << Base::HEX2 << int(d1);
+ nextLineBytes << Base::HEX2 << int(d1);
}
break;
}
case ABS_INDIRECT:
{
- ad = Debugger::debugger().dpeek(myPC+myOffset); myPC+=2;
- labfound = mark(ad, CartDebug::REFERENCED);
- if (pass == 2 && !check_bit(ad & myAppData.end, CartDebug::CODE))
- {
+ ad = Debugger::debugger().dpeek(myPC + myOffset); myPC += 2;
+ labelFound = mark(ad, CartDebug::REFERENCED);
+ if (pass == 2 && !checkBit(ad & myAppData.end, CartDebug::CODE)) {
// Since we can't know what address is being accessed unless we also
// know the current X value, this is marked as ROW instead of DATA
// The processing is left here, however, in case future versions of
// the code can somehow track access to CPU registers
mark(ad, CartDebug::ROW);
- }
- else if (pass == 3)
- {
- if (ad < 0x100 && mySettings.fflag)
- nextline << ".ind ";
+ } else if (pass == 3) {
+ if (ad < 0x100 && mySettings.fFlag)
+ nextLine << ".ind ";
else
- nextline << " ";
+ nextLine << " ";
}
- if (labfound == 1)
- {
- nextline << "(";
+ if (labelFound == 1) {
+ nextLine << "(";
LABEL_A12_HIGH(ad);
- nextline << ")";
+ nextLine << ")";
}
// TODO - should we consider case 4??
- else
- {
- nextline << "(";
+ else {
+ nextLine << "(";
LABEL_A12_LOW(ad);
- nextline << ")";
+ nextLine << ")";
}
- nextlinebytes << Base::HEX2 << int(ad&0xff) << " " << Base::HEX2 << int(ad>>8);
+ nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8);
break;
}
@@ -794,33 +530,33 @@ void DiStella::disasm(uInt32 distart, int pass)
break;
} // end switch
- if (pass == 1)
- {
- // RTS/JMP/RTI always indicate the end of a block of CODE
- if (!strcmp(ourLookup[op].mnemonic,"RTS") ||
- !strcmp(ourLookup[op].mnemonic,"JMP") ||
- /* !strcmp(ourLookup[op].mnemonic,"BRK") || */
- !strcmp(ourLookup[op].mnemonic,"RTI"))
- {
- myPCEnd = (myPC-1) + myOffset;
- return;
- }
- }
- else if (pass == 3)
- {
+ if (pass == 3) {
+ cycles += int(ourLookup[opcode].cycles);
// A complete line of disassembly (text, cycle count, and bytes)
- myDisasmBuf << nextline.str() << "'"
- << ";" << std::dec << int(ourLookup[op].cycles) << "'"
- << nextlinebytes.str();
+ myDisasmBuf << nextLine.str() << "'"
+ << ";" << std::dec << int(ourLookup[opcode].cycles)
+ << (addrMode == RELATIVE ? (ad & 0xf00) != ((myPC + myOffset) & 0xf00) ? "/3!" : "/3 " : " ");
+ if ((opcode == 0x40 || opcode == 0x60 || opcode == 0x4c || opcode == 0x00 // code block end
+ || checkBit(myPC, CartDebug::REFERENCED) // referenced address
+ || (ourLookup[opcode].rw_mode == WRITE && d1 == WSYNC)) // strobe WSYNC
+ && cycles > 0) {
+ // output cycles for previous code block
+ myDisasmBuf << "'= " << std::setw(3) << std::setfill(' ') << std::dec << cycles;
+ cycles = 0;
+ } else {
+ myDisasmBuf << "' ";
+ }
+ myDisasmBuf << "'" << nextLineBytes.str();
+
addEntry(CartDebug::CODE);
- if (op == 0x40 || op == 0x60)
- {
+ if (opcode == 0x40 || opcode == 0x60 || opcode == 0x4c || opcode == 0x00) {
myDisasmBuf << " ' ' ";
addEntry(CartDebug::NONE);
+ mySegType = CartDebug::NONE; // prevent extra lines if data follows
}
- nextline.str("");
- nextlinebytes.str("");
+ nextLine.str("");
+ nextLineBytes.str("");
}
}
} /* while loop */
@@ -829,6 +565,257 @@ void DiStella::disasm(uInt32 distart, int pass)
myPCEnd = myAppData.end + myOffset;
}
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void DiStella::disasmPass1(CartDebug::AddressList& debuggerAddresses)
+{
+ auto it = debuggerAddresses.cbegin();
+ uInt16 start = *it++;
+
+ // After we've disassembled from all addresses in the address list,
+ // use all access points determined by Stella during emulation
+ int codeAccessPoint = 0;
+
+ // Sometimes we get a circular reference, in that processing a certain
+ // PC address leads us to a sequence of addresses that end up trying
+ // to process the same address again. We detect such consecutive PC
+ // addresses and only process the first one
+ uInt16 lastPC = 0;
+ bool duplicateFound = false;
+
+ while (!myAddressQueue.empty())
+ myAddressQueue.pop();
+ myAddressQueue.push(start);
+
+ while (!(myAddressQueue.empty() || duplicateFound)) {
+ uInt16 pcBeg = myPC = lastPC = myAddressQueue.front();
+ myAddressQueue.pop();
+
+ disasmFromAddress(myPC);
+
+ if (pcBeg <= myPCEnd) {
+ // Tentatively mark all addresses in the range as CODE
+ // Note that this is a 'best-effort' approach, since
+ // Distella will normally keep going until the end of the
+ // range or branch is encountered
+ // However, addresses *specifically* marked as DATA/GFX/PGFX
+ // in the emulation core indicate that the CODE range has finished
+ // Therefore, we stop at the first such address encountered
+ for (uInt32 k = pcBeg; k <= myPCEnd; k++) {
+ if (checkBits(k, CartDebug::CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX,
+ CartDebug::CODE)) {
+ //if (Debugger::debugger().getAccessFlags(k) &
+ // (CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX)) {
+ // TODO: this should never happen, remove when we are sure
+ // TODO: NOT USED: uInt8 flags = Debugger::debugger().getAccessFlags(k);
+ myPCEnd = k - 1;
+ break;
+ }
+ mark(k, CartDebug::CODE);
+ }
+ }
+
+ // When we get to this point, all addresses have been processed
+ // starting from the initial one in the address list
+ // If so, process the next one in the list that hasn't already
+ // been marked as CODE
+ // If it *has* been marked, it can be removed from consideration
+ // in all subsequent passes
+ //
+ // Once the address list has been exhausted, we process all addresses
+ // determined during emulation to represent code, which *haven't* already
+ // been considered
+ //
+ // Note that we can't simply add all addresses right away, since
+ // the processing of a single address can cause others to be added in
+ // the ::disasm method
+ // All of these have to be exhausted before considering a new address
+ while (myAddressQueue.empty() && it != debuggerAddresses.end()) {
+ uInt16 addr = *it;
+
+ if (!checkBit(addr - myOffset, CartDebug::CODE)) {
+ myAddressQueue.push(addr);
+ ++it;
+ } else // remove this address, it is redundant
+ it = debuggerAddresses.erase(it);
+ }
+
+ // Stella itself can provide hints on whether an address has ever
+ // been referenced as CODE
+ while (myAddressQueue.empty() && codeAccessPoint <= myAppData.end) {
+ if ((Debugger::debugger().getAccessFlags(codeAccessPoint + myOffset) & CartDebug::CODE)
+ && !(myLabels[codeAccessPoint & myAppData.end] & CartDebug::CODE)) {
+ myAddressQueue.push(codeAccessPoint + myOffset);
+ ++codeAccessPoint;
+ break;
+ }
+ ++codeAccessPoint;
+ }
+ duplicateFound = !myAddressQueue.empty() && (myAddressQueue.front() == lastPC); // TODO: check!
+ } // while
+
+ for (int k = 0; k <= myAppData.end; k++) {
+ // Let the emulation core know about tentative code
+ if (checkBit(k, CartDebug::CODE) &&
+ !(Debugger::debugger().getAccessFlags(k + myOffset) & CartDebug::CODE)
+ && myOffset != 0) {
+ Debugger::debugger().setAccessFlags(k + myOffset, CartDebug::TCODE);
+ }
+
+ // Must be ROW / unused bytes
+ if (!checkBit(k, CartDebug::CODE | CartDebug::GFX |
+ CartDebug::PGFX | CartDebug::DATA))
+ mark(k + myOffset, CartDebug::ROW);
+ }
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void DiStella::disasmFromAddress(uInt32 distart)
+{
+ uInt8 opcode, d1;
+ uInt16 ad;
+ AddressingMode addrMode;
+
+ myPC = distart - myOffset;
+
+ while (myPC <= myAppData.end) {
+
+ // abort when we reach non-code areas
+ if (checkBits(myPC, CartDebug::CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX, CartDebug::CODE)) {
+ myPCEnd = (myPC - 1) + myOffset;
+ return;
+ }
+
+ // so this should be code now...
+ // get opcode
+ opcode = Debugger::debugger().peek(myPC + myOffset); myPC++;
+ // get address mode for opcode
+ addrMode = ourLookup[opcode].addr_mode;
+
+ // Add operand(s) for PC values outside the app data range
+ if (myPC >= myAppData.end) {
+ switch (addrMode) {
+ case ABSOLUTE:
+ case ABSOLUTE_X:
+ case ABSOLUTE_Y:
+ case INDIRECT_X:
+ case INDIRECT_Y:
+ case ABS_INDIRECT:
+ myPCEnd = myAppData.end + myOffset;
+ return;
+
+ case ZERO_PAGE:
+ case IMMEDIATE:
+ case ZERO_PAGE_X:
+ case ZERO_PAGE_Y:
+ case RELATIVE:
+ if (myPC > myAppData.end) {
+ myPC++;
+ myPCEnd = myAppData.end + myOffset;
+ return;
+ }
+
+ default:
+ break;
+ } // end switch(addr_mode)
+ } // end if (myPC >= myAppData.end)
+
+ // Add operand(s)
+ switch (addrMode) {
+ case ABSOLUTE:
+ ad = Debugger::debugger().dpeek(myPC + myOffset); myPC += 2;
+ mark(ad, CartDebug::REFERENCED);
+ // handle JMP/JSR
+ if (ourLookup[opcode].source == M_ADDR) {
+ // do NOT use flags set by debugger, else known CODE will not analyzed statically.
+ if (!checkBit(ad & myAppData.end, CartDebug::CODE, false)) {
+ if (ad > 0xfff)
+ myAddressQueue.push((ad & myAppData.end) + myOffset);
+ mark(ad, CartDebug::CODE);
+ }
+ } else
+ mark(ad, CartDebug::DATA);
+ break;
+
+ case ZERO_PAGE:
+ d1 = Debugger::debugger().peek(myPC + myOffset); myPC++;
+ mark(d1, CartDebug::REFERENCED);
+ break;
+
+ case IMMEDIATE:
+ myPC++;
+ break;
+
+ case ABSOLUTE_X:
+ ad = Debugger::debugger().dpeek(myPC + myOffset); myPC += 2;
+ mark(ad, CartDebug::REFERENCED);
+ break;
+
+ case ABSOLUTE_Y:
+ ad = Debugger::debugger().dpeek(myPC + myOffset); myPC += 2;
+ mark(ad, CartDebug::REFERENCED);
+ break;
+
+ case INDIRECT_X:
+ myPC++;
+ break;
+
+ case INDIRECT_Y:
+ myPC++;
+ break;
+
+ case ZERO_PAGE_X:
+ d1 = Debugger::debugger().peek(myPC + myOffset); myPC++;
+ mark(d1, CartDebug::REFERENCED);
+ break;
+
+ case ZERO_PAGE_Y:
+ d1 = Debugger::debugger().peek(myPC + myOffset); myPC++;
+ mark(d1, CartDebug::REFERENCED);
+ break;
+
+ case RELATIVE:
+ // SA - 04-06-2010: there seemed to be a bug in distella,
+ // where wraparound occurred on a 32-bit int, and subsequent
+ // indexing into the labels array caused a crash
+ d1 = Debugger::debugger().peek(myPC + myOffset); myPC++;
+ ad = ((myPC + Int8(d1)) & 0xfff) + myOffset;
+ mark(ad, CartDebug::REFERENCED);
+ // do NOT use flags set by debugger, else known CODE will not analyzed statically.
+ if (!checkBit(ad - myOffset, CartDebug::CODE, false)) {
+ myAddressQueue.push(ad);
+ mark(ad, CartDebug::CODE);
+ }
+ break;
+
+ case ABS_INDIRECT:
+ ad = Debugger::debugger().dpeek(myPC + myOffset); myPC += 2;
+ mark(ad, CartDebug::REFERENCED);
+ break;
+
+ default:
+ break;
+ } // end switch
+
+ // mark BRK vector
+ if (opcode == 0x00) {
+ ad = Debugger::debugger().dpeek(0xfffe, CartDebug::DATA);
+ if (!myReserved.breakFound) {
+ myAddressQueue.push(ad);
+ mark(ad, CartDebug::CODE);
+ myReserved.breakFound = true;
+ }
+ }
+
+ // JMP/RTS/RTI always indicate the end of a block of CODE
+ if (opcode == 0x4c || opcode == 0x60 || opcode == 0x40) {
+ // code block end
+ myPCEnd = (myPC - 1) + myOffset;
+ return;
+ }
+ } // while
+}
+
+
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int DiStella::mark(uInt32 address, uInt8 mask, bool directive)
{
@@ -882,77 +869,68 @@ int DiStella::mark(uInt32 address, uInt8 mask, bool directive)
// Check for equates before ROM/ZP-RAM accesses, because the original logic
// of Distella assumed either equates or ROM; it didn't take ZP-RAM into account
CartDebug::AddrType type = myDbg.addressType(address);
- if (type == CartDebug::ADDR_TIA)
- {
+ if (type == CartDebug::ADDR_TIA) {
return 2;
- }
- else if (type == CartDebug::ADDR_IO)
- {
+ } else if (type == CartDebug::ADDR_IO) {
return 3;
- }
- else if (type == CartDebug::ADDR_ZPRAM && myOffset != 0)
- {
+ } else if (type == CartDebug::ADDR_ZPRAM && myOffset != 0) {
return 5;
- }
- else if (address >= myOffset && address <= myAppData.end + myOffset)
- {
- myLabels[address-myOffset] = myLabels[address-myOffset] | mask;
- if(directive) myDirectives[address-myOffset] = mask;
+ } else if (address >= myOffset && address <= myAppData.end + myOffset) {
+ myLabels[address - myOffset] = myLabels[address - myOffset] | mask;
+ if (directive) myDirectives[address - myOffset] = mask;
return 1;
- }
- else if (address > 0x1000 && myOffset != 0) // Exclude zero-page accesses
+ } else if (address > 0x1000 && myOffset != 0) // Exclude zero-page accesses
{
/* 2K & 4K case */
myLabels[address & myAppData.end] = myLabels[address & myAppData.end] | mask;
- if(directive) myDirectives[address & myAppData.end] = mask;
+ if (directive) myDirectives[address & myAppData.end] = mask;
return 4;
- }
- else
+ } else
return 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool DiStella::check_bit(uInt16 address, uInt8 mask) const
+bool DiStella::checkBit(uInt16 address, uInt8 mask, bool useDebugger) const
{
// The REFERENCED and VALID_ENTRY flags are needed for any inspection of
// an address
// Since they're set only in the labels array (as the lower two bits),
// they must be included in the other bitfields
- uInt8 label = myLabels[address & myAppData.end],
- lastbits = label & 0x03,
- directive = myDirectives[address & myAppData.end] & 0xFC,
- debugger = Debugger::debugger().getAccessFlags(address | myOffset) & 0xFC;
+ uInt8 label = myLabels[address & myAppData.end],
+ lastbits = label & 0x03,
+ directive = myDirectives[address & myAppData.end] & 0xFC,
+ debugger = Debugger::debugger().getAccessFlags(address | myOffset) & 0xFC;
// Any address marked by a manual directive always takes priority
- if(directive)
+ if (directive)
return (directive | lastbits) & mask;
- // Next, the results from a dynamic/runtime analysis are used
- else if((debugger | lastbits) & mask)
+ // Next, the results from a dynamic/runtime analysis are used (except for pass 1)
+ else if (useDebugger && ((debugger | lastbits) & mask))
return true;
// Otherwise, default to static analysis from Distella
else
return label & mask;
}
+bool DiStella::checkBits(uInt16 address, uInt8 mask, uInt8 notMask, bool useDebugger) const
+{
+ return checkBit(address, mask, useDebugger) && !checkBit(address, notMask, useDebugger);
+}
+
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool DiStella::check_range(uInt16 beg, uInt16 end) const
{
- if(beg > end)
- {
+ if (beg > end) {
cerr << "Beginning of range greater than end: start = " << std::hex << beg
- << ", end = " << std::hex << end << endl;
+ << ", end = " << std::hex << end << endl;
return false;
- }
- else if(beg > myAppData.end + myOffset)
- {
+ } else if (beg > myAppData.end + myOffset) {
cerr << "Beginning of range out of range: start = " << std::hex << beg
- << ", range = " << std::hex << (myAppData.end + myOffset) << endl;
+ << ", range = " << std::hex << (myAppData.end + myOffset) << endl;
return false;
- }
- else if(beg < myOffset)
- {
+ } else if (beg < myOffset) {
cerr << "Beginning of range out of range: start = " << std::hex << beg
- << ", offset = " << std::hex << myOffset << endl;
+ << ", offset = " << std::hex << myOffset << endl;
return false;
}
return true;
@@ -968,27 +946,24 @@ void DiStella::addEntry(CartDebug::DisasmType type)
// Address
myDisasmBuf.seekg(0, std::ios::beg);
- if(myDisasmBuf.peek() == ' ')
+ if (myDisasmBuf.peek() == ' ')
tag.address = 0;
else
myDisasmBuf >> std::setw(4) >> std::hex >> tag.address;
// Only include addresses within the requested range
- if(tag.address < myAppData.start)
+ if (tag.address < myAppData.start)
goto DONE_WITH_ADD;
// Label (a user-defined label always overrides any auto-generated one)
myDisasmBuf.seekg(5, std::ios::beg);
- if(tag.address)
- {
+ if (tag.address) {
tag.label = myDbg.getLabel(tag.address, true);
tag.hllabel = true;
- if(tag.label == EmptyString)
- {
- if(myDisasmBuf.peek() != ' ')
+ if (tag.label == EmptyString) {
+ if (myDisasmBuf.peek() != ' ')
getline(myDisasmBuf, tag.label, '\'');
- else if(mySettings.show_addresses && tag.type == CartDebug::CODE)
- {
+ else if (mySettings.showAddresses && tag.type == CartDebug::CODE) {
// Have addresses indented, to differentiate from actual labels
tag.label = " " + Base::toString(tag.address, Base::F_16_4);
tag.hllabel = false;
@@ -1000,11 +975,11 @@ void DiStella::addEntry(CartDebug::DisasmType type)
// Up to this point the field sizes are fixed, until we get to
// variable length labels, cycle counts, etc
myDisasmBuf.seekg(11, std::ios::beg);
- switch(tag.type)
- {
+ switch (tag.type) {
case CartDebug::CODE:
getline(myDisasmBuf, tag.disasm, '\'');
getline(myDisasmBuf, tag.ccount, '\'');
+ getline(myDisasmBuf, tag.ctotal, '\'');
getline(myDisasmBuf, tag.bytes);
// Make note of when we override CODE sections from the debugger
@@ -1012,9 +987,8 @@ void DiStella::addEntry(CartDebug::DisasmType type)
// but it could also indicate that code will *never* be accessed
// Since it is impossible to tell the difference, marking the address
// in the disassembly at least tells the user about it
- if(!(Debugger::debugger().getAccessFlags(tag.address) & CartDebug::CODE)
- && myOffset != 0)
- {
+ if (!(Debugger::debugger().getAccessFlags(tag.address) & CartDebug::CODE)
+ && myOffset != 0) {
tag.ccount += " *";
Debugger::debugger().setAccessFlags(tag.address, CartDebug::TCODE);
}
@@ -1031,6 +1005,7 @@ void DiStella::addEntry(CartDebug::DisasmType type)
case CartDebug::ROW:
getline(myDisasmBuf, tag.disasm);
break;
+ case CartDebug::NONE:
default: // should never happen
tag.disasm = " ";
break;
@@ -1042,353 +1017,436 @@ DONE_WITH_ADD:
myDisasmBuf.str("");
}
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void DiStella::outputGraphics()
+{
+ bool isPGfx = checkBit(myPC, CartDebug::PGFX);
+ const string& bitString = isPGfx ? "\x1f" : "\x1e";
+ uInt8 byte = Debugger::debugger().peek(myPC + myOffset);
+
+ // add extra spacing line when switching from non-graphics to graphics
+ if (mySegType != CartDebug::GFX && mySegType != CartDebug::NONE) {
+ myDisasmBuf << " ' ' ";
+ addEntry(CartDebug::NONE);
+ }
+ mySegType = CartDebug::GFX;
+
+ if (checkBit(myPC, CartDebug::REFERENCED))
+ myDisasmBuf << Base::HEX4 << myPC + myOffset << "'L" << Base::HEX4 << myPC + myOffset << "'";
+ else
+ myDisasmBuf << Base::HEX4 << myPC + myOffset << "' '";
+ myDisasmBuf << ".byte $" << Base::HEX2 << int(byte) << " |";
+ for (uInt8 i = 0, c = byte; i < 8; ++i, c <<= 1)
+ myDisasmBuf << ((c > 127) ? bitString : " ");
+ myDisasmBuf << "| $" << Base::HEX4 << myPC + myOffset << "'";
+ if (mySettings.gfxFormat == Base::F_2)
+ myDisasmBuf << Base::toString(byte, Base::F_2_8);
+ else
+ myDisasmBuf << Base::HEX2 << int(byte);
+
+ addEntry(isPGfx ? CartDebug::PGFX : CartDebug::GFX);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void DiStella::outputBytes(CartDebug::DisasmType type)
+{
+ bool isType = true;
+ bool referenced = checkBit(myPC, CartDebug::REFERENCED);
+ bool lineEmpty = true;
+ int numBytes = 0;
+
+ // add extra spacing line when switching from non-data to data
+ if (mySegType != CartDebug::DATA && mySegType != CartDebug::NONE) {
+ myDisasmBuf << " ' ' ";
+ addEntry(CartDebug::NONE);
+ }
+ mySegType = CartDebug::DATA;
+
+ while (isType && myPC <= myAppData.end) {
+ if (referenced) {
+ // start a new line with a label
+ if (!lineEmpty)
+ addEntry(type);
+
+ myDisasmBuf << Base::HEX4 << myPC + myOffset << "'L" << Base::HEX4
+ << myPC + myOffset << "'.byte " << "$" << Base::HEX2
+ << int(Debugger::debugger().peek(myPC + myOffset));
+ myPC++;
+ numBytes = 1;
+ lineEmpty = false;
+ } else if (lineEmpty) {
+ // start a new line without a label
+ myDisasmBuf << Base::HEX4 << myPC + myOffset << "' '"
+ << ".byte $" << Base::HEX2 << int(Debugger::debugger().peek(myPC + myOffset));
+ myPC++;
+ numBytes = 1;
+ lineEmpty = false;
+ }
+ // Otherwise, append bytes to the current line, up until the maximum
+ else if (++numBytes == mySettings.bytesWidth) {
+ addEntry(type);
+ lineEmpty = true;
+ } else {
+ myDisasmBuf << ",$" << Base::HEX2 << int(Debugger::debugger().peek(myPC + myOffset));
+ myPC++;
+ }
+ isType = checkBits(myPC, type,
+ CartDebug::CODE | (type != CartDebug::DATA ? CartDebug::DATA : 0) | CartDebug::GFX | CartDebug::PGFX);
+ referenced = checkBit(myPC, CartDebug::REFERENCED);
+ }
+ if (!lineEmpty)
+ addEntry(type);
+ /*myDisasmBuf << " ' ' ";
+ addEntry(CartDebug::NONE);*/
+}
+
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DiStella::processDirectives(const CartDebug::DirectiveList& directives)
{
- for(const auto& tag: directives)
- {
- if(check_range(tag.start, tag.end))
- for(uInt32 k = tag.start; k <= tag.end; ++k)
+ for (const auto& tag : directives) {
+ if (check_range(tag.start, tag.end))
+ for (uInt32 k = tag.start; k <= tag.end; ++k)
mark(k, tag.type, true);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DiStella::Settings DiStella::settings = {
- Base::F_2, // gfx_format
- true, // resolve_code (opposite of -d in Distella)
- true, // show_addresses (not used externally; always off)
- false, // aflag (-a in Distella)
- true, // fflag (-f in Distella)
- false, // rflag (-r in Distella)
- 9 // number of bytes to use with .byte directive
+ Base::F_2, // gfxFormat
+ true, // resolveCode (opposite of -d in Distella)
+ true, // showAddresses (not used externally; always off)
+ false, // aFlag (-a in Distella)
+ true, // fFlag (-f in Distella)
+ false, // rFlag (-r in Distella)
+ false, // bFlag (-b in Distella)
+ 8+1 // number of bytes to use with .byte directive
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const DiStella::Instruction_tag DiStella::ourLookup[256] = {
-/**** Positive ****/
+ /**** Positive ****/
- /* 00 */ { "BRK", IMPLIED, M_NONE, NONE, 7 }, /* Pseudo Absolute */
- /* 01 */ { "ORA", INDIRECT_X, M_INDX, READ, 6 }, /* (Indirect,X) */
- /* 02 */ { ".jam",IMPLIED, M_NONE, NONE, 0 }, /* TILT */
- /* 03 */ { "slo", INDIRECT_X, M_INDX, WRITE, 8 },
+ /* 00 */{"brk", IMPLIED, M_NONE, NONE, 7, 1}, /* Pseudo Absolute */
+ /* 01 */{"ora", INDIRECT_X, M_INDX, READ, 6, 2}, /* (Indirect,X) */
+ /* 02 */{".JAM",IMPLIED, M_NONE, NONE, 0, 1}, /* TILT */
+ /* 03 */{"SLO", INDIRECT_X, M_INDX, WRITE, 8, 2},
- /* 04 */ { "nop", ZERO_PAGE, M_NONE, NONE, 3 },
- /* 05 */ { "ORA", ZERO_PAGE, M_ZERO, READ, 3 }, /* Zeropage */
- /* 06 */ { "ASL", ZERO_PAGE, M_ZERO, WRITE, 5 }, /* Zeropage */
- /* 07 */ { "slo", ZERO_PAGE, M_ZERO, WRITE, 5 },
+ /* 04 */{"NOP", ZERO_PAGE, M_NONE, NONE, 3, 2},
+ /* 05 */{"ora", ZERO_PAGE, M_ZERO, READ, 3, 2}, /* Zeropage */
+ /* 06 */{"asl", ZERO_PAGE, M_ZERO, WRITE, 5, 2}, /* Zeropage */
+ /* 07 */{"SLO", ZERO_PAGE, M_ZERO, WRITE, 5, 2},
- /* 08 */ { "PHP", IMPLIED, M_SR, NONE, 3 },
- /* 09 */ { "ORA", IMMEDIATE, M_IMM, READ, 2 }, /* Immediate */
- /* 0a */ { "ASL", ACCUMULATOR, M_AC, WRITE, 2 }, /* Accumulator */
- /* 0b */ { "anc", IMMEDIATE, M_ACIM, READ, 2 },
+ /* 08 */{"php", IMPLIED, M_SR, NONE, 3, 1},
+ /* 09 */{"ora", IMMEDIATE, M_IMM, READ, 2, 2}, /* Immediate */
+ /* 0a */{"asl", ACCUMULATOR, M_AC, WRITE, 2, 1}, /* Accumulator */
+ /* 0b */{"ANC", IMMEDIATE, M_ACIM, READ, 2, 2},
- /* 0c */ { "nop", ABSOLUTE, M_NONE, NONE, 4 },
- /* 0d */ { "ORA", ABSOLUTE, M_ABS, READ, 4 }, /* Absolute */
- /* 0e */ { "ASL", ABSOLUTE, M_ABS, WRITE, 6 }, /* Absolute */
- /* 0f */ { "slo", ABSOLUTE, M_ABS, WRITE, 6 },
+ /* 0c */{"NOP", ABSOLUTE, M_NONE, NONE, 4, 3},
+ /* 0d */{"ora", ABSOLUTE, M_ABS, READ, 4, 3}, /* Absolute */
+ /* 0e */{"asl", ABSOLUTE, M_ABS, WRITE, 6, 3}, /* Absolute */
+ /* 0f */{"SLO", ABSOLUTE, M_ABS, WRITE, 6, 3},
- /* 10 */ { "BPL", RELATIVE, M_REL, READ, 2 },
- /* 11 */ { "ORA", INDIRECT_Y, M_INDY, READ, 5 }, /* (Indirect),Y */
- /* 12 */ { ".jam",IMPLIED, M_NONE, NONE, 0 }, /* TILT */
- /* 13 */ { "slo", INDIRECT_Y, M_INDY, WRITE, 8 },
+ /* 10 */{"bpl", RELATIVE, M_REL, READ, 2, 2},
+ /* 11 */{"ora", INDIRECT_Y, M_INDY, READ, 5, 2}, /* (Indirect),Y */
+ /* 12 */{".JAM",IMPLIED, M_NONE, NONE, 0, 1}, /* TILT */
+ /* 13 */{"SLO", INDIRECT_Y, M_INDY, WRITE, 8, 2},
- /* 14 */ { "nop", ZERO_PAGE_X, M_NONE, NONE, 4 },
- /* 15 */ { "ORA", ZERO_PAGE_X, M_ZERX, READ, 4 }, /* Zeropage,X */
- /* 16 */ { "ASL", ZERO_PAGE_X, M_ZERX, WRITE, 6 }, /* Zeropage,X */
- /* 17 */ { "slo", ZERO_PAGE_X, M_ZERX, WRITE, 6 },
+ /* 14 */{"NOP", ZERO_PAGE_X, M_NONE, NONE, 4, 2},
+ /* 15 */{"ora", ZERO_PAGE_X, M_ZERX, READ, 4, 2}, /* Zeropage,X */
+ /* 16 */{"asl", ZERO_PAGE_X, M_ZERX, WRITE, 6, 2}, /* Zeropage,X */
+ /* 17 */{"SLO", ZERO_PAGE_X, M_ZERX, WRITE, 6, 2},
- /* 18 */ { "CLC", IMPLIED, M_NONE, NONE, 2 },
- /* 19 */ { "ORA", ABSOLUTE_Y, M_ABSY, READ, 4 }, /* Absolute,Y */
- /* 1a */ { ".nop",IMPLIED, M_NONE, NONE, 2 },
- /* 1b */ { "slo", ABSOLUTE_Y, M_ABSY, WRITE, 7 },
+ /* 18 */{"clc", IMPLIED, M_NONE, NONE, 2, 1},
+ /* 19 */{"ora", ABSOLUTE_Y, M_ABSY, READ, 4, 3}, /* Absolute,Y */
+ /* 1a */{"NOP", IMPLIED, M_NONE, NONE, 2, 1},
+ /* 1b */{"SLO", ABSOLUTE_Y, M_ABSY, WRITE, 7, 3},
- /* 1c */ { "nop", ABSOLUTE_X, M_NONE, NONE, 4 },
- /* 1d */ { "ORA", ABSOLUTE_X, M_ABSX, READ, 4 }, /* Absolute,X */
- /* 1e */ { "ASL", ABSOLUTE_X, M_ABSX, WRITE, 7 }, /* Absolute,X */
- /* 1f */ { "slo", ABSOLUTE_X, M_ABSX, WRITE, 7 },
+ /* 1c */{"NOP", ABSOLUTE_X, M_NONE, NONE, 4, 3},
+ /* 1d */{"ora", ABSOLUTE_X, M_ABSX, READ, 4, 3}, /* Absolute,X */
+ /* 1e */{"asl", ABSOLUTE_X, M_ABSX, WRITE, 7, 3}, /* Absolute,X */
+ /* 1f */{"SLO", ABSOLUTE_X, M_ABSX, WRITE, 7, 3},
- /* 20 */ { "JSR", ABSOLUTE, M_ADDR, READ, 6 },
- /* 21 */ { "AND", INDIRECT_X, M_INDX, READ, 6 }, /* (Indirect ,X) */
- /* 22 */ { ".jam",IMPLIED, M_NONE, NONE, 0 }, /* TILT */
- /* 23 */ { "rla", INDIRECT_X, M_INDX, WRITE, 8 },
+ /* 20 */{"jsr", ABSOLUTE, M_ADDR, READ, 6, 3},
+ /* 21 */{"and", INDIRECT_X, M_INDX, READ, 6, 2}, /* (Indirect ,X) */
+ /* 22 */{".JAM",IMPLIED, M_NONE, NONE, 0, 1}, /* TILT */
+ /* 23 */{"RLA", INDIRECT_X, M_INDX, WRITE, 8, 2},
- /* 24 */ { "BIT", ZERO_PAGE, M_ZERO, READ, 3 }, /* Zeropage */
- /* 25 */ { "AND", ZERO_PAGE, M_ZERO, READ, 3 }, /* Zeropage */
- /* 26 */ { "ROL", ZERO_PAGE, M_ZERO, WRITE, 5 }, /* Zeropage */
- /* 27 */ { "rla", ZERO_PAGE, M_ZERO, WRITE, 5 },
+ /* 24 */{"bit", ZERO_PAGE, M_ZERO, READ, 3, 2}, /* Zeropage */
+ /* 25 */{"and", ZERO_PAGE, M_ZERO, READ, 3, 2}, /* Zeropage */
+ /* 26 */{"rol", ZERO_PAGE, M_ZERO, WRITE, 5, 2}, /* Zeropage */
+ /* 27 */{"RLA", ZERO_PAGE, M_ZERO, WRITE, 5, 2},
- /* 28 */ { "PLP", IMPLIED, M_NONE, NONE, 4 },
- /* 29 */ { "AND", IMMEDIATE, M_IMM, READ, 2 }, /* Immediate */
- /* 2a */ { "ROL", ACCUMULATOR, M_AC, WRITE, 2 }, /* Accumulator */
- /* 2b */ { ".anc",IMMEDIATE, M_ACIM, READ, 2 },
+ /* 28 */{"plp", IMPLIED, M_NONE, NONE, 4, 1},
+ /* 29 */{"and", IMMEDIATE, M_IMM, READ, 2, 2}, /* Immediate */
+ /* 2a */{"rol", ACCUMULATOR, M_AC, WRITE, 2, 1}, /* Accumulator */
+ /* 2b */{"ANC", IMMEDIATE, M_ACIM, READ, 2, 2},
- /* 2c */ { "BIT", ABSOLUTE, M_ABS, READ, 4 }, /* Absolute */
- /* 2d */ { "AND", ABSOLUTE, M_ABS, READ, 4 }, /* Absolute */
- /* 2e */ { "ROL", ABSOLUTE, M_ABS, WRITE, 6 }, /* Absolute */
- /* 2f */ { "rla", ABSOLUTE, M_ABS, WRITE, 6 },
+ /* 2c */{"bit", ABSOLUTE, M_ABS, READ, 4, 3}, /* Absolute */
+ /* 2d */{"and", ABSOLUTE, M_ABS, READ, 4, 3}, /* Absolute */
+ /* 2e */{"rol", ABSOLUTE, M_ABS, WRITE, 6, 3}, /* Absolute */
+ /* 2f */{"RLA", ABSOLUTE, M_ABS, WRITE, 6, 3},
- /* 30 */ { "BMI", RELATIVE, M_REL, READ, 2 },
- /* 31 */ { "AND", INDIRECT_Y, M_INDY, READ, 5 }, /* (Indirect),Y */
- /* 32 */ { ".jam",IMPLIED, M_NONE, NONE, 0 }, /* TILT */
- /* 33 */ { "rla", INDIRECT_Y, M_INDY, WRITE, 8 },
+ /* 30 */{"bmi", RELATIVE, M_REL, READ, 2, 2},
+ /* 31 */{"and", INDIRECT_Y, M_INDY, READ, 5, 2}, /* (Indirect),Y */
+ /* 32 */{".JAM",IMPLIED, M_NONE, NONE, 0, 1}, /* TILT */
+ /* 33 */{"RLA", INDIRECT_Y, M_INDY, WRITE, 8, 2},
- /* 34 */ { ".nop",ZERO_PAGE_X, M_NONE, NONE, 4 },
- /* 35 */ { "AND", ZERO_PAGE_X, M_ZERX, READ, 4 }, /* Zeropage,X */
- /* 36 */ { "ROL", ZERO_PAGE_X, M_ZERX, WRITE, 6 }, /* Zeropage,X */
- /* 37 */ { "rla", ZERO_PAGE_X, M_ZERX, WRITE, 6 },
+ /* 34 */{"NOP", ZERO_PAGE_X, M_NONE, NONE, 4, 2},
+ /* 35 */{"and", ZERO_PAGE_X, M_ZERX, READ, 4, 2}, /* Zeropage,X */
+ /* 36 */{"rol", ZERO_PAGE_X, M_ZERX, WRITE, 6, 2}, /* Zeropage,X */
+ /* 37 */{"RLA", ZERO_PAGE_X, M_ZERX, WRITE, 6, 2},
- /* 38 */ { "SEC", IMPLIED, M_NONE, NONE, 2 },
- /* 39 */ { "AND", ABSOLUTE_Y, M_ABSY, READ, 4 }, /* Absolute,Y */
- /* 3a */ { ".nop",IMPLIED, M_NONE, NONE, 2 },
- /* 3b */ { "rla", ABSOLUTE_Y, M_ABSY, WRITE, 7 },
+ /* 38 */{"sec", IMPLIED, M_NONE, NONE, 2, 1},
+ /* 39 */{"and", ABSOLUTE_Y, M_ABSY, READ, 4, 3}, /* Absolute,Y */
+ /* 3a */{"NOP", IMPLIED, M_NONE, NONE, 2, 1},
+ /* 3b */{"RLA", ABSOLUTE_Y, M_ABSY, WRITE, 7, 3},
- /* 3c */ { ".nop",ABSOLUTE_X, M_NONE, NONE, 4 },
- /* 3d */ { "AND", ABSOLUTE_X, M_ABSX, READ, 4 }, /* Absolute,X */
- /* 3e */ { "ROL", ABSOLUTE_X, M_ABSX, WRITE, 7 }, /* Absolute,X */
- /* 3f */ { "rla", ABSOLUTE_X, M_ABSX, WRITE, 7 },
+ /* 3c */{"NOP", ABSOLUTE_X, M_NONE, NONE, 4, 3},
+ /* 3d */{"and", ABSOLUTE_X, M_ABSX, READ, 4, 3}, /* Absolute,X */
+ /* 3e */{"rol", ABSOLUTE_X, M_ABSX, WRITE, 7, 3}, /* Absolute,X */
+ /* 3f */{"RLA", ABSOLUTE_X, M_ABSX, WRITE, 7, 3},
- /* 40 */ { "RTI", IMPLIED, M_NONE, NONE, 6 },
- /* 41 */ { "EOR", INDIRECT_X, M_INDX, READ, 6 }, /* (Indirect,X) */
- /* 42 */ { ".jam",IMPLIED, M_NONE, NONE, 0 }, /* TILT */
- /* 43 */ { "sre", INDIRECT_X, M_INDX, WRITE, 8 },
+ /* 40 */{"rti", IMPLIED, M_NONE, NONE, 6, 1},
+ /* 41 */{"eor", INDIRECT_X, M_INDX, READ, 6, 2}, /* (Indirect,X) */
+ /* 42 */{".JAM",IMPLIED, M_NONE, NONE, 0, 1}, /* TILT */
+ /* 43 */{"SRE", INDIRECT_X, M_INDX, WRITE, 8, 2},
- /* 44 */ { ".nop",ZERO_PAGE, M_NONE, NONE, 3 },
- /* 45 */ { "EOR", ZERO_PAGE, M_ZERO, READ, 3 }, /* Zeropage */
- /* 46 */ { "LSR", ZERO_PAGE, M_ZERO, WRITE, 5 }, /* Zeropage */
- /* 47 */ { "sre", ZERO_PAGE, M_ZERO, WRITE, 5 },
+ /* 44 */{"NOP", ZERO_PAGE, M_NONE, NONE, 3, 2},
+ /* 45 */{"eor", ZERO_PAGE, M_ZERO, READ, 3, 2}, /* Zeropage */
+ /* 46 */{"lsr", ZERO_PAGE, M_ZERO, WRITE, 5, 2}, /* Zeropage */
+ /* 47 */{"SRE", ZERO_PAGE, M_ZERO, WRITE, 5, 2},
- /* 48 */ { "PHA", IMPLIED, M_AC, NONE, 3 },
- /* 49 */ { "EOR", IMMEDIATE, M_IMM, READ, 2 }, /* Immediate */
- /* 4a */ { "LSR", ACCUMULATOR, M_AC, WRITE, 2 }, /* Accumulator */
- /* 4b */ { "asr", IMMEDIATE, M_ACIM, READ, 2 }, /* (AC & IMM) >>1 */
+ /* 48 */{"pha", IMPLIED, M_AC, NONE, 3, 1},
+ /* 49 */{"eor", IMMEDIATE, M_IMM, READ, 2, 2}, /* Immediate */
+ /* 4a */{"lsr", ACCUMULATOR, M_AC, WRITE, 2, 1}, /* Accumulator */
+ /* 4b */{"ASR", IMMEDIATE, M_ACIM, READ, 2, 2}, /* (AC & IMM) >>1 */
- /* 4c */ { "JMP", ABSOLUTE, M_ADDR, READ, 3 }, /* Absolute */
- /* 4d */ { "EOR", ABSOLUTE, M_ABS, READ, 4 }, /* Absolute */
- /* 4e */ { "LSR", ABSOLUTE, M_ABS, WRITE, 6 }, /* Absolute */
- /* 4f */ { "sre", ABSOLUTE, M_ABS, WRITE, 6 },
+ /* 4c */{"jmp", ABSOLUTE, M_ADDR, READ, 3, 3}, /* Absolute */
+ /* 4d */{"eor", ABSOLUTE, M_ABS, READ, 4, 3}, /* Absolute */
+ /* 4e */{"lsr", ABSOLUTE, M_ABS, WRITE, 6, 3}, /* Absolute */
+ /* 4f */{"SRE", ABSOLUTE, M_ABS, WRITE, 6, 3},
- /* 50 */ { "BVC", RELATIVE, M_REL, READ, 2 },
- /* 51 */ { "EOR", INDIRECT_Y, M_INDY, READ, 5 }, /* (Indirect),Y */
- /* 52 */ { ".jam",IMPLIED, M_NONE, NONE, 0 }, /* TILT */
- /* 53 */ { "sre", INDIRECT_Y, M_INDY, WRITE, 8 },
+ /* 50 */{"bvc", RELATIVE, M_REL, READ, 2, 2},
+ /* 51 */{"eor", INDIRECT_Y, M_INDY, READ, 5, 2}, /* (Indirect),Y */
+ /* 52 */{".JAM",IMPLIED, M_NONE, NONE, 0, 1}, /* TILT */
+ /* 53 */{"SRE", INDIRECT_Y, M_INDY, WRITE, 8, 2},
- /* 54 */ { ".nop",ZERO_PAGE_X, M_NONE, NONE, 4 },
- /* 55 */ { "EOR", ZERO_PAGE_X, M_ZERX, READ, 4 }, /* Zeropage,X */
- /* 56 */ { "LSR", ZERO_PAGE_X, M_ZERX, WRITE, 6 }, /* Zeropage,X */
- /* 57 */ { "sre", ZERO_PAGE_X, M_ZERX, WRITE, 6 },
+ /* 54 */{"NOP", ZERO_PAGE_X, M_NONE, NONE, 4, 2},
+ /* 55 */{"eor", ZERO_PAGE_X, M_ZERX, READ, 4, 2}, /* Zeropage,X */
+ /* 56 */{"lsr", ZERO_PAGE_X, M_ZERX, WRITE, 6, 2}, /* Zeropage,X */
+ /* 57 */{"SRE", ZERO_PAGE_X, M_ZERX, WRITE, 6, 2},
- /* 58 */ { "CLI", IMPLIED, M_NONE, NONE, 2 },
- /* 59 */ { "EOR", ABSOLUTE_Y, M_ABSY, READ, 4 }, /* Absolute,Y */
- /* 5a */ { ".nop",IMPLIED, M_NONE, NONE, 2 },
- /* 5b */ { "sre", ABSOLUTE_Y, M_ABSY, WRITE, 7 },
+ /* 58 */{"cli", IMPLIED, M_NONE, NONE, 2, 1},
+ /* 59 */{"eor", ABSOLUTE_Y, M_ABSY, READ, 4, 3}, /* Absolute,Y */
+ /* 5a */{"NOP", IMPLIED, M_NONE, NONE, 2, 1},
+ /* 5b */{"SRE", ABSOLUTE_Y, M_ABSY, WRITE, 7, 3},
- /* 5c */ { ".nop",ABSOLUTE_X, M_NONE, NONE, 4 },
- /* 5d */ { "EOR", ABSOLUTE_X, M_ABSX, READ, 4 }, /* Absolute,X */
- /* 5e */ { "LSR", ABSOLUTE_X, M_ABSX, WRITE, 7 }, /* Absolute,X */
- /* 5f */ { "sre", ABSOLUTE_X, M_ABSX, WRITE, 7 },
+ /* 5c */{"NOP", ABSOLUTE_X, M_NONE, NONE, 4, 3},
+ /* 5d */{"eor", ABSOLUTE_X, M_ABSX, READ, 4, 3}, /* Absolute,X */
+ /* 5e */{"lsr", ABSOLUTE_X, M_ABSX, WRITE, 7, 3}, /* Absolute,X */
+ /* 5f */{"SRE", ABSOLUTE_X, M_ABSX, WRITE, 7, 3},
- /* 60 */ { "RTS", IMPLIED, M_NONE, NONE, 6 },
- /* 61 */ { "ADC", INDIRECT_X, M_INDX, READ, 6 }, /* (Indirect,X) */
- /* 62 */ { ".jam",IMPLIED, M_NONE, NONE, 0 }, /* TILT */
- /* 63 */ { "rra", INDIRECT_X, M_INDX, WRITE, 8 },
+ /* 60 */{"rts", IMPLIED, M_NONE, NONE, 6, 1},
+ /* 61 */{"adc", INDIRECT_X, M_INDX, READ, 6, 2}, /* (Indirect,X) */
+ /* 62 */{".JAM",IMPLIED, M_NONE, NONE, 0, 1}, /* TILT */
+ /* 63 */{"RRA", INDIRECT_X, M_INDX, WRITE, 8, 2},
- /* 64 */ { ".nop",ZERO_PAGE, M_NONE, NONE, 3 },
- /* 65 */ { "ADC", ZERO_PAGE, M_ZERO, READ, 3 }, /* Zeropage */
- /* 66 */ { "ROR", ZERO_PAGE, M_ZERO, WRITE, 5 }, /* Zeropage */
- /* 67 */ { "rra", ZERO_PAGE, M_ZERO, WRITE, 5 },
+ /* 64 */{"NOP", ZERO_PAGE, M_NONE, NONE, 3, 2},
+ /* 65 */{"adc", ZERO_PAGE, M_ZERO, READ, 3, 2}, /* Zeropage */
+ /* 66 */{"ror", ZERO_PAGE, M_ZERO, WRITE, 5, 2}, /* Zeropage */
+ /* 67 */{"RRA", ZERO_PAGE, M_ZERO, WRITE, 5, 2},
- /* 68 */ { "PLA", IMPLIED, M_NONE, NONE, 4 },
- /* 69 */ { "ADC", IMMEDIATE, M_IMM, READ, 2 }, /* Immediate */
- /* 6a */ { "ROR", ACCUMULATOR, M_AC, WRITE, 2 }, /* Accumulator */
- /* 6b */ { "arr", IMMEDIATE, M_ACIM, READ, 2 }, /* ARR isn't typo */
+ /* 68 */{"pla", IMPLIED, M_NONE, NONE, 4, 1},
+ /* 69 */{"adc", IMMEDIATE, M_IMM, READ, 2, 2}, /* Immediate */
+ /* 6a */{"ror", ACCUMULATOR, M_AC, WRITE, 2, 1}, /* Accumulator */
+ /* 6b */{"ARR", IMMEDIATE, M_ACIM, READ, 2, 2}, /* ARR isn't typo */
- /* 6c */ { "JMP", ABS_INDIRECT,M_AIND, READ, 5 }, /* Indirect */
- /* 6d */ { "ADC", ABSOLUTE, M_ABS, READ, 4 }, /* Absolute */
- /* 6e */ { "ROR", ABSOLUTE, M_ABS, WRITE, 6 }, /* Absolute */
- /* 6f */ { "rra", ABSOLUTE, M_ABS, WRITE, 6 },
+ /* 6c */{"jmp", ABS_INDIRECT,M_AIND, READ, 5, 3}, /* Indirect */
+ /* 6d */{"adc", ABSOLUTE, M_ABS, READ, 4, 3}, /* Absolute */
+ /* 6e */{"ror", ABSOLUTE, M_ABS, WRITE, 6, 3}, /* Absolute */
+ /* 6f */{"RRA", ABSOLUTE, M_ABS, WRITE, 6, 3},
- /* 70 */ { "BVS", RELATIVE, M_REL, READ, 2 },
- /* 71 */ { "ADC", INDIRECT_Y, M_INDY, READ, 5 }, /* (Indirect),Y */
- /* 72 */ { ".jam",IMPLIED, M_NONE, NONE, 0 }, /* TILT relative? */
- /* 73 */ { "rra", INDIRECT_Y, M_INDY, WRITE, 8 },
+ /* 70 */{"bvs", RELATIVE, M_REL, READ, 2, 2},
+ /* 71 */{"adc", INDIRECT_Y, M_INDY, READ, 5, 2}, /* (Indirect),Y */
+ /* 72 */{".JAM",IMPLIED, M_NONE, NONE, 0, 1}, /* TILT relative? */
+ /* 73 */{"RRA", INDIRECT_Y, M_INDY, WRITE, 8, 2},
- /* 74 */ { ".nop",ZERO_PAGE_X, M_NONE, NONE, 4 },
- /* 75 */ { "ADC", ZERO_PAGE_X, M_ZERX, READ, 4 }, /* Zeropage,X */
- /* 76 */ { "ROR", ZERO_PAGE_X, M_ZERX, WRITE, 6 }, /* Zeropage,X */
- /* 77 */ { "rra", ZERO_PAGE_X, M_ZERX, WRITE, 6 },
+ /* 74 */{"NOP", ZERO_PAGE_X, M_NONE, NONE, 4, 2},
+ /* 75 */{"adc", ZERO_PAGE_X, M_ZERX, READ, 4, 2}, /* Zeropage,X */
+ /* 76 */{"ror", ZERO_PAGE_X, M_ZERX, WRITE, 6, 2}, /* Zeropage,X */
+ /* 77 */{"RRA", ZERO_PAGE_X, M_ZERX, WRITE, 6, 2},
- /* 78 */ { "SEI", IMPLIED, M_NONE, NONE, 2 },
- /* 79 */ { "ADC", ABSOLUTE_Y, M_ABSY, READ, 4 }, /* Absolute,Y */
- /* 7a */ { ".nop",IMPLIED, M_NONE, NONE, 2 },
- /* 7b */ { "rra", ABSOLUTE_Y, M_ABSY, WRITE, 7 },
+ /* 78 */{"sei", IMPLIED, M_NONE, NONE, 2, 1},
+ /* 79 */{"adc", ABSOLUTE_Y, M_ABSY, READ, 4, 3}, /* Absolute,Y */
+ /* 7a */{"NOP", IMPLIED, M_NONE, NONE, 2, 1},
+ /* 7b */{"RRA", ABSOLUTE_Y, M_ABSY, WRITE, 7, 3},
- /* 7c */ { ".nop",ABSOLUTE_X, M_NONE, NONE, 4 },
- /* 7d */ { "ADC", ABSOLUTE_X, M_ABSX, READ, 4 }, /* Absolute,X */
- /* 7e */ { "ROR", ABSOLUTE_X, M_ABSX, WRITE, 7 }, /* Absolute,X */
- /* 7f */ { "rra", ABSOLUTE_X, M_ABSX, WRITE, 7 },
+ /* 7c */{"NOP", ABSOLUTE_X, M_NONE, NONE, 4, 3},
+ /* 7d */{"adc", ABSOLUTE_X, M_ABSX, READ, 4, 3}, /* Absolute,X */
+ /* 7e */{"ror", ABSOLUTE_X, M_ABSX, WRITE, 7, 3}, /* Absolute,X */
+ /* 7f */{"RRA", ABSOLUTE_X, M_ABSX, WRITE, 7, 3},
/**** Negative ****/
- /* 80 */ { "nop", IMMEDIATE, M_NONE, NONE, 2 },
- /* 81 */ { "STA", INDIRECT_X, M_AC, WRITE, 6 }, /* (Indirect,X) */
- /* 82 */ { ".nop",IMMEDIATE, M_NONE, NONE, 2 },
- /* 83 */ { "sax", INDIRECT_X, M_ANXR, WRITE, 6 },
+ /* 80 */{"NOP", IMMEDIATE, M_NONE, NONE, 2, 2},
+ /* 81 */{"sta", INDIRECT_X, M_AC, WRITE, 6, 2}, /* (Indirect,X) */
+ /* 82 */{"NOP", IMMEDIATE, M_NONE, NONE, 2, 2},
+ /* 83 */{"SAX", INDIRECT_X, M_ANXR, WRITE, 6, 2},
- /* 84 */ { "STY", ZERO_PAGE, M_YR, WRITE, 3 }, /* Zeropage */
- /* 85 */ { "STA", ZERO_PAGE, M_AC, WRITE, 3 }, /* Zeropage */
- /* 86 */ { "STX", ZERO_PAGE, M_XR, WRITE, 3 }, /* Zeropage */
- /* 87 */ { "sax", ZERO_PAGE, M_ANXR, WRITE, 3 },
+ /* 84 */{"sty", ZERO_PAGE, M_YR, WRITE, 3, 2}, /* Zeropage */
+ /* 85 */{"sta", ZERO_PAGE, M_AC, WRITE, 3, 2}, /* Zeropage */
+ /* 86 */{"stx", ZERO_PAGE, M_XR, WRITE, 3, 2}, /* Zeropage */
+ /* 87 */{"SAX", ZERO_PAGE, M_ANXR, WRITE, 3, 2},
- /* 88 */ { "DEY", IMPLIED, M_YR, NONE, 2 },
- /* 89 */ { ".nop",IMMEDIATE, M_NONE, NONE, 2 },
- /* 8a */ { "TXA", IMPLIED, M_XR, NONE, 2 },
+ /* 88 */{"dey", IMPLIED, M_YR, NONE, 2, 1},
+ /* 89 */{"NOP", IMMEDIATE, M_NONE, NONE, 2, 2},
+ /* 8a */{"txa", IMPLIED, M_XR, NONE, 2, 1},
/**** very abnormal: usually AC = AC | #$EE & XR & #$oper ****/
- /* 8b */ { "ane", IMMEDIATE, M_AXIM, READ, 2 },
+ /* 8b */{"ANE", IMMEDIATE, M_AXIM, READ, 2, 2},
- /* 8c */ { "STY", ABSOLUTE, M_YR, WRITE, 4 }, /* Absolute */
- /* 8d */ { "STA", ABSOLUTE, M_AC, WRITE, 4 }, /* Absolute */
- /* 8e */ { "STX", ABSOLUTE, M_XR, WRITE, 4 }, /* Absolute */
- /* 8f */ { "sax", ABSOLUTE, M_ANXR, WRITE, 4 },
+ /* 8c */{"sty", ABSOLUTE, M_YR, WRITE, 4, 3}, /* Absolute */
+ /* 8d */{"sta", ABSOLUTE, M_AC, WRITE, 4, 3}, /* Absolute */
+ /* 8e */{"stx", ABSOLUTE, M_XR, WRITE, 4, 3}, /* Absolute */
+ /* 8f */{"SAX", ABSOLUTE, M_ANXR, WRITE, 4, 3},
- /* 90 */ { "BCC", RELATIVE, M_REL, READ, 2 },
- /* 91 */ { "STA", INDIRECT_Y, M_AC, WRITE, 6 }, /* (Indirect),Y */
- /* 92 */ { ".jam",IMPLIED, M_NONE, NONE, 0 }, /* TILT relative? */
- /* 93 */ { "sha", INDIRECT_Y, M_ANXR, WRITE, 6 },
+ /* 90 */{"bcc", RELATIVE, M_REL, READ, 2, 2},
+ /* 91 */{"sta", INDIRECT_Y, M_AC, WRITE, 6, 2}, /* (Indirect),Y */
+ /* 92 */{".JAM",IMPLIED, M_NONE, NONE, 0, 1}, /* TILT relative? */
+ /* 93 */{"SHA", INDIRECT_Y, M_ANXR, WRITE, 6, 2},
- /* 94 */ { "STY", ZERO_PAGE_X, M_YR, WRITE, 4 }, /* Zeropage,X */
- /* 95 */ { "STA", ZERO_PAGE_X, M_AC, WRITE, 4 }, /* Zeropage,X */
- /* 96 */ { "STX", ZERO_PAGE_Y, M_XR, WRITE, 4 }, /* Zeropage,Y */
- /* 97 */ { "sax", ZERO_PAGE_Y, M_ANXR, WRITE, 4 },
+ /* 94 */{"sty", ZERO_PAGE_X, M_YR, WRITE, 4, 2}, /* Zeropage,X */
+ /* 95 */{"sta", ZERO_PAGE_X, M_AC, WRITE, 4, 2}, /* Zeropage,X */
+ /* 96 */{"stx", ZERO_PAGE_Y, M_XR, WRITE, 4, 2}, /* Zeropage,Y */
+ /* 97 */{"SAX", ZERO_PAGE_Y, M_ANXR, WRITE, 4, 2},
- /* 98 */ { "TYA", IMPLIED, M_YR, NONE, 2 },
- /* 99 */ { "STA", ABSOLUTE_Y, M_AC, WRITE, 5 }, /* Absolute,Y */
- /* 9a */ { "TXS", IMPLIED, M_XR, NONE, 2 },
- /*** This is very mysterious comm AND ... */
- /* 9b */ { "shs", ABSOLUTE_Y, M_ANXR, WRITE, 5 },
+ /* 98 */{"tya", IMPLIED, M_YR, NONE, 2, 1},
+ /* 99 */{"sta", ABSOLUTE_Y, M_AC, WRITE, 5, 3}, /* Absolute,Y */
+ /* 9a */{"txs", IMPLIED, M_XR, NONE, 2, 1},
+ /*** This is very mysterious command ... */
+ /* 9b */{"SHS", ABSOLUTE_Y, M_ANXR, WRITE, 5, 3},
- /* 9c */ { "shy", ABSOLUTE_X, M_YR, WRITE, 5 },
- /* 9d */ { "STA", ABSOLUTE_X, M_AC, WRITE, 5 }, /* Absolute,X */
- /* 9e */ { "shx", ABSOLUTE_Y, M_XR , WRITE, 5 },
- /* 9f */ { "sha", ABSOLUTE_Y, M_ANXR, WRITE, 5 },
+ /* 9c */{"SHY", ABSOLUTE_X, M_YR, WRITE, 5, 3},
+ /* 9d */{"sta", ABSOLUTE_X, M_AC, WRITE, 5, 3}, /* Absolute,X */
+ /* 9e */{"SHX", ABSOLUTE_Y, M_XR , WRITE, 5, 3},
+ /* 9f */{"SHA", ABSOLUTE_Y, M_ANXR, WRITE, 5, 3},
- /* a0 */ { "LDY", IMMEDIATE, M_IMM, READ, 2 }, /* Immediate */
- /* a1 */ { "LDA", INDIRECT_X, M_INDX, READ, 6 }, /* (indirect,X) */
- /* a2 */ { "LDX", IMMEDIATE, M_IMM, READ, 2 }, /* Immediate */
- /* a3 */ { "lax", INDIRECT_X, M_INDX, READ, 6 }, /* (indirect,X) */
+ /* a0 */{"ldy", IMMEDIATE, M_IMM, READ, 2, 2}, /* Immediate */
+ /* a1 */{"lda", INDIRECT_X, M_INDX, READ, 6, 2}, /* (indirect,X) */
+ /* a2 */{"ldx", IMMEDIATE, M_IMM, READ, 2, 2}, /* Immediate */
+ /* a3 */{"LAX", INDIRECT_X, M_INDX, READ, 6, 2}, /* (indirect,X) */
- /* a4 */ { "LDY", ZERO_PAGE, M_ZERO, READ, 3 }, /* Zeropage */
- /* a5 */ { "LDA", ZERO_PAGE, M_ZERO, READ, 3 }, /* Zeropage */
- /* a6 */ { "LDX", ZERO_PAGE, M_ZERO, READ, 3 }, /* Zeropage */
- /* a7 */ { "lax", ZERO_PAGE, M_ZERO, READ, 3 },
+ /* a4 */{"ldy", ZERO_PAGE, M_ZERO, READ, 3, 2}, /* Zeropage */
+ /* a5 */{"lda", ZERO_PAGE, M_ZERO, READ, 3, 2}, /* Zeropage */
+ /* a6 */{"ldx", ZERO_PAGE, M_ZERO, READ, 3, 2}, /* Zeropage */
+ /* a7 */{"LAX", ZERO_PAGE, M_ZERO, READ, 3, 2},
- /* a8 */ { "TAY", IMPLIED, M_AC, NONE, 2 },
- /* a9 */ { "LDA", IMMEDIATE, M_IMM, READ, 2 }, /* Immediate */
- /* aa */ { "TAX", IMPLIED, M_AC, NONE, 2 },
- /* ab */ { "lxa", IMMEDIATE, M_ACIM, READ, 2 }, /* LXA isn't a typo */
+ /* a8 */{"tay", IMPLIED, M_AC, NONE, 2, 1},
+ /* a9 */{"lda", IMMEDIATE, M_IMM, READ, 2, 2}, /* Immediate */
+ /* aa */{"tax", IMPLIED, M_AC, NONE, 2, 1},
+ /* ab */{"LXA", IMMEDIATE, M_ACIM, READ, 2, 2}, /* LXA isn't a typo */
- /* ac */ { "LDY", ABSOLUTE, M_ABS, READ, 4 }, /* Absolute */
- /* ad */ { "LDA", ABSOLUTE, M_ABS, READ, 4 }, /* Absolute */
- /* ae */ { "LDX", ABSOLUTE, M_ABS, READ, 4 }, /* Absolute */
- /* af */ { "lax", ABSOLUTE, M_ABS, READ, 4 },
+ /* ac */{"ldy", ABSOLUTE, M_ABS, READ, 4, 3}, /* Absolute */
+ /* ad */{"lda", ABSOLUTE, M_ABS, READ, 4, 3}, /* Absolute */
+ /* ae */{"ldx", ABSOLUTE, M_ABS, READ, 4, 3}, /* Absolute */
+ /* af */{"LAX", ABSOLUTE, M_ABS, READ, 4, 3},
- /* b0 */ { "BCS", RELATIVE, M_REL, READ, 2 },
- /* b1 */ { "LDA", INDIRECT_Y, M_INDY, READ, 5 }, /* (indirect),Y */
- /* b2 */ { ".jam",IMPLIED, M_NONE, NONE, 0 }, /* TILT */
- /* b3 */ { "lax", INDIRECT_Y, M_INDY, READ, 5 },
+ /* b0 */{"bcs", RELATIVE, M_REL, READ, 2, 2},
+ /* b1 */{"lda", INDIRECT_Y, M_INDY, READ, 5, 2}, /* (indirect),Y */
+ /* b2 */{".JAM",IMPLIED, M_NONE, NONE, 0, 1}, /* TILT */
+ /* b3 */{"LAX", INDIRECT_Y, M_INDY, READ, 5, 2},
- /* b4 */ { "LDY", ZERO_PAGE_X, M_ZERX, READ, 4 }, /* Zeropage,X */
- /* b5 */ { "LDA", ZERO_PAGE_X, M_ZERX, READ, 4 }, /* Zeropage,X */
- /* b6 */ { "LDX", ZERO_PAGE_Y, M_ZERY, READ, 4 }, /* Zeropage,Y */
- /* b7 */ { "lax", ZERO_PAGE_Y, M_ZERY, READ, 4 },
+ /* b4 */{"ldy", ZERO_PAGE_X, M_ZERX, READ, 4, 2}, /* Zeropage,X */
+ /* b5 */{"lda", ZERO_PAGE_X, M_ZERX, READ, 4, 2}, /* Zeropage,X */
+ /* b6 */{"ldx", ZERO_PAGE_Y, M_ZERY, READ, 4, 2}, /* Zeropage,Y */
+ /* b7 */{"LAX", ZERO_PAGE_Y, M_ZERY, READ, 4, 2},
- /* b8 */ { "CLV", IMPLIED, M_NONE, NONE, 2 },
- /* b9 */ { "LDA", ABSOLUTE_Y, M_ABSY, READ, 4 }, /* Absolute,Y */
- /* ba */ { "TSX", IMPLIED, M_SP, NONE, 2 },
- /* bb */ { "las", ABSOLUTE_Y, M_SABY, READ, 4 },
+ /* b8 */{"clv", IMPLIED, M_NONE, NONE, 2, 1},
+ /* b9 */{"lda", ABSOLUTE_Y, M_ABSY, READ, 4, 3}, /* Absolute,Y */
+ /* ba */{"tsx", IMPLIED, M_SP, NONE, 2, 1},
+ /* bb */{"LAS", ABSOLUTE_Y, M_SABY, READ, 4, 3},
- /* bc */ { "LDY", ABSOLUTE_X, M_ABSX, READ, 4 }, /* Absolute,X */
- /* bd */ { "LDA", ABSOLUTE_X, M_ABSX, READ, 4 }, /* Absolute,X */
- /* be */ { "LDX", ABSOLUTE_Y, M_ABSY, READ, 4 }, /* Absolute,Y */
- /* bf */ { "lax", ABSOLUTE_Y, M_ABSY, READ, 4 },
+ /* bc */{"ldy", ABSOLUTE_X, M_ABSX, READ, 4, 3}, /* Absolute,X */
+ /* bd */{"lda", ABSOLUTE_X, M_ABSX, READ, 4, 3}, /* Absolute,X */
+ /* be */{"ldx", ABSOLUTE_Y, M_ABSY, READ, 4, 3}, /* Absolute,Y */
+ /* bf */{"LAX", ABSOLUTE_Y, M_ABSY, READ, 4, 3},
- /* c0 */ { "CPY", IMMEDIATE, M_IMM, READ, 2 }, /* Immediate */
- /* c1 */ { "CMP", INDIRECT_X, M_INDX, READ, 6 }, /* (Indirect,X) */
- /* c2 */ { ".nop",IMMEDIATE, M_NONE, NONE, 2 }, /* occasional TILT */
- /* c3 */ { "dcp", INDIRECT_X, M_INDX, WRITE, 8 },
+ /* c0 */{"cpy", IMMEDIATE, M_IMM, READ, 2, 2}, /* Immediate */
+ /* c1 */{"cmp", INDIRECT_X, M_INDX, READ, 6, 2}, /* (Indirect,X) */
+ /* c2 */{"NOP", IMMEDIATE, M_NONE, NONE, 2, 2}, /* occasional TILT */
+ /* c3 */{"DCP", INDIRECT_X, M_INDX, WRITE, 8, 2},
- /* c4 */ { "CPY", ZERO_PAGE, M_ZERO, READ, 3 }, /* Zeropage */
- /* c5 */ { "CMP", ZERO_PAGE, M_ZERO, READ, 3 }, /* Zeropage */
- /* c6 */ { "DEC", ZERO_PAGE, M_ZERO, WRITE, 5 }, /* Zeropage */
- /* c7 */ { "dcp", ZERO_PAGE, M_ZERO, WRITE, 5 },
+ /* c4 */{"cpy", ZERO_PAGE, M_ZERO, READ, 3, 2}, /* Zeropage */
+ /* c5 */{"cmp", ZERO_PAGE, M_ZERO, READ, 3, 2}, /* Zeropage */
+ /* c6 */{"dec", ZERO_PAGE, M_ZERO, WRITE, 5, 2}, /* Zeropage */
+ /* c7 */{"DCP", ZERO_PAGE, M_ZERO, WRITE, 5, 2},
- /* c8 */ { "INY", IMPLIED, M_YR, NONE, 2 },
- /* c9 */ { "CMP", IMMEDIATE, M_IMM, READ, 2 }, /* Immediate */
- /* ca */ { "DEX", IMPLIED, M_XR, NONE, 2 },
- /* cb */ { "sbx", IMMEDIATE, M_IMM, READ, 2 },
+ /* c8 */{"iny", IMPLIED, M_YR, NONE, 2, 1},
+ /* c9 */{"cmp", IMMEDIATE, M_IMM, READ, 2, 2}, /* Immediate */
+ /* ca */{"dex", IMPLIED, M_XR, NONE, 2, 1},
+ /* cb */{"SBX", IMMEDIATE, M_IMM, READ, 2, 2},
- /* cc */ { "CPY", ABSOLUTE, M_ABS, READ, 4 }, /* Absolute */
- /* cd */ { "CMP", ABSOLUTE, M_ABS, READ, 4 }, /* Absolute */
- /* ce */ { "DEC", ABSOLUTE, M_ABS, WRITE, 6 }, /* Absolute */
- /* cf */ { "dcp", ABSOLUTE, M_ABS, WRITE, 6 },
+ /* cc */{"cpy", ABSOLUTE, M_ABS, READ, 4, 3}, /* Absolute */
+ /* cd */{"cmp", ABSOLUTE, M_ABS, READ, 4, 3}, /* Absolute */
+ /* ce */{"dec", ABSOLUTE, M_ABS, WRITE, 6, 3}, /* Absolute */
+ /* cf */{"DCP", ABSOLUTE, M_ABS, WRITE, 6, 3},
- /* d0 */ { "BNE", RELATIVE, M_REL, READ, 2 },
- /* d1 */ { "CMP", INDIRECT_Y, M_INDY, READ, 5 }, /* (Indirect),Y */
- /* d2 */ { ".jam",IMPLIED, M_NONE, NONE, 0 }, /* TILT */
- /* d3 */ { "dcp", INDIRECT_Y, M_INDY, WRITE, 8 },
+ /* d0 */{"bne", RELATIVE, M_REL, READ, 2, 2},
+ /* d1 */{"cmp", INDIRECT_Y, M_INDY, READ, 5, 2}, /* (Indirect),Y */
+ /* d2 */{".JAM",IMPLIED, M_NONE, NONE, 0, 1}, /* TILT */
+ /* d3 */{"DCP", INDIRECT_Y, M_INDY, WRITE, 8, 2},
- /* d4 */ { ".nop",ZERO_PAGE_X, M_NONE, NONE, 4 },
- /* d5 */ { "CMP", ZERO_PAGE_X, M_ZERX, READ, 4 }, /* Zeropage,X */
- /* d6 */ { "DEC", ZERO_PAGE_X, M_ZERX, WRITE, 6 }, /* Zeropage,X */
- /* d7 */ { "dcp", ZERO_PAGE_X, M_ZERX, WRITE, 6 },
+ /* d4 */{"NOP", ZERO_PAGE_X, M_NONE, NONE, 4, 2},
+ /* d5 */{"cmp", ZERO_PAGE_X, M_ZERX, READ, 4, 2}, /* Zeropage,X */
+ /* d6 */{"dec", ZERO_PAGE_X, M_ZERX, WRITE, 6, 2}, /* Zeropage,X */
+ /* d7 */{"DCP", ZERO_PAGE_X, M_ZERX, WRITE, 6, 2},
- /* d8 */ { "CLD", IMPLIED, M_NONE, NONE, 2 },
- /* d9 */ { "CMP", ABSOLUTE_Y, M_ABSY, READ, 4 }, /* Absolute,Y */
- /* da */ { ".nop",IMPLIED, M_NONE, NONE, 2 },
- /* db */ { "dcp", ABSOLUTE_Y, M_ABSY, WRITE, 7 },
+ /* d8 */{"cld", IMPLIED, M_NONE, NONE, 2, 1},
+ /* d9 */{"cmp", ABSOLUTE_Y, M_ABSY, READ, 4, 3}, /* Absolute,Y */
+ /* da */{"NOP", IMPLIED, M_NONE, NONE, 2, 1},
+ /* db */{"DCP", ABSOLUTE_Y, M_ABSY, WRITE, 7, 3},
- /* dc */ { ".nop",ABSOLUTE_X, M_NONE, NONE, 4 },
- /* dd */ { "CMP", ABSOLUTE_X, M_ABSX, READ, 4 }, /* Absolute,X */
- /* de */ { "DEC", ABSOLUTE_X, M_ABSX, WRITE, 7 }, /* Absolute,X */
- /* df */ { "dcp", ABSOLUTE_X, M_ABSX, WRITE, 7 },
+ /* dc */{"NOP", ABSOLUTE_X, M_NONE, NONE, 4, 3},
+ /* dd */{"cmp", ABSOLUTE_X, M_ABSX, READ, 4, 3}, /* Absolute,X */
+ /* de */{"dec", ABSOLUTE_X, M_ABSX, WRITE, 7, 3}, /* Absolute,X */
+ /* df */{"DCP", ABSOLUTE_X, M_ABSX, WRITE, 7, 3},
- /* e0 */ { "CPX", IMMEDIATE, M_IMM, READ, 2 }, /* Immediate */
- /* e1 */ { "SBC", INDIRECT_X, M_INDX, READ, 6 }, /* (Indirect,X) */
- /* e2 */ { ".nop",IMMEDIATE, M_NONE, NONE, 2 },
- /* e3 */ { "isb", INDIRECT_X, M_INDX, WRITE, 8 },
+ /* e0 */{"cpx", IMMEDIATE, M_IMM, READ, 2, 2}, /* Immediate */
+ /* e1 */{"sbc", INDIRECT_X, M_INDX, READ, 6, 2}, /* (Indirect,X) */
+ /* e2 */{"NOP", IMMEDIATE, M_NONE, NONE, 2, 2},
+ /* e3 */{"ISB", INDIRECT_X, M_INDX, WRITE, 8, 2},
- /* e4 */ { "CPX", ZERO_PAGE, M_ZERO, READ, 3 }, /* Zeropage */
- /* e5 */ { "SBC", ZERO_PAGE, M_ZERO, READ, 3 }, /* Zeropage */
- /* e6 */ { "INC", ZERO_PAGE, M_ZERO, WRITE, 5 }, /* Zeropage */
- /* e7 */ { "isb", ZERO_PAGE, M_ZERO, WRITE, 5 },
+ /* e4 */{"cpx", ZERO_PAGE, M_ZERO, READ, 3, 2}, /* Zeropage */
+ /* e5 */{"sbc", ZERO_PAGE, M_ZERO, READ, 3, 2}, /* Zeropage */
+ /* e6 */{"inc", ZERO_PAGE, M_ZERO, WRITE, 5, 2}, /* Zeropage */
+ /* e7 */{"ISB", ZERO_PAGE, M_ZERO, WRITE, 5, 2},
- /* e8 */ { "INX", IMPLIED, M_XR, NONE, 2 },
- /* e9 */ { "SBC", IMMEDIATE, M_IMM, READ, 2 }, /* Immediate */
- /* ea */ { "NOP", IMPLIED, M_NONE, NONE, 2 },
- /* eb */ { ".sbc",IMMEDIATE, M_IMM, READ, 2 }, /* same as e9 */
+ /* e8 */{"inx", IMPLIED, M_XR, NONE, 2, 1},
+ /* e9 */{"sbc", IMMEDIATE, M_IMM, READ, 2, 2}, /* Immediate */
+ /* ea */{"nop", IMPLIED, M_NONE, NONE, 2, 1},
+ /* eb */{"SBC", IMMEDIATE, M_IMM, READ, 2, 2}, /* same as e9 */
- /* ec */ { "CPX", ABSOLUTE, M_ABS, READ, 4 }, /* Absolute */
- /* ed */ { "SBC", ABSOLUTE, M_ABS, READ, 4 }, /* Absolute */
- /* ee */ { "INC", ABSOLUTE, M_ABS, WRITE, 6 }, /* Absolute */
- /* ef */ { "isb", ABSOLUTE, M_ABS, WRITE, 6 },
+ /* ec */{"cpx", ABSOLUTE, M_ABS, READ, 4, 3}, /* Absolute */
+ /* ed */{"sbc", ABSOLUTE, M_ABS, READ, 4, 3}, /* Absolute */
+ /* ee */{"inc", ABSOLUTE, M_ABS, WRITE, 6, 3}, /* Absolute */
+ /* ef */{"ISB", ABSOLUTE, M_ABS, WRITE, 6, 3},
- /* f0 */ { "BEQ", RELATIVE, M_REL, READ, 2 },
- /* f1 */ { "SBC", INDIRECT_Y, M_INDY, READ, 5 }, /* (Indirect),Y */
- /* f2 */ { ".jam",IMPLIED, M_NONE, NONE, 0 }, /* TILT */
- /* f3 */ { "isb", INDIRECT_Y, M_INDY, WRITE, 8 },
+ /* f0 */{"beq", RELATIVE, M_REL, READ, 2, 2},
+ /* f1 */{"sbc", INDIRECT_Y, M_INDY, READ, 5, 2}, /* (Indirect),Y */
+ /* f2 */{".JAM",IMPLIED, M_NONE, NONE, 0, 1}, /* TILT */
+ /* f3 */{"ISB", INDIRECT_Y, M_INDY, WRITE, 8, 2},
- /* f4 */ { ".nop",ZERO_PAGE_X, M_NONE, NONE, 4 },
- /* f5 */ { "SBC", ZERO_PAGE_X, M_ZERX, READ, 4 }, /* Zeropage,X */
- /* f6 */ { "INC", ZERO_PAGE_X, M_ZERX, WRITE, 6 }, /* Zeropage,X */
- /* f7 */ { "isb", ZERO_PAGE_X, M_ZERX, WRITE, 6 },
+ /* f4 */{"NOP", ZERO_PAGE_X, M_NONE, NONE, 4, 2},
+ /* f5 */{"sbc", ZERO_PAGE_X, M_ZERX, READ, 4, 2}, /* Zeropage,X */
+ /* f6 */{"inc", ZERO_PAGE_X, M_ZERX, WRITE, 6, 2}, /* Zeropage,X */
+ /* f7 */{"ISB", ZERO_PAGE_X, M_ZERX, WRITE, 6, 2},
- /* f8 */ { "SED", IMPLIED, M_NONE, NONE, 2 },
- /* f9 */ { "SBC", ABSOLUTE_Y, M_ABSY, READ, 4 }, /* Absolute,Y */
- /* fa */ { ".nop",IMPLIED, M_NONE, NONE, 2 },
- /* fb */ { "isb", ABSOLUTE_Y, M_ABSY, WRITE, 7 },
+ /* f8 */{"sed", IMPLIED, M_NONE, NONE, 2, 1},
+ /* f9 */{"sbc", ABSOLUTE_Y, M_ABSY, READ, 4, 3}, /* Absolute,Y */
+ /* fa */{"NOP", IMPLIED, M_NONE, NONE, 2, 1},
+ /* fb */{"ISB", ABSOLUTE_Y, M_ABSY, WRITE, 7, 3},
- /* fc */ { ".nop",ABSOLUTE_X, M_NONE, NONE, 4 },
- /* fd */ { "SBC", ABSOLUTE_X, M_ABSX, READ, 4 }, /* Absolute,X */
- /* fe */ { "INC", ABSOLUTE_X, M_ABSX, WRITE, 7 }, /* Absolute,X */
- /* ff */ { "isb", ABSOLUTE_X, M_ABSX, WRITE, 7 }
+ /* fc */{"NOP" ,ABSOLUTE_X, M_NONE, NONE, 4, 3},
+ /* fd */{"sbc", ABSOLUTE_X, M_ABSX, READ, 4, 3}, /* Absolute,X */
+ /* fe */{"inc", ABSOLUTE_X, M_ABSX, WRITE, 7, 3}, /* Absolute,X */
+ /* ff */{"ISB", ABSOLUTE_X, M_ABSX, WRITE, 7, 3}
};
diff --git a/src/debugger/DiStella.hxx b/src/debugger/DiStella.hxx
index 43cf5fad3..c5adce185 100644
--- a/src/debugger/DiStella.hxx
+++ b/src/debugger/DiStella.hxx
@@ -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 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];
diff --git a/src/debugger/TIADebug.cxx b/src/debugger/TIADebug.cxx
index 3cc2983fc..6a6dd008d 100644
--- a/src/debugger/TIADebug.cxx
+++ b/src/debugger/TIADebug.cxx
@@ -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);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/src/debugger/TIADebug.hxx b/src/debugger/TIADebug.hxx
index e53eba93a..3830d75f1 100644
--- a/src/debugger/TIADebug.hxx
+++ b/src/debugger/TIADebug.hxx
@@ -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;
diff --git a/src/debugger/gui/Cart0840Widget.cxx b/src/debugger/gui/Cart0840Widget.cxx
index 4b33fdc5a..8902690d8 100644
--- a/src/debugger/gui/Cart0840Widget.cxx
+++ b/src/debugger/gui/Cart0840Widget.cxx
@@ -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();
}
diff --git a/src/debugger/gui/CartBFSCWidget.cxx b/src/debugger/gui/CartBFSCWidget.cxx
index 03ae13442..fe512396b 100644
--- a/src/debugger/gui/CartBFSCWidget.cxx
+++ b/src/debugger/gui/CartBFSCWidget.cxx
@@ -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();
}
diff --git a/src/debugger/gui/CartBFWidget.cxx b/src/debugger/gui/CartBFWidget.cxx
index 48f82e589..a319843af 100644
--- a/src/debugger/gui/CartBFWidget.cxx
+++ b/src/debugger/gui/CartBFWidget.cxx
@@ -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();
}
diff --git a/src/debugger/gui/CartBUSWidget.cxx b/src/debugger/gui/CartBUSWidget.cxx
index d92f27497..39574f297 100644
--- a/src/debugger/gui/CartBUSWidget.cxx
+++ b/src/debugger/gui/CartBUSWidget.cxx
@@ -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();
}
diff --git a/src/debugger/gui/CartCDFWidget.cxx b/src/debugger/gui/CartCDFWidget.cxx
index 04e308c83..a5cfd67f8 100644
--- a/src/debugger/gui/CartCDFWidget.cxx
+++ b/src/debugger/gui/CartCDFWidget.cxx
@@ -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();
}
diff --git a/src/debugger/gui/CartCMWidget.cxx b/src/debugger/gui/CartCMWidget.cxx
index e101fa79b..c49c2b63a 100644
--- a/src/debugger/gui/CartCMWidget.cxx
+++ b/src/debugger/gui/CartCMWidget.cxx
@@ -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(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");
diff --git a/src/debugger/gui/CartDFSCWidget.cxx b/src/debugger/gui/CartDFSCWidget.cxx
index 90a542840..290bba8c4 100644
--- a/src/debugger/gui/CartDFSCWidget.cxx
+++ b/src/debugger/gui/CartDFSCWidget.cxx
@@ -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();
}
diff --git a/src/debugger/gui/CartDFWidget.cxx b/src/debugger/gui/CartDFWidget.cxx
index 1cd34929f..4462a9a49 100644
--- a/src/debugger/gui/CartDFWidget.cxx
+++ b/src/debugger/gui/CartDFWidget.cxx
@@ -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();
}
diff --git a/src/debugger/gui/CartDPCPlusWidget.cxx b/src/debugger/gui/CartDPCPlusWidget.cxx
index 538e91874..89e957dae 100644
--- a/src/debugger/gui/CartDPCPlusWidget.cxx
+++ b/src/debugger/gui/CartDPCPlusWidget.cxx
@@ -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();
}
diff --git a/src/debugger/gui/CartDPCWidget.cxx b/src/debugger/gui/CartDPCWidget.cxx
index 37c18bb47..0e6bab277 100644
--- a/src/debugger/gui/CartDPCWidget.cxx
+++ b/src/debugger/gui/CartDPCWidget.cxx
@@ -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();
}
diff --git a/src/debugger/gui/CartEFSCWidget.cxx b/src/debugger/gui/CartEFSCWidget.cxx
index 6e97bec34..13d88c881 100644
--- a/src/debugger/gui/CartEFSCWidget.cxx
+++ b/src/debugger/gui/CartEFSCWidget.cxx
@@ -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();
}
diff --git a/src/debugger/gui/CartEFWidget.cxx b/src/debugger/gui/CartEFWidget.cxx
index 2ce7b5fbd..cc4b5c29d 100644
--- a/src/debugger/gui/CartEFWidget.cxx
+++ b/src/debugger/gui/CartEFWidget.cxx
@@ -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();
}
diff --git a/src/debugger/gui/CartF0Widget.cxx b/src/debugger/gui/CartF0Widget.cxx
index 353126c4f..8212f78f6 100644
--- a/src/debugger/gui/CartF0Widget.cxx
+++ b/src/debugger/gui/CartF0Widget.cxx
@@ -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();
}
diff --git a/src/debugger/gui/CartF4SCWidget.cxx b/src/debugger/gui/CartF4SCWidget.cxx
index 98d67e952..b702c0ce6 100644
--- a/src/debugger/gui/CartF4SCWidget.cxx
+++ b/src/debugger/gui/CartF4SCWidget.cxx
@@ -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();
}
diff --git a/src/debugger/gui/CartF4Widget.cxx b/src/debugger/gui/CartF4Widget.cxx
index df62423ea..5cc9293f0 100644
--- a/src/debugger/gui/CartF4Widget.cxx
+++ b/src/debugger/gui/CartF4Widget.cxx
@@ -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();
}
diff --git a/src/debugger/gui/CartF6SCWidget.cxx b/src/debugger/gui/CartF6SCWidget.cxx
index 4ba888d0f..5c7b47acd 100644
--- a/src/debugger/gui/CartF6SCWidget.cxx
+++ b/src/debugger/gui/CartF6SCWidget.cxx
@@ -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();
}
diff --git a/src/debugger/gui/CartF6Widget.cxx b/src/debugger/gui/CartF6Widget.cxx
index 3bd34235b..e94442db4 100644
--- a/src/debugger/gui/CartF6Widget.cxx
+++ b/src/debugger/gui/CartF6Widget.cxx
@@ -60,7 +60,7 @@ CartridgeF6Widget::CartridgeF6Widget(
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF6Widget::loadConfig()
{
- myBank->setSelectedIndex(myCart.myCurrentBank);
+ myBank->setSelectedIndex(myCart.getBank());
CartDebugWidget::loadConfig();
}
@@ -84,8 +84,8 @@ string CartridgeF6Widget::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();
}
diff --git a/src/debugger/gui/CartF8SCWidget.cxx b/src/debugger/gui/CartF8SCWidget.cxx
index 78b256714..f8cf69629 100644
--- a/src/debugger/gui/CartF8SCWidget.cxx
+++ b/src/debugger/gui/CartF8SCWidget.cxx
@@ -71,7 +71,7 @@ void CartridgeF8SCWidget::saveOldState()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF8SCWidget::loadConfig()
{
- myBank->setSelectedIndex(myCart.myCurrentBank);
+ myBank->setSelectedIndex(myCart.getBank());
CartDebugWidget::loadConfig();
}
@@ -95,8 +95,8 @@ string CartridgeF8SCWidget::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();
}
diff --git a/src/debugger/gui/CartF8Widget.cxx b/src/debugger/gui/CartF8Widget.cxx
index 416f1d427..02dab5d8a 100644
--- a/src/debugger/gui/CartF8Widget.cxx
+++ b/src/debugger/gui/CartF8Widget.cxx
@@ -58,7 +58,7 @@ CartridgeF8Widget::CartridgeF8Widget(
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF8Widget::loadConfig()
{
- myBank->setSelectedIndex(myCart.myCurrentBank);
+ myBank->setSelectedIndex(myCart.getBank());
CartDebugWidget::loadConfig();
}
@@ -82,8 +82,8 @@ string CartridgeF8Widget::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();
}
diff --git a/src/debugger/gui/CartFA2Widget.cxx b/src/debugger/gui/CartFA2Widget.cxx
index 5827abb13..1a992b096 100644
--- a/src/debugger/gui/CartFA2Widget.cxx
+++ b/src/debugger/gui/CartFA2Widget.cxx
@@ -109,14 +109,14 @@ void CartridgeFA2Widget::saveOldState()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeFA2Widget::loadConfig()
{
- myBank->setSelectedIndex(myCart.myCurrentBank);
+ myBank->setSelectedIndex(myCart.getBank());
CartDebugWidget::loadConfig();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeFA2Widget::handleCommand(CommandSender* sender,
- int cmd, int data, int id)
+ int cmd, int data, int id)
{
switch(cmd)
{
@@ -149,8 +149,8 @@ string CartridgeFA2Widget::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();
}
diff --git a/src/debugger/gui/CartFAWidget.cxx b/src/debugger/gui/CartFAWidget.cxx
index b41496cb9..7a8a27e2d 100644
--- a/src/debugger/gui/CartFAWidget.cxx
+++ b/src/debugger/gui/CartFAWidget.cxx
@@ -72,7 +72,7 @@ void CartridgeFAWidget::saveOldState()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeFAWidget::loadConfig()
{
- myBank->setSelectedIndex(myCart.myCurrentBank);
+ myBank->setSelectedIndex(myCart.getBank());
CartDebugWidget::loadConfig();
}
@@ -96,8 +96,8 @@ string CartridgeFAWidget::bankState()
ostringstream& buf = buffer();
static const char* const spot[] = { "$FFF8", "$FFF9", "$FFFA" };
- buf << "Bank = " << std::dec << myCart.myCurrentBank
- << ", hotspot = " << spot[myCart.myCurrentBank];
+ buf << "Bank = " << std::dec << myCart.getBank()
+ << ", hotspot = " << spot[myCart.getBank()];
return buf.str();
}
diff --git a/src/debugger/gui/CartFEWidget.cxx b/src/debugger/gui/CartFEWidget.cxx
index db779620b..a8c8d8a1c 100644
--- a/src/debugger/gui/CartFEWidget.cxx
+++ b/src/debugger/gui/CartFEWidget.cxx
@@ -16,6 +16,7 @@
//============================================================================
#include "CartFE.hxx"
+#include "PopUpWidget.hxx"
#include "CartFEWidget.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -27,15 +28,45 @@ CartridgeFEWidget::CartridgeFEWidget(
{
string info =
"FE cartridge, two 4K banks\n"
- "Doesn't support bankswitching with hotspots, "
- "but instead watches A13 of called addresses:\n"
- "Bank 0 @ $F000 - $FFFF (A13 = 1)\n"
- "Bank 1 @ $D000 - $DFFF (A13 = 0)\n"
- "\n"
- "Changing banks is not currently supported, since it "
- "would immediately switch on the next address change\n";
+ "Monitors access to hotspot $01FE, and uses "
+ "upper 3 bits of databus for bank number:\n"
+ "Bank 0 @ $F000 - $FFFF (DATA = 111, D5 = 1)\n"
+ "Bank 1 @ $D000 - $DFFF (DATA = 110, D5 = 0)\n";
- addBaseInformation(2 * 4096, "Activision", info);
+ int xpos = 10,
+ ypos = addBaseInformation(2 * 4096, "Activision", info) + myLineHeight;
+
+ VariantList items;
+ VarList::push_back(items, "0 ($01FE, D5=1)");
+ VarList::push_back(items, "1 ($01FE, D5=0)");
+ myBank =
+ new PopUpWidget(boss, _font, xpos, ypos-2,
+ _font.getStringWidth("0 ($01FE, D5=1)"),
+ myLineHeight, items, "Set bank ",
+ _font.getStringWidth("Set bank "), kBankChanged);
+ myBank->setTarget(this);
+ addFocusWidget(myBank);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void CartridgeFEWidget::loadConfig()
+{
+ myBank->setSelectedIndex(myCart.getBank());
+
+ CartDebugWidget::loadConfig();
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void CartridgeFEWidget::handleCommand(CommandSender* sender,
+ int cmd, int data, int id)
+{
+ if(cmd == kBankChanged)
+ {
+ myCart.unlockBank();
+ myCart.bank(myBank->getSelected());
+ myCart.lockBank();
+ invalidate();
+ }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/src/debugger/gui/CartFEWidget.hxx b/src/debugger/gui/CartFEWidget.hxx
index 07b00b390..23a48b0b2 100644
--- a/src/debugger/gui/CartFEWidget.hxx
+++ b/src/debugger/gui/CartFEWidget.hxx
@@ -19,6 +19,8 @@
#define CARTRIDGEFE_WIDGET_HXX
class CartridgeFE;
+class PopUpWidget;
+
#include "CartDebugWidget.hxx"
class CartridgeFEWidget : public CartDebugWidget
@@ -32,11 +34,14 @@ class CartridgeFEWidget : public CartDebugWidget
private:
CartridgeFE& myCart;
+ PopUpWidget* myBank;
+
+ enum { kBankChanged = 'bkCH' };
private:
// No implementation for non-bankswitched ROMs
- void loadConfig() override { }
- void handleCommand(CommandSender* sender, int cmd, int data, int id) override { }
+ void loadConfig() override;
+ void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
string bankState() override;
diff --git a/src/debugger/gui/CartMCWidget.cxx b/src/debugger/gui/CartMCWidget.cxx
deleted file mode 100644
index e0902cebf..000000000
--- a/src/debugger/gui/CartMCWidget.cxx
+++ /dev/null
@@ -1,143 +0,0 @@
-//============================================================================
-//
-// 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 "CartMC.hxx"
-#include "PopUpWidget.hxx"
-#include "CartMCWidget.hxx"
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-CartridgeMCWidget::CartridgeMCWidget(
- GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
- int x, int y, int w, int h, CartridgeMC& cart)
- : CartDebugWidget(boss, lfont, nfont, x, y, w, h),
- myCart(cart)
-{
- uInt32 size = 128 * 1024;
-
- string info =
- "MC cartridge, 128 1K slices ROM + 32 1K RAM\n"
- "Write $80 - $FF into a hotspot for ROM (128)\n"
- "Write $00 - $3F into a hotspot for RAM (32)\n"
- "Segment 0 @ $F000 - $F3FF (hotspot = $3C)\n"
- "Segment 1 @ $F400 - $F7FF (hotspot = $3D)\n"
- "Segment 2 @ $F800 - $FBFF (hotspot = $3E)\n"
- "Segment 3 @ $FC00 - $FFFF (hotspot = $3F)\n"
- "\nTHIS SCHEME IS NOT FULLY IMPLEMENTED OR TESTED\n";
-
- int xpos = 10,
- ypos = addBaseInformation(size, "Chris Wilkson's Megacart", info) +
- myLineHeight;
-
- VariantList items;
- // Add 128 1K 'ROM' blocks
- for(uInt32 i = 0x80; i <= 0xFF; ++i)
- {
- const string& b = Variant(i).toString();
- VarList::push_back(items, b + " (ROM)", b);
- }
- // Add 64 512B 'RAM' blocks
- for(uInt32 i = 0x00; i <= 0x3F; ++i)
- {
- const string& b = Variant(i).toString();
- VarList::push_back(items, b + " (RAM)", b);
- }
-
- const int lwidth = _font.getStringWidth("Set slice for segment X ($3X) "),
- fwidth = _font.getStringWidth("255 (ROM)");
-
- mySlice0 =
- new PopUpWidget(boss, _font, xpos, ypos-2, fwidth,
- myLineHeight, items, "Set slice for segment 0 ($3C) ",
- lwidth, kSlice0Changed);
- mySlice0->setTarget(this);
- addFocusWidget(mySlice0);
- ypos += mySlice0->getHeight() + 4;
-
- mySlice1 =
- new PopUpWidget(boss, _font, xpos, ypos-2, fwidth,
- myLineHeight, items, "Set slice for segment 1 ($3D) ",
- lwidth, kSlice1Changed);
- mySlice1->setTarget(this);
- addFocusWidget(mySlice1);
- ypos += mySlice1->getHeight() + 4;
-
- mySlice2 =
- new PopUpWidget(boss, _font, xpos, ypos-2, fwidth,
- myLineHeight, items, "Set slice for segment 2 ($3E) ",
- lwidth, kSlice2Changed);
- mySlice2->setTarget(this);
- addFocusWidget(mySlice2);
- ypos += mySlice2->getHeight() + 4;
-
- mySlice3 =
- new PopUpWidget(boss, _font, xpos, ypos-2, fwidth,
- myLineHeight, items, "Set slice for segment 3 ($3F) ",
- lwidth, kSlice3Changed);
- mySlice3->setTarget(this);
- addFocusWidget(mySlice3);
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void CartridgeMCWidget::loadConfig()
-{
- mySlice0->setSelectedIndex(myCart.myCurrentBlock[0]);
- mySlice1->setSelectedIndex(myCart.myCurrentBlock[1]);
- mySlice2->setSelectedIndex(myCart.myCurrentBlock[2]);
- mySlice3->setSelectedIndex(myCart.myCurrentBlock[3]);
-
- CartDebugWidget::loadConfig();
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void CartridgeMCWidget::handleCommand(CommandSender* sender,
- int cmd, int data, int id)
-{
- myCart.unlockBank();
-
- switch(cmd)
- {
- case kSlice0Changed:
- myCart.myCurrentBlock[0] = mySlice0->getSelectedTag().toInt();
- break;
- case kSlice1Changed:
- myCart.myCurrentBlock[1] = mySlice1->getSelectedTag().toInt();
- break;
- case kSlice2Changed:
- myCart.myCurrentBlock[2] = mySlice2->getSelectedTag().toInt();
- break;
- case kSlice3Changed:
- myCart.myCurrentBlock[3] = mySlice3->getSelectedTag().toInt();
- break;
- }
-
- myCart.lockBank();
- invalidate();
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-string CartridgeMCWidget::bankState()
-{
- ostringstream& buf = buffer();
-
- buf << "Slices: " << std::dec
- << myCart.myCurrentBlock[0] << " / "
- << myCart.myCurrentBlock[1] << " / "
- << myCart.myCurrentBlock[2] << " / "
- << myCart.myCurrentBlock[3];
-
- return buf.str();
-}
diff --git a/src/debugger/gui/CartMCWidget.hxx b/src/debugger/gui/CartMCWidget.hxx
deleted file mode 100644
index 170d6248c..000000000
--- a/src/debugger/gui/CartMCWidget.hxx
+++ /dev/null
@@ -1,60 +0,0 @@
-//============================================================================
-//
-// 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 CARTRIDGEMC_WIDGET_HXX
-#define CARTRIDGEMC_WIDGET_HXX
-
-class CartridgeMC;
-class PopUpWidget;
-
-#include "CartDebugWidget.hxx"
-
-class CartridgeMCWidget : public CartDebugWidget
-{
- public:
- CartridgeMCWidget(GuiObject* boss, const GUI::Font& lfont,
- const GUI::Font& nfont,
- int x, int y, int w, int h,
- CartridgeMC& cart);
- virtual ~CartridgeMCWidget() = default;
-
- private:
- CartridgeMC& myCart;
- PopUpWidget *mySlice0, *mySlice1, *mySlice2, *mySlice3;
-
- enum {
- kSlice0Changed = 's0CH',
- kSlice1Changed = 's1CH',
- kSlice2Changed = 's2CH',
- kSlice3Changed = 's3CH'
- };
-
- private:
- void loadConfig() override;
- void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
-
- string bankState() override;
-
- // Following constructors and assignment operators not supported
- CartridgeMCWidget() = delete;
- CartridgeMCWidget(const CartridgeMCWidget&) = delete;
- CartridgeMCWidget(CartridgeMCWidget&&) = delete;
- CartridgeMCWidget& operator=(const CartridgeMCWidget&) = delete;
- CartridgeMCWidget& operator=(CartridgeMCWidget&&) = delete;
-};
-
-#endif
diff --git a/src/debugger/gui/CartMDMWidget.cxx b/src/debugger/gui/CartMDMWidget.cxx
index 4cd13fffc..a49cb4be7 100644
--- a/src/debugger/gui/CartMDMWidget.cxx
+++ b/src/debugger/gui/CartMDMWidget.cxx
@@ -64,7 +64,7 @@ CartridgeMDMWidget::CartridgeMDMWidget(
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeMDMWidget::loadConfig()
{
- myBank->setSelectedIndex(myCart.myCurrentBank);
+ myBank->setSelectedIndex(myCart.getBank());
myBankDisabled->setState(myCart.myBankingDisabled);
CartDebugWidget::loadConfig();
@@ -92,9 +92,9 @@ string CartridgeMDMWidget::bankState()
{
ostringstream& buf = buffer();
- buf << "Bank = " << std::dec << myCart.myCurrentBank
+ buf << "Bank = " << std::dec << myCart.getBank()
<< ", hotspot = " << "$" << Common::Base::HEX4
- << (myCart.myCurrentBank+0x800);
+ << (myCart.getBank()+0x800);
return buf.str();
}
diff --git a/src/debugger/gui/CartSBWidget.cxx b/src/debugger/gui/CartSBWidget.cxx
index 29b925494..ed102641e 100644
--- a/src/debugger/gui/CartSBWidget.cxx
+++ b/src/debugger/gui/CartSBWidget.cxx
@@ -65,7 +65,7 @@ CartridgeSBWidget::CartridgeSBWidget(
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeSBWidget::loadConfig()
{
- myBank->setSelectedIndex(myCart.myCurrentBank);
+ myBank->setSelectedIndex(myCart.getBank());
CartDebugWidget::loadConfig();
}
@@ -88,8 +88,8 @@ string CartridgeSBWidget::bankState()
{
ostringstream& buf = buffer();
- buf << "Bank = " << std::dec << myCart.myCurrentBank
- << ", hotspot = $" << Common::Base::HEX2 << (myCart.myCurrentBank + 0x800);
+ buf << "Bank = " << std::dec << myCart.getBank()
+ << ", hotspot = $" << Common::Base::HEX2 << (myCart.getBank() + 0x800);
return buf.str();
}
diff --git a/src/debugger/gui/CartUAWidget.cxx b/src/debugger/gui/CartUAWidget.cxx
index 1503ad13e..ba2482004 100644
--- a/src/debugger/gui/CartUAWidget.cxx
+++ b/src/debugger/gui/CartUAWidget.cxx
@@ -59,7 +59,7 @@ CartridgeUAWidget::CartridgeUAWidget(
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeUAWidget::loadConfig()
{
- myBank->setSelectedIndex(myCart.myCurrentBank);
+ myBank->setSelectedIndex(myCart.getBank());
CartDebugWidget::loadConfig();
}
@@ -83,8 +83,8 @@ string CartridgeUAWidget::bankState()
ostringstream& buf = buffer();
static const char* const spot[] = { "$200", "$240" };
- buf << "Bank = " << std::dec << myCart.myCurrentBank
- << ", hotspot = " << spot[myCart.myCurrentBank];
+ buf << "Bank = " << std::dec << myCart.getBank()
+ << ", hotspot = " << spot[myCart.getBank()];
return buf.str();
}
diff --git a/src/debugger/gui/PromptWidget.cxx b/src/debugger/gui/PromptWidget.cxx
index aa5acb51c..66b6b9a92 100644
--- a/src/debugger/gui/PromptWidget.cxx
+++ b/src/debugger/gui/PromptWidget.cxx
@@ -876,21 +876,21 @@ void PromptWidget::scrollToCurrent()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool PromptWidget::saveBuffer(string& filename)
+bool PromptWidget::saveBuffer(const FilesystemNode& file)
{
- ofstream out(filename);
+ ofstream out(file.getPath());
if(!out.is_open())
return false;
- for(int start=0; start<_promptStartPos; start+=_lineWidth)
+ for(int start = 0; start < _promptStartPos; start += _lineWidth)
{
- int end = start+_lineWidth-1;
+ int end = start + _lineWidth - 1;
- // look for first non-space, printing char from end of line
+ // Look for first non-space, printing char from end of line
while( char(_buffer[end] & 0xff) <= ' ' && end >= start)
end--;
- // spit out the line minus its trailing junk.
+ // Spit out the line minus its trailing junk
// Strip off any color/inverse bits
for(int j = start; j <= end; ++j)
out << char(_buffer[j] & 0xff);
diff --git a/src/debugger/gui/PromptWidget.hxx b/src/debugger/gui/PromptWidget.hxx
index 0b7ff1cd4..95e3a6142 100644
--- a/src/debugger/gui/PromptWidget.hxx
+++ b/src/debugger/gui/PromptWidget.hxx
@@ -21,6 +21,7 @@
#include
class ScrollBarWidget;
+class FilesystemNode;
#include "Widget.hxx"
#include "Command.hxx"
@@ -38,7 +39,7 @@ class PromptWidget : public Widget, public CommandSender
int vprintf(const char* format, va_list argptr);
void print(const string& str);
void printPrompt();
- bool saveBuffer(string& filename);
+ bool saveBuffer(const FilesystemNode& file);
// Clear screen and erase all history
void clearScreen();
diff --git a/src/debugger/gui/RomListWidget.cxx b/src/debugger/gui/RomListWidget.cxx
index 4fbc0ca4d..a2fe75564 100644
--- a/src/debugger/gui/RomListWidget.cxx
+++ b/src/debugger/gui/RomListWidget.cxx
@@ -67,7 +67,7 @@ RomListWidget::RomListWidget(GuiObject* boss, const GUI::Font& lfont,
_labelWidth = std::max(16, int(0.20 * (numchars - 12))) * fontWidth - 1;
_bytesWidth = 12 * fontWidth;
- //////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////
// Add checkboxes
int ypos = _y + 2;
@@ -461,7 +461,7 @@ void RomListWidget::drawWidget(bool hilite)
s.vLine(_x + CheckboxWidget::boxSize() + 5, _y, _y + _h - 1, kColor);
// Draw the list items
- int ccountw = _fontWidth << 2,
+ int ccountw = _fontWidth << 3,
large_disasmw = _w - l.x() - _labelWidth,
medium_disasmw = large_disasmw - r.width(),
small_disasmw = medium_disasmw - (ccountw << 1),
@@ -582,7 +582,7 @@ void RomListWidget::startEditMode()
{
case CartDebug::GFX:
case CartDebug::PGFX:
- _base = DiStella::settings.gfx_format;
+ _base = DiStella::settings.gfxFormat;
break;
default:
_base = Common::Base::format();
diff --git a/src/debugger/gui/RomWidget.cxx b/src/debugger/gui/RomWidget.cxx
index 921c322c8..4a5a19bc1 100644
--- a/src/debugger/gui/RomWidget.cxx
+++ b/src/debugger/gui/RomWidget.cxx
@@ -122,18 +122,18 @@ void RomWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
case RomListWidget::kTentativeCodeCmd:
{
// 'data' is the boolean value
- DiStella::settings.resolve_code = data;
+ DiStella::settings.resolveCode = data;
instance().settings().setValue("dis.resolve",
- DiStella::settings.resolve_code);
+ DiStella::settings.resolveCode);
invalidate();
break;
}
case RomListWidget::kPCAddressesCmd:
// 'data' is the boolean value
- DiStella::settings.show_addresses = data;
+ DiStella::settings.showAddresses = data;
instance().settings().setValue("dis.showaddr",
- DiStella::settings.show_addresses);
+ DiStella::settings.showAddresses);
invalidate();
break;
@@ -141,12 +141,12 @@ void RomWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
// 'data' is the boolean value
if(data)
{
- DiStella::settings.gfx_format = Common::Base::F_2;
+ DiStella::settings.gfxFormat = Common::Base::F_2;
instance().settings().setValue("dis.gfxformat", "2");
}
else
{
- DiStella::settings.gfx_format = Common::Base::F_16;
+ DiStella::settings.gfxFormat = Common::Base::F_16;
instance().settings().setValue("dis.gfxformat", "16");
}
invalidate();
@@ -154,9 +154,9 @@ void RomWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
case RomListWidget::kAddrRelocationCmd:
// 'data' is the boolean value
- DiStella::settings.rflag = data;
+ DiStella::settings.rFlag = data;
instance().settings().setValue("dis.relocate",
- DiStella::settings.rflag);
+ DiStella::settings.rFlag);
invalidate();
break;
}
diff --git a/src/debugger/gui/TiaInfoWidget.cxx b/src/debugger/gui/TiaInfoWidget.cxx
index ba444a561..f42d5abd8 100644
--- a/src/debugger/gui/TiaInfoWidget.cxx
+++ b/src/debugger/gui/TiaInfoWidget.cxx
@@ -129,7 +129,7 @@ void TiaInfoWidget::loadConfig()
TIADebug& tia = dbg.tiaDebug();
myFrameCount->setText(Common::Base::toString(tia.frameCount(), Common::Base::F_10));
- myFrameCycles->setText(Common::Base::toString(dbg.cycles(), Common::Base::F_10));
+ myFrameCycles->setText(Common::Base::toString(tia.frameCycles(), Common::Base::F_10));
myVSync->setState(tia.vsync());
myVBlank->setState(tia.vblank());
diff --git a/src/debugger/gui/module.mk b/src/debugger/gui/module.mk
index bdf5e627c..82eea94a4 100644
--- a/src/debugger/gui/module.mk
+++ b/src/debugger/gui/module.mk
@@ -57,7 +57,6 @@ MODULE_OBJS := \
src/debugger/gui/CartFAWidget.o \
src/debugger/gui/CartFA2Widget.o \
src/debugger/gui/CartFEWidget.o \
- src/debugger/gui/CartMCWidget.o \
src/debugger/gui/CartMDMWidget.o \
src/debugger/gui/CartSBWidget.o \
src/debugger/gui/CartUAWidget.o \
diff --git a/src/emucore/AmigaMouse.cxx b/src/emucore/AmigaMouse.cxx
deleted file mode 100644
index 4c0eaf509..000000000
--- a/src/emucore/AmigaMouse.cxx
+++ /dev/null
@@ -1,122 +0,0 @@
-//============================================================================
-//
-// 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 "Event.hxx"
-#include "System.hxx"
-#include "TIA.hxx"
-#include "AmigaMouse.hxx"
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-AmigaMouse::AmigaMouse(Jack jack, const Event& event, const System& system)
- : Controller(jack, event, system, Controller::AmigaMouse),
- myHCounter(0),
- myVCounter(0),
- myMouseEnabled(false)
-{
- // This code in ::read() is set up to always return IOPortA values in
- // the lower 4 bits data value
- // As such, the jack type (left or right) isn't necessary here
-
- myTrakBallCountH = myTrakBallCountV = 0;
- myTrakBallLinesH = myTrakBallLinesV = 1;
-
- myTrakBallLeft = myTrakBallDown = myScanCountV = myScanCountH =
- myCountV = myCountH = 0;
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-uInt8 AmigaMouse::read()
-{
- int scanline = mySystem.tia().scanlines();
-
- if(myScanCountV > scanline) myScanCountV = 0;
- if(myScanCountH > scanline) myScanCountH = 0;
- while((myScanCountV + myTrakBallLinesV) < scanline)
- {
- if(myTrakBallCountV)
- {
- if(myTrakBallDown) myCountV--;
- else myCountV++;
- myTrakBallCountV--;
- }
- myScanCountV += myTrakBallLinesV;
- }
-
- while((myScanCountH + myTrakBallLinesH) < scanline)
- {
- if(myTrakBallCountH)
- {
- if(myTrakBallLeft) myCountH--;
- else myCountH++;
- myTrakBallCountH--;
- }
- myScanCountH += myTrakBallLinesH;
- }
-
- myCountV &= 0x03;
- myCountH &= 0x03;
-
- static constexpr uInt32 ourTableH[4] = { 0x00, 0x10, 0x50, 0x40 };
- static constexpr uInt32 ourTableV[4] = { 0x00, 0x80, 0xa0, 0x20 };
- uInt8 IOPortA = ourTableV[myCountV] | ourTableH[myCountH];
-
- myDigitalPinState[One] = IOPortA & 0x10;
- myDigitalPinState[Two] = IOPortA & 0x20;
- myDigitalPinState[Three] = IOPortA & 0x40;
- myDigitalPinState[Four] = IOPortA & 0x80;
-
- return (IOPortA >> 4);
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void AmigaMouse::update()
-{
- if(!myMouseEnabled)
- return;
-
- // Get the current mouse position
- myHCounter = myEvent.get(Event::MouseAxisXValue);
- myVCounter = myEvent.get(Event::MouseAxisYValue);
-
- if(myVCounter < 0) myTrakBallLeft = 1;
- else myTrakBallLeft = 0;
- if(myHCounter < 0) myTrakBallDown = 0;
- else myTrakBallDown = 1;
- myTrakBallCountH = abs(myVCounter >> 1);
- myTrakBallCountV = abs(myHCounter >> 1);
- myTrakBallLinesH = mySystem.tia().height() / (myTrakBallCountH + 1);
- if(myTrakBallLinesH == 0) myTrakBallLinesH = 1;
- myTrakBallLinesV = mySystem.tia().height() / (myTrakBallCountV + 1);
- if(myTrakBallLinesV == 0) myTrakBallLinesV = 1;
-
- // Get mouse button state
- myDigitalPinState[Six] = (myEvent.get(Event::MouseButtonLeftValue) == 0) &&
- (myEvent.get(Event::MouseButtonRightValue) == 0);
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool AmigaMouse::setMouseControl(
- Controller::Type xtype, int xid, Controller::Type ytype, int yid)
-{
- // Currently, the various trakball controllers take full control of the
- // mouse, and use both mouse buttons for the single fire button
- // As well, there's no separate setting for x and y axis, so any
- // combination of Controller and id is valid
- myMouseEnabled = (xtype == myType || ytype == myType) &&
- (xid != -1 || yid != -1);
- return true;
-}
diff --git a/src/emucore/AmigaMouse.hxx b/src/emucore/AmigaMouse.hxx
index 872b95dba..7ed9d1aca 100644
--- a/src/emucore/AmigaMouse.hxx
+++ b/src/emucore/AmigaMouse.hxx
@@ -18,17 +18,9 @@
#ifndef AMIGAMOUSE_HXX
#define AMIGAMOUSE_HXX
-#include "bspf.hxx"
-#include "Control.hxx"
-#include "Event.hxx"
+#include "PointingDevice.hxx"
-/**
- Trakball-like controller emulating the original Amiga mouse.
- This code was heavily borrowed from z26.
-
- @author Stephen Anthony & z26 team
-*/
-class AmigaMouse : public Controller
+class AmigaMouse : public PointingDevice
{
public:
/**
@@ -38,73 +30,21 @@ class AmigaMouse : public Controller
@param event The event object to use for events
@param system The system using this controller
*/
- AmigaMouse(Jack jack, const Event& event, const System& system);
+ AmigaMouse(Jack jack, const Event& event, const System& system)
+ : PointingDevice(jack, event, system, Controller::AmigaMouse,
+ trackballSensitivity) { }
virtual ~AmigaMouse() = default;
- public:
- using Controller::read;
+ protected:
+ uInt8 ioPortA(uInt8 countH, uInt8 countV, uInt8, uInt8) override
+ {
+ static constexpr uInt32 ourTableH[4] = { 0x00, 0x80, 0xa0, 0x20 };
+ static constexpr uInt32 ourTableV[4] = { 0x00, 0x10, 0x50, 0x40 };
- /**
- Read the entire state of all digital pins for this controller.
- Note that this method must use the lower 4 bits, and zero the upper bits.
+ return ourTableH[countH] | ourTableV[countV];
+ }
- @return The state of all digital pins
- */
- uInt8 read() override;
-
- /**
- Update the entire digital and analog pin state according to the
- events currently set.
- */
- void update() override;
-
- /**
- Determines how this controller will treat values received from the
- X/Y axis and left/right buttons of the mouse. Since not all controllers
- use the mouse the same way (or at all), it's up to the specific class to
- decide how to use this data.
-
- In the current implementation, the left button is tied to the X axis,
- and the right one tied to the Y axis.
-
- @param xtype The controller to use for x-axis data
- @param xid The controller ID to use for x-axis data (-1 for no id)
- @param ytype The controller to use for y-axis data
- @param yid The controller ID to use for y-axis data (-1 for no id)
-
- @return Whether the controller supports using the mouse
- */
- bool setMouseControl(Controller::Type xtype, int xid,
- Controller::Type ytype, int yid) override;
-
- private:
- // Counter to iterate through the gray codes
- int myHCounter, myVCounter;
-
- // How many new horizontal and vertical values this frame
- int myTrakBallCountH, myTrakBallCountV;
-
- // How many lines to wait before sending new horz and vert val
- int myTrakBallLinesH, myTrakBallLinesV;
-
- // Was TrakBall moved left or moved right instead
- int myTrakBallLeft;
-
- // Was TrakBall moved down or moved up instead
- int myTrakBallDown;
-
- int myScanCountH, myScanCountV, myCountH, myCountV;
-
- // Whether to use the mouse to emulate this controller
- int myMouseEnabled;
-
- private:
- // Following constructors and assignment operators not supported
- AmigaMouse() = delete;
- AmigaMouse(const AmigaMouse&) = delete;
- AmigaMouse(AmigaMouse&&) = delete;
- AmigaMouse& operator=(const AmigaMouse&) = delete;
- AmigaMouse& operator=(AmigaMouse&&) = delete;
+ static constexpr float trackballSensitivity = 0.8f;
};
-#endif
+#endif // AMIGAMOUSE_HXX
diff --git a/src/emucore/AtariMouse.cxx b/src/emucore/AtariMouse.cxx
deleted file mode 100644
index f495a7bf9..000000000
--- a/src/emucore/AtariMouse.cxx
+++ /dev/null
@@ -1,122 +0,0 @@
-//============================================================================
-//
-// 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 "Event.hxx"
-#include "System.hxx"
-#include "TIA.hxx"
-#include "AtariMouse.hxx"
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-AtariMouse::AtariMouse(Jack jack, const Event& event, const System& system)
- : Controller(jack, event, system, Controller::AtariMouse),
- myHCounter(0),
- myVCounter(0),
- myMouseEnabled(false)
-{
- // This code in ::read() is set up to always return IOPortA values in
- // the lower 4 bits data value
- // As such, the jack type (left or right) isn't necessary here
-
- myTrakBallCountH = myTrakBallCountV = 0;
- myTrakBallLinesH = myTrakBallLinesV = 1;
-
- myTrakBallLeft = myTrakBallDown = myScanCountV = myScanCountH =
- myCountV = myCountH = 0;
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-uInt8 AtariMouse::read()
-{
- int scanline = mySystem.tia().scanlines();
-
- if(myScanCountV > scanline) myScanCountV = 0;
- if(myScanCountH > scanline) myScanCountH = 0;
- while((myScanCountV + myTrakBallLinesV) < scanline)
- {
- if(myTrakBallCountV)
- {
- if(myTrakBallDown) myCountV--;
- else myCountV++;
- myTrakBallCountV--;
- }
- myScanCountV += myTrakBallLinesV;
- }
-
- while((myScanCountH + myTrakBallLinesH) < scanline)
- {
- if(myTrakBallCountH)
- {
- if(myTrakBallLeft) myCountH--;
- else myCountH++;
- myTrakBallCountH--;
- }
- myScanCountH += myTrakBallLinesH;
- }
-
- myCountV &= 0x03;
- myCountH &= 0x03;
-
- static constexpr uInt32 ourTableH[4] = { 0x00, 0x80, 0xc0, 0x40 };
- static constexpr uInt32 ourTableV[4] = { 0x00, 0x10, 0x30, 0x20 };
- uInt8 IOPortA = ourTableV[myCountV] | ourTableH[myCountH];
-
- myDigitalPinState[One] = IOPortA & 0x10;
- myDigitalPinState[Two] = IOPortA & 0x20;
- myDigitalPinState[Three] = IOPortA & 0x40;
- myDigitalPinState[Four] = IOPortA & 0x80;
-
- return (IOPortA >> 4);
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void AtariMouse::update()
-{
- if(!myMouseEnabled)
- return;
-
- // Get the current mouse position
- myHCounter = myEvent.get(Event::MouseAxisXValue);
- myVCounter = myEvent.get(Event::MouseAxisYValue);
-
- if(myVCounter < 0) myTrakBallLeft = 1;
- else myTrakBallLeft = 0;
- if(myHCounter < 0) myTrakBallDown = 0;
- else myTrakBallDown = 1;
- myTrakBallCountH = abs(myVCounter >> 1);
- myTrakBallCountV = abs(myHCounter >> 1);
- myTrakBallLinesH = mySystem.tia().height() / (myTrakBallCountH + 1);
- if(myTrakBallLinesH == 0) myTrakBallLinesH = 1;
- myTrakBallLinesV = mySystem.tia().height() / (myTrakBallCountV + 1);
- if(myTrakBallLinesV == 0) myTrakBallLinesV = 1;
-
- // Get mouse button state
- myDigitalPinState[Six] = (myEvent.get(Event::MouseButtonLeftValue) == 0) &&
- (myEvent.get(Event::MouseButtonRightValue) == 0);
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool AtariMouse::setMouseControl(
- Controller::Type xtype, int xid, Controller::Type ytype, int yid)
-{
- // Currently, the various trakball controllers take full control of the
- // mouse, and use both mouse buttons for the single fire button
- // As well, there's no separate setting for x and y axis, so any
- // combination of Controller and id is valid
- myMouseEnabled = (xtype == myType || ytype == myType) &&
- (xid != -1 || yid != -1);
- return true;
-}
diff --git a/src/emucore/AtariMouse.hxx b/src/emucore/AtariMouse.hxx
index 46637d9c4..255ecbb7b 100644
--- a/src/emucore/AtariMouse.hxx
+++ b/src/emucore/AtariMouse.hxx
@@ -18,93 +18,33 @@
#ifndef ATARIMOUSE_HXX
#define ATARIMOUSE_HXX
-#include "bspf.hxx"
-#include "Control.hxx"
-#include "Event.hxx"
+#include "PointingDevice.hxx"
-/**
- Trakball-like controller emulating the Atari ST mouse.
- This code was heavily borrowed from z26.
-
- @author Stephen Anthony & z26 team
-*/
-class AtariMouse : public Controller
+class AtariMouse : public PointingDevice
{
public:
/**
- Create a new AtariMouse controller plugged into the specified jack
+ Create a new Atari Mouse controller plugged into the specified jack
@param jack The jack the controller is plugged into
@param event The event object to use for events
@param system The system using this controller
*/
- AtariMouse(Jack jack, const Event& event, const System& system);
+ AtariMouse(Jack jack, const Event& event, const System& system)
+ : PointingDevice(jack, event, system, Controller::AtariMouse,
+ trackballSensitivity) { }
virtual ~AtariMouse() = default;
- public:
- using Controller::read;
+ protected:
+ uInt8 ioPortA(uInt8 countH, uInt8 countV, uInt8, uInt8) override
+ {
+ static constexpr uInt32 ourTableH[4] = { 0x00, 0x10, 0x30, 0x20 };
+ static constexpr uInt32 ourTableV[4] = { 0x00, 0x80, 0xc0, 0x40 };
- /**
- Read the entire state of all digital pins for this controller.
- Note that this method must use the lower 4 bits, and zero the upper bits.
+ return ourTableH[countH] | ourTableV[countV];
+ }
- @return The state of all digital pins
- */
- uInt8 read() override;
-
- /**
- Update the entire digital and analog pin state according to the
- events currently set.
- */
- void update() override;
-
- /**
- Determines how this controller will treat values received from the
- X/Y axis and left/right buttons of the mouse. Since not all controllers
- use the mouse the same way (or at all), it's up to the specific class to
- decide how to use this data.
-
- In the current implementation, the left button is tied to the X axis,
- and the right one tied to the Y axis.
-
- @param xtype The controller to use for x-axis data
- @param xid The controller ID to use for x-axis data (-1 for no id)
- @param ytype The controller to use for y-axis data
- @param yid The controller ID to use for y-axis data (-1 for no id)
-
- @return Whether the controller supports using the mouse
- */
- bool setMouseControl(Controller::Type xtype, int xid,
- Controller::Type ytype, int yid) override;
-
- private:
- // Counter to iterate through the gray codes
- int myHCounter, myVCounter;
-
- // How many new horizontal and vertical values this frame
- int myTrakBallCountH, myTrakBallCountV;
-
- // How many lines to wait before sending new horz and vert val
- int myTrakBallLinesH, myTrakBallLinesV;
-
- // Was TrakBall moved left or moved right instead
- int myTrakBallLeft;
-
- // Was TrakBall moved down or moved up instead
- int myTrakBallDown;
-
- int myScanCountH, myScanCountV, myCountH, myCountV;
-
- // Whether to use the mouse to emulate this controller
- int myMouseEnabled;
-
- private:
- // Following constructors and assignment operators not supported
- AtariMouse() = delete;
- AtariMouse(const AtariMouse&) = delete;
- AtariMouse(AtariMouse&&) = delete;
- AtariMouse& operator=(const AtariMouse&) = delete;
- AtariMouse& operator=(AtariMouse&&) = delete;
+ static constexpr float trackballSensitivity = 0.8f;
};
-#endif
+#endif // ATARIMOUSE_HXX
diff --git a/src/emucore/AtariVox.cxx b/src/emucore/AtariVox.cxx
index 55e417d54..34695edf8 100644
--- a/src/emucore/AtariVox.cxx
+++ b/src/emucore/AtariVox.cxx
@@ -99,13 +99,12 @@ void AtariVox::write(DigitalPin pin, bool value)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AtariVox::clockDataIn(bool value)
{
- uInt32 cycle = mySystem.cycles();
-
if(value && (myShiftCount == 0))
return;
// If this is the first write this frame, or if it's been a long time
// since the last write, start a new data byte.
+ uInt64 cycle = mySystem.cycles();
if((cycle < myLastDataWriteCycle) || (cycle > myLastDataWriteCycle + 1000))
{
myShiftRegister = 0;
@@ -138,6 +137,13 @@ void AtariVox::clockDataIn(bool value)
myLastDataWriteCycle = cycle;
}
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void AtariVox::reset()
+{
+ myLastDataWriteCycle = 0;
+ myEEPROM->systemReset();
+}
+
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AtariVox::close()
{
@@ -145,16 +151,6 @@ void AtariVox::close()
myEEPROM.reset();
}
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void AtariVox::systemCyclesReset()
-{
- myLastDataWriteCycle -= mySystem.cycles();
-
- // The EEPROM keeps track of cycle counts, and needs to know when the
- // cycles are reset
- myEEPROM->systemCyclesReset();
-}
-
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string AtariVox::about() const
{
diff --git a/src/emucore/AtariVox.hxx b/src/emucore/AtariVox.hxx
index 323925d2b..2992b052d 100644
--- a/src/emucore/AtariVox.hxx
+++ b/src/emucore/AtariVox.hxx
@@ -79,6 +79,13 @@ class AtariVox : public Controller
*/
void update() override { }
+ /**
+ Notification method invoked by the system after its reset method has
+ been called. It may be necessary to override this method for
+ controllers that need to know a reset has occurred.
+ */
+ void reset() override;
+
/**
Notification method invoked by the system indicating that the
console is about to be destroyed. It may be necessary to override
@@ -86,13 +93,6 @@ class AtariVox : public Controller
*/
void close() override;
- /**
- Notification method invoked by the system right before the
- system resets its cycle counter to zero. It may be necessary
- to override this method for devices that remember cycle counts.
- */
- void systemCyclesReset() override;
-
string about() const override;
private:
@@ -121,7 +121,7 @@ class AtariVox : public Controller
// The real SpeakJet chip reads data at 19200 bits/sec. Alex's
// driver code sends data at 62 CPU cycles per bit, which is
// "close enough".
- uInt32 myLastDataWriteCycle;
+ uInt64 myLastDataWriteCycle;
// Holds information concerning serial port usage
string myAboutString;
diff --git a/src/emucore/BSType.hxx b/src/emucore/BSType.hxx
index 88b780621..744bfb5d0 100644
--- a/src/emucore/BSType.hxx
+++ b/src/emucore/BSType.hxx
@@ -28,8 +28,7 @@ enum class BSType {
_CM, _CTY, _CV, _CVP, _DASH, _DF, _DFSC,
_DPC, _DPCP, _E0, _E7, _EF, _EFSC, _F0,
_F4, _F4SC, _F6, _F6SC, _F8, _F8SC, _FA,
- _FA2, _FE, _MC, _MDM, _SB, _UA, _WD,
- _X07,
+ _FA2, _FE, _MDM, _SB, _UA, _WD, _X07,
NumSchemes
};
@@ -85,7 +84,6 @@ static BSDescription BSList[int(BSType::NumSchemes)] = {
{ "FA", "FA (CBS RAM Plus)" },
{ "FA2", "FA2 (CBS RAM Plus 24/28K)" },
{ "FE", "FE (8K Decathlon)" },
- { "MC", "MC (C. Wilkson Megacart)" },
{ "MDM", "MDM (Menu Driven Megacart)" },
{ "SB", "SB (128-256K SUPERbank)" },
{ "UA", "UA (8K UA Ltd.)" },
diff --git a/src/emucore/Cart.cxx b/src/emucore/Cart.cxx
index 05063f38c..efab74363 100644
--- a/src/emucore/Cart.cxx
+++ b/src/emucore/Cart.cxx
@@ -45,10 +45,10 @@ void Cartridge::setAbout(const string& about, const string& type,
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge::saveROM(ofstream& out) const
{
- int size = -1;
+ uInt32 size = 0;
const uInt8* image = getImage(size);
- if(image == nullptr || size <= 0)
+ if(image == nullptr || size == 0)
{
cerr << "save not supported" << endl;
return false;
diff --git a/src/emucore/Cart.hxx b/src/emucore/Cart.hxx
index ba3a0c8fd..cd6e175d3 100644
--- a/src/emucore/Cart.hxx
+++ b/src/emucore/Cart.hxx
@@ -146,7 +146,7 @@ class Cartridge : public Device
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- virtual const uInt8* getImage(int& size) const = 0;
+ virtual const uInt8* getImage(uInt32& size) const = 0;
/**
Informs the cartridge about the name of the ROM file used when
diff --git a/src/emucore/Cart0840.cxx b/src/emucore/Cart0840.cxx
index 877fed9cd..71aad05b7 100644
--- a/src/emucore/Cart0840.cxx
+++ b/src/emucore/Cart0840.cxx
@@ -22,7 +22,7 @@
Cartridge0840::Cartridge0840(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings),
- myCurrentBank(0)
+ myBankOffset(0)
{
// Copy the ROM image into my buffer
memcpy(myImage, image.get(), std::min(8192u, size));
@@ -46,19 +46,19 @@ void Cartridge0840::install(System& system)
// Get the page accessing methods for the hot spots since they overlap
// areas within the TIA we'll need to forward requests to the TIA
- myHotSpotPageAccess[0] = mySystem->getPageAccess(0x0800 >> System::PAGE_SHIFT);
- myHotSpotPageAccess[1] = mySystem->getPageAccess(0x0900 >> System::PAGE_SHIFT);
- myHotSpotPageAccess[2] = mySystem->getPageAccess(0x0A00 >> System::PAGE_SHIFT);
- myHotSpotPageAccess[3] = mySystem->getPageAccess(0x0B00 >> System::PAGE_SHIFT);
- myHotSpotPageAccess[4] = mySystem->getPageAccess(0x0C00 >> System::PAGE_SHIFT);
- myHotSpotPageAccess[5] = mySystem->getPageAccess(0x0D00 >> System::PAGE_SHIFT);
- myHotSpotPageAccess[6] = mySystem->getPageAccess(0x0E00 >> System::PAGE_SHIFT);
- myHotSpotPageAccess[7] = mySystem->getPageAccess(0x0F00 >> System::PAGE_SHIFT);
+ myHotSpotPageAccess[0] = mySystem->getPageAccess(0x0800);
+ myHotSpotPageAccess[1] = mySystem->getPageAccess(0x0900);
+ myHotSpotPageAccess[2] = mySystem->getPageAccess(0x0A00);
+ myHotSpotPageAccess[3] = mySystem->getPageAccess(0x0B00);
+ myHotSpotPageAccess[4] = mySystem->getPageAccess(0x0C00);
+ myHotSpotPageAccess[5] = mySystem->getPageAccess(0x0D00);
+ myHotSpotPageAccess[6] = mySystem->getPageAccess(0x0E00);
+ myHotSpotPageAccess[7] = mySystem->getPageAccess(0x0F00);
// Set the page accessing methods for the hot spots
System::PageAccess access(this, System::PA_READ);
- for(uInt32 i = 0x0800; i < 0x0FFF; i += (1 << System::PAGE_SHIFT))
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ for(uInt16 addr = 0x0800; addr < 0x0FFF; addr += System::PAGE_SIZE)
+ mySystem->setPageAccess(addr, access);
// Install pages for bank 0
bank(myStartBank);
@@ -86,15 +86,10 @@ uInt8 Cartridge0840::peek(uInt16 address)
break;
}
- if(!(address & 0x1000))
- {
- // Because of the way we've set up accessing above, we can only
- // get here when the addresses are from 0x800 - 0xFFF
- int hotspot = ((address & 0x0F00) >> 8) - 8;
- return myHotSpotPageAccess[hotspot].device->peek(address);
- }
-
- return 0;
+ // Because of the way we've set up accessing above, we can only
+ // get here when the addresses are from 0x800 - 0xFFF
+ int hotspot = ((address & 0x0F00) >> 8) - 8;
+ return myHotSpotPageAccess[hotspot].device->peek(address);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -119,13 +114,14 @@ bool Cartridge0840::poke(uInt16 address, uInt8 value)
break;
}
+ // Because of the way accessing is set up, we will may get here by
+ // doing a write to 0x800 - 0xFFF or cart; we ignore the cart write
if(!(address & 0x1000))
{
- // Because of the way we've set up accessing above, we can only
- // get here when the addresses are from 0x800 - 0xFFF
int hotspot = ((address & 0x0F00) >> 8) - 8;
myHotSpotPageAccess[hotspot].device->poke(address, value);
}
+
return false;
}
@@ -135,18 +131,17 @@ bool Cartridge0840::bank(uInt16 bank)
if(bankLocked()) return false;
// Remember what bank we're in
- myCurrentBank = bank;
- uInt16 offset = myCurrentBank << 12;
+ myBankOffset = bank << 12;
// Setup the page access methods for the current bank
System::PageAccess access(this, System::PA_READ);
// Map ROM image into the system
- for(uInt32 address = 0x1000; address < 0x2000; address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
@@ -154,7 +149,7 @@ bool Cartridge0840::bank(uInt16 bank)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 Cartridge0840::getBank() const
{
- return myCurrentBank;
+ return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -166,12 +161,12 @@ uInt16 Cartridge0840::bankCount() const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge0840::patch(uInt16 address, uInt8 value)
{
- myImage[(myCurrentBank << 12) + (address & 0x0fff)] = value;
+ myImage[myBankOffset + (address & 0x0fff)] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* Cartridge0840::getImage(int& size) const
+const uInt8* Cartridge0840::getImage(uInt32& size) const
{
size = 8192;
return myImage;
@@ -183,7 +178,7 @@ bool Cartridge0840::save(Serializer& out) const
try
{
out.putString(name());
- out.putShort(myCurrentBank);
+ out.putShort(myBankOffset);
}
catch(...)
{
@@ -202,7 +197,7 @@ bool Cartridge0840::load(Serializer& in)
if(in.getString() != name())
return false;
- myCurrentBank = in.getShort();
+ myBankOffset = in.getShort();
}
catch(...)
{
@@ -211,7 +206,7 @@ bool Cartridge0840::load(Serializer& in)
}
// Remember what bank we were in
- bank(myCurrentBank);
+ bank(myBankOffset);
return true;
}
diff --git a/src/emucore/Cart0840.hxx b/src/emucore/Cart0840.hxx
index ebc6965df..e5c5d0cbb 100644
--- a/src/emucore/Cart0840.hxx
+++ b/src/emucore/Cart0840.hxx
@@ -27,7 +27,8 @@
/**
Cartridge class used for 0840 "Econobanking" 8K bankswitched games. There
- are two 4K banks.
+ are two 4K banks, which are switched by accessing $0800 (bank 0) and
+ $0840 (bank 1).
@author Fred X. Quimby
*/
@@ -92,7 +93,7 @@ class Cartridge0840 : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -150,8 +151,8 @@ class Cartridge0840 : public Cartridge
// The 8K ROM image of the cartridge
uInt8 myImage[8192];
- // Indicates which bank is currently active
- uInt16 myCurrentBank;
+ // Indicates the offset into the ROM image (aligns to current bank)
+ uInt16 myBankOffset;
// Previous Device's page access
System::PageAccess myHotSpotPageAccess[8];
diff --git a/src/emucore/Cart2K.cxx b/src/emucore/Cart2K.cxx
index 005687eaf..262ebfd2b 100644
--- a/src/emucore/Cart2K.cxx
+++ b/src/emucore/Cart2K.cxx
@@ -31,11 +31,8 @@ Cartridge2K::Cartridge2K(const BytePtr& image, uInt32 size,
while(mySize < size)
mySize <<= 1;
- // The smallest addressable area by Stella is 64 bytes
- // This should really be read from the System, but for now I'm going
- // to cheat a little and hard-code it to 64 (aka 2^6)
- if(mySize < 64)
- mySize = 64;
+ // We can't use a size smaller than the minimum page size in Stella
+ mySize = std::max(mySize, System::PAGE_SIZE);
// Initialize ROM with illegal 6502 opcode that causes a real 6502 to jam
myImage = make_unique(mySize);
@@ -62,28 +59,17 @@ void Cartridge2K::install(System& system)
mySystem = &system;
// Map ROM image into the system
+ // Note that we don't need our own peek/poke methods, since the mapping
+ // takes care of the entire address space
System::PageAccess access(this, System::PA_READ);
- for(uInt32 address = 0x1000; address < 0x2000; address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[address & myMask];
- access.codeAccessBase = &myCodeAccessBase[address & myMask];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[addr & myMask];
+ access.codeAccessBase = &myCodeAccessBase[addr & myMask];
+ mySystem->setPageAccess(addr, access);
}
}
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-uInt8 Cartridge2K::peek(uInt16 address)
-{
- return myImage[address & myMask];
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool Cartridge2K::poke(uInt16, uInt8)
-{
- // This is ROM so poking has no effect :-)
- return false;
-}
-
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge2K::patch(uInt16 address, uInt8 value)
{
@@ -92,7 +78,7 @@ bool Cartridge2K::patch(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* Cartridge2K::getImage(int& size) const
+const uInt8* Cartridge2K::getImage(uInt32& size) const
{
size = mySize;
return myImage.get();
diff --git a/src/emucore/Cart2K.hxx b/src/emucore/Cart2K.hxx
index 273627d6e..61d1246fe 100644
--- a/src/emucore/Cart2K.hxx
+++ b/src/emucore/Cart2K.hxx
@@ -27,11 +27,13 @@ class System;
#endif
/**
- This is the standard Atari 2K cartridge. These cartridges
- are not bankswitched, however, the data repeats twice in the
- 2600's 4K cartridge addressing space.
+ This is the standard Atari 2K cartridge. These cartridges are not
+ bankswitched, however, the data repeats twice in the 2600's 4K cartridge
+ addressing space. For 'Sub2K' ROMs (ROMs less than 2K in size), the
+ data repeats in intervals based on the size of the ROM (which will
+ always be a power of 2).
- @author Bradford W. Mott
+ @author Stephen Anthony
*/
class Cartridge2K : public Cartridge
{
@@ -77,7 +79,7 @@ class Cartridge2K : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -114,23 +116,6 @@ class Cartridge2K : public Cartridge
}
#endif
- public:
- /**
- Get the byte at the specified address
-
- @return The byte at the specified address
- */
- uInt8 peek(uInt16 address) override;
-
- /**
- Change the byte at the specified address to the given value
-
- @param address The address where the value should be stored
- @param value The value to be stored at the address
- @return True if the poke changed the device address space, else false
- */
- bool poke(uInt16 address, uInt8 value) override;
-
private:
// Pointer to a dynamically allocated ROM image of the cartridge
BytePtr myImage;
diff --git a/src/emucore/Cart3E.cxx b/src/emucore/Cart3E.cxx
index e3261a851..ca2e8a573 100644
--- a/src/emucore/Cart3E.cxx
+++ b/src/emucore/Cart3E.cxx
@@ -53,20 +53,17 @@ void Cartridge3E::install(System& system)
System::PageAccess access(this, System::PA_READWRITE);
- // Set the page accessing methods for the hot spots (for 100% emulation
- // we need to chain any accesses below 0x40 to the TIA. Our poke() method
- // does this via mySystem->tiaPoke(...), at least until we come up with a
- // cleaner way to do it).
- for(uInt32 i = 0x00; i < 0x40; i += (1 << System::PAGE_SHIFT))
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ // The hotspots ($3E and $3F) are in TIA address space, so we claim it here
+ for(uInt16 addr = 0x00; addr < 0x40; addr += System::PAGE_SIZE)
+ mySystem->setPageAccess(addr, access);
// Setup the second segment to always point to the last ROM slice
access.type = System::PA_READ;
- for(uInt32 j = 0x1800; j < 0x2000; j += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1800; addr < 0x2000; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[(mySize - 2048) + (j & 0x07FF)];
- access.codeAccessBase = &myCodeAccessBase[(mySize - 2048) + (j & 0x07FF)];
- mySystem->setPageAccess(j >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[(mySize - 2048) + (addr & 0x07FF)];
+ access.codeAccessBase = &myCodeAccessBase[(mySize - 2048) + (addr & 0x07FF)];
+ mySystem->setPageAccess(addr, access);
}
// Install pages for the startup bank into the first segment
@@ -124,10 +121,7 @@ bool Cartridge3E::poke(uInt16 address, uInt8 value)
bank(value + 256);
}
- // Pass the poke through to the TIA. In a real Atari, both the cart and the
- // TIA see the address lines, and both react accordingly. In Stella, each
- // 64-byte chunk of address space is "owned" by only one device. If we
- // don't chain the poke to the TIA, then the TIA can't see it...
+ // Handle TIA space that we claimed above
mySystem->tia().poke(address, value);
return false;
@@ -158,12 +152,11 @@ bool Cartridge3E::bank(uInt16 bank)
System::PageAccess access(this, System::PA_READ);
// Map ROM image into the system
- for(uInt32 address = 0x1000; address < 0x1800;
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < 0x1800; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[offset + (address & 0x07FF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x07FF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[offset + (addr & 0x07FF)];
+ access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x07FF)];
+ mySystem->setPageAccess(addr, access);
}
}
else
@@ -173,28 +166,27 @@ bool Cartridge3E::bank(uInt16 bank)
myCurrentBank = bank + 256;
uInt32 offset = bank << 10;
- uInt32 address;
// Setup the page access methods for the current bank
System::PageAccess access(this, System::PA_READ);
// Map read-port RAM image into the system
- for(address = 0x1000; address < 0x1400; address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myRAM[offset + (address & 0x03FF)];
- access.codeAccessBase = &myCodeAccessBase[mySize + offset + (address & 0x03FF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myRAM[offset + (addr & 0x03FF)];
+ access.codeAccessBase = &myCodeAccessBase[mySize + offset + (addr & 0x03FF)];
+ mySystem->setPageAccess(addr, access);
}
access.directPeekBase = 0;
access.type = System::PA_WRITE;
// Map write-port RAM image into the system
- for(address = 0x1400; address < 0x1800; address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE)
{
- access.directPokeBase = &myRAM[offset + (address & 0x03FF)];
- access.codeAccessBase = &myCodeAccessBase[mySize + offset + (address & 0x03FF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPokeBase = &myRAM[offset + (addr & 0x03FF)];
+ access.codeAccessBase = &myCodeAccessBase[mySize + offset + (addr & 0x03FF)];
+ mySystem->setPageAccess(addr, access);
}
}
return myBankChanged = true;
@@ -236,7 +228,7 @@ bool Cartridge3E::patch(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* Cartridge3E::getImage(int& size) const
+const uInt8* Cartridge3E::getImage(uInt32& size) const
{
size = mySize;
return myImage.get();
diff --git a/src/emucore/Cart3E.hxx b/src/emucore/Cart3E.hxx
index d0a049c1e..d5ae9e8f1 100644
--- a/src/emucore/Cart3E.hxx
+++ b/src/emucore/Cart3E.hxx
@@ -122,7 +122,7 @@ class Cartridge3E : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
diff --git a/src/emucore/Cart3EPlus.cxx b/src/emucore/Cart3EPlus.cxx
index 174a97591..359c84f84 100644
--- a/src/emucore/Cart3EPlus.cxx
+++ b/src/emucore/Cart3EPlus.cxx
@@ -61,12 +61,9 @@ void Cartridge3EPlus::install(System& system)
System::PageAccess access(this, System::PA_READWRITE);
- // Set the page accessing methods for the hot spots (for 100% emulation
- // we need to chain any accesses below 0x40 to the TIA. Our poke() method
- // does this via mySystem->tiaPoke(...), at least until we come up with a
- // cleaner way to do it).
- for(uInt32 i = 0x00; i < 0x40; i += (1 << System::PAGE_SHIFT))
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ // The hotspots are in TIA address space, so we claim it here
+ for(uInt16 addr = 0x00; addr < 0x40; addr += System::PAGE_SIZE)
+ mySystem->setPageAccess(addr, access);
// Initialise bank values for all ROM/RAM access
// This is used to reverse-lookup from address to bank location
@@ -132,10 +129,7 @@ bool Cartridge3EPlus::poke(uInt16 address, uInt8 value)
else if(address == BANK_SWITCH_HOTSPOT_ROM)
changed = bankROM(value);
- // Pass the poke through to the TIA. In a real Atari, both the cart and the
- // TIA see the address lines, and both react accordingly. In Stella, each
- // 64-byte chunk of address space is "owned" by only one device. If we
- // don't chain the poke to the TIA, then the TIA can't see it...
+ // Handle TIA space that we claimed above
mySystem->tia().poke(address, value);
return changed;
@@ -180,20 +174,20 @@ void Cartridge3EPlus::bankRAMSlot(uInt16 bank)
access.type = System::PA_READ;
}
- uInt32 start = 0x1000 + (bankNumber << (RAM_BANK_TO_POWER+1)) + (upper ? RAM_WRITE_OFFSET : 0);
- uInt32 end = start + RAM_BANK_SIZE - 1;
+ uInt16 start = 0x1000 + (bankNumber << (RAM_BANK_TO_POWER+1)) + (upper ? RAM_WRITE_OFFSET : 0);
+ uInt16 end = start + RAM_BANK_SIZE - 1;
//cerr << "bank RAM: " << bankNumber << " -> " << (bankNumber * 2 + (upper ? 1 : 0)) << (upper ? " (W)" : " (R)") << endl
// << "start=" << std::hex << start << ", end=" << end << endl << endl;
- for(uInt32 address = start; address <= end; address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = start; addr <= end; addr += System::PAGE_SIZE)
{
if(upper)
- access.directPokeBase = &myRAM[startCurrentBank + (address & (RAM_BANK_SIZE - 1))];
+ access.directPokeBase = &myRAM[startCurrentBank + (addr & (RAM_BANK_SIZE - 1))];
else
- access.directPeekBase = &myRAM[startCurrentBank + (address & (RAM_BANK_SIZE - 1))];
+ access.directPeekBase = &myRAM[startCurrentBank + (addr & (RAM_BANK_SIZE - 1))];
- access.codeAccessBase = &myCodeAccessBase[mySize + startCurrentBank + (address & (RAM_BANK_SIZE - 1))];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.codeAccessBase = &myCodeAccessBase[mySize + startCurrentBank + (addr & (RAM_BANK_SIZE - 1))];
+ mySystem->setPageAccess(addr, access);
}
}
@@ -226,14 +220,14 @@ void Cartridge3EPlus::bankROMSlot(uInt16 bank)
// Setup the page access methods for the current bank
System::PageAccess access(this, System::PA_READ);
- uInt32 start = 0x1000 + (bankNumber << ROM_BANK_TO_POWER) + (upper ? ROM_BANK_SIZE / 2 : 0);
- uInt32 end = start + ROM_BANK_SIZE / 2 - 1;
+ uInt16 start = 0x1000 + (bankNumber << ROM_BANK_TO_POWER) + (upper ? ROM_BANK_SIZE / 2 : 0);
+ uInt16 end = start + ROM_BANK_SIZE / 2 - 1;
- for(uInt32 address = start; address <= end; address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = start; addr <= end; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[startCurrentBank + (address & (ROM_BANK_SIZE - 1))];
- access.codeAccessBase = &myCodeAccessBase[startCurrentBank + (address & (ROM_BANK_SIZE - 1))];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[startCurrentBank + (addr & (ROM_BANK_SIZE - 1))];
+ access.codeAccessBase = &myCodeAccessBase[startCurrentBank + (addr & (ROM_BANK_SIZE - 1))];
+ mySystem->setPageAccess(addr, access);
}
}
@@ -247,10 +241,10 @@ void Cartridge3EPlus::initializeBankState()
{
// All accesses point to peek/poke above
System::PageAccess access(this, System::PA_READ);
- uInt32 start = 0x1000 + (b << RAM_BANK_TO_POWER);
- uInt32 end = start + RAM_BANK_SIZE - 1;
- for (uInt32 address = start; address <= end; address += (1 << System::PAGE_SHIFT))
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ uInt16 start = 0x1000 + (b << RAM_BANK_TO_POWER);
+ uInt16 end = start + RAM_BANK_SIZE - 1;
+ for(uInt16 addr = start; addr <= end; addr += System::PAGE_SIZE)
+ mySystem->setPageAccess(addr, access);
}
else if (bankInUse[b] & BITMASK_ROMRAM)
bankRAMSlot(bankInUse[b]);
@@ -297,7 +291,7 @@ bool Cartridge3EPlus::patch(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* Cartridge3EPlus::getImage(int& size) const
+const uInt8* Cartridge3EPlus::getImage(uInt32& size) const
{
size = mySize;
return myImage.get();
diff --git a/src/emucore/Cart3EPlus.hxx b/src/emucore/Cart3EPlus.hxx
index 81e80807c..9116f8620 100644
--- a/src/emucore/Cart3EPlus.hxx
+++ b/src/emucore/Cart3EPlus.hxx
@@ -83,7 +83,7 @@ class Cartridge3EPlus: public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
diff --git a/src/emucore/Cart3F.cxx b/src/emucore/Cart3F.cxx
index c6c5476e7..524d35ee5 100644
--- a/src/emucore/Cart3F.cxx
+++ b/src/emucore/Cart3F.cxx
@@ -51,20 +51,17 @@ void Cartridge3F::install(System& system)
System::PageAccess access(this, System::PA_READWRITE);
- // Set the page accessing methods for the hot spots (for 100% emulation
- // we need to chain any accesses below 0x40 to the TIA. Our poke() method
- // does this via mySystem->tiaPoke(...), at least until we come up with a
- // cleaner way to do it).
- for(uInt32 i = 0x00; i < 0x40; i += (1 << System::PAGE_SHIFT))
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ // The hotspot ($3F) is in TIA address space, so we claim it here
+ for(uInt16 addr = 0x00; addr < 0x40; addr += System::PAGE_SIZE)
+ mySystem->setPageAccess(addr, access);
// Setup the second segment to always point to the last ROM slice
access.type = System::PA_READ;
- for(uInt32 j = 0x1800; j < 0x2000; j += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1800; addr < 0x2000; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[(mySize - 2048) + (j & 0x07FF)];
- access.codeAccessBase = &myCodeAccessBase[(mySize - 2048) + (j & 0x07FF)];
- mySystem->setPageAccess(j >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[(mySize - 2048) + (addr & 0x07FF)];
+ access.codeAccessBase = &myCodeAccessBase[(mySize - 2048) + (addr & 0x07FF)];
+ mySystem->setPageAccess(addr, access);
}
// Install pages for startup bank into the first segment
@@ -77,13 +74,9 @@ uInt8 Cartridge3F::peek(uInt16 address)
address &= 0x0FFF;
if(address < 0x0800)
- {
return myImage[(address & 0x07FF) + (myCurrentBank << 11)];
- }
else
- {
return myImage[(address & 0x07FF) + mySize - 2048];
- }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -95,10 +88,7 @@ bool Cartridge3F::poke(uInt16 address, uInt8 value)
if(address <= 0x003F)
bank(value);
- // Pass the poke through to the TIA. In a real Atari, both the cart and the
- // TIA see the address lines, and both react accordingly. In Stella, each
- // 64-byte chunk of address space is "owned" by only one device. If we
- // don't chain the poke to the TIA, then the TIA can't see it...
+ // Handle TIA space that we claimed above
mySystem->tia().poke(address, value);
return false;
@@ -128,12 +118,11 @@ bool Cartridge3F::bank(uInt16 bank)
System::PageAccess access(this, System::PA_READ);
// Map ROM image into the system
- for(uInt32 address = 0x1000; address < 0x1800;
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < 0x1800; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[offset + (address & 0x07FF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x07FF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[offset + (addr & 0x07FF)];
+ access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x07FF)];
+ mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
@@ -164,7 +153,7 @@ bool Cartridge3F::patch(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* Cartridge3F::getImage(int& size) const
+const uInt8* Cartridge3F::getImage(uInt32& size) const
{
size = mySize;
return myImage.get();
diff --git a/src/emucore/Cart3F.hxx b/src/emucore/Cart3F.hxx
index d216fa7ca..a6f114d8b 100644
--- a/src/emucore/Cart3F.hxx
+++ b/src/emucore/Cart3F.hxx
@@ -99,7 +99,7 @@ class Cartridge3F : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
diff --git a/src/emucore/Cart4A50.cxx b/src/emucore/Cart4A50.cxx
index 2612860ee..0d21ea00e 100644
--- a/src/emucore/Cart4A50.cxx
+++ b/src/emucore/Cart4A50.cxx
@@ -73,8 +73,8 @@ void Cartridge4A50::install(System& system)
// Map all of the accesses to call peek and poke (We don't yet indicate RAM areas)
System::PageAccess access(this, System::PA_READ);
- for(uInt32 i = 0x1000; i < 0x2000; i += (1 << System::PAGE_SHIFT))
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE)
+ mySystem->setPageAccess(addr, access);
// Mirror all access in TIA and RIOT; by doing so we're taking responsibility
// for that address space in peek and poke below.
@@ -356,7 +356,7 @@ bool Cartridge4A50::patch(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* Cartridge4A50::getImage(int& size) const
+const uInt8* Cartridge4A50::getImage(uInt32& size) const
{
size = mySize;
return myImage;
diff --git a/src/emucore/Cart4A50.hxx b/src/emucore/Cart4A50.hxx
index 94d3b47e4..60916e6a5 100644
--- a/src/emucore/Cart4A50.hxx
+++ b/src/emucore/Cart4A50.hxx
@@ -28,7 +28,7 @@ class System;
/**
Bankswitching method as defined/created by John Payson (aka Supercat),
- documented at http://www.casperkitty.com/stella/cartfmt.htm.
+ documented at https://stella-emu.github.io/4A50.html.
In this bankswitching scheme the 2600's 4K cartridge address space
is broken into four segments. The first 2K segment accesses any 2K
@@ -44,6 +44,12 @@ class System;
for the ROM address space to change that we just consider the bank to
have changed on every poke operation (for any RAM) or an actual bankswitch.
+ NOTE: This scheme hasn't been fully implemented, and may never be (there
+ is only one test ROM, and it hasn't been extended any further).
+ In particular, the following functionality is missing:
+ - hires helper functions
+ - 1E00 page wrap
+
@author Eckhard Stolberg & Stephen Anthony
*/
class Cartridge4A50 : public Cartridge
@@ -90,7 +96,7 @@ class Cartridge4A50 : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
diff --git a/src/emucore/Cart4K.cxx b/src/emucore/Cart4K.cxx
index 3e376f264..56c9d4496 100644
--- a/src/emucore/Cart4K.cxx
+++ b/src/emucore/Cart4K.cxx
@@ -40,29 +40,17 @@ void Cartridge4K::install(System& system)
mySystem = &system;
// Map ROM image into the system
+ // Note that we don't need our own peek/poke methods, since the mapping
+ // takes care of the entire address space
System::PageAccess access(this, System::PA_READ);
- for(uInt32 address = 0x1000; address < 0x2000;
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[address & 0x0FFF];
- access.codeAccessBase = &myCodeAccessBase[address & 0x0FFF];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[addr & 0x0FFF];
+ access.codeAccessBase = &myCodeAccessBase[addr & 0x0FFF];
+ mySystem->setPageAccess(addr, access);
}
}
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-uInt8 Cartridge4K::peek(uInt16 address)
-{
- return myImage[address & 0x0FFF];
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool Cartridge4K::poke(uInt16, uInt8)
-{
- // This is ROM so poking has no effect :-)
- return false;
-}
-
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge4K::patch(uInt16 address, uInt8 value)
{
@@ -71,7 +59,7 @@ bool Cartridge4K::patch(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* Cartridge4K::getImage(int& size) const
+const uInt8* Cartridge4K::getImage(uInt32& size) const
{
size = 4096;
return myImage;
diff --git a/src/emucore/Cart4K.hxx b/src/emucore/Cart4K.hxx
index 07d98d77a..bc9df42c8 100644
--- a/src/emucore/Cart4K.hxx
+++ b/src/emucore/Cart4K.hxx
@@ -76,7 +76,7 @@ class Cartridge4K : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -113,23 +113,6 @@ class Cartridge4K : public Cartridge
}
#endif
- public:
- /**
- Get the byte at the specified address.
-
- @return The byte at the specified address
- */
- uInt8 peek(uInt16 address) override;
-
- /**
- Change the byte at the specified address to the given value
-
- @param address The address where the value should be stored
- @param value The value to be stored at the address
- @return True if the poke changed the device address space, else false
- */
- bool poke(uInt16 address, uInt8 value) override;
-
private:
// The 4K ROM image for the cartridge
uInt8 myImage[4096];
diff --git a/src/emucore/Cart4KSC.cxx b/src/emucore/Cart4KSC.cxx
index daead3848..f2c939663 100644
--- a/src/emucore/Cart4KSC.cxx
+++ b/src/emucore/Cart4KSC.cxx
@@ -45,62 +45,47 @@ void Cartridge4KSC::install(System& system)
// Set the page accessing method for the RAM writing pages
access.type = System::PA_WRITE;
- for(uInt32 j = 0x1000; j < 0x1080; j += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE)
{
- access.directPokeBase = &myRAM[j & 0x007F];
- access.codeAccessBase = &myCodeAccessBase[j & 0x007F];
- mySystem->setPageAccess(j >> System::PAGE_SHIFT, access);
+ access.directPokeBase = &myRAM[addr & 0x007F];
+ access.codeAccessBase = &myCodeAccessBase[addr & 0x007F];
+ mySystem->setPageAccess(addr, access);
}
// Set the page accessing method for the RAM reading pages
access.directPokeBase = 0;
access.type = System::PA_READ;
- for(uInt32 k = 0x1080; k < 0x1100; k += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myRAM[k & 0x007F];
- access.codeAccessBase = &myCodeAccessBase[0x80 + (k & 0x007F)];
- mySystem->setPageAccess(k >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myRAM[addr & 0x007F];
+ access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)];
+ mySystem->setPageAccess(addr, access);
}
// Map ROM image into the system
- for(uInt32 address = 0x1100; address < 0x2000; address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1100; addr < 0x2000; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[address & 0x0FFF];
- access.codeAccessBase = &myCodeAccessBase[address & 0x0FFF];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[addr & 0x0FFF];
+ access.codeAccessBase = &myCodeAccessBase[addr & 0x0FFF];
+ mySystem->setPageAccess(addr, access);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 Cartridge4KSC::peek(uInt16 address)
{
- uInt16 peekAddress = address;
- address &= 0x0FFF;
+ // The only way we can get to this method is if we attempt to read from
+ // the write port (0xF000 - 0xF080, 128 bytes), in which case an
+ // unwanted write is triggered
+ uInt8 value = mySystem->getDataBusState(0xFF);
- if(address < 0x0080) // Write port is at 0xF000 - 0xF080 (128 bytes)
- {
- // Reading from the write port triggers an unwanted write
- uInt8 value = mySystem->getDataBusState(0xFF);
-
- if(bankLocked())
- return value;
- else
- {
- triggerReadFromWritePort(peekAddress);
- return myRAM[address] = value;
- }
- }
+ if(bankLocked())
+ return value;
else
- return myImage[address & 0x0FFF];
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool Cartridge4KSC::poke(uInt16 address, uInt8)
-{
- // NOTE: This does not handle accessing RAM, however, this function
- // should never be called for RAM because of the way page accessing
- // has been setup
- return false;
+ {
+ triggerReadFromWritePort(address);
+ return myRAM[address & 0x0FFF] = value;
+ }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -122,7 +107,7 @@ bool Cartridge4KSC::patch(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* Cartridge4KSC::getImage(int& size) const
+const uInt8* Cartridge4KSC::getImage(uInt32& size) const
{
size = 4096;
return myImage;
diff --git a/src/emucore/Cart4KSC.hxx b/src/emucore/Cart4KSC.hxx
index 668a8c718..1ad6ab560 100644
--- a/src/emucore/Cart4KSC.hxx
+++ b/src/emucore/Cart4KSC.hxx
@@ -28,6 +28,7 @@ class System;
/**
Cartridge class used for 4K games with 128 bytes of RAM.
+ RAM read port is $1080 - $10FF, write port is $1000 - $107F.
*/
class Cartridge4KSC : public Cartridge
@@ -74,7 +75,7 @@ class Cartridge4KSC : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -119,17 +120,8 @@ class Cartridge4KSC : public Cartridge
*/
uInt8 peek(uInt16 address) override;
- /**
- Change the byte at the specified address to the given value
-
- @param address The address where the value should be stored
- @param value The value to be stored at the address
- @return True if the poke changed the device address space, else false
- */
- bool poke(uInt16 address, uInt8 value) override;
-
private:
- // The 8K ROM image of the cartridge
+ // The 4K ROM image of the cartridge
uInt8 myImage[4096];
// The 128 bytes of RAM
diff --git a/src/emucore/CartAR.cxx b/src/emucore/CartAR.cxx
index 4f4796bfb..3b8e798cc 100644
--- a/src/emucore/CartAR.cxx
+++ b/src/emucore/CartAR.cxx
@@ -26,7 +26,6 @@ CartridgeAR::CartridgeAR(const BytePtr& image, uInt32 size,
mySize(std::max(size, 8448u)),
myWriteEnabled(false),
myPower(true),
- myPowerRomCycle(0),
myDataHoldRegister(0),
myNumberOfDistinctAccesses(0),
myWritePending(false),
@@ -64,7 +63,6 @@ void CartridgeAR::reset()
myWriteEnabled = false;
myPower = true;
- myPowerRomCycle = mySystem->cycles();
myDataHoldRegister = 0;
myNumberOfDistinctAccesses = 0;
@@ -74,13 +72,6 @@ void CartridgeAR::reset()
bankConfiguration(0);
}
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void CartridgeAR::systemCyclesReset()
-{
- // Adjust cycle values
- myPowerRomCycle -= mySystem->cycles();
-}
-
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeAR::install(System& system)
{
@@ -88,8 +79,8 @@ void CartridgeAR::install(System& system)
// Map all of the accesses to call peek and poke (we don't yet indicate RAM areas)
System::PageAccess access(this, System::PA_READ);
- for(uInt32 i = 0x1000; i < 0x2000; i += (1 << System::PAGE_SHIFT))
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE)
+ mySystem->setPageAccess(addr, access);
bankConfiguration(0);
}
@@ -243,11 +234,6 @@ bool CartridgeAR::bankConfiguration(uInt8 configuration)
// Handle ROM power configuration
myPower = !(configuration & 0x01);
- if(myPower)
- {
- myPowerRomCycle = mySystem->cycles();
- }
-
myWriteEnabled = configuration & 0x02;
switch((configuration >> 2) & 0x07)
@@ -439,7 +425,7 @@ bool CartridgeAR::patch(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeAR::getImage(int& size) const
+const uInt8* CartridgeAR::getImage(uInt32& size) const
{
size = mySize;
return myLoadImages.get();
@@ -474,9 +460,6 @@ bool CartridgeAR::save(Serializer& out) const
// Indicates if the ROM's power is on or off
out.putBool(myPower);
- // Indicates when the power was last turned on
- out.putInt(myPowerRomCycle);
-
// Data hold register used for writing
out.putByte(myDataHoldRegister);
@@ -525,9 +508,6 @@ bool CartridgeAR::load(Serializer& in)
// Indicates if the ROM's power is on or off
myPower = in.getBool();
- // Indicates when the power was last turned on
- myPowerRomCycle = in.getInt();
-
// Data hold register used for writing
myDataHoldRegister = in.getByte();
diff --git a/src/emucore/CartAR.hxx b/src/emucore/CartAR.hxx
index dc1f1ca58..9e33ee1d1 100644
--- a/src/emucore/CartAR.hxx
+++ b/src/emucore/CartAR.hxx
@@ -27,6 +27,8 @@ class System;
#endif
/**
+ FIXME: This scheme needs to be be described in more detail.
+
This is the cartridge class for Arcadia (aka Starpath) Supercharger
games. Christopher Salomon provided most of the technical details
used in creating this class. A good description of the Supercharger
@@ -58,13 +60,6 @@ class CartridgeAR : public Cartridge
*/
void reset() override;
- /**
- Notification method invoked by the system right before the
- system resets its cycle counter to zero. It may be necessary
- to override this method for devices that remember cycle counts.
- */
- void systemCyclesReset() override;
-
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@@ -105,7 +100,7 @@ class CartridgeAR : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -206,9 +201,6 @@ class CartridgeAR : public Cartridge
// Indicates if the ROM's power is on or off
bool myPower;
- // Indicates when the power was last turned on
- Int32 myPowerRomCycle;
-
// Data hold register used for writing
uInt8 myDataHoldRegister;
diff --git a/src/emucore/CartBF.cxx b/src/emucore/CartBF.cxx
index dba54fb9a..a7e227793 100644
--- a/src/emucore/CartBF.cxx
+++ b/src/emucore/CartBF.cxx
@@ -22,7 +22,7 @@
CartridgeBF::CartridgeBF(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings),
- myCurrentBank(0)
+ myBankOffset(0)
{
// Copy the ROM image into my buffer
memcpy(myImage, image.get(), std::min(262144u, size));
@@ -51,18 +51,22 @@ void CartridgeBF::install(System& system)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeBF::peek(uInt16 address)
{
+ // Due to the way addressing is set up, we will only get here if the
+ // address is in the hotspot range ($1F80 - $1FFF)
address &= 0x0FFF;
// Switch banks if necessary
if((address >= 0x0F80) && (address <= 0x0FBF))
bank(address - 0x0F80);
- return myImage[(myCurrentBank << 12) + address];
+ return myImage[myBankOffset + address];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeBF::poke(uInt16 address, uInt8)
{
+ // Due to the way addressing is set up, we will only get here if the
+ // address is in the hotspot range ($1F80 - $1FFF)
address &= 0x0FFF;
// Switch banks if necessary
@@ -78,26 +82,25 @@ bool CartridgeBF::bank(uInt16 bank)
if(bankLocked()) return false;
// Remember what bank we're in
- myCurrentBank = bank;
- uInt32 offset = myCurrentBank << 12;
+ myBankOffset = bank << 12;
System::PageAccess access(this, System::PA_READ);
// Set the page accessing methods for the hot spots
- for(uInt32 i = (0x1F80 & ~System::PAGE_MASK); i < 0x2000;
- i += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = (0x1F80 & ~System::PAGE_MASK); addr < 0x2000;
+ addr += System::PAGE_SIZE)
{
- access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)];
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
// Setup the page access methods for the current bank
- for(uInt32 address = 0x1000; address < (0x1F80U & ~System::PAGE_MASK);
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < (0x1F80U & ~System::PAGE_MASK);
+ addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
@@ -105,7 +108,7 @@ bool CartridgeBF::bank(uInt16 bank)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeBF::getBank() const
{
- return myCurrentBank;
+ return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -117,14 +120,14 @@ uInt16 CartridgeBF::bankCount() const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeBF::patch(uInt16 address, uInt8 value)
{
- myImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value;
+ myImage[myBankOffset + (address & 0x0FFF)] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeBF::getImage(int& size) const
+const uInt8* CartridgeBF::getImage(uInt32& size) const
{
- size = 262144;
+ size = 64 * 4096;
return myImage;
}
@@ -134,7 +137,7 @@ bool CartridgeBF::save(Serializer& out) const
try
{
out.putString(name());
- out.putShort(myCurrentBank);
+ out.putInt(myBankOffset);
}
catch(...)
{
@@ -153,7 +156,7 @@ bool CartridgeBF::load(Serializer& in)
if(in.getString() != name())
return false;
- myCurrentBank = in.getShort();
+ myBankOffset = in.getInt();
}
catch(...)
{
@@ -162,7 +165,7 @@ bool CartridgeBF::load(Serializer& in)
}
// Remember what bank we were in
- bank(myCurrentBank);
+ bank(myBankOffset >> 12);
return true;
}
diff --git a/src/emucore/CartBF.hxx b/src/emucore/CartBF.hxx
index 77fc4a1c4..98a145b53 100644
--- a/src/emucore/CartBF.hxx
+++ b/src/emucore/CartBF.hxx
@@ -94,7 +94,7 @@ class CartridgeBF : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -152,8 +152,8 @@ class CartridgeBF : public Cartridge
// The 256K ROM image of the cartridge
uInt8 myImage[64 * 4096];
- // Indicates which bank is currently active
- uInt16 myCurrentBank;
+ // Indicates the offset into the ROM image (aligns to current bank)
+ uInt32 myBankOffset;
private:
// Following constructors and assignment operators not supported
diff --git a/src/emucore/CartBFSC.cxx b/src/emucore/CartBFSC.cxx
index b693d2221..c4b7a1815 100644
--- a/src/emucore/CartBFSC.cxx
+++ b/src/emucore/CartBFSC.cxx
@@ -22,7 +22,7 @@
CartridgeBFSC::CartridgeBFSC(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings),
- myCurrentBank(0)
+ myBankOffset(0)
{
// Copy the ROM image into my buffer
memcpy(myImage, image.get(), std::min(262144u, size));
@@ -50,21 +50,21 @@ void CartridgeBFSC::install(System& system)
// Set the page accessing method for the RAM writing pages
access.type = System::PA_WRITE;
- for(uInt32 j = 0x1000; j < 0x1080; j += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE)
{
- access.directPokeBase = &myRAM[j & 0x007F];
- access.codeAccessBase = &myCodeAccessBase[j & 0x007F];
- mySystem->setPageAccess(j >> System::PAGE_SHIFT, access);
+ access.directPokeBase = &myRAM[addr & 0x007F];
+ access.codeAccessBase = &myCodeAccessBase[addr & 0x007F];
+ mySystem->setPageAccess(addr, access);
}
// Set the page accessing method for the RAM reading pages
access.directPokeBase = 0;
access.type = System::PA_READ;
- for(uInt32 k = 0x1080; k < 0x1100; k += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myRAM[k & 0x007F];
- access.codeAccessBase = &myCodeAccessBase[0x80 + (k & 0x007F)];
- mySystem->setPageAccess(k >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myRAM[addr & 0x007F];
+ access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)];
+ mySystem->setPageAccess(addr, access);
}
// Install pages for the startup bank
@@ -95,7 +95,7 @@ uInt8 CartridgeBFSC::peek(uInt16 address)
}
}
else
- return myImage[(myCurrentBank << 12) + address];
+ return myImage[myBankOffset + address];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -107,7 +107,7 @@ bool CartridgeBFSC::poke(uInt16 address, uInt8)
if((address >= 0x0F80) && (address <= 0x0FBF))
bank(address - 0x0F80);
- // NOTE: This does not handle accessing RAM, however, this function
+ // NOTE: This does not handle accessing RAM, however, this method
// should never be called for RAM because of the way page accessing
// has been setup
return false;
@@ -119,26 +119,25 @@ bool CartridgeBFSC::bank(uInt16 bank)
if(bankLocked()) return false;
// Remember what bank we're in
- myCurrentBank = bank;
- uInt32 offset = myCurrentBank << 12;
+ myBankOffset = bank << 12;
System::PageAccess access(this, System::PA_READ);
// Set the page accessing methods for the hot spots
- for(uInt32 i = (0x1F80 & ~System::PAGE_MASK); i < 0x2000;
- i += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = (0x1F80 & ~System::PAGE_MASK); addr < 0x2000;
+ addr += System::PAGE_SIZE)
{
- access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)];
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
// Setup the page access methods for the current bank
- for(uInt32 address = 0x1100; address < (0x1F80U & ~System::PAGE_MASK);
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1100; addr < (0x1F80U & ~System::PAGE_MASK);
+ addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
@@ -146,7 +145,7 @@ bool CartridgeBFSC::bank(uInt16 bank)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeBFSC::getBank() const
{
- return myCurrentBank;
+ return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -168,15 +167,15 @@ bool CartridgeBFSC::patch(uInt16 address, uInt8 value)
myRAM[address & 0x007F] = value;
}
else
- myImage[(myCurrentBank << 12) + address] = value;
+ myImage[myBankOffset + address] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeBFSC::getImage(int& size) const
+const uInt8* CartridgeBFSC::getImage(uInt32& size) const
{
- size = 256*1024;
+ size = 64 * 4096;
return myImage;
}
@@ -186,7 +185,7 @@ bool CartridgeBFSC::save(Serializer& out) const
try
{
out.putString(name());
- out.putShort(myCurrentBank);
+ out.putInt(myBankOffset);
out.putByteArray(myRAM, 128);
}
catch(...)
@@ -206,7 +205,7 @@ bool CartridgeBFSC::load(Serializer& in)
if(in.getString() != name())
return false;
- myCurrentBank = in.getShort();
+ myBankOffset = in.getInt();
in.getByteArray(myRAM, 128);
}
catch(...)
@@ -216,7 +215,7 @@ bool CartridgeBFSC::load(Serializer& in)
}
// Remember what bank we were in
- bank(myCurrentBank);
+ bank(myBankOffset >> 12);
return true;
}
diff --git a/src/emucore/CartBFSC.hxx b/src/emucore/CartBFSC.hxx
index cf27d0a46..e5becb811 100644
--- a/src/emucore/CartBFSC.hxx
+++ b/src/emucore/CartBFSC.hxx
@@ -29,6 +29,7 @@ class System;
/**
There are 64 4K banks (total of 256K ROM) with 128 bytes of RAM.
Accessing $1F80 - $1FBF switches to each bank.
+ RAM read port is $1080 - $10FF, write port is $1000 - $107F.
@author Stephen Anthony
*/
@@ -93,7 +94,7 @@ class CartridgeBFSC : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -154,8 +155,8 @@ class CartridgeBFSC : public Cartridge
// The 128 bytes of RAM
uInt8 myRAM[128];
- // Indicates which bank is currently active
- uInt16 myCurrentBank;
+ // Indicates the offset into the ROM image (aligns to current bank)
+ uInt32 myBankOffset;
private:
// Following constructors and assignment operators not supported
diff --git a/src/emucore/CartBUS.cxx b/src/emucore/CartBUS.cxx
index 2769adaf0..c5cabd6ae 100644
--- a/src/emucore/CartBUS.cxx
+++ b/src/emucore/CartBUS.cxx
@@ -43,7 +43,7 @@
CartridgeBUS::CartridgeBUS(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings),
- mySystemCycles(0),
+ myAudioCycles(0),
myARMCycles(0),
myFractionalClocks(0.0)
{
@@ -74,15 +74,10 @@ CartridgeBUS::CartridgeBUS(const BytePtr& image, uInt32 size,
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeBUS::reset()
{
- // Initialize RAM
- if(mySettings.getBool("ramrandom"))
- initializeRAM(myBUSRAM+2048, 8192-2048);
- else
- memset(myBUSRAM+2048, 0, 8192-2048);
+ initializeRAM(myBUSRAM+2048, 8192-2048);
// Update cycles to the current system cycles
- mySystemCycles = mySystem->cycles();
- myARMCycles = mySystem->cycles();
+ myAudioCycles = myARMCycles = 0;
myFractionalClocks = 0.0;
setInitialState();
@@ -116,14 +111,6 @@ void CartridgeBUS::consoleChanged(ConsoleTiming timing)
#endif
}
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void CartridgeBUS::systemCyclesReset()
-{
- // Adjust the cycle counter so that it reflects the new value
- mySystemCycles -= mySystem->cycles();
- myARMCycles -= mySystem->cycles();
-}
-
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeBUS::install(System& system)
{
@@ -131,8 +118,8 @@ void CartridgeBUS::install(System& system)
// Map all of the accesses to call peek and poke
System::PageAccess access(this, System::PA_READ);
- for(uInt32 i = 0x1000; i < 0x1040; i += (1 << System::PAGE_SHIFT))
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ for(uInt16 addr = 0x1000; addr < 0x1040; addr += System::PAGE_SIZE)
+ mySystem->setPageAccess(addr, access);
// Mirror all access in TIA and RIOT; by doing so we're taking responsibility
// for that address space in peek and poke below.
@@ -147,20 +134,18 @@ void CartridgeBUS::install(System& system)
inline void CartridgeBUS::updateMusicModeDataFetchers()
{
// Calculate the number of cycles since the last update
- Int32 cycles = mySystem->cycles() - mySystemCycles;
- mySystemCycles = mySystem->cycles();
+ uInt32 cycles = uInt32(mySystem->cycles() - myAudioCycles);
+ myAudioCycles = mySystem->cycles();
// Calculate the number of BUS OSC clocks since the last update
double clocks = ((20000.0 * cycles) / 1193191.66666667) + myFractionalClocks;
- Int32 wholeClocks = Int32(clocks);
+ uInt32 wholeClocks = uInt32(clocks);
myFractionalClocks = clocks - double(wholeClocks);
- if(wholeClocks <= 0)
- return;
-
// Let's update counters and flags of the music mode data fetchers
- for(int x = 0; x <= 2; ++x)
- myMusicCounters[x] += myMusicFrequencies[x] * wholeClocks;
+ if(wholeClocks > 0)
+ for(int x = 0; x <= 2; ++x)
+ myMusicCounters[x] += myMusicFrequencies[x] * wholeClocks;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -174,7 +159,7 @@ inline void CartridgeBUS::callFunction(uInt8 value)
// time for Stella as ARM code "runs in zero 6507 cycles".
case 255: // call without IRQ driven audio
try {
- Int32 cycles = mySystem->cycles() - myARMCycles;
+ Int32 cycles = Int32(mySystem->cycles() - myARMCycles);
myARMCycles = mySystem->cycles();
myThumbEmulator->run(cycles);
@@ -210,7 +195,7 @@ uInt8 CartridgeBUS::peek(uInt16 address)
{
address &= 0x0FFF;
- uInt8 peekvalue = myProgramImage[(myCurrentBank << 12) + address];
+ uInt8 peekvalue = myProgramImage[myBankOffset + address];
// In debugger/bank-locked mode, we ignore all hotspots and in general
// anything that can change the internal state of the cart
@@ -238,8 +223,8 @@ uInt8 CartridgeBUS::peek(uInt16 address)
// test for JMP FASTJUMP where FASTJUMP = $0000
if (BUS_STUFF_ON
&& peekvalue == 0x4C
- && myProgramImage[(myCurrentBank << 12) + address+1] == 0
- && myProgramImage[(myCurrentBank << 12) + address+2] == 0)
+ && myProgramImage[myBankOffset + address+1] == 0
+ && myProgramImage[myBankOffset + address+2] == 0)
{
myFastJumpActive = 2; // return next two peeks from datastream 17
myJMPoperandAddress = address + 1;
@@ -449,18 +434,16 @@ bool CartridgeBUS::bank(uInt16 bank)
if(bankLocked()) return false;
// Remember what bank we're in
- myCurrentBank = bank;
- uInt16 offset = myCurrentBank << 12;
+ myBankOffset = bank << 12;
// Setup the page access methods for the current bank
System::PageAccess access(this, System::PA_READ);
// Map Program ROM image into the system
- for(uInt32 address = 0x1040; address < 0x2000;
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1040; addr < 0x2000; addr += System::PAGE_SIZE)
{
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
@@ -468,7 +451,7 @@ bool CartridgeBUS::bank(uInt16 bank)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeBUS::getBank() const
{
- return myCurrentBank;
+ return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -485,7 +468,7 @@ bool CartridgeBUS::patch(uInt16 address, uInt8 value)
// For now, we ignore attempts to patch the BUS address space
if(address >= 0x0040)
{
- myProgramImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value;
+ myProgramImage[myBankOffset + (address & 0x0FFF)] = value;
return myBankChanged = true;
}
else
@@ -493,7 +476,7 @@ bool CartridgeBUS::patch(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeBUS::getImage(int& size) const
+const uInt8* CartridgeBUS::getImage(uInt32& size) const
{
size = 32768;
return myImage;
@@ -564,7 +547,7 @@ bool CartridgeBUS::save(Serializer& out) const
out.putString(name());
// Indicates which bank is currently active
- out.putShort(myCurrentBank);
+ out.putShort(myBankOffset);
// Harmony RAM
out.putByteArray(myBUSRAM, 8192);
@@ -575,9 +558,9 @@ bool CartridgeBUS::save(Serializer& out) const
out.putShort(myJMPoperandAddress);
// Save cycles and clocks
- out.putInt(mySystemCycles);
- out.putInt((uInt32)(myFractionalClocks * 100000000.0));
- out.putInt(myARMCycles);
+ out.putLong(myAudioCycles);
+ out.putDouble(myFractionalClocks);
+ out.putLong(myARMCycles);
// Audio info
out.putIntArray(myMusicCounters, 3);
@@ -608,7 +591,7 @@ bool CartridgeBUS::load(Serializer& in)
return false;
// Indicates which bank is currently active
- myCurrentBank = in.getShort();
+ myBankOffset = in.getShort();
// Harmony RAM
in.getByteArray(myBUSRAM, 8192);
@@ -619,9 +602,9 @@ bool CartridgeBUS::load(Serializer& in)
myJMPoperandAddress = in.getShort();
// Get system cycles and fractional clocks
- mySystemCycles = (Int32)in.getInt();
- myFractionalClocks = (double)in.getInt() / 100000000.0;
- myARMCycles = (Int32)in.getInt();
+ myAudioCycles = in.getLong();
+ myFractionalClocks = in.getDouble();
+ myARMCycles = in.getLong();
// Audio info
in.getIntArray(myMusicCounters, 3);
@@ -641,7 +624,7 @@ bool CartridgeBUS::load(Serializer& in)
}
// Now, go to the current bank
- bank(myCurrentBank);
+ bank(myBankOffset >> 12);
return true;
}
diff --git a/src/emucore/CartBUS.hxx b/src/emucore/CartBUS.hxx
index 9a676b16d..cfe9503c3 100644
--- a/src/emucore/CartBUS.hxx
+++ b/src/emucore/CartBUS.hxx
@@ -73,13 +73,6 @@ class CartridgeBUS : public Cartridge
*/
void consoleChanged(ConsoleTiming timing) override;
- /**
- Notification method invoked by the system right before the
- system resets its cycle counter to zero. It may be necessary
- to override this method for devices that remember cycle counts.
- */
- void systemCyclesReset() override;
-
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@@ -120,7 +113,7 @@ class CartridgeBUS : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -238,8 +231,8 @@ class CartridgeBUS : public Cartridge
unique_ptr myThumbEmulator;
#endif
- // Indicates which bank is currently active
- uInt16 myCurrentBank;
+ // Indicates the offset into the ROM image (aligns to current bank)
+ uInt16 myBankOffset;
// Address to override the bus for
uInt16 myBusOverdriveAddress;
@@ -251,11 +244,11 @@ class CartridgeBUS : public Cartridge
// *and* the next two bytes in ROM are 00 00
uInt16 myJMPoperandAddress;
- // System cycle count when the last update to music data fetchers occurred
- Int32 mySystemCycles;
+ // System cycle count from when the last update to music data fetchers occurred
+ uInt64 myAudioCycles;
// ARM cycle count from when the last callFunction() occurred
- Int32 myARMCycles;
+ uInt64 myARMCycles;
// The music mode counters
uInt32 myMusicCounters[3];
diff --git a/src/emucore/CartCDF.cxx b/src/emucore/CartCDF.cxx
index dbd5d28bc..93cd02553 100644
--- a/src/emucore/CartCDF.cxx
+++ b/src/emucore/CartCDF.cxx
@@ -27,9 +27,10 @@
#include "TIA.hxx"
// Location of data within the RAM copy of the CDF Driver.
-#define DSxPTR 0x06E0
-#define DSxINC 0x0768
-#define WAVEFORM 0x07F0
+// Version 0 1
+const uInt16 DSxPTR[] = {0x06E0, 0x00A0};
+const uInt16 DSxINC[] = {0x0768, 0x0128};
+const uInt16 WAVEFORM[] = {0x07F0, 0x01B0};
#define DSRAM 0x0800
#define COMMSTREAM 0x20
@@ -62,10 +63,15 @@ CartridgeCDF::CartridgeCDF(const BytePtr& image, uInt32 size,
// Pointer to the display RAM
myDisplayImage = myCDFRAM + DSRAM;
+
+ setVersion();
+
#ifdef THUMB_SUPPORT
// Create Thumbulator ARM emulator
- myThumbEmulator = make_unique((uInt16*)myImage, (uInt16*)myCDFRAM,
- settings.getBool("thumb.trapfatal"), Thumbulator::ConfigureFor::CDF, this);
+ myThumbEmulator = make_unique(
+ (uInt16*)myImage, (uInt16*)myCDFRAM, settings.getBool("thumb.trapfatal"),
+ myVersion ? Thumbulator::ConfigureFor::CDF1 : Thumbulator::ConfigureFor::CDF,
+ this);
#endif
setInitialState();
}
@@ -73,15 +79,9 @@ CartridgeCDF::CartridgeCDF(const BytePtr& image, uInt32 size,
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeCDF::reset()
{
- // Initialize RAM
- if(mySettings.getBool("ramrandom"))
- initializeRAM(myCDFRAM+2048, 8192-2048);
- else
- memset(myCDFRAM+2048, 0, 8192-2048);
+ initializeRAM(myCDFRAM+2048, 8192-2048);
- // Update cycles to the current system cycles
- myAudioCycles = mySystem->cycles();
- myARMCycles = mySystem->cycles();
+ myAudioCycles = myARMCycles = 0;
myFractionalClocks = 0.0;
setInitialState();
@@ -117,14 +117,6 @@ void CartridgeCDF::consoleChanged(ConsoleTiming timing)
#endif
}
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void CartridgeCDF::systemCyclesReset()
-{
- // Adjust the cycle counter so that it reflects the new value
- myAudioCycles -= mySystem->cycles();
- myARMCycles -= mySystem->cycles();
-}
-
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeCDF::install(System& system)
{
@@ -132,8 +124,8 @@ void CartridgeCDF::install(System& system)
// Map all of the accesses to call peek and poke
System::PageAccess access(this, System::PA_READ);
- for(uInt32 i = 0x1000; i < 0x1040; i += (1 << System::PAGE_SHIFT))
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ for(uInt16 addr = 0x1000; addr < 0x1040; addr += System::PAGE_SIZE)
+ mySystem->setPageAccess(addr, access);
// Install pages for the startup bank
bank(myStartBank);
@@ -143,20 +135,18 @@ void CartridgeCDF::install(System& system)
inline void CartridgeCDF::updateMusicModeDataFetchers()
{
// Calculate the number of cycles since the last update
- Int32 cycles = mySystem->cycles() - myAudioCycles;
+ uInt32 cycles = uInt32(mySystem->cycles() - myAudioCycles);
myAudioCycles = mySystem->cycles();
// Calculate the number of CDF OSC clocks since the last update
double clocks = ((20000.0 * cycles) / 1193191.66666667) + myFractionalClocks;
- Int32 wholeClocks = Int32(clocks);
+ uInt32 wholeClocks = uInt32(clocks);
myFractionalClocks = clocks - double(wholeClocks);
- if(wholeClocks <= 0)
- return;
-
// Let's update counters and flags of the music mode data fetchers
- for(int x = 0; x <= 2; ++x)
- myMusicCounters[x] += myMusicFrequencies[x] * wholeClocks;
+ if(wholeClocks > 0)
+ for(int x = 0; x <= 2; ++x)
+ myMusicCounters[x] += myMusicFrequencies[x] * wholeClocks;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -170,7 +160,7 @@ inline void CartridgeCDF::callFunction(uInt8 value)
// time for Stella as ARM code "runs in zero 6507 cycles".
case 255: // call without IRQ driven audio
try {
- Int32 cycles = mySystem->cycles() - myARMCycles;
+ Int32 cycles = Int32(mySystem->cycles() - myARMCycles);
myARMCycles = mySystem->cycles();
myThumbEmulator->run(cycles);
@@ -195,7 +185,7 @@ uInt8 CartridgeCDF::peek(uInt16 address)
{
address &= 0x0FFF;
- uInt8 peekvalue = myProgramImage[(myCurrentBank << 12) + address];
+ uInt8 peekvalue = myProgramImage[myBankOffset + address];
// In debugger/bank-locked mode, we ignore all hotspots and in general
// anything that can change the internal state of the cart
@@ -223,8 +213,8 @@ uInt8 CartridgeCDF::peek(uInt16 address)
// test for JMP FASTJUMP where FASTJUMP = $0000
if (FAST_FETCH_ON
&& peekvalue == 0x4C
- && myProgramImage[(myCurrentBank << 12) + address+1] == 0
- && myProgramImage[(myCurrentBank << 12) + address+2] == 0)
+ && myProgramImage[myBankOffset + address+1] == 0
+ && myProgramImage[myBankOffset + address+2] == 0)
{
myFastJumpActive = 2; // return next two peeks from datastream 31
myJMPoperandAddress = address + 1;
@@ -407,18 +397,16 @@ bool CartridgeCDF::bank(uInt16 bank)
if(bankLocked()) return false;
// Remember what bank we're in
- myCurrentBank = bank;
- uInt16 offset = myCurrentBank << 12;
+ myBankOffset = bank << 12;
// Setup the page access methods for the current bank
System::PageAccess access(this, System::PA_READ);
// Map Program ROM image into the system
- for(uInt32 address = 0x1040; address < 0x2000;
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1040; addr < 0x2000; addr += System::PAGE_SIZE)
{
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
@@ -426,7 +414,7 @@ bool CartridgeCDF::bank(uInt16 bank)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeCDF::getBank() const
{
- return myCurrentBank;
+ return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -443,7 +431,7 @@ bool CartridgeCDF::patch(uInt16 address, uInt8 value)
// For now, we ignore attempts to patch the CDF address space
if(address >= 0x0040)
{
- myProgramImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value;
+ myProgramImage[myBankOffset + (address & 0x0FFF)] = value;
return myBankChanged = true;
}
else
@@ -451,7 +439,7 @@ bool CartridgeCDF::patch(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeCDF::getImage(int& size) const
+const uInt8* CartridgeCDF::getImage(uInt32& size) const
{
size = 32768;
return myImage;
@@ -497,7 +485,7 @@ bool CartridgeCDF::save(Serializer& out) const
out.putString(name());
// Indicates which bank is currently active
- out.putShort(myCurrentBank);
+ out.putShort(myBankOffset);
// Indicates current mode
out.putByte(myMode);
@@ -518,9 +506,9 @@ bool CartridgeCDF::save(Serializer& out) const
out.putByteArray(myMusicWaveformSize, 3);
// Save cycles and clocks
- out.putInt(myAudioCycles);
- out.putInt((uInt32)(myFractionalClocks * 100000000.0));
- out.putInt(myARMCycles);
+ out.putLong(myAudioCycles);
+ out.putDouble(myFractionalClocks);
+ out.putLong(myARMCycles);
}
catch(...)
{
@@ -540,7 +528,7 @@ bool CartridgeCDF::load(Serializer& in)
return false;
// Indicates which bank is currently active
- myCurrentBank = in.getShort();
+ myBankOffset = in.getShort();
// Indicates current mode
myMode = in.getByte();
@@ -561,9 +549,9 @@ bool CartridgeCDF::load(Serializer& in)
in.getByteArray(myMusicWaveformSize, 3);
// Get cycles and clocks
- myAudioCycles = (Int32)in.getInt();
- myFractionalClocks = (double)in.getInt() / 100000000.0;
- myARMCycles = (Int32)in.getInt();
+ myAudioCycles = in.getLong();
+ myFractionalClocks = in.getDouble();
+ myARMCycles = in.getLong();
}
catch(...)
{
@@ -572,7 +560,7 @@ bool CartridgeCDF::load(Serializer& in)
}
// Now, go to the current bank
- bank(myCurrentBank);
+ bank(myBankOffset >> 12);
return true;
}
@@ -580,51 +568,57 @@ bool CartridgeCDF::load(Serializer& in)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 CartridgeCDF::getDatastreamPointer(uInt8 index) const
{
- // index &= 0x0f;
+ uInt16 address = DSxPTR[myVersion] + index * 4;
- return myCDFRAM[DSxPTR + index*4 + 0] + // low byte
- (myCDFRAM[DSxPTR + index*4 + 1] << 8) +
- (myCDFRAM[DSxPTR + index*4 + 2] << 16) +
- (myCDFRAM[DSxPTR + index*4 + 3] << 24) ; // high byte
+ return myCDFRAM[address + 0] + // low byte
+ (myCDFRAM[address + 1] << 8) +
+ (myCDFRAM[address + 2] << 16) +
+ (myCDFRAM[address + 3] << 24) ; // high byte
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeCDF::setDatastreamPointer(uInt8 index, uInt32 value)
{
- // index &= 0x1f;
- myCDFRAM[DSxPTR + index*4 + 0] = value & 0xff; // low byte
- myCDFRAM[DSxPTR + index*4 + 1] = (value >> 8) & 0xff;
- myCDFRAM[DSxPTR + index*4 + 2] = (value >> 16) & 0xff;
- myCDFRAM[DSxPTR + index*4 + 3] = (value >> 24) & 0xff; // high byte
+ uInt16 address = DSxPTR[myVersion] + index * 4;
+
+ myCDFRAM[address + 0] = value & 0xff; // low byte
+ myCDFRAM[address + 1] = (value >> 8) & 0xff;
+ myCDFRAM[address + 2] = (value >> 16) & 0xff;
+ myCDFRAM[address + 3] = (value >> 24) & 0xff; // high byte
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 CartridgeCDF::getDatastreamIncrement(uInt8 index) const
{
- return myCDFRAM[DSxINC + index*4 + 0] + // low byte
- (myCDFRAM[DSxINC + index*4 + 1] << 8) +
- (myCDFRAM[DSxINC + index*4 + 2] << 16) +
- (myCDFRAM[DSxINC + index*4 + 3] << 24) ; // high byte
+ uInt16 address = DSxINC[myVersion] + index * 4;
+
+ return myCDFRAM[address + 0] + // low byte
+ (myCDFRAM[address + 1] << 8) +
+ (myCDFRAM[address + 2] << 16) +
+ (myCDFRAM[address + 3] << 24) ; // high byte
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeCDF::setDatastreamIncrement(uInt8 index, uInt32 value)
{
- myCDFRAM[DSxINC + index*4 + 0] = value & 0xff; // low byte
- myCDFRAM[DSxINC + index*4 + 1] = (value >> 8) & 0xff;
- myCDFRAM[DSxINC + index*4 + 2] = (value >> 16) & 0xff;
- myCDFRAM[DSxINC + index*4 + 3] = (value >> 24) & 0xff; // high byte
+ uInt16 address = DSxINC[myVersion] + index * 4;
+
+ myCDFRAM[address + 0] = value & 0xff; // low byte
+ myCDFRAM[address + 1] = (value >> 8) & 0xff;
+ myCDFRAM[address + 2] = (value >> 16) & 0xff;
+ myCDFRAM[address + 3] = (value >> 24) & 0xff; // high byte
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 CartridgeCDF::getWaveform(uInt8 index) const
{
uInt32 result;
+ uInt16 address = WAVEFORM[myVersion] + index * 4;
- result = myCDFRAM[WAVEFORM + index*4 + 0] + // low byte
- (myCDFRAM[WAVEFORM + index*4 + 1] << 8) +
- (myCDFRAM[WAVEFORM + index*4 + 2] << 16) +
- (myCDFRAM[WAVEFORM + index*4 + 3] << 24); // high byte
+ result = myCDFRAM[address + 0] + // low byte
+ (myCDFRAM[address + 1] << 8) +
+ (myCDFRAM[address + 2] << 16) +
+ (myCDFRAM[address + 3] << 24); // high byte
result -= (0x40000000 + DSRAM);
@@ -638,11 +632,12 @@ uInt32 CartridgeCDF::getWaveform(uInt8 index) const
uInt32 CartridgeCDF::getSample()
{
uInt32 result;
+ uInt16 address = WAVEFORM[myVersion];
- result = myCDFRAM[WAVEFORM + 0] + // low byte
- (myCDFRAM[WAVEFORM + 1] << 8) +
- (myCDFRAM[WAVEFORM + 2] << 16) +
- (myCDFRAM[WAVEFORM + 3] << 24); // high byte
+ result = myCDFRAM[address + 0] + // low byte
+ (myCDFRAM[address + 1] << 8) +
+ (myCDFRAM[address + 2] << 16) +
+ (myCDFRAM[address + 3] << 24); // high byte
return result;
}
@@ -673,3 +668,21 @@ uInt8 CartridgeCDF::readFromDatastream(uInt8 index)
setDatastreamPointer(index, pointer);
return value;
}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void CartridgeCDF::setVersion()
+{
+ myVersion = 0;
+
+ for(uInt32 i = 0; i < 2048; i += 4)
+ {
+ // CDF signature occurs 3 times in a row, i+3 (+7 or +11) is version
+ if ( myImage[i+0] == 0x43 && myImage[i + 4] == 0x43 && myImage[i + 8] == 0x43) // C
+ if ( myImage[i+1] == 0x44 && myImage[i + 5] == 0x44 && myImage[i + 9] == 0x44) // D
+ if (myImage[i+2] == 0x46 && myImage[i + 6] == 0x46 && myImage[i +10] == 0x46) // F
+ {
+ myVersion = myImage[i+3];
+ break;
+ }
+ }
+}
diff --git a/src/emucore/CartCDF.hxx b/src/emucore/CartCDF.hxx
index 0e08b2eae..34d4e9bf9 100644
--- a/src/emucore/CartCDF.hxx
+++ b/src/emucore/CartCDF.hxx
@@ -32,12 +32,12 @@ class System;
/**
Cartridge class used for CDF.
- THIS NEEDS TO BE UPDATED
-
-
There are seven 4K program banks, a 4K Display Data RAM,
- 1K C Varaible and Stack, and the CDF chip.
- CDF chip access is mapped to $1000 - $103F.
+ 1K C Variable and Stack, and the CDF chip.
+ CDF chip access is mapped to $1000 - $103F (both read and write).
+ Program banks are accessible by read/write to $1FF5 - $1FFB.
+
+ FIXME: THIS NEEDS TO BE UPDATED
@authors: Darrell Spice Jr, Chris Walton, Fred Quimby,
Stephen Anthony, Bradford W. Mott
@@ -73,13 +73,6 @@ class CartridgeCDF : public Cartridge
*/
void consoleChanged(ConsoleTiming timing) override;
- /**
- Notification method invoked by the system right before the
- system resets its cycle counter to zero. It may be necessary
- to override this method for devices that remember cycle counts.
- */
- void systemCyclesReset() override;
-
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@@ -120,7 +113,7 @@ class CartridgeCDF : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -145,8 +138,6 @@ class CartridgeCDF : public Cartridge
*/
string name() const override { return "CartridgeCDF"; }
- // uInt8 busOverdrive(uInt16 address) override;
-
/**
Used for Thumbulator to pass values back to the cartridge
*/
@@ -209,6 +200,7 @@ class CartridgeCDF : public Cartridge
uInt32 getWaveform(uInt8 index) const;
uInt32 getWaveformSize(uInt8 index) const;
uInt32 getSample();
+ void setVersion();
private:
// The 32K ROM image of the cartridge
@@ -234,14 +226,14 @@ class CartridgeCDF : public Cartridge
unique_ptr myThumbEmulator;
#endif
- // Indicates which bank is currently active
- uInt16 myCurrentBank;
+ // Indicates the offset into the ROM image (aligns to current bank)
+ uInt16 myBankOffset;
// System cycle count from when the last update to music data fetchers occurred
- Int32 myAudioCycles;
+ uInt64 myAudioCycles;
// ARM cycle count from when the last callFunction() occurred
- Int32 myARMCycles;
+ uInt64 myARMCycles;
// The audio routines in the driver run in 32-bit mode and take advantage
// of the FIQ Shadow Registers which are not accessible to 16-bit thumb
@@ -250,16 +242,16 @@ class CartridgeCDF : public Cartridge
// Thumbulator will trap these calls and pass the appropriate information to
// the Cartridge Class via callFunction() so it can emulate the 32 bit audio routines.
- /* Register usage for audio:
- r8 = channel0 accumulator
- r9 = channel1 accumulator
- r10 = channel2 accumulator
- r11 = channel0 frequency
- r12 = channel1 frequency
- r13 = channel2 frequency
- r14 = timer base */
+ /* Register usage for audio:
+ r8 = channel0 accumulator
+ r9 = channel1 accumulator
+ r10 = channel2 accumulator
+ r11 = channel0 frequency
+ r12 = channel1 frequency
+ r13 = channel2 frequency
+ r14 = timer base */
- // The music counters, ARM FIQ shadow registers r8, r9, r10
+ // The music counters, ARM FIQ shadow registers r8, r9, r10
uInt32 myMusicCounters[3];
// The music frequency, ARM FIQ shadow registers r11, r12, r13
@@ -289,6 +281,9 @@ class CartridgeCDF : public Cartridge
uInt8 myFastJumpActive;
+ // version of CDF
+ uInt16 myVersion;
+
private:
// Following constructors and assignment operators not supported
CartridgeCDF() = delete;
diff --git a/src/emucore/CartCM.cxx b/src/emucore/CartCM.cxx
index d1ba9a789..0acfca19f 100644
--- a/src/emucore/CartCM.cxx
+++ b/src/emucore/CartCM.cxx
@@ -25,7 +25,7 @@ CartridgeCM::CartridgeCM(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings),
mySWCHA(0xFF), // portA is all 1's
- myCurrentBank(0)
+ myBankOffset(0)
{
// Copy the ROM image into my buffer
memcpy(myImage, image.get(), std::min(16384u, size));
@@ -60,7 +60,7 @@ void CartridgeCM::install(System& system)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeCM::peek(uInt16 address)
{
- // NOTE: This does not handle accessing cart ROM/RAM, however, this function
+ // NOTE: This does not handle accessing cart ROM/RAM, however, this method
// should never be called for ROM/RAM because of the way page accessing
// has been setup (it will only ever be called for RIOT reads)
return mySystem->m6532().peek(address);
@@ -104,8 +104,7 @@ bool CartridgeCM::bank(uInt16 bank)
if(bankLocked()) return false;
// Remember what bank we're in
- myCurrentBank = bank;
- uInt16 offset = myCurrentBank << 12;
+ myBankOffset = bank << 12;
// Although this scheme contains four 4K ROM banks and one 2K RAM bank,
// it's easier to think of things in terms of 2K slices, as follows:
@@ -118,37 +117,35 @@ bool CartridgeCM::bank(uInt16 bank)
System::PageAccess access(this, System::PA_READ);
// Lower 2K (always ROM)
- for(uInt32 address = 0x1000; address < 0x1800;
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < 0x1800; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
// Upper 2K (RAM or ROM)
- for(uInt32 address = 0x1800; address < 0x2000;
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1800; addr < 0x2000; addr += System::PAGE_SIZE)
{
access.type = System::PA_READWRITE;
if(mySWCHA & 0x10)
{
- access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
+ access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
}
else
{
- access.directPeekBase = &myRAM[address & 0x7FF];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x07FF)];
+ access.directPeekBase = &myRAM[addr & 0x7FF];
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x07FF)];
}
if((mySWCHA & 0x30) == 0x20)
- access.directPokeBase = &myRAM[address & 0x7FF];
+ access.directPokeBase = &myRAM[addr & 0x7FF];
else
access.directPokeBase = 0;
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
@@ -157,7 +154,7 @@ bool CartridgeCM::bank(uInt16 bank)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeCM::getBank() const
{
- return myCurrentBank;
+ return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -176,13 +173,13 @@ bool CartridgeCM::patch(uInt16 address, uInt8 value)
if((mySWCHA & 0x30) == 0x20)
myRAM[address & 0x7FF] = value;
else
- myImage[(myCurrentBank << 12) + address] = value;
+ myImage[myBankOffset + address] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeCM::getImage(int& size) const
+const uInt8* CartridgeCM::getImage(uInt32& size) const
{
size = 16384;
return myImage;
@@ -194,7 +191,7 @@ bool CartridgeCM::save(Serializer& out) const
try
{
out.putString(name());
- out.putShort(myCurrentBank);
+ out.putShort(myBankOffset);
out.putByte(mySWCHA);
out.putByte(myCompuMate->column());
out.putByteArray(myRAM, 2048);
@@ -216,7 +213,7 @@ bool CartridgeCM::load(Serializer& in)
if(in.getString() != name())
return false;
- myCurrentBank = in.getShort();
+ myBankOffset = in.getShort();
mySWCHA = in.getByte();
myCompuMate->column() = in.getByte();
in.getByteArray(myRAM, 2048);
@@ -228,7 +225,7 @@ bool CartridgeCM::load(Serializer& in)
}
// Remember what bank we were in
- bank(myCurrentBank);
+ bank(myBankOffset >> 12);
return true;
}
diff --git a/src/emucore/CartCM.hxx b/src/emucore/CartCM.hxx
index 750ba69e4..94aef6c3a 100644
--- a/src/emucore/CartCM.hxx
+++ b/src/emucore/CartCM.hxx
@@ -28,6 +28,9 @@ class System;
#endif
/**
+ FIXME: This scheme is not yet fully implemented. In particular, loading
+ from and saving to the cassette is completely missing.
+
Cartridge class used for SpectraVideo CompuMate bankswitched games.
This is more than just a cartridge mapper - it's also a "computer" add-on.
@@ -165,7 +168,7 @@ class CartridgeCM : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -244,8 +247,8 @@ class CartridgeCM : public Cartridge
// Current copy of SWCHA (controls ROM/RAM accesses)
uInt8 mySWCHA;
- // Indicates which bank is currently active
- uInt16 myCurrentBank;
+ // Indicates the offset into the ROM image (aligns to current bank)
+ uInt16 myBankOffset;
private:
// Following constructors and assignment operators not supported
diff --git a/src/emucore/CartCTY.cxx b/src/emucore/CartCTY.cxx
index f8977eb11..616796792 100644
--- a/src/emucore/CartCTY.cxx
+++ b/src/emucore/CartCTY.cxx
@@ -31,9 +31,9 @@ CartridgeCTY::CartridgeCTY(const BytePtr& image, uInt32 size,
myLDAimmediate(false),
myRandomNumber(0x2B435044),
myRamAccessTimeout(0),
- mySystemCycles(0),
+ myAudioCycles(0),
myFractionalClocks(0.0),
- myCurrentBank(0)
+ myBankOffset(0)
{
// Copy the ROM image into my buffer
memcpy(myImage, image.get(), std::min(32768u, size));
@@ -53,21 +53,13 @@ void CartridgeCTY::reset()
myRAM[0] = myRAM[1] = myRAM[2] = myRAM[3] = 0xFF;
- // Update cycles to the current system cycles
- mySystemCycles = mySystem->cycles();
+ myAudioCycles = 0;
myFractionalClocks = 0.0;
// Upon reset we switch to the startup bank
bank(myStartBank);
}
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void CartridgeCTY::systemCyclesReset()
-{
- // Adjust the cycle counter so that it reflects the new value
- mySystemCycles -= mySystem->cycles();
-}
-
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeCTY::install(System& system)
{
@@ -75,8 +67,8 @@ void CartridgeCTY::install(System& system)
// Map all RAM accesses to call peek and poke
System::PageAccess access(this, System::PA_READ);
- for(uInt32 i = 0x1000; i < 0x1080; i += (1 << System::PAGE_SHIFT))
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE)
+ mySystem->setPageAccess(addr, access);
// Install pages for the startup bank
bank(myStartBank);
@@ -87,7 +79,7 @@ uInt8 CartridgeCTY::peek(uInt16 address)
{
uInt16 peekAddress = address;
address &= 0x0FFF;
- uInt8 peekValue = myImage[myCurrentBank + address];
+ uInt8 peekValue = myImage[myBankOffset + address];
// In debugger/bank-locked mode, we ignore all hotspots and in general
// anything that can change the internal state of the cart
@@ -233,15 +225,14 @@ bool CartridgeCTY::bank(uInt16 bank)
if(bankLocked()) return false;
// Remember what bank we're in
- myCurrentBank = bank << 12;
+ myBankOffset = bank << 12;
// Setup the page access methods for the current bank
System::PageAccess access(this, System::PA_READ);
- for(uInt32 address = 0x1080; address < 0x2000;
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1080; addr < 0x2000; addr += System::PAGE_SIZE)
{
- access.codeAccessBase = &myCodeAccessBase[myCurrentBank + (address & 0x0FFF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
@@ -249,7 +240,7 @@ bool CartridgeCTY::bank(uInt16 bank)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeCTY::getBank() const
{
- return myCurrentBank >> 12;
+ return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -271,13 +262,13 @@ bool CartridgeCTY::patch(uInt16 address, uInt8 value)
myRAM[address & 0x003F] = value;
}
else
- myImage[myCurrentBank + address] = value;
+ myImage[myBankOffset + address] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeCTY::getImage(int& size) const
+const uInt8* CartridgeCTY::getImage(uInt32& size) const
{
size = 32768;
return myImage;
@@ -296,8 +287,8 @@ bool CartridgeCTY::save(Serializer& out) const
out.putShort(myCounter);
out.putBool(myLDAimmediate);
out.putInt(myRandomNumber);
- out.putInt(mySystemCycles);
- out.putInt(uInt32(myFractionalClocks * 100000000.0));
+ out.putLong(myAudioCycles);
+ out.putDouble(myFractionalClocks);
}
catch(...)
@@ -325,8 +316,8 @@ bool CartridgeCTY::load(Serializer& in)
myCounter = in.getShort();
myLDAimmediate = in.getBool();
myRandomNumber = in.getInt();
- mySystemCycles = in.getInt();
- myFractionalClocks = double(in.getInt()) / 100000000.0;
+ myAudioCycles = in.getLong();
+ myFractionalClocks = in.getDouble();
}
catch(...)
{
@@ -403,7 +394,7 @@ uInt8 CartridgeCTY::ramReadWrite()
break;
}
// Bit 6 is 1, busy
- return myImage[myCurrentBank + 0xFF4] | 0x40;
+ return myImage[myBankOffset + 0xFF4] | 0x40;
}
else
{
@@ -414,11 +405,11 @@ uInt8 CartridgeCTY::ramReadWrite()
myRAM[0] = 0; // Successful operation
// Bit 6 is 0, ready/success
- return myImage[myCurrentBank + 0xFF4] & ~0x40;
+ return myImage[myBankOffset + 0xFF4] & ~0x40;
}
else
// Bit 6 is 1, busy
- return myImage[myCurrentBank + 0xFF4] | 0x40;
+ return myImage[myBankOffset + 0xFF4] | 0x40;
}
}
@@ -513,18 +504,16 @@ void CartridgeCTY::wipeAllScores()
inline void CartridgeCTY::updateMusicModeDataFetchers()
{
// Calculate the number of cycles since the last update
- Int32 cycles = mySystem->cycles() - mySystemCycles;
- mySystemCycles = mySystem->cycles();
+ uInt32 cycles = uInt32(mySystem->cycles() - myAudioCycles);
+ myAudioCycles = mySystem->cycles();
- // Calculate the number of DPC OSC clocks since the last update
+ // Calculate the number of CTY OSC clocks since the last update
double clocks = ((20000.0 * cycles) / 1193191.66666667) + myFractionalClocks;
- Int32 wholeClocks = Int32(clocks);
+ uInt32 wholeClocks = uInt32(clocks);
myFractionalClocks = clocks - double(wholeClocks);
- if(wholeClocks <= 0)
- return;
-
// Let's update counters and flags of the music mode data fetchers
- for(int x = 0; x <= 2; ++x)
- ; // myMusicCounters[x] += myMusicFrequencies[x] * wholeClocks;
+ if(wholeClocks > 0)
+ for(int x = 0; x <= 2; ++x)
+ ; //myMusicCounters[x] += myMusicFrequencies[x] * wholeClocks;
}
diff --git a/src/emucore/CartCTY.hxx b/src/emucore/CartCTY.hxx
index 7a722773c..67b95ee26 100644
--- a/src/emucore/CartCTY.hxx
+++ b/src/emucore/CartCTY.hxx
@@ -27,6 +27,8 @@ class System;
#endif
/**
+ FIXME: This scheme is not yet fully implemented.
+
The 'Chetiry' bankswitch scheme was developed by Chris D. Walton for a
Tetris clone game by the same name. It makes use of a Harmony cart,
whereby ARM code in bank 0 is executed to implement the bankswitch scheme.
@@ -128,13 +130,6 @@ class CartridgeCTY : public Cartridge
*/
void reset() override;
- /**
- Notification method invoked by the system right before the
- system resets its cycle counter to zero. It may be necessary
- to override this method for devices that remember cycle counts.
- */
- void systemCyclesReset() override;
-
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@@ -175,7 +170,7 @@ class CartridgeCTY : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -297,14 +292,14 @@ class CartridgeCTY : public Cartridge
// of internal RAM to Harmony cart EEPROM
string myEEPROMFile;
- // System cycle count when the last update to music data fetchers occurred
- Int32 mySystemCycles;
+ // System cycle count from when the last update to music data fetchers occurred
+ uInt64 myAudioCycles;
// Fractional DPC music OSC clocks unused during the last update
double myFractionalClocks;
- // Indicates which bank is currently active
- uInt16 myCurrentBank;
+ // Indicates the offset into the ROM image (aligns to current bank)
+ uInt16 myBankOffset;
private:
// Following constructors and assignment operators not supported
diff --git a/src/emucore/CartCV.cxx b/src/emucore/CartCV.cxx
index b22616542..4888611a2 100644
--- a/src/emucore/CartCV.cxx
+++ b/src/emucore/CartCV.cxx
@@ -66,62 +66,49 @@ void CartridgeCV::install(System& system)
System::PageAccess access(this, System::PA_READ);
// Map ROM image into the system
- for(uInt32 address = 0x1800; address < 0x2000;
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1800; addr < 0x2000; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[address & 0x07FF];
- access.codeAccessBase = &myCodeAccessBase[address & 0x07FF];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[addr & 0x07FF];
+ access.codeAccessBase = &myCodeAccessBase[addr & 0x07FF];
+ mySystem->setPageAccess(addr, access);
}
// Set the page accessing method for the RAM writing pages
access.directPeekBase = 0;
access.codeAccessBase = 0;
access.type = System::PA_WRITE;
- for(uInt32 j = 0x1400; j < 0x1800; j += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE)
{
- access.directPokeBase = &myRAM[j & 0x03FF];
- mySystem->setPageAccess(j >> System::PAGE_SHIFT, access);
+ access.directPokeBase = &myRAM[addr & 0x03FF];
+ mySystem->setPageAccess(addr, access);
}
// Set the page accessing method for the RAM reading pages
access.directPokeBase = 0;
access.type = System::PA_READ;
- for(uInt32 k = 0x1000; k < 0x1400; k += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myRAM[k & 0x03FF];
- access.codeAccessBase = &myCodeAccessBase[2048 + (k & 0x03FF)];
- mySystem->setPageAccess(k >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myRAM[addr & 0x03FF];
+ access.codeAccessBase = &myCodeAccessBase[2048 + (addr & 0x03FF)];
+ mySystem->setPageAccess(addr, access);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeCV::peek(uInt16 address)
{
- if((address & 0x0FFF) < 0x0800) // Write port is at 0xF400 - 0xF800 (1024 bytes)
- { // Read port is handled in ::install()
- // Reading from the write port triggers an unwanted write
- uInt8 value = mySystem->getDataBusState(0xFF);
+ // The only way we can get to this method is if we attempt to read from
+ // the write port (0xF400 - 0xF800, 1024 bytes), in which case an
+ // unwanted write is triggered
+ uInt8 value = mySystem->getDataBusState(0xFF);
- if(bankLocked())
- return value;
- else
- {
- triggerReadFromWritePort(address);
- return myRAM[address & 0x03FF] = value;
- }
- }
+ if(bankLocked())
+ return value;
else
- return myImage[address & 0x07FF];
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool CartridgeCV::poke(uInt16, uInt8)
-{
- // NOTE: This does not handle accessing RAM, however, this function
- // should never be called for RAM because of the way page accessing
- // has been setup
- return false;
+ {
+ triggerReadFromWritePort(address);
+ return myRAM[address & 0x03FF] = value;
+ }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -144,7 +131,7 @@ bool CartridgeCV::patch(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeCV::getImage(int& size) const
+const uInt8* CartridgeCV::getImage(uInt32& size) const
{
size = 2048;
return myImage;
diff --git a/src/emucore/CartCV.hxx b/src/emucore/CartCV.hxx
index 0686bc362..f523ede46 100644
--- a/src/emucore/CartCV.hxx
+++ b/src/emucore/CartCV.hxx
@@ -79,7 +79,7 @@ class CartridgeCV : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -124,15 +124,6 @@ class CartridgeCV : public Cartridge
*/
uInt8 peek(uInt16 address) override;
- /**
- Change the byte at the specified address to the given value
-
- @param address The address where the value should be stored
- @param value The value to be stored at the address
- @return True if the poke changed the device address space, else false
- */
- bool poke(uInt16 address, uInt8 value) override;
-
private:
// Pointer to the initial RAM data from the cart
// This doesn't always exist, so we don't pre-allocate it
diff --git a/src/emucore/CartCVPlus.cxx b/src/emucore/CartCVPlus.cxx
index c9bf1d258..8718deb1a 100644
--- a/src/emucore/CartCVPlus.cxx
+++ b/src/emucore/CartCVPlus.cxx
@@ -53,32 +53,29 @@ void CartridgeCVPlus::install(System& system)
System::PageAccess access(this, System::PA_READWRITE);
- // Set the page accessing methods for the hot spots (for 100% emulation
- // we need to chain any accesses below 0x40 to the TIA. Our poke() method
- // does this via mySystem->tiaPoke(...), at least until we come up with a
- // cleaner way to do it).
- for(uInt32 i = 0x00; i < 0x40; i += (1 << System::PAGE_SHIFT))
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ // The hotspot ($3D) is in TIA address space, so we claim it here
+ for(uInt16 addr = 0x00; addr < 0x40; addr += System::PAGE_SIZE)
+ mySystem->setPageAccess(addr, access);
// Set the page accessing method for the RAM writing pages
access.directPeekBase = 0;
access.codeAccessBase = 0;
access.type = System::PA_WRITE;
- for(uInt32 j = 0x1400; j < 0x1800; j += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE)
{
- access.directPokeBase = &myRAM[j & 0x03FF];
- access.codeAccessBase = &myCodeAccessBase[mySize + (j & 0x03FF)];
- mySystem->setPageAccess(j >> System::PAGE_SHIFT, access);
+ access.directPokeBase = &myRAM[addr & 0x03FF];
+ access.codeAccessBase = &myCodeAccessBase[mySize + (addr & 0x03FF)];
+ mySystem->setPageAccess(addr, access);
}
// Set the page accessing method for the RAM reading pages
access.directPokeBase = 0;
access.type = System::PA_READ;
- for(uInt32 k = 0x1000; k < 0x1400; k += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myRAM[k & 0x03FF];
- access.codeAccessBase = &myCodeAccessBase[mySize + (k & 0x03FF)];
- mySystem->setPageAccess(k >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myRAM[addr & 0x03FF];
+ access.codeAccessBase = &myCodeAccessBase[mySize + (addr & 0x03FF)];
+ mySystem->setPageAccess(addr, access);
}
// Install pages for the startup bank into the first segment
@@ -114,10 +111,7 @@ bool CartridgeCVPlus::poke(uInt16 address, uInt8 value)
if(address == 0x003D)
bank(value);
- // Pass the poke through to the TIA. In a real Atari, both the cart and the
- // TIA see the address lines, and both react accordingly. In Stella, each
- // 64-byte chunk of address space is "owned" by only one device. If we
- // don't chain the poke to the TIA, then the TIA can't see it...
+ // Handle TIA space that we claimed above
mySystem->tia().poke(address, value);
return false;
@@ -146,12 +140,11 @@ bool CartridgeCVPlus::bank(uInt16 bank)
System::PageAccess access(this, System::PA_READ);
// Map ROM image into the system
- for(uInt32 address = 0x1800; address < 0x2000;
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1800; addr < 0x2000; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[offset + (address & 0x07FF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x07FF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[offset + (addr & 0x07FF)];
+ access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x07FF)];
+ mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
@@ -189,7 +182,7 @@ bool CartridgeCVPlus::patch(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeCVPlus::getImage(int& size) const
+const uInt8* CartridgeCVPlus::getImage(uInt32& size) const
{
size = mySize;
return myImage.get();
diff --git a/src/emucore/CartCVPlus.hxx b/src/emucore/CartCVPlus.hxx
index f60bfa7a2..bd513a862 100644
--- a/src/emucore/CartCVPlus.hxx
+++ b/src/emucore/CartCVPlus.hxx
@@ -106,7 +106,7 @@ class CartridgeCVPlus : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
diff --git a/src/emucore/CartDASH.cxx b/src/emucore/CartDASH.cxx
index 814c1fbed..993626ce5 100644
--- a/src/emucore/CartDASH.cxx
+++ b/src/emucore/CartDASH.cxx
@@ -63,12 +63,9 @@ void CartridgeDASH::install(System& system)
System::PageAccess access(this, System::PA_READWRITE);
- // Set the page accessing methods for the hot spots (for 100% emulation
- // we need to chain any accesses below 0x40 to the TIA. Our poke() method
- // does this via mySystem->tiaPoke(...), at least until we come up with a
- // cleaner way to do it).
- for (uInt32 i = 0x00; i < 0x40; i += (1 << System::PAGE_SHIFT))
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ // The hotspots are in TIA address space, so we claim it here
+ for (uInt16 addr = 0x00; addr < 0x40; addr += System::PAGE_SIZE)
+ mySystem->setPageAccess(addr, access);
// Initialise bank values for all ROM/RAM access
// This is used to reverse-lookup from address to bank location
@@ -136,10 +133,7 @@ bool CartridgeDASH::poke(uInt16 address, uInt8 value)
else if (address == BANK_SWITCH_HOTSPOT_ROM)
changed = bankROM(value);
- // Pass the poke through to the TIA. In a real Atari, both the cart and the
- // TIA see the address lines, and both react accordingly. In Stella, each
- // 64-byte chunk of address space is "owned" by only one device. If we
- // don't chain the poke to the TIA, then the TIA can't see it...
+ // Handle TIA space that we claimed above
mySystem->tia().poke(address, value);
return changed;
@@ -184,18 +178,18 @@ void CartridgeDASH::bankRAMSlot(uInt16 bank)
access.type = System::PA_READ;
}
- uInt32 start = 0x1000 + (bankNumber << RAM_BANK_TO_POWER) + (upper ? RAM_WRITE_OFFSET : 0);
- uInt32 end = start + RAM_BANK_SIZE - 1;
+ uInt16 start = 0x1000 + (bankNumber << RAM_BANK_TO_POWER) + (upper ? RAM_WRITE_OFFSET : 0);
+ uInt16 end = start + RAM_BANK_SIZE - 1;
- for (uInt32 address = start; address <= end; address += (1 << System::PAGE_SHIFT))
+ for (uInt16 addr = start; addr <= end; addr += System::PAGE_SIZE)
{
if(upper)
- access.directPokeBase = &myRAM[startCurrentBank + (address & (RAM_BANK_SIZE - 1))];
+ access.directPokeBase = &myRAM[startCurrentBank + (addr & (RAM_BANK_SIZE - 1))];
else
- access.directPeekBase = &myRAM[startCurrentBank + (address & (RAM_BANK_SIZE - 1))];
+ access.directPeekBase = &myRAM[startCurrentBank + (addr & (RAM_BANK_SIZE - 1))];
- access.codeAccessBase = &myCodeAccessBase[mySize + startCurrentBank + (address & (RAM_BANK_SIZE - 1))];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.codeAccessBase = &myCodeAccessBase[mySize + startCurrentBank + (addr & (RAM_BANK_SIZE - 1))];
+ mySystem->setPageAccess(addr, access);
}
}
@@ -231,14 +225,14 @@ void CartridgeDASH::bankROMSlot(uInt16 bank)
// Setup the page access methods for the current bank
System::PageAccess access(this, System::PA_READ);
- uInt32 start = 0x1000 + (bankNumber << ROM_BANK_TO_POWER) + (upper ? ROM_BANK_SIZE / 2 : 0);
- uInt32 end = start + ROM_BANK_SIZE / 2 - 1;
+ uInt16 start = 0x1000 + (bankNumber << ROM_BANK_TO_POWER) + (upper ? ROM_BANK_SIZE / 2 : 0);
+ uInt16 end = start + ROM_BANK_SIZE / 2 - 1;
- for (uInt32 address = start; address <= end; address += (1 << System::PAGE_SHIFT))
+ for (uInt16 addr = start; addr <= end; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[startCurrentBank + (address & (ROM_BANK_SIZE - 1))];
- access.codeAccessBase = &myCodeAccessBase[startCurrentBank + (address & (ROM_BANK_SIZE - 1))];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[startCurrentBank + (addr & (ROM_BANK_SIZE - 1))];
+ access.codeAccessBase = &myCodeAccessBase[startCurrentBank + (addr & (ROM_BANK_SIZE - 1))];
+ mySystem->setPageAccess(addr, access);
}
}
@@ -252,10 +246,10 @@ void CartridgeDASH::initializeBankState()
{
// All accesses point to peek/poke above
System::PageAccess access(this, System::PA_READ);
- uInt32 start = 0x1000 + (b << RAM_BANK_TO_POWER);
- uInt32 end = start + RAM_BANK_SIZE - 1;
- for (uInt32 address = start; address <= end; address += (1 << System::PAGE_SHIFT))
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ uInt16 start = 0x1000 + (b << RAM_BANK_TO_POWER);
+ uInt16 end = start + RAM_BANK_SIZE - 1;
+ for (uInt16 addr = start; addr <= end; addr += System::PAGE_SIZE)
+ mySystem->setPageAccess(addr, access);
}
else if (bankInUse[b] & BITMASK_ROMRAM)
bankRAMSlot(bankInUse[b]);
@@ -302,7 +296,7 @@ bool CartridgeDASH::patch(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeDASH::getImage(int& size) const
+const uInt8* CartridgeDASH::getImage(uInt32& size) const
{
size = mySize;
return myImage.get();
diff --git a/src/emucore/CartDASH.hxx b/src/emucore/CartDASH.hxx
index 6b28c608d..372258ea0 100644
--- a/src/emucore/CartDASH.hxx
+++ b/src/emucore/CartDASH.hxx
@@ -29,98 +29,98 @@ class CartridgeDASHWidget;
#endif
/**
- Cartridge class for new tiling engine "Boulder Dash" format games with RAM.
- Kind of a combination of 3F and 3E, with better switchability.
- B.Watson's Cart3E was used as a template for building this implementation.
+ Cartridge class for new tiling engine "Boulder Dash" format games with RAM.
+ Kind of a combination of 3F and 3E, with better switchability.
+ B.Watson's Cart3E was used as a template for building this implementation.
- The destination bank (0-3) is held in the top bits of the value written to
- $3E (for RAM switching) or $3F (for ROM switching). The low 6 bits give
- the actual bank number (0-63) corresponding to 512 byte blocks for RAM and
- 1024 byte blocks for ROM. The maximum size is therefore 32K RAM and 64K ROM.
+ The destination bank (0-3) is held in the top bits of the value written to
+ $3E (for RAM switching) or $3F (for ROM switching). The low 6 bits give
+ the actual bank number (0-63) corresponding to 512 byte blocks for RAM and
+ 1024 byte blocks for ROM. The maximum size is therefore 32K RAM and 64K ROM.
- D7D6 indicate the bank number (0-3)
- D5D4D3D2D1D0 indicate the actual # (0-63) from the image/ram
+ D7D6 indicate the bank number (0-3)
+ D5D4D3D2D1D0 indicate the actual # (0-63) from the image/ram
- ROM:
+ ROM:
- Note: in descriptions $F000 is equivalent to $1000 -- that is, we only deal
- with the low 13 bits of addressing. Stella code uses $1000, I'm used to $F000
- So, mask with top bits clear :) when reading this document.
+ Note: in descriptions $F000 is equivalent to $1000 -- that is, we only deal
+ with the low 13 bits of addressing. Stella code uses $1000, I'm used to $F000
+ So, mask with top bits clear :) when reading this document.
- In this scheme, the 4K address space is broken into four 1K ROM segments.
- living at 0x1000, 0x1400, 0x1800, 0x1C00 (or, same thing, 0xF000... etc.),
- and four 512 byte RAM segments, living at 0x1000, 0x1200, 0x1400, 0x1600
- with write-mirrors +0x800 of these. The last 1K ROM ($FC00-$FFFF) segment
- in the 6502 address space (ie: $1C00-$1FFF) is initialised to point to the
- FIRST 1K of the ROM image, so the reset vectors must be placed at the
- end of the first 1K in the ROM image. Note, this is DIFFERENT to 3E which
- switches in the UPPER bank and this bank is fixed. This allows variable sized
- ROM without having to detect size. First bank (0) in ROM is the default fixed
- bank mapped to $FC00.
+ In this scheme, the 4K address space is broken into four 1K ROM segments.
+ living at 0x1000, 0x1400, 0x1800, 0x1C00 (or, same thing, 0xF000... etc.),
+ and four 512 byte RAM segments, living at 0x1000, 0x1200, 0x1400, 0x1600
+ with write-mirrors +0x800 of these. The last 1K ROM ($FC00-$FFFF) segment
+ in the 6502 address space (ie: $1C00-$1FFF) is initialised to point to the
+ FIRST 1K of the ROM image, so the reset vectors must be placed at the
+ end of the first 1K in the ROM image. Note, this is DIFFERENT to 3E which
+ switches in the UPPER bank and this bank is fixed. This allows variable sized
+ ROM without having to detect size. First bank (0) in ROM is the default fixed
+ bank mapped to $FC00.
- The system requires the reset vectors to be valid on a reset, so either the
- hardware first switches in the first bank, or the programmer must ensure
- that the reset vector is present in ALL ROM banks which might be switched
- into the last bank area. Currently the latter (programmer onus) is required,
- but it would be nice for the cartridge hardware to auto-switch on reset.
+ The system requires the reset vectors to be valid on a reset, so either the
+ hardware first switches in the first bank, or the programmer must ensure
+ that the reset vector is present in ALL ROM banks which might be switched
+ into the last bank area. Currently the latter (programmer onus) is required,
+ but it would be nice for the cartridge hardware to auto-switch on reset.
- ROM switching (write of block+bank number to $3F) D7D6 upper 2 bits of bank #
- indicates the destination segment (0-3, corresponding to $F000, $F400, $F800,
- $FC00), and lower 6 bits indicate the 1K bank to switch in. Can handle 64
- x 1K ROM banks (64K total).
+ ROM switching (write of block+bank number to $3F) D7D6 upper 2 bits of bank #
+ indicates the destination segment (0-3, corresponding to $F000, $F400, $F800,
+ $FC00), and lower 6 bits indicate the 1K bank to switch in. Can handle 64
+ x 1K ROM banks (64K total).
- D7 D6 D5D4D3D2D1D0
- 0 0 x x x x x x switch a 1K ROM bank xxxxx to $F000
- 0 1 switch a 1K ROM bank xxxxx to $F400
- 1 0 switch a 1K ROM bank xxxxx to $F800
- 1 1 switch a 1K ROM bank xxxxx to $FC00
+ D7 D6 D5D4D3D2D1D0
+ 0 0 x x x x x x switch a 1K ROM bank xxxxx to $F000
+ 0 1 switch a 1K ROM bank xxxxx to $F400
+ 1 0 switch a 1K ROM bank xxxxx to $F800
+ 1 1 switch a 1K ROM bank xxxxx to $FC00
- RAM switching (write of segment+bank number to $3E) with D7D6 upper 2 bits of
- bank # indicates the destination RAM segment (0-3, corresponding to $F000,
- $F200, $F400, $F600). Note that this allows contiguous 2K of RAM to be
- configured by setting 4 consecutive RAM segments each 512 bytes with
- consecutive addresses. However, as the write address of RAM is +0x800, this
- invalidates ROM access as described below.
+ RAM switching (write of segment+bank number to $3E) with D7D6 upper 2 bits of
+ bank # indicates the destination RAM segment (0-3, corresponding to $F000,
+ $F200, $F400, $F600). Note that this allows contiguous 2K of RAM to be
+ configured by setting 4 consecutive RAM segments each 512 bytes with
+ consecutive addresses. However, as the write address of RAM is +0x800, this
+ invalidates ROM access as described below.
- can handle 64 x 512 byte RAM banks (32K total)
+ can handle 64 x 512 byte RAM banks (32K total)
- D7 D6 D5D4D3D2D1D0
- 0 0 x x x x x x switch a 512 byte RAM bank xxxxx to $F000 with write @ $F800
- 0 1 switch a 512 byte RAM bank xxxxx to $F200 with write @ $FA00
- 1 0 switch a 512 byte RAM bank xxxxx to $F400 with write @ $FC00
- 1 1 switch a 512 byte RAM bank xxxxx to $F600 with write @ $FE00
+ D7 D6 D5D4D3D2D1D0
+ 0 0 x x x x x x switch a 512 byte RAM bank xxxxx to $F000 with write @ $F800
+ 0 1 switch a 512 byte RAM bank xxxxx to $F200 with write @ $FA00
+ 1 0 switch a 512 byte RAM bank xxxxx to $F400 with write @ $FC00
+ 1 1 switch a 512 byte RAM bank xxxxx to $F600 with write @ $FE00
- It is possible to switch multiple RAM banks and ROM banks together
+ It is possible to switch multiple RAM banks and ROM banks together
- For example,
- F000-F1FF RAM bank A (512 byte READ)
- F200-F3FF high 512 bytes of ROM bank previously loaded at F000
- F400 ROM bank 0 (1K)
- F800 RAM bank A (512 byte WRITE)
- FA00-FBFF high 512 bytes of ROM bank previously loaded at F400
- FC00 ROM bank 1
+ For example,
+ F000-F1FF RAM bank A (512 byte READ)
+ F200-F3FF high 512 bytes of ROM bank previously loaded at F000
+ F400 ROM bank 0 (1K)
+ F800 RAM bank A (512 byte WRITE)
+ FA00-FBFF high 512 bytes of ROM bank previously loaded at F400
+ FC00 ROM bank 1
- This example shows 512 bytes of RAM, and 2 1K ROM banks and two 512 byte ROM
- bank halves.
+ This example shows 512 bytes of RAM, and 2 1K ROM banks and two 512 byte ROM
+ bank halves.
- Switching RAM blocks (D7D6 of $3E) partially invalidates ROM blocks, as below...
+ Switching RAM blocks (D7D6 of $3E) partially invalidates ROM blocks, as below...
- RAM block Invalidates ROM block
- 0 0 (lower half), 2 (lower half)
- 1 0 (upper half), 2 (upper half)
- 2 1 (lower half), 3 (upper half)
- 3 1 (upper half), 3 (lower half)
+ RAM block Invalidates ROM block
+ 0 0 (lower half), 2 (lower half)
+ 1 0 (upper half), 2 (upper half)
+ 2 1 (lower half), 3 (upper half)
+ 3 1 (upper half), 3 (lower half)
- For example, RAM block 1 uses address $F200-$F3FF and $FA00-$FBFF
- ROM block 0 uses address $F000-$F3FF, and ROM block 2 uses address $F800-$FBFF
- Switching in RAM block 1 makes F200-F3FF ROM inaccessible, however F000-F1FF is
- still readable. So, care must be paid.
+ For example, RAM block 1 uses address $F200-$F3FF and $FA00-$FBFF
+ ROM block 0 uses address $F000-$F3FF, and ROM block 2 uses address $F800-$FBFF
+ Switching in RAM block 1 makes F200-F3FF ROM inaccessible, however F000-F1FF is
+ still readable. So, care must be paid.
- This crazy RAM layout is useful as it allows contiguous RAM to be switched in,
- up to 2K in one sequentially accessible block. This means you CAN have 2K of
- consecutive RAM (don't forget to copy your reset vectors!)
+ This crazy RAM layout is useful as it allows contiguous RAM to be switched in,
+ up to 2K in one sequentially accessible block. This means you CAN have 2K of
+ consecutive RAM (don't forget to copy your reset vectors!)
- @author Andrew Davie
+ @author Andrew Davie
*/
class CartridgeDASH: public Cartridge
@@ -165,7 +165,7 @@ class CartridgeDASH: public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
diff --git a/src/emucore/CartDF.cxx b/src/emucore/CartDF.cxx
index 8997fd3fe..1091c9a02 100644
--- a/src/emucore/CartDF.cxx
+++ b/src/emucore/CartDF.cxx
@@ -22,7 +22,7 @@
CartridgeDF::CartridgeDF(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings),
- myCurrentBank(0)
+ myBankOffset(0)
{
// Copy the ROM image into my buffer
memcpy(myImage, image.get(), std::min(131072u, size));
@@ -57,7 +57,7 @@ uInt8 CartridgeDF::peek(uInt16 address)
if((address >= 0x0FC0) && (address <= 0x0FDF))
bank(address - 0x0FC0);
- return myImage[(myCurrentBank << 12) + address];
+ return myImage[myBankOffset + address];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -78,26 +78,25 @@ bool CartridgeDF::bank(uInt16 bank)
if(bankLocked()) return false;
// Remember what bank we're in
- myCurrentBank = bank;
- uInt32 offset = myCurrentBank << 12;
+ myBankOffset = bank << 12;
System::PageAccess access(this, System::PA_READ);
// Set the page accessing methods for the hot spots
- for(uInt32 i = (0x1FC0 & ~System::PAGE_MASK); i < 0x2000;
- i += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = (0x1FC0 & ~System::PAGE_MASK); addr < 0x2000;
+ addr += System::PAGE_SIZE)
{
- access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)];
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
// Setup the page access methods for the current bank
- for(uInt32 address = 0x1000; address < (0x1FC0U & ~System::PAGE_MASK);
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < (0x1FC0U & ~System::PAGE_MASK);
+ addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
@@ -105,7 +104,7 @@ bool CartridgeDF::bank(uInt16 bank)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeDF::getBank() const
{
- return myCurrentBank;
+ return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -117,12 +116,12 @@ uInt16 CartridgeDF::bankCount() const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeDF::patch(uInt16 address, uInt8 value)
{
- myImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value;
+ myImage[myBankOffset + (address & 0x0FFF)] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeDF::getImage(int& size) const
+const uInt8* CartridgeDF::getImage(uInt32& size) const
{
size = 131072;
return myImage;
@@ -134,7 +133,7 @@ bool CartridgeDF::save(Serializer& out) const
try
{
out.putString(name());
- out.putShort(myCurrentBank);
+ out.putInt(myBankOffset);
}
catch(...)
{
@@ -153,7 +152,7 @@ bool CartridgeDF::load(Serializer& in)
if(in.getString() != name())
return false;
- myCurrentBank = in.getShort();
+ myBankOffset = in.getInt();
}
catch(...)
{
@@ -162,7 +161,7 @@ bool CartridgeDF::load(Serializer& in)
}
// Remember what bank we were in
- bank(myCurrentBank);
+ bank(myBankOffset >> 12);
return true;
}
diff --git a/src/emucore/CartDF.hxx b/src/emucore/CartDF.hxx
index 031dfe019..74a05958b 100644
--- a/src/emucore/CartDF.hxx
+++ b/src/emucore/CartDF.hxx
@@ -94,7 +94,7 @@ class CartridgeDF : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -152,8 +152,8 @@ class CartridgeDF : public Cartridge
// The 128K ROM image of the cartridge
uInt8 myImage[32 * 4096];
- // Indicates which bank is currently active
- uInt16 myCurrentBank;
+ // Indicates the offset into the ROM image (aligns to current bank)
+ uInt32 myBankOffset;
private:
// Following constructors and assignment operators not supported
diff --git a/src/emucore/CartDFSC.cxx b/src/emucore/CartDFSC.cxx
index 6a71a21cb..1db4103e8 100644
--- a/src/emucore/CartDFSC.cxx
+++ b/src/emucore/CartDFSC.cxx
@@ -22,7 +22,7 @@
CartridgeDFSC::CartridgeDFSC(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings),
- myCurrentBank(0)
+ myBankOffset(0)
{
// Copy the ROM image into my buffer
memcpy(myImage, image.get(), std::min(131072u, size));
@@ -50,21 +50,21 @@ void CartridgeDFSC::install(System& system)
// Set the page accessing method for the RAM writing pages
access.type = System::PA_WRITE;
- for(uInt32 j = 0x1000; j < 0x1080; j += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE)
{
- access.directPokeBase = &myRAM[j & 0x007F];
- access.codeAccessBase = &myCodeAccessBase[j & 0x007F];
- mySystem->setPageAccess(j >> System::PAGE_SHIFT, access);
+ access.directPokeBase = &myRAM[addr & 0x007F];
+ access.codeAccessBase = &myCodeAccessBase[addr & 0x007F];
+ mySystem->setPageAccess(addr, access);
}
// Set the page accessing method for the RAM reading pages
access.directPokeBase = 0;
access.type = System::PA_READ;
- for(uInt32 k = 0x1080; k < 0x1100; k += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myRAM[k & 0x007F];
- access.codeAccessBase = &myCodeAccessBase[0x80 + (k & 0x007F)];
- mySystem->setPageAccess(k >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myRAM[addr & 0x007F];
+ access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)];
+ mySystem->setPageAccess(addr, access);
}
// Install pages for the startup bank
@@ -95,7 +95,7 @@ uInt8 CartridgeDFSC::peek(uInt16 address)
}
}
else
- return myImage[(myCurrentBank << 12) + address];
+ return myImage[myBankOffset + address];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -107,7 +107,7 @@ bool CartridgeDFSC::poke(uInt16 address, uInt8)
if((address >= 0x0FC0) && (address <= 0x0FDF))
bank(address - 0x0FC0);
- // NOTE: This does not handle accessing RAM, however, this function
+ // NOTE: This does not handle accessing RAM, however, this method
// should never be called for RAM because of the way page accessing
// has been setup
return false;
@@ -119,26 +119,25 @@ bool CartridgeDFSC::bank(uInt16 bank)
if(bankLocked()) return false;
// Remember what bank we're in
- myCurrentBank = bank;
- uInt32 offset = myCurrentBank << 12;
+ myBankOffset = bank << 12;
System::PageAccess access(this, System::PA_READ);
// Set the page accessing methods for the hot spots
- for(uInt32 i = (0x1FC0 & ~System::PAGE_MASK); i < 0x2000;
- i += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = (0x1FC0 & ~System::PAGE_MASK); addr < 0x2000;
+ addr += System::PAGE_SIZE)
{
- access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)];
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
// Setup the page access methods for the current bank
- for(uInt32 address = 0x1100; address < (0x1FC0U & ~System::PAGE_MASK);
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1100; addr < (0x1FC0U & ~System::PAGE_MASK);
+ addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
@@ -146,7 +145,7 @@ bool CartridgeDFSC::bank(uInt16 bank)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeDFSC::getBank() const
{
- return myCurrentBank;
+ return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -168,13 +167,13 @@ bool CartridgeDFSC::patch(uInt16 address, uInt8 value)
myRAM[address & 0x007F] = value;
}
else
- myImage[(myCurrentBank << 12) + address] = value;
+ myImage[myBankOffset + address] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeDFSC::getImage(int& size) const
+const uInt8* CartridgeDFSC::getImage(uInt32& size) const
{
size = 131072;
return myImage;
@@ -186,7 +185,7 @@ bool CartridgeDFSC::save(Serializer& out) const
try
{
out.putString(name());
- out.putShort(myCurrentBank);
+ out.putInt(myBankOffset);
out.putByteArray(myRAM, 128);
}
catch(...)
@@ -206,7 +205,7 @@ bool CartridgeDFSC::load(Serializer& in)
if(in.getString() != name())
return false;
- myCurrentBank = in.getShort();
+ myBankOffset = in.getInt();
in.getByteArray(myRAM, 128);
}
catch(...)
@@ -216,7 +215,7 @@ bool CartridgeDFSC::load(Serializer& in)
}
// Remember what bank we were in
- bank(myCurrentBank);
+ bank(myBankOffset >> 12);
return true;
}
diff --git a/src/emucore/CartDFSC.hxx b/src/emucore/CartDFSC.hxx
index d0d65fa4e..dc41285aa 100644
--- a/src/emucore/CartDFSC.hxx
+++ b/src/emucore/CartDFSC.hxx
@@ -29,6 +29,7 @@ class System;
/**
There are 32 4K banks (total of 128K ROM) with 128 bytes of RAM.
Accessing $1FC0 - $1FDF switches to each bank.
+ RAM read port is $1080 - $10FF, write port is $1000 - $107F.
@author Stephen Anthony
*/
@@ -93,7 +94,7 @@ class CartridgeDFSC : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -154,8 +155,8 @@ class CartridgeDFSC : public Cartridge
// The 128 bytes of RAM
uInt8 myRAM[128];
- // Indicates which bank is currently active
- uInt16 myCurrentBank;
+ // Indicates the offset into the ROM image (aligns to current bank)
+ uInt32 myBankOffset;
private:
// Following constructors and assignment operators not supported
diff --git a/src/emucore/CartDPC.cxx b/src/emucore/CartDPC.cxx
index a38b23d7d..bf46166cd 100644
--- a/src/emucore/CartDPC.cxx
+++ b/src/emucore/CartDPC.cxx
@@ -23,9 +23,9 @@ CartridgeDPC::CartridgeDPC(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings),
mySize(size),
- mySystemCycles(0),
+ myAudioCycles(0),
myFractionalClocks(0.0),
- myCurrentBank(0)
+ myBankOffset(0)
{
// Make a copy of the entire image
memcpy(myImage, image.get(), std::min(size, 8192u + 2048u + 256u));
@@ -54,21 +54,13 @@ CartridgeDPC::CartridgeDPC(const BytePtr& image, uInt32 size,
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeDPC::reset()
{
- // Update cycles to the current system cycles
- mySystemCycles = mySystem->cycles();
+ myAudioCycles = 0;
myFractionalClocks = 0.0;
// Upon reset we switch to the startup bank
bank(myStartBank);
}
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void CartridgeDPC::systemCyclesReset()
-{
- // Adjust the cycle counter so that it reflects the new value
- mySystemCycles -= mySystem->cycles();
-}
-
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeDPC::install(System& system)
{
@@ -76,8 +68,8 @@ void CartridgeDPC::install(System& system)
// Set the page accessing method for the DPC reading & writing pages
System::PageAccess access(this, System::PA_READWRITE);
- for(uInt32 j = 0x1000; j < 0x1080; j += (1 << System::PAGE_SHIFT))
- mySystem->setPageAccess(j >> System::PAGE_SHIFT, access);
+ for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE)
+ mySystem->setPageAccess(addr, access);
// Install pages for the startup bank
bank(myStartBank);
@@ -105,18 +97,16 @@ inline void CartridgeDPC::clockRandomNumberGenerator()
inline void CartridgeDPC::updateMusicModeDataFetchers()
{
// Calculate the number of cycles since the last update
- Int32 cycles = mySystem->cycles() - mySystemCycles;
- mySystemCycles = mySystem->cycles();
+ uInt32 cycles = uInt32(mySystem->cycles() - myAudioCycles);
+ myAudioCycles = mySystem->cycles();
// Calculate the number of DPC OSC clocks since the last update
double clocks = ((20000.0 * cycles) / 1193191.66666667) + myFractionalClocks;
- Int32 wholeClocks = Int32(clocks);
+ uInt32 wholeClocks = uInt32(clocks);
myFractionalClocks = clocks - double(wholeClocks);
if(wholeClocks <= 0)
- {
return;
- }
// Let's update counters and flags of the music mode data fetchers
for(int x = 5; x <= 7; ++x)
@@ -131,24 +121,16 @@ inline void CartridgeDPC::updateMusicModeDataFetchers()
{
newLow -= (wholeClocks % top);
if(newLow < 0)
- {
newLow += top;
- }
}
else
- {
newLow = 0;
- }
// Update flag register for this data fetcher
if(newLow <= myBottoms[x])
- {
myFlags[x] = 0x00;
- }
else if(newLow <= myTops[x])
- {
myFlags[x] = 0xff;
- }
myCounters[x] = (myCounters[x] & 0x0700) | uInt16(newLow);
}
@@ -163,7 +145,7 @@ uInt8 CartridgeDPC::peek(uInt16 address)
// In debugger/bank-locked mode, we ignore all hotspots and in general
// anything that can change the internal state of the cart
if(bankLocked())
- return myProgramImage[(myCurrentBank << 12) + address];
+ return myProgramImage[myBankOffset + address];
// Clock the random number generator. This should be done for every
// cartridge access, however, we're only doing it for the DPC and
@@ -279,7 +261,7 @@ uInt8 CartridgeDPC::peek(uInt16 address)
default:
break;
}
- return myProgramImage[(myCurrentBank << 12) + address];
+ return myProgramImage[myBankOffset + address];
}
}
@@ -395,26 +377,25 @@ bool CartridgeDPC::bank(uInt16 bank)
if(bankLocked()) return false;
// Remember what bank we're in
- myCurrentBank = bank;
- uInt16 offset = myCurrentBank << 12;
+ myBankOffset = bank << 12;
System::PageAccess access(this, System::PA_READ);
// Set the page accessing methods for the hot spots
- for(uInt32 i = (0x1FF8 & ~System::PAGE_MASK); i < 0x2000;
- i += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = (0x1FF8 & ~System::PAGE_MASK); addr < 0x2000;
+ addr += System::PAGE_SIZE)
{
- access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)];
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
// Setup the page access methods for the current bank
- for(uInt32 address = 0x1080; address < (0x1FF8U & ~System::PAGE_MASK);
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1080; addr < (0x1FF8U & ~System::PAGE_MASK);
+ addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myProgramImage[offset + (address & 0x0FFF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myProgramImage[myBankOffset + (addr & 0x0FFF)];
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
@@ -422,7 +403,7 @@ bool CartridgeDPC::bank(uInt16 bank)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeDPC::getBank() const
{
- return myCurrentBank;
+ return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -439,7 +420,7 @@ bool CartridgeDPC::patch(uInt16 address, uInt8 value)
// For now, we ignore attempts to patch the DPC address space
if(address >= 0x0080)
{
- myProgramImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value;
+ myProgramImage[myBankOffset + (address & 0x0FFF)] = value;
return myBankChanged = true;
}
else
@@ -447,7 +428,7 @@ bool CartridgeDPC::patch(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeDPC::getImage(int& size) const
+const uInt8* CartridgeDPC::getImage(uInt32& size) const
{
size = mySize;
return myImage;
@@ -461,7 +442,7 @@ bool CartridgeDPC::save(Serializer& out) const
out.putString(name());
// Indicates which bank is currently active
- out.putShort(myCurrentBank);
+ out.putShort(myBankOffset);
// The top registers for the data fetchers
out.putByteArray(myTops, 8);
@@ -482,8 +463,8 @@ bool CartridgeDPC::save(Serializer& out) const
// The random number generator register
out.putByte(myRandomNumber);
- out.putInt(mySystemCycles);
- out.putInt(uInt32(myFractionalClocks * 100000000.0));
+ out.putLong(myAudioCycles);
+ out.putDouble(myFractionalClocks);
}
catch(...)
{
@@ -503,7 +484,7 @@ bool CartridgeDPC::load(Serializer& in)
return false;
// Indicates which bank is currently active
- myCurrentBank = in.getShort();
+ myBankOffset = in.getShort();
// The top registers for the data fetchers
in.getByteArray(myTops, 8);
@@ -525,8 +506,8 @@ bool CartridgeDPC::load(Serializer& in)
myRandomNumber = in.getByte();
// Get system cycles and fractional clocks
- mySystemCycles = Int32(in.getInt());
- myFractionalClocks = double(in.getInt()) / 100000000.0;
+ myAudioCycles = in.getLong();
+ myFractionalClocks = in.getDouble();
}
catch(...)
{
@@ -535,7 +516,7 @@ bool CartridgeDPC::load(Serializer& in)
}
// Now, go to the current bank
- bank(myCurrentBank);
+ bank(myBankOffset >> 12);
return true;
}
diff --git a/src/emucore/CartDPC.hxx b/src/emucore/CartDPC.hxx
index 2dd892e9c..e05e5544c 100644
--- a/src/emucore/CartDPC.hxx
+++ b/src/emucore/CartDPC.hxx
@@ -58,13 +58,6 @@ class CartridgeDPC : public Cartridge
*/
void reset() override;
- /**
- Notification method invoked by the system right before the
- system resets its cycle counter to zero. It may be necessary
- to override this method for devices that remember cycle counts.
- */
- void systemCyclesReset() override;
-
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@@ -105,7 +98,7 @@ class CartridgeDPC : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -202,14 +195,14 @@ class CartridgeDPC : public Cartridge
// The random number generator register
uInt8 myRandomNumber;
- // System cycle count when the last update to music data fetchers occurred
- Int32 mySystemCycles;
+ // System cycle count from when the last update to music data fetchers occurred
+ uInt64 myAudioCycles;
// Fractional DPC music OSC clocks unused during the last update
double myFractionalClocks;
- // Indicates which bank is currently active
- uInt16 myCurrentBank;
+ // Indicates the offset into the ROM image (aligns to current bank)
+ uInt16 myBankOffset;
private:
// Following constructors and assignment operators not supported
diff --git a/src/emucore/CartDPCPlus.cxx b/src/emucore/CartDPCPlus.cxx
index 95ac21990..3e6099ac1 100644
--- a/src/emucore/CartDPCPlus.cxx
+++ b/src/emucore/CartDPCPlus.cxx
@@ -30,10 +30,10 @@ CartridgeDPCPlus::CartridgeDPCPlus(const BytePtr& image, uInt32 size,
myFastFetch(false),
myLDAimmediate(false),
myParameterPointer(0),
- mySystemCycles(0),
- myFractionalClocks(0.0),
+ myAudioCycles(0),
myARMCycles(0),
- myCurrentBank(0)
+ myFractionalClocks(0.0),
+ myBankOffset(0)
{
// Image is always 32K, but in the case of ROM > 29K, the image is
// copied to the end of the buffer
@@ -70,9 +70,7 @@ CartridgeDPCPlus::CartridgeDPCPlus(const BytePtr& image, uInt32 size,
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeDPCPlus::reset()
{
- // Update cycles to the current system cycles
- mySystemCycles = mySystem->cycles();
- myARMCycles = mySystem->cycles();
+ myAudioCycles = myARMCycles = 0;
myFractionalClocks = 0.0;
setInitialState();
@@ -110,14 +108,6 @@ void CartridgeDPCPlus::consoleChanged(ConsoleTiming timing)
#endif
}
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void CartridgeDPCPlus::systemCyclesReset()
-{
- // Adjust the cycle counter so that it reflects the new value
- mySystemCycles -= mySystem->cycles();
- myARMCycles -= mySystem->cycles();
-}
-
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeDPCPlus::install(System& system)
{
@@ -125,8 +115,8 @@ void CartridgeDPCPlus::install(System& system)
// Map all of the accesses to call peek and poke
System::PageAccess access(this, System::PA_READ);
- for(uInt32 i = 0x1000; i < 0x1080; i += (1 << System::PAGE_SHIFT))
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE)
+ mySystem->setPageAccess(addr, access);
// Install pages for the startup bank
bank(myStartBank);
@@ -153,20 +143,18 @@ inline void CartridgeDPCPlus::priorClockRandomNumberGenerator()
inline void CartridgeDPCPlus::updateMusicModeDataFetchers()
{
// Calculate the number of cycles since the last update
- Int32 cycles = mySystem->cycles() - mySystemCycles;
- mySystemCycles = mySystem->cycles();
+ uInt32 cycles = uInt32(mySystem->cycles() - myAudioCycles);
+ myAudioCycles = mySystem->cycles();
- // Calculate the number of DPC OSC clocks since the last update
+ // Calculate the number of DPC+ OSC clocks since the last update
double clocks = ((20000.0 * cycles) / 1193191.66666667) + myFractionalClocks;
- Int32 wholeClocks = Int32(clocks);
+ uInt32 wholeClocks = uInt32(clocks);
myFractionalClocks = clocks - double(wholeClocks);
- if(wholeClocks <= 0)
- return;
-
// Let's update counters and flags of the music mode data fetchers
- for(int x = 0; x <= 2; ++x)
- myMusicCounters[x] += myMusicFrequencies[x] * wholeClocks;
+ if(wholeClocks > 0)
+ for(int x = 0; x <= 2; ++x)
+ myMusicCounters[x] += myMusicFrequencies[x] * wholeClocks;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -195,7 +183,7 @@ inline void CartridgeDPCPlus::callFunction(uInt8 value)
// time for Stella as ARM code "runs in zero 6507 cycles".
case 255: // call without IRQ driven audio
try {
- Int32 cycles = mySystem->cycles() - myARMCycles;
+ Int32 cycles = Int32(mySystem->cycles() - myARMCycles);
myARMCycles = mySystem->cycles();
myThumbEmulator->run(cycles);
@@ -221,7 +209,7 @@ uInt8 CartridgeDPCPlus::peek(uInt16 address)
{
address &= 0x0FFF;
- uInt8 peekvalue = myProgramImage[(myCurrentBank << 12) + address];
+ uInt8 peekvalue = myProgramImage[myBankOffset + address];
uInt8 flag;
// In debugger/bank-locked mode, we ignore all hotspots and in general
@@ -593,18 +581,16 @@ bool CartridgeDPCPlus::bank(uInt16 bank)
if(bankLocked()) return false;
// Remember what bank we're in
- myCurrentBank = bank;
- uInt16 offset = myCurrentBank << 12;
+ myBankOffset = bank << 12;
// Setup the page access methods for the current bank
System::PageAccess access(this, System::PA_READ);
// Map Program ROM image into the system
- for(uInt32 address = 0x1080; address < 0x2000;
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1080; addr < 0x2000; addr += System::PAGE_SIZE)
{
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
@@ -612,7 +598,7 @@ bool CartridgeDPCPlus::bank(uInt16 bank)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeDPCPlus::getBank() const
{
- return myCurrentBank;
+ return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -629,7 +615,7 @@ bool CartridgeDPCPlus::patch(uInt16 address, uInt8 value)
// For now, we ignore attempts to patch the DPC address space
if(address >= 0x0080)
{
- myProgramImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value;
+ myProgramImage[myBankOffset + (address & 0x0FFF)] = value;
return myBankChanged = true;
}
else
@@ -637,7 +623,7 @@ bool CartridgeDPCPlus::patch(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeDPCPlus::getImage(int& size) const
+const uInt8* CartridgeDPCPlus::getImage(uInt32& size) const
{
size = mySize;
return myImage + (32768u - mySize);
@@ -651,7 +637,7 @@ bool CartridgeDPCPlus::save(Serializer& out) const
out.putString(name());
// Indicates which bank is currently active
- out.putShort(myCurrentBank);
+ out.putShort(myBankOffset);
// Harmony RAM
out.putByteArray(myDPCRAM, 8192);
@@ -691,11 +677,11 @@ bool CartridgeDPCPlus::save(Serializer& out) const
out.putInt(myRandomNumber);
// Get system cycles and fractional clocks
- out.putInt(mySystemCycles);
- out.putInt(uInt32(myFractionalClocks * 100000000.0));
+ out.putLong(myAudioCycles);
+ out.putDouble(myFractionalClocks);
// Clock info for Thumbulator
- out.putInt(myARMCycles);
+ out.putLong(myARMCycles);
}
catch(...)
{
@@ -715,7 +701,7 @@ bool CartridgeDPCPlus::load(Serializer& in)
return false;
// Indicates which bank is currently active
- myCurrentBank = in.getShort();
+ myBankOffset = in.getShort();
// Harmony RAM
in.getByteArray(myDPCRAM, 8192);
@@ -754,12 +740,12 @@ bool CartridgeDPCPlus::load(Serializer& in)
// The random number generator register
myRandomNumber = in.getInt();
- // Get system cycles and fractional clocks
- mySystemCycles = in.getInt();
- myFractionalClocks = double(in.getInt()) / 100000000.0;
+ // Get audio cycles and fractional clocks
+ myAudioCycles = in.getLong();
+ myFractionalClocks = in.getDouble();
// Clock info for Thumbulator
- myARMCycles = in.getInt();
+ myARMCycles = in.getLong();
}
catch(...)
{
@@ -768,7 +754,7 @@ bool CartridgeDPCPlus::load(Serializer& in)
}
// Now, go to the current bank
- bank(myCurrentBank);
+ bank(myBankOffset >> 12);
return true;
}
diff --git a/src/emucore/CartDPCPlus.hxx b/src/emucore/CartDPCPlus.hxx
index 8f5eb4883..37d7ad2fe 100644
--- a/src/emucore/CartDPCPlus.hxx
+++ b/src/emucore/CartDPCPlus.hxx
@@ -34,11 +34,14 @@ class System;
program banks, a 4K display bank, 1K frequency table and the DPC chip.
DPC chip access is mapped to $1000 - $1080 ($1000 - $103F is read port,
$1040 - $107F is write port).
+ Program banks are accessible by read/write to $1FF6 - $1FFB.
+
+ FIXME: THIS NEEDS TO BE UPDATED
For complete details on the DPC chip see David P. Crane's United States
Patent Number 4,644,495.
- @author Darrell Spice Jr, Fred Quimby, Stephen Anthony, Bradford W. Mott
+ @authors Darrell Spice Jr, Fred Quimby, Stephen Anthony, Bradford W. Mott
*/
class CartridgeDPCPlus : public Cartridge
{
@@ -71,13 +74,6 @@ class CartridgeDPCPlus : public Cartridge
*/
void consoleChanged(ConsoleTiming timing) override;
- /**
- Notification method invoked by the system right before the
- system resets its cycle counter to zero. It may be necessary
- to override this method for devices that remember cycle counts.
- */
- void systemCyclesReset() override;
-
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@@ -118,7 +114,7 @@ class CartridgeDPCPlus : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -263,17 +259,17 @@ class CartridgeDPCPlus : public Cartridge
// The random number generator register
uInt32 myRandomNumber;
- // System cycle count when the last update to music data fetchers occurred
- Int32 mySystemCycles;
+ // System cycle count from when the last update to music data fetchers occurred
+ uInt64 myAudioCycles;
+
+ // System cycle count when the last Thumbulator::run() occurred
+ uInt64 myARMCycles;
// Fractional DPC music OSC clocks unused during the last update
double myFractionalClocks;
- // System cycle count when the last Thumbulator::run() occurred
- Int32 myARMCycles;
-
- // Indicates which bank is currently active
- uInt16 myCurrentBank;
+ // Indicates the offset into the ROM image (aligns to current bank)
+ uInt16 myBankOffset;
private:
// Following constructors and assignment operators not supported
diff --git a/src/emucore/CartDetector.cxx b/src/emucore/CartDetector.cxx
index 8b09c3f97..0ff32824c 100644
--- a/src/emucore/CartDetector.cxx
+++ b/src/emucore/CartDetector.cxx
@@ -53,7 +53,6 @@
#include "CartFA.hxx"
#include "CartFA2.hxx"
#include "CartFE.hxx"
-#include "CartMC.hxx"
#include "CartMDM.hxx"
#include "CartSB.hxx"
#include "CartUA.hxx"
@@ -310,8 +309,6 @@ CartDetector::createFromImage(const BytePtr& image, uInt32 size, BSType type,
return make_unique(image, size, osystem);
case BSType::_FE:
return make_unique(image, size, osystem.settings());
- case BSType::_MC:
- return make_unique(image, size, osystem.settings());
case BSType::_MDM:
return make_unique(image, size, osystem.settings());
case BSType::_UA:
@@ -470,8 +467,6 @@ BSType CartDetector::autodetectType(const BytePtr& image, uInt32 size)
type = BSType::_4A50;
else if(isProbablySB(image, size))
type = BSType::_SB;
- else
- type = BSType::_MC;
}
else if(size == 256*1024) // 256K
{
diff --git a/src/emucore/CartE0.cxx b/src/emucore/CartE0.cxx
index 270f9ee4a..a00611aad 100644
--- a/src/emucore/CartE0.cxx
+++ b/src/emucore/CartE0.cxx
@@ -47,12 +47,12 @@ void CartridgeE0::install(System& system)
System::PageAccess access(this, System::PA_READ);
// Set the page acessing methods for the first part of the last segment
- for(uInt32 i = 0x1C00; i < (0x1FE0U & ~System::PAGE_MASK);
- i += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1C00; addr < (0x1FE0U & ~System::PAGE_MASK);
+ addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[7168 + (i & 0x03FF)];
- access.codeAccessBase = &myCodeAccessBase[7168 + (i & 0x03FF)];
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[7168 + (addr & 0x03FF)];
+ access.codeAccessBase = &myCodeAccessBase[7168 + (addr & 0x03FF)];
+ mySystem->setPageAccess(addr, access);
}
myCurrentSlice[3] = 7;
@@ -60,9 +60,9 @@ void CartridgeE0::install(System& system)
access.directPeekBase = 0;
access.codeAccessBase = &myCodeAccessBase[8128];
access.type = System::PA_READ;
- for(uInt32 j = (0x1FE0 & ~System::PAGE_MASK); j < 0x2000;
- j += (1 << System::PAGE_SHIFT))
- mySystem->setPageAccess(j >> System::PAGE_SHIFT, access);
+ for(uInt16 addr = (0x1FE0 & ~System::PAGE_MASK); addr < 0x2000;
+ addr += System::PAGE_SIZE)
+ mySystem->setPageAccess(addr, access);
// Install some default slices for the other segments
segmentZero(4);
@@ -125,12 +125,11 @@ void CartridgeE0::segmentZero(uInt16 slice)
// Setup the page access methods for the current bank
System::PageAccess access(this, System::PA_READ);
- for(uInt32 address = 0x1000; address < 0x1400;
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[offset + (address & 0x03FF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x03FF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[offset + (addr & 0x03FF)];
+ access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)];
+ mySystem->setPageAccess(addr, access);
}
myBankChanged = true;
}
@@ -147,11 +146,11 @@ void CartridgeE0::segmentOne(uInt16 slice)
// Setup the page access methods for the current bank
System::PageAccess access(this, System::PA_READ);
- for(uInt32 address = 0x1400; address < 0x1800; address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[offset + (address & 0x03FF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x03FF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[offset + (addr & 0x03FF)];
+ access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)];
+ mySystem->setPageAccess(addr, access);
}
myBankChanged = true;
}
@@ -168,12 +167,11 @@ void CartridgeE0::segmentTwo(uInt16 slice)
// Setup the page access methods for the current bank
System::PageAccess access(this, System::PA_READ);
- for(uInt32 address = 0x1800; address < 0x1C00;
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1800; addr < 0x1C00; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[offset + (address & 0x03FF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x03FF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[offset + (addr & 0x03FF)];
+ access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)];
+ mySystem->setPageAccess(addr, access);
}
myBankChanged = true;
}
@@ -187,7 +185,7 @@ bool CartridgeE0::patch(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeE0::getImage(int& size) const
+const uInt8* CartridgeE0::getImage(uInt32& size) const
{
size = 8192;
return myImage;
diff --git a/src/emucore/CartE0.hxx b/src/emucore/CartE0.hxx
index c2805c927..12063254c 100644
--- a/src/emucore/CartE0.hxx
+++ b/src/emucore/CartE0.hxx
@@ -30,9 +30,9 @@ class System;
This is the cartridge class for Parker Brothers' 8K games. In
this bankswitching scheme the 2600's 4K cartridge address space
is broken into four 1K segments. The desired 1K slice of the
- ROM is selected by accessing 1FE0 to 1FE7 for the first 1K.
- 1FE8 to 1FEF selects the slice for the second 1K, and 1FF0 to
- 1FF7 selects the slice for the third 1K. The last 1K segment
+ ROM is selected by accessing $1FE0 to $1FE7 for the first 1K.
+ $1FE8 to $1FEF selects the slice for the second 1K, and $1FF0 to
+ $1FF7 selects the slice for the third 1K. The last 1K segment
always points to the last 1K of the ROM image.
Because of the complexity of this scheme, the cart reports having
@@ -85,7 +85,7 @@ class CartridgeE0 : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
diff --git a/src/emucore/CartE7.cxx b/src/emucore/CartE7.cxx
index d031931fe..25f6778a6 100644
--- a/src/emucore/CartE7.cxx
+++ b/src/emucore/CartE7.cxx
@@ -52,20 +52,20 @@ void CartridgeE7::install(System& system)
System::PageAccess access(this, System::PA_READ);
// Set the page accessing methods for the hot spots
- for(uInt32 i = (0x1FE0 & ~System::PAGE_MASK); i < 0x2000;
- i += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = (0x1FE0 & ~System::PAGE_MASK); addr < 0x2000;
+ addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[8128];
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ mySystem->setPageAccess(addr, access);
}
// Setup the second segment to always point to the last ROM slice
- for(uInt32 j = 0x1A00; j < (0x1FE0U & ~System::PAGE_MASK);
- j += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1A00; addr < (0x1FE0U & ~System::PAGE_MASK);
+ addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[7 * 2048 + (j & 0x07FF)];
- access.codeAccessBase = &myCodeAccessBase[7 * 2048 + (j & 0x07FF)];
- mySystem->setPageAccess(j >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[7 * 2048 + (addr & 0x07FF)];
+ access.codeAccessBase = &myCodeAccessBase[7 * 2048 + (addr & 0x07FF)];
+ mySystem->setPageAccess(addr, access);
}
myCurrentSlice[1] = 7;
@@ -136,7 +136,7 @@ bool CartridgeE7::poke(uInt16 address, uInt8)
}
// NOTE: This does not handle writing to RAM, however, this
- // function should never be called for RAM because of the
+ // method should never be called for RAM because of the
// way page accessing has been setup
return false;
}
@@ -154,21 +154,21 @@ void CartridgeE7::bankRAM(uInt16 bank)
System::PageAccess access(this, System::PA_WRITE);
// Set the page accessing method for the 256 bytes of RAM writing pages
- for(uInt32 j = 0x1800; j < 0x1900; j += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1800; addr < 0x1900; addr += System::PAGE_SIZE)
{
- access.directPokeBase = &myRAM[1024 + offset + (j & 0x00FF)];
- access.codeAccessBase = &myCodeAccessBase[8192 + 1024 + offset + (j & 0x00FF)];
- mySystem->setPageAccess(j >> System::PAGE_SHIFT, access);
+ access.directPokeBase = &myRAM[1024 + offset + (addr & 0x00FF)];
+ access.codeAccessBase = &myCodeAccessBase[8192 + 1024 + offset + (addr & 0x00FF)];
+ mySystem->setPageAccess(addr, access);
}
// Set the page accessing method for the 256 bytes of RAM reading pages
access.directPokeBase = 0;
access.type = System::PA_READ;
- for(uInt32 k = 0x1900; k < 0x1A00; k += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1900; addr < 0x1A00; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myRAM[1024 + offset + (k & 0x00FF)];
- access.codeAccessBase = &myCodeAccessBase[8192 + 1024 + offset + (k & 0x00FF)];
- mySystem->setPageAccess(k >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myRAM[1024 + offset + (addr & 0x00FF)];
+ access.codeAccessBase = &myCodeAccessBase[8192 + 1024 + offset + (addr & 0x00FF)];
+ mySystem->setPageAccess(addr, access);
}
myBankChanged = true;
}
@@ -188,12 +188,11 @@ bool CartridgeE7::bank(uInt16 slice)
System::PageAccess access(this, System::PA_READ);
// Map ROM image into first segment
- for(uInt32 address = 0x1000; address < 0x1800;
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < 0x1800; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[offset + (address & 0x07FF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x07FF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[offset + (addr & 0x07FF)];
+ access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x07FF)];
+ mySystem->setPageAccess(addr, access);
}
}
else
@@ -201,21 +200,21 @@ bool CartridgeE7::bank(uInt16 slice)
System::PageAccess access(this, System::PA_WRITE);
// Set the page accessing method for the 1K slice of RAM writing pages
- for(uInt32 j = 0x1000; j < 0x1400; j += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE)
{
- access.directPokeBase = &myRAM[j & 0x03FF];
- access.codeAccessBase = &myCodeAccessBase[8192 + (j & 0x03FF)];
- mySystem->setPageAccess(j >> System::PAGE_SHIFT, access);
+ access.directPokeBase = &myRAM[addr & 0x03FF];
+ access.codeAccessBase = &myCodeAccessBase[8192 + (addr & 0x03FF)];
+ mySystem->setPageAccess(addr, access);
}
// Set the page accessing method for the 1K slice of RAM reading pages
access.directPokeBase = 0;
access.type = System::PA_READ;
- for(uInt32 k = 0x1400; k < 0x1800; k += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myRAM[k & 0x03FF];
- access.codeAccessBase = &myCodeAccessBase[8192 + (k & 0x03FF)];
- mySystem->setPageAccess(k >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myRAM[addr & 0x03FF];
+ access.codeAccessBase = &myCodeAccessBase[8192 + (addr & 0x03FF)];
+ mySystem->setPageAccess(addr, access);
}
}
return myBankChanged = true;
@@ -264,7 +263,7 @@ bool CartridgeE7::patch(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeE7::getImage(int& size) const
+const uInt8* CartridgeE7::getImage(uInt32& size) const
{
size = 16384;
return myImage;
diff --git a/src/emucore/CartE7.hxx b/src/emucore/CartE7.hxx
index c27332f1f..86ec30a42 100644
--- a/src/emucore/CartE7.hxx
+++ b/src/emucore/CartE7.hxx
@@ -119,7 +119,7 @@ class CartridgeE7 : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
diff --git a/src/emucore/CartEF.cxx b/src/emucore/CartEF.cxx
index 3982ceb09..3de99dab1 100644
--- a/src/emucore/CartEF.cxx
+++ b/src/emucore/CartEF.cxx
@@ -22,7 +22,7 @@
CartridgeEF::CartridgeEF(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings),
- myCurrentBank(0)
+ myBankOffset(0)
{
// Copy the ROM image into my buffer
memcpy(myImage, image.get(), std::min(65536u, size));
@@ -57,7 +57,7 @@ uInt8 CartridgeEF::peek(uInt16 address)
if((address >= 0x0FE0) && (address <= 0x0FEF))
bank(address - 0x0FE0);
- return myImage[(myCurrentBank << 12) + address];
+ return myImage[myBankOffset + address];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -78,26 +78,25 @@ bool CartridgeEF::bank(uInt16 bank)
if(bankLocked()) return false;
// Remember what bank we're in
- myCurrentBank = bank;
- uInt16 offset = myCurrentBank << 12;
+ myBankOffset = bank << 12;
System::PageAccess access(this, System::PA_READ);
// Set the page accessing methods for the hot spots
- for(uInt32 i = (0x1FE0 & ~System::PAGE_MASK); i < 0x2000;
- i += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = (0x1FE0 & ~System::PAGE_MASK); addr < 0x2000;
+ addr += System::PAGE_SIZE)
{
- access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)];
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
// Setup the page access methods for the current bank
- for(uInt32 address = 0x1000; address < (0x1FE0U & ~System::PAGE_MASK);
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < (0x1FE0U & ~System::PAGE_MASK);
+ addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
@@ -105,7 +104,7 @@ bool CartridgeEF::bank(uInt16 bank)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeEF::getBank() const
{
- return myCurrentBank;
+ return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -117,12 +116,12 @@ uInt16 CartridgeEF::bankCount() const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeEF::patch(uInt16 address, uInt8 value)
{
- myImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value;
+ myImage[myBankOffset + (address & 0x0FFF)] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeEF::getImage(int& size) const
+const uInt8* CartridgeEF::getImage(uInt32& size) const
{
size = 65536;
return myImage;
@@ -134,7 +133,7 @@ bool CartridgeEF::save(Serializer& out) const
try
{
out.putString(name());
- out.putShort(myCurrentBank);
+ out.putShort(myBankOffset);
}
catch(...)
{
@@ -153,7 +152,7 @@ bool CartridgeEF::load(Serializer& in)
if(in.getString() != name())
return false;
- myCurrentBank = in.getShort();
+ myBankOffset = in.getShort();
}
catch(...)
{
@@ -162,7 +161,7 @@ bool CartridgeEF::load(Serializer& in)
}
// Remember what bank we were in
- bank(myCurrentBank);
+ bank(myBankOffset >> 12);
return true;
}
diff --git a/src/emucore/CartEF.hxx b/src/emucore/CartEF.hxx
index 21f4955ca..624b1b938 100644
--- a/src/emucore/CartEF.hxx
+++ b/src/emucore/CartEF.hxx
@@ -31,9 +31,6 @@ class System;
There are 16 4K banks (total of 64K ROM).
Accessing $1FE0 - $1FEF switches to each bank.
- This interpretation is based on analysis of the z26 assembly code,
- as this scheme doesn't seem to be documented anywhere.
-
@author Stephen Anthony
*/
class CartridgeEF : public Cartridge
@@ -97,7 +94,7 @@ class CartridgeEF : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -155,8 +152,8 @@ class CartridgeEF : public Cartridge
// The 64K ROM image of the cartridge
uInt8 myImage[65536];
- // Indicates which bank is currently active
- uInt16 myCurrentBank;
+ // Indicates the offset into the ROM image (aligns to current bank)
+ uInt16 myBankOffset;
private:
// Following constructors and assignment operators not supported
diff --git a/src/emucore/CartEFSC.cxx b/src/emucore/CartEFSC.cxx
index 15835d120..14e5dd113 100644
--- a/src/emucore/CartEFSC.cxx
+++ b/src/emucore/CartEFSC.cxx
@@ -22,7 +22,7 @@
CartridgeEFSC::CartridgeEFSC(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings),
- myCurrentBank(0)
+ myBankOffset(0)
{
// Copy the ROM image into my buffer
memcpy(myImage, image.get(), std::min(65536u, size));
@@ -50,21 +50,21 @@ void CartridgeEFSC::install(System& system)
// Set the page accessing method for the RAM writing pages
access.type = System::PA_WRITE;
- for(uInt32 j = 0x1000; j < 0x1080; j += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE)
{
- access.directPokeBase = &myRAM[j & 0x007F];
- access.codeAccessBase = &myCodeAccessBase[j & 0x007F];
- mySystem->setPageAccess(j >> System::PAGE_SHIFT, access);
+ access.directPokeBase = &myRAM[addr & 0x007F];
+ access.codeAccessBase = &myCodeAccessBase[addr & 0x007F];
+ mySystem->setPageAccess(addr, access);
}
// Set the page accessing method for the RAM reading pages
access.directPokeBase = 0;
access.type = System::PA_READ;
- for(uInt32 k = 0x1080; k < 0x1100; k += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myRAM[k & 0x007F];
- access.codeAccessBase = &myCodeAccessBase[0x80 + (k & 0x007F)];
- mySystem->setPageAccess(k >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myRAM[addr & 0x007F];
+ access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)];
+ mySystem->setPageAccess(addr, access);
}
// Install pages for the startup bank
@@ -95,7 +95,7 @@ uInt8 CartridgeEFSC::peek(uInt16 address)
}
}
else
- return myImage[(myCurrentBank << 12) + address];
+ return myImage[myBankOffset + address];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -119,26 +119,25 @@ bool CartridgeEFSC::bank(uInt16 bank)
if(bankLocked()) return false;
// Remember what bank we're in
- myCurrentBank = bank;
- uInt16 offset = myCurrentBank << 12;
+ myBankOffset = bank << 12;
System::PageAccess access(this, System::PA_READ);
// Set the page accessing methods for the hot spots
- for(uInt32 i = (0x1FE0 & ~System::PAGE_MASK); i < 0x2000;
- i += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = (0x1FE0 & ~System::PAGE_MASK); addr < 0x2000;
+ addr += System::PAGE_SIZE)
{
- access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)];
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
// Setup the page access methods for the current bank
- for(uInt32 address = 0x1100; address < (0x1FE0U & ~System::PAGE_MASK);
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1100; addr < (0x1FE0U & ~System::PAGE_MASK);
+ addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
@@ -146,7 +145,7 @@ bool CartridgeEFSC::bank(uInt16 bank)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeEFSC::getBank() const
{
- return myCurrentBank;
+ return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -168,13 +167,13 @@ bool CartridgeEFSC::patch(uInt16 address, uInt8 value)
myRAM[address & 0x007F] = value;
}
else
- myImage[(myCurrentBank << 12) + address] = value;
+ myImage[myBankOffset + address] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeEFSC::getImage(int& size) const
+const uInt8* CartridgeEFSC::getImage(uInt32& size) const
{
size = 65536;
return myImage;
@@ -186,7 +185,7 @@ bool CartridgeEFSC::save(Serializer& out) const
try
{
out.putString(name());
- out.putShort(myCurrentBank);
+ out.putShort(myBankOffset);
out.putByteArray(myRAM, 128);
}
catch(...)
@@ -206,7 +205,7 @@ bool CartridgeEFSC::load(Serializer& in)
if(in.getString() != name())
return false;
- myCurrentBank = in.getShort();
+ myBankOffset = in.getShort();
in.getByteArray(myRAM, 128);
}
catch(...)
@@ -216,7 +215,7 @@ bool CartridgeEFSC::load(Serializer& in)
}
// Remember what bank we were in
- bank(myCurrentBank);
+ bank(myBankOffset >> 12);
return true;
}
diff --git a/src/emucore/CartEFSC.hxx b/src/emucore/CartEFSC.hxx
index 0faf709d3..30e328b9e 100644
--- a/src/emucore/CartEFSC.hxx
+++ b/src/emucore/CartEFSC.hxx
@@ -30,9 +30,7 @@ class System;
Cartridge class used for Homestar Runner by Paul Slocum.
There are 16 4K banks (total of 64K ROM) with 128 bytes of RAM.
Accessing $1FE0 - $1FEF switches to each bank.
-
- This interpretation is based on analysis of the z26 assembly code,
- as this scheme doesn't seem to be documented anywhere.
+ RAM read port is $1080 - $10FF, write port is $1000 - $107F.
@author Stephen Anthony
*/
@@ -97,7 +95,7 @@ class CartridgeEFSC : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -158,8 +156,8 @@ class CartridgeEFSC : public Cartridge
// The 128 bytes of RAM
uInt8 myRAM[128];
- // Indicates which bank is currently active
- uInt16 myCurrentBank;
+ // Indicates the offset into the ROM image (aligns to current bank)
+ uInt16 myBankOffset;
private:
// Following constructors and assignment operators not supported
diff --git a/src/emucore/CartF0.cxx b/src/emucore/CartF0.cxx
index 90a114360..e312e77f6 100644
--- a/src/emucore/CartF0.cxx
+++ b/src/emucore/CartF0.cxx
@@ -22,7 +22,7 @@
CartridgeF0::CartridgeF0(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings),
- myCurrentBank(0)
+ myBankOffset(0)
{
// Copy the ROM image into my buffer
memcpy(myImage, image.get(), std::min(65536u, size));
@@ -35,9 +35,8 @@ CartridgeF0::CartridgeF0(const BytePtr& image, uInt32 size,
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF0::reset()
{
- // Upon reset we switch to bank 15
- myCurrentBank = 14;
- incbank();
+ // Upon reset we switch to the startup bank
+ bank(myStartBank);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -45,9 +44,8 @@ void CartridgeF0::install(System& system)
{
mySystem = &system;
- // Install pages for bank 1
- myCurrentBank = 0;
- incbank();
+ // Install pages for the startup bank
+ bank(myStartBank);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -59,7 +57,7 @@ uInt8 CartridgeF0::peek(uInt16 address)
if(address == 0x0FF0)
incbank();
- return myImage[(myCurrentBank << 12) + address];
+ return myImage[myBankOffset + address];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -77,32 +75,9 @@ bool CartridgeF0::poke(uInt16 address, uInt8)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF0::incbank()
{
- if(bankLocked()) return;
-
- // Remember what bank we're in
- myCurrentBank++;
- myCurrentBank &= 0x0F;
- uInt16 offset = myCurrentBank << 12;
-
- System::PageAccess access(this, System::PA_READ);
-
- // Set the page accessing methods for the hot spots
- for(uInt32 i = (0x1FF0 & ~System::PAGE_MASK); i < 0x2000;
- i += (1 << System::PAGE_SHIFT))
- {
- access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)];
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
- }
-
- // Setup the page access methods for the current bank
- for(uInt32 address = 0x1000; address < (0x1FF0U & ~System::PAGE_MASK);
- address += (1 << System::PAGE_SHIFT))
- {
- access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
- }
- myBankChanged = true;
+ // Determine current bank, and increment to the next one
+ uInt8 nextBank = ((myBankOffset >> 12) + 1) & 0x0F;
+ bank(nextBank);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -110,8 +85,27 @@ bool CartridgeF0::bank(uInt16 bank)
{
if(bankLocked()) return false;
- myCurrentBank = bank - 1;
- incbank();
+ // Remember what bank we're in
+ myBankOffset = bank << 12;
+
+ System::PageAccess access(this, System::PA_READ);
+
+ // Set the page accessing methods for the hot spots
+ for(uInt16 addr = (0x1FF0 & ~System::PAGE_MASK); addr < 0x2000;
+ addr += System::PAGE_SIZE)
+ {
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
+ }
+
+ // Setup the page access methods for the current bank
+ for(uInt16 addr = 0x1000; addr < (0x1FF0U & ~System::PAGE_MASK);
+ addr += System::PAGE_SIZE)
+ {
+ access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
+ }
return myBankChanged = true;
}
@@ -119,7 +113,7 @@ bool CartridgeF0::bank(uInt16 bank)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeF0::getBank() const
{
- return myCurrentBank;
+ return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -131,12 +125,12 @@ uInt16 CartridgeF0::bankCount() const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeF0::patch(uInt16 address, uInt8 value)
{
- myImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value;
+ myImage[myBankOffset + (address & 0x0FFF)] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeF0::getImage(int& size) const
+const uInt8* CartridgeF0::getImage(uInt32& size) const
{
size = 65536;
return myImage;
@@ -148,7 +142,7 @@ bool CartridgeF0::save(Serializer& out) const
try
{
out.putString(name());
- out.putShort(myCurrentBank);
+ out.putShort(myBankOffset);
}
catch(...)
{
@@ -167,7 +161,7 @@ bool CartridgeF0::load(Serializer& in)
if(in.getString() != name())
return false;
- myCurrentBank = in.getShort();
+ myBankOffset = in.getShort();
}
catch(...)
{
@@ -176,8 +170,7 @@ bool CartridgeF0::load(Serializer& in)
}
// Remember what bank we were in
- --myCurrentBank;
- incbank();
+ bank(myBankOffset >> 12);
return true;
}
diff --git a/src/emucore/CartF0.hxx b/src/emucore/CartF0.hxx
index 26f6acf70..aa81d68f3 100644
--- a/src/emucore/CartF0.hxx
+++ b/src/emucore/CartF0.hxx
@@ -94,7 +94,7 @@ class CartridgeF0 : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -158,8 +158,8 @@ class CartridgeF0 : public Cartridge
// The 64K ROM image of the cartridge
uInt8 myImage[65536];
- // Indicates which bank is currently active
- uInt16 myCurrentBank;
+ // Indicates the offset into the ROM image (aligns to current bank)
+ uInt16 myBankOffset;
private:
// Following constructors and assignment operators not supported
diff --git a/src/emucore/CartF4.cxx b/src/emucore/CartF4.cxx
index 6c57e1986..6deb0a829 100644
--- a/src/emucore/CartF4.cxx
+++ b/src/emucore/CartF4.cxx
@@ -23,7 +23,7 @@
CartridgeF4::CartridgeF4(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings),
- myCurrentBank(0)
+ myBankOffset(0)
{
// Copy the ROM image into my buffer
memcpy(myImage, image.get(), std::min(32768u, size));
@@ -60,7 +60,7 @@ uInt8 CartridgeF4::peek(uInt16 address)
bank(address - 0x0FF4);
}
- return myImage[(myCurrentBank << 12) + address];
+ return myImage[myBankOffset + address];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -83,26 +83,25 @@ bool CartridgeF4::bank(uInt16 bank)
if(bankLocked()) return false;
// Remember what bank we're in
- myCurrentBank = bank;
- uInt16 offset = myCurrentBank << 12;
+ myBankOffset = bank << 12;
System::PageAccess access(this, System::PA_READ);
// Set the page accessing methods for the hot spots
- for(uInt32 i = (0x1FF4 & ~System::PAGE_MASK); i < 0x2000;
- i += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = (0x1FF4 & ~System::PAGE_MASK); addr < 0x2000;
+ addr += System::PAGE_SIZE)
{
- access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)];
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
// Setup the page access methods for the current bank
- for(uInt32 address = 0x1000; address < (0x1FF4U & ~System::PAGE_MASK);
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < (0x1FF4U & ~System::PAGE_MASK);
+ addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
@@ -110,7 +109,7 @@ bool CartridgeF4::bank(uInt16 bank)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeF4::getBank() const
{
- return myCurrentBank;
+ return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -122,12 +121,12 @@ uInt16 CartridgeF4::bankCount() const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeF4::patch(uInt16 address, uInt8 value)
{
- myImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value;
+ myImage[myBankOffset + (address & 0x0FFF)] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeF4::getImage(int& size) const
+const uInt8* CartridgeF4::getImage(uInt32& size) const
{
size = 32768;
return myImage;
@@ -139,7 +138,7 @@ bool CartridgeF4::save(Serializer& out) const
try
{
out.putString(name());
- out.putShort(myCurrentBank);
+ out.putShort(myBankOffset);
}
catch(...)
{
@@ -158,7 +157,7 @@ bool CartridgeF4::load(Serializer& in)
if(in.getString() != name())
return false;
- myCurrentBank = in.getShort();
+ myBankOffset = in.getShort();
}
catch(...)
{
@@ -167,7 +166,7 @@ bool CartridgeF4::load(Serializer& in)
}
// Remember what bank we were in
- bank(myCurrentBank);
+ bank(myBankOffset >> 12);
return true;
}
diff --git a/src/emucore/CartF4.hxx b/src/emucore/CartF4.hxx
index 6262e0686..8372a0206 100644
--- a/src/emucore/CartF4.hxx
+++ b/src/emucore/CartF4.hxx
@@ -27,8 +27,8 @@ class System;
#endif
/**
- Cartridge class used for Atari's 32K bankswitched games. There
- are eight 4K banks.
+ Cartridge class used for Atari's 32K bankswitched games. There are eight
+ 4K banks, accessible by read/write to $1FF4 - $1FFB.
@author Bradford W. Mott
*/
@@ -93,7 +93,7 @@ class CartridgeF4 : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -151,8 +151,8 @@ class CartridgeF4 : public Cartridge
// The 32K ROM image of the cartridge
uInt8 myImage[32768];
- // Indicates which bank is currently active
- uInt16 myCurrentBank;
+ // Indicates the offset into the ROM image (aligns to current bank)
+ uInt16 myBankOffset;
private:
// Following constructors and assignment operators not supported
diff --git a/src/emucore/CartF4SC.cxx b/src/emucore/CartF4SC.cxx
index 616feac72..8e32f3fa6 100644
--- a/src/emucore/CartF4SC.cxx
+++ b/src/emucore/CartF4SC.cxx
@@ -22,7 +22,7 @@
CartridgeF4SC::CartridgeF4SC(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings),
- myCurrentBank(0)
+ myBankOffset(0)
{
// Copy the ROM image into my buffer
memcpy(myImage, image.get(), std::min(32768u, size));
@@ -50,21 +50,21 @@ void CartridgeF4SC::install(System& system)
// Set the page accessing method for the RAM writing pages
access.type = System::PA_WRITE;
- for(uInt32 j = 0x1000; j < 0x1080; j += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE)
{
- access.directPokeBase = &myRAM[j & 0x007F];
- access.codeAccessBase = &myCodeAccessBase[j & 0x007F];
- mySystem->setPageAccess(j >> System::PAGE_SHIFT, access);
+ access.directPokeBase = &myRAM[addr & 0x007F];
+ access.codeAccessBase = &myCodeAccessBase[addr & 0x007F];
+ mySystem->setPageAccess(addr, access);
}
// Set the page accessing method for the RAM reading pages
access.directPokeBase = 0;
access.type = System::PA_READ;
- for(uInt32 k = 0x1080; k < 0x1100; k += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myRAM[k & 0x007F];
- access.codeAccessBase = &myCodeAccessBase[0x80 + (k & 0x007F)];
- mySystem->setPageAccess(k >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myRAM[addr & 0x007F];
+ access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)];
+ mySystem->setPageAccess(addr, access);
}
// Install pages for the startup bank
@@ -98,7 +98,7 @@ uInt8 CartridgeF4SC::peek(uInt16 address)
// NOTE: This does not handle accessing RAM, however, this function
// should never be called for RAM because of the way page accessing
// has been setup
- return myImage[(myCurrentBank << 12) + address];
+ return myImage[myBankOffset + address];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -122,26 +122,25 @@ bool CartridgeF4SC::bank(uInt16 bank)
if(bankLocked()) return false;
// Remember what bank we're in
- myCurrentBank = bank;
- uInt16 offset = myCurrentBank << 12;
+ myBankOffset = bank << 12;
System::PageAccess access(this, System::PA_READ);
// Set the page accessing methods for the hot spots
- for(uInt32 i = (0x1FF4 & ~System::PAGE_MASK); i < 0x2000;
- i += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = (0x1FF4 & ~System::PAGE_MASK); addr < 0x2000;
+ addr += System::PAGE_SIZE)
{
- access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)];
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
// Setup the page access methods for the current bank
- for(uInt32 address = 0x1100; address < (0x1FF4U & ~System::PAGE_MASK);
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1100; addr < (0x1FF4U & ~System::PAGE_MASK);
+ addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
@@ -149,7 +148,7 @@ bool CartridgeF4SC::bank(uInt16 bank)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeF4SC::getBank() const
{
- return myCurrentBank;
+ return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -171,13 +170,13 @@ bool CartridgeF4SC::patch(uInt16 address, uInt8 value)
myRAM[address & 0x007F] = value;
}
else
- myImage[(myCurrentBank << 12) + address] = value;
+ myImage[myBankOffset + address] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeF4SC::getImage(int& size) const
+const uInt8* CartridgeF4SC::getImage(uInt32& size) const
{
size = 32768;
return myImage;
@@ -189,7 +188,7 @@ bool CartridgeF4SC::save(Serializer& out) const
try
{
out.putString(name());
- out.putShort(myCurrentBank);
+ out.putShort(myBankOffset);
out.putByteArray(myRAM, 128);
}
catch(...)
@@ -209,7 +208,7 @@ bool CartridgeF4SC::load(Serializer& in)
if(in.getString() != name())
return false;
- myCurrentBank = in.getShort();
+ myBankOffset = in.getShort();
in.getByteArray(myRAM, 128);
}
catch(...)
@@ -219,7 +218,7 @@ bool CartridgeF4SC::load(Serializer& in)
}
// Remember what bank we were in
- bank(myCurrentBank);
+ bank(myBankOffset >> 12);
return true;
}
diff --git a/src/emucore/CartF4SC.hxx b/src/emucore/CartF4SC.hxx
index c13f6f540..d26ecb49c 100644
--- a/src/emucore/CartF4SC.hxx
+++ b/src/emucore/CartF4SC.hxx
@@ -27,8 +27,9 @@ class System;
#endif
/**
- Cartridge class used for Atari's 32K bankswitched games with
- 128 bytes of RAM. There are eight 4K banks.
+ Cartridge class used for Atari's 32K bankswitched games with 128 bytes of
+ RAM. There are eight 4K banks, accessible by read/write to $1FF4 - $1FFB.
+ RAM read port is $1080 - $10FF, write port is $1000 - $107F.
@author Bradford W. Mott
*/
@@ -93,7 +94,7 @@ class CartridgeF4SC : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -154,8 +155,8 @@ class CartridgeF4SC : public Cartridge
// The 128 bytes of RAM
uInt8 myRAM[128];
- // Indicates which bank is currently active
- uInt16 myCurrentBank;
+ // Indicates the offset into the ROM image (aligns to current bank)
+ uInt16 myBankOffset;
private:
// Following constructors and assignment operators not supported
diff --git a/src/emucore/CartF6.cxx b/src/emucore/CartF6.cxx
index 4d3f52453..b8d6deba4 100644
--- a/src/emucore/CartF6.cxx
+++ b/src/emucore/CartF6.cxx
@@ -22,7 +22,7 @@
CartridgeF6::CartridgeF6(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings),
- myCurrentBank(0)
+ myBankOffset(0)
{
// Copy the ROM image into my buffer
memcpy(myImage, image.get(), std::min(16384u, size));
@@ -80,7 +80,7 @@ uInt8 CartridgeF6::peek(uInt16 address)
break;
}
- return myImage[(myCurrentBank << 12) + address];
+ return myImage[myBankOffset + address];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -123,26 +123,25 @@ bool CartridgeF6::bank(uInt16 bank)
if(bankLocked()) return false;
// Remember what bank we're in
- myCurrentBank = bank;
- uInt16 offset = myCurrentBank << 12;
+ myBankOffset = bank << 12;
System::PageAccess access(this, System::PA_READ);
// Set the page accessing methods for the hot spots
- for(uInt32 i = (0x1FF6 & ~System::PAGE_MASK); i < 0x2000;
- i += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = (0x1FF6 & ~System::PAGE_MASK); addr < 0x2000;
+ addr += System::PAGE_SIZE)
{
- access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)];
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
// Setup the page access methods for the current bank
- for(uInt32 address = 0x1000; address < (0x1FF6U & ~System::PAGE_MASK);
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < (0x1FF6U & ~System::PAGE_MASK);
+ addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
@@ -150,7 +149,7 @@ bool CartridgeF6::bank(uInt16 bank)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeF6::getBank() const
{
- return myCurrentBank;
+ return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -162,12 +161,12 @@ uInt16 CartridgeF6::bankCount() const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeF6::patch(uInt16 address, uInt8 value)
{
- myImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value;
+ myImage[myBankOffset + (address & 0x0FFF)] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeF6::getImage(int& size) const
+const uInt8* CartridgeF6::getImage(uInt32& size) const
{
size = 16384;
return myImage;
@@ -179,7 +178,7 @@ bool CartridgeF6::save(Serializer& out) const
try
{
out.putString(name());
- out.putShort(myCurrentBank);
+ out.putShort(myBankOffset);
}
catch(...)
{
@@ -198,7 +197,7 @@ bool CartridgeF6::load(Serializer& in)
if(in.getString() != name())
return false;
- myCurrentBank = in.getShort();
+ myBankOffset = in.getShort();
}
catch(...)
{
@@ -207,7 +206,7 @@ bool CartridgeF6::load(Serializer& in)
}
// Remember what bank we were in
- bank(myCurrentBank);
+ bank(myBankOffset >> 12);
return true;
}
diff --git a/src/emucore/CartF6.hxx b/src/emucore/CartF6.hxx
index 1f7212697..15d9d1085 100644
--- a/src/emucore/CartF6.hxx
+++ b/src/emucore/CartF6.hxx
@@ -27,8 +27,8 @@ class System;
#endif
/**
- Cartridge class used for Atari's 16K bankswitched games. There
- are four 4K banks.
+ Cartridge class used for Atari's 16K bankswitched games. There are four
+ 4K banks, accessible by read/write to $1FF6 - $1FF9.
@author Bradford W. Mott
*/
@@ -93,7 +93,7 @@ class CartridgeF6 : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -151,8 +151,8 @@ class CartridgeF6 : public Cartridge
// The 16K ROM image of the cartridge
uInt8 myImage[16384];
- // Indicates which bank is currently active
- uInt16 myCurrentBank;
+ // Indicates the offset into the ROM image (aligns to current bank)
+ uInt16 myBankOffset;
private:
// Following constructors and assignment operators not supported
diff --git a/src/emucore/CartF6SC.cxx b/src/emucore/CartF6SC.cxx
index 90e49bffd..cbe4139b8 100644
--- a/src/emucore/CartF6SC.cxx
+++ b/src/emucore/CartF6SC.cxx
@@ -22,7 +22,7 @@
CartridgeF6SC::CartridgeF6SC(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings),
- myCurrentBank(0)
+ myBankOffset(0)
{
// Copy the ROM image into my buffer
memcpy(myImage, image.get(), std::min(16384u, size));
@@ -50,21 +50,21 @@ void CartridgeF6SC::install(System& system)
// Set the page accessing method for the RAM writing pages
access.type = System::PA_WRITE;
- for(uInt32 j = 0x1000; j < 0x1080; j += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE)
{
- access.directPokeBase = &myRAM[j & 0x007F];
- access.codeAccessBase = &myCodeAccessBase[j & 0x007F];
- mySystem->setPageAccess(j >> System::PAGE_SHIFT, access);
+ access.directPokeBase = &myRAM[addr & 0x007F];
+ access.codeAccessBase = &myCodeAccessBase[addr & 0x007F];
+ mySystem->setPageAccess(addr, access);
}
// Set the page accessing method for the RAM reading pages
access.directPokeBase = 0;
access.type = System::PA_READ;
- for(uInt32 k = 0x1080; k < 0x1100; k += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myRAM[k & 0x007F];
- access.codeAccessBase = &myCodeAccessBase[0x80 + (k & 0x007F)];
- mySystem->setPageAccess(k >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myRAM[addr & 0x007F];
+ access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)];
+ mySystem->setPageAccess(addr, access);
}
// Install pages for the startup bank
@@ -118,7 +118,7 @@ uInt8 CartridgeF6SC::peek(uInt16 address)
}
}
else
- return myImage[(myCurrentBank << 12) + address];
+ return myImage[myBankOffset + address];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -165,26 +165,25 @@ bool CartridgeF6SC::bank(uInt16 bank)
if(bankLocked()) return false;
// Remember what bank we're in
- myCurrentBank = bank;
- uInt16 offset = myCurrentBank << 12;
+ myBankOffset = bank << 12;
System::PageAccess access(this, System::PA_READ);
// Set the page accessing methods for the hot spots
- for(uInt32 i = (0x1FF6 & ~System::PAGE_MASK); i < 0x2000;
- i += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = (0x1FF6 & ~System::PAGE_MASK); addr < 0x2000;
+ addr += System::PAGE_SIZE)
{
- access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)];
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
// Setup the page access methods for the current bank
- for(uInt32 address = 0x1100; address < (0x1FF6U & ~System::PAGE_MASK);
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1100; addr < (0x1FF6U & ~System::PAGE_MASK);
+ addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
@@ -192,7 +191,7 @@ bool CartridgeF6SC::bank(uInt16 bank)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeF6SC::getBank() const
{
- return myCurrentBank;
+ return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -214,13 +213,13 @@ bool CartridgeF6SC::patch(uInt16 address, uInt8 value)
myRAM[address & 0x007F] = value;
}
else
- myImage[(myCurrentBank << 12) + address] = value;
+ myImage[myBankOffset + address] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeF6SC::getImage(int& size) const
+const uInt8* CartridgeF6SC::getImage(uInt32& size) const
{
size = 16384;
return myImage;
@@ -232,7 +231,7 @@ bool CartridgeF6SC::save(Serializer& out) const
try
{
out.putString(name());
- out.putShort(myCurrentBank);
+ out.putShort(myBankOffset);
out.putByteArray(myRAM, 128);
}
catch(...)
@@ -252,7 +251,7 @@ bool CartridgeF6SC::load(Serializer& in)
if(in.getString() != name())
return false;
- myCurrentBank = in.getShort();
+ myBankOffset = in.getShort();
in.getByteArray(myRAM, 128);
}
catch(...)
@@ -262,7 +261,7 @@ bool CartridgeF6SC::load(Serializer& in)
}
// Remember what bank we were in
- bank(myCurrentBank);
+ bank(myBankOffset >> 12);
return true;
}
diff --git a/src/emucore/CartF6SC.hxx b/src/emucore/CartF6SC.hxx
index ab8bf1535..401d0ac79 100644
--- a/src/emucore/CartF6SC.hxx
+++ b/src/emucore/CartF6SC.hxx
@@ -27,8 +27,9 @@ class System;
#endif
/**
- Cartridge class used for Atari's 16K bankswitched games with
- 128 bytes of RAM. There are four 4K banks.
+ Cartridge class used for Atari's 16K bankswitched games with 128 bytes of
+ RAM. There are four 4K banks, accessible by read/write to $1FF6 - $1FF9.
+ RAM read port is $1080 - $10FF, write port is $1000 - $107F.
@author Bradford W. Mott
*/
@@ -93,7 +94,7 @@ class CartridgeF6SC : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -154,8 +155,8 @@ class CartridgeF6SC : public Cartridge
// The 128 bytes of RAM
uInt8 myRAM[128];
- // Indicates which bank is currently active
- uInt16 myCurrentBank;
+ // Indicates the offset into the ROM image (aligns to current bank)
+ uInt16 myBankOffset;
private:
// Following constructors and assignment operators not supported
diff --git a/src/emucore/CartF8.cxx b/src/emucore/CartF8.cxx
index 9c763bc85..aaa163379 100644
--- a/src/emucore/CartF8.cxx
+++ b/src/emucore/CartF8.cxx
@@ -22,7 +22,7 @@
CartridgeF8::CartridgeF8(const BytePtr& image, uInt32 size, const string& md5,
const Settings& settings)
: Cartridge(settings),
- myCurrentBank(0)
+ myBankOffset(0)
{
// Copy the ROM image into my buffer
memcpy(myImage, image.get(), std::min(8192u, size));
@@ -78,7 +78,7 @@ uInt8 CartridgeF8::peek(uInt16 address)
break;
}
- return myImage[(myCurrentBank << 12) + address];
+ return myImage[myBankOffset + address];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -111,26 +111,25 @@ bool CartridgeF8::bank(uInt16 bank)
if(bankLocked()) return false;
// Remember what bank we're in
- myCurrentBank = bank;
- uInt16 offset = myCurrentBank << 12;
+ myBankOffset = bank << 12;
System::PageAccess access(this, System::PA_READ);
// Set the page accessing methods for the hot spots
- for(uInt32 i = (0x1FF8 & ~System::PAGE_MASK); i < 0x2000;
- i += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = (0x1FF8 & ~System::PAGE_MASK); addr < 0x2000;
+ addr += System::PAGE_SIZE)
{
- access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)];
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
// Setup the page access methods for the current bank
- for(uInt32 address = 0x1000; address < (0x1FF8U & ~System::PAGE_MASK);
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < (0x1FF8U & ~System::PAGE_MASK);
+ addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
@@ -138,7 +137,7 @@ bool CartridgeF8::bank(uInt16 bank)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeF8::getBank() const
{
- return myCurrentBank;
+ return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -150,12 +149,12 @@ uInt16 CartridgeF8::bankCount() const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeF8::patch(uInt16 address, uInt8 value)
{
- myImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value;
+ myImage[myBankOffset + (address & 0x0FFF)] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeF8::getImage(int& size) const
+const uInt8* CartridgeF8::getImage(uInt32& size) const
{
size = 8192;
return myImage;
@@ -167,7 +166,7 @@ bool CartridgeF8::save(Serializer& out) const
try
{
out.putString(name());
- out.putShort(myCurrentBank);
+ out.putShort(myBankOffset);
}
catch(...)
{
@@ -186,7 +185,7 @@ bool CartridgeF8::load(Serializer& in)
if(in.getString() != name())
return false;
- myCurrentBank = in.getShort();
+ myBankOffset = in.getShort();
}
catch(...)
{
@@ -195,7 +194,7 @@ bool CartridgeF8::load(Serializer& in)
}
// Remember what bank we were in
- bank(myCurrentBank);
+ bank(myBankOffset >> 12);
return true;
}
diff --git a/src/emucore/CartF8.hxx b/src/emucore/CartF8.hxx
index a9ae9f4ec..8504f67b1 100644
--- a/src/emucore/CartF8.hxx
+++ b/src/emucore/CartF8.hxx
@@ -27,8 +27,8 @@ class System;
#endif
/**
- Cartridge class used for Atari's 8K bankswitched games. There
- are two 4K banks.
+ Cartridge class used for Atari's 8K bankswitched games. There are two
+ 4K banks, accessible by read/write to $1FF8 - $1FF9.
@author Bradford W. Mott
*/
@@ -95,7 +95,7 @@ class CartridgeF8 : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -153,8 +153,8 @@ class CartridgeF8 : public Cartridge
// The 8K ROM image of the cartridge
uInt8 myImage[8192];
- // Indicates which bank is currently active
- uInt16 myCurrentBank;
+ // Indicates the offset into the ROM image (aligns to current bank)
+ uInt16 myBankOffset;
private:
// Following constructors and assignment operators not supported
diff --git a/src/emucore/CartF8SC.cxx b/src/emucore/CartF8SC.cxx
index 8738b0b4e..7094233e4 100644
--- a/src/emucore/CartF8SC.cxx
+++ b/src/emucore/CartF8SC.cxx
@@ -22,7 +22,7 @@
CartridgeF8SC::CartridgeF8SC(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings),
- myCurrentBank(0)
+ myBankOffset(0)
{
// Copy the ROM image into my buffer
memcpy(myImage, image.get(), std::min(8192u, size));
@@ -50,21 +50,21 @@ void CartridgeF8SC::install(System& system)
// Set the page accessing method for the RAM writing pages
access.type = System::PA_WRITE;
- for(uInt32 j = 0x1000; j < 0x1080; j += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE)
{
- access.directPokeBase = &myRAM[j & 0x007F];
- access.codeAccessBase = &myCodeAccessBase[j & 0x007F];
- mySystem->setPageAccess(j >> System::PAGE_SHIFT, access);
+ access.directPokeBase = &myRAM[addr & 0x007F];
+ access.codeAccessBase = &myCodeAccessBase[addr & 0x007F];
+ mySystem->setPageAccess(addr, access);
}
// Set the page accessing method for the RAM reading pages
access.directPokeBase = 0;
access.type = System::PA_READ;
- for(uInt32 k = 0x1080; k < 0x1100; k += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myRAM[k & 0x007F];
- access.codeAccessBase = &myCodeAccessBase[0x80 + (k & 0x007F)];
- mySystem->setPageAccess(k >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myRAM[addr & 0x007F];
+ access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)];
+ mySystem->setPageAccess(addr, access);
}
// Install pages for the startup bank
@@ -108,7 +108,7 @@ uInt8 CartridgeF8SC::peek(uInt16 address)
}
}
else
- return myImage[(myCurrentBank << 12) + address];
+ return myImage[myBankOffset + address];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -145,26 +145,25 @@ bool CartridgeF8SC::bank(uInt16 bank)
if(bankLocked()) return false;
// Remember what bank we're in
- myCurrentBank = bank;
- uInt16 offset = myCurrentBank << 12;
+ myBankOffset = bank << 12;
System::PageAccess access(this, System::PA_READ);
// Set the page accessing methods for the hot spots
- for(uInt32 i = (0x1FF8 & ~System::PAGE_MASK); i < 0x2000;
- i += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = (0x1FF8 & ~System::PAGE_MASK); addr < 0x2000;
+ addr += System::PAGE_SIZE)
{
- access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)];
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
// Setup the page access methods for the current bank
- for(uInt32 address = 0x1100; address < (0x1FF8U & ~System::PAGE_MASK);
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1100; addr < (0x1FF8U & ~System::PAGE_MASK);
+ addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
@@ -172,7 +171,7 @@ bool CartridgeF8SC::bank(uInt16 bank)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeF8SC::getBank() const
{
- return myCurrentBank;
+ return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -194,13 +193,13 @@ bool CartridgeF8SC::patch(uInt16 address, uInt8 value)
myRAM[address & 0x007F] = value;
}
else
- myImage[(myCurrentBank << 12) + address] = value;
+ myImage[myBankOffset + address] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeF8SC::getImage(int& size) const
+const uInt8* CartridgeF8SC::getImage(uInt32& size) const
{
size = 8192;
return myImage;
@@ -212,7 +211,7 @@ bool CartridgeF8SC::save(Serializer& out) const
try
{
out.putString(name());
- out.putShort(myCurrentBank);
+ out.putShort(myBankOffset);
out.putByteArray(myRAM, 128);
}
catch(...)
@@ -232,7 +231,7 @@ bool CartridgeF8SC::load(Serializer& in)
if(in.getString() != name())
return false;
- myCurrentBank = in.getShort();
+ myBankOffset = in.getShort();
in.getByteArray(myRAM, 128);
}
catch(...)
@@ -242,7 +241,7 @@ bool CartridgeF8SC::load(Serializer& in)
}
// Remember what bank we were in
- bank(myCurrentBank);
+ bank(myBankOffset >> 12);
return true;
}
diff --git a/src/emucore/CartF8SC.hxx b/src/emucore/CartF8SC.hxx
index 1baf4be3e..f19f22a79 100644
--- a/src/emucore/CartF8SC.hxx
+++ b/src/emucore/CartF8SC.hxx
@@ -27,8 +27,9 @@ class System;
#endif
/**
- Cartridge class used for Atari's 8K bankswitched games with
- 128 bytes of RAM. There are two 4K banks.
+ Cartridge class used for Atari's 8K bankswitched games with 128 bytes of
+ RAM. There are two 4K banks, accessible by read/write to $1FF8 - $1FF9.
+ RAM read port is $1080 - $10FF, write port is $1000 - $107F.
@author Bradford W. Mott
*/
@@ -93,7 +94,7 @@ class CartridgeF8SC : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -154,8 +155,8 @@ class CartridgeF8SC : public Cartridge
// The 128 bytes of RAM
uInt8 myRAM[128];
- // Indicates which bank is currently active
- uInt16 myCurrentBank;
+ // Indicates the offset into the ROM image (aligns to current bank)
+ uInt16 myBankOffset;
private:
// Following constructors and assignment operators not supported
diff --git a/src/emucore/CartFA.cxx b/src/emucore/CartFA.cxx
index 511352f44..f0808f9a5 100644
--- a/src/emucore/CartFA.cxx
+++ b/src/emucore/CartFA.cxx
@@ -22,7 +22,7 @@
CartridgeFA::CartridgeFA(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings),
- myCurrentBank(0)
+ myBankOffset(0)
{
// Copy the ROM image into my buffer
memcpy(myImage, image.get(), std::min(12288u, size));
@@ -50,21 +50,21 @@ void CartridgeFA::install(System& system)
// Set the page accessing method for the RAM writing pages
access.type = System::PA_WRITE;
- for(uInt32 j = 0x1000; j < 0x1100; j += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < 0x1100; addr += System::PAGE_SIZE)
{
- access.directPokeBase = &myRAM[j & 0x00FF];
- access.codeAccessBase = &myCodeAccessBase[j & 0x00FF];
- mySystem->setPageAccess(j >> System::PAGE_SHIFT, access);
+ access.directPokeBase = &myRAM[addr & 0x00FF];
+ access.codeAccessBase = &myCodeAccessBase[addr & 0x00FF];
+ mySystem->setPageAccess(addr, access);
}
// Set the page accessing method for the RAM reading pages
access.directPokeBase = 0;
access.type = System::PA_READ;
- for(uInt32 k = 0x1100; k < 0x1200; k += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1100; addr < 0x1200; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myRAM[k & 0x00FF];
- access.codeAccessBase = &myCodeAccessBase[0x100 + (k & 0x00FF)];
- mySystem->setPageAccess(k >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myRAM[addr & 0x00FF];
+ access.codeAccessBase = &myCodeAccessBase[0x100 + (addr & 0x00FF)];
+ mySystem->setPageAccess(addr, access);
}
// Install pages for the startup bank
@@ -113,7 +113,7 @@ uInt8 CartridgeFA::peek(uInt16 address)
}
}
else
- return myImage[(myCurrentBank << 12) + address];
+ return myImage[myBankOffset + address];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -155,26 +155,25 @@ bool CartridgeFA::bank(uInt16 bank)
if(bankLocked()) return false;
// Remember what bank we're in
- myCurrentBank = bank;
- uInt16 offset = myCurrentBank << 12;
+ myBankOffset = bank << 12;
System::PageAccess access(this, System::PA_READ);
// Set the page accessing methods for the hot spots
- for(uInt32 i = (0x1FF8 & ~System::PAGE_MASK); i < 0x2000;
- i += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = (0x1FF8 & ~System::PAGE_MASK); addr < 0x2000;
+ addr += System::PAGE_SIZE)
{
- access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)];
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
// Setup the page access methods for the current bank
- for(uInt32 address = 0x1200; address < (0x1FF8U & ~System::PAGE_MASK);
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1200; addr < (0x1FF8U & ~System::PAGE_MASK);
+ addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
@@ -182,7 +181,7 @@ bool CartridgeFA::bank(uInt16 bank)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeFA::getBank() const
{
- return myCurrentBank;
+ return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -204,13 +203,13 @@ bool CartridgeFA::patch(uInt16 address, uInt8 value)
myRAM[address & 0x00FF] = value;
}
else
- myImage[(myCurrentBank << 12) + address] = value;
+ myImage[myBankOffset + address] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeFA::getImage(int& size) const
+const uInt8* CartridgeFA::getImage(uInt32& size) const
{
size = 12288;
return myImage;
@@ -222,7 +221,7 @@ bool CartridgeFA::save(Serializer& out) const
try
{
out.putString(name());
- out.putShort(myCurrentBank);
+ out.putShort(myBankOffset);
out.putByteArray(myRAM, 256);
}
catch(...)
@@ -242,7 +241,7 @@ bool CartridgeFA::load(Serializer& in)
if(in.getString() != name())
return false;
- myCurrentBank = in.getShort();
+ myBankOffset = in.getShort();
in.getByteArray(myRAM, 256);
}
catch(...)
@@ -252,7 +251,7 @@ bool CartridgeFA::load(Serializer& in)
}
// Remember what bank we were in
- bank(myCurrentBank);
+ bank(myBankOffset >> 12);
return true;
}
diff --git a/src/emucore/CartFA.hxx b/src/emucore/CartFA.hxx
index 2f52d68e0..0018afd0d 100644
--- a/src/emucore/CartFA.hxx
+++ b/src/emucore/CartFA.hxx
@@ -27,8 +27,9 @@ class System;
#endif
/**
- Cartridge class used for CBS' RAM Plus cartridges. There are
- three 4K banks and 256 bytes of RAM.
+ Cartridge class used for CBS' RAM Plus cartridges. There are three 4K
+ banks, accessible by read/write at $1FF8 - $1FFA, and 256 bytes of RAM.
+ RAM read port is $1100 - $11FF, write port is $1000 - $10FF.
@author Bradford W. Mott
*/
@@ -93,7 +94,7 @@ class CartridgeFA : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -154,8 +155,8 @@ class CartridgeFA : public Cartridge
// The 256 bytes of RAM on the cartridge
uInt8 myRAM[256];
- // Indicates which bank is currently active
- uInt16 myCurrentBank;
+ // Indicates the offset into the ROM image (aligns to current bank)
+ uInt16 myBankOffset;
private:
// Following constructors and assignment operators not supported
diff --git a/src/emucore/CartFA2.cxx b/src/emucore/CartFA2.cxx
index 4df33060c..162cc54e1 100644
--- a/src/emucore/CartFA2.cxx
+++ b/src/emucore/CartFA2.cxx
@@ -27,7 +27,7 @@ CartridgeFA2::CartridgeFA2(const BytePtr& image, uInt32 size,
myOSystem(osystem),
mySize(28 * 1024),
myRamAccessTimeout(0),
- myCurrentBank(0)
+ myBankOffset(0)
{
// 29/32K version of FA2 has valid data @ 1K - 29K
const uInt8* img_ptr = image.get();
@@ -62,21 +62,21 @@ void CartridgeFA2::install(System& system)
// Set the page accessing method for the RAM writing pages
access.type = System::PA_WRITE;
- for(uInt32 j = 0x1000; j < 0x1100; j += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < 0x1100; addr += System::PAGE_SIZE)
{
- access.directPokeBase = &myRAM[j & 0x00FF];
- access.codeAccessBase = &myCodeAccessBase[j & 0x00FF];
- mySystem->setPageAccess(j >> System::PAGE_SHIFT, access);
+ access.directPokeBase = &myRAM[addr & 0x00FF];
+ access.codeAccessBase = &myCodeAccessBase[addr & 0x00FF];
+ mySystem->setPageAccess(addr, access);
}
// Set the page accessing method for the RAM reading pages
access.directPokeBase = 0;
access.type = System::PA_READ;
- for(uInt32 k = 0x1100; k < 0x1200; k += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1100; addr < 0x1200; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myRAM[k & 0x00FF];
- access.codeAccessBase = &myCodeAccessBase[0x100 + (k & 0x00FF)];
- mySystem->setPageAccess(k >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myRAM[addr & 0x00FF];
+ access.codeAccessBase = &myCodeAccessBase[0x100 + (addr & 0x00FF)];
+ mySystem->setPageAccess(addr, access);
}
// Install pages for the startup bank
@@ -152,7 +152,7 @@ uInt8 CartridgeFA2::peek(uInt16 address)
}
}
else
- return myImage[(myCurrentBank << 12) + address];
+ return myImage[myBankOffset + address];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -221,26 +221,25 @@ bool CartridgeFA2::bank(uInt16 bank)
if(bankLocked()) return false;
// Remember what bank we're in
- myCurrentBank = bank;
- uInt16 offset = myCurrentBank << 12;
+ myBankOffset = bank << 12;
System::PageAccess access(this, System::PA_READ);
// Set the page accessing methods for the hot spots
- for(uInt32 i = (0x1FF4 & ~System::PAGE_MASK); i < 0x2000;
- i += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = (0x1FF4 & ~System::PAGE_MASK); addr < 0x2000;
+ addr += System::PAGE_SIZE)
{
- access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)];
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
// Setup the page access methods for the current bank
- for(uInt32 address = 0x1200; address < (0x1FF4U & ~System::PAGE_MASK);
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1200; addr < (0x1FF4U & ~System::PAGE_MASK);
+ addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
@@ -248,7 +247,7 @@ bool CartridgeFA2::bank(uInt16 bank)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeFA2::getBank() const
{
- return myCurrentBank;
+ return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -270,13 +269,13 @@ bool CartridgeFA2::patch(uInt16 address, uInt8 value)
myRAM[address & 0x00FF] = value;
}
else
- myImage[(myCurrentBank << 12) + address] = value;
+ myImage[myBankOffset + address] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeFA2::getImage(int& size) const
+const uInt8* CartridgeFA2::getImage(uInt32& size) const
{
size = mySize;
return myImage;
@@ -288,7 +287,7 @@ bool CartridgeFA2::save(Serializer& out) const
try
{
out.putString(name());
- out.putShort(myCurrentBank);
+ out.putShort(myBankOffset);
out.putByteArray(myRAM, 256);
}
catch(...)
@@ -308,7 +307,7 @@ bool CartridgeFA2::load(Serializer& in)
if(in.getString() != name())
return false;
- myCurrentBank = in.getShort();
+ myBankOffset = in.getShort();
in.getByteArray(myRAM, 256);
}
catch(...)
@@ -318,7 +317,7 @@ bool CartridgeFA2::load(Serializer& in)
}
// Remember what bank we were in
- bank(myCurrentBank);
+ bank(myBankOffset >> 12);
return true;
}
@@ -388,7 +387,7 @@ uInt8 CartridgeFA2::ramReadWrite()
}
}
// Bit 6 is 1, busy
- return myImage[(myCurrentBank << 12) + 0xFF4] | 0x40;
+ return myImage[myBankOffset + 0xFF4] | 0x40;
}
else
{
@@ -399,11 +398,11 @@ uInt8 CartridgeFA2::ramReadWrite()
myRAM[255] = 0; // Successful operation
// Bit 6 is 0, ready/success
- return myImage[(myCurrentBank << 12) + 0xFF4] & ~0x40;
+ return myImage[myBankOffset + 0xFF4] & ~0x40;
}
else
// Bit 6 is 1, busy
- return myImage[(myCurrentBank << 12) + 0xFF4] | 0x40;
+ return myImage[myBankOffset + 0xFF4] | 0x40;
}
}
diff --git a/src/emucore/CartFA2.hxx b/src/emucore/CartFA2.hxx
index 4a5bc6223..caf8c0f4c 100644
--- a/src/emucore/CartFA2.hxx
+++ b/src/emucore/CartFA2.hxx
@@ -30,13 +30,18 @@ class System;
This is an extended version of the CBS RAM Plus bankswitching scheme
supported by the Harmony cartridge.
- There are six (or seven) 4K banks and 256 bytes of RAM. The 256 bytes
- of RAM can be loaded/saved to Harmony cart flash, which is emulated by
- storing in a file.
+ There are six (or seven) 4K banks, accessible by read/write to $1FF5 -
+ $1FFA (or $1FFB), and 256 bytes of RAM.
- For 29K versions of the scheme, the first 1K is ARM code
- (implements actual bankswitching on the Harmony cart), which is
- completely ignored by the emulator.
+ The 256 bytes of RAM can be loaded/saved to Harmony cart flash by
+ accessing $1FF4 (see ramReadWrite() for more information), which is
+ emulated by storing in a file.
+ RAM read port is $1100 - $11FF, write port is $1000 - $10FF.
+
+ For 29K versions of the scheme, the first 1K is ARM code (implements
+ actual bankswitching on the Harmony cart), which is completely ignored
+ by the emulator. Also supported is a 32K variant. In any event, only
+ data at 1K - 29K of the ROM is used.
@author Chris D. Walton
*/
@@ -101,7 +106,7 @@ class CartridgeFA2 : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -205,8 +210,8 @@ class CartridgeFA2 : public Cartridge
// of internal RAM to Harmony cart flash
string myFlashFile;
- // Indicates which bank is currently active
- uInt16 myCurrentBank;
+ // Indicates the offset into the ROM image (aligns to current bank)
+ uInt16 myBankOffset;
private:
// Following constructors and assignment operators not supported
diff --git a/src/emucore/CartFE.cxx b/src/emucore/CartFE.cxx
index e77540188..cabb070f3 100644
--- a/src/emucore/CartFE.cxx
+++ b/src/emucore/CartFE.cxx
@@ -22,26 +22,21 @@
CartridgeFE::CartridgeFE(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings),
- myLastAddress1(0),
- myLastAddress2(0),
- myLastAddressChanged(false)
+ myBankOffset(0),
+ myLastAccessWasFE(false)
{
// Copy the ROM image into my buffer
memcpy(myImage, image.get(), std::min(8192u, size));
-
- // We use System::PageAccess.codeAccessBase, but don't allow its use
- // through a pointer, since the address space of FE carts can change
- // at the instruction level, and PageAccess is normally defined at an
- // interval of 64 bytes
- //
- // Instead, access will be through the getAccessFlags and setAccessFlags
- // methods below
createCodeAccessBase(8192);
+
+ myStartBank = 0; // For now, we assume this; more research is needed
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeFE::reset()
{
+ bank(myStartBank);
+ myLastAccessWasFE = false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -49,50 +44,73 @@ void CartridgeFE::install(System& system)
{
mySystem = &system;
- // Map all of the accesses to call peek and poke
- System::PageAccess access(this, System::PA_READ);
- for(uInt32 i = 0x1000; i < 0x2000; i += (1 << System::PAGE_SHIFT))
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ // The hotspot $01FE is in a mirror of zero-page RAM
+ // We need to claim access to it here, and deal with it in peek/poke below
+ System::PageAccess access(this, System::PA_READWRITE);
+ for(uInt16 addr = 0x180; addr < 0x200; addr += System::PAGE_SIZE)
+ mySystem->setPageAccess(addr, access);
+
+ // Map all of the cart accesses to call peek and poke
+ access.type = System::PA_READ;
+ for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE)
+ mySystem->setPageAccess(addr, access);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeFE::peek(uInt16 address)
{
- // The bank is determined by A13 of the processor
- // We keep track of the two most recent accesses to determine which bank
- // we're in, and when the values actually changed
- myLastAddress2 = myLastAddress1;
- myLastAddress1 = address;
- myLastAddressChanged = true;
+ uInt8 value = (address < 0x200) ? mySystem->m6532().peek(address) :
+ myImage[myBankOffset + (address & 0x0FFF)];
- return myImage[(address & 0x0FFF) + (((address & 0x2000) == 0) ? 4096 : 0)];
+ // Check if we hit hotspot
+ checkBankSwitch(address, value);
+
+ return value;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool CartridgeFE::poke(uInt16, uInt8)
+bool CartridgeFE::poke(uInt16 address, uInt8 value)
{
+ if(address < 0x200)
+ mySystem->m6532().poke(address, value);
+
+ // Check if we hit hotspot
+ checkBankSwitch(address, value);
+
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-uInt8 CartridgeFE::getAccessFlags(uInt16 address) const
+void CartridgeFE::checkBankSwitch(uInt16 address, uInt8 value)
{
- return myCodeAccessBase[(address & 0x0FFF) +
- (((address & 0x2000) == 0) ? 4096 : 0)];
+ if(bankLocked())
+ return;
+
+ // Did we detect $01FE on the last address bus access?
+ // If so, we bankswitch according to the upper 3 bits of the data bus
+ // NOTE: see the header file for the significance of 'value & 0x20'
+ if(myLastAccessWasFE)
+ bank((value & 0x20) ? 0 : 1);
+
+ // On the next cycle, we use the (then) current data bus value to decode
+ // the bank to use
+ myLastAccessWasFE = address == 0x01FE;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void CartridgeFE::setAccessFlags(uInt16 address, uInt8 flags)
+bool CartridgeFE::bank(uInt16 bank)
{
- myCodeAccessBase[(address & 0x0FFF) +
- (((address & 0x2000) == 0) ? 4096 : 0)] |= flags;
+ if(bankLocked())
+ return false;
+
+ myBankOffset = bank << 12;
+ return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeFE::getBank() const
{
- // The current bank depends on the last address accessed
- return ((myLastAddress1 & 0x2000) == 0) ? 1 : 0;
+ return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -101,32 +119,15 @@ uInt16 CartridgeFE::bankCount() const
return 2;
}
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool CartridgeFE::bankChanged()
-{
- if(myLastAddressChanged)
- {
- // A bankswitch occurs when the addresses transition from state to another
- myBankChanged = ((myLastAddress1 & 0x2000) == 0) !=
- ((myLastAddress2 & 0x2000) == 0);
- myLastAddressChanged = false;
- }
- else
- myBankChanged = false;
-
- // In any event, let the base class know about it
- return Cartridge::bankChanged();
-}
-
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeFE::patch(uInt16 address, uInt8 value)
{
- myImage[(address & 0x0FFF) + (((address & 0x2000) == 0) ? 4096 : 0)] = value;
+ myImage[myBankOffset + (address & 0x0FFF)] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeFE::getImage(int& size) const
+const uInt8* CartridgeFE::getImage(uInt32& size) const
{
size = 8192;
return myImage;
@@ -138,8 +139,8 @@ bool CartridgeFE::save(Serializer& out) const
try
{
out.putString(name());
- out.putShort(myLastAddress1);
- out.putShort(myLastAddress2);
+ out.putShort(myBankOffset);
+ out.putBool(myLastAccessWasFE);
}
catch(...)
{
@@ -158,8 +159,8 @@ bool CartridgeFE::load(Serializer& in)
if(in.getString() != name())
return false;
- myLastAddress1 = in.getShort();
- myLastAddress2 = in.getShort();
+ myBankOffset = in.getShort();
+ myLastAccessWasFE = in.getBool();
}
catch(...)
{
diff --git a/src/emucore/CartFE.hxx b/src/emucore/CartFE.hxx
index 67d02665b..d26988dc5 100644
--- a/src/emucore/CartFE.hxx
+++ b/src/emucore/CartFE.hxx
@@ -29,23 +29,51 @@ class System;
/**
Bankswitching method used by Activision's Robot Tank and Decathlon.
- Kevin Horton describes FE as follows:
+ This scheme was originally designed to have up to 8 4K banks, and is
+ triggered by monitoring the address bus for address $01FE. All released
+ carts had only two banks, and this implementation assumes that (ie, ROM
+ is always 8K, and there are two 4K banks).
- Used only on two carts (Robot Tank and Decathlon). These
- carts are very weird. It does not use accesses to the stack
- like was previously thought. Instead, if you watch the called
- addresses very carefully, you can see that they are either Dxxx
- or Fxxx. This determines the bank to use. Just monitor A13 of
- the processor and use it to determine your bank! :-) Of course
- the 6507 in the 2600 does not have an A13, so the cart must have
- an extra bit in the ROM matrix to tell when to switch banks.
- There is *no* way to determine which bank you want to be in from
- monitoring the bus.
+ The following is paraphrased from the original patent by David Crane,
+ European Patent Application # 84300730.3, dated 06.02.84:
- This cart reports having 2 banks, even though this cannot be
- determined on a real system.
+ ---------------------------------------------------------------------------
+ The twelve line address bus is connected to a plurality of 4K by eight bit
+ memories.
- @author Bradford W. Mott
+ The eight line data bus is connected to each of the banks of memory, also.
+ An address comparator is connected to the bus for detecting the presence of
+ the 01FE address. Actually, the comparator will detect only the lowest 12
+ bits of 1FE, because of the twelve bit limitation of the address bus. Upon
+ detection of the 01FE address, a one cycle delay is activated which then
+ actuates latch connected to the data bus. The three most significant bits
+ on the data bus are latched and provide the address bits A13, A14, and A15
+ which are then applied to a 3 to 8 de-multiplexer. The 3 bits A13-A15
+ define a code for selecting one of the eight banks of memory which is used
+ to enable one of the banks of memory by applying a control signal to the
+ enable, EN, terminal thereof. Accordingly, memory bank selection is
+ accomplished from address codes on the data bus following a particular
+ program instruction, such as a jump to subroutine.
+ ---------------------------------------------------------------------------
+
+ Note that in the general scheme, we use D7, D6 and D5 for the bank number
+ (3 bits, so 8 possible banks). However, the scheme as used historically
+ by Activision only uses two banks. Furthermore, the two banks it uses
+ are actually indicated by binary 110 and 111, and translated as follows:
+
+ binary 110 -> decimal 6 -> Upper 4K ROM (bank 1) @ $D000 - $DFFF
+ binary 111 -> decimal 7 -> Lower 4K ROM (bank 0) @ $F000 - $FFFF
+
+ Since the actual bank numbers (0 and 1) do not map directly to their
+ respective bitstrings (7 and 6), we simply test for D5 being 0 or 1.
+ This is the significance of the test '(value & 0x20) ? 0 : 1' in the code.
+
+ NOTE: Consult the patent application for more specific information, in
+ particular *why* the address $01FE will be placed on the address
+ bus after both the JSR and RTS opcodes.
+
+ @author Stephen Anthony; with ideas/research from Christian Speckner and
+ alex_79 and TomSon (of AtariAge)
*/
class CartridgeFE : public Cartridge
{
@@ -76,6 +104,13 @@ class CartridgeFE : public Cartridge
*/
void install(System& system) override;
+ /**
+ Install pages for the specified bank in the system.
+
+ @param bank The bank that should be installed in the system
+ */
+ bool bank(uInt16 bank) override;
+
/**
Get the current bank.
*/
@@ -86,14 +121,6 @@ class CartridgeFE : public Cartridge
*/
uInt16 bankCount() const override;
- /**
- Answer whether the bank has changed since the last time this
- method was called.
-
- @return Whether the bank was changed
- */
- bool bankChanged() override;
-
/**
Patch the cartridge ROM.
@@ -109,7 +136,7 @@ class CartridgeFE : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -155,7 +182,7 @@ class CartridgeFE : public Cartridge
uInt8 peek(uInt16 address) override;
/**
- Change the byte at the specified address to the given value
+ Change the byte at the specified address to the given value.
@param address The address where the value should be stored
@param value The value to be stored at the address
@@ -165,23 +192,20 @@ class CartridgeFE : public Cartridge
private:
/**
- Query/change the given address type to use the given disassembly flags
-
- @param address The address to modify
- @param flags A bitfield of DisasmType directives for the given address
+ Perform bankswitch when necessary, by monitoring for $01FE
+ on the address bus and getting the bank number from the data bus.
*/
- uInt8 getAccessFlags(uInt16 address) const override;
- void setAccessFlags(uInt16 address, uInt8 flags) override;
+ void checkBankSwitch(uInt16 address, uInt8 value);
private:
// The 8K ROM image of the cartridge
uInt8 myImage[8192];
- // Previous two addresses accessed by peek()
- uInt16 myLastAddress1, myLastAddress2;
+ // Indicates the offset into the ROM image (aligns to current bank)
+ uInt16 myBankOffset;
- // Last two addresses have been modified by peek()
- bool myLastAddressChanged;
+ // Whether previous address by peek/poke equals $01FE (hotspot)
+ bool myLastAccessWasFE;
private:
// Following constructors and assignment operators not supported
diff --git a/src/emucore/CartMC.cxx b/src/emucore/CartMC.cxx
deleted file mode 100644
index c77af110b..000000000
--- a/src/emucore/CartMC.cxx
+++ /dev/null
@@ -1,270 +0,0 @@
-//============================================================================
-//
-// 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
-
-#include "System.hxx"
-#include "CartMC.hxx"
-
-// TODO - much more testing of this scheme is required
-// No test ROMs exist as of 2009-11-08, so we can't be sure how
-// accurate the emulation is
-// Bankchange and RAM modification cannot be completed until
-// adequate test ROMs are available
-// TODO (2010-10-03) - support CodeAccessBase functionality somehow
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-CartridgeMC::CartridgeMC(const BytePtr& image, uInt32 size,
- const Settings& settings)
- : Cartridge(settings),
- mySlot3Locked(false)
-{
- // Make sure size is reasonable
- assert(size <= 131072);
-
- // Set the contents of the entire ROM to 0
- memset(myImage, 0, 131072);
-
- // Copy the ROM image to the end of the ROM buffer
- memcpy(myImage + 131072 - size, image.get(), size);
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void CartridgeMC::reset()
-{
- initializeRAM(myRAM, 32768);
-
- myBankChanged = true;
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void CartridgeMC::install(System& system)
-{
- mySystem = &system;
-
-/*
- // Make sure the system we're being installed in has a page size that'll work
- assert(((0x1000 & mask) == 0) && ((0x1400 & mask) == 0) &&
- ((0x1800 & mask) == 0) && ((0x1C00 & mask) == 0));
-*/
-
- // Set the page accessing methods for the hot spots in the TIA. For
- // correct emulation I would need to chain any accesses below 0x40 to
- // the TIA but for now I'll just forget about them.
- //
- // TODO: These TIA accesses may need to be chained, however, at this
- // point Chris isn't sure if the hardware will allow it or not
- //
- System::PageAccess access(this, System::PA_READWRITE);
-
- for(uInt32 i = 0x00; i < 0x40; i += (1 << System::PAGE_SHIFT))
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
-
- // Map the cartridge into the system
- access.type = System::PA_READ; // We don't yet indicate RAM areas
- for(uInt32 j = 0x1000; j < 0x2000; j += (1 << System::PAGE_SHIFT))
- mySystem->setPageAccess(j >> System::PAGE_SHIFT, access);
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-uInt8 CartridgeMC::peek(uInt16 address)
-{
- uInt16 peekAddress = address;
- address &= 0x1FFF;
-
- // Accessing the RESET vector so lets handle the powerup special case
- if((address == 0x1FFC) || (address == 0x1FFD))
- {
- // Indicate that slot 3 is locked for now
- mySlot3Locked = true;
- }
- // Should we unlock slot 3?
- else if(mySlot3Locked && (address >= 0x1000) && (address <= 0x1BFF))
- {
- // Indicate that slot 3 is unlocked now
- mySlot3Locked = false;
- }
-
- // Handle reads made to the TIA addresses
- if(address < 0x1000)
- {
- return 0;
- }
- else
- {
- uInt8 block;
-
- if(mySlot3Locked && ((address & 0x0C00) == 0x0C00))
- {
- block = 0xFF;
- }
- else
- {
- block = myCurrentBlock[(address & 0x0C00) >> 10];
- }
-
- // Is this a RAM or a ROM access
- if(block & 0x80)
- {
- // ROM access
- return myImage[uInt32((block & 0x7F) << 10) + (address & 0x03FF)];
- }
- else
- {
- // This is a RAM access, however, is it to the read or write port?
- if(address & 0x0200)
- {
- // Reading from the read port of the RAM block
- return myRAM[uInt32((block & 0x3F) << 9) + (address & 0x01FF)];
- }
- else
- {
- // Oops, reading from the write port of the RAM block!
- // Reading from the write port triggers an unwanted write
- uInt8 value = mySystem->getDataBusState(0xFF);
-
- if(bankLocked())
- return value;
- else
- {
- triggerReadFromWritePort(peekAddress);
- return myRAM[uInt32((block & 0x3F) << 9) + (address & 0x01FF)] = value;
- }
- }
- }
- }
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool CartridgeMC::poke(uInt16 address, uInt8 value)
-{
- address &= 0x1FFF;
-
- // Accessing the RESET vector so lets handle the powerup special case
- if((address == 0x1FFC) || (address == 0x1FFD))
- {
- // Indicate that slot 3 is locked for now
- mySlot3Locked = true;
- }
- // Should we unlock slot 3?
- else if(mySlot3Locked && (address >= 0x1000) && (address <= 0x1BFF))
- {
- // Indicate that slot 3 is unlocked now
- mySlot3Locked = false;
- }
-
- // Handle bank-switching writes
- if((address >= 0x003C) && (address <= 0x003F))
- {
- myCurrentBlock[address - 0x003C] = value;
- }
- else
- {
- uInt8 block;
-
- if(mySlot3Locked && ((address & 0x0C00) == 0x0C00))
- {
- block = 0xFF;
- }
- else
- {
- block = myCurrentBlock[(address & 0x0C00) >> 10];
- }
-
- // Is this a RAM write access
- if(!(block & 0x80) && !(address & 0x0200))
- {
- // Handle the write to RAM
- myRAM[uInt32((block & 0x3F) << 9) + (address & 0x01FF)] = value;
- return true;
- }
- }
- return false;
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-uInt16 CartridgeMC::getBank() const
-{
- // TODO - add support for debugger
- return 0;
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-uInt16 CartridgeMC::bankCount() const
-{
- // TODO - add support for debugger
- return 1;
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool CartridgeMC::patch(uInt16 address, uInt8 value)
-{
- // TODO - add support for debugger
- return false;
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeMC::getImage(int& size) const
-{
- size = 128 * 1024;
- return myImage;
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool CartridgeMC::save(Serializer& out) const
-{
- try
- {
- out.putString(name());
-
- // The currentBlock array
- out.putByteArray(myCurrentBlock, 4);
-
- // The 32K of RAM
- out.putByteArray(myRAM, 32 * 1024);
- }
- catch(...)
- {
- cerr << "ERROR: CartridgeMC::save" << endl;
- return false;
- }
-
- return true;
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool CartridgeMC::load(Serializer& in)
-{
- try
- {
- if(in.getString() != name())
- return false;
-
- // The currentBlock array
- in.getByteArray(myCurrentBlock, 4);
-
- // The 32K of RAM
- in.getByteArray(myRAM, 32 * 1024);
- }
- catch(...)
- {
- cerr << "ERROR: CartridgeMC::load" << endl;
- return false;
- }
-
- return true;
-}
diff --git a/src/emucore/CartMC.hxx b/src/emucore/CartMC.hxx
deleted file mode 100644
index 55885eee8..000000000
--- a/src/emucore/CartMC.hxx
+++ /dev/null
@@ -1,271 +0,0 @@
-//============================================================================
-//
-// 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 CARTRIDGEMC_HXX
-#define CARTRIDGEMC_HXX
-
-class System;
-
-#include "bspf.hxx"
-#include "Cart.hxx"
-#ifdef DEBUGGER_SUPPORT
- #include "CartMCWidget.hxx"
-#endif
-
-/**
- This is the cartridge class for Chris Wilkson's Megacart. It does not
- handle battery-backed RAM at this time and the code could use some serious
- speed improvements. It is based on the following Megacart specification:
-
-
- Megacart Specification, Rev1.1
- (c) 1997 Chris Wilkson
- cwilkson@mit.edu
-
- Description
- -----------
-
- The Megacart is an external memory cartridge for the Atari 2600 and compatible
- home video game consoles. It plugs into the standard cartridge port, and
- contains a total of 128K bytes of ROM storage and 32K bytes of battery-backed
- RAM storage.
-
- General Operation
- -----------------
-
- The Megacart uses "bank switching" to fit the 160K bytes of physical memory
- into the console's available 4K address space. Physical memory is divided
- into 64 RAM blocks of 512 bytes each, and 128 ROM blocks of 1K bytes each.
- RAM blocks are numbered $00 through $3F, and ROM blocks are numbered $80
- through $FF.
-
- The console's address space is divided into 4 slots of 1K each. Any physical
- memory block can be switched into any memory slot by writing its block number
- to the "hot address" for the desired slot. Memory locations $3C through $3F
- serve as "hot addresses" for memory slots 0 through 3, respectively.
-
-
- Example:
-
- To make ROM addresses $1A400-$1A7FF (block $E9) available to the console at
- memory locations $F800-$FBFF (slot 2), write $E9 to memory location $3e.
-
- Caution:
-
- Note that these memory locations are write only. Trying to read the contents
- of memory locations $3C through $3F will not only return invalid data, but
- will also corrupt the contents causing the software to crash. Reading these
- addresses should not be attempted.
-
- Special Case - RAM
- -------------------
-
- RAM blocks differ from ROM blocks in that one of the console's address lines,
- A9 in this case, must be used as a read/write select. Because of this, RAM
- blocks are limited to 512 bytes each, yet still occupy an entire 1K slot.
- To store a value A9 must be low. To retrieve a value A9 must high.
-
- Example:
-
- First, let's set slot 0 (console addresses $F000-$F3FF) to point to RAM
- block $9 (RAM $1200-$13ff). To do this, write $9 to console address $3c.
- To store the value $69 in RAM location $1234, write $69 to console address
- $F034 (A9=0). To retrieve the value of RAM location $1234, read from console
- address $F234 (A9=1).
-
- Special Case - Powerup
- -----------------------
-
- Because the console's memory is randomized at powerup, there is no way to
- predict the data initially contained in the "hot addresses". Therefore,
- hardware will force slot 3 to always point to ROM block $FF immediately
- after any read or write to the RESET vector at $FFFC-$FFFD. Block $FF
- must contain code to initialize the 4 memory slots to point to the desired
- physical memory blocks before any other code can be executed. After program
- execution jumps out of the boot code, the hardware will release slot 3 and
- it will function just like any other slot.
-
- Example (the first column is the physical ROM address):
-
- $00C00 JUNK ... ; random code and data
- ...
- ...
- ...
- ...
- $1F400 START ... ; program starts here
- ... ; slot 3 now points to rom block $83
- ...
- ...
- ...
- $1FFDD BOOT SEI ; disable interrupts
- $1FFDE CLD ; set hexadecimal arithmetic mode
- $1FFDF LDX #$FF ;
- $1FFE1 TXS ; set stack pointer to $ff
- $1FFE2 LDA #$00
- $1FFE4 ZERO STA 00,X ; clear RIOT and TIA -BEFORE- setting
- $1FFE6 DEX ; up banks
- $1FFE7 BNE ZERO
- $1FFE9 BANKS LDA #$00 ; ram block 0 ($0000-$01ff)
- $1FFEB STA SLOT0 ; slot 0 points to ram block 0
- $1FFED LDA #$34 ; ram block $34 ($6800-$69ff)
- $1FFEF STA SLOT1 ; slot 1 points to ram block $34
- $1FFF1 LDA #$FD ; rom block $fd ($1f400-$1f7ff)
- $1FFF3 STA SLOT2 ; slot 2 points to rom block $fd
- $1FFF5 LDA #$83 ; rom block $83 ($00C00-$01000)
- $1FFF7 STA SLOT3 ; slot 3 points to bootcode
- ; (rom block $ff)
- ; until jumping out of slot 3
- $1FFF9 JMP $F800 ; jump to slot 2
- $1FFFC RESET .WORD $FFDD ; powerup reset vector
- $1FFFE SWI .WORD $FFDD ; software interrupt vector (BRK)
-
-
- @author Bradford W. Mott
-*/
-class CartridgeMC : public Cartridge
-{
- friend class CartridgeMCWidget;
-
- public:
- /**
- Create a new cartridge using the specified image and size. If the
- size of the image is less than 128K then the cartridge will pad the
- beginning of the 128K ROM with zeros.
-
- @param image Pointer to the ROM image
- @param size The size of the ROM image
- @param settings A reference to the various settings (read-only)
- */
- CartridgeMC(const BytePtr& image, uInt32 size, const Settings& settings);
- virtual ~CartridgeMC() = default;
-
- public:
- /**
- Reset device to its power-on state
- */
- void reset() override;
-
- /**
- Install cartridge in the specified system. Invoked by the system
- when the cartridge is attached to it.
-
- @param system The system the device should install itself in
- */
- void install(System& system) override;
-
- /**
- Get the current bank.
- */
- uInt16 getBank() const override;
-
- /**
- Query the number of banks supported by the cartridge.
- */
- uInt16 bankCount() const override;
-
- /**
- Patch the cartridge ROM.
-
- @param address The ROM address to patch
- @param value The value to place into the address
- @return Success or failure of the patch operation
- */
- bool patch(uInt16 address, uInt8 value) override;
-
- /**
- Access the internal ROM image for this cartridge.
-
- @param size Set to the size of the internal ROM image data
- @return A pointer to the internal ROM image data
- */
- const uInt8* getImage(int& size) const override;
-
- /**
- Save the current state of this cart to the given Serializer.
-
- @param out The Serializer object to use
- @return False on any errors, else true
- */
- bool save(Serializer& out) const override;
-
- /**
- Load the current state of this cart from the given Serializer.
-
- @param in The Serializer object to use
- @return False on any errors, else true
- */
- bool load(Serializer& in) override;
-
- /**
- Get a descriptor for the device name (used in error checking).
-
- @return The name of the object
- */
- string name() const override { return "CartridgeMC"; }
-
- #ifdef DEBUGGER_SUPPORT
- /**
- Get debugger widget responsible for accessing the inner workings
- of the cart.
- */
- CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont,
- const GUI::Font& nfont, int x, int y, int w, int h) override
- {
- return new CartridgeMCWidget(boss, lfont, nfont, x, y, w, h, *this);
- }
- #endif
-
- public:
- /**
- Get the byte at the specified address
-
- @return The byte at the specified address
- */
- uInt8 peek(uInt16 address) override;
-
- /**
- Change the byte at the specified address to the given value
-
- @param address The address where the value should be stored
- @param value The value to be stored at the address
- @return True if the poke changed the device address space, else false
- */
- bool poke(uInt16 address, uInt8 value) override;
-
- private:
- // The 128K ROM image for the cartridge
- uInt8 myImage[131072];
-
- // The 32K of RAM for the cartridge
- uInt8 myRAM[32768];
-
- // Indicates which block is currently active for the four segments
- uInt8 myCurrentBlock[4];
-
- // Indicates if slot 3 is locked to block $FF or not
- bool mySlot3Locked;
-
- private:
- // Following constructors and assignment operators not supported
- CartridgeMC() = delete;
- CartridgeMC(const CartridgeMC&) = delete;
- CartridgeMC(CartridgeMC&&) = delete;
- CartridgeMC& operator=(const CartridgeMC&) = delete;
- CartridgeMC& operator=(CartridgeMC&&) = delete;
-};
-
-#endif
diff --git a/src/emucore/CartMDM.cxx b/src/emucore/CartMDM.cxx
index 013052ae5..f911cc5c1 100644
--- a/src/emucore/CartMDM.cxx
+++ b/src/emucore/CartMDM.cxx
@@ -23,7 +23,7 @@ CartridgeMDM::CartridgeMDM(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings),
mySize(size),
- myCurrentBank(0),
+ myBankOffset(0),
myBankingDisabled(false)
{
// Allocate array for the ROM image
@@ -51,19 +51,19 @@ void CartridgeMDM::install(System& system)
// Get the page accessing methods for the hot spots since they overlap
// areas within the TIA we'll need to forward requests to the TIA
- myHotSpotPageAccess[0] = mySystem->getPageAccess(0x0800 >> System::PAGE_SHIFT);
- myHotSpotPageAccess[1] = mySystem->getPageAccess(0x0900 >> System::PAGE_SHIFT);
- myHotSpotPageAccess[2] = mySystem->getPageAccess(0x0A00 >> System::PAGE_SHIFT);
- myHotSpotPageAccess[3] = mySystem->getPageAccess(0x0B00 >> System::PAGE_SHIFT);
- myHotSpotPageAccess[4] = mySystem->getPageAccess(0x0C00 >> System::PAGE_SHIFT);
- myHotSpotPageAccess[5] = mySystem->getPageAccess(0x0D00 >> System::PAGE_SHIFT);
- myHotSpotPageAccess[6] = mySystem->getPageAccess(0x0E00 >> System::PAGE_SHIFT);
- myHotSpotPageAccess[7] = mySystem->getPageAccess(0x0F00 >> System::PAGE_SHIFT);
+ myHotSpotPageAccess[0] = mySystem->getPageAccess(0x0800);
+ myHotSpotPageAccess[1] = mySystem->getPageAccess(0x0900);
+ myHotSpotPageAccess[2] = mySystem->getPageAccess(0x0A00);
+ myHotSpotPageAccess[3] = mySystem->getPageAccess(0x0B00);
+ myHotSpotPageAccess[4] = mySystem->getPageAccess(0x0C00);
+ myHotSpotPageAccess[5] = mySystem->getPageAccess(0x0D00);
+ myHotSpotPageAccess[6] = mySystem->getPageAccess(0x0E00);
+ myHotSpotPageAccess[7] = mySystem->getPageAccess(0x0F00);
// Set the page accessing methods for the hot spots
System::PageAccess access(this, System::PA_READWRITE);
- for(uInt32 i = 0x0800; i < 0x0BFF; i += (1 << System::PAGE_SHIFT))
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ for(uInt16 addr = 0x0800; addr < 0x0BFF; addr += System::PAGE_SIZE)
+ mySystem->setPageAccess(addr, access);
// Install pages for bank 0
bank(myStartBank);
@@ -105,19 +105,17 @@ bool CartridgeMDM::bank(uInt16 bank)
// Remember what bank we're in
// Wrap around to a valid bank number if necessary
- myCurrentBank = bank % bankCount();
- uInt32 offset = myCurrentBank << 12;
+ myBankOffset = (bank % bankCount()) << 12;
// Setup the page access methods for the current bank
System::PageAccess access(this, System::PA_READ);
// Map ROM image into the system
- for(uInt32 address = 0x1000; address < 0x2000;
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
// Accesses above bank 127 disable further bankswitching; we're only
@@ -129,7 +127,7 @@ bool CartridgeMDM::bank(uInt16 bank)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeMDM::getBank() const
{
- return myCurrentBank;
+ return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -141,12 +139,12 @@ uInt16 CartridgeMDM::bankCount() const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeMDM::patch(uInt16 address, uInt8 value)
{
- myImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value;
+ myImage[myBankOffset + (address & 0x0FFF)] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeMDM::getImage(int& size) const
+const uInt8* CartridgeMDM::getImage(uInt32& size) const
{
size = mySize;
return myImage.get();
@@ -158,7 +156,7 @@ bool CartridgeMDM::save(Serializer& out) const
try
{
out.putString(name());
- out.putShort(myCurrentBank);
+ out.putInt(myBankOffset);
}
catch(...)
{
@@ -177,7 +175,7 @@ bool CartridgeMDM::load(Serializer& in)
if(in.getString() != name())
return false;
- myCurrentBank = in.getShort();
+ myBankOffset = in.getInt();
}
catch(...)
{
@@ -186,7 +184,7 @@ bool CartridgeMDM::load(Serializer& in)
}
// Remember what bank we were in
- bank(myCurrentBank);
+ bank(myBankOffset >> 12);
return true;
}
diff --git a/src/emucore/CartMDM.hxx b/src/emucore/CartMDM.hxx
index b12ef2267..1be154e60 100644
--- a/src/emucore/CartMDM.hxx
+++ b/src/emucore/CartMDM.hxx
@@ -105,7 +105,7 @@ class CartridgeMDM : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -169,8 +169,8 @@ class CartridgeMDM : public Cartridge
// Previous Device's page access
System::PageAccess myHotSpotPageAccess[8];
- // Indicates which bank is currently active
- uInt16 myCurrentBank;
+ // Indicates the offset into the ROM image (aligns to current bank)
+ uInt32 myBankOffset;
// Indicates whether banking has been disabled due to a bankswitch
// above bank 127
diff --git a/src/emucore/CartSB.cxx b/src/emucore/CartSB.cxx
index 17ac31295..0093033d6 100644
--- a/src/emucore/CartSB.cxx
+++ b/src/emucore/CartSB.cxx
@@ -23,7 +23,7 @@ CartridgeSB::CartridgeSB(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings),
mySize(size),
- myCurrentBank(0)
+ myBankOffset(0)
{
// Allocate array for the ROM image
myImage = make_unique(mySize);
@@ -50,20 +50,20 @@ void CartridgeSB::install(System& system)
// Get the page accessing methods for the hot spots since they overlap
// areas within the TIA we'll need to forward requests to the TIA
- myHotSpotPageAccess[0] = mySystem->getPageAccess(0x0800 >> System::PAGE_SHIFT);
- myHotSpotPageAccess[1] = mySystem->getPageAccess(0x0900 >> System::PAGE_SHIFT);
- myHotSpotPageAccess[2] = mySystem->getPageAccess(0x0A00 >> System::PAGE_SHIFT);
- myHotSpotPageAccess[3] = mySystem->getPageAccess(0x0B00 >> System::PAGE_SHIFT);
- myHotSpotPageAccess[4] = mySystem->getPageAccess(0x0C00 >> System::PAGE_SHIFT);
- myHotSpotPageAccess[5] = mySystem->getPageAccess(0x0D00 >> System::PAGE_SHIFT);
- myHotSpotPageAccess[6] = mySystem->getPageAccess(0x0E00 >> System::PAGE_SHIFT);
- myHotSpotPageAccess[7] = mySystem->getPageAccess(0x0F00 >> System::PAGE_SHIFT);
+ myHotSpotPageAccess[0] = mySystem->getPageAccess(0x0800);
+ myHotSpotPageAccess[1] = mySystem->getPageAccess(0x0900);
+ myHotSpotPageAccess[2] = mySystem->getPageAccess(0x0A00);
+ myHotSpotPageAccess[3] = mySystem->getPageAccess(0x0B00);
+ myHotSpotPageAccess[4] = mySystem->getPageAccess(0x0C00);
+ myHotSpotPageAccess[5] = mySystem->getPageAccess(0x0D00);
+ myHotSpotPageAccess[6] = mySystem->getPageAccess(0x0E00);
+ myHotSpotPageAccess[7] = mySystem->getPageAccess(0x0F00);
System::PageAccess access(this, System::PA_READ);
// Set the page accessing methods for the hot spots
- for(uInt32 i = 0x0800; i < 0x0FFF; i += (1 << System::PAGE_SHIFT))
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ for(uInt16 addr = 0x0800; addr < 0x0FFF; addr += System::PAGE_SIZE)
+ mySystem->setPageAccess(addr, access);
// Install pages for startup bank
bank(myStartBank);
@@ -114,19 +114,17 @@ bool CartridgeSB::bank(uInt16 bank)
if(bankLocked()) return false;
// Remember what bank we're in
- myCurrentBank = bank;
- uInt32 offset = myCurrentBank << 12;
+ myBankOffset = bank << 12;
// Setup the page access methods for the current bank
System::PageAccess access(this, System::PA_READ);
// Map ROM image into the system
- for(uInt32 address = 0x1000; address < 0x2000;
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
@@ -134,7 +132,7 @@ bool CartridgeSB::bank(uInt16 bank)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeSB::getBank() const
{
- return myCurrentBank;
+ return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -146,12 +144,12 @@ uInt16 CartridgeSB::bankCount() const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeSB::patch(uInt16 address, uInt8 value)
{
- myImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value;
+ myImage[myBankOffset + (address & 0x0FFF)] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeSB::getImage(int& size) const
+const uInt8* CartridgeSB::getImage(uInt32& size) const
{
size = mySize;
return myImage.get();
@@ -163,7 +161,7 @@ bool CartridgeSB::save(Serializer& out) const
try
{
out.putString(name());
- out.putShort(myCurrentBank);
+ out.putInt(myBankOffset);
}
catch(...)
{
@@ -182,7 +180,7 @@ bool CartridgeSB::load(Serializer& in)
if(in.getString() != name())
return false;
- myCurrentBank = in.getShort();
+ myBankOffset = in.getInt();
}
catch(...)
{
@@ -191,7 +189,7 @@ bool CartridgeSB::load(Serializer& in)
}
// Remember what bank we were in
- bank(myCurrentBank);
+ bank(myBankOffset >> 12);
return true;
}
diff --git a/src/emucore/CartSB.hxx b/src/emucore/CartSB.hxx
index c17dd6fcc..eb8324702 100644
--- a/src/emucore/CartSB.hxx
+++ b/src/emucore/CartSB.hxx
@@ -94,7 +94,7 @@ class CartridgeSB : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -153,8 +153,8 @@ class CartridgeSB : public Cartridge
BytePtr myImage;
uInt32 mySize;
- // Indicates which bank is currently active
- uInt16 myCurrentBank;
+ // Indicates the offset into the ROM image (aligns to current bank)
+ uInt32 myBankOffset;
// Previous Device's page access
System::PageAccess myHotSpotPageAccess[8];
diff --git a/src/emucore/CartUA.cxx b/src/emucore/CartUA.cxx
index ae6b29c93..eaee04527 100644
--- a/src/emucore/CartUA.cxx
+++ b/src/emucore/CartUA.cxx
@@ -22,7 +22,7 @@
CartridgeUA::CartridgeUA(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings),
- myCurrentBank(0)
+ myBankOffset(0)
{
// Copy the ROM image into my buffer
memcpy(myImage, image.get(), std::min(8192u, size));
@@ -46,12 +46,12 @@ void CartridgeUA::install(System& system)
// Get the page accessing methods for the hot spots since they overlap
// areas within the TIA we'll need to forward requests to the TIA
- myHotSpotPageAccess = mySystem->getPageAccess(0x0220 >> System::PAGE_SHIFT);
+ myHotSpotPageAccess = mySystem->getPageAccess(0x0220);
// Set the page accessing methods for the hot spots
System::PageAccess access(this, System::PA_READ);
- mySystem->setPageAccess(0x0220 >> System::PAGE_SHIFT, access);
- mySystem->setPageAccess(0x0240 >> System::PAGE_SHIFT, access);
+ mySystem->setPageAccess(0x0220, access);
+ mySystem->setPageAccess(0x0240, access);
// Install pages for the startup bank
bank(myStartBank);
@@ -79,14 +79,9 @@ uInt8 CartridgeUA::peek(uInt16 address)
break;
}
- if(!(address & 0x1000))
- {
- return myHotSpotPageAccess.device->peek(address);
- }
- else
- {
- return 0;
- }
+ // Because of the way accessing is set up, we will only get here
+ // when doing a TIA read
+ return myHotSpotPageAccess.device->peek(address);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -111,10 +106,11 @@ bool CartridgeUA::poke(uInt16 address, uInt8 value)
break;
}
+ // Because of the way accessing is set up, we will may get here by
+ // doing a write to TIA or cart; we ignore the cart write
if(!(address & 0x1000))
- {
myHotSpotPageAccess.device->poke(address, value);
- }
+
return false;
}
@@ -124,19 +120,17 @@ bool CartridgeUA::bank(uInt16 bank)
if(bankLocked()) return false;
// Remember what bank we're in
- myCurrentBank = bank;
- uInt16 offset = myCurrentBank << 12;
+ myBankOffset = bank << 12;
// Setup the page access methods for the current bank
System::PageAccess access(this, System::PA_READ);
// Map ROM image into the system
- for(uInt32 address = 0x1000; address < 0x2000;
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
+ access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
@@ -144,7 +138,7 @@ bool CartridgeUA::bank(uInt16 bank)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeUA::getBank() const
{
- return myCurrentBank;
+ return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -156,12 +150,12 @@ uInt16 CartridgeUA::bankCount() const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeUA::patch(uInt16 address, uInt8 value)
{
- myImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value;
+ myImage[myBankOffset + (address & 0x0FFF)] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeUA::getImage(int& size) const
+const uInt8* CartridgeUA::getImage(uInt32& size) const
{
size = 8192;
return myImage;
@@ -173,7 +167,7 @@ bool CartridgeUA::save(Serializer& out) const
try
{
out.putString(name());
- out.putShort(myCurrentBank);
+ out.putShort(myBankOffset);
}
catch(...)
{
@@ -192,7 +186,7 @@ bool CartridgeUA::load(Serializer& in)
if(in.getString() != name())
return false;
- myCurrentBank = in.getShort();
+ myBankOffset = in.getShort();
}
catch(...)
{
@@ -201,7 +195,7 @@ bool CartridgeUA::load(Serializer& in)
}
// Remember what bank we were in
- bank(myCurrentBank);
+ bank(myBankOffset >> 12);
return true;
}
diff --git a/src/emucore/CartUA.hxx b/src/emucore/CartUA.hxx
index 0fea1969f..0ff1bfd26 100644
--- a/src/emucore/CartUA.hxx
+++ b/src/emucore/CartUA.hxx
@@ -28,7 +28,8 @@ class System;
/**
Cartridge class used for UA Limited's 8K bankswitched games. There
- are two 4K banks.
+ are two 4K banks, which are switched by accessing $0220 (bank 0) and
+ $0240 (bank 1).
@author Bradford W. Mott
*/
@@ -93,7 +94,7 @@ class CartridgeUA : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -154,8 +155,8 @@ class CartridgeUA : public Cartridge
// Previous Device's page access
System::PageAccess myHotSpotPageAccess;
- // Indicates which bank is currently active
- uInt16 myCurrentBank;
+ // Indicates the offset into the ROM image (aligns to current bank)
+ uInt16 myBankOffset;
private:
// Following constructors and assignment operators not supported
diff --git a/src/emucore/CartWD.cxx b/src/emucore/CartWD.cxx
index 08454a5a5..340000fc4 100644
--- a/src/emucore/CartWD.cxx
+++ b/src/emucore/CartWD.cxx
@@ -56,20 +56,20 @@ void CartridgeWD::install(System& system)
// Set the page accessing method for the RAM reading pages
System::PageAccess read(this, System::PA_READ);
- for(uInt32 k = 0x1000; k < 0x1040; k += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < 0x1040; addr += System::PAGE_SIZE)
{
- read.directPeekBase = &myRAM[k & 0x003F];
- read.codeAccessBase = &myCodeAccessBase[k & 0x003F];
- mySystem->setPageAccess(k >> System::PAGE_SHIFT, read);
+ read.directPeekBase = &myRAM[addr & 0x003F];
+ read.codeAccessBase = &myCodeAccessBase[addr & 0x003F];
+ mySystem->setPageAccess(addr, read);
}
// Set the page accessing method for the RAM writing pages
System::PageAccess write(this, System::PA_WRITE);
- for(uInt32 j = 0x1040; j < 0x1080; j += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1040; addr < 0x1080; addr += System::PAGE_SIZE)
{
- write.directPokeBase = &myRAM[j & 0x003F];
- write.codeAccessBase = &myCodeAccessBase[j & 0x003F];
- mySystem->setPageAccess(j >> System::PAGE_SHIFT, write);
+ write.directPokeBase = &myRAM[addr & 0x003F];
+ write.codeAccessBase = &myCodeAccessBase[addr & 0x003F];
+ mySystem->setPageAccess(addr, write);
}
// Mirror all access in TIA; by doing so we're taking responsibility
@@ -168,11 +168,10 @@ void CartridgeWD::segmentZero(uInt8 slice)
System::PageAccess access(this, System::PA_READ);
// Skip first 128 bytes; it is always RAM
- for(uInt32 address = 0x1080; address < 0x1400;
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1080; addr < 0x1400; addr += System::PAGE_SIZE)
{
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x03FF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)];
+ mySystem->setPageAccess(addr, access);
}
myOffset[0] = offset;
}
@@ -183,11 +182,10 @@ void CartridgeWD::segmentOne(uInt8 slice)
uInt16 offset = slice << 10;
System::PageAccess access(this, System::PA_READ);
- for(uInt32 address = 0x1400; address < 0x1800;
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE)
{
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x03FF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)];
+ mySystem->setPageAccess(addr, access);
}
myOffset[1] = offset;
}
@@ -198,11 +196,10 @@ void CartridgeWD::segmentTwo(uInt8 slice)
uInt16 offset = slice << 10;
System::PageAccess access(this, System::PA_READ);
- for(uInt32 address = 0x1800; address < 0x1C00;
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1800; addr < 0x1C00; addr += System::PAGE_SIZE)
{
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x03FF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)];
+ mySystem->setPageAccess(addr, access);
}
myOffset[2] = offset;
}
@@ -224,11 +221,10 @@ void CartridgeWD::segmentThree(uInt8 slice, bool map3bytes)
System::PageAccess access(this, System::PA_READ);
- for(uInt32 address = 0x1C00; address < 0x2000;
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1C00; addr < 0x2000; addr += System::PAGE_SIZE)
{
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x03FF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)];
+ mySystem->setPageAccess(addr, access);
}
myOffset[3] = offset;
}
@@ -261,7 +257,7 @@ bool CartridgeWD::patch(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeWD::getImage(int& size) const
+const uInt8* CartridgeWD::getImage(uInt32& size) const
{
size = mySize;
return myImage;
@@ -275,7 +271,7 @@ bool CartridgeWD::save(Serializer& out) const
out.putString(name());
out.putShort(myCurrentBank);
out.putByteArray(myRAM, 64);
- out.putInt(myCyclesAtBankswitchInit);
+ out.putLong(myCyclesAtBankswitchInit);
out.putShort(myPendingBank);
}
catch(...)
@@ -297,7 +293,7 @@ bool CartridgeWD::load(Serializer& in)
myCurrentBank = in.getShort();
in.getByteArray(myRAM, 64);
- myCyclesAtBankswitchInit = in.getInt();
+ myCyclesAtBankswitchInit = in.getLong();
myPendingBank = in.getShort();
bank(myCurrentBank);
diff --git a/src/emucore/CartWD.hxx b/src/emucore/CartWD.hxx
index aff9a3ee2..b40a9c287 100644
--- a/src/emucore/CartWD.hxx
+++ b/src/emucore/CartWD.hxx
@@ -122,7 +122,7 @@ class CartridgeWD : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
@@ -224,7 +224,7 @@ class CartridgeWD : public Cartridge
uInt16 myOffset[4];
// Indicates the cycle at which a bankswitch was initiated
- uInt32 myCyclesAtBankswitchInit;
+ uInt64 myCyclesAtBankswitchInit;
// Indicates the bank we wish to switch to in the future
uInt16 myPendingBank;
diff --git a/src/emucore/CartX07.cxx b/src/emucore/CartX07.cxx
index 6ffe4138a..3716092e3 100644
--- a/src/emucore/CartX07.cxx
+++ b/src/emucore/CartX07.cxx
@@ -50,8 +50,8 @@ void CartridgeX07::install(System& system)
// The hotspots use almost all addresses below 0x1000, so we simply grab them
// all and forward the TIA/RIOT calls from the peek and poke methods.
System::PageAccess access(this, System::PA_READWRITE);
- for(uInt32 i = 0x00; i < 0x1000; i += (1 << System::PAGE_SHIFT))
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ for(uInt16 addr = 0x00; addr < 0x1000; addr += System::PAGE_SIZE)
+ mySystem->setPageAccess(addr, access);
// Install pages for the startup bank
bank(myStartBank);
@@ -115,12 +115,11 @@ bool CartridgeX07::bank(uInt16 bank)
System::PageAccess access(this, System::PA_READ);
// Map ROM image into the system
- for(uInt32 address = 0x1000; address < 0x2000;
- address += (1 << System::PAGE_SHIFT))
+ for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE)
{
- access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
- access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ access.directPeekBase = &myImage[offset + (addr & 0x0FFF)];
+ access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x0FFF)];
+ mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
@@ -145,7 +144,7 @@ bool CartridgeX07::patch(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const uInt8* CartridgeX07::getImage(int& size) const
+const uInt8* CartridgeX07::getImage(uInt32& size) const
{
size = 65536;
return myImage;
diff --git a/src/emucore/CartX07.hxx b/src/emucore/CartX07.hxx
index c3f2d8e7b..7d6d63cbc 100644
--- a/src/emucore/CartX07.hxx
+++ b/src/emucore/CartX07.hxx
@@ -103,7 +103,7 @@ class CartridgeX07 : public Cartridge
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
- const uInt8* getImage(int& size) const override;
+ const uInt8* getImage(uInt32& size) const override;
/**
Save the current state of this cart to the given Serializer.
diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx
index d08a996d6..bb3968e8c 100644
--- a/src/emucore/Console.cxx
+++ b/src/emucore/Console.cxx
@@ -183,18 +183,13 @@ Console::Console(OSystem& osystem, unique_ptr& cart,
myConsoleTiming = ConsoleTiming::secam;
}
- // Bumper Bash and Decathlon always require all 4 directions
+ // Bumper Bash always require all 4 directions
// Other ROMs can use it if the setting is enabled
// Hopefully this list should stay short
// If it starts to get too long, we should add a ROM properties entry
bool joyallow4 = md5 == "aa1c41f86ec44c0a44eb64c332ce08af" || // Bumper Bash
md5 == "16ee443c990215f61f7dd1e55a0d2256" || // Bumper Bash (PAL)
md5 == "1bf503c724001b09be79c515ecfcbd03" || // Bumper Bash (Unknown)
- md5 == "ac7c2260378975614192ca2bc3d20e0b" || // Decathlon
- md5 == "883258dcd68cefc6cd4d40b1185116dc" || // Decathlon (PAL)
- md5 == "ede4ab11ca346bd023b2c21d941e0c50" || // Decathlon (SECAM)
- md5 == "525f2dfc8b21b0186cff2568e0509bfc" || // Decathlon [fixed]
- md5 == "bf52327c2197d9d2c4544be053caded1" || // Decathlon (HES)
myOSystem.settings().getBool("joyallow4");
myOSystem.eventHandler().allowAllDirections(joyallow4);
@@ -429,32 +424,26 @@ void Console::setPalette(const string& type)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Console::togglePhosphor()
{
- const string& phosphor = myProperties.get(Display_Phosphor);
- int blend = atoi(myProperties.get(Display_PPBlend).c_str());
- bool enable;
- if(phosphor == "YES")
+ if(myOSystem.frameBuffer().tiaSurface().phosphorEnabled())
{
myProperties.set(Display_Phosphor, "No");
- enable = false;
+ myOSystem.frameBuffer().tiaSurface().enablePhosphor(false);
myOSystem.frameBuffer().showMessage("Phosphor effect disabled");
}
else
{
myProperties.set(Display_Phosphor, "Yes");
- enable = true;
+ myOSystem.frameBuffer().tiaSurface().enablePhosphor(true);
myOSystem.frameBuffer().showMessage("Phosphor effect enabled");
}
-
- myOSystem.frameBuffer().tiaSurface().enablePhosphor(enable, blend);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Console::changePhosphor(int direction)
{
- bool enable = myProperties.get(Display_Phosphor) == "YES";
int blend = atoi(myProperties.get(Display_PPBlend).c_str());
- if(enable)
+ if(myOSystem.frameBuffer().tiaSurface().phosphorEnabled())
{
if(direction == +1) // increase blend
{
@@ -483,7 +472,7 @@ void Console::changePhosphor(int direction)
val << blend;
myProperties.set(Display_PPBlend, val.str());
myOSystem.frameBuffer().showMessage("Phosphor blend " + val.str());
- myOSystem.frameBuffer().tiaSurface().enablePhosphor(enable, blend);
+ myOSystem.frameBuffer().tiaSurface().enablePhosphor(true, blend);
}
else
myOSystem.frameBuffer().showMessage("Phosphor effect disabled");
diff --git a/src/emucore/Control.hxx b/src/emucore/Control.hxx
index 86112e261..418a56227 100644
--- a/src/emucore/Control.hxx
+++ b/src/emucore/Control.hxx
@@ -171,6 +171,13 @@ class Controller : public Serializable
*/
virtual void update() = 0;
+ /**
+ Notification method invoked by the system after its reset method has
+ been called. It may be necessary to override this method for
+ controllers that need to know a reset has occurred.
+ */
+ virtual void reset() { }
+
/**
Notification method invoked by the system indicating that the
console is about to be destroyed. It may be necessary to override
@@ -178,13 +185,6 @@ class Controller : public Serializable
*/
virtual void close() { };
- /**
- Notification method invoked by the system right before the
- system resets its cycle counter to zero. It may be necessary
- to override this method for controllers that remember cycle counts.
- */
- virtual void systemCyclesReset() { }
-
/**
Determines how this controller will treat values received from the
X/Y axis and left/right buttons of the mouse. Since not all controllers
diff --git a/src/emucore/DefProps.hxx b/src/emucore/DefProps.hxx
index 1c44fae4c..6b3524fd6 100644
--- a/src/emucore/DefProps.hxx
+++ b/src/emucore/DefProps.hxx
@@ -25,7 +25,7 @@
regenerated and the application recompiled.
*/
-#define DEF_PROPS_SIZE 3299
+#define DEF_PROPS_SIZE 3303
static const char* const DefProps[DEF_PROPS_SIZE][21] = {
{ "000509d1ed2b8d30a9d94be1b3b5febb", "Greg Zumwalt", "", "Jungle Jane (2003) (Greg Zumwalt) (Hack)", "Hack of Pitfall!", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
@@ -69,7 +69,7 @@ static const char* const DefProps[DEF_PROPS_SIZE][21] = {
{ "033e21521e0bf4e54e8816873943406d", "20th Century Fox Video Games, Dan Thompson", "11020", "Earth Dies Screaming, The (1983) (20th Century Fox)", "The Day the Earth Stood Still", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "034c1434280b0f2c9f229777d790d1e1", "Telegames", "5665 A016", "Baseball (1988) (Telegames) (PAL)", "AKA Super Challenge Baseball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "0375f589f7da06d2d2be532e0d4d4b94", "", "", "Push (V0.04) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
- { "0383dc02cb82302da3d155fd108bfe3a", "AtariAge, Chris Spry", "26200", "Princess Rescue (2013) (Sprybug) (PAL60)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "YES", "" },
+ { "0383dc02cb82302da3d155fd108bfe3a", "AtariAge, Chris Spry", "CX26200", "Princess Rescue (2013) (Sprybug) (PAL60)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "YES", "" },
{ "038e1e79c3d4410defde4bfe0b99cc32", "Atari, Tod Frye, Gary Shannon", "", "Aquaventure (08-12-1983) (Atari) (Prototype)", "AKA Sea Sentinel", "Unbelievably Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "039cf18b459d33b8a8fca31d06c4c244", "", "", "Demo Image Series #0 (12-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "03b1051c9374678363c899914412cfc5", "", "", "Incoming (30-10-2002) (Ben Larson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
@@ -241,7 +241,7 @@ static const char* const DefProps[DEF_PROPS_SIZE][21] = {
{ "103d4c890c2108cb536372c98d093e5f", "", "", "Star Fire - Star Background (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "103e9d616328969f5d7b4e0a381b25d5", "", "", "Playfield Illustration and Logo Demo (2001) (Jake Patterson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "103f1756d9dc0dd2b16b53ad0f0f1859", "Home Vision, Gem International Corp.", "", "Go Go Home Monster (1983) (Home Vision) (PAL)", "AKA Go Go Home", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
- { "104468e44898b8e9fa4a1500fde8d4cb", "AtariAge, Chris Spry", "26200", "Princess Rescue (2013) (Sprybug)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" },
+ { "104468e44898b8e9fa4a1500fde8d4cb", "AtariAge, Chris Spry", "CX26200", "Princess Rescue (2013) (Sprybug)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" },
{ "106326c262dfd3e8eaeabd961d2a0519", "", "", "PAL-NTSC Detector (15-11-2002) (CT)[a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "106855474c69d08c8ffa308d47337269", "Atari, Adam Clayton, John Howard Palevich", "CX26151", "Dark Chambers (1988) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" },
{ "107cc025334211e6d29da0b6be46aec7", "Atari, Bob Smith - Sears", "CX2648 - 49-75161", "Video Pinball (1981) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
@@ -472,6 +472,7 @@ static const char* const DefProps[DEF_PROPS_SIZE][21] = {
{ "2319922df4d0c820b3e5f15faa870cc3", "Atari - GCC, Mike Feinstein", "CX2681, CX2681P", "Battlezone (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "2327456f86d7e0deda94758c518d05b3", "Digitel", "", "Mr. Postman (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "2351d26d0bfdee3095bec9c05cbcf7b0", "", "", "Warring Worms (19-01-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
+ { "2353725ec98e0f0073462109e886efd7", "Champ Games", "CG-03-P", "Scramble (PAL60)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "YES", "" },
{ "235436ab0832370e73677c9c6f0c8b06", "", "", "Beast Invaders (Double Shot) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "2365e1534d67f94d8670394ab99150ce", "Thomas Jentzsch", "", "Missile Command (Atari Mouse) (2002) (TJ)", "Uses Atari ST Mouse Controller", "Homebrew", "", "", "", "", "", "", "ATARIMOUSE", "", "", "", "", "", "", "YES", "" },
{ "23d445ea19a18fb78d5035878d9fb649", "CBS Electronics, Sylvia Day, Henry Will IV", "4L1818, 4L1819, 4L1820, 4L1821", "Mouse Trap (1982) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" },
@@ -928,6 +929,7 @@ static const char* const DefProps[DEF_PROPS_SIZE][21] = {
{ "4543b7691914dfd69c3755a5287a95e1", "CommaVid, Irwin Gaines", "CM-005", "Mines of Minos (1982) (CommaVid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" },
{ "456453a54ca65191781aef316343ae00", "", "", "Full Screen Bitmap (3-D Green) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "4565c1a7abce773e53c75b35414adefd", "Arcadia Corporation", "", "Supercharger BIOS (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
+ { "457b03cd48ff6d895795ef043c6b0f1e", "AtariAge, Chris Spry", "CX26201", "Zippy the Porcupine (2014) (Sprybug)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "457e7d4fcd56ebc47f5925dbea3ee427", "Carrere Video, Garry Kitchen - Teldec", "USC1001", "Space Jockey (1983) (Carrere Video) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "457f4ad2cda5f4803f122508bfbde3f5", "", "", "Canyon Bomber (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "458883f1d952cd772cf0057abca57497", "", "", "Fishing Derby (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
@@ -1774,7 +1776,7 @@ static const char* const DefProps[DEF_PROPS_SIZE][21] = {
{ "855a42078b14714bcfd490d2cf57e68d", "Atari, Suki Lee", "CX26113", "Miss Piggy's Wedding (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "24", "", "", "" },
{ "85a4133f6dcf4180e36e70ad0fca0921", "CCE", "C-827", "Chopper Command (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "85b1bca93e69f13905107cc802a02470", "Atari, Craig Nelson", "CX2617, CX2617P", "Backgammon (1979) (Atari) (PAL)", "Uses the Paddle Controllers", "Extremely Rare", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "AUTO 80", "", "", "", "", "" },
- { "85bbefb90e16bf386b304c1e9a1f6084", "Champ Games", "", "Conquest Of Mars (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "", "" },
+ { "85bbefb90e16bf386b304c1e9a1f6084", "Champ Games", "CG-02-P", "Conquest Of Mars (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "", "" },
{ "85e48d68c8d802e3ba9d494a47d6e016", "", "", "Ship Demo (V 15) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "85e564dae5687e431955056fbda10978", "Milton Bradley Company", "4362", "Survival Run (1983) (Milton Bradley)", "AKA Cosmic Commander", "", "", "", "", "", "", "", "", "", "", "", "", "", "225", "YES", "" },
{ "86128001e69ab049937f265911ce7e8a", "Apollo - Games by Apollo, Steve Stringfellow", "AP-2005", "Lochjaw (1981) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
@@ -2199,6 +2201,7 @@ static const char* const DefProps[DEF_PROPS_SIZE][21] = {
{ "a98b649912b6ca19eaf5c2d2faf38562", "", "", "This Planet Sucks (Greg Troutman) (PAL) [!]", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "36", "", "", "" },
{ "a995b6cbdb1f0433abc74050808590e6", "Imagic, Rob Fulop, Bob Smith", "720106-1A, IA3600", "Riddle of the Sphinx (1982) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "a9cb638cd2cb2e8e0643d7a67db4281c", "M Network, Larry Zwick - INTV", "MT5861", "Air Raiders (1982) (M Network)", "AKA Air Battle", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
+ { "a9d9e19d0c89fb31780b5d63e1f8c6a4", "AtariAge, Chris Spry", "CX26201", "Zippy the Porcupine (2014) (Sprybug) (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "", "" },
{ "a9e3c23599c0d77151602f8e31daf879", "", "", "Kung Fu Master (Genesis)", "Genesis controller (C is extra kick modes)", "Hack of Kung Fu Master", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "" },
{ "aa1c41f86ec44c0a44eb64c332ce08af", "Spectravideo, David Lubar", "SA-218", "Bumper Bash (1983) (Spectravideo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "20", "", "", "" },
{ "aa2c4b32656bde9a75042a4d158583e1", "", "", "Oystron X (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
@@ -2244,7 +2247,7 @@ static const char* const DefProps[DEF_PROPS_SIZE][21] = {
{ "adb770ff70e9adf08bbb907a7eccd240", "", "", "Inv Demo 3 (2001) (Erik Mooney) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "adb79f9ac1a633cdd44954e2eac14774", "Digivision", "", "Frostbite (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "adf1afac3bdd7b36d2eda5949f1a0fa3", "Quelle", "495.463 2 - 746381", "Angriff der Luftflotten (1983) (Quelle) (PAL)", "AKA Paris Attack, M.A.D.", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
- { "adfbd2e8a38f96e03751717f7422851d", "Champ Games", "", "Lady Bug (NTSC)", "", "Homebrew", "", "", "", "A", "", "", "", "", "", "", "", "", "", "YES", "" },
+ { "adfbd2e8a38f96e03751717f7422851d", "Champ Games", "CG-01-N", "Lady Bug (NTSC)", "", "Homebrew", "", "", "", "A", "", "", "", "", "", "", "", "", "", "YES", "" },
{ "ae047e9468bda961d8e9e9d8ff52980f", "", "", "Tunnel Demo (Red Spiral) (30-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "ae0d4f3396cb49de0fabdff03cb2756f", "Retroactive", "", "Qb (V2.02) (PAL) (2001) (Retroactive)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" },
{ "ae10527840a1ac24de43730645ed508d", "Charles Morgan", "", "Planet Invaders (Charles Morgan) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
@@ -2373,7 +2376,7 @@ static const char* const DefProps[DEF_PROPS_SIZE][21] = {
{ "b9336ed6d94a5cc81a16483b0a946a73", "Atari, Jerome Domurat, Michael Sierchio", "CX2667, CX2667P", "RealSports Soccer (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" },
{ "b958d5fd9574c5cf9ece4b9421c28ecd", "Piero Cavina", "", "Multi-Sprite Game V1.0 (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "b95a6274ca0e0c773bfdc06b4c3daa42", "Paul Slocum", "", "3-D Corridor (29-03-2003) (Paul Slocum)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
- { "b98cc2c6f7a0f05176f74f0f62c45488", "Spectravideo", "SV-010", "CompuMate (1983) (Spectravideo)", "", "", "", "CM", "", "", "", "", "COMPUMATE", "COMPUMATE", "", "", "", "", "", "YES", "60" },
+ { "b98cc2c6f7a0f05176f74f0f62c45488", "Spectravideo", "SV-010", "CompuMate (1983) (Spectravideo)", "", "", "", "CM", "", "", "", "", "COMPUMATE", "COMPUMATE", "", "", "", "", "", "YES", "80" },
{ "b9b4612358a0b2c1b4d66bb146767306", "Commavid, Ben Burch", "CM-010", "Rush Hour (1983) (Commavid) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "23", "245", "", "" },
{ "b9d1e3be30b131324482345959aed5e5", "Activision, Rex Bradford", "", "Kabobber (07-25-1983) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "b9f6fa399b8cd386c235983ec45e4355", "Parker Brothers, John Emerson", "931511", "Action Force (1983) (Parker Bros) (PAL)", "AKA G.I. Joe - Cobra Strike", "", "", "", "", "", "", "", "PADDLES", "", "", "01 55", "", "", "", "", "" },
@@ -2479,7 +2482,7 @@ static const char* const DefProps[DEF_PROPS_SIZE][21] = {
{ "c2b5c50ccb59816867036d7cf730bf75", "Salu - Avantgarde Software, Michael Buetepage", "460741", "Ghostbusters II (1992) (Salu) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" },
{ "c2bcd8f2378c3779067f3a551f662bb7", "Activision, Bob Whitehead - Ariola", "EAG-002, EAG-002-04I, PAG-002 - 711 002-715", "Boxing (1980) (Activision) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "c2c7a11717e255593e54d0acaf653ee5", "", "", "Chopper Command (208 in 1) (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
- { "c2fbef02b6eea37d8df3e91107f89950", "Champ Games", "", "Conquest Of Mars (NTSC)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
+ { "c2fbef02b6eea37d8df3e91107f89950", "Champ Games", "CG-02-N", "Conquest Of Mars (NTSC)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "c31a17942d162b80962cb1f7571cd1d5", "Home Vision - Gem International Corp.", "VCS83112", "Sky Alien (1983) (Home Vision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "c3205e3707f646e1a106e09c5c49c1bf", "", "", "Unknown Title (bin00003 (200206)) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "c3472fa98c3b452fa2fd37d1c219fb6f", "Atari, Carla Meninsky - Sears", "CX2637 - 49-75158", "Dodge 'Em (1980) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
@@ -2991,7 +2994,7 @@ static const char* const DefProps[DEF_PROPS_SIZE][21] = {
{ "e7864caaf9ec49ed67b1904ce8602690", "", "", "Donkey Kong 2K3 Pic (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "e7a758bb0b43d0f7004e92b9abf4bc83", "", "", "Troll's Adventure (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "e7dd8c2e6c100044002c1086d02b366e", "Activision, Steve Cartwright - Ariola", "EAX-013, PAX-013, 711 013-720", "Barnstorming (1982) (Activision) (PAL)", "AKA Die tollkeuhnen Flieger", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
- { "e7f005ddb6902c648de098511f6ae2e5", "Spectravideo - Universum", "SV-010", "CompuMate (1983) (Spectravideo) (PAL)", "", "", "", "CM", "", "", "", "", "COMPUMATE", "COMPUMATE", "", "", "", "", "", "YES", "60" },
+ { "e7f005ddb6902c648de098511f6ae2e5", "Spectravideo - Universum", "SV-010", "CompuMate (1983) (Spectravideo) (PAL)", "", "", "", "CM", "", "", "", "", "COMPUMATE", "COMPUMATE", "", "", "", "", "", "YES", "80" },
{ "e800e4aec7c6c54c9cf3db0d1d030058", "", "", "Qb (2.06) (Retroactive) (Stella)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" },
{ "e80a4026d29777c3c7993fbfaee8920f", "", "", "Frisco (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "e823b13751e4388f1f2a375d3560a8d7", "Arcadia Corporation, Stephen Harland Landrum", "AR-4105", "Official Frogger (Preview) (1983) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "32", "", "", "" },
@@ -3017,6 +3020,7 @@ static const char* const DefProps[DEF_PROPS_SIZE][21] = {
{ "e9cb18770a41a16de63b124c1e8bd493", "Parker Brothers, Joe Gaucher", "931519", "Popeye (1983) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" },
{ "e9e646f730b8400cd5da08c849ef3e3b", "Tron", "", "Enduro (Tron)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "e9e6ad30549a6e2cd89fe93b7691d447", "Atari, Robert C. Polaro", "CX26140, CX26140P", "Desert Falcon (05-27-1987) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
+ { "e9f25c7af4f27c9e1b5b8f6fe6141e8c", "Champ Games", "CG-03-N", "Scramble (NTSC)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" },
{ "ea38fcfc06ad87a0aed1a3d1588744e4", "Atari, Lou Harp", "CX26122", "Sinistar (1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "ea6d40db5498d6386571a76df448aa4c", "", "", "Vertical Playfield Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "ea7e25ade3fe68f5b786ee0aa82b1fe5", "", "", "Galatic (208 in 1) (Unknown) (PAL)", "AKA Challenge of.... Nexar, The", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
@@ -3114,7 +3118,7 @@ static const char* const DefProps[DEF_PROPS_SIZE][21] = {
{ "f11cfab087fcbd930ab8b0becc5b2e5a", "Canal 3 - Intellivision", "", "River Raid (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "f12afbffa080dd3b2801dd14d4837cf6", "Atari, Michael Kosaka, Peter C. Niday, Robert Vieira", "CX26110", "Crystal Castles (01-04-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" },
{ "f137211537438b1fce3d811baef25457", "", "", "Incoming (02-10-2002) (Ben Larson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
- { "f1489e27a4539a0c6c8529262f9f7e18", "Champ Games", "", "Lady Bug (PAL60)", "", "Homebrew", "", "", "", "A", "", "", "", "", "", "", "PAL60", "", "", "YES", "" },
+ { "f1489e27a4539a0c6c8529262f9f7e18", "Champ Games", "CG-01-P", "Lady Bug (PAL60)", "", "Homebrew", "", "", "", "A", "", "", "", "", "", "", "PAL60", "", "", "YES", "" },
{ "f14d5e96ec3380aef57a4b70132c6677", "Goliath - Hot Shot", "83-414", "Pac Kong (1983) (Goliath) (PAL)", "AKA Inca Gold", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "f1554569321dc933c87981cf5c239c43", "Atari, Glenn Axworthy", "CX26129", "Midnight Magic (1984) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" },
{ "f16c709df0a6c52f47ff52b9d95b7d8d", "Atari, Alan Miller - Sears", "CX2662 - 6-99811", "Hangman (1978) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
diff --git a/src/emucore/Device.hxx b/src/emucore/Device.hxx
index 817cb9ef7..68c4fe802 100644
--- a/src/emucore/Device.hxx
+++ b/src/emucore/Device.hxx
@@ -55,13 +55,6 @@ class Device : public Serializable
*/
virtual void consoleChanged(ConsoleTiming timing) { }
- /**
- Notification method invoked by the system right before the
- system resets its cycle counter to zero. It may be necessary
- to override this method for devices that remember cycle counts.
- */
- virtual void systemCyclesReset() { }
-
/**
Install device in the specified system. Invoked by the system
when the device is attached to it.
@@ -99,7 +92,7 @@ class Device : public Serializable
@return The byte at the specified address
*/
- virtual uInt8 peek(uInt16 address) = 0;
+ virtual uInt8 peek(uInt16 address) { return 0; }
/**
Change the byte at the specified address to the given value
@@ -109,7 +102,7 @@ class Device : public Serializable
@return True if the poke changed the device address space, else false
*/
- virtual bool poke(uInt16 address, uInt8 value) = 0;
+ virtual bool poke(uInt16 address, uInt8 value) { return false; }
/**
Query the given address for its disassembly flags
diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx
index e41f32671..75bc58e19 100644
--- a/src/emucore/EventHandler.cxx
+++ b/src/emucore/EventHandler.cxx
@@ -32,6 +32,7 @@
#include "OSystem.hxx"
#include "Joystick.hxx"
#include "Paddles.hxx"
+#include "PointingDevice.hxx"
#include "PropsSet.hxx"
#include "ListWidget.hxx"
#include "ScrollBarWidget.hxx"
@@ -62,6 +63,7 @@ EventHandler::EventHandler(OSystem& osystem)
myFryingFlag(false),
myUseCtrlKeyFlag(true),
mySkipMouseMotion(true),
+ myAltKeyCounter(0),
myContSnapshotInterval(0),
myContSnapshotCounter(0)
{
@@ -94,6 +96,7 @@ void EventHandler::initialize()
Joystick::setDeadZone(myOSystem.settings().getInt("joydeadzone"));
Paddles::setDigitalSensitivity(myOSystem.settings().getInt("dsense"));
Paddles::setMouseSensitivity(myOSystem.settings().getInt("msense"));
+ PointingDevice::setSensitivity(myOSystem.settings().getInt("tsense"));
// Set quick select delay when typing characters in listwidgets
ListWidget::setQuickSelectDelay(myOSystem.settings().getInt("listdelay"));
@@ -116,12 +119,6 @@ void EventHandler::reset(State state)
myOSystem.state().reset();
setContinuousSnapshots(0);
-
- // Reset events almost immediately after starting emulation mode
- // We wait a little while, since 'hold' events may be present, and we want
- // time for the ROM to process them
- if(state == S_EMULATE)
- SDL_AddTimer(500, resetEventsCallback, static_cast(this));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -200,27 +197,20 @@ void EventHandler::poll(uInt64 time)
{
myOSystem.console().riot().update();
-#if 0
// Now check if the StateManager should be saving or loading state
- // Per-frame cheats are disabled if the StateManager is active, since
- // it would interfere with proper playback
- if(myOSystem.state().isActive())
- {
+ // (for rewind and/or movies
+ if(myOSystem.state().mode() != StateManager::Mode::Off)
myOSystem.state().update();
- }
- else
-#endif
- {
- #ifdef CHEATCODE_SUPPORT
- for(auto& cheat: myOSystem.cheat().perFrame())
- cheat->evaluate();
- #endif
- // Handle continuous snapshots
- if(myContSnapshotInterval > 0 &&
- (++myContSnapshotCounter % myContSnapshotInterval == 0))
- takeSnapshot(uInt32(time) >> 10); // not quite milliseconds, but close enough
- }
+ #ifdef CHEATCODE_SUPPORT
+ for(auto& cheat: myOSystem.cheat().perFrame())
+ cheat->evaluate();
+ #endif
+
+ // Handle continuous snapshots
+ if(myContSnapshotInterval > 0 &&
+ (++myContSnapshotCounter % myContSnapshotInterval == 0))
+ takeSnapshot(uInt32(time) >> 10); // not quite milliseconds, but close enough
}
else if(myOverlay)
{
@@ -246,6 +236,16 @@ void EventHandler::handleTextEvent(char text)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::handleKeyEvent(StellaKey key, StellaMod mod, bool state)
{
+ // Swallow KBDK_TAB under certain conditions
+ // See commments on 'myAltKeyCounter' for more information
+#ifdef BSPF_UNIX
+ if(myAltKeyCounter > 1 && key == KBDK_TAB)
+ {
+ myAltKeyCounter = false;
+ return;
+ }
+#endif
+
bool handled = true;
// Immediately store the key state
@@ -263,7 +263,13 @@ void EventHandler::handleKeyEvent(StellaKey key, StellaMod mod, bool state)
}
else
#endif
- if(key == KBDK_RETURN)
+ if(key == KBDK_TAB)
+ {
+ // Swallow Alt-Tab, but remember that it happened
+ myAltKeyCounter = 1;
+ return;
+ }
+ else if(key == KBDK_RETURN)
{
myOSystem.frameBuffer().toggleFullscreen();
}
@@ -428,6 +434,10 @@ void EventHandler::handleKeyEvent(StellaKey key, StellaMod mod, bool state)
myOSystem.frameBuffer().toggleFrameStats();
break;
+ case KBDK_R: // Alt-r toggles continuous store rewind states
+ myOSystem.state().toggleRewindMode();
+ break;
+
case KBDK_S:
if(myContSnapshotInterval == 0)
{
@@ -823,11 +833,18 @@ void EventHandler::handleSystemEvent(SystemEvent e, int, int)
switch(e)
{
case EVENT_WINDOW_EXPOSED:
- myOSystem.frameBuffer().update();
- break;
+ myOSystem.frameBuffer().update();
+ break;
+
+ case EVENT_WINDOW_FOCUS_GAINED:
+ // Used to handle Alt-x key combos; sometimes the key associated with
+ // Alt gets 'stuck' and is passed to the core for processing
+ if(myAltKeyCounter > 0)
+ myAltKeyCounter = 2;
+ break;
#if 0
case EVENT_WINDOW_MINIMIZED:
- if(myState == S_EMULATE) enterMenuMode(S_MENU);
+ if(myState == S_EMULATE) enterMenuMode(S_MENU);
break;
#endif
default: // handle other events as testing requires
@@ -1074,6 +1091,56 @@ void EventHandler::handleEvent(Event::Type event, int state)
myEvent.set(event, state);
}
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void EventHandler::handleConsoleStartupEvents()
+{
+ bool update = false;
+ if(myOSystem.settings().getBool("holdreset"))
+ {
+ handleEvent(Event::ConsoleReset, 1);
+ update = true;
+ }
+ if(myOSystem.settings().getBool("holdselect"))
+ {
+ handleEvent(Event::ConsoleSelect, 1);
+ update = true;
+ }
+
+ const string& holdjoy0 = myOSystem.settings().getString("holdjoy0");
+ update = update || holdjoy0 != "";
+ if(BSPF::containsIgnoreCase(holdjoy0, "U"))
+ handleEvent(Event::JoystickZeroUp, 1);
+ if(BSPF::containsIgnoreCase(holdjoy0, "D"))
+ handleEvent(Event::JoystickZeroDown, 1);
+ if(BSPF::containsIgnoreCase(holdjoy0, "L"))
+ handleEvent(Event::JoystickZeroLeft, 1);
+ if(BSPF::containsIgnoreCase(holdjoy0, "R"))
+ handleEvent(Event::JoystickZeroRight, 1);
+ if(BSPF::containsIgnoreCase(holdjoy0, "F"))
+ handleEvent(Event::JoystickZeroFire, 1);
+
+ const string& holdjoy1 = myOSystem.settings().getString("holdjoy1");
+ update = update || holdjoy1 != "";
+ if(BSPF::containsIgnoreCase(holdjoy1, "U"))
+ handleEvent(Event::JoystickOneUp, 1);
+ if(BSPF::containsIgnoreCase(holdjoy1, "D"))
+ handleEvent(Event::JoystickOneDown, 1);
+ if(BSPF::containsIgnoreCase(holdjoy1, "L"))
+ handleEvent(Event::JoystickOneLeft, 1);
+ if(BSPF::containsIgnoreCase(holdjoy1, "R"))
+ handleEvent(Event::JoystickOneRight, 1);
+ if(BSPF::containsIgnoreCase(holdjoy1, "F"))
+ handleEvent(Event::JoystickOneFire, 1);
+
+ if(update)
+ myOSystem.console().riot().update();
+
+#ifdef DEBUGGER_SUPPORT
+ if(myOSystem.settings().getBool("debug"))
+ enterDebugMode();
+#endif
+}
+
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool EventHandler::eventStateChange(Event::Type type)
{
@@ -1861,7 +1928,7 @@ void EventHandler::takeSnapshot(uInt32 number)
{
// Make sure we have a 'clean' image, with no onscreen messages
myOSystem.frameBuffer().enableMessages(false);
- myOSystem.frameBuffer().tiaSurface().render();
+ myOSystem.frameBuffer().tiaSurface().reRender();
string message = "Snapshot saved";
try
@@ -2038,6 +2105,7 @@ void EventHandler::setEventState(State state)
case S_LAUNCHER:
myOverlay = &myOSystem.launcher();
enableTextEvents(true);
+ myEvent.clear();
break;
#ifdef DEBUGGER_SUPPORT
@@ -2059,21 +2127,11 @@ void EventHandler::setEventState(State state)
if(myOSystem.hasConsole())
myOSystem.console().stateChanged(myState);
- // Always clear any pending events when changing states
- myEvent.clear();
-
// Sometimes an extraneous mouse motion event is generated
// after a state change, which should be supressed
mySkipMouseMotion = true;
}
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-uInt32 EventHandler::resetEventsCallback(uInt32 interval, void* param)
-{
- (static_cast(param))->myEvent.clear();
- return 0;
-}
-
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EventHandler::ActionList EventHandler::ourEmulActionList[kEmulActionListSize] = {
{ Event::ConsoleSelect, "Select", "", true },
diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx
index d6dc58b5e..d31c67ffd 100644
--- a/src/emucore/EventHandler.hxx
+++ b/src/emucore/EventHandler.hxx
@@ -167,10 +167,10 @@ class EventHandler
inline bool kbdAlt(int mod) const
{
- #ifndef BSPF_MAC_OSX
- return (mod & KBDM_ALT);
- #else
+ #if defined(BSPF_MAC_OSX) || defined(OSX_KEYS)
return (mod & KBDM_GUI);
+ #else
+ return (mod & KBDM_ALT);
#endif
}
@@ -199,6 +199,12 @@ class EventHandler
*/
void handleEvent(Event::Type type, Int32 value);
+ /**
+ Handle events that must be processed each time a new console is
+ created. Typically, these are events set by commandline arguments.
+ */
+ void handleConsoleStartupEvents();
+
bool frying() const { return myFryingFlag; }
StringList getActionList(EventMode mode) const;
@@ -536,9 +542,6 @@ class EventHandler
void setEventState(State state);
- // Callback function invoked by the event-reset timer
- static uInt32 resetEventsCallback(uInt32 interval, void* param);
-
private:
// Structure used for action menu items
struct ActionList {
@@ -583,6 +586,19 @@ class EventHandler
// state change; we detect when this happens and discard the event
bool mySkipMouseMotion;
+ // Sometimes key combos with the Alt key become 'stuck' after the
+ // window changes state, and we want to ignore that event
+ // For example, press Alt-Tab and then upon re-entering the window,
+ // the app receives 'tab'; obviously the 'tab' shouldn't be happening
+ // So we keep track of the cases that matter (for now, Alt-Tab)
+ // and swallow the event afterwards
+ // Basically, the initial event sets the variable to 1, and upon
+ // returning to the app (ie, receiving EVENT_WINDOW_FOCUS_GAINED),
+ // the count is updated to 2, but only if it was already updated to 1
+ // TODO - This may be a bug in SDL, and might be removed in the future
+ // It only seems to be an issue in Linux
+ uInt8 myAltKeyCounter;
+
// Used for continuous snapshot mode
uInt32 myContSnapshotInterval;
uInt32 myContSnapshotCounter;
diff --git a/src/emucore/FSNode.hxx b/src/emucore/FSNode.hxx
index 04c10b813..6c1ec0f2d 100644
--- a/src/emucore/FSNode.hxx
+++ b/src/emucore/FSNode.hxx
@@ -120,6 +120,15 @@ class FilesystemNode
return BSPF::compareIgnoreCase(getName(), node.getName()) == 0;
}
+ /**
+ * By default, the output operator simply outputs the fully-qualified
+ * pathname of the node.
+ */
+ friend ostream& operator<<(ostream& os, const FilesystemNode& node)
+ {
+ return os << node.getPath();
+ }
+
/**
* Indicates whether the object referred by this path exists in the
* filesystem or not.
diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx
index d4ce3b0fe..eeca3ab9d 100644
--- a/src/emucore/FrameBuffer.cxx
+++ b/src/emucore/FrameBuffer.cxx
@@ -588,8 +588,9 @@ void FrameBuffer::setCursorState()
bool analog = myOSystem.hasConsole() ?
(myOSystem.eventHandler().controllerIsAnalog(Controller::Left) ||
myOSystem.eventHandler().controllerIsAnalog(Controller::Right)) : false;
+ bool alwaysUseMouse = BSPF::equalsIgnoreCase("always", myOSystem.settings().getString("usemouse"));
- grabMouse(emulation && analog && myOSystem.settings().getBool("grabmouse"));
+ grabMouse(emulation && (analog || alwaysUseMouse) && myOSystem.settings().getBool("grabmouse"));
// Show/hide cursor in UI/emulation mode based on 'cursor' setting
switch(myOSystem.settings().getInt("cursor"))
diff --git a/src/emucore/Genesis.cxx b/src/emucore/Genesis.cxx
index d7e1cd22f..16547df3c 100644
--- a/src/emucore/Genesis.cxx
+++ b/src/emucore/Genesis.cxx
@@ -41,6 +41,8 @@ Genesis::Genesis(Jack jack, const Event& event, const System& system)
myFire1Event = Event::JoystickOneFire;
myFire2Event = Event::JoystickOneFire5;
}
+
+ updateAnalogPin(Five, minimumResistance);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/src/emucore/M6502.cxx b/src/emucore/M6502.cxx
index 20bacfa69..6aa430eec 100644
--- a/src/emucore/M6502.cxx
+++ b/src/emucore/M6502.cxx
@@ -27,6 +27,7 @@
#define DISASM_PGFX CartDebug::PGFX
#define DISASM_DATA CartDebug::DATA
#define DISASM_ROW CartDebug::ROW
+ #define DISASM_WRITE CartDebug::WRITE
#define DISASM_NONE 0
#else
// Flags for disassembly types
@@ -36,6 +37,7 @@
#define DISASM_DATA 0
#define DISASM_ROW 0
#define DISASM_NONE 0
+ #define DISASM_WRITE 0
#endif
#include "Settings.hxx"
#include "Vec.hxx"
@@ -49,7 +51,6 @@ M6502::M6502(const Settings& settings)
mySettings(settings),
A(0), X(0), Y(0), SP(0), IR(0), PC(0),
N(false), V(false), B(false), D(false), I(false), notZ(false), C(false),
- myLastAccessWasRead(true),
myNumberOfDistinctAccesses(0),
myLastAddress(0),
myLastPeekAddress(0),
@@ -94,9 +95,6 @@ void M6502::reset()
PS(BSPF::containsIgnoreCase(cpurandom, "P") ?
mySystem->randGenerator().next() : 0x20);
- // Reset access flag
- myLastAccessWasRead = true;
-
// Load PC from the reset vector
PC = uInt16(mySystem->peek(0xfffc)) | (uInt16(mySystem->peek(0xfffd)) << 8);
@@ -133,13 +131,12 @@ inline uInt8 M6502::peek(uInt16 address, uInt8 flags)
#endif // DEBUGGER_SUPPORT
uInt8 result = mySystem->peek(address, flags);
- myLastAccessWasRead = true;
myLastPeekAddress = address;
return result;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-inline void M6502::poke(uInt16 address, uInt8 value)
+inline void M6502::poke(uInt16 address, uInt8 value, uInt8 flags)
{
////////////////////////////////////////////////
// TODO - move this logic directly into CartAR
@@ -160,8 +157,7 @@ inline void M6502::poke(uInt16 address, uInt8 value)
}
#endif // DEBUGGER_SUPPORT
- mySystem->poke(address, value);
- myLastAccessWasRead = false;
+ mySystem->poke(address, value, flags);
myLastPokeAddress = address;
}
@@ -414,7 +410,7 @@ void M6502::attach(Debugger& debugger)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 M6502::addCondBreak(Expression* e, const string& name)
{
- myBreakConds.emplace_back(unique_ptr(e));
+ myBreakConds.emplace_back(e);
myBreakCondNames.push_back(name);
return uInt32(myBreakConds.size() - 1);
}
diff --git a/src/emucore/M6502.hxx b/src/emucore/M6502.hxx
index a03631337..b22a5727f 100644
--- a/src/emucore/M6502.hxx
+++ b/src/emucore/M6502.hxx
@@ -136,13 +136,6 @@ class M6502 : public Serializable
*/
uInt16 getPC() const { return PC; }
- /**
- Answer true iff the last memory access was a read.
-
- @return true iff last access was a read
- */
- bool lastAccessWasRead() const { return myLastAccessWasRead; }
-
/**
Return the last address that was part of a read/peek. Note that
reads which are part of a write are not considered here, unless
@@ -245,7 +238,7 @@ class M6502 : public Serializable
@param address The address where the value should be stored
@param value The value to be stored at the address
*/
- void poke(uInt16 address, uInt8 value);
+ void poke(uInt16 address, uInt8 value, uInt8 flags = 0);
/**
Get the 8-bit value of the Processor Status register.
@@ -327,9 +320,6 @@ class M6502 : public Serializable
bool notZ; // Z flag complement for processor status register
bool C; // C flag for processor status register
- /// Indicates if the last memory access was a read or not
- bool myLastAccessWasRead;
-
/// Indicates the numer of distinct memory accesses
uInt32 myNumberOfDistinctAccesses;
diff --git a/src/emucore/M6502.ins b/src/emucore/M6502.ins
index 780c86395..0ea0115b5 100644
--- a/src/emucore/M6502.ins
+++ b/src/emucore/M6502.ins
@@ -38,7 +38,7 @@
#ifndef CLEAR_LAST_PEEK
#ifdef DEBUGGER_SUPPORT
- #define CLEAR_LAST_PEEK(_addr) _addr = -1;
+ #define CLEAR_LAST_PEEK(_addr) _addr = 0;
#else
#define CLEAR_LAST_PEEK(_addr)
#endif
@@ -266,8 +266,8 @@
-
-
+//////////////////////////////////////////////////
+// ADC
case 0x69:
{
operand = peek(PC++, DISASM_CODE);
@@ -344,7 +344,7 @@ break;
case 0x75:
{
intermediateAddress = peek(PC++, DISASM_CODE);
- peek(intermediateAddress, DISASM_DATA);
+ peek(intermediateAddress, DISASM_NONE);
intermediateAddress += X;
operand = peek(intermediateAddress, DISASM_DATA);
}
@@ -423,11 +423,15 @@ case 0x7d:
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
intermediateAddress = high | uInt8(low + X);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + X) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + X;
operand = peek(intermediateAddress, DISASM_DATA);
+ }
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
}
}
{
@@ -467,12 +471,16 @@ case 0x79:
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
intermediateAddress = high | uInt8(low + Y);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + Y) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + Y;
operand = peek(intermediateAddress, DISASM_DATA);
}
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
+ }
}
{
if(!D)
@@ -509,7 +517,7 @@ break;
case 0x61:
{
uInt8 pointer = peek(PC++, DISASM_CODE);
- peek(pointer, DISASM_DATA);
+ peek(pointer, DISASM_NONE);
pointer += X;
intermediateAddress = peek(pointer++, DISASM_DATA);
intermediateAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8);
@@ -553,12 +561,16 @@ case 0x71:
uInt16 low = peek(pointer++, DISASM_DATA);
uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8);
intermediateAddress = high | uInt8(low + Y);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + Y) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + Y;
operand = peek(intermediateAddress, DISASM_DATA);
}
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
+ }
}
{
if(!D)
@@ -592,7 +604,8 @@ case 0x71:
}
break;
-
+//////////////////////////////////////////////////
+// ASR
case 0x4b:
{
operand = peek(PC++, DISASM_CODE);
@@ -610,7 +623,8 @@ case 0x4b:
}
break;
-
+//////////////////////////////////////////////////
+// ANC
case 0x0b:
case 0x2b:
{
@@ -624,7 +638,8 @@ case 0x2b:
}
break;
-
+//////////////////////////////////////////////////
+// AND
case 0x29:
{
operand = peek(PC++, DISASM_CODE);
@@ -651,7 +666,7 @@ break;
case 0x35:
{
intermediateAddress = peek(PC++, DISASM_CODE);
- peek(intermediateAddress, DISASM_DATA);
+ peek(intermediateAddress, DISASM_NONE);
intermediateAddress += X;
operand = peek(intermediateAddress, DISASM_DATA);
}
@@ -680,11 +695,15 @@ case 0x3d:
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
intermediateAddress = high | uInt8(low + X);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + X) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + X;
operand = peek(intermediateAddress, DISASM_DATA);
+ }
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
}
}
{
@@ -699,12 +718,16 @@ case 0x39:
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
intermediateAddress = high | uInt8(low + Y);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + Y) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + Y;
operand = peek(intermediateAddress, DISASM_DATA);
}
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
+ }
}
{
A &= operand;
@@ -716,7 +739,7 @@ break;
case 0x21:
{
uInt8 pointer = peek(PC++, DISASM_CODE);
- peek(pointer, DISASM_DATA);
+ peek(pointer, DISASM_NONE);
pointer += X;
intermediateAddress = peek(pointer++, DISASM_DATA);
intermediateAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8);
@@ -735,12 +758,16 @@ case 0x31:
uInt16 low = peek(pointer++, DISASM_DATA);
uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8);
intermediateAddress = high | uInt8(low + Y);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + Y) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + Y;
operand = peek(intermediateAddress, DISASM_DATA);
}
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
+ }
}
{
A &= operand;
@@ -749,7 +776,8 @@ case 0x31:
}
break;
-
+//////////////////////////////////////////////////
+// ANE
case 0x8b:
{
operand = peek(PC++, DISASM_CODE);
@@ -764,7 +792,8 @@ case 0x8b:
}
break;
-
+//////////////////////////////////////////////////
+// ARR
case 0x6b:
{
operand = peek(PC++, DISASM_CODE);
@@ -811,7 +840,8 @@ case 0x6b:
}
break;
-
+//////////////////////////////////////////////////
+// ASL
case 0x0a:
{
peek(PC, DISASM_NONE);
@@ -831,14 +861,14 @@ case 0x06:
{
operandAddress = peek(PC++, DISASM_CODE);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
// Set carry flag according to the left-most bit in value
C = operand & 0x80;
operand <<= 1;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
notZ = operand;
N = operand & 0x80;
@@ -848,17 +878,17 @@ break;
case 0x16:
{
operandAddress = peek(PC++, DISASM_CODE);
- peek(operandAddress, DISASM_DATA);
+ peek(operandAddress, DISASM_NONE);
operandAddress = (operandAddress + X) & 0xFF;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
// Set carry flag according to the left-most bit in value
C = operand & 0x80;
operand <<= 1;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
notZ = operand;
N = operand & 0x80;
@@ -870,14 +900,14 @@ case 0x0e:
operandAddress = peek(PC++, DISASM_CODE);
operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
// Set carry flag according to the left-most bit in value
C = operand & 0x80;
operand <<= 1;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
notZ = operand;
N = operand & 0x80;
@@ -888,24 +918,52 @@ case 0x1e:
{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
- peek(high | uInt8(low + X), DISASM_DATA);
+ peek(high | uInt8(low + X), DISASM_NONE);
operandAddress = (high | low) + X;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
// Set carry flag according to the left-most bit in value
C = operand & 0x80;
operand <<= 1;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
notZ = operand;
N = operand & 0x80;
}
break;
+//////////////////////////////////////////////////
+// BIT
+case 0x24:
+{
+ intermediateAddress = peek(PC++, DISASM_CODE);
+ operand = peek(intermediateAddress, DISASM_DATA);
+}
+{
+ notZ = (A & operand);
+ N = operand & 0x80;
+ V = operand & 0x40;
+}
+break;
+case 0x2C:
+{
+ intermediateAddress = peek(PC++, DISASM_CODE);
+ intermediateAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8);
+ operand = peek(intermediateAddress, DISASM_DATA);
+}
+{
+ notZ = (A & operand);
+ N = operand & 0x80;
+ V = operand & 0x40;
+}
+break;
+
+//////////////////////////////////////////////////
+// Branches
case 0x90:
{
operand = peek(PC++, DISASM_CODE);
@@ -957,32 +1015,6 @@ case 0xf0:
break;
-case 0x24:
-{
- intermediateAddress = peek(PC++, DISASM_CODE);
- operand = peek(intermediateAddress, DISASM_DATA);
-}
-{
- notZ = (A & operand);
- N = operand & 0x80;
- V = operand & 0x40;
-}
-break;
-
-case 0x2C:
-{
- intermediateAddress = peek(PC++, DISASM_CODE);
- intermediateAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8);
- operand = peek(intermediateAddress, DISASM_DATA);
-}
-{
- notZ = (A & operand);
- N = operand & 0x80;
- V = operand & 0x40;
-}
-break;
-
-
case 0x30:
{
operand = peek(PC++, DISASM_CODE);
@@ -1034,24 +1066,6 @@ case 0x10:
break;
-case 0x00:
-{
- peek(PC++, DISASM_CODE);
-
- B = true;
-
- poke(0x0100 + SP--, PC >> 8);
- poke(0x0100 + SP--, PC & 0x00ff);
- poke(0x0100 + SP--, PS());
-
- I = true;
-
- PC = peek(0xfffe, DISASM_NONE);
- PC |= (uInt16(peek(0xffff, DISASM_NONE)) << 8);
-}
-break;
-
-
case 0x50:
{
operand = peek(PC++, DISASM_CODE);
@@ -1085,7 +1099,27 @@ case 0x70:
}
break;
+//////////////////////////////////////////////////
+// BRK
+case 0x00:
+{
+ peek(PC++, DISASM_NONE);
+ B = true;
+
+ poke(0x0100 + SP--, PC >> 8, DISASM_WRITE);
+ poke(0x0100 + SP--, PC & 0x00ff, DISASM_WRITE);
+ poke(0x0100 + SP--, PS(), DISASM_WRITE);
+
+ I = true;
+
+ PC = peek(0xfffe, DISASM_DATA);
+ PC |= (uInt16(peek(0xffff, DISASM_DATA)) << 8);
+}
+break;
+
+//////////////////////////////////////////////////
+// CLC
case 0x18:
{
peek(PC, DISASM_NONE);
@@ -1095,7 +1129,8 @@ case 0x18:
}
break;
-
+//////////////////////////////////////////////////
+// CLD
case 0xd8:
{
peek(PC, DISASM_NONE);
@@ -1105,7 +1140,8 @@ case 0xd8:
}
break;
-
+//////////////////////////////////////////////////
+// CLI
case 0x58:
{
peek(PC, DISASM_NONE);
@@ -1115,7 +1151,8 @@ case 0x58:
}
break;
-
+//////////////////////////////////////////////////
+// CLV
case 0xb8:
{
peek(PC, DISASM_NONE);
@@ -1125,7 +1162,8 @@ case 0xb8:
}
break;
-
+//////////////////////////////////////////////////
+// CMP
case 0xc9:
{
operand = peek(PC++, DISASM_CODE);
@@ -1156,7 +1194,7 @@ break;
case 0xd5:
{
intermediateAddress = peek(PC++, DISASM_CODE);
- peek(intermediateAddress, DISASM_DATA);
+ peek(intermediateAddress, DISASM_NONE);
intermediateAddress += X;
operand = peek(intermediateAddress, DISASM_DATA);
}
@@ -1189,11 +1227,15 @@ case 0xdd:
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
intermediateAddress = high | uInt8(low + X);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + X) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + X;
operand = peek(intermediateAddress, DISASM_DATA);
+ }
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
}
}
{
@@ -1210,12 +1252,16 @@ case 0xd9:
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
intermediateAddress = high | uInt8(low + Y);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + Y) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + Y;
operand = peek(intermediateAddress, DISASM_DATA);
}
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
+ }
}
{
uInt16 value = uInt16(A) - uInt16(operand);
@@ -1229,7 +1275,7 @@ break;
case 0xc1:
{
uInt8 pointer = peek(PC++, DISASM_CODE);
- peek(pointer, DISASM_DATA);
+ peek(pointer, DISASM_NONE);
pointer += X;
intermediateAddress = peek(pointer++, DISASM_DATA);
intermediateAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8);
@@ -1250,12 +1296,16 @@ case 0xd1:
uInt16 low = peek(pointer++, DISASM_DATA);
uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8);
intermediateAddress = high | uInt8(low + Y);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + Y) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + Y;
operand = peek(intermediateAddress, DISASM_DATA);
}
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
+ }
}
{
uInt16 value = uInt16(A) - uInt16(operand);
@@ -1266,7 +1316,8 @@ case 0xd1:
}
break;
-
+//////////////////////////////////////////////////
+// CPX
case 0xe0:
{
operand = peek(PC++, DISASM_CODE);
@@ -1309,7 +1360,8 @@ case 0xec:
}
break;
-
+//////////////////////////////////////////////////
+// CPY
case 0xc0:
{
operand = peek(PC++, DISASM_CODE);
@@ -1352,17 +1404,18 @@ case 0xcc:
}
break;
-
+//////////////////////////////////////////////////
+// DCP
case 0xcf:
{
operandAddress = peek(PC++, DISASM_CODE);
operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
uInt8 value = operand - 1;
- poke(operandAddress, value);
+ poke(operandAddress, value, DISASM_WRITE);
uInt16 value2 = uInt16(A) - uInt16(value);
notZ = value2;
@@ -1375,14 +1428,14 @@ case 0xdf:
{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
- peek(high | uInt8(low + X), DISASM_DATA);
+ peek(high | uInt8(low + X), DISASM_NONE);
operandAddress = (high | low) + X;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
uInt8 value = operand - 1;
- poke(operandAddress, value);
+ poke(operandAddress, value, DISASM_WRITE);
uInt16 value2 = uInt16(A) - uInt16(value);
notZ = value2;
@@ -1395,14 +1448,14 @@ case 0xdb:
{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
- peek(high | uInt8(low + Y), DISASM_DATA);
+ peek(high | uInt8(low + Y), DISASM_NONE);
operandAddress = (high | low) + Y;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
uInt8 value = operand - 1;
- poke(operandAddress, value);
+ poke(operandAddress, value, DISASM_WRITE);
uInt16 value2 = uInt16(A) - uInt16(value);
notZ = value2;
@@ -1415,11 +1468,11 @@ case 0xc7:
{
operandAddress = peek(PC++, DISASM_CODE);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
uInt8 value = operand - 1;
- poke(operandAddress, value);
+ poke(operandAddress, value, DISASM_WRITE);
uInt16 value2 = uInt16(A) - uInt16(value);
notZ = value2;
@@ -1431,14 +1484,14 @@ break;
case 0xd7:
{
operandAddress = peek(PC++, DISASM_CODE);
- peek(operandAddress, DISASM_DATA);
+ peek(operandAddress, DISASM_NONE);
operandAddress = (operandAddress + X) & 0xFF;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
uInt8 value = operand - 1;
- poke(operandAddress, value);
+ poke(operandAddress, value, DISASM_WRITE);
uInt16 value2 = uInt16(A) - uInt16(value);
notZ = value2;
@@ -1450,16 +1503,16 @@ break;
case 0xc3:
{
uInt8 pointer = peek(PC++, DISASM_CODE);
- peek(pointer, DISASM_DATA);
+ peek(pointer, DISASM_NONE);
pointer += X;
operandAddress = peek(pointer++, DISASM_DATA);
operandAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
uInt8 value = operand - 1;
- poke(operandAddress, value);
+ poke(operandAddress, value, DISASM_WRITE);
uInt16 value2 = uInt16(A) - uInt16(value);
notZ = value2;
@@ -1473,14 +1526,14 @@ case 0xd3:
uInt8 pointer = peek(PC++, DISASM_CODE);
uInt16 low = peek(pointer++, DISASM_DATA);
uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8);
- peek(high | uInt8(low + Y), DISASM_DATA);
+ peek(high | uInt8(low + Y), DISASM_NONE);
operandAddress = (high | low) + Y;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
uInt8 value = operand - 1;
- poke(operandAddress, value);
+ poke(operandAddress, value, DISASM_WRITE);
uInt16 value2 = uInt16(A) - uInt16(value);
notZ = value2;
@@ -1489,16 +1542,17 @@ case 0xd3:
}
break;
-
+//////////////////////////////////////////////////
+// DEC
case 0xc6:
{
operandAddress = peek(PC++, DISASM_CODE);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
uInt8 value = operand - 1;
- poke(operandAddress, value);
+ poke(operandAddress, value, DISASM_WRITE);
notZ = value;
N = value & 0x80;
@@ -1508,14 +1562,14 @@ break;
case 0xd6:
{
operandAddress = peek(PC++, DISASM_CODE);
- peek(operandAddress, DISASM_DATA);
+ peek(operandAddress, DISASM_NONE);
operandAddress = (operandAddress + X) & 0xFF;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
uInt8 value = operand - 1;
- poke(operandAddress, value);
+ poke(operandAddress, value, DISASM_WRITE);
notZ = value;
N = value & 0x80;
@@ -1527,11 +1581,11 @@ case 0xce:
operandAddress = peek(PC++, DISASM_CODE);
operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
uInt8 value = operand - 1;
- poke(operandAddress, value);
+ poke(operandAddress, value, DISASM_WRITE);
notZ = value;
N = value & 0x80;
@@ -1542,21 +1596,22 @@ case 0xde:
{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
- peek(high | uInt8(low + X), DISASM_DATA);
+ peek(high | uInt8(low + X), DISASM_NONE);
operandAddress = (high | low) + X;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
uInt8 value = operand - 1;
- poke(operandAddress, value);
+ poke(operandAddress, value, DISASM_WRITE);
notZ = value;
N = value & 0x80;
}
break;
-
+//////////////////////////////////////////////////
+// DEX
case 0xca:
{
peek(PC, DISASM_NONE);
@@ -1569,7 +1624,8 @@ case 0xca:
}
break;
-
+//////////////////////////////////////////////////
+// DEY
case 0x88:
{
peek(PC, DISASM_NONE);
@@ -1582,7 +1638,8 @@ case 0x88:
}
break;
-
+//////////////////////////////////////////////////
+// EOR
case 0x49:
{
operand = peek(PC++, DISASM_CODE);
@@ -1609,7 +1666,7 @@ break;
case 0x55:
{
intermediateAddress = peek(PC++, DISASM_CODE);
- peek(intermediateAddress, DISASM_DATA);
+ peek(intermediateAddress, DISASM_NONE);
intermediateAddress += X;
operand = peek(intermediateAddress, DISASM_DATA);
}
@@ -1638,11 +1695,15 @@ case 0x5d:
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
intermediateAddress = high | uInt8(low + X);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + X) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + X;
operand = peek(intermediateAddress, DISASM_DATA);
+ }
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
}
}
{
@@ -1657,12 +1718,16 @@ case 0x59:
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
intermediateAddress = high | uInt8(low + Y);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + Y) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + Y;
operand = peek(intermediateAddress, DISASM_DATA);
}
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
+ }
}
{
A ^= operand;
@@ -1674,7 +1739,7 @@ break;
case 0x41:
{
uInt8 pointer = peek(PC++, DISASM_CODE);
- peek(pointer, DISASM_DATA);
+ peek(pointer, DISASM_NONE);
pointer += X;
intermediateAddress = peek(pointer++, DISASM_DATA);
intermediateAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8);
@@ -1693,12 +1758,16 @@ case 0x51:
uInt16 low = peek(pointer++, DISASM_DATA);
uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8);
intermediateAddress = high | uInt8(low + Y);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + Y) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + Y;
operand = peek(intermediateAddress, DISASM_DATA);
}
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
+ }
}
{
A ^= operand;
@@ -1707,16 +1776,17 @@ case 0x51:
}
break;
-
+//////////////////////////////////////////////////
+// INC
case 0xe6:
{
operandAddress = peek(PC++, DISASM_CODE);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
uInt8 value = operand + 1;
- poke(operandAddress, value);
+ poke(operandAddress, value, DISASM_WRITE);
notZ = value;
N = value & 0x80;
@@ -1726,14 +1796,14 @@ break;
case 0xf6:
{
operandAddress = peek(PC++, DISASM_CODE);
- peek(operandAddress, DISASM_DATA);
+ peek(operandAddress, DISASM_NONE);
operandAddress = (operandAddress + X) & 0xFF;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
uInt8 value = operand + 1;
- poke(operandAddress, value);
+ poke(operandAddress, value, DISASM_WRITE);
notZ = value;
N = value & 0x80;
@@ -1745,11 +1815,11 @@ case 0xee:
operandAddress = peek(PC++, DISASM_CODE);
operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
uInt8 value = operand + 1;
- poke(operandAddress, value);
+ poke(operandAddress, value, DISASM_WRITE);
notZ = value;
N = value & 0x80;
@@ -1760,21 +1830,22 @@ case 0xfe:
{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
- peek(high | uInt8(low + X), DISASM_DATA);
+ peek(high | uInt8(low + X), DISASM_NONE);
operandAddress = (high | low) + X;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
uInt8 value = operand + 1;
- poke(operandAddress, value);
+ poke(operandAddress, value, DISASM_WRITE);
notZ = value;
N = value & 0x80;
}
break;
-
+//////////////////////////////////////////////////
+// INX
case 0xe8:
{
peek(PC, DISASM_NONE);
@@ -1786,7 +1857,8 @@ case 0xe8:
}
break;
-
+//////////////////////////////////////////////////
+// INY
case 0xc8:
{
peek(PC, DISASM_NONE);
@@ -1798,17 +1870,18 @@ case 0xc8:
}
break;
-
+//////////////////////////////////////////////////
+// ISB
case 0xef:
{
operandAddress = peek(PC++, DISASM_CODE);
operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
operand = operand + 1;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
// N, V, Z, C flags are the same in either mode (C calculated at the end)
Int32 sum = A - operand - (C ? 0 : 1);
@@ -1842,14 +1915,14 @@ case 0xff:
{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
- peek(high | uInt8(low + X), DISASM_DATA);
+ peek(high | uInt8(low + X), DISASM_NONE);
operandAddress = (high | low) + X;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
operand = operand + 1;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
// N, V, Z, C flags are the same in either mode (C calculated at the end)
Int32 sum = A - operand - (C ? 0 : 1);
@@ -1883,14 +1956,14 @@ case 0xfb:
{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
- peek(high | uInt8(low + Y), DISASM_DATA);
+ peek(high | uInt8(low + Y), DISASM_NONE);
operandAddress = (high | low) + Y;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
operand = operand + 1;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
// N, V, Z, C flags are the same in either mode (C calculated at the end)
Int32 sum = A - operand - (C ? 0 : 1);
@@ -1924,11 +1997,11 @@ case 0xe7:
{
operandAddress = peek(PC++, DISASM_CODE);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
operand = operand + 1;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
// N, V, Z, C flags are the same in either mode (C calculated at the end)
Int32 sum = A - operand - (C ? 0 : 1);
@@ -1961,14 +2034,14 @@ break;
case 0xf7:
{
operandAddress = peek(PC++, DISASM_CODE);
- peek(operandAddress, DISASM_DATA);
+ peek(operandAddress, DISASM_NONE);
operandAddress = (operandAddress + X) & 0xFF;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
operand = operand + 1;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
// N, V, Z, C flags are the same in either mode (C calculated at the end)
Int32 sum = A - operand - (C ? 0 : 1);
@@ -2001,16 +2074,16 @@ break;
case 0xe3:
{
uInt8 pointer = peek(PC++, DISASM_CODE);
- peek(pointer, DISASM_DATA);
+ peek(pointer, DISASM_NONE);
pointer += X;
operandAddress = peek(pointer++, DISASM_DATA);
operandAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
operand = operand + 1;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
// N, V, Z, C flags are the same in either mode (C calculated at the end)
Int32 sum = A - operand - (C ? 0 : 1);
@@ -2045,14 +2118,14 @@ case 0xf3:
uInt8 pointer = peek(PC++, DISASM_CODE);
uInt16 low = peek(pointer++, DISASM_DATA);
uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8);
- peek(high | uInt8(low + Y), DISASM_DATA);
+ peek(high | uInt8(low + Y), DISASM_NONE);
operandAddress = (high | low) + Y;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
operand = operand + 1;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
// N, V, Z, C flags are the same in either mode (C calculated at the end)
Int32 sum = A - operand - (C ? 0 : 1);
@@ -2082,7 +2155,8 @@ case 0xf3:
}
break;
-
+//////////////////////////////////////////////////
+// JMP
case 0x4c:
{
operandAddress = peek(PC++, DISASM_CODE);
@@ -2109,7 +2183,8 @@ case 0x6c:
}
break;
-
+//////////////////////////////////////////////////
+// JSR
case 0x20:
{
uInt8 low = peek(PC++, DISASM_CODE);
@@ -2118,25 +2193,30 @@ case 0x20:
// It seems that the 650x does not push the address of the next instruction
// on the stack it actually pushes the address of the next instruction
// minus one. This is compensated for in the RTS instruction
- poke(0x0100 + SP--, PC >> 8);
- poke(0x0100 + SP--, PC & 0xff);
+ poke(0x0100 + SP--, PC >> 8, DISASM_WRITE);
+ poke(0x0100 + SP--, PC & 0xff, DISASM_WRITE);
PC = (low | (uInt16(peek(PC, DISASM_CODE)) << 8));
}
break;
-
+//////////////////////////////////////////////////
+// LAS
case 0xbb:
{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
intermediateAddress = high | uInt8(low + Y);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + Y) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + Y;
operand = peek(intermediateAddress, DISASM_DATA);
}
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
+ }
}
{
A = X = SP = SP & operand;
@@ -2169,12 +2249,16 @@ case 0xbf:
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
intermediateAddress = high | uInt8(low + Y);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + Y) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + Y;
operand = peek(intermediateAddress, DISASM_DATA);
}
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
+ }
}
SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress)
SET_LAST_PEEK(myLastSrcAddressX, intermediateAddress)
@@ -2204,7 +2288,7 @@ break;
case 0xb7:
{
intermediateAddress = peek(PC++, DISASM_CODE);
- peek(intermediateAddress, DISASM_DATA);
+ peek(intermediateAddress, DISASM_NONE);
intermediateAddress += Y;
operand = peek(intermediateAddress, DISASM_DATA);
}
@@ -2221,7 +2305,7 @@ break;
case 0xa3:
{
uInt8 pointer = peek(PC++, DISASM_CODE);
- peek(pointer, DISASM_DATA);
+ peek(pointer, DISASM_NONE);
pointer += X;
intermediateAddress = peek(pointer++, DISASM_DATA);
intermediateAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8);
@@ -2243,12 +2327,16 @@ case 0xb3:
uInt16 low = peek(pointer++, DISASM_DATA);
uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8);
intermediateAddress = high | uInt8(low + Y);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + Y) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + Y;
operand = peek(intermediateAddress, DISASM_DATA);
}
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
+ }
}
SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress)
SET_LAST_PEEK(myLastSrcAddressX, intermediateAddress) // TODO - check this
@@ -2292,7 +2380,7 @@ break;
case 0xb5:
{
intermediateAddress = peek(PC++, DISASM_CODE);
- peek(intermediateAddress, DISASM_DATA);
+ peek(intermediateAddress, DISASM_NONE);
intermediateAddress += X;
operand = peek(intermediateAddress, DISASM_DATA);
}
@@ -2323,11 +2411,15 @@ case 0xbd:
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
intermediateAddress = high | uInt8(low + X);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + X) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + X;
operand = peek(intermediateAddress, DISASM_DATA);
+ }
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
}
}
SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress)
@@ -2343,12 +2435,16 @@ case 0xb9:
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
intermediateAddress = high | uInt8(low + Y);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + Y) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + Y;
operand = peek(intermediateAddress, DISASM_DATA);
}
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
+ }
}
SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress)
{
@@ -2361,7 +2457,7 @@ break;
case 0xa1:
{
uInt8 pointer = peek(PC++, DISASM_CODE);
- peek(pointer, DISASM_DATA);
+ peek(pointer, DISASM_NONE);
pointer += X;
intermediateAddress = peek(pointer++, DISASM_DATA);
intermediateAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8);
@@ -2381,12 +2477,16 @@ case 0xb1:
uInt16 low = peek(pointer++, DISASM_DATA);
uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8);
intermediateAddress = high | uInt8(low + Y);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + Y) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + Y;
operand = peek(intermediateAddress, DISASM_DATA);
}
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
+ }
}
SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress)
{
@@ -2428,7 +2528,7 @@ break;
case 0xb6:
{
intermediateAddress = peek(PC++, DISASM_CODE);
- peek(intermediateAddress, DISASM_DATA);
+ peek(intermediateAddress, DISASM_NONE);
intermediateAddress += Y;
operand = peek(intermediateAddress, DISASM_DATA);
}
@@ -2459,12 +2559,16 @@ case 0xbe:
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
intermediateAddress = high | uInt8(low + Y);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + Y) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + Y;
operand = peek(intermediateAddress, DISASM_DATA);
}
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
+ }
}
SET_LAST_PEEK(myLastSrcAddressX, intermediateAddress)
{
@@ -2506,7 +2610,7 @@ break;
case 0xb4:
{
intermediateAddress = peek(PC++, DISASM_CODE);
- peek(intermediateAddress, DISASM_DATA);
+ peek(intermediateAddress, DISASM_NONE);
intermediateAddress += X;
operand = peek(intermediateAddress, DISASM_DATA);
}
@@ -2537,11 +2641,15 @@ case 0xbc:
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
intermediateAddress = high | uInt8(low + X);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + X) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + X;
operand = peek(intermediateAddress, DISASM_DATA);
+ }
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
}
}
SET_LAST_PEEK(myLastSrcAddressY, intermediateAddress)
@@ -2553,7 +2661,8 @@ SET_LAST_PEEK(myLastSrcAddressY, intermediateAddress)
break;
//////////////////////////////////////////////////
-
+//////////////////////////////////////////////////
+// LSR
case 0x4a:
{
peek(PC, DISASM_NONE);
@@ -2574,14 +2683,14 @@ case 0x46:
{
operandAddress = peek(PC++, DISASM_CODE);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
// Set carry flag according to the right-most bit in value
C = operand & 0x01;
operand = (operand >> 1) & 0x7f;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
notZ = operand;
N = operand & 0x80;
@@ -2591,17 +2700,17 @@ break;
case 0x56:
{
operandAddress = peek(PC++, DISASM_CODE);
- peek(operandAddress, DISASM_DATA);
+ peek(operandAddress, DISASM_NONE);
operandAddress = (operandAddress + X) & 0xFF;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
// Set carry flag according to the right-most bit in value
C = operand & 0x01;
operand = (operand >> 1) & 0x7f;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
notZ = operand;
N = operand & 0x80;
@@ -2613,14 +2722,14 @@ case 0x4e:
operandAddress = peek(PC++, DISASM_CODE);
operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
// Set carry flag according to the right-most bit in value
C = operand & 0x01;
operand = (operand >> 1) & 0x7f;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
notZ = operand;
N = operand & 0x80;
@@ -2631,24 +2740,25 @@ case 0x5e:
{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
- peek(high | uInt8(low + X), DISASM_DATA);
+ peek(high | uInt8(low + X), DISASM_NONE);
operandAddress = (high | low) + X;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
// Set carry flag according to the right-most bit in value
C = operand & 0x01;
operand = (operand >> 1) & 0x7f;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
notZ = operand;
N = operand & 0x80;
}
break;
-
+//////////////////////////////////////////////////
+// LXA
case 0xab:
{
operand = peek(PC++, DISASM_CODE);
@@ -2663,7 +2773,8 @@ case 0xab:
}
break;
-
+//////////////////////////////////////////////////
+// NOP
case 0x1a:
case 0x3a:
case 0x5a:
@@ -2709,7 +2820,7 @@ case 0xd4:
case 0xf4:
{
intermediateAddress = peek(PC++, DISASM_CODE);
- peek(intermediateAddress, DISASM_DATA);
+ peek(intermediateAddress, DISASM_NONE);
intermediateAddress += X;
operand = peek(intermediateAddress, DISASM_DATA);
}
@@ -2737,11 +2848,15 @@ case 0xfc:
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
intermediateAddress = high | uInt8(low + X);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + X) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + X;
operand = peek(intermediateAddress, DISASM_DATA);
+ }
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
}
}
{
@@ -2779,7 +2894,7 @@ break;
case 0x15:
{
intermediateAddress = peek(PC++, DISASM_CODE);
- peek(intermediateAddress, DISASM_DATA);
+ peek(intermediateAddress, DISASM_NONE);
intermediateAddress += X;
operand = peek(intermediateAddress, DISASM_DATA);
}
@@ -2810,11 +2925,15 @@ case 0x1d:
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
intermediateAddress = high | uInt8(low + X);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + X) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + X;
operand = peek(intermediateAddress, DISASM_DATA);
+ }
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
}
}
SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress)
@@ -2830,12 +2949,16 @@ case 0x19:
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
intermediateAddress = high | uInt8(low + Y);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + Y) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + Y;
operand = peek(intermediateAddress, DISASM_DATA);
}
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
+ }
}
SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress)
{
@@ -2848,7 +2971,7 @@ break;
case 0x01:
{
uInt8 pointer = peek(PC++, DISASM_CODE);
- peek(pointer, DISASM_DATA);
+ peek(pointer, DISASM_NONE);
pointer += X;
intermediateAddress = peek(pointer++, DISASM_DATA);
intermediateAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8);
@@ -2868,12 +2991,16 @@ case 0x11:
uInt16 low = peek(pointer++, DISASM_DATA);
uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8);
intermediateAddress = high | uInt8(low + Y);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + Y) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + Y;
operand = peek(intermediateAddress, DISASM_DATA);
}
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
+ }
}
SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress)
{
@@ -2884,29 +3011,32 @@ SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress)
break;
//////////////////////////////////////////////////
-
+//////////////////////////////////////////////////
+// PHA
case 0x48:
{
peek(PC, DISASM_NONE);
}
// TODO - add tracking for this opcode
{
- poke(0x0100 + SP--, A);
+ poke(0x0100 + SP--, A, DISASM_WRITE);
}
break;
-
+//////////////////////////////////////////////////
+// PHP
case 0x08:
{
peek(PC, DISASM_NONE);
}
// TODO - add tracking for this opcode
{
- poke(0x0100 + SP--, PS());
+ poke(0x0100 + SP--, PS(), DISASM_WRITE);
}
break;
-
+//////////////////////////////////////////////////
+// PLA
case 0x68:
{
peek(PC, DISASM_NONE);
@@ -2914,13 +3044,14 @@ case 0x68:
// TODO - add tracking for this opcode
{
peek(0x0100 + SP++, DISASM_NONE);
- A = peek(0x0100 + SP, DISASM_NONE);
+ A = peek(0x0100 + SP, DISASM_DATA);
notZ = A;
N = A & 0x80;
}
break;
-
+//////////////////////////////////////////////////
+// PLP
case 0x28:
{
peek(PC, DISASM_NONE);
@@ -2928,21 +3059,22 @@ case 0x28:
// TODO - add tracking for this opcode
{
peek(0x0100 + SP++, DISASM_NONE);
- PS(peek(0x0100 + SP, DISASM_NONE));
+ PS(peek(0x0100 + SP, DISASM_DATA));
}
break;
-
+//////////////////////////////////////////////////
+// RLA
case 0x2f:
{
operandAddress = peek(PC++, DISASM_CODE);
operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
uInt8 value = (operand << 1) | (C ? 1 : 0);
- poke(operandAddress, value);
+ poke(operandAddress, value, DISASM_WRITE);
A &= value;
C = operand & 0x80;
@@ -2955,14 +3087,14 @@ case 0x3f:
{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
- peek(high | uInt8(low + X), DISASM_DATA);
+ peek(high | uInt8(low + X), DISASM_NONE);
operandAddress = (high | low) + X;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
uInt8 value = (operand << 1) | (C ? 1 : 0);
- poke(operandAddress, value);
+ poke(operandAddress, value, DISASM_WRITE);
A &= value;
C = operand & 0x80;
@@ -2975,14 +3107,14 @@ case 0x3b:
{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
- peek(high | uInt8(low + Y), DISASM_DATA);
+ peek(high | uInt8(low + Y), DISASM_NONE);
operandAddress = (high | low) + Y;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
uInt8 value = (operand << 1) | (C ? 1 : 0);
- poke(operandAddress, value);
+ poke(operandAddress, value, DISASM_WRITE);
A &= value;
C = operand & 0x80;
@@ -2995,11 +3127,11 @@ case 0x27:
{
operandAddress = peek(PC++, DISASM_CODE);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
uInt8 value = (operand << 1) | (C ? 1 : 0);
- poke(operandAddress, value);
+ poke(operandAddress, value, DISASM_WRITE);
A &= value;
C = operand & 0x80;
@@ -3011,14 +3143,14 @@ break;
case 0x37:
{
operandAddress = peek(PC++, DISASM_CODE);
- peek(operandAddress, DISASM_DATA);
+ peek(operandAddress, DISASM_NONE);
operandAddress = (operandAddress + X) & 0xFF;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
uInt8 value = (operand << 1) | (C ? 1 : 0);
- poke(operandAddress, value);
+ poke(operandAddress, value, DISASM_WRITE);
A &= value;
C = operand & 0x80;
@@ -3030,16 +3162,16 @@ break;
case 0x23:
{
uInt8 pointer = peek(PC++, DISASM_CODE);
- peek(pointer, DISASM_DATA);
+ peek(pointer, DISASM_NONE);
pointer += X;
operandAddress = peek(pointer++, DISASM_DATA);
operandAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
uInt8 value = (operand << 1) | (C ? 1 : 0);
- poke(operandAddress, value);
+ poke(operandAddress, value, DISASM_WRITE);
A &= value;
C = operand & 0x80;
@@ -3053,14 +3185,14 @@ case 0x33:
uInt8 pointer = peek(PC++, DISASM_CODE);
uInt16 low = peek(pointer++, DISASM_DATA);
uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8);
- peek(high | uInt8(low + Y), DISASM_DATA);
+ peek(high | uInt8(low + Y), DISASM_NONE);
operandAddress = (high | low) + Y;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
uInt8 value = (operand << 1) | (C ? 1 : 0);
- poke(operandAddress, value);
+ poke(operandAddress, value, DISASM_WRITE);
A &= value;
C = operand & 0x80;
@@ -3069,7 +3201,8 @@ case 0x33:
}
break;
-
+//////////////////////////////////////////////////
+// ROL
case 0x2a:
{
peek(PC, DISASM_NONE);
@@ -3087,12 +3220,11 @@ case 0x2a:
}
break;
-
case 0x26:
{
operandAddress = peek(PC++, DISASM_CODE);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
bool oldC = C;
@@ -3101,7 +3233,7 @@ case 0x26:
C = operand & 0x80;
operand = (operand << 1) | (oldC ? 1 : 0);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
notZ = operand;
N = operand & 0x80;
@@ -3111,10 +3243,10 @@ break;
case 0x36:
{
operandAddress = peek(PC++, DISASM_CODE);
- peek(operandAddress, DISASM_DATA);
+ peek(operandAddress, DISASM_NONE);
operandAddress = (operandAddress + X) & 0xFF;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
bool oldC = C;
@@ -3123,7 +3255,7 @@ case 0x36:
C = operand & 0x80;
operand = (operand << 1) | (oldC ? 1 : 0);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
notZ = operand;
N = operand & 0x80;
@@ -3135,7 +3267,7 @@ case 0x2e:
operandAddress = peek(PC++, DISASM_CODE);
operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
bool oldC = C;
@@ -3144,7 +3276,7 @@ case 0x2e:
C = operand & 0x80;
operand = (operand << 1) | (oldC ? 1 : 0);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
notZ = operand;
N = operand & 0x80;
@@ -3155,10 +3287,10 @@ case 0x3e:
{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
- peek(high | uInt8(low + X), DISASM_DATA);
+ peek(high | uInt8(low + X), DISASM_NONE);
operandAddress = (high | low) + X;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
bool oldC = C;
@@ -3167,14 +3299,15 @@ case 0x3e:
C = operand & 0x80;
operand = (operand << 1) | (oldC ? 1 : 0);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
notZ = operand;
N = operand & 0x80;
}
break;
-
+//////////////////////////////////////////////////
+// ROR
case 0x6a:
{
peek(PC, DISASM_NONE);
@@ -3196,7 +3329,7 @@ case 0x66:
{
operandAddress = peek(PC++, DISASM_CODE);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
bool oldC = C;
@@ -3205,7 +3338,7 @@ case 0x66:
C = operand & 0x01;
operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
notZ = operand;
N = operand & 0x80;
@@ -3215,10 +3348,10 @@ break;
case 0x76:
{
operandAddress = peek(PC++, DISASM_CODE);
- peek(operandAddress, DISASM_DATA);
+ peek(operandAddress, DISASM_NONE);
operandAddress = (operandAddress + X) & 0xFF;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
bool oldC = C;
@@ -3227,7 +3360,7 @@ case 0x76:
C = operand & 0x01;
operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
notZ = operand;
N = operand & 0x80;
@@ -3239,7 +3372,7 @@ case 0x6e:
operandAddress = peek(PC++, DISASM_CODE);
operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
bool oldC = C;
@@ -3248,7 +3381,7 @@ case 0x6e:
C = operand & 0x01;
operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
notZ = operand;
N = operand & 0x80;
@@ -3259,10 +3392,10 @@ case 0x7e:
{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
- peek(high | uInt8(low + X), DISASM_DATA);
+ peek(high | uInt8(low + X), DISASM_NONE);
operandAddress = (high | low) + X;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
bool oldC = C;
@@ -3271,20 +3404,21 @@ case 0x7e:
C = operand & 0x01;
operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
notZ = operand;
N = operand & 0x80;
}
break;
-
+//////////////////////////////////////////////////
+// RRA
case 0x6f:
{
operandAddress = peek(PC++, DISASM_CODE);
operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
bool oldC = C;
@@ -3293,7 +3427,7 @@ case 0x6f:
C = operand & 0x01;
operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
if(!D)
{
@@ -3330,10 +3464,10 @@ case 0x7f:
{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
- peek(high | uInt8(low + X), DISASM_DATA);
+ peek(high | uInt8(low + X), DISASM_NONE);
operandAddress = (high | low) + X;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
bool oldC = C;
@@ -3342,7 +3476,7 @@ case 0x7f:
C = operand & 0x01;
operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
if(!D)
{
@@ -3379,10 +3513,10 @@ case 0x7b:
{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
- peek(high | uInt8(low + Y), DISASM_DATA);
+ peek(high | uInt8(low + Y), DISASM_NONE);
operandAddress = (high | low) + Y;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
bool oldC = C;
@@ -3391,7 +3525,7 @@ case 0x7b:
C = operand & 0x01;
operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
if(!D)
{
@@ -3428,7 +3562,7 @@ case 0x67:
{
operandAddress = peek(PC++, DISASM_CODE);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
bool oldC = C;
@@ -3437,7 +3571,7 @@ case 0x67:
C = operand & 0x01;
operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
if(!D)
{
@@ -3473,10 +3607,10 @@ break;
case 0x77:
{
operandAddress = peek(PC++, DISASM_CODE);
- peek(operandAddress, DISASM_DATA);
+ peek(operandAddress, DISASM_NONE);
operandAddress = (operandAddress + X) & 0xFF;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
bool oldC = C;
@@ -3485,7 +3619,7 @@ case 0x77:
C = operand & 0x01;
operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
if(!D)
{
@@ -3521,12 +3655,12 @@ break;
case 0x63:
{
uInt8 pointer = peek(PC++, DISASM_CODE);
- peek(pointer, DISASM_DATA);
+ peek(pointer, DISASM_NONE);
pointer += X;
operandAddress = peek(pointer++, DISASM_DATA);
operandAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
bool oldC = C;
@@ -3535,7 +3669,7 @@ case 0x63:
C = operand & 0x01;
operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
if(!D)
{
@@ -3573,10 +3707,10 @@ case 0x73:
uInt8 pointer = peek(PC++, DISASM_CODE);
uInt16 low = peek(pointer++, DISASM_DATA);
uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8);
- peek(high | uInt8(low + Y), DISASM_DATA);
+ peek(high | uInt8(low + Y), DISASM_NONE);
operandAddress = (high | low) + Y;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
bool oldC = C;
@@ -3585,7 +3719,7 @@ case 0x73:
C = operand & 0x01;
operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
if(!D)
{
@@ -3618,7 +3752,8 @@ case 0x73:
}
break;
-
+//////////////////////////////////////////////////
+// RTI
case 0x40:
{
peek(PC, DISASM_NONE);
@@ -3631,7 +3766,8 @@ case 0x40:
}
break;
-
+//////////////////////////////////////////////////
+// RTS
case 0x60:
{
peek(PC, DISASM_NONE);
@@ -3640,18 +3776,19 @@ case 0x60:
peek(0x0100 + SP++, DISASM_NONE);
PC = peek(0x0100 + SP++, DISASM_NONE);
PC |= (uInt16(peek(0x0100 + SP, DISASM_NONE)) << 8);
- peek(PC++, DISASM_CODE);
+ peek(PC++, DISASM_NONE);
}
break;
-
+//////////////////////////////////////////////////
+// SAX
case 0x8f:
{
operandAddress = peek(PC++, DISASM_CODE);
operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8);
}
{
- poke(operandAddress, A & X);
+ poke(operandAddress, A & X, DISASM_WRITE);
}
break;
@@ -3660,35 +3797,36 @@ case 0x87:
operandAddress = peek(PC++, DISASM_CODE);
}
{
- poke(operandAddress, A & X);
+ poke(operandAddress, A & X, DISASM_WRITE);
}
break;
case 0x97:
{
operandAddress = peek(PC++, DISASM_CODE);
- peek(operandAddress, DISASM_DATA);
+ peek(operandAddress, DISASM_NONE);
operandAddress = (operandAddress + Y) & 0xFF;
}
{
- poke(operandAddress, A & X);
+ poke(operandAddress, A & X, DISASM_WRITE);
}
break;
case 0x83:
{
uInt8 pointer = peek(PC++, DISASM_CODE);
- peek(pointer, DISASM_DATA);
+ peek(pointer, DISASM_NONE);
pointer += X;
operandAddress = peek(pointer++, DISASM_DATA);
operandAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8);
}
{
- poke(operandAddress, A & X);
+ poke(operandAddress, A & X, DISASM_WRITE);
}
break;
-
+//////////////////////////////////////////////////
+// SBC
case 0xe9:
case 0xeb:
{
@@ -3760,7 +3898,7 @@ break;
case 0xf5:
{
intermediateAddress = peek(PC++, DISASM_CODE);
- peek(intermediateAddress, DISASM_DATA);
+ peek(intermediateAddress, DISASM_NONE);
intermediateAddress += X;
operand = peek(intermediateAddress, DISASM_DATA);
}
@@ -3833,11 +3971,15 @@ case 0xfd:
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
intermediateAddress = high | uInt8(low + X);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + X) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + X;
operand = peek(intermediateAddress, DISASM_DATA);
+ }
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
}
}
{
@@ -3874,12 +4016,16 @@ case 0xf9:
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
intermediateAddress = high | uInt8(low + Y);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + Y) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + Y;
operand = peek(intermediateAddress, DISASM_DATA);
}
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
+ }
}
{
// N, V, Z, C flags are the same in either mode (C calculated at the end)
@@ -3913,7 +4059,7 @@ break;
case 0xe1:
{
uInt8 pointer = peek(PC++, DISASM_CODE);
- peek(pointer, DISASM_DATA);
+ peek(pointer, DISASM_NONE);
pointer += X;
intermediateAddress = peek(pointer++, DISASM_DATA);
intermediateAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8);
@@ -3954,12 +4100,16 @@ case 0xf1:
uInt16 low = peek(pointer++, DISASM_DATA);
uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8);
intermediateAddress = high | uInt8(low + Y);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + Y) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + Y;
operand = peek(intermediateAddress, DISASM_DATA);
}
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
+ }
}
{
// N, V, Z, C flags are the same in either mode (C calculated at the end)
@@ -3990,7 +4140,8 @@ case 0xf1:
}
break;
-
+//////////////////////////////////////////////////
+// SBX
case 0xcb:
{
operand = peek(PC++, DISASM_CODE);
@@ -4005,7 +4156,8 @@ case 0xcb:
}
break;
-
+//////////////////////////////////////////////////
+// SEC
case 0x38:
{
peek(PC, DISASM_NONE);
@@ -4015,7 +4167,8 @@ case 0x38:
}
break;
-
+//////////////////////////////////////////////////
+// SED
case 0xf8:
{
peek(PC, DISASM_NONE);
@@ -4025,7 +4178,8 @@ case 0xf8:
}
break;
-
+//////////////////////////////////////////////////
+// SEI
case 0x78:
{
peek(PC, DISASM_NONE);
@@ -4035,18 +4189,19 @@ case 0x78:
}
break;
-
+//////////////////////////////////////////////////
+// SHA
case 0x9f:
{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
- peek(high | uInt8(low + Y), DISASM_DATA);
+ peek(high | uInt8(low + Y), DISASM_NONE);
operandAddress = (high | low) + Y;
}
{
// NOTE: There are mixed reports on the actual operation
// of this instruction!
- poke(operandAddress, A & X & (((operandAddress >> 8) & 0xff) + 1));
+ poke(operandAddress, A & X & (((operandAddress >> 8) & 0xff) + 1), DISASM_WRITE);
}
break;
@@ -4055,76 +4210,80 @@ case 0x93:
uInt8 pointer = peek(PC++, DISASM_CODE);
uInt16 low = peek(pointer++, DISASM_DATA);
uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8);
- peek(high | uInt8(low + Y), DISASM_DATA);
+ peek(high | uInt8(low + Y), DISASM_NONE);
operandAddress = (high | low) + Y;
}
{
// NOTE: There are mixed reports on the actual operation
// of this instruction!
- poke(operandAddress, A & X & (((operandAddress >> 8) & 0xff) + 1));
+ poke(operandAddress, A & X & (((operandAddress >> 8) & 0xff) + 1), DISASM_WRITE);
}
break;
-
+//////////////////////////////////////////////////
+// SHS
case 0x9b:
{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
- peek(high | uInt8(low + Y), DISASM_DATA);
+ peek(high | uInt8(low + Y), DISASM_NONE);
operandAddress = (high | low) + Y;
}
{
// NOTE: There are mixed reports on the actual operation
// of this instruction!
SP = A & X;
- poke(operandAddress, A & X & (((operandAddress >> 8) & 0xff) + 1));
+ poke(operandAddress, A & X & (((operandAddress >> 8) & 0xff) + 1), DISASM_WRITE);
}
break;
-
+//////////////////////////////////////////////////
+// SHX
case 0x9e:
{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
- peek(high | uInt8(low + Y), DISASM_DATA);
+ peek(high | uInt8(low + Y), DISASM_NONE);
operandAddress = (high | low) + Y;
}
{
// NOTE: There are mixed reports on the actual operation
// of this instruction!
- poke(operandAddress, X & (((operandAddress >> 8) & 0xff) + 1));
+ poke(operandAddress, X & (((operandAddress >> 8) & 0xff) + 1), DISASM_WRITE);
}
break;
-
+//////////////////////////////////////////////////
+// SHY
case 0x9c:
{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
- peek(high | uInt8(low + X), DISASM_DATA);
+ peek(high | uInt8(low + X), DISASM_NONE);
operandAddress = (high | low) + X;
}
{
// NOTE: There are mixed reports on the actual operation
// of this instruction!
- poke(operandAddress, Y & (((operandAddress >> 8) & 0xff) + 1));
+ poke(operandAddress, Y & (((operandAddress >> 8) & 0xff) + 1), DISASM_WRITE);
}
break;
-
+//////////////////////////////////////////////////
+// SLO
case 0x0f:
{
operandAddress = peek(PC++, DISASM_CODE);
operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
// Set carry flag according to the left-most bit in value
C = operand & 0x80;
operand <<= 1;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
A |= operand;
notZ = A;
@@ -4136,17 +4295,17 @@ case 0x1f:
{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
- peek(high | uInt8(low + X), DISASM_DATA);
+ peek(high | uInt8(low + X), DISASM_NONE);
operandAddress = (high | low) + X;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
// Set carry flag according to the left-most bit in value
C = operand & 0x80;
operand <<= 1;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
A |= operand;
notZ = A;
@@ -4158,17 +4317,17 @@ case 0x1b:
{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
- peek(high | uInt8(low + Y), DISASM_DATA);
+ peek(high | uInt8(low + Y), DISASM_NONE);
operandAddress = (high | low) + Y;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
// Set carry flag according to the left-most bit in value
C = operand & 0x80;
operand <<= 1;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
A |= operand;
notZ = A;
@@ -4180,14 +4339,14 @@ case 0x07:
{
operandAddress = peek(PC++, DISASM_CODE);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
// Set carry flag according to the left-most bit in value
C = operand & 0x80;
operand <<= 1;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
A |= operand;
notZ = A;
@@ -4198,17 +4357,17 @@ break;
case 0x17:
{
operandAddress = peek(PC++, DISASM_CODE);
- peek(operandAddress, DISASM_DATA);
+ peek(operandAddress, DISASM_NONE);
operandAddress = (operandAddress + X) & 0xFF;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
// Set carry flag according to the left-most bit in value
C = operand & 0x80;
operand <<= 1;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
A |= operand;
notZ = A;
@@ -4219,19 +4378,19 @@ break;
case 0x03:
{
uInt8 pointer = peek(PC++, DISASM_CODE);
- peek(pointer, DISASM_DATA);
+ peek(pointer, DISASM_NONE);
pointer += X;
operandAddress = peek(pointer++, DISASM_DATA);
operandAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
// Set carry flag according to the left-most bit in value
C = operand & 0x80;
operand <<= 1;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
A |= operand;
notZ = A;
@@ -4244,17 +4403,17 @@ case 0x13:
uInt8 pointer = peek(PC++, DISASM_CODE);
uInt16 low = peek(pointer++, DISASM_DATA);
uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8);
- peek(high | uInt8(low + Y), DISASM_DATA);
+ peek(high | uInt8(low + Y), DISASM_NONE);
operandAddress = (high | low) + Y;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
// Set carry flag according to the left-most bit in value
C = operand & 0x80;
operand <<= 1;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
A |= operand;
notZ = A;
@@ -4262,20 +4421,21 @@ case 0x13:
}
break;
-
+//////////////////////////////////////////////////
+// SRE
case 0x4f:
{
operandAddress = peek(PC++, DISASM_CODE);
operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
// Set carry flag according to the right-most bit in value
C = operand & 0x01;
operand = (operand >> 1) & 0x7f;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
A ^= operand;
notZ = A;
@@ -4287,17 +4447,17 @@ case 0x5f:
{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
- peek(high | uInt8(low + X), DISASM_DATA);
+ peek(high | uInt8(low + X), DISASM_NONE);
operandAddress = (high | low) + X;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
// Set carry flag according to the right-most bit in value
C = operand & 0x01;
operand = (operand >> 1) & 0x7f;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
A ^= operand;
notZ = A;
@@ -4309,17 +4469,17 @@ case 0x5b:
{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
- peek(high | uInt8(low + Y), DISASM_DATA);
+ peek(high | uInt8(low + Y), DISASM_NONE);
operandAddress = (high | low) + Y;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
// Set carry flag according to the right-most bit in value
C = operand & 0x01;
operand = (operand >> 1) & 0x7f;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
A ^= operand;
notZ = A;
@@ -4331,14 +4491,14 @@ case 0x47:
{
operandAddress = peek(PC++, DISASM_CODE);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
// Set carry flag according to the right-most bit in value
C = operand & 0x01;
operand = (operand >> 1) & 0x7f;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
A ^= operand;
notZ = A;
@@ -4349,17 +4509,17 @@ break;
case 0x57:
{
operandAddress = peek(PC++, DISASM_CODE);
- peek(operandAddress, DISASM_DATA);
+ peek(operandAddress, DISASM_NONE);
operandAddress = (operandAddress + X) & 0xFF;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
// Set carry flag according to the right-most bit in value
C = operand & 0x01;
operand = (operand >> 1) & 0x7f;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
A ^= operand;
notZ = A;
@@ -4370,19 +4530,19 @@ break;
case 0x43:
{
uInt8 pointer = peek(PC++, DISASM_CODE);
- peek(pointer, DISASM_DATA);
+ peek(pointer, DISASM_NONE);
pointer += X;
operandAddress = peek(pointer++, DISASM_DATA);
operandAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
// Set carry flag according to the right-most bit in value
C = operand & 0x01;
operand = (operand >> 1) & 0x7f;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
A ^= operand;
notZ = A;
@@ -4395,17 +4555,17 @@ case 0x53:
uInt8 pointer = peek(PC++, DISASM_CODE);
uInt16 low = peek(pointer++, DISASM_DATA);
uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8);
- peek(high | uInt8(low + Y), DISASM_DATA);
+ peek(high | uInt8(low + Y), DISASM_NONE);
operandAddress = (high | low) + Y;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}
{
// Set carry flag according to the right-most bit in value
C = operand & 0x01;
operand = (operand >> 1) & 0x7f;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
A ^= operand;
notZ = A;
@@ -4422,18 +4582,18 @@ case 0x85:
}
SET_LAST_POKE(myLastSrcAddressA)
{
- poke(operandAddress, A);
+ poke(operandAddress, A, DISASM_WRITE);
}
break;
case 0x95:
{
operandAddress = peek(PC++, DISASM_CODE);
- peek(operandAddress, DISASM_DATA);
+ peek(operandAddress, DISASM_NONE);
operandAddress = (operandAddress + X) & 0xFF;
}
{
- poke(operandAddress, A);
+ poke(operandAddress, A, DISASM_WRITE);
}
break;
@@ -4443,7 +4603,7 @@ case 0x8d:
operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8);
}
{
- poke(operandAddress, A);
+ poke(operandAddress, A, DISASM_WRITE);
}
break;
@@ -4451,11 +4611,11 @@ case 0x9d:
{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
- peek(high | uInt8(low + X), DISASM_DATA);
+ peek(high | uInt8(low + X), DISASM_NONE);
operandAddress = (high | low) + X;
}
{
- poke(operandAddress, A);
+ poke(operandAddress, A, DISASM_WRITE);
}
break;
@@ -4463,24 +4623,24 @@ case 0x99:
{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
- peek(high | uInt8(low + Y), DISASM_DATA);
+ peek(high | uInt8(low + Y), DISASM_NONE);
operandAddress = (high | low) + Y;
}
{
- poke(operandAddress, A);
+ poke(operandAddress, A, DISASM_WRITE);
}
break;
case 0x81:
{
uInt8 pointer = peek(PC++, DISASM_CODE);
- peek(pointer, DISASM_DATA);
+ peek(pointer, DISASM_NONE);
pointer += X;
operandAddress = peek(pointer++, DISASM_DATA);
operandAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8);
}
{
- poke(operandAddress, A);
+ poke(operandAddress, A, DISASM_WRITE);
}
break;
@@ -4489,11 +4649,11 @@ case 0x91:
uInt8 pointer = peek(PC++, DISASM_CODE);
uInt16 low = peek(pointer++, DISASM_DATA);
uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8);
- peek(high | uInt8(low + Y), DISASM_DATA);
+ peek(high | uInt8(low + Y), DISASM_NONE);
operandAddress = (high | low) + Y;
}
{
- poke(operandAddress, A);
+ poke(operandAddress, A, DISASM_WRITE);
}
break;
//////////////////////////////////////////////////
@@ -4507,18 +4667,18 @@ case 0x86:
}
SET_LAST_POKE(myLastSrcAddressX)
{
- poke(operandAddress, X);
+ poke(operandAddress, X, DISASM_WRITE);
}
break;
case 0x96:
{
operandAddress = peek(PC++, DISASM_CODE);
- peek(operandAddress, DISASM_DATA);
+ peek(operandAddress, DISASM_NONE);
operandAddress = (operandAddress + Y) & 0xFF;
}
{
- poke(operandAddress, X);
+ poke(operandAddress, X, DISASM_WRITE);
}
break;
@@ -4528,7 +4688,7 @@ case 0x8e:
operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8);
}
{
- poke(operandAddress, X);
+ poke(operandAddress, X, DISASM_WRITE);
}
break;
//////////////////////////////////////////////////
@@ -4542,18 +4702,18 @@ case 0x84:
}
SET_LAST_POKE(myLastSrcAddressY)
{
- poke(operandAddress, Y);
+ poke(operandAddress, Y, DISASM_WRITE);
}
break;
case 0x94:
{
operandAddress = peek(PC++, DISASM_CODE);
- peek(operandAddress, DISASM_DATA);
+ peek(operandAddress, DISASM_NONE);
operandAddress = (operandAddress + X) & 0xFF;
}
{
- poke(operandAddress, Y);
+ poke(operandAddress, Y, DISASM_WRITE);
}
break;
@@ -4563,7 +4723,7 @@ case 0x8c:
operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8);
}
{
- poke(operandAddress, Y);
+ poke(operandAddress, Y, DISASM_WRITE);
}
break;
//////////////////////////////////////////////////
diff --git a/src/emucore/M6502.m4 b/src/emucore/M6502.m4
index cff0b6fbb..78171780c 100644
--- a/src/emucore/M6502.m4
+++ b/src/emucore/M6502.m4
@@ -38,7 +38,7 @@
#ifndef CLEAR_LAST_PEEK
#ifdef DEBUGGER_SUPPORT
- #define CLEAR_LAST_PEEK(_addr) _addr = -1;
+ #define CLEAR_LAST_PEEK(_addr) _addr = 0;
#else
#define CLEAR_LAST_PEEK(_addr)
#endif
@@ -76,63 +76,71 @@ define(M6502_ABSOLUTE_READMODIFYWRITE, `{
operandAddress = peek(PC++, DISASM_CODE);
operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}')
define(M6502_ABSOLUTEX_READ, `{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
intermediateAddress = high | uInt8(low + X);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + X) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + X;
operand = peek(intermediateAddress, DISASM_DATA);
+ }
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
}
}')
define(M6502_ABSOLUTEX_WRITE, `{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
- peek(high | uInt8(low + X), DISASM_DATA);
+ peek(high | uInt8(low + X), DISASM_NONE);
operandAddress = (high | low) + X;
}')
define(M6502_ABSOLUTEX_READMODIFYWRITE, `{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
- peek(high | uInt8(low + X), DISASM_DATA);
+ peek(high | uInt8(low + X), DISASM_NONE);
operandAddress = (high | low) + X;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}')
define(M6502_ABSOLUTEY_READ, `{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
intermediateAddress = high | uInt8(low + Y);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + Y) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + Y;
operand = peek(intermediateAddress, DISASM_DATA);
}
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
+ }
}')
define(M6502_ABSOLUTEY_WRITE, `{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
- peek(high | uInt8(low + Y), DISASM_DATA);
+ peek(high | uInt8(low + Y), DISASM_NONE);
operandAddress = (high | low) + Y;
}')
define(M6502_ABSOLUTEY_READMODIFYWRITE, `{
uInt16 low = peek(PC++, DISASM_CODE);
uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8);
- peek(high | uInt8(low + Y), DISASM_DATA);
+ peek(high | uInt8(low + Y), DISASM_NONE);
operandAddress = (high | low) + Y;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}')
define(M6502_ZERO_READ, `{
@@ -147,49 +155,49 @@ define(M6502_ZERO_WRITE, `{
define(M6502_ZERO_READMODIFYWRITE, `{
operandAddress = peek(PC++, DISASM_CODE);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}')
define(M6502_ZEROX_READ, `{
intermediateAddress = peek(PC++, DISASM_CODE);
- peek(intermediateAddress, DISASM_DATA);
+ peek(intermediateAddress, DISASM_NONE);
intermediateAddress += X;
operand = peek(intermediateAddress, DISASM_DATA);
}')
define(M6502_ZEROX_WRITE, `{
operandAddress = peek(PC++, DISASM_CODE);
- peek(operandAddress, DISASM_DATA);
+ peek(operandAddress, DISASM_NONE);
operandAddress = (operandAddress + X) & 0xFF;
}')
define(M6502_ZEROX_READMODIFYWRITE, `{
operandAddress = peek(PC++, DISASM_CODE);
- peek(operandAddress, DISASM_DATA);
+ peek(operandAddress, DISASM_NONE);
operandAddress = (operandAddress + X) & 0xFF;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}')
define(M6502_ZEROY_READ, `{
intermediateAddress = peek(PC++, DISASM_CODE);
- peek(intermediateAddress, DISASM_DATA);
+ peek(intermediateAddress, DISASM_NONE);
intermediateAddress += Y;
operand = peek(intermediateAddress, DISASM_DATA);
}')
define(M6502_ZEROY_WRITE, `{
operandAddress = peek(PC++, DISASM_CODE);
- peek(operandAddress, DISASM_DATA);
+ peek(operandAddress, DISASM_NONE);
operandAddress = (operandAddress + Y) & 0xFF;
}')
define(M6502_ZEROY_READMODIFYWRITE, `{
operandAddress = peek(PC++, DISASM_CODE);
- peek(operandAddress, DISASM_DATA);
+ peek(operandAddress, DISASM_NONE);
operandAddress = (operandAddress + Y) & 0xFF;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}')
define(M6502_INDIRECT, `{
@@ -205,7 +213,7 @@ define(M6502_INDIRECT, `{
define(M6502_INDIRECTX_READ, `{
uInt8 pointer = peek(PC++, DISASM_CODE);
- peek(pointer, DISASM_DATA);
+ peek(pointer, DISASM_NONE);
pointer += X;
intermediateAddress = peek(pointer++, DISASM_DATA);
intermediateAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8);
@@ -214,7 +222,7 @@ define(M6502_INDIRECTX_READ, `{
define(M6502_INDIRECTX_WRITE, `{
uInt8 pointer = peek(PC++, DISASM_CODE);
- peek(pointer, DISASM_DATA);
+ peek(pointer, DISASM_NONE);
pointer += X;
operandAddress = peek(pointer++, DISASM_DATA);
operandAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8);
@@ -222,12 +230,12 @@ define(M6502_INDIRECTX_WRITE, `{
define(M6502_INDIRECTX_READMODIFYWRITE, `{
uInt8 pointer = peek(PC++, DISASM_CODE);
- peek(pointer, DISASM_DATA);
+ peek(pointer, DISASM_NONE);
pointer += X;
operandAddress = peek(pointer++, DISASM_DATA);
operandAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8);
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}')
define(M6502_INDIRECTY_READ, `{
@@ -235,19 +243,23 @@ define(M6502_INDIRECTY_READ, `{
uInt16 low = peek(pointer++, DISASM_DATA);
uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8);
intermediateAddress = high | uInt8(low + Y);
- operand = peek(intermediateAddress, DISASM_DATA);
if((low + Y) > 0xFF)
{
+ operand = peek(intermediateAddress, DISASM_NONE);
intermediateAddress = (high | low) + Y;
operand = peek(intermediateAddress, DISASM_DATA);
}
+ else
+ {
+ operand = peek(intermediateAddress, DISASM_DATA);
+ }
}')
define(M6502_INDIRECTY_WRITE, `{
uInt8 pointer = peek(PC++, DISASM_CODE);
uInt16 low = peek(pointer++, DISASM_DATA);
uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8);
- peek(high | uInt8(low + Y), DISASM_DATA);
+ peek(high | uInt8(low + Y), DISASM_NONE);
operandAddress = (high | low) + Y;
}')
@@ -255,13 +267,12 @@ define(M6502_INDIRECTY_READMODIFYWRITE, `{
uInt8 pointer = peek(PC++, DISASM_CODE);
uInt16 low = peek(pointer++, DISASM_DATA);
uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8);
- peek(high | uInt8(low + Y), DISASM_DATA);
+ peek(high | uInt8(low + Y), DISASM_NONE);
operandAddress = (high | low) + Y;
operand = peek(operandAddress, DISASM_DATA);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
}')
-
define(M6502_BCC, `{
if(!C)
{
@@ -449,7 +460,7 @@ define(M6502_ASL, `{
C = operand & 0x80;
operand <<= 1;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
notZ = operand;
N = operand & 0x80;
@@ -484,18 +495,18 @@ define(M6502_BIT, `{
}')
define(M6502_BRK, `{
- peek(PC++, DISASM_CODE);
+ peek(PC++, DISASM_NONE);
B = true;
- poke(0x0100 + SP--, PC >> 8);
- poke(0x0100 + SP--, PC & 0x00ff);
- poke(0x0100 + SP--, PS());
+ poke(0x0100 + SP--, PC >> 8, DISASM_WRITE);
+ poke(0x0100 + SP--, PC & 0x00ff, DISASM_WRITE);
+ poke(0x0100 + SP--, PS(), DISASM_WRITE);
I = true;
- PC = peek(0xfffe, DISASM_NONE);
- PC |= (uInt16(peek(0xffff, DISASM_NONE)) << 8);
+ PC = peek(0xfffe, DISASM_DATA);
+ PC |= (uInt16(peek(0xffff, DISASM_DATA)) << 8);
}')
define(M6502_CLC, `{
@@ -540,7 +551,7 @@ define(M6502_CPY, `{
define(M6502_DCP, `{
uInt8 value = operand - 1;
- poke(operandAddress, value);
+ poke(operandAddress, value, DISASM_WRITE);
uInt16 value2 = uInt16(A) - uInt16(value);
notZ = value2;
@@ -550,7 +561,7 @@ define(M6502_DCP, `{
define(M6502_DEC, `{
uInt8 value = operand - 1;
- poke(operandAddress, value);
+ poke(operandAddress, value, DISASM_WRITE);
notZ = value;
N = value & 0x80;
@@ -579,7 +590,7 @@ define(M6502_EOR, `{
define(M6502_INC, `{
uInt8 value = operand + 1;
- poke(operandAddress, value);
+ poke(operandAddress, value, DISASM_WRITE);
notZ = value;
N = value & 0x80;
@@ -599,7 +610,7 @@ define(M6502_INY, `{
define(M6502_ISB, `{
operand = operand + 1;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
// N, V, Z, C flags are the same in either mode (C calculated at the end)
Int32 sum = A - operand - (C ? 0 : 1);
@@ -639,8 +650,8 @@ define(M6502_JSR, `{
// It seems that the 650x does not push the address of the next instruction
// on the stack it actually pushes the address of the next instruction
// minus one. This is compensated for in the RTS instruction
- poke(0x0100 + SP--, PC >> 8);
- poke(0x0100 + SP--, PC & 0xff);
+ poke(0x0100 + SP--, PC >> 8, DISASM_WRITE);
+ poke(0x0100 + SP--, PC & 0xff, DISASM_WRITE);
PC = (low | (uInt16(peek(PC, DISASM_CODE)) << 8));
}')
@@ -681,7 +692,7 @@ define(M6502_LSR, `{
C = operand & 0x01;
operand = (operand >> 1) & 0x7f;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
notZ = operand;
N = operand & 0x80;
@@ -716,28 +727,28 @@ define(M6502_ORA, `{
}')
define(M6502_PHA, `{
- poke(0x0100 + SP--, A);
+ poke(0x0100 + SP--, A, DISASM_WRITE);
}')
define(M6502_PHP, `{
- poke(0x0100 + SP--, PS());
+ poke(0x0100 + SP--, PS(), DISASM_WRITE);
}')
define(M6502_PLA, `{
peek(0x0100 + SP++, DISASM_NONE);
- A = peek(0x0100 + SP, DISASM_NONE);
+ A = peek(0x0100 + SP, DISASM_DATA);
notZ = A;
N = A & 0x80;
}')
define(M6502_PLP, `{
peek(0x0100 + SP++, DISASM_NONE);
- PS(peek(0x0100 + SP, DISASM_NONE));
+ PS(peek(0x0100 + SP, DISASM_DATA));
}')
define(M6502_RLA, `{
uInt8 value = (operand << 1) | (C ? 1 : 0);
- poke(operandAddress, value);
+ poke(operandAddress, value, DISASM_WRITE);
A &= value;
C = operand & 0x80;
@@ -752,7 +763,7 @@ define(M6502_ROL, `{
C = operand & 0x80;
operand = (operand << 1) | (oldC ? 1 : 0);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
notZ = operand;
N = operand & 0x80;
@@ -777,7 +788,7 @@ define(M6502_ROR, `{
C = operand & 0x01;
operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
notZ = operand;
N = operand & 0x80;
@@ -802,7 +813,7 @@ define(M6502_RRA, `{
C = operand & 0x01;
operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00);
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
if(!D)
{
@@ -845,11 +856,11 @@ define(M6502_RTS, `{
peek(0x0100 + SP++, DISASM_NONE);
PC = peek(0x0100 + SP++, DISASM_NONE);
PC |= (uInt16(peek(0x0100 + SP, DISASM_NONE)) << 8);
- peek(PC++, DISASM_CODE);
+ peek(PC++, DISASM_NONE);
}')
define(M6502_SAX, `{
- poke(operandAddress, A & X);
+ poke(operandAddress, A & X, DISASM_WRITE);
}')
define(M6502_SBC, `{
@@ -904,26 +915,26 @@ define(M6502_SEI, `{
define(M6502_SHA, `{
// NOTE: There are mixed reports on the actual operation
// of this instruction!
- poke(operandAddress, A & X & (((operandAddress >> 8) & 0xff) + 1));
+ poke(operandAddress, A & X & (((operandAddress >> 8) & 0xff) + 1), DISASM_WRITE);
}')
define(M6502_SHS, `{
// NOTE: There are mixed reports on the actual operation
// of this instruction!
SP = A & X;
- poke(operandAddress, A & X & (((operandAddress >> 8) & 0xff) + 1));
+ poke(operandAddress, A & X & (((operandAddress >> 8) & 0xff) + 1), DISASM_WRITE);
}')
define(M6502_SHX, `{
// NOTE: There are mixed reports on the actual operation
// of this instruction!
- poke(operandAddress, X & (((operandAddress >> 8) & 0xff) + 1));
+ poke(operandAddress, X & (((operandAddress >> 8) & 0xff) + 1), DISASM_WRITE);
}')
define(M6502_SHY, `{
// NOTE: There are mixed reports on the actual operation
// of this instruction!
- poke(operandAddress, Y & (((operandAddress >> 8) & 0xff) + 1));
+ poke(operandAddress, Y & (((operandAddress >> 8) & 0xff) + 1), DISASM_WRITE);
}')
define(M6502_SLO, `{
@@ -931,7 +942,7 @@ define(M6502_SLO, `{
C = operand & 0x80;
operand <<= 1;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
A |= operand;
notZ = A;
@@ -943,7 +954,7 @@ define(M6502_SRE, `{
C = operand & 0x01;
operand = (operand >> 1) & 0x7f;
- poke(operandAddress, operand);
+ poke(operandAddress, operand, DISASM_WRITE);
A ^= operand;
notZ = A;
@@ -951,15 +962,15 @@ define(M6502_SRE, `{
}')
define(M6502_STA, `{
- poke(operandAddress, A);
+ poke(operandAddress, A, DISASM_WRITE);
}')
define(M6502_STX, `{
- poke(operandAddress, X);
+ poke(operandAddress, X, DISASM_WRITE);
}')
define(M6502_STY, `{
- poke(operandAddress, Y);
+ poke(operandAddress, Y, DISASM_WRITE);
}')
define(M6502_TAX, `{
@@ -996,7 +1007,8 @@ define(M6502_TYA, `{
N = A & 0x80;
}')
-
+//////////////////////////////////////////////////
+// ADC
case 0x69:
M6502_IMMEDIATE_READ
M6502_ADC
@@ -1037,20 +1049,23 @@ M6502_INDIRECTY_READ
M6502_ADC
break;
-
+//////////////////////////////////////////////////
+// ASR
case 0x4b:
M6502_IMMEDIATE_READ
M6502_ASR
break;
-
+//////////////////////////////////////////////////
+// ANC
case 0x0b:
case 0x2b:
M6502_IMMEDIATE_READ
M6502_ANC
break;
-
+//////////////////////////////////////////////////
+// AND
case 0x29:
M6502_IMMEDIATE_READ
M6502_AND
@@ -1091,19 +1106,22 @@ M6502_INDIRECTY_READ
M6502_AND
break;
-
+//////////////////////////////////////////////////
+// ANE
case 0x8b:
M6502_IMMEDIATE_READ
M6502_ANE
break;
-
+//////////////////////////////////////////////////
+// ARR
case 0x6b:
M6502_IMMEDIATE_READ
M6502_ARR
break;
-
+//////////////////////////////////////////////////
+// ASL
case 0x0a:
M6502_IMPLIED
M6502_ASLA
@@ -1129,7 +1147,20 @@ M6502_ABSOLUTEX_READMODIFYWRITE
M6502_ASL
break;
+//////////////////////////////////////////////////
+// BIT
+case 0x24:
+M6502_ZERO_READ
+M6502_BIT
+break;
+case 0x2C:
+M6502_ABSOLUTE_READ
+M6502_BIT
+break;
+
+//////////////////////////////////////////////////
+// Branches
case 0x90:
M6502_IMMEDIATE_READ
M6502_BCC
@@ -1148,17 +1179,6 @@ M6502_BEQ
break;
-case 0x24:
-M6502_ZERO_READ
-M6502_BIT
-break;
-
-case 0x2C:
-M6502_ABSOLUTE_READ
-M6502_BIT
-break;
-
-
case 0x30:
M6502_IMMEDIATE_READ
M6502_BMI
@@ -1177,11 +1197,6 @@ M6502_BPL
break;
-case 0x00:
-M6502_BRK
-break;
-
-
case 0x50:
M6502_IMMEDIATE_READ
M6502_BVC
@@ -1193,31 +1208,42 @@ M6502_IMMEDIATE_READ
M6502_BVS
break;
+//////////////////////////////////////////////////
+// BRK
+case 0x00:
+M6502_BRK
+break;
+//////////////////////////////////////////////////
+// CLC
case 0x18:
M6502_IMPLIED
M6502_CLC
break;
-
+//////////////////////////////////////////////////
+// CLD
case 0xd8:
M6502_IMPLIED
M6502_CLD
break;
-
+//////////////////////////////////////////////////
+// CLI
case 0x58:
M6502_IMPLIED
M6502_CLI
break;
-
+//////////////////////////////////////////////////
+// CLV
case 0xb8:
M6502_IMPLIED
M6502_CLV
break;
-
+//////////////////////////////////////////////////
+// CMP
case 0xc9:
M6502_IMMEDIATE_READ
M6502_CMP
@@ -1258,7 +1284,8 @@ M6502_INDIRECTY_READ
M6502_CMP
break;
-
+//////////////////////////////////////////////////
+// CPX
case 0xe0:
M6502_IMMEDIATE_READ
M6502_CPX
@@ -1274,7 +1301,8 @@ M6502_ABSOLUTE_READ
M6502_CPX
break;
-
+//////////////////////////////////////////////////
+// CPY
case 0xc0:
M6502_IMMEDIATE_READ
M6502_CPY
@@ -1290,7 +1318,8 @@ M6502_ABSOLUTE_READ
M6502_CPY
break;
-
+//////////////////////////////////////////////////
+// DCP
case 0xcf:
M6502_ABSOLUTE_READMODIFYWRITE
M6502_DCP
@@ -1326,7 +1355,8 @@ M6502_INDIRECTY_READMODIFYWRITE
M6502_DCP
break;
-
+//////////////////////////////////////////////////
+// DEC
case 0xc6:
M6502_ZERO_READMODIFYWRITE
M6502_DEC
@@ -1347,19 +1377,22 @@ M6502_ABSOLUTEX_READMODIFYWRITE
M6502_DEC
break;
-
+//////////////////////////////////////////////////
+// DEX
case 0xca:
M6502_IMPLIED
M6502_DEX
break;
-
+//////////////////////////////////////////////////
+// DEY
case 0x88:
M6502_IMPLIED
M6502_DEY
break;
-
+//////////////////////////////////////////////////
+// EOR
case 0x49:
M6502_IMMEDIATE_READ
M6502_EOR
@@ -1400,7 +1433,8 @@ M6502_INDIRECTY_READ
M6502_EOR
break;
-
+//////////////////////////////////////////////////
+// INC
case 0xe6:
M6502_ZERO_READMODIFYWRITE
M6502_INC
@@ -1421,19 +1455,22 @@ M6502_ABSOLUTEX_READMODIFYWRITE
M6502_INC
break;
-
+//////////////////////////////////////////////////
+// INX
case 0xe8:
M6502_IMPLIED
M6502_INX
break;
-
+//////////////////////////////////////////////////
+// INY
case 0xc8:
M6502_IMPLIED
M6502_INY
break;
-
+//////////////////////////////////////////////////
+// ISB
case 0xef:
M6502_ABSOLUTE_READMODIFYWRITE
M6502_ISB
@@ -1469,7 +1506,8 @@ M6502_INDIRECTY_READMODIFYWRITE
M6502_ISB
break;
-
+//////////////////////////////////////////////////
+// JMP
case 0x4c:
M6502_ABSOLUTE_WRITE
M6502_JMP
@@ -1480,12 +1518,14 @@ M6502_INDIRECT
M6502_JMP
break;
-
+//////////////////////////////////////////////////
+// JSR
case 0x20:
M6502_JSR
break;
-
+//////////////////////////////////////////////////
+// LAS
case 0xbb:
M6502_ABSOLUTEY_READ
M6502_LAS
@@ -1657,7 +1697,8 @@ M6502_LDY
break;
//////////////////////////////////////////////////
-
+//////////////////////////////////////////////////
+// LSR
case 0x4a:
M6502_IMPLIED
M6502_LSRA
@@ -1684,13 +1725,15 @@ M6502_ABSOLUTEX_READMODIFYWRITE
M6502_LSR
break;
-
+//////////////////////////////////////////////////
+// LXA
case 0xab:
M6502_IMMEDIATE_READ
M6502_LXA
break;
-
+//////////////////////////////////////////////////
+// NOP
case 0x1a:
case 0x3a:
case 0x5a:
@@ -1795,35 +1838,40 @@ M6502_ORA
break;
//////////////////////////////////////////////////
-
+//////////////////////////////////////////////////
+// PHA
case 0x48:
M6502_IMPLIED
// TODO - add tracking for this opcode
M6502_PHA
break;
-
+//////////////////////////////////////////////////
+// PHP
case 0x08:
M6502_IMPLIED
// TODO - add tracking for this opcode
M6502_PHP
break;
-
+//////////////////////////////////////////////////
+// PLA
case 0x68:
M6502_IMPLIED
// TODO - add tracking for this opcode
M6502_PLA
break;
-
+//////////////////////////////////////////////////
+// PLP
case 0x28:
M6502_IMPLIED
// TODO - add tracking for this opcode
M6502_PLP
break;
-
+//////////////////////////////////////////////////
+// RLA
case 0x2f:
M6502_ABSOLUTE_READMODIFYWRITE
M6502_RLA
@@ -1859,13 +1907,13 @@ M6502_INDIRECTY_READMODIFYWRITE
M6502_RLA
break;
-
+//////////////////////////////////////////////////
+// ROL
case 0x2a:
M6502_IMPLIED
M6502_ROLA
break;
-
case 0x26:
M6502_ZERO_READMODIFYWRITE
M6502_ROL
@@ -1886,7 +1934,8 @@ M6502_ABSOLUTEX_READMODIFYWRITE
M6502_ROL
break;
-
+//////////////////////////////////////////////////
+// ROR
case 0x6a:
M6502_IMPLIED
M6502_RORA
@@ -1912,7 +1961,8 @@ M6502_ABSOLUTEX_READMODIFYWRITE
M6502_ROR
break;
-
+//////////////////////////////////////////////////
+// RRA
case 0x6f:
M6502_ABSOLUTE_READMODIFYWRITE
M6502_RRA
@@ -1948,19 +1998,22 @@ M6502_INDIRECTY_READMODIFYWRITE
M6502_RRA
break;
-
+//////////////////////////////////////////////////
+// RTI
case 0x40:
M6502_IMPLIED
M6502_RTI
break;
-
+//////////////////////////////////////////////////
+// RTS
case 0x60:
M6502_IMPLIED
M6502_RTS
break;
-
+//////////////////////////////////////////////////
+// SAX
case 0x8f:
M6502_ABSOLUTE_WRITE
M6502_SAX
@@ -1981,7 +2034,8 @@ M6502_INDIRECTX_WRITE
M6502_SAX
break;
-
+//////////////////////////////////////////////////
+// SBC
case 0xe9:
case 0xeb:
M6502_IMMEDIATE_READ
@@ -2023,31 +2077,36 @@ M6502_INDIRECTY_READ
M6502_SBC
break;
-
+//////////////////////////////////////////////////
+// SBX
case 0xcb:
M6502_IMMEDIATE_READ
M6502_SBX
break;
-
+//////////////////////////////////////////////////
+// SEC
case 0x38:
M6502_IMPLIED
M6502_SEC
break;
-
+//////////////////////////////////////////////////
+// SED
case 0xf8:
M6502_IMPLIED
M6502_SED
break;
-
+//////////////////////////////////////////////////
+// SEI
case 0x78:
M6502_IMPLIED
M6502_SEI
break;
-
+//////////////////////////////////////////////////
+// SHA
case 0x9f:
M6502_ABSOLUTEY_WRITE
M6502_SHA
@@ -2058,25 +2117,29 @@ M6502_INDIRECTY_WRITE
M6502_SHA
break;
-
+//////////////////////////////////////////////////
+// SHS
case 0x9b:
M6502_ABSOLUTEY_WRITE
M6502_SHS
break;
-
+//////////////////////////////////////////////////
+// SHX
case 0x9e:
M6502_ABSOLUTEY_WRITE
M6502_SHX
break;
-
+//////////////////////////////////////////////////
+// SHY
case 0x9c:
M6502_ABSOLUTEX_WRITE
M6502_SHY
break;
-
+//////////////////////////////////////////////////
+// SLO
case 0x0f:
M6502_ABSOLUTE_READMODIFYWRITE
M6502_SLO
@@ -2112,7 +2175,8 @@ M6502_INDIRECTY_READMODIFYWRITE
M6502_SLO
break;
-
+//////////////////////////////////////////////////
+// SRE
case 0x4f:
M6502_ABSOLUTE_READMODIFYWRITE
M6502_SRE
diff --git a/src/emucore/M6532.cxx b/src/emucore/M6532.cxx
index b495f222c..557ba5c71 100644
--- a/src/emucore/M6532.cxx
+++ b/src/emucore/M6532.cxx
@@ -23,6 +23,10 @@
#include "Settings.hxx"
#include "Switches.hxx"
#include "System.hxx"
+#ifdef DEBUGGER_SUPPORT
+ //#include "Debugger.hxx"
+ #include "CartDebug.hxx"
+#endif
#include "M6532.hxx"
@@ -31,11 +35,13 @@ M6532::M6532(const Console& console, const Settings& settings)
: myConsole(console),
mySettings(settings),
myTimer(0), mySubTimer(0), myDivider(1),
- myTimerWrapped(false), myWrappedThisCycle(false), mySetTimerCycle(0), myLastCycle(0),
+ myTimerWrapped(false), myWrappedThisCycle(false),
+ mySetTimerCycle(0), myLastCycle(0),
myDDRA(0), myDDRB(0), myOutA(0), myOutB(0),
myInterruptFlag(false),
- myEdgeDetectPositive(false)
-{
+ myEdgeDetectPositive(false),
+ myRAMAccessBase(nullptr)
+{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -54,8 +60,7 @@ void M6532::reset()
myTimerWrapped = false;
myWrappedThisCycle = false;
- mySetTimerCycle = 0;
- myLastCycle = mySystem->cycles();
+ mySetTimerCycle = myLastCycle = 0;
// Zero the I/O registers
myDDRA = myDDRB = myOutA = myOutB = 0x00;
@@ -68,19 +73,14 @@ void M6532::reset()
// Edge-detect set to negative (high to low)
myEdgeDetectPositive = false;
-}
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void M6532::systemCyclesReset()
-{
- // System cycles are being reset to zero so we need to adjust
- // the cycle count we remembered when the timer was last set
- myLastCycle -= mySystem->cycles();
- mySetTimerCycle -= mySystem->cycles();
+ // Let the controllers know about the reset
+ myConsole.leftController().reset();
+ myConsole.rightController().reset();
- // We should also inform any 'smart' controllers as well
- myConsole.leftController().systemCyclesReset();
- myConsole.rightController().systemCyclesReset();
+#ifdef DEBUGGER_SUPPORT
+ createAccessBases();
+#endif // DEBUGGER_SUPPORT
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -109,7 +109,7 @@ void M6532::update()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void M6532::updateEmulation()
{
- uInt32 cycles = mySystem->cycles() - myLastCycle;
+ uInt32 cycles = uInt32(mySystem->cycles() - myLastCycle);
uInt32 subTimer = mySubTimer;
// Guard against further state changes if the debugger alread forwarded emulation
@@ -159,10 +159,17 @@ void M6532::installDelegate(System& system, Device& device)
// All accesses are to the given device
System::PageAccess access(&device, System::PA_READWRITE);
- // We're installing in a 2600 system
- for(int address = 0; address < 8192; address += (1 << System::PAGE_SHIFT))
- if((address & 0x1080) == 0x0080)
- mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
+ // Map all peek/poke to mirrors of RIOT address space to this class
+ // That is, all mirrors of ZP RAM ($80 - $FF) and IO ($280 - $29F) in the
+ // lower 4K of the 2600 address space are mapped here
+ // The two types of addresses are differentiated in peek/poke as follows:
+ // (addr & 0x0200) == 0x0200 is IO (A9 is 1)
+ // (addr & 0x0300) == 0x0100 is Stack (A8 is 1, A9 is 0)
+ // (addr & 0x0300) == 0x0000 is ZP RAM (A8 is 0, A9 is 0)
+ for (uInt16 addr = 0; addr < 0x1000; addr += System::PAGE_SIZE)
+ if ((addr & 0x0080) == 0x0080) {
+ mySystem->setPageAccess(addr, access);
+ }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -170,11 +177,10 @@ uInt8 M6532::peek(uInt16 addr)
{
updateEmulation();
- // Access RAM directly. Originally, accesses to RAM could bypass
- // this method and its pages could be installed directly into the
- // system. However, certain cartridges (notably 4A50) can mirror
- // the RAM address space, making it necessary to chain accesses.
- if((addr & 0x1080) == 0x0080 && (addr & 0x0200) == 0x0000)
+ // A9 distinguishes I/O registers from ZP RAM
+ // A9 = 1 is read from I/O
+ // A9 = 0 is read from RAM
+ if((addr & 0x0200) == 0x0000)
return myRAM[addr & 0x007f];
switch(addr & 0x07)
@@ -239,11 +245,10 @@ bool M6532::poke(uInt16 addr, uInt8 value)
{
updateEmulation();
- // Access RAM directly. Originally, accesses to RAM could bypass
- // this method and its pages could be installed directly into the
- // system. However, certain cartridges (notably 4A50) can mirror
- // the RAM address space, making it necessary to chain accesses.
- if((addr & 0x1080) == 0x0080 && (addr & 0x0200) == 0x0000)
+ // A9 distinguishes I/O registers from ZP RAM
+ // A9 = 1 is write to I/O
+ // A9 = 0 is write to RAM
+ if((addr & 0x0200) == 0x0000)
{
myRAM[addr & 0x007f] = value;
return true;
@@ -361,8 +366,8 @@ bool M6532::save(Serializer& out) const
out.putInt(myDivider);
out.putBool(myTimerWrapped);
out.putBool(myWrappedThisCycle);
- out.putInt(myLastCycle);
- out.putInt(mySetTimerCycle);
+ out.putLong(myLastCycle);
+ out.putLong(mySetTimerCycle);
out.putByte(myDDRA);
out.putByte(myDDRB);
@@ -397,8 +402,8 @@ bool M6532::load(Serializer& in)
myDivider = in.getInt();
myTimerWrapped = in.getBool();
myWrappedThisCycle = in.getBool();
- myLastCycle = in.getInt();
- mySetTimerCycle = in.getInt();
+ myLastCycle = in.getLong();
+ mySetTimerCycle = in.getLong();
myDDRA = in.getByte();
myDDRB = in.getByte();
@@ -449,5 +454,56 @@ Int32 M6532::intimClocks()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 M6532::timerClocks() const
{
- return mySystem->cycles() - mySetTimerCycle;
+ return uInt32(mySystem->cycles() - mySetTimerCycle);
}
+
+#ifdef DEBUGGER_SUPPORT
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void M6532::createAccessBases()
+{
+#ifdef DEBUGGER_SUPPORT
+ myRAMAccessBase = make_unique(RAM_SIZE);
+ memset(myRAMAccessBase.get(), CartDebug::NONE, RAM_SIZE);
+ myStackAccessBase = make_unique(STACK_SIZE);
+ memset(myStackAccessBase.get(), CartDebug::NONE, STACK_SIZE);
+ myIOAccessBase = make_unique(IO_SIZE);
+ memset(myIOAccessBase.get(), CartDebug::NONE, IO_SIZE);
+
+ myZPAccessDelay = make_unique(RAM_SIZE);
+ memset(myZPAccessDelay.get(), ZP_DELAY, RAM_SIZE);
+#else
+ myRAMAccessBase = myStackAccessBase = myIOAccessBase = nullptr;
+#endif
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+uInt8 M6532::getAccessFlags(uInt16 address) const
+{
+ if (address & IO_BIT)
+ return myIOAccessBase[address & IO_MASK];
+ else if (address & STACK_BIT)
+ return myStackAccessBase[address & STACK_MASK];
+ else
+ return myRAMAccessBase[address & RAM_MASK];
+ return 0;
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void M6532::setAccessFlags(uInt16 address, uInt8 flags)
+{
+ // ignore none flag
+ if (flags != CartDebug::NONE) {
+ if (address & IO_BIT)
+ myIOAccessBase[address & IO_MASK] |= flags;
+ else {
+ // the first access, either by direct RAM or stack access is assumed as initialization
+ if (myZPAccessDelay[address & RAM_MASK])
+ myZPAccessDelay[address & RAM_MASK]--;
+ else if (address & STACK_BIT)
+ myStackAccessBase[address & STACK_MASK] |= flags;
+ else
+ myRAMAccessBase[address & RAM_MASK] |= flags;
+ }
+ }
+}
+#endif // DEBUGGER_SUPPORT
\ No newline at end of file
diff --git a/src/emucore/M6532.hxx b/src/emucore/M6532.hxx
index a42ebeb81..fbffb4b12 100644
--- a/src/emucore/M6532.hxx
+++ b/src/emucore/M6532.hxx
@@ -60,13 +60,6 @@ class M6532 : public Device
*/
void reset() override;
- /**
- Notification method invoked by the system right before the
- system resets its cycle counter to zero. It may be necessary
- to override this method for devices that remember cycle counts.
- */
- void systemCyclesReset() override;
-
/**
Update the entire digital and analog pin state of ports A and B.
*/
@@ -146,6 +139,17 @@ class M6532 : public Device
uInt8 timint();
Int32 intimClocks();
uInt32 timerClocks() const;
+#ifdef DEBUGGER_SUPPORT
+ void createAccessBases();
+ /**
+ Query/change the given address type to use the given disassembly flags
+
+ @param address The address to modify
+ @param flags A bitfield of DisasmType directives for the given address
+ */
+ uInt8 getAccessFlags(uInt16 address) const override;
+ void setAccessFlags(uInt16 address, uInt8 flags) override;
+#endif // DEBUGGER_SUPPORT
private:
// Accessible bits in the interrupt flag register
@@ -178,10 +182,10 @@ class M6532 : public Device
bool myWrappedThisCycle;
// Cycle when the timer set. Debugging only.
- Int32 mySetTimerCycle;
+ uInt64 mySetTimerCycle;
// Last cycle considered in emu updates
- Int32 myLastCycle;
+ uInt64 myLastCycle;
// Data Direction Register for Port A
uInt8 myDDRA;
@@ -205,6 +209,22 @@ class M6532 : public Device
// Last value written to the timer registers
uInt8 myOutTimer[4];
+#ifdef DEBUGGER_SUPPORT
+ // The arrays containing information about every byte of RIOT
+ // indicating whether and how (RW) it is used.
+ BytePtr myRAMAccessBase;
+ BytePtr myStackAccessBase;
+ BytePtr myIOAccessBase;
+ // The array used to skip the first ZP access tracking
+ BytePtr myZPAccessDelay;
+
+ static constexpr uInt16
+ RAM_SIZE = 0x80, RAM_MASK = RAM_SIZE - 1,
+ STACK_SIZE = RAM_SIZE, STACK_MASK = RAM_MASK, STACK_BIT = 0x100,
+ IO_SIZE = 0x20, IO_MASK = IO_SIZE - 1, IO_BIT = 0x200,
+ ZP_DELAY = 1;
+#endif // DEBUGGER_SUPPORT
+
private:
// Following constructors and assignment operators not supported
M6532() = delete;
diff --git a/src/emucore/MT24LC256.cxx b/src/emucore/MT24LC256.cxx
index b2dad531f..4f4305e2c 100644
--- a/src/emucore/MT24LC256.cxx
+++ b/src/emucore/MT24LC256.cxx
@@ -144,6 +144,13 @@ void MT24LC256::update()
}
}
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void MT24LC256::systemReset()
+{
+ myCyclesWhenSDASet = myCyclesWhenSCLSet = myCyclesWhenTimerSet =
+ mySystem.cycles();
+}
+
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void MT24LC256::erase()
{
@@ -151,17 +158,6 @@ void MT24LC256::erase()
myDataChanged = true;
}
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void MT24LC256::systemCyclesReset()
-{
- // System cycles are being reset to zero so we need to adjust
- // the cycle counts we remembered
- uInt32 cycles = mySystem.cycles();
- myCyclesWhenSDASet -= cycles;
- myCyclesWhenSCLSet -= cycles;
- myCyclesWhenTimerSet -= cycles;
-}
-
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void MT24LC256::jpee_init()
{
@@ -366,7 +362,7 @@ bool MT24LC256::jpee_timercheck(int mode)
{
if(myTimerActive)
{
- uInt32 elapsed = mySystem.cycles() - myCyclesWhenTimerSet;
+ uInt32 elapsed = uInt32(mySystem.cycles() - myCyclesWhenTimerSet);
myTimerActive = elapsed < uInt32(5000000.0 / 838.0);
}
return myTimerActive;
diff --git a/src/emucore/MT24LC256.hxx b/src/emucore/MT24LC256.hxx
index 9fd246d9c..1f110aea9 100644
--- a/src/emucore/MT24LC256.hxx
+++ b/src/emucore/MT24LC256.hxx
@@ -50,16 +50,12 @@ class MT24LC256
void writeSDA(bool state);
void writeSCL(bool state);
+ /** Called when the system is being reset */
+ void systemReset();
+
/** Erase entire EEPROM to known state ($FF) */
void erase();
- /**
- Notification method invoked by the system right before the
- system resets its cycle counter to zero. It may be necessary
- to override this method for devices that remember cycle counts.
- */
- void systemCyclesReset();
-
private:
// I2C access code provided by Supercat
void jpee_init();
@@ -85,10 +81,10 @@ class MT24LC256
bool myTimerActive;
// Indicates when the timer was set
- uInt32 myCyclesWhenTimerSet;
+ uInt64 myCyclesWhenTimerSet;
// Indicates when the SDA and SCL pins were set/written
- uInt32 myCyclesWhenSDASet, myCyclesWhenSCLSet;
+ uInt64 myCyclesWhenSDASet, myCyclesWhenSCLSet;
// The file containing the EEPROM data
string myDataFile;
diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx
index 23025eb0f..ea27471eb 100644
--- a/src/emucore/OSystem.cxx
+++ b/src/emucore/OSystem.cxx
@@ -190,8 +190,8 @@ void OSystem::setConfigPaths()
string s;
validatePath(myStateDir, "statedir", myBaseDir + "state");
- validatePath(mySnapshotSaveDir, "snapsavedir", defaultSnapSaveDir());
- validatePath(mySnapshotLoadDir, "snaploaddir", defaultSnapLoadDir());
+ validatePath(mySnapshotSaveDir, "snapsavedir", defaultSaveDir());
+ validatePath(mySnapshotLoadDir, "snaploaddir", defaultLoadDir());
validatePath(myNVRamDir, "nvramdir", myBaseDir + "nvram");
validatePath(myCfgDir, "cfgdir", myBaseDir + "cfg");
@@ -361,38 +361,7 @@ string OSystem::createConsole(const FilesystemNode& rom, const string& md5sum,
// Also check if certain virtual buttons should be held down
// These must be checked each time a new console is being created
- if(mySettings->getBool("holdreset"))
- myEventHandler->handleEvent(Event::ConsoleReset, 1);
- if(mySettings->getBool("holdselect"))
- myEventHandler->handleEvent(Event::ConsoleSelect, 1);
-
- const string& holdjoy0 = mySettings->getString("holdjoy0");
- if(BSPF::containsIgnoreCase(holdjoy0, "U"))
- myEventHandler->handleEvent(Event::JoystickZeroUp, 1);
- if(BSPF::containsIgnoreCase(holdjoy0, "D"))
- myEventHandler->handleEvent(Event::JoystickZeroDown, 1);
- if(BSPF::containsIgnoreCase(holdjoy0, "L"))
- myEventHandler->handleEvent(Event::JoystickZeroLeft, 1);
- if(BSPF::containsIgnoreCase(holdjoy0, "R"))
- myEventHandler->handleEvent(Event::JoystickZeroRight, 1);
- if(BSPF::containsIgnoreCase(holdjoy0, "F"))
- myEventHandler->handleEvent(Event::JoystickZeroFire, 1);
-
- const string& holdjoy1 = mySettings->getString("holdjoy1");
- if(BSPF::containsIgnoreCase(holdjoy1, "U"))
- myEventHandler->handleEvent(Event::JoystickOneUp, 1);
- if(BSPF::containsIgnoreCase(holdjoy1, "D"))
- myEventHandler->handleEvent(Event::JoystickOneDown, 1);
- if(BSPF::containsIgnoreCase(holdjoy1, "L"))
- myEventHandler->handleEvent(Event::JoystickOneLeft, 1);
- if(BSPF::containsIgnoreCase(holdjoy1, "R"))
- myEventHandler->handleEvent(Event::JoystickOneRight, 1);
- if(BSPF::containsIgnoreCase(holdjoy1, "F"))
- myEventHandler->handleEvent(Event::JoystickOneFire, 1);
- #ifdef DEBUGGER_SUPPORT
- if(mySettings->getBool("debug"))
- myEventHandler->enterDebugMode();
- #endif
+ myEventHandler->handleConsoleStartupEvents();
}
return EmptyString;
}
diff --git a/src/emucore/OSystem.hxx b/src/emucore/OSystem.hxx
index 6610b2e91..b3b136467 100644
--- a/src/emucore/OSystem.hxx
+++ b/src/emucore/OSystem.hxx
@@ -403,14 +403,14 @@ class OSystem
virtual void stateChanged(EventHandler::State state) { }
/**
- Returns the default save and load paths for the snapshot directory.
- Since this varies greatly among different systems and is the one
- directory that most end-users care about (vs. config file stuff
- that usually isn't user-modifiable), we create a special method
- for it.
+ Returns the default save and load paths for various files
+ (snapshots, disassembly, roms, etc). Since this varies greatly
+ among different systems and is the one directory that most end-users
+ care about (vs. config file stuff that usually isn't user-modifiable),
+ we create a special method for it.
*/
- virtual string defaultSnapSaveDir() { return string("~") + BSPF::PATH_SEPARATOR; }
- virtual string defaultSnapLoadDir() { return string("~") + BSPF::PATH_SEPARATOR; }
+ virtual string defaultSaveDir() const { return string("~") + BSPF::PATH_SEPARATOR; }
+ virtual string defaultLoadDir() const { return string("~") + BSPF::PATH_SEPARATOR; }
protected:
/**
diff --git a/src/emucore/Paddles.hxx b/src/emucore/Paddles.hxx
index 3d126381c..0f7c9777f 100644
--- a/src/emucore/Paddles.hxx
+++ b/src/emucore/Paddles.hxx
@@ -127,12 +127,12 @@ class Paddles : public Controller
// Range of values over which digital and mouse movement is scaled
// to paddle resistance
- static const int TRIGMIN = 1;
- static const int TRIGMAX = 4096;
+ static constexpr int TRIGMIN = 1;
+ static constexpr int TRIGMAX = 4096;
static int TRIGRANGE; // This one is variable for the upper range
- static const int MAX_DIGITAL_SENSE = 20;
- static const int MAX_MOUSE_SENSE = 20;
+ static constexpr int MAX_DIGITAL_SENSE = 20;
+ static constexpr int MAX_MOUSE_SENSE = 20;
static int DIGITAL_SENSITIVITY, DIGITAL_DISTANCE;
static int MOUSE_SENSITIVITY;
diff --git a/src/emucore/PointingDevice.cxx b/src/emucore/PointingDevice.cxx
new file mode 100644
index 000000000..be7c6fac4
--- /dev/null
+++ b/src/emucore/PointingDevice.cxx
@@ -0,0 +1,156 @@
+//============================================================================
+//
+// 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 "Control.hxx"
+#include "Event.hxx"
+#include "System.hxx"
+#include "TIA.hxx"
+
+#include "PointingDevice.hxx"
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+PointingDevice::PointingDevice(Jack jack, const Event& event,
+ const System& system, Controller::Type type,
+ float sensitivity)
+ : Controller(jack, event, system, type),
+ mySensitivity(sensitivity),
+ myHCounterRemainder(0.0), myVCounterRemainder(0.0),
+ myTrackBallLinesH(1), myTrackBallLinesV(1),
+ myTrackBallLeft(false), myTrackBallDown(false),
+ myCountH(0), myCountV(0),
+ myScanCountH(0), myScanCountV(0),
+ myFirstScanOffsetH(0), myFirstScanOffsetV(0),
+ myMouseEnabled(false)
+{
+ // The code in ::read() is set up to always return IOPortA values in
+ // the lower 4 bits data value
+ // As such, the jack type (left or right) isn't necessary here
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+uInt8 PointingDevice::read()
+{
+ int scanline = mySystem.tia().scanlines();
+
+ // Loop over all missed changes
+ while(myScanCountH < scanline)
+ {
+ if(myTrackBallLeft) myCountH--;
+ else myCountH++;
+
+ // Define scanline of next change
+ myScanCountH += myTrackBallLinesH;
+ }
+
+ // Loop over all missed changes
+ while(myScanCountV < scanline)
+ {
+ if(myTrackBallDown) myCountV--;
+ else myCountV++;
+
+ // Define scanline of next change
+ myScanCountV += myTrackBallLinesV;
+ }
+
+ myCountH &= 0x03;
+ myCountV &= 0x03;
+
+ uInt8 portA = ioPortA(myCountH, myCountV, myTrackBallLeft, myTrackBallDown);
+
+ myDigitalPinState[One] = portA & 0x10;
+ myDigitalPinState[Two] = portA & 0x20;
+ myDigitalPinState[Three] = portA & 0x40;
+ myDigitalPinState[Four] = portA & 0x80;
+
+ return (portA >> 4);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void PointingDevice::update()
+{
+ if(!myMouseEnabled)
+ return;
+
+ // Update horizontal direction
+ updateDirection( myEvent.get(Event::MouseAxisXValue), myHCounterRemainder,
+ myTrackBallLeft, myTrackBallLinesH, myScanCountH, myFirstScanOffsetH);
+
+ // Update vertical direction
+ updateDirection(-myEvent.get(Event::MouseAxisYValue), myVCounterRemainder,
+ myTrackBallDown, myTrackBallLinesV, myScanCountV, myFirstScanOffsetV);
+
+ // Get mouse button state
+ myDigitalPinState[Six] = (myEvent.get(Event::MouseButtonLeftValue) == 0) &&
+ (myEvent.get(Event::MouseButtonRightValue) == 0);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+bool PointingDevice::setMouseControl(
+ Controller::Type xtype, int xid, Controller::Type ytype, int yid)
+{
+ // Currently, the various trakball controllers take full control of the
+ // mouse, and use both mouse buttons for the single fire button
+ // As well, there's no separate setting for x and y axis, so any
+ // combination of Controller and id is valid
+ myMouseEnabled = (xtype == myType || ytype == myType) &&
+ (xid != -1 || yid != -1);
+ return true;
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void PointingDevice::setSensitivity(int sensitivity)
+{
+ BSPF::clamp(sensitivity, 1, 20, 10);
+ TB_SENSITIVITY = sensitivity / 10.0;
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void PointingDevice::updateDirection(int counter, float& counterRemainder,
+ bool& trackBallDir, int& trackBallLines, int& scanCount, int& firstScanOffset)
+{
+ // Apply sensitivity and calculate remainder
+ float fTrackBallCount = counter * mySensitivity * TB_SENSITIVITY + counterRemainder;
+ int trackBallCount = int(std::lround(fTrackBallCount));
+ counterRemainder = fTrackBallCount - trackBallCount;
+
+ if(trackBallCount)
+ {
+ trackBallDir = (trackBallCount > 0);
+ trackBallCount = abs(trackBallCount);
+
+ // Calculate lines to wait between sending new horz/vert values
+ trackBallLines = mySystem.tia().scanlinesLastFrame() / trackBallCount;
+
+ // Set lower limit in case of (unrealistic) ultra fast mouse movements
+ if (trackBallLines == 0) trackBallLines = 1;
+
+ // Define scanline of first change
+ scanCount = (trackBallLines * firstScanOffset) >> 12;
+ }
+ else
+ {
+ // Prevent any change
+ scanCount = INT_MAX;
+
+ // Define offset factor for first change, move randomly forward by up to 1/8th
+ firstScanOffset = (((firstScanOffset << 3) + rand() %
+ (1 << 12)) >> 3) & ((1 << 12) - 1);
+ }
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+float PointingDevice::TB_SENSITIVITY = 1.0;
diff --git a/src/emucore/PointingDevice.hxx b/src/emucore/PointingDevice.hxx
new file mode 100644
index 000000000..6a6f5880d
--- /dev/null
+++ b/src/emucore/PointingDevice.hxx
@@ -0,0 +1,133 @@
+//============================================================================
+//
+// 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 POINTING_DEVICE_HXX
+#define POINTING_DEVICE_HXX
+
+class Controller;
+class Event;
+
+#include "bspf.hxx"
+
+/**
+ Common controller class for pointing devices (Atari Mouse, Amiga Mouse, Trak-Ball)
+ This code was heavily borrowed from z26.
+
+ @author Stephen Anthony, Thomas Jentzsch & z26 team
+*/
+class PointingDevice : public Controller
+{
+ public:
+ PointingDevice(Jack jack, const Event& event,
+ const System& system, Controller::Type type,
+ float sensitivity);
+ virtual ~PointingDevice() = default;
+
+ public:
+ using Controller::read;
+
+ /**
+ Read the entire state of all digital pins for this controller.
+ Note that this method must use the lower 4 bits, and zero the upper bits.
+
+ @return The state of all digital pins
+ */
+ uInt8 read() override;
+
+ /**
+ Update the entire digital and analog pin state according to the
+ events currently set.
+ */
+ void update() override;
+
+ /**
+ Determines how this controller will treat values received from the
+ X/Y axis and left/right buttons of the mouse. Since not all controllers
+ use the mouse the same way (or at all), it's up to the specific class to
+ decide how to use this data.
+
+ In the current implementation, the left button is tied to the X axis,
+ and the right one tied to the Y axis.
+
+ @param xtype The controller to use for x-axis data
+ @param xid The controller ID to use for x-axis data (-1 for no id)
+ @param ytype The controller to use for y-axis data
+ @param yid The controller ID to use for y-axis data (-1 for no id)
+
+ @return Whether the controller supports using the mouse
+ */
+ bool setMouseControl(Controller::Type xtype, int xid,
+ Controller::Type ytype, int yid) override;
+
+ /**
+ Sets the sensitivity for analog emulation of trackball movement
+ using a mouse.
+
+ @param sensitivity Value from 1 to 20, with larger values causing
+ more movement (10 represents the baseline)
+ */
+ static void setSensitivity(int sensitivity);
+
+ protected:
+ // Each derived class must implement this, to determine how its
+ // IOPortA values are calculated
+ virtual uInt8 ioPortA(uInt8 countH, uInt8 countV, uInt8 left, uInt8 down) = 0;
+
+ private:
+ void updateDirection(int counter, float& counterRemainder,
+ bool& trackBallDir, int& trackBallLines,
+ int& scanCount, int& firstScanOffset);
+
+ private:
+ // Mouse input to sensitivity emulation
+ float mySensitivity, myHCounterRemainder, myVCounterRemainder;
+
+ // How many lines to wait between sending new horz and vert values
+ int myTrackBallLinesH, myTrackBallLinesV;
+
+ // Was TrackBall moved left or moved right instead
+ bool myTrackBallLeft;
+
+ // Was TrackBall moved down or moved up instead
+ bool myTrackBallDown;
+
+ // Counter to iterate through the gray codes
+ uInt8 myCountH, myCountV;
+
+ // Next scanline for change
+ int myScanCountH, myScanCountV;
+
+ // Offset factor for first scanline, 0..(1 << 12 - 1)
+ int myFirstScanOffsetH, myFirstScanOffsetV;
+
+ // Whether to use the mouse to emulate this controller
+ bool myMouseEnabled;
+
+ // User-defined sensitivity; adjustable since end-users may have different
+ // mouse speeds
+ static float TB_SENSITIVITY;
+
+private:
+ // Following constructors and assignment operators not supported
+ PointingDevice() = delete;
+ PointingDevice(const PointingDevice&) = delete;
+ PointingDevice(PointingDevice&&) = delete;
+ PointingDevice& operator=(const PointingDevice&) = delete;
+ PointingDevice& operator=(PointingDevice&&) = delete;
+};
+
+#endif // POINTING_DEVICE_HXX
diff --git a/src/emucore/Random.hxx b/src/emucore/Random.hxx
index 2170a599c..940e3fa90 100644
--- a/src/emucore/Random.hxx
+++ b/src/emucore/Random.hxx
@@ -22,6 +22,7 @@
#include "bspf.hxx"
#include "OSystem.hxx"
+#include "Serializable.hxx"
/**
This is a quick-and-dirty random number generator. It is based on
@@ -30,7 +31,7 @@
@author Bradford W. Mott
*/
-class Random
+class Random : public Serializable
{
public:
/**
@@ -57,6 +58,59 @@ class Random
return (myValue = (myValue * 2416 + 374441) % 1771875);
}
+ /**
+ Save the current state of this device to the given Serializer.
+
+ @param out The Serializer object to use
+ @return False on any errors, else true
+ */
+ bool save(Serializer& out) const override
+ {
+ try
+ {
+ out.putString(name());
+ out.putInt(myValue);
+ }
+ catch(...)
+ {
+ cerr << "ERROR: Random::save" << endl;
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ Load the current state of this device from the given Serializer.
+
+ @param in The Serializer object to use
+ @return False on any errors, else true
+ */
+ bool load(Serializer& in) override
+ {
+ try
+ {
+ if(in.getString() != name())
+ return false;
+
+ myValue = in.getInt();
+ }
+ catch(...)
+ {
+ cerr << "ERROR: Random::load" << endl;
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ Get a descriptor for the device name (used in error checking).
+
+ @return The name of the object
+ */
+ string name() const override { return "Random"; }
+
private:
// Set the OSystem we're using
const OSystem& myOSystem;
diff --git a/src/emucore/SaveKey.cxx b/src/emucore/SaveKey.cxx
index 24823c760..725737ca8 100644
--- a/src/emucore/SaveKey.cxx
+++ b/src/emucore/SaveKey.cxx
@@ -72,17 +72,15 @@ void SaveKey::write(DigitalPin pin, bool value)
}
}
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void SaveKey::reset()
+{
+ myEEPROM->systemReset();
+}
+
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SaveKey::close()
{
// Force the EEPROM object to cleanup
myEEPROM.reset();
}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void SaveKey::systemCyclesReset()
-{
- // The EEPROM keeps track of cycle counts, and needs to know when the
- // cycles are reset
- myEEPROM->systemCyclesReset();
-}
diff --git a/src/emucore/SaveKey.hxx b/src/emucore/SaveKey.hxx
index 91a27f9da..c53062517 100644
--- a/src/emucore/SaveKey.hxx
+++ b/src/emucore/SaveKey.hxx
@@ -74,6 +74,13 @@ class SaveKey : public Controller
*/
void update() override { }
+ /**
+ Notification method invoked by the system after its reset method has
+ been called. It may be necessary to override this method for
+ controllers that need to know a reset has occurred.
+ */
+ void reset() override;
+
/**
Notification method invoked by the system indicating that the
console is about to be destroyed. It may be necessary to override
@@ -81,13 +88,6 @@ class SaveKey : public Controller
*/
void close() override;
- /**
- Notification method invoked by the system right before the
- system resets its cycle counter to zero. It may be necessary
- to override this method for devices that remember cycle counts.
- */
- void systemCyclesReset() override;
-
private:
// The EEPROM used in the SaveKey
unique_ptr myEEPROM;
diff --git a/src/emucore/Serializer.cxx b/src/emucore/Serializer.cxx
index c880bf8c0..193560649 100644
--- a/src/emucore/Serializer.cxx
+++ b/src/emucore/Serializer.cxx
@@ -133,6 +133,15 @@ void Serializer::getIntArray(uInt32* array, uInt32 size) const
myStream->read(reinterpret_cast(array), sizeof(uInt32)*size);
}
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+uInt64 Serializer::getLong() const
+{
+ uInt64 val = 0;
+ myStream->read(reinterpret_cast(&val), sizeof(uInt64));
+
+ return val;
+}
+
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
double Serializer::getDouble() const
{
@@ -195,6 +204,12 @@ void Serializer::putIntArray(const uInt32* array, uInt32 size)
myStream->write(reinterpret_cast(array), sizeof(uInt32)*size);
}
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void Serializer::putLong(uInt64 value)
+{
+ myStream->write(reinterpret_cast(&value), sizeof(uInt64));
+}
+
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Serializer::putDouble(double value)
{
diff --git a/src/emucore/Serializer.hxx b/src/emucore/Serializer.hxx
index e956a158c..03acbc852 100644
--- a/src/emucore/Serializer.hxx
+++ b/src/emucore/Serializer.hxx
@@ -27,12 +27,9 @@
stream can be either an actual file, or an in-memory structure.
Bytes are written as characters, shorts as 2 characters (16-bits),
- integers as 4 characters (32-bits), strings are written as characters
- prepended by the length of the string, boolean values are written using
- a special character pattern.
-
- All bytes, shorts and ints should be cast to their appropriate data type upon
- method return.
+ integers as 4 characters (32-bits), long integers as 8 bytes (64-bits),
+ strings are written as characters prepended by the length of the string,
+ boolean values are written using a special character pattern.
@author Stephen Anthony
*/
@@ -110,6 +107,13 @@ class Serializer
*/
void getIntArray(uInt32* array, uInt32 size) const;
+ /**
+ Reads a long int value (unsigned 64-bit) from the current input stream.
+
+ @result The long int value which has been read from the stream.
+ */
+ uInt64 getLong() const;
+
/**
Reads a double value (signed 64-bit) from the current input stream.
@@ -176,6 +180,13 @@ class Serializer
*/
void putIntArray(const uInt32* array, uInt32 size);
+ /**
+ Writes a long int value (unsigned 64-bit) to the current output stream.
+
+ @param value The long int value to write to the output stream.
+ */
+ void putLong(uInt64 value);
+
/**
Writes a double value (signed 64-bit) to the current output stream.
diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx
index 79fecf190..9b97f4522 100644
--- a/src/emucore/Settings.cxx
+++ b/src/emucore/Settings.cxx
@@ -90,6 +90,7 @@ Settings::Settings(OSystem& osystem)
setInternal("cursor", "2");
setInternal("dsense", "10");
setInternal("msense", "10");
+ setInternal("tsense", "10");
setInternal("saport", "lr");
setInternal("ctrlcombo", "true");
@@ -138,6 +139,7 @@ Settings::Settings(OSystem& osystem)
setInternal("avoxport", "");
setInternal("stats", "false");
setInternal("fastscbios", "true");
+ setInternal("threads", "false");
setExternal("romloadcount", "0");
setExternal("maxres", "");
@@ -294,7 +296,7 @@ void Settings::validate()
#ifdef SOUND_SUPPORT
i = getInt("volume");
- if(i < 0 || i > 100) setInternal("volume", "100");
+ if(i < 0 || i > 100) setInternal("volume", "100");
i = getInt("freq");
if(!(i == 11025 || i == 22050 || i == 31400 || i == 44100 || i == 48000))
setInternal("freq", "31400");
@@ -309,12 +311,16 @@ void Settings::validate()
setInternal("cursor", "2");
i = getInt("dsense");
- if(i < 1) setInternal("dsense", "1");
- else if(i > 20) setInternal("dsense", "10");
+ if(i < 1 || i > 20)
+ setInternal("dsense", "10");
i = getInt("msense");
- if(i < 1) setInternal("msense", "1");
- else if(i > 20) setInternal("msense", "15");
+ if(i < 1 || i > 20)
+ setInternal("msense", "10");
+
+ i = getInt("tsense");
+ if(i < 1 || i > 20)
+ setInternal("tsense", "10");
i = getInt("ssinterval");
if(i < 1) setInternal("ssinterval", "2");
@@ -413,11 +419,13 @@ void Settings::usage() const
<< " -cursor <0,1,2,3> Set cursor state in UI/emulation modes\n"
<< " -dsense Sensitivity of digital emulated paddle movement (1-20)\n"
<< " -msense Sensitivity of mouse emulated paddle movement (1-20)\n"
+ << " -tsense Sensitivity of mouse emulated trackball movement (1-20)\n"
<< " -saport How to assign virtual ports to multiple Stelladaptor/2600-daptors\n"
<< " -ctrlcombo <1|0> Use key combos involving the Control key (Control-Q for quit may be disabled!)\n"
<< " -autoslot <1|0> Automatically switch to next save slot when state saving\n"
<< " -stats <1|0> Overlay console info during emulation\n"
<< " -fastscbios <1|0> Disable Supercharger BIOS progress loading bars\n"
+ << " -threads <1|0> Whether to using multi-threading during emulation\n"
<< " -snapsavedir The directory to save snapshot files to\n"
<< " -snaploaddir The directory to load snapshot files from\n"
<< " -snapname Name snapshots according to internal database or ROM\n"
@@ -616,9 +624,7 @@ int Settings::setInternal(const string& key, const Variant& value,
}
else
{
- Setting setting;
- setting.key = key;
- setting.value = value;
+ Setting setting(key, value);
if(useAsInitial) setting.initialValue = value;
myInternalSettings.push_back(setting);
@@ -670,9 +676,7 @@ int Settings::setExternal(const string& key, const Variant& value,
}
else
{
- Setting setting;
- setting.key = key;
- setting.value = value;
+ Setting setting(key, value);
if(useAsInitial) setting.initialValue = value;
myExternalSettings.push_back(setting);
diff --git a/src/emucore/Settings.hxx b/src/emucore/Settings.hxx
index f6351555c..0020512fc 100644
--- a/src/emucore/Settings.hxx
+++ b/src/emucore/Settings.hxx
@@ -115,6 +115,9 @@ class Settings
string key;
Variant value;
Variant initialValue;
+
+ Setting(const string& k, const Variant& v, const Variant& i = EmptyVariant)
+ : key(k), value(v), initialValue(i) { }
};
using SettingsArray = vector;
diff --git a/src/emucore/Sound.hxx b/src/emucore/Sound.hxx
index 0aa52faa1..a46afe114 100644
--- a/src/emucore/Sound.hxx
+++ b/src/emucore/Sound.hxx
@@ -47,14 +47,6 @@ class Sound : public Serializable
*/
virtual void setEnabled(bool enable) = 0;
- /**
- 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
- */
- virtual void adjustCycleCounter(Int32 amount) = 0;
-
/**
Sets the number of channels (mono or stereo sound).
@@ -101,7 +93,7 @@ class Sound : public Serializable
@param value The value to save into the register
@param cycle The system cycle at which the register is being updated
*/
- virtual void set(uInt16 addr, uInt8 value, Int32 cycle) = 0;
+ virtual void set(uInt16 addr, uInt8 value, uInt64 cycle) = 0;
/**
Sets the volume of the sound device to the specified level. The
diff --git a/src/emucore/System.cxx b/src/emucore/System.cxx
index dfcf2f82a..820d28c31 100644
--- a/src/emucore/System.cxx
+++ b/src/emucore/System.cxx
@@ -45,7 +45,7 @@ System::System(const OSystem& osystem, M6502& m6502, M6532& m6532,
PageAccess access(&myNullDevice, System::PA_READ);
for(int page = 0; page < NUM_PAGES; ++page)
{
- setPageAccess(page, access);
+ myPageAccessTable[page] = access;
myPageIsDirtyTable[page] = false;
}
@@ -69,10 +69,8 @@ void System::reset(bool autodetect)
// Provide hint to devices that autodetection is active (or not)
mySystemInAutodetect = autodetect;
- // Reset system cycle counter
- resetCycles();
-
// Reset all devices
+ myCycles = 0; // Must be done first (the reset() methods may use its value)
myM6532.reset();
myTIA.reset();
myCart.reset();
@@ -82,18 +80,6 @@ void System::reset(bool autodetect)
clearDirtyPages();
}
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void System::resetCycles()
-{
- // First we let all of the device attached to me know about the reset
- myM6532.systemCyclesReset();
- myTIA.systemCyclesReset();
- myCart.systemCyclesReset();
-
- // Now, we reset cycle count to zero
- myCycles = 0;
-}
-
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void System::consoleChanged(ConsoleTiming timing)
{
@@ -125,7 +111,7 @@ void System::clearDirtyPages()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 System::peek(uInt16 addr, uInt8 flags)
{
- PageAccess& access = myPageAccessTable[(addr & ADDRESS_MASK) >> PAGE_SHIFT];
+ const PageAccess& access = getPageAccess(addr);
#ifdef DEBUGGER_SUPPORT
// Set access type
@@ -151,10 +137,18 @@ uInt8 System::peek(uInt16 addr, uInt8 flags)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void System::poke(uInt16 addr, uInt8 value)
+void System::poke(uInt16 addr, uInt8 value, uInt8 flags)
{
uInt16 page = (addr & ADDRESS_MASK) >> PAGE_SHIFT;
- PageAccess& access = myPageAccessTable[page];
+ const PageAccess& access = myPageAccessTable[page];
+
+#ifdef DEBUGGER_SUPPORT
+ // Set access type
+ if (access.codeAccessBase)
+ *(access.codeAccessBase + (addr & PAGE_MASK)) |= flags;
+ else
+ access.device->setAccessFlags(addr, flags);
+#endif
// See if this page uses direct accessing or not
if(access.directPokeBase)
@@ -179,7 +173,7 @@ void System::poke(uInt16 addr, uInt8 value)
uInt8 System::getAccessFlags(uInt16 addr) const
{
#ifdef DEBUGGER_SUPPORT
- const PageAccess& access = myPageAccessTable[(addr & ADDRESS_MASK) >> PAGE_SHIFT];
+ const PageAccess& access = getPageAccess(addr);
if(access.codeAccessBase)
return *(access.codeAccessBase + (addr & PAGE_MASK));
@@ -194,7 +188,7 @@ uInt8 System::getAccessFlags(uInt16 addr) const
void System::setAccessFlags(uInt16 addr, uInt8 flags)
{
#ifdef DEBUGGER_SUPPORT
- PageAccess& access = myPageAccessTable[(addr & ADDRESS_MASK) >> PAGE_SHIFT];
+ const PageAccess& access = getPageAccess(addr);
if(access.codeAccessBase)
*(access.codeAccessBase + (addr & PAGE_MASK)) |= flags;
@@ -209,7 +203,7 @@ bool System::save(Serializer& out) const
try
{
out.putString(name());
- out.putInt(myCycles);
+ out.putLong(myCycles);
out.putByte(myDataBusState);
// Save the state of each device
@@ -221,6 +215,8 @@ bool System::save(Serializer& out) const
return false;
if(!myCart.save(out))
return false;
+ if(!randGenerator().save(out))
+ return false;
}
catch(...)
{
@@ -239,7 +235,7 @@ bool System::load(Serializer& in)
if(in.getString() != name())
return false;
- myCycles = in.getInt();
+ myCycles = in.getLong();
myDataBusState = in.getByte();
// Load the state of each device
@@ -251,6 +247,8 @@ bool System::load(Serializer& in)
return false;
if(!myCart.load(in))
return false;
+ if(!randGenerator().load(in))
+ return false;
}
catch(...)
{
diff --git a/src/emucore/System.hxx b/src/emucore/System.hxx
index d62f36fec..ddde896b3 100644
--- a/src/emucore/System.hxx
+++ b/src/emucore/System.hxx
@@ -59,8 +59,11 @@ class System : public Serializable
// Amount to shift an address by to determine what page it's on
static constexpr uInt16 PAGE_SHIFT = 6;
+ // Size of a page
+ static constexpr uInt16 PAGE_SIZE = (1 << PAGE_SHIFT);
+
// Mask to apply to an address to obtain its page offset
- static constexpr uInt16 PAGE_MASK = (1 << PAGE_SHIFT) - 1;
+ static constexpr uInt16 PAGE_MASK = PAGE_SIZE - 1;
// Number of pages in the system
static constexpr uInt16 NUM_PAGES = 1 << (13 - PAGE_SHIFT);
@@ -126,12 +129,12 @@ class System : public Serializable
public:
/**
- Get the number of system cycles which have passed since the last
- time cycles were reset or the system was reset.
+ Get the number of system cycles which have passed since the
+ system was created.
@return The number of system cycles which have passed
*/
- uInt32 cycles() const { return myCycles; }
+ uInt64 cycles() const { return myCycles; }
/**
Increment the system cycles by the specified number of cycles.
@@ -140,14 +143,6 @@ class System : public Serializable
*/
void incrementCycles(uInt32 amount) { myCycles += amount; }
- /**
- Reset the system cycle count to zero. The first thing that
- happens is that all devices are notified of the reset by invoking
- their systemCyclesReset method then the system cycle count is
- reset to zero.
- */
- void resetCycles();
-
/**
Informs all attached devices that the console type has changed.
*/
@@ -215,7 +210,7 @@ class System : public Serializable
@param address The address where the value should be stored
@param value The value to be stored at the address
*/
- void poke(uInt16 address, uInt8 value);
+ void poke(uInt16 address, uInt8 value, uInt8 flags = 0);
/**
Lock/unlock the data bus. When the bus is locked, peek() and
@@ -306,23 +301,23 @@ class System : public Serializable
};
/**
- Set the page accessing method for the specified page.
+ Set the page accessing method for the specified address.
- @param page The page accessing methods should be set for
+ @param addr The address/page accessing methods should be set for
@param access The accessing methods to be used by the page
*/
- void setPageAccess(uInt16 page, const PageAccess& access) {
- myPageAccessTable[page] = access;
+ void setPageAccess(uInt16 addr, const PageAccess& access) {
+ myPageAccessTable[(addr & ADDRESS_MASK) >> PAGE_SHIFT] = access;
}
/**
- Get the page accessing method for the specified page.
+ Get the page accessing method for the specified address.
- @param page The page to get accessing methods for
+ @param addr The address/page to get accessing methods for
@return The accessing methods used by the page
*/
- const PageAccess& getPageAccess(uInt16 page) const {
- return myPageAccessTable[page];
+ const PageAccess& getPageAccess(uInt16 addr) const {
+ return myPageAccessTable[(addr & ADDRESS_MASK) >> PAGE_SHIFT];
}
/**
@@ -396,8 +391,8 @@ class System : public Serializable
// Cartridge device attached to the system
Cartridge& myCart;
- // Number of system cycles executed since the last reset
- uInt32 myCycles;
+ // Number of system cycles executed since last reset
+ uInt64 myCycles;
// Null device to use for page which are not installed
NullDevice myNullDevice;
diff --git a/src/emucore/TIASurface.cxx b/src/emucore/TIASurface.cxx
index 5c84874f0..4cef17504 100644
--- a/src/emucore/TIASurface.cxx
+++ b/src/emucore/TIASurface.cxx
@@ -16,6 +16,8 @@
//============================================================================
#include
+#include
+#include
#include "FrameBuffer.hxx"
#include "Settings.hxx"
@@ -55,6 +57,9 @@ TIASurface::TIASurface(OSystem& system)
myBaseTiaSurface = myFB.allocateSurface(kTIAW*2, kTIAH);
memset(myRGBFramebuffer, 0, AtariNTSC::outWidth(kTIAW) * kTIAH);
+
+ // Enable/disable threading in the NTSC TV effects renderer
+ myNTSCFilter.enableThreading(myOSystem.settings().getBool("threads"));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -107,20 +112,27 @@ void TIASurface::setPalette(const uInt32* tia_palette, const uInt32* rgb_palette
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const FBSurface& TIASurface::baseSurface(GUI::Rect& rect) const
{
- uInt32 tiaw = myTIA->width(), width = tiaw*2, height = myTIA->height();
+ uInt32 tiaw = myTIA->width(), width = tiaw * 2, height = myTIA->height();
rect.setBounds(0, 0, width, height);
+ // Get Blargg buffer and width
+ uInt32 *blarggBuf, blarggPitch;
+ myTiaSurface->basePtr(blarggBuf, blarggPitch);
+ double blarggXFactor = (double)blarggPitch / width;
+ bool useBlargg = ntscEnabled();
+
// Fill the surface with pixels from the TIA, scaled 2x horizontally
uInt32 *buf_ptr, pitch;
myBaseTiaSurface->basePtr(buf_ptr, pitch);
for(uInt32 y = 0; y < height; ++y)
{
- for(uInt32 x = 0; x < tiaw; ++x)
+ for(uInt32 x = 0; x < width; ++x)
{
- uInt32 pixel = myFB.tiaSurface().pixel(y*tiaw+x);
- *buf_ptr++ = pixel;
- *buf_ptr++ = pixel;
+ if (useBlargg)
+ *buf_ptr++ = blarggBuf[y * blarggPitch + (uInt32)nearbyint(x * blarggXFactor)];
+ else
+ *buf_ptr++ = myPalette[*(myTIA->frameBuffer() + y * tiaw + x / 2)];
}
}
@@ -130,22 +142,7 @@ const FBSurface& TIASurface::baseSurface(GUI::Rect& rect) const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 TIASurface::pixel(uInt32 idx, uInt8 shift)
{
- uInt8 c = *(myTIA->frameBuffer() + idx) | shift;
-
- if(!myUsePhosphor)
- return myPalette[c];
- else
- {
- const uInt32 p = myRGBFramebuffer[idx];
-
- // Mix current calculated frame with previous displayed frame
- const uInt32 retVal = getRGBPhosphor(myPalette[c], p, shift);
-
- // Store back into displayed frame buffer (for next frame)
- myRGBFramebuffer[idx] = retVal;
-
- return retVal;
- }
+ return myPalette[*(myTIA->frameBuffer() + idx) | shift];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -228,35 +225,38 @@ void TIASurface::enableScanlineInterpolation(bool enable)
void TIASurface::enablePhosphor(bool enable, int blend)
{
myUsePhosphor = enable;
- myPhosphorPercent = blend / 100.0;
+ if(blend >= 0)
+ myPhosphorPercent = blend / 100.0;
myFilter = Filter(enable ? uInt8(myFilter) | 0x01 : uInt8(myFilter) & 0x10);
myTiaSurface->setDirty();
mySLineSurface->setDirty();
memset(myRGBFramebuffer, 0, AtariNTSC::outWidth(kTIAW) * kTIAH * 4);
+
+ // Precalculate the average colors for the 'phosphor' effect
+ if(myUsePhosphor)
+ {
+ for(Int16 c = 255; c >= 0; c--)
+ for(Int16 p = 255; p >= 0; p--)
+ myPhosphorPalette[c][p] = getPhosphor(c, p);
+
+ myNTSCFilter.setPhosphorPalette(myPhosphorPalette);
+ }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-inline uInt32 TIASurface::getRGBPhosphor(uInt32 c, uInt32 p, uInt8 shift) const
+inline uInt32 TIASurface::getRGBPhosphor(const uInt32 c, const uInt32 p) const
{
#define TO_RGB(color, red, green, blue) \
- red = color >> 16; green = color >> 8; blue = color;
-
- uInt8 rc, gc, bc, rp, gp, bp;
+ 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
- uInt8 rn = getPhosphor(rc, rp);
- uInt8 gn = getPhosphor(gc, gp);
- uInt8 bn = getPhosphor(bc, bp);
-
- if(shift)
- {
- // Convert RGB to grayscale
- rn = gn = bn = uInt8(0.2126*rn + 0.7152*gn + 0.0722*bn);
- }
+ const uInt8 rn = myPhosphorPalette[rc][rp];
+ const uInt8 gn = myPhosphorPalette[gc][gp];
+ const uInt8 bn = myPhosphorPalette[bc][bp];
return (rn << 16) | (gn << 8) | bn;
}
@@ -325,16 +325,17 @@ void TIASurface::render()
{
case Filter::Normal:
{
- uInt8* in = myTIA->frameBuffer();
+ uInt8* tiaIn = myTIA->frameBuffer();
- uInt32 bufofsY = 0, screenofsY = 0, pos = 0;
+ uInt32 bufofs = 0, screenofsY = 0, pos;
for(uInt32 y = 0; y < height; ++y)
{
pos = screenofsY;
- for(uInt32 x = 0; x < width; ++x)
- out[pos++] = myPalette[in[bufofsY + x]];
-
- bufofsY += width;
+ for (uInt32 x = width / 2; x; --x)
+ {
+ out[pos++] = myPalette[tiaIn[bufofs++]];
+ out[pos++] = myPalette[tiaIn[bufofs++]];
+ }
screenofsY += outPitch;
}
break;
@@ -345,21 +346,18 @@ void TIASurface::render()
uInt8* tiaIn = myTIA->frameBuffer();
uInt32* rgbIn = myRGBFramebuffer;
- uInt32 bufofsY = 0, screenofsY = 0, pos = 0;
- for(uInt32 y = 0; y < height; ++y)
+ uInt32 bufofs = 0, screenofsY = 0, pos;
+ for(uInt32 y = height; y ; --y)
{
pos = screenofsY;
- for(uInt32 x = 0; x < width; ++x)
+ for(uInt32 x = width / 2; x ; --x)
{
- const uInt32 bufofs = bufofsY + x;
- const uInt8 c = tiaIn[bufofs];
- const uInt32 retVal = getRGBPhosphor(myPalette[c], rgbIn[bufofs]);
-
// Store back into displayed frame buffer (for next frame)
- rgbIn[bufofs] = retVal;
- out[pos++] = retVal;
+ rgbIn[bufofs] = out[pos++] = getRGBPhosphor(myPalette[tiaIn[bufofs]], rgbIn[bufofs]);
+ bufofs++;
+ rgbIn[bufofs] = out[pos++] = getRGBPhosphor(myPalette[tiaIn[bufofs]], rgbIn[bufofs]);
+ bufofs++;
}
- bufofsY += width;
screenofsY += outPitch;
}
break;
@@ -373,28 +371,7 @@ void TIASurface::render()
case Filter::BlarggPhosphor:
{
- // First do Blargg filtering
- myNTSCFilter.render(myTIA->frameBuffer(), width, height, out, outPitch << 2);
-
- // Then do phosphor mode (blend the resulting frames)
- uInt32* rgbIn = myRGBFramebuffer;
-
- uInt32 bufofsY = 0, screenofsY = 0, pos = 0;
- for(uInt32 y = 0; y < height; ++y)
- {
- pos = screenofsY;
- for(uInt32 x = 0; x < AtariNTSC::outWidth(kTIAW); ++x)
- {
- const uInt32 bufofs = bufofsY + x;
- const uInt32 retVal = getRGBPhosphor(out[bufofs], rgbIn[bufofs]);
-
- // Store back into displayed frame buffer (for next frame)
- rgbIn[bufofs] = retVal;
- out[pos++] = retVal;
- }
- bufofsY += AtariNTSC::outWidth(kTIAW);
- screenofsY += outPitch;
- }
+ myNTSCFilter.render(myTIA->frameBuffer(), width, height, out, outPitch << 2, myRGBFramebuffer);
break;
}
}
@@ -410,3 +387,49 @@ void TIASurface::render()
mySLineSurface->render();
}
}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void TIASurface::reRender()
+{
+ uInt32 width = myTIA->width();
+ uInt32 height = myTIA->height();
+ uInt32 pos = 0;
+ uInt32 *outPtr, outPitch;
+
+ myTiaSurface->basePtr(outPtr, outPitch);
+
+ switch (myFilter)
+ {
+ // for non-phosphor modes, render the frame again
+ case Filter::Normal:
+ case Filter::BlarggNormal:
+ render();
+ break;
+ // for phosphor modes, copy the phosphor framebuffer
+ case Filter::Phosphor:
+ for (uInt32 y = height; y; --y)
+ {
+ memcpy(outPtr, myRGBFramebuffer + pos, width);
+ outPtr += outPitch;
+ pos += width;
+ }
+ break;
+ case Filter::BlarggPhosphor:
+ memcpy(outPtr, myRGBFramebuffer, height * outPitch << 2);
+ break;
+ }
+
+ if (myUsePhosphor)
+ {
+ // Draw TIA image
+ myTiaSurface->setDirty();
+ myTiaSurface->render();
+
+ // Draw overlaying scanlines
+ if (myScanlinesEnabled)
+ {
+ mySLineSurface->setDirty();
+ mySLineSurface->render();
+ }
+ }
+}
diff --git a/src/emucore/TIASurface.hxx b/src/emucore/TIASurface.hxx
index 707b35645..d29e177cc 100644
--- a/src/emucore/TIASurface.hxx
+++ b/src/emucore/TIASurface.hxx
@@ -25,6 +25,9 @@ class FrameBuffer;
class FBSurface;
class VideoMode;
+#include
+
+#include "FrameManager.hxx"
#include "Rect.hxx"
#include "NTSCFilter.hxx"
#include "bspf.hxx"
@@ -107,9 +110,10 @@ class TIASurface
void enableScanlineInterpolation(bool enable);
/**
- Enable/disable phosphor effect.
+ Enable/disable/query phosphor effect.
*/
- void enablePhosphor(bool enable, int blend);
+ void enablePhosphor(bool enable, int blend = -1);
+ bool phosphorEnabled() const { return myUsePhosphor; }
/**
Used to calculate an averaged color for the 'phosphor' effect.
@@ -119,7 +123,7 @@ class TIASurface
@return Averaged value of the two colors
*/
- inline uInt8 getPhosphor(uInt8 c1, uInt8 c2) const {
+ inline uInt8 getPhosphor(const uInt8 c1, uInt8 c2) const {
// Use maximum of current and decayed previous values
c2 = uInt8(c2 * myPhosphorPercent);
if(c1 > c2) return c1; // raise (assumed immediate)
@@ -134,7 +138,7 @@ class TIASurface
@return Averaged value of the two RGB colors
*/
- uInt32 getRGBPhosphor(uInt32 c, uInt32 cp, uInt8 shift = 0) const;
+ uInt32 getRGBPhosphor(const uInt32 c, const uInt32 cp) const;
/**
Enable/disable/query NTSC filtering effects.
@@ -148,6 +152,11 @@ class TIASurface
*/
void render();
+ /**
+ This method renders the current frame again.
+ */
+ void reRender();
+
private:
OSystem& myOSystem;
FrameBuffer& myFB;
@@ -184,6 +193,9 @@ class TIASurface
// Amount to blend when using phosphor effect
float myPhosphorPercent;
+
+ // Precalculated averaged phosphor colors
+ uInt8 myPhosphorPalette[256][256];
/////////////////////////////////////////////////////////////
// Use scanlines in TIA rendering mode
diff --git a/src/emucore/Thumbulator.cxx b/src/emucore/Thumbulator.cxx
index 9363b642e..84c2e6a29 100644
--- a/src/emucore/Thumbulator.cxx
+++ b/src/emucore/Thumbulator.cxx
@@ -234,6 +234,7 @@ void Thumbulator::write16(uInt32 addr, uInt32 data)
// as additional RAM
case ConfigureFor::BUS:
case ConfigureFor::CDF:
+ case ConfigureFor::CDF1:
if((addr > 0x40000028) && (addr < 0x40000800))
fatalError("write16", addr, "to bankswitch code area");
break;
@@ -1198,6 +1199,67 @@ int Thumbulator::execute()
break;
+ case ConfigureFor::CDF1:
+ // this subroutine interface is used in the CDF driver,
+ // it starts at address 0x00000750
+ // _SetNote:
+ // ldr r4, =NoteStore
+ // bx r4 // bx instruction at 0x000006e2
+ // _ResetWave:
+ // ldr r4, =ResetWaveStore
+ // bx r4 // bx instruction at 0x000006e6
+ // _GetWavePtr:
+ // ldr r4, =WavePtrFetch
+ // bx r4 // bx instruction at 0x000006ea
+ // _SetWaveSize:
+ // ldr r4, =WaveSizeStore
+ // bx r4 // bx instruction at 0x000006ee
+
+ // address to test for is + 4 due to pipelining
+
+#define CDF1_SetNote (0x00000752 + 4)
+#define CDF1_ResetWave (0x00000756 + 4)
+#define CDF1_GetWavePtr (0x0000075a + 4)
+#define CDF1_SetWaveSize (0x0000075e + 4)
+
+ if (pc == CDF1_SetNote)
+ {
+ myCartridge->thumbCallback(0, read_register(2), read_register(3));
+ handled = true;
+ }
+ else if (pc == CDF1_ResetWave)
+ {
+ myCartridge->thumbCallback(1, read_register(2), 0);
+ handled = true;
+ }
+ else if (pc == CDF1_GetWavePtr)
+ {
+ write_register(2, myCartridge->thumbCallback(2, read_register(2), 0));
+ handled = true;
+ }
+ else if (pc == CDF1_SetWaveSize)
+ {
+ myCartridge->thumbCallback(3, read_register(2), read_register(3));
+ handled = true;
+ }
+ else if (pc == 0x0000083a)
+ {
+ // exiting Custom ARM code, returning to BUS Driver control
+ }
+ else
+ {
+#if 0 // uncomment this for testing
+ uInt32 r0 = read_register(0);
+ uInt32 r1 = read_register(1);
+ uInt32 r2 = read_register(2);
+ uInt32 r3 = read_register(3);
+ uInt32 r4 = read_register(4);
+#endif
+ myCartridge->thumbCallback(255, 0, 0);
+ }
+
+ break;
+
case ConfigureFor::DPCplus:
// no 32-bit subroutines in DPC+
break;
@@ -2266,6 +2328,7 @@ int Thumbulator::reset()
// future 2K Harmony/Melody drivers will most likely use these settings
case ConfigureFor::BUS:
case ConfigureFor::CDF:
+ case ConfigureFor::CDF1:
reg_norm[14] = 0x00000800; // Link Register
reg_norm[15] = 0x0000080B; // Program Counter
break;
diff --git a/src/emucore/Thumbulator.hxx b/src/emucore/Thumbulator.hxx
index 1051c377a..4adf3285b 100644
--- a/src/emucore/Thumbulator.hxx
+++ b/src/emucore/Thumbulator.hxx
@@ -50,6 +50,7 @@ class Thumbulator
enum ConfigureFor {
BUS, // cartridges of type BUS
CDF, // cartridges of type CDF
+ CDF1, // cartridges of type CDF version 1
DPCplus // cartridges of type DPC+
};
diff --git a/src/emucore/TrakBall.cxx b/src/emucore/TrakBall.cxx
deleted file mode 100644
index fb28e7369..000000000
--- a/src/emucore/TrakBall.cxx
+++ /dev/null
@@ -1,125 +0,0 @@
-//============================================================================
-//
-// 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
-
-#include "Event.hxx"
-#include "System.hxx"
-#include "TIA.hxx"
-#include "TrakBall.hxx"
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-TrakBall::TrakBall(Jack jack, const Event& event, const System& system)
- : Controller(jack, event, system, Controller::TrakBall),
- myHCounter(0),
- myVCounter(0),
- myMouseEnabled(false)
-{
- // This code in ::read() is set up to always return IOPortA values in
- // the lower 4 bits data value
- // As such, the jack type (left or right) isn't necessary here
-
- myTrakBallCountH = myTrakBallCountV = 0;
- myTrakBallLinesH = myTrakBallLinesV = 1;
-
- myTrakBallLeft = myTrakBallDown = myScanCountV = myScanCountH =
- myCountV = myCountH = 0;
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-uInt8 TrakBall::read()
-{
- int scanline = mySystem.tia().scanlines();
-
- if(myScanCountV > scanline) myScanCountV = 0;
- if(myScanCountH > scanline) myScanCountH = 0;
- while((myScanCountV + myTrakBallLinesV) < scanline)
- {
- if(myTrakBallCountV)
- {
- if(myTrakBallDown) myCountV--;
- else myCountV++;
- myTrakBallCountV--;
- }
- myScanCountV += myTrakBallLinesV;
- }
-
- while((myScanCountH + myTrakBallLinesH) < scanline)
- {
- if(myTrakBallCountH)
- {
- if(myTrakBallLeft) myCountH--;
- else myCountH++;
- myTrakBallCountH--;
- }
- myScanCountH += myTrakBallLinesH;
- }
-
- myCountV &= 0x03;
- myCountH &= 0x03;
-
- static constexpr uInt32 ourTableH[2][2] = {{ 0x40, 0x00 }, { 0xc0, 0x80 }};
- static constexpr uInt32 ourTableV[2][2] = {{ 0x00, 0x10 }, { 0x20, 0x30 }};
- uInt8 IOPortA = ourTableV[myCountV & 0x01][myTrakBallDown] |
- ourTableH[myCountH & 0x01][myTrakBallLeft];
-
- myDigitalPinState[One] = IOPortA & 0x10;
- myDigitalPinState[Two] = IOPortA & 0x20;
- myDigitalPinState[Three] = IOPortA & 0x40;
- myDigitalPinState[Four] = IOPortA & 0x80;
-
- return (IOPortA >> 4);
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void TrakBall::update()
-{
- if(!myMouseEnabled)
- return;
-
- // Get the current mouse position
- myHCounter = myEvent.get(Event::MouseAxisXValue);
- myVCounter = myEvent.get(Event::MouseAxisYValue);
-
- if(myVCounter < 0) myTrakBallLeft = 1;
- else myTrakBallLeft = 0;
- if(myHCounter < 0) myTrakBallDown = 0;
- else myTrakBallDown = 1;
- myTrakBallCountH = abs(myVCounter >> 2); // Extra div by 2, since trakball has
- myTrakBallCountV = abs(myHCounter >> 2); // half spatial resolution as ST/Amiga mouse
- myTrakBallLinesH = mySystem.tia().height() / (myTrakBallCountH + 1);
- if(myTrakBallLinesH == 0) myTrakBallLinesH = 1;
- myTrakBallLinesV = mySystem.tia().height() / (myTrakBallCountV + 1);
- if(myTrakBallLinesV == 0) myTrakBallLinesV = 1;
-
- // Get mouse button state
- myDigitalPinState[Six] = (myEvent.get(Event::MouseButtonLeftValue) == 0) &&
- (myEvent.get(Event::MouseButtonRightValue) == 0);
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool TrakBall::setMouseControl(
- Controller::Type xtype, int xid, Controller::Type ytype, int yid)
-{
- // Currently, the various trakball controllers take full control of the
- // mouse, and use both mouse buttons for the single fire button
- // As well, there's no separate setting for x and y axis, so any
- // combination of Controller and id is valid
- myMouseEnabled = (xtype == myType || ytype == myType) &&
- (xid != -1 || yid != -1);
- return true;
-}
diff --git a/src/emucore/TrakBall.hxx b/src/emucore/TrakBall.hxx
index 45a85c8c2..ef51b2361 100644
--- a/src/emucore/TrakBall.hxx
+++ b/src/emucore/TrakBall.hxx
@@ -18,93 +18,34 @@
#ifndef TRAKBALL_HXX
#define TRAKBALL_HXX
-#include "bspf.hxx"
-#include "Control.hxx"
-#include "Event.hxx"
+#include "PointingDevice.hxx"
-/**
- Emulates the standard trakball controller, sometimes known as the 'CX22'
- controller. This code was heavily borrowed from z26.
-
- @author Stephen Anthony & z26 team
-*/
-class TrakBall : public Controller
+class TrakBall : public PointingDevice
{
public:
/**
- Create a new TrakBall controller plugged into the specified jack
+ Create a new trakball controller plugged into the specified jack
@param jack The jack the controller is plugged into
@param event The event object to use for events
@param system The system using this controller
*/
- TrakBall(Jack jack, const Event& event, const System& system);
+ TrakBall(Jack jack, const Event& event, const System& system)
+ : PointingDevice(jack, event, system, Controller::TrakBall,
+ trackballSensitivity) { }
virtual ~TrakBall() = default;
- public:
- using Controller::read;
+ protected:
+ uInt8 ioPortA(uInt8 countH, uInt8 countV, uInt8 left, uInt8 down) override
+ {
+ static constexpr uInt32 ourTableH[2][2] = {{ 0x00, 0x10 }, { 0x20, 0x30 }};
+ static constexpr uInt32 ourTableV[2][2] = {{ 0x40, 0x00 }, { 0xc0, 0x80 }};
- /**
- Read the entire state of all digital pins for this controller.
- Note that this method must use the lower 4 bits, and zero the upper bits.
+ return ourTableH[countH & 0x01][left] | ourTableV[countV & 0x01][down];
+ }
- @return The state of all digital pins
- */
- uInt8 read() override;
-
- /**
- Update the entire digital and analog pin state according to the
- events currently set.
- */
- void update() override;
-
- /**
- Determines how this controller will treat values received from the
- X/Y axis and left/right buttons of the mouse. Since not all controllers
- use the mouse the same way (or at all), it's up to the specific class to
- decide how to use this data.
-
- In the current implementation, the left button is tied to the X axis,
- and the right one tied to the Y axis.
-
- @param xtype The controller to use for x-axis data
- @param xid The controller ID to use for x-axis data (-1 for no id)
- @param ytype The controller to use for y-axis data
- @param yid The controller ID to use for y-axis data (-1 for no id)
-
- @return Whether the controller supports using the mouse
- */
- bool setMouseControl(Controller::Type xtype, int xid,
- Controller::Type ytype, int yid) override;
-
- private:
- // Counter to iterate through the gray codes
- int myHCounter, myVCounter;
-
- // How many new horizontal and vertical values this frame
- int myTrakBallCountH, myTrakBallCountV;
-
- // How many lines to wait before sending new horz and vert val
- int myTrakBallLinesH, myTrakBallLinesV;
-
- // Was TrakBall moved left or moved right instead
- int myTrakBallLeft;
-
- // Was TrakBall moved down or moved up instead
- int myTrakBallDown;
-
- int myScanCountH, myScanCountV, myCountH, myCountV;
-
- // Whether to use the mouse to emulate this controller
- int myMouseEnabled;
-
- private:
- // Following constructors and assignment operators not supported
- TrakBall() = delete;
- TrakBall(const TrakBall&) = delete;
- TrakBall(TrakBall&&) = delete;
- TrakBall& operator=(const TrakBall&) = delete;
- TrakBall& operator=(TrakBall&&) = delete;
+ // 50% of Atari and Amiga mouse
+ static constexpr float trackballSensitivity = 0.4f;
};
-#endif
+#endif // TRAKBALL_HXX
diff --git a/src/emucore/module.mk b/src/emucore/module.mk
index 26ce32cad..2bcbeaa7c 100644
--- a/src/emucore/module.mk
+++ b/src/emucore/module.mk
@@ -41,7 +41,6 @@ MODULE_OBJS := \
src/emucore/CartFA.o \
src/emucore/CartFA2.o \
src/emucore/CartFE.o \
- src/emucore/CartMC.o \
src/emucore/CartMDM.o \
src/emucore/CartSB.o \
src/emucore/CartUA.o \
@@ -67,19 +66,16 @@ MODULE_OBJS := \
src/emucore/MD5.o \
src/emucore/OSystem.o \
src/emucore/Paddles.o \
+ src/emucore/PointingDevice.o \
src/emucore/Props.o \
src/emucore/PropsSet.o \
src/emucore/SaveKey.o \
src/emucore/Serializer.o \
src/emucore/Settings.o \
src/emucore/Switches.o \
- src/emucore/StateManager.o \
src/emucore/System.o \
src/emucore/TIASnd.o \
src/emucore/TIASurface.o \
- src/emucore/AmigaMouse.o \
- src/emucore/AtariMouse.o \
- src/emucore/TrakBall.o \
src/emucore/Thumbulator.o
MODULE_DIRS += \
diff --git a/src/emucore/stella.pro b/src/emucore/stella.pro
index 42201510c..b80bea13f 100644
--- a/src/emucore/stella.pro
+++ b/src/emucore/stella.pro
@@ -253,7 +253,7 @@
"Cartridge.MD5" "0383dc02cb82302da3d155fd108bfe3a"
"Cartridge.Manufacturer" "AtariAge, Chris Spry"
-"Cartridge.ModelNo" "26200"
+"Cartridge.ModelNo" "CX26200"
"Cartridge.Name" "Princess Rescue (2013) (Sprybug) (PAL60)"
"Cartridge.Note" "Compatible with Genesis controller"
"Cartridge.Rarity" "Homebrew"
@@ -1311,7 +1311,7 @@
"Cartridge.MD5" "104468e44898b8e9fa4a1500fde8d4cb"
"Cartridge.Manufacturer" "AtariAge, Chris Spry"
-"Cartridge.ModelNo" "26200"
+"Cartridge.ModelNo" "CX26200"
"Cartridge.Name" "Princess Rescue (2013) (Sprybug)"
"Cartridge.Note" "Compatible with Genesis controller"
"Cartridge.Rarity" "Homebrew"
@@ -10728,6 +10728,7 @@
"Cartridge.MD5" "85bbefb90e16bf386b304c1e9a1f6084"
"Cartridge.Manufacturer" "Champ Games"
+"Cartridge.ModelNo" "CG-02-P"
"Cartridge.Name" "Conquest Of Mars (PAL60)"
"Cartridge.Rarity" "Homebrew"
"Display.Format" "PAL60"
@@ -13564,6 +13565,7 @@
"Cartridge.MD5" "adfbd2e8a38f96e03751717f7422851d"
"Cartridge.Manufacturer" "Champ Games"
+"Cartridge.ModelNo" "CG-01-N"
"Cartridge.Name" "Lady Bug (NTSC)"
"Cartridge.Rarity" "Homebrew"
"Console.RightDifficulty" "A"
@@ -14380,7 +14382,7 @@
"Controller.Left" "COMPUMATE"
"Controller.Right" "COMPUMATE"
"Display.Phosphor" "YES"
-"Display.PPBlend" "60"
+"Display.PPBlend" "80"
""
"Cartridge.MD5" "b9b4612358a0b2c1b4d66bb146767306"
@@ -14999,6 +15001,7 @@
"Cartridge.MD5" "c2fbef02b6eea37d8df3e91107f89950"
"Cartridge.Manufacturer" "Champ Games"
+"Cartridge.ModelNo" "CG-02-N"
"Cartridge.Name" "Conquest Of Mars (NTSC)"
"Cartridge.Rarity" "Homebrew"
""
@@ -18178,7 +18181,7 @@
"Controller.Left" "COMPUMATE"
"Controller.Right" "COMPUMATE"
"Display.Phosphor" "YES"
-"Display.PPBlend" "60"
+"Display.PPBlend" "80"
""
"Cartridge.MD5" "e800e4aec7c6c54c9cf3db0d1d030058"
@@ -18903,6 +18906,7 @@
"Cartridge.MD5" "f1489e27a4539a0c6c8529262f9f7e18"
"Cartridge.Manufacturer" "Champ Games"
+"Cartridge.ModelNo" "CG-01-P"
"Cartridge.Name" "Lady Bug (PAL60)"
"Cartridge.Rarity" "Homebrew"
"Console.RightDifficulty" "A"
@@ -20234,3 +20238,37 @@
"Cartridge.Name" "Hunchy II (2005)"
"Cartridge.Note" "Homebrew"
""
+
+"Cartridge.MD5" "2353725ec98e0f0073462109e886efd7"
+"Cartridge.Manufacturer" "Champ Games"
+"Cartridge.ModelNo" "CG-03-P"
+"Cartridge.Name" "Scramble (PAL60)"
+"Cartridge.Note" "Compatible with Genesis controller"
+"Cartridge.Rarity" "Homebrew"
+"Display.Format" "PAL60"
+"Display.Phosphor" "YES"
+""
+
+"Cartridge.MD5" "e9f25c7af4f27c9e1b5b8f6fe6141e8c"
+"Cartridge.Manufacturer" "Champ Games"
+"Cartridge.ModelNo" "CG-03-N"
+"Cartridge.Name" "Scramble (NTSC)"
+"Cartridge.Note" "Compatible with Genesis controller"
+"Cartridge.Rarity" "Homebrew"
+"Display.Phosphor" "YES"
+""
+
+"Cartridge.MD5" "457b03cd48ff6d895795ef043c6b0f1e"
+"Cartridge.Manufacturer" "AtariAge, Chris Spry"
+"Cartridge.ModelNo" "CX26201"
+"Cartridge.Name" "Zippy the Porcupine (2014) (Sprybug)"
+"Cartridge.Rarity" "Homebrew"
+""
+
+"Cartridge.MD5" "a9d9e19d0c89fb31780b5d63e1f8c6a4"
+"Cartridge.Manufacturer" "AtariAge, Chris Spry"
+"Cartridge.ModelNo" "CX26201"
+"Cartridge.Name" "Zippy the Porcupine (2014) (Sprybug) (PAL60)"
+"Cartridge.Rarity" "Homebrew"
+"Display.Format" "PAL60"
+""
diff --git a/src/emucore/tia/Ball.cxx b/src/emucore/tia/Ball.cxx
index 6cf421ced..1552df84a 100644
--- a/src/emucore/tia/Ball.cxx
+++ b/src/emucore/tia/Ball.cxx
@@ -251,8 +251,16 @@ void Ball::applyColors()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 Ball::getPosition() const
{
+ // position =
+ // current playfield x +
+ // (current counter - 156 (the decode clock of copy 0)) +
+ // clock count after decode until first pixel +
+ // 1 (it'll take another cycle after the decode for the rendter counter to start ticking)
+ //
+ // The result may be negative, so we add 160 and do the modulus -> 317 = 156 + 160 + 1
+ //
// Mind the sign of renderCounterOffset: it's defined negative above
- return (316 - myCounter - Count::renderCounterOffset + myTIA->getPosition()) % 160;
+ return (317 - myCounter - Count::renderCounterOffset + myTIA->getPosition()) % 160;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -260,7 +268,8 @@ void Ball::setPosition(uInt8 newPosition)
{
myTIA->flushLineCache();
- myCounter = (316 - newPosition - Count::renderCounterOffset + myTIA->getPosition()) % 160;
+ // See getPosition for an explanation
+ myCounter = (317 - newPosition - Count::renderCounterOffset + myTIA->getPosition()) % 160;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/src/emucore/tia/Ball.hxx b/src/emucore/tia/Ball.hxx
index 1f6a8d575..9602334b4 100644
--- a/src/emucore/tia/Ball.hxx
+++ b/src/emucore/tia/Ball.hxx
@@ -62,9 +62,8 @@ class Ball : public Serializable
void tick(bool isReceivingMclock = true);
- uInt8 getPixel(uInt8 colorIn) const {
- return (collision & 0x8000) ? myColor : colorIn;
- }
+ bool isOn() const { return (collision & 0x8000); }
+ uInt8 getColor() const { return myColor; }
void shuffleStatus();
diff --git a/src/emucore/tia/DrawCounterDecodes.cxx b/src/emucore/tia/DrawCounterDecodes.cxx
index 553c2c6df..e4a473866 100644
--- a/src/emucore/tia/DrawCounterDecodes.cxx
+++ b/src/emucore/tia/DrawCounterDecodes.cxx
@@ -38,8 +38,9 @@ DrawCounterDecodes& DrawCounterDecodes::DrawCounterDecodes::get()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DrawCounterDecodes::DrawCounterDecodes()
{
- for (uInt8 *decodes : {myDecodes0, myDecodes1, myDecodes2, myDecodes3,
- myDecodes4, myDecodes6})
+ uInt8 *decodeTables[] = {myDecodes0, myDecodes1, myDecodes2, myDecodes3, myDecodes4, myDecodes6};
+
+ for (uInt8 *decodes : decodeTables)
{
memset(decodes, 0, 160);
decodes[156] = 1;
diff --git a/src/emucore/tia/Missile.cxx b/src/emucore/tia/Missile.cxx
index 0ff01acc0..b74a441d7 100644
--- a/src/emucore/tia/Missile.cxx
+++ b/src/emucore/tia/Missile.cxx
@@ -264,15 +264,25 @@ void Missile::applyColors()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 Missile::getPosition() const
{
+ // position =
+ // current playfield x +
+ // (current counter - 156 (the decode clock of copy 0)) +
+ // clock count after decode until first pixel +
+ // 1 (it'll take another cycle after the decode for the rendter counter to start ticking)
+ //
+ // The result may be negative, so we add 160 and do the modulus
+ //
// Mind the sign of renderCounterOffset: it's defined negative above
- return (316 - myCounter - Count::renderCounterOffset + myTIA->getPosition()) % 160;
+ return (317 - myCounter - Count::renderCounterOffset + myTIA->getPosition()) % 160;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Missile::setPosition(uInt8 newPosition)
{
myTIA->flushLineCache();
- myCounter = (316 - newPosition - Count::renderCounterOffset + myTIA->getPosition()) % 160;
+
+ // See getPosition for an explanation
+ myCounter = (317 - newPosition - Count::renderCounterOffset + myTIA->getPosition()) % 160;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/src/emucore/tia/Missile.hxx b/src/emucore/tia/Missile.hxx
index 12bef6626..9d3433659 100644
--- a/src/emucore/tia/Missile.hxx
+++ b/src/emucore/tia/Missile.hxx
@@ -63,9 +63,8 @@ class Missile : public Serializable
void toggleEnabled(bool enabled);
- uInt8 getPixel(uInt8 colorIn) const {
- return (collision & 0x8000) ? myColor : colorIn;
- }
+ bool isOn() const { return (collision & 0x8000); }
+ uInt8 getColor() const { return myColor; }
uInt8 getPosition() const;
void setPosition(uInt8 newPosition);
diff --git a/src/emucore/tia/PaddleReader.cxx b/src/emucore/tia/PaddleReader.cxx
index 69c828ea6..461bd6f77 100644
--- a/src/emucore/tia/PaddleReader.cxx
+++ b/src/emucore/tia/PaddleReader.cxx
@@ -19,14 +19,6 @@
#include "PaddleReader.hxx"
-static constexpr double
- C = 68e-9,
- RPOT = 1e6,
- R0 = 1.5e3,
- USUPP = 5;
-
-static constexpr double TRIPPOINT_LINES = 379;
-
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PaddleReader::PaddleReader()
{
diff --git a/src/emucore/tia/PaddleReader.hxx b/src/emucore/tia/PaddleReader.hxx
index 00238a4fe..1c7a2013d 100644
--- a/src/emucore/tia/PaddleReader.hxx
+++ b/src/emucore/tia/PaddleReader.hxx
@@ -65,6 +65,14 @@ class PaddleReader : public Serializable
bool myIsDumped;
+ static constexpr double
+ R0 = 1.5e3,
+ C = 68e-9,
+ RPOT = 1e6,
+ USUPP = 5;
+
+ static constexpr double TRIPPOINT_LINES = 379;
+
private:
PaddleReader(const PaddleReader&) = delete;
PaddleReader(PaddleReader&&) = delete;
diff --git a/src/emucore/tia/Player.cxx b/src/emucore/tia/Player.cxx
index dcc6bd2e1..c587ef218 100644
--- a/src/emucore/tia/Player.cxx
+++ b/src/emucore/tia/Player.cxx
@@ -397,10 +397,20 @@ void Player::applyColors()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 Player::getPosition() const
{
+ // Wide players are shifted by one pixel to the right
const uInt8 shift = myDivider == 1 ? 0 : 1;
+ // position =
+ // current playfield x +
+ // (current counter - 156 (the decode clock of copy 0)) +
+ // clock count after decode until first pixel +
+ // shift (accounts for wide player shift) +
+ // 1 (it'll take another cycle after the decode for the rendter counter to start ticking)
+ //
+ // The result may be negative, so we add 160 and do the modulus -> 317 = 156 + 160 + 1
+ //
// Mind the sign of renderCounterOffset: it's defined negative above
- return (316 - myCounter - Count::renderCounterOffset + shift + myTIA->getPosition()) % 160;
+ return (317 - myCounter - Count::renderCounterOffset + shift + myTIA->getPosition()) % 160;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -410,7 +420,8 @@ void Player::setPosition(uInt8 newPosition)
const uInt8 shift = myDivider == 1 ? 0 : 1;
- myCounter = (316 - newPosition - Count::renderCounterOffset + shift + myTIA->getPosition()) % 160;
+ // See getPosition for an explanation
+ myCounter = (317 - newPosition - Count::renderCounterOffset + shift + myTIA->getPosition()) % 160;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/src/emucore/tia/Player.hxx b/src/emucore/tia/Player.hxx
index e2cca4ccf..8addd44e8 100644
--- a/src/emucore/tia/Player.hxx
+++ b/src/emucore/tia/Player.hxx
@@ -64,9 +64,8 @@ class Player : public Serializable
void tick();
uInt8 getClock() const { return myCounter; }
- uInt8 getPixel(uInt8 colorIn) const {
- return (collision & 0x8000) ? myColor : colorIn;
- }
+ bool isOn() const { return (collision & 0x8000); }
+ uInt8 getColor() const { return myColor; }
void shufflePatterns();
diff --git a/src/emucore/tia/Playfield.hxx b/src/emucore/tia/Playfield.hxx
index 59aaa55f4..1d987e2ad 100644
--- a/src/emucore/tia/Playfield.hxx
+++ b/src/emucore/tia/Playfield.hxx
@@ -59,10 +59,8 @@ class Playfield : public Serializable
void tick(uInt32 x);
- uInt8 getPixel(uInt8 colorIn) const {
- if (collision & 0x8000) return myX < 80 ? myColorLeft : myColorRight;
- return colorIn;
- }
+ bool isOn() const { return (collision & 0x8000); }
+ uInt8 getColor() const { return myX < 80 ? myColorLeft : myColorRight; }
/**
Serializable methods (see that class for more information).
diff --git a/src/emucore/tia/TIA.cxx b/src/emucore/tia/TIA.cxx
index 872e31b00..ef275831a 100644
--- a/src/emucore/tia/TIA.cxx
+++ b/src/emucore/tia/TIA.cxx
@@ -146,11 +146,17 @@ void TIA::reset()
myDelayQueue.reset();
myFrameManager.reset();
+ myCyclesAtFrameStart = 0;
+
frameReset(); // Recalculate the size of the display
// Must be done last, after all other items have reset
enableFixedColors(false);
setFixedColorPalette(mySettings.getString("tia.dbgcolors"));
+
+#ifdef DEBUGGER_SUPPORT
+ createAccessBase();
+#endif // DEBUGGER_SUPPORT
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -161,16 +167,6 @@ void TIA::frameReset()
enableColorLoss(mySettings.getBool("colorloss"));
}
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void TIA::systemCyclesReset()
-{
- const uInt32 cycles = mySystem->cycles();
-
- myLastCycle -= cycles;
-
- mySound.adjustCycleCounter(-1 * cycles);
-}
-
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIA::install(System& system)
{
@@ -186,10 +182,12 @@ void TIA::installDelegate(System& system, Device& device)
// All accesses are to the given device
System::PageAccess access(&device, System::PA_READWRITE);
- // We're installing in a 2600 system
- for(uInt32 i = 0; i < 8192; i += (1 << System::PAGE_SHIFT))
- if((i & 0x1080) == 0x0000)
- mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
+ // Map all peek/poke to mirrors of TIA address space to this class
+ // That is, all mirrors of ($00 - $3F) in the lower 4K of the 2600
+ // address space are mapped here
+ for(uInt16 addr = 0; addr < 0x1000; addr += System::PAGE_SIZE)
+ if((addr & TIA_BIT) == 0x0000)
+ mySystem->setPageAccess(addr, access);
mySystem->m6502().setOnHaltCallback(
[this] () {
@@ -244,7 +242,7 @@ bool TIA::save(Serializer& out) const
out.putInt(int(myPriority));
out.putByte(mySubClock);
- out.putInt(myLastCycle);
+ out.putLong(myLastCycle);
out.putByte(mySpriteEnabledBits);
out.putByte(myCollisionsEnabledBits);
@@ -256,6 +254,8 @@ bool TIA::save(Serializer& out) const
out.putBool(myAutoFrameEnabled);
out.putByteArray(myShadowRegisters, 64);
+
+ out.putLong(myCyclesAtFrameStart);
}
catch(...)
{
@@ -313,7 +313,7 @@ bool TIA::load(Serializer& in)
myPriority = Priority(in.getInt());
mySubClock = in.getByte();
- myLastCycle = in.getInt();
+ myLastCycle = in.getLong();
mySpriteEnabledBits = in.getByte();
myCollisionsEnabledBits = in.getByte();
@@ -325,6 +325,8 @@ bool TIA::load(Serializer& in)
myAutoFrameEnabled = in.getBool();
in.getByteArray(myShadowRegisters, 64);
+
+ myCyclesAtFrameStart = in.getLong();
}
catch(...)
{
@@ -340,15 +342,15 @@ void TIA::bindToControllers()
{
myConsole.leftController().setOnAnalogPinUpdateCallback(
[this] (Controller::AnalogPin pin) {
- TIA& tia = mySystem->tia();
+ updateEmulation();
switch (pin) {
case Controller::AnalogPin::Five:
- tia.updatePaddle(1);
+ updatePaddle(1);
break;
case Controller::AnalogPin::Nine:
- tia.updatePaddle(0);
+ updatePaddle(0);
break;
}
}
@@ -356,15 +358,15 @@ void TIA::bindToControllers()
myConsole.rightController().setOnAnalogPinUpdateCallback(
[this] (Controller::AnalogPin pin) {
- TIA& tia = mySystem->tia();
+ updateEmulation();
switch (pin) {
case Controller::AnalogPin::Five:
- tia.updatePaddle(3);
+ updatePaddle(3);
break;
case Controller::AnalogPin::Nine:
- tia.updatePaddle(2);
+ updatePaddle(2);
break;
}
}
@@ -418,7 +420,7 @@ uInt8 TIA::peek(uInt16 address)
break;
case CXBLPF:
- result = collCXBLPF() | (lastDataBusValue & 0x40);
+ result = collCXBLPF();
break;
case INPT0:
@@ -1020,8 +1022,8 @@ TIA& TIA::updateScanline()
{
// Update frame by one scanline at a time
uInt32 line = scanlines();
- while (line == scanlines())
- updateScanlineByStep();
+ while (line == scanlines() && mySystem->m6502().execute(1))
+ updateEmulation();
return *this;
}
@@ -1030,8 +1032,8 @@ TIA& TIA::updateScanline()
TIA& TIA::updateScanlineByStep()
{
// Update frame by one CPU instruction/color clock
- mySystem->m6502().execute(1);
- updateEmulation();
+ if (mySystem->m6502().execute(1))
+ updateEmulation();
return *this;
}
@@ -1039,8 +1041,10 @@ TIA& TIA::updateScanlineByStep()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TIA& TIA::updateScanlineByTrace(int target)
{
- while (mySystem->m6502().getPC() != target)
- updateScanlineByStep();
+ uInt32 count = 100; // only try up to 100 steps
+ while (mySystem->m6502().getPC() != target && count-- &&
+ mySystem->m6502().execute(1))
+ updateEmulation();
return *this;
}
@@ -1054,12 +1058,12 @@ uInt8 TIA::registerValue(uInt8 reg) const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIA::updateEmulation()
{
- const uInt32 systemCycles = mySystem->cycles();
+ const uInt64 systemCycles = mySystem->cycles();
if (mySubClock > 2)
throw runtime_error("subclock exceeds range");
- const uInt32 cyclesToRun = 3 * (systemCycles - myLastCycle) + mySubClock;
+ const uInt32 cyclesToRun = 3 * uInt32(systemCycles - myLastCycle) + mySubClock;
mySubClock = 0;
myLastCycle = systemCycles;
@@ -1102,7 +1106,7 @@ void TIA::onRenderingStart()
void TIA::onFrameComplete()
{
mySystem->m6502().stop();
- mySystem->resetCycles();
+ myCyclesAtFrameStart = mySystem->cycles();
if (myXAtRenderingStart > 0)
memset(myFramebuffer, 0, myXAtRenderingStart);
@@ -1144,7 +1148,7 @@ void TIA::cycle(uInt32 colorClocks)
else
tickHframe();
- if (myCollisionUpdateRequired) updateCollision();
+ if (myCollisionUpdateRequired && !myFrameManager.vblank()) updateCollision();
}
if (++myHctr >= 228)
@@ -1277,51 +1281,57 @@ void TIA::renderPixel(uInt32 x, uInt32 y)
{
if (x >= 160) return;
- uInt8 color = myBackground.getColor();
+ uInt8 color = 0;
- switch (myPriority)
+ if (!myFrameManager.vblank())
{
- // Playfield has priority so ScoreBit isn't used
- // Priority from highest to lowest:
- // BL/PF => P0/M0 => P1/M1 => BK
- case Priority::pfp: // CTRLPF D2=1, D1=ignored
- color = myMissile1.getPixel(color);
- color = myPlayer1.getPixel(color);
- color = myMissile0.getPixel(color);
- color = myPlayer0.getPixel(color);
- color = myPlayfield.getPixel(color);
- color = myBall.getPixel(color);
- break;
+ switch (myPriority)
+ {
+ case Priority::pfp: // CTRLPF D2=1, D1=ignored
+ // Playfield has priority so ScoreBit isn't used
+ // Priority from highest to lowest:
+ // BL/PF => P0/M0 => P1/M1 => BK
+ if (myPlayfield.isOn()) color = myPlayfield.getColor();
+ else if (myBall.isOn()) color = myBall.getColor();
+ else if (myPlayer0.isOn()) color = myPlayer0.getColor();
+ else if (myMissile0.isOn()) color = myMissile0.getColor();
+ else if (myPlayer1.isOn()) color = myPlayer1.getColor();
+ else if (myMissile1.isOn()) color = myMissile1.getColor();
+ else color = myBackground.getColor();
+ break;
- case Priority::score: // CTRLPF D2=0, D1=1
- // Formally we have (priority from highest to lowest)
- // PF/P0/M0 => P1/M1 => BL => BK
- // for the first half and
- // P0/M0 => PF/P1/M1 => BL => BK
- // for the second half. However, the first ordering is equivalent
- // to the second (PF has the same color as P0/M0), so we can just
- // write
- color = myBall.getPixel(color);
- color = myMissile1.getPixel(color);
- color = myPlayer1.getPixel(color);
- color = myPlayfield.getPixel(color);
- color = myMissile0.getPixel(color);
- color = myPlayer0.getPixel(color);
- break;
+ case Priority::score: // CTRLPF D2=0, D1=1
+ // Formally we have (priority from highest to lowest)
+ // PF/P0/M0 => P1/M1 => BL => BK
+ // for the first half and
+ // P0/M0 => PF/P1/M1 => BL => BK
+ // for the second half. However, the first ordering is equivalent
+ // to the second (PF has the same color as P0/M0), so we can just
+ // write
+ if (myPlayer0.isOn()) color = myPlayer0.getColor();
+ else if (myMissile0.isOn()) color = myMissile0.getColor();
+ else if (myPlayfield.isOn()) color = myPlayfield.getColor();
+ else if (myPlayer1.isOn()) color = myPlayer1.getColor();
+ else if (myMissile1.isOn()) color = myMissile1.getColor();
+ else if (myBall.isOn()) color = myBall.getColor();
+ else color = myBackground.getColor();
+ break;
- // Priority from highest to lowest:
- // P0/M0 => P1/M1 => BL/PF => BK
- case Priority::normal: // CTRLPF D2=0, D1=0
- color = myPlayfield.getPixel(color);
- color = myBall.getPixel(color);
- color = myMissile1.getPixel(color);
- color = myPlayer1.getPixel(color);
- color = myMissile0.getPixel(color);
- color = myPlayer0.getPixel(color);
- break;
+ case Priority::normal: // CTRLPF D2=0, D1=0
+ // Priority from highest to lowest:
+ // P0/M0 => P1/M1 => BL/PF => BK
+ if (myPlayer0.isOn()) color = myPlayer0.getColor();
+ else if (myMissile0.isOn()) color = myMissile0.getColor();
+ else if (myPlayer1.isOn()) color = myPlayer1.getColor();
+ else if (myMissile1.isOn()) color = myMissile1.getColor();
+ else if (myPlayfield.isOn()) color = myPlayfield.getColor();
+ else if (myBall.isOn()) color = myBall.getColor();
+ else color = myBackground.getColor();
+ break;
+ }
}
- myFramebuffer[y * 160 + x] = myFrameManager.vblank() ? 0 : color;
+ myFramebuffer[y * 160 + x] = color;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -1402,11 +1412,12 @@ void TIA::delayedWrite(uInt8 address, uInt8 value)
break;
case HMCLR:
- myMissile0.hmm(0);
- myMissile1.hmm(0);
- myPlayer0.hmp(0);
- myPlayer1.hmp(0);
- myBall.hmbl(0);
+ // We must update the shadow registers for each HM object too
+ myMissile0.hmm(0); myShadowRegisters[HMM0] = 0;
+ myMissile1.hmm(0); myShadowRegisters[HMM1] = 0;
+ myPlayer0.hmp(0); myShadowRegisters[HMP0] = 0;
+ myPlayer1.hmp(0); myShadowRegisters[HMP1] = 0;
+ myBall.hmbl(0); myShadowRegisters[HMBL] = 0;
break;
case GRP0:
@@ -1570,3 +1581,40 @@ uInt8 TIA::collCXBLPF() const
{
return (myCollisionMask & CollisionMask::ball & CollisionMask::playfield) ? 0x80 : 0;
}
+
+#ifdef DEBUGGER_SUPPORT
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void TIA::createAccessBase()
+{
+#ifdef DEBUGGER_SUPPORT
+ myAccessBase = make_unique(TIA_SIZE);
+ memset(myAccessBase.get(), CartDebug::NONE, TIA_SIZE);
+ myAccessDelay = make_unique(TIA_SIZE);
+ memset(myAccessDelay.get(), TIA_DELAY, TIA_SIZE);
+#else
+ myAccessBase = nullptr;
+#endif
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+uInt8 TIA::getAccessFlags(uInt16 address) const
+{
+ return myAccessBase[address & TIA_MASK];
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void TIA::setAccessFlags(uInt16 address, uInt8 flags)
+{
+ // ignore none flag
+ if (flags != CartDebug::NONE) {
+ if (flags == CartDebug::WRITE) {
+ // the first two write accesses are assumed as initialization
+ if (myAccessDelay[address & TIA_MASK])
+ myAccessDelay[address & TIA_MASK]--;
+ else
+ myAccessBase[address & TIA_MASK] |= flags;
+ } else
+ myAccessBase[address & TIA_READ_MASK] |= flags;
+ }
+}
+#endif // DEBUGGER_SUPPORT
diff --git a/src/emucore/tia/TIA.hxx b/src/emucore/tia/TIA.hxx
index de922da28..c58c1f375 100644
--- a/src/emucore/tia/TIA.hxx
+++ b/src/emucore/tia/TIA.hxx
@@ -39,6 +39,7 @@
#include "PaddleReader.hxx"
#include "DelayQueueIterator.hxx"
#include "Control.hxx"
+#include "System.hxx"
/**
This class is a device that emulates the Television Interface Adaptor
@@ -56,12 +57,19 @@
class TIA : public Device
{
public:
+ /**
+ * These dummy register addresses are used to represent the delayed
+ * old / new register swap on writing GRPx and ENABL in the DelayQueue (see below).
+ */
enum DummyRegisters: uInt8 {
shuffleP0 = 0xF0,
shuffleP1 = 0xF1,
shuffleBL = 0xF2
};
+ /**
+ * Possible palette entries for objects in "fixed debug color mode".
+ */
enum FixedColor {
NTSC_RED = 0x30,
NTSC_ORANGE = 0x38,
@@ -106,12 +114,6 @@ class TIA : public Device
*/
void frameReset();
- /**
- Notification method invoked by the system right before the
- system resets its cycle counter to zero.
- */
- void systemCyclesReset() override;
-
/**
Install TIA in the specified system. Invoked by the system
when the TIA is attached to it.
@@ -258,6 +260,23 @@ class TIA : public Device
*/
uInt32 scanlinesLastFrame() const { return myFrameManager.scanlinesLastFrame(); }
+ /**
+ Answers the total system cycles from the start of the emulation.
+ */
+ uInt64 cycles() const { return uInt64(mySystem->cycles()); }
+
+ /**
+ Answers the frame count from the start of the emulation.
+ */
+ uInt32 frameCount() const { return myFrameManager.frameCount(); }
+
+ /**
+ Answers the system cycles from the start of the current frame.
+ */
+ uInt32 frameCycles() const {
+ return uInt32(mySystem->cycles() - myCyclesAtFrameStart);
+ }
+
/**
Answers whether the TIA is currently in being rendered
(we're in between the start and end of drawing a frame).
@@ -409,53 +428,123 @@ class TIA : public Device
string name() const override { return "TIA"; }
private:
+ /**
+ * During each line, the TIA cycles through these two states.
+ */
enum HState {blank, frame};
+
+ /**
+ * The three different modes of the priority encoder. Check TIA::renderPixel
+ * for a precise definition.
+ */
enum Priority {pfp, score, normal};
+ /**
+ * Palette and indices for fixed debug colors.
+ */
enum FixedObject { P0, M0, P1, M1, PF, BL };
FixedColor myFixedColorPalette[2][6];
private:
+ /**
+ * This callback is invoked by FrameManager when a new frame starts.
+ */
void onFrameStart();
+ /**
+ * This callback is invoked by FrameManager when the visible range of the
+ * current frame starts.
+ */
void onRenderingStart();
+ /**
+ * This callback is invoked by FrameManager when the current frame completes.
+ */
void onFrameComplete();
+ /**
+ * Called when the CPU enters halt state (RDY pulled low). Execution continues
+ * immediatelly afterwards, so we have to adjust the system clock to account
+ * for the cycles the 6502 spent in halt state.
+ */
void onHalt();
+ /**
+ * Run and forward TIA emulation to the current system clock.
+ */
void updateEmulation();
+ /**
+ * Execute colorClocks cycles of TIA simulation.
+ */
void cycle(uInt32 colorClocks);
+ /**
+ * Advance the movement logic by a single clock.
+ */
void tickMovement();
+ /**
+ * Advance a single clock during hblank.
+ */
void tickHblank();
+ /**
+ * Advance a single clock duing the visible part of the scanline.
+ */
void tickHframe();
+ /**
+ * Execute a RSYNC.
+ */
void applyRsync();
+ /**
+ * Update the collision bitfield.
+ */
void updateCollision();
+ /**
+ * Render the current pixel into the framebuffer.
+ */
void renderPixel(uInt32 x, uInt32 y);
+ /**
+ * Clear the first 8 pixels of a scanline with black if we are in hblank
+ * (called during HMOVE).
+ */
void clearHmoveComb();
+ /**
+ * Advance a line and update our state accordingly.
+ */
void nextLine();
+ /**
+ * Clone the last line. Called in nextLine if TIA state was unchanged.
+ */
void cloneLastLine();
+ /**
+ * Execute a delayed write. Called when the DelayQueue is pumped.
+ */
void delayedWrite(uInt8 address, uInt8 value);
+ /**
+ * Update all paddle readout circuits to the current controller state.
+ */
void updatePaddle(uInt8 idx);
+ /**
+ * Get the target counter value during a RESx. This essentially depends on
+ * the position in the current scanline.
+ */
uInt8 resxCounter();
/**
Get the result of the specified collision register.
- */
+ */
uInt8 collCXM0P() const;
uInt8 collCXM1P() const;
uInt8 collCXP0FB() const;
@@ -465,18 +554,50 @@ class TIA : public Device
uInt8 collCXPPMM() const;
uInt8 collCXBLPF() const;
+#ifdef DEBUGGER_SUPPORT
+ void createAccessBase();
+ /**
+ Query/change the given address type to use the given disassembly flags
+
+ @param address The address to modify
+ @param flags A bitfield of DisasmType directives for the given address
+ */
+ uInt8 getAccessFlags(uInt16 address) const override;
+ void setAccessFlags(uInt16 address, uInt8 flags) override;
+#endif // DEBUGGER_SUPPORT
+
private:
Console& myConsole;
Sound& mySound;
Settings& mySettings;
+ /**
+ * The length of the delay queue (maximum number of clocks delay)
+ */
static constexpr unsigned delayQueueLength = 16;
+
+ /**
+ * The size of the delay queue (maximum number of writes scheduled in a single slot).
+ */
static constexpr unsigned delayQueueSize = 16;
+
+ /**
+ * A list of delayed writes that are queued up for future execution. Delayed
+ * writes can be both actual writes whose effect is delayed by one or more clocks
+ * on real hardware and delayed side effects of certain operations (GRPx!).
+ */
DelayQueue myDelayQueue;
+ /**
+ * The frame manager is responsible for detecting frame boundaries and the visible
+ * region of each frame.
+ */
FrameManager myFrameManager;
+ /**
+ * The various TIA objects.
+ */
Background myBackground;
Playfield myPlayfield;
Missile myMissile0;
@@ -484,57 +605,147 @@ class TIA : public Device
Player myPlayer0;
Player myPlayer1;
Ball myBall;
+
+ /**
+ * The paddle readout circuits.
+ */
PaddleReader myPaddleReaders[4];
+ /**
+ * Circuits for the "latched inputs".
+ */
LatchedInput myInput0;
LatchedInput myInput1;
// Pointer to the internal color-index-based frame buffer
uInt8 myFramebuffer[160 * TIAConstants::frameBufferHeight];
+ /**
+ * Setting this to true injects random values into undefined reads.
+ */
bool myTIAPinsDriven;
+ /**
+ * The current "line state" --- either hblank or frame.
+ */
HState myHstate;
- // Master line counter
+ /**
+ * Master line counter
+ */
+
uInt8 myHctr;
- // Delta between master line counter and actual color clock. Nonzero after RSYNC (before the scanline terminates)
+ /**
+ * Delta between master line counter and actual color clock. Nonzero after
+ * RSYNC (before the scanline terminates)
+ */
Int32 myHctrDelta;
- // Electron beam x at rendering start (used for blanking out any pixels from the last frame that are not overwritten)
+ /**
+ * Electron beam x at rendering start (used for blanking out any pixels from
+ * the last frame that are not overwritten)
+ */
uInt8 myXAtRenderingStart;
+ /**
+ * Do we need to update the collision mask this clock?
+ */
bool myCollisionUpdateRequired;
+
+ /**
+ * The collision latches are represented by 15 bits in a bitfield.
+ */
uInt32 myCollisionMask;
+ /**
+ * The movement clock counts the extra ticks sent to the objects during
+ * movement.
+ */
uInt32 myMovementClock;
+ /**
+ * Movement mode --- are we sending movement clocks?
+ */
bool myMovementInProgress;
+ /**
+ * Do we have an extended hblank this line? Get set by strobing HMOVE and
+ * cleared when the line wraps.
+ */
bool myExtendedHblank;
+ /**
+ * Counts the number of line wraps since the last external TIA state change.
+ * If at least two line breaks have passed, the TIA will suspend simulation
+ * and just reuse the last line instead.
+ */
uInt32 myLinesSinceChange;
+ /**
+ * The current mode of the priority encoder.
+ */
Priority myPriority;
+ /**
+ * The index of the last CPU cycle that was included in the simulation.
+ */
+ uInt64 myLastCycle;
+ /**
+ * Keeps track of a possible fractional number of clocks that still need
+ * to be simulated.
+ */
uInt8 mySubClock;
- Int32 myLastCycle;
+ /**
+ * Bitmasks that track which sprites / collisions are enabled / disabled.
+ */
uInt8 mySpriteEnabledBits;
uInt8 myCollisionsEnabledBits;
+ /**
+ * The color used to highlight HMOVE blanks (if enabled).
+ */
uInt8 myColorHBlank;
+ /**
+ * The total number of color clocks since emulation started. This is a
+ * double a) to avoid overflows and b) as it will enter floating point
+ * expressions in the paddle readout simulation anyway.
+ */
double myTimestamp;
+ /**
+ * The "shadow registers" track the last written register value for the
+ * debugger.
+ */
uInt8 myShadowRegisters[64];
- // Automatic framerate correction based on number of scanlines
+ /**
+ * Automatic framerate correction based on number of scanlines.
+ */
bool myAutoFrameEnabled;
- // Indicates if color loss should be enabled or disabled. Color loss
- // occurs on PAL-like systems when the previous frame contains an odd
- // number of scanlines.
+ /**
+ * Indicates if color loss should be enabled or disabled. Color loss
+ * occurs on PAL-like systems when the previous frame contains an odd
+ * number of scanlines.
+ */
bool myColorLossEnabled;
bool myColorLossActive;
+ /**
+ * System cycles at the end of the previous frame / beginning of next frame
+ */
+ uInt64 myCyclesAtFrameStart;
+
+#ifdef DEBUGGER_SUPPORT
+ // The arrays containing information about every byte of TIA
+ // indicating whether and how (RW) it is used.
+ BytePtr myAccessBase;
+ // The array used to skip the first two TIA access trackings
+ BytePtr myAccessDelay;
+
+ static constexpr uInt16
+ TIA_SIZE = 0x40, TIA_MASK = TIA_SIZE - 1, TIA_READ_MASK = 0x0f, TIA_BIT = 0x080, TIA_DELAY = 2;
+#endif // DEBUGGER_SUPPORT
+
private:
TIA() = delete;
TIA(const TIA&) = delete;
diff --git a/src/emucore/tia/frame-manager/FrameManager.cxx b/src/emucore/tia/frame-manager/FrameManager.cxx
index 66c399728..cc10cb3c2 100644
--- a/src/emucore/tia/frame-manager/FrameManager.cxx
+++ b/src/emucore/tia/frame-manager/FrameManager.cxx
@@ -32,7 +32,6 @@ enum Metrics: uInt32 {
maxLinesVsync = 32,
maxLinesVsyncDuringAutodetect = 100,
visibleOverscan = 20,
- maxUnderscan = 10,
tvModeDetectionTolerance = 20,
initialGarbageFrames = TIAConstants::initialGarbageFrames,
framesForModeConfirmation = 5,
@@ -317,7 +316,7 @@ void FrameManager::updateLayout(FrameLayout layout)
if (layout == myLayout) return;
#ifdef TIA_FRAMEMANAGER_DEBUG_LOG
- (cout << "TV mode switched to " << int(mode) << "\n").flush();
+ (cout << "TV mode switched to " << int(layout) << "\n").flush();
#endif // TIA_FRAMEMANAGER_DEBUG_LOG
myLayout = layout;
@@ -350,6 +349,10 @@ void FrameManager::updateLayout(FrameLayout layout)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameManager::setVblank(bool vblank)
{
+ #ifdef TIA_FRAMEMANAGER_DEBUG_LOG
+ (cout << "vblank change " << myVblankManager.vblank() << " -> " << vblank << "@" << myLineInState << "\n").flush();
+ #endif // TIA_FRAMEMANAGER_DEBUG_LOG
+
if (myState == State::waitForFrameStart) {
if (myVblankManager.setVblankDuringVblank(vblank, myTotalFrames <= Metrics::initialGarbageFrames)) {
setState(State::frame);
diff --git a/src/emucore/tia/frame-manager/VblankManager.cxx b/src/emucore/tia/frame-manager/VblankManager.cxx
index b0a92e106..554537a4c 100644
--- a/src/emucore/tia/frame-manager/VblankManager.cxx
+++ b/src/emucore/tia/frame-manager/VblankManager.cxx
@@ -75,9 +75,6 @@ void VblankManager::start()
myIsRunning = true;
myVblankViolated = false;
- if (myMode == VblankMode::locked && ++myFramesInLockedMode > Metrics::framesUntilFinal)
- setVblankMode(VblankMode::final);
-
if (myJitter > 0) myJitter = std::max(myJitter - myJitterFactor, 0);
if (myJitter < 0) myJitter = std::min(myJitter + myJitterFactor, 0);
}
@@ -87,11 +84,17 @@ bool VblankManager::nextLine(bool isGarbageFrame)
{
if (!myIsRunning) return false;
- myCurrentLine++;
-
+ // Make sure that we do the transition check **before** incrementing the line
+ // counter. This ensures that, if the transition is caused by VBLANK off during
+ // the line, this will continue to trigger the transition in 'locked' mode. Otherwise,
+ // the transition would be triggered by the line change **before** the VBLANK
+ // and thus detected as a suprious violation. Sigh, this stuff is complicated,
+ // isn't it?
const bool transition = shouldTransition(isGarbageFrame);
if (transition) myIsRunning = false;
+ myCurrentLine++;
+
return transition;
}
@@ -122,26 +125,37 @@ bool VblankManager::setVblankDuringVblank(bool vblank, bool isGarbageFrame)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool VblankManager::shouldTransition(bool isGarbageFrame)
{
- bool shouldTransition = myCurrentLine >= (myVblank ? myVblankLines : myVblankLines - Metrics::maxUnderscan);
+ // Are we free to transition as per vblank cycle?
+ bool shouldTransition = myCurrentLine + 1 >= (myVblank ? myVblankLines : myVblankLines - Metrics::maxUnderscan);
+
+ // Do we **actually** transition? This depends on what mode we are in.
bool transition = false;
switch (myMode) {
+ // Floating mode: we still are looking for a stable frame start
case VblankMode::floating:
+ // Are we free to transition?
if (shouldTransition) {
+ // Is this same scanline in which the transition ocurred last frame?
if (!isGarbageFrame && myCurrentLine == myLastVblankLines)
+ // Yes? -> Increase the number of stable frames
myStableVblankFrames++;
else
+ // No? -> Frame start shifted again, set the number of consecutive stable frames to zero
myStableVblankFrames = 0;
+ // Save the transition point for checking on it next frame
myLastVblankLines = myCurrentLine;
#ifdef TIA_VBLANK_MANAGER_DEBUG_LOG
(cout << "leaving vblank in floating mode, should transition: " << shouldTransition << "\n").flush();
#endif
+ // In floating mode, we transition whenever we can.
transition = true;
}
+ // Transition to locked mode if we saw enough stable frames in a row.
if (myStableVblankFrames >= Metrics::minStableVblankFrames) {
setVblankMode(VblankMode::locked);
myVblankViolations = 0;
@@ -149,13 +163,20 @@ bool VblankManager::shouldTransition(bool isGarbageFrame)
break;
+ // Locked mode: always transition at the same point, but check whether this is actually the
+ // detected transition point and revert state if applicable
case VblankMode::locked:
+ // Have we reached the transition point?
if (myCurrentLine == myLastVblankLines) {
+ // Are we free to transition per the algorithm and didn't we observe an violation before?
+ // (aka did the algorithm tell us to transition before reaching the actual line)
if (shouldTransition && !myVblankViolated)
+ // Reset the number of irregular frames (if any)
myVblankViolations = 0;
else {
+ // Record a violation if it wasn't recorded before
if (!myVblankViolated) myVblankViolations++;
myVblankViolated = true;
}
@@ -164,24 +185,33 @@ bool VblankManager::shouldTransition(bool isGarbageFrame)
(cout << "leaving vblank in locked mode, should transition: " << shouldTransition << "\n").flush();
#endif
+ // transition
transition = true;
- } else if (shouldTransition){
+ // The algorithm tells us to transition although we haven't reached the trip line before
+ } else if (shouldTransition) {
+ // Record a violation if it wasn't recorded before
if (!myVblankViolated) myVblankViolations++;
myVblankViolated = true;
}
- if (myVblankViolations > Metrics::maxVblankViolations) {
+ // Freeze frame start if the detected value seems to be sufficiently stable
+ if (transition && ++myFramesInLockedMode > Metrics::framesUntilFinal) {
+ setVblankMode(VblankMode::final);
+ // Revert to floating mode if there were too many irregular frames in a row
+ } else if (myVblankViolations > Metrics::maxVblankViolations) {
setVblankMode(VblankMode::floating);
myStableVblankFrames = 0;
}
break;
+ // Fixed mode: use external ystart value
case VblankMode::fixed:
transition = (Int32)myCurrentLine >=
std::max(myYstart + std::min(myJitter, Metrics::maxJitter), 0);
break;
+ // Final mode: use detected ystart value
case VblankMode::final:
transition = (Int32)myCurrentLine >=
std::max(myLastVblankLines + std::min(myJitter, Metrics::maxJitter), 0);
diff --git a/src/gui/InputDialog.cxx b/src/gui/InputDialog.cxx
index c0bc7ad68..2e3bfc8e5 100644
--- a/src/gui/InputDialog.cxx
+++ b/src/gui/InputDialog.cxx
@@ -20,6 +20,7 @@
#include "OSystem.hxx"
#include "Joystick.hxx"
#include "Paddles.hxx"
+#include "PointingDevice.hxx"
#include "Settings.hxx"
#include "EventMappingWidget.hxx"
#include "EditTextWidget.hxx"
@@ -45,7 +46,7 @@ InputDialog::InputDialog(OSystem& osystem, DialogContainer& parent,
// Set real dimensions
_w = std::min(50 * fontWidth + 10, max_w);
- _h = std::min(15 * (lineHeight + 4) + 14, max_h);
+ _h = std::min(16 * (lineHeight + 4) + 14, max_h);
// The tab widget
xpos = 2; ypos = vBorder;
@@ -164,8 +165,8 @@ void InputDialog::addDevicePortTab(const GUI::Font& font)
// Add paddle speed (digital emulation)
xpos = 5; ypos += lineHeight + 4;
myDPaddleSpeed = new SliderWidget(myTab, font, xpos, ypos, pwidth, lineHeight,
- "Digital paddle sensitivity ",
- lwidth, kDPSpeedChanged);
+ "Digital paddle sensitivity ",
+ lwidth, kDPSpeedChanged);
myDPaddleSpeed->setMinValue(1); myDPaddleSpeed->setMaxValue(20);
xpos += myDPaddleSpeed->getWidth() + 5;
myDPaddleLabel = new StaticTextWidget(myTab, font, xpos, ypos+1, 24, lineHeight,
@@ -176,8 +177,8 @@ void InputDialog::addDevicePortTab(const GUI::Font& font)
// Add paddle speed (mouse emulation)
xpos = 5; ypos += lineHeight + 4;
myMPaddleSpeed = new SliderWidget(myTab, font, xpos, ypos, pwidth, lineHeight,
- "Mouse paddle sensitivity ",
- lwidth, kMPSpeedChanged);
+ "Mouse paddle sensitivity ",
+ lwidth, kMPSpeedChanged);
myMPaddleSpeed->setMinValue(1); myMPaddleSpeed->setMaxValue(20);
xpos += myMPaddleSpeed->getWidth() + 5;
myMPaddleLabel = new StaticTextWidget(myTab, font, xpos, ypos+1, 24, lineHeight,
@@ -185,6 +186,18 @@ void InputDialog::addDevicePortTab(const GUI::Font& font)
myMPaddleSpeed->setFlags(WIDGET_CLEARBG);
wid.push_back(myMPaddleSpeed);
+ // Add trackball speed
+ xpos = 5; ypos += lineHeight + 4;
+ myTrackBallSpeed = new SliderWidget(myTab, font, xpos, ypos, pwidth, lineHeight,
+ "Trackball sensitivity ",
+ lwidth, kTBSpeedChanged);
+ myTrackBallSpeed->setMinValue(1); myTrackBallSpeed->setMaxValue(20);
+ xpos += myTrackBallSpeed->getWidth() + 5;
+ myTrackBallLabel = new StaticTextWidget(myTab, font, xpos, ypos+1, 24, lineHeight,
+ "", kTextAlignLeft);
+ myTrackBallSpeed->setFlags(WIDGET_CLEARBG);
+ wid.push_back(myTrackBallSpeed);
+
// Add 'allow all 4 directions' for joystick
xpos = 10; ypos += lineHeight + 12;
myAllowAll4 = new CheckboxWidget(myTab, font, xpos, ypos,
@@ -240,6 +253,10 @@ void InputDialog::loadConfig()
myMPaddleSpeed->setValue(instance().settings().getInt("msense"));
myMPaddleLabel->setLabel(instance().settings().getString("msense"));
+ // Trackball speed
+ myTrackBallSpeed->setValue(instance().settings().getInt("tsense"));
+ myTrackBallLabel->setLabel(instance().settings().getString("tsense"));
+
// AtariVox serial port
myAVoxPort->setText(instance().settings().getString("avoxport"));
@@ -279,6 +296,11 @@ void InputDialog::saveConfig()
instance().settings().setValue("msense", sensitivity);
Paddles::setMouseSensitivity(sensitivity);
+ // Trackball speed
+ sensitivity = myTrackBallSpeed->getValue();
+ instance().settings().setValue("tsense", sensitivity);
+ PointingDevice::setSensitivity(sensitivity);
+
// AtariVox serial port
instance().settings().setValue("avoxport", myAVoxPort->getText());
@@ -330,6 +352,8 @@ void InputDialog::setDefaults()
myDPaddleLabel->setLabel("10");
myMPaddleSpeed->setValue(10);
myMPaddleLabel->setLabel("10");
+ myTrackBallSpeed->setValue(10);
+ myTrackBallLabel->setLabel("10");
// AtariVox serial port
myAVoxPort->setText("");
@@ -433,6 +457,10 @@ void InputDialog::handleCommand(CommandSender* sender, int cmd,
myMPaddleLabel->setValue(myMPaddleSpeed->getValue());
break;
+ case kTBSpeedChanged:
+ myTrackBallLabel->setValue(myTrackBallSpeed->getValue());
+ break;
+
case kDBButtonPressed:
if(!myJoyDialog)
myJoyDialog = make_unique
diff --git a/src/gui/InputDialog.hxx b/src/gui/InputDialog.hxx
index d471c8e10..d2b56efc5 100644
--- a/src/gui/InputDialog.hxx
+++ b/src/gui/InputDialog.hxx
@@ -57,6 +57,7 @@ class InputDialog : public Dialog
kDeadzoneChanged = 'DZch',
kDPSpeedChanged = 'PDch',
kMPSpeedChanged = 'PMch',
+ kTBSpeedChanged = 'TBch',
kDBButtonPressed = 'DBbp'
};
@@ -75,8 +76,10 @@ class InputDialog : public Dialog
StaticTextWidget* myDeadzoneLabel;
SliderWidget* myDPaddleSpeed;
SliderWidget* myMPaddleSpeed;
+ SliderWidget* myTrackBallSpeed;
StaticTextWidget* myDPaddleLabel;
StaticTextWidget* myMPaddleLabel;
+ StaticTextWidget* myTrackBallLabel;
CheckboxWidget* myAllowAll4;
CheckboxWidget* myGrabMouse;
CheckboxWidget* myCtrlCombo;
diff --git a/src/gui/SnapshotDialog.cxx b/src/gui/SnapshotDialog.cxx
index 6dd3a7aee..05b1e7272 100644
--- a/src/gui/SnapshotDialog.cxx
+++ b/src/gui/SnapshotDialog.cxx
@@ -111,7 +111,7 @@ SnapshotDialog::SnapshotDialog(OSystem& osystem, DialogContainer& parent,
// Snapshot in 1x mode (ignore scaling)
ypos += mySnapSingle->getHeight() + 4;
mySnap1x = new CheckboxWidget(this, font, xpos, ypos,
- "Disable image filtering (1x mode)");
+ "Ignore scaling (1x mode)");
wid.push_back(mySnap1x);
// Add Defaults, OK and Cancel buttons
@@ -156,8 +156,8 @@ void SnapshotDialog::saveConfig()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SnapshotDialog::setDefaults()
{
- mySnapSavePath->setText(instance().defaultSnapSaveDir());
- mySnapLoadPath->setText(instance().defaultSnapLoadDir());
+ mySnapSavePath->setText(instance().defaultSaveDir());
+ mySnapLoadPath->setText(instance().defaultLoadDir());
mySnapSingle->setState(false);
mySnap1x->setState(false);
diff --git a/src/gui/VideoDialog.cxx b/src/gui/VideoDialog.cxx
index 1a20c186d..9a311b7d8 100644
--- a/src/gui/VideoDialog.cxx
+++ b/src/gui/VideoDialog.cxx
@@ -188,6 +188,11 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent,
// Center window (in windowed mode)
myCenter = new CheckboxWidget(myTab, font, xpos, ypos, "Center window");
wid.push_back(myCenter);
+ ypos += lineHeight + 4;
+
+ // Use multi-threading
+ myUseThreads = new CheckboxWidget(myTab, font, xpos, ypos, "Use multi-threading");
+ wid.push_back(myUseThreads);
// Add items for tab 0
addToFocusList(wid, myTab, tabID);
@@ -437,6 +442,9 @@ void VideoDialog::loadConfig()
// Fast loading of Supercharger BIOS
myFastSCBios->setState(instance().settings().getBool("fastscbios"));
+ // Multi-threaded rendering
+ myUseThreads->setState(instance().settings().getBool("threads"));
+
// TV Mode
myTVMode->setSelected(
instance().settings().getString("tv.filter"), "0");
@@ -530,6 +538,11 @@ void VideoDialog::saveConfig()
// Fast loading of Supercharger BIOS
instance().settings().setValue("fastscbios", myFastSCBios->getState());
+ // Multi-threaded rendering
+ instance().settings().setValue("threads", myUseThreads->getState());
+ if(instance().hasConsole())
+ instance().frameBuffer().tiaSurface().ntsc().enableThreading(myUseThreads->getState());
+
// TV Mode
instance().settings().setValue("tv.filter",
myTVMode->getSelectedTag().toString());
@@ -607,6 +620,7 @@ void VideoDialog::setDefaults()
myUIMessages->setState(true);
myCenter->setState(false);
myFastSCBios->setState(true);
+ myUseThreads->setState(false);
break;
}
diff --git a/src/gui/VideoDialog.hxx b/src/gui/VideoDialog.hxx
index b15bcd128..71222d82b 100644
--- a/src/gui/VideoDialog.hxx
+++ b/src/gui/VideoDialog.hxx
@@ -74,6 +74,7 @@ class VideoDialog : public Dialog
CheckboxWidget* myUIMessages;
CheckboxWidget* myCenter;
CheckboxWidget* myFastSCBios;
+ CheckboxWidget* myUseThreads;
// TV effects adjustables (custom mode)
PopUpWidget* myTVMode;
diff --git a/src/libpng/png.c b/src/libpng/png.c
index 40688be12..2352df13c 100644
--- a/src/libpng/png.c
+++ b/src/libpng/png.c
@@ -1,7 +1,7 @@
/* png.c - location for general purpose libpng functions
*
- * Last changed in libpng 1.6.30 [(PENDING RELEASE)]
+ * Last changed in libpng 1.6.32 [August 24, 2017]
* Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -14,7 +14,27 @@
#include "pngpriv.h"
/* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_6_30 Your_png_h_is_not_version_1_6_30;
+typedef png_libpng_version_1_6_32 Your_png_h_is_not_version_1_6_32;
+
+#ifdef __GNUC__
+/* The version tests may need to be added to, but the problem warning has
+ * consistently been fixed in GCC versions which obtain wide-spread release.
+ * The problem is that many versions of GCC rearrange comparison expressions in
+ * the optimizer in such a way that the results of the comparison will change
+ * if signed integer overflow occurs. Such comparisons are not permitted in
+ * ANSI C90, however GCC isn't clever enough to work out that that do not occur
+ * below in png_ascii_from_fp and png_muldiv, so it produces a warning with
+ * -Wextra. Unfortunately this is highly dependent on the optimizer and the
+ * machine architecture so the warning comes and goes unpredictably and is
+ * impossible to "fix", even were that a good idea.
+ */
+#if __GNUC__ == 7 && __GNUC_MINOR__ == 1
+#define GCC_STRICT_OVERFLOW 1
+#endif /* GNU 7.1.x */
+#endif /* GNU */
+#ifndef GCC_STRICT_OVERFLOW
+#define GCC_STRICT_OVERFLOW 0
+#endif
/* Tells libpng that we have already handled the first "num_bytes" bytes
* of the PNG file signature. If the PNG data is embedded into another
@@ -595,6 +615,26 @@ png_free_data(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 mask,
}
#endif
+#ifdef PNG_eXIf_SUPPORTED
+ /* Free any eXIf entry */
+ if (((mask & PNG_FREE_EXIF) & info_ptr->free_me) != 0)
+ {
+# ifdef PNG_READ_eXIf_SUPPORTED
+ if (info_ptr->eXIf_buf)
+ {
+ png_free(png_ptr, info_ptr->eXIf_buf);
+ info_ptr->eXIf_buf = NULL;
+ }
+# endif
+ if (info_ptr->exif)
+ {
+ png_free(png_ptr, info_ptr->exif);
+ info_ptr->exif = NULL;
+ }
+ info_ptr->valid &= ~PNG_INFO_eXIf;
+ }
+#endif
+
#ifdef PNG_hIST_SUPPORTED
/* Free any hIST entry */
if (((mask & PNG_FREE_HIST) & info_ptr->free_me) != 0)
@@ -776,14 +816,14 @@ png_get_copyright(png_const_structrp png_ptr)
#else
# ifdef __STDC__
return PNG_STRING_NEWLINE \
- "libpng version 1.6.30 - June 28, 2017" PNG_STRING_NEWLINE \
+ "libpng version 1.6.32 - August 24, 2017" PNG_STRING_NEWLINE \
"Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson" \
PNG_STRING_NEWLINE \
"Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
"Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \
PNG_STRING_NEWLINE;
# else
- return "libpng version 1.6.30 - June 28, 2017\
+ return "libpng version 1.6.32 - August 24, 2017\
Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson\
Copyright (c) 1996-1997 Andreas Dilger\
Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.";
@@ -2857,6 +2897,14 @@ png_pow10(int power)
/* Function to format a floating point value in ASCII with a given
* precision.
*/
+#if GCC_STRICT_OVERFLOW
+#pragma GCC diagnostic push
+/* The problem arises below with exp_b10, which can never overflow because it
+ * comes, originally, from frexp and is therefore limited to a range which is
+ * typically +/-710 (log2(DBL_MAX)/log2(DBL_MIN)).
+ */
+#pragma GCC diagnostic warning "-Wstrict-overflow=2"
+#endif /* GCC_STRICT_OVERFLOW */
void /* PRIVATE */
png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, png_size_t size,
double fp, unsigned int precision)
@@ -2946,7 +2994,7 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, png_size_t size,
*/
if (exp_b10 < 0 && exp_b10 > -3) /* PLUS 3 TOTAL 4 */
{
- czero = (unsigned int)(-exp_b10); /* PLUS 2 digits: TOTAL 3 */
+ czero = 0U-exp_b10; /* PLUS 2 digits: TOTAL 3 */
exp_b10 = 0; /* Dot added below before first output. */
}
else
@@ -3087,7 +3135,7 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, png_size_t size,
/* Check for an exponent, if we don't need one we are
* done and just need to terminate the string. At
- * this point exp_b10==(-1) is effectively if flag - it got
+ * this point exp_b10==(-1) is effectively a flag - it got
* to '-1' because of the decrement after outputting
* the decimal point above (the exponent required is
* *not* -1!)
@@ -3101,7 +3149,7 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, png_size_t size,
* zeros were *not* output, so this doesn't increase
* the output count.
*/
- while (--exp_b10 >= 0) *ascii++ = 48;
+ while (exp_b10-- > 0) *ascii++ = 48;
*ascii = 0;
@@ -3131,11 +3179,11 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, png_size_t size,
if (exp_b10 < 0)
{
*ascii++ = 45; --size; /* '-': PLUS 1 TOTAL 3+precision */
- uexp_b10 = (unsigned int)(-exp_b10);
+ uexp_b10 = 0U-exp_b10;
}
else
- uexp_b10 = (unsigned int)exp_b10;
+ uexp_b10 = 0U+exp_b10;
cdigits = 0;
@@ -3178,6 +3226,9 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, png_size_t size,
/* Here on buffer too small. */
png_error(png_ptr, "ASCII conversion buffer too small");
}
+#if GCC_STRICT_OVERFLOW
+#pragma GCC diagnostic pop
+#endif /* GCC_STRICT_OVERFLOW */
# endif /* FLOATING_POINT */
@@ -3291,6 +3342,15 @@ png_fixed(png_const_structrp png_ptr, double fp, png_const_charp text)
* the nearest .00001). Overflow and divide by zero are signalled in
* the result, a boolean - true on success, false on overflow.
*/
+#if GCC_STRICT_OVERFLOW /* from above */
+/* It is not obvious which comparison below gets optimized in such a way that
+ * signed overflow would change the result; looking through the code does not
+ * reveal any tests which have the form GCC complains about, so presumably the
+ * optimizer is moving an add or subtract into the 'if' somewhere.
+ */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic warning "-Wstrict-overflow=2"
+#endif /* GCC_STRICT_OVERFLOW */
int
png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times,
png_int_32 divisor)
@@ -3405,6 +3465,9 @@ png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times,
return 0;
}
+#if GCC_STRICT_OVERFLOW
+#pragma GCC diagnostic pop
+#endif /* GCC_STRICT_OVERFLOW */
#endif /* READ_GAMMA || INCH_CONVERSIONS */
#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED)
diff --git a/src/libpng/png.h b/src/libpng/png.h
index c2c4fdf25..51ac8abe7 100644
--- a/src/libpng/png.h
+++ b/src/libpng/png.h
@@ -1,7 +1,7 @@
/* png.h - header file for PNG reference library
*
- * libpng version 1.6.30, June 28, 2017
+ * libpng version 1.6.32, August 24, 2017
*
* Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
@@ -12,7 +12,7 @@
* Authors and maintainers:
* libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat
* libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger
- * libpng versions 0.97, January 1998, through 1.6.30, June 28, 2017:
+ * libpng versions 0.97, January 1998, through 1.6.32, August 24, 2017:
* Glenn Randers-Pehrson.
* See also "Contributing Authors", below.
*/
@@ -25,7 +25,7 @@
*
* This code is released under the libpng license.
*
- * libpng versions 1.0.7, July 1, 2000 through 1.6.30, June 28, 2017 are
+ * libpng versions 1.0.7, July 1, 2000 through 1.6.32, August 24, 2017 are
* Copyright (c) 2000-2002, 2004, 2006-2017 Glenn Randers-Pehrson, are
* derived from libpng-1.0.6, and are distributed according to the same
* disclaimer and license as libpng-1.0.6 with the following individuals
@@ -213,7 +213,7 @@
* ...
* 1.5.28 15 10527 15.so.15.28[.0]
* ...
- * 1.6.30 16 10630 16.so.16.30[.0]
+ * 1.6.32 16 10632 16.so.16.32[.0]
*
* Henceforth the source version will match the shared-library major
* and minor numbers; the shared-library major version number will be
@@ -241,13 +241,13 @@
* Y2K compliance in libpng:
* =========================
*
- * June 28, 2017
+ * August 24, 2017
*
* Since the PNG Development group is an ad-hoc body, we can't make
* an official declaration.
*
* This is your unofficial assurance that libpng from version 0.71 and
- * upward through 1.6.30 are Y2K compliant. It is my belief that
+ * upward through 1.6.32 are Y2K compliant. It is my belief that
* earlier versions were also Y2K compliant.
*
* Libpng only has two year fields. One is a 2-byte unsigned integer
@@ -309,8 +309,8 @@
*/
/* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.6.30"
-#define PNG_HEADER_VERSION_STRING " libpng version 1.6.30 - June 28, 2017\n"
+#define PNG_LIBPNG_VER_STRING "1.6.32"
+#define PNG_HEADER_VERSION_STRING " libpng version 1.6.32 - August 24, 2017\n"
#define PNG_LIBPNG_VER_SONUM 16
#define PNG_LIBPNG_VER_DLLNUM 16
@@ -318,7 +318,7 @@
/* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
#define PNG_LIBPNG_VER_MAJOR 1
#define PNG_LIBPNG_VER_MINOR 6
-#define PNG_LIBPNG_VER_RELEASE 30
+#define PNG_LIBPNG_VER_RELEASE 32
/* This should match the numeric part of the final component of
* PNG_LIBPNG_VER_STRING, omitting any leading zero:
@@ -349,7 +349,7 @@
* version 1.0.0 was mis-numbered 100 instead of 10000). From
* version 1.0.1 it's xxyyzz, where x=major, y=minor, z=release
*/
-#define PNG_LIBPNG_VER 10630 /* 1.6.30 */
+#define PNG_LIBPNG_VER 10632 /* 1.6.32 */
/* Library configuration: these options cannot be changed after
* the library has been built.
@@ -459,7 +459,7 @@ extern "C" {
/* This triggers a compiler error in png.c, if png.c and png.h
* do not agree upon the version number.
*/
-typedef char* png_libpng_version_1_6_30;
+typedef char* png_libpng_version_1_6_32;
/* Basic control structions. Read libpng-manual.txt or libpng.3 for more info.
*
@@ -776,6 +776,7 @@ typedef png_unknown_chunk * * png_unknown_chunkpp;
#define PNG_INFO_sPLT 0x2000U /* ESR, 1.0.6 */
#define PNG_INFO_sCAL 0x4000U /* ESR, 1.0.6 */
#define PNG_INFO_IDAT 0x8000U /* ESR, 1.0.6 */
+#define PNG_INFO_eXIf 0x10000U /* GR-P, 1.6.31 */
/* This is used for the transformation routines, as some of them
* change these values for the row. It also should enable using
@@ -1788,7 +1789,8 @@ PNG_EXPORT(99, void, png_data_freer, (png_const_structrp png_ptr,
#define PNG_FREE_PLTE 0x1000U
#define PNG_FREE_TRNS 0x2000U
#define PNG_FREE_TEXT 0x4000U
-#define PNG_FREE_ALL 0x7fffU
+#define PNG_FREE_EXIF 0x8000U /* Added at libpng-1.6.31 */
+#define PNG_FREE_ALL 0xffffU
#define PNG_FREE_MUL 0x4220U /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */
#ifdef PNG_USER_MEM_SUPPORTED
@@ -2007,6 +2009,18 @@ PNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed, (png_const_structrp png_ptr,
png_fixed_point int_blue_Z))
#endif
+#ifdef PNG_eXIf_SUPPORTED
+PNG_EXPORT(246, png_uint_32, png_get_eXIf, (png_const_structrp png_ptr,
+ png_inforp info_ptr, png_bytep *exif));
+PNG_EXPORT(247, void, png_set_eXIf, (png_const_structrp png_ptr,
+ png_inforp info_ptr, const png_bytep exif));
+
+PNG_EXPORT(248, png_uint_32, png_get_eXIf_1, (png_const_structrp png_ptr,
+ png_const_inforp info_ptr, png_uint_32 *num_exif, png_bytep *exif));
+PNG_EXPORT(249, void, png_set_eXIf_1, (png_const_structrp png_ptr,
+ png_inforp info_ptr, const png_uint_32 num_exif, const png_bytep exif));
+#endif
+
#ifdef PNG_gAMA_SUPPORTED
PNG_FP_EXPORT(137, png_uint_32, png_get_gAMA, (png_const_structrp png_ptr,
png_const_inforp info_ptr, double *file_gamma))
@@ -2025,9 +2039,6 @@ PNG_FIXED_EXPORT(140, void, png_set_gAMA_fixed, (png_const_structrp png_ptr,
#ifdef PNG_hIST_SUPPORTED
PNG_EXPORT(141, png_uint_32, png_get_hIST, (png_const_structrp png_ptr,
png_inforp info_ptr, png_uint_16p *hist));
-#endif
-
-#ifdef PNG_hIST_SUPPORTED
PNG_EXPORT(142, void, png_set_hIST, (png_const_structrp png_ptr,
png_inforp info_ptr, png_const_uint_16p hist));
#endif
@@ -3253,7 +3264,7 @@ PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option,
* one to use is one more than this.)
*/
#ifdef PNG_EXPORT_LAST_ORDINAL
- PNG_EXPORT_LAST_ORDINAL(245);
+ PNG_EXPORT_LAST_ORDINAL(249);
#endif
#ifdef __cplusplus
diff --git a/src/libpng/pngconf.h b/src/libpng/pngconf.h
index f64592acd..c0f15547b 100644
--- a/src/libpng/pngconf.h
+++ b/src/libpng/pngconf.h
@@ -1,7 +1,7 @@
/* pngconf.h - machine configurable file for libpng
*
- * libpng version 1.6.30, June 28, 2017
+ * libpng version 1.6.32, August 24, 2017
*
* Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
diff --git a/src/libpng/pngerror.c b/src/libpng/pngerror.c
index 00d76f7c0..ad48bfb98 100644
--- a/src/libpng/pngerror.c
+++ b/src/libpng/pngerror.c
@@ -1,8 +1,8 @@
/* pngerror.c - stub functions for i/o and memory allocation
*
- * Last changed in libpng 1.6.26 [October 20, 2016]
- * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
+ * Last changed in libpng 1.6.31 [July 27, 2017]
+ * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
@@ -163,7 +163,7 @@ png_format_number(png_const_charp start, png_charp end, int format,
case PNG_NUMBER_FORMAT_02u:
/* Expects at least 2 digits. */
mincount = 2;
- /* FALL THROUGH */
+ /* FALLTHROUGH */
case PNG_NUMBER_FORMAT_u:
*--end = digits[number % 10];
@@ -173,7 +173,7 @@ png_format_number(png_const_charp start, png_charp end, int format,
case PNG_NUMBER_FORMAT_02x:
/* This format expects at least two digits */
mincount = 2;
- /* FALL THROUGH */
+ /* FALLTHROUGH */
case PNG_NUMBER_FORMAT_x:
*--end = digits[number & 0xf];
diff --git a/src/libpng/pngget.c b/src/libpng/pngget.c
index 141c39333..26e9fb1c3 100644
--- a/src/libpng/pngget.c
+++ b/src/libpng/pngget.c
@@ -1,8 +1,8 @@
/* pngget.c - retrieval of values from info struct
*
- * Last changed in libpng 1.6.26 [October 20, 2016]
- * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
+ * Last changed in libpng 1.6.32 [August 24, 2017]
+ * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
@@ -773,6 +773,35 @@ png_get_sPLT(png_const_structrp png_ptr, png_inforp info_ptr,
}
#endif
+#ifdef PNG_eXIf_SUPPORTED
+png_uint_32 PNGAPI
+png_get_eXIf(png_const_structrp png_ptr, png_inforp info_ptr,
+ png_bytep *exif)
+{
+ png_warning(png_ptr, "png_get_eXIf does not work; use png_get_eXIf_1");
+ PNG_UNUSED(info_ptr)
+ PNG_UNUSED(exif)
+ return 0;
+}
+
+png_uint_32 PNGAPI
+png_get_eXIf_1(png_const_structrp png_ptr, png_const_inforp info_ptr,
+ png_uint_32 *num_exif, png_bytep *exif)
+{
+ png_debug1(1, "in %s retrieval function", "eXIf");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_eXIf) != 0 && exif != NULL)
+ {
+ *num_exif = info_ptr->num_exif;
+ *exif = info_ptr->exif;
+ return (PNG_INFO_eXIf);
+ }
+
+ return (0);
+}
+#endif
+
#ifdef PNG_hIST_SUPPORTED
png_uint_32 PNGAPI
png_get_hIST(png_const_structrp png_ptr, png_inforp info_ptr,
diff --git a/src/libpng/pnginfo.h b/src/libpng/pnginfo.h
index 361ed8be7..d5f6149db 100644
--- a/src/libpng/pnginfo.h
+++ b/src/libpng/pnginfo.h
@@ -185,6 +185,14 @@ defined(PNG_READ_BACKGROUND_SUPPORTED)
png_byte phys_unit_type; /* resolution type (see PNG_RESOLUTION_ below) */
#endif
+#ifdef PNG_eXIf_SUPPORTED
+ int num_exif; /* Added at libpng-1.6.31 */
+ png_bytep exif;
+# ifdef PNG_READ_eXIf_SUPPORTED
+ png_bytep eXIf_buf; /* Added at libpng-1.6.32 */
+# endif
+#endif
+
#ifdef PNG_hIST_SUPPORTED
/* The hIST chunk contains the relative frequency or importance of the
* various palette entries, so that a viewer can intelligently select a
diff --git a/src/libpng/pnglibconf.h b/src/libpng/pnglibconf.h
index dc8e14fff..ec7d75baa 100644
--- a/src/libpng/pnglibconf.h
+++ b/src/libpng/pnglibconf.h
@@ -1,6 +1,6 @@
/* pnglibconf.h - library build configuration */
-/* libpng version 1.6.30, June 28, 2017 */
+/* libpng version 1.6.32, August 24, 2017 */
/* Copyright (c) 1998-2017 Glenn Randers-Pehrson */
@@ -82,6 +82,7 @@
#define PNG_READ_USER_TRANSFORM_SUPPORTED
#define PNG_READ_bKGD_SUPPORTED
#define PNG_READ_cHRM_SUPPORTED
+#define PNG_READ_eXIf_SUPPORTED
#define PNG_READ_gAMA_SUPPORTED
#define PNG_READ_hIST_SUPPORTED
#define PNG_READ_iCCP_SUPPORTED
@@ -151,6 +152,7 @@
#define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
#define PNG_WRITE_bKGD_SUPPORTED
#define PNG_WRITE_cHRM_SUPPORTED
+#define PNG_WRITE_eXIf_SUPPORTED
#define PNG_WRITE_gAMA_SUPPORTED
#define PNG_WRITE_hIST_SUPPORTED
#define PNG_WRITE_iCCP_SUPPORTED
@@ -168,6 +170,7 @@
#define PNG_WRITE_zTXt_SUPPORTED
#define PNG_bKGD_SUPPORTED
#define PNG_cHRM_SUPPORTED
+#define PNG_eXIf_SUPPORTED
#define PNG_gAMA_SUPPORTED
#define PNG_hIST_SUPPORTED
#define PNG_iCCP_SUPPORTED
diff --git a/src/libpng/pngpread.c b/src/libpng/pngpread.c
index 650ba1e23..fbe361dc3 100644
--- a/src/libpng/pngpread.c
+++ b/src/libpng/pngpread.c
@@ -1,8 +1,8 @@
/* pngpread.c - read a png file in push mode
*
- * Last changed in libpng 1.6.24 [August 4, 2016]
- * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
+ * Last changed in libpng 1.6.32 [August 24, 2017]
+ * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
@@ -189,6 +189,7 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)
png_crc_read(png_ptr, chunk_tag, 4);
png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag);
png_check_chunk_name(png_ptr, png_ptr->chunk_name);
+ png_check_chunk_length(png_ptr, png_ptr->push_length);
png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
}
diff --git a/src/libpng/pngpriv.h b/src/libpng/pngpriv.h
index a062a8da1..1f2e90f2b 100644
--- a/src/libpng/pngpriv.h
+++ b/src/libpng/pngpriv.h
@@ -1,7 +1,7 @@
/* pngpriv.h - private declarations for use inside libpng
*
- * Last changed in libpng 1.6.30 [(PENDING RELEASE)]
+ * Last changed in libpng 1.6.32 [August 24, 2017]
* Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -35,7 +35,9 @@
* Windows/Visual Studio) there is no effect; the OS specific tests below are
* still required (as of 2011-05-02.)
*/
-#define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */
+#ifndef _POSIX_SOURCE
+# define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */
+#endif
#ifndef PNG_VERSION_INFO_ONLY
/* Standard library headers not required by png.h: */
@@ -452,6 +454,21 @@
# define png_fixed_error(s1,s2) png_err(s1)
#endif
+/* Some fixed point APIs are still required even if not exported because
+ * they get used by the corresponding floating point APIs. This magic
+ * deals with this:
+ */
+#ifdef PNG_FIXED_POINT_SUPPORTED
+# define PNGFAPI PNGAPI
+#else
+# define PNGFAPI /* PRIVATE */
+#endif
+
+#ifndef PNG_VERSION_INFO_ONLY
+/* Other defines specific to compilers can go here. Try to keep
+ * them inside an appropriate ifdef/endif pair for portability.
+ */
+
/* C allows up-casts from (void*) to any pointer and (const void*) to any
* pointer to a const object. C++ regards this as a type error and requires an
* explicit, static, cast and provides the static_cast<> rune to ensure that
@@ -480,20 +497,6 @@
# define png_aligncastconst(type, value) ((const void*)(value))
#endif /* __cplusplus */
-/* Some fixed point APIs are still required even if not exported because
- * they get used by the corresponding floating point APIs. This magic
- * deals with this:
- */
-#ifdef PNG_FIXED_POINT_SUPPORTED
-# define PNGFAPI PNGAPI
-#else
-# define PNGFAPI /* PRIVATE */
-#endif
-
-#ifndef PNG_VERSION_INFO_ONLY
-/* Other defines specific to compilers can go here. Try to keep
- * them inside an appropriate ifdef/endif pair for portability.
- */
#if defined(PNG_FLOATING_POINT_SUPPORTED) ||\
defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)
/* png.c requires the following ANSI-C constants if the conversion of
@@ -839,6 +842,7 @@
#define png_PLTE PNG_U32( 80, 76, 84, 69)
#define png_bKGD PNG_U32( 98, 75, 71, 68)
#define png_cHRM PNG_U32( 99, 72, 82, 77)
+#define png_eXIf PNG_U32(101, 88, 73, 102) /* registered July 2017 */
#define png_fRAc PNG_U32(102, 82, 65, 99) /* registered, not defined */
#define png_gAMA PNG_U32(103, 65, 77, 65)
#define png_gIFg PNG_U32(103, 73, 70, 103)
@@ -1139,6 +1143,11 @@ PNG_INTERNAL_FUNCTION(void,png_write_sRGB,(png_structrp png_ptr,
int intent),PNG_EMPTY);
#endif
+#ifdef PNG_WRITE_eXIf_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_write_eXIf,(png_structrp png_ptr,
+ png_bytep exif, int num_exif),PNG_EMPTY);
+#endif
+
#ifdef PNG_WRITE_iCCP_SUPPORTED
PNG_INTERNAL_FUNCTION(void,png_write_iCCP,(png_structrp png_ptr,
png_const_charp name, png_const_bytep profile), PNG_EMPTY);
@@ -1438,6 +1447,11 @@ PNG_INTERNAL_FUNCTION(void,png_handle_cHRM,(png_structrp png_ptr,
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
#endif
+#ifdef PNG_READ_eXIf_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_handle_eXIf,(png_structrp png_ptr,
+ png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
+#endif
+
#ifdef PNG_READ_gAMA_SUPPORTED
PNG_INTERNAL_FUNCTION(void,png_handle_gAMA,(png_structrp png_ptr,
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
@@ -1513,8 +1527,11 @@ PNG_INTERNAL_FUNCTION(void,png_handle_zTXt,(png_structrp png_ptr,
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
#endif
-PNG_INTERNAL_FUNCTION(void,png_check_chunk_name,(png_structrp png_ptr,
- png_uint_32 chunk_name),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_check_chunk_name,(png_const_structrp png_ptr,
+ const png_uint_32 chunk_name),PNG_EMPTY);
+
+PNG_INTERNAL_FUNCTION(void,png_check_chunk_length,(png_const_structrp png_ptr,
+ const png_uint_32 chunk_length),PNG_EMPTY);
PNG_INTERNAL_FUNCTION(void,png_handle_unknown,(png_structrp png_ptr,
png_inforp info_ptr, png_uint_32 length, int keep),PNG_EMPTY);
diff --git a/src/libpng/pngread.c b/src/libpng/pngread.c
index 106a80588..e34ddd99a 100644
--- a/src/libpng/pngread.c
+++ b/src/libpng/pngread.c
@@ -1,8 +1,8 @@
/* pngread.c - read a PNG file
*
- * Last changed in libpng 1.6.26 [October 20, 2016]
- * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
+ * Last changed in libpng 1.6.32 [August 24, 2017]
+ * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
@@ -175,6 +175,11 @@ png_read_info(png_structrp png_ptr, png_inforp info_ptr)
png_handle_cHRM(png_ptr, info_ptr, length);
#endif
+#ifdef PNG_READ_eXIf_SUPPORTED
+ else if (chunk_name == png_eXIf)
+ png_handle_eXIf(png_ptr, info_ptr, length);
+#endif
+
#ifdef PNG_READ_gAMA_SUPPORTED
else if (chunk_name == png_gAMA)
png_handle_gAMA(png_ptr, info_ptr, length);
@@ -534,6 +539,7 @@ png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row)
png_error(png_ptr, "Invalid attempt to read row data");
/* Fill the row with IDAT data: */
+ png_ptr->row_buf[0]=255; /* to force error if no data was found */
png_read_IDAT_data(png_ptr, png_ptr->row_buf, row_info.rowbytes + 1);
if (png_ptr->row_buf[0] > PNG_FILTER_VALUE_NONE)
@@ -842,6 +848,11 @@ png_read_end(png_structrp png_ptr, png_inforp info_ptr)
png_handle_cHRM(png_ptr, info_ptr, length);
#endif
+#ifdef PNG_READ_eXIf_SUPPORTED
+ else if (chunk_name == png_eXIf)
+ png_handle_eXIf(png_ptr, info_ptr, length);
+#endif
+
#ifdef PNG_READ_gAMA_SUPPORTED
else if (chunk_name == png_gAMA)
png_handle_gAMA(png_ptr, info_ptr, length);
@@ -1883,7 +1894,7 @@ png_create_colormap_entry(png_image_read_control *display,
{
case 4:
entry[afirst ? 0 : 3] = (png_uint_16)alpha;
- /* FALL THROUGH */
+ /* FALLTHROUGH */
case 3:
if (alpha < 65535)
@@ -1905,7 +1916,7 @@ png_create_colormap_entry(png_image_read_control *display,
case 2:
entry[1 ^ afirst] = (png_uint_16)alpha;
- /* FALL THROUGH */
+ /* FALLTHROUGH */
case 1:
if (alpha < 65535)
@@ -1934,6 +1945,7 @@ png_create_colormap_entry(png_image_read_control *display,
{
case 4:
entry[afirst ? 0 : 3] = (png_byte)alpha;
+ /* FALLTHROUGH */
case 3:
entry[afirst + (2 ^ bgr)] = (png_byte)blue;
entry[afirst + 1] = (png_byte)green;
@@ -1942,6 +1954,7 @@ png_create_colormap_entry(png_image_read_control *display,
case 2:
entry[1 ^ afirst] = (png_byte)alpha;
+ /* FALLTHROUGH */
case 1:
entry[afirst] = (png_byte)green;
break;
@@ -2861,7 +2874,7 @@ png_image_read_colormap(png_voidp argument)
case P_sRGB:
/* Change to 8-bit sRGB */
png_set_alpha_mode_fixed(png_ptr, PNG_ALPHA_PNG, PNG_GAMMA_sRGB);
- /* FALL THROUGH */
+ /* FALLTHROUGH */
case P_FILE:
if (png_ptr->bit_depth > 8)
@@ -3179,8 +3192,7 @@ png_image_read_colormapped(png_voidp argument)
image->colormap_entries == 244 /* 216 + 1 + 27 */)
break;
- /* goto bad_output; */
- /* FALL THROUGH */
+ goto bad_output;
default:
bad_output:
diff --git a/src/libpng/pngrtran.c b/src/libpng/pngrtran.c
index 3886833af..9a30ddf22 100644
--- a/src/libpng/pngrtran.c
+++ b/src/libpng/pngrtran.c
@@ -1,7 +1,7 @@
/* pngrtran.c - transforms the data in a row for PNG readers
*
- * Last changed in libpng 1.6.30 [(PENDING RELEASE)]
+ * Last changed in libpng 1.6.31 [July 27, 2017]
* Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -49,6 +49,7 @@ png_set_crc_action(png_structrp png_ptr, int crit_action, int ancil_action)
case PNG_CRC_WARN_DISCARD: /* Not a valid action for critical data */
png_warning(png_ptr,
"Can't discard critical data on CRC error");
+ /* FALLTHROUGH */
case PNG_CRC_ERROR_QUIT: /* Error/quit */
case PNG_CRC_DEFAULT:
@@ -1253,7 +1254,7 @@ png_init_rgb_transformations(png_structrp png_ptr)
default:
case 8:
- /* FALL THROUGH (Already 8 bits) */
+ /* FALLTHROUGH */ /* (Already 8 bits) */
case 16:
/* Already a full 16 bits */
diff --git a/src/libpng/pngrutil.c b/src/libpng/pngrutil.c
index f60545bf9..a4fa71457 100644
--- a/src/libpng/pngrutil.c
+++ b/src/libpng/pngrutil.c
@@ -1,7 +1,7 @@
/* pngrutil.c - utilities to read a PNG file
*
- * Last changed in libpng 1.6.30 [(PENDING RELEASE)]
+ * Last changed in libpng 1.6.32 [August 24, 2017]
* Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -181,6 +181,9 @@ png_read_chunk_header(png_structrp png_ptr)
/* Check to see if chunk name is valid. */
png_check_chunk_name(png_ptr, png_ptr->chunk_name);
+ /* Check for too-large chunk length */
+ png_check_chunk_length(png_ptr, length);
+
#ifdef PNG_IO_STATE_SUPPORTED
png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_DATA;
#endif
@@ -1377,11 +1380,13 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
* chunk is just ignored, so does not invalidate the color space. An
* alternative is to set the 'invalid' flags at the start of this routine
* and only clear them in they were not set before and all the tests pass.
- * The minimum 'deflate' stream is assumed to be just the 2 byte header and
- * 4 byte checksum. The keyword must be at least one character and there is
- * a terminator (0) byte and the compression method.
*/
- if (length < 9)
+
+ /* The keyword must be at least one character and there is a
+ * terminator (0) byte and the compression method byte, and the
+ * 'zlib' datastream is at least 11 bytes.
+ */
+ if (length < 14)
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "too short");
@@ -1413,6 +1418,16 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
png_crc_read(png_ptr, (png_bytep)keyword, read_length);
length -= read_length;
+ /* The minimum 'zlib' stream is assumed to be just the 2 byte header,
+ * 5 bytes minimum 'deflate' stream, and the 4 byte checksum.
+ */
+ if (length < 11)
+ {
+ png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "too short");
+ return;
+ }
+
keyword_length = 0;
while (keyword_length < 80 && keyword_length < read_length &&
keyword[keyword_length] != 0)
@@ -1431,7 +1446,7 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
if (png_inflate_claim(png_ptr, png_iCCP) == Z_OK)
{
- Byte profile_header[132];
+ Byte profile_header[132]={0};
Byte local_buffer[PNG_INFLATE_BUF_SIZE];
png_alloc_size_t size = (sizeof profile_header);
@@ -2009,6 +2024,69 @@ png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
}
#endif
+#ifdef PNG_READ_eXIf_SUPPORTED
+void /* PRIVATE */
+png_handle_eXIf(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
+{
+ unsigned int i;
+
+ png_debug(1, "in png_handle_eXIf");
+
+ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
+ png_chunk_error(png_ptr, "missing IHDR");
+
+ if (length < 2)
+ {
+ png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "too short");
+ return;
+ }
+
+ else if (info_ptr == NULL || (info_ptr->valid & PNG_INFO_eXIf) != 0)
+ {
+ png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "duplicate");
+ return;
+ }
+
+ info_ptr->free_me |= PNG_FREE_EXIF;
+
+ info_ptr->eXIf_buf = png_voidcast(png_bytep,
+ png_malloc_warn(png_ptr, length));
+
+ if (info_ptr->eXIf_buf == NULL)
+ {
+ png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of memory");
+ return;
+ }
+
+ for (i = 0; i < length; i++)
+ {
+ png_byte buf[1];
+ png_crc_read(png_ptr, buf, 1);
+ info_ptr->eXIf_buf[i] = buf[0];
+ if (i == 1 && buf[0] != 'M' && buf[0] != 'I'
+ && info_ptr->eXIf_buf[0] != buf[0])
+ {
+ png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "incorrect byte-order specifier");
+ png_free(png_ptr, info_ptr->eXIf_buf);
+ info_ptr->eXIf_buf = NULL;
+ return;
+ }
+ }
+
+ if (png_crc_finish(png_ptr, 0) != 0)
+ return;
+
+ png_set_eXIf_1(png_ptr, info_ptr, length, info_ptr->eXIf_buf);
+
+ png_free(png_ptr, info_ptr->eXIf_buf);
+ info_ptr->eXIf_buf = NULL;
+}
+#endif
+
#ifdef PNG_READ_hIST_SUPPORTED
void /* PRIVATE */
png_handle_hIST(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
@@ -2586,23 +2664,28 @@ png_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_text text;
- /* It worked; png_ptr->read_buffer now looks like a tEXt chunk except
- * for the extra compression type byte and the fact that it isn't
- * necessarily '\0' terminated.
- */
- buffer = png_ptr->read_buffer;
- buffer[uncompressed_length+(keyword_length+2)] = 0;
+ if (png_ptr->read_buffer == NULL)
+ errmsg="Read failure in png_handle_zTXt";
+ else
+ {
+ /* It worked; png_ptr->read_buffer now looks like a tEXt chunk
+ * except for the extra compression type byte and the fact that
+ * it isn't necessarily '\0' terminated.
+ */
+ buffer = png_ptr->read_buffer;
+ buffer[uncompressed_length+(keyword_length+2)] = 0;
- text.compression = PNG_TEXT_COMPRESSION_zTXt;
- text.key = (png_charp)buffer;
- text.text = (png_charp)(buffer + keyword_length+2);
- text.text_length = uncompressed_length;
- text.itxt_length = 0;
- text.lang = NULL;
- text.lang_key = NULL;
+ text.compression = PNG_TEXT_COMPRESSION_zTXt;
+ text.key = (png_charp)buffer;
+ text.text = (png_charp)(buffer + keyword_length+2);
+ text.text_length = uncompressed_length;
+ text.itxt_length = 0;
+ text.lang = NULL;
+ text.lang_key = NULL;
- if (png_set_text_2(png_ptr, info_ptr, &text, 1) != 0)
- errmsg = "insufficient memory";
+ if (png_set_text_2(png_ptr, info_ptr, &text, 1) != 0)
+ errmsg = "insufficient memory";
+ }
}
else
@@ -2978,7 +3061,7 @@ png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr,
case 2:
png_ptr->user_chunk_cache_max = 1;
png_chunk_benign_error(png_ptr, "no space in chunk cache");
- /* FALL THROUGH */
+ /* FALLTHROUGH */
case 1:
/* NOTE: prior to 1.6.0 this case resulted in an unknown critical
* chunk being skipped, now there will be a hard error below.
@@ -2987,7 +3070,7 @@ png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr,
default: /* not at limit */
--(png_ptr->user_chunk_cache_max);
- /* FALL THROUGH */
+ /* FALLTHROUGH */
case 0: /* no limit */
# endif /* USER_LIMITS */
/* Here when the limit isn't reached or when limits are compiled
@@ -3038,20 +3121,58 @@ png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr,
*/
void /* PRIVATE */
-png_check_chunk_name(png_structrp png_ptr, png_uint_32 chunk_name)
+png_check_chunk_name(png_const_structrp png_ptr, const png_uint_32 chunk_name)
{
int i;
+ png_uint_32 cn=chunk_name;
png_debug(1, "in png_check_chunk_name");
for (i=1; i<=4; ++i)
{
- int c = chunk_name & 0xff;
+ int c = cn & 0xff;
if (c < 65 || c > 122 || (c > 90 && c < 97))
png_chunk_error(png_ptr, "invalid chunk type");
- chunk_name >>= 8;
+ cn >>= 8;
+ }
+}
+
+void /* PRIVATE */
+png_check_chunk_length(png_const_structrp png_ptr, const png_uint_32 length)
+{
+ png_alloc_size_t limit = PNG_UINT_31_MAX;
+
+ if (png_ptr->chunk_name != png_IDAT)
+ {
+# ifdef PNG_SET_USER_LIMITS_SUPPORTED
+ if (png_ptr->user_chunk_malloc_max > 0 &&
+ png_ptr->user_chunk_malloc_max < limit)
+ limit = png_ptr->user_chunk_malloc_max;
+# elif PNG_USER_CHUNK_MALLOC_MAX > 0
+ if (PNG_USER_CHUNK_MALLOC_MAX < limit)
+ limit = PNG_USER_CHUNK_MALLOC_MAX;
+# endif
+ }
+ else
+ {
+ size_t row_factor =
+ (png_ptr->width * png_ptr->channels * (png_ptr->bit_depth > 8? 2: 1)
+ + 1 + (png_ptr->interlaced? 6: 0));
+ if (png_ptr->height > PNG_UINT_32_MAX/row_factor)
+ limit=PNG_UINT_31_MAX;
+ else
+ limit = png_ptr->height * row_factor;
+ limit += 6 + 5*(limit/32566+1); /* zlib+deflate overhead */
+ limit=limit < PNG_UINT_31_MAX? limit : PNG_UINT_31_MAX;
+ }
+
+ if (length > limit)
+ {
+ png_debug2(0," length = %lu, limit = %lu",
+ (unsigned long)length,(unsigned long)limit);
+ png_chunk_error(png_ptr, "chunk data is too large");
}
}
diff --git a/src/libpng/pngset.c b/src/libpng/pngset.c
index fb495ac3f..6f3a1ee11 100644
--- a/src/libpng/pngset.c
+++ b/src/libpng/pngset.c
@@ -1,7 +1,7 @@
/* pngset.c - storage of image information into info struct
*
- * Last changed in libpng 1.6.30 [(PENDING RELEASE)]
+ * Last changed in libpng 1.6.32 [August 24, 2017]
* Copyright (c) 1998-2017 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -134,6 +134,53 @@ png_set_cHRM_XYZ(png_const_structrp png_ptr, png_inforp info_ptr, double red_X,
#endif /* cHRM */
+#ifdef PNG_eXIf_SUPPORTED
+void PNGAPI
+png_set_eXIf(png_const_structrp png_ptr, png_inforp info_ptr,
+ const png_bytep eXIf_buf)
+{
+ png_warning(png_ptr, "png_set_eXIf does not work; use png_set_eXIf_1");
+ PNG_UNUSED(info_ptr)
+ PNG_UNUSED(eXIf_buf)
+}
+
+void PNGAPI
+png_set_eXIf_1(png_const_structrp png_ptr, png_inforp info_ptr,
+ const png_uint_32 num_exif, const png_bytep eXIf_buf)
+{
+ int i;
+
+ png_debug1(1, "in %s storage function", "eXIf");
+
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ if (info_ptr->exif)
+ {
+ png_free(png_ptr, info_ptr->exif);
+ info_ptr->exif = NULL;
+ }
+
+ info_ptr->num_exif = num_exif;
+
+ info_ptr->exif = png_voidcast(png_bytep, png_malloc_warn(png_ptr,
+ info_ptr->num_exif));
+
+ if (info_ptr->exif == NULL)
+ {
+ png_warning(png_ptr, "Insufficient memory for eXIf chunk data");
+ return;
+ }
+
+ info_ptr->free_me |= PNG_FREE_EXIF;
+
+ for (i = 0; i < (int) info_ptr->num_exif; i++)
+ info_ptr->exif[i] = eXIf_buf[i];
+
+ info_ptr->valid |= PNG_INFO_eXIf;
+}
+#endif /* eXIf */
+
#ifdef PNG_gAMA_SUPPORTED
void PNGFAPI
png_set_gAMA_fixed(png_const_structrp png_ptr, png_inforp info_ptr,
@@ -1355,6 +1402,7 @@ png_set_keep_unknown_chunks(png_structrp png_ptr, int keep,
static PNG_CONST png_byte chunks_to_ignore[] = {
98, 75, 71, 68, '\0', /* bKGD */
99, 72, 82, 77, '\0', /* cHRM */
+ 101, 88, 73, 102, '\0', /* eXIf */
103, 65, 77, 65, '\0', /* gAMA */
104, 73, 83, 84, '\0', /* hIST */
105, 67, 67, 80, '\0', /* iCCP */
diff --git a/src/libpng/pngstruct.h b/src/libpng/pngstruct.h
index 749d7e35b..d83f97125 100644
--- a/src/libpng/pngstruct.h
+++ b/src/libpng/pngstruct.h
@@ -1,7 +1,7 @@
/* pngstruct.h - header file for PNG reference library
*
- * Last changed in libpng 1.6.28 [January 5, 2017]
+ * Last changed in libpng 1.6.32 [August 24, 2017]
* Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
diff --git a/src/libpng/pngtrans.c b/src/libpng/pngtrans.c
index 6c8c64623..326ac33f0 100644
--- a/src/libpng/pngtrans.c
+++ b/src/libpng/pngtrans.c
@@ -1,7 +1,7 @@
/* pngtrans.c - transforms the data in a row (used by both readers and writers)
*
- * Last changed in libpng 1.6.30 [(PENDING RELEASE)]
+ * Last changed in libpng 1.6.30 [June 28, 2017]
* Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
diff --git a/src/libpng/pngwrite.c b/src/libpng/pngwrite.c
index 07088ee75..a7662acb7 100644
--- a/src/libpng/pngwrite.c
+++ b/src/libpng/pngwrite.c
@@ -1,8 +1,8 @@
/* pngwrite.c - general routines to write a PNG file
*
- * Last changed in libpng 1.6.26 [October 20, 2016]
- * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
+ * Last changed in libpng 1.6.32 [August 24, 2017]
+ * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
@@ -237,6 +237,11 @@ png_write_info(png_structrp png_ptr, png_const_inforp info_ptr)
png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type);
#endif
+#ifdef PNG_WRITE_eXIf_SUPPORTED
+ if ((info_ptr->valid & PNG_INFO_eXIf) != 0)
+ png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif);
+#endif
+
#ifdef PNG_WRITE_hIST_SUPPORTED
if ((info_ptr->valid & PNG_INFO_hIST) != 0)
png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette);
@@ -432,6 +437,12 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr)
}
}
#endif
+
+#ifdef PNG_WRITE_eXIf_SUPPORTED
+ if ((info_ptr->valid & PNG_INFO_eXIf) != 0)
+ png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif);
+#endif
+
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
write_unknown_chunks(png_ptr, info_ptr, PNG_AFTER_IDAT);
#endif
@@ -1007,8 +1018,8 @@ png_set_filter(png_structrp png_ptr, int method, int filters)
case 5:
case 6:
case 7: png_app_error(png_ptr, "Unknown row filter for method 0");
- /* FALL THROUGH */
#endif /* WRITE_FILTER */
+ /* FALLTHROUGH */
case PNG_FILTER_VALUE_NONE:
png_ptr->do_filter = PNG_FILTER_NONE; break;
@@ -1875,7 +1886,7 @@ png_image_set_PLTE(png_image_write_control *display)
tRNS[i] = entry[afirst ? 0 : 3];
if (tRNS[i] < 255)
num_trans = i+1;
- /* FALL THROUGH */
+ /* FALLTHROUGH */
case 3:
palette[i].blue = entry[afirst + (2 ^ bgr)];
palette[i].green = entry[afirst + 1];
@@ -1886,7 +1897,7 @@ png_image_set_PLTE(png_image_write_control *display)
tRNS[i] = entry[1 ^ afirst];
if (tRNS[i] < 255)
num_trans = i+1;
- /* FALL THROUGH */
+ /* FALLTHROUGH */
case 1:
palette[i].blue = palette[i].red = palette[i].green =
entry[afirst];
diff --git a/src/libpng/pngwutil.c b/src/libpng/pngwutil.c
index dd800586b..0d4fb1336 100644
--- a/src/libpng/pngwutil.c
+++ b/src/libpng/pngwutil.c
@@ -1,8 +1,8 @@
/* pngwutil.c - utilities to write a PNG file
*
- * Last changed in libpng 1.6.26 [October 20, 2016]
- * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
+ * Last changed in libpng 1.6.32 [August 24, 2017]
+ * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
@@ -1473,6 +1473,28 @@ png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type)
}
#endif
+#ifdef PNG_WRITE_eXIf_SUPPORTED
+/* Write the Exif data */
+void /* PRIVATE */
+png_write_eXIf(png_structrp png_ptr, png_bytep exif, int num_exif)
+{
+ int i;
+ png_byte buf[1];
+
+ png_debug(1, "in png_write_eXIf");
+
+ png_write_chunk_header(png_ptr, png_eXIf, (png_uint_32)(num_exif));
+
+ for (i = 0; i < num_exif; i++)
+ {
+ buf[0] = exif[i];
+ png_write_chunk_data(png_ptr, buf, (png_size_t)1);
+ }
+
+ png_write_chunk_end(png_ptr);
+}
+#endif
+
#ifdef PNG_WRITE_hIST_SUPPORTED
/* Write the histogram */
void /* PRIVATE */
diff --git a/src/macosx/English.lproj/InfoPlist.strings b/src/macosx/English.lproj/InfoPlist.strings
index aa4dc64bc..9d601a273 100755
--- a/src/macosx/English.lproj/InfoPlist.strings
+++ b/src/macosx/English.lproj/InfoPlist.strings
@@ -1,8 +1,8 @@
/* Localized versions of Info.plist keys */
CFBundleName = "Stella";
-CFBundleShortVersionString = "Stella version 5.0.1";
-CFBundleGetInfoString = "Stella version 5.0.1";
+CFBundleShortVersionString = "Stella version 5.0.2";
+CFBundleGetInfoString = "Stella version 5.0.2";
NSHumanReadableCopyright = "Stella MacOS X version by Stephen Anthony and Mark Grebe.";
"Atari 2600 Cartridge File" = "Atari 2600 Cartridge File";
diff --git a/src/macosx/Info-Stella.plist b/src/macosx/Info-Stella.plist
index 36c1a433a..f7725edb1 100644
--- a/src/macosx/Info-Stella.plist
+++ b/src/macosx/Info-Stella.plist
@@ -53,7 +53,7 @@
CFBundleSignature
StLa
CFBundleVersion
- 5.0.1
+ 5.0.2
LSApplicationCategoryType
public.app-category.games
LSMinimumSystemVersionByArchitecture
diff --git a/src/macosx/OSystemMACOSX.cxx b/src/macosx/OSystemMACOSX.cxx
index ab28d3f66..286fe7b4a 100644
--- a/src/macosx/OSystemMACOSX.cxx
+++ b/src/macosx/OSystemMACOSX.cxx
@@ -32,21 +32,21 @@
OSystemMACOSX::OSystemMACOSX()
: OSystem()
{
- setBaseDir("~/Library/Application Support/Stella");
+ setBaseDir("~/Library/Application Support/Stella/");
// This will be overridden, as OSX uses plist files for settings
setConfigFile("~/Library/Application Support/Stella/stellarc");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-string OSystemMACOSX::defaultSnapSaveDir()
+string OSystemMACOSX::defaultSaveDir() const
{
- FilesystemNode desktop("~/Desktop");
- return desktop.isDirectory() ? desktop.getShortPath() : "~";
+ FilesystemNode desktop("~/Desktop/");
+ return desktop.isDirectory() ? desktop.getShortPath() : "~/";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-string OSystemMACOSX::defaultSnapLoadDir()
+string OSystemMACOSX::defaultLoadDir() const
{
- return defaultSnapSaveDir();
+ return defaultSaveDir();
}
diff --git a/src/macosx/OSystemMACOSX.hxx b/src/macosx/OSystemMACOSX.hxx
index cfa4857a3..76fbe0f7f 100644
--- a/src/macosx/OSystemMACOSX.hxx
+++ b/src/macosx/OSystemMACOSX.hxx
@@ -35,10 +35,10 @@ class OSystemMACOSX : public OSystem
virtual ~OSystemMACOSX() = default;
/**
- Returns the default paths for the snapshot directory.
+ Returns the default paths for loading/saving files.
*/
- string defaultSnapSaveDir() override;
- string defaultSnapLoadDir() override;
+ string defaultSaveDir() const override;
+ string defaultLoadDir() const override;
private:
// Following constructors and assignment operators not supported
diff --git a/src/macosx/stella.xcodeproj/project.pbxproj b/src/macosx/stella.xcodeproj/project.pbxproj
index 922004d7d..de34f2778 100644
--- a/src/macosx/stella.xcodeproj/project.pbxproj
+++ b/src/macosx/stella.xcodeproj/project.pbxproj
@@ -25,7 +25,6 @@
2D9173DA09BA90380026E9FF /* CartF8.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF2D0627AE07006BEC99 /* CartF8.hxx */; };
2D9173DB09BA90380026E9FF /* CartF8SC.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF2F0627AE07006BEC99 /* CartF8SC.hxx */; };
2D9173DD09BA90380026E9FF /* CartFE.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF330627AE07006BEC99 /* CartFE.hxx */; };
- 2D9173DF09BA90380026E9FF /* CartMC.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF370627AE07006BEC99 /* CartMC.hxx */; };
2D9173E009BA90380026E9FF /* Console.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF390627AE07006BEC99 /* Console.hxx */; };
2D9173E109BA90380026E9FF /* Control.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF3B0627AE07006BEC99 /* Control.hxx */; };
2D9173E309BA90380026E9FF /* Driving.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF3F0627AE07006BEC99 /* Driving.hxx */; };
@@ -132,7 +131,6 @@
2D91748309BA90380026E9FF /* CartF8.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF2C0627AE07006BEC99 /* CartF8.cxx */; };
2D91748409BA90380026E9FF /* CartF8SC.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF2E0627AE07006BEC99 /* CartF8SC.cxx */; };
2D91748609BA90380026E9FF /* CartFE.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF320627AE07006BEC99 /* CartFE.cxx */; };
- 2D91748809BA90380026E9FF /* CartMC.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF360627AE07006BEC99 /* CartMC.cxx */; };
2D91748909BA90380026E9FF /* Console.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF380627AE07006BEC99 /* Console.cxx */; };
2D91748A09BA90380026E9FF /* Control.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF3A0627AE07006BEC99 /* Control.cxx */; };
2D91748C09BA90380026E9FF /* Driving.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF3E0627AE07006BEC99 /* Driving.cxx */; };
@@ -224,8 +222,6 @@
CFE3F6161E84A9CE00A8204E /* CartCDF.hxx in Headers */ = {isa = PBXBuildFile; fileRef = CFE3F6121E84A9CE00A8204E /* CartCDF.hxx */; };
DC047FEE1A4A6F3600348F0F /* JoystickDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC047FEC1A4A6F3600348F0F /* JoystickDialog.cxx */; };
DC047FEF1A4A6F3600348F0F /* JoystickDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC047FED1A4A6F3600348F0F /* JoystickDialog.hxx */; };
- DC07A3C80CAD738A009B4BC9 /* StateManager.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC07A3C60CAD738A009B4BC9 /* StateManager.cxx */; };
- DC07A3C90CAD738A009B4BC9 /* StateManager.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC07A3C70CAD738A009B4BC9 /* StateManager.hxx */; };
DC0984850D3985160073C852 /* CartSB.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC0984830D3985160073C852 /* CartSB.cxx */; };
DC0984860D3985160073C852 /* CartSB.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC0984840D3985160073C852 /* CartSB.hxx */; };
DC0DF8690F0DAAF500B0F1F3 /* GlobalPropsDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC0DF8670F0DAAF500B0F1F3 /* GlobalPropsDialog.cxx */; };
@@ -236,11 +232,8 @@
DC13B540176FF2F500B8B4BB /* RomListSettings.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC13B53E176FF2F500B8B4BB /* RomListSettings.hxx */; };
DC173F760E2CAC1E00320F94 /* ContextMenu.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC173F740E2CAC1E00320F94 /* ContextMenu.cxx */; };
DC173F770E2CAC1E00320F94 /* ContextMenu.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC173F750E2CAC1E00320F94 /* ContextMenu.hxx */; };
- DC1B2EC31E50036100F62837 /* AmigaMouse.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC1B2EBD1E50036100F62837 /* AmigaMouse.cxx */; };
DC1B2EC41E50036100F62837 /* AmigaMouse.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC1B2EBE1E50036100F62837 /* AmigaMouse.hxx */; };
- DC1B2EC51E50036100F62837 /* AtariMouse.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC1B2EBF1E50036100F62837 /* AtariMouse.cxx */; };
DC1B2EC61E50036100F62837 /* AtariMouse.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC1B2EC01E50036100F62837 /* AtariMouse.hxx */; };
- DC1B2EC71E50036100F62837 /* TrakBall.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC1B2EC11E50036100F62837 /* TrakBall.cxx */; };
DC1B2EC81E50036100F62837 /* TrakBall.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC1B2EC21E50036100F62837 /* TrakBall.hxx */; };
DC1FC18A0DB3B2C7009B3DF7 /* SerialPortMACOSX.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC1FC1880DB3B2C7009B3DF7 /* SerialPortMACOSX.cxx */; };
DC1FC18B0DB3B2C7009B3DF7 /* SerialPortMACOSX.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC1FC1890DB3B2C7009B3DF7 /* SerialPortMACOSX.hxx */; };
@@ -258,6 +251,7 @@
DC368F5918A2FB710084199C /* SoundSDL2.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC368F5318A2FB710084199C /* SoundSDL2.hxx */; };
DC36D2C814CAFAB0007DC821 /* CartFA2.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC36D2C614CAFAB0007DC821 /* CartFA2.cxx */; };
DC36D2C914CAFAB0007DC821 /* CartFA2.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC36D2C714CAFAB0007DC821 /* CartFA2.hxx */; };
+ DC3DAFAC1F2E233B00A64410 /* PointingDevice.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC3DAFAB1F2E233B00A64410 /* PointingDevice.hxx */; };
DC3EE8561E2C0E6D00905161 /* adler32.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3EE83C1E2C0E6D00905161 /* adler32.c */; };
DC3EE8571E2C0E6D00905161 /* compress.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3EE83D1E2C0E6D00905161 /* compress.c */; };
DC3EE8581E2C0E6D00905161 /* crc32.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3EE83E1E2C0E6D00905161 /* crc32.c */; };
@@ -305,6 +299,7 @@
DC4AC6F00DC8DACB00CD3AD2 /* RiotWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC4AC6EE0DC8DACB00CD3AD2 /* RiotWidget.hxx */; };
DC4AC6F30DC8DAEF00CD3AD2 /* SaveKey.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC4AC6F10DC8DAEF00CD3AD2 /* SaveKey.cxx */; };
DC4AC6F40DC8DAEF00CD3AD2 /* SaveKey.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC4AC6F20DC8DAEF00CD3AD2 /* SaveKey.hxx */; };
+ DC53B6AE1F3622DA00AA6BFB /* PointingDevice.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC53B6AD1F3622DA00AA6BFB /* PointingDevice.cxx */; };
DC56FCDE14CCCC4900A31CC3 /* MouseControl.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC56FCDC14CCCC4900A31CC3 /* MouseControl.cxx */; };
DC56FCDF14CCCC4900A31CC3 /* MouseControl.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC56FCDD14CCCC4900A31CC3 /* MouseControl.hxx */; };
DC5BE4B317C913AC0091FD64 /* ConsoleBFont.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC5BE4B117C913AC0091FD64 /* ConsoleBFont.hxx */; };
@@ -349,8 +344,6 @@
DC676A541729A0B000E4E73D /* CartFA2Widget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC676A381729A0B000E4E73D /* CartFA2Widget.hxx */; };
DC676A551729A0B000E4E73D /* CartFEWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC676A391729A0B000E4E73D /* CartFEWidget.cxx */; };
DC676A561729A0B000E4E73D /* CartFEWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC676A3A1729A0B000E4E73D /* CartFEWidget.hxx */; };
- DC676A571729A0B000E4E73D /* CartMCWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC676A3B1729A0B000E4E73D /* CartMCWidget.cxx */; };
- DC676A581729A0B000E4E73D /* CartMCWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC676A3C1729A0B000E4E73D /* CartMCWidget.hxx */; };
DC676A591729A0B000E4E73D /* CartSBWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC676A3D1729A0B000E4E73D /* CartSBWidget.cxx */; };
DC676A5A1729A0B000E4E73D /* CartSBWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC676A3E1729A0B000E4E73D /* CartSBWidget.hxx */; };
DC676A5B1729A0B000E4E73D /* CartX07Widget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC676A3F1729A0B000E4E73D /* CartX07Widget.cxx */; };
@@ -524,6 +517,10 @@
DCDA03B01A2009BB00711920 /* CartWD.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCDA03AE1A2009BA00711920 /* CartWD.cxx */; };
DCDA03B11A2009BB00711920 /* CartWD.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCDA03AF1A2009BB00711920 /* CartWD.hxx */; };
DCDAF4D918CA9AAB00D3865D /* SDL2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCDAF4D818CA9AAB00D3865D /* SDL2.framework */; };
+ DCDDEAC41F5DBF0400C67366 /* RewindManager.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCDDEAC01F5DBF0400C67366 /* RewindManager.cxx */; };
+ DCDDEAC51F5DBF0400C67366 /* RewindManager.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCDDEAC11F5DBF0400C67366 /* RewindManager.hxx */; };
+ DCDDEAC61F5DBF0400C67366 /* StateManager.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCDDEAC21F5DBF0400C67366 /* StateManager.cxx */; };
+ DCDDEAC71F5DBF0400C67366 /* StateManager.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCDDEAC31F5DBF0400C67366 /* StateManager.hxx */; };
DCDE17FA17724E5D00EB1AC6 /* ConfigPathDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCDE17F617724E5D00EB1AC6 /* ConfigPathDialog.cxx */; };
DCDE17FB17724E5D00EB1AC6 /* ConfigPathDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCDE17F717724E5D00EB1AC6 /* ConfigPathDialog.hxx */; };
DCDE17FC17724E5D00EB1AC6 /* SnapshotDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCDE17F817724E5D00EB1AC6 /* SnapshotDialog.cxx */; };
@@ -800,8 +797,6 @@
2DE2DF2F0627AE07006BEC99 /* CartF8SC.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = CartF8SC.hxx; sourceTree = ""; };
2DE2DF320627AE07006BEC99 /* CartFE.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CartFE.cxx; sourceTree = ""; };
2DE2DF330627AE07006BEC99 /* CartFE.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = CartFE.hxx; sourceTree = ""; };
- 2DE2DF360627AE07006BEC99 /* CartMC.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CartMC.cxx; sourceTree = ""; };
- 2DE2DF370627AE07006BEC99 /* CartMC.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = CartMC.hxx; sourceTree = ""; };
2DE2DF380627AE07006BEC99 /* Console.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Console.cxx; sourceTree = ""; };
2DE2DF390627AE07006BEC99 /* Console.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Console.hxx; sourceTree = ""; };
2DE2DF3A0627AE07006BEC99 /* Control.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Control.cxx; sourceTree = ""; };
@@ -851,8 +846,6 @@
CFE3F6121E84A9CE00A8204E /* CartCDF.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartCDF.hxx; sourceTree = ""; };
DC047FEC1A4A6F3600348F0F /* JoystickDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JoystickDialog.cxx; sourceTree = ""; };
DC047FED1A4A6F3600348F0F /* JoystickDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = JoystickDialog.hxx; sourceTree = ""; };
- DC07A3C60CAD738A009B4BC9 /* StateManager.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = StateManager.cxx; sourceTree = ""; };
- DC07A3C70CAD738A009B4BC9 /* StateManager.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = StateManager.hxx; sourceTree = ""; };
DC0984830D3985160073C852 /* CartSB.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartSB.cxx; sourceTree = ""; };
DC0984840D3985160073C852 /* CartSB.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartSB.hxx; sourceTree = ""; };
DC0DF8670F0DAAF500B0F1F3 /* GlobalPropsDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GlobalPropsDialog.cxx; sourceTree = ""; };
@@ -863,11 +856,8 @@
DC13B53E176FF2F500B8B4BB /* RomListSettings.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RomListSettings.hxx; sourceTree = ""; };
DC173F740E2CAC1E00320F94 /* ContextMenu.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = ContextMenu.cxx; sourceTree = ""; };
DC173F750E2CAC1E00320F94 /* ContextMenu.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = ContextMenu.hxx; sourceTree = ""; };
- DC1B2EBD1E50036100F62837 /* AmigaMouse.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AmigaMouse.cxx; sourceTree = ""; };
DC1B2EBE1E50036100F62837 /* AmigaMouse.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AmigaMouse.hxx; sourceTree = ""; };
- DC1B2EBF1E50036100F62837 /* AtariMouse.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AtariMouse.cxx; sourceTree = ""; };
DC1B2EC01E50036100F62837 /* AtariMouse.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AtariMouse.hxx; sourceTree = ""; };
- DC1B2EC11E50036100F62837 /* TrakBall.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TrakBall.cxx; sourceTree = ""; };
DC1B2EC21E50036100F62837 /* TrakBall.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TrakBall.hxx; sourceTree = ""; };
DC1FC1880DB3B2C7009B3DF7 /* SerialPortMACOSX.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = SerialPortMACOSX.cxx; sourceTree = ""; };
DC1FC1890DB3B2C7009B3DF7 /* SerialPortMACOSX.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = SerialPortMACOSX.hxx; sourceTree = ""; };
@@ -885,6 +875,7 @@
DC368F5318A2FB710084199C /* SoundSDL2.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SoundSDL2.hxx; sourceTree = ""; };
DC36D2C614CAFAB0007DC821 /* CartFA2.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartFA2.cxx; sourceTree = ""; };
DC36D2C714CAFAB0007DC821 /* CartFA2.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartFA2.hxx; sourceTree = ""; };
+ DC3DAFAB1F2E233B00A64410 /* PointingDevice.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PointingDevice.hxx; sourceTree = ""; };
DC3EE83C1E2C0E6D00905161 /* adler32.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = adler32.c; sourceTree = ""; };
DC3EE83D1E2C0E6D00905161 /* compress.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = compress.c; sourceTree = ""; };
DC3EE83E1E2C0E6D00905161 /* crc32.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = crc32.c; sourceTree = ""; };
@@ -932,6 +923,7 @@
DC4AC6EE0DC8DACB00CD3AD2 /* RiotWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = RiotWidget.hxx; sourceTree = ""; };
DC4AC6F10DC8DAEF00CD3AD2 /* SaveKey.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = SaveKey.cxx; sourceTree = ""; };
DC4AC6F20DC8DAEF00CD3AD2 /* SaveKey.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = SaveKey.hxx; sourceTree = ""; };
+ DC53B6AD1F3622DA00AA6BFB /* PointingDevice.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PointingDevice.cxx; sourceTree = ""; };
DC56FCDC14CCCC4900A31CC3 /* MouseControl.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MouseControl.cxx; sourceTree = ""; };
DC56FCDD14CCCC4900A31CC3 /* MouseControl.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MouseControl.hxx; sourceTree = ""; };
DC5BE4B117C913AC0091FD64 /* ConsoleBFont.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ConsoleBFont.hxx; sourceTree = ""; };
@@ -976,8 +968,6 @@
DC676A381729A0B000E4E73D /* CartFA2Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartFA2Widget.hxx; sourceTree = ""; };
DC676A391729A0B000E4E73D /* CartFEWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartFEWidget.cxx; sourceTree = ""; };
DC676A3A1729A0B000E4E73D /* CartFEWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartFEWidget.hxx; sourceTree = ""; };
- DC676A3B1729A0B000E4E73D /* CartMCWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartMCWidget.cxx; sourceTree = ""; };
- DC676A3C1729A0B000E4E73D /* CartMCWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartMCWidget.hxx; sourceTree = ""; };
DC676A3D1729A0B000E4E73D /* CartSBWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartSBWidget.cxx; sourceTree = ""; };
DC676A3E1729A0B000E4E73D /* CartSBWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartSBWidget.hxx; sourceTree = ""; };
DC676A3F1729A0B000E4E73D /* CartX07Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartX07Widget.cxx; sourceTree = ""; };
@@ -1153,6 +1143,10 @@
DCDA03AE1A2009BA00711920 /* CartWD.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartWD.cxx; sourceTree = ""; };
DCDA03AF1A2009BB00711920 /* CartWD.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartWD.hxx; sourceTree = ""; };
DCDAF4D818CA9AAB00D3865D /* SDL2.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL2.framework; path = /Library/Frameworks/SDL2.framework; sourceTree = ""; };
+ DCDDEAC01F5DBF0400C67366 /* RewindManager.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RewindManager.cxx; sourceTree = ""; };
+ DCDDEAC11F5DBF0400C67366 /* RewindManager.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RewindManager.hxx; sourceTree = ""; };
+ DCDDEAC21F5DBF0400C67366 /* StateManager.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StateManager.cxx; sourceTree = ""; };
+ DCDDEAC31F5DBF0400C67366 /* StateManager.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StateManager.hxx; sourceTree = ""; };
DCDE17F617724E5D00EB1AC6 /* ConfigPathDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConfigPathDialog.cxx; sourceTree = ""; };
DCDE17F717724E5D00EB1AC6 /* ConfigPathDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ConfigPathDialog.hxx; sourceTree = ""; };
DCDE17F817724E5D00EB1AC6 /* SnapshotDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SnapshotDialog.cxx; sourceTree = ""; };
@@ -1403,8 +1397,6 @@
DCAAE5D01715887B0080BB82 /* CartFAWidget.hxx */,
DC676A391729A0B000E4E73D /* CartFEWidget.cxx */,
DC676A3A1729A0B000E4E73D /* CartFEWidget.hxx */,
- DC676A3B1729A0B000E4E73D /* CartMCWidget.cxx */,
- DC676A3C1729A0B000E4E73D /* CartMCWidget.hxx */,
DC6A18F619B3E65500DEB242 /* CartMDMWidget.cxx */,
DC6A18F719B3E65500DEB242 /* CartMDMWidget.hxx */,
DC2AADB2194F390F0026C7A4 /* CartRamWidget.cxx */,
@@ -1492,10 +1484,14 @@
DC56FCDD14CCCC4900A31CC3 /* MouseControl.hxx */,
DCD6FC9111C28C6F005DA767 /* PNGLibrary.cxx */,
DCD6FC9211C28C6F005DA767 /* PNGLibrary.hxx */,
+ DCDDEAC01F5DBF0400C67366 /* RewindManager.cxx */,
+ DCDDEAC11F5DBF0400C67366 /* RewindManager.hxx */,
DCF467B40F93993B00B25D7A /* SoundNull.hxx */,
DC368F5218A2FB710084199C /* SoundSDL2.cxx */,
DC368F5318A2FB710084199C /* SoundSDL2.hxx */,
DC5D1AA6102C6FC900E59AC1 /* Stack.hxx */,
+ DCDDEAC21F5DBF0400C67366 /* StateManager.cxx */,
+ DCDDEAC31F5DBF0400C67366 /* StateManager.hxx */,
DC5C768E14C26F7C0031EBC7 /* StellaKeys.hxx */,
DC74D6A0138D4D7E00F05C5C /* StringParser.hxx */,
DCC467EA14FBEC9600E15508 /* tv_filters */,
@@ -1533,9 +1529,7 @@
2D6050CC0898776500C6DE89 /* emucore */ = {
isa = PBXGroup;
children = (
- DC1B2EBD1E50036100F62837 /* AmigaMouse.cxx */,
DC1B2EBE1E50036100F62837 /* AmigaMouse.hxx */,
- DC1B2EBF1E50036100F62837 /* AtariMouse.cxx */,
DC1B2EC01E50036100F62837 /* AtariMouse.hxx */,
DC487FB40DA5350900E12499 /* AtariVox.cxx */,
DC487FB50DA5350900E12499 /* AtariVox.hxx */,
@@ -1619,8 +1613,6 @@
DC36D2C714CAFAB0007DC821 /* CartFA2.hxx */,
2DE2DF320627AE07006BEC99 /* CartFE.cxx */,
2DE2DF330627AE07006BEC99 /* CartFE.hxx */,
- 2DE2DF360627AE07006BEC99 /* CartMC.cxx */,
- 2DE2DF370627AE07006BEC99 /* CartMC.hxx */,
DC6A18FA19B3E67A00DEB242 /* CartMDM.cxx */,
DC6A18FB19B3E67A00DEB242 /* CartMDM.hxx */,
DC0984830D3985160073C852 /* CartSB.cxx */,
@@ -1674,6 +1666,8 @@
2DDBEB7508457B7D00812C11 /* OSystem.hxx */,
2DE2DF820627AE34006BEC99 /* Paddles.cxx */,
2DE2DF830627AE34006BEC99 /* Paddles.hxx */,
+ DC53B6AD1F3622DA00AA6BFB /* PointingDevice.cxx */,
+ DC3DAFAB1F2E233B00A64410 /* PointingDevice.hxx */,
2DE2DF840627AE34006BEC99 /* Props.cxx */,
2DE2DF850627AE34006BEC99 /* Props.hxx */,
2DE2DF860627AE34006BEC99 /* PropsSet.cxx */,
@@ -1688,8 +1682,6 @@
2D944848062904E800DD9879 /* Settings.cxx */,
2D733D77062895F1006265D9 /* Settings.hxx */,
2DE2DF8D0627AE34006BEC99 /* Sound.hxx */,
- DC07A3C60CAD738A009B4BC9 /* StateManager.cxx */,
- DC07A3C70CAD738A009B4BC9 /* StateManager.hxx */,
2DE2DF8E0627AE34006BEC99 /* Switches.cxx */,
2DE2DF8F0627AE34006BEC99 /* Switches.hxx */,
DCC527CE10B9DA19005E1287 /* System.cxx */,
@@ -1702,7 +1694,6 @@
DC2AADAC194F389C0026C7A4 /* TIASurface.cxx */,
DC2AADAD194F389C0026C7A4 /* TIASurface.hxx */,
DCF3A7011DFC76BC008A8AF3 /* TIATypes.hxx */,
- DC1B2EC11E50036100F62837 /* TrakBall.cxx */,
DC1B2EC21E50036100F62837 /* TrakBall.hxx */,
);
path = emucore;
@@ -2003,7 +1994,6 @@
DC3EE8591E2C0E6D00905161 /* crc32.h in Headers */,
2D9173DB09BA90380026E9FF /* CartF8SC.hxx in Headers */,
2D9173DD09BA90380026E9FF /* CartFE.hxx in Headers */,
- 2D9173DF09BA90380026E9FF /* CartMC.hxx in Headers */,
DC62E6481960E87B007AEF05 /* AtariVoxWidget.hxx in Headers */,
2D9173E009BA90380026E9FF /* Console.hxx in Headers */,
2D9173E109BA90380026E9FF /* Control.hxx in Headers */,
@@ -2126,7 +2116,6 @@
DC8078EB0B4BD697005E9305 /* UIDialog.hxx in Headers */,
DCEECE570B5E5E540021D754 /* Cart0840.hxx in Headers */,
DCE3BBFA0C95CEDC00A671DF /* RomInfoWidget.hxx in Headers */,
- DC07A3C90CAD738A009B4BC9 /* StateManager.hxx in Headers */,
DC0984860D3985160073C852 /* CartSB.hxx in Headers */,
DCEC585E1E945175002F0246 /* DelayQueueIterator.hxx in Headers */,
DCA23AEA0D75B22500F77B33 /* CartX07.hxx in Headers */,
@@ -2190,6 +2179,7 @@
DC6C726313CDEA0A008A5975 /* LoggerDialog.hxx in Headers */,
DC8C1BAE14B25DE7006440EE /* CartCM.hxx in Headers */,
DCF3A6FB1DFC75E3008A8AF3 /* Player.hxx in Headers */,
+ DCDDEAC71F5DBF0400C67366 /* StateManager.hxx in Headers */,
DC8C1BB014B25DE7006440EE /* CompuMate.hxx in Headers */,
DC8C1BB214B25DE7006440EE /* MindLink.hxx in Headers */,
DCCF47DE14B60DEE00814FAB /* ControllerWidget.hxx in Headers */,
@@ -2243,9 +2233,9 @@
DC676A521729A0B000E4E73D /* CartE7Widget.hxx in Headers */,
DC676A541729A0B000E4E73D /* CartFA2Widget.hxx in Headers */,
DC676A561729A0B000E4E73D /* CartFEWidget.hxx in Headers */,
- DC676A581729A0B000E4E73D /* CartMCWidget.hxx in Headers */,
DC676A5A1729A0B000E4E73D /* CartSBWidget.hxx in Headers */,
DC676A5C1729A0B000E4E73D /* CartX07Widget.hxx in Headers */,
+ DC3DAFAC1F2E233B00A64410 /* PointingDevice.hxx in Headers */,
DC7A24D5173B1CF600B20FE9 /* Variant.hxx in Headers */,
DC7A24E0173B1DBC00B20FE9 /* FileListWidget.hxx in Headers */,
DC13B540176FF2F500B8B4BB /* RomListSettings.hxx in Headers */,
@@ -2265,6 +2255,7 @@
DCAACB0F188D636F00A4D282 /* Cart4KSCWidget.hxx in Headers */,
DCAACB11188D636F00A4D282 /* CartBFSCWidget.hxx in Headers */,
DC6A18FD19B3E67A00DEB242 /* CartMDM.hxx in Headers */,
+ DCDDEAC51F5DBF0400C67366 /* RewindManager.hxx in Headers */,
DCAACB13188D636F00A4D282 /* CartBFWidget.hxx in Headers */,
DCAACB15188D636F00A4D282 /* CartDFSCWidget.hxx in Headers */,
DC44019F1F1A5D01008C08F6 /* ColorWidget.hxx in Headers */,
@@ -2395,7 +2386,6 @@
2D91748409BA90380026E9FF /* CartF8SC.cxx in Sources */,
DCF3A6FA1DFC75E3008A8AF3 /* Player.cxx in Sources */,
2D91748609BA90380026E9FF /* CartFE.cxx in Sources */,
- 2D91748809BA90380026E9FF /* CartMC.cxx in Sources */,
2D91748909BA90380026E9FF /* Console.cxx in Sources */,
2D91748A09BA90380026E9FF /* Control.cxx in Sources */,
2D91748C09BA90380026E9FF /* Driving.cxx in Sources */,
@@ -2429,7 +2419,6 @@
2D9174B609BA90380026E9FF /* Menu.cxx in Sources */,
DC5E473B19EC9A14000E45DF /* EventJoyHandler.cxx in Sources */,
CFE3F60D1E84A9A200A8204E /* CartCDFWidget.cxx in Sources */,
- DC1B2EC71E50036100F62837 /* TrakBall.cxx in Sources */,
2D9174B709BA90380026E9FF /* OptionsDialog.cxx in Sources */,
2D9174B809BA90380026E9FF /* PopUpWidget.cxx in Sources */,
DCBDDE9A1D6A5F0E009DF1E9 /* Cart3EPlusWidget.cxx in Sources */,
@@ -2443,12 +2432,12 @@
2D9174BE09BA90380026E9FF /* CartUA.cxx in Sources */,
DC3EE86E1E2C0E6D00905161 /* zutil.c in Sources */,
CFE3F60B1E84A9A200A8204E /* CartBUSWidget.cxx in Sources */,
- DC1B2EC51E50036100F62837 /* AtariMouse.cxx in Sources */,
DCEC58581E945125002F0246 /* DelayQueueWidget.cxx in Sources */,
2D9174BF09BA90380026E9FF /* FSNode.cxx in Sources */,
DCF3A6FE1DFC75E3008A8AF3 /* TIA.cxx in Sources */,
2D9174C009BA90380026E9FF /* OSystem.cxx in Sources */,
2D9174C209BA90380026E9FF /* Preferences.m in Sources */,
+ DC53B6AE1F3622DA00AA6BFB /* PointingDevice.cxx in Sources */,
2D9174C409BA90380026E9FF /* AboutBox.m in Sources */,
2D9174C509BA90380026E9FF /* Font.cxx in Sources */,
2D9174C609BA90380026E9FF /* Debugger.cxx in Sources */,
@@ -2479,7 +2468,6 @@
2D9174FD09BA90380026E9FF /* RomListWidget.cxx in Sources */,
DCF3A6F81DFC75E3008A8AF3 /* PaddleReader.cxx in Sources */,
2D9174FE09BA90380026E9FF /* RomWidget.cxx in Sources */,
- DC1B2EC31E50036100F62837 /* AmigaMouse.cxx in Sources */,
2D9174FF09BA90380026E9FF /* TiaInfoWidget.cxx in Sources */,
2D91750009BA90380026E9FF /* TiaOutputWidget.cxx in Sources */,
2D91750109BA90380026E9FF /* TiaWidget.cxx in Sources */,
@@ -2490,6 +2478,7 @@
2D91750609BA90380026E9FF /* TiaZoomWidget.cxx in Sources */,
CFE3F6131E84A9CE00A8204E /* CartBUS.cxx in Sources */,
DC73BD851915E5B1003FAFAD /* FBSurfaceSDL2.cxx in Sources */,
+ DCDDEAC41F5DBF0400C67366 /* RewindManager.cxx in Sources */,
2D91750709BA90380026E9FF /* TIASnd.cxx in Sources */,
2D91750809BA90380026E9FF /* AudioWidget.cxx in Sources */,
2D91750B09BA90380026E9FF /* EventMappingWidget.cxx in Sources */,
@@ -2507,7 +2496,6 @@
DCEECE560B5E5E540021D754 /* Cart0840.cxx in Sources */,
DC3EE8571E2C0E6D00905161 /* compress.c in Sources */,
DCE3BBF90C95CEDC00A671DF /* RomInfoWidget.cxx in Sources */,
- DC07A3C80CAD738A009B4BC9 /* StateManager.cxx in Sources */,
DC0984850D3985160073C852 /* CartSB.cxx in Sources */,
DC3EE8651E2C0E6D00905161 /* inflate.c in Sources */,
DC6D39871A3CE65000171E71 /* CartWDWidget.cxx in Sources */,
@@ -2566,6 +2554,7 @@
DCD2839812E39F1200A808DC /* Thumbulator.cxx in Sources */,
DC6C726213CDEA0A008A5975 /* LoggerDialog.cxx in Sources */,
DC8C1BAD14B25DE7006440EE /* CartCM.cxx in Sources */,
+ DCDDEAC61F5DBF0400C67366 /* StateManager.cxx in Sources */,
DC8C1BAF14B25DE7006440EE /* CompuMate.cxx in Sources */,
DC8C1BB114B25DE7006440EE /* MindLink.cxx in Sources */,
DCCF47DF14B60DEE00814FAB /* JoystickWidget.cxx in Sources */,
@@ -2617,7 +2606,6 @@
DC676A511729A0B000E4E73D /* CartE7Widget.cxx in Sources */,
DC676A531729A0B000E4E73D /* CartFA2Widget.cxx in Sources */,
DC676A551729A0B000E4E73D /* CartFEWidget.cxx in Sources */,
- DC676A571729A0B000E4E73D /* CartMCWidget.cxx in Sources */,
DC676A591729A0B000E4E73D /* CartSBWidget.cxx in Sources */,
DC676A5B1729A0B000E4E73D /* CartX07Widget.cxx in Sources */,
DC7A24DF173B1DBC00B20FE9 /* FileListWidget.cxx in Sources */,
diff --git a/src/unix/stella.spec b/src/unix/stella.spec
index 872053f6d..67b6ffae7 100644
--- a/src/unix/stella.spec
+++ b/src/unix/stella.spec
@@ -1,5 +1,5 @@
%define name stella
-%define version 5.0.1
+%define version 5.0.2
%define rel 1
%define enable_sound 1
@@ -101,6 +101,9 @@ rm -rf $RPM_BUILD_DIR/%{name}-%{version}
%_datadir/icons/large/%{name}.png
%changelog
+* Sun Aug 20 2017 Stephen Anthony 5.0.2-1
+- Version 5.0.2 release
+
* Sun Jul 23 2017 Stephen Anthony 5.0.1-1
- Version 5.0.1 release
diff --git a/src/windows/FSNodeWINDOWS.cxx b/src/windows/FSNodeWINDOWS.cxx
index 5405d4566..dfd3e1d2a 100644
--- a/src/windows/FSNodeWINDOWS.cxx
+++ b/src/windows/FSNodeWINDOWS.cxx
@@ -298,22 +298,16 @@ bool FilesystemNodeWINDOWS::rename(const string& newfile)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AbstractFSNode* FilesystemNodeWINDOWS::getParent() const
{
- if(!_isValid || _isPseudoRoot)
+ if(_isPseudoRoot)
return nullptr;
- FilesystemNodeWINDOWS* p = new FilesystemNodeWINDOWS();
if(_path.size() > 3)
{
const char* start = _path.c_str();
const char* end = lastPathComponent(_path);
- p->_path = string(start, end - start);
- p->_isValid = true;
- p->_isDirectory = true;
- p->_isFile = false;
- p->_displayName = lastPathComponent(p->_path);
- p->_isPseudoRoot = false;
+ return new FilesystemNodeWINDOWS(string(start, size_t(end - start)));
}
-
- return p;
+ else
+ return new FilesystemNodeWINDOWS();
}
diff --git a/src/windows/HomeFinder.hxx b/src/windows/HomeFinder.hxx
index 7e34cf318..8d2409975 100644
--- a/src/windows/HomeFinder.hxx
+++ b/src/windows/HomeFinder.hxx
@@ -56,21 +56,21 @@ class HomeFinder
return ourAppDataPath;
}
- // Return the 'DESKTOPDIRECTORY' folder, or an empty string if the folder couldn't be determined.
- const string& getDesktopPath() const
+ // Return the 'My Documents' folder, or an empty string if the folder couldn't be determined.
+ const string& getDocumentsPath() const
{
- if(ourDesktopPath == "")
+ if(ourDocumentsPath == "")
{
char folder_path[MAX_PATH];
- HRESULT const result = SHGetFolderPathA(NULL, CSIDL_DESKTOPDIRECTORY | CSIDL_FLAG_CREATE,
+ HRESULT const result = SHGetFolderPathA(NULL, CSIDL_MYDOCUMENTS | CSIDL_FLAG_CREATE,
NULL, 0, folder_path);
- ourDesktopPath = (result == S_OK) ? folder_path : EmptyString;
+ ourDocumentsPath = (result == S_OK) ? folder_path : EmptyString;
}
- return ourDesktopPath;
+ return ourDocumentsPath;
}
private:
- static string ourHomePath, ourAppDataPath, ourDesktopPath;
+ static string ourHomePath, ourAppDataPath, ourDocumentsPath;
// Following constructors and assignment operators not supported
HomeFinder(const HomeFinder&) = delete;
@@ -81,6 +81,6 @@ class HomeFinder
__declspec(selectany) string HomeFinder::ourHomePath = "";
__declspec(selectany) string HomeFinder::ourAppDataPath = "";
-__declspec(selectany) string HomeFinder::ourDesktopPath = "";
+__declspec(selectany) string HomeFinder::ourDocumentsPath = "";
#endif
diff --git a/src/windows/OSystemWINDOWS.cxx b/src/windows/OSystemWINDOWS.cxx
index 246e0e93a..4ae497cff 100644
--- a/src/windows/OSystemWINDOWS.cxx
+++ b/src/windows/OSystemWINDOWS.cxx
@@ -71,26 +71,31 @@ OSystemWINDOWS::OSystemWINDOWS()
basedir = appdata.getShortPath();
if(basedir.length() > 1 && basedir[basedir.length()-1] != '\\')
basedir += '\\';
- basedir += "Stella";
+ basedir += "Stella\\";
}
else
- basedir = "."; // otherwise, default to current directory
+ basedir = ".\\"; // otherwise, default to current directory
}
setBaseDir(basedir);
- setConfigFile(basedir + "\\stella.ini");
+ setConfigFile(basedir + "stella.ini");
+
+ // Create default save/load dir
+ FilesystemNode node(defaultSaveDir());
+ if(!node.exists())
+ node.makeDir();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-string OSystemWINDOWS::defaultSnapSaveDir()
+string OSystemWINDOWS::defaultSaveDir() const
{
HomeFinder homefinder;
- FilesystemNode desktop(homefinder.getDesktopPath());
- return desktop.isDirectory() ? desktop.getShortPath() : "~";
+ FilesystemNode documents(homefinder.getDocumentsPath());
+ return documents.isDirectory() ? documents.getShortPath() + "\\Stella\\" : "~\\";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-string OSystemWINDOWS::defaultSnapLoadDir()
+string OSystemWINDOWS::defaultLoadDir() const
{
- return defaultSnapSaveDir();
+ return defaultSaveDir();
}
diff --git a/src/windows/OSystemWINDOWS.hxx b/src/windows/OSystemWINDOWS.hxx
index 87ee39ff5..fc7bec449 100644
--- a/src/windows/OSystemWINDOWS.hxx
+++ b/src/windows/OSystemWINDOWS.hxx
@@ -22,8 +22,6 @@
/**
This class defines Windows system specific settings.
-
- @author Stephen Anthony
*/
class OSystemWINDOWS : public OSystem
{
@@ -36,10 +34,10 @@ class OSystemWINDOWS : public OSystem
public:
/**
- Returns the default paths for the snapshot directory.
+ Returns the default paths for loading/saving files.
*/
- string defaultSnapSaveDir() override;
- string defaultSnapLoadDir() override;
+ string defaultSaveDir() const override;
+ string defaultLoadDir() const override;
private:
// Following constructors and assignment operators not supported
diff --git a/src/windows/SerialPortWINDOWS.hxx b/src/windows/SerialPortWINDOWS.hxx
index ea0694fc6..5d0c2b011 100644
--- a/src/windows/SerialPortWINDOWS.hxx
+++ b/src/windows/SerialPortWINDOWS.hxx
@@ -24,8 +24,6 @@
/**
Implement reading and writing from a serial port under Windows systems.
-
- @author Stephen Anthony
*/
class SerialPortWINDOWS : public SerialPort
{
diff --git a/src/windows/Stella.vcxproj b/src/windows/Stella.vcxproj
index 7cf7f4110..b07f88a65 100644
--- a/src/windows/Stella.vcxproj
+++ b/src/windows/Stella.vcxproj
@@ -89,22 +89,22 @@
AllRules.ruleset
- C:\Users\stephen\Source\sdl\include;$(IncludePath)
- C:\Users\stephen\Source\sdl\include;$(IncludePath)
- C:\Users\stephen\Source\sdl\include;$(IncludePath)
- C:\Users\stephen\Source\sdl\lib\x86;$(LibraryPath)
+ $(ProjectDir)\SDL\lib\x86;$(LibraryPath)
+ $(ProjectDir)\SDL\include;$(IncludePath)
- C:\Users\stephen\Source\sdl\include;$(IncludePath)
- C:\Users\stephen\Source\sdl\lib\x86;$(LibraryPath)
+ $(ProjectDir)\SDL\lib\x86;$(LibraryPath)
+ $(ProjectDir)\SDL\include;$(IncludePath)
- C:\Users\stephen\Source\sdl\lib\x64;$(LibraryPath)
+ $(ProjectDir)\SDL\lib\x64;$(LibraryPath)
+ $(ProjectDir)\SDL\include;$(IncludePath)
- C:\Users\stephen\Source\sdl\lib\x64;$(LibraryPath)
+ $(ProjectDir)\SDL\lib\x64;$(LibraryPath)
+ $(ProjectDir)\SDL\include;$(IncludePath)
@@ -235,6 +235,8 @@
+
+
@@ -276,7 +278,6 @@
-
@@ -292,8 +293,6 @@
-
-
@@ -314,6 +313,7 @@
+
@@ -326,7 +326,6 @@
-
@@ -364,7 +363,6 @@
-
@@ -389,7 +387,6 @@
-
@@ -503,6 +500,8 @@
+
+
@@ -549,7 +548,6 @@
-
@@ -590,6 +588,7 @@
+
@@ -656,7 +655,6 @@
-
@@ -688,7 +686,6 @@
-
diff --git a/src/windows/Stella.vcxproj.filters b/src/windows/Stella.vcxproj.filters
index b1b815c94..ed00b4d3c 100644
--- a/src/windows/Stella.vcxproj.filters
+++ b/src/windows/Stella.vcxproj.filters
@@ -156,9 +156,6 @@
Source Files\emucore
-
- Source Files\emucore
-
Source Files\emucore
@@ -231,9 +228,6 @@
Source Files\emucore
-
- Source Files\emucore
-
Source Files\emucore
@@ -669,9 +663,6 @@
Source Files\debugger
-
- Source Files\debugger
-
Source Files\debugger
@@ -816,15 +807,6 @@
Source Files\emucore\tia
-
- Source Files\emucore
-
-
- Source Files\emucore
-
-
- Source Files\emucore
-
Source Files\debugger
@@ -849,6 +831,15 @@
Source Files\gui
+
+ Source Files\emucore
+
+
+ Source Files
+
+
+ Source Files
+
@@ -962,9 +953,6 @@
Header Files\emucore
-
- Header Files\emucore
-
Header Files\emucore
@@ -1058,9 +1046,6 @@
Header Files\emucore
-
- Header Files\emucore
-
Header Files\emucore
@@ -1514,9 +1499,6 @@
Header Files\debugger
-
- Header Files\debugger
-
Header Files\debugger
@@ -1724,6 +1706,15 @@
Header Files\gui
+
+ Header Files\emucore
+
+
+ Header Files
+
+
+ Header Files
+
diff --git a/src/windows/stella.rc b/src/windows/stella.rc
index b1549d321..01bb8af33 100755
--- a/src/windows/stella.rc
+++ b/src/windows/stella.rc
@@ -36,8 +36,8 @@ IDI_ICON ICON "stella.ico"
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 5,0,1,0
- PRODUCTVERSION 5,0,1,0
+ FILEVERSION 5,0,2,0
+ PRODUCTVERSION 5,0,2,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -55,12 +55,12 @@ BEGIN
VALUE "Comments", "The multi-platform Atari 2600 emulator. Stella is released under the GPLv2."
VALUE "CompanyName", "The Stella Team (https://stella-emu.github.io)"
VALUE "FileDescription", "Stella"
- VALUE "FileVersion", "5.0.1"
+ VALUE "FileVersion", "5.0.2"
VALUE "InternalName", "Stella"
VALUE "LegalCopyright", "Copyright (C) 1995-2017 The Stella Team"
VALUE "OriginalFilename", "Stella.exe"
VALUE "ProductName", "Stella"
- VALUE "ProductVersion", "5.0.1"
+ VALUE "ProductVersion", "5.0.2"
END
END
BLOCK "VarFileInfo"
diff --git a/src/yacc/YaccParser.cxx b/src/yacc/YaccParser.cxx
index 23506b2aa..6a010b720 100644
--- a/src/yacc/YaccParser.cxx
+++ b/src/yacc/YaccParser.cxx
@@ -217,6 +217,12 @@ TiaMethod getTiaSpecial(char* ch)
return &TIADebug::scanlines;
else if(BSPF::equalsIgnoreCase(ch, "_fcount"))
return &TIADebug::frameCount;
+ else if(BSPF::equalsIgnoreCase(ch, "_fcycles"))
+ return &TIADebug::frameCycles;
+ else if(BSPF::equalsIgnoreCase(ch, "_cyclesLo"))
+ return &TIADebug::cyclesLo;
+ else if(BSPF::equalsIgnoreCase(ch, "_cyclesHi"))
+ return &TIADebug::cyclesHi;
else if(BSPF::equalsIgnoreCase(ch, "_cclocks"))
return &TIADebug::clocksThisLine;
else if(BSPF::equalsIgnoreCase(ch, "_vsync"))