This commit is contained in:
Thomas Jentzsch 2020-07-04 10:10:36 +02:00
commit b1bbda8376
184 changed files with 3041 additions and 1533 deletions

View File

@ -9,7 +9,7 @@
SSSS ttt eeeee llll llll aaaaa
===========================================================================
Release 6.1 for Linux, macOS and Windows
Release 6.2.1 for Linux, macOS and Windows
===========================================================================
The Atari 2600 Video Computer System (VCS), introduced in 1977, was the
@ -21,27 +21,27 @@ 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.1 release of Stella for Linux, macOS and Windows. The
This is the 6.2.1 release of Stella for Linux, macOS and Windows. The
distributions currently available are:
* Binaries for Windows Vista/7/8/10 :
Stella-6.1-win32.exe (32-bit EXE installer)
Stella-6.1-x64.exe (64-bit EXE installer)
Stella-6.1-windows.zip (32/64 bit versions)
Stella-6.2.1-win32.exe (32-bit EXE installer)
Stella-6.2.1-x64.exe (64-bit EXE installer)
Stella-6.2.1-windows.zip (32/64 bit versions)
* Binary distribution for macOS 10.7 and above :
Stella-6.1-macos.dmg (64-bit Intel)
Stella-6.2.1-macos.dmg (64-bit Intel)
* Binary distribution in 32-bit & 64-bit Ubuntu DEB format :
stella_6.1-1_i386.deb
stella_6.1-1_amd64.deb
stella_6.2.1-1_i386.deb
stella_6.2.1-1_amd64.deb
* Binary distribution in 32-bit & 64-bit RPM format :
stella-6.1-2.i386.rpm
stella-6.1-2.x86_64.rpm
stella-6.2.1-2.i386.rpm
stella-6.2.1-2.x86_64.rpm
* Source code distribution for all platforms :
stella-6.1-src.tar.xz
stella-6.2.1-src.tar.xz
Distribution Site

View File

@ -12,32 +12,84 @@
Release History
===========================================================================
6.1.2 to 6.2: (??? ??, 2020)
6.2.1 to 6.3 (XXXX XX, 2020)
* Added high scores: Score addresses, game variation etc. can be defined for
a game. This allows the user to save high scores for these games. For each
game and variation, the top 10 scores can be saved. (TODO: Doc)
* Added new interface palette 'Dark'. (TODO: DOC)
* Extended global hotkeys for debug options.
6.2 to 6.2.1: (June 20, 2020)
* Fixed Pitfall II ROM not working correctly.
* Fixed crashes when using some combinations of bankswitching schemes on
incorrect ROMs, or when using invalid ROM file sizes, etc.
* Fixed RIOT timer behaviour on reading/writing at the wraparound cycle.
* Fixed incorrectly setting D6 bit on TIA reads in some cases. Related
to this, improve 'tiadriven' option to randomize only D5..D0 bits.
* Fixed custom palette and TV effects adjustable slider rounding issue.
* Fixed some bugs in 3E+ scheme when using non-standard ROM sizes.
* Fixed crash in Audio & Video dialog when opened from debugger, and the
debugger window sometimes being resized when using the Options dialog.
* Make NTSC custom phase shift not affect Yellow anymore.
* Fixed '1x' snapshot mode; TV effects are now disabled. This mode
now generates a clean, pixel-exact image.
* Fixed mappings sometimes not being saved in the Retron77 port.
* A ROM properties file may now be placed next to the ROM (with the same
name as the ROM, except ending in .pro), and Stella will automatically
apply the properties to the ROM. [NOTE: this was present in 6.2, but
was mistakenly left out of the changelog]
* Added button to Game Info dialog to save properties of the currently
loaded ROM to a separate properties file (in the default save directory).
This is useful in conjunction with the previous item.
* Allow changing custom palette and TV effects adjustables in 1% steps
again.
* Updated documentation for changes in ROM properties key names.
* The codebase now compiles under gcc6 again. Future versions will
require gcc7, though.
-Have fun!
6.1.2 to 6.2: (June 7, 2020)
* Added interactive palette to Video & Audio settings.
* Added 'Custom' palette, generated from user controlled phase shifts.
* Added that adjustable audio & video settings are displayed as gauge bars
* Added that adjustable audio & video settings are displayed as gauge bars.
* Added four global hotkeys which allow selecting and changing numerous
audio & video settings without having to remember the dedicated hotkeys
audio & video settings without having to remember the dedicated hotkeys.
* Added 'Turbo' mode, runs the game as fast as the computer allows.
* Added that paddle centering (per ROM) and sensitivity can be adjusted
* Added that paddle centering (per ROM) and sensitivity can be adjusted.
* Added that mouse sensitivity for Driving controller can be adjusted
* Added that mouse sensitivity for Driving controller can be adjusted.
* Added selectable dialog fonts
* Added paddle filtering in UI to avoid unwanted navigation events.
* Added separate positioning of launcher, emulator and debugger
* Added selectable dialog fonts.
* Added option which lets default ROM path follow launcher navigation
* Added separate positioning of launcher, emulator and debugger.
* Added optional display to game refresh rate adaption in fullscreen mode.
* Added option which lets default ROM path follow launcher navigation.
* Added debugger 'saveaccess' function, which saves memory access counts to
a CSV file.
@ -51,11 +103,11 @@
* Restored 'cfg' directory for Distella config files.
* Added 3EX bank switching type.
* Added TV Boy and 3EX bank switching types.
* Removed unused CV+ and DASH bank switching types.
-Have fun!
* Added support for loading grayscale PNG images in the ROM launcher.
6.1.1 to 6.1.2: (April 25, 2020)

View File

@ -96,7 +96,7 @@ EXECUTABLE := stella$(EXEEXT)
EXECUTABLE_PROFILE_GENERATE := stella-pgo-generate$(EXEEXT)
EXECUTABLE_PROFILE_USE := stella-pgo$(EXEEXT)
PROFILE_DIR = $(CURDIR)/profile
PROFILE_DIR = $(CURDIR)/test/roms/profile
PROFILE_OUT = $(PROFILE_DIR)/out
PROFILE_STAMP = profile.stamp

14
debian/changelog vendored
View File

@ -1,3 +1,17 @@
stella (6.2.1-1) stable; urgency=high
* Version 6.2.1 release
-- Stephen Anthony <sa666666@gmail.com> Sat, 20 Jun 2020 17:09:59 -0230
stella (6.2-1) stable; urgency=high
* Version 6.2 release
-- Stephen Anthony <sa666666@gmail.com> Sun, 7 Jun 2020 17:09:59 -0230
stella (6.1.2-1) stable; urgency=high
* Version 6.1.2 release

View File

