Merge branch 'release/6.0'
|
@ -67,6 +67,7 @@
|
||||||
"unordered_map": "cpp",
|
"unordered_map": "cpp",
|
||||||
"istream": "cpp",
|
"istream": "cpp",
|
||||||
"thread": "cpp",
|
"thread": "cpp",
|
||||||
"utility": "cpp"
|
"utility": "cpp",
|
||||||
|
"streambuf": "cpp"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
SSSS ttt eeeee llll llll aaaaa
|
SSSS ttt eeeee llll llll aaaaa
|
||||||
|
|
||||||
===========================================================================
|
===========================================================================
|
||||||
Release 6.0 for Linux, MacOSX and Windows
|
Release 6.0 for Linux, macOS and Windows
|
||||||
===========================================================================
|
===========================================================================
|
||||||
|
|
||||||
The Atari 2600 Video Computer System (VCS), introduced in 1977, was the
|
The Atari 2600 Video Computer System (VCS), introduced in 1977, was the
|
||||||
|
@ -21,7 +21,7 @@ all of your favourite Atari 2600 games again! Stella was originally
|
||||||
developed for Linux by Bradford W. Mott, however, it has been ported to a
|
developed for Linux by Bradford W. Mott, however, it has been ported to a
|
||||||
number of other platforms and is currently maintained by Stephen Anthony.
|
number of other platforms and is currently maintained by Stephen Anthony.
|
||||||
|
|
||||||
This is the 6.0 release of Stella for Linux, Mac OSX and Windows. The
|
This is the 6.0 release of Stella for Linux, macOS and Windows. The
|
||||||
distributions currently available are:
|
distributions currently available are:
|
||||||
|
|
||||||
* Binaries for Windows XP_SP3(*)/Vista/7/8/10 :
|
* Binaries for Windows XP_SP3(*)/Vista/7/8/10 :
|
||||||
|
@ -32,8 +32,8 @@ distributions currently available are:
|
||||||
(*) Note: Support for Windows XP is problematic on some systems,
|
(*) Note: Support for Windows XP is problematic on some systems,
|
||||||
and will probably be discontinued in a future release.
|
and will probably be discontinued in a future release.
|
||||||
|
|
||||||
* Binary distribution for MacOS X 10.7 and above :
|
* Binary distribution for macOS 10.7 and above :
|
||||||
Stella-6.0-macosx.dmg (64-bit Intel)
|
Stella-6.0-macos.dmg (64-bit Intel)
|
||||||
|
|
||||||
* Binary distribution in 32-bit & 64-bit Ubuntu DEB format :
|
* Binary distribution in 32-bit & 64-bit Ubuntu DEB format :
|
||||||
stella_6.0-1_i386.deb
|
stella_6.0-1_i386.deb
|
||||||
|
|
54
Changes.txt
|
@ -12,7 +12,7 @@
|
||||||
Release History
|
Release History
|
||||||
===========================================================================
|
===========================================================================
|
||||||
|
|
||||||
5.1.3 to 6.0: (MMM d, 2018)
|
5.1.3 to 6.0: (December 23, 2018)
|
||||||
|
|
||||||
* Note: because of major TIA sound changes, the state file format has
|
* Note: because of major TIA sound changes, the state file format has
|
||||||
changed, and old state files will not work with this release.
|
changed, and old state files will not work with this release.
|
||||||
|
@ -31,26 +31,33 @@
|
||||||
* Main loop rewritten; emulating speed and timing is now much more
|
* Main loop rewritten; emulating speed and timing is now much more
|
||||||
faithful (i.e. speed in Pick'n'Pile).
|
faithful (i.e. speed in Pick'n'Pile).
|
||||||
|
|
||||||
* Audio settings replaced with new 'audio.xxx' settings.
|
* Added preliminary support for 'CTY' bankswitching scheme and recently
|
||||||
|
released 'Chetiry' ROMs. Special thanks to SpiceWare for adding music
|
||||||
* FPS setting replaced with speed setting for adjusting emulation speed.
|
support to this scheme.
|
||||||
|
|
||||||
* Extra functionality for Time Machine dialog (start/stop recording;
|
|
||||||
minor fixes; TODO button and initial key repeats...)
|
|
||||||
|
|
||||||
* Fixes for collision corner cases (during HBlank).
|
|
||||||
|
|
||||||
* UI modernization (new widget look, dialog titles added, dialogs
|
* UI modernization (new widget look, dialog titles added, dialogs
|
||||||
refactored).
|
refactored).
|
||||||
|
|
||||||
* Fixed excessive CPU usage while in UI modes (ROM launcher, debugger,
|
|
||||||
etc).
|
|
||||||
|
|
||||||
* The bankswitch scheme can now be forced by naming the ROM with a
|
* The bankswitch scheme can now be forced by naming the ROM with a
|
||||||
specific extension (ie: .f8s for F8SC, .fe for FE, etc). The
|
specific extension (ie: .f8s for F8SC, .fe for FE, etc). The
|
||||||
supported extensions are the same as the ones from HarmonyCart and
|
supported extensions are the same as the ones from HarmonyCart and
|
||||||
UnoCart.
|
UnoCart.
|
||||||
|
|
||||||
|
* Audio settings replaced with new 'audio.xxx' settings.
|
||||||
|
|
||||||
|
* FPS setting replaced with speed setting for adjusting emulation speed.
|
||||||
|
|
||||||
|
* Extra functionality for Time Machine dialog (start/stop recording;
|
||||||
|
minor fixes).
|
||||||
|
|
||||||
|
* When logging messages to the System Logger, condense similar messages
|
||||||
|
that arrive in batches into fewer messages (including timestamps).
|
||||||
|
|
||||||
|
* Fixes for collision corner cases (during HBlank).
|
||||||
|
|
||||||
|
* Fixed excessive CPU usage while in UI modes (ROM launcher, debugger,
|
||||||
|
etc).
|
||||||
|
|
||||||
* The 'launcherexts' option has been replaced by a true/false option
|
* The 'launcherexts' option has been replaced by a true/false option
|
||||||
named 'launcherroms', which specifies to show only ROMs or all files
|
named 'launcherroms', which specifies to show only ROMs or all files
|
||||||
in the ROM launcher.
|
in the ROM launcher.
|
||||||
|
@ -63,6 +70,10 @@
|
||||||
|
|
||||||
* Fixed bug in autodetecting Genesis controllers.
|
* Fixed bug in autodetecting Genesis controllers.
|
||||||
|
|
||||||
|
* Fixed bug with 'thumb.trapfatal' commandline argument; sometimes Stella
|
||||||
|
would lock up when encountering a fatal error instead of entering the
|
||||||
|
debugger and displaying a message.
|
||||||
|
|
||||||
* Fixed bug in reading from settings file with entries that were empty;
|
* Fixed bug in reading from settings file with entries that were empty;
|
||||||
the parsing was failing. This affected the 'cpurandom' argument; when
|
the parsing was failing. This affected the 'cpurandom' argument; when
|
||||||
all options in it were turned off, they were all turned on again during
|
all options in it were turned off, they were all turned on again during
|
||||||
|
@ -97,19 +108,29 @@
|
||||||
* The ROM name saved in a PNG tEXt chunk now honours the 'snapname'
|
* The ROM name saved in a PNG tEXt chunk now honours the 'snapname'
|
||||||
setting.
|
setting.
|
||||||
|
|
||||||
|
* Improved snapshots when phosphor is enabled.
|
||||||
|
|
||||||
* Updated PAL palette.
|
* Updated PAL palette.
|
||||||
|
|
||||||
* Added 'Cartridge.StartBank' ROM property, to force a ROM to use a
|
* Added 'Cartridge.StartBank' ROM property, to force a ROM to use a
|
||||||
specific bank for its reset vector.
|
specific bank for its reset vector.
|
||||||
|
|
||||||
|
* Added Developer setting, which breaks on reads from write ports. It
|
||||||
|
now detects such conditions in many more cases. This new way of
|
||||||
|
detecting RWP errors obsoletes the old '_rwport' debugger command,
|
||||||
|
which has now been removed.
|
||||||
|
|
||||||
* Added recently released 'Arkyology' prototype ROM to the database.
|
* Added recently released 'Arkyology' prototype ROM to the database.
|
||||||
|
|
||||||
|
* Added 'Amoeba Jump' and 'Flappy' ROMs (from the Retron77) to the
|
||||||
|
database.
|
||||||
|
|
||||||
* Fixed 'Street Racer' and 'Video Olympics' ROMs to use paddles in both
|
* Fixed 'Street Racer' and 'Video Olympics' ROMs to use paddles in both
|
||||||
ports.
|
ports.
|
||||||
|
|
||||||
* Added premliminary support for 'CTY' bankswitching scheme and recently
|
* If using SDL 2.0.5 or above, the calculated desktop size now takes
|
||||||
released 'Chetiry' ROMs. Special thanks to SpiceWare for adding music
|
the taskbar/dock into account (so windows should no longer overlap
|
||||||
support to this scheme.
|
those areas).
|
||||||
|
|
||||||
* For UNIX systems: in the ROM launcher, when using symlinks use the
|
* For UNIX systems: in the ROM launcher, when using symlinks use the
|
||||||
symlink pathname instead of the underlying filesystem pathname.
|
symlink pathname instead of the underlying filesystem pathname.
|
||||||
|
@ -117,6 +138,9 @@
|
||||||
* The UNIX builds now use the system-installed PNG and ZLIB libraries
|
* The UNIX builds now use the system-installed PNG and ZLIB libraries
|
||||||
by default.
|
by default.
|
||||||
|
|
||||||
|
* The Macintosh builds are now named 'macOS' throughout the codebase to
|
||||||
|
reflect the new naming from Apple.
|
||||||
|
|
||||||
* For better compatibility, the Windows 32-bit version does not require
|
* For better compatibility, the Windows 32-bit version does not require
|
||||||
SSE2 anymore.
|
SSE2 anymore.
|
||||||
|
|
||||||
|
|
|
@ -716,7 +716,7 @@ case $_host_os in
|
||||||
INCLUDES="$INCLUDES -I$SRC/unix"
|
INCLUDES="$INCLUDES -I$SRC/unix"
|
||||||
;;
|
;;
|
||||||
darwin)
|
darwin)
|
||||||
DEFINES="$DEFINES -DBSPF_UNIX -DOSX_KEYS"
|
DEFINES="$DEFINES -DBSPF_UNIX -DMACOS_KEYS"
|
||||||
MODULES="$MODULES $SRC/unix"
|
MODULES="$MODULES $SRC/unix"
|
||||||
INCLUDES="$INCLUDES -I$SRC/unix"
|
INCLUDES="$INCLUDES -I$SRC/unix"
|
||||||
;;
|
;;
|
||||||
|
@ -823,7 +823,7 @@ rm -f stella-conf*
|
||||||
if test "$_host_os" = darwin; then
|
if test "$_host_os" = darwin; then
|
||||||
cat <<EOI
|
cat <<EOI
|
||||||
|
|
||||||
WARNING: plain UNIX-style builds on OSX without XCode have degraded functionality
|
WARNING: plain UNIX-style builds on macOS without XCode have degraded functionality
|
||||||
and are unsupported. Continue on your own risk...
|
and are unsupported. Continue on your own risk...
|
||||||
EOI
|
EOI
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -744,7 +744,6 @@ that holds 'number of scanlines' on an actual console).</p>
|
||||||
<tr><td> _fcount</td><td> Number of frames since emulation started</td></tr>
|
<tr><td> _fcount</td><td> Number of frames since emulation started</td></tr>
|
||||||
<tr><td> _fcycles</td><td> Number of cycles since frame started</td></tr>
|
<tr><td> _fcycles</td><td> Number of cycles since frame started</td></tr>
|
||||||
<tr><td> _icycles</td><td> Number of cycles of last instruction</td></tr>
|
<tr><td> _icycles</td><td> Number of cycles of last instruction</td></tr>
|
||||||
<tr><td> _rwport</td><td> Last address to attempt a read from the cart write port</td></tr>
|
|
||||||
<tr><td> _scan</td><td> Current scanline count</td></tr>
|
<tr><td> _scan</td><td> Current scanline count</td></tr>
|
||||||
<tr><td> _scycles</td><td> Number of cycles in current scanline</td></tr>
|
<tr><td> _scycles</td><td> Number of cycles in current scanline</td></tr>
|
||||||
<tr><td> _vblank</td><td> Whether vertical blank is enabled (1 or 0)</td></tr>
|
<tr><td> _vblank</td><td> Whether vertical blank is enabled (1 or 0)</td></tr>
|
||||||
|
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 7.0 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 508 B After Width: | Height: | Size: 429 B |
Before Width: | Height: | Size: 788 B After Width: | Height: | Size: 534 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 856 B |
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 386 B After Width: | Height: | Size: 335 B |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 9.5 KiB |
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 9.8 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 7.5 KiB |
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 7.8 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 1.6 KiB |
|
@ -61,7 +61,7 @@
|
||||||
|
|
||||||
<br><br><br>
|
<br><br><br>
|
||||||
|
|
||||||
<center><b>February 1999 - TODO 2018</b></center>
|
<center><b>February 1999 - December 2018</b></center>
|
||||||
<center><b>The Stella Team</b></center>
|
<center><b>The Stella Team</b></center>
|
||||||
<center><b><a href="https://stella-emu.github.io">Stella Homepage</a></b></center>
|
<center><b><a href="https://stella-emu.github.io">Stella Homepage</a></b></center>
|
||||||
|
|
||||||
|
@ -358,7 +358,7 @@
|
||||||
<p>The Mac version of Stella is designed to work on an Apple Macintosh with
|
<p>The Mac version of Stella is designed to work on an Apple Macintosh with
|
||||||
the following:</p>
|
the following:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>MacOSX 10.7 (Lion) or above</li>
|
<li>macOS 10.7 or above</li>
|
||||||
<li>64-bit Intel processor</li>
|
<li>64-bit Intel processor</li>
|
||||||
<li>OpenGL capable video card</li>
|
<li>OpenGL capable video card</li>
|
||||||
<li>Xcode 8.0 is required to compile the Stella source code</li>
|
<li>Xcode 8.0 is required to compile the Stella source code</li>
|
||||||
|
@ -382,7 +382,7 @@
|
||||||
<h3><b><u>Other</u></b></h3>
|
<h3><b><u>Other</u></b></h3>
|
||||||
|
|
||||||
<p>Stella is extremely portable, and in its lifetime has been ported to almost every
|
<p>Stella is extremely portable, and in its lifetime has been ported to almost every
|
||||||
platform where the SDL library exists. It is 32/64-bit and endian clean in Linux/Unix, MacOSX
|
platform where the SDL library exists. It is 32/64-bit and endian clean in Linux/Unix, macOS
|
||||||
and Windows. The Stella Team is interested in hearing about any problems you may
|
and Windows. The Stella Team is interested in hearing about any problems you may
|
||||||
encounter with diverse operating systems and CPU types.</p>
|
encounter with diverse operating systems and CPU types.</p>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
@ -423,7 +423,7 @@
|
||||||
<p>
|
<p>
|
||||||
<h3><b><u>Macintosh</u></b></h3>
|
<h3><b><u>Macintosh</u></b></h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>Binary DMG file</b> (Stella-<i>release</i>-macosx.dmg)
|
<li><b>Binary DMG file</b> (Stella-<i>release</i>-macos.dmg)
|
||||||
<ul>
|
<ul>
|
||||||
<li>Double-click the disk image, open the 'Stella' folder, then copy the
|
<li>Double-click the disk image, open the 'Stella' folder, then copy the
|
||||||
<b>Stella.app</b> package to your 'Applications' folder.</li>
|
<b>Stella.app</b> package to your 'Applications' folder.</li>
|
||||||
|
@ -632,7 +632,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<th>Function</th>
|
<th>Function</th>
|
||||||
<th>Key (Standard)</th>
|
<th>Key (Standard)</th>
|
||||||
<th>Key (MacOSX)</th>
|
<th>Key (macOS)</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -1262,7 +1262,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<th>Function</th>
|
<th>Function</th>
|
||||||
<th>Key (Standard)</th>
|
<th>Key (Standard)</th>
|
||||||
<th>Key (MacOSX)</th>
|
<th>Key (macOS)</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Disable TV effects</td>
|
<td>Disable TV effects</td>
|
||||||
|
@ -1347,7 +1347,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<th>Function</th>
|
<th>Function</th>
|
||||||
<th>Key (Standard)</th>
|
<th>Key (Standard)</th>
|
||||||
<th>Key (MacOSX)</th>
|
<th>Key (macOS)</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -1483,7 +1483,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<th>Function</th>
|
<th>Function</th>
|
||||||
<th>Key (Standard)</th>
|
<th>Key (Standard)</th>
|
||||||
<th>Key (MacOSX)</th>
|
<th>Key (macOS)</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -2538,9 +2538,15 @@
|
||||||
<td><pre>-<plr.|dev.>tiadriven <1|0></pre></td>
|
<td><pre>-<plr.|dev.>tiadriven <1|0></pre></td>
|
||||||
<td>Set unused TIA pins to be randomly driven high or low on a read/peek.
|
<td>Set unused TIA pins to be randomly driven high or low on a read/peek.
|
||||||
If disabled, use the last databus value for those pins instead.</td>
|
If disabled, use the last databus value for those pins instead.</td>
|
||||||
|
</tr><tr>
|
||||||
|
<td><pre>-<plr.|dev.>rwportbreak <1|0></pre></td>
|
||||||
|
<td>Since the 2600 has no dedicated R/W line, different addresses are used
|
||||||
|
for RAM read or write access. If the code reads from such a write address, this causes
|
||||||
|
an unwanted, semi-random write to that address.
|
||||||
|
When this option is enabled, such reads interrupt emulation and the debugger is entered.</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><pre>-<plr.|dev.>thumb.trapfatal <1|0></pre></td>
|
<td><pre>-<plr.|dev.>thumb.trapfatal <1|0></pre></td>
|
||||||
<td>The default of true allows the Thumb ARM emulation to
|
<td>When enabled, this allows the Thumb ARM emulation to
|
||||||
throw an exception and enter the debugger on fatal errors. When disabled, such
|
throw an exception and enter the debugger on fatal errors. When disabled, such
|
||||||
fatal errors are simply logged, and emulation continues. Do not use this
|
fatal errors are simply logged, and emulation continues. Do not use this
|
||||||
unless you know exactly what you're doing, as it changes the behaviour as
|
unless you know exactly what you're doing, as it changes the behaviour as
|
||||||
|
@ -2651,7 +2657,7 @@
|
||||||
</table>
|
</table>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<p><b>TODO! Audio Settings</b> dialog:</p>
|
<p><b>Audio Settings</b> dialog:</p>
|
||||||
<table border="5" cellpadding="2" frame="box" rules="none">
|
<table border="5" cellpadding="2" frame="box" rules="none">
|
||||||
<tr>
|
<tr>
|
||||||
<td><img src="graphics/options_audio.png"></td>
|
<td><img src="graphics/options_audio.png"></td>
|
||||||
|
@ -2659,11 +2665,35 @@
|
||||||
<td valign="top">
|
<td valign="top">
|
||||||
<table border="1" cellpadding="4">
|
<table border="1" cellpadding="4">
|
||||||
<tr><th>Item</th><th>Brief description</th><th>For more information,<br>see <a href="#CommandLine">CommandLine</a></th></tr>
|
<tr><th>Item</th><th>Brief description</th><th>For more information,<br>see <a href="#CommandLine">CommandLine</a></th></tr>
|
||||||
<tr><td>Volume</td><td>Self-explanatory</td><td>-volume</td></tr>
|
<tr><td>Enable audio</td><td>Self-explanatory</td><td>-audio.enabled</td></tr>
|
||||||
<tr><td>Sample size (*)</td><td>Set size of audio buffers</td><td>-fragsize</td></tr>
|
<tr><td>Volume</td><td>Self-explanatory</td><td>-audio.volume</td></tr>
|
||||||
<tr><td>Frequency (*)</td><td>Change sound output frequency</td><td>-freq</td></tr>
|
<tr><td>Mode</td><td>Select an audio preset or choose 'custom' for manual configuration</td><td>-audio.preset</td></tr>
|
||||||
<tr><td>Enable sound</td><td>Self-explanatory</td><td>-sound</td></tr>
|
<tr><td>Fragment size</td><td>The number of samples in a single fragment processed by the audio driver. Smaller values mean less latency, but may lead to dropouts (depending on OS and hardware).</td><td>-audio.fragment_size</td></tr>
|
||||||
|
<tr><td>Sample rate</td><td>
|
||||||
|
Output samples per second. Higher values reduce artifacts from resampling and decrease latency,
|
||||||
|
but may lead to dropouts (depending on OS and hardware).
|
||||||
|
</td><td>-audio.sample_rate</td></tr>
|
||||||
|
<tr><td>Resampling quality</td><td>
|
||||||
|
Chooses the algorithm used for resampling (= converting TIA output to the target sample rate).
|
||||||
|
'High' and 'ultra' use a high-quality Lanczos filter
|
||||||
|
but require slightly more CPU, while 'low' may lead to audible screeching artifacts in
|
||||||
|
some games (notably Quadrun).
|
||||||
|
</td><td>-audio.resampling_quality</td></tr>
|
||||||
|
<tr><td>Headroom</td><td>Number of frames to buffer before playback starts. Higher values increase latency, but reduce the potential for dropouts.</td><td>-audio.headroom</td></tr>
|
||||||
|
<tr><td>Buffer size</td><td>Maximum size of the audio buffer. Higher values increase maximum latency, but reduce the potential for dropouts</td><td>-audio.buffer_size</td></tr>
|
||||||
</table>
|
</table>
|
||||||
|
<p>
|
||||||
|
<strong>IMPORTANT:</strong> In order to maintain a stable stream of audio data, emulation speed must be
|
||||||
|
synchronized with the audio hardware. Buffering happens in multiple places (OS = fragment size, Stella =
|
||||||
|
headroom and buffer size) and improves the tolerance to speed fluctuations, but introduces latency which
|
||||||
|
manifests as a lag between audio and video.
|
||||||
|
</p><p>
|
||||||
|
Too aggressive settings for your combination of hardware and software (high sample rate,
|
||||||
|
low fragment size, low headroom, low buffer size) may lead to audio dropouts whose effect may range from
|
||||||
|
isolated popping artifacts to garbled audio. You can check the system log for related messages. If you
|
||||||
|
get recurring messages about audio overruns and underruns (isolates underruns / overruns are normal
|
||||||
|
and a consequence of host system activity), you might have to adjust your settings.
|
||||||
|
</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
@ -3042,8 +3072,8 @@
|
||||||
|
|
||||||
<p>Note that you must use the entire name of the port as specified by
|
<p>Note that you must use the entire name of the port as specified by
|
||||||
your operating system. For example, in Windows this would be COM1,
|
your operating system. For example, in Windows this would be COM1,
|
||||||
COM2, etc.; Linux and MacOSX tend to use names similar to '/dev/xxxxxx'.
|
COM2, etc.; Linux and macOS tend to use names similar to '/dev/xxxxxx'.
|
||||||
For now, only Linux/UNIX, MacOSX, and Windows are supported.</p>
|
For now, only Linux/UNIX, macOS, and Windows are supported.</p>
|
||||||
|
|
||||||
<p>Support for the EEPROM portion of the AtariVox and SaveKey is currently
|
<p>Support for the EEPROM portion of the AtariVox and SaveKey is currently
|
||||||
emulated. That is, a file will be created on your computer simulating the
|
emulated. That is, a file will be created on your computer simulating the
|
||||||
|
@ -3110,6 +3140,11 @@
|
||||||
<tr><td>Randomize zero-page ...</td><td>When loading a ROM, randomize all RAM content instead of initializing with all zeroes (for 'Console' = 'Atari 2600' only)</td><td>-plr.ramrandom<br/>-dev.ramrandom</td></tr>
|
<tr><td>Randomize zero-page ...</td><td>When loading a ROM, randomize all RAM content instead of initializing with all zeroes (for 'Console' = 'Atari 2600' only)</td><td>-plr.ramrandom<br/>-dev.ramrandom</td></tr>
|
||||||
<tr><td>Randomize CPU</td><td>When loading a ROM, randomize the content of the specified CPU registers</td><td>-plr.cpurandom<br/>-dev.cpurandom</td></tr>
|
<tr><td>Randomize CPU</td><td>When loading a ROM, randomize the content of the specified CPU registers</td><td>-plr.cpurandom<br/>-dev.cpurandom</td></tr>
|
||||||
<tr><td>Drive unused TIA pins ...</td><td>Unused TIA pins are read random instead of the last databus values</td><td>-plr.tiadriven<br/>-dev.tiadriven</td></tr>
|
<tr><td>Drive unused TIA pins ...</td><td>Unused TIA pins are read random instead of the last databus values</td><td>-plr.tiadriven<br/>-dev.tiadriven</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>Break on reads from ...</td>
|
||||||
|
<td>A read from a write port interrupts emulation and the debugger is entered.</td>
|
||||||
|
<td><span style="white-space:nowrap">-plr.rwportbreak<br/>-dev.rwportbreak</span></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Fatal ARM emulation ...</td>
|
<td>Fatal ARM emulation ...</td>
|
||||||
<td>Thumb ARM emulation throws an exception and enters the debugger on fatal errors</td>
|
<td>Thumb ARM emulation throws an exception and enters the debugger on fatal errors</td>
|
||||||
|
|
|
@ -22,12 +22,11 @@
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
CheetahCheat::CheetahCheat(OSystem& os, const string& name, const string& code)
|
CheetahCheat::CheetahCheat(OSystem& os, const string& name, const string& code)
|
||||||
: Cheat(os, name, code)
|
: Cheat(os, name, code),
|
||||||
|
address(0xf000 + unhex(code.substr(0, 3))),
|
||||||
|
value(uInt8(unhex(code.substr(3, 2)))),
|
||||||
|
count(uInt8(unhex(code.substr(5, 1)) + 1))
|
||||||
{
|
{
|
||||||
address = 0xf000 + unhex(code.substr(0, 3));
|
|
||||||
value = uInt8(unhex(code.substr(3, 2)));
|
|
||||||
count = uInt8(unhex(code.substr(5, 1)) + 1);
|
|
||||||
|
|
||||||
// Back up original data; we need this if the cheat is ever disabled
|
// Back up original data; we need this if the cheat is ever disabled
|
||||||
for(int i = 0; i < count; ++i)
|
for(int i = 0; i < count; ++i)
|
||||||
savedRom[i] = myOSystem.console().cartridge().peek(address + i);
|
savedRom[i] = myOSystem.console().cartridge().peek(address + i);
|
||||||
|
|
|
@ -24,10 +24,10 @@
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
RamCheat::RamCheat(OSystem& os, const string& name, const string& code)
|
RamCheat::RamCheat(OSystem& os, const string& name, const string& code)
|
||||||
: Cheat(os, name, code)
|
: Cheat(os, name, code),
|
||||||
|
address(uInt16(unhex(myCode.substr(0, 2)))),
|
||||||
|
value(uInt8(unhex(myCode.substr(2, 2))))
|
||||||
{
|
{
|
||||||
address = uInt16(unhex(myCode.substr(0, 2)));
|
|
||||||
value = uInt8(unhex(myCode.substr(2, 2)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#define FSNODE_FACTORY_HXX
|
#define FSNODE_FACTORY_HXX
|
||||||
|
|
||||||
class AbstractFSNode;
|
class AbstractFSNode;
|
||||||
#if defined(BSPF_UNIX) || defined(BSPF_MAC_OSX)
|
#if defined(BSPF_UNIX) || defined(BSPF_MACOS)
|
||||||
#include "FSNodePOSIX.hxx"
|
#include "FSNodePOSIX.hxx"
|
||||||
#elif defined(BSPF_WINDOWS)
|
#elif defined(BSPF_WINDOWS)
|
||||||
#include "FSNodeWINDOWS.hxx"
|
#include "FSNodeWINDOWS.hxx"
|
||||||
|
@ -45,7 +45,7 @@ class FilesystemNodeFactory
|
||||||
switch(type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case SYSTEM:
|
case SYSTEM:
|
||||||
#if defined(BSPF_UNIX) || defined(BSPF_MAC_OSX)
|
#if defined(BSPF_UNIX) || defined(BSPF_MACOS)
|
||||||
return make_unique<FilesystemNodePOSIX>(path);
|
return make_unique<FilesystemNodePOSIX>(path);
|
||||||
#elif defined(BSPF_WINDOWS)
|
#elif defined(BSPF_WINDOWS)
|
||||||
return make_unique<FilesystemNodeWINDOWS>(path);
|
return make_unique<FilesystemNodeWINDOWS>(path);
|
||||||
|
|
|
@ -89,12 +89,12 @@ void FrameBufferSDL2::queryHardware(vector<GUI::Size>& displays,
|
||||||
|
|
||||||
// First get the maximum windowed desktop resolution
|
// First get the maximum windowed desktop resolution
|
||||||
int maxDisplays = SDL_GetNumVideoDisplays();
|
int maxDisplays = SDL_GetNumVideoDisplays();
|
||||||
#if 0 //def BSPF_MAC_OSX
|
#if SDL_VERSION_ATLEAST(2,0,5)
|
||||||
SDL_Rect r;
|
SDL_Rect r;
|
||||||
for(int i = 0; i < maxDisplays; ++i)
|
for(int i = 0; i < maxDisplays; ++i)
|
||||||
{
|
{
|
||||||
// Display bounds minus dock
|
// Display bounds minus dock
|
||||||
SDL_GetDisplayUsableBounds(i, &r); // Requires SDL-2.0.5 or higher
|
SDL_GetDisplayUsableBounds(i, &r); // Requires SDL-2.0.5 or higher
|
||||||
displays.emplace_back(r.w, r.h);
|
displays.emplace_back(r.w, r.h);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -105,7 +105,7 @@ void FrameBufferSDL2::queryHardware(vector<GUI::Size>& displays,
|
||||||
displays.emplace_back(display.w, display.h);
|
displays.emplace_back(display.w, display.h);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct RenderName
|
struct RenderName
|
||||||
{
|
{
|
||||||
string sdlName;
|
string sdlName;
|
||||||
|
@ -189,12 +189,12 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode)
|
||||||
: SDL_WINDOWPOS_UNDEFINED_DISPLAY(displayIndex);
|
: SDL_WINDOWPOS_UNDEFINED_DISPLAY(displayIndex);
|
||||||
uInt32 flags = mode.fsIndex != -1 ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0;
|
uInt32 flags = mode.fsIndex != -1 ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0;
|
||||||
|
|
||||||
// OSX seems to have issues with destroying the window, and wants to keep
|
// macOS seems to have issues with destroying the window, and wants to
|
||||||
// the same handle
|
// keep the same handle
|
||||||
// Problem is, doing so on other platforms results in flickering when
|
// Problem is, doing so on other platforms results in flickering when
|
||||||
// toggling fullscreen windowed mode
|
// toggling fullscreen windowed mode
|
||||||
// So we have a special case for OSX
|
// So we have a special case for macOS
|
||||||
#ifndef BSPF_MAC_OSX
|
#ifndef BSPF_MACOS
|
||||||
// Don't re-create the window if its size hasn't changed, as it's not
|
// Don't re-create the window if its size hasn't changed, as it's not
|
||||||
// necessary, and causes flashing in fullscreen mode
|
// necessary, and causes flashing in fullscreen mode
|
||||||
if(myWindow)
|
if(myWindow)
|
||||||
|
@ -213,7 +213,7 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode)
|
||||||
SDL_SetWindowTitle(myWindow, title.c_str());
|
SDL_SetWindowTitle(myWindow, title.c_str());
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
// OSX wants to *never* re-create the window
|
// macOS wants to *never* re-create the window
|
||||||
// This sometimes results in the window being resized *after* it's displayed,
|
// This sometimes results in the window being resized *after* it's displayed,
|
||||||
// but at least the code works and doesn't crash
|
// but at least the code works and doesn't crash
|
||||||
if(myWindow)
|
if(myWindow)
|
||||||
|
@ -346,7 +346,7 @@ void FrameBufferSDL2::setWindowIcon()
|
||||||
{
|
{
|
||||||
ASSERT_MAIN_THREAD;
|
ASSERT_MAIN_THREAD;
|
||||||
|
|
||||||
#ifndef BSPF_MAC_OSX // Currently not needed for OSX
|
#ifndef BSPF_MACOS // Currently not needed for macOS
|
||||||
#include "stella_icon.hxx" // The Stella icon
|
#include "stella_icon.hxx" // The Stella icon
|
||||||
|
|
||||||
SDL_Surface* surface = SDL_CreateRGBSurfaceFrom(stella_icon, 32, 32, 32,
|
SDL_Surface* surface = SDL_CreateRGBSurfaceFrom(stella_icon, 32, 32, 32,
|
||||||
|
|
|
@ -32,10 +32,10 @@
|
||||||
#include "SerialPortWINDOWS.hxx"
|
#include "SerialPortWINDOWS.hxx"
|
||||||
#include "SettingsWINDOWS.hxx"
|
#include "SettingsWINDOWS.hxx"
|
||||||
#include "OSystemWINDOWS.hxx"
|
#include "OSystemWINDOWS.hxx"
|
||||||
#elif defined(BSPF_MAC_OSX)
|
#elif defined(BSPF_MACOS)
|
||||||
#include "SerialPortMACOSX.hxx"
|
#include "SerialPortMACOS.hxx"
|
||||||
#include "SettingsMACOSX.hxx"
|
#include "SettingsMACOS.hxx"
|
||||||
#include "OSystemMACOSX.hxx"
|
#include "OSystemMACOS.hxx"
|
||||||
extern "C" {
|
extern "C" {
|
||||||
int stellaMain(int argc, char* argv[]);
|
int stellaMain(int argc, char* argv[]);
|
||||||
}
|
}
|
||||||
|
@ -73,8 +73,8 @@ class MediaFactory
|
||||||
return make_unique<OSystemUNIX>();
|
return make_unique<OSystemUNIX>();
|
||||||
#elif defined(BSPF_WINDOWS)
|
#elif defined(BSPF_WINDOWS)
|
||||||
return make_unique<OSystemWINDOWS>();
|
return make_unique<OSystemWINDOWS>();
|
||||||
#elif defined(BSPF_MAC_OSX)
|
#elif defined(BSPF_MACOS)
|
||||||
return make_unique<OSystemMACOSX>();
|
return make_unique<OSystemMACOS>();
|
||||||
#else
|
#else
|
||||||
#error Unsupported platform for OSystem!
|
#error Unsupported platform for OSystem!
|
||||||
#endif
|
#endif
|
||||||
|
@ -86,8 +86,8 @@ class MediaFactory
|
||||||
return make_unique<SettingsUNIX>(osystem);
|
return make_unique<SettingsUNIX>(osystem);
|
||||||
#elif defined(BSPF_WINDOWS)
|
#elif defined(BSPF_WINDOWS)
|
||||||
return make_unique<SettingsWINDOWS>(osystem);
|
return make_unique<SettingsWINDOWS>(osystem);
|
||||||
#elif defined(BSPF_MAC_OSX)
|
#elif defined(BSPF_MACOS)
|
||||||
return make_unique<SettingsMACOSX>(osystem);
|
return make_unique<SettingsMACOS>(osystem);
|
||||||
#else
|
#else
|
||||||
#error Unsupported platform for Settings!
|
#error Unsupported platform for Settings!
|
||||||
#endif
|
#endif
|
||||||
|
@ -99,8 +99,8 @@ class MediaFactory
|
||||||
return make_unique<SerialPortUNIX>();
|
return make_unique<SerialPortUNIX>();
|
||||||
#elif defined(BSPF_WINDOWS)
|
#elif defined(BSPF_WINDOWS)
|
||||||
return make_unique<SerialPortWINDOWS>();
|
return make_unique<SerialPortWINDOWS>();
|
||||||
#elif defined(BSPF_MAC_OSX)
|
#elif defined(BSPF_MACOS)
|
||||||
return make_unique<SerialPortMACOSX>();
|
return make_unique<SerialPortMACOS>();
|
||||||
#else
|
#else
|
||||||
return make_unique<SerialPort>();
|
return make_unique<SerialPort>();
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -259,7 +259,7 @@ void PhysicalKeyboardHandler::handleEvent(StellaKey key, StellaMod mod, bool sta
|
||||||
// Control or Alt/Cmd combos first
|
// Control or Alt/Cmd combos first
|
||||||
if(StellaModTest::isAlt(mod) && state)
|
if(StellaModTest::isAlt(mod) && state)
|
||||||
{
|
{
|
||||||
#ifdef BSPF_MAC_OSX
|
#ifdef BSPF_MACOS
|
||||||
// These keys work in all states
|
// These keys work in all states
|
||||||
if(key == KBDK_Q)
|
if(key == KBDK_Q)
|
||||||
{
|
{
|
||||||
|
|
|
@ -142,7 +142,7 @@ void PNGLibrary::saveImage(const string& filename, const VariantList& comments)
|
||||||
rows[k] = png_bytep(buffer.get() + k*width*4);
|
rows[k] = png_bytep(buffer.get() + k*width*4);
|
||||||
|
|
||||||
// And save the image
|
// And save the image
|
||||||
saveImage(out, rows, width, height, comments);
|
saveImageToDisk(out, rows, width, height, comments);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -171,11 +171,11 @@ void PNGLibrary::saveImage(const string& filename, const FBSurface& surface,
|
||||||
rows[k] = png_bytep(buffer.get() + k*width*4);
|
rows[k] = png_bytep(buffer.get() + k*width*4);
|
||||||
|
|
||||||
// And save the image
|
// And save the image
|
||||||
saveImage(out, rows, width, height, comments);
|
saveImageToDisk(out, rows, width, height, comments);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void PNGLibrary::saveImage(ofstream& out, const unique_ptr<png_bytep[]>& rows,
|
void PNGLibrary::saveImageToDisk(ofstream& out, const unique_ptr<png_bytep[]>& rows,
|
||||||
png_uint_32 width, png_uint_32 height, const VariantList& comments)
|
png_uint_32 width, png_uint_32 height, const VariantList& comments)
|
||||||
{
|
{
|
||||||
#define saveImageERROR(s) { err_message = s; goto done; }
|
#define saveImageERROR(s) { err_message = s; goto done; }
|
||||||
|
@ -359,7 +359,7 @@ void PNGLibrary::takeSnapshot(uInt32 number)
|
||||||
{
|
{
|
||||||
// Make sure we have a 'clean' image, with no onscreen messages
|
// Make sure we have a 'clean' image, with no onscreen messages
|
||||||
myOSystem.frameBuffer().enableMessages(false);
|
myOSystem.frameBuffer().enableMessages(false);
|
||||||
myOSystem.frameBuffer().tiaSurface().reRender();
|
myOSystem.frameBuffer().tiaSurface().renderForSnapshot();
|
||||||
|
|
||||||
string message = "Snapshot saved";
|
string message = "Snapshot saved";
|
||||||
try
|
try
|
||||||
|
|
|
@ -114,6 +114,9 @@ class PNGLibrary
|
||||||
void setContinuousSnapInterval(uInt32 interval);
|
void setContinuousSnapInterval(uInt32 interval);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
NOTE: This method will be made private soon, so all calls from
|
||||||
|
external code should be refactored
|
||||||
|
|
||||||
Create a new snapshot based on the name of the ROM, and also
|
Create a new snapshot based on the name of the ROM, and also
|
||||||
optionally using the number given as a parameter.
|
optionally using the number given as a parameter.
|
||||||
|
|
||||||
|
@ -161,9 +164,9 @@ class PNGLibrary
|
||||||
@param height The height of the PNG image
|
@param height The height of the PNG image
|
||||||
@param comments The text comments to add to the PNG image
|
@param comments The text comments to add to the PNG image
|
||||||
*/
|
*/
|
||||||
void saveImage(ofstream& out, const unique_ptr<png_bytep[]>& rows,
|
void saveImageToDisk(ofstream& out, const unique_ptr<png_bytep[]>& rows,
|
||||||
png_uint_32 width, png_uint_32 height,
|
png_uint_32 width, png_uint_32 height,
|
||||||
const VariantList& comments);
|
const VariantList& comments);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Load the PNG data from 'ReadInfo' into the FBSurface. The surface
|
Load the PNG data from 'ReadInfo' into the FBSurface. The surface
|
||||||
|
|
|
@ -305,7 +305,7 @@ void SoundSDL2::initResampler()
|
||||||
return nextFragment;
|
return nextFragment;
|
||||||
};
|
};
|
||||||
|
|
||||||
StaggeredLogger::Logger logger = [this](string msg) { myOSystem.logMessage(msg, 0); };
|
StaggeredLogger::Logger logger = [this](string msg) { myOSystem.logMessage(msg, 1); };
|
||||||
|
|
||||||
Resampler::Format formatFrom =
|
Resampler::Format formatFrom =
|
||||||
Resampler::Format(myEmulationTiming->audioSampleRate(), myAudioQueue->fragmentSize(), myAudioQueue->isStereo());
|
Resampler::Format(myEmulationTiming->audioSampleRate(), myAudioQueue->fragmentSize(), myAudioQueue->isStereo());
|
||||||
|
|
|
@ -42,13 +42,35 @@ StaggeredLogger::StaggeredLogger(const string& message, Logger logger)
|
||||||
myCurrentIntervalSize(100),
|
myCurrentIntervalSize(100),
|
||||||
myMaxIntervalFactor(9),
|
myMaxIntervalFactor(9),
|
||||||
myCurrentIntervalFactor(1),
|
myCurrentIntervalFactor(1),
|
||||||
myCooldownTime(1000)
|
myCooldownTime(1000),
|
||||||
|
myTimer(new TimerManager()),
|
||||||
|
myTimerCallbackId(0)
|
||||||
{
|
{
|
||||||
if (logger) myLogger = logger;
|
if (logger) myLogger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
StaggeredLogger::~StaggeredLogger()
|
||||||
|
{
|
||||||
|
myTimer->clear(myTimerId);
|
||||||
|
|
||||||
|
// make sure that the worker thread joins before continuing with the destruction
|
||||||
|
delete myTimer;
|
||||||
|
|
||||||
|
// the worker thread has joined and there will be no more reentrant calls ->
|
||||||
|
// continue with destruction
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void StaggeredLogger::setLogger(Logger logger)
|
void StaggeredLogger::setLogger(Logger logger)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(myMutex);
|
||||||
|
|
||||||
|
_setLogger(logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void StaggeredLogger::_setLogger(Logger logger)
|
||||||
{
|
{
|
||||||
myLogger = logger;
|
myLogger = logger;
|
||||||
}
|
}
|
||||||
|
@ -61,45 +83,32 @@ void StaggeredLogger::log()
|
||||||
_log();
|
_log();
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
void StaggeredLogger::advance()
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(myMutex);
|
|
||||||
|
|
||||||
_advance();
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void StaggeredLogger::_log()
|
void StaggeredLogger::_log()
|
||||||
{
|
{
|
||||||
_advance();
|
if (!myIsCurrentlyCollecting) startInterval();
|
||||||
|
|
||||||
if (!myIsCurrentlyCollecting) {
|
++myCurrentEventCount;
|
||||||
myCurrentEventCount = 0;
|
|
||||||
myIsCurrentlyCollecting = true;
|
|
||||||
myCurrentIntervalStartTimestamp = high_resolution_clock::now();
|
|
||||||
}
|
|
||||||
|
|
||||||
myCurrentEventCount++;
|
|
||||||
myLastLogEventTimestamp = high_resolution_clock::now();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void StaggeredLogger::logLine()
|
void StaggeredLogger::logLine()
|
||||||
{
|
{
|
||||||
|
if (!myLogger) return;
|
||||||
|
|
||||||
|
high_resolution_clock::time_point now = high_resolution_clock::now();
|
||||||
|
Int64 millisecondsSinceIntervalStart =
|
||||||
|
duration_cast<duration<Int64, std::milli>>(now - myLastIntervalStartTimestamp).count();
|
||||||
|
|
||||||
stringstream ss;
|
stringstream ss;
|
||||||
ss
|
ss
|
||||||
<< currentTimestamp() << ": "
|
<< currentTimestamp() << ": "
|
||||||
<< myMessage
|
<< myMessage
|
||||||
<< " (" << myCurrentEventCount << " times in "
|
<< " (" << myCurrentEventCount << " times in "
|
||||||
<< myCurrentIntervalSize << " milliseconds"
|
<< millisecondsSinceIntervalStart << " milliseconds"
|
||||||
<< ")";
|
<< ")";
|
||||||
|
|
||||||
myLogger(ss.str());
|
myLogger(ss.str());
|
||||||
|
|
||||||
myIsCurrentlyCollecting = false;
|
|
||||||
|
|
||||||
increaseInterval();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -107,7 +116,7 @@ void StaggeredLogger::increaseInterval()
|
||||||
{
|
{
|
||||||
if (myCurrentIntervalFactor >= myMaxIntervalFactor) return;
|
if (myCurrentIntervalFactor >= myMaxIntervalFactor) return;
|
||||||
|
|
||||||
myCurrentIntervalFactor++;
|
++myCurrentIntervalFactor;
|
||||||
myCurrentIntervalSize *= 2;
|
myCurrentIntervalSize *= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,27 +125,44 @@ void StaggeredLogger::decreaseInterval()
|
||||||
{
|
{
|
||||||
if (myCurrentIntervalFactor <= 1) return;
|
if (myCurrentIntervalFactor <= 1) return;
|
||||||
|
|
||||||
myCurrentIntervalFactor--;
|
--myCurrentIntervalFactor;
|
||||||
myCurrentIntervalSize /= 2;
|
myCurrentIntervalSize /= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void StaggeredLogger::_advance()
|
void StaggeredLogger::startInterval()
|
||||||
{
|
{
|
||||||
|
if (myIsCurrentlyCollecting) return;
|
||||||
|
|
||||||
|
myIsCurrentlyCollecting = true;
|
||||||
|
|
||||||
high_resolution_clock::time_point now = high_resolution_clock::now();
|
high_resolution_clock::time_point now = high_resolution_clock::now();
|
||||||
|
Int64 msecSinceLastIntervalEnd =
|
||||||
|
duration_cast<duration<Int64, std::milli>>(now - myLastIntervalEndTimestamp).count();
|
||||||
|
|
||||||
if (myIsCurrentlyCollecting) {
|
while (msecSinceLastIntervalEnd > myCooldownTime && myCurrentIntervalFactor > 1) {
|
||||||
Int64 msecSinceIntervalStart =
|
msecSinceLastIntervalEnd -= myCooldownTime;
|
||||||
duration_cast<duration<Int64, std::milli>>(now - myCurrentIntervalStartTimestamp).count();
|
|
||||||
|
|
||||||
if (msecSinceIntervalStart > myCurrentIntervalSize) logLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
Int64 msec =
|
|
||||||
duration_cast<duration<Int64, std::milli>>(now - myLastLogEventTimestamp).count();
|
|
||||||
|
|
||||||
while (msec > myCooldownTime && myCurrentIntervalFactor > 1) {
|
|
||||||
msec -= myCooldownTime;
|
|
||||||
decreaseInterval();
|
decreaseInterval();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
myCurrentEventCount = 0;
|
||||||
|
myLastIntervalStartTimestamp = now;
|
||||||
|
|
||||||
|
myTimer->clear(myTimerId);
|
||||||
|
myTimerId = myTimer->setTimeout(std::bind(&StaggeredLogger::onTimerExpired, this, ++myTimerCallbackId), myCurrentIntervalSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void StaggeredLogger::onTimerExpired(uInt32 timerCallbackId)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(myMutex);
|
||||||
|
|
||||||
|
if (timerCallbackId != myTimerCallbackId) return;
|
||||||
|
|
||||||
|
logLine();
|
||||||
|
|
||||||
|
myIsCurrentlyCollecting = false;
|
||||||
|
increaseInterval();
|
||||||
|
|
||||||
|
myLastIntervalEndTimestamp = high_resolution_clock::now();
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,9 +21,10 @@
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
|
#include "TimerManager.hxx"
|
||||||
/**
|
/**
|
||||||
* This class buffers log events and logs them after a certain time window has expired.
|
* This class buffers log events and logs them after a certain time window has expired.
|
||||||
* The timout increases after every log line by a factor of two until a maximum is reached.
|
* The timout increases after every log line by a factor of two until a maximum is reached.
|
||||||
|
@ -39,9 +40,9 @@ class StaggeredLogger {
|
||||||
|
|
||||||
StaggeredLogger(const string& message, Logger logger = Logger());
|
StaggeredLogger(const string& message, Logger logger = Logger());
|
||||||
|
|
||||||
void log();
|
~StaggeredLogger();
|
||||||
|
|
||||||
void advance();
|
void log();
|
||||||
|
|
||||||
void setLogger(Logger logger);
|
void setLogger(Logger logger);
|
||||||
|
|
||||||
|
@ -49,7 +50,11 @@ class StaggeredLogger {
|
||||||
|
|
||||||
void _log();
|
void _log();
|
||||||
|
|
||||||
void _advance();
|
void _setLogger(Logger logger);
|
||||||
|
|
||||||
|
void onTimerExpired(uInt32 timerId);
|
||||||
|
|
||||||
|
void startInterval();
|
||||||
|
|
||||||
void increaseInterval();
|
void increaseInterval();
|
||||||
|
|
||||||
|
@ -63,8 +68,8 @@ class StaggeredLogger {
|
||||||
uInt32 myCurrentEventCount;
|
uInt32 myCurrentEventCount;
|
||||||
bool myIsCurrentlyCollecting;
|
bool myIsCurrentlyCollecting;
|
||||||
|
|
||||||
std::chrono::high_resolution_clock::time_point myCurrentIntervalStartTimestamp;
|
std::chrono::high_resolution_clock::time_point myLastIntervalStartTimestamp;
|
||||||
std::chrono::high_resolution_clock::time_point myLastLogEventTimestamp;
|
std::chrono::high_resolution_clock::time_point myLastIntervalEndTimestamp;
|
||||||
|
|
||||||
uInt32 myCurrentIntervalSize;
|
uInt32 myCurrentIntervalSize;
|
||||||
uInt32 myMaxIntervalFactor;
|
uInt32 myMaxIntervalFactor;
|
||||||
|
@ -72,6 +77,17 @@ class StaggeredLogger {
|
||||||
uInt32 myCooldownTime;
|
uInt32 myCooldownTime;
|
||||||
|
|
||||||
std::mutex myMutex;
|
std::mutex myMutex;
|
||||||
|
|
||||||
|
// We need control over the destruction porcess and over the exact point where
|
||||||
|
// the worker thread joins -> allocate on the heap end delete explicitly in
|
||||||
|
// our destructor.
|
||||||
|
TimerManager *myTimer;
|
||||||
|
TimerManager::TimerId myTimerId;
|
||||||
|
|
||||||
|
// It is possible that the timer callback is running even after TimerManager::clear
|
||||||
|
// returns. This id is unique per timer and is used to return from the callback
|
||||||
|
// early in case the time is stale.
|
||||||
|
uInt32 myTimerCallbackId;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // STAGGERED_LOGGER
|
#endif // STAGGERED_LOGGER
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
#include "StateManager.hxx"
|
#include "StateManager.hxx"
|
||||||
|
|
||||||
#define STATE_HEADER "05099200state"
|
#define STATE_HEADER "06000000state"
|
||||||
// #define MOVIE_HEADER "03030000movie"
|
// #define MOVIE_HEADER "03030000movie"
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
|
@ -417,7 +417,7 @@ namespace StellaModTest
|
||||||
{
|
{
|
||||||
inline bool isAlt(int mod)
|
inline bool isAlt(int mod)
|
||||||
{
|
{
|
||||||
#if defined(BSPF_MAC_OSX) || defined(OSX_KEYS)
|
#if defined(BSPF_MACOS) || defined(MACOS_KEYS)
|
||||||
return (mod & KBDM_GUI);
|
return (mod & KBDM_GUI);
|
||||||
#else
|
#else
|
||||||
return (mod & KBDM_ALT);
|
return (mod & KBDM_ALT);
|
||||||
|
|
|
@ -20,7 +20,8 @@
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
ThreadDebuggingHelper::ThreadDebuggingHelper()
|
ThreadDebuggingHelper::ThreadDebuggingHelper()
|
||||||
: myMainThreadIdConfigured(false)
|
: myMainThreadIdConfigured(false)
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
ThreadDebuggingHelper& ThreadDebuggingHelper::instance()
|
ThreadDebuggingHelper& ThreadDebuggingHelper::instance()
|
||||||
|
|
|
@ -46,7 +46,7 @@ class ThreadDebuggingHelper {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void fail(const string& message);
|
[[noreturn]] void fail(const string& message);
|
||||||
|
|
||||||
ThreadDebuggingHelper();
|
ThreadDebuggingHelper();
|
||||||
|
|
||||||
|
|
|
@ -57,8 +57,20 @@ class Variant
|
||||||
// Conversion methods
|
// Conversion methods
|
||||||
const string& toString() const { return data; }
|
const string& toString() const { return data; }
|
||||||
const char* const toCString() const { return data.c_str(); }
|
const char* const toCString() const { return data.c_str(); }
|
||||||
const Int32 toInt() const { return atoi(data.c_str()); }
|
const Int32 toInt() const {
|
||||||
const float toFloat() const { return float(atof(data.c_str())); }
|
istringstream ss(data);
|
||||||
|
Int32 parsed;
|
||||||
|
ss >> parsed;
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
const float toFloat() const {
|
||||||
|
istringstream ss(data);
|
||||||
|
float parsed;
|
||||||
|
ss >> parsed;
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
const bool toBool() const { return data == "1" || data == "true"; }
|
const bool toBool() const { return data == "1" || data == "true"; }
|
||||||
const GUI::Size toSize() const { return GUI::Size(data); }
|
const GUI::Size toSize() const { return GUI::Size(data); }
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
#ifndef VERSION_HXX
|
#ifndef VERSION_HXX
|
||||||
#define VERSION_HXX
|
#define VERSION_HXX
|
||||||
|
|
||||||
#define STELLA_VERSION "6.0_beta2"
|
#define STELLA_VERSION "6.0"
|
||||||
#define STELLA_BUILD "4603"
|
#define STELLA_BUILD "4667"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -90,7 +90,7 @@ static const string EmptyString("");
|
||||||
namespace BSPF
|
namespace BSPF
|
||||||
{
|
{
|
||||||
// Defines to help with path handling
|
// Defines to help with path handling
|
||||||
#if defined(BSPF_UNIX) || defined(BSPF_MAC_OSX)
|
#if defined(BSPF_UNIX) || defined(BSPF_MACOS)
|
||||||
static const string PATH_SEPARATOR = "/";
|
static const string PATH_SEPARATOR = "/";
|
||||||
#define ATTRIBUTE_FMT_PRINTF __attribute__((__format__ (__printf__, 2, 0)))
|
#define ATTRIBUTE_FMT_PRINTF __attribute__((__format__ (__printf__, 2, 0)))
|
||||||
#elif defined(BSPF_WINDOWS)
|
#elif defined(BSPF_WINDOWS)
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "OSystem.hxx"
|
#include "OSystem.hxx"
|
||||||
#include "PNGLibrary.hxx"
|
#include "PNGLibrary.hxx"
|
||||||
#include "System.hxx"
|
#include "System.hxx"
|
||||||
|
#include "TIASurface.hxx"
|
||||||
|
|
||||||
#include "ThreadDebugging.hxx"
|
#include "ThreadDebugging.hxx"
|
||||||
|
|
||||||
|
@ -43,7 +44,7 @@
|
||||||
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
#if defined(BSPF_MAC_OSX)
|
#if defined(BSPF_MACOS)
|
||||||
int stellaMain(int argc, char* argv[])
|
int stellaMain(int argc, char* argv[])
|
||||||
#else
|
#else
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
|
@ -137,12 +138,16 @@ int main(int argc, char* argv[])
|
||||||
if(result != EmptyString)
|
if(result != EmptyString)
|
||||||
return Cleanup();
|
return Cleanup();
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
TODO: Fix this to use functionality from OSystem::mainLoop
|
||||||
if(theOSystem->settings().getBool("takesnapshot"))
|
if(theOSystem->settings().getBool("takesnapshot"))
|
||||||
{
|
{
|
||||||
for(int i = 0; i < 30; ++i) theOSystem->frameBuffer().update();
|
for(int i = 0; i < 30; ++i) theOSystem->frameBuffer().update();
|
||||||
|
// theOSystem->frameBuffer().tiaSurface().saveSnapShot();
|
||||||
theOSystem->png().takeSnapshot();
|
theOSystem->png().takeSnapshot();
|
||||||
return Cleanup();
|
return Cleanup();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
catch(const runtime_error& e)
|
catch(const runtime_error& e)
|
||||||
{
|
{
|
||||||
|
|
|
@ -32,6 +32,8 @@
|
||||||
#include "CartRamWidget.hxx"
|
#include "CartRamWidget.hxx"
|
||||||
#include "RomWidget.hxx"
|
#include "RomWidget.hxx"
|
||||||
#include "Base.hxx"
|
#include "Base.hxx"
|
||||||
|
#include "exception/EmulationWarning.hxx"
|
||||||
|
|
||||||
using Common::Base;
|
using Common::Base;
|
||||||
using std::hex;
|
using std::hex;
|
||||||
using std::dec;
|
using std::dec;
|
||||||
|
@ -46,7 +48,6 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem)
|
||||||
myOSystem(osystem),
|
myOSystem(osystem),
|
||||||
myDebugWidget(nullptr),
|
myDebugWidget(nullptr),
|
||||||
myAddrToLineIsROM(true),
|
myAddrToLineIsROM(true),
|
||||||
myRWPortAddress(0),
|
|
||||||
myLabelLength(8) // longest pre-defined label
|
myLabelLength(8) // longest pre-defined label
|
||||||
{
|
{
|
||||||
// Add case sensitive compare for user labels
|
// Add case sensitive compare for user labels
|
||||||
|
@ -158,30 +159,6 @@ void CartDebug::saveOldState()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
void CartDebug::triggerReadFromWritePort(uInt16 addr)
|
|
||||||
{
|
|
||||||
myRWPortAddress = addr;
|
|
||||||
mySystem.setDirtyPage(addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
int CartDebug::readFromWritePort()
|
|
||||||
{
|
|
||||||
uInt16 addr = myRWPortAddress;
|
|
||||||
myRWPortAddress = 0;
|
|
||||||
|
|
||||||
// A read from the write port occurs when the read is actually in the write
|
|
||||||
// port address space AND the last access was actually a read (the latter
|
|
||||||
// differentiates between reads that are normally part of a write cycle vs.
|
|
||||||
// ones that are illegal)
|
|
||||||
if(mySystem.m6502().lastReadAddress() &&
|
|
||||||
(mySystem.getPageAccessType(addr) & System::PA_WRITE) == System::PA_WRITE)
|
|
||||||
return addr;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
int CartDebug::lastReadBaseAddress()
|
int CartDebug::lastReadBaseAddress()
|
||||||
{
|
{
|
||||||
|
|
|
@ -109,14 +109,6 @@ class CartDebug : public DebuggerSystem
|
||||||
CartDebugWidget* getDebugWidget() const { return myDebugWidget; }
|
CartDebugWidget* getDebugWidget() const { return myDebugWidget; }
|
||||||
void setDebugWidget(CartDebugWidget* w) { myDebugWidget = w; }
|
void setDebugWidget(CartDebugWidget* w) { myDebugWidget = w; }
|
||||||
|
|
||||||
// Indicate that a read from write port has occurred at the specified
|
|
||||||
// address.
|
|
||||||
void triggerReadFromWritePort(uInt16 address);
|
|
||||||
|
|
||||||
// Return the address at which an invalid read was performed in a
|
|
||||||
// write port area.
|
|
||||||
int readFromWritePort();
|
|
||||||
|
|
||||||
// Return the base (= non-mirrored) address of the last CPU read
|
// Return the base (= non-mirrored) address of the last CPU read
|
||||||
int lastReadBaseAddress();
|
int lastReadBaseAddress();
|
||||||
// Return the base (= non-mirrored) address of the last CPU write
|
// Return the base (= non-mirrored) address of the last CPU write
|
||||||
|
@ -353,10 +345,6 @@ class CartDebug : public DebuggerSystem
|
||||||
// handled differently
|
// handled differently
|
||||||
LabelToAddr mySystemAddresses;
|
LabelToAddr mySystemAddresses;
|
||||||
|
|
||||||
// Holds address at which the most recent read from a write port
|
|
||||||
// occurred
|
|
||||||
uInt16 myRWPortAddress;
|
|
||||||
|
|
||||||
// The maximum length of all labels currently defined
|
// The maximum length of all labels currently defined
|
||||||
uInt16 myLabelLength;
|
uInt16 myLabelLength;
|
||||||
|
|
||||||
|
|
|
@ -836,7 +836,6 @@ Debugger::PseudoRegister Debugger::ourPseudoRegisters[NUM_PSEUDO_REGS] = {
|
||||||
{ "_fcount", "Number of frames since emulation started" },
|
{ "_fcount", "Number of frames since emulation started" },
|
||||||
{ "_fcycles", "Number of cycles since frame started" },
|
{ "_fcycles", "Number of cycles since frame started" },
|
||||||
{ "_icycles", "Number of cycles of last instruction" },
|
{ "_icycles", "Number of cycles of last instruction" },
|
||||||
{ "_rwport", "Address at which a read from a write port occurred" },
|
|
||||||
{ "_scan", "Current scanline count" },
|
{ "_scan", "Current scanline count" },
|
||||||
{ "_scycles", "Number of cycles in current scanline" },
|
{ "_scycles", "Number of cycles in current scanline" },
|
||||||
{ "_vblank", "Whether vertical blank is enabled (1 or 0)" },
|
{ "_vblank", "Whether vertical blank is enabled (1 or 0)" },
|
||||||
|
|
|
@ -324,7 +324,7 @@ class Debugger : public DialogContainer
|
||||||
string name, help;
|
string name, help;
|
||||||
};
|
};
|
||||||
static const uInt32 NUM_BUILTIN_FUNCS = 18;
|
static const uInt32 NUM_BUILTIN_FUNCS = 18;
|
||||||
static const uInt32 NUM_PSEUDO_REGS = 12;
|
static const uInt32 NUM_PSEUDO_REGS = 11;
|
||||||
static BuiltinFunction ourBuiltinFunctions[NUM_BUILTIN_FUNCS];
|
static BuiltinFunction ourBuiltinFunctions[NUM_BUILTIN_FUNCS];
|
||||||
static PseudoRegister ourPseudoRegisters[NUM_PSEUDO_REGS];
|
static PseudoRegister ourPseudoRegisters[NUM_PSEUDO_REGS];
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#include "Settings.hxx"
|
#include "Settings.hxx"
|
||||||
#include "System.hxx"
|
#include "System.hxx"
|
||||||
|
#include "MD5.hxx"
|
||||||
#ifdef DEBUGGER_SUPPORT
|
#ifdef DEBUGGER_SUPPORT
|
||||||
#include "Debugger.hxx"
|
#include "Debugger.hxx"
|
||||||
#include "CartDebug.hxx"
|
#include "CartDebug.hxx"
|
||||||
|
@ -25,13 +26,24 @@
|
||||||
#include "Cart.hxx"
|
#include "Cart.hxx"
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
Cartridge::Cartridge(const Settings& settings)
|
Cartridge::Cartridge(const Settings& settings, const string& md5)
|
||||||
: mySettings(settings),
|
: mySettings(settings),
|
||||||
myBankChanged(true),
|
myBankChanged(true),
|
||||||
myCodeAccessBase(nullptr),
|
myCodeAccessBase(nullptr),
|
||||||
myStartBank(0),
|
myStartBank(0),
|
||||||
myBankLocked(false)
|
myBankLocked(false)
|
||||||
{
|
{
|
||||||
|
auto to_uInt32 = [](const string& s, uInt32 pos) {
|
||||||
|
return uInt32(std::stoul(s.substr(pos, 8), nullptr, 16));
|
||||||
|
};
|
||||||
|
|
||||||
|
uInt32 seed = to_uInt32(md5, 0) ^ to_uInt32(md5, 8) ^
|
||||||
|
to_uInt32(md5, 16) ^ to_uInt32(md5, 24);
|
||||||
|
Random rand(seed);
|
||||||
|
for(uInt32 i = 0; i < 256; ++i)
|
||||||
|
myRWPRandomValues[i] = rand.next();
|
||||||
|
|
||||||
|
myRAMAccesses.reserve(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -69,12 +81,40 @@ bool Cartridge::bankChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Cartridge::triggerReadFromWritePort(uInt16 address)
|
uInt8 Cartridge::peekRAM(uInt8& dest, uInt16 address)
|
||||||
|
{
|
||||||
|
uInt8 value = myRWPRandomValues[address & 0xFF];
|
||||||
|
|
||||||
|
// Reading from the write port triggers an unwanted write
|
||||||
|
// But this only happens when in normal emulation mode
|
||||||
|
#ifdef DEBUGGER_SUPPORT
|
||||||
|
if(!bankLocked() && !mySystem->autodetectMode())
|
||||||
|
{
|
||||||
|
// Record access here; final determination will happen in ::pokeRAM()
|
||||||
|
myRAMAccesses.push_back(address);
|
||||||
|
dest = value;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if(!mySystem->autodetectMode())
|
||||||
|
dest = value;
|
||||||
|
#endif
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void Cartridge::pokeRAM(uInt8& dest, uInt16 address, uInt8 value)
|
||||||
{
|
{
|
||||||
#ifdef DEBUGGER_SUPPORT
|
#ifdef DEBUGGER_SUPPORT
|
||||||
if(!mySystem->autodetectMode())
|
for(auto i = myRAMAccesses.begin(); i != myRAMAccesses.end(); ++i)
|
||||||
Debugger::debugger().cartDebug().triggerReadFromWritePort(address);
|
{
|
||||||
|
if(*i == address)
|
||||||
|
{
|
||||||
|
myRAMAccesses.erase(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
dest = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -99,18 +139,16 @@ void Cartridge::initializeRAM(uInt8* arr, uInt32 size, uInt8 val) const
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
uInt16 Cartridge::initializeStartBank(int defaultBank)
|
uInt16 Cartridge::initializeStartBank(uInt16 defaultBank)
|
||||||
{
|
{
|
||||||
int propsBank = myStartBankFromPropsFunc();
|
int propsBank = myStartBankFromPropsFunc();
|
||||||
|
|
||||||
bool userandom = randomStartBank() || (defaultBank < 0 && propsBank < 0);
|
if(randomStartBank())
|
||||||
|
|
||||||
if(userandom)
|
|
||||||
return myStartBank = mySystem->randGenerator().next() % bankCount();
|
return myStartBank = mySystem->randGenerator().next() % bankCount();
|
||||||
else if(propsBank >= 0)
|
else if(propsBank >= 0)
|
||||||
return myStartBank = BSPF::clamp(propsBank, 0, bankCount() - 1);
|
return myStartBank = BSPF::clamp(propsBank, 0, bankCount() - 1);
|
||||||
else
|
else
|
||||||
return myStartBank = BSPF::clamp(defaultBank, 0, bankCount() - 1);
|
return myStartBank = BSPF::clamp(int(defaultBank), 0, bankCount() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
|
@ -47,8 +47,9 @@ class Cartridge : public Device
|
||||||
Create a new cartridge
|
Create a new cartridge
|
||||||
|
|
||||||
@param settings A reference to the various settings (read-only)
|
@param settings A reference to the various settings (read-only)
|
||||||
|
@param md5 The md5sum of the cart image
|
||||||
*/
|
*/
|
||||||
Cartridge(const Settings& settings);
|
Cartridge(const Settings& settings, const string& md5);
|
||||||
virtual ~Cartridge() = default;
|
virtual ~Cartridge() = default;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -103,6 +104,25 @@ class Cartridge : public Device
|
||||||
*/
|
*/
|
||||||
virtual bool bankChanged();
|
virtual bool bankChanged();
|
||||||
|
|
||||||
|
#ifdef DEBUGGER_SUPPORT
|
||||||
|
/**
|
||||||
|
To be called at the start of each instruction.
|
||||||
|
Clears information about all accesses to cart RAM.
|
||||||
|
*/
|
||||||
|
void clearAllRAMAccesses() { myRAMAccesses.clear(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
To be called at the end of each instruction.
|
||||||
|
Answers whether an access in the last instruction cycle generated
|
||||||
|
an illegal RAM access.
|
||||||
|
|
||||||
|
@return Address of illegal access if one occurred, else 0
|
||||||
|
*/
|
||||||
|
uInt16 getIllegalRAMAccess() const {
|
||||||
|
return myRAMAccesses.size() > 0 ? myRAMAccesses[0] : 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// The following methods are cart-specific and will usually be
|
// The following methods are cart-specific and will usually be
|
||||||
|
@ -189,11 +209,28 @@ class Cartridge : public Device
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
Indicate that an illegal read from a write port has occurred.
|
Get a random value to use when a read from the write port happens.
|
||||||
|
Sometimes a RWP means that RAM should be overwritten, sometimes not.
|
||||||
|
|
||||||
|
Internally, this method also keeps track of illegal accesses.
|
||||||
|
|
||||||
|
@param dest The location to place the value, when an overwrite should happen
|
||||||
@param address The address of the illegal read
|
@param address The address of the illegal read
|
||||||
|
@return The value read, whether it is overwritten or not
|
||||||
*/
|
*/
|
||||||
void triggerReadFromWritePort(uInt16 address);
|
uInt8 peekRAM(uInt8& dest, uInt16 address);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Use the given value when writing to RAM.
|
||||||
|
|
||||||
|
Internally, this method also keeps track of legal accesses, and removes
|
||||||
|
them from the illegal list.
|
||||||
|
|
||||||
|
@param dest The final location (including address) to place the value
|
||||||
|
@param address The address of the legal write
|
||||||
|
@param value The value to write to the given address
|
||||||
|
*/
|
||||||
|
void pokeRAM(uInt8& dest, uInt16 address, uInt8 value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Create an array that holds code-access information for every byte
|
Create an array that holds code-access information for every byte
|
||||||
|
@ -221,11 +258,12 @@ class Cartridge : public Device
|
||||||
NOTE: If this method is used, it *must* be called from the cart reset()
|
NOTE: If this method is used, it *must* be called from the cart reset()
|
||||||
method, *not* from the c'tor.
|
method, *not* from the c'tor.
|
||||||
|
|
||||||
@param defaultBank The actual bank to use during reset
|
@param defaultBank The default bank to use during reset, if
|
||||||
|
randomization or properties aren't being used
|
||||||
|
|
||||||
@return The bank number that was determined
|
@return The bank number that was determined
|
||||||
*/
|
*/
|
||||||
uInt16 initializeStartBank(int defaultBank = -1);
|
uInt16 initializeStartBank(uInt16 defaultBank);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Checks if initial RAM randomization is enabled.
|
Checks if initial RAM randomization is enabled.
|
||||||
|
@ -260,6 +298,9 @@ class Cartridge : public Device
|
||||||
// by the debugger, when disassembling/dumping ROM.
|
// by the debugger, when disassembling/dumping ROM.
|
||||||
bool myBankLocked;
|
bool myBankLocked;
|
||||||
|
|
||||||
|
// Semi-random values to use when a read from write port occurs
|
||||||
|
uInt8 myRWPRandomValues[256];
|
||||||
|
|
||||||
// Contains various info about this cartridge
|
// Contains various info about this cartridge
|
||||||
// This needs to be stored separately from child classes, since
|
// This needs to be stored separately from child classes, since
|
||||||
// sometimes the information in both do not match
|
// sometimes the information in both do not match
|
||||||
|
@ -269,6 +310,9 @@ class Cartridge : public Device
|
||||||
// Used when we want the 'Cartridge.StartBank' ROM property
|
// Used when we want the 'Cartridge.StartBank' ROM property
|
||||||
StartBankFromPropsFunc myStartBankFromPropsFunc;
|
StartBankFromPropsFunc myStartBankFromPropsFunc;
|
||||||
|
|
||||||
|
// Contains
|
||||||
|
ShortArray myRAMAccesses;
|
||||||
|
|
||||||
// Following constructors and assignment operators not supported
|
// Following constructors and assignment operators not supported
|
||||||
Cartridge() = delete;
|
Cartridge() = delete;
|
||||||
Cartridge(const Cartridge&) = delete;
|
Cartridge(const Cartridge&) = delete;
|
||||||
|
|
|
@ -20,8 +20,8 @@
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
Cartridge0840::Cartridge0840(const BytePtr& image, uInt32 size,
|
Cartridge0840::Cartridge0840(const BytePtr& image, uInt32 size,
|
||||||
const Settings& settings)
|
const string& md5, const Settings& settings)
|
||||||
: Cartridge(settings),
|
: Cartridge(settings, md5),
|
||||||
myBankOffset(0)
|
myBankOffset(0)
|
||||||
{
|
{
|
||||||
// Copy the ROM image into my buffer
|
// Copy the ROM image into my buffer
|
||||||
|
@ -32,9 +32,8 @@ Cartridge0840::Cartridge0840(const BytePtr& image, uInt32 size,
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Cartridge0840::reset()
|
void Cartridge0840::reset()
|
||||||
{
|
{
|
||||||
initializeStartBank();
|
|
||||||
|
|
||||||
// Upon reset we switch to the startup bank
|
// Upon reset we switch to the startup bank
|
||||||
|
initializeStartBank(0);
|
||||||
bank(startBank());
|
bank(startBank());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,9 +42,11 @@ class Cartridge0840 : public Cartridge
|
||||||
|
|
||||||
@param image Pointer to the ROM image
|
@param image Pointer to the ROM image
|
||||||
@param size The size of the ROM image
|
@param size The size of the ROM image
|
||||||
|
@param md5 The md5sum of the ROM image
|
||||||
@param settings A reference to the various settings (read-only)
|
@param settings A reference to the various settings (read-only)
|
||||||
*/
|
*/
|
||||||
Cartridge0840(const BytePtr& image, uInt32 size, const Settings& settings);
|
Cartridge0840(const BytePtr& image, uInt32 size, const string& md5,
|
||||||
|
const Settings& settings);
|
||||||
virtual ~Cartridge0840() = default;
|
virtual ~Cartridge0840() = default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -20,8 +20,8 @@
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
Cartridge2K::Cartridge2K(const BytePtr& image, uInt32 size,
|
Cartridge2K::Cartridge2K(const BytePtr& image, uInt32 size,
|
||||||
const Settings& settings)
|
const string& md5, const Settings& settings)
|
||||||
: Cartridge(settings)
|
: Cartridge(settings, md5)
|
||||||
{
|
{
|
||||||
// Size can be a maximum of 2K
|
// Size can be a maximum of 2K
|
||||||
if(size > 2048) size = 2048;
|
if(size > 2048) size = 2048;
|
||||||
|
|
|
@ -45,9 +45,11 @@ class Cartridge2K : public Cartridge
|
||||||
|
|
||||||
@param image Pointer to the ROM image
|
@param image Pointer to the ROM image
|
||||||
@param size The size of the ROM image (<= 2048 bytes)
|
@param size The size of the ROM image (<= 2048 bytes)
|
||||||
|
@param md5 The md5sum of the ROM image
|
||||||
@param settings A reference to the various settings (read-only)
|
@param settings A reference to the various settings (read-only)
|
||||||
*/
|
*/
|
||||||
Cartridge2K(const BytePtr& image, uInt32 size, const Settings& settings);
|
Cartridge2K(const BytePtr& image, uInt32 size, const string& md5,
|
||||||
|
const Settings& settings);
|
||||||
virtual ~Cartridge2K() = default;
|
virtual ~Cartridge2K() = default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -21,8 +21,8 @@
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
Cartridge3E::Cartridge3E(const BytePtr& image, uInt32 size,
|
Cartridge3E::Cartridge3E(const BytePtr& image, uInt32 size,
|
||||||
const Settings& settings)
|
const string& md5, const Settings& settings)
|
||||||
: Cartridge(settings),
|
: Cartridge(settings, md5),
|
||||||
mySize(size),
|
mySize(size),
|
||||||
myCurrentBank(0)
|
myCurrentBank(0)
|
||||||
{
|
{
|
||||||
|
@ -85,15 +85,7 @@ uInt8 Cartridge3E::peek(uInt16 address)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Reading from the write port triggers an unwanted write
|
// Reading from the write port triggers an unwanted write
|
||||||
uInt8 value = mySystem->getDataBusState(0xFF);
|
return peekRAM(myRAM[(address & 0x03FF) + ((myCurrentBank - 256) << 10)], peekAddress);
|
||||||
|
|
||||||
if(bankLocked())
|
|
||||||
return value;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
triggerReadFromWritePort(peekAddress);
|
|
||||||
return myRAM[(address & 0x03FF) + ((myCurrentBank - 256) << 10)] = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,23 +98,24 @@ uInt8 Cartridge3E::peek(uInt16 address)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool Cartridge3E::poke(uInt16 address, uInt8 value)
|
bool Cartridge3E::poke(uInt16 address, uInt8 value)
|
||||||
{
|
{
|
||||||
|
uInt16 pokeAddress = address;
|
||||||
address &= 0x0FFF;
|
address &= 0x0FFF;
|
||||||
|
|
||||||
// Switch banks if necessary. Armin (Kroko) says there are no mirrored
|
// Switch banks if necessary. Armin (Kroko) says there are no mirrored
|
||||||
// hotspots.
|
// hotspots.
|
||||||
if(address == 0x003F)
|
if(address < 0x0040)
|
||||||
{
|
{
|
||||||
bank(value);
|
if(address == 0x003F)
|
||||||
}
|
bank(value);
|
||||||
else if(address == 0x003E)
|
else if(address == 0x003E)
|
||||||
{
|
bank(value + 256);
|
||||||
bank(value + 256);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle TIA space that we claimed above
|
return mySystem->tia().poke(address, value);
|
||||||
mySystem->tia().poke(address, value);
|
}
|
||||||
|
else
|
||||||
|
pokeRAM(myRAM[(address & 0x03FF) + ((myCurrentBank - 256) << 10)], pokeAddress, value);
|
||||||
|
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -180,9 +173,10 @@ bool Cartridge3E::bank(uInt16 bank)
|
||||||
access.type = System::PA_WRITE;
|
access.type = System::PA_WRITE;
|
||||||
|
|
||||||
// Map write-port RAM image into the system
|
// Map write-port RAM image into the system
|
||||||
|
// Map access to this class, since we need to inspect all accesses to
|
||||||
|
// check if RWP happens
|
||||||
for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE)
|
for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE)
|
||||||
{
|
{
|
||||||
access.directPokeBase = &myRAM[offset + (addr & 0x03FF)];
|
|
||||||
access.codeAccessBase = &myCodeAccessBase[mySize + offset + (addr & 0x03FF)];
|
access.codeAccessBase = &myCodeAccessBase[mySize + offset + (addr & 0x03FF)];
|
||||||
mySystem->setPageAccess(addr, access);
|
mySystem->setPageAccess(addr, access);
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,9 +71,11 @@ class Cartridge3E : public Cartridge
|
||||||
|
|
||||||
@param image Pointer to the ROM image
|
@param image Pointer to the ROM image
|
||||||
@param size The size of the ROM image
|
@param size The size of the ROM image
|
||||||
|
@param md5 The md5sum of the ROM image
|
||||||
@param settings A reference to the various settings (read-only)
|
@param settings A reference to the various settings (read-only)
|
||||||
*/
|
*/
|
||||||
Cartridge3E(const BytePtr& image, uInt32 size, const Settings& settings);
|
Cartridge3E(const BytePtr& image, uInt32 size, const string& md5,
|
||||||
|
const Settings& settings);
|
||||||
virtual ~Cartridge3E() = default;
|
virtual ~Cartridge3E() = default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -21,8 +21,8 @@
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
Cartridge3EPlus::Cartridge3EPlus(const BytePtr& image, uInt32 size,
|
Cartridge3EPlus::Cartridge3EPlus(const BytePtr& image, uInt32 size,
|
||||||
const Settings& settings)
|
const string& md5, const Settings& settings)
|
||||||
: Cartridge(settings),
|
: Cartridge(settings, md5),
|
||||||
mySize(size)
|
mySize(size)
|
||||||
{
|
{
|
||||||
// Allocate array for the ROM image
|
// Allocate array for the ROM image
|
||||||
|
@ -96,20 +96,11 @@ uInt8 Cartridge3EPlus::peek(uInt16 address)
|
||||||
}
|
}
|
||||||
else if(imageBank & BITMASK_ROMRAM) // a RAM bank
|
else if(imageBank & BITMASK_ROMRAM) // a RAM bank
|
||||||
{
|
{
|
||||||
// Reading from the write port triggers an unwanted write
|
Int32 ramBank = imageBank & BIT_BANK_MASK; // discard irrelevant bits
|
||||||
value = mySystem->getDataBusState(0xFF);
|
Int32 offset = ramBank << RAM_BANK_TO_POWER; // base bank address in RAM
|
||||||
|
offset += (address & BITMASK_RAM_BANK); // + byte offset in RAM bank
|
||||||
|
|
||||||
if(bankLocked())
|
return peekRAM(myRAM[offset], peekAddress);
|
||||||
return value;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
triggerReadFromWritePort(peekAddress);
|
|
||||||
|
|
||||||
Int32 ramBank = imageBank & BIT_BANK_MASK; // discard irrelevant bits
|
|
||||||
Int32 offset = ramBank << RAM_BANK_TO_POWER; // base bank address in RAM
|
|
||||||
offset += (address & BITMASK_RAM_BANK); // + byte offset in RAM bank
|
|
||||||
return myRAM[offset] = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
|
@ -125,12 +116,27 @@ bool Cartridge3EPlus::poke(uInt16 address, uInt8 value)
|
||||||
|
|
||||||
if(address == BANK_SWITCH_HOTSPOT_RAM)
|
if(address == BANK_SWITCH_HOTSPOT_RAM)
|
||||||
changed = bankRAM(value);
|
changed = bankRAM(value);
|
||||||
|
|
||||||
else if(address == BANK_SWITCH_HOTSPOT_ROM)
|
else if(address == BANK_SWITCH_HOTSPOT_ROM)
|
||||||
changed = bankROM(value);
|
changed = bankROM(value);
|
||||||
|
|
||||||
// Handle TIA space that we claimed above
|
if(!(address & 0x1000))
|
||||||
mySystem->tia().poke(address, value);
|
{
|
||||||
|
// Handle TIA space that we claimed above
|
||||||
|
changed = changed || mySystem->tia().poke(address, value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uInt32 bankNumber = (address >> RAM_BANK_TO_POWER) & 7; // now 512 byte bank # (ie: 0-7)
|
||||||
|
Int16 whichBankIsThere = bankInUse[bankNumber]; // ROM or RAM bank reference
|
||||||
|
|
||||||
|
if(whichBankIsThere & BITMASK_ROMRAM)
|
||||||
|
{
|
||||||
|
uInt32 byteOffset = address & BITMASK_RAM_BANK;
|
||||||
|
uInt32 baseAddress = ((whichBankIsThere & BIT_BANK_MASK) << RAM_BANK_TO_POWER) + byteOffset;
|
||||||
|
pokeRAM(myRAM[baseAddress], address, value);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
@ -181,9 +187,7 @@ void Cartridge3EPlus::bankRAMSlot(uInt16 bank)
|
||||||
// << "start=" << std::hex << start << ", end=" << end << endl << endl;
|
// << "start=" << std::hex << start << ", end=" << end << endl << endl;
|
||||||
for(uInt16 addr = start; addr <= end; addr += System::PAGE_SIZE)
|
for(uInt16 addr = start; addr <= end; addr += System::PAGE_SIZE)
|
||||||
{
|
{
|
||||||
if(upper)
|
if(!upper)
|
||||||
access.directPokeBase = &myRAM[startCurrentBank + (addr & (RAM_BANK_SIZE - 1))];
|
|
||||||
else
|
|
||||||
access.directPeekBase = &myRAM[startCurrentBank + (addr & (RAM_BANK_SIZE - 1))];
|
access.directPeekBase = &myRAM[startCurrentBank + (addr & (RAM_BANK_SIZE - 1))];
|
||||||
|
|
||||||
access.codeAccessBase = &myCodeAccessBase[mySize + startCurrentBank + (addr & (RAM_BANK_SIZE - 1))];
|
access.codeAccessBase = &myCodeAccessBase[mySize + startCurrentBank + (addr & (RAM_BANK_SIZE - 1))];
|
||||||
|
|
|
@ -51,9 +51,11 @@ class Cartridge3EPlus: public Cartridge
|
||||||
|
|
||||||
@param image Pointer to the ROM image
|
@param image Pointer to the ROM image
|
||||||
@param size The size of the ROM image
|
@param size The size of the ROM image
|
||||||
|
@param md5 The md5sum of the ROM image
|
||||||
@param settings A reference to the various settings (read-only)
|
@param settings A reference to the various settings (read-only)
|
||||||
*/
|
*/
|
||||||
Cartridge3EPlus(const BytePtr& image, uInt32 size, const Settings& settings);
|
Cartridge3EPlus(const BytePtr& image, uInt32 size, const string& md5,
|
||||||
|
const Settings& settings);
|
||||||
virtual ~Cartridge3EPlus() = default;
|
virtual ~Cartridge3EPlus() = default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -21,8 +21,8 @@
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
Cartridge3F::Cartridge3F(const BytePtr& image, uInt32 size,
|
Cartridge3F::Cartridge3F(const BytePtr& image, uInt32 size,
|
||||||
const Settings& settings)
|
const string& md5, const Settings& settings)
|
||||||
: Cartridge(settings),
|
: Cartridge(settings, md5),
|
||||||
mySize(size),
|
mySize(size),
|
||||||
myCurrentBank(0)
|
myCurrentBank(0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -48,9 +48,11 @@ class Cartridge3F : public Cartridge
|
||||||
|
|
||||||
@param image Pointer to the ROM image
|
@param image Pointer to the ROM image
|
||||||
@param size The size of the ROM image
|
@param size The size of the ROM image
|
||||||
|
@param md5 The md5sum of the ROM image
|
||||||
@param settings A reference to the various settings (read-only)
|
@param settings A reference to the various settings (read-only)
|
||||||
*/
|
*/
|
||||||
Cartridge3F(const BytePtr& image, uInt32 size, const Settings& settings);
|
Cartridge3F(const BytePtr& image, uInt32 size, const string& md5,
|
||||||
|
const Settings& settings);
|
||||||
virtual ~Cartridge3F() = default;
|
virtual ~Cartridge3F() = default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -22,8 +22,8 @@
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
Cartridge4A50::Cartridge4A50(const BytePtr& image, uInt32 size,
|
Cartridge4A50::Cartridge4A50(const BytePtr& image, uInt32 size,
|
||||||
const Settings& settings)
|
const string& md5, const Settings& settings)
|
||||||
: Cartridge(settings),
|
: Cartridge(settings, md5),
|
||||||
mySize(size),
|
mySize(size),
|
||||||
mySliceLow(0),
|
mySliceLow(0),
|
||||||
mySliceMiddle(0),
|
mySliceMiddle(0),
|
||||||
|
|
|
@ -62,9 +62,11 @@ class Cartridge4A50 : public Cartridge
|
||||||
|
|
||||||
@param image Pointer to the ROM image
|
@param image Pointer to the ROM image
|
||||||
@param size The size of the ROM image
|
@param size The size of the ROM image
|
||||||
|
@param md5 The md5sum of the ROM image
|
||||||
@param settings A reference to the various settings (read-only)
|
@param settings A reference to the various settings (read-only)
|
||||||
*/
|
*/
|
||||||
Cartridge4A50(const BytePtr& image, uInt32 size, const Settings& settings);
|
Cartridge4A50(const BytePtr& image, uInt32 size, const string& md5,
|
||||||
|
const Settings& settings);
|
||||||
virtual ~Cartridge4A50() = default;
|
virtual ~Cartridge4A50() = default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -20,8 +20,8 @@
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
Cartridge4K::Cartridge4K(const BytePtr& image, uInt32 size,
|
Cartridge4K::Cartridge4K(const BytePtr& image, uInt32 size,
|
||||||
const Settings& settings)
|
const string& md5, const Settings& settings)
|
||||||
: Cartridge(settings)
|
: Cartridge(settings, md5)
|
||||||
{
|
{
|
||||||
// Copy the ROM image into my buffer
|
// Copy the ROM image into my buffer
|
||||||
memcpy(myImage, image.get(), std::min(4096u, size));
|
memcpy(myImage, image.get(), std::min(4096u, size));
|
||||||
|
|
|
@ -42,9 +42,11 @@ class Cartridge4K : public Cartridge
|
||||||
|
|
||||||
@param image Pointer to the ROM image
|
@param image Pointer to the ROM image
|
||||||
@param size The size of the ROM image
|
@param size The size of the ROM image
|
||||||
|
@param md5 The md5sum of the ROM image
|
||||||
@param settings A reference to the various settings (read-only)
|
@param settings A reference to the various settings (read-only)
|
||||||
*/
|
*/
|
||||||
Cartridge4K(const BytePtr& image, uInt32 size, const Settings& settings);
|
Cartridge4K(const BytePtr& image, uInt32 size, const string& md5,
|
||||||
|
const Settings& settings);
|
||||||
virtual ~Cartridge4K() = default;
|
virtual ~Cartridge4K() = default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -20,8 +20,8 @@
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
Cartridge4KSC::Cartridge4KSC(const BytePtr& image, uInt32 size,
|
Cartridge4KSC::Cartridge4KSC(const BytePtr& image, uInt32 size,
|
||||||
const Settings& settings)
|
const string& md5, const Settings& settings)
|
||||||
: Cartridge(settings)
|
: Cartridge(settings, md5)
|
||||||
{
|
{
|
||||||
// Copy the ROM image into my buffer
|
// Copy the ROM image into my buffer
|
||||||
memcpy(myImage, image.get(), std::min(4096u, size));
|
memcpy(myImage, image.get(), std::min(4096u, size));
|
||||||
|
@ -44,16 +44,16 @@ void Cartridge4KSC::install(System& system)
|
||||||
System::PageAccess access(this, System::PA_READ);
|
System::PageAccess access(this, System::PA_READ);
|
||||||
|
|
||||||
// Set the page accessing method for the RAM writing pages
|
// Set the page accessing method for the RAM writing pages
|
||||||
|
// Map access to this class, since we need to inspect all accesses to
|
||||||
|
// check if RWP happens
|
||||||
access.type = System::PA_WRITE;
|
access.type = System::PA_WRITE;
|
||||||
for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE)
|
for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE)
|
||||||
{
|
{
|
||||||
access.directPokeBase = &myRAM[addr & 0x007F];
|
|
||||||
access.codeAccessBase = &myCodeAccessBase[addr & 0x007F];
|
access.codeAccessBase = &myCodeAccessBase[addr & 0x007F];
|
||||||
mySystem->setPageAccess(addr, access);
|
mySystem->setPageAccess(addr, access);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the page accessing method for the RAM reading pages
|
// Set the page accessing method for the RAM reading pages
|
||||||
access.directPokeBase = nullptr;
|
|
||||||
access.type = System::PA_READ;
|
access.type = System::PA_READ;
|
||||||
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
|
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
|
||||||
{
|
{
|
||||||
|
@ -75,17 +75,16 @@ void Cartridge4KSC::install(System& system)
|
||||||
uInt8 Cartridge4KSC::peek(uInt16 address)
|
uInt8 Cartridge4KSC::peek(uInt16 address)
|
||||||
{
|
{
|
||||||
// The only way we can get to this method is if we attempt to read from
|
// 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
|
// the write port (0xF000 - 0xF07F, 128 bytes), in which case an
|
||||||
// unwanted write is triggered
|
// unwanted write is potentially triggered
|
||||||
uInt8 value = mySystem->getDataBusState(0xFF);
|
return peekRAM(myRAM[address & 0x007F], address);
|
||||||
|
}
|
||||||
|
|
||||||
if(bankLocked())
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
return value;
|
bool Cartridge4KSC::poke(uInt16 address, uInt8 value)
|
||||||
else
|
{
|
||||||
{
|
pokeRAM(myRAM[address & 0x007F], address, value);
|
||||||
triggerReadFromWritePort(address);
|
return true;
|
||||||
return myRAM[address & 0x0FFF] = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
|
@ -41,9 +41,11 @@ class Cartridge4KSC : public Cartridge
|
||||||
|
|
||||||
@param image Pointer to the ROM image
|
@param image Pointer to the ROM image
|
||||||
@param size The size of the ROM image
|
@param size The size of the ROM image
|
||||||
|
@param md5 The md5sum of the ROM image
|
||||||
@param settings A reference to the various settings (read-only)
|
@param settings A reference to the various settings (read-only)
|
||||||
*/
|
*/
|
||||||
Cartridge4KSC(const BytePtr& image, uInt32 size, const Settings& settings);
|
Cartridge4KSC(const BytePtr& image, uInt32 size, const string& md5,
|
||||||
|
const Settings& settings);
|
||||||
virtual ~Cartridge4KSC() = default;
|
virtual ~Cartridge4KSC() = default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -120,6 +122,15 @@ class Cartridge4KSC : public Cartridge
|
||||||
*/
|
*/
|
||||||
uInt8 peek(uInt16 address) override;
|
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:
|
private:
|
||||||
// The 4K ROM image of the cartridge
|
// The 4K ROM image of the cartridge
|
||||||
uInt8 myImage[4096];
|
uInt8 myImage[4096];
|
||||||
|
|