diff --git a/Announce.txt b/Announce.txt index 18f636c79..2262f7975 100644 --- a/Announce.txt +++ b/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 diff --git a/Changes.txt b/Changes.txt index 557157f25..cc1ca3b3b 100644 --- a/Changes.txt +++ b/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) diff --git a/Makefile b/Makefile index 939f0d7cf..08cfc640c 100644 --- a/Makefile +++ b/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 diff --git a/debian/changelog b/debian/changelog index 81ab67bce..75c7267b6 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,17 @@ +stella (6.2.1-1) stable; urgency=high + + * Version 6.2.1 release + + -- Stephen Anthony Sat, 20 Jun 2020 17:09:59 -0230 + + +stella (6.2-1) stable; urgency=high + + * Version 6.2 release + + -- Stephen Anthony Sun, 7 Jun 2020 17:09:59 -0230 + + stella (6.1.2-1) stable; urgency=high * Version 6.1.2 release diff --git a/docs/debugger.html b/docs/debugger.html index 423a20aa1..306885c34 100644 --- a/docs/debugger.html +++ b/docs/debugger.html @@ -15,7 +15,7 @@
Stella
-

Release 6.1

+

Release 6.2.1

Integrated Debugger

(a work in progress)


diff --git a/docs/graphics/launcher_options_snapshots.png b/docs/graphics/launcher_options_snapshots.png index 0d2b2e8d6..a833f8bb3 100644 Binary files a/docs/graphics/launcher_options_snapshots.png and b/docs/graphics/launcher_options_snapshots.png differ diff --git a/docs/graphics/options_gameinfo_cartridge.png b/docs/graphics/options_gameinfo_cartridge.png index ea09b9842..b90761623 100644 Binary files a/docs/graphics/options_gameinfo_cartridge.png and b/docs/graphics/options_gameinfo_cartridge.png differ diff --git a/docs/graphics/options_gameinfo_console.png b/docs/graphics/options_gameinfo_console.png index 49577140c..e3aee16e5 100644 Binary files a/docs/graphics/options_gameinfo_console.png and b/docs/graphics/options_gameinfo_console.png differ diff --git a/docs/graphics/options_gameinfo_controller.png b/docs/graphics/options_gameinfo_controller.png index 04cc025db..fe5adb275 100644 Binary files a/docs/graphics/options_gameinfo_controller.png and b/docs/graphics/options_gameinfo_controller.png differ diff --git a/docs/graphics/options_gameinfo_emulation.png b/docs/graphics/options_gameinfo_emulation.png index 0db133505..221a08fa5 100644 Binary files a/docs/graphics/options_gameinfo_emulation.png and b/docs/graphics/options_gameinfo_emulation.png differ diff --git a/docs/graphics/options_video.png b/docs/graphics/options_video.png index deb857ca4..58654148a 100644 Binary files a/docs/graphics/options_video.png and b/docs/graphics/options_video.png differ diff --git a/docs/index.html b/docs/index.html index 3bf9ee26a..bc3f46f29 100644 --- a/docs/index.html +++ b/docs/index.html @@ -19,7 +19,7 @@

A multi-platform Atari 2600 VCS emulator

-

Release 6.2

+

Release 6.2.1



User's Guide

@@ -70,7 +70,7 @@


-
February 1999 - ??? 2020
+
February 1999 - June 2020
The Stella Team
Stella Homepage
@@ -355,12 +355,11 @@

The Linux version of Stella is designed to work on a Linux Workstation with the following:

@@ -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 ROM properties section under - Cartridge.Type -> File Extension.

+ Cart.Type -> File Extension.

Note: 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 @@ Pause/resume emulation Pause -   + Shift-Cmd + p @@ -1377,6 +1376,13 @@ Alt + Enter Cmd + Enter + + Toggle adapting display refresh rate to game frame rate +
+ Note: Not available for macOS. + Alt + r + Cmd + r + Decrease overscan in fullscreen mode Shift + PageDown @@ -1424,7 +1430,7 @@

- These settings can also be changed using Global Audio & Video Keys
+ These settings can also be changed using Global Keys @@ -1474,7 +1480,7 @@
- These settings can also be changed using Global Audio & Video Keys
+ These settings can also be changed using Global Keys @@ -1544,7 +1550,7 @@
- These settings can also be changed using Global Audio & Video Keys
+ These settings can also be changed using Global Keys @@ -1553,45 +1559,6 @@ -

Global Audio & Video Keys (can be remapped)

-

These keys allow selecting and changing audio & video settings without having to remember the - dedicated keys.

- - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionKey (Standard)Key (macOS)
Select previous AV settingEndFn + Left arrow
Select next AV settingHomeFn + Right arrow
Decrease current AV settingPageDownFn + Down arrow
Increase current AV setting - PageUpFn + Up arrow
-

Notes: -

    -
  • Only available if UI messages are enabled.
  • -
  • Currently not available settings are automatically skipped.
  • -
  • If a setting was selected via dedicated key, its value can also be changed with the - global keys.
  • -
-


-

Developer Keys (can be remapped)

@@ -1709,8 +1676,62 @@ Alt + j Cmd + j + +
+ These settings can also be changed using Global Keys
+ + +

Global Keys (can be remapped)

+

These keys allow selecting and changing settings without having to remember the + dedicated keys. They keys are grouped by Audio & Video and Debug settings.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FunctionKey (Standard)Key (macOS)
Select previous setting groupControl + EndControl-Fn + Left arrow
Select next setting groupControl + HomeControl-Fn + Right arrow
Select previous settingEndFn + Left arrow
Select next settingHomeFn + Right arrow
Decrease current settingPageDownFn + Down arrow
Increase current setting + PageUpFn + Up arrow
+

Notes: +

    +
  • Only available if UI messages are enabled.
  • +
  • Currently not available settings are automatically skipped.
  • +
  • If a setting was selected via dedicated key, its value can also be changed with the + global keys.
  • +
+

+

Other Emulation Keys (can be remapped)

@@ -1742,9 +1763,15 @@ + + + + + + + Load next game in ROM (multicart ROM, TIA mode) @@ -1952,7 +1979,7 @@ - + @@ -2155,7 +2182,7 @@ @@ -2191,7 +2218,7 @@ - + @@ -2218,6 +2245,13 @@ aspect ratio. + + + + + @@ -2322,9 +2356,10 @@ - - + + @@ -2337,6 +2372,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - + - - + + - - + + @@ -2568,11 +2614,6 @@ - - - - - - @@ -2716,27 +2757,27 @@ - + - + - + - + - + @@ -2943,13 +2984,15 @@
Control + 1
Load previous game in ROM (multicart ROM, TIA mode)Shift-Control + rShift-Control + r
Reload current ROM (singlecart ROM, TIA mode)
- Load next game in ROM (multicart ROM, TIA mode)
Control + r Control + r
N/A N/A N/A N/A voice (2600-daptor II)
SaveKey
-audio.preset <1 - 5>
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'.
-audio.dpc_pitch <10000 - 30000>
Set the pitch o f Pitfall II music.Set the pitch of Pitfall II music.
-tia.fs_refresh <1|0>
While in fullscreen mode, adapt the display's refresh rate to the game's frame rate + to minimize judder.
+ Note: Not available for macOS.
-tia.fs_overscan <0 - 10>
Add overscan to TIA image while in fullscreen mode
-joyallow4 <1|0>
Allow all 4 directions on a joystick to be pressed - simultaneously.
-psense <number>
Sensitivity for emulation of paddles when using analog paddles. + Valid range of values is from 1 to 30, with larger numbers causing + faster movement.
Impact of fast paddle movement on input averaging.
-dcsense <number>
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.
-joyallow4 <1|0>
Allow all 4 directions on a joystick to be pressed + simultaneously.
-modcombo <1|0>
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.
+ 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.
-saport <lr|rl>
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.
-avoxport <name>
Set the name of the serial port where an AtariVox is connected.
-usemouse <always|analog|never>
Use mouse as a controller as specified by ROM properties in specific case. @@ -2344,24 +2414,6 @@ (paddles, trackball, etc.).
-grabmouse <1|0>
Locks the mouse cursor in the game window in emulation mode.
-cursor <0|1|2|3>
Set mouse cursor state in UI/emulation modes.
-dsense <number>
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.
-msense <number>
Sensitivity for emulation of paddles when using a mouse. @@ -2377,27 +2429,21 @@
-dcsense <number>
Sensitivity for emulation of driving controllers when using a mouse. +
-dsense <number>
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.
-saport <lr|rl>
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.
-cursor <0|1|2|3>
Set mouse cursor state in UI/emulation modes.
-modcombo <1|0>
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.
- 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.
-grabmouse <1|0>
Locks the mouse cursor in the game window in emulation mode.
Make the start path follow ROM launcher navigation.
-avoxport <name>
Set the name of the serial port where an AtariVox is connected.
-maxres <WxH>
Useful for developers, this sets the maximum size of window that @@ -2705,7 +2746,7 @@
-bs <type>
Set "Cartridge.Type" property. See the Game Properties section + Set "Cart.Type" property. See the Game Properties section for valid types.
-startbank <bank>
Set "Cartridge.StartBank" property.Set "Cart.StartBank" property.
-channels <Mono|Stereo>
Set "Cartridge.Sound" property.Set "Cart.Sound" property.
-ld <A|B>
Set "Console.LeftDifficulty" property.Set "Console.LeftDiff" property.
-rd <A|B>
Set "Console.RightDifficulty" property.Set "Console.RightDiff" property.
-tv <Color|BW>
Set "Console.TelevisionType" property.Set "Console.TVType" property.
- - + + - + + - +
ItemBrief descriptionFor more information,
see CommandLine
RendererUse specified rendering mode-video
InterpolationInterpolation of TIA image-tia.inter
ZoomZoom level of TIA image-tia.zoom
InterpolationEnable interpolation of the TIA image-tia.inter
ZoomZoom level of the TIA image-tia.zoom
FullscreenSelf-explanatory - Note that colors may slightly change. This depends on the OS and renderer used.-fullscreen
StretchIn fullscreen mode, completely fill screen with TIA image-tia.fs_stretch
StretchIn fullscreen mode, completely fill screen with the TIA image.-tia.fs_stretch
Adapt display...In fullscreen mode, adapt the display's refresh rate to the game's frame rate to minimize judder. +
Note: Not available for macOS.
-tia.fs_refresh
OverscanIn fullscreen mode, add overscan to the TIA image-tia.fs_overscan
V-Size adjustAdjust height of TIA image-tia.vsizeadjust
V-Size adjustAdjust height of the TIA image-tia.vsizeadjust
@@ -3144,9 +3187,9 @@ Save pathSpecifies where to save snapshots-snapsavedir Continuous snapshot intervalInterval (in seconds) between snapshots-ssinterval - Use actual ROM nameUse the actual ROM filename instead of the internal database name.-snapname + Use actual ROM nameUse the actual ROM filename instead of the internal database name-snapname Overwrite existing filesWhether to overwrite old snapshots-sssingle - Ignore scaling (1x mode)Save snapshot in 1x mode without scaling-ss1x + Create pixel-exact image (no zoom/post-processing)Save snapshot using the exact pixels from the TIA image, without zoom or any post-processing effects-ss1x @@ -3933,24 +3976,24 @@ Ms Pac-Man (Stella extended codes):

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

Every block in the property file must have a unique value for the - Cartridge.MD5 property.

+ Cart.MD5 property.

Properties

@@ -3964,7 +4007,7 @@ Ms Pac-Man (Stella extended codes): - + + @@ -4028,7 +4072,7 @@ Ms Pac-Man (Stella extended codes): - + @@ -4052,7 +4096,7 @@ Ms Pac-Man (Stella extended codes): @@ -4070,7 +4114,7 @@ Ms Pac-Man (Stella extended codes): - +
Cartridge.Type:Cart.Type: Indicates the bank-switching type for the game. The value of this property must be either Auto or one of the following (for more information about bank-switching see Kevin Horton's 2600 bankswitching @@ -4019,6 +4062,7 @@ Ms Pac-Man (Stella extended codes):
FE 8K Decathlon .FE
MDM Menu Driven Megacart .MDM
SB 128-256K SUPERbanking .SB
TVBOY512K TV Boy (127 games).TVB, .TVBOY
UA 8K UA Ltd. .UA
UASW 8K UA Ltd. (swapped banks).UASW
WD Wickstead Design (Pink Panther) .WD
Cartridge.StartBank:Cart.StartBank: Indicates which bank to use for reading the reset vector.
Display.VCenter: Indicates the offset for the vertical center of the display. - The value must be n such that -5 <= n <= 5. + The value must be n such that -20 <= n <= 20.
Cartridge.Sound:Cart.Sound: 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): - + - + - + @@ -4202,14 +4246,14 @@ Ms Pac-Man (Stella extended codes):

Console.TelevisionType:Console.TVType: Indicates the default television setting for the game. The value must be Color or BW.
Console.LeftDifficulty:Console.LeftDiff: Indicates the default difficulty setting for the left player. The value must be A or B.
Console.RightDifficulty:Console.RightDiff: Indicates the default difficulty setting for the right player. The value must be A or B.
- + - + - + - + - + - +
Cartridge.Name:Cart.Name: Indicates the actual name of the game. When you save snapshots, load/save state files, or use the ROM Audit Mode functionality, this is the name that will be used for the respective file(s).
Cartridge.MD5:Cart.MD5: 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):
Cartridge.Manufacturer:Cart.Manufacturer: Indicates the game's manufacturer.
Cartridge.ModelNo:Cart.ModelNo: Indicates the manufacturer's model number for the game.
Cartridge.Rarity:Cart.Rarity: Indicates how rare a cartridge is, based on the scale described on AtariAge.
Cartridge.Note:Cart.Note: Contains any special notes about playing the game.
+

The buttons at the bottom of the dialogs work as follows: +

    +
  • Defaults: Reset the properties to those built into Stella.
  • +
  • Save: Save the properties for the currently selected ROM only + to a properties file in the users default save directory.
  • +
  • OK: Merge/commit any changes into the ROM properties database, which + contains info on all ROMs.
  • +
  • Cancel: Revert any changes in the dialog, and cancel the operation.
  • +
+

The name of the properties file will depend on the version of Stella, as follows:

@@ -4261,7 +4315,7 @@ Ms Pac-Man (Stella extended codes):
_BASEDIR_/stella.pro
-

Stella will require a restart for changes to this file to take effect.

+

Note: For manual changes to the property files Stella will require a restart to take effect.


Palette Support

diff --git a/docs/index_r77.html b/docs/index_r77.html index 710f5e561..cc15b11ab 100644 --- a/docs/index_r77.html +++ b/docs/index_r77.html @@ -58,7 +58,7 @@

Stella for RetroN 77

Atari 2600 VCS emulator

-
Release 6.1
+
Release 6.2.1

Quick Navigation Guide


diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index 4d013a35d..d930b2fc0 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -15,6 +15,8 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include + #include "SDL_lib.hxx" #include "bspf.hxx" #include "Logger.hxx" @@ -99,19 +101,32 @@ void FrameBufferSDL2::queryHardware(vector& 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); diff --git a/src/common/FrameBufferSDL2.hxx b/src/common/FrameBufferSDL2.hxx index d2825037c..7904ed0ee 100644 --- a/src/common/FrameBufferSDL2.hxx +++ b/src/common/FrameBufferSDL2.hxx @@ -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}; diff --git a/src/common/PJoystickHandler.cxx b/src/common/PJoystickHandler.cxx index 3b2452798..1af10feac 100644 --- a/src/common/PJoystickHandler.cxx +++ b/src/common/PJoystickHandler.cxx @@ -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 } } diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index cf4a31831..59beffdac 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -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}, diff --git a/src/common/PNGLibrary.cxx b/src/common/PNGLibrary.cxx index e1980a975..23dd798d6 100644 --- a/src/common/PNGLibrary.cxx +++ b/src/common/PNGLibrary.cxx @@ -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) { diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index d2a2a7768..ec0d7691b 100644 --- a/src/common/PaletteHandler.cxx +++ b/src/common/PaletteHandler.cxx @@ -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++) diff --git a/src/common/PaletteHandler.hxx b/src/common/PaletteHandler.hxx index bd102d9f0..ed46da516 100644 --- a/src/common/PaletteHandler.hxx +++ b/src/common/PaletteHandler.hxx @@ -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. diff --git a/src/common/StateManager.hxx b/src/common/StateManager.hxx index 3da98499c..efb9286cb 100644 --- a/src/common/StateManager.hxx +++ b/src/common/StateManager.hxx @@ -18,7 +18,7 @@ #ifndef STATE_MANAGER_HXX #define STATE_MANAGER_HXX -#define STATE_HEADER "06010000state" +#define STATE_HEADER "06020100state" class OSystem; class RewindManager; diff --git a/src/common/Version.hxx b/src/common/Version.hxx index 09c706540..9c070d208 100644 --- a/src/common/Version.hxx +++ b/src/common/Version.hxx @@ -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 diff --git a/src/common/ZipHandler.hxx b/src/common/ZipHandler.hxx index 861e1350a..aaf289357 100644 --- a/src/common/ZipHandler.hxx +++ b/src/common/ZipHandler.hxx @@ -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; diff --git a/src/common/bspf.hxx b/src/common/bspf.hxx index f21a99a4c..5201ef2ff 100644 --- a/src/common/bspf.hxx +++ b/src/common/bspf.hxx @@ -90,9 +90,9 @@ using DWordBuffer = std::unique_ptr; // NOLINT using AdjustFunction = std::function; // 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(size * 1024); + return static_cast(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 using array2D = std::array, ROW>; diff --git a/src/common/tv_filters/NTSCFilter.cxx b/src/common/tv_filters/NTSCFilter.cxx index 9764f1ac3..5a61dd140 100644 --- a/src/common/tv_filters/NTSCFilter.cxx +++ b/src/common/tv_filters/NTSCFilter.cxx @@ -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); diff --git a/src/debugger/DebuggerParser.cxx b/src/debugger/DebuggerParser.cxx index 49692ef8a..9e3c0745b 100644 --- a/src/debugger/DebuggerParser.cxx +++ b/src/debugger/DebuggerParser.cxx @@ -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; diff --git a/src/debugger/gui/Cart3EPlusWidget.cxx b/src/debugger/gui/Cart3EPlusWidget.cxx index 8e7cdf063..cd0fda251 100644 --- a/src/debugger/gui/Cart3EPlusWidget.cxx +++ b/src/debugger/gui/Cart3EPlusWidget.cxx @@ -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(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::bankEnum = { - kBank0Changed, kBank1Changed, kBank2Changed, kBank3Changed -}; diff --git a/src/debugger/gui/Cart3EPlusWidget.hxx b/src/debugger/gui/Cart3EPlusWidget.hxx index 7cde61042..44473e0cf 100644 --- a/src/debugger/gui/Cart3EPlusWidget.hxx +++ b/src/debugger/gui/Cart3EPlusWidget.hxx @@ -56,13 +56,10 @@ class Cartridge3EPlusWidget : public CartridgeEnhancedWidget std::array myBankCommit{nullptr}; std::array myBankState{nullptr}; - enum BankID { - kBank0Changed = 'b0CH', - kBank1Changed = 'b1CH', - kBank2Changed = 'b2CH', - kBank3Changed = 'b3CH' + enum { + kRomRamChanged = 'rrCh', + kChangeBank = 'chBk', }; - static const std::array bankEnum; private: // Following constructors and assignment operators not supported diff --git a/src/debugger/gui/Cart3EWidget.cxx b/src/debugger/gui/Cart3EWidget.cxx index 4683ea7d4..910f03368 100644 --- a/src/debugger/gui/Cart3EWidget.cxx +++ b/src/debugger/gui/Cart3EWidget.cxx @@ -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(); diff --git a/src/debugger/gui/Cart3FWidget.cxx b/src/debugger/gui/Cart3FWidget.cxx index ff5b0d219..a84f0fd4f 100644 --- a/src/debugger/gui/Cart3FWidget.cxx +++ b/src/debugger/gui/Cart3FWidget.cxx @@ -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" diff --git a/src/debugger/gui/CartEnhancedWidget.cxx b/src/debugger/gui/CartEnhancedWidget.cxx index 0bf38f529..97beb1f6b 100644 --- a/src/debugger/gui/CartEnhancedWidget.cxx +++ b/src/debugger/gui/CartEnhancedWidget.cxx @@ -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; } diff --git a/src/debugger/gui/CartRamWidget.cxx b/src/debugger/gui/CartRamWidget.cxx index 84cc8b9ab..76c8e972a 100644 --- a/src/debugger/gui/CartRamWidget.cxx +++ b/src/debugger/gui/CartRamWidget.cxx @@ -74,7 +74,6 @@ CartRamWidget::CartRamWidget( myDesc->setEditable(false); myDesc->setEnabled(false); myDesc->setList(sl); - addFocusWidget(myDesc); ypos += myDesc->getHeight() + myFontHeight / 2; diff --git a/src/debugger/gui/CartTVBoyWidget.cxx b/src/debugger/gui/CartTVBoyWidget.cxx new file mode 100644 index 000000000..5012642ba --- /dev/null +++ b/src/debugger/gui/CartTVBoyWidget.cxx @@ -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); +} diff --git a/src/debugger/gui/CartTVBoyWidget.hxx b/src/debugger/gui/CartTVBoyWidget.hxx new file mode 100644 index 000000000..e1c2780e6 --- /dev/null +++ b/src/debugger/gui/CartTVBoyWidget.hxx @@ -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 diff --git a/src/debugger/gui/DebuggerDialog.cxx b/src/debugger/gui/DebuggerDialog.cxx index 6674311f6..be9ad7515 100644 --- a/src/debugger/gui/DebuggerDialog.cxx +++ b/src/debugger/gui/DebuggerDialog.cxx @@ -251,6 +251,7 @@ void DebuggerDialog::handleCommand(CommandSender* sender, int cmd, break; case kDDOptionsCmd: + saveConfig(); myOptions->open(); loadConfig(); break; diff --git a/src/debugger/gui/RomWidget.cxx b/src/debugger/gui/RomWidget.cxx index 010ae5f0b..52b2e81b8 100644 --- a/src/debugger/gui/RomWidget.cxx +++ b/src/debugger/gui/RomWidget.cxx @@ -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)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/debugger/gui/TiaOutputWidget.cxx b/src/debugger/gui/TiaOutputWidget.cxx index 5277647dc..01d6d094b 100644 --- a/src/debugger/gui/TiaOutputWidget.cxx +++ b/src/debugger/gui/TiaOutputWidget.cxx @@ -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) { diff --git a/src/debugger/gui/module.mk b/src/debugger/gui/module.mk index 8f19ce5fa..d992ae85a 100644 --- a/src/debugger/gui/module.mk +++ b/src/debugger/gui/module.mk @@ -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 \ diff --git a/src/emucore/Bankswitch.cxx b/src/emucore/Bankswitch.cxx index 1b907eea7..2ea053df1 100644 --- a/src/emucore/Bankswitch.cxx +++ b/src/emucore/Bankswitch.cxx @@ -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 }, diff --git a/src/emucore/Bankswitch.hxx b/src/emucore/Bankswitch.hxx index 0dd3871c7..6ef5da867 100644 --- a/src/emucore/Bankswitch.hxx +++ b/src/emucore/Bankswitch.hxx @@ -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 diff --git a/src/emucore/Cart.cxx b/src/emucore/Cart.cxx index 7639101ff..045d4c784 100644 --- a/src/emucore/Cart.cxx +++ b/src/emucore/Cart.cxx @@ -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(image), size); + out.write(reinterpret_cast(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( + std::min(size / romBankCount(), 4_KB)); // assuming that each bank has the same size } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Cart.hxx b/src/emucore/Cart.hxx index b04a95f10..8a2e4656e 100644 --- a/src/emucore/Cart.hxx +++ b/src/emucore/Cart.hxx @@ -48,6 +48,9 @@ class Cartridge : public Device public: using StartBankFromPropsFunc = std::function; + // 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. diff --git a/src/emucore/Cart0840.cxx b/src/emucore/Cart0840.cxx index e071f61a2..c560b0a1b 100644 --- a/src/emucore/Cart0840.cxx +++ b/src/emucore/Cart0840.cxx @@ -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) { } diff --git a/src/emucore/Cart0840.hxx b/src/emucore/Cart0840.hxx index af1977485..0d120aad4 100644 --- a/src/emucore/Cart0840.hxx +++ b/src/emucore/Cart0840.hxx @@ -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: diff --git a/src/emucore/Cart2K.cxx b/src/emucore/Cart2K.cxx index f4d4ef7bd..d204d93ed 100644 --- a/src/emucore/Cart2K.cxx +++ b/src/emucore/Cart2K.cxx @@ -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(mySize, System::PAGE_SIZE); - myImage = make_unique(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; } } diff --git a/src/emucore/Cart2K.hxx b/src/emucore/Cart2K.hxx index 0ed6fedef..878df4714 100644 --- a/src/emucore/Cart2K.hxx +++ b/src/emucore/Cart2K.hxx @@ -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: diff --git a/src/emucore/Cart3E.cxx b/src/emucore/Cart3E.cxx index be69d105d..e3d049eea 100644 --- a/src/emucore/Cart3E.cxx +++ b/src/emucore/Cart3E.cxx @@ -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; diff --git a/src/emucore/Cart3E.hxx b/src/emucore/Cart3E.hxx index f2ead51f5..60e50613a 100644 --- a/src/emucore/Cart3E.hxx +++ b/src/emucore/Cart3E.hxx @@ -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: diff --git a/src/emucore/Cart3EPlus.cxx b/src/emucore/Cart3EPlus.cxx index 6c9fe7c2a..2233b0d71 100644 --- a/src/emucore/Cart3EPlus.cxx +++ b/src/emucore/Cart3EPlus.cxx @@ -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); diff --git a/src/emucore/Cart3EPlus.hxx b/src/emucore/Cart3EPlus.hxx index fe6a0a263..2ba54d313 100644 --- a/src/emucore/Cart3EPlus.hxx +++ b/src/emucore/Cart3EPlus.hxx @@ -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: diff --git a/src/emucore/Cart3F.cxx b/src/emucore/Cart3F.cxx index 21b21b9c7..a44c28a5e 100644 --- a/src/emucore/Cart3F.cxx +++ b/src/emucore/Cart3F.cxx @@ -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; } diff --git a/src/emucore/Cart3F.hxx b/src/emucore/Cart3F.hxx index 7bdcbd99c..f5eeac809 100644 --- a/src/emucore/Cart3F.hxx +++ b/src/emucore/Cart3F.hxx @@ -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: diff --git a/src/emucore/Cart4A50.cxx b/src/emucore/Cart4A50.cxx index 845229bc4..6939bc0ef 100644 --- a/src/emucore/Cart4A50.cxx +++ b/src/emucore/Cart4A50.cxx @@ -24,6 +24,7 @@ Cartridge4A50::Cartridge4A50(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) : Cartridge(settings, md5), + myImage(make_unique(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; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Cart4A50.hxx b/src/emucore/Cart4A50.hxx index e68bb8f4a..8a4fdaa2d 100644 --- a/src/emucore/Cart4A50.hxx +++ b/src/emucore/Cart4A50.hxx @@ -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 myImage; + ByteBuffer myImage; // The 32K of RAM on the cartridge std::array myRAM; diff --git a/src/emucore/Cart4K.cxx b/src/emucore/Cart4K.cxx index 9e684afad..830cffd49 100644 --- a/src/emucore/Cart4K.cxx +++ b/src/emucore/Cart4K.cxx @@ -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) { } diff --git a/src/emucore/Cart4K.hxx b/src/emucore/Cart4K.hxx index 1a7c428f4..cc2bb5aef 100644 --- a/src/emucore/Cart4K.hxx +++ b/src/emucore/Cart4K.hxx @@ -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: diff --git a/src/emucore/Cart4KSC.cxx b/src/emucore/Cart4KSC.cxx index 92d2e946e..50ad78e8b 100644 --- a/src/emucore/Cart4KSC.cxx +++ b/src/emucore/Cart4KSC.cxx @@ -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; } diff --git a/src/emucore/Cart4KSC.hxx b/src/emucore/Cart4KSC.hxx index 3f28de9ce..a2197e018 100644 --- a/src/emucore/Cart4KSC.hxx +++ b/src/emucore/Cart4KSC.hxx @@ -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: diff --git a/src/emucore/CartAR.cxx b/src/emucore/CartAR.cxx index a0eea7486..cc58d60be 100644 --- a/src/emucore/CartAR.cxx +++ b/src/emucore/CartAR.cxx @@ -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; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartAR.hxx b/src/emucore/CartAR.hxx index 0bc74a291..0b4369f31 100644 --- a/src/emucore/CartAR.hxx +++ b/src/emucore/CartAR.hxx @@ -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. diff --git a/src/emucore/CartBF.cxx b/src/emucore/CartBF.cxx index ce3c53198..cd815c518 100644 --- a/src/emucore/CartBF.cxx +++ b/src/emucore/CartBF.cxx @@ -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) { } diff --git a/src/emucore/CartBF.hxx b/src/emucore/CartBF.hxx index 23c51f760..5190f73da 100644 --- a/src/emucore/CartBF.hxx +++ b/src/emucore/CartBF.hxx @@ -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: diff --git a/src/emucore/CartBFSC.cxx b/src/emucore/CartBFSC.cxx index bd9793893..ac8a105b3 100644 --- a/src/emucore/CartBFSC.cxx +++ b/src/emucore/CartBFSC.cxx @@ -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; } diff --git a/src/emucore/CartBFSC.hxx b/src/emucore/CartBFSC.hxx index 9bb22aa0a..4a660ecc8 100644 --- a/src/emucore/CartBFSC.hxx +++ b/src/emucore/CartBFSC.hxx @@ -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; /** diff --git a/src/emucore/CartBUS.cxx b/src/emucore/CartBUS.cxx index e2eb9b74a..46d220bbf 100644 --- a/src/emucore/CartBUS.cxx +++ b/src/emucore/CartBUS.cxx @@ -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(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( - reinterpret_cast(myImage.data()), + reinterpret_cast(myImage.get()), reinterpret_cast(myRAM.data()), - static_cast(myImage.size()), + static_cast(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; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartBUS.hxx b/src/emucore/CartBUS.hxx index 3ab40f7ec..2e21b5f24 100644 --- a/src/emucore/CartBUS.hxx +++ b/src/emucore/CartBUS.hxx @@ -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 myImage; + ByteBuffer myImage; // Pointer to the 28K program ROM image of the cartridge uInt8* myProgramImage{nullptr}; diff --git a/src/emucore/CartCDF.cxx b/src/emucore/CartCDF.cxx index 6f9a5f4f7..e09480464 100644 --- a/src/emucore/CartCDF.cxx +++ b/src/emucore/CartCDF.cxx @@ -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(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( - reinterpret_cast(myImage.data()), + reinterpret_cast(myImage.get()), reinterpret_cast(myRAM.data()), - static_cast(myImage.size()), + static_cast(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; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartCDF.hxx b/src/emucore/CartCDF.hxx index 14b1eda26..99374de2b 100644 --- a/src/emucore/CartCDF.hxx +++ b/src/emucore/CartCDF.hxx @@ -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 myImage; + ByteBuffer myImage; // Pointer to the 28K program ROM image of the cartridge uInt8* myProgramImage{nullptr}; diff --git a/src/emucore/CartCM.cxx b/src/emucore/CartCM.cxx index 40ec603e5..dbaac7a54 100644 --- a/src/emucore/CartCM.cxx +++ b/src/emucore/CartCM.cxx @@ -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(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; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartCM.hxx b/src/emucore/CartCM.hxx index bf8b2586e..3a58889b4 100644 --- a/src/emucore/CartCM.hxx +++ b/src/emucore/CartCM.hxx @@ -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 myCompuMate; // The 16K ROM image of the cartridge - std::array myImage; + ByteBuffer myImage; // The 2K of RAM std::array myRAM; diff --git a/src/emucore/CartCTY.cxx b/src/emucore/CartCTY.cxx index 822473081..67647f89c 100644 --- a/src/emucore/CartCTY.cxx +++ b/src/emucore/CartCTY.cxx @@ -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(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; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartCTY.hxx b/src/emucore/CartCTY.hxx index fdd6c1e19..5af3ceff4 100644 --- a/src/emucore/CartCTY.hxx +++ b/src/emucore/CartCTY.hxx @@ -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 myImage; + ByteBuffer myImage; // The 28K ROM image of the music std::array myTuneData; diff --git a/src/emucore/CartCV.cxx b/src/emucore/CartCV.cxx index 8d7ac9d89..8fe746f1a 100644 --- a/src/emucore/CartCV.cxx +++ b/src/emucore/CartCV.cxx @@ -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(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(1_KB); // Copy the RAM image into a buffer for use in reset() diff --git a/src/emucore/CartCV.hxx b/src/emucore/CartCV.hxx index a5403b19f..809d9b373 100644 --- a/src/emucore/CartCV.hxx +++ b/src/emucore/CartCV.hxx @@ -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: diff --git a/src/emucore/CartCreator.cxx b/src/emucore/CartCreator.cxx new file mode 100644 index 000000000..fe7faed55 --- /dev/null +++ b/src/emucore/CartCreator.cxx @@ -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 CartCreator::create(const FilesystemNode& file, + const ByteBuffer& image, size_t size, string& md5, + const string& propertiesType, Settings& settings) +{ + unique_ptr 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 +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(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 +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(image, size, md5, settings); + case Bankswitch::Type::_2K: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_3E: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_3EX: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_3EP: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_3F: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_4A50: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_4K: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_4KSC: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_AR: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_BF: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_BFSC: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_BUS: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_CDF: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_CM: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_CTY: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_CV: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_DF: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_DFSC: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_DPC: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_DPCP: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_E0: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_E7: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_E78K: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_EF: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_EFSC: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_F0: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_F4: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_F4SC: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_F6: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_F6SC: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_F8: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_F8SC: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_FA: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_FA2: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_FC: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_FE: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_MDM: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_UA: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_UASW: + return make_unique(image, size, md5, settings, true); + case Bankswitch::Type::_SB: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_TVBOY: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_WD: + case Bankswitch::Type::_WDSW: + return make_unique(image, size, md5, settings); + case Bankswitch::Type::_X07: + return make_unique(image, size, md5, settings); + default: + return nullptr; // The remaining types have already been handled + } +} diff --git a/src/emucore/CartCreator.hxx b/src/emucore/CartCreator.hxx new file mode 100644 index 000000000..757d306ba --- /dev/null +++ b/src/emucore/CartCreator.hxx @@ -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 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 + 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 + 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 diff --git a/src/emucore/CartDF.cxx b/src/emucore/CartDF.cxx index 0f4d9a1ca..58206a3b5 100644 --- a/src/emucore/CartDF.cxx +++ b/src/emucore/CartDF.cxx @@ -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) { } diff --git a/src/emucore/CartDF.hxx b/src/emucore/CartDF.hxx index 3c33e8bff..18d0f2489 100644 --- a/src/emucore/CartDF.hxx +++ b/src/emucore/CartDF.hxx @@ -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: diff --git a/src/emucore/CartDFSC.cxx b/src/emucore/CartDFSC.cxx index f759136a7..4dafe3bb7 100644 --- a/src/emucore/CartDFSC.cxx +++ b/src/emucore/CartDFSC.cxx @@ -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; } diff --git a/src/emucore/CartDFSC.hxx b/src/emucore/CartDFSC.hxx index 637dde3da..efc6d30e8 100644 --- a/src/emucore/CartDFSC.hxx +++ b/src/emucore/CartDFSC.hxx @@ -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: diff --git a/src/emucore/CartDPC.cxx b/src/emucore/CartDPC.cxx index bc8962b1b..c77aacd8a 100644 --- a/src/emucore/CartDPC.cxx +++ b/src/emucore/CartDPC.cxx @@ -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) { } diff --git a/src/emucore/CartDPC.hxx b/src/emucore/CartDPC.hxx index e0a1b866e..4d90fb140 100644 --- a/src/emucore/CartDPC.hxx +++ b/src/emucore/CartDPC.hxx @@ -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: diff --git a/src/emucore/CartDPCPlus.cxx b/src/emucore/CartDPCPlus.cxx index b71f5a8c0..71500ee94 100644 --- a/src/emucore/CartDPCPlus.cxx +++ b/src/emucore/CartDPCPlus.cxx @@ -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(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 - (reinterpret_cast(myImage.data()), + (reinterpret_cast(myImage.get()), reinterpret_cast(myDPCRAM.data()), - static_cast(myImage.size()), + static_cast(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; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartDPCPlus.hxx b/src/emucore/CartDPCPlus.hxx index 9617d6545..04a1b0de4 100644 --- a/src/emucore/CartDPCPlus.hxx +++ b/src/emucore/CartDPCPlus.hxx @@ -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 myImage; + ByteBuffer myImage; size_t mySize{0}; // Pointer to the 24K program ROM image of the cartridge diff --git a/src/emucore/CartDetector.cxx b/src/emucore/CartDetector.cxx index 976d56579..0ecc6e82e 100644 --- a/src/emucore/CartDetector.cxx +++ b/src/emucore/CartDetector.cxx @@ -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 CartDetector::create(const FilesystemNode& file, - const ByteBuffer& image, size_t size, string& md5, - const string& propertiesType, Settings& settings) -{ - unique_ptr 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 -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(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 -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(image, size, md5, settings); - case Bankswitch::Type::_2K: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_3E: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_3EX: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_3EP: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_3F: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_4A50: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_4K: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_4KSC: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_AR: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_BF: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_BFSC: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_BUS: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_CDF: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_CM: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_CTY: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_CV: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_DF: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_DFSC: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_DPC: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_DPCP: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_E0: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_E7: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_E78K: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_EF: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_EFSC: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_F0: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_F4: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_F4SC: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_F6: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_F6SC: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_F8: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_F8SC: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_FA: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_FA2: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_FC: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_FE: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_MDM: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_UA: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_UASW: - return make_unique(image, size, md5, settings, true); - case Bankswitch::Type::_SB: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_WD: - case Bankswitch::Type::_WDSW: - return make_unique(image, size, md5, settings); - case Bankswitch::Type::_X07: - return make_unique(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) { diff --git a/src/emucore/CartDetector.hxx b/src/emucore/CartDetector.hxx index 9ff193c87..810ed24a7 100644 --- a/src/emucore/CartDetector.hxx +++ b/src/emucore/CartDetector.hxx @@ -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 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 - 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 - 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 */ diff --git a/src/emucore/CartE0.cxx b/src/emucore/CartE0.cxx index 07afae5a2..9204d5619 100644 --- a/src/emucore/CartE0.cxx +++ b/src/emucore/CartE0.cxx @@ -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; } diff --git a/src/emucore/CartE0.hxx b/src/emucore/CartE0.hxx index 84c9ae667..70af8f85d 100644 --- a/src/emucore/CartE0.hxx +++ b/src/emucore/CartE0.hxx @@ -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: diff --git a/src/emucore/CartEF.cxx b/src/emucore/CartEF.cxx index 039f4aa5c..c063b0c05 100644 --- a/src/emucore/CartEF.cxx +++ b/src/emucore/CartEF.cxx @@ -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) { } diff --git a/src/emucore/CartEF.hxx b/src/emucore/CartEF.hxx index ff71b9909..2c86d0d71 100644 --- a/src/emucore/CartEF.hxx +++ b/src/emucore/CartEF.hxx @@ -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: diff --git a/src/emucore/CartEFSC.cxx b/src/emucore/CartEFSC.cxx index c70cff194..f73557245 100644 --- a/src/emucore/CartEFSC.cxx +++ b/src/emucore/CartEFSC.cxx @@ -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; } diff --git a/src/emucore/CartEFSC.hxx b/src/emucore/CartEFSC.hxx index f6c7e40ea..ac95c9e2c 100644 --- a/src/emucore/CartEFSC.hxx +++ b/src/emucore/CartEFSC.hxx @@ -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: diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index 27fa425b5..633104cf3 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -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(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(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(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(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; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartEnhanced.hxx b/src/emucore/CartEnhanced.hxx index 743a4b50e..e99afc917 100644 --- a/src/emucore/CartEnhanced.hxx +++ b/src/emucore/CartEnhanced.hxx @@ -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; diff --git a/src/emucore/CartF0.cxx b/src/emucore/CartF0.cxx index 8747c57f3..0429109e3 100644 --- a/src/emucore/CartF0.cxx +++ b/src/emucore/CartF0.cxx @@ -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) { } diff --git a/src/emucore/CartF0.hxx b/src/emucore/CartF0.hxx index 0d5837066..e49b8ce31 100644 --- a/src/emucore/CartF0.hxx +++ b/src/emucore/CartF0.hxx @@ -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: diff --git a/src/emucore/CartF4.cxx b/src/emucore/CartF4.cxx index 6a8cd6e00..c00163efb 100644 --- a/src/emucore/CartF4.cxx +++ b/src/emucore/CartF4.cxx @@ -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) { } diff --git a/src/emucore/CartF4.hxx b/src/emucore/CartF4.hxx index d44e96640..81a5e176e 100644 --- a/src/emucore/CartF4.hxx +++ b/src/emucore/CartF4.hxx @@ -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: diff --git a/src/emucore/CartF4SC.cxx b/src/emucore/CartF4SC.cxx index 4fe6e13eb..d012874c6 100644 --- a/src/emucore/CartF4SC.cxx +++ b/src/emucore/CartF4SC.cxx @@ -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; } diff --git a/src/emucore/CartF4SC.hxx b/src/emucore/CartF4SC.hxx index 58b255e42..49f1278ac 100644 --- a/src/emucore/CartF4SC.hxx +++ b/src/emucore/CartF4SC.hxx @@ -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: diff --git a/src/emucore/CartF6.cxx b/src/emucore/CartF6.cxx index 50e993e26..7b120d0b0 100644 --- a/src/emucore/CartF6.cxx +++ b/src/emucore/CartF6.cxx @@ -19,8 +19,9 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF6::CartridgeF6(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) { } @@ -36,4 +37,3 @@ bool CartridgeF6::checkSwitchBank(uInt16 address, uInt8) } return false; } - diff --git a/src/emucore/CartF6.hxx b/src/emucore/CartF6.hxx index 16faeebab..7707f1ef6 100644 --- a/src/emucore/CartF6.hxx +++ b/src/emucore/CartF6.hxx @@ -41,9 +41,10 @@ class CartridgeF6 : 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 */ CartridgeF6(const ByteBuffer& image, size_t size, const string& md5, - const Settings& settings); + const Settings& settings, size_t bsSize = 16_KB); virtual ~CartridgeF6() = default; public: diff --git a/src/emucore/CartF6SC.cxx b/src/emucore/CartF6SC.cxx index 15613a357..084091d12 100644 --- a/src/emucore/CartF6SC.cxx +++ b/src/emucore/CartF6SC.cxx @@ -19,9 +19,10 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF6SC::CartridgeF6SC(const ByteBuffer& image, size_t size, - const string& md5, const Settings& settings) - : CartridgeF6(image, size, md5, settings) + const string& md5, const Settings& settings, + size_t bsSize) + : CartridgeF6(image, size, md5, settings, bsSize) { myRamSize = RAM_SIZE; - myRamMask = RAM_SIZE - 1; + myRamMask = RAM_SIZE - 1; } diff --git a/src/emucore/CartF6SC.hxx b/src/emucore/CartF6SC.hxx index c61c9715f..4365036bb 100644 --- a/src/emucore/CartF6SC.hxx +++ b/src/emucore/CartF6SC.hxx @@ -42,9 +42,10 @@ class CartridgeF6SC : public CartridgeF6 @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 */ CartridgeF6SC(const ByteBuffer& image, size_t size, const string& md5, - const Settings& settings); + const Settings& settings, size_t bsSize = 16_KB); virtual ~CartridgeF6SC() = default; public: diff --git a/src/emucore/CartF8.cxx b/src/emucore/CartF8.cxx index 5d898091c..732cb306d 100644 --- a/src/emucore/CartF8.cxx +++ b/src/emucore/CartF8.cxx @@ -19,8 +19,9 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF8::CartridgeF8(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) { } diff --git a/src/emucore/CartF8.hxx b/src/emucore/CartF8.hxx index 29b308808..90b34497a 100644 --- a/src/emucore/CartF8.hxx +++ b/src/emucore/CartF8.hxx @@ -41,9 +41,10 @@ class CartridgeF8 : 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 */ CartridgeF8(const ByteBuffer& image, size_t size, const string& md5, - const Settings& settings); + const Settings& settings, size_t bsSize = 8_KB); virtual ~CartridgeF8() = default; public: diff --git a/src/emucore/CartF8SC.cxx b/src/emucore/CartF8SC.cxx index 98ce4357f..9607d9687 100644 --- a/src/emucore/CartF8SC.cxx +++ b/src/emucore/CartF8SC.cxx @@ -19,8 +19,9 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF8SC::CartridgeF8SC(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) { myRamSize = RAM_SIZE; } diff --git a/src/emucore/CartF8SC.hxx b/src/emucore/CartF8SC.hxx index c5a005543..3eb3539ae 100644 --- a/src/emucore/CartF8SC.hxx +++ b/src/emucore/CartF8SC.hxx @@ -42,9 +42,10 @@ class CartridgeF8SC : 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 */ CartridgeF8SC(const ByteBuffer& image, size_t size, const string& md5, - const Settings& settings); + const Settings& settings, size_t bsSize = 8_KB); virtual ~CartridgeF8SC() = default; public: diff --git a/src/emucore/CartFA.cxx b/src/emucore/CartFA.cxx index 082e403f7..ec242f615 100644 --- a/src/emucore/CartFA.cxx +++ b/src/emucore/CartFA.cxx @@ -20,8 +20,9 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeFA::CartridgeFA(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) { myRamSize = RAM_SIZE; } diff --git a/src/emucore/CartFA.hxx b/src/emucore/CartFA.hxx index a2f197b75..d234de743 100644 --- a/src/emucore/CartFA.hxx +++ b/src/emucore/CartFA.hxx @@ -45,9 +45,10 @@ class CartridgeFA : 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 */ CartridgeFA(const ByteBuffer& image, size_t size, const string& md5, - const Settings& settings); + const Settings& settings, size_t bsSize = 12_KB); virtual ~CartridgeFA() = default; public: diff --git a/src/emucore/CartFA2.cxx b/src/emucore/CartFA2.cxx index 14c8f2156..2443b106a 100644 --- a/src/emucore/CartFA2.cxx +++ b/src/emucore/CartFA2.cxx @@ -20,8 +20,9 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeFA2::CartridgeFA2(const ByteBuffer& image, size_t size, - const string& md5, const Settings& settings) - : CartridgeFA(image, size, md5, settings) + const string& md5, const Settings& settings, + size_t bsSize) + : CartridgeFA(image, size, md5, settings, bsSize) { // 29/32K version of FA2 has valid data @ 1K - 29K const uInt8* img_ptr = image.get(); diff --git a/src/emucore/CartFA2.hxx b/src/emucore/CartFA2.hxx index 16d33bf2b..ea60fbe45 100644 --- a/src/emucore/CartFA2.hxx +++ b/src/emucore/CartFA2.hxx @@ -57,9 +57,10 @@ class CartridgeFA2 : public CartridgeFA @param size The size of the ROM image @param md5 The md5sum of the ROM image @param settings A reference to the settings object + @param bsSize The size specified by the bankswitching scheme */ CartridgeFA2(const ByteBuffer& image, size_t size, const string& md5, - const Settings& settings); + const Settings& settings, size_t bsSize = 28_KB); virtual ~CartridgeFA2() = default; public: diff --git a/src/emucore/CartFC.cxx b/src/emucore/CartFC.cxx index c415ba1af..1b431592e 100644 --- a/src/emucore/CartFC.cxx +++ b/src/emucore/CartFC.cxx @@ -20,8 +20,10 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeFC::CartridgeFC(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) { } diff --git a/src/emucore/CartFC.hxx b/src/emucore/CartFC.hxx index 5858ae85a..92be2a421 100644 --- a/src/emucore/CartFC.hxx +++ b/src/emucore/CartFC.hxx @@ -47,9 +47,11 @@ class CartridgeFC : 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) */ CartridgeFC(const ByteBuffer& image, size_t size, const string& md5, - const Settings& settings); + const Settings& settings, size_t bsSize = 0); virtual ~CartridgeFC() = default; public: diff --git a/src/emucore/CartFE.cxx b/src/emucore/CartFE.cxx index 7c3debda3..d0c01886b 100644 --- a/src/emucore/CartFE.cxx +++ b/src/emucore/CartFE.cxx @@ -21,8 +21,9 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeFE::CartridgeFE(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) { myDirectPeek = false; } diff --git a/src/emucore/CartFE.hxx b/src/emucore/CartFE.hxx index 6c453d284..77ebee767 100644 --- a/src/emucore/CartFE.hxx +++ b/src/emucore/CartFE.hxx @@ -87,9 +87,10 @@ class CartridgeFE : 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 */ CartridgeFE(const ByteBuffer& image, size_t size, const string& md5, - const Settings& settings); + const Settings& settings, size_t bsSize = 8_KB); virtual ~CartridgeFE() = default; public: diff --git a/src/emucore/CartMDM.cxx b/src/emucore/CartMDM.cxx index decb634ec..f92563ec2 100644 --- a/src/emucore/CartMDM.cxx +++ b/src/emucore/CartMDM.cxx @@ -20,8 +20,10 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeMDM::CartridgeMDM(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) { } @@ -88,7 +90,7 @@ bool CartridgeMDM::poke(uInt16 address, uInt8 value) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeMDM::bank(uInt16 bank) +bool CartridgeMDM::bank(uInt16 bank, uInt16) { if(bankLocked() || myBankingDisabled) return false; diff --git a/src/emucore/CartMDM.hxx b/src/emucore/CartMDM.hxx index 4b0786e42..4e12571e1 100644 --- a/src/emucore/CartMDM.hxx +++ b/src/emucore/CartMDM.hxx @@ -56,9 +56,11 @@ class CartridgeMDM : 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) */ CartridgeMDM(const ByteBuffer& image, size_t size, const string& md5, - const Settings& settings); + const Settings& settings, size_t bsSize = 0); virtual ~CartridgeMDM() = default; public: @@ -73,9 +75,12 @@ class CartridgeMDM : public CartridgeEnhanced /** 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; /** Save the current state of this cart to the given Serializer. diff --git a/src/emucore/CartMNetwork.cxx b/src/emucore/CartMNetwork.cxx index c6542b2b8..78c68e6a0 100644 --- a/src/emucore/CartMNetwork.cxx +++ b/src/emucore/CartMNetwork.cxx @@ -201,7 +201,7 @@ void CartridgeMNetwork::bankRAM(uInt16 bank) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeMNetwork::bank(uInt16 bank) +bool CartridgeMNetwork::bank(uInt16 bank, uInt16) { if(bankLocked()) return false; @@ -263,10 +263,10 @@ bool CartridgeMNetwork::patch(uInt16 address, uInt8 value) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeMNetwork::getImage(size_t& size) const +const ByteBuffer& CartridgeMNetwork::getImage(size_t& size) const { size = romBankCount() * BANK_SIZE; - return myImage.get(); + return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartMNetwork.hxx b/src/emucore/CartMNetwork.hxx index 95cd24b56..9b17a4b67 100644 --- a/src/emucore/CartMNetwork.hxx +++ b/src/emucore/CartMNetwork.hxx @@ -94,9 +94,12 @@ class CartridgeMNetwork : 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. @@ -123,9 +126,9 @@ class CartridgeMNetwork : 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. diff --git a/src/emucore/CartSB.cxx b/src/emucore/CartSB.cxx index 5caa01be7..18d160cff 100644 --- a/src/emucore/CartSB.cxx +++ b/src/emucore/CartSB.cxx @@ -20,8 +20,10 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeSB::CartridgeSB(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) { } diff --git a/src/emucore/CartSB.hxx b/src/emucore/CartSB.hxx index 85c8e9ccb..17cea387c 100644 --- a/src/emucore/CartSB.hxx +++ b/src/emucore/CartSB.hxx @@ -45,9 +45,11 @@ class CartridgeSB : 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) */ CartridgeSB(const ByteBuffer& image, size_t size, const string& md5, - const Settings& settings); + const Settings& settings, size_t bsSize = 0); virtual ~CartridgeSB() = default; public: diff --git a/src/emucore/CartTVBoy.cxx b/src/emucore/CartTVBoy.cxx new file mode 100644 index 000000000..50d66cb57 --- /dev/null +++ b/src/emucore/CartTVBoy.cxx @@ -0,0 +1,88 @@ +//============================================================================ +// +// 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 "System.hxx" +#include "CartTVBoy.hxx" + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +CartridgeTVBoy::CartridgeTVBoy(const ByteBuffer& image, size_t size, + const string& md5, const Settings& settings, + size_t bsSize) + : CartridgeEnhanced(image, size, md5, settings, bsSize) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CartridgeTVBoy::checkSwitchBank(uInt16 address, uInt8) +{ + // Switch banks if necessary + if((address & ADDR_MASK) >= 0x1800 && (address & ADDR_MASK) <= 0x187F) + { + bank(address & (romBankCount() - 1)); + return true; + } + return false; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CartridgeTVBoy::bank(uInt16 bank, uInt16) +{ + if(myBankingDisabled) return false; + + bool banked = CartridgeEnhanced::bank(bank); + + // Any bankswitching locks further bankswitching, we check for bank 0 + // to avoid locking on cart init. + if (banked && bank != 0) + myBankingDisabled = true; + + return banked; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CartridgeTVBoy::save(Serializer& out) const +{ + CartridgeEnhanced::save(out); + try + { + out.putBool(myBankingDisabled); + } + catch(...) + { + cerr << "ERROR: CartridgeTVBoy::save" << endl; + return false; + } + + return true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CartridgeTVBoy::load(Serializer& in) +{ + CartridgeEnhanced::load(in); + try + { + myBankingDisabled = in.getBool(); + } + catch(...) + { + cerr << "ERROR: CartridgeTVBoy::load" << endl; + return false; + } + + return true; +} diff --git a/src/emucore/CartTVBoy.hxx b/src/emucore/CartTVBoy.hxx new file mode 100644 index 000000000..d1787e55b --- /dev/null +++ b/src/emucore/CartTVBoy.hxx @@ -0,0 +1,117 @@ +//============================================================================ +// +// 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_HXX +#define CARTRIDGETVBOY_HXX + +#include "bspf.hxx" +#include "CartEnhanced.hxx" +#include "System.hxx" +#ifdef DEBUGGER_SUPPORT +#include "CartTVBoyWidget.hxx" +#endif + +/** + Cartridge class used for TV Boy + There are 128 4K banks, accessing $F800..$F87F selects bank and locks any + further bankswitching. + + @author Thomas Jentzsch +*/ +class CartridgeTVBoy : public CartridgeEnhanced +{ + friend class CartridgeTVBoyWidget; + + public: + /** + Create a new cartridge using the specified image + + @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 + */ + CartridgeTVBoy(const ByteBuffer& image, size_t size, const string& md5, + const Settings& settings, size_t bsSize = 512_KB); + virtual ~CartridgeTVBoy() = default; + + public: + /** + Install pages for the specified bank 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, uInt16 segment = 0) override; + + /** + Save the current state of this cart to the given Serializer. + + @param out The Serializer object to use + @return False on any errors, else true + */ + bool save(Serializer& out) const override; + + /** + Load the current state of this cart from the given Serializer. + + @param in The Serializer object to use + @return False on any errors, else true + */ + bool load(Serializer& in) override; + + /** + Get a descriptor for the device name (used in error checking). + + @return The name of the object + */ + string name() const override { return "CartridgeTVBoy"; } + + #ifdef DEBUGGER_SUPPORT + /** + Get debugger widget responsible for accessing the inner workings + of the cart. + */ + CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, + const GUI::Font& nfont, int x, int y, int w, int h) override + { + return new CartridgeTVBoyWidget(boss, lfont, nfont, x, y, w, h, *this); + } + #endif + + private: + bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; + + uInt16 hotspot() const override { return 0x1800; } + + private: + // Indicates whether banking has been disabled due to a bankswitch + bool myBankingDisabled{false}; + + private: + // Following constructors and assignment operators not supported + CartridgeTVBoy() = delete; + CartridgeTVBoy(const CartridgeTVBoy&) = delete; + CartridgeTVBoy(CartridgeTVBoy&&) = delete; + CartridgeTVBoy& operator=(const CartridgeTVBoy&) = delete; + CartridgeTVBoy& operator=(CartridgeTVBoy&&) = delete; +}; + +#endif diff --git a/src/emucore/CartUA.cxx b/src/emucore/CartUA.cxx index 74ccc3773..e73f166db 100644 --- a/src/emucore/CartUA.cxx +++ b/src/emucore/CartUA.cxx @@ -22,7 +22,7 @@ CartridgeUA::CartridgeUA(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings, bool swapHotspots) - : CartridgeEnhanced(image, size, md5, settings), + : CartridgeEnhanced(image, size, md5, settings, 8_KB), mySwappedHotspots(swapHotspots) { } diff --git a/src/emucore/CartWD.cxx b/src/emucore/CartWD.cxx index 11ebc653e..d985abd00 100644 --- a/src/emucore/CartWD.cxx +++ b/src/emucore/CartWD.cxx @@ -22,11 +22,12 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeWD::CartridgeWD(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) { // Copy the ROM image into my buffer - if (mySize == 8_KB + 3) + if(size == 8_KB + 3) { // swap banks 2 & 3 of bad dump and correct size std::copy_n(image.get() + 1_KB * 3, 1_KB * 1, myImage.get() + 1_KB * 2); diff --git a/src/emucore/CartWD.hxx b/src/emucore/CartWD.hxx index 398571a52..4c1d9d3d9 100644 --- a/src/emucore/CartWD.hxx +++ b/src/emucore/CartWD.hxx @@ -65,9 +65,10 @@ class CartridgeWD : 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 */ CartridgeWD(const ByteBuffer& image, size_t size, const string& md5, - const Settings& settings); + const Settings& settings, size_t bsSize = 8_KB); virtual ~CartridgeWD() = default; public: diff --git a/src/emucore/CartX07.cxx b/src/emucore/CartX07.cxx index ac40b6ac6..4f3294d5c 100644 --- a/src/emucore/CartX07.cxx +++ b/src/emucore/CartX07.cxx @@ -22,8 +22,9 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeX07::CartridgeX07(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) { } diff --git a/src/emucore/CartX07.hxx b/src/emucore/CartX07.hxx index 3cde4efdf..3f59ca7c3 100644 --- a/src/emucore/CartX07.hxx +++ b/src/emucore/CartX07.hxx @@ -54,9 +54,10 @@ class CartridgeX07 : 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 */ CartridgeX07(const ByteBuffer& image, size_t size, const string& md5, - const Settings& settings); + const Settings& settings, size_t bsSize = 64_KB); virtual ~CartridgeX07() = default; public: diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 1e796a0bd..1f828ee94 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -444,7 +444,7 @@ void Console::setFormat(uInt32 format, bool force) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::toggleColorLoss() +void Console::toggleColorLoss(bool toggle) { bool colorloss = !myTIA->colorLossEnabled(); if(myTIA->enableColorLoss(colorloss)) @@ -726,7 +726,7 @@ void Console::setControllers(const string& romMd5) Controller::Type leftType = Controller::getType(myProperties.get(PropType::Controller_Left)); Controller::Type rightType = Controller::getType(myProperties.get(PropType::Controller_Right)); size_t size = 0; - const uInt8* image = myCart->getImage(size); + const ByteBuffer& image = myCart->getImage(size); const bool swappedPorts = myProperties.get(PropType::Console_SwapPorts) == "YES"; // Try to detect controllers @@ -876,51 +876,56 @@ float Console::getFramerate() const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::toggleTIABit(TIABit bit, const string& bitname, bool show) const +void Console::toggleTIABit(TIABit bit, const string& bitname, bool show, bool toggle) const { - bool result = myTIA->toggleBit(bit); - string message = bitname + (result ? " enabled" : " disabled"); + bool result = myTIA->toggleBit(bit, toggle ? 2 : 3); + const string message = bitname + (result ? " enabled" : " disabled"); + myOSystem.frameBuffer().showMessage(message); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::toggleBits() const +void Console::toggleBits(bool toggle) const { - bool enabled = myTIA->toggleBits(); - string message = string("TIA bits") + (enabled ? " enabled" : " disabled"); + bool enabled = myTIA->toggleBits(toggle); + const string message = string("TIA bits ") + (enabled ? "enabled" : "disabled"); + myOSystem.frameBuffer().showMessage(message); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::toggleTIACollision(TIABit bit, const string& bitname, bool show) const +void Console::toggleTIACollision(TIABit bit, const string& bitname, bool show, bool toggle) const { - bool result = myTIA->toggleCollision(bit); - string message = bitname + (result ? " collision enabled" : " collision disabled"); + bool result = myTIA->toggleCollision(bit, toggle ? 2 : 3); + const string message = bitname + (result ? " collision enabled" : " collision disabled"); + myOSystem.frameBuffer().showMessage(message); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::toggleCollisions() const +void Console::toggleCollisions(bool toggle) const { - bool enabled = myTIA->toggleCollisions(); - string message = string("TIA collisions") + (enabled ? " enabled" : " disabled"); + bool enabled = myTIA->toggleCollisions(toggle); + const string message = string("TIA collisions ") + (enabled ? "enabled" : "disabled"); + myOSystem.frameBuffer().showMessage(message); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::toggleFixedColors() const +void Console::toggleFixedColors(bool toggle) const { - if(myTIA->toggleFixedColors()) - myOSystem.frameBuffer().showMessage("Fixed debug colors enabled"); - else - myOSystem.frameBuffer().showMessage("Fixed debug colors disabled"); + bool enabled = toggle ? myTIA->toggleFixedColors() : myTIA->usingFixedColors(); + const string message = string("Fixed debug colors ") + (enabled ? "enabled" : "disabled"); + + myOSystem.frameBuffer().showMessage(message); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::toggleJitter() const +void Console::toggleJitter(bool toggle) const { - bool enabled = myTIA->toggleJitter(); - string message = string("TV scanline jitter") + (enabled ? " enabled" : " disabled"); + bool enabled = myTIA->toggleJitter(toggle ? 2 : 3); + const string message = string("TV scanline jitter ") + (enabled ? "enabled" : "disabled"); + myOSystem.frameBuffer().showMessage(message); } diff --git a/src/emucore/Console.hxx b/src/emucore/Console.hxx index d13588b07..1cc37fc0b 100644 --- a/src/emucore/Console.hxx +++ b/src/emucore/Console.hxx @@ -229,7 +229,7 @@ class Console : public Serializable, public ConsoleIO /** Toggles the PAL color-loss effect. */ - void toggleColorLoss(); + void toggleColorLoss(bool toggle = true); void enableColorLoss(bool state); /** @@ -278,34 +278,34 @@ class Console : public Serializable, public ConsoleIO /** Toggles the TIA bit specified in the method name. */ - void toggleP0Bit() const { toggleTIABit(P0Bit, "P0"); } - void toggleP1Bit() const { toggleTIABit(P1Bit, "P1"); } - void toggleM0Bit() const { toggleTIABit(M0Bit, "M0"); } - void toggleM1Bit() const { toggleTIABit(M1Bit, "M1"); } - void toggleBLBit() const { toggleTIABit(BLBit, "BL"); } - void togglePFBit() const { toggleTIABit(PFBit, "PF"); } - void toggleBits() const; + void toggleP0Bit(bool toggle = true) const { toggleTIABit(P0Bit, "P0", true, toggle); } + void toggleP1Bit(bool toggle = true) const { toggleTIABit(P1Bit, "P1", true, toggle); } + void toggleM0Bit(bool toggle = true) const { toggleTIABit(M0Bit, "M0", true, toggle); } + void toggleM1Bit(bool toggle = true) const { toggleTIABit(M1Bit, "M1", true, toggle); } + void toggleBLBit(bool toggle = true) const { toggleTIABit(BLBit, "BL", true, toggle); } + void togglePFBit(bool toggle = true) const { toggleTIABit(PFBit, "PF", true, toggle); } + void toggleBits(bool toggle = true) const; /** Toggles the TIA collisions specified in the method name. */ - void toggleP0Collision() const { toggleTIACollision(P0Bit, "P0"); } - void toggleP1Collision() const { toggleTIACollision(P1Bit, "P1"); } - void toggleM0Collision() const { toggleTIACollision(M0Bit, "M0"); } - void toggleM1Collision() const { toggleTIACollision(M1Bit, "M1"); } - void toggleBLCollision() const { toggleTIACollision(BLBit, "BL"); } - void togglePFCollision() const { toggleTIACollision(PFBit, "PF"); } - void toggleCollisions() const; + void toggleP0Collision(bool toggle = true) const { toggleTIACollision(P0Bit, "P0", true, toggle); } + void toggleP1Collision(bool toggle = true) const { toggleTIACollision(P1Bit, "P1", true, toggle); } + void toggleM0Collision(bool toggle = true) const { toggleTIACollision(M0Bit, "M0", true, toggle); } + void toggleM1Collision(bool toggle = true) const { toggleTIACollision(M1Bit, "M1", true, toggle); } + void toggleBLCollision(bool toggle = true) const { toggleTIACollision(BLBit, "BL", true, toggle); } + void togglePFCollision(bool toggle = true) const { toggleTIACollision(PFBit, "PF", true, toggle); } + void toggleCollisions(bool toggle = true) const; /** Toggles the TIA 'fixed debug colors' mode. */ - void toggleFixedColors() const; + void toggleFixedColors(bool toggle = true) const; /** Toggles the TIA 'scanline jitter' mode. */ - void toggleJitter() const; + void toggleJitter(bool toggle = true) const; /** * Update vcenter @@ -351,8 +351,10 @@ class Console : public Serializable, public ConsoleIO unique_ptr getControllerPort(const Controller::Type type, const Controller::Jack port, const string& romMd5); - void toggleTIABit(TIABit bit, const string& bitname, bool show = true) const; - void toggleTIACollision(TIABit bit, const string& bitname, bool show = true) const; + void toggleTIABit(TIABit bit, const string& bitname, + bool show = true, bool toggle = true) const; + void toggleTIACollision(TIABit bit, const string& bitname, + bool show = true, bool toggle = true) const; private: // Reference to the osystem object diff --git a/src/emucore/ControllerDetector.cxx b/src/emucore/ControllerDetector.cxx index 023302d81..95922051b 100644 --- a/src/emucore/ControllerDetector.cxx +++ b/src/emucore/ControllerDetector.cxx @@ -22,8 +22,10 @@ #include "ControllerDetector.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Controller::Type ControllerDetector::detectType(const uInt8* image, size_t size, - const Controller::Type type, const Controller::Jack port, const Settings& settings) +Controller::Type ControllerDetector::detectType( + const ByteBuffer& image, size_t size, + const Controller::Type type, const Controller::Jack port, + const Settings& settings) { if(type == Controller::Type::Unknown || settings.getBool("rominfo")) { @@ -43,7 +45,7 @@ Controller::Type ControllerDetector::detectType(const uInt8* image, size_t size, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string ControllerDetector::detectName(const uInt8* image, size_t size, +string ControllerDetector::detectName(const ByteBuffer& image, size_t size, const Controller::Type controller, const Controller::Jack port, const Settings& settings) { @@ -51,7 +53,8 @@ string ControllerDetector::detectName(const uInt8* image, size_t size, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Controller::Type ControllerDetector::autodetectPort(const uInt8* image, size_t size, +Controller::Type ControllerDetector::autodetectPort( + const ByteBuffer& image, size_t size, Controller::Jack port, const Settings& settings) { // default type joystick @@ -88,7 +91,7 @@ Controller::Type ControllerDetector::autodetectPort(const uInt8* image, size_t s } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool ControllerDetector::searchForBytes(const uInt8* image, size_t imagesize, +bool ControllerDetector::searchForBytes(const ByteBuffer& image, size_t imagesize, const uInt8* signature, uInt32 sigsize) { if (imagesize >= sigsize) @@ -112,7 +115,7 @@ bool ControllerDetector::searchForBytes(const uInt8* image, size_t imagesize, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool ControllerDetector::usesJoystickButton(const uInt8* image, size_t size, +bool ControllerDetector::usesJoystickButton(const ByteBuffer& image, size_t size, Controller::Jack port) { if(port == Controller::Jack::Left) @@ -242,7 +245,7 @@ bool ControllerDetector::usesJoystickButton(const uInt8* image, size_t size, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool ControllerDetector::usesKeyboard(const uInt8* image, size_t size, +bool ControllerDetector::usesKeyboard(const ByteBuffer& image, size_t size, Controller::Jack port) { if(port == Controller::Jack::Left) @@ -314,13 +317,14 @@ bool ControllerDetector::usesKeyboard(const uInt8* image, size_t size, else if(port == Controller::Jack::Right) { // check for INPT2 *AND* INPT3 access - const int NUM_SIGS_0_0 = 5; + const int NUM_SIGS_0_0 = 6; const int SIG_SIZE_0_0 = 3; uInt8 signature_0_0[NUM_SIGS_0_0][SIG_SIZE_0_0] = { { 0x24, 0x3a, 0x30 }, // bit INPT2|$30; bmi { 0xa5, 0x3a, 0x10 }, // lda INPT2|$30; bpl { 0xa4, 0x3a, 0x30 }, // ldy INPT2|$30; bmi { 0x24, 0x0a, 0x30 }, // bit INPT2; bmi + { 0x24, 0x0a, 0x10 }, // bit INPT2; bpl { 0xa6, 0x0a, 0x30 } // ldx INPT2; bmi }; const int NUM_SIGS_0_2 = 1; @@ -329,13 +333,14 @@ bool ControllerDetector::usesKeyboard(const uInt8* image, size_t size, { 0xb5, 0x38, 0x29, 0x80, 0xd0 } // lda INPT2,x; and #80; bne }; - const int NUM_SIGS_1_0 = 5; + const int NUM_SIGS_1_0 = 6; const int SIG_SIZE_1_0 = 3; uInt8 signature_1_0[NUM_SIGS_1_0][SIG_SIZE_1_0] = { { 0x24, 0x3b, 0x30 }, // bit INPT3|$30; bmi { 0xa5, 0x3b, 0x10 }, // lda INPT3|$30; bpl { 0xa4, 0x3b, 0x30 }, // ldy INPT3|$30; bmi { 0x24, 0x0b, 0x30 }, // bit INPT3; bmi + { 0x24, 0x0b, 0x10 }, // bit INPT3; bpl { 0xa6, 0x0b, 0x30 } // ldx INPT3; bmi }; const int NUM_SIGS_1_2 = 1; @@ -381,7 +386,7 @@ bool ControllerDetector::usesKeyboard(const uInt8* image, size_t size, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool ControllerDetector::usesGenesisButton(const uInt8* image, size_t size, +bool ControllerDetector::usesGenesisButton(const ByteBuffer& image, size_t size, Controller::Jack port) { if(port == Controller::Jack::Left) @@ -438,7 +443,7 @@ bool ControllerDetector::usesGenesisButton(const uInt8* image, size_t size, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool ControllerDetector::usesPaddle(const uInt8* image, size_t size, +bool ControllerDetector::usesPaddle(const ByteBuffer& image, size_t size, Controller::Jack port, const Settings& settings) { if(port == Controller::Jack::Left) @@ -547,7 +552,7 @@ bool ControllerDetector::usesPaddle(const uInt8* image, size_t size, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool ControllerDetector::isProbablyTrakBall(const uInt8* image, size_t size) +bool ControllerDetector::isProbablyTrakBall(const ByteBuffer& image, size_t size) { // check for TrakBall tables const int NUM_SIGS = 3; @@ -566,7 +571,7 @@ bool ControllerDetector::isProbablyTrakBall(const uInt8* image, size_t size) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool ControllerDetector::isProbablyAtariMouse(const uInt8* image, size_t size) +bool ControllerDetector::isProbablyAtariMouse(const ByteBuffer& image, size_t size) { // check for Atari Mouse tables const int NUM_SIGS = 3; @@ -585,7 +590,7 @@ bool ControllerDetector::isProbablyAtariMouse(const uInt8* image, size_t size) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool ControllerDetector::isProbablyAmigaMouse(const uInt8* image, size_t size) +bool ControllerDetector::isProbablyAmigaMouse(const ByteBuffer& image, size_t size) { // check for Amiga Mouse tables const int NUM_SIGS = 4; @@ -605,7 +610,7 @@ bool ControllerDetector::isProbablyAmigaMouse(const uInt8* image, size_t size) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool ControllerDetector::isProbablySaveKey(const uInt8* image, size_t size, +bool ControllerDetector::isProbablySaveKey(const ByteBuffer& image, size_t size, Controller::Jack port) { // check for known SaveKey code, only supports right port @@ -650,7 +655,7 @@ bool ControllerDetector::isProbablySaveKey(const uInt8* image, size_t size, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool ControllerDetector::isProbablyLightGun(const uInt8* image, size_t size, +bool ControllerDetector::isProbablyLightGun(const ByteBuffer& image, size_t size, Controller::Jack port) { if (port == Controller::Jack::Left) diff --git a/src/emucore/ControllerDetector.hxx b/src/emucore/ControllerDetector.hxx index d37076eb1..be24ae09d 100644 --- a/src/emucore/ControllerDetector.hxx +++ b/src/emucore/ControllerDetector.hxx @@ -34,14 +34,14 @@ class ControllerDetector /** Detects the controller type at the given port if no controller is provided. - @param image A pointer to the ROM image + @param image A reference to the ROM image @param size The size of the ROM image @param controller The provided controller type of the ROM image @param port The port to be checked @param settings A reference to the various settings (read-only) @return The detected controller type */ - static Controller::Type detectType(const uInt8* image, size_t size, + static Controller::Type detectType(const ByteBuffer& image, size_t size, const Controller::Type controller, const Controller::Jack port, const Settings& settings); @@ -49,7 +49,7 @@ class ControllerDetector Detects the controller type at the given port if no controller is provided and returns its name. - @param image A pointer to the ROM image + @param image A reference to the ROM image @param size The size of the ROM image @param type The provided controller type of the ROM image @param port The port to be checked @@ -57,7 +57,7 @@ class ControllerDetector @return The (detected) controller name */ - static string detectName(const uInt8* image, size_t size, + static string detectName(const ByteBuffer& image, size_t size, const Controller::Type type, const Controller::Jack port, const Settings& settings); @@ -65,14 +65,14 @@ class ControllerDetector /** Detects the controller type at the given port. - @param image A pointer to the ROM image + @param image A reference to the ROM image @param size The size of the ROM image @param port The port to be checked @param settings A reference to the various settings (read-only) @return The detected controller type */ - static Controller::Type autodetectPort(const uInt8* image, size_t size, + static Controller::Type autodetectPort(const ByteBuffer& image, size_t size, Controller::Jack port, const Settings& settings); /** @@ -85,36 +85,41 @@ class ControllerDetector @return True if the signature was found, else false */ - static bool searchForBytes(const uInt8* image, size_t imagesize, + static bool searchForBytes(const ByteBuffer& image, size_t imagesize, const uInt8* signature, uInt32 sigsize); // Returns true if the port's joystick button access code is found. - static bool usesJoystickButton(const uInt8* image, size_t size, Controller::Jack port); + static bool usesJoystickButton(const ByteBuffer& image, size_t size, + Controller::Jack port); // Returns true if the port's keyboard access code is found. - static bool usesKeyboard(const uInt8* image, size_t size, Controller::Jack port); + static bool usesKeyboard(const ByteBuffer& image, size_t size, + Controller::Jack port); // Returns true if the port's 2nd Genesis button access code is found. - static bool usesGenesisButton(const uInt8* image, size_t size, Controller::Jack port); + static bool usesGenesisButton(const ByteBuffer& image, size_t size, + Controller::Jack port); // Returns true if the port's paddle button access code is found. - static bool usesPaddle(const uInt8* image, size_t size, Controller::Jack port, - const Settings& settings); + static bool usesPaddle(const ByteBuffer& image, size_t size, + Controller::Jack port, const Settings& settings); // Returns true if a Trak-Ball table is found. - static bool isProbablyTrakBall(const uInt8* image, size_t size); + static bool isProbablyTrakBall(const ByteBuffer& image, size_t size); // Returns true if an Atari Mouse table is found. - static bool isProbablyAtariMouse(const uInt8* image, size_t size); + static bool isProbablyAtariMouse(const ByteBuffer& image, size_t size); // Returns true if an Amiga Mouse table is found. - static bool isProbablyAmigaMouse(const uInt8* image, size_t size); + static bool isProbablyAmigaMouse(const ByteBuffer& image, size_t size); // Returns true if a SaveKey code pattern is found. - static bool isProbablySaveKey(const uInt8* image, size_t size, Controller::Jack port); + static bool isProbablySaveKey(const ByteBuffer& image, size_t size, + Controller::Jack port); // Returns true if a Lightgun code pattern is found - static bool isProbablyLightGun(const uInt8* image, size_t size, Controller::Jack port); + static bool isProbablyLightGun(const ByteBuffer& image, size_t size, + Controller::Jack port); private: @@ -127,4 +132,3 @@ class ControllerDetector }; #endif - diff --git a/src/emucore/DefProps.hxx b/src/emucore/DefProps.hxx index fc0fe6155..65f2d67ca 100644 --- a/src/emucore/DefProps.hxx +++ b/src/emucore/DefProps.hxx @@ -25,7 +25,7 @@ regenerated and the application recompiled. */ -static constexpr uInt32 DEF_PROPS_SIZE = 3514; +static constexpr uInt32 DEF_PROPS_SIZE = 3518; static const BSPF::array2D DefProps = {{ { "000509d1ed2b8d30a9d94be1b3b5febb", "Greg Zumwalt", "", "Jungle Jane (2003) (Greg Zumwalt) (Hack)", "Hack of Pitfall!", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -405,6 +405,7 @@ static const BSPF::array2D DefProps = {{ { "1b1daaa9aa5cded3d633bfcbeb06479c", "", "", "Ship Demo (V 1502) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1b22a3d79ddd79335b69c94dd9b3e44e", "Tron", "", "Moon Patrol (Tron)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1b4b06c2a14ed3ee73b7d0fd61b6aaf5", "Arcadia Corporation, Stephen H. Landrum", "AR-4400", "Excalibur (Dragonstomper Beta) (1982) (Arcadia) (Prototype) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1b5a8da0622bffcee4c5b42aed4e0ef0", "Akor", "", "TV Boy II (1992) (Akor)", "Includes 127 games", "", "", "", "", "", "", "", "", "JOYSTICK", "JOYSTICK", "", "", "", "", "", "", "", "" }, { "1b8c3c0bfb815b2a1010bba95998b66e", "Telegames", "", "Frogs and Flies (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1b8d35d93697450ea26ebf7ff17bd4d1", "Quelle - Otto Versand", "176.764 9 - 781644", "Marineflieger (1983) (Quelle) (PAL)", "AKA Seahawk", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1bb91bae919ddbd655fa25c54ea6f532", "Suntek", "SS-026", "Treasure Island (1983) (Suntek) (PAL)", "AKA Treasure Discovery", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -1426,6 +1427,7 @@ static const BSPF::array2D DefProps = {{ { "65917ae29a8c9785bb1f2acb0d6aafd0", "", "", "Junkosoft One Year Demo (1999) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6596b3737ae4b976e4aadb68d836c5c7", "Digivision", "", "Defender (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "659a20019de4a23c748ec2292ea5f221", "Retroactive", "", "Qb (V2.05) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "65a6f1255fe22468a8bf84ff28a4d289", "Akor", "", "Super TV Boy (1995) (Akor)", "Includes 127 games", "", "", "", "", "", "", "", "", "JOYSTICK", "JOYSTICK", "", "", "", "", "", "", "", "" }, { "65b106eba3e45f3dab72ea907f39f8b4", "Christian Software Development - HomeComputer Software, Dan Schafer, Glenn Stohel, Jon Tedesco - Sparrow", "GCG 1001T", "Music Machine, The (1983) (Sparrow)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "", "", "AUTO 45", "", "", "", "" }, { "65ba1a4c643d1ab44481bdddeb403827", "Quelle", "876.013 4", "Katastrophen-Einsatz (1983) (Quelle) (PAL)", "AKA M.A.S.H.", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "65bd29e8ab1b847309775b0de6b2e4fe", "Coleco, Ed English", "2667", "Roc 'n Rope (1984) (Coleco)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -3146,6 +3148,7 @@ static const BSPF::array2D DefProps = {{ { "e4c666ca0c36928b95b13d33474dbb44", "Arcadia Corporation, Steve Hales, Stephen H. Landrum", "4 AR-4102", "Suicide Mission (1982) (Arcadia)", "AKA Meteoroids", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "e4d41f2d59a56a9d917038682b8e0b8c", "Cody Pittman", "", "Kiss Meets Pacman (Cody Pittman) (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e4e9125a8741977583776729359614e1", "SnailSoft", "", "Comitoid beta 4 (SnailSoft)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e4fa739c81b003c92bea7da5e84c7feb", "Akor", "", "TV Boy (1992) (Akor) (NTSC) [bad dump]", "Includes 127 games", "", "", "", "", "", "", "", "", "JOYSTICK", "JOYSTICK", "", "", "", "", "", "", "", "" }, { "e505bd8e59e31aaed20718d47b15c61b", "Funvision - Fund. Int'l Co.", "", "Space War (1982) (Funvision) (PAL)", "AKA Condor Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e51030251e440cffaab1ac63438b44ae", "Parker Brothers - On-Time Software, Joe Gaucher, Louis Marbel", "PB5110", "James Bond 007 (1984) (Parker Bros)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "e51c23389e43ab328ccfb05be7d451da", "Arcadia Corporation, Scott Nelson", "13", "Sweat! - The Decathlon Game (1983) (Arcadia) (Prototype)", "Uses the Paddle Controllers (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -3357,7 +3360,7 @@ static const BSPF::array2D DefProps = {{ { "f39e4bc99845edd8621b0f3c7b8c4fd9", "AtariAge", "", "Toyshop Trouble (AtariAge)", "F8 Emulator Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f3c431930e035a457fe370ed4d230659", "", "", "Crackpots (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f3cd0f886201d1376f3abab2df53b1b9", "Commavid, Ben Burch", "CM-010", "Rush Hour (1983) (Commavid) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f3dfae774f3bd005a026e29894db40d3", "Otto Versand", "649635", "See Saw (Double-Game Package) (1983) (Otto Versand) (PAL)", "AKA Circus Atari", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f3dfae774f3bd005a026e29894db40d3", "Otto Versand", "649635", "See Saw (Double-Game Package) (1983) (Otto Versand) (PAL)", "AKA Circus Atari", "", "", "", "", "", "", "", "", "JOYSTICK", "JOYSTICK", "", "", "", "", "", "", "", "" }, { "f3f5f72bfdd67f3d0e45d097e11b8091", "Sears Tele-Games, Marilyn Churchill, Matthew L. Hubbard", "CX2647 - 49-75142", "Submarine Commander (1982) (Sears)", "AKA Seawolf 3", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f3f92aad3a335f0a1ead24a0214ff446", "", "", "Spectrum Color Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f40e437a9ebf0bdfe26204152f74f868", "Bit Corporation", "R320", "Jawbreaker (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -3420,6 +3423,7 @@ static const BSPF::array2D DefProps = {{ { "f7af41a87533524d9a478575b0d873d0", "Quelle", "495.663 7", "Spiderman (1983) (Quelle) (PAL)", "AKA Spider-Man", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f7d6592dcb773c81c278140ed4d01669", "Activision, David Crane, Dan Kitchen", "EAG-108-04, EAZ-108-04B", "Ghostbusters (1985) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f7e07080ed8396b68f2e5788a5c245e2", "Video Game Cartridge - Ariola", "TP-617", "Farmyard Fun (Ariola)", "AKA Play Farm", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f7ec2f2bdbe8fbea048c0d5fa6503b0b", "Akor", "", "TV Boy (1992) (Akor) (PAL)", "Includes 127 games", "", "", "", "", "", "", "", "", "JOYSTICK", "JOYSTICK", "", "", "", "", "", "", "", "" }, { "f7f50d9c9d28bcc9f7d3075668b7ac89", "Activision, David Crane - Ariola", "EAG-008, PAG-008, EAG-008-04I - 711 008-720", "Laser Blast (1981) (Activision) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f7fac15cf54b55c5597718b6742dbec2", "Spiceware", "SW-01", "Medieval Mayhem (NTSC)", "", "Homebrew", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "AUTO 55", "", "", "", "" }, { "f802fa61011dd9eb6f80b271bac479d0", "Suntek", "SS-023", "Mole Hunter (1983) (Suntek) (PAL)", "AKA Topy", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, diff --git a/src/emucore/Event.hxx b/src/emucore/Event.hxx index fa8a4d04d..f666e19bc 100644 --- a/src/emucore/Event.hxx +++ b/src/emucore/Event.hxx @@ -121,8 +121,10 @@ class Event ToggleCollisions, ToggleBits, ToggleFixedColors, ToggleFrameStats, ToggleSAPortOrder, ExitGame, - // add new events from here to avoid that user remapped events get overwritten SettingDecrease, SettingIncrease, PreviousSetting, NextSetting, + ToggleAdaptRefresh, PreviousMultiCartRom, + // add new events from here to avoid that user remapped events get overwritten + PreviousSettingGroup, NextSettingGroup, LastType }; diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index fa87be91d..536b33e65 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -342,6 +342,16 @@ void EventHandler::handleSystemEvent(SystemEvent e, int, int) } } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +EventHandler::AdjustGroup EventHandler::getAdjustGroup() +{ + if (myAdjustSetting >= AdjustSetting::START_DEBUG_ADJ && myAdjustSetting <= AdjustSetting::END_DEBUG_ADJ) + return AdjustGroup::DEBUG; + + return AdjustGroup::AV; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - AdjustFunction EventHandler::cycleAdjustSetting(int direction) { @@ -350,17 +360,42 @@ AdjustFunction EventHandler::cycleAdjustSetting(int direction) myOSystem.settings().getString("palette") == PaletteHandler::SETTING_CUSTOM; const bool isCustomFilter = myOSystem.settings().getInt("tv.filter") == int(NTSCFilter::Preset::CUSTOM); + const bool isPAL = myOSystem.console().timing() == ConsoleTiming::pal; + bool repeat = false; do { - myAdjustSetting = - AdjustSetting(BSPF::clampw(int(myAdjustSetting) + direction, 0, int(AdjustSetting::MAX_ADJ))); - // skip currently non-relevant adjustments - } while((myAdjustSetting == AdjustSetting::OVERSCAN && !isFullScreen) + switch (getAdjustGroup()) + { + case AdjustGroup::AV: + myAdjustSetting = + AdjustSetting(BSPF::clampw(int(myAdjustSetting) + direction, + int(AdjustSetting::START_AV_ADJ), int(AdjustSetting::END_AV_ADJ))); + // skip currently non-relevant adjustments + repeat = (myAdjustSetting == AdjustSetting::OVERSCAN && !isFullScreen) + #ifdef ADAPTABLE_REFRESH_SUPPORT + || (myAdjustSetting == AdjustSetting::ADAPT_REFRESH && !isFullScreen) + #endif || (myAdjustSetting == AdjustSetting::PALETTE_PHASE && !isCustomPalette) || (myAdjustSetting >= AdjustSetting::NTSC_SHARPNESS && myAdjustSetting <= AdjustSetting::NTSC_BLEEDING - && !isCustomFilter)); + && !isCustomFilter); + break; + + case AdjustGroup::DEBUG: + myAdjustSetting = + AdjustSetting(BSPF::clampw(int(myAdjustSetting) + direction, + int(AdjustSetting::START_DEBUG_ADJ), int(AdjustSetting::END_DEBUG_ADJ))); + repeat = (myAdjustSetting == AdjustSetting::COLOR_LOSS && !isPAL); + break; + + default: + break; + } + // avoid endless loop + if(repeat && !direction) + direction = 1; + } while(repeat); return getAdjustSetting(myAdjustSetting); } @@ -373,9 +408,13 @@ AdjustFunction EventHandler::getAdjustSetting(AdjustSetting setting) // - This array MUST have the same order as AdjustSetting const AdjustFunction ADJUST_FUNCTIONS[int(AdjustSetting::NUM_ADJ)] = { + // Audio & Video settings std::bind(&Sound::adjustVolume, &myOSystem.sound(), _1), std::bind(&FrameBuffer::selectVidMode, &myOSystem.frameBuffer(), _1), std::bind(&FrameBuffer::toggleFullscreen, &myOSystem.frameBuffer(), _1), + #ifdef ADAPTABLE_REFRESH_SUPPORT + std::bind(&FrameBuffer::toggleAdaptRefresh, &myOSystem.frameBuffer(), _1), + #endif std::bind(&FrameBuffer::changeOverscan, &myOSystem.frameBuffer(), _1), std::bind(&Console::selectFormat, &myOSystem.console(), _1), std::bind(&Console::changeVerticalCenter, &myOSystem.console(), _1), @@ -409,6 +448,25 @@ AdjustFunction EventHandler::getAdjustSetting(AdjustSetting setting) std::bind(&Console::changePhosphor, &myOSystem.console(), _1), std::bind(&TIASurface::setScanlineIntensity, &myOSystem.frameBuffer().tiaSurface(), _1), std::bind(&Console::toggleInter, &myOSystem.console(), _1), + // Debug settings + std::bind(&FrameBuffer::toggleFrameStats, &myOSystem.frameBuffer(), _1), + std::bind(&Console::toggleP0Bit, &myOSystem.console(), _1), + std::bind(&Console::toggleP1Bit, &myOSystem.console(), _1), + std::bind(&Console::toggleM0Bit, &myOSystem.console(), _1), + std::bind(&Console::toggleM1Bit, &myOSystem.console(), _1), + std::bind(&Console::toggleBLBit, &myOSystem.console(), _1), + std::bind(&Console::togglePFBit, &myOSystem.console(), _1), + std::bind(&Console::toggleBits, &myOSystem.console(), _1), + std::bind(&Console::toggleP0Collision, &myOSystem.console(), _1), + std::bind(&Console::toggleP1Collision, &myOSystem.console(), _1), + std::bind(&Console::toggleM0Collision, &myOSystem.console(), _1), + std::bind(&Console::toggleM1Collision, &myOSystem.console(), _1), + std::bind(&Console::toggleBLCollision, &myOSystem.console(), _1), + std::bind(&Console::togglePFCollision, &myOSystem.console(), _1), + std::bind(&Console::toggleCollisions, &myOSystem.console(), _1), + std::bind(&Console::toggleFixedColors, &myOSystem.console(), _1), + std::bind(&Console::toggleColorLoss, &myOSystem.console(), _1), + std::bind(&Console::toggleJitter, &myOSystem.console(), _1), // Following functions are not used when cycling settings but for "direct only" hotkeys std::bind(&StateManager::changeState, &myOSystem.state(), _1), std::bind(&PaletteHandler::changeCurrentAdjustable, &myOSystem.frameBuffer().tiaSurface().paletteHandler(), _1), @@ -435,8 +493,10 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) myAdjustActive = false; myAdjustDirect = AdjustSetting::NONE; } + const bool adjustActive = myAdjustActive; - const AdjustSetting adjustDirect = myAdjustDirect; + const AdjustSetting adjustAVDirect = myAdjustDirect; + if(pressed) { myAdjustActive = false; @@ -446,6 +506,36 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) switch(event) { //////////////////////////////////////////////////////////////////////// + // Allow adjusting several (mostly repeated) settings using the same four hotkeys + case Event::PreviousSettingGroup: + case Event::NextSettingGroup: + if (pressed && !repeated) + { + const int direction = event == Event::PreviousSettingGroup ? -1 : +1; + AdjustGroup adjustGroup = AdjustGroup(BSPF::clampw(int(getAdjustGroup()) + direction, + 0, int(AdjustGroup::NUM_GROUPS) - 1)); + string msg; + + switch (adjustGroup) + { + case AdjustGroup::AV: + msg = "Audio & Video"; + myAdjustSetting = AdjustSetting::START_AV_ADJ; + break; + + case AdjustGroup::DEBUG: + msg = "Debug"; + myAdjustSetting = AdjustSetting::START_DEBUG_ADJ; + break; + + default: + break; + } + myOSystem.frameBuffer().showMessage(msg + " settings"); + myAdjustActive = false; + } + break; + // Allow adjusting several (mostly repeated) settings using the same four hotkeys case Event::PreviousSetting: case Event::NextSetting: @@ -470,9 +560,9 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) const int direction = event == Event::SettingDecrease ? -1 : +1; // if a "direct only" hotkey was pressed last, use this one - if(adjustDirect != AdjustSetting::NONE) + if(adjustAVDirect != AdjustSetting::NONE) { - myAdjustDirect = adjustDirect; + myAdjustDirect = adjustAVDirect; getAdjustSetting(myAdjustDirect)(direction); } else @@ -526,16 +616,9 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) if(!myAllowAllDirectionsFlag && pressed) myEvent.set(Event::JoystickOneLeft, 0); break; - //////////////////////////////////////////////////////////////////////// - - case Event::Fry: - if(!repeated) myFryingFlag = pressed; - return; - - case Event::ReloadConsole: - if(pressed && !repeated) myOSystem.reloadConsole(); - return; + /////////////////////////////////////////////////////////////////////////// + // Audio & Video events (with global hotkeys) case Event::VolumeDecrease: if(pressed) { @@ -581,6 +664,62 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) } return; + case Event::ToggleFullScreen: + if (pressed && !repeated) + { + myOSystem.frameBuffer().toggleFullscreen(); + myAdjustSetting = AdjustSetting::FULLSCREEN; + myAdjustActive = true; + } + return; + + #ifdef ADAPTABLE_REFRESH_SUPPORT + case Event::ToggleAdaptRefresh: + if (pressed && !repeated) + { + myOSystem.frameBuffer().toggleAdaptRefresh(); + myAdjustSetting = AdjustSetting::ADAPT_REFRESH; + myAdjustActive = true; + } + return; + #endif + + case Event::OverscanDecrease: + if (pressed) + { + myOSystem.frameBuffer().changeOverscan(-1); + myAdjustSetting = AdjustSetting::OVERSCAN; + myAdjustActive = true; + } + return; + + case Event::OverscanIncrease: + if (pressed) + { + myOSystem.frameBuffer().changeOverscan(+1); + myAdjustSetting = AdjustSetting::OVERSCAN; + myAdjustActive = true; + } + return; + + case Event::FormatDecrease: + if (pressed && !repeated) + { + myOSystem.console().selectFormat(-1); + myAdjustSetting = AdjustSetting::TVFORMAT; + myAdjustActive = true; + } + return; + + case Event::FormatIncrease: + if (pressed && !repeated) + { + myOSystem.console().selectFormat(+1); + myAdjustSetting = AdjustSetting::TVFORMAT; + myAdjustActive = true; + } + return; + case Event::VCenterDecrease: if(pressed) { @@ -617,61 +756,20 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) } return; - case Event::PreviousPaletteAttribute: - if(pressed) + case Event::PaletteDecrease: + if (pressed && !repeated) { - myOSystem.frameBuffer().tiaSurface().paletteHandler().cycleAdjustable(-1); - myAdjustDirect = AdjustSetting::PALETTE_CHANGE_ATTRIBUTE; - } - return; - - case Event::NextPaletteAttribute: - if(pressed) - { - myOSystem.frameBuffer().tiaSurface().paletteHandler().cycleAdjustable(+1); - myAdjustDirect = AdjustSetting::PALETTE_CHANGE_ATTRIBUTE; - } - return; - - case Event::PaletteAttributeDecrease: - if(pressed) - { - myOSystem.frameBuffer().tiaSurface().paletteHandler().changeCurrentAdjustable(-1); - myAdjustDirect = AdjustSetting::PALETTE_CHANGE_ATTRIBUTE; - } - return; - - case Event::PaletteAttributeIncrease: - if(pressed) - { - myOSystem.frameBuffer().tiaSurface().paletteHandler().changeCurrentAdjustable(+1); - myAdjustDirect = AdjustSetting::PALETTE_CHANGE_ATTRIBUTE; - } - return; - - case Event::ToggleFullScreen: - if(pressed && !repeated) - { - myOSystem.frameBuffer().toggleFullscreen(); - myAdjustSetting = AdjustSetting::FULLSCREEN; + myOSystem.frameBuffer().tiaSurface().paletteHandler().cyclePalette(-1); + myAdjustSetting = AdjustSetting::PALETTE; myAdjustActive = true; } return; - case Event::OverscanDecrease: - if(pressed) + case Event::PaletteIncrease: + if (pressed && !repeated) { - myOSystem.frameBuffer().changeOverscan(-1); - myAdjustSetting = AdjustSetting::OVERSCAN; - myAdjustActive = true; - } - return; - - case Event::OverscanIncrease: - if(pressed) - { - myOSystem.frameBuffer().changeOverscan(+1); - myAdjustSetting = AdjustSetting::OVERSCAN; + myOSystem.frameBuffer().tiaSurface().paletteHandler().cyclePalette(+1); + myAdjustSetting = AdjustSetting::PALETTE; myAdjustActive = true; } return; @@ -695,80 +793,58 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::VidmodeStd: - if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::OFF); + if(pressed && !repeated) + { + myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::OFF); + myAdjustDirect = AdjustSetting::NTSC_PRESET; + myAdjustActive = true; + } return; case Event::VidmodeRGB: - if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::RGB); + if(pressed && !repeated) + { + myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::RGB); + myAdjustSetting = AdjustSetting::NTSC_PRESET; + myAdjustActive = true; + } return; case Event::VidmodeSVideo: - if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::SVIDEO); + if(pressed && !repeated) + { + myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::SVIDEO); + myAdjustSetting = AdjustSetting::NTSC_PRESET; + myAdjustActive = true; + } return; case Event::VidModeComposite: - if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::COMPOSITE); + if(pressed && !repeated) + { + myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::COMPOSITE); + myAdjustSetting = AdjustSetting::NTSC_PRESET; + myAdjustActive = true; + } return; case Event::VidModeBad: - if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::BAD); + if(pressed && !repeated) + { + myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::BAD); + myAdjustSetting = AdjustSetting::NTSC_PRESET; + myAdjustActive = true; + } return; case Event::VidModeCustom: - if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::CUSTOM); - return; - - case Event::PreviousAttribute: - if(pressed) + if(pressed && !repeated) { - myOSystem.frameBuffer().tiaSurface().setNTSCAdjustable(-1); - myAdjustDirect = AdjustSetting::NTSC_CHANGE_ATTRIBUTE; - } - return; - - case Event::NextAttribute: - if(pressed) - { - myOSystem.frameBuffer().tiaSurface().setNTSCAdjustable(+1); - myAdjustDirect = AdjustSetting::NTSC_CHANGE_ATTRIBUTE; - } - return; - - case Event::DecreaseAttribute: - if(pressed) - { - myOSystem.frameBuffer().tiaSurface().changeCurrentNTSCAdjustable(-1); - myAdjustDirect = AdjustSetting::NTSC_CHANGE_ATTRIBUTE; - } - return; - - case Event::IncreaseAttribute: - if(pressed) - { - myOSystem.frameBuffer().tiaSurface().changeCurrentNTSCAdjustable(+1); - myAdjustDirect = AdjustSetting::NTSC_CHANGE_ATTRIBUTE; - } - return; - - case Event::ScanlinesDecrease: - if(pressed) - { - myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(-1); - myAdjustSetting = AdjustSetting::SCANLINES; - myAdjustActive = true; - - } - return; - - case Event::ScanlinesIncrease: - if(pressed) - { - myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(+1); - myAdjustSetting = AdjustSetting::SCANLINES; + myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::CUSTOM); + myAdjustSetting = AdjustSetting::NTSC_PRESET; myAdjustActive = true; } return; - case Event::PhosphorDecrease: if(pressed) { @@ -796,24 +872,20 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) } return; - case Event::ToggleColorLoss: - if (pressed && !repeated) myOSystem.console().toggleColorLoss(); - return; - - case Event::PaletteDecrease: - if(pressed && !repeated) + case Event::ScanlinesDecrease: + if (pressed) { - myOSystem.frameBuffer().tiaSurface().paletteHandler().cyclePalette(-1); - myAdjustSetting = AdjustSetting::PALETTE; + myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(-1); + myAdjustSetting = AdjustSetting::SCANLINES; myAdjustActive = true; } return; - case Event::PaletteIncrease: - if(pressed && !repeated) + case Event::ScanlinesIncrease: + if (pressed) { - myOSystem.frameBuffer().tiaSurface().paletteHandler().cyclePalette(+1); - myAdjustSetting = AdjustSetting::PALETTE; + myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(+1); + myAdjustSetting = AdjustSetting::SCANLINES; myAdjustActive = true; } return; @@ -827,125 +899,242 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) } return; - case Event::ToggleTurbo: - if (pressed && !repeated) myOSystem.console().toggleTurbo(); + /////////////////////////////////////////////////////////////////////////// + // Direct key Audio & Video events + case Event::PreviousPaletteAttribute: + if (pressed) + { + myOSystem.frameBuffer().tiaSurface().paletteHandler().cycleAdjustable(-1); + myAdjustDirect = AdjustSetting::PALETTE_CHANGE_ATTRIBUTE; + } return; - case Event::ToggleJitter: - if (pressed && !repeated) myOSystem.console().toggleJitter(); + case Event::NextPaletteAttribute: + if (pressed) + { + myOSystem.frameBuffer().tiaSurface().paletteHandler().cycleAdjustable(+1); + myAdjustDirect = AdjustSetting::PALETTE_CHANGE_ATTRIBUTE; + } return; + case Event::PaletteAttributeDecrease: + if (pressed) + { + myOSystem.frameBuffer().tiaSurface().paletteHandler().changeCurrentAdjustable(-1); + myAdjustDirect = AdjustSetting::PALETTE_CHANGE_ATTRIBUTE; + } + return; + + case Event::PaletteAttributeIncrease: + if (pressed) + { + myOSystem.frameBuffer().tiaSurface().paletteHandler().changeCurrentAdjustable(+1); + myAdjustDirect = AdjustSetting::PALETTE_CHANGE_ATTRIBUTE; + } + return; + + case Event::PreviousAttribute: + if (pressed) + { + myOSystem.frameBuffer().tiaSurface().setNTSCAdjustable(-1); + myAdjustDirect = AdjustSetting::NTSC_CHANGE_ATTRIBUTE; + } + return; + + case Event::NextAttribute: + if (pressed) + { + myOSystem.frameBuffer().tiaSurface().setNTSCAdjustable(+1); + myAdjustDirect = AdjustSetting::NTSC_CHANGE_ATTRIBUTE; + } + return; + + case Event::DecreaseAttribute: + if (pressed) + { + myOSystem.frameBuffer().tiaSurface().changeCurrentNTSCAdjustable(-1); + myAdjustDirect = AdjustSetting::NTSC_CHANGE_ATTRIBUTE; + } + return; + + case Event::IncreaseAttribute: + if (pressed) + { + myOSystem.frameBuffer().tiaSurface().changeCurrentNTSCAdjustable(+1); + myAdjustDirect = AdjustSetting::NTSC_CHANGE_ATTRIBUTE; + } + return; + + /////////////////////////////////////////////////////////////////////////// + // Debug events (with global hotkeys) + case Event::ToggleFrameStats: - if (pressed) myOSystem.frameBuffer().toggleFrameStats(); - return; - - case Event::ToggleTimeMachine: - if (pressed && !repeated) myOSystem.state().toggleTimeMachine(); - return; - - #ifdef PNG_SUPPORT - case Event::ToggleContSnapshots: - if (pressed && !repeated) myOSystem.png().toggleContinuousSnapshots(false); - return; - - case Event::ToggleContSnapshotsFrame: - if (pressed && !repeated) myOSystem.png().toggleContinuousSnapshots(true); - return; - #endif - - case Event::HandleMouseControl: - if (pressed && !repeated) handleMouseControl(); - return; - - case Event::ToggleSAPortOrder: - if (pressed && !repeated) toggleSAPortOrder(); - return; - - case Event::FormatDecrease: - if(pressed && !repeated) + if (pressed && !repeated) { - myOSystem.console().selectFormat(-1); - myAdjustSetting = AdjustSetting::TVFORMAT; + myOSystem.frameBuffer().toggleFrameStats(); + myAdjustSetting = AdjustSetting::STATS; myAdjustActive = true; } return; - case Event::FormatIncrease: - if(pressed && !repeated) - { - myOSystem.console().selectFormat(+1); - myAdjustSetting = AdjustSetting::TVFORMAT; - myAdjustActive = true; - } - return; - - case Event::ToggleGrabMouse: - if (pressed && !repeated && !myOSystem.frameBuffer().fullScreen()) - myOSystem.frameBuffer().toggleGrabMouse(); - return; - case Event::ToggleP0Collision: - if (pressed && !repeated) myOSystem.console().toggleP0Collision(); + if (pressed && !repeated) + { + myOSystem.console().toggleP0Collision(); + myAdjustSetting = AdjustSetting::P0_CX; + myAdjustActive = true; + } return; case Event::ToggleP0Bit: - if (pressed && !repeated) myOSystem.console().toggleP0Bit(); + if (pressed && !repeated) + { + myOSystem.console().toggleP0Bit(); + myAdjustSetting = AdjustSetting::P0_ENAM; + myAdjustActive = true; + } return; case Event::ToggleP1Collision: - if (pressed && !repeated) myOSystem.console().toggleP1Collision(); + if (pressed && !repeated) + { + myOSystem.console().toggleP1Collision(); + myAdjustSetting = AdjustSetting::P1_CX; + myAdjustActive = true; + } return; case Event::ToggleP1Bit: - if (pressed && !repeated) myOSystem.console().toggleP1Bit(); + if (pressed && !repeated) + { + myOSystem.console().toggleP1Bit(); + myAdjustSetting = AdjustSetting::P1_ENAM; + myAdjustActive = true; + } return; case Event::ToggleM0Collision: - if (pressed && !repeated) myOSystem.console().toggleM0Collision(); + if (pressed && !repeated) + { + myOSystem.console().toggleM0Collision(); + myAdjustSetting = AdjustSetting::M0_CX; + myAdjustActive = true; + } return; case Event::ToggleM0Bit: - if (pressed && !repeated) myOSystem.console().toggleM0Bit(); + if (pressed && !repeated) + { + myOSystem.console().toggleM0Bit(); + myAdjustSetting = AdjustSetting::M0_ENAM; + myAdjustActive = true; + } return; case Event::ToggleM1Collision: - if (pressed && !repeated) myOSystem.console().toggleM1Collision(); + if (pressed && !repeated) + { + myOSystem.console().toggleM1Collision(); + myAdjustSetting = AdjustSetting::M1_CX; + myAdjustActive = true; + } return; case Event::ToggleM1Bit: - if (pressed && !repeated) myOSystem.console().toggleM1Bit(); + if (pressed && !repeated) + { + myOSystem.console().toggleM1Bit(); + myAdjustSetting = AdjustSetting::M1_ENAM; + myAdjustActive = true; + } return; case Event::ToggleBLCollision: - if (pressed && !repeated) myOSystem.console().toggleBLCollision(); + if (pressed && !repeated) + { + myOSystem.console().toggleBLCollision(); + myAdjustSetting = AdjustSetting::BL_CX; + myAdjustActive = true; + } return; case Event::ToggleBLBit: - if (pressed) myOSystem.console().toggleBLBit(); + if (pressed && !repeated) + { + myOSystem.console().toggleBLBit(); + myAdjustSetting = AdjustSetting::BL_ENAM; + myAdjustActive = true; + } return; case Event::TogglePFCollision: - if (pressed && !repeated) myOSystem.console().togglePFCollision(); + if (pressed && !repeated) + { + myOSystem.console().togglePFCollision(); + myAdjustSetting = AdjustSetting::PF_CX; + myAdjustActive = true; + } return; case Event::TogglePFBit: - if (pressed && !repeated) myOSystem.console().togglePFBit(); - return; - - case Event::ToggleFixedColors: - if (pressed) myOSystem.console().toggleFixedColors(); + if (pressed && !repeated) + { + myOSystem.console().togglePFBit(); + myAdjustSetting = AdjustSetting::PF_ENAM; + myAdjustActive = true; + } return; case Event::ToggleCollisions: - if (pressed && !repeated) myOSystem.console().toggleCollisions(); + if (pressed && !repeated) + { + myOSystem.console().toggleCollisions(); + myAdjustSetting = AdjustSetting::ALL_CX; + myAdjustActive = true; + } return; case Event::ToggleBits: - if (pressed && !repeated) myOSystem.console().toggleBits(); + if (pressed && !repeated) + { + myOSystem.console().toggleBits(); + myAdjustSetting = AdjustSetting::ALL_ENAM; + myAdjustActive = true; + } return; + case Event::ToggleFixedColors: + if (pressed && !repeated) + { + myOSystem.console().toggleFixedColors(); + myAdjustSetting = AdjustSetting::FIXED_COL; + myAdjustActive = true; + } + return; + + case Event::ToggleColorLoss: + if (pressed && !repeated) + { + myOSystem.console().toggleColorLoss(); + myAdjustSetting = AdjustSetting::COLOR_LOSS; + myAdjustActive = true; + } + return; + + case Event::ToggleJitter: + if (pressed && !repeated) + { + myOSystem.console().toggleJitter(); + myAdjustSetting = AdjustSetting::JITTER; + myAdjustActive = true; + } + return; + + /////////////////////////////////////////////////////////////////////////// + // State events + case Event::SaveState: - if(pressed && !repeated) + if (pressed && !repeated) { myOSystem.state().saveState(); myAdjustDirect = AdjustSetting::STATE; @@ -958,7 +1147,7 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::PreviousState: - if(pressed) + if (pressed) { myOSystem.state().changeState(-1); myAdjustDirect = AdjustSetting::STATE; @@ -966,7 +1155,7 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::NextState: - if(pressed) + if (pressed) { myOSystem.state().changeState(+1); myAdjustDirect = AdjustSetting::STATE; @@ -978,7 +1167,7 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::LoadState: - if(pressed && !repeated) + if (pressed && !repeated) { myOSystem.state().loadState(); myAdjustDirect = AdjustSetting::STATE; @@ -1026,6 +1215,52 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) if (pressed) enterTimeMachineMenuMode(1000, true); return; + /////////////////////////////////////////////////////////////////////////// + // Misc events + + case Event::ToggleTurbo: + if (pressed && !repeated) myOSystem.console().toggleTurbo(); + return; + + case Event::Fry: + if (!repeated) myFryingFlag = pressed; + return; + + case Event::ReloadConsole: + if (pressed && !repeated) myOSystem.reloadConsole(true); + return; + + case Event::PreviousMultiCartRom: + if (pressed && !repeated) myOSystem.reloadConsole(false); + return; + + case Event::ToggleTimeMachine: + if (pressed && !repeated) myOSystem.state().toggleTimeMachine(); + return; + + #ifdef PNG_SUPPORT + case Event::ToggleContSnapshots: + if (pressed && !repeated) myOSystem.png().toggleContinuousSnapshots(false); + return; + + case Event::ToggleContSnapshotsFrame: + if (pressed && !repeated) myOSystem.png().toggleContinuousSnapshots(true); + return; + #endif + + case Event::HandleMouseControl: + if (pressed && !repeated) handleMouseControl(); + return; + + case Event::ToggleSAPortOrder: + if (pressed && !repeated) toggleSAPortOrder(); + return; + + case Event::ToggleGrabMouse: + if (pressed && !repeated && !myOSystem.frameBuffer().fullScreen()) + myOSystem.frameBuffer().toggleGrabMouse(); + return; + case Event::TakeSnapshot: if(pressed && !repeated) myOSystem.frameBuffer().tiaSurface().saveSnapShot(); return; @@ -1138,7 +1373,6 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) if(myComboTable[combo][i] != Event::NoType) handleEvent(myComboTable[combo][i], pressed, repeated); return; - //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// // Events which relate to switches() @@ -1263,6 +1497,7 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) myOSystem.console().switches().update(); } return; + //////////////////////////////////////////////////////////////////////// case Event::NoType: // Ignore unmapped events @@ -2120,6 +2355,7 @@ void EventHandler::exitEmulation(bool checkLauncher) EventHandler::EmulActionList EventHandler::ourEmulActionList = { { { Event::Quit, "Quit", "" }, { Event::ReloadConsole, "Reload current ROM/load next game", "" }, + { Event::PreviousMultiCartRom, "Load previous multicart game", "" }, { Event::ExitMode, "Exit current Stella menu/mode", "" }, { Event::OptionsMenuMode, "Enter Options menu UI", "" }, { Event::CmdMenuMode, "Toggle Commands menu UI", "" }, @@ -2218,6 +2454,9 @@ EventHandler::EmulActionList EventHandler::ourEmulActionList = { { { Event::KeyboardOnePound, "P1 Keyboard #", "" }, // Video { Event::ToggleFullScreen, "Toggle fullscreen", "" }, +#ifdef ADAPTABLE_REFRESH_SUPPORT + { Event::ToggleAdaptRefresh, "Toggle fullscreen refresh rate adapt", "" }, +#endif { Event::OverscanDecrease, "Decrease overscan in fullscreen mode", "" }, { Event::OverscanIncrease, "Increase overscan in fullscreen mode", "" }, { Event::VidmodeDecrease, "Previous zoom level", "" }, @@ -2256,6 +2495,8 @@ EventHandler::EmulActionList EventHandler::ourEmulActionList = { { { Event::ScanlinesDecrease, "Decrease scanlines", "" }, { Event::ScanlinesIncrease, "Increase scanlines", "" }, + { Event::PreviousSettingGroup, "Select previous setting group", "" }, + { Event::NextSettingGroup, "Select next setting group", "" }, { Event::PreviousSetting, "Select previous setting", "" }, { Event::NextSetting, "Select next setting", "" }, { Event::SettingDecrease, "Decrease current setting", "" }, @@ -2354,14 +2595,17 @@ const Event::EventSet EventHandler::MiscEvents = { // Event::MouseAxisXMove, Event::MouseAxisYMove, // Event::MouseButtonLeftValue, Event::MouseButtonRightValue, Event::HandleMouseControl, Event::ToggleGrabMouse, - Event::ToggleSAPortOrder, + Event::ToggleSAPortOrder, Event::PreviousMultiCartRom, + Event::PreviousSettingGroup, Event::NextSettingGroup, + Event::PreviousSetting, Event::NextSetting, + Event::SettingDecrease, Event::SettingIncrease, }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const Event::EventSet EventHandler::AudioVideoEvents = { Event::VolumeDecrease, Event::VolumeIncrease, Event::SoundToggle, Event::VidmodeDecrease, Event::VidmodeIncrease, - Event::ToggleFullScreen, + Event::ToggleFullScreen, Event::ToggleAdaptRefresh, Event::OverscanDecrease, Event::OverscanIncrease, Event::FormatDecrease, Event::FormatIncrease, Event::VCenterDecrease, Event::VCenterIncrease, @@ -2375,8 +2619,6 @@ const Event::EventSet EventHandler::AudioVideoEvents = { Event::PhosphorDecrease, Event::PhosphorIncrease, Event::TogglePhosphor, Event::ScanlinesDecrease, Event::ScanlinesIncrease, Event::ToggleInter, - Event::PreviousSetting, Event::NextSetting, - Event::SettingDecrease, Event::SettingIncrease, }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx index 0ab40c7cd..0ff428998 100644 --- a/src/emucore/EventHandler.hxx +++ b/src/emucore/EventHandler.hxx @@ -395,9 +395,13 @@ class EventHandler enum class AdjustSetting { NONE = -1, + // *** Audio & Video group *** VOLUME, ZOOM, FULLSCREEN, + #ifdef ADAPTABLE_REFRESH_SUPPORT + ADAPT_REFRESH, + #endif OVERSCAN, TVFORMAT, VCENTER, @@ -417,15 +421,45 @@ class EventHandler NTSC_ARTIFACTS, NTSC_FRINGING, NTSC_BLEEDING, + // Other TV effects adjustables PHOSPHOR, SCANLINES, INTERPOLATION, - MAX_ADJ = INTERPOLATION, - // Only used via direct hotkeys + // *** Debug group *** + STATS, + P0_ENAM, + P1_ENAM, + M0_ENAM, + M1_ENAM, + BL_ENAM, + PF_ENAM, + ALL_ENAM, + P0_CX, + P1_CX, + M0_CX, + M1_CX, + BL_CX, + PF_CX, + ALL_CX, + FIXED_COL, + COLOR_LOSS, + JITTER, + // *** Only used via direct hotkeys *** STATE, PALETTE_CHANGE_ATTRIBUTE, NTSC_CHANGE_ATTRIBUTE, - NUM_ADJ + // *** Ranges *** + NUM_ADJ, + START_AV_ADJ = VOLUME, + END_AV_ADJ = INTERPOLATION, + START_DEBUG_ADJ = STATS, + END_DEBUG_ADJ = JITTER, + }; + enum class AdjustGroup + { + AV, + DEBUG, + NUM_GROUPS }; private: @@ -456,6 +490,7 @@ class EventHandler // The following two methods are used for adjusting several settings using global hotkeys // They return the function used to adjust the currenly selected setting + AdjustGroup getAdjustGroup(); AdjustFunction cycleAdjustSetting(int direction); AdjustFunction getAdjustSetting(AdjustSetting setting); @@ -467,10 +502,10 @@ class EventHandler string key; }; - // ID of the currently selected global setting - AdjustSetting myAdjustSetting{AdjustSetting::VOLUME}; // If true, the setting is visible and its value can be changed bool myAdjustActive{false}; + // ID of the currently selected global setting + AdjustSetting myAdjustSetting{AdjustSetting::START_AV_ADJ}; // ID of the currently selected direct hotkey setting (0 if none) AdjustSetting myAdjustDirect{AdjustSetting::NONE}; @@ -517,7 +552,12 @@ class EventHandler #else PNG_SIZE = 0, #endif - EMUL_ACTIONLIST_SIZE = 156 + PNG_SIZE + COMBO_SIZE, + #ifdef ADAPTABLE_REFRESH_SUPPORT + REFRESH_SIZE = 1, + #else + REFRESH_SIZE = 0, + #endif + EMUL_ACTIONLIST_SIZE = 159 + PNG_SIZE + COMBO_SIZE + REFRESH_SIZE, MENU_ACTIONLIST_SIZE = 18 ; diff --git a/src/emucore/FSNode.cxx b/src/emucore/FSNode.cxx index 64af7212e..e9da05b03 100644 --- a/src/emucore/FSNode.cxx +++ b/src/emucore/FSNode.cxx @@ -18,6 +18,7 @@ // Copyright (C) 2002-2004 The ScummVM project //============================================================================ +#include "Cart.hxx" #include "FSNodeFactory.hxx" #include "FSNode.hxx" @@ -47,7 +48,8 @@ bool FilesystemNode::exists() const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FilesystemNode::getChildren(FSList& fslist, ListMode mode, - const NameFilter& filter) const + const NameFilter& filter, + bool includeParentDirectory) const { if (!_realNode || !_realNode->isDirectory()) return false; @@ -83,7 +85,7 @@ bool FilesystemNode::getChildren(FSList& fslist, ListMode mode, ); // Add parent node, if it is valid to do so - if (hasParent()) + if (includeParentDirectory && hasParent()) { FilesystemNode parent = getParent(); parent.setName(" [..]"); @@ -236,7 +238,7 @@ size_t FilesystemNode::read(ByteBuffer& image) const return size; // Otherwise, the default behaviour is to read from a normal C++ ifstream - image = make_unique(512 * 1024); + image = make_unique(Cartridge::maxSize()); ifstream in(getPath(), std::ios::binary); if (in) { @@ -247,7 +249,7 @@ size_t FilesystemNode::read(ByteBuffer& image) const if (length == 0) throw runtime_error("Zero-byte file"); - size = std::min(length, 512 * 1024); + size = std::min(length, Cartridge::maxSize()); in.read(reinterpret_cast(image.get()), size); } else diff --git a/src/emucore/FSNode.hxx b/src/emucore/FSNode.hxx index 2a8acc278..16360cafe 100644 --- a/src/emucore/FSNode.hxx +++ b/src/emucore/FSNode.hxx @@ -134,7 +134,8 @@ class FilesystemNode * does not exist). */ bool getChildren(FSList& fslist, ListMode mode = ListMode::DirectoriesOnly, - const NameFilter& filter = [](const FilesystemNode&){ return true; }) const; + const NameFilter& filter = [](const FilesystemNode&){ return true; }, + bool includeParentDirectory = true) const; /** * Set/get a string representation of the name of the file. This is can be diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 4599a3860..2f4626968 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -513,7 +513,8 @@ void FrameBuffer::showMessage(const string& message, MessagePosition position, myMsg.text = message; myMsg.color = kBtnTextColor; myMsg.showGauge = false; - myMsg.w = font().getStringWidth(myMsg.text) + HBORDER * 2; + myMsg.w = std::min(fontWidth * (MESSAGE_WIDTH) - HBORDER * 2, + font().getStringWidth(myMsg.text) + HBORDER * 2); myMsg.h = fontHeight + VBORDER * 2; myMsg.position = position; myMsg.enabled = true; @@ -533,7 +534,7 @@ void FrameBuffer::showMessage(const string& message, const string& valueText, return; const int fontWidth = font().getMaxCharWidth(), - fontHeight = font().getFontHeight(); + fontHeight = font().getFontHeight(); const int VBORDER = fontHeight / 4; const int HBORDER = fontWidth * 1.25 / 2.0; @@ -565,7 +566,7 @@ void FrameBuffer::showMessage(const string& message, const string& valueText, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool FrameBuffer::messageShown() +bool FrameBuffer::messageShown() const { #ifdef GUI_SUPPORT return myMsg.enabled; @@ -633,11 +634,15 @@ void FrameBuffer::drawFrameStats(float framesPerSecond) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBuffer::toggleFrameStats() +void FrameBuffer::toggleFrameStats(bool toggle) { - showFrameStats(!myStatsEnabled); + if (toggle) + showFrameStats(!myStatsEnabled); myOSystem.settings().setValue( myOSystem.settings().getBool("dev.settings") ? "dev.stats" : "plr.stats", myStatsEnabled); + + myOSystem.frameBuffer().showMessage(string("Console info ") + + (myStatsEnabled ? "enabled" : "disabled")); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -861,6 +866,7 @@ void FrameBuffer::setUIPalette() const UIPaletteArray& ui_palette = (myOSystem.settings().getString("uipalette") == "classic") ? ourClassicUIPalette : (myOSystem.settings().getString("uipalette") == "light") ? ourLightUIPalette : + (myOSystem.settings().getString("uipalette") == "dark") ? ourDarkUIPalette : ourStandardUIPalette; for(size_t i = 0, j = myFullPalette.size() - ui_palette.size(); @@ -959,6 +965,7 @@ void FrameBuffer::setFullscreen(bool enable) default: return; } + saveCurrentWindowPosition(); // Changing the video mode can take some time, during which the last // sound played may get 'stuck' @@ -989,13 +996,65 @@ void FrameBuffer::setFullscreen(bool enable) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::toggleFullscreen(bool toggle) { - const bool isFullscreen = toggle ? !fullScreen() : fullScreen(); + switch (myOSystem.eventHandler().state()) + { + case EventHandlerState::LAUNCHER: + case EventHandlerState::EMULATION: + case EventHandlerState::PAUSE: + case EventHandlerState::DEBUGGER: + { + const bool isFullscreen = toggle ? !fullScreen() : fullScreen(); - setFullscreen(isFullscreen); + setFullscreen(isFullscreen); - showMessage(string("Fullscreen ") + (isFullscreen ? "enabled" : "disabled")); + if (myBufferType != BufferType::Launcher) + { + ostringstream msg; + + msg << "Fullscreen "; + if (isFullscreen) + msg << "enabled (" << refreshRate() << " Hz)"; + else + msg << "disabled"; + + showMessage(msg.str()); + } + break; + } + default: + break; + } } +#ifdef ADAPTABLE_REFRESH_SUPPORT +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FrameBuffer::toggleAdaptRefresh(bool toggle) +{ + bool isAdaptRefresh = myOSystem.settings().getInt("tia.fs_refresh"); + + if(toggle) + isAdaptRefresh = !isAdaptRefresh; + + if(myBufferType == BufferType::Emulator) + { + if(toggle) + { + myOSystem.settings().setValue("tia.fs_refresh", isAdaptRefresh); + // issue a complete framebuffer re-initialization + myOSystem.createFrameBuffer(); + } + + ostringstream msg; + + msg << "Adapt refresh rate "; + msg << (isAdaptRefresh ? "enabled" : "disabled"); + msg << " (" << refreshRate() << " Hz)"; + + showMessage(msg.str()); + } +} +#endif + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::changeOverscan(int direction) { @@ -1511,3 +1570,16 @@ UIPaletteArray FrameBuffer::ourLightUIPalette = { 0xffffff, 0x333333, 0xf0f0f0, 0x808080, 0xc0c0c0 // other } }; + +UIPaletteArray FrameBuffer::ourDarkUIPalette = { + { 0x646464, 0xc0c0c0, 0x3c3c3c, 0x282828, 0x989898, // base + 0xc0c0c0, 0x1567a5, 0x0059a3, 0xc0c0c0, // text + 0x202020, 0x000000, 0x0059a3, 0xb0b0b0, // UI elements + 0x282828, 0x00467f, 0x646464, 0x0059a3, 0xc0c0c0, 0xc0c0c0, // buttons + 0x989898, // checkbox + 0x3c3c3c, 0x646464, // scrollbar + 0x7f2020, 0xc0c0c0, 0xe00000, 0xc00000, // debugger + 0x989898, 0x0059a3, 0x3c3c3c, 0x000000, 0x3c3c3c, // slider + 0x000000, 0x989898, 0x202020, 0x646464, 0x3c3c3c // other + } +}; diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index 3912f38cd..58d61dfd3 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -81,6 +81,13 @@ class FrameBuffer } }; + struct DisplayMode + { + uInt32 display; + Common::Size size; + uInt32 refresh_rate; + }; + enum class BufferType { None, Launcher, @@ -159,12 +166,12 @@ class FrameBuffer void showMessage(const string& message, const string& valueText, float value, float minValue = 0.F, float maxValue = 100.F); - bool messageShown(); + bool messageShown() const; /** Toggles showing or hiding framerate statistics. */ - void toggleFrameStats(); + void toggleFrameStats(bool toggle = true); /** Shows a message containing frame statistics for the current frame. @@ -262,6 +269,13 @@ class FrameBuffer */ void toggleFullscreen(bool toggle = true); + #ifdef ADAPTABLE_REFRESH_SUPPORT + /** + Toggles between adapt fullscreen refresh rate on and off. + */ + void toggleAdaptRefresh(bool toggle = true); + #endif + /** Changes the fullscreen overscan. @@ -439,6 +453,7 @@ class FrameBuffer virtual int scaleY(int y) const { return y; } protected: + /** This method is called to query and initialize the video hardware for desktop and fullscreen resolution information. Since several @@ -510,6 +525,11 @@ class FrameBuffer */ virtual string about() const = 0; + /** + Retrieve the current display's refresh rate + */ + virtual int refreshRate() const { return 0; } + protected: // The parent system for the framebuffer OSystem& myOSystem; @@ -694,7 +714,8 @@ class FrameBuffer FullPaletteArray myFullPalette; // Holds UI palette data (for each variation) - static UIPaletteArray ourStandardUIPalette, ourClassicUIPalette, ourLightUIPalette; + static UIPaletteArray ourStandardUIPalette, ourClassicUIPalette, + ourLightUIPalette, ourDarkUIPalette; private: // Following constructors and assignment operators not supported diff --git a/src/emucore/M6532.cxx b/src/emucore/M6532.cxx index f9eb8025c..18f950e62 100644 --- a/src/emucore/M6532.cxx +++ b/src/emucore/M6532.cxx @@ -59,7 +59,6 @@ void M6532::reset() myTimer = mySystem->randGenerator().next() & 0xff; myDivider = 1024; mySubTimer = 0; - myTimerWrapped = false; myWrappedThisCycle = false; mySetTimerCycle = myLastCycle = 0; @@ -121,16 +120,16 @@ void M6532::updateEmulation() myWrappedThisCycle = false; mySubTimer = (cycles + mySubTimer) % myDivider; - if(!myTimerWrapped) + if ((myInterruptFlag & TimerBit) == 0) { uInt32 timerTicks = (cycles + subTimer) / myDivider; if(timerTicks > myTimer) { cycles -= ((myTimer + 1) * myDivider - subTimer); + myWrappedThisCycle = cycles == 0; myTimer = 0xFF; - myTimerWrapped = true; myInterruptFlag |= TimerBit; } else @@ -140,8 +139,10 @@ void M6532::updateEmulation() } } - if(myTimerWrapped) + if((myInterruptFlag & TimerBit) != 0) { myTimer = (myTimer - cycles) & 0xFF; + myWrappedThisCycle = myTimer == 0xFF; + } myLastCycle = mySystem->cycles(); } @@ -219,7 +220,7 @@ uInt8 M6532::peek(uInt16 addr) { // Timer Flag is always cleared when accessing INTIM if (!myWrappedThisCycle) myInterruptFlag &= ~TimerBit; - myTimerWrapped = false; + return myTimer; } @@ -312,10 +313,9 @@ void M6532::setTimerRegister(uInt8 value, uInt8 interval) myTimer = value; mySubTimer = myDivider - 1; - myTimerWrapped = false; // Interrupt timer flag is cleared (and invalid) when writing to the timer - myInterruptFlag &= ~TimerBit; + if (!myWrappedThisCycle) myInterruptFlag &= ~TimerBit; mySetTimerCycle = mySystem->cycles(); } @@ -364,7 +364,6 @@ bool M6532::save(Serializer& out) const out.putInt(myTimer); out.putInt(mySubTimer); out.putInt(myDivider); - out.putBool(myTimerWrapped); out.putBool(myWrappedThisCycle); out.putLong(myLastCycle); out.putLong(mySetTimerCycle); @@ -397,7 +396,6 @@ bool M6532::load(Serializer& in) myTimer = in.getInt(); mySubTimer = in.getInt(); myDivider = in.getInt(); - myTimerWrapped = in.getBool(); myWrappedThisCycle = in.getBool(); myLastCycle = in.getLong(); mySetTimerCycle = in.getLong(); @@ -446,7 +444,7 @@ Int32 M6532::intimClocks() // INTIM value, it will give the current number of clocks between one // INTIM value and the next - return myTimerWrapped ? 1 : (myDivider - mySubTimer); + return ((myInterruptFlag & TimerBit) != 0) ? 1 : (myDivider - mySubTimer); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/M6532.hxx b/src/emucore/M6532.hxx index 9aa4368b9..6e7408798 100644 --- a/src/emucore/M6532.hxx +++ b/src/emucore/M6532.hxx @@ -196,8 +196,7 @@ class M6532 : public Device // The divider uInt32 myDivider{1}; - // Has the timer wrapped? - bool myTimerWrapped{false}; + // Has the timer wrapped this very cycle? bool myWrappedThisCycle{false}; // Cycle when the timer set. Debugging only. diff --git a/src/emucore/MT24LC256.hxx b/src/emucore/MT24LC256.hxx index 2832aef6c..94b894b21 100644 --- a/src/emucore/MT24LC256.hxx +++ b/src/emucore/MT24LC256.hxx @@ -46,9 +46,9 @@ class MT24LC256 public: // Sizes of the EEPROM - static constexpr uInt32 FLASH_SIZE = 32_KB; - static constexpr uInt32 PAGE_SIZE = 64; - static constexpr uInt32 PAGE_NUM = FLASH_SIZE / PAGE_SIZE; + static constexpr size_t FLASH_SIZE = 32_KB; + static constexpr size_t PAGE_SIZE = 64; + static constexpr size_t PAGE_NUM = FLASH_SIZE / PAGE_SIZE; // Initial state value of flash EEPROM static constexpr uInt8 INITIAL_VALUE = 0xff; diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index 9c84b4165..0d1364790 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -46,7 +46,7 @@ #include "FSNode.hxx" #include "MD5.hxx" #include "Cart.hxx" -#include "CartDetector.hxx" +#include "CartCreator.hxx" #include "FrameBuffer.hxx" #include "TIASurface.hxx" #include "PaletteHandler.hxx" @@ -399,7 +399,7 @@ string OSystem::createConsole(const FilesystemNode& rom, const string& md5sum, // Each time a new console is loaded, we simulate a cart removal // Some carts need knowledge of this, as they behave differently // based on how many power-cycles they've been through since plugged in - mySettings->setValue("romloadcount", 0); + mySettings->setValue("romloadcount", -1); // we move to the next game initially } // Create an instance of the 2600 game console @@ -414,7 +414,7 @@ string OSystem::createConsole(const FilesystemNode& rom, const string& md5sum, } catch(const runtime_error& e) { - buf << "ERROR: Couldn't create console (" << e.what() << ")"; + buf << "ERROR: " << e.what(); Logger::error(buf.str()); return buf.str(); } @@ -474,8 +474,10 @@ string OSystem::createConsole(const FilesystemNode& rom, const string& md5sum, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool OSystem::reloadConsole() +bool OSystem::reloadConsole(bool nextrom) { + mySettings->setValue("romloadprev", !nextrom); + return createConsole(myRomFile, myRomMD5, false) == EmptyString; } @@ -569,7 +571,7 @@ unique_ptr OSystem::openConsole(const FilesystemNode& romfile, string& string cartmd5 = md5; const string& type = props.get(PropType::Cart_Type); unique_ptr cart = - CartDetector::create(romfile, image, size, cartmd5, type, *mySettings); + CartCreator::create(romfile, image, size, cartmd5, type, *mySettings); // Some properties may not have a name set; we can't leave it blank if(props.get(PropType::Cart_Name) == EmptyString) diff --git a/src/emucore/OSystem.hxx b/src/emucore/OSystem.hxx index 2bc5368c6..4958efead 100644 --- a/src/emucore/OSystem.hxx +++ b/src/emucore/OSystem.hxx @@ -345,9 +345,11 @@ class OSystem Reloads the current console (essentially deletes and re-creates it). This can be thought of as a real console off/on toggle. + @param nextrom If true select next multicart ROM, else previous one + @return True on successful creation, otherwise false */ - bool reloadConsole(); + bool reloadConsole(bool nextrom = true); /** Creates a new ROM launcher, to select a new ROM to emulate. diff --git a/src/emucore/ProfilingRunner.cxx b/src/emucore/ProfilingRunner.cxx index e7d81b997..877d35934 100644 --- a/src/emucore/ProfilingRunner.cxx +++ b/src/emucore/ProfilingRunner.cxx @@ -20,8 +20,8 @@ #include "ProfilingRunner.hxx" #include "FSNode.hxx" -#include "CartDetector.hxx" #include "Cart.hxx" +#include "CartCreator.hxx" #include "MD5.hxx" #include "Control.hxx" #include "M6502.hxx" @@ -109,7 +109,8 @@ bool ProfilingRunner::runOne(const ProfilingRun& run) string md5 = MD5::hash(image, size); string type = ""; - unique_ptr cartridge = CartDetector::create(imageFile, image, size, md5, type, mySettings); + unique_ptr cartridge = CartCreator::create( + imageFile, image, size, md5, type, mySettings); if (!cartridge) { cout << "ERROR: unable to determine cartridge type" << endl; diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index f5e120408..0c5073d45 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -52,6 +52,7 @@ Settings::Settings() setPermanent("tia.zoom", "3"); setPermanent("fullscreen", "false"); setPermanent("tia.fs_stretch", "false"); + setPermanent("tia.fs_refresh", "false"); setPermanent("tia.fs_overscan", "0"); setPermanent("tia.vsizeadjust", 0); setPermanent("tia.dbgcolors", "roygpb"); @@ -68,7 +69,7 @@ Settings::Settings() setPermanent("tv.filter", "0"); setPermanent("tv.phosphor", "byrom"); setPermanent("tv.phosblend", "50"); - setPermanent("tv.scanlines", "25"); + setPermanent("tv.scanlines", "0"); // TV options when using 'custom' mode setPermanent("tv.sharpness", "0.0"); setPermanent("tv.resolution", "0.0"); @@ -441,6 +442,7 @@ void Settings::usage() const << " -tia.inter <1|0> Enable interpolated (smooth) scaling for TIA\n" << " image\n" << " -tia.fs_stretch <1|0> Stretch TIA image to fill fullscreen mode\n" + << " -tia.fs_refresh <1|0> Try to adapt display refresh rate to game's FPS\n" << " -tia.fs_overscan <0-10> Add overscan to TIA image in fullscreen mode\n" << " -tia.dbgcolors Debug colors to use for each object (see manual\n" << " for description)\n" @@ -522,7 +524,8 @@ void Settings::usage() const << " launcher\n" << " -romloadcount Number of ROM to load next from multicard\n" << " -uipalette \n" + << " classic|\n" + << " light|dark>\n" << " -hidpi <0|1> Enable HiDPI mode\n" << " -dialogfont width(), width = tiaw * 2, height = myTIA->height(); rect.setBounds(0, 0, width, height); - // Get Blargg buffer and width - uInt32 *blarggBuf, blarggPitch; - myTiaSurface->basePtr(blarggBuf, blarggPitch); - double blarggXFactor = double(blarggPitch) / width; - bool useBlargg = ntscEnabled(); - // Fill the surface with pixels from the TIA, scaled 2x horizontally uInt32 *buf_ptr, pitch; myBaseTiaSurface->basePtr(buf_ptr, pitch); for(uInt32 y = 0; y < height; ++y) - { for(uInt32 x = 0; x < width; ++x) - { - if (useBlargg) - *buf_ptr++ = blarggBuf[y * blarggPitch + uInt32(nearbyint(x * blarggXFactor))]; - else *buf_ptr++ = myPalette[*(myTIA->frameBuffer() + y * tiaw + x / 2)]; - } - } return *myBaseTiaSurface; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 TIASurface::mapIndexedPixel(uInt8 indexedColor, uInt8 shift) +uInt32 TIASurface::mapIndexedPixel(uInt8 indexedColor, uInt8 shift) const { return myPalette[indexedColor | shift]; } diff --git a/src/emucore/TIASurface.hxx b/src/emucore/TIASurface.hxx index 826ff75d9..2b6213785 100644 --- a/src/emucore/TIASurface.hxx +++ b/src/emucore/TIASurface.hxx @@ -70,14 +70,18 @@ class TIASurface void setPalette(const PaletteArray& tia_palette, const PaletteArray& rgb_palette); /** - Get the TIA base surface for use in saving to a PNG image. + Get a TIA surface that has no post-processing whatsoever. This is + currently used to save PNG image in the so-called '1x mode'. + + @param rect Specifies the area in which the surface data is valid */ const FBSurface& baseSurface(Common::Rect& rect) const; /** - Use the palette to map a single indexed pixel color. This is used by the TIA output widget. + Use the palette to map a single indexed pixel color. This is used by the + TIA output widget. */ - uInt32 mapIndexedPixel(uInt8 indexedColor, uInt8 shift = 0); + uInt32 mapIndexedPixel(uInt8 indexedColor, uInt8 shift = 0) const; /** Get the NTSCFilter object associated with the framebuffer @@ -220,7 +224,7 @@ class TIASurface bool mySaveSnapFlag{false}; // The palette handler - unique_ptrmyPaletteHandler; + unique_ptr myPaletteHandler; private: // Following constructors and assignment operators not supported diff --git a/src/emucore/module.mk b/src/emucore/module.mk index e0dd4f96f..71bd33847 100644 --- a/src/emucore/module.mk +++ b/src/emucore/module.mk @@ -5,6 +5,7 @@ MODULE_OBJS := \ src/emucore/Bankswitch.o \ src/emucore/Booster.o \ src/emucore/Cart.o \ + src/emucore/CartCreator.o \ src/emucore/CartDetector.o \ src/emucore/CartEnhanced.o \ src/emucore/Cart0840.o \ @@ -47,6 +48,7 @@ MODULE_OBJS := \ src/emucore/CartFE.o \ src/emucore/CartMDM.o \ src/emucore/CartSB.o \ + src/emucore/CartTVBoy.o \ src/emucore/CartUA.o \ src/emucore/CartWD.o \ src/emucore/CartX07.o \ diff --git a/src/emucore/stella.pro b/src/emucore/stella.pro index 8b783bba4..6253c7bfb 100644 --- a/src/emucore/stella.pro +++ b/src/emucore/stella.pro @@ -2291,6 +2291,14 @@ "Cart.Name" "Excalibur (Dragonstomper Beta) (1982) (Arcadia) (Prototype) [a]" "" +"Cart.MD5" "1b5a8da0622bffcee4c5b42aed4e0ef0" +"Cart.Manufacturer" "Akor" +"Cart.Name" "TV Boy II (1992) (Akor)" +"Cart.Note" "Includes 127 games" +"Controller.Left" "JOYSTICK" +"Controller.Right" "JOYSTICK" +"" + "Cart.MD5" "1b8c3c0bfb815b2a1010bba95998b66e" "Cart.Manufacturer" "Telegames" "Cart.Name" "Frogs and Flies (1988) (Telegames) (PAL)" @@ -7084,6 +7092,16 @@ "Cart.Name" "Carnival Shooter (PD)" "" +"Cart.MD5" "541cac55ebcf7891d9d51c415922303f" +"Cart.Manufacturer" "SpiceWare - Darrell Spice Jr." +"Cart.ModelNo" "SW-05" +"Cart.Name" "Stay Frosty 2" +"Cart.Note" "AtariAge Holiday Greetings 2014" +"Cart.Rarity" "Homebrew" +"Controller.Left" "JOYSTICK" +"Display.Phosphor" "YES" +"" + "Cart.MD5" "5428cdfada281c569c74c7308c7f2c26" "Cart.Manufacturer" "Activision, Larry Kaplan, David Crane" "Cart.ModelNo" "AG-010, AG-010-04" @@ -8526,6 +8544,14 @@ "Display.Phosphor" "YES" "" +"Cart.MD5" "65a6f1255fe22468a8bf84ff28a4d289" +"Cart.Manufacturer" "Akor" +"Cart.Name" "Super TV Boy (1995) (Akor)" +"Cart.Note" "Includes 127 games" +"Controller.Left" "JOYSTICK" +"Controller.Right" "JOYSTICK" +"" + "Cart.MD5" "65b106eba3e45f3dab72ea907f39f8b4" "Cart.Manufacturer" "Christian Software Development - HomeComputer Software, Dan Schafer, Glenn Stohel, Jon Tedesco - Sparrow" "Cart.ModelNo" "GCG 1001T" @@ -10223,6 +10249,16 @@ "Cart.Note" "Abenteuer im Urwald (Jungle Runner)" "" +"Cart.MD5" "791c88eca9836af8c34bf32b07cb58a7" +"Cart.Manufacturer" "SpiceWare - Darrell Spice Jr." +"Cart.ModelNo" "SW-05" +"Cart.Name" "Stay Frosty 2 (PAL60)" +"Cart.Note" "AtariAge Holiday Greetings 2014" +"Cart.Rarity" "Homebrew" +"Controller.Left" "JOYSTICK" +"Display.Phosphor" "YES" +"" + "Cart.MD5" "7926083ad423ed685de3b3a04a914315" "Cart.Manufacturer" "Barry Laws Jr." "Cart.Name" "Face Invaders 2 (Barry Laws Jr.) (Hack)" @@ -18954,6 +18990,14 @@ "Cart.Name" "Comitoid beta 4 (SnailSoft)" "" +"Cart.MD5" "e4fa739c81b003c92bea7da5e84c7feb" +"Cart.Manufacturer" "Akor" +"Cart.Name" "TV Boy (1992) (Akor) (NTSC) [bad dump]" +"Cart.Note" "Includes 127 games" +"Controller.Left" "JOYSTICK" +"Controller.Right" "JOYSTICK" +"" + "Cart.MD5" "e505bd8e59e31aaed20718d47b15c61b" "Cart.Manufacturer" "Funvision - Fund. Int'l Co." "Cart.Name" "Space War (1982) (Funvision) (PAL)" @@ -20241,6 +20285,8 @@ "Cart.ModelNo" "649635" "Cart.Name" "See Saw (Double-Game Package) (1983) (Otto Versand) (PAL)" "Cart.Note" "AKA Circus Atari" +"Controller.Left" "JOYSTICK" +"Controller.Right" "JOYSTICK" "" "Cart.MD5" "f3f5f72bfdd67f3d0e45d097e11b8091" @@ -20611,6 +20657,14 @@ "Cart.Note" "AKA Play Farm" "" +"Cart.MD5" "f7ec2f2bdbe8fbea048c0d5fa6503b0b" +"Cart.Manufacturer" "Akor" +"Cart.Name" "TV Boy (1992) (Akor) (PAL)" +"Cart.Note" "Includes 127 games" +"Controller.Left" "JOYSTICK" +"Controller.Right" "JOYSTICK" +"" + "Cart.MD5" "f7f50d9c9d28bcc9f7d3075668b7ac89" "Cart.Manufacturer" "Activision, David Crane - Ariola" "Cart.ModelNo" "EAG-008, PAG-008, EAG-008-04I - 711 008-720" @@ -21353,23 +21407,3 @@ "Cart.MD5" "ffebb0070689b9d322687edd9c0a2bae" "Cart.Name" "Spitfire Attack (1983) (Milton Bradley) [h1]" "" - -"Cart.MD5" "541cac55ebcf7891d9d51c415922303f" -"Cart.Manufacturer" "SpiceWare - Darrell Spice Jr." -"Cart.ModelNo" "SW-05" -"Cart.Name" "Stay Frosty 2" -"Cart.Note" "AtariAge Holiday Greetings 2014" -"Cart.Rarity" "Homebrew" -"Controller.Left" "JOYSTICK" -"Display.Phosphor" "YES" -"" - -"Cart.MD5" "791c88eca9836af8c34bf32b07cb58a7" -"Cart.Manufacturer" "SpiceWare - Darrell Spice Jr." -"Cart.ModelNo" "SW-05" -"Cart.Name" "Stay Frosty 2 (PAL60)" -"Cart.Note" "AtariAge Holiday Greetings 2014" -"Cart.Rarity" "Homebrew" -"Controller.Left" "JOYSTICK" -"Display.Phosphor" "YES" -"" diff --git a/src/emucore/tia/TIA.cxx b/src/emucore/tia/TIA.cxx index 656524eae..b3a48c335 100644 --- a/src/emucore/tia/TIA.cxx +++ b/src/emucore/tia/TIA.cxx @@ -414,85 +414,81 @@ uInt8 TIA::peek(uInt16 address) { updateEmulation(); - // If pins are undriven, we start with the last databus value - // Otherwise, there is some randomness injected into the mix - // In either case, we start out with D7 and D6 disabled (the only - // valid bits in a TIA read), and selectively enable them - uInt8 lastDataBusValue = - !myTIAPinsDriven ? mySystem->getDataBusState() : mySystem->getDataBusState(0xFF); - - uInt8 result; + // Start with all bits disabled + // In some cases both D7 and D6 are used; in other cases only D7 is used + uInt8 result = 0b0000000; switch (address & 0x0F) { case CXM0P: - result = collCXM0P(); + result = collCXM0P() & 0b11000000; break; case CXM1P: - result = collCXM1P(); + result = collCXM1P() & 0b11000000; break; case CXP0FB: - result = collCXP0FB(); + result = collCXP0FB() & 0b11000000; break; case CXP1FB: - result = collCXP1FB(); + result = collCXP1FB() & 0b11000000; break; case CXM0FB: - result = collCXM0FB(); + result = collCXM0FB() & 0b11000000; break; case CXM1FB: - result = collCXM1FB(); + result = collCXM1FB() & 0b11000000; break; case CXPPMM: - result = collCXPPMM(); + result = collCXPPMM() & 0b11000000; break; case CXBLPF: - result = collCXBLPF(); + result = collCXBLPF() & 0b10000000; break; case INPT0: updatePaddle(0); - result = myPaddleReaders[0].inpt(myTimestamp) | (lastDataBusValue & 0x40); + result = myPaddleReaders[0].inpt(myTimestamp) & 0b10000000; break; case INPT1: updatePaddle(1); - result = myPaddleReaders[1].inpt(myTimestamp) | (lastDataBusValue & 0x40); + result = myPaddleReaders[1].inpt(myTimestamp) & 0b10000000; break; case INPT2: updatePaddle(2); - result = myPaddleReaders[2].inpt(myTimestamp) | (lastDataBusValue & 0x40); + result = myPaddleReaders[2].inpt(myTimestamp) & 0b10000000; break; case INPT3: updatePaddle(3); - result = myPaddleReaders[3].inpt(myTimestamp) | (lastDataBusValue & 0x40); + result = myPaddleReaders[3].inpt(myTimestamp) & 0b10000000; break; case INPT4: - result = - myInput0.inpt(!myConsole.leftController().read(Controller::DigitalPin::Six)) | - (lastDataBusValue & 0x40); + result = myInput0.inpt(!myConsole.leftController().read(Controller::DigitalPin::Six)) + & 0b10000000; break; case INPT5: - result = - myInput1.inpt(!myConsole.rightController().read(Controller::DigitalPin::Six)) | - (lastDataBusValue & 0x40); + result = myInput1.inpt(!myConsole.rightController().read(Controller::DigitalPin::Six)) + & 0b10000000; break; default: - result = 0; + break; } - return (result & 0xC0) | (lastDataBusValue & 0x3F); + // Bits D5 .. D0 are floating + // The options are either to use the last databus value, or use random data + return result | ((!myTIAPinsDriven ? mySystem->getDataBusState() : + mySystem->randGenerator().next()) & 0b00111111); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1033,9 +1029,13 @@ bool TIA::toggleBit(TIABit b, uInt8 mode) mask = b; break; - default: + case 2: mask = (~mySpriteEnabledBits & b); break; + + default: + mask = (mySpriteEnabledBits & b); + break; } mySpriteEnabledBits = (mySpriteEnabledBits & ~b) | mask; @@ -1051,9 +1051,11 @@ bool TIA::toggleBit(TIABit b, uInt8 mode) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool TIA::toggleBits() +bool TIA::toggleBits(bool toggle) { - toggleBit(TIABit(0xFF), mySpriteEnabledBits > 0 ? 0 : 1); + toggleBit(TIABit(0xFF), toggle + ? mySpriteEnabledBits > 0 ? 0 : 1 + : mySpriteEnabledBits); return mySpriteEnabledBits; } @@ -1072,9 +1074,13 @@ bool TIA::toggleCollision(TIABit b, uInt8 mode) mask = b; break; - default: + case 2: mask = (~myCollisionsEnabledBits & b); break; + + default: + mask = (myCollisionsEnabledBits & b); + break; } myCollisionsEnabledBits = (myCollisionsEnabledBits & ~b) | mask; @@ -1090,9 +1096,11 @@ bool TIA::toggleCollision(TIABit b, uInt8 mode) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool TIA::toggleCollisions() +bool TIA::toggleCollisions(bool toggle) { - toggleCollision(TIABit(0xFF), myCollisionsEnabledBits > 0 ? 0 : 1); + toggleCollision(TIABit(0xFF), toggle + ? myCollisionsEnabledBits > 0 ? 0 : 1 + : myCollisionsEnabledBits); return myCollisionsEnabledBits; } @@ -1211,6 +1219,9 @@ bool TIA::toggleJitter(uInt8 mode) myEnableJitter = !myEnableJitter; break; + case 3: + break; + default: throw runtime_error("invalid argument for toggleJitter"); } diff --git a/src/emucore/tia/TIA.hxx b/src/emucore/tia/TIA.hxx index de3c373a4..3b2cbea7c 100644 --- a/src/emucore/tia/TIA.hxx +++ b/src/emucore/tia/TIA.hxx @@ -356,23 +356,25 @@ class TIA : public Device disabling a graphical object also disables its collisions. @param mode 1/0 indicates on/off, and values greater than 1 mean - flip the bit from its current state + 2 means flip the bit from its current state + and values greater than 2 mean return current state @return Whether the bit was enabled or disabled */ bool toggleBit(TIABit b, uInt8 mode = 2); - bool toggleBits(); + bool toggleBits(bool toggle = true); /** Enables/disable/toggle the specified (or all) TIA bit collision(s). - @param mode 1/0 indicates on/off, and values greater than 1 mean - flip the collision from its current state + @param mode 1/0 indicates on/off, + 2 means flip the collision from its current state + and values greater than 2 mean return current state @return Whether the collision was enabled or disabled */ bool toggleCollision(TIABit b, uInt8 mode = 2); - bool toggleCollisions(); + bool toggleCollisions(bool toggle = true); /** Enables/disable/toggle/query 'fixed debug colors' mode. diff --git a/src/gui/Dialog.cxx b/src/gui/Dialog.cxx index 1cc0b3b8c..e455a976c 100644 --- a/src/gui/Dialog.cxx +++ b/src/gui/Dialog.cxx @@ -835,6 +835,34 @@ void Dialog::addDefaultsOKCancelBGroup(WidgetArray& wid, const GUI::Font& font, addOKCancelBGroup(wid, font, okText, cancelText, focusOKButton, buttonWidth); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Dialog::addDefaultsExtraOKCancelBGroup( + WidgetArray& wid, const GUI::Font& font, + const string& extraText, int extraCmd, + const string& okText, const string& cancelText, const string& defaultsText, + bool focusOKButton) +{ + const int fontWidth = font.getMaxCharWidth(), + fontHeight = font.getFontHeight(), + buttonHeight = font.getLineHeight() * 1.25; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int BTN_BORDER = fontWidth * 2.5; + const int BUTTON_GAP = fontWidth; + const int buttonWidth = font.getStringWidth(defaultsText) + BTN_BORDER; + + addDefaultWidget(new ButtonWidget(this, font, HBORDER, _h - buttonHeight - VBORDER, + buttonWidth, buttonHeight, defaultsText, GuiObject::kDefaultsCmd)); + wid.push_back(_defaultWidget); + + wid.push_back(new ButtonWidget(this, font, HBORDER + buttonWidth + BUTTON_GAP, + _h - buttonHeight - VBORDER, buttonWidth, buttonHeight, + extraText, extraCmd) + ); + + addOKCancelBGroup(wid, font, okText, cancelText, focusOKButton, buttonWidth); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::TabFocus::appendFocusList(WidgetArray& list) { diff --git a/src/gui/Dialog.hxx b/src/gui/Dialog.hxx index 5b95fe5e0..0dc5e7118 100644 --- a/src/gui/Dialog.hxx +++ b/src/gui/Dialog.hxx @@ -158,6 +158,15 @@ class Dialog : public GuiObject const string& defaultsText = "Defaults", bool focusOKButton = true); + // NOTE: This method, and the two above it, are due to be refactored at some + // point, since the parameter list is kind of getting ridiculous + void addDefaultsExtraOKCancelBGroup(WidgetArray& wid, const GUI::Font& font, + const string& extraText, int extraCmd, + const string& okText = "OK", + const string& cancelText = "Cancel", + const string& defaultsText = "Defaults", + bool focusOKButton = true); + void processCancelWithoutWidget(bool state) { _processCancel = state; } virtual void processCancel() { close(); } diff --git a/src/gui/EmulationDialog.cxx b/src/gui/EmulationDialog.cxx index e9bb3804a..dcbb42859 100644 --- a/src/gui/EmulationDialog.cxx +++ b/src/gui/EmulationDialog.cxx @@ -237,6 +237,7 @@ void EmulationDialog::saveConfig() instance().console().initializeAudio(); // update VSync instance().console().initializeVideo(); + instance().createFrameBuffer(); instance().frameBuffer().tiaSurface().ntsc().enableThreading(myUseThreads->getState()); } diff --git a/src/gui/GameInfoDialog.cxx b/src/gui/GameInfoDialog.cxx index fd646c6ed..ff1fca0c6 100644 --- a/src/gui/GameInfoDialog.cxx +++ b/src/gui/GameInfoDialog.cxx @@ -383,7 +383,7 @@ GameInfoDialog::GameInfoDialog( // Add Defaults, OK and Cancel buttons wid.clear(); - addDefaultsOKCancelBGroup(wid, font); + addDefaultsExtraOKCancelBGroup(wid, font, "Save", kSavePressed); addBGroupToFocusList(wid); } @@ -393,11 +393,13 @@ void GameInfoDialog::loadConfig() if(instance().hasConsole()) { myGameProperties = instance().console().properties(); + myGameFile = instance().romFile(); } else { const string& md5 = instance().launcher().selectedRomMD5(); instance().propSet().getMD5(md5, myGameProperties); + myGameFile = FilesystemNode(instance().launcher().selectedRom()); } loadEmulationProperties(myGameProperties); @@ -568,7 +570,7 @@ void GameInfoDialog::loadCartridgeProperties(const Properties& props) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void GameInfoDialog::saveConfig() +void GameInfoDialog::saveProperties() { // Emulation properties myGameProperties.set(PropType::Cart_Type, myBSType->getSelectedTag().toString()); @@ -613,6 +615,12 @@ void GameInfoDialog::saveConfig() myGameProperties.set(PropType::Cart_ModelNo, myModelNo->getText()); myGameProperties.set(PropType::Cart_Rarity, myRarity->getText()); myGameProperties.set(PropType::Cart_Note, myNote->getText()); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void GameInfoDialog::saveConfig() +{ + saveProperties(); // Always insert; if the properties are already present, nothing will happen instance().propSet().insert(myGameProperties); @@ -626,7 +634,7 @@ void GameInfoDialog::saveConfig() // update 'Emulation' tab settings immediately instance().console().setFormat(myFormat->getSelected()); instance().frameBuffer().tiaSurface().enablePhosphor(myPhosphor->getState(), myPPBlend->getValue()); - instance().console().updateVcenter(vcenter); + instance().console().updateVcenter(myVCenter->getValue()); instance().console().initializeAudio(); // update 'Console' tab settings immediately @@ -699,7 +707,7 @@ void GameInfoDialog::updateControllerStates() label = (!swapPorts ? instance().console().leftController().name() : instance().console().rightController().name()) + " detected"; else if(autoDetect) - label = ControllerDetector::detectName(image.get(), size, type, + label = ControllerDetector::detectName(image, size, type, !swapPorts ? Controller::Jack::Left : Controller::Jack::Right, instance().settings()) + " detected"; } @@ -714,7 +722,7 @@ void GameInfoDialog::updateControllerStates() label = (!swapPorts ? instance().console().rightController().name() : instance().console().leftController().name()) + " detected"; else if(autoDetect) - label = ControllerDetector::detectName(image.get(), size, type, + label = ControllerDetector::detectName(image, size, type, !swapPorts ? Controller::Jack::Right : Controller::Jack::Left, instance().settings()) + " detected"; } @@ -782,19 +790,38 @@ void GameInfoDialog::eraseEEPROM() Controller& lport = instance().console().leftController(); Controller& rport = instance().console().rightController(); - if(lport.type() == Controller::Type::SaveKey || lport.type() == Controller::Type::AtariVox) + if(lport.type() == Controller::Type::SaveKey || + lport.type() == Controller::Type::AtariVox) { SaveKey& skey = static_cast(lport); skey.eraseCurrent(); } - if(rport.type() == Controller::Type::SaveKey || rport.type() == Controller::Type::AtariVox) + if(rport.type() == Controller::Type::SaveKey || + rport.type() == Controller::Type::AtariVox) { SaveKey& skey = static_cast(rport); skey.eraseCurrent(); } } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void GameInfoDialog::saveCurrentPropertiesToDisk() +{ + saveProperties(); + + FilesystemNode propfile(instance().defaultSaveDir() + myGameFile.getNameWithExt(".pro")); + ofstream out(propfile.getPath()); + if(out) + { + out << myGameProperties; + instance().frameBuffer().showMessage("Properties saved to " + + propfile.getShortPath()); + } + else + instance().frameBuffer().showMessage("Error saving properties"); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void GameInfoDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) @@ -810,6 +837,10 @@ void GameInfoDialog::handleCommand(CommandSender* sender, int cmd, setDefaults(); break; + case kSavePressed: + saveCurrentPropertiesToDisk(); + break; + case TabWidget::kTabChangedCmd: if(data == 2) // 'Controllers' tab selected updateControllerStates(); diff --git a/src/gui/GameInfoDialog.hxx b/src/gui/GameInfoDialog.hxx index 2e2dc4f8a..7e5febdde 100644 --- a/src/gui/GameInfoDialog.hxx +++ b/src/gui/GameInfoDialog.hxx @@ -53,9 +53,12 @@ class GameInfoDialog : public Dialog, public CommandSender void loadControllerProperties(const Properties& props); // load the properties for the 'Cartridge' tab void loadCartridgeProperties(const Properties& props); + // save properties from all tabs into the local properties object + void saveProperties(); void updateControllerStates(); void eraseEEPROM(); + void saveCurrentPropertiesToDisk(); private: TabWidget* myTab{nullptr}; @@ -115,10 +118,13 @@ class GameInfoDialog : public Dialog, public CommandSender kEEButtonPressed = 'EEgb', kPXCenterChanged = 'Pxch', kPYCenterChanged = 'Pych', + kSavePressed = 'GIsp' }; // Game properties for currently loaded ROM Properties myGameProperties; + // Filename of the currently loaded ROM + FilesystemNode myGameFile; private: // Following constructors and assignment operators not supported diff --git a/src/gui/RomInfoWidget.cxx b/src/gui/RomInfoWidget.cxx index 3cfa43185..b90a45fb2 100644 --- a/src/gui/RomInfoWidget.cxx +++ b/src/gui/RomInfoWidget.cxx @@ -152,10 +152,10 @@ void RomInfoWidget::parseProperties(const FilesystemNode& node) (image = instance().openROM(node, md5, size)) != nullptr) { Logger::debug(myProperties.get(PropType::Cart_Name) + ":"); - left = ControllerDetector::detectName(image.get(), size, leftType, + left = ControllerDetector::detectName(image, size, leftType, !swappedPorts ? Controller::Jack::Left : Controller::Jack::Right, instance().settings()); - right = ControllerDetector::detectName(image.get(), size, rightType, + right = ControllerDetector::detectName(image, size, rightType, !swappedPorts ? Controller::Jack::Right : Controller::Jack::Left, instance().settings()); if (bsDetected == "AUTO") diff --git a/src/gui/SnapshotDialog.cxx b/src/gui/SnapshotDialog.cxx index 870a82b54..e7f5795ed 100644 --- a/src/gui/SnapshotDialog.cxx +++ b/src/gui/SnapshotDialog.cxx @@ -89,7 +89,7 @@ SnapshotDialog::SnapshotDialog(OSystem& osystem, DialogContainer& parent, // Snapshot in 1x mode (ignore scaling) ypos += lineHeight + VGAP; mySnap1x = new CheckboxWidget(this, font, xpos, ypos, - "Ignore scaling (1x mode)"); + "Create pixel-exact image (no zoom/post-processing)"); wid.push_back(mySnap1x); // Add Defaults, OK and Cancel buttons diff --git a/src/gui/StellaSettingsDialog.cxx b/src/gui/StellaSettingsDialog.cxx index b5c1e5106..74e8ca35f 100644 --- a/src/gui/StellaSettingsDialog.cxx +++ b/src/gui/StellaSettingsDialog.cxx @@ -540,7 +540,7 @@ void StellaSettingsDialog::updateControllerStates() if(instance().hasConsole()) label = (instance().console().leftController().name()) + " detected"; else if(autoDetect) - label = ControllerDetector::detectName(image.get(), size, type, + label = ControllerDetector::detectName(image, size, type, Controller::Jack::Left, instance().settings()) + " detected"; } @@ -554,7 +554,7 @@ void StellaSettingsDialog::updateControllerStates() if(instance().hasConsole()) label = (instance().console().rightController().name()) + " detected"; else if(autoDetect) - label = ControllerDetector::detectName(image.get(), size, type, + label = ControllerDetector::detectName(image, size, type, Controller::Jack::Right, instance().settings()) + " detected"; } diff --git a/src/gui/UIDialog.cxx b/src/gui/UIDialog.cxx index eafc2e00b..598dd0756 100644 --- a/src/gui/UIDialog.cxx +++ b/src/gui/UIDialog.cxx @@ -85,6 +85,7 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, VarList::push_back(items, "Standard", "standard"); VarList::push_back(items, "Classic", "classic"); VarList::push_back(items, "Light", "light"); + VarList::push_back(items, "Dark", "dark"); myPalettePopup = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, "Theme ", lwidth); wid.push_back(myPalettePopup); diff --git a/src/gui/VideoAudioDialog.cxx b/src/gui/VideoAudioDialog.cxx index 48fdcc8de..e87cbe221 100644 --- a/src/gui/VideoAudioDialog.cxx +++ b/src/gui/VideoAudioDialog.cxx @@ -47,7 +47,7 @@ new SliderWidget(myTab, _font, xpos, ypos-1, swidth, lineHeight, \ desc, lwidth, cmd, fontWidth*4, "%"); \ myTV ## obj->setMinValue(0); myTV ## obj->setMaxValue(100); \ - myTV ## obj->setStepValue(2); \ + myTV ## obj->setStepValue(1); \ myTV ## obj->setTickmarkIntervals(2); \ wid.push_back(myTV ## obj); \ ypos += lineHeight + VGAP; @@ -83,14 +83,6 @@ VideoAudioDialog::VideoAudioDialog(OSystem& osystem, DialogContainer& parent, addTVEffectsTab(); addAudioTab(); - //const int req_w = std::max(myFastSCBios->getRight(), myCloneBad->getRight()) + HBORDER + 1; - //const int req_h = _th + VGAP * 3 - // + std::max(myUseVSync->getBottom(), myTVScanIntense->getBottom()) - // + buttonHeight + VBORDER * 2; - //// Set real dimensions - //setSize(req_w, req_h, max_w, max_h); - - // Add Defaults, OK and Cancel buttons WidgetArray wid; addDefaultsOKCancelBGroup(wid, _font); @@ -149,26 +141,29 @@ void VideoAudioDialog::addDisplayTab() wid.push_back(myFullscreen); ypos += lineHeight + VGAP; - /*pwidth = font.getStringWidth("0: 3840x2860@120Hz"); - myFullScreenMode = new PopUpWidget(myTab, font, xpos + INDENT + 2, ypos, pwidth, lineHeight, - instance().frameBuffer().supportedScreenModes(), "Mode "); - wid.push_back(myFullScreenMode); - ypos += lineHeight + VGAP;*/ - // FS stretch myUseStretch = new CheckboxWidget(myTab, _font, xpos + INDENT, ypos + 1, "Stretch"); wid.push_back(myUseStretch); + +#ifdef ADAPTABLE_REFRESH_SUPPORT + // Adapt refresh rate ypos += lineHeight + VGAP; + myRefreshAdapt = new CheckboxWidget(myTab, _font, xpos + INDENT, ypos + 1, "Adapt display refresh rate"); + wid.push_back(myRefreshAdapt); +#else + myRefreshAdapt = nullptr; +#endif // FS overscan + ypos += lineHeight + VGAP; myTVOverscan = new SliderWidget(myTab, _font, xpos + INDENT, ypos - 1, swidth, lineHeight, "Overscan", lwidth - INDENT, kOverscanChanged, fontWidth * 3, "%"); myTVOverscan->setMinValue(0); myTVOverscan->setMaxValue(10); myTVOverscan->setTickmarkIntervals(2); wid.push_back(myTVOverscan); - ypos += lineHeight + VGAP; // Vertical size + ypos += lineHeight + VGAP; myVSizeAdjust = new SliderWidget(myTab, _font, xpos, ypos-1, swidth, lineHeight, "V-Size adjust", lwidth, kVSizeChanged, fontWidth * 7, "%", 0, true); @@ -176,6 +171,7 @@ void VideoAudioDialog::addDisplayTab() myVSizeAdjust->setTickmarkIntervals(2); wid.push_back(myVSizeAdjust); + // Add items for tab 0 addToFocusList(wid, myTab, tabID); } @@ -480,10 +476,12 @@ void VideoAudioDialog::loadConfig() // Fullscreen myFullscreen->setState(instance().settings().getBool("fullscreen")); - /*string mode = instance().settings().getString("fullscreenmode"); - myFullScreenMode->setSelected(mode);*/ // Fullscreen stretch setting myUseStretch->setState(instance().settings().getBool("tia.fs_stretch")); +#ifdef ADAPTABLE_REFRESH_SUPPORT + // Adapt refresh rate + myRefreshAdapt->setState(instance().settings().getBool("tia.fs_refresh")); +#endif // Fullscreen overscan setting myTVOverscan->setValue(instance().settings().getInt("tia.fs_overscan")); handleFullScreenChange(); @@ -595,6 +593,10 @@ void VideoAudioDialog::saveConfig() instance().settings().setValue("fullscreen", myFullscreen->getState()); // Fullscreen stretch setting instance().settings().setValue("tia.fs_stretch", myUseStretch->getState()); +#ifdef ADAPTABLE_REFRESH_SUPPORT + // Adapt refresh rate + instance().settings().setValue("tia.fs_refresh", myRefreshAdapt->getState()); +#endif // Fullscreen overscan instance().settings().setValue("tia.fs_overscan", myTVOverscan->getValueLabel()); @@ -611,7 +613,6 @@ void VideoAudioDialog::saveConfig() // Note: Palette values are saved directly when changed! - ///////////////////////////////////////////////////////////////////////////// // TV Effects tab // TV Mode @@ -706,8 +707,10 @@ void VideoAudioDialog::setDefaults() myTIAInterpolate->setState(false); // screen size myFullscreen->setState(false); - //myFullScreenMode->setSelectedIndex(0); myUseStretch->setState(false); + #ifdef ADAPTABLE_REFRESH_SUPPORT + myRefreshAdapt->setState(false); + #endif myTVOverscan->setValue(0); myTIAZoom->setValue(300); myVSizeAdjust->setValue(0); @@ -726,6 +729,7 @@ void VideoAudioDialog::setDefaults() myTVBright->setValue(50); myTVGamma->setValue(50); handlePaletteChange(); + handlePaletteUpdate(); break; case 2: // TV effects @@ -833,6 +837,9 @@ void VideoAudioDialog::handleFullScreenChange() { bool enable = myFullscreen->getState(); myUseStretch->setEnabled(enable); +#ifdef ADAPTABLE_REFRESH_SUPPORT + myRefreshAdapt->setEnabled(enable); +#endif myTVOverscan->setEnabled(enable); } @@ -998,24 +1005,21 @@ void VideoAudioDialog::handleCommand(CommandSender* sender, int cmd, // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void VideoAudioDialog::addPalette(int x, int y, int w, int h) { - if(instance().hasConsole()) - { - constexpr int NUM_LUMA = 8; - constexpr int NUM_CHROMA = 16; - const GUI::Font& ifont = instance().frameBuffer().infoFont(); - const int lwidth = ifont.getMaxCharWidth() * 1.5; - const float COLW = float(w - lwidth) / NUM_LUMA; - const float COLH = float(h) / NUM_CHROMA; - const int yofs = (COLH - ifont.getFontHeight() + 1) / 2; + constexpr int NUM_LUMA = 8; + constexpr int NUM_CHROMA = 16; + const GUI::Font& ifont = instance().frameBuffer().infoFont(); + const int lwidth = ifont.getMaxCharWidth() * 1.5; + const float COLW = float(w - lwidth) / NUM_LUMA; + const float COLH = float(h) / NUM_CHROMA; + const int yofs = (COLH - ifont.getFontHeight() + 1) / 2; - for(int idx = 0; idx < NUM_CHROMA; ++idx) + for(int idx = 0; idx < NUM_CHROMA; ++idx) + { + myColorLbl[idx] = new StaticTextWidget(myTab, ifont, x, y + yofs + idx * COLH, " "); + for(int lum = 0; lum < NUM_LUMA; ++lum) { - myColorLbl[idx] = new StaticTextWidget(myTab, ifont, x, y + yofs + idx * COLH, " "); - for(int lum = 0; lum < NUM_LUMA; ++lum) - { - myColor[idx][lum] = new ColorWidget(myTab, _font, x + lwidth + lum * COLW, y + idx * COLH, - COLW + 1, COLH + 1, 0, false); - } + myColor[idx][lum] = new ColorWidget(myTab, _font, x + lwidth + lum * COLW, y + idx * COLH, + COLW + 1, COLH + 1, 0, false); } } } diff --git a/src/gui/VideoAudioDialog.hxx b/src/gui/VideoAudioDialog.hxx index f46740ae6..0961f776e 100644 --- a/src/gui/VideoAudioDialog.hxx +++ b/src/gui/VideoAudioDialog.hxx @@ -71,9 +71,9 @@ class VideoAudioDialog : public Dialog PopUpWidget* myRenderer{nullptr}; CheckboxWidget* myTIAInterpolate{nullptr}; CheckboxWidget* myFullscreen{nullptr}; - //PopUpWidget* myFullScreenMode; CheckboxWidget* myUseStretch{nullptr}; SliderWidget* myTVOverscan{nullptr}; + CheckboxWidget* myRefreshAdapt{nullptr}; SliderWidget* myTIAZoom{nullptr}; SliderWidget* myVSizeAdjust{nullptr}; diff --git a/src/libretro/FSNodeLIBRETRO.cxx b/src/libretro/FSNodeLIBRETRO.cxx index c2ee02b97..f3670f0a2 100644 --- a/src/libretro/FSNodeLIBRETRO.cxx +++ b/src/libretro/FSNodeLIBRETRO.cxx @@ -15,6 +15,8 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include "bspf.hxx" +#include "Cart.hxx" #include "FSNodeLIBRETRO.hxx" #ifdef _WIN32 @@ -92,7 +94,7 @@ AbstractFSNodePtr FilesystemNodeLIBRETRO::getParent() const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - size_t FilesystemNodeLIBRETRO::read(ByteBuffer& image) const { - image = make_unique(512 * 1024); + image = make_unique(Cartridge::maxSize()); extern uInt32 libretro_read_rom(void* data); return libretro_read_rom(image.get()); diff --git a/src/libretro/Makefile.common b/src/libretro/Makefile.common index 5fafdd855..994628725 100644 --- a/src/libretro/Makefile.common +++ b/src/libretro/Makefile.common @@ -39,6 +39,7 @@ SOURCES_CXX := \ $(CORE_DIR)/emucore/Bankswitch.cxx \ $(CORE_DIR)/emucore/Booster.cxx \ $(CORE_DIR)/emucore/Cart.cxx \ + $(CORE_DIR)/emucore/CartCreator.cxx \ $(CORE_DIR)/emucore/CartDetector.cxx \ $(CORE_DIR)/emucore/CartEnhanced.cxx \ $(CORE_DIR)/emucore/Cart0840.cxx \ @@ -81,6 +82,7 @@ SOURCES_CXX := \ $(CORE_DIR)/emucore/CartMDM.cxx \ $(CORE_DIR)/emucore/CartMNetwork.cxx \ $(CORE_DIR)/emucore/CartSB.cxx \ + $(CORE_DIR)/emucore/CartTVBoy.cxx \ $(CORE_DIR)/emucore/CartUA.cxx \ $(CORE_DIR)/emucore/CartWD.cxx \ $(CORE_DIR)/emucore/CartX07.cxx \ diff --git a/src/libretro/StellaLIBRETRO.cxx b/src/libretro/StellaLIBRETRO.cxx index d670c45a9..38e52e734 100644 --- a/src/libretro/StellaLIBRETRO.cxx +++ b/src/libretro/StellaLIBRETRO.cxx @@ -188,7 +188,6 @@ void StellaLIBRETRO::updateVideo() if(tia.scanlines() == 0) break; } - video_ready = tia.newFramePending(); if (video_ready) @@ -221,7 +220,7 @@ bool StellaLIBRETRO::loadState(const void* data, size_t size) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool StellaLIBRETRO::saveState(void* data, size_t size) +bool StellaLIBRETRO::saveState(void* data, size_t size) const { Serializer state; @@ -236,7 +235,7 @@ bool StellaLIBRETRO::saveState(void* data, size_t size) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -size_t StellaLIBRETRO::getStateSize() +size_t StellaLIBRETRO::getStateSize() const { Serializer state; @@ -247,52 +246,52 @@ size_t StellaLIBRETRO::getStateSize() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -float StellaLIBRETRO::getVideoAspectPar() +float StellaLIBRETRO::getVideoAspectPar() const { float par; if (getVideoNTSC()) { - if (!video_aspect_ntsc) - { - if (video_filter != NTSCFilter::Preset::OFF) + if (!video_aspect_ntsc) { - // non-interlace square pixel clock -- 1.0 pixel @ color burst -- double-width pixels - par = (6.1363635f / 3.579545454f) / 2.0; + if (video_filter != NTSCFilter::Preset::OFF) + { + // non-interlace square pixel clock -- 1.0 pixel @ color burst -- double-width pixels + par = (6.1363635f / 3.579545454f) / 2.0; + } + else + { + // blargg filter + par = 1.0; + } } else - { - // blargg filter - par = 1.0; - } - } - else - par = video_aspect_ntsc / 100.0; + par = video_aspect_ntsc / 100.0; } else { - if (!video_aspect_pal) - { - if (video_filter != NTSCFilter::Preset::OFF) + if (!video_aspect_pal) { - // non-interlace square pixel clock -- 0.8 pixel @ color burst -- double-width pixels - par = (7.3750000f / (4.43361875f * 4.0f / 5.0f)) / 2.0f; + if (video_filter != NTSCFilter::Preset::OFF) + { + // non-interlace square pixel clock -- 0.8 pixel @ color burst -- double-width pixels + par = (7.3750000f / (4.43361875f * 4.0f / 5.0f)) / 2.0f; + } + else + { + // blargg filter + par = 1.0; + } } else - { - // blargg filter - par = 1.0; - } - } - else - par = video_aspect_pal / 100.0; + par = video_aspect_pal / 100.0; } return par; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -float StellaLIBRETRO::getVideoAspect() +float StellaLIBRETRO::getVideoAspect() const { uInt32 width = myOSystem->console().tia().width() * 2; @@ -301,7 +300,7 @@ float StellaLIBRETRO::getVideoAspect() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void* StellaLIBRETRO::getVideoBuffer() +void* StellaLIBRETRO::getVideoBuffer() const { FrameBufferLIBRETRO& frame = static_cast(myOSystem->frameBuffer()); @@ -309,7 +308,7 @@ void* StellaLIBRETRO::getVideoBuffer() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool StellaLIBRETRO::getVideoNTSC() +bool StellaLIBRETRO::getVideoNTSC() const { const ConsoleInfo& console_info = myOSystem->console().about(); string format = console_info.DisplayFormat; @@ -348,13 +347,13 @@ void StellaLIBRETRO::setConsoleFormat(uInt32 mode) { switch(mode) { - case 0: console_format = "AUTO"; break; - case 1: console_format = "NTSC"; break; - case 2: console_format = "PAL"; break; - case 3: console_format = "SECAM"; break; - case 4: console_format = "NTSC50"; break; - case 5: console_format = "PAL60"; break; - case 6: console_format = "SECAM60"; break; + case 0: console_format = "AUTO"; break; + case 1: console_format = "NTSC"; break; + case 2: console_format = "PAL"; break; + case 3: console_format = "SECAM"; break; + case 4: console_format = "NTSC50"; break; + case 5: console_format = "PAL60"; break; + case 6: console_format = "SECAM60"; break; } if (system_ready) @@ -388,9 +387,9 @@ void StellaLIBRETRO::setVideoPhosphor(uInt32 mode, uInt32 blend) { switch (mode) { - case 0: video_phosphor = "byrom"; break; - case 1: video_phosphor = "never"; break; - case 2: video_phosphor = "always"; break; + case 0: video_phosphor = "byrom"; break; + case 1: video_phosphor = "never"; break; + case 2: video_phosphor = "always"; break; } video_phosphor_blend = blend; @@ -414,9 +413,9 @@ void StellaLIBRETRO::setAudioStereo(int mode) { switch (mode) { - case 0: audio_mode = "byrom"; break; - case 1: audio_mode = "mono"; break; - case 2: audio_mode = "stereo"; break; + case 0: audio_mode = "byrom"; break; + case 1: audio_mode = "mono"; break; + case 2: audio_mode = "stereo"; break; } if (system_ready) diff --git a/src/libretro/StellaLIBRETRO.hxx b/src/libretro/StellaLIBRETRO.hxx index 3078e8eb1..b3d87725b 100644 --- a/src/libretro/StellaLIBRETRO.hxx +++ b/src/libretro/StellaLIBRETRO.hxx @@ -21,6 +21,7 @@ #include "bspf.hxx" #include "OSystemLIBRETRO.hxx" +#include "Cart.hxx" #include "Console.hxx" #include "ConsoleTiming.hxx" #include "Control.hxx" @@ -32,7 +33,6 @@ #include "TIA.hxx" #include "TIASurface.hxx" - /** This class wraps Stella core for easier libretro maintenance */ @@ -52,46 +52,59 @@ class StellaLIBRETRO void runFrame(); bool loadState(const void* data, size_t size); - bool saveState(void* data, size_t size); + bool saveState(void* data, size_t size) const; public: - const char* getCoreName() { return "Stella"; } - const char* getROMExtensions() { return "a26|bin"; } + const char* getCoreName() const { return "Stella"; } + const char* getROMExtensions() const { return "a26|bin"; } - void* getROM() { return rom_image.get(); } - uInt32 getROMSize() { return rom_size; } - uInt32 getROMMax() { return 512 * 1024; } + void* getROM() const { return rom_image.get(); } + uInt32 getROMSize() const { return rom_size; } + constexpr uInt32 getROMMax() const { return Cartridge::maxSize(); } uInt8* getRAM() { return system_ram; } - uInt32 getRAMSize() { return 128; } + constexpr uInt32 getRAMSize() const { return 128; } - size_t getStateSize(); + size_t getStateSize() const; - bool getConsoleNTSC() { return console_timing == ConsoleTiming::ntsc; } + bool getConsoleNTSC() const { return console_timing == ConsoleTiming::ntsc; } - float getVideoAspectPar(); - float getVideoAspect(); - bool getVideoNTSC(); - float getVideoRate() { return getVideoNTSC() ? 60.0 : 50.0; } + float getVideoAspectPar() const; + float getVideoAspect() const; + bool getVideoNTSC() const; + float getVideoRate() const { return getVideoNTSC() ? 60.0 : 50.0; } - bool getVideoReady() { return video_ready; } - uInt32 getVideoZoom() { return myOSystem->frameBuffer().tiaSurface().ntscEnabled() ? 2 : 1; } + bool getVideoReady() const { return video_ready; } + uInt32 getVideoZoom() const { + return myOSystem->frameBuffer().tiaSurface().ntscEnabled() ? 2 : 1; + } bool getVideoResize(); - void* getVideoBuffer(); - uInt32 getVideoWidth() { return getVideoZoom()==1 ? myOSystem->console().tia().width() : getVideoWidthMax(); } - uInt32 getVideoHeight() { return myOSystem->console().tia().height(); } - uInt32 getVideoPitch() { return getVideoWidthMax() * 4; } + void* getVideoBuffer() const; + uInt32 getVideoWidth() const { + return getVideoZoom() == 1 ? myOSystem->console().tia().width() : getVideoWidthMax(); + } + uInt32 getVideoHeight() const { + return myOSystem->console().tia().height(); + } + constexpr uInt32 getVideoPitch() const { return getVideoWidthMax() * 4; } - uInt32 getVideoWidthMax() { return AtariNTSC::outWidth(160); } - uInt32 getVideoHeightMax() { return 312; } + constexpr uInt32 getVideoWidthMax() const { return AtariNTSC::outWidth(160); } + constexpr uInt32 getVideoHeightMax() const { return 312; } - uInt32 getRenderWidth() { return getVideoZoom()==1 ? myOSystem->console().tia().width() * 2 : getVideoWidthMax(); } - uInt32 getRenderHeight() { return myOSystem->console().tia().height() * getVideoZoom(); } + uInt32 getRenderWidth() const { + return getVideoZoom() == 1 ? myOSystem->console().tia().width() * 2 + : getVideoWidthMax(); + } + uInt32 getRenderHeight() const { + return myOSystem->console().tia().height() * getVideoZoom(); + } - float getAudioRate() { return getConsoleNTSC() ? (262 * 76 * 60) / 38.0 : (312 * 76 * 50) / 38.0; } - bool getAudioReady() { return audio_samples > 0; } - uInt32 getAudioSize() { return audio_samples; } + float getAudioRate() const { + return getConsoleNTSC() ? (262 * 76 * 60) / 38.0 : (312 * 76 * 50) / 38.0; + } + bool getAudioReady() const { return audio_samples > 0; } + uInt32 getAudioSize() const { return audio_samples; } Int16* getAudioBuffer() { return audio_buffer.get(); } @@ -101,7 +114,7 @@ class StellaLIBRETRO void setConsoleFormat(uInt32 mode); void setVideoAspectNTSC(uInt32 value) { video_aspect_ntsc = value; }; - void setVideoAspectPAL(uInt32 value) { video_aspect_pal = value; }; + void setVideoAspectPAL(uInt32 value) { video_aspect_pal = value; }; void setVideoFilter(NTSCFilter::Preset mode); void setVideoPalette(const string& mode); @@ -109,12 +122,18 @@ class StellaLIBRETRO void setAudioStereo(int mode); - void setInputEvent(Event::Type type, Int32 state) { myOSystem->eventHandler().handleEvent(type, state); } + void setInputEvent(Event::Type type, Int32 state) { + myOSystem->eventHandler().handleEvent(type, state); + } - Controller::Type getLeftControllerType() { return myOSystem->console().leftController().type(); } - Controller::Type getRightControllerType() { return myOSystem->console().rightController().type(); } + Controller::Type getLeftControllerType() const { + return myOSystem->console().leftController().type(); + } + Controller::Type getRightControllerType() const { + return myOSystem->console().rightController().type(); + } - void setPaddleJoypadSensitivity(int sensitivity) + void setPaddleJoypadSensitivity(int sensitivity) { if(getLeftControllerType() == Controller::Type::Paddles) static_cast(myOSystem->console().leftController()).setDigitalSensitivity(sensitivity); @@ -137,7 +156,7 @@ class StellaLIBRETRO unique_ptr myOSystem; uInt32 system_ready; - unique_ptr rom_image; + ByteBuffer rom_image; uInt32 rom_size; string rom_path; diff --git a/src/libretro/libretro.cxx b/src/libretro/libretro.cxx index 8caae3765..42408bd97 100644 --- a/src/libretro/libretro.cxx +++ b/src/libretro/libretro.cxx @@ -559,7 +559,7 @@ bool retro_load_game(const struct retro_game_info *info) { 0, 0, 0, 0, NULL }, }; - if(!info || info->size >= stella.getROMMax()) return false; + if(!info || info->size > stella.getROMMax()) return false; environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc); diff --git a/src/macos/Info-Stella.plist b/src/macos/Info-Stella.plist index 8f37a40c3..d9eb7520e 100644 --- a/src/macos/Info-Stella.plist +++ b/src/macos/Info-Stella.plist @@ -45,7 +45,7 @@ CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion - 6.1 + 6.2.1 CFBundleName Stella CFBundlePackageType @@ -53,7 +53,7 @@ CFBundleSignature StLa CFBundleVersion - 6.1 + 6.2.1 LSApplicationCategoryType public.app-category.games LSMinimumSystemVersionByArchitecture diff --git a/src/macos/stella.xcodeproj/project.pbxproj b/src/macos/stella.xcodeproj/project.pbxproj index d59aac510..f8c0789ce 100644 --- a/src/macos/stella.xcodeproj/project.pbxproj +++ b/src/macos/stella.xcodeproj/project.pbxproj @@ -407,6 +407,12 @@ DC8078DB0B4BD5F3005E9305 /* DebuggerExpressions.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC8078DA0B4BD5F3005E9305 /* DebuggerExpressions.hxx */; }; DC8078EA0B4BD697005E9305 /* UIDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC8078E60B4BD697005E9305 /* UIDialog.cxx */; }; DC8078EB0B4BD697005E9305 /* UIDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC8078E70B4BD697005E9305 /* UIDialog.hxx */; }; + DC84397B247B294E00C6A4FC /* CartTVBoy.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC843979247B294D00C6A4FC /* CartTVBoy.hxx */; }; + DC84397C247B294E00C6A4FC /* CartTVBoy.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC84397A247B294D00C6A4FC /* CartTVBoy.cxx */; }; + DC84397F247B297A00C6A4FC /* CartTVBoyWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC84397D247B297A00C6A4FC /* CartTVBoyWidget.hxx */; }; + DC843980247B297A00C6A4FC /* CartTVBoyWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC84397E247B297A00C6A4FC /* CartTVBoyWidget.cxx */; }; + DC857D352482F66200C7C14F /* CartCreator.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC857D332482F66200C7C14F /* CartCreator.cxx */; }; + DC857D362482F66200C7C14F /* CartCreator.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC857D342482F66200C7C14F /* CartCreator.hxx */; }; DC8C1BAD14B25DE7006440EE /* CartCM.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC8C1BA714B25DE7006440EE /* CartCM.cxx */; }; DC8C1BAE14B25DE7006440EE /* CartCM.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC8C1BA814B25DE7006440EE /* CartCM.hxx */; }; DC8C1BAF14B25DE7006440EE /* CompuMate.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC8C1BA914B25DE7006440EE /* CompuMate.cxx */; }; @@ -700,6 +706,8 @@ isa = PBXBuildRule; compilerSpec = com.apple.compilers.llvm.clang.1_0; fileType = sourcecode.c; + inputFiles = ( + ); isEditable = 1; outputFiles = ( ); @@ -709,6 +717,8 @@ isa = PBXBuildRule; compilerSpec = com.apple.compilers.llvm.clang.1_0; fileType = sourcecode.asm; + inputFiles = ( + ); isEditable = 1; outputFiles = ( ); @@ -718,6 +728,8 @@ isa = PBXBuildRule; compilerSpec = com.apple.compilers.llvm.clang.1_0; fileType = sourcecode.cpp; + inputFiles = ( + ); isEditable = 1; outputFiles = ( ); @@ -1146,6 +1158,12 @@ DC8078DA0B4BD5F3005E9305 /* DebuggerExpressions.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = DebuggerExpressions.hxx; sourceTree = ""; }; DC8078E60B4BD697005E9305 /* UIDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = UIDialog.cxx; sourceTree = ""; }; DC8078E70B4BD697005E9305 /* UIDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = UIDialog.hxx; sourceTree = ""; }; + DC843979247B294D00C6A4FC /* CartTVBoy.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartTVBoy.hxx; sourceTree = ""; }; + DC84397A247B294D00C6A4FC /* CartTVBoy.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartTVBoy.cxx; sourceTree = ""; }; + DC84397D247B297A00C6A4FC /* CartTVBoyWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartTVBoyWidget.hxx; sourceTree = ""; }; + DC84397E247B297A00C6A4FC /* CartTVBoyWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartTVBoyWidget.cxx; sourceTree = ""; }; + DC857D332482F66200C7C14F /* CartCreator.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartCreator.cxx; sourceTree = ""; }; + DC857D342482F66200C7C14F /* CartCreator.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartCreator.hxx; sourceTree = ""; }; DC8C1BA714B25DE7006440EE /* CartCM.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartCM.cxx; sourceTree = ""; }; DC8C1BA814B25DE7006440EE /* CartCM.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartCM.hxx; sourceTree = ""; }; DC8C1BA914B25DE7006440EE /* CompuMate.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CompuMate.cxx; sourceTree = ""; }; @@ -1643,6 +1661,8 @@ DC2AADB3194F390F0026C7A4 /* CartRamWidget.hxx */, DC676A3D1729A0B000E4E73D /* CartSBWidget.cxx */, DC676A3E1729A0B000E4E73D /* CartSBWidget.hxx */, + DC84397E247B297A00C6A4FC /* CartTVBoyWidget.cxx */, + DC84397D247B297A00C6A4FC /* CartTVBoyWidget.hxx */, DCAAE5D11715887B0080BB82 /* CartUAWidget.cxx */, DCAAE5D21715887B0080BB82 /* CartUAWidget.hxx */, DC6D39851A3CE65000171E71 /* CartWDWidget.cxx */, @@ -1848,6 +1868,8 @@ CFE3F6121E84A9CE00A8204E /* CartCDF.hxx */, DC8C1BA714B25DE7006440EE /* CartCM.cxx */, DC8C1BA814B25DE7006440EE /* CartCM.hxx */, + DC857D332482F66200C7C14F /* CartCreator.cxx */, + DC857D342482F66200C7C14F /* CartCreator.hxx */, DC6727081556F4860023653B /* CartCTY.cxx */, DC6727091556F4860023653B /* CartCTY.hxx */, 2DE2DF1C0627AE07006BEC99 /* CartCV.cxx */, @@ -1902,6 +1924,8 @@ DC71EA9C1FDA06D2008827CB /* CartMNetwork.hxx */, DC0984830D3985160073C852 /* CartSB.cxx */, DC0984840D3985160073C852 /* CartSB.hxx */, + DC84397A247B294D00C6A4FC /* CartTVBoy.cxx */, + DC843979247B294D00C6A4FC /* CartTVBoy.hxx */, 2DDBEB7008457B7D00812C11 /* CartUA.cxx */, 2DDBEB7108457B7D00812C11 /* CartUA.hxx */, DCDA03AE1A2009BA00711920 /* CartWD.cxx */, @@ -2362,6 +2386,7 @@ 2D9173CF09BA90380026E9FF /* Cart3F.hxx in Headers */, DC3EE86D1E2C0E6D00905161 /* zlib.h in Headers */, E08FCD5523A037EB0051F59B /* Blitter.hxx in Headers */, + DC84397F247B297A00C6A4FC /* CartTVBoyWidget.hxx in Headers */, E034A5EF209FB25D00C89E9E /* EmulationTiming.hxx in Headers */, DC3EE86A1E2C0E6D00905161 /* trees.h in Headers */, 2D9173D009BA90380026E9FF /* Cart4K.hxx in Headers */, @@ -2563,6 +2588,7 @@ DC9EA8880F729A36000452B5 /* KidVid.hxx in Headers */, DCF7F128223D796000701A47 /* ConsoleIO.hxx in Headers */, DCF467B80F93993B00B25D7A /* SoundNull.hxx in Headers */, + DC857D362482F66200C7C14F /* CartCreator.hxx in Headers */, DCBDDE9F1D6A5F2F009DF1E9 /* Cart3EPlus.hxx in Headers */, DCF467BD0F9399F500B25D7A /* Version.hxx in Headers */, DC2B85E81EF5EF2300379EB9 /* AtariNTSC.hxx in Headers */, @@ -2696,6 +2722,7 @@ DCAACAFB188D631500A4D282 /* CartBFSC.hxx in Headers */, DCAACAFD188D631500A4D282 /* CartDF.hxx in Headers */, DCAACAFF188D631500A4D282 /* CartDFSC.hxx in Headers */, + DC84397B247B294E00C6A4FC /* CartTVBoy.hxx in Headers */, DCAACB0F188D636F00A4D282 /* Cart4KSCWidget.hxx in Headers */, DCAACB11188D636F00A4D282 /* CartBFSCWidget.hxx in Headers */, DCA82C741FEB4E780059340F /* TimeMachineDialog.hxx in Headers */, @@ -2833,6 +2860,7 @@ 2D91747D09BA90380026E9FF /* CartE0.cxx in Sources */, DCF8621921C9D43300F95F52 /* StaggeredLogger.cxx in Sources */, E0DCD3AA20A64E96000B614E /* ConvolutionBuffer.cxx in Sources */, + DC843980247B297A00C6A4FC /* CartTVBoyWidget.cxx in Sources */, 2D91747E09BA90380026E9FF /* CartE7.cxx in Sources */, DC9616321F817830008A2206 /* PointingDeviceWidget.cxx in Sources */, 2D91747F09BA90380026E9FF /* CartF4.cxx in Sources */, @@ -2893,6 +2921,7 @@ 2D9174BD09BA90380026E9FF /* Widget.cxx in Sources */, 2D9174BE09BA90380026E9FF /* CartUA.cxx in Sources */, DC3EE86E1E2C0E6D00905161 /* zutil.c in Sources */, + DC857D352482F66200C7C14F /* CartCreator.cxx in Sources */, CFE3F60B1E84A9A200A8204E /* CartBUSWidget.cxx in Sources */, DCEC58581E945125002F0246 /* DelayQueueWidget.cxx in Sources */, 2D9174BF09BA90380026E9FF /* FSNode.cxx in Sources */, @@ -3068,6 +3097,7 @@ DCDA03B01A2009BB00711920 /* CartWD.cxx in Sources */, DCC6A4B220A2622500863C59 /* SimpleResampler.cxx in Sources */, DC21E5BF21CA903E007D0E1A /* OSystemMACOS.cxx in Sources */, + DC84397C247B294E00C6A4FC /* CartTVBoy.cxx in Sources */, DCAAE5D91715887B0080BB82 /* Cart0840Widget.cxx in Sources */, DCAAE5DB1715887B0080BB82 /* CartCVWidget.cxx in Sources */, DCA233B423BAB1300032ABF3 /* Lightgun.cxx in Sources */, diff --git a/src/tools/PropSet.pm b/src/tools/PropSet.pm index 7cba557f9..0c40d7452 100755 --- a/src/tools/PropSet.pm +++ b/src/tools/PropSet.pm @@ -3,29 +3,29 @@ package PropSet; # NOTE: If the property types ever change in Stella, the following hashmap # and array must be updated (and stay in sequence) my %prop_type = ( - "Cart.MD5" => 0, - "Cart.Manufacturer" => 1, - "Cart.ModelNo" => 2, - "Cart.Name" => 3, - "Cart.Note" => 4, - "Cart.Rarity" => 5, - "Cart.Sound" => 6, - "Cart.StartBank" => 7, - "Cart.Type" => 8, - "Console.LeftDiff" => 9, - "Console.RightDiff" => 10, - "Console.TVType" => 11, - "Console.SwapPorts" => 12, - "Controller.Left" => 13, - "Controller.Right" => 14, - "Controller.SwapPaddles" => 15, + "Cart.MD5" => 0, + "Cart.Manufacturer" => 1, + "Cart.ModelNo" => 2, + "Cart.Name" => 3, + "Cart.Note" => 4, + "Cart.Rarity" => 5, + "Cart.Sound" => 6, + "Cart.StartBank" => 7, + "Cart.Type" => 8, + "Console.LeftDiff" => 9, + "Console.RightDiff" => 10, + "Console.TVType" => 11, + "Console.SwapPorts" => 12, + "Controller.Left" => 13, + "Controller.Right" => 14, + "Controller.SwapPaddles" => 15, "Controller.PaddlesXCenter" => 16, - "Controller.PaddlesYCenter" => 17, - "Controller.MouseAxis" => 18, - "Display.Format" => 19, - "Display.VCenter" => 20, - "Display.Phosphor" => 21, - "Display.PPBlend" => 22 + "Controller.PaddlesYCenter" => 17, + "Controller.MouseAxis" => 18, + "Display.Format" => 19, + "Display.VCenter" => 20, + "Display.Phosphor" => 21, + "Display.PPBlend" => 22 ); my @prop_type_as_string = ( "Cart.MD5", diff --git a/src/unix/FSNodePOSIX.cxx b/src/unix/FSNodePOSIX.cxx index 33f6b5226..f483dc899 100644 --- a/src/unix/FSNodePOSIX.cxx +++ b/src/unix/FSNodePOSIX.cxx @@ -159,7 +159,7 @@ bool FilesystemNodePOSIX::getChildren(AbstractFSList& myList, ListMode mode) con if (entry._isDirectory) entry._path += "/"; - entry._isValid = entry._isDirectory || entry._isFile; + entry._isValid = true; } #endif diff --git a/src/unix/stella.spec b/src/unix/stella.spec index 796217ea6..c54cf259a 100644 --- a/src/unix/stella.spec +++ b/src/unix/stella.spec @@ -1,5 +1,5 @@ %define name stella -%define version 6.1.2 +%define version 6.2.1 %define rel 1 %define enable_sound 1 @@ -100,6 +100,12 @@ rm -rf $RPM_BUILD_DIR/%{name}-%{version} %_datadir/icons/large/%{name}.png %changelog +* Sat Jun 20 2020 Stephen Anthony 6.2.1-1 +- Version 6.2.1 release + +* Sun Jun 7 2020 Stephen Anthony 6.2-1 +- Version 6.2 release + * Sat Apr 25 2020 Stephen Anthony 6.1.2-1 - Version 6.1.2 release diff --git a/src/windows/Stella.vcxproj b/src/windows/Stella.vcxproj index 6fef5d589..33abbe73e 100644 --- a/src/windows/Stella.vcxproj +++ b/src/windows/Stella.vcxproj @@ -662,6 +662,9 @@ true + + true + true @@ -714,6 +717,7 @@ + @@ -729,6 +733,7 @@ + @@ -1671,6 +1676,9 @@ true + + true + true @@ -1732,6 +1740,7 @@ + @@ -1747,6 +1756,7 @@ + diff --git a/src/windows/Stella.vcxproj.filters b/src/windows/Stella.vcxproj.filters index 0e4f58929..ded397f71 100644 --- a/src/windows/Stella.vcxproj.filters +++ b/src/windows/Stella.vcxproj.filters @@ -1005,6 +1005,15 @@ Source Files\gui + + Source Files\emucore + + + Source Files + + + Source Files\emucore + @@ -2063,6 +2072,15 @@ Header Files\gui + + Header Files\emucore + + + Header Files + + + Header Files\emucore + diff --git a/src/windows/stella.rc b/src/windows/stella.rc index d6fcd5ce3..0958a136d 100755 --- a/src/windows/stella.rc +++ b/src/windows/stella.rc @@ -36,8 +36,8 @@ IDI_ICON ICON "stella.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 6,1,0,0 - PRODUCTVERSION 6,1,0,0 + FILEVERSION 6,2,1,0 + PRODUCTVERSION 6,2,1,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -55,12 +55,12 @@ BEGIN VALUE "Comments", "The multi-platform Atari 2600 emulator. Stella is released under the GPLv2." VALUE "CompanyName", "The Stella Team (https://stella-emu.github.io)" VALUE "FileDescription", "Stella" - VALUE "FileVersion", "6.1" + VALUE "FileVersion", "6.2.1" VALUE "InternalName", "Stella" VALUE "LegalCopyright", "Copyright (c) 1995-2020 The Stella Team" VALUE "OriginalFilename", "Stella.exe" VALUE "ProductName", "Stella" - VALUE "ProductVersion", "6.1" + VALUE "ProductVersion", "6.2.1" END END BLOCK "VarFileInfo" diff --git a/test/roms/bankswitching/TVBoy/Super TV Boy.bin b/test/roms/bankswitching/TVBoy/Super TV Boy.bin new file mode 100644 index 000000000..bd2d29392 Binary files /dev/null and b/test/roms/bankswitching/TVBoy/Super TV Boy.bin differ diff --git a/test/roms/bankswitching/TVBoy/TV Boy (NTSC) (bad).bin b/test/roms/bankswitching/TVBoy/TV Boy (NTSC) (bad).bin new file mode 100644 index 000000000..ab1a0ec54 Binary files /dev/null and b/test/roms/bankswitching/TVBoy/TV Boy (NTSC) (bad).bin differ diff --git a/test/roms/bankswitching/TVBoy/TV Boy (PAL).bin b/test/roms/bankswitching/TVBoy/TV Boy (PAL).bin new file mode 100644 index 000000000..9af5fb68c Binary files /dev/null and b/test/roms/bankswitching/TVBoy/TV Boy (PAL).bin differ diff --git a/test/roms/bankswitching/TVBoy/TV Boy 2.bin b/test/roms/bankswitching/TVBoy/TV Boy 2.bin new file mode 100644 index 000000000..8dd5df76b Binary files /dev/null and b/test/roms/bankswitching/TVBoy/TV Boy 2.bin differ diff --git a/test/roms/bankswitching/odd_sized/An Exercise In Minimalism (V1) (1999) (Marc de Smet) (PD).a26 b/test/roms/bankswitching/odd_sized/An Exercise In Minimalism (V1) (1999) (Marc de Smet) (PD).a26 new file mode 100644 index 000000000..ebf137a09 Binary files /dev/null and b/test/roms/bankswitching/odd_sized/An Exercise In Minimalism (V1) (1999) (Marc de Smet) (PD).a26 differ