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",
"istream": "cpp",
"thread": "cpp",
"utility": "cpp"
"utility": "cpp",
"streambuf": "cpp"
}
}

View File

@ -9,7 +9,7 @@
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
@ -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
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:
* 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,
and will probably be discontinued in a future release.
* Binary distribution for MacOS X 10.7 and above :
Stella-6.0-macosx.dmg (64-bit Intel)
* Binary distribution for macOS 10.7 and above :
Stella-6.0-macos.dmg (64-bit Intel)
* Binary distribution in 32-bit & 64-bit Ubuntu DEB format :
stella_6.0-1_i386.deb

View File

@ -12,7 +12,7 @@
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
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
faithful (i.e. speed in Pick'n'Pile).
* 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; TODO button and initial key repeats...)
* Fixes for collision corner cases (during HBlank).
* Added preliminary support for 'CTY' bankswitching scheme and recently
released 'Chetiry' ROMs. Special thanks to SpiceWare for adding music
support to this scheme.
* UI modernization (new widget look, dialog titles added, dialogs
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
specific extension (ie: .f8s for F8SC, .fe for FE, etc). The
supported extensions are the same as the ones from HarmonyCart and
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
named 'launcherroms', which specifies to show only ROMs or all files
in the ROM launcher.
@ -63,6 +70,10 @@
* 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;
the parsing was failing. This affected the 'cpurandom' argument; when
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'
setting.
* Improved snapshots when phosphor is enabled.
* Updated PAL palette.
* Added 'Cartridge.StartBank' ROM property, to force a ROM to use a
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 'Amoeba Jump' and 'Flappy' ROMs (from the Retron77) to the
database.
* Fixed 'Street Racer' and 'Video Olympics' ROMs to use paddles in both
ports.
* Added premliminary support for 'CTY' bankswitching scheme and recently
released 'Chetiry' ROMs. Special thanks to SpiceWare for adding music
support to this scheme.
* If using SDL 2.0.5 or above, the calculated desktop size now takes
the taskbar/dock into account (so windows should no longer overlap
those areas).
* For UNIX systems: in the ROM launcher, when using symlinks use the
symlink pathname instead of the underlying filesystem pathname.
@ -117,6 +138,9 @@
* The UNIX builds now use the system-installed PNG and ZLIB libraries
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
SSE2 anymore.

4
configure vendored
View File

@ -716,7 +716,7 @@ case $_host_os in
INCLUDES="$INCLUDES -I$SRC/unix"
;;
darwin)
DEFINES="$DEFINES -DBSPF_UNIX -DOSX_KEYS"
DEFINES="$DEFINES -DBSPF_UNIX -DMACOS_KEYS"
MODULES="$MODULES $SRC/unix"
INCLUDES="$INCLUDES -I$SRC/unix"
;;
@ -823,7 +823,7 @@ rm -f stella-conf*
if test "$_host_os" = darwin; then
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...
EOI
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> _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> _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> _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>

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>
<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><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
the following:</p>
<ul>
<li>MacOSX 10.7 (Lion) or above</li>
<li>macOS 10.7 or above</li>
<li>64-bit Intel processor</li>
<li>OpenGL capable video card</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>
<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
encounter with diverse operating systems and CPU types.</p>
</blockquote>
@ -423,7 +423,7 @@
<p>
<h3><b><u>Macintosh</u></b></h3>
<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>
<li>Double-click the disk image, open the 'Stella' folder, then copy the
<b>Stella.app</b> package to your 'Applications' folder.</li>
@ -632,7 +632,7 @@
<tr>
<th>Function</th>
<th>Key (Standard)</th>
<th>Key (MacOSX)</th>
<th>Key (macOS)</th>
</tr>
<tr>
@ -1262,7 +1262,7 @@
<tr>
<th>Function</th>
<th>Key (Standard)</th>
<th>Key (MacOSX)</th>
<th>Key (macOS)</th>
</tr>
<tr>
<td>Disable TV effects</td>
@ -1347,7 +1347,7 @@
<tr>
<th>Function</th>
<th>Key (Standard)</th>
<th>Key (MacOSX)</th>
<th>Key (macOS)</th>
</tr>
<tr>
@ -1483,7 +1483,7 @@
<tr>
<th>Function</th>
<th>Key (Standard)</th>
<th>Key (MacOSX)</th>
<th>Key (macOS)</th>
</tr>
<tr>
@ -2538,9 +2538,15 @@
<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.
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>
<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
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
@ -2651,7 +2657,7 @@
</table>
<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">
<tr>
<td><img src="graphics/options_audio.png"></td>
@ -2659,11 +2665,35 @@
<td valign="top">
<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><td>Volume</td><td>Self-explanatory</td><td>-volume</td></tr>
<tr><td>Sample size (*)</td><td>Set size of audio buffers</td><td>-fragsize</td></tr>
<tr><td>Frequency (*)</td><td>Change sound output frequency</td><td>-freq</td></tr>
<tr><td>Enable sound</td><td>Self-explanatory</td><td>-sound</td></tr>
<tr><td>Enable audio</td><td>Self-explanatory</td><td>-audio.enabled</td></tr>
<tr><td>Volume</td><td>Self-explanatory</td><td>-audio.volume</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>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>
<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>
</tr>
</table>
@ -3042,8 +3072,8 @@
<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,
COM2, etc.; Linux and MacOSX tend to use names similar to '/dev/xxxxxx'.
For now, only Linux/UNIX, MacOSX, and Windows are supported.</p>
COM2, etc.; Linux and macOS tend to use names similar to '/dev/xxxxxx'.
For now, only Linux/UNIX, macOS, and Windows are supported.</p>
<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
@ -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 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>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>
<td>Fatal ARM emulation ...</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)
: 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
for(int i = 0; i < count; ++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)
: 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
class AbstractFSNode;
#if defined(BSPF_UNIX) || defined(BSPF_MAC_OSX)
#if defined(BSPF_UNIX) || defined(BSPF_MACOS)
#include "FSNodePOSIX.hxx"
#elif defined(BSPF_WINDOWS)
#include "FSNodeWINDOWS.hxx"
@ -45,7 +45,7 @@ class FilesystemNodeFactory
switch(type)
{
case SYSTEM:
#if defined(BSPF_UNIX) || defined(BSPF_MAC_OSX)
#if defined(BSPF_UNIX) || defined(BSPF_MACOS)
return make_unique<FilesystemNodePOSIX>(path);
#elif defined(BSPF_WINDOWS)
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
int maxDisplays = SDL_GetNumVideoDisplays();
#if 0 //def BSPF_MAC_OSX
#if SDL_VERSION_ATLEAST(2,0,5)
SDL_Rect r;
for(int i = 0; i < maxDisplays; ++i)
{
// 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);
}
#else
@ -105,7 +105,7 @@ void FrameBufferSDL2::queryHardware(vector<GUI::Size>& displays,
displays.emplace_back(display.w, display.h);
}
#endif
struct RenderName
{
string sdlName;
@ -189,12 +189,12 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode)
: SDL_WINDOWPOS_UNDEFINED_DISPLAY(displayIndex);
uInt32 flags = mode.fsIndex != -1 ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0;
// OSX seems to have issues with destroying the window, and wants to keep
// the same handle
// macOS seems to have issues with destroying the window, and wants to
// keep the same handle
// Problem is, doing so on other platforms results in flickering when
// toggling fullscreen windowed mode
// So we have a special case for OSX
#ifndef BSPF_MAC_OSX
// So we have a special case for macOS
#ifndef BSPF_MACOS
// Don't re-create the window if its size hasn't changed, as it's not
// necessary, and causes flashing in fullscreen mode
if(myWindow)
@ -213,7 +213,7 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode)
SDL_SetWindowTitle(myWindow, title.c_str());
}
#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,
// but at least the code works and doesn't crash
if(myWindow)
@ -346,7 +346,7 @@ void FrameBufferSDL2::setWindowIcon()
{
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
SDL_Surface* surface = SDL_CreateRGBSurfaceFrom(stella_icon, 32, 32, 32,

View File

@ -32,10 +32,10 @@
#include "SerialPortWINDOWS.hxx"
#include "SettingsWINDOWS.hxx"
#include "OSystemWINDOWS.hxx"
#elif defined(BSPF_MAC_OSX)
#include "SerialPortMACOSX.hxx"
#include "SettingsMACOSX.hxx"
#include "OSystemMACOSX.hxx"
#elif defined(BSPF_MACOS)
#include "SerialPortMACOS.hxx"
#include "SettingsMACOS.hxx"
#include "OSystemMACOS.hxx"
extern "C" {
int stellaMain(int argc, char* argv[]);
}
@ -73,8 +73,8 @@ class MediaFactory
return make_unique<OSystemUNIX>();
#elif defined(BSPF_WINDOWS)
return make_unique<OSystemWINDOWS>();
#elif defined(BSPF_MAC_OSX)
return make_unique<OSystemMACOSX>();
#elif defined(BSPF_MACOS)
return make_unique<OSystemMACOS>();
#else
#error Unsupported platform for OSystem!
#endif
@ -86,8 +86,8 @@ class MediaFactory
return make_unique<SettingsUNIX>(osystem);
#elif defined(BSPF_WINDOWS)
return make_unique<SettingsWINDOWS>(osystem);
#elif defined(BSPF_MAC_OSX)
return make_unique<SettingsMACOSX>(osystem);
#elif defined(BSPF_MACOS)
return make_unique<SettingsMACOS>(osystem);
#else
#error Unsupported platform for Settings!
#endif
@ -99,8 +99,8 @@ class MediaFactory
return make_unique<SerialPortUNIX>();
#elif defined(BSPF_WINDOWS)
return make_unique<SerialPortWINDOWS>();
#elif defined(BSPF_MAC_OSX)
return make_unique<SerialPortMACOSX>();
#elif defined(BSPF_MACOS)
return make_unique<SerialPortMACOS>();
#else
return make_unique<SerialPort>();
#endif

View File

@ -259,7 +259,7 @@ void PhysicalKeyboardHandler::handleEvent(StellaKey key, StellaMod mod, bool sta
// Control or Alt/Cmd combos first
if(StellaModTest::isAlt(mod) && state)
{
#ifdef BSPF_MAC_OSX
#ifdef BSPF_MACOS
// These keys work in all states
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);
// 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);
// 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)
{
#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
myOSystem.frameBuffer().enableMessages(false);
myOSystem.frameBuffer().tiaSurface().reRender();
myOSystem.frameBuffer().tiaSurface().renderForSnapshot();
string message = "Snapshot saved";
try

View File

@ -114,6 +114,9 @@ class PNGLibrary
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
optionally using the number given as a parameter.
@ -161,9 +164,9 @@ class PNGLibrary
@param height The height of the PNG image
@param comments The text comments to add to the PNG image
*/
void saveImage(ofstream& out, const unique_ptr<png_bytep[]>& rows,
png_uint_32 width, png_uint_32 height,
const VariantList& comments);
void saveImageToDisk(ofstream& out, const unique_ptr<png_bytep[]>& rows,
png_uint_32 width, png_uint_32 height,
const VariantList& comments);
/**
Load the PNG data from 'ReadInfo' into the FBSurface. The surface

View File

@ -305,7 +305,7 @@ void SoundSDL2::initResampler()
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(myEmulationTiming->audioSampleRate(), myAudioQueue->fragmentSize(), myAudioQueue->isStereo());

View File

@ -42,13 +42,35 @@ StaggeredLogger::StaggeredLogger(const string& message, Logger logger)
myCurrentIntervalSize(100),
myMaxIntervalFactor(9),
myCurrentIntervalFactor(1),
myCooldownTime(1000)
myCooldownTime(1000),
myTimer(new TimerManager()),
myTimerCallbackId(0)
{
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)
{
std::lock_guard<std::mutex> lock(myMutex);
_setLogger(logger);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void StaggeredLogger::_setLogger(Logger logger)
{
myLogger = logger;
}
@ -61,45 +83,32 @@ void StaggeredLogger::log()
_log();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void StaggeredLogger::advance()
{
std::lock_guard<std::mutex> lock(myMutex);
_advance();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void StaggeredLogger::_log()
{
_advance();
if (!myIsCurrentlyCollecting) startInterval();
if (!myIsCurrentlyCollecting) {
myCurrentEventCount = 0;
myIsCurrentlyCollecting = true;
myCurrentIntervalStartTimestamp = high_resolution_clock::now();
}
myCurrentEventCount++;
myLastLogEventTimestamp = high_resolution_clock::now();
++myCurrentEventCount;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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;
ss
<< currentTimestamp() << ": "
<< myMessage
<< " (" << myCurrentEventCount << " times in "
<< myCurrentIntervalSize << " milliseconds"
<< millisecondsSinceIntervalStart << " milliseconds"
<< ")";
myLogger(ss.str());
myIsCurrentlyCollecting = false;
increaseInterval();
myLogger(ss.str());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -107,7 +116,7 @@ void StaggeredLogger::increaseInterval()
{
if (myCurrentIntervalFactor >= myMaxIntervalFactor) return;
myCurrentIntervalFactor++;
++myCurrentIntervalFactor;
myCurrentIntervalSize *= 2;
}
@ -116,27 +125,44 @@ void StaggeredLogger::decreaseInterval()
{
if (myCurrentIntervalFactor <= 1) return;
myCurrentIntervalFactor--;
--myCurrentIntervalFactor;
myCurrentIntervalSize /= 2;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void StaggeredLogger::_advance()
void StaggeredLogger::startInterval()
{
if (myIsCurrentlyCollecting) return;
myIsCurrentlyCollecting = true;
high_resolution_clock::time_point now = high_resolution_clock::now();
Int64 msecSinceLastIntervalEnd =
duration_cast<duration<Int64, std::milli>>(now - myLastIntervalEndTimestamp).count();
if (myIsCurrentlyCollecting) {
Int64 msecSinceIntervalStart =
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;
while (msecSinceLastIntervalEnd > myCooldownTime && myCurrentIntervalFactor > 1) {
msecSinceLastIntervalEnd -= myCooldownTime;
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 <chrono>
#include <thread>
#include <mutex>
#include "bspf.hxx"
#include "TimerManager.hxx"
/**
* 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.
@ -39,9 +40,9 @@ class StaggeredLogger {
StaggeredLogger(const string& message, Logger logger = Logger());
void log();
~StaggeredLogger();
void advance();
void log();
void setLogger(Logger logger);
@ -49,7 +50,11 @@ class StaggeredLogger {
void _log();
void _advance();
void _setLogger(Logger logger);
void onTimerExpired(uInt32 timerId);
void startInterval();
void increaseInterval();
@ -63,8 +68,8 @@ class StaggeredLogger {
uInt32 myCurrentEventCount;
bool myIsCurrentlyCollecting;
std::chrono::high_resolution_clock::time_point myCurrentIntervalStartTimestamp;
std::chrono::high_resolution_clock::time_point myLastLogEventTimestamp;
std::chrono::high_resolution_clock::time_point myLastIntervalStartTimestamp;
std::chrono::high_resolution_clock::time_point myLastIntervalEndTimestamp;
uInt32 myCurrentIntervalSize;
uInt32 myMaxIntervalFactor;
@ -72,6 +77,17 @@ class StaggeredLogger {
uInt32 myCooldownTime;
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

View File

@ -27,7 +27,7 @@
#include "StateManager.hxx"
#define STATE_HEADER "05099200state"
#define STATE_HEADER "06000000state"
// #define MOVIE_HEADER "03030000movie"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -417,7 +417,7 @@ namespace StellaModTest
{
inline bool isAlt(int mod)
{
#if defined(BSPF_MAC_OSX) || defined(OSX_KEYS)
#if defined(BSPF_MACOS) || defined(MACOS_KEYS)
return (mod & KBDM_GUI);
#else
return (mod & KBDM_ALT);

View File

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

View File

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

View File

@ -57,8 +57,20 @@ class Variant
// Conversion methods
const string& toString() const { return data; }
const char* const toCString() const { return data.c_str(); }
const Int32 toInt() const { return atoi(data.c_str()); }
const float toFloat() const { return float(atof(data.c_str())); }
const Int32 toInt() const {
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 GUI::Size toSize() const { return GUI::Size(data); }

View File

@ -18,7 +18,7 @@
#ifndef VERSION_HXX
#define VERSION_HXX
#define STELLA_VERSION "6.0_beta2"
#define STELLA_BUILD "4603"
#define STELLA_VERSION "6.0"
#define STELLA_BUILD "4667"
#endif

View File

@ -90,7 +90,7 @@ static const string EmptyString("");
namespace BSPF
{
// 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 = "/";
#define ATTRIBUTE_FMT_PRINTF __attribute__((__format__ (__printf__, 2, 0)))
#elif defined(BSPF_WINDOWS)

View File

@ -30,6 +30,7 @@
#include "OSystem.hxx"
#include "PNGLibrary.hxx"
#include "System.hxx"
#include "TIASurface.hxx"
#include "ThreadDebugging.hxx"
@ -43,7 +44,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#if defined(BSPF_MAC_OSX)
#if defined(BSPF_MACOS)
int stellaMain(int argc, char* argv[])
#else
int main(int argc, char* argv[])
@ -137,12 +138,16 @@ int main(int argc, char* argv[])
if(result != EmptyString)
return Cleanup();
#if 0
TODO: Fix this to use functionality from OSystem::mainLoop
if(theOSystem->settings().getBool("takesnapshot"))
{
for(int i = 0; i < 30; ++i) theOSystem->frameBuffer().update();
// theOSystem->frameBuffer().tiaSurface().saveSnapShot();
theOSystem->png().takeSnapshot();
return Cleanup();
}
#endif
}
catch(const runtime_error& e)
{

View File

@ -32,6 +32,8 @@
#include "CartRamWidget.hxx"
#include "RomWidget.hxx"
#include "Base.hxx"
#include "exception/EmulationWarning.hxx"
using Common::Base;
using std::hex;
using std::dec;
@ -46,7 +48,6 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem)
myOSystem(osystem),
myDebugWidget(nullptr),
myAddrToLineIsROM(true),
myRWPortAddress(0),
myLabelLength(8) // longest pre-defined label
{
// 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()
{

View File

@ -109,14 +109,6 @@ class CartDebug : public DebuggerSystem
CartDebugWidget* getDebugWidget() const { return myDebugWidget; }
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
int lastReadBaseAddress();
// Return the base (= non-mirrored) address of the last CPU write
@ -353,10 +345,6 @@ class CartDebug : public DebuggerSystem
// handled differently
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
uInt16 myLabelLength;

View File

@ -836,7 +836,6 @@ Debugger::PseudoRegister Debugger::ourPseudoRegisters[NUM_PSEUDO_REGS] = {
{ "_fcount", "Number of frames since emulation started" },
{ "_fcycles", "Number of cycles since frame started" },
{ "_icycles", "Number of cycles of last instruction" },
{ "_rwport", "Address at which a read from a write port occurred" },
{ "_scan", "Current scanline count" },
{ "_scycles", "Number of cycles in current scanline" },
{ "_vblank", "Whether vertical blank is enabled (1 or 0)" },

View File

@ -324,7 +324,7 @@ class Debugger : public DialogContainer
string name, help;
};
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 PseudoRegister ourPseudoRegisters[NUM_PSEUDO_REGS];

View File

@ -17,6 +17,7 @@
#include "Settings.hxx"
#include "System.hxx"
#include "MD5.hxx"
#ifdef DEBUGGER_SUPPORT
#include "Debugger.hxx"
#include "CartDebug.hxx"
@ -25,13 +26,24 @@
#include "Cart.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge::Cartridge(const Settings& settings)
Cartridge::Cartridge(const Settings& settings, const string& md5)
: mySettings(settings),
myBankChanged(true),
myCodeAccessBase(nullptr),
myStartBank(0),
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
if(!mySystem->autodetectMode())
Debugger::debugger().cartDebug().triggerReadFromWritePort(address);
for(auto i = myRAMAccesses.begin(); i != myRAMAccesses.end(); ++i)
{
if(*i == address)
{
myRAMAccesses.erase(i);
break;
}
}
#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();
bool userandom = randomStartBank() || (defaultBank < 0 && propsBank < 0);
if(userandom)
if(randomStartBank())
return myStartBank = mySystem->randGenerator().next() % bankCount();
else if(propsBank >= 0)
return myStartBank = BSPF::clamp(propsBank, 0, bankCount() - 1);
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
@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;
/**
@ -103,6 +104,25 @@ class Cartridge : public Device
*/
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:
//////////////////////////////////////////////////////////////////////
// The following methods are cart-specific and will usually be
@ -189,11 +209,28 @@ class Cartridge : public Device
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
@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
@ -221,11 +258,12 @@ class Cartridge : public Device
NOTE: If this method is used, it *must* be called from the cart reset()
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
*/
uInt16 initializeStartBank(int defaultBank = -1);
uInt16 initializeStartBank(uInt16 defaultBank);
/**
Checks if initial RAM randomization is enabled.
@ -260,6 +298,9 @@ class Cartridge : public Device
// by the debugger, when disassembling/dumping ROM.
bool myBankLocked;
// Semi-random values to use when a read from write port occurs
uInt8 myRWPRandomValues[256];
// Contains various info about this cartridge
// This needs to be stored separately from child classes, since
// 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
StartBankFromPropsFunc myStartBankFromPropsFunc;
// Contains
ShortArray myRAMAccesses;
// Following constructors and assignment operators not supported
Cartridge() = delete;
Cartridge(const Cartridge&) = delete;

View File

@ -20,8 +20,8 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge0840::Cartridge0840(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings),
const string& md5, const Settings& settings)
: Cartridge(settings, md5),
myBankOffset(0)
{
// Copy the ROM image into my buffer
@ -32,9 +32,8 @@ Cartridge0840::Cartridge0840(const BytePtr& image, uInt32 size,
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Cartridge0840::reset()
{
initializeStartBank();
// Upon reset we switch to the startup bank
initializeStartBank(0);
bank(startBank());
}

View File

@ -42,9 +42,11 @@ class Cartridge0840 : public Cartridge
@param image Pointer to 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)
*/
Cartridge0840(const BytePtr& image, uInt32 size, const Settings& settings);
Cartridge0840(const BytePtr& image, uInt32 size, const string& md5,
const Settings& settings);
virtual ~Cartridge0840() = default;
public:

View File

@ -20,8 +20,8 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge2K::Cartridge2K(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings)
const string& md5, const Settings& settings)
: Cartridge(settings, md5)
{
// Size can be a maximum of 2K
if(size > 2048) size = 2048;

View File

@ -45,9 +45,11 @@ class Cartridge2K : public Cartridge
@param image Pointer to the ROM image
@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)
*/
Cartridge2K(const BytePtr& image, uInt32 size, const Settings& settings);
Cartridge2K(const BytePtr& image, uInt32 size, const string& md5,
const Settings& settings);
virtual ~Cartridge2K() = default;
public:

View File

@ -21,8 +21,8 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge3E::Cartridge3E(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings),
const string& md5, const Settings& settings)
: Cartridge(settings, md5),
mySize(size),
myCurrentBank(0)
{
@ -85,15 +85,7 @@ uInt8 Cartridge3E::peek(uInt16 address)
else
{
// Reading from the write port triggers an unwanted write
uInt8 value = mySystem->getDataBusState(0xFF);
if(bankLocked())
return value;
else
{
triggerReadFromWritePort(peekAddress);
return myRAM[(address & 0x03FF) + ((myCurrentBank - 256) << 10)] = value;
}
return peekRAM(myRAM[(address & 0x03FF) + ((myCurrentBank - 256) << 10)], peekAddress);
}
}
}
@ -106,23 +98,24 @@ uInt8 Cartridge3E::peek(uInt16 address)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge3E::poke(uInt16 address, uInt8 value)
{
uInt16 pokeAddress = address;
address &= 0x0FFF;
// Switch banks if necessary. Armin (Kroko) says there are no mirrored
// hotspots.
if(address == 0x003F)
if(address < 0x0040)
{
bank(value);
}
else if(address == 0x003E)
{
bank(value + 256);
}
if(address == 0x003F)
bank(value);
else if(address == 0x003E)
bank(value + 256);
// Handle TIA space that we claimed above
mySystem->tia().poke(address, value);
return 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;
// 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)
{
access.directPokeBase = &myRAM[offset + (addr & 0x03FF)];
access.codeAccessBase = &myCodeAccessBase[mySize + offset + (addr & 0x03FF)];
mySystem->setPageAccess(addr, access);
}

View File

@ -71,9 +71,11 @@ class Cartridge3E : public Cartridge
@param image Pointer to 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)
*/
Cartridge3E(const BytePtr& image, uInt32 size, const Settings& settings);
Cartridge3E(const BytePtr& image, uInt32 size, const string& md5,
const Settings& settings);
virtual ~Cartridge3E() = default;
public:

View File

@ -21,8 +21,8 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge3EPlus::Cartridge3EPlus(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings),
const string& md5, const Settings& settings)
: Cartridge(settings, md5),
mySize(size)
{
// Allocate array for the ROM image
@ -96,20 +96,11 @@ uInt8 Cartridge3EPlus::peek(uInt16 address)
}
else if(imageBank & BITMASK_ROMRAM) // a RAM bank
{
// Reading from the write port triggers an unwanted write
value = mySystem->getDataBusState(0xFF);
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
if(bankLocked())
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 peekRAM(myRAM[offset], peekAddress);
}
return value;
@ -125,12 +116,27 @@ bool Cartridge3EPlus::poke(uInt16 address, uInt8 value)
if(address == BANK_SWITCH_HOTSPOT_RAM)
changed = bankRAM(value);
else if(address == BANK_SWITCH_HOTSPOT_ROM)
changed = bankROM(value);
// Handle TIA space that we claimed above
mySystem->tia().poke(address, value);
if(!(address & 0x1000))
{
// 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;
}
@ -181,9 +187,7 @@ void Cartridge3EPlus::bankRAMSlot(uInt16 bank)
// << "start=" << std::hex << start << ", end=" << end << endl << endl;
for(uInt16 addr = start; addr <= end; addr += System::PAGE_SIZE)
{
if(upper)
access.directPokeBase = &myRAM[startCurrentBank + (addr & (RAM_BANK_SIZE - 1))];
else
if(!upper)
access.directPeekBase = &myRAM[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 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)
*/
Cartridge3EPlus(const BytePtr& image, uInt32 size, const Settings& settings);
Cartridge3EPlus(const BytePtr& image, uInt32 size, const string& md5,
const Settings& settings);
virtual ~Cartridge3EPlus() = default;
public:

View File

@ -21,8 +21,8 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge3F::Cartridge3F(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings),
const string& md5, const Settings& settings)
: Cartridge(settings, md5),
mySize(size),
myCurrentBank(0)
{

View File

@ -48,9 +48,11 @@ class Cartridge3F : public Cartridge
@param image Pointer to 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)
*/
Cartridge3F(const BytePtr& image, uInt32 size, const Settings& settings);
Cartridge3F(const BytePtr& image, uInt32 size, const string& md5,
const Settings& settings);
virtual ~Cartridge3F() = default;
public:

