Merge branch 'release/6.0'
|
@ -67,6 +67,7 @@
|
|||
"unordered_map": "cpp",
|
||||
"istream": "cpp",
|
||||
"thread": "cpp",
|
||||
"utility": "cpp"
|
||||
"utility": "cpp",
|
||||
"streambuf": "cpp"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
54
Changes.txt
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 7.0 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 508 B After Width: | Height: | Size: 429 B |
Before Width: | Height: | Size: 788 B After Width: | Height: | Size: 534 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 856 B |
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 386 B After Width: | Height: | Size: 335 B |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 9.5 KiB |
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 9.8 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 7.5 KiB |
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 7.8 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 1.6 KiB |
|
@ -61,7 +61,7 @@
|
|||
|
||||
<br><br><br>
|
||||
|
||||
<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>-<plr.|dev.>tiadriven <1|0></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>-<plr.|dev.>rwportbreak <1|0></pre></td>
|
||||
<td>Since the 2600 has no dedicated R/W line, different addresses are used
|
||||
for RAM read or write access. If the code reads from such a write address, this causes
|
||||
an unwanted, semi-random write to that address.
|
||||
When this option is enabled, such reads interrupt emulation and the debugger is entered.</td>
|
||||
</tr><tr>
|
||||
<td><pre>-<plr.|dev.>thumb.trapfatal <1|0></pre></td>
|
||||
<td>The default of true allows the Thumb ARM emulation to
|
||||
<td>When enabled, this allows the Thumb ARM emulation to
|
||||
throw an exception and enter the debugger on fatal errors. When disabled, such
|
||||
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>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
#include "StateManager.hxx"
|
||||
|
||||
#define STATE_HEADER "05099200state"
|
||||
#define STATE_HEADER "06000000state"
|
||||
// #define MOVIE_HEADER "03030000movie"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -20,7 +20,8 @@
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
ThreadDebuggingHelper::ThreadDebuggingHelper()
|
||||
: myMainThreadIdConfigured(false)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
ThreadDebuggingHelper& ThreadDebuggingHelper::instance()
|
||||
|
|
|
@ -46,7 +46,7 @@ class ThreadDebuggingHelper {
|
|||
|
||||
private:
|
||||
|
||||
void fail(const string& message);
|
||||
[[noreturn]] void fail(const string& message);
|
||||
|
||||
ThreadDebuggingHelper();
|
||||
|
||||
|
|
|
@ -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); }
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)" },
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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))];
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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];
|
||||
|
|