@ -15,7 +15,7 @@
<body>
<center><b><font size="7">Stella</font></b></center>
<center><h4><b>Release 6.1</b></h4></center>
<center><h4><b>Release 6.2.1</b></h4></center>
<center><h1><b>Integrated Debugger</b></h1></center>
<center><h4><b>(a work in progress)</b></h4></center>
<br>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -19,7 +19,7 @@
<br><br>
<center><h2><b>A multi-platform Atari 2600 VCS emulator</b></h2></center>
<center><h4><b>Release 6.2</b></h4></center>
<center><h4><b>Release 6.2.1</b></h4></center>
<br><br>
<center><h2><b>User's Guide</b></h2></center>
@ -70,7 +70,7 @@
<br><br><br>
<center><b>February 1999 - ??? 2020</b></center>
<center><b>February 1999 - June 2020</b></center>
<center><b>The Stella Team</b></center>
<center><b><a href="https://stella-emu.github.io">Stella Homepage</a></b></center>
@ -355,12 +355,11 @@
<p>The Linux version of Stella is designed to work on a Linux Workstation with
the following:</p>
<ul>
<li>Linux Kernel 3.x</li>
<li>i386 or x86_64 class machine, with 32 or 64-bit distribution</li>
<li>OpenGL capable video card</li>
<li>Other architectures (MIPS, PPC, PPC64, etc.) have been confirmed to work,
but aren't as well tested as i386/x86_64</li>
<li>GNU g++ v/5 or Clang v/3.5 (with C++14 support) and the make utility are required for compiling the Stella source code</li>
<li>GNU g++ v/6 or Clang v/3.9 (with C++14 support) and the make utility are required for compiling the Stella source code</li>
</ul>
<p>
@ -549,7 +548,7 @@
have to do anything yourself. However, it is also possible to force the
bankswitch type to use by adding a special filename extension. These extensions
are listed in the <a href="#Properties">ROM properties</a> section under
<a href="#PropertiesCartType">Cartridge.Type -&gt; File Extension</a>.</p>
<a href="#PropertiesCartType">Cart.Type -&gt; File Extension</a>.</p>
<p><b>Note:</b> These extensions are the same as those used by the Harmony Cart
and Unocart and are not case-sensitive, so you can name your files and have them
@ -775,7 +774,7 @@
<tr>
<td>Pause/resume emulation</td>
<td>Pause</td>
<td>&nbsp;</td>
<td>Shift-Cmd + p</td>
</tr>
</table>
@ -1377,6 +1376,13 @@
<td>Alt + Enter</td>
<td>Cmd + Enter</td>
</tr>
<tr>
<td>Toggle adapting display refresh rate to game frame rate
</br>
Note: Not available for macOS.</td>
<td>Alt + r</td>
<td>Cmd + r</td>
</tr>
<tr>
<td><i>Decrease</i> overscan in fullscreen mode</td>
<td>Shift + PageDown</td>
@ -1424,7 +1430,7 @@
</tr>
<tr>
<td colspan="3"><center><font size="-1">
These settings can also be changed using <a href="#GlobalKeys"><b>Global Audio & Video Keys</a></font></center>
These settings can also be changed using <a href="#GlobalKeys"><b>Global Keys</a></font></center>
</td>
</tr>
</table>
@ -1474,7 +1480,7 @@
</tr>
<tr>
<td colspan="3"><center><font size="-1">
These settings can also be changed using <a href="#GlobalKeys"><b>Global Audio & Video Keys</a></font></center>
These settings can also be changed using <a href="#GlobalKeys"><b>Global Keys</a></font></center>
</td>
</tr>
</table>
@ -1544,7 +1550,7 @@
</tr>
<tr>
<td colspan="3"><center><font size="-1">
These settings can also be changed using <a href="#GlobalKeys"><b>Global Audio & Video Keys</a></font></center>
These settings can also be changed using <a href="#GlobalKeys"><b>Global Keys</a></font></center>
</td>
</tr>
<tr>
@ -1553,45 +1559,6 @@
</tr>
</table>
<p><b><a name="GlobalKeys">Global Audio & Video Keys</a> (can be remapped)</b></p>
<p>These keys allow selecting and changing audio & video settings without having to remember the
dedicated keys.</p>
<table BORDER=2 cellpadding=4>
<tr>
<th>Function</th>
<th>Key (Standard)</th>
<th>Key (macOS)</th>
</tr>
<tr>
<td>Select <i>previous</i> AV setting</td>
<td>End</td>
<td>Fn + Left arrow</td>
</tr>
<tr>
<td>Select <i>next</i> AV setting</td>
<td>Home</td>
<td>Fn + Right arrow</td>
</tr>
<tr>
<td><i>Decrease</i> current AV setting</td>
<td>PageDown</td>
<td>Fn + Down arrow</td>
</tr>
<tr>
<td><i>Increase</i> current AV setting
<td>PageUp</td>
<td>Fn + Up arrow</td>
</tr>
</table>
<p>Notes:
<ul>
<li>Only available if UI messages are enabled.</li>
<li>Currently not available settings are automatically skipped.</li>
<li>If a setting was selected via dedicated key, its value can also be changed with the
global keys.</li>
</ul>
</p></br>
<a name="DeveloperKeys"></a>
<p><b>Developer Keys (can be remapped)</b></p>
@ -1709,8 +1676,62 @@
<td>Alt + j</td>
<td>Cmd + j</td>
</tr>
<tr>
<td colspan="3"><center><font size="-1">
These settings can also be changed using <a href="#GlobalKeys"><b>Global Keys</a></font></center>
</td>
</tr>
</table>
<p><b><a name="GlobalKeys">Global Keys</a> (can be remapped)</b></p>
<p>These keys allow selecting and changing settings without having to remember the
dedicated keys. They keys are grouped by Audio & Video and Debug settings.</p>
<table BORDER=2 cellpadding=4>
<tr>
<th>Function</th>
<th>Key (Standard)</th>
<th>Key (macOS)</th>
</tr>
<tr>
<td>Select <i>previous</i> setting group</td>
<td>Control + End</td>
<td>Control-Fn + Left arrow</td>
</tr>
<tr>
<td>Select <i>next</i> setting group</td>
<td>Control + Home</td>
<td>Control-Fn + Right arrow</td>
</tr>
<tr>
<td>Select <i>previous</i> setting</td>
<td>End</td>
<td>Fn + Left arrow</td>
</tr>
<tr>
<td>Select <i>next</i> setting</td>
<td>Home</td>
<td>Fn + Right arrow</td>
</tr>
<tr>
<td><i>Decrease</i> current setting</td>
<td>PageDown</td>
<td>Fn + Down arrow</td>
</tr>
<tr>
<td><i>Increase</i> current setting
<td>PageUp</td>
<td>Fn + Up arrow</td>
</tr>
</table>
<p>Notes:
<ul>
<li>Only available if UI messages are enabled.</li>
<li>Currently not available settings are automatically skipped.</li>
<li>If a setting was selected via dedicated key, its value can also be changed with the
global keys.</li>
</ul>
</p>
<p><b>Other Emulation Keys (can be remapped)</b></p>
<table BORDER=2 cellpadding=4>
@ -1742,9 +1763,15 @@
<td>Control + 1</td>
</tr>
<tr>
<td>Load <i>previous</i> game in ROM (multicart ROM, TIA mode)</td>
<td>Shift-Control + r</td>
<td>Shift-Control + r</td>
</tr>
<tr>
<td>Reload current ROM (singlecart ROM, TIA mode)<br>
Load next game in ROM (multicart ROM, TIA mode)</td>
Load <i>next</i> game in ROM (multicart ROM, TIA mode)</td>
<td>Control + r</td>
<td>Control + r</td>
</tr>
@ -1952,7 +1979,7 @@
<td> N/A</td>
<td> N/A</td>
<td> N/A</td>
<td> N/A</td>
<td> voice (2600-daptor II)</td>
</tr>
<tr>
<th> SaveKey</th>
@ -2155,7 +2182,7 @@
<tr>
<td><pre>-audio.preset &lt;1 - 5&gt;</pre></td>
<td>Set an audio preset. Numbers in sequence represent presets for
'custom', 'low quality, 'medium lag', 'high quality, medium lag',
'custom', 'low quality, medium lag', 'high quality, medium lag',
'high quality, low lag' and 'ultra quality, minimal lag'.</td>
</tr>
@ -2191,7 +2218,7 @@
<tr>
<td><pre>-audio.dpc_pitch &lt;10000 - 30000&gt;</pre></td>
<td>Set the pitch o f Pitfall II music.</td>
<td>Set the pitch of Pitfall II music.</td>
</tr>
<tr>
@ -2218,6 +2245,13 @@
aspect ratio.</td>
</tr>
<tr>
<td><pre>-tia.fs_refresh &lt;1|0&gt;</pre></td>
<td>While in fullscreen mode, adapt the display's refresh rate to the game's frame rate
to minimize judder.</br>
Note: Not available for macOS.</td>
</tr>
<tr>
<td><pre>-tia.fs_overscan &lt;0 - 10&gt;</pre></td>
<td>Add overscan to TIA image while in fullscreen mode</td>
@ -2322,9 +2356,10 @@
</tr>
<tr>
<td><pre>-joyallow4 &lt;1|0&gt;</pre></td>
<td>Allow all 4 directions on a joystick to be pressed
simultaneously.</td>
<td><pre>-psense &lt;number&gt;</pre></td>
<td>Sensitivity for emulation of paddles when using analog paddles.
Valid range of values is from 1 to 30, with larger numbers causing
faster movement.</td>
</tr>
<tr>
@ -2337,6 +2372,41 @@
<td>Impact of fast paddle movement on input averaging.</td>
</tr>
<tr>
<td><pre>-dcsense &lt;number&gt;</pre></td>
<td>Sensitivity for emulation of driving controllers when using a mouse.
Valid range of values is from 1 to 20, with larger numbers causing
faster movement.</td>
</tr>
<tr>
<td><pre>-joyallow4 &lt;1|0&gt;</pre></td>
<td>Allow all 4 directions on a joystick to be pressed
simultaneously.</td>
</tr>
<tr>
<td><pre>-modcombo &lt;1|0&gt;</pre></td>
<td>Use modifier(Shift/Alt/Control)-x key combos. This is normally enabled,
since the 'Quit' command is tied to 'Control-q'. However, there are times
when you want to disable them.</br>
E.g. a 2-player game is using either the 'f' or 'r' keys for movement,
and pressing Control (for Fire) will perform an unwanted action
associated with Control-r or Control-f default keys.</td>
</tr>
<tr>
<td><pre>-saport &lt;lr|rl&gt;</pre></td>
<td>Determines how to enumerate the Stelladaptor/2600-daptor devices in the
order they are found: 'lr' means first is left port, second is right port,
'rl' means the opposite.</td>
</tr>
<tr>
<td><pre>-avoxport &lt;name&gt;</pre></td>
<td>Set the name of the serial port where an AtariVox is connected.</td>
</tr>
<tr>
<td><pre>-usemouse &lt;always|analog|never&gt;</pre></td>
<td>Use mouse as a controller as specified by ROM properties in specific case.
@ -2344,24 +2414,6 @@
(paddles, trackball, etc.).</td>
</tr>
<tr>
<td><pre>-grabmouse &lt;1|0&gt;</pre></td>
<td>Locks the mouse cursor in the game window in emulation mode.</td>
</tr>
<tr>
<td><pre>-cursor &lt;0|1|2|3&gt;</pre></td>
<td>Set mouse cursor state in UI/emulation modes.</td>
</tr>
<tr>
<td><pre>-dsense &lt;number&gt;</pre></td>
<td>Sensitivity for emulation of paddles when using a digital device
(ie, joystick digital axis or button, keyboard key, etc.).
Valid range of values is from 1 to 20, with larger numbers causing
faster movement.</td>
</tr>
<tr>
<td><pre>-msense &lt;number&gt;</pre></td>
<td>Sensitivity for emulation of paddles when using a mouse.
@ -2377,27 +2429,21 @@
</tr>
<tr>
<td><pre>-dcsense &lt;number&gt;</pre></td>
<td>Sensitivity for emulation of driving controllers when using a mouse.
<td><pre>-dsense &lt;number&gt;</pre></td>
<td>Sensitivity for emulation of paddles when using a digital device
(ie, joystick digital axis or button, keyboard key, etc.).
Valid range of values is from 1 to 20, with larger numbers causing
faster movement.</td>
</tr>
<tr>
<td><pre>-saport &lt;lr|rl&gt;</pre></td>
<td>Determines how to enumerate the Stelladaptor/2600-daptor devices in the
order they are found: 'lr' means first is left port, second is right port,
'rl' means the opposite.</td>
<td><pre>-cursor &lt;0|1|2|3&gt;</pre></td>
<td>Set mouse cursor state in UI/emulation modes.</td>
</tr>
<tr>
<td><pre>-modcombo &lt;1|0&gt;</pre></td>
<td>Use modifier(Shift/Alt/Control)-x key combos. This is normally enabled,
since the 'Quit' command is tied to 'Control-q'. However, there are times
when you want to disable them.</br>
E.g. a 2-player game is using either the 'f' or 'r' keys for movement,
and pressing Control (for Fire) will perform an unwanted action
associated with Control-r or Control-f default keys.</td>
<td><pre>-grabmouse &lt;1|0&gt;</pre></td>
<td>Locks the mouse cursor in the game window in emulation mode.</td>
</tr>
<tr>
@ -2568,11 +2614,6 @@
<td>Make the start path follow ROM launcher navigation.</td>
</tr>
<tr>
<td><pre>-avoxport &lt;name&gt;</pre></td>
<td>Set the name of the serial port where an AtariVox is connected.</td>
</tr>
<tr>
<td><pre>-maxres &lt;WxH&gt;</pre></td>
<td>Useful for developers, this sets the maximum size of window that
@ -2705,7 +2746,7 @@
<tr>
<td><pre>-bs &lt;type&gt;</pre></td>
<td>Set "Cartridge.Type" property. See the <a href="#Properties"><b>Game Properties</b></a> section
<td>Set "Cart.Type" property. See the <a href="#Properties"><b>Game Properties</b></a> section
for valid types.</td>
</tr>
@ -2716,27 +2757,27 @@
<tr>
<td><pre>-startbank &lt;bank&gt;</pre></td>
<td>Set "Cartridge.StartBank" property.</td>
<td>Set "Cart.StartBank" property.</td>
</tr>
<tr>
<td><pre>-channels &lt;Mono|Stereo&gt;</pre></td>
<td>Set "Cartridge.Sound" property.</td>
<td>Set "Cart.Sound" property.</td>
</tr>
<tr>
<td><pre>-ld &lt;A|B&gt;</pre></td>
<td>Set "Console.LeftDifficulty" property.</td>
<td>Set "Console.LeftDiff" property.</td>
</tr>
<tr>
<td><pre>-rd &lt;A|B&gt;</pre></td>
<td>Set "Console.RightDifficulty" property.</td>
<td>Set "Console.RightDiff" property.</td>
</tr>
<tr>
<td><pre>-tv &lt;Color|BW&gt;</pre></td>
<td>Set "Console.TelevisionType" property.</td>
<td>Set "Console.TVType" property.</td>
</tr>
<tr>
@ -2943,13 +2984,15 @@
<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>Renderer</td><td>Use specified rendering mode</td><td>-video</td></tr>
<tr><td>Interpolation</td><td>Interpolation of TIA image</td><td>-tia.inter</td></tr>
<tr><td>Zoom</td><td>Zoom level of TIA image</td><td>-tia.zoom</td></tr>
<tr><td>Interpolation</td><td>Enable interpolation of the TIA image</td><td>-tia.inter</td></tr>
<tr><td>Zoom</td><td>Zoom level of the TIA image</td><td>-tia.zoom</td></tr>
<tr><td>Fullscreen</td><td>Self-explanatory - Note that colors may slightly change.
This depends on the OS and renderer used.</td><td>-fullscreen</td></tr>
<tr><td>Stretch</td><td>In fullscreen mode, completely fill screen with TIA image</td><td>-tia.fs_stretch</td></tr>
<tr><td>Stretch</td><td>In fullscreen mode, completely fill screen with the TIA image.</td><td>-tia.fs_stretch</td></tr>
<tr><td>Adapt display...</td><td>In fullscreen mode, adapt the display's refresh rate to the game's frame rate to minimize judder.
</br>Note: Not available for macOS.</td><td>-tia.fs_refresh</td></tr>
<tr><td>Overscan</td><td>In fullscreen mode, add overscan to the TIA image</td><td>-tia.fs_overscan</td></tr>
<tr><td>V-Size adjust</td><td>Adjust height of TIA image</td><td>-tia.vsizeadjust</td></tr>
<tr><td>V-Size adjust</td><td>Adjust height of the TIA image</td><td>-tia.vsizeadjust</td></tr>
</table>
</td>
</tr>
@ -3144,9 +3187,9 @@
<tr><td>Save path</td><td>Specifies where to save snapshots</td><td>-snapsavedir</td></tr>
<!--<tr><td>Load path</td><td>Specifies where to load snapshots</td><td>-snaploaddir</td></tr> -->
<tr><td>Continuous snapshot interval</td><td>Interval (in seconds) between snapshots</td><td>-ssinterval</td></tr>
<tr><td>Use actual ROM name</td><td>Use the actual ROM filename instead of the internal database name.</td><td>-snapname</td></tr>
<tr><td>Use actual ROM name</td><td>Use the actual ROM filename instead of the internal database name</td><td>-snapname</td></tr>
<tr><td>Overwrite existing files</td><td>Whether to overwrite old snapshots</td><td>-sssingle</td></tr>
<tr><td>Ignore scaling (1x mode)</td><td>Save snapshot in 1x mode without scaling</td><td>-ss1x</td></tr>
<tr><td>Create pixel-exact image (no zoom/post-processing)</td><td>Save snapshot using the exact pixels from the TIA image, without zoom or any post-processing effects</td><td>-ss1x</td></tr>
</table>
</td>
</tr>
@ -3933,24 +3976,24 @@ Ms Pac-Man (Stella extended codes):
<p>
<pre>
; Comments
"Cartridge.MD5" "Value"
"Property" "Value"
"Cart.MD5" "Value"
"Property" "Value"
""
; Comments
"Cartridge.MD5" "Value"
"Property" "Value"
"Cart.MD5" "Value"
"Property" "Value"
""
. . .
; Comments
"Cartridge.MD5" "Value"
"Property" "Value"
"Cart.MD5" "Value"
"Property" "Value"
""</pre>
<p>Every block in the property file must have a unique value for the
<i>Cartridge.MD5</i> property.</p>
<i>Cart.MD5</i> property.</p>
<p>
<h2><b>Properties</b></h2>
@ -3964,7 +4007,7 @@ Ms Pac-Man (Stella extended codes):
<table CELLSPACING="10">
<tr>
<td VALIGN="TOP"><a name="PropertiesCartType"><i>Cartridge.Type:</i></a></td>
<td VALIGN="TOP"><a name="PropertiesCartType"><i>Cart.Type:</i></a></td>
<td>Indicates the bank-switching type for the game.
The value of this property must be either <b>Auto</b> or one of the following
(for more information about bank-switching see Kevin Horton's <a href="http://kevtris.org/files/sizes.txt">2600 bankswitching
@ -4019,6 +4062,7 @@ Ms Pac-Man (Stella extended codes):
<tr><td>FE </td><td>8K Decathlon </td><td>.FE </td></tr>
<tr><td>MDM </td><td>Menu Driven Megacart </td><td>.MDM </td></tr>
<tr><td>SB </td><td>128-256K SUPERbanking </td><td>.SB </td></tr>
<tr><td>TVBOY</td><td>512K TV Boy (127 games)</td><td>.TVB, .TVBOY </td></tr>
<tr><td>UA </td><td>8K UA Ltd. </td><td>.UA </td></tr>
<tr><td>UASW </td><td>8K UA Ltd. (swapped banks)</td><td>.UASW </td></tr>
<tr><td>WD </td><td>Wickstead Design (Pink Panther) </td><td>.WD </td></tr>
@ -4028,7 +4072,7 @@ Ms Pac-Man (Stella extended codes):
</tr>
<tr>
<td VALIGN="TOP"><i>Cartridge.StartBank:</i></td>
<td VALIGN="TOP"><i>Cart.StartBank:</i></td>
<td>Indicates which bank to use for reading the reset vector.</td>
</tr>
@ -4052,7 +4096,7 @@ Ms Pac-Man (Stella extended codes):
<tr>
<td VALIGN="TOP"><i>Display.VCenter:</i></td>
<td>Indicates the offset for the vertical center of the display.
The value must be <i>n</i> such that -5 &lt;= <i>n</i> &lt;= 5.
The value must be <i>n</i> such that -20 &lt;= <i>n</i> &lt;= 20.
</td>
</tr>
@ -4070,7 +4114,7 @@ Ms Pac-Man (Stella extended codes):
</tr>
<tr>
<td VALIGN="TOP"><i>Cartridge.Sound:</i></td>
<td VALIGN="TOP"><i>Cart.Sound:</i></td>
<td>Indicates if the game should use 1 or 2 channels for sound output.
All original Atari 2600 machines supported 1 channel only,
but some homebrew games have been written to take advantage of stereo
@ -4089,19 +4133,19 @@ Ms Pac-Man (Stella extended codes):
<table CELLSPACING="10">
<tr>
<td VALIGN="TOP"><i>Console.TelevisionType:</i></td>
<td VALIGN="TOP"><i>Console.TVType:</i></td>
<td>Indicates the default television setting for the
game. The value must be <b>Color</b> or <b>BW</b>.</td>
</tr>
<tr>
<td VALIGN="TOP"><i>Console.LeftDifficulty:</i></td>
<td VALIGN="TOP"><i>Console.LeftDiff:</i></td>
<td>Indicates the default difficulty setting for the left
player. The value must be <b>A</b> or <b>B</b>.</td>
</tr>
<tr>
<td VALIGN="TOP"><i>Console.RightDifficulty:</i></td>
<td VALIGN="TOP"><i>Console.RightDiff:</i></td>
<td>Indicates the default difficulty setting for the
right player. The value must be <b>A</b> or <b>B</b>.</td>
</tr>
@ -4202,14 +4246,14 @@ Ms Pac-Man (Stella extended codes):
</p>
<table CELLSPACING="10">
<tr>
<td VALIGN="TOP"><i>Cartridge.Name:</i></td>
<td VALIGN="TOP"><i>Cart.Name:</i></td>
<td>Indicates the actual name of the game. When you save snapshots,
load/save state files, or use the <a href="#ROMAudit"><b>ROM Audit Mode</b></a> functionality,
this is the name that will be used for the respective file(s).</td>
</tr>
<tr>
<td VALIGN="TOP"><i>Cartridge.MD5:</i></td>
<td VALIGN="TOP"><i>Cart.MD5:</i></td>
<td>Indicates the MD5 checksum of the ROM image as a
string of hexadecimal digits. Stella uses this property while
attempting to match a game with its block of properties. If the
@ -4220,27 +4264,37 @@ Ms Pac-Man (Stella extended codes):
</tr>
<tr>
<td VALIGN="TOP"><i>Cartridge.Manufacturer:</i></td>
<td VALIGN="TOP"><i>Cart.Manufacturer:</i></td>
<td>Indicates the game's manufacturer.</td>
</tr>
<tr>
<td VALIGN="TOP"><i>Cartridge.ModelNo:</i></td>
<td VALIGN="TOP"><i>Cart.ModelNo:</i></td>
<td>Indicates the manufacturer's model number for the game.</td>
</tr>
<tr>
<td VALIGN="TOP"><i>Cartridge.Rarity:</i></td>
<td VALIGN="TOP"><i>Cart.Rarity:</i></td>
<td>Indicates how rare a cartridge is, based on the scale described on AtariAge.</td>
</tr>
<tr>
<td VALIGN="TOP"><i>Cartridge.Note:</i></td>
<td VALIGN="TOP"><i>Cart.Note:</i></td>
<td>Contains any special notes about playing the game.</td>
</tr>
</table>
<p>The buttons at the bottom of the dialogs work as follows:
<ul>
<li><b>Defaults</b>: Reset the properties to those built into Stella.</li>
<li><b>Save</b>: Save the properties for the <i>currently selected ROM only</i>
to a properties file in the users default save directory.</li>
<li><b>OK</b>: Merge/commit any changes into the ROM properties database, which
contains info on all ROMs.</li>
<li><b>Cancel</b>: Revert any changes in the dialog, and cancel the operation.</li>
</ul>
<p>The name of the properties file will depend on the version of Stella, as follows:</p>
<p><table cellpadding="4" border="1">
@ -4261,7 +4315,7 @@ Ms Pac-Man (Stella extended codes):
<td><i>_BASEDIR_/stella.pro</i></td>
</tr>
</table>
<p>Stella will require a restart for changes to this file to take effect.</p>
<p>Note: For manual changes to the property files Stella will require a restart to take effect.</p>
</blockquote></br>
<h2><b><a name="Palette">Palette Support</a></b></h2>

View File

@ -58,7 +58,7 @@
<center><h1>Stella for RetroN 77</h1></center>
<center><h2>Atari 2600 VCS emulator</h2></center>
<center>Release 6.1</center>
<center>Release 6.2.1</center>
<center><h2>Quick Navigation Guide</h2></center>
<br/>

View File

@ -15,6 +15,8 @@
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include <cmath>
#include "SDL_lib.hxx"
#include "bspf.hxx"
#include "Logger.hxx"
@ -99,19 +101,32 @@ void FrameBufferSDL2::queryHardware(vector<Common::Size>& fullscreenRes,
int numModes = SDL_GetNumDisplayModes(i);
ostringstream s;
s << "Supported video modes for display " << i << ":";
Logger::debug(s.str());
s << "Supported video modes (" << numModes << ") for display " << i << ":";
string lastRes = "";
for (int m = 0; m < numModes; m++)
{
SDL_DisplayMode mode;
ostringstream res;
SDL_GetDisplayMode(i, m, &mode);
s.str("");
s << " " << m << ": " << mode.w << "x" << mode.h << "@" << mode.refresh_rate << "Hz";
if (mode.w == display.w && mode.h == display.h && mode.refresh_rate == display.refresh_rate)
s << " (active)";
Logger::debug(s.str());
res << std::setw(4) << mode.w << "x" << std::setw(4) << mode.h;
if(lastRes != res.str())
{
Logger::debug(s.str());
s.str("");
lastRes = res.str();
s << lastRes << ": ";
}
s << mode.refresh_rate << "Hz";
if(mode.w == display.w && mode.h == display.h && mode.refresh_rate == display.refresh_rate)
s << "* ";
else
s << " ";
}
Logger::debug(s.str());
}
// Now get the maximum windowed desktop resolution
@ -218,21 +233,14 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode)
if(SDL_WasInit(SDL_INIT_VIDEO) == 0)
return false;
// TODO: On multiple displays, switching from centered mode, does not respect
// current window's display (which many not be centered anymore)
const bool fullScreen = mode.fsIndex != -1;
bool forceCreateRenderer = false;
// Get windowed window's last display
Int32 displayIndex = std::min(myNumDisplays, myOSystem.settings().getInt(getDisplayKey()));
// Get windowed window's last position
myWindowedPos = myOSystem.settings().getPoint(getPositionKey());
// Always recreate renderer (some systems need this)
if(myRenderer)
{
SDL_DestroyRenderer(myRenderer);
myRenderer = nullptr;
}
int posX, posY;
myCenter = myOSystem.settings().getBool("center");
@ -261,49 +269,45 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode)
posX = BSPF::clamp(posX, x0 - Int32(mode.screen.w) + 50, x1 - 50);
posY = BSPF::clamp(posY, y0 + 50, y1 - 50);
}
uInt32 flags = mode.fsIndex != -1 ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0;
flags |= SDL_WINDOW_ALLOW_HIGHDPI;
// 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 macOS
#ifndef BSPF_MACOS
#ifdef ADAPTABLE_REFRESH_SUPPORT
SDL_DisplayMode adaptedSdlMode;
const bool shouldAdapt = fullScreen && myOSystem.settings().getBool("tia.fs_refresh")
&& gameRefreshRate()
// take care of 59.94 Hz
&& refreshRate() % gameRefreshRate() != 0 && refreshRate() % (gameRefreshRate() - 1) != 0;
const bool adaptRefresh = shouldAdapt && adaptRefreshRate(displayIndex, adaptedSdlMode);
#else
const bool adaptRefresh = false;
#endif
const uInt32 flags = SDL_WINDOW_ALLOW_HIGHDPI
| (fullScreen ? adaptRefresh ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
// Don't re-create the window if its display and size hasn't changed,
// as it's not necessary, and causes flashing in fullscreen mode
if(myWindow)
{
int d = SDL_GetWindowDisplayIndex(myWindow);
const int d = SDL_GetWindowDisplayIndex(myWindow);
int w, h;
SDL_GetWindowSize(myWindow, &w, &h);
if(d != displayIndex || uInt32(w) != mode.screen.w || uInt32(h) != mode.screen.h)
if(d != displayIndex || uInt32(w) != mode.screen.w || uInt32(h) != mode.screen.h
|| adaptRefresh)
{
SDL_DestroyWindow(myWindow);
myWindow = nullptr;
}
}
if(myWindow)
{
// Even though window size stayed the same, the title may have changed
SDL_SetWindowTitle(myWindow, title.c_str());
SDL_SetWindowPosition(myWindow, posX, posY);
}
#else
// 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)
{
SDL_SetWindowFullscreen(myWindow, flags);
SDL_SetWindowSize(myWindow, mode.screen.w, mode.screen.h);
SDL_SetWindowPosition(myWindow, posX, posY);
SDL_SetWindowTitle(myWindow, title.c_str());
}
#endif
else
{
forceCreateRenderer = true;
myWindow = SDL_CreateWindow(title.c_str(), posX, posY,
mode.screen.w, mode.screen.h, flags);
if(myWindow == nullptr)
@ -312,31 +316,133 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode)
Logger::error(msg);
return false;
}
setWindowIcon();
}
#ifdef ADAPTABLE_REFRESH_SUPPORT
if(adaptRefresh)
{
// Switch to mode for adapted refresh rate
if(SDL_SetWindowDisplayMode(myWindow, &adaptedSdlMode) != 0)
{
Logger::error("ERROR: Display refresh rate change failed");
}
else
{
ostringstream msg;
msg << "Display refresh rate changed to " << adaptedSdlMode.refresh_rate << " Hz";
Logger::info(msg.str());
}
}
#endif
return createRenderer(forceCreateRenderer);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adaptedSdlMode)
{
SDL_DisplayMode sdlMode;
if(SDL_GetCurrentDisplayMode(displayIndex, &sdlMode) != 0)
{
Logger::error("ERROR: Display mode could not be retrieved");
return false;
}
const int currentRefreshRate = sdlMode.refresh_rate;
const int wantedRefreshRate = gameRefreshRate();
// Take care of rounded refresh rates (e.g. 59.94 Hz)
float factor = std::min(float(currentRefreshRate) / wantedRefreshRate,
float(currentRefreshRate) / (wantedRefreshRate - 1));
// Calculate difference taking care of integer factors (e.g. 100/120)
float bestDiff = std::abs(factor - std::round(factor)) / factor;
bool adapt = false;
// Display refresh rate should be an integer factor of the game's refresh rate
// Note: Modes are scanned with size being first priority,
// therefore the size will never change.
// Check for integer factors 1 (60/50 Hz) and 2 (120/100 Hz)
for(int m = 1; m <= 2; ++m)
{
SDL_DisplayMode closestSdlMode;
sdlMode.refresh_rate = wantedRefreshRate * m;
if(SDL_GetClosestDisplayMode(displayIndex, &sdlMode, &closestSdlMode) == nullptr)
{
Logger::error("ERROR: Closest display mode could not be retrieved");
return adapt;
}
factor = std::min(float(sdlMode.refresh_rate) / sdlMode.refresh_rate,
float(sdlMode.refresh_rate) / (sdlMode.refresh_rate - 1));
const float diff = std::abs(factor - std::round(factor)) / factor;
if(diff < bestDiff)
{
bestDiff = diff;
adaptedSdlMode = closestSdlMode;
adapt = true;
}
}
//cerr << "refresh rate adapt ";
//if(adapt)
// cerr << "required (" << currentRefreshRate << " Hz -> " << adaptedSdlMode.refresh_rate << " Hz)";
//else
// cerr << "not required/possible";
//cerr << endl;
// Only change if the display supports a better refresh rate
return adapt;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FrameBufferSDL2::createRenderer(bool force)
{
// A new renderer is only created when necessary:
// - new myWindow (force = true)
// - no renderer existing
// - different renderer flags
// - different renderer name
bool recreate = force || myRenderer == nullptr;
uInt32 renderFlags = SDL_RENDERER_ACCELERATED;
const string& video = myOSystem.settings().getString("video"); // Render hint
SDL_RendererInfo renderInfo;
if(myOSystem.settings().getBool("vsync")
&& !myOSystem.settings().getBool("turbo")) // V'synced blits option
renderFlags |= SDL_RENDERER_PRESENTVSYNC;
const string& video = myOSystem.settings().getString("video"); // Render hint
if(video != "")
SDL_SetHint(SDL_HINT_RENDER_DRIVER, video.c_str());
myRenderer = SDL_CreateRenderer(myWindow, -1, renderFlags);
// check renderer flags and name
recreate |= (SDL_GetRendererInfo(myRenderer, &renderInfo) != 0)
|| ((renderInfo.flags & (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC)) != renderFlags
|| (video != renderInfo.name));
detectFeatures();
determineDimensions();
if(myRenderer == nullptr)
if(recreate)
{
string msg = "ERROR: Unable to create SDL renderer: " + string(SDL_GetError());
Logger::error(msg);
return false;
//cerr << "Create new renderer for buffer type #" << int(myBufferType) << endl;
if(myRenderer)
SDL_DestroyRenderer(myRenderer);
if(video != "")
SDL_SetHint(SDL_HINT_RENDER_DRIVER, video.c_str());
myRenderer = SDL_CreateRenderer(myWindow, -1, renderFlags);
detectFeatures();
determineDimensions();
if(myRenderer == nullptr)
{
string msg = "ERROR: Unable to create SDL renderer: " + string(SDL_GetError());
Logger::error(msg);
return false;
}
}
clear();
SDL_RendererInfo renderinfo;
if(SDL_GetRendererInfo(myRenderer, &renderinfo) >= 0)
myOSystem.settings().setValue("video", renderinfo.name);
@ -404,6 +510,36 @@ bool FrameBufferSDL2::fullScreen() const
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int FrameBufferSDL2::refreshRate() const
{
ASSERT_MAIN_THREAD;
const uInt32 displayIndex = SDL_GetWindowDisplayIndex(myWindow);
SDL_DisplayMode sdlMode;
if(SDL_GetCurrentDisplayMode(displayIndex, &sdlMode) == 0)
return sdlMode.refresh_rate;
if(myWindow != nullptr)
Logger::error("Could not retrieve current display mode");
return 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int FrameBufferSDL2::gameRefreshRate() const
{
if(myOSystem.hasConsole())
{
const string format = myOSystem.console().getFormatString();
const bool isNtsc = format == "NTSC" || format == "PAL60" || format == "SECAM60";
return isNtsc ? 60 : 50; // The code will take care of 59/49 Hz
}
return 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSDL2::renderToScreen()
{
@ -416,10 +552,9 @@ void FrameBufferSDL2::renderToScreen()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSDL2::setWindowIcon()
{
ASSERT_MAIN_THREAD;
#if !defined(BSPF_MACOS) && !defined(RETRON77)
#include "stella_icon.hxx"
ASSERT_MAIN_THREAD;
SDL_Surface* surface = SDL_CreateRGBSurfaceFrom(stella_icon, 32, 32, 32,
32 * 4, 0xFF0000, 0x00FF00, 0x0000FF, 0xFF000000);

View File

@ -181,6 +181,25 @@ class FrameBufferSDL2 : public FrameBuffer
*/
bool setVideoMode(const string& title, const VideoMode& mode) override;
/**
Checks if the display refresh rate should be adapted to game refresh rate in (real) fullscreen mode
@param displayIndex The display which should be checked
@param adaptedSdlMode The best matching mode if the refresh rate should be changed
@return True if the refresh rate should be changed
*/
bool adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adaptedSdlMode);
/**
Create a new renderer if required
@param force If true, force new renderer creation
@return False on any errors, else true
*/
bool createRenderer(bool force);
/**
This method is called to create a surface with the given attributes.
@ -233,6 +252,16 @@ class FrameBufferSDL2 : public FrameBuffer
*/
void determineDimensions();
/**
Retrieve the current display's refresh rate, or 0 if no window
*/
int refreshRate() const override;
/**
Retrieve the current game's refresh rate, or 60 if no game
*/
int gameRefreshRate() const;
private:
// The SDL video buffer
SDL_Window* myWindow{nullptr};

View File

@ -687,27 +687,32 @@ void PhysicalJoystickHandler::handleAxisEvent(int stick, int axis, int value)
}
j->axisLastValue[axis] = value;
}
#ifdef GUI_SUPPORT
else if(myHandler.hasOverlay())
{
// First, clamp the values to simulate digital input
// (the only thing that the underlying code understands)
if(value > Joystick::deadzone())
value = 32000;
else if(value < -Joystick::deadzone())
value = -32000;
else
value = 0;
// Now filter out consecutive, similar values
// (only pass on the event if the state has changed)
if(value != j->axisLastValue[axis])
// A value change lower than Joystick::deadzone indicates analog input which is ignored
if((abs(j->axisLastValue[axis] - value) > Joystick::deadzone()))
{
#ifdef GUI_SUPPORT
myHandler.overlay().handleJoyAxisEvent(stick, JoyAxis(axis), convertAxisValue(value), button);
#endif
j->axisLastValue[axis] = value;
// First, clamp the values to simulate digital input
// (the only thing that the underlying code understands)
if(value > Joystick::deadzone())
value = 32000;
else if(value < -Joystick::deadzone())
value = -32000;
else
value = 0;
// Now filter out consecutive, similar values
// (only pass on the event if the state has changed)
if(value != j->axisLastValue[axis])
{
myHandler.overlay().handleJoyAxisEvent(stick, JoyAxis(axis), convertAxisValue(value), button);
}
}
j->axisLastValue[axis] = value;
}
#endif
}
}

View File

@ -39,6 +39,7 @@ PhysicalKeyboardHandler::PhysicalKeyboardHandler(OSystem& system, EventHandler&
myHandler(handler)
{
Int32 version = myOSystem.settings().getInt("event_ver");
bool updateDefaults = false;
// Compare if event list version has changed so that key maps became invalid
if (version == Event::VERSION)
@ -53,11 +54,12 @@ PhysicalKeyboardHandler::PhysicalKeyboardHandler(OSystem& system, EventHandler&
myKeyMap.loadMapping(list, EventMode::kKeypadMode);
list = myOSystem.settings().getString("keymap_ui");
myKeyMap.loadMapping(list, EventMode::kMenuMode);
updateDefaults = true;
}
myKeyMap.enableMod() = myOSystem.settings().getBool("modcombo");
setDefaultMapping(Event::NoType, EventMode::kEmulationMode, true);
setDefaultMapping(Event::NoType, EventMode::kMenuMode, true);
setDefaultMapping(Event::NoType, EventMode::kEmulationMode, updateDefaults);
setDefaultMapping(Event::NoType, EventMode::kMenuMode, updateDefaults);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -443,7 +445,11 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo
{Event::LoadState, KBDK_F11},
{Event::LoadAllStates, KBDK_F11, MOD3},
{Event::TakeSnapshot, KBDK_F12},
#ifdef BSPF_MACOS
{Event::TogglePauseMode, KBDK_P, KBDM_SHIFT | MOD3},
#else
{Event::TogglePauseMode, KBDK_PAUSE},
#endif
{Event::OptionsMenuMode, KBDK_TAB},
{Event::CmdMenuMode, KBDK_BACKSLASH},
{Event::TimeMachineMode, KBDK_T, KBDM_SHIFT},
@ -455,6 +461,7 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo
{Event::Quit, KBDK_Q, KBDM_CTRL},
#endif
{Event::ReloadConsole, KBDK_R, KBDM_CTRL},
{Event::PreviousMultiCartRom, KBDK_R, KBDM_SHIFT | KBDM_CTRL},
{Event::VidmodeDecrease, KBDK_MINUS, MOD3},
{Event::VidmodeIncrease, KBDK_EQUALS, MOD3},
@ -467,6 +474,7 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo
{Event::SoundToggle, KBDK_RIGHTBRACKET, KBDM_CTRL},
{Event::ToggleFullScreen, KBDK_RETURN, MOD3},
{Event::ToggleAdaptRefresh, KBDK_R, MOD3},
{Event::OverscanDecrease, KBDK_PAGEDOWN, KBDM_SHIFT},
{Event::OverscanIncrease, KBDK_PAGEUP, KBDM_SHIFT},
//{Event::VidmodeStd, KBDK_1, MOD3},
@ -497,9 +505,13 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo
#ifndef BSPF_MACOS
{Event::PreviousSetting, KBDK_END},
{Event::NextSetting, KBDK_HOME},
{Event::PreviousSettingGroup, KBDK_END, KBDM_CTRL},
{Event::NextSettingGroup, KBDK_HOME, KBDM_CTRL},
#else
{Event::PreviousSetting, KBDK_HOME},
{Event::NextSetting, KBDK_END},
{Event::PreviousSettingGroup, KBDK_HOME, KBDM_CTRL},
{Event::NextSettingGroup, KBDK_END, KBDM_CTRL},
#endif
{Event::SettingDecrease, KBDK_PAGEDOWN},
{Event::SettingIncrease, KBDK_PAGEUP},

View File

@ -89,7 +89,7 @@ void PNGLibrary::loadImage(const string& filename, FBSurface& surface)
}
else if(color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
{
loadImageERROR("Greyscale PNG images not supported");
png_set_gray_to_rgb(png_ptr);
}
else if(color_type == PNG_COLOR_TYPE_PALETTE)
{

View File

@ -139,7 +139,7 @@ void PaletteHandler::changeCurrentAdjustable(int direction)
{
int newVal = scaleTo100(*myAdjustables[myCurrentAdjustable].value);
newVal = BSPF::clamp(newVal + direction * 2, 0, 100);
newVal = BSPF::clamp(newVal + direction * 1, 0, 100);
*myAdjustables[myCurrentAdjustable].value = scaleFrom100(newVal);
@ -385,7 +385,7 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing)
for(int chroma = 1; chroma < NUM_CHROMA; chroma++)
{
color[chroma][0] = SATURATION * sinf(offset + shift * (chroma - 1));
color[chroma][1] = SATURATION * sinf(offset + shift * (chroma - 1 - BSPF::PI_f));
color[chroma][1] = SATURATION * cosf(offset + shift * (chroma - 1) - BSPF::PI_f);
}
for(int chroma = 0; chroma < NUM_CHROMA; chroma++)

View File

@ -125,8 +125,8 @@ class PaletteHandler
/**
Convert adjustables from/to 100% scale
*/
constexpr float scaleFrom100(float x) const { return (x / 50.F) - 1.F; }
constexpr uInt32 scaleTo100(float x) const { return uInt32(50 * (x + 1.F)); }
static constexpr float scaleFrom100(float x) { return (x / 50.F) - 1.F; }
static constexpr uInt32 scaleTo100(float x) { return uInt32(50.0001F * (x + 1.F)); }
/**
Convert palette settings name to enumeration.

View File

@ -18,7 +18,7 @@
#ifndef STATE_MANAGER_HXX
#define STATE_MANAGER_HXX
#define STATE_HEADER "06010000state"
#define STATE_HEADER "06020100state"
class OSystem;
class RewindManager;

View File

@ -18,7 +18,7 @@
#ifndef VERSION_HXX
#define VERSION_HXX
#define STELLA_VERSION "6.2_pre"
#define STELLA_BUILD "5741"
#define STELLA_VERSION "6.2.1"
#define STELLA_BUILD "6041"
#endif

View File

@ -297,7 +297,7 @@ class ZipHandler
void addToCache();
private:
static constexpr uInt32 DECOMPRESS_BUFSIZE = 16_KB;
static constexpr size_t DECOMPRESS_BUFSIZE = 16_KB;
static constexpr uInt32 CACHE_SIZE = 8; // number of open files to cache
ZipFilePtr myZip;

View File

@ -90,9 +90,9 @@ using DWordBuffer = std::unique_ptr<uInt32[]>; // NOLINT
using AdjustFunction = std::function<void(int)>;
// We use KB a lot; let's make a literal for it
constexpr uInt32 operator "" _KB(unsigned long long size)
constexpr size_t operator "" _KB(unsigned long long size)
{
return static_cast<uInt32>(size * 1024);
return static_cast<size_t>(size * 1024);
}
static const string EmptyString("");
@ -101,6 +101,12 @@ static const string EmptyString("");
#undef PAGE_SIZE
#undef PAGE_MASK
// Adaptable refresh is currently not available on MacOS
// In the future, this may expand to other systems
#if !defined(BSPF_MACOS)
#define ADAPTABLE_REFRESH_SUPPORT
#endif
namespace BSPF
{
static constexpr float PI_f = 3.141592653589793238462643383279502884F;
@ -122,6 +128,21 @@ namespace BSPF
static const string ARCH = "NOARCH";
#endif
// Get next power of two greater than or equal to the given value
inline size_t nextPowerOfTwo(size_t size) {
if(size < 2) return 1;
size_t power2 = 1;
while(power2 < size)
power2 <<= 1;
return power2;
}
// Get next multiple of the given value
// Note that this only works when multiple is a power of two
inline size_t nextMultipleOf(size_t size, size_t multiple) {
return (size + multiple - 1) & ~(multiple - 1);
}
// Make 2D-arrays using std::array less verbose
template<typename T, size_t ROW, size_t COL>
using array2D = std::array<std::array<T, COL>, ROW>;

View File

@ -20,8 +20,8 @@
#include "NTSCFilter.hxx"
constexpr float scaleFrom100(float x) { return (x/50.F) - 1.F; }
constexpr uInt32 scaleTo100(float x) { return uInt32(50*(x+1.F)); }
constexpr float scaleFrom100(float x) { return (x / 50.F) - 1.F; }
constexpr uInt32 scaleTo100(float x) { return uInt32(50.0001F * (x + 1.F)); }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string NTSCFilter::setPreset(Preset preset)
@ -119,7 +119,7 @@ void NTSCFilter::changeCurrentAdjustable(int direction,
// return "'Custom' TV mode not selected";
newValue = scaleTo100(*ourCustomAdjustables[myCurrentAdjustable].value);
newValue = BSPF::clamp(newValue + direction * 2, 0, 100);
newValue = BSPF::clamp(newValue + direction * 1, 0, 100);
*ourCustomAdjustables[myCurrentAdjustable].value = scaleFrom100(newValue);

View File

@ -112,6 +112,8 @@ string DebuggerParser::run(const string& command)
if(validateArgs(i))
{
myCommand = i;
if(commands[i].refreshRequired)
debugger.baseDialog()->saveConfig();
commands[i].executor(this);
}
@ -1733,6 +1735,8 @@ void DebuggerParser::executeRunTo()
const CartDebug& cartdbg = debugger.cartDebug();
const CartDebug::DisassemblyList& list = cartdbg.disassembly().list;
debugger.saveOldState();
uInt32 count = 0, max_iterations = uInt32(list.size());
// Create a progress dialog box to show the progress searching through the
@ -1776,6 +1780,8 @@ void DebuggerParser::executeRunToPc()
const CartDebug& cartdbg = debugger.cartDebug();
const CartDebug::DisassemblyList& list = cartdbg.disassembly().list;
debugger.saveOldState();
uInt32 count = 0;
bool done = false;
constexpr uInt32 max_iterations = 1000000;

View File

@ -35,18 +35,18 @@ string Cartridge3EPlusWidget::description()
{
ostringstream info;
size_t size;
const uInt8* image = myCart.getImage(size);
const ByteBuffer& image = myCart.getImage(size);
uInt16 numRomBanks = myCart.romBankCount();
uInt16 numRamBanks = myCart.ramBankCount();
info << "3E+ cartridge - (4..64K ROM + RAM)\n"
info << "3E+ cartridge - (4" << ELLIPSIS << "64K ROM + RAM)\n"
<< " " << numRomBanks << " 1K ROM banks + " << numRamBanks << " 512b RAM banks\n"
<< " mapped into four segments\n"
"ROM bank & segment selected by writing to $3F\n"
"RAM bank & segment selected by writing to $3E\n"
" Lower 512b of segment for read access\n"
" Upper 512b of segment for write access\n"
"Startup bank = 0/-1/-1/0 (ROM)\n";
"Startup bank = -1/-1/-1/0 (ROM)\n";
// Eventually, we should query this from the debugger/disassembler
uInt16 start = (image[0x400 - 3] << 8) | image[0x400 - 4];
@ -60,7 +60,8 @@ string Cartridge3EPlusWidget::description()
void Cartridge3EPlusWidget::bankSelect(int& ypos)
{
size_t size;
const uInt8* image = myCart.getImage(size);
const ByteBuffer& image = myCart.getImage(size);
const int VGAP = myFontHeight / 4;
VariantList banktype;
VarList::push_back(banktype, "ROM", "ROM");
@ -68,6 +69,8 @@ void Cartridge3EPlusWidget::bankSelect(int& ypos)
myBankWidgets = make_unique<PopUpWidget* []>(bankSegs());
ypos -= VGAP * 2;
for(uInt32 seg = 0; seg < bankSegs(); ++seg)
{
int xpos = 2, xpos_s, ypos_s = ypos + 1, width;
@ -77,20 +80,25 @@ void Cartridge3EPlusWidget::bankSelect(int& ypos)
label << "Set segment " << seg << " as ";
new StaticTextWidget(_boss, _font, xpos, ypos, label.str());
ypos += myLineHeight + 8;
ypos += myLineHeight + VGAP * 2;
xpos += _font.getMaxCharWidth() * 2;
CartridgeEnhancedWidget::bankList(myCart.romBankCount(), seg, items, width);
CartridgeEnhancedWidget::bankList(std::max(myCart.romBankCount(), myCart.ramBankCount()),
seg, items, width);
myBankWidgets[seg] =
new PopUpWidget(_boss, _font, xpos, ypos - 2, width,
myLineHeight, items, "Bank ");
myLineHeight, items, "Bank ", 0, kBankChanged);
myBankWidgets[seg]->setID(seg);
myBankWidgets[seg]->setTarget(this);
addFocusWidget(myBankWidgets[seg]);
xpos += myBankWidgets[seg]->getWidth();
myBankType[seg] =
new PopUpWidget(_boss, _font, xpos, ypos - 2, 3 * _font.getMaxCharWidth(),
myLineHeight, banktype, " of ");
myLineHeight, banktype, " of ", 0, kRomRamChanged);
myBankType[seg]->setID(seg);
myBankType[seg]->setTarget(this);
addFocusWidget(myBankType[seg]);
xpos = myBankType[seg]->getRight() + _font.getMaxCharWidth();
@ -98,7 +106,8 @@ void Cartridge3EPlusWidget::bankSelect(int& ypos)
// add "Commit" button (why required?)
myBankCommit[seg] = new ButtonWidget(_boss, _font, xpos, ypos - 4,
_font.getStringWidth(" Commit "), myButtonHeight,
"Commit", bankEnum[seg]);
"Commit", kChangeBank);
myBankCommit[seg]->setID(seg);
myBankCommit[seg]->setTarget(this);
addFocusWidget(myBankCommit[seg]);
@ -117,7 +126,7 @@ void Cartridge3EPlusWidget::bankSelect(int& ypos)
myBankState[2 * seg] = new EditTextWidget(_boss, _font, xoffset, ypos_s,
_w - xoffset - 10, myLineHeight, "");
myBankState[2 * seg]->setEditable(false, true);
ypos_s += myLineHeight + 4;
ypos_s += myLineHeight + VGAP;
label.str("");
label << "$" << Common::Base::HEX4 << addr2 << "-$" << Common::Base::HEX4 << (addr2 + 0x1FF);
@ -127,7 +136,7 @@ void Cartridge3EPlusWidget::bankSelect(int& ypos)
_w - xoffset - 10, myLineHeight, "");
myBankState[2 * seg + 1]->setEditable(false, true);
ypos += 2 * myLineHeight;
ypos += myLineHeight + VGAP * 4;
}
}
@ -142,42 +151,44 @@ void Cartridge3EPlusWidget::loadConfig()
void Cartridge3EPlusWidget::handleCommand(CommandSender* sender,
int cmd, int data, int id)
{
uInt16 segment = 0;
const uInt16 segment = id;
switch(cmd)
{
case kBank0Changed:
segment = 0;
case kBankChanged:
case kRomRamChanged:
{
const bool isROM = myBankType[segment]->getSelectedTag() == "ROM";
int bank = myBankWidgets[segment]->getSelected();
myBankCommit[segment]->setEnabled((isROM && bank < myCart.romBankCount())
|| (!isROM && bank < myCart.ramBankCount()));
break;
case kBank1Changed:
segment = 1;
break;
case kBank2Changed:
segment = 2;
break;
case kBank3Changed:
segment = 3;
}
case kChangeBank:
{
// Ignore bank if either number or type hasn't been selected
if(myBankWidgets[segment]->getSelected() < 0 ||
myBankType[segment]->getSelected() < 0)
return;
uInt8 bank = myBankWidgets[segment]->getSelected();
myCart.unlockBank();
if(myBankType[segment]->getSelectedTag() == "ROM")
myCart.bank(bank, segment);
else
myCart.bank(bank + myCart.romBankCount(), segment);
myCart.lockBank();
invalidate();
updateUIState();
break;
}
default:
break;
}
// Ignore bank if either number or type hasn't been selected
if(myBankWidgets[segment]->getSelected() < 0 ||
myBankType[segment]->getSelected() < 0)
return;
uInt8 bank = myBankWidgets[segment]->getSelected();
myCart.unlockBank();
if(myBankType[segment]->getSelectedTag() == "ROM")
myCart.bank(bank, segment);
else
myCart.bank(bank + myCart.romBankCount(), segment);
myCart.lockBank();
invalidate();
updateUIState();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -234,8 +245,3 @@ string Cartridge3EPlusWidget::internalRamDescription()
return desc.str();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const std::array<Cartridge3EPlusWidget::BankID, 4> Cartridge3EPlusWidget::bankEnum = {
kBank0Changed, kBank1Changed, kBank2Changed, kBank3Changed
};

View File

@ -56,13 +56,10 @@ class Cartridge3EPlusWidget : public CartridgeEnhancedWidget
std::array<ButtonWidget*, 4> myBankCommit{nullptr};
std::array<EditTextWidget*, 8> myBankState{nullptr};
enum BankID {
kBank0Changed = 'b0CH',
kBank1Changed = 'b1CH',
kBank2Changed = 'b2CH',
kBank3Changed = 'b3CH'
enum {
kRomRamChanged = 'rrCh',
kChangeBank = 'chBk',
};
static const std::array<BankID, 4> bankEnum;
private:
// Following constructors and assignment operators not supported

View File

@ -33,7 +33,7 @@ string Cartridge3EWidget::description()
{
ostringstream info;
size_t size;
const uInt8* image = myCart.getImage(size);
const ByteBuffer& image = myCart.getImage(size);
uInt16 numRomBanks = myCart.romBankCount();
uInt16 numRamBanks = myCart.ramBankCount();

View File

@ -33,7 +33,7 @@ string Cartridge3FWidget::description()
{
ostringstream info;
size_t size;
const uInt8* image = myCart.getImage(size);
const ByteBuffer& image = myCart.getImage(size);
info << "Tigervision 3F cartridge, 2 - 256 2K banks\n"
<< "First 2K bank selected by writing to " << hotspotStr() << "\n"

View File

@ -94,7 +94,7 @@ string CartridgeEnhancedWidget::romDescription()
{
ostringstream info;
size_t size;
const uInt8* image = myCart.getImage(size);
const ByteBuffer& image = myCart.getImage(size);
if(myCart.romBankCount() > 1)
{
@ -125,7 +125,7 @@ string CartridgeEnhancedWidget::romDescription()
start -= start % std::min(int(size), 0x1000);
end = start + uInt16(myCart.mySize) - 1;
// special check for ROMs where the extra RAM is not included in the image (e.g. CV).
if((start & 0xFFF) < size)
if((start & 0xFFFU) < size)
{
start += myCart.myRomOffset;
}

View File

@ -74,7 +74,6 @@ CartRamWidget::CartRamWidget(
myDesc->setEditable(false);
myDesc->setEnabled(false);
myDesc->setList(sl);
addFocusWidget(myDesc);
ypos += myDesc->getHeight() + myFontHeight / 2;

View File

@ -0,0 +1,79 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include "CartTVBoy.hxx"
#include "PopUpWidget.hxx"
#include "CartTVBoyWidget.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeTVBoyWidget::CartridgeTVBoyWidget(
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
int x, int y, int w, int h, CartridgeTVBoy& cart)
: CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart),
myCartTVBoy(cart)
{
initialize();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string CartridgeTVBoyWidget::description()
{
ostringstream info;
info << "TV Boy, " << myCart.romBankCount() << " 4K banks\n"
<< "Hotspots are from $" << Common::Base::HEX2 << 0xf800 << " to $"
<< Common::Base::HEX2 << (0xf800 + myCart.romBankCount() - 1) << "\n";
info << CartridgeEnhancedWidget::description();
return info.str();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeTVBoyWidget::bankSelect(int& ypos)
{
CartridgeEnhancedWidget::bankSelect(ypos);
int xpos = myBankWidgets[0]->getRight() + _font.getMaxCharWidth() * 4;
ypos = myBankWidgets[0]->getTop();
myBankLocked = new CheckboxWidget(_boss, _font, xpos, ypos + 1,
"Bankswitching is locked",
kBankLocked);
myBankLocked->setTarget(this);
addFocusWidget(myBankLocked);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeTVBoyWidget::loadConfig()
{
myBankWidgets[0]->setEnabled(!myCartTVBoy.myBankingDisabled);
myBankLocked->setState(myCartTVBoy.myBankingDisabled);
CartridgeEnhancedWidget::loadConfig();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeTVBoyWidget::handleCommand(CommandSender* sender,
int cmd, int data, int id)
{
if(cmd == kBankLocked)
{
myCartTVBoy.myBankingDisabled = myBankLocked->getState();
myBankWidgets[0]->setEnabled(!myCartTVBoy.myBankingDisabled);
}
else
CartridgeEnhancedWidget::handleCommand(sender, cmd, data, id);
}

View File

@ -0,0 +1,62 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#ifndef CARTRIDGETVBOY_WIDGET_HXX
#define CARTRIDGETVBOY_WIDGET_HXX
class CartridgeTVBoy;
class CheckboxWidget;
#include "CartEnhancedWidget.hxx"
class CartridgeTVBoyWidget : public CartridgeEnhancedWidget
{
public:
CartridgeTVBoyWidget(GuiObject* boss, const GUI::Font& lfont,
const GUI::Font& nfont,
int x, int y, int w, int h,
CartridgeTVBoy& cart);
virtual ~CartridgeTVBoyWidget() = default;
private:
string manufacturer() override { return "Akor"; }
string description() override;
void bankSelect(int& ypos) override;
CartridgeTVBoy& myCartTVBoy;
CheckboxWidget* myBankLocked{nullptr};
enum {
kBankLocked = 'bkLO'
};
private:
void loadConfig() override;
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
private:
// Following constructors and assignment operators not supported
CartridgeTVBoyWidget() = delete;
CartridgeTVBoyWidget(const CartridgeTVBoyWidget&) = delete;
CartridgeTVBoyWidget(CartridgeTVBoyWidget&&) = delete;
CartridgeTVBoyWidget& operator=(const CartridgeTVBoyWidget&) = delete;
CartridgeTVBoyWidget& operator=(CartridgeTVBoyWidget&&) = delete;
};
#endif

View File

@ -251,6 +251,7 @@ void DebuggerDialog::handleCommand(CommandSender* sender, int cmd,
break;
case kDDOptionsCmd:
saveConfig();
myOptions->open();
loadConfig();
break;

View File

@ -165,13 +165,16 @@ void RomWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void RomWidget::toggleBreak(int disasm_line)
{
Debugger& debugger = instance().debugger();
const CartDebug::DisassemblyList& list =
instance().debugger().cartDebug().disassembly().list;
debugger.cartDebug().disassembly().list;
if(disasm_line >= int(list.size())) return;
if(list[disasm_line].address != 0 && list[disasm_line].bytes != "")
instance().debugger().toggleBreakPoint(list[disasm_line].address,
instance().debugger().cartDebug().getBank(list[disasm_line].address));
const uInt16 address = list[disasm_line].address;
if(address != 0)
debugger.toggleBreakPoint(address, debugger.cartDebug().getBank(address));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -179,7 +179,7 @@ void TiaOutputWidget::drawWidget(bool hilite)
bool visible = instance().console().tia().electronBeamPos(scanx, scany);
scanoffset = width * scany + scanx;
uInt8* tiaOutputBuffer = instance().console().tia().outputBuffer();
TIASurface& tiaSurface(instance().frameBuffer().tiaSurface());
const TIASurface& tiaSurface = instance().frameBuffer().tiaSurface();
for(uInt32 y = 0, i = yStart * width; y < height; ++y)
{

View File

@ -48,6 +48,7 @@ MODULE_OBJS := \
src/debugger/gui/CartMDMWidget.o \
src/debugger/gui/CartRamWidget.o \
src/debugger/gui/CartSBWidget.o \
src/debugger/gui/CartTVBoyWidget.o \
src/debugger/gui/CartUAWidget.o \
src/debugger/gui/CartWDWidget.o \
src/debugger/gui/CartX07Widget.o \

View File

@ -141,6 +141,7 @@ Bankswitch::BSList = {{
{ "FE" , "FE (8K Decathlon)" },
{ "MDM" , "MDM (Menu Driven Megacart)" },
{ "SB" , "SB (128-256K SUPERbank)" },
{ "TVBOY" , "TV Boy (512K)" },
{ "UA" , "UA (8K UA Ltd.)" },
{ "UASW" , "UASW (8K UA swapped banks)" },
{ "WD" , "WD (Pink Panther)" },
@ -226,6 +227,8 @@ Bankswitch::ExtensionMap Bankswitch::ourExtensions = {
{ "FE" , Bankswitch::Type::_FE },
{ "MDM" , Bankswitch::Type::_MDM },
{ "SB" , Bankswitch::Type::_SB },
{ "TVB" , Bankswitch::Type::_TVBOY },
{ "TVBOY" , Bankswitch::Type::_TVBOY },
{ "UA" , Bankswitch::Type::_UA },
{ "UASW" , Bankswitch::Type::_UASW },
{ "WD" , Bankswitch::Type::_WD },
@ -282,6 +285,7 @@ Bankswitch::NameToTypeMap Bankswitch::ourNameToTypes = {
{ "FE" , Bankswitch::Type::_FE },
{ "MDM" , Bankswitch::Type::_MDM },
{ "SB" , Bankswitch::Type::_SB },
{ "TVBOY" , Bankswitch::Type::_TVBOY },
{ "UA" , Bankswitch::Type::_UA },
{ "UASW" , Bankswitch::Type::_UASW },
{ "WD" , Bankswitch::Type::_WD },

View File

@ -38,14 +38,14 @@ class Bankswitch
public:
// Currently supported bankswitch schemes
enum class Type {
_AUTO, _0840, _2IN1, _4IN1, _8IN1, _16IN1, _32IN1,
_64IN1, _128IN1, _2K, _3E, _3EX, _3EP, _3F,
_4A50, _4K, _4KSC, _AR, _BF, _BFSC, _BUS,
_CDF, _CM, _CTY, _CV, _DF, _DFSC, _DPC,
_DPCP, _E0, _E7, _E78K, _EF, _EFSC, _F0,
_F4, _F4SC, _F6, _F6SC, _F8, _F8SC, _FA,
_FA2, _FC, _FE, _MDM, _SB, _UA, _UASW,
_WD, _WDSW, _X07,
_AUTO, _0840, _2IN1, _4IN1, _8IN1, _16IN1, _32IN1,
_64IN1, _128IN1, _2K, _3E, _3EX, _3EP, _3F,
_4A50, _4K, _4KSC, _AR, _BF, _BFSC, _BUS,
_CDF, _CM, _CTY, _CV, _DF, _DFSC, _DPC,
_DPCP, _E0, _E7, _E78K, _EF, _EFSC, _F0,
_F4, _F4SC, _F6, _F6SC, _F8, _F8SC, _FA,
_FA2, _FC, _FE, _MDM, _SB, _TVBOY, _UA,
_UASW, _WD, _WDSW, _X07,
#ifdef CUSTOM_ARM
_CUSTOM,
#endif

View File

@ -56,14 +56,14 @@ bool Cartridge::saveROM(ofstream& out) const
{
size_t size = 0;
const uInt8* image = getImage(size);
if(image == nullptr || size == 0)
const ByteBuffer& image = getImage(size);
if(size == 0)
{
cerr << "save not supported" << endl;
return false;
}
out.write(reinterpret_cast<const char*>(image), size);
out.write(reinterpret_cast<const char*>(image.get()), size);
return true;
}
@ -80,10 +80,10 @@ bool Cartridge::bankChanged()
uInt16 Cartridge::bankSize(uInt16 bank) const
{
size_t size;
getImage(size);
return std::min(uInt32(size) / romBankCount(), 4_KB); // assuming that each bank has the same size
return static_cast<uInt16>(
std::min(size / romBankCount(), 4_KB)); // assuming that each bank has the same size
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -48,6 +48,9 @@ class Cartridge : public Device
public:
using StartBankFromPropsFunc = std::function<int()>;
// Maximum size of a ROM cart that Stella can support
static constexpr size_t maxSize() { return 512_KB; }
public:
/**
Create a new cartridge
@ -140,7 +143,6 @@ class Cartridge : public Device
*/
uInt16 getIllegalRAMWriteAccess() const { return myRamWriteAccess; }
/**
Query the access counters
@ -169,8 +171,13 @@ class Cartridge : public Device
scheme defines banks in a standard format (ie, 0 for first bank,
1 for second, etc). Carts which will handle their own bankswitching
completely or non-bankswitched carts can ignore this method.
@param bank The bank that should be installed in the system
@param segment The segment the bank should be using
@return true, if bank has changed
*/
virtual bool bank(uInt16) { return false; }
virtual bool bank(uInt16 bank, uInt16 segment = 0) { return false; }
/**
Get the current bank for the provided address. Carts which have only
@ -197,7 +204,6 @@ class Cartridge : public Device
*/
virtual uInt16 romBankCount() const { return 1; }
/**
Query the number of RAM 'banks' supported by the cartridge. Note that
this information is cart-specific, where each cart basically defines
@ -226,9 +232,9 @@ class Cartridge : public Device
Access the internal ROM image for this cartridge.
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
@return A reference to the internal ROM image data
*/
virtual const uInt8* getImage(size_t& size) const = 0;
virtual const ByteBuffer& getImage(size_t& size) const = 0;
/**
Get a descriptor for the cart name.

View File

@ -20,8 +20,9 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge0840::Cartridge0840(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: CartridgeEnhanced(image, size, md5, settings)
const string& md5, const Settings& settings,
size_t bsSize)
: CartridgeEnhanced(image, size, md5, settings, bsSize)
{
}

View File

@ -44,9 +44,10 @@ class Cartridge0840 : public CartridgeEnhanced
@param size The size of the ROM image
@param md5 The md5sum of the ROM image
@param settings A reference to the various settings (read-only)
@param bsSize The size specified by the bankswitching scheme
*/
Cartridge0840(const ByteBuffer& image, size_t size, const string& md5,
const Settings& settings);
const Settings& settings, size_t bsSize = 8_KB);
virtual ~Cartridge0840() = default;
public:

View File

@ -20,12 +20,15 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge2K::Cartridge2K(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: CartridgeEnhanced(image, size, md5, settings)
const string& md5, const Settings& settings,
size_t bsSize)
: CartridgeEnhanced(image, size, md5, settings, bsSize)
{
// When creating a 2K cart, we always initially create a buffer of size 2_KB
// Sometimes we only use a portion of that buffer; we check for that now
// Size can be a maximum of 2K
if(size > 2_KB)
size = 2_KB;
size = std::min(size, bsSize);
// Set image size to closest power-of-two for the given size
mySize = 1; myBankShift = 0;
@ -35,24 +38,14 @@ Cartridge2K::Cartridge2K(const ByteBuffer& image, size_t size,
myBankShift++;
}
// Initialize ROM with illegal 6502 opcode that causes a real 6502 to jam
size_t bufSize = std::max<size_t>(mySize, System::PAGE_SIZE);
myImage = make_unique<uInt8[]>(bufSize);
std::fill_n(myImage.get(), bufSize, 0x02);
// Handle cases where ROM is smaller than the page size
// It's much easier to do it this way rather than changing the page size
if(mySize >= System::PAGE_SIZE)
{
// Directly copy the ROM image into the buffer
std::copy_n(image.get(), mySize, myImage.get());
}
else
if(mySize < System::PAGE_SIZE)
{
// Manually 'mirror' the ROM image into the buffer
for(size_t i = 0; i < System::PAGE_SIZE; i += mySize)
std::copy_n(image.get(), mySize, myImage.get() + i);
mySize = System::PAGE_SIZE;
myBankShift = 6;
myBankShift = System::PAGE_SHIFT;
}
}

View File

@ -47,9 +47,10 @@ class Cartridge2K : public CartridgeEnhanced
@param size The size of the ROM image (<= 2048 bytes)
@param md5 The md5sum of the ROM image
@param settings A reference to the various settings (read-only)
@param bsSize The size specified by the bankswitching scheme
*/
Cartridge2K(const ByteBuffer& image, size_t size, const string& md5,
const Settings& settings);
const Settings& settings, size_t bsSize = 2_KB);
virtual ~Cartridge2K() = default;
public:

View File

@ -21,8 +21,10 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge3E::Cartridge3E(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: CartridgeEnhanced(image, size, md5, settings)
const string& md5, const Settings& settings,
size_t bsSize)
: CartridgeEnhanced(image, size, md5, settings,
bsSize == 0 ? BSPF::nextMultipleOf(size, 2_KB) : bsSize)
{
myBankShift = BANK_SHIFT;
myRamSize = RAM_SIZE;

View File

@ -65,15 +65,17 @@ class Cartridge3E : public CartridgeEnhanced
public:
/**
Create a new cartridge using the specified image and size
Create a new cartridge using the specified image and size.
@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)
@param bsSize The size specified by the bankswitching scheme
(where 0 means variable-sized ROM)
*/
Cartridge3E(const ByteBuffer& image, size_t size, const string& md5,
const Settings& settings);
const Settings& settings, size_t bsSize = 0);
virtual ~Cartridge3E() = default;
public:

View File

@ -21,8 +21,10 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge3EPlus::Cartridge3EPlus(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: Cartridge3E(image, size, md5, settings)
const string& md5, const Settings& settings,
size_t bsSize)
: Cartridge3E(image, size, md5, settings,
bsSize == 0 ? BSPF::nextMultipleOf(size, 1_KB) : bsSize)
{
myBankShift = BANK_SHIFT;
myRamSize = RAM_SIZE;
@ -34,7 +36,7 @@ void Cartridge3EPlus::reset()
{
CartridgeEnhanced::reset();
// 1st segment in mapped to start bank in CartridgeEnhanced
bank(mySystem->randGenerator().next() % romBankCount(), 0);
bank(mySystem->randGenerator().next() % romBankCount(), 1);
bank(mySystem->randGenerator().next() % romBankCount(), 2);
bank(startBank(), 3);

View File

@ -42,7 +42,7 @@ class System;
ROM:
Note: in descriptions $F000 is equivalent to $1000 -- that is, we only deal
Note: In descriptions $F000 is equivalent to $1000 -- that is, we only deal
with the low 13 bits of addressing. Stella code uses $1000, I'm used to $F000
So, mask with top bits clear :) when reading this document.
@ -51,16 +51,10 @@ class System;
The last 1K ROM ($FC00-$FFFF) segment in the 6502 address space (ie: $1C00-$1FFF)
is initialised to point to the FIRST 1K of the ROM image, so the reset vectors
must be placed at the end of the first 1K in the ROM image. Note, this is
DIFFERENT to 3E which switches in the UPPER bank and this bank is fixed. This
allows variable sized ROM without having to detect size. First bank (0) in ROM is
the default fixed bank mapped to $FC00.
must be placed at the end of the first 1K in the ROM image.
The system requires the reset vectors to be valid on a reset, so either the
hardware first switches in the first bank, or the programmer must ensure
that the reset vector is present in ALL ROM banks which might be switched
into the last bank area. Currently the latter (programmer onus) is required,
but it would be nice for the cartridge hardware to auto-switch on reset.
Note: This is DIFFERENT to 3E which switches in the UPPER bank and this bank is
fixed. This allows variable sized ROM without having to detect size.
ROM switching (write of block+bank number to $3F) D7D6 upper 2 bits of bank #
indicates the destination segment (0-3, corresponding to $F000, $F400, $F800,
@ -100,9 +94,11 @@ class Cartridge3EPlus: public Cartridge3E
@param size The size of the ROM image
@param md5 The md5sum of the ROM image
@param settings A reference to the various settings (read-only)
@param bsSize The size specified by the bankswitching scheme
(where 0 means variable-sized ROM)
*/
Cartridge3EPlus(const ByteBuffer& image, size_t size, const string& md5,
const Settings& settings);
const Settings& settings, size_t bsSize = 0);
virtual ~Cartridge3EPlus() = default;
public:

View File

@ -21,8 +21,10 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge3F::Cartridge3F(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: CartridgeEnhanced(image, size, md5, settings)
const string& md5, const Settings& settings,
size_t bsSize)
: CartridgeEnhanced(image, size, md5, settings,
bsSize == 0 ? BSPF::nextPowerOfTwo(size) : bsSize)
{
myBankShift = BANK_SHIFT;
}

View File

@ -50,9 +50,11 @@ class Cartridge3F : public CartridgeEnhanced
@param size The size of the ROM image
@param md5 The md5sum of the ROM image
@param settings A reference to the various settings (read-only)
@param bsSize The size specified by the bankswitching scheme
(where 0 means variable-sized ROM)
*/
Cartridge3F(const ByteBuffer& image, size_t size, const string& md5,
const Settings& settings);
const Settings& settings, size_t bsSize = 0);
virtual ~Cartridge3F() = default;
public:

View File

@ -24,6 +24,7 @@
Cartridge4A50::Cartridge4A50(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: Cartridge(settings, md5),
myImage(make_unique<uInt8[]>(128_KB)),
mySize(size)
{
// Copy the ROM image into my buffer
@ -32,7 +33,7 @@ Cartridge4A50::Cartridge4A50(const ByteBuffer& image, size_t size,
else if(size < 128_KB) size = 64_KB;
else size = 128_KB;
for(uInt32 slice = 0; slice < 128_KB / size; ++slice)
std::copy_n(image.get(), size, myImage.begin() + (slice*size));
std::copy_n(image.get(), size, myImage.get() + (slice*size));
// We use System::PageAccess.romAccessBase, but don't allow its use
// through a pointer, since the address space of 4A50 carts can change
@ -41,7 +42,7 @@ Cartridge4A50::Cartridge4A50(const ByteBuffer& image, size_t size,
//
// Instead, access will be through the getAccessFlags and setAccessFlags
// methods below
createRomAccessArrays(myImage.size() + myRAM.size());
createRomAccessArrays(128_KB + myRAM.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -350,10 +351,10 @@ bool Cartridge4A50::patch(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt8* Cartridge4A50::getImage(size_t& size) const
const ByteBuffer& Cartridge4A50::getImage(size_t& size) const
{
size = mySize;
return myImage.data();
return myImage;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -96,9 +96,9 @@ class Cartridge4A50 : public Cartridge
Access the internal ROM image for this cartridge.
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
@return A reference to the internal ROM image data
*/
const uInt8* getImage(size_t& size) const override;
const ByteBuffer& getImage(size_t& size) const override;
/**
Save the current state of this cart to the given Serializer.
@ -220,7 +220,7 @@ class Cartridge4A50 : public Cartridge
private:
// The 128K ROM image of the cartridge
std::array<uInt8, 128_KB> myImage;
ByteBuffer myImage;
// The 32K of RAM on the cartridge
std::array<uInt8, 32_KB> myRAM;

View File

@ -20,7 +20,8 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge4K::Cartridge4K(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: CartridgeEnhanced(image, size, md5, settings)
const string& md5, const Settings& settings,
size_t bsSize)
: CartridgeEnhanced(image, size, md5, settings, bsSize)
{
}

View File

@ -44,9 +44,10 @@ class Cartridge4K : public CartridgeEnhanced
@param size The size of the ROM image
@param md5 The md5sum of the ROM image
@param settings A reference to the various settings (read-only)
@param bsSize The size specified by the bankswitching scheme
*/
Cartridge4K(const ByteBuffer& image, size_t size, const string& md5,
const Settings& settings);
const Settings& settings, size_t bsSize = 4_KB);
virtual ~Cartridge4K() = default;
public:

View File

@ -20,8 +20,9 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge4KSC::Cartridge4KSC(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: Cartridge4K(image, size, md5, settings)
const string& md5, const Settings& settings,
size_t bsSize)
: Cartridge4K(image, size, md5, settings, bsSize)
{
myRamSize = RAM_SIZE;
}

View File

@ -45,9 +45,10 @@ class Cartridge4KSC : public Cartridge4K
@param size The size of the ROM image
@param md5 The md5sum of the ROM image
@param settings A reference to the various settings (read-only)
@param bsSize The size specified by the bankswitching scheme
*/
Cartridge4KSC(const ByteBuffer& image, size_t size, const string& md5,
const Settings& settings);
const Settings& settings, size_t bsSize = 4_KB);
virtual ~Cartridge4KSC() = default;
public:

View File

@ -392,7 +392,7 @@ void CartridgeAR::loadIntoRAM(uInt8 load)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeAR::bank(uInt16 bank)
bool CartridgeAR::bank(uInt16 bank, uInt16)
{
if(!bankLocked())
return bankConfiguration(uInt8(bank));
@ -420,10 +420,10 @@ bool CartridgeAR::patch(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt8* CartridgeAR::getImage(size_t& size) const
const ByteBuffer& CartridgeAR::getImage(size_t& size) const
{
size = mySize;
return myLoadImages.get();
return myLoadImages;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -73,9 +73,12 @@ class CartridgeAR : public Cartridge
/**
Install pages for the specified bank in the system.
@param bank The bank that should be installed in the system
@param bank The bank that should be installed in the system
@param segment The segment the bank should be using
@return true, if bank has changed
*/
bool bank(uInt16 bank) override;
bool bank(uInt16 bank, uInt16 segment = 0) override;
/**
Get the current bank.
@ -102,9 +105,9 @@ class CartridgeAR : public Cartridge
Access the internal ROM image for this cartridge.
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
@return A reference to the internal ROM image data
*/
const uInt8* getImage(size_t& size) const override;
const ByteBuffer& getImage(size_t& size) const override;
/**
Save the current state of this cart to the given Serializer.

View File

@ -20,8 +20,9 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeBF::CartridgeBF(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: CartridgeEnhanced(image, size, md5, settings)
const string& md5, const Settings& settings,
size_t bsSize)
: CartridgeEnhanced(image, size, md5, settings, bsSize)
{
}

View File

@ -45,9 +45,10 @@ class CartridgeBF : public CartridgeEnhanced
@param size The size of the ROM image
@param md5 The md5sum of the ROM image
@param settings A reference to the various settings (read-only)
@param bsSize The size specified by the bankswitching scheme
*/
CartridgeBF(const ByteBuffer& image, size_t size, const string& md5,
const Settings& settings);
const Settings& settings, size_t bsSize = 256_KB);
virtual ~CartridgeBF() = default;
public:

View File

@ -20,8 +20,9 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeBFSC::CartridgeBFSC(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: CartridgeBF(image, size, md5, settings)
const string& md5, const Settings& settings,
size_t bsSize)
: CartridgeBF(image, size, md5, settings, bsSize)
{
myRamSize = RAM_SIZE;
}

View File

@ -45,9 +45,10 @@ class CartridgeBFSC : public CartridgeBF
@param size The size of the ROM image
@param md5 The md5sum of the ROM image
@param settings A reference to the various settings (read-only)
@param bsSize The size specified by the bankswitching scheme
*/
CartridgeBFSC(const ByteBuffer& image, size_t size, const string& md5,
const Settings& settings);
const Settings& settings, size_t bsSize = 256_KB);
virtual ~CartridgeBFSC() = default;
/**

View File

@ -43,17 +43,18 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeBUS::CartridgeBUS(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: Cartridge(settings, md5)
: Cartridge(settings, md5),
myImage(make_unique<uInt8[]>(32_KB))
{
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
std::copy_n(image.get(), std::min(32_KB, size), myImage.get());
// Even though the ROM is 32K, only 28K is accessible to the 6507
createRomAccessArrays(28_KB);
// Pointer to the program ROM (28K @ 0 byte offset)
// which starts after the 2K BUS Driver and 2K C Code
myProgramImage = myImage.data() + 4_KB;
myProgramImage = myImage.get() + 4_KB;
// Pointer to BUS driver in RAM
myDriverImage = myRAM.data();
@ -64,9 +65,9 @@ CartridgeBUS::CartridgeBUS(const ByteBuffer& image, size_t size,
// Create Thumbulator ARM emulator
bool devSettings = settings.getBool("dev.settings");
myThumbEmulator = make_unique<Thumbulator>(
reinterpret_cast<uInt16*>(myImage.data()),
reinterpret_cast<uInt16*>(myImage.get()),
reinterpret_cast<uInt16*>(myRAM.data()),
static_cast<uInt32>(myImage.size()),
static_cast<uInt32>(32_KB),
devSettings ? settings.getBool("dev.thumb.trapfatal") : false, Thumbulator::ConfigureFor::BUS, this
);
@ -95,7 +96,7 @@ void CartridgeBUS::reset()
void CartridgeBUS::setInitialState()
{
// Copy initial BUS driver to Harmony RAM
std::copy_n(myImage.begin(), 2_KB, myDriverImage);
std::copy_n(myImage.get(), 2_KB, myDriverImage);
myMusicWaveformSize.fill(27);
@ -429,7 +430,7 @@ bool CartridgeBUS::poke(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeBUS::bank(uInt16 bank)
bool CartridgeBUS::bank(uInt16 bank, uInt16)
{
if(bankLocked()) return false;
@ -478,10 +479,10 @@ bool CartridgeBUS::patch(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt8* CartridgeBUS::getImage(size_t& size) const
const ByteBuffer& CartridgeBUS::getImage(size_t& size) const
{
size = myImage.size();
return myImage.data();
size = 32_KB;
return myImage;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -84,9 +84,12 @@ class CartridgeBUS : public Cartridge
/**
Install pages for the specified bank in the system.
@param bank The bank that should be installed in the system
@param bank The bank that should be installed in the system
@param segment The segment the bank should be using
@return true, if bank has changed
*/
bool bank(uInt16 bank) override;
bool bank(uInt16 bank, uInt16 segment = 0) override;
/**
Get the current bank.
@ -113,9 +116,9 @@ class CartridgeBUS : public Cartridge
Access the internal ROM image for this cartridge.
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
@return A reference to the internal ROM image data
*/
const uInt8* getImage(size_t& size) const override;
const ByteBuffer& getImage(size_t& size) const override;
/**
Save the current state of this cart to the given Serializer.
@ -211,7 +214,7 @@ class CartridgeBUS : public Cartridge
private:
// The 32K ROM image of the cartridge
std::array<uInt8, 32_KB> myImage;
ByteBuffer myImage;
// Pointer to the 28K program ROM image of the cartridge
uInt8* myProgramImage{nullptr};

View File

@ -59,17 +59,19 @@ namespace {
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeCDF::CartridgeCDF(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: Cartridge(settings, md5)
: Cartridge(settings, md5),
myImage(make_unique<uInt8[]>(32_KB))
{
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
std::fill_n(myImage.get(), 32_KB, 0);
std::copy_n(image.get(), std::min(32_KB, size), myImage.get());
// even though the ROM is 32K, only 28K is accessible to the 6507
createRomAccessArrays(28_KB);
// Pointer to the program ROM (28K @ 0 byte offset)
// which starts after the 2K CDF Driver and 2K C Code
myProgramImage = myImage.data() + 4_KB;
myProgramImage = myImage.get() + 4_KB;
// Pointer to CDF driver in RAM
myDriverImage = myRAM.data();
@ -82,9 +84,9 @@ CartridgeCDF::CartridgeCDF(const ByteBuffer& image, size_t size,
// Create Thumbulator ARM emulator
bool devSettings = settings.getBool("dev.settings");
myThumbEmulator = make_unique<Thumbulator>(
reinterpret_cast<uInt16*>(myImage.data()),
reinterpret_cast<uInt16*>(myImage.get()),
reinterpret_cast<uInt16*>(myRAM.data()),
static_cast<uInt32>(myImage.size()),
static_cast<uInt32>(32_KB),
devSettings ? settings.getBool("dev.thumb.trapfatal") : false, thumulatorConfiguration(myCDFSubtype), this);
setInitialState();
@ -111,7 +113,7 @@ void CartridgeCDF::reset()
void CartridgeCDF::setInitialState()
{
// Copy initial CDF driver to Harmony RAM
std::copy_n(myImage.begin(), 2_KB, myDriverImage);
std::copy_n(myImage.get(), 2_KB, myDriverImage);
myMusicWaveformSize.fill(27);
@ -402,7 +404,7 @@ bool CartridgeCDF::poke(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeCDF::bank(uInt16 bank)
bool CartridgeCDF::bank(uInt16 bank, uInt16)
{
if(bankLocked()) return false;
@ -451,10 +453,10 @@ bool CartridgeCDF::patch(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt8* CartridgeCDF::getImage(size_t& size) const
const ByteBuffer& CartridgeCDF::getImage(size_t& size) const
{
size = myImage.size();
return myImage.data();
size = 32_KB;
return myImage;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -90,9 +90,12 @@ class CartridgeCDF : public Cartridge
/**
Install pages for the specified bank in the system.
@param bank The bank that should be installed in the system
@param bank The bank that should be installed in the system
@param segment The segment the bank should be using
@return true, if bank has changed
*/
bool bank(uInt16 bank) override;
bool bank(uInt16 bank, uInt16 segment = 0) override;
/**
Get the current bank.
@ -119,9 +122,9 @@ class CartridgeCDF : public Cartridge
Access the internal ROM image for this cartridge.
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
@return A reference to the internal ROM image data
*/
const uInt8* getImage(size_t& size) const override;
const ByteBuffer& getImage(size_t& size) const override;
/**
Save the current state of this cart to the given Serializer.
@ -211,7 +214,7 @@ class CartridgeCDF : public Cartridge
private:
// The 32K ROM image of the cartridge
std::array<uInt8, 32_KB> myImage;
ByteBuffer myImage;
// Pointer to the 28K program ROM image of the cartridge
uInt8* myProgramImage{nullptr};

View File

@ -23,11 +23,12 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeCM::CartridgeCM(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: Cartridge(settings, md5)
: Cartridge(settings, md5),
myImage(make_unique<uInt8[]>(16_KB))
{
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createRomAccessArrays(myImage.size());
std::copy_n(image.get(), std::min(16_KB, size), myImage.get());
createRomAccessArrays(16_KB);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -98,7 +99,7 @@ uInt8 CartridgeCM::column() const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeCM::bank(uInt16 bank)
bool CartridgeCM::bank(uInt16 bank, uInt16)
{
if(bankLocked()) return false;
@ -184,10 +185,10 @@ bool CartridgeCM::patch(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt8* CartridgeCM::getImage(size_t& size) const
const ByteBuffer& CartridgeCM::getImage(size_t& size) const
{
size = myImage.size();
return myImage.data();
size = 16_KB;
return myImage;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -141,9 +141,12 @@ class CartridgeCM : public Cartridge
/**
Install pages for the specified bank in the system.
@param bank The bank that should be installed in the system
@param bank The bank that should be installed in the system
@param segment The segment the bank should be using
@return true, if bank has changed
*/
bool bank(uInt16 bank) override;
bool bank(uInt16 bank, uInt16 segment = 0) override;
/**
Get the current bank.
@ -170,9 +173,9 @@ class CartridgeCM : public Cartridge
Access the internal ROM image for this cartridge.
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
@return A reference to the internal ROM image data
*/
const uInt8* getImage(size_t& size) const override;
const ByteBuffer& getImage(size_t& size) const override;
/**
Save the current state of this cart to the given Serializer.
@ -243,7 +246,7 @@ class CartridgeCM : public Cartridge
shared_ptr<CompuMate> myCompuMate;
// The 16K ROM image of the cartridge
std::array<uInt8, 16_KB> myImage;
ByteBuffer myImage;
// The 2K of RAM
std::array<uInt8, 2_KB> myRAM;

View File

@ -24,18 +24,19 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeCTY::CartridgeCTY(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: Cartridge(settings, md5)
: Cartridge(settings, md5),
myImage(make_unique<uInt8[]>(32_KB))
{
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createRomAccessArrays(myImage.size());
std::copy_n(image.get(), std::min(32_KB, size), myImage.get());
createRomAccessArrays(32_KB);
// Default to no tune data in case user is utilizing an old ROM
myTuneData.fill(0);
// Extract tune data if it exists
if(size > myImage.size())
std::copy_n(image.get() + myImage.size(), size - myImage.size(), myTuneData.begin());
if(size > 32_KB)
std::copy_n(image.get() + 32_KB, size - 32_KB, myTuneData.begin());
// Point to the first tune
myFrequencyImage = myTuneData.data();
@ -229,7 +230,7 @@ bool CartridgeCTY::poke(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeCTY::bank(uInt16 bank)
bool CartridgeCTY::bank(uInt16 bank, uInt16)
{
if(bankLocked()) return false;
@ -279,10 +280,10 @@ bool CartridgeCTY::patch(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt8* CartridgeCTY::getImage(size_t& size) const
const ByteBuffer& CartridgeCTY::getImage(size_t& size) const
{
size = myImage.size();
return myImage.data();
size = 32_KB;
return myImage;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -139,9 +139,12 @@ class CartridgeCTY : public Cartridge
/**
Install pages for the specified bank in the system.
@param bank The bank that should be installed in the system
@param bank The bank that should be installed in the system
@param segment The segment the bank should be using
@return true, if bank has changed
*/
bool bank(uInt16 bank) override;
bool bank(uInt16 bank, uInt16 segment = 0) override;
/**
Get the current bank.
@ -168,9 +171,9 @@ class CartridgeCTY : public Cartridge
Access the internal ROM image for this cartridge.
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
@return A reference to the internal ROM image data
*/
const uInt8* getImage(size_t& size) const override;
const ByteBuffer& getImage(size_t& size) const override;
/**
Save the current state of this cart to the given Serializer.
@ -260,7 +263,7 @@ class CartridgeCTY : public Cartridge
private:
// The 32K ROM image of the cartridge
std::array<uInt8, 32_KB> myImage;
ByteBuffer myImage;
// The 28K ROM image of the music
std::array<uInt8, 28_KB> myTuneData;

View File

@ -20,24 +20,21 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeCV::CartridgeCV(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: CartridgeEnhanced(image, size, md5, settings)
const string& md5, const Settings& settings,
size_t bsSize)
: CartridgeEnhanced(image, size, md5, settings, bsSize)
{
myBankShift = BANK_SHIFT;
myRamSize = RAM_SIZE;
myRamWpHigh = RAM_HIGH_WP;
if(mySize == 4_KB)
if(size == 4_KB)
{
// The game has something saved in the RAM
// Useful for MagiCard program listings
// Allocate array for the ROM image
mySize = 2_KB;
myImage = make_unique<uInt8[]>(mySize);
// Copy the ROM image into my buffer
std::copy_n(image.get() + mySize, mySize, myImage.get());
std::copy_n(image.get() + 2_KB, 2_KB, myImage.get());
myInitialRAM = make_unique<uInt8[]>(1_KB);
// Copy the RAM image into a buffer for use in reset()

View File

@ -47,9 +47,10 @@ class CartridgeCV : public CartridgeEnhanced
@param size The size of the ROM image
@param md5 The md5sum of the ROM image
@param settings A reference to the various settings (read-only)
@param bsSize The size specified by the bankswitching scheme
*/
CartridgeCV(const ByteBuffer& image, size_t size, const string& md5,
const Settings& settings);
const Settings& settings, size_t bsSize = 2_KB);
virtual ~CartridgeCV() = default;
public:

348
src/emucore/CartCreator.cxx Normal file
View File

@ -0,0 +1,348 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include "bspf.hxx"
#include "Cart.hxx"
#include "Cart0840.hxx"
#include "Cart2K.hxx"
#include "Cart3E.hxx"
#include "Cart3EX.hxx"
#include "Cart3EPlus.hxx"
#include "Cart3F.hxx"
#include "Cart4A50.hxx"
#include "Cart4K.hxx"
#include "Cart4KSC.hxx"
#include "CartAR.hxx"
#include "CartBF.hxx"
#include "CartBFSC.hxx"
#include "CartBUS.hxx"
#include "CartCDF.hxx"
#include "CartCM.hxx"
#include "CartCTY.hxx"
#include "CartCV.hxx"
#include "CartDF.hxx"
#include "CartDFSC.hxx"
#include "CartDPC.hxx"
#include "CartDPCPlus.hxx"
#include "CartE0.hxx"
#include "CartE7.hxx"
#include "CartE78K.hxx"
#include "CartEF.hxx"
#include "CartEFSC.hxx"
#include "CartF0.hxx"
#include "CartF4.hxx"
#include "CartF4SC.hxx"
#include "CartF6.hxx"
#include "CartF6SC.hxx"
#include "CartF8.hxx"
#include "CartF8SC.hxx"
#include "CartFA.hxx"
#include "CartFA2.hxx"
#include "CartFC.hxx"
#include "CartFE.hxx"
#include "CartMDM.hxx"
#include "CartSB.hxx"
#include "CartTVBoy.hxx"
#include "CartUA.hxx"
#include "CartWD.hxx"
#include "CartX07.hxx"
#include "MD5.hxx"
#include "Props.hxx"
#include "Logger.hxx"
#include "OSystem.hxx"
#include "CartDetector.hxx"
#include "CartCreator.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unique_ptr<Cartridge> CartCreator::create(const FilesystemNode& file,
const ByteBuffer& image, size_t size, string& md5,
const string& propertiesType, Settings& settings)
{
unique_ptr<Cartridge> cartridge;
Bankswitch::Type type = Bankswitch::nameToType(propertiesType),
detectedType = type;
string id;
// Collect some info about the ROM
ostringstream buf;
// First inspect the file extension itself
// If a valid type is found, it will override the one passed into this method
Bankswitch::Type typeByName = Bankswitch::typeFromExtension(file);
if(typeByName != Bankswitch::Type::_AUTO)
type = detectedType = typeByName;
// See if we should try to auto-detect the cartridge type
// If we ask for extended info, always do an autodetect
if(type == Bankswitch::Type::_AUTO || settings.getBool("rominfo"))
{
detectedType = CartDetector::autodetectType(image, size);
if(type != Bankswitch::Type::_AUTO && type != detectedType)
cerr << "Auto-detection not consistent: "
<< Bankswitch::typeToName(type) << ", "
<< Bankswitch::typeToName(detectedType) << endl;
type = detectedType;
buf << Bankswitch::typeToName(type) << "*";
}
else
buf << Bankswitch::typeToName(type);
// Check for multicart first; if found, get the correct part of the image
switch(type)
{
case Bankswitch::Type::_2IN1:
// Make sure we have a valid sized image
if(size == 2*2_KB || size == 2*4_KB || size == 2*8_KB || size == 2*16_KB)
{
cartridge =
createFromMultiCart(image, size, 2, md5, detectedType, id, settings);
buf << id;
}
else
throw runtime_error("Invalid cart size for type '" +
Bankswitch::typeToName(type) + "'");
break;
case Bankswitch::Type::_4IN1:
// Make sure we have a valid sized image
if(size == 4*2_KB || size == 4*4_KB || size == 4*8_KB)
{
cartridge =
createFromMultiCart(image, size, 4, md5, detectedType, id, settings);
buf << id;
}
else
throw runtime_error("Invalid cart size for type '" +
Bankswitch::typeToName(type) + "'");
break;
case Bankswitch::Type::_8IN1:
// Make sure we have a valid sized image
if(size == 8*2_KB || size == 8*4_KB || size == 8*8_KB)
{
cartridge =
createFromMultiCart(image, size, 8, md5, detectedType, id, settings);
buf << id;
}
else
throw runtime_error("Invalid cart size for type '" +
Bankswitch::typeToName(type) + "'");
break;
case Bankswitch::Type::_16IN1:
// Make sure we have a valid sized image
if(size == 16*2_KB || size == 16*4_KB || size == 16*8_KB)
{
cartridge =
createFromMultiCart(image, size, 16, md5, detectedType, id, settings);
buf << id;
}
else
throw runtime_error("Invalid cart size for type '" +
Bankswitch::typeToName(type) + "'");
break;
case Bankswitch::Type::_32IN1:
// Make sure we have a valid sized image
if(size == 32*2_KB || size == 32*4_KB)
{
cartridge =
createFromMultiCart(image, size, 32, md5, detectedType, id, settings);
buf << id;
}
else
throw runtime_error("Invalid cart size for type '" +
Bankswitch::typeToName(type) + "'");
break;
case Bankswitch::Type::_64IN1:
// Make sure we have a valid sized image
if(size == 64*2_KB || size == 64*4_KB)
{
cartridge =
createFromMultiCart(image, size, 64, md5, detectedType, id, settings);
buf << id;
}
else
throw runtime_error("Invalid cart size for type '" +
Bankswitch::typeToName(type) + "'");
break;
case Bankswitch::Type::_128IN1:
// Make sure we have a valid sized image
if(size == 128*2_KB || size == 128*4_KB)
{
cartridge =
createFromMultiCart(image, size, 128, md5, detectedType, id, settings);
buf << id;
}
else
throw runtime_error("Invalid cart size for type '" +
Bankswitch::typeToName(type) + "'");
break;
default:
cartridge = createFromImage(image, size, detectedType, md5, settings);
break;
}
if(size < 1_KB)
buf << " (" << size << "B) ";
else
buf << " (" << (size/1_KB) << "K) ";
cartridge->setAbout(buf.str(), Bankswitch::typeToName(type), id);
return cartridge;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unique_ptr<Cartridge>
CartCreator::createFromMultiCart(const ByteBuffer& image, size_t& size,
uInt32 numroms, string& md5, Bankswitch::Type type, string& id, Settings& settings)
{
// Get a piece of the larger image
uInt32 i = settings.getInt("romloadcount");
// Move to the next game
if(!settings.getBool("romloadprev"))
i = (i + 1) % numroms;
else
i = (i - 1) % numroms;
settings.setValue("romloadcount", i);
size /= numroms;
ByteBuffer slice = make_unique<uInt8[]>(size);
std::copy_n(image.get()+i*size, size, slice.get());
// We need a new md5 and name
md5 = MD5::hash(slice, uInt32(size)); // FIXME
ostringstream buf;
buf << " [G" << (i+1) << "]";
id = buf.str();
if(size <= 2_KB) type = Bankswitch::Type::_2K;
else if(size == 4_KB) type = Bankswitch::Type::_4K;
else if(size == 8_KB) type = Bankswitch::Type::_F8;
else /* default */ type = Bankswitch::Type::_4K;
return createFromImage(slice, size, type, md5, settings);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unique_ptr<Cartridge>
CartCreator::createFromImage(const ByteBuffer& image, size_t size, Bankswitch::Type type,
const string& md5, Settings& settings)
{
// We should know the cart's type by now so let's create it
switch(type)
{
case Bankswitch::Type::_0840:
return make_unique<Cartridge0840>(image, size, md5, settings);
case Bankswitch::Type::_2K:
return make_unique<Cartridge2K>(image, size, md5, settings);
case Bankswitch::Type::_3E:
return make_unique<Cartridge3E>(image, size, md5, settings);
case Bankswitch::Type::_3EX:
return make_unique<Cartridge3EX>(image, size, md5, settings);
case Bankswitch::Type::_3EP:
return make_unique<Cartridge3EPlus>(image, size, md5, settings);
case Bankswitch::Type::_3F:
return make_unique<Cartridge3F>(image, size, md5, settings);
case Bankswitch::Type::_4A50:
return make_unique<Cartridge4A50>(image, size, md5, settings);
case Bankswitch::Type::_4K:
return make_unique<Cartridge4K>(image, size, md5, settings);
case Bankswitch::Type::_4KSC:
return make_unique<Cartridge4KSC>(image, size, md5, settings);
case Bankswitch::Type::_AR:
return make_unique<CartridgeAR>(image, size, md5, settings);
case Bankswitch::Type::_BF:
return make_unique<CartridgeBF>(image, size, md5, settings);
case Bankswitch::Type::_BFSC:
return make_unique<CartridgeBFSC>(image, size, md5, settings);
case Bankswitch::Type::_BUS:
return make_unique<CartridgeBUS>(image, size, md5, settings);
case Bankswitch::Type::_CDF:
return make_unique<CartridgeCDF>(image, size, md5, settings);
case Bankswitch::Type::_CM:
return make_unique<CartridgeCM>(image, size, md5, settings);
case Bankswitch::Type::_CTY:
return make_unique<CartridgeCTY>(image, size, md5, settings);
case Bankswitch::Type::_CV:
return make_unique<CartridgeCV>(image, size, md5, settings);
case Bankswitch::Type::_DF:
return make_unique<CartridgeDF>(image, size, md5, settings);
case Bankswitch::Type::_DFSC:
return make_unique<CartridgeDFSC>(image, size, md5, settings);
case Bankswitch::Type::_DPC:
return make_unique<CartridgeDPC>(image, size, md5, settings);
case Bankswitch::Type::_DPCP:
return make_unique<CartridgeDPCPlus>(image, size, md5, settings);
case Bankswitch::Type::_E0:
return make_unique<CartridgeE0>(image, size, md5, settings);
case Bankswitch::Type::_E7:
return make_unique<CartridgeE7>(image, size, md5, settings);
case Bankswitch::Type::_E78K:
return make_unique<CartridgeE78K>(image, size, md5, settings);
case Bankswitch::Type::_EF:
return make_unique<CartridgeEF>(image, size, md5, settings);
case Bankswitch::Type::_EFSC:
return make_unique<CartridgeEFSC>(image, size, md5, settings);
case Bankswitch::Type::_F0:
return make_unique<CartridgeF0>(image, size, md5, settings);
case Bankswitch::Type::_F4:
return make_unique<CartridgeF4>(image, size, md5, settings);
case Bankswitch::Type::_F4SC:
return make_unique<CartridgeF4SC>(image, size, md5, settings);
case Bankswitch::Type::_F6:
return make_unique<CartridgeF6>(image, size, md5, settings);
case Bankswitch::Type::_F6SC:
return make_unique<CartridgeF6SC>(image, size, md5, settings);
case Bankswitch::Type::_F8:
return make_unique<CartridgeF8>(image, size, md5, settings);
case Bankswitch::Type::_F8SC:
return make_unique<CartridgeF8SC>(image, size, md5, settings);
case Bankswitch::Type::_FA:
return make_unique<CartridgeFA>(image, size, md5, settings);
case Bankswitch::Type::_FA2:
return make_unique<CartridgeFA2>(image, size, md5, settings);
case Bankswitch::Type::_FC:
return make_unique<CartridgeFC>(image, size, md5, settings);
case Bankswitch::Type::_FE:
return make_unique<CartridgeFE>(image, size, md5, settings);
case Bankswitch::Type::_MDM:
return make_unique<CartridgeMDM>(image, size, md5, settings);
case Bankswitch::Type::_UA:
return make_unique<CartridgeUA>(image, size, md5, settings);
case Bankswitch::Type::_UASW:
return make_unique<CartridgeUA>(image, size, md5, settings, true);
case Bankswitch::Type::_SB:
return make_unique<CartridgeSB>(image, size, md5, settings);
case Bankswitch::Type::_TVBOY:
return make_unique<CartridgeTVBoy>(image, size, md5, settings);
case Bankswitch::Type::_WD:
case Bankswitch::Type::_WDSW:
return make_unique<CartridgeWD>(image, size, md5, settings);
case Bankswitch::Type::_X07:
return make_unique<CartridgeX07>(image, size, md5, settings);
default:
return nullptr; // The remaining types have already been handled
}
}

View File

@ -0,0 +1,96 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#ifndef CARTRIDGE_CREATOR_HXX
#define CARTRIDGE_CREATOR_HXX
class Cartridge;
class Properties;
class Settings;
#include "Bankswitch.hxx"
#include "bspf.hxx"
/**
Create a cartridge based on the given information. Internally, it will
use autodetection and various heuristics to determine the cart type.
@author Stephen Anthony
*/
class CartCreator
{
public:
/**
Create a new cartridge object allocated on the heap. The
type of cartridge created depends on the properties object.
@param image A pointer to the ROM image
@param size The size of the ROM image
@param md5 The md5sum for the given ROM image (can be updated)
@param dtype The detected bankswitch type of the ROM image
@param settings The settings container
@return Pointer to the new cartridge object allocated on the heap
*/
static unique_ptr<Cartridge> create(const FilesystemNode& file,
const ByteBuffer& image, size_t size, string& md5,
const string& dtype, Settings& settings);
private:
/**
Create a cartridge from a multi-cart image pointer; internally this
takes a slice of the ROM image ues that for the cartridge.
@param image A pointer to the complete ROM image
@param size The size of the ROM image slice
@param numroms The number of ROMs in the multicart
@param md5 The md5sum for the slice of the ROM image
@param type The detected type of the slice of the ROM image
@param id The ID for the slice of the ROM image
@param settings The settings container
@return Pointer to the new cartridge object allocated on the heap
*/
static unique_ptr<Cartridge>
createFromMultiCart(const ByteBuffer& image, size_t& size,
uInt32 numroms, string& md5, Bankswitch::Type type, string& id,
Settings& settings);
/**
Create a cartridge from the entire image pointer.
@param image A pointer to the complete ROM image
@param size The size of the ROM image
@param type The bankswitch type of the ROM image
@param md5 The md5sum for the ROM image
@param settings The settings container
@return Pointer to the new cartridge object allocated on the heap
*/
static unique_ptr<Cartridge>
createFromImage(const ByteBuffer& image, size_t size, Bankswitch::Type type,
const string& md5, Settings& settings);
private:
// Following constructors and assignment operators not supported
CartCreator() = delete;
CartCreator(const CartCreator&) = delete;
CartCreator(CartCreator&&) = delete;
CartCreator& operator=(const CartCreator&) = delete;
CartCreator& operator=(CartCreator&&) = delete;
};
#endif

View File

@ -20,8 +20,9 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeDF::CartridgeDF(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: CartridgeEnhanced(image, size, md5, settings)
const string& md5, const Settings& settings,
size_t bsSize)
: CartridgeEnhanced(image, size, md5, settings, bsSize)
{
}

View File

@ -45,9 +45,10 @@ class CartridgeDF : public CartridgeEnhanced
@param size The size of the ROM image
@param md5 The md5sum of the ROM image
@param settings A reference to the various settings (read-only)
@param bsSize The size specified by the bankswitching scheme
*/
CartridgeDF(const ByteBuffer& image, size_t size, const string& md5,
const Settings& settings);
const Settings& settings, size_t bsSize = 128_KB);
virtual ~CartridgeDF() = default;
public:

View File

@ -20,8 +20,9 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeDFSC::CartridgeDFSC(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: CartridgeDF(image, size, md5, settings)
const string& md5, const Settings& settings,
size_t bsSize)
: CartridgeDF(image, size, md5, settings, bsSize)
{
myRamSize = RAM_SIZE;
}

View File

@ -45,9 +45,10 @@ class CartridgeDFSC : public CartridgeDF
@param size The size of the ROM image
@param md5 The md5sum of the ROM image
@param settings A reference to the various settings (read-only)
@param bsSize The size specified by the bankswitching scheme
*/
CartridgeDFSC(const ByteBuffer& image, size_t size, const string& md5,
const Settings& settings);
const Settings& settings, size_t bsSize = 128_KB);
virtual ~CartridgeDFSC() = default;
public:

View File

@ -22,8 +22,9 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeDPC::CartridgeDPC(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: CartridgeF8(image, size, md5, settings)
const string& md5, const Settings& settings,
size_t bsSize)
: CartridgeF8(image, size, md5, settings, bsSize)
{
}

View File

@ -46,9 +46,10 @@ class CartridgeDPC : public CartridgeF8
@param size The size of the ROM image
@param md5 The md5sum of the ROM image
@param settings A reference to the various settings (read-only)
@param bsSize The size specified by the bankswitching scheme
*/
CartridgeDPC(const ByteBuffer& image, size_t size, const string& md5,
const Settings& settings);
const Settings& settings, size_t bsSize = 10_KB);
virtual ~CartridgeDPC() = default;
public:

View File

@ -29,17 +29,18 @@
CartridgeDPCPlus::CartridgeDPCPlus(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: Cartridge(settings, md5),
mySize(std::min(size, myImage.size()))
myImage(make_unique<uInt8[]>(32_KB)),
mySize(std::min(size, 32_KB))
{
// Image is always 32K, but in the case of ROM > 29K, the image is
// Image is always 32K, but in the case of ROM < 32K, the image is
// copied to the end of the buffer
if(mySize < myImage.size())
myImage.fill(0);
std::copy_n(image.get(), size, myImage.begin() + (myImage.size() - mySize));
if(mySize < 32_KB)
std::fill_n(myImage.get(), mySize, 0);
std::copy_n(image.get(), size, myImage.get() + (32_KB - mySize));
createRomAccessArrays(24_KB);
// Pointer to the program ROM (24K @ 3K offset; ignore first 3K)
myProgramImage = myImage.data() + 3_KB;
myProgramImage = myImage.get() + 3_KB;
// Pointer to the display RAM
myDisplayImage = myDPCRAM.data() + 3_KB;
@ -50,9 +51,9 @@ CartridgeDPCPlus::CartridgeDPCPlus(const ByteBuffer& image, size_t size,
// Create Thumbulator ARM emulator
bool devSettings = settings.getBool("dev.settings");
myThumbEmulator = make_unique<Thumbulator>
(reinterpret_cast<uInt16*>(myImage.data()),
(reinterpret_cast<uInt16*>(myImage.get()),
reinterpret_cast<uInt16*>(myDPCRAM.data()),
static_cast<uInt32>(myImage.size()),
static_cast<uInt32>(32_KB),
devSettings ? settings.getBool("dev.thumb.trapfatal") : false,
Thumbulator::ConfigureFor::DPCplus,
this);
@ -591,7 +592,7 @@ bool CartridgeDPCPlus::poke(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeDPCPlus::bank(uInt16 bank)
bool CartridgeDPCPlus::bank(uInt16 bank, uInt16)
{
if(bankLocked()) return false;
@ -640,10 +641,10 @@ bool CartridgeDPCPlus::patch(uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt8* CartridgeDPCPlus::getImage(size_t& size) const
const ByteBuffer& CartridgeDPCPlus::getImage(size_t& size) const
{
size = mySize;
return myImage.data() + (myImage.size() - mySize);
return myImage;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -86,9 +86,12 @@ class CartridgeDPCPlus : public Cartridge
/**
Install pages for the specified bank in the system.
@param bank The bank that should be installed in the system
@param bank The bank that should be installed in the system
@param segment The segment the bank should be using
@return true, if bank has changed
*/
bool bank(uInt16 bank) override;
bool bank(uInt16 bank, uInt16 segment = 0) override;
/**
Get the current bank.
@ -115,9 +118,9 @@ class CartridgeDPCPlus : public Cartridge
Access the internal ROM image for this cartridge.
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
@return A reference to the internal ROM image data
*/
const uInt8* getImage(size_t& size) const override;
const ByteBuffer& getImage(size_t& size) const override;
/**
Save the current state of this cart to the given Serializer.
@ -200,7 +203,7 @@ class CartridgeDPCPlus : public Cartridge
private:
// The ROM image and size
std::array<uInt8, 32_KB> myImage;
ByteBuffer myImage;
size_t mySize{0};
// Pointer to the 24K program ROM image of the cartridge

View File

@ -16,328 +16,10 @@
//============================================================================
#include "bspf.hxx"
#include "Cart.hxx"
#include "Cart0840.hxx"
#include "Cart2K.hxx"
#include "Cart3E.hxx"
#include "Cart3EX.hxx"
#include "Cart3EPlus.hxx"
#include "Cart3F.hxx"
#include "Cart4A50.hxx"
#include "Cart4K.hxx"
#include "Cart4KSC.hxx"
#include "CartAR.hxx"
#include "CartBF.hxx"
#include "CartBFSC.hxx"
#include "CartBUS.hxx"
#include "CartCDF.hxx"
#include "CartCM.hxx"
#include "CartCTY.hxx"
#include "CartCV.hxx"
#include "CartDF.hxx"
#include "CartDFSC.hxx"
#include "CartDPC.hxx"
#include "CartDPCPlus.hxx"
#include "CartE0.hxx"
#include "CartE7.hxx"
#include "CartE78K.hxx"
#include "CartEF.hxx"
#include "CartEFSC.hxx"
#include "CartF0.hxx"
#include "CartF4.hxx"
#include "CartF4SC.hxx"
#include "CartF6.hxx"
#include "CartF6SC.hxx"
#include "CartF8.hxx"
#include "CartF8SC.hxx"
#include "CartFA.hxx"
#include "CartFA2.hxx"
#include "CartFC.hxx"
#include "CartFE.hxx"
#include "CartMDM.hxx"
#include "CartSB.hxx"
#include "CartUA.hxx"
#include "CartWD.hxx"
#include "CartX07.hxx"
#include "MD5.hxx"
#include "Props.hxx"
#include "Logger.hxx"
#include "OSystem.hxx"
#include "CartDetector.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unique_ptr<Cartridge> CartDetector::create(const FilesystemNode& file,
const ByteBuffer& image, size_t size, string& md5,
const string& propertiesType, Settings& settings)
{
unique_ptr<Cartridge> cartridge;
Bankswitch::Type type = Bankswitch::nameToType(propertiesType),
detectedType = type;
string id;
// Collect some info about the ROM
ostringstream buf;
// First inspect the file extension itself
// If a valid type is found, it will override the one passed into this method
Bankswitch::Type typeByName = Bankswitch::typeFromExtension(file);
if(typeByName != Bankswitch::Type::_AUTO)
type = detectedType = typeByName;
// See if we should try to auto-detect the cartridge type
// If we ask for extended info, always do an autodetect
if(type == Bankswitch::Type::_AUTO || settings.getBool("rominfo"))
{
detectedType = autodetectType(image, size);
if(type != Bankswitch::Type::_AUTO && type != detectedType)
cerr << "Auto-detection not consistent: "
<< Bankswitch::typeToName(type) << ", "
<< Bankswitch::typeToName(detectedType) << endl;
type = detectedType;
buf << Bankswitch::typeToName(type) << "*";
}
else
buf << Bankswitch::typeToName(type);
// Check for multicart first; if found, get the correct part of the image
switch(type)
{
case Bankswitch::Type::_2IN1:
// Make sure we have a valid sized image
if(size == 2*2_KB || size == 2*4_KB || size == 2*8_KB || size == 2*16_KB)
{
cartridge =
createFromMultiCart(image, size, 2, md5, detectedType, id, settings);
buf << id;
}
else
throw runtime_error("Invalid cart size for type '" +
Bankswitch::typeToName(type) + "'");
break;
case Bankswitch::Type::_4IN1:
// Make sure we have a valid sized image
if(size == 4*2_KB || size == 4*4_KB || size == 4*8_KB)
{
cartridge =
createFromMultiCart(image, size, 4, md5, detectedType, id, settings);
buf << id;
}
else
throw runtime_error("Invalid cart size for type '" +
Bankswitch::typeToName(type) + "'");
break;
case Bankswitch::Type::_8IN1:
// Make sure we have a valid sized image
if(size == 8*2_KB || size == 8*4_KB || size == 8*8_KB)
{
cartridge =
createFromMultiCart(image, size, 8, md5, detectedType, id, settings);
buf << id;
}
else
throw runtime_error("Invalid cart size for type '" +
Bankswitch::typeToName(type) + "'");
break;
case Bankswitch::Type::_16IN1:
// Make sure we have a valid sized image
if(size == 16*2_KB || size == 16*4_KB || size == 16*8_KB)
{
cartridge =
createFromMultiCart(image, size, 16, md5, detectedType, id, settings);
buf << id;
}
else
throw runtime_error("Invalid cart size for type '" +
Bankswitch::typeToName(type) + "'");
break;
case Bankswitch::Type::_32IN1:
// Make sure we have a valid sized image
if(size == 32*2_KB || size == 32*4_KB)
{
cartridge =
createFromMultiCart(image, size, 32, md5, detectedType, id, settings);
buf << id;
}
else
throw runtime_error("Invalid cart size for type '" +
Bankswitch::typeToName(type) + "'");
break;
case Bankswitch::Type::_64IN1:
// Make sure we have a valid sized image
if(size == 64*2_KB || size == 64*4_KB)
{
cartridge =
createFromMultiCart(image, size, 64, md5, detectedType, id, settings);
buf << id;
}
else
throw runtime_error("Invalid cart size for type '" +
Bankswitch::typeToName(type) + "'");
break;
case Bankswitch::Type::_128IN1:
// Make sure we have a valid sized image
if(size == 128*2_KB || size == 128*4_KB)
{
cartridge =
createFromMultiCart(image, size, 128, md5, detectedType, id, settings);
buf << id;
}
else
throw runtime_error("Invalid cart size for type '" +
Bankswitch::typeToName(type) + "'");
break;
default:
cartridge = createFromImage(image, size, detectedType, md5, settings);
break;
}
if(size < 1_KB)
buf << " (" << size << "B) ";
else
buf << " (" << (size/1_KB) << "K) ";
cartridge->setAbout(buf.str(), Bankswitch::typeToName(type), id);
return cartridge;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unique_ptr<Cartridge>
CartDetector::createFromMultiCart(const ByteBuffer& image, size_t& size,
uInt32 numroms, string& md5, Bankswitch::Type type, string& id, Settings& settings)
{
// Get a piece of the larger image
uInt32 i = settings.getInt("romloadcount");
size /= numroms;
ByteBuffer slice = make_unique<uInt8[]>(size);
std::copy_n(image.get()+i*size, size, slice.get());
// We need a new md5 and name
md5 = MD5::hash(slice, uInt32(size)); // FIXME
ostringstream buf;
buf << " [G" << (i+1) << "]";
id = buf.str();
// Move to the next game the next time this ROM is loaded
settings.setValue("romloadcount", (i+1)%numroms);
if(size <= 2_KB) type = Bankswitch::Type::_2K;
else if(size == 4_KB) type = Bankswitch::Type::_4K;
else if(size == 8_KB) type = Bankswitch::Type::_F8;
else /* default */ type = Bankswitch::Type::_4K;
return createFromImage(slice, size, type, md5, settings);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unique_ptr<Cartridge>
CartDetector::createFromImage(const ByteBuffer& image, size_t size, Bankswitch::Type type,
const string& md5, Settings& settings)
{
// We should know the cart's type by now so let's create it
switch(type)
{
case Bankswitch::Type::_0840:
return make_unique<Cartridge0840>(image, size, md5, settings);
case Bankswitch::Type::_2K:
return make_unique<Cartridge2K>(image, size, md5, settings);
case Bankswitch::Type::_3E:
return make_unique<Cartridge3E>(image, size, md5, settings);
case Bankswitch::Type::_3EX:
return make_unique<Cartridge3EX>(image, size, md5, settings);
case Bankswitch::Type::_3EP:
return make_unique<Cartridge3EPlus>(image, size, md5, settings);
case Bankswitch::Type::_3F:
return make_unique<Cartridge3F>(image, size, md5, settings);
case Bankswitch::Type::_4A50:
return make_unique<Cartridge4A50>(image, size, md5, settings);
case Bankswitch::Type::_4K:
return make_unique<Cartridge4K>(image, size, md5, settings);
case Bankswitch::Type::_4KSC:
return make_unique<Cartridge4KSC>(image, size, md5, settings);
case Bankswitch::Type::_AR:
return make_unique<CartridgeAR>(image, size, md5, settings);
case Bankswitch::Type::_BF:
return make_unique<CartridgeBF>(image, size, md5, settings);
case Bankswitch::Type::_BFSC:
return make_unique<CartridgeBFSC>(image, size, md5, settings);
case Bankswitch::Type::_BUS:
return make_unique<CartridgeBUS>(image, size, md5, settings);
case Bankswitch::Type::_CDF:
return make_unique<CartridgeCDF>(image, size, md5, settings);
case Bankswitch::Type::_CM:
return make_unique<CartridgeCM>(image, size, md5, settings);
case Bankswitch::Type::_CTY:
return make_unique<CartridgeCTY>(image, size, md5, settings);
case Bankswitch::Type::_CV:
return make_unique<CartridgeCV>(image, size, md5, settings);
case Bankswitch::Type::_DF:
return make_unique<CartridgeDF>(image, size, md5, settings);
case Bankswitch::Type::_DFSC:
return make_unique<CartridgeDFSC>(image, size, md5, settings);
case Bankswitch::Type::_DPC:
return make_unique<CartridgeDPC>(image, size, md5, settings);
case Bankswitch::Type::_DPCP:
return make_unique<CartridgeDPCPlus>(image, size, md5, settings);
case Bankswitch::Type::_E0:
return make_unique<CartridgeE0>(image, size, md5, settings);
case Bankswitch::Type::_E7:
return make_unique<CartridgeE7>(image, size, md5, settings);
case Bankswitch::Type::_E78K:
return make_unique<CartridgeE78K>(image, size, md5, settings);
case Bankswitch::Type::_EF:
return make_unique<CartridgeEF>(image, size, md5, settings);
case Bankswitch::Type::_EFSC:
return make_unique<CartridgeEFSC>(image, size, md5, settings);
case Bankswitch::Type::_F0:
return make_unique<CartridgeF0>(image, size, md5, settings);
case Bankswitch::Type::_F4:
return make_unique<CartridgeF4>(image, size, md5, settings);
case Bankswitch::Type::_F4SC:
return make_unique<CartridgeF4SC>(image, size, md5, settings);
case Bankswitch::Type::_F6:
return make_unique<CartridgeF6>(image, size, md5, settings);
case Bankswitch::Type::_F6SC:
return make_unique<CartridgeF6SC>(image, size, md5, settings);
case Bankswitch::Type::_F8:
return make_unique<CartridgeF8>(image, size, md5, settings);
case Bankswitch::Type::_F8SC:
return make_unique<CartridgeF8SC>(image, size, md5, settings);
case Bankswitch::Type::_FA:
return make_unique<CartridgeFA>(image, size, md5, settings);
case Bankswitch::Type::_FA2:
return make_unique<CartridgeFA2>(image, size, md5, settings);
case Bankswitch::Type::_FC:
return make_unique<CartridgeFC>(image, size, md5, settings);
case Bankswitch::Type::_FE:
return make_unique<CartridgeFE>(image, size, md5, settings);
case Bankswitch::Type::_MDM:
return make_unique<CartridgeMDM>(image, size, md5, settings);
case Bankswitch::Type::_UA:
return make_unique<CartridgeUA>(image, size, md5, settings);
case Bankswitch::Type::_UASW:
return make_unique<CartridgeUA>(image, size, md5, settings, true);
case Bankswitch::Type::_SB:
return make_unique<CartridgeSB>(image, size, md5, settings);
case Bankswitch::Type::_WD:
case Bankswitch::Type::_WDSW:
return make_unique<CartridgeWD>(image, size, md5, settings);
case Bankswitch::Type::_X07:
return make_unique<CartridgeX07>(image, size, md5, settings);
default:
return nullptr; // The remaining types have already been handled
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t size)
{
@ -524,6 +206,17 @@ Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t si
else /*if(isProbablySB(image, size))*/
type = Bankswitch::Type::_SB;
}
else if(size == 512_KB)
{
if(isProbablyTVBoy(image, size))
type = Bankswitch::Type::_TVBOY;
else if(isProbably3EX(image, size))
type = Bankswitch::Type::_3EX;
else if(isProbably3E(image, size))
type = Bankswitch::Type::_3E;
else if(isProbably3F(image, size))
type = Bankswitch::Type::_3F;
}
else // what else can we do?
{
if(isProbably3EX(image, size))
@ -936,7 +629,7 @@ bool CartDetector::isProbablyFA2(const ByteBuffer& image, size_t)
// file sizes
// 32K version has all zeros in 29K-32K area
for(uInt32 i = 29_KB; i < 32_KB; ++i)
for(size_t i = 29_KB; i < 32_KB; ++i)
if(image[i] != 0)
return false;
@ -1000,6 +693,14 @@ bool CartDetector::isProbablySB(const ByteBuffer& image, size_t size)
return searchForBytes(image, size, signature[1], 3);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartDetector::isProbablyTVBoy(const ByteBuffer& image, size_t size)
{
// TV Boy cart bankswitching switches banks by accessing addresses 0x1800..$187F
uInt8 signature[5] = {0x91, 0x82, 0x6c, 0xfc, 0xff}; // STA ($82),Y; JMP ($FFFC)
return searchForBytes(image, size, signature, 5);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartDetector::isProbablyUA(const ByteBuffer& image, size_t size)
{

View File

@ -18,10 +18,6 @@
#ifndef CARTRIDGE_DETECTOR_HXX
#define CARTRIDGE_DETECTOR_HXX
class Cartridge;
class Properties;
class Settings;
#include "Bankswitch.hxx"
#include "bspf.hxx"
@ -34,21 +30,6 @@ class Settings;
class CartDetector
{
public:
/**
Create a new cartridge object allocated on the heap. The
type of cartridge created depends on the properties object.
@param image A pointer to the ROM image
@param size The size of the ROM image
@param md5 The md5sum for the given ROM image (can be updated)
@param dtype The detected bankswitch type of the ROM image
@param settings The settings container
@return Pointer to the new cartridge object allocated on the heap
*/
static unique_ptr<Cartridge> create(const FilesystemNode& file,
const ByteBuffer& image, size_t size, string& md5,
const string& dtype, Settings& settings);
/**
Try to auto-detect the bankswitching type of the cartridge
@ -60,40 +41,6 @@ class CartDetector
static Bankswitch::Type autodetectType(const ByteBuffer& image, size_t size);
private:
/**
Create a cartridge from a multi-cart image pointer; internally this
takes a slice of the ROM image ues that for the cartridge.
@param image A pointer to the complete ROM image
@param size The size of the ROM image slice
@param numroms The number of ROMs in the multicart
@param md5 The md5sum for the slice of the ROM image
@param type The detected type of the slice of the ROM image
@param id The ID for the slice of the ROM image
@param settings The settings container
@return Pointer to the new cartridge object allocated on the heap
*/
static unique_ptr<Cartridge>
createFromMultiCart(const ByteBuffer& image, size_t& size,
uInt32 numroms, string& md5, Bankswitch::Type type, string& id,
Settings& settings);
/**
Create a cartridge from the entire image pointer.
@param image A pointer to the complete ROM image
@param size The size of the ROM image
@param type The bankswitch type of the ROM image
@param md5 The md5sum for the ROM image
@param settings The settings container
@return Pointer to the new cartridge object allocated on the heap
*/
static unique_ptr<Cartridge>
createFromImage(const ByteBuffer& image, size_t size, Bankswitch::Type type,
const string& md5, Settings& settings);
/**
Search the image for the specified byte signature
@ -247,6 +194,11 @@ class CartDetector
*/
static bool isProbablySB(const ByteBuffer& image, size_t size);
/**
Returns true if the image is probably a TV Boy bankswitching cartridge
*/
static bool isProbablyTVBoy(const ByteBuffer& image, size_t size);
/**
Returns true if the image is probably a UA bankswitching cartridge
*/

View File

@ -20,8 +20,9 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeE0::CartridgeE0(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: CartridgeEnhanced(image, size, md5, settings)
const string& md5, const Settings& settings,
size_t bsSize)
: CartridgeEnhanced(image, size, md5, settings, bsSize)
{
myBankShift = BANK_SHIFT;
}

View File

@ -53,9 +53,10 @@ class CartridgeE0 : public CartridgeEnhanced
@param size The size of the ROM image
@param md5 The md5sum of the ROM image
@param settings A reference to the various settings (read-only)
@param bsSize The size specified by the bankswitching scheme
*/
CartridgeE0(const ByteBuffer& image, size_t size, const string& md5,
const Settings& settings);
const Settings& settings, size_t bsSize = 8_KB);
virtual ~CartridgeE0() = default;
public:

View File

@ -20,8 +20,9 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeEF::CartridgeEF(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: CartridgeEnhanced(image, size, md5, settings)
const string& md5, const Settings& settings,
size_t bsSize)
: CartridgeEnhanced(image, size, md5, settings, bsSize)
{
}

View File

@ -45,9 +45,10 @@ class CartridgeEF : public CartridgeEnhanced
@param size The size of the ROM image
@param md5 The md5sum of the ROM image
@param settings A reference to the various settings (read-only)
@param bsSize The size specified by the bankswitching scheme
*/
CartridgeEF(const ByteBuffer& image, size_t size, const string& md5,
const Settings& settings);
const Settings& settings, size_t bsSize = 64_KB);
virtual ~CartridgeEF() = default;
public:

View File

@ -20,8 +20,9 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeEFSC::CartridgeEFSC(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: CartridgeEF(image, size, md5, settings)
const string& md5, const Settings& settings,
size_t bsSize)
: CartridgeEF(image, size, md5, settings, bsSize)
{
myRamSize = RAM_SIZE;
}

View File

@ -46,9 +46,10 @@ class CartridgeEFSC : public CartridgeEF
@param size The size of the ROM image
@param md5 The md5sum of the ROM image
@param settings A reference to the various settings (read-only)
@param bsSize The size specified by the bankswitching scheme
*/
CartridgeEFSC(const ByteBuffer& image, size_t size, const string& md5,
const Settings& settings);
const Settings& settings, size_t bsSize = 64_KB);
virtual ~CartridgeEFSC() = default;
public:

View File

@ -15,20 +15,45 @@
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include "Logger.hxx"
#include "System.hxx"
#include "CartEnhanced.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeEnhanced::CartridgeEnhanced(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: Cartridge(settings, md5),
mySize(size)
const string& md5, const Settings& settings,
size_t bsSize)
: Cartridge(settings, md5)
{
// Allocate array for the ROM image (at least 64 bytzes)
myImage = make_unique<uInt8[]>(std::max(uInt32(mySize), uInt32(System::PAGE_SIZE)));
// ROMs are not always at the 'legal' size for their associated
// bankswitching scheme; here we deal with the differing sizes
// Copy the ROM image into my buffer
std::copy_n(image.get(), mySize, myImage.get());
// Is the ROM too large? If so, we cap it
if(size > bsSize)
{
ostringstream buf;
buf << "ROM larger than expected (" << size << " > " << bsSize
<< "), truncating " << (size - bsSize) << " bytes\n";
Logger::info(buf.str());
}
else if(size < mySize)
{
ostringstream buf;
buf << "ROM smaller than expected (" << mySize << " > " << size
<< "), appending " << (mySize - size) << " bytes\n";
Logger::info(buf.str());
}
mySize = bsSize;
// Initialize ROM with all 0's, to fill areas that the ROM may not cover
myImage = make_unique<uInt8[]>(mySize);
std::fill_n(myImage.get(), mySize, 0);
// Directly copy the ROM image into the buffer
// Only copy up to the amount of data the ROM provides; extra unused
// space will be filled with 0's from above
std::copy_n(image.get(), std::min(mySize, size), myImage.get());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -44,7 +69,7 @@ void CartridgeEnhanced::install(System& system)
// or the ROM is < 4K (-> 1 segment)
myBankSegs = std::min(1 << (MAX_BANK_SHIFT - myBankShift),
int(mySize) / myBankSize); // e.g. = 1
myRomOffset = myRamBankCount > 0 ? 0 : uInt32(myRamSize) * 2;
myRomOffset = myRamBankCount > 0U ? 0U : static_cast<uInt16>(myRamSize * 2);
myRamMask = ramSize - 1; // e.g. = 0xFFFF (doesn't matter for RAM size 0)
myWriteOffset = myRamWpHigh ? ramSize : 0; // e.g. = 0x0000
myReadOffset = myRamWpHigh ? 0 : ramSize; // e.g. = 0x0080
@ -130,8 +155,7 @@ uInt8 CartridgeEnhanced::peek(uInt16 address)
// This is a read access to a write port!
// Reading from the write port triggers an unwanted write
// The RAM banks follow the ROM banks and are half the size of a ROM bank
return peekRAM(myRAM[((myCurrentSegOffset[(peekAddress & ROM_MASK) >> myBankShift] - mySize) >> 1) + address],
peekAddress);
return peekRAM(myRAM[ramAddressSegmentOffset(peekAddress) + address], peekAddress);
}
address &= ROM_MASK;
@ -143,8 +167,7 @@ uInt8 CartridgeEnhanced::peek(uInt16 address)
return peekRAM(myRAM[address], peekAddress);
}
return myImage[myCurrentSegOffset[(peekAddress & ROM_MASK) >> myBankShift]
+ (peekAddress & myBankMask)];
return myImage[romAddressSegmentOffset(peekAddress) + (peekAddress & myBankMask)];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -165,7 +188,7 @@ bool CartridgeEnhanced::poke(uInt16 address, uInt8 value)
{
address &= myRamMask;
// The RAM banks follow the ROM banks and are half the size of a ROM bank
pokeRAM(myRAM[((myCurrentSegOffset[(pokeAddress & ROM_MASK) >> myBankShift] - mySize) >> 1) + address],
pokeRAM(myRAM[ramAddressSegmentOffset(pokeAddress) + address],
pokeAddress, value);
return true;
}
@ -275,10 +298,22 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment)
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline uInt16 CartridgeEnhanced::romAddressSegmentOffset(uInt16 address) const
{
return myCurrentSegOffset[((address & ROM_MASK) >> myBankShift) % myBankSegs];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline uInt16 CartridgeEnhanced::ramAddressSegmentOffset(uInt16 address) const
{
return uInt16(myCurrentSegOffset[((address & ROM_MASK) >> myBankShift) % myBankSegs] - mySize) >> 1;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeEnhanced::getBank(uInt16 address) const
{
return myCurrentSegOffset[(address & ROM_MASK) >> myBankShift] >> myBankShift;
return romAddressSegmentOffset(address) >> myBankShift;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -310,11 +345,11 @@ bool CartridgeEnhanced::patch(uInt16 address, uInt8 value)
{
if(isRamBank(address))
{
myRAM[((myCurrentSegOffset[(address & ROM_MASK) >> myBankShift] - mySize) >> 1) + (address & myRamMask)] = value;
myRAM[ramAddressSegmentOffset(address) + (address & myRamMask)] = value;
}
else
{
if((address & myBankMask) < myRamSize * 2)
if(static_cast<size_t>(address & myBankMask) < myRamSize * 2)
{
// Normally, a write to the read port won't do anything
// However, the patch command is special in that ignores such
@ -322,17 +357,17 @@ bool CartridgeEnhanced::patch(uInt16 address, uInt8 value)
myRAM[address & myRamMask] = value;
}
else
myImage[myCurrentSegOffset[(address & ROM_MASK) >> myBankShift] + (address & myBankMask)] = value;
myImage[romAddressSegmentOffset(address) + (address & myBankMask)] = value;
}
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt8* CartridgeEnhanced::getImage(size_t& size) const
const ByteBuffer& CartridgeEnhanced::getImage(size_t& size) const
{
size = mySize;
return myImage.get();
return myImage;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -43,9 +43,11 @@ class CartridgeEnhanced : public Cartridge
@param size The size of the ROM image
@param md5 The md5sum of the ROM image
@param settings A reference to the various settings (read-only)
@param bsSize The size specified by the bankswitching scheme
*/
CartridgeEnhanced(const ByteBuffer& image, size_t size, const string& md5,
const Settings& settings);
CartridgeEnhanced(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings,
size_t bsSize);
virtual ~CartridgeEnhanced() = default;
public:
@ -70,16 +72,7 @@ class CartridgeEnhanced : public Cartridge
@return true, if bank has changed
*/
virtual bool bank(uInt16 bank, uInt16 segment);
/**
Install pages for the specified bank in the system.
@param bank The bank that should be installed in the system
@return true, if bank has changed
*/
bool bank(uInt16 bank) override { return this->bank(bank, 0); }
bool bank(uInt16 bank, uInt16 segment = 0) override;
/**
Get the current bank.
@ -127,9 +120,9 @@ class CartridgeEnhanced : public Cartridge
Access the internal ROM image for this cartridge.
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
@return A reference to the internal ROM image data
*/
const uInt8* getImage(size_t& size) const override;
const ByteBuffer& getImage(size_t& size) const override;
/**
Save the current state of this cart to the given Serializer.
@ -263,6 +256,7 @@ class CartridgeEnhanced : public Cartridge
@param address The address to check
@param value The optional value used to determine the bank switched to
@return True if a bank switch happened.
*/
virtual bool checkSwitchBank(uInt16 address, uInt8 value = 0) = 0;
@ -275,6 +269,22 @@ class CartridgeEnhanced : public Cartridge
*/
virtual uInt16 getStartBank() const { return 0; }
/**
Get the ROM offset of the segment of the given address
@param address The address to get the offset for
@return The calculated offset
*/
uInt16 romAddressSegmentOffset(uInt16 address) const;
/**
Get the RAM offset of the segment of the given address
@param address The address to get the offset for
@return The calculated offset
*/
uInt16 ramAddressSegmentOffset(uInt16 address) const;
private:
// Following constructors and assignment operators not supported
CartridgeEnhanced() = delete;

View File

@ -19,8 +19,9 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeF0::CartridgeF0(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: CartridgeEnhanced(image, size, md5, settings)
const string& md5, const Settings& settings,
size_t bsSize)
: CartridgeEnhanced(image, size, md5, settings, bsSize)
{
}

View File

@ -42,9 +42,10 @@ class CartridgeF0 : public CartridgeEnhanced
@param size The size of the ROM image
@param md5 The md5sum of the ROM image
@param settings A reference to the various settings (read-only)
@param bsSize The size specified by the bankswitching scheme
*/
CartridgeF0(const ByteBuffer& image, size_t size, const string& md5,
const Settings& settings);
const Settings& settings, size_t bsSize = 64_KB);
virtual ~CartridgeF0() = default;
public:

View File

@ -19,8 +19,9 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeF4::CartridgeF4(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: CartridgeEnhanced(image, size, md5, settings)
const string& md5, const Settings& settings,
size_t bsSize)
: CartridgeEnhanced(image, size, md5, settings, bsSize)
{
}

View File

@ -41,9 +41,10 @@ class CartridgeF4 : public CartridgeEnhanced
@param size The size of the ROM image
@param md5 The md5sum of the ROM image
@param settings A reference to the various settings (read-only)
@param bsSize The size specified by the bankswitching scheme
*/
CartridgeF4(const ByteBuffer& image, size_t size, const string& md5,
const Settings& settings);
const Settings& settings, size_t bsSize = 32_KB);
virtual ~CartridgeF4() = default;
public:

View File

@ -19,8 +19,9 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeF4SC::CartridgeF4SC(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: CartridgeF4(image, size, md5, settings)
const string& md5, const Settings& settings,
size_t bsSize)
: CartridgeF4(image, size, md5, settings, bsSize)
{
myRamSize = RAM_SIZE;
myRamMask = RAM_SIZE - 1;

View File

@ -42,9 +42,10 @@ class CartridgeF4SC : public CartridgeF4
@param size The size of the ROM image
@param md5 The md5sum of the ROM image
@param settings A reference to the various settings (read-only)
@param bsSize The size specified by the bankswitching scheme
*/
CartridgeF4SC(const ByteBuffer& image, size_t size, const string& md5,
const Settings& settings);
const Settings& settings, size_t bsSize = 32_KB);
virtual ~CartridgeF4SC() = default;
public:

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