Merge branch 'master' of https://github.com/stella-emu/stella
22
Announce.txt
|
@ -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
|
||||
|
|
78
Changes.txt
|
@ -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)
|
||||
|
|
2
Makefile
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.9 KiB |
302
docs/index.html
|
@ -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 -> File Extension</a>.</p>
|
||||
<a href="#PropertiesCartType">Cart.Type -> 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> </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 <1 - 5></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 <10000 - 30000></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 <1|0></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 <0 - 10></pre></td>
|
||||
<td>Add overscan to TIA image while in fullscreen mode</td>
|
||||
|
@ -2322,9 +2356,10 @@
|
|||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><pre>-joyallow4 <1|0></pre></td>
|
||||
<td>Allow all 4 directions on a joystick to be pressed
|
||||
simultaneously.</td>
|
||||
<td><pre>-psense <number></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 <number></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 <1|0></pre></td>
|
||||
<td>Allow all 4 directions on a joystick to be pressed
|
||||
simultaneously.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><pre>-modcombo <1|0></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 <lr|rl></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 <name></pre></td>
|
||||
<td>Set the name of the serial port where an AtariVox is connected.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><pre>-usemouse <always|analog|never></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 <1|0></pre></td>
|
||||
<td>Locks the mouse cursor in the game window in emulation mode.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><pre>-cursor <0|1|2|3></pre></td>
|
||||
<td>Set mouse cursor state in UI/emulation modes.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><pre>-dsense <number></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 <number></pre></td>
|
||||
<td>Sensitivity for emulation of paddles when using a mouse.
|
||||
|
@ -2377,27 +2429,21 @@
|
|||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><pre>-dcsense <number></pre></td>
|
||||
<td>Sensitivity for emulation of driving controllers when using a mouse.
|
||||
<td><pre>-dsense <number></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 <lr|rl></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 <0|1|2|3></pre></td>
|
||||
<td>Set mouse cursor state in UI/emulation modes.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><pre>-modcombo <1|0></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 <1|0></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 <name></pre></td>
|
||||
<td>Set the name of the serial port where an AtariVox is connected.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><pre>-maxres <WxH></pre></td>
|
||||
<td>Useful for developers, this sets the maximum size of window that
|
||||
|
@ -2705,7 +2746,7 @@
|
|||
|
||||
<tr>
|
||||
<td><pre>-bs <type></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 <bank></pre></td>
|
||||
<td>Set "Cartridge.StartBank" property.</td>
|
||||
<td>Set "Cart.StartBank" property.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><pre>-channels <Mono|Stereo></pre></td>
|
||||
<td>Set "Cartridge.Sound" property.</td>
|
||||
<td>Set "Cart.Sound" property.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><pre>-ld <A|B></pre></td>
|
||||
<td>Set "Console.LeftDifficulty" property.</td>
|
||||
<td>Set "Console.LeftDiff" property.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><pre>-rd <A|B></pre></td>
|
||||
<td>Set "Console.RightDifficulty" property.</td>
|
||||
<td>Set "Console.RightDiff" property.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><pre>-tv <Color|BW></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 <= <i>n</i> <= 5.
|
||||
The value must be <i>n</i> such that -20 <= <i>n</i> <= 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>
|
||||
|
|
|
@ -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/>
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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++)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#ifndef STATE_MANAGER_HXX
|
||||
#define STATE_MANAGER_HXX
|
||||
|
||||
#define STATE_HEADER "06010000state"
|
||||
#define STATE_HEADER "06020100state"
|
||||
|
||||
class OSystem;
|
||||
class RewindManager;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -74,7 +74,6 @@ CartRamWidget::CartRamWidget(
|
|||
myDesc->setEditable(false);
|
||||
myDesc->setEnabled(false);
|
||||
myDesc->setList(sl);
|
||||
addFocusWidget(myDesc);
|
||||
|
||||
ypos += myDesc->getHeight() + myFontHeight / 2;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -251,6 +251,7 @@ void DebuggerDialog::handleCommand(CommandSender* sender, int cmd,
|
|||
break;
|
||||
|
||||
case kDDOptionsCmd:
|
||||
saveConfig();
|
||||
myOptions->open();
|
||||
loadConfig();
|
||||
break;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -19,9 +19,10 @@
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
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;
|
||||
myRamMask = RAM_SIZE - 1;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|