View File

@ -22,8 +22,8 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge4A50::Cartridge4A50(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings),
const string& md5, const Settings& settings)
: Cartridge(settings, md5),
mySize(size),
mySliceLow(0),
mySliceMiddle(0),

View File

@ -62,9 +62,11 @@ class Cartridge4A50 : public Cartridge
@param image Pointer to 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)
*/
Cartridge4A50(const BytePtr& image, uInt32 size, const Settings& settings);
Cartridge4A50(const BytePtr& image, uInt32 size, const string& md5,
const Settings& settings);
virtual ~Cartridge4A50() = default;
public:

View File

@ -20,8 +20,8 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge4K::Cartridge4K(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings)
const string& md5, const Settings& settings)
: Cartridge(settings, md5)
{
// Copy the ROM image into my buffer
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 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)
*/
Cartridge4K(const BytePtr& image, uInt32 size, const Settings& settings);
Cartridge4K(const BytePtr& image, uInt32 size, const string& md5,
const Settings& settings);
virtual ~Cartridge4K() = default;
public:

View File

@ -20,8 +20,8 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge4KSC::Cartridge4KSC(const BytePtr& image, uInt32 size,
const Settings& settings)
: Cartridge(settings)
const string& md5, const Settings& settings)
: Cartridge(settings, md5)
{
// Copy the ROM image into my buffer
memcpy(myImage, image.get(), std::min(4096u, size));
@ -44,16 +44,16 @@ void Cartridge4KSC::install(System& system)
System::PageAccess access(this, System::PA_READ);
// 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;
for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE)
{
access.directPokeBase = &myRAM[addr & 0x007F];
access.codeAccessBase = &myCodeAccessBase[addr & 0x007F];
mySystem->setPageAccess(addr, access);
}
// Set the page accessing method for the RAM reading pages
access.directPokeBase = nullptr;
access.type = System::PA_READ;
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
{
@ -75,17 +75,16 @@ void Cartridge4KSC::install(System& system)
uInt8 Cartridge4KSC::peek(uInt16 address)
{
// The only way we can get to this method is if we attempt to read from
// the write port (0xF000 - 0xF080, 128 bytes), in which case an
// unwanted write is triggered
uInt8 value = mySystem->getDataBusState(0xFF);
// the write port (0xF000 - 0xF07F, 128 bytes), in which case an
// unwanted write is potentially triggered
return peekRAM(myRAM[address & 0x007F], address);
}
if(bankLocked())
return value;
else
{
triggerReadFromWritePort(address);
return myRAM[address & 0x0FFF] = value;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge4KSC::poke(uInt16 address, uInt8 value)
{
pokeRAM(myRAM[address & 0x007F], address, value);
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -41,9 +41,11 @@ class Cartridge4KSC : public Cartridge
@param image Pointer to 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)
*/
Cartridge4KSC(const BytePtr& image, uInt32 size, const Settings& settings);
Cartridge4KSC(const BytePtr& image, uInt32 size, const string& md5,
const Settings& settings);
virtual ~Cartridge4KSC() = default;
public:
@ -120,6 +122,15 @@ class Cartridge4KSC : public Cartridge
*/
uInt8 peek(uInt16 address) override;
/**
Change the byte at the specified address to the given value
@param address The address where the value should be stored
@param value The value to be stored at the address
@return True if the poke changed the device address space, else false
*/
bool poke(uInt16 address, uInt8 value) override;
private:
// The 4K ROM image of the cartridge
uInt8 myImage[4096];

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