Merge branch 'release/6.0'

This commit is contained in:
Stephen Anthony 2018-12-26 14:30:46 -03:30
commit 67ac657fcf
255 changed files with 1727 additions and 1300 deletions

View File

@ -67,6 +67,7 @@
"unordered_map": "cpp", "unordered_map": "cpp",
"istream": "cpp", "istream": "cpp",
"thread": "cpp", "thread": "cpp",
"utility": "cpp" "utility": "cpp",
"streambuf": "cpp"
} }
} }

View File

@ -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

View File

@ -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.

4
configure vendored
View File

@ -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

View File

@ -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>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 508 B

After

Width:  |  Height:  |  Size: 429 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 788 B

After

Width:  |  Height:  |  Size: 534 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 856 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 386 B

After

Width:  |  Height:  |  Size: 335 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -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>-&lt;plr.|dev.&gt;tiadriven &lt;1|0&gt;</pre></td> <td><pre>-&lt;plr.|dev.&gt;tiadriven &lt;1|0&gt;</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>-&lt;plr.|dev.&gt;rwportbreak &lt;1|0&gt;</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>-&lt;plr.|dev.&gt;thumb.trapfatal &lt;1|0&gt;</pre></td> <td><pre>-&lt;plr.|dev.&gt;thumb.trapfatal &lt;1|0&gt;</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>

View File

@ -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);

View File

@ -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)));
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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);

View File

@ -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,

View File

@ -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

View File

@ -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)
{ {

View File

@ -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

View File

@ -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

View File

@ -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());

View File

@ -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();
} }

View File

@ -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

View File

@ -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"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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);

View File

@ -20,7 +20,8 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ThreadDebuggingHelper::ThreadDebuggingHelper() ThreadDebuggingHelper::ThreadDebuggingHelper()
: myMainThreadIdConfigured(false) : myMainThreadIdConfigured(false)
{} {
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ThreadDebuggingHelper& ThreadDebuggingHelper::instance() ThreadDebuggingHelper& ThreadDebuggingHelper::instance()

View File

@ -46,7 +46,7 @@ class ThreadDebuggingHelper {
private: private:
void fail(const string& message); [[noreturn]] void fail(const string& message);
ThreadDebuggingHelper(); ThreadDebuggingHelper();

View File

@ -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); }

View File

@ -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

View File

@ -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)

View File

@ -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)
{ {

View File

@ -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()
{ {

View File

@ -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;

View File

@ -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)" },

View File

@ -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];

View File

@ -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);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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;

View File

@ -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());
} }

View File

@ -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:

View File

@ -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;

View File

@ -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:

View File

@ -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);
} }

View File

@ -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:

View File

@ -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))];

View File

@ -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:

View File

@ -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)
{ {

View File

@ -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:

View File

@ -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),

View File

@ -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:

View File

@ -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));

View File

@ -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:

View File

@ -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;
}
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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];

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