From 80b08348bec12290dbbdef8eb6ae0e520d0e8ae1 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 22 Feb 2020 19:03:21 +0100 Subject: [PATCH 001/377] define R77 paddle mapping for front ports AND OTA adapter use "Grab Mouse" to switch mouse cursor in light gun games --- src/common/PJoystickHandler.cxx | 12 ++++-------- src/emucore/FrameBuffer.cxx | 12 ++++++------ 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/common/PJoystickHandler.cxx b/src/common/PJoystickHandler.cxx index 0f7a90493..e67793078 100644 --- a/src/common/PJoystickHandler.cxx +++ b/src/common/PJoystickHandler.cxx @@ -849,19 +849,17 @@ PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultRight // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultLeftPaddlesMapping = { + {Event::PaddleZeroAnalog, JOY_CTRL_NONE, JoyAxis::X, JoyDir::ANALOG}, #if defined(RETRON77) {Event::PaddleZeroAnalog, JOY_CTRL_NONE, JoyAxis::Z, JoyDir::ANALOG}, -#else - {Event::PaddleZeroAnalog, JOY_CTRL_NONE, JoyAxis::X, JoyDir::ANALOG}, #endif // Current code does NOT allow digital and anlog events on the same axis at the same time //{Event::PaddleZeroDecrease, JOY_CTRL_NONE, JoyAxis::X, JoyDir::POS}, //{Event::PaddleZeroIncrease, JOY_CTRL_NONE, JoyAxis::X, JoyDir::NEG}, {Event::PaddleZeroFire, 0}, + {Event::PaddleOneAnalog, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::ANALOG}, #if defined(RETRON77) {Event::PaddleOneAnalog, JOY_CTRL_NONE, JoyAxis::A3, JoyDir::ANALOG}, -#else - {Event::PaddleOneAnalog, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::ANALOG}, #endif // Current code does NOT allow digital and anlog events on the same axis at the same //{Event::PaddleOneDecrease, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::POS}, @@ -871,19 +869,17 @@ PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultLeftP // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultRightPaddlesMapping = { + {Event::PaddleTwoAnalog, JOY_CTRL_NONE, JoyAxis::X, JoyDir::ANALOG}, #if defined(RETRON77) {Event::PaddleTwoAnalog, JOY_CTRL_NONE, JoyAxis::Z, JoyDir::ANALOG}, -#else - {Event::PaddleTwoAnalog, JOY_CTRL_NONE, JoyAxis::X, JoyDir::ANALOG}, #endif // Current code does NOT allow digital and anlog events on the same axis at the same //{Event::PaddleTwoDecrease, JOY_CTRL_NONE, JoyAxis::X, JoyDir::POS}, //{Event::PaddleTwoIncrease, JOY_CTRL_NONE, JoyAxis::X, JoyDir::NEG}, {Event::PaddleTwoFire, 0}, + {Event::PaddleThreeAnalog, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::ANALOG}, #if defined(RETRON77) {Event::PaddleThreeAnalog, JOY_CTRL_NONE, JoyAxis::A3, JoyDir::ANALOG}, -#else - {Event::PaddleThreeAnalog, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::ANALOG}, #endif // Current code does NOT allow digital and anlog events on the same axis at the same //{Event::PaddleThreeDecrease,JOY_CTRL_NONE, JoyAxis::Y, JoyDir::POS}, diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index a503d89b3..769fa6798 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -862,23 +862,23 @@ void FrameBuffer::setCursorState() // Show/hide cursor in UI/emulation mode based on 'cursor' setting int cursor = myOSystem.settings().getInt("cursor"); // always enable cursor in lightgun games - if (usesLightgun) - cursor |= 1; + if (usesLightgun && !myGrabMouse) + cursor |= 1; // +Emulation switch(cursor) { - case 0: + case 0: // -UI, -Emulation showCursor(false); break; case 1: - showCursor(emulation); + showCursor(emulation); //-UI, +Emulation myGrabMouse = false; // disable grab while cursor is shown in emulation break; - case 2: + case 2: // +UI, -Emulation showCursor(!emulation); break; case 3: - showCursor(true); + showCursor(true); // +UI, +Emulation myGrabMouse = false; // disable grab while cursor is shown in emulation break; } From e1f57f94aed7a4123f61ecafa298d542cb15b10c Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 23 Feb 2020 10:03:39 +0100 Subject: [PATCH 002/377] allow paddle detection for games which also support joysticks --- src/emucore/ControllerDetector.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/emucore/ControllerDetector.cxx b/src/emucore/ControllerDetector.cxx index 863721b46..023302d81 100644 --- a/src/emucore/ControllerDetector.cxx +++ b/src/emucore/ControllerDetector.cxx @@ -73,6 +73,9 @@ Controller::Type ControllerDetector::autodetectPort(const uInt8* image, size_t s type = Controller::Type::Genesis; else if(isProbablyLightGun(image, size, port)) type = Controller::Type::Lightgun; + // add check for games which support joystick and paddles, prefer paddles here + else if(usesPaddle(image, size, port, settings)) + type = Controller::Type::Paddles; } else { From a475ca34c4842b7d5e6568c4352f8f6f753e4e8d Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Wed, 26 Feb 2020 10:46:43 +0000 Subject: [PATCH 003/377] Disable QIS on the R77 when scanlines and / or TV effects are enabled. --- src/emucore/TIASurface.cxx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/emucore/TIASurface.cxx b/src/emucore/TIASurface.cxx index 46b2250c0..d0c4ffe2c 100644 --- a/src/emucore/TIASurface.cxx +++ b/src/emucore/TIASurface.cxx @@ -28,9 +28,18 @@ namespace { FrameBuffer::ScalingInterpolation interpolationModeFromSettings(const Settings& settings) { +#ifdef RETRON77 + // Witv TV / and or scanline interpolation, the image has a height of ~480px. THe R77 runs at 720p, so there + // is no benefit from QIS in y-direction. In addition, QIS on the R77 has performance issues if TV effects are + // enabled. + return settings.getBool("tia.inter") || settings.getInt("tv.filter") != 0 || settings.getInt("tv.scanlines") != 0 + ? FrameBuffer::ScalingInterpolation::blur + : FrameBuffer::ScalingInterpolation::sharp; +#else return settings.getBool("tia.inter") ? FrameBuffer::ScalingInterpolation::blur : FrameBuffer::ScalingInterpolation::sharp; +#endif } } From ba8dfda3a8bfc3a00a6499ffc6b0e90f0a759a7b Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 29 Feb 2020 10:55:50 +0100 Subject: [PATCH 004/377] add a bit more R77 help --- src/gui/R77HelpDialog.cxx | 5 ++++- src/gui/R77HelpDialog.hxx | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/gui/R77HelpDialog.cxx b/src/gui/R77HelpDialog.cxx index 617f783be..1e4601ced 100644 --- a/src/gui/R77HelpDialog.cxx +++ b/src/gui/R77HelpDialog.cxx @@ -38,7 +38,7 @@ R77HelpDialog::R77HelpDialog(OSystem& osystem, DialogContainer& parent, // Set real dimensions _w = 47 * fontWidth + HBORDER * 2; - _h = (LINES_PER_PAGE + 2) * lineHeight + 20 + _th; + _h = (LINES_PER_PAGE + 2) * lineHeight + 12 + _th; // Add Previous, Next and Close buttons xpos = HBORDER; ypos = _h - buttonHeight - 10; @@ -130,6 +130,7 @@ void R77HelpDialog::updateStrings(uInt8 page, uInt8 lines, string& title) ADD_BIND("Right", "MODE", "Page down"); ADD_BIND("Button 1", "SKILL P1", "Start selected game"); ADD_BIND("\\c2Button 2", "SKILL P2", "Open power-on options"); + ADD_BIND(" or hold Bu", "tton 1", ""); ADD_BIND("\\c2Button 4", "Color,B/W", "Open settings"); break; @@ -144,7 +145,9 @@ void R77HelpDialog::updateStrings(uInt8 page, uInt8 lines, string& title) ADD_BIND("Button 1", "SKILL P1", "Select element"); ADD_BIND("\\c2Button 2", "SKILL P2", "OK"); ADD_BIND("\\c2Button 3", "4:3,16:9", "Previous tab"); + ADD_BIND(" or Button ", "1+Left", ""); ADD_BIND("\\c2Button 4", "FRY", "Next tab"); + ADD_BIND(" or Button ", "1+Right", ""); ADD_BIND("\\c2Button 6", "\\c2-", "Cancel"); break; diff --git a/src/gui/R77HelpDialog.hxx b/src/gui/R77HelpDialog.hxx index a7b8e7fa2..731de5e65 100644 --- a/src/gui/R77HelpDialog.hxx +++ b/src/gui/R77HelpDialog.hxx @@ -41,7 +41,7 @@ class R77HelpDialog : public Dialog void loadConfig() override; private: - static constexpr uInt32 LINES_PER_PAGE = 11; + static constexpr uInt32 LINES_PER_PAGE = 13; ButtonWidget* myNextButton{nullptr}; ButtonWidget* myPrevButton{nullptr}; From 3935f9a52b961892efb4ab5eed94f6364e0fedfc Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 29 Feb 2020 15:25:28 +0100 Subject: [PATCH 005/377] add Overscan info text to R77 settings --- src/gui/StellaSettingsDialog.cxx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/gui/StellaSettingsDialog.cxx b/src/gui/StellaSettingsDialog.cxx index df3b5e0fc..fa67bf517 100644 --- a/src/gui/StellaSettingsDialog.cxx +++ b/src/gui/StellaSettingsDialog.cxx @@ -47,7 +47,7 @@ StellaSettingsDialog::StellaSettingsDialog(OSystem& osystem, DialogContainer& pa VariantList items; // Set real dimensions - setSize(35 * fontWidth + HBORDER * 2 + 3, 14 * (lineHeight + VGAP) + VGAP * 9 + 10 + _th, max_w, max_h); + setSize(35 * fontWidth + HBORDER * 2 + 3, 15 * (lineHeight + VGAP) + VGAP * 9 + 10 + _th, max_w, max_h); xpos = HBORDER; ypos = VBORDER + _th; @@ -117,15 +117,15 @@ void StellaSettingsDialog::addVideoOptions(WidgetArray& wid, int& xpos, int& ypo const GUI::Font& font) { const int VGAP = 4; + const GUI::Font& ifont = instance().frameBuffer().infoFont(); const int lineHeight = font.getLineHeight(), - fontWidth = font.getMaxCharWidth(); + fontWidth = font.getMaxCharWidth(); VariantList items; // TV effects options int swidth = font.getMaxCharWidth() * 11; // TV Mode - items.clear(); VarList::push_back(items, "Disabled", static_cast(NTSCFilter::Preset::OFF)); VarList::push_back(items, "RGB", static_cast(NTSCFilter::Preset::RGB)); VarList::push_back(items, "S-Video", static_cast(NTSCFilter::Preset::SVIDEO)); @@ -157,11 +157,14 @@ void StellaSettingsDialog::addVideoOptions(WidgetArray& wid, int& xpos, int& ypo // FS overscan myTVOverscan = new SliderWidget(this, font, xpos, ypos - 1, swidth, lineHeight, - "Overscan ", lwidth, kOverscanChanged, fontWidth * 3); + "Overscan (*) ", lwidth, kOverscanChanged, fontWidth * 3); myTVOverscan->setMinValue(0); myTVOverscan->setMaxValue(10); myTVOverscan->setTickmarkIntervals(2); wid.push_back(myTVOverscan); ypos += lineHeight + VGAP; + + new StaticTextWidget(this, ifont, xpos, ypos + 1, "(*) Change requires launcher reboot"); + ypos += ifont.getLineHeight() + VGAP; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -172,7 +175,6 @@ void StellaSettingsDialog::addGameOptions(WidgetArray& wid, int& xpos, int& ypos const GUI::Font& ifont = instance().frameBuffer().infoFont(); VariantList ctrls; - ctrls.clear(); VarList::push_back(ctrls, "Auto-detect", "AUTO"); VarList::push_back(ctrls, "Joystick", "JOYSTICK"); VarList::push_back(ctrls, "Paddles", "PADDLES"); From e4345bcc16c15265025390c552fdb548332e246e Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 29 Feb 2020 18:46:32 +0100 Subject: [PATCH 006/377] add Sadistroids to properties --- src/emucore/DefProps.hxx | 9 +++++---- src/emucore/stella.pro | 16 +++++++++++++--- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/emucore/DefProps.hxx b/src/emucore/DefProps.hxx index 6b09a99a7..b0e4f9a34 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 = 3507; +static constexpr uInt32 DEF_PROPS_SIZE = 3508; static const BSPF::array2D DefProps = {{ { "000509d1ed2b8d30a9d94be1b3b5febb", "Greg Zumwalt", "", "Jungle Jane (2003) (Greg Zumwalt) (Hack)", "Hack of Pitfall!", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -657,7 +657,7 @@ static const BSPF::array2D DefProps = {{ { "2d9e5d8d083b6367eda880e80dfdfaeb", "QDI, Mike Montana, Rich Montana - Selchow & Righter", "87", "Glib (1983) (QDI)", "AKA Video Word Game", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2d9e65959808a6098c16c82a59c9d9dc", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (1 of 3) (1982) (Starpath) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2dbc92688f9ba92a7e086d62be9df79d", "", "", "How to Draw a Playfield (1997) (Jim Crawford) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2dbdca3058035d2b40c734dcf06a86d9", "Thomas Jentzsch", "", "Asteroids DC+ (Thomas Jentzsch) (Hack)", "Uses the Joystick (left) or Steering (right) Controller", "Hack", "", "", "", "", "", "", "", "", "DRIVING", "", "58", "", "", "YES", "" }, + { "2dbdca3058035d2b40c734dcf06a86d9", "Thomas Jentzsch", "", "Asteroids DC+ (Thomas Jentzsch) (Hack)", "Uses the Joystick (left) or Driving (right) Controller", "Hack", "", "", "", "", "", "", "", "", "DRIVING", "", "58", "", "", "YES", "" }, { "2dcf9ce486393cd36ca0928cd53b96cb", "Atari - GCC, Mike Feinstein, John Allred", "CX2688, CX2688P", "Jungle Hunt (1983) (Atari) (PAL) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2de41a11c6767e54a5ee9ebaffec72af", "Gray Games & AtariAge", "", "E.T. Book Cart (PAL60)", "Charles F. Gray & Michael Rideout", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "YES", "55" }, { "2dfec1615c49501fefc02165c81955e6", "", "", "Song (05-11-2002) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, @@ -1011,7 +1011,7 @@ static const BSPF::array2D DefProps = {{ { "4799a40b6e889370b7ee55c17ba65141", "Konami", "RC 100-X 02", "Pooyan (1983) (Konami)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "47aad247cce2534fd70c412cb483c7e0", "Rainbow Vision - Suntek", "SS-010", "Mafia (1983) (Rainbow Vision) (PAL)", "AKA Gangster Alley", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "47abfb993ff14f502f88cf988092e055", "Zellers", "", "Inca Gold (Zellers)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "47aef18509051bab493589cb2619170b", "", "", "Stell-A-Sketch (Bob Colbert) (PD)", "Uses Driving, Joystick, or Amiga/Atari ST mouse Controllers", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "47aef18509051bab493589cb2619170b", "", "", "Stell-A-Sketch (Bob Colbert) (PD)", "Uses Driving, Joystick, or Amiga/Atari ST Mouse Controllers", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "47b82d47e491ac7fdb5053a88fccc832", "Atari Freak 1, Franklin Cruz", "", "Asteroid 2 (Atari Freak 1) (Hack)", "Hack of Asteroids", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "47cd61f83457a0890de381e478f5cf5f", "Imagic, Wilfredo Aguilar, Michael Becker, Rob Fulop", "720111-2A, 13205", "Fathom (1983) (Imagic) (PAL)", "AKA Scuba", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "481d20ec22e7a63e818d5ef9679d548b", "Atari", "CX26163P", "Freeway Rabbit (32 in 1) (1988) (Atari) (PAL)", "AKA Freeway", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -1262,7 +1262,7 @@ static const BSPF::array2D DefProps = {{ { "5a81ad4e184050851e63c8e16e3dac77", "Jone Yuan Telephonic Enterprise Co", "Hack", "Sky Diver (Jone Yuan) (Hack)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5a8afe5422abbfb0a342fb15afd7415f", "Atari - Bobco, Robert C. Polaro", "CX26155", "Sprint Master (1988) (Atari)", "AKA Sprint 88, Sprint 2000", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5a93265095146458df2baf2162014889", "Activision, Steve Cartwright - Ariola", "EAX-031, EAX-031-04B - 711 031-717", "Frostbite (1983) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5a9685c4d51a6c1d6a9544946d9e8dc3", "AtariAge", "", "Grandma's Revenge (AtariAge)", "Can use driving controller in right port", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5a9685c4d51a6c1d6a9544946d9e8dc3", "AtariAge", "", "Grandma's Revenge (AtariAge)", "Can use Driving Controller in right port", "", "", "", "", "", "", "", "", "", "DRIVING", "", "", "", "", "", "" }, { "5a9d188245aff829efde816fcade0b16", "CCE", "C-808", "Phantom Tank (1983) (CCE) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5acf9865a72c0ce944979f76ff9610f0", "", "", "Dodge Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5ae73916fa1da8d38ceff674fa25a78a", "CCE", "", "Barnstorming (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -1891,6 +1891,7 @@ static const BSPF::array2D DefProps = {{ { "85e48d68c8d802e3ba9d494a47d6e016", "", "", "Ship Demo (V 15) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "85e564dae5687e431955056fbda10978", "Milton Bradley Company - Renaissance Technology, Ty Roberts", "4362", "Survival Run (1983) (Milton Bradley)", "AKA Cosmic Commander", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "86128001e69ab049937f265911ce7e8a", "Apollo - Games by Apollo, Steve Stringfellow", "AP-2005", "Lochjaw (1982) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8619da7f6796cedff59e5aa20712fb4e", "Thomas Jentzsch", "", "Sadistroids (v1.2) (2003) (Thomas Jentzsch)", "Supports Driving Controller in right port", "", "", "", "", "", "", "", "", "", "DRIVING", "", "", "", "", "YES", "30" }, { "862cf669cbced78f9ed31a5d375b2ebe", "", "", "Gunfight 2600 - Flicker acceptance (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8644352b806985efde499ae6fc7b0fec", "CCE", "C-801", "Mr. Postman (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8654d7f0fb351960016e06646f639b02", "Home Vision, R.J.P.G. - Gem International Corp. - VDI", "VCS83106", "Ski Hunt (1983) (Home Vision) (PAL)", "AKA Skiiing Hunt", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, diff --git a/src/emucore/stella.pro b/src/emucore/stella.pro index f2edd993d..42d4cc186 100644 --- a/src/emucore/stella.pro +++ b/src/emucore/stella.pro @@ -3872,7 +3872,7 @@ "Cart.MD5" "2dbdca3058035d2b40c734dcf06a86d9" "Cart.Manufacturer" "Thomas Jentzsch" "Cart.Name" "Asteroids DC+ (Thomas Jentzsch) (Hack)" -"Cart.Note" "Uses the Joystick (left) or Steering (right) Controller" +"Cart.Note" "Uses the Joystick (left) or Driving (right) Controller" "Cart.Rarity" "Hack" "Controller.Right" "DRIVING" "Controller.MouseAxis" "58" @@ -6011,7 +6011,7 @@ "Cart.MD5" "47aef18509051bab493589cb2619170b" "Cart.Name" "Stell-A-Sketch (Bob Colbert) (PD)" -"Cart.Note" "Uses Driving, Joystick, or Amiga/Atari ST mouse Controllers" +"Cart.Note" "Uses Driving, Joystick, or Amiga/Atari ST Mouse Controllers" "Cart.Rarity" "New Release" "Display.Phosphor" "YES" "" @@ -7562,7 +7562,8 @@ "Cart.MD5" "5a9685c4d51a6c1d6a9544946d9e8dc3" "Cart.Manufacturer" "AtariAge" "Cart.Name" "Grandma's Revenge (AtariAge)" -"Cart.Note" "Can use driving controller in right port" +"Cart.Note" "Can use Driving Controller in right port" +"Controller.Right" "DRIVING" "" "Cart.MD5" "5a9d188245aff829efde816fcade0b16" @@ -11404,6 +11405,15 @@ "Cart.Name" "Lochjaw (1982) (Apollo)" "" +"Cart.MD5" "8619da7f6796cedff59e5aa20712fb4e" +"Cart.Manufacturer" "Thomas Jentzsch" +"Cart.Name" "Sadistroids (v1.2) (2003) (Thomas Jentzsch)" +"Cart.Note" "Supports Driving Controller in right port" +"Controller.Right" "DRIVING" +"Display.Phosphor" "YES" +"Display.PPBlend" "30" +"" + "Cart.MD5" "862cf669cbced78f9ed31a5d375b2ebe" "Cart.Name" "Gunfight 2600 - Flicker acceptance (2001) (MP)" "" From 0d6688002263cc4743338ad2017def233a3445d9 Mon Sep 17 00:00:00 2001 From: Thomas Jentzsch Date: Tue, 3 Mar 2020 11:27:15 +0100 Subject: [PATCH 007/377] allow remapping of fire button for trackball and light gun games --- src/emucore/Lightgun.cxx | 10 +++++++--- src/emucore/PointingDevice.cxx | 10 +++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/emucore/Lightgun.cxx b/src/emucore/Lightgun.cxx index 65f44cce6..1c6c82ba7 100644 --- a/src/emucore/Lightgun.cxx +++ b/src/emucore/Lightgun.cxx @@ -115,7 +115,11 @@ bool Lightgun::read(DigitalPin pin) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Lightgun::update() { - // we allow left and right mouse buttons for fire button - setPin(DigitalPin::One, myEvent.get(Event::MouseButtonLeftValue) - || myEvent.get(Event::MouseButtonRightValue)); + // Digital events (from keyboard or joystick hats & buttons) + setPin(DigitalPin::One, myEvent.get(Event::JoystickZeroFire) == 0); + + // We allow left and right mouse buttons for fire button + if(myEvent.get(Event::MouseButtonLeftValue) || + myEvent.get(Event::MouseButtonRightValue)) + setPin(DigitalPin::One, false); } diff --git a/src/emucore/PointingDevice.cxx b/src/emucore/PointingDevice.cxx index 0ee561c31..1a2c781b4 100644 --- a/src/emucore/PointingDevice.cxx +++ b/src/emucore/PointingDevice.cxx @@ -86,9 +86,13 @@ void PointingDevice::update() updateDirection(-myEvent.get(Event::MouseAxisYMove), myVCounterRemainder, myTrackBallDown, myTrackBallLinesV, myScanCountV, myFirstScanOffsetV); - // Get mouse button state - setPin(DigitalPin::Six, (myEvent.get(Event::MouseButtonLeftValue) == 0) && - (myEvent.get(Event::MouseButtonRightValue) == 0)); + // Digital events (from keyboard or joystick hats & buttons) + setPin(DigitalPin::Six, myEvent.get(Event::JoystickZeroFire) == 0); + + // We allow left and right mouse buttons for fire button + if(myEvent.get(Event::MouseButtonLeftValue) || + myEvent.get(Event::MouseButtonRightValue)) + setPin(DigitalPin::Six, false); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 9dcad59a3a0440894e7d42a6280b2ee7467d6fa9 Mon Sep 17 00:00:00 2001 From: Thomas Jentzsch Date: Tue, 3 Mar 2020 11:27:15 +0100 Subject: [PATCH 008/377] allow remapping of fire button for trackball and light gun games --- src/emucore/Lightgun.cxx | 10 +++++++--- src/emucore/PointingDevice.cxx | 10 +++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/emucore/Lightgun.cxx b/src/emucore/Lightgun.cxx index 65f44cce6..1c6c82ba7 100644 --- a/src/emucore/Lightgun.cxx +++ b/src/emucore/Lightgun.cxx @@ -115,7 +115,11 @@ bool Lightgun::read(DigitalPin pin) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Lightgun::update() { - // we allow left and right mouse buttons for fire button - setPin(DigitalPin::One, myEvent.get(Event::MouseButtonLeftValue) - || myEvent.get(Event::MouseButtonRightValue)); + // Digital events (from keyboard or joystick hats & buttons) + setPin(DigitalPin::One, myEvent.get(Event::JoystickZeroFire) == 0); + + // We allow left and right mouse buttons for fire button + if(myEvent.get(Event::MouseButtonLeftValue) || + myEvent.get(Event::MouseButtonRightValue)) + setPin(DigitalPin::One, false); } diff --git a/src/emucore/PointingDevice.cxx b/src/emucore/PointingDevice.cxx index 0ee561c31..1a2c781b4 100644 --- a/src/emucore/PointingDevice.cxx +++ b/src/emucore/PointingDevice.cxx @@ -86,9 +86,13 @@ void PointingDevice::update() updateDirection(-myEvent.get(Event::MouseAxisYMove), myVCounterRemainder, myTrackBallDown, myTrackBallLinesV, myScanCountV, myFirstScanOffsetV); - // Get mouse button state - setPin(DigitalPin::Six, (myEvent.get(Event::MouseButtonLeftValue) == 0) && - (myEvent.get(Event::MouseButtonRightValue) == 0)); + // Digital events (from keyboard or joystick hats & buttons) + setPin(DigitalPin::Six, myEvent.get(Event::JoystickZeroFire) == 0); + + // We allow left and right mouse buttons for fire button + if(myEvent.get(Event::MouseButtonLeftValue) || + myEvent.get(Event::MouseButtonRightValue)) + setPin(DigitalPin::Six, false); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 8ef869423bc31cf86e6ca1b994a6b5ade800b183 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 3 Mar 2020 19:54:45 +0100 Subject: [PATCH 009/377] update doc for Trackball and Light Gun fire button --- docs/index.html | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/docs/index.html b/docs/index.html index 47144c162..6d54cb181 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1028,6 +1028,50 @@ +

Trackball Controller (uses mouse, left port only)

+ + + + + + + + +
Left Trackball
+ + + + + + + + + +
FunctionKey
Fire ButtonSame as 'Joy0 Fire'
+
+ +

Light Gun Controller (uses mouse, left port only)

+ + + + + + + + +
Left Light Gun
+ + + + + + + + + +
FunctionKey
Fire ButtonSame as 'Joy0 Fire'
+
+

Paddle Controller digital emulation (can be remapped)

From 0622639d7c213a1684e25ef48b3ddbbcbb215a61 Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Fri, 6 Mar 2020 00:22:50 +0100 Subject: [PATCH 010/377] Update TIA surface settings after making changes in the mini settings. --- src/gui/StellaSettingsDialog.cxx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/gui/StellaSettingsDialog.cxx b/src/gui/StellaSettingsDialog.cxx index fa67bf517..26f5cbde8 100644 --- a/src/gui/StellaSettingsDialog.cxx +++ b/src/gui/StellaSettingsDialog.cxx @@ -23,6 +23,7 @@ #include "NTSCFilter.hxx" #include "PopUpWidget.hxx" #include "MessageBox.hxx" +#include "TIASurface.hxx" #include "StellaSettingsDialog.hxx" @@ -119,7 +120,7 @@ void StellaSettingsDialog::addVideoOptions(WidgetArray& wid, int& xpos, int& ypo const int VGAP = 4; const GUI::Font& ifont = instance().frameBuffer().infoFont(); const int lineHeight = font.getLineHeight(), - fontWidth = font.getMaxCharWidth(); + fontWidth = font.getMaxCharWidth(); VariantList items; // TV effects options @@ -293,8 +294,11 @@ void StellaSettingsDialog::saveConfig() instance().console().setProperties(myGameProperties); } - // Finally, issue a complete framebuffer re-initialization + // Finally, issue a complete framebuffer re-initialization... instance().createFrameBuffer(); + + // ... and apply potential setting changes to the TIA surface + instance().frameBuffer().tiaSurface().updateSurfaceSettings(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 71f4a94eea17cfd34514edaa236493557ecef402 Mon Sep 17 00:00:00 2001 From: Stephen Kitt Date: Tue, 10 Mar 2020 11:45:04 +0100 Subject: [PATCH 011/377] Handle GCC versions after 9 This simplifies the interpretation of GCC versions, and handles all versions greater than 4, hopefully for good. Fixes: #590 Signed-off-by: Stephen Kitt --- configure | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 85c81550a..4fb2cf08d 100755 --- a/configure +++ b/configure @@ -458,11 +458,17 @@ elif test "$have_gcc" = yes; then fi case $cxx_version in - 4.[7-9]|4.[7-9].[0-9]|4.[7-9].[0-9][-.]*|[5-9]|[5-9].[0-9]|[5-9].[0-9].[0-9]|[5-9].[0-9].[0-9][-.]*) + [1-9]*) _cxx_major=`echo $cxx_version | cut -d '.' -f 1` _cxx_minor=`echo $cxx_version | cut -d '.' -f 2` - cxx_version="$cxx_version, ok" - cxx_verc_fail=no + # Need at least version 4.7 + if [ $_cxx_major -ge 5 ] || [ $_cxx_major -eq 4 -a $_cxx_minor -ge 7 ]; then + cxx_version="$cxx_version, ok" + cxx_verc_fail=no + else + cxx_version="$cxx_version, bad" + cxx_verc_fail=yes + fi ;; 'not found') cxx_verc_fail=yes From b02a58e4ea853e19d9eb5708c16ecf6d1cff0918 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Wed, 11 Mar 2020 18:33:12 -0230 Subject: [PATCH 012/377] Changed 'romviewer' option to be treated as a multiplier for the zoom level of snapshots. Old settings will still work (0 means off, 1 or 2 mean 1x and 2x zoom). Floats are now supported too, so we get fractional scaling. Still TODO is update the UI to modify this setting. --- Changes.txt | 3 +- src/emucore/Settings.cxx | 3 +- src/gui/LauncherDialog.cxx | 63 +++++++++++++++++++++++++++++--------- src/gui/LauncherDialog.hxx | 3 ++ src/gui/RomInfoWidget.cxx | 13 ++++---- src/gui/RomInfoWidget.hxx | 3 +- 6 files changed, 62 insertions(+), 26 deletions(-) diff --git a/Changes.txt b/Changes.txt index 3ca8e06c5..4e001d9e3 100644 --- a/Changes.txt +++ b/Changes.txt @@ -120,7 +120,8 @@ * Added option to change pitch of Pitfall II music. * ROM Info Launcher can now display multiple lines per property and - bank switching type. + bank switching type. Related to this, added fractional (25% increments) + snapshot zooms. * In file listings, you can now select directories by holding 'Shift' on the first character entered. Entering characters in lowercase still diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index 6fee4347a..1ad12575c 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -350,8 +350,7 @@ void Settings::validate() setValue("dbg.fontsize", "medium"); i = getInt("romviewer"); - if(i < 0) setValue("romviewer", "0"); - else if(i > 2) setValue("romviewer", "2"); + if(i < 0) setValue("romviewer", "0"); i = getInt("loglevel"); if(i < int(Logger::Level::MIN) || i > int(Logger::Level::MAX)) diff --git a/src/gui/LauncherDialog.cxx b/src/gui/LauncherDialog.cxx index 047b4e4c5..b72a68c97 100644 --- a/src/gui/LauncherDialog.cxx +++ b/src/gui/LauncherDialog.cxx @@ -37,6 +37,7 @@ #include "Props.hxx" #include "PropsSet.hxx" #include "RomInfoWidget.hxx" +#include "TIAConstants.hxx" #include "Settings.hxx" #include "Widget.hxx" #include "Font.hxx" @@ -123,15 +124,11 @@ LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent, // Add list with game titles // Before we add the list, we need to know the size of the RomInfoWidget - xpos = HBORDER; ypos += lineHeight + 4; - int romWidth = 0; - int romSize = instance().settings().getInt("romviewer"); - if(romSize > 1 && w >= 1000 && h >= 720) - romWidth = 660; - else if(romSize > 0 && w >= 640 && h >= 480) - romWidth = 365; - + float imgZoom = getRomInfoZoom(); + int romWidth = imgZoom * TIAConstants::viewableWidth; + if(romWidth > 0) romWidth += 10; int listWidth = _w - (romWidth > 0 ? romWidth+8 : 0) - 20; + xpos = HBORDER; ypos += lineHeight + 4; myList = new FileListWidget(this, font, xpos, ypos, listWidth, _h - 43 - bheight - fontHeight - lineHeight); myList->setEditable(false); @@ -142,10 +139,17 @@ LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent, if(romWidth > 0) { xpos += myList->getWidth() + 8; - myRomInfoWidget = new RomInfoWidget(this, - romWidth < 660 ? instance().frameBuffer().smallFont() : - instance().frameBuffer().infoFont(), - xpos, ypos, romWidth, myList->getHeight()); + + // Initial surface size is the same as the viewable area + Common::Size imgSize(TIAConstants::viewableWidth*imgZoom, + TIAConstants::viewableHeight*imgZoom); + + // Calculate font area, and in the process the font that can be used + Common::Size fontArea(romWidth, myList->getHeight() - imgSize.h); + const GUI::Font& rominfoFont = getRomInfoFont(fontArea); + + myRomInfoWidget = new RomInfoWidget(this, rominfoFont, + xpos, ypos, romWidth, myList->getHeight(), imgSize); } // Add textfield to show current directory @@ -197,7 +201,7 @@ LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent, wid.push_back(myStartButton); #endif } - if (myUseMinimalUI) // Highlight 'Rom Listing' + if(myUseMinimalUI) // Highlight 'Rom Listing' mySelectedItem = 0; else mySelectedItem = 2; @@ -207,8 +211,7 @@ LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent, // Create (empty) context menu for ROM list options myMenu = make_unique(this, osystem.frameBuffer().font(), EmptyVarList); - - // Create global props dialog, which is used to temporarily overrride + // Create global props dialog, which is used to temporarily override // ROM properties myGlobalProps = make_unique(this, myUseMinimalUI ? osystem.frameBuffer().launcherFont() : osystem.frameBuffer().font()); @@ -325,6 +328,36 @@ void LauncherDialog::applyFiltering() ); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +float LauncherDialog::getRomInfoZoom() +{ + // The ROM info area is some multiple of the minimum TIA image size + // However, it can't exceed 70% of the total dialog width, nor less than + // the base size of the TIA image + float zoom = instance().settings().getFloat("romviewer"); + if(zoom < 1.F) + return 0.F; + else if(zoom * TIAConstants::viewableWidth > _w * 0.7F) + return (_w * 0.7F) / TIAConstants::viewableWidth; + else + return zoom; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const GUI::Font& LauncherDialog::getRomInfoFont(const Common::Size& area) +{ + // TODO: Perhaps offer a setting to override the font used? + + // Try to pick a font that works best, based on the available area + if(area.h / instance().frameBuffer().launcherFont().getLineHeight() >= 8) + return instance().frameBuffer().launcherFont(); + else if(area.h / instance().frameBuffer().infoFont().getLineHeight() >= 8 && + area.w / instance().frameBuffer().infoFont().getMaxCharWidth() >= 80) + return instance().frameBuffer().infoFont(); + else + return instance().frameBuffer().smallFont(); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LauncherDialog::loadRomInfo() { diff --git a/src/gui/LauncherDialog.hxx b/src/gui/LauncherDialog.hxx index f43a57439..598c147a5 100644 --- a/src/gui/LauncherDialog.hxx +++ b/src/gui/LauncherDialog.hxx @@ -98,6 +98,9 @@ class LauncherDialog : public Dialog void updateUI(); void applyFiltering(); + float getRomInfoZoom(); + const GUI::Font& getRomInfoFont(const Common::Size& area); + void loadRom(); void loadRomInfo(); void handleContextMenu(); diff --git a/src/gui/RomInfoWidget.cxx b/src/gui/RomInfoWidget.cxx index a5278876f..e72eabb59 100644 --- a/src/gui/RomInfoWidget.cxx +++ b/src/gui/RomInfoWidget.cxx @@ -29,16 +29,14 @@ #include "PNGLibrary.hxx" #include "Rect.hxx" #include "Widget.hxx" -#include "TIAConstants.hxx" #include "RomInfoWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RomInfoWidget::RomInfoWidget(GuiObject* boss, const GUI::Font& font, - int x, int y, int w, int h) + int x, int y, int w, int h, + const Common::Size& imgSize) : Widget(boss, font, x, y, w, h), - myAvail(w > 400 ? - Common::Size(TIAConstants::viewableWidth*2, TIAConstants::viewableHeight*2) : - Common::Size(TIAConstants::viewableWidth, TIAConstants::viewableHeight)) + myAvail(imgSize) { _flags = Widget::FLAG_ENABLED; _bgcolor = kDlgColor; @@ -87,7 +85,7 @@ void RomInfoWidget::parseProperties(const FilesystemNode& node) if(mySurface == nullptr) { mySurface = instance().frameBuffer().allocateSurface( - TIAConstants::viewableWidth*2, TIAConstants::viewableHeight*2, FrameBuffer::ScalingInterpolation::blur); + myAvail.w, myAvail.h, FrameBuffer::ScalingInterpolation::blur); mySurface->applyAttributes(); dialog().addSurface(mySurface); @@ -205,11 +203,12 @@ void RomInfoWidget::drawWidget(bool hilite) s.drawString(font, mySurfaceErrorMsg, x, y, _w - 10, onTop ? _textcolor : _shadowcolor); } - int xpos = _x + 8, ypos = _y + yoff + 10; + int xpos = _x + 8, ypos = _y + yoff + 5; for(const auto& info: myRomInfo) { int lines = s.drawString(_font, info, xpos, ypos, _w - 16, _font.getFontHeight() * 3, onTop ? _textcolor : _shadowcolor); + if(ypos >= _h) break; ypos += _font.getLineHeight() + (lines - 1) * _font.getFontHeight(); } } diff --git a/src/gui/RomInfoWidget.hxx b/src/gui/RomInfoWidget.hxx index 9ae045ac6..e1a964263 100644 --- a/src/gui/RomInfoWidget.hxx +++ b/src/gui/RomInfoWidget.hxx @@ -31,7 +31,8 @@ class RomInfoWidget : public Widget { public: RomInfoWidget(GuiObject *boss, const GUI::Font& font, - int x, int y, int w, int h); + int x, int y, int w, int h, + const Common::Size& imgSize); virtual ~RomInfoWidget() = default; void setProperties(const Properties& props, const FilesystemNode& node); From 83f34f14e39c73b26cd217435734cf85f5fbe321 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 12 Mar 2020 17:01:45 +0100 Subject: [PATCH 013/377] UI now allows to select ROM info width as 0..100% (the actual limits and ROM info fonts are determined when the launcher is created) --- src/gui/LauncherDialog.cxx | 53 +++++++++++++------ src/gui/LauncherDialog.hxx | 8 ++- src/gui/RomInfoWidget.cxx | 7 ++- src/gui/UIDialog.cxx | 105 +++++++++++++++++++++++++------------ src/gui/UIDialog.hxx | 4 +- 5 files changed, 118 insertions(+), 59 deletions(-) diff --git a/src/gui/LauncherDialog.cxx b/src/gui/LauncherDialog.cxx index b72a68c97..6f603802f 100644 --- a/src/gui/LauncherDialog.cxx +++ b/src/gui/LauncherDialog.cxx @@ -124,13 +124,13 @@ LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent, // Add list with game titles // Before we add the list, we need to know the size of the RomInfoWidget - float imgZoom = getRomInfoZoom(); + int listHeight = _h - 43 - bheight - fontHeight - lineHeight; + float imgZoom = getRomInfoZoom(listHeight); int romWidth = imgZoom * TIAConstants::viewableWidth; if(romWidth > 0) romWidth += 10; int listWidth = _w - (romWidth > 0 ? romWidth+8 : 0) - 20; xpos = HBORDER; ypos += lineHeight + 4; - myList = new FileListWidget(this, font, xpos, ypos, - listWidth, _h - 43 - bheight - fontHeight - lineHeight); + myList = new FileListWidget(this, font, xpos, ypos, listWidth, listHeight); myList->setEditable(false); myList->setListMode(FilesystemNode::ListMode::All); wid.push_back(myList); @@ -145,7 +145,7 @@ LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent, TIAConstants::viewableHeight*imgZoom); // Calculate font area, and in the process the font that can be used - Common::Size fontArea(romWidth, myList->getHeight() - imgSize.h); + Common::Size fontArea(romWidth - 16, myList->getHeight() - imgSize.h - 16); const GUI::Font& rominfoFont = getRomInfoFont(fontArea); myRomInfoWidget = new RomInfoWidget(this, rominfoFont, @@ -329,30 +329,49 @@ void LauncherDialog::applyFiltering() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -float LauncherDialog::getRomInfoZoom() +float LauncherDialog::getRomInfoZoom(int listHeight) const { // The ROM info area is some multiple of the minimum TIA image size - // However, it can't exceed 70% of the total dialog width, nor less than - // the base size of the TIA image float zoom = instance().settings().getFloat("romviewer"); - if(zoom < 1.F) - return 0.F; - else if(zoom * TIAConstants::viewableWidth > _w * 0.7F) - return (_w * 0.7F) / TIAConstants::viewableWidth; - else - return zoom; + + if(zoom > 0.F) + { + // upper zoom limit - at least 24 launchers chars/line and 8 ROM info lines + if((_w - 58 - zoom * TIAConstants::viewableWidth) + / instance().frameBuffer().launcherFont().getMaxCharWidth() < MIN_LAUNCHER_CHARS) + { + zoom = float(_w - 58 - MIN_LAUNCHER_CHARS * instance().frameBuffer().launcherFont().getMaxCharWidth()) + / TIAConstants::viewableWidth; + } + if((listHeight - 20 - zoom * TIAConstants::viewableHeight) + / instance().frameBuffer().smallFont().getLineHeight() < MIN_ROMINFO_LINES) + { + zoom = float(listHeight - 20 - MIN_ROMINFO_LINES * instance().frameBuffer().smallFont().getLineHeight()) + / TIAConstants::viewableHeight; + } + + // lower zoom limit - at least 24 ROM info chars/line + if((zoom * TIAConstants::viewableWidth) + / instance().frameBuffer().smallFont().getMaxCharWidth() < MIN_ROMINFO_CHARS + 6) + { + zoom = float(MIN_ROMINFO_CHARS * instance().frameBuffer().smallFont().getMaxCharWidth() + 6) + / TIAConstants::viewableWidth; + } + } + return zoom; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const GUI::Font& LauncherDialog::getRomInfoFont(const Common::Size& area) +const GUI::Font& LauncherDialog::getRomInfoFont(const Common::Size& area) const { // TODO: Perhaps offer a setting to override the font used? // Try to pick a font that works best, based on the available area - if(area.h / instance().frameBuffer().launcherFont().getLineHeight() >= 8) + if(area.h / instance().frameBuffer().launcherFont().getLineHeight() >= MIN_ROMINFO_LINES && + area.w/ instance().frameBuffer().launcherFont().getMaxCharWidth() >= MIN_ROMINFO_CHARS) return instance().frameBuffer().launcherFont(); - else if(area.h / instance().frameBuffer().infoFont().getLineHeight() >= 8 && - area.w / instance().frameBuffer().infoFont().getMaxCharWidth() >= 80) + else if(area.h / instance().frameBuffer().infoFont().getLineHeight() >= MIN_ROMINFO_LINES && + area.w / instance().frameBuffer().infoFont().getMaxCharWidth() >= MIN_ROMINFO_CHARS) return instance().frameBuffer().infoFont(); else return instance().frameBuffer().smallFont(); diff --git a/src/gui/LauncherDialog.hxx b/src/gui/LauncherDialog.hxx index 598c147a5..942b20f4e 100644 --- a/src/gui/LauncherDialog.hxx +++ b/src/gui/LauncherDialog.hxx @@ -86,6 +86,10 @@ class LauncherDialog : public Dialog void reload(); private: + static constexpr int MIN_LAUNCHER_CHARS = 24; + static constexpr int MIN_ROMINFO_CHARS = 24; + static constexpr int MIN_ROMINFO_LINES = 8; + void center() override { positionAt(0); } void handleKeyDown(StellaKey key, StellaMod mod, bool repeated) override; void handleMouseDown(int x, int y, MouseButton b, int clickCount) override; @@ -98,8 +102,8 @@ class LauncherDialog : public Dialog void updateUI(); void applyFiltering(); - float getRomInfoZoom(); - const GUI::Font& getRomInfoFont(const Common::Size& area); + float getRomInfoZoom(int listHeight) const; + const GUI::Font& getRomInfoFont(const Common::Size& area) const; void loadRom(); void loadRomInfo(); diff --git a/src/gui/RomInfoWidget.cxx b/src/gui/RomInfoWidget.cxx index e72eabb59..752876735 100644 --- a/src/gui/RomInfoWidget.cxx +++ b/src/gui/RomInfoWidget.cxx @@ -197,10 +197,9 @@ void RomInfoWidget::drawWidget(bool hilite) } else if(mySurfaceErrorMsg != "") { - const GUI::Font& font = instance().frameBuffer().font(); - uInt32 x = _x + ((_w - font.getStringWidth(mySurfaceErrorMsg)) >> 1); - uInt32 y = _y + ((yoff - font.getLineHeight()) >> 1); - s.drawString(font, mySurfaceErrorMsg, x, y, _w - 10, onTop ? _textcolor : _shadowcolor); + uInt32 x = _x + ((_w - _font.getStringWidth(mySurfaceErrorMsg)) >> 1); + uInt32 y = _y + ((yoff - _font.getLineHeight()) >> 1); + s.drawString(_font, mySurfaceErrorMsg, x, y, _w - 10, onTop ? _textcolor : _shadowcolor); } int xpos = _x + 8, ypos = _y + yoff + 5; diff --git a/src/gui/UIDialog.cxx b/src/gui/UIDialog.cxx index 0d601f168..b32675993 100644 --- a/src/gui/UIDialog.cxx +++ b/src/gui/UIDialog.cxx @@ -194,7 +194,7 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, // Launcher width and height myLauncherWidthSlider = new SliderWidget(myTab, font, xpos, ypos, "Launcher width ", - lwidth, kLauncherSize, 6 * fontWidth, "px"); + lwidth, 0, 6 * fontWidth, "px"); myLauncherWidthSlider->setMinValue(FBMinimum::Width); myLauncherWidthSlider->setMaxValue(ds.w); myLauncherWidthSlider->setStepValue(10); @@ -204,7 +204,7 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, ypos += lineHeight + V_GAP; myLauncherHeightSlider = new SliderWidget(myTab, font, xpos, ypos, "Launcher height ", - lwidth, kLauncherSize, 6 * fontWidth, "px"); + lwidth, 0, 6 * fontWidth, "px"); myLauncherHeightSlider->setMinValue(FBMinimum::Height); myLauncherHeightSlider->setMaxValue(ds.h); myLauncherHeightSlider->setStepValue(10); @@ -226,14 +226,15 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, ypos += lineHeight + V_GAP * 4; // ROM launcher info/snapshot viewer - items.clear(); - VarList::push_back(items, "Off", "0"); - VarList::push_back(items, "1x (640x480) ", "1"); - VarList::push_back(items, "2x (1000x760)", "2"); - myRomViewerPopup = - new PopUpWidget(myTab, font, xpos, ypos + 1, pwidth, lineHeight, items, - "ROM info viewer ", lwidth, kRomViewer); - wid.push_back(myRomViewerPopup); + myRomViewerSize = new SliderWidget(myTab, font, xpos, ypos, "ROM info width ", + lwidth, kRomViewer, 6 * fontWidth, "% "); + myRomViewerSize->setMinValue(0); + myRomViewerSize->setMaxValue(100); + myRomViewerSize->setStepValue(2); + // set tickmarks every ~20% + myRomViewerSize->setTickmarkIntervals((myRomViewerSize->getMaxValue() - myRomViewerSize->getMinValue()) / 20); + + wid.push_back(myRomViewerSize); ypos += lineHeight + V_GAP; // Snapshot path (load files) @@ -309,8 +310,9 @@ void UIDialog::loadConfig() myLauncherFontPopup->setSelected(font, "medium"); // ROM launcher info viewer - const string& viewer = settings.getString("romviewer"); - myRomViewerPopup->setSelected(viewer, "0"); + float zoom = instance().settings().getFloat("romviewer"); + int percentage = zoom * TIAConstants::viewableWidth * 100 / w; + myRomViewerSize->setValue(percentage); // ROM launcher info viewer image path mySnapLoadPath->setText(settings.getString("snaploaddir")); @@ -383,8 +385,9 @@ void UIDialog::saveConfig() myLauncherFontPopup->getSelectedTag().toString()); // ROM launcher info viewer - settings.setValue("romviewer", - myRomViewerPopup->getSelectedTag().toString()); + int w = myLauncherWidthSlider->getValue(); + float zoom = myRomViewerSize->getValue() * w / 100.F / TIAConstants::viewableWidth; + settings.setValue("romviewer", zoom); // ROM launcher info viewer image path settings.setValue("snaploaddir", mySnapLoadPath->getText()); @@ -456,7 +459,7 @@ void UIDialog::setDefaults() myLauncherWidthSlider->setValue(w); myLauncherHeightSlider->setValue(h); myLauncherFontPopup->setSelected("medium", ""); - myRomViewerPopup->setSelected("1", ""); + myRomViewerSize->setValue(50); mySnapLoadPath->setText(instance().defaultLoadDir()); myLauncherExitWidget->setState(false); break; @@ -530,7 +533,6 @@ void UIDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) myRomPath->setText(myBrowser->getResult().getShortPath()); break; - case kLauncherSize: case kRomViewer: handleRomViewer(); break; @@ -553,30 +555,65 @@ void UIDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) } } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +/*void UIDialog::handleLauncherSize() +// an attempt to limit the minimal and maximal ROM info percentages +// whiche became too complex +{ + string launcherFont = myLauncherFontPopup->getSelectedTag().toString(); + int fwidth, fheight; + if(launcherFont == "small") + { + fwidth = GUI::consoleDesc.maxwidth; + fheight = GUI::consoleDesc.height; + } + else if(launcherFont == "medium") + { + fwidth = GUI::stellaMediumDesc.maxwidth; + fheight = GUI::stellaMediumDesc.height; + } + else + { + fwidth = GUI::stellaLargeDesc.maxwidth; + fheight = GUI::stellaLargeDesc.height; + } + int minInfoWidth = instance().frameBuffer().smallFont().getMaxCharWidth() * 20 + 16; + int minInfoHeight = instance().frameBuffer().smallFont().getLineHeight() * 8 + 16; + int minLauncherWidth = fwidth * 20 + 64; + int w = myLauncherWidthSlider->getValue(); + int h = myLauncherHeightSlider->getValue(); + int size = std::max(minInfoWidth * 100.F / w, minInfoHeight * 100.F / h); + + myRomViewerSize->setMinValue(size); + myRomViewerSize->setMaxValue(100 - minLauncherWidth * 100.F / w); + // set tickmarks every ~10% + myRomViewerSize->setTickmarkIntervals((myRomViewerSize->getMaxValue() - myRomViewerSize->getMinValue()) / 10); + + size = myRomViewerSize->getValue(); + size = std::max(size, myRomViewerSize->getMinValue()); + size = std::min(size, myRomViewerSize->getMaxValue()); + + myRomViewerSize->setValue(size); +}*/ + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void UIDialog::handleRomViewer() { - int size = myRomViewerPopup->getSelected(); - bool enable = myRomViewerPopup->getSelectedName() != "Off"; - VariantList items; + int size = myRomViewerSize->getValue(); + bool enable = size > myRomViewerSize->getMinValue(); + if(enable) + { + myRomViewerSize->setValueLabel(size); + myRomViewerSize->setValueUnit("%"); + } + else + { + myRomViewerSize->setValueLabel("Off"); + myRomViewerSize->setValueUnit(""); + } myOpenBrowserButton->setEnabled(enable); mySnapLoadPath->setEnabled(enable); - - items.clear(); - VarList::push_back(items, "Off", "0"); - VarList::push_back(items, "1x (640x480) ", "1"); - if(myLauncherWidthSlider->getValue() >= 1000 && - myLauncherHeightSlider->getValue() >= 760) - { - VarList::push_back(items, "2x (1000x760)", "2"); - } - else if (size == 2) - { - myRomViewerPopup->setSelected(1); - } - - myRomViewerPopup->addItems(items); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/gui/UIDialog.hxx b/src/gui/UIDialog.hxx index 9774c2290..ff41c7702 100644 --- a/src/gui/UIDialog.hxx +++ b/src/gui/UIDialog.hxx @@ -33,6 +33,7 @@ class UIDialog : public Dialog, public CommandSender void setDefaults() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; + //void handleLauncherSize(); void handleRomViewer(); void createBrowser(const string& title); @@ -43,7 +44,6 @@ class UIDialog : public Dialog, public CommandSender kMouseWheel = 'UIMw', kControllerDelay = 'UIcd', kChooseRomDirCmd = 'LOrm', // rom select - kLauncherSize = 'UIls', kRomViewer = 'UIRv', kChooseSnapLoadDirCmd = 'UIsl', // snapshot dir (load files) kSnapLoadDirChosenCmd = 'UIsc' // snap chosen (load files) @@ -57,7 +57,7 @@ class UIDialog : public Dialog, public CommandSender SliderWidget* myLauncherWidthSlider{nullptr}; SliderWidget* myLauncherHeightSlider{nullptr}; PopUpWidget* myLauncherFontPopup{nullptr}; - PopUpWidget* myRomViewerPopup{nullptr}; + SliderWidget* myRomViewerSize{nullptr}; ButtonWidget* myOpenBrowserButton{nullptr}; EditTextWidget* mySnapLoadPath{nullptr}; CheckboxWidget* myLauncherExitWidget{nullptr}; From d5da21ed24d87fca26d1f702df32077cc834694d Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 12 Mar 2020 17:11:50 +0100 Subject: [PATCH 014/377] aligned ROM viewer's UI default to Settings.cxx default --- src/gui/UIDialog.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/UIDialog.cxx b/src/gui/UIDialog.cxx index b32675993..083bb7636 100644 --- a/src/gui/UIDialog.cxx +++ b/src/gui/UIDialog.cxx @@ -459,7 +459,7 @@ void UIDialog::setDefaults() myLauncherWidthSlider->setValue(w); myLauncherHeightSlider->setValue(h); myLauncherFontPopup->setSelected("medium", ""); - myRomViewerSize->setValue(50); + myRomViewerSize->setValue(35); mySnapLoadPath->setText(instance().defaultLoadDir()); myLauncherExitWidget->setState(false); break; From 25ffced003b382262248f09fbcd694bbaebd3b73 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 14 Mar 2020 09:55:58 +0100 Subject: [PATCH 015/377] refine ROM viewer font size calculation define zoom factor for R77 --- src/gui/LauncherDialog.cxx | 21 +++++++++++++-------- src/gui/LauncherDialog.hxx | 3 ++- src/unix/r77/SettingsR77.cxx | 2 +- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/gui/LauncherDialog.cxx b/src/gui/LauncherDialog.cxx index 6f603802f..d57892f38 100644 --- a/src/gui/LauncherDialog.cxx +++ b/src/gui/LauncherDialog.cxx @@ -145,7 +145,7 @@ LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent, TIAConstants::viewableHeight*imgZoom); // Calculate font area, and in the process the font that can be used - Common::Size fontArea(romWidth - 16, myList->getHeight() - imgSize.h - 16); + Common::Size fontArea(romWidth - 16, myList->getHeight() - imgSize.h - 12); const GUI::Font& rominfoFont = getRomInfoFont(fontArea); myRomInfoWidget = new RomInfoWidget(this, rominfoFont, @@ -343,10 +343,13 @@ float LauncherDialog::getRomInfoZoom(int listHeight) const zoom = float(_w - 58 - MIN_LAUNCHER_CHARS * instance().frameBuffer().launcherFont().getMaxCharWidth()) / TIAConstants::viewableWidth; } - if((listHeight - 20 - zoom * TIAConstants::viewableHeight) - / instance().frameBuffer().smallFont().getLineHeight() < MIN_ROMINFO_LINES) + if((listHeight - 12 - zoom * TIAConstants::viewableHeight) < + MIN_ROMINFO_ROWS * instance().frameBuffer().smallFont().getLineHeight() + + MIN_ROMINFO_LINES * instance().frameBuffer().smallFont().getFontHeight()) { - zoom = float(listHeight - 20 - MIN_ROMINFO_LINES * instance().frameBuffer().smallFont().getLineHeight()) + zoom = float(listHeight - 12 - + MIN_ROMINFO_ROWS * instance().frameBuffer().smallFont().getLineHeight() - + MIN_ROMINFO_LINES * instance().frameBuffer().smallFont().getFontHeight()) / TIAConstants::viewableHeight; } @@ -367,11 +370,13 @@ const GUI::Font& LauncherDialog::getRomInfoFont(const Common::Size& area) const // TODO: Perhaps offer a setting to override the font used? // Try to pick a font that works best, based on the available area - if(area.h / instance().frameBuffer().launcherFont().getLineHeight() >= MIN_ROMINFO_LINES && - area.w/ instance().frameBuffer().launcherFont().getMaxCharWidth() >= MIN_ROMINFO_CHARS) + if(area.h >= uInt32(MIN_ROMINFO_ROWS * instance().frameBuffer().launcherFont().getLineHeight() + + MIN_ROMINFO_LINES * instance().frameBuffer().launcherFont().getFontHeight()) + && area.w >= uInt32(MIN_ROMINFO_CHARS * instance().frameBuffer().launcherFont().getMaxCharWidth())) return instance().frameBuffer().launcherFont(); - else if(area.h / instance().frameBuffer().infoFont().getLineHeight() >= MIN_ROMINFO_LINES && - area.w / instance().frameBuffer().infoFont().getMaxCharWidth() >= MIN_ROMINFO_CHARS) + else if(area.h >= uInt32(MIN_ROMINFO_ROWS * instance().frameBuffer().infoFont().getLineHeight() + + MIN_ROMINFO_LINES * instance().frameBuffer().infoFont().getFontHeight()) + && area.w >= uInt32(MIN_ROMINFO_CHARS * instance().frameBuffer().infoFont().getMaxCharWidth())) return instance().frameBuffer().infoFont(); else return instance().frameBuffer().smallFont(); diff --git a/src/gui/LauncherDialog.hxx b/src/gui/LauncherDialog.hxx index 942b20f4e..dc1ce321c 100644 --- a/src/gui/LauncherDialog.hxx +++ b/src/gui/LauncherDialog.hxx @@ -88,7 +88,8 @@ class LauncherDialog : public Dialog private: static constexpr int MIN_LAUNCHER_CHARS = 24; static constexpr int MIN_ROMINFO_CHARS = 24; - static constexpr int MIN_ROMINFO_LINES = 8; + static constexpr int MIN_ROMINFO_ROWS = 7; // full lines + static constexpr int MIN_ROMINFO_LINES = 2; // extra lines void center() override { positionAt(0); } void handleKeyDown(StellaKey key, StellaMod mod, bool repeated) override; diff --git a/src/unix/r77/SettingsR77.cxx b/src/unix/r77/SettingsR77.cxx index ba8ce6858..c3f0d61fd 100644 --- a/src/unix/r77/SettingsR77.cxx +++ b/src/unix/r77/SettingsR77.cxx @@ -51,7 +51,7 @@ SettingsR77::SettingsR77() setPermanent("launcherres", "1280x720"); setPermanent("launcherfont", "large"); - setPermanent("romviewer", "2"); + setPermanent("romviewer", "1.6"); setPermanent("exitlauncher", "true"); setTemporary("minimal_ui", true); From 934cc11a77fd16a2bf2b930f3d722115188f86c7 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 14 Mar 2020 11:14:24 +0100 Subject: [PATCH 016/377] replace launcher's small font with bold version add 'small medium' font to launcher font options doc update for variable ROM viewer widths and new launcher font size --- Changes.txt | 7 ++++--- docs/graphics/options_ui.png | Bin 6207 -> 3363 bytes docs/index.html | 35 +++++++++++++++-------------------- src/emucore/FrameBuffer.cxx | 14 +++++++++----- src/emucore/Settings.cxx | 8 ++++---- src/gui/UIDialog.cxx | 1 + 6 files changed, 33 insertions(+), 32 deletions(-) diff --git a/Changes.txt b/Changes.txt index 4e001d9e3..056572a76 100644 --- a/Changes.txt +++ b/Changes.txt @@ -119,9 +119,10 @@ * Added option to change pitch of Pitfall II music. - * ROM Info Launcher can now display multiple lines per property and - bank switching type. Related to this, added fractional (25% increments) - snapshot zooms. + * ROM Info Viewer size is not limited to fixed zoom steps anymore. + + * ROM Info Viewer can now display multiple lines per property and the + bank switching type. * In file listings, you can now select directories by holding 'Shift' on the first character entered. Entering characters in lowercase still diff --git a/docs/graphics/options_ui.png b/docs/graphics/options_ui.png index 14a6e33afd033d90ee516f74be3b92f2dd9837f5..322527cb3b1b18c5243fe9d57922f8373479749c 100644 GIT binary patch literal 3363 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 Ul#q-``}SlpHaMzZtm_!_A4m^S{{R30 literal 6207 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 A%K!iX diff --git a/docs/index.html b/docs/index.html index 6d54cb181..93779088a 100644 --- a/docs/index.html +++ b/docs/index.html @@ -2371,7 +2371,7 @@ - + @@ -2382,9 +2382,10 @@ - - + + @@ -3079,8 +3080,8 @@ launcher and fonts, as well as the 'ROM Info Viewer' can be changed in UI Settings - Launcher dialog, as shown below:

-

Most of the options are self-explanatory, except for the 'ROM Info - viewer', which is described below.

+

Most of the options are self-explanatory, except for the 'ROM info + width', which is described below.

ROM Info Viewer

@@ -3092,27 +3093,21 @@ for each new release of Stella. Note that the snapshots can be any size generated by Stella; they will be resized accordingly.

-

Currently, there are several restrictions for this feature:

-
    -
  1. The ROM Info Viewer can be shown in 1x or 2x mode only.
  2. -
  3. To view snapshots in 1x mode, the ROM launcher window must be sized at - least 640x480. If the launcher isn't large enough, the functionality - will be disabled.
  4. -
  5. To view snapshots in 2x mode, the ROM launcher window must be sized at - least 1000x720. If the launcher isn't large enough, an attempt will - be made to use 1x mode.
  6. -
+ The ROM Info Viewer's width can be defined between 0% (off) and 100%. The + value is relative to the launcher width. For too small or too large values, + Stella will automatically correct the width at runtime so that the ROM names + and the current ROM's information always have enough space.

The following snapshots illustrate the various font sizes and rom info - zoom levels:

+ widths:

-

ROM Info Viewer in 1x mode, UI sized 800x480, small launcher font:

+

ROM Info Viewer width at 40%, UI sized 800x480, small launcher font:

-

ROM Info Viewer in 1x mode, UI sized 1000x720, medium launcher font:

+

ROM Info Viewer width at 32%, UI sized 1000x720, medium launcher font:

-

ROM Info Viewer in 2x mode, UI sized 1280x900, large launcher font:

+

ROM Info Viewer width at 50% , UI sized 1280x900, large launcher font:

The text box in the upper right corner can be used to narrow down the diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 769fa6798..c3789f0ed 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -36,9 +36,11 @@ #ifdef GUI_SUPPORT #include "Font.hxx" #include "StellaFont.hxx" + #include "ConsoleMediumBFont.hxx" #include "StellaMediumFont.hxx" #include "StellaLargeFont.hxx" #include "ConsoleFont.hxx" + #include "ConsoleBFont.hxx" #include "Launcher.hxx" #include "Menu.hxx" #include "CommandMenu.hxx" @@ -106,7 +108,7 @@ bool FrameBuffer::initialize() // This font is used in a variety of situations when a really small // font is needed; we let the specific widget/dialog decide when to // use it - mySmallFont = make_unique(GUI::stellaDesc); + mySmallFont = make_unique(GUI::stellaDesc); // 6x10 // The general font used in all UI elements // This is determined by the size of the framebuffer @@ -117,16 +119,18 @@ bool FrameBuffer::initialize() // The info font used in all UI elements // This is determined by the size of the framebuffer - myInfoFont = make_unique(GUI::consoleDesc); + myInfoFont = make_unique(GUI::consoleDesc); // 8x13 // The font used by the ROM launcher const string& lf = myOSystem.settings().getString("launcherfont"); if(lf == "small") - myLauncherFont = make_unique(GUI::consoleDesc); + myLauncherFont = make_unique(GUI::consoleBDesc); // 8x13 + else if(lf == "small medium") + myLauncherFont = make_unique(GUI::consoleMediumBDesc); // 9x15 else if(lf == "medium") - myLauncherFont = make_unique(GUI::stellaMediumDesc); + myLauncherFont = make_unique(GUI::stellaMediumDesc); // 9x18 else - myLauncherFont = make_unique(GUI::stellaLargeDesc); + myLauncherFont = make_unique(GUI::stellaLargeDesc); // 10x20 #endif // Determine possible TIA windowed zoom levels diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index 1ad12575c..00bb983fd 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -342,7 +342,7 @@ void Settings::validate() setValue("palette", "standard"); s = getString("launcherfont"); - if(s != "small" && s != "medium" && s != "large") + if(s != "small" && s != "small medium" && s != "medium" && s != "large") setValue("launcherfont", "medium"); s = getString("dbg.fontsize"); @@ -478,10 +478,10 @@ void Settings::usage() const << " -exitlauncher <1|0> On exiting a ROM, go back to the ROM launcher\n" << " -launcherres The resolution to use in ROM launcher mode\n" << " -launcherfont \n" + << " small medium|large>\n" << " -launcherroms <1|0> Show only ROMs in the launcher (vs. all files)\n" - << " -romviewer <0|1|2> Show ROM info viewer at given zoom level in ROM\n" - << " launcher (0 for off)\n" + << " -romviewer Show ROM info viewer at given zoom level in ROM\n" + << " launcher (use 0 for off)\n" << " -lastrom Last played ROM, automatically selected in launcher\n" << " -romloadcount Number of ROM to load next from multicard\n" << " -uipalette Date: Sat, 14 Mar 2020 13:52:37 +0100 Subject: [PATCH 017/377] replace launcher font value "small medium" with "small_medium" --- docs/index.html | 2 +- src/emucore/FrameBuffer.cxx | 2 +- src/emucore/Settings.cxx | 4 ++-- src/gui/UIDialog.cxx | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/index.html b/docs/index.html index 93779088a..2f750bde9 100644 --- a/docs/index.html +++ b/docs/index.html @@ -2371,7 +2371,7 @@

- + diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index c3789f0ed..d75179f86 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -125,7 +125,7 @@ bool FrameBuffer::initialize() const string& lf = myOSystem.settings().getString("launcherfont"); if(lf == "small") myLauncherFont = make_unique(GUI::consoleBDesc); // 8x13 - else if(lf == "small medium") + else if(lf == "small_medium") myLauncherFont = make_unique(GUI::consoleMediumBDesc); // 9x15 else if(lf == "medium") myLauncherFont = make_unique(GUI::stellaMediumDesc); // 9x18 diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index 00bb983fd..7588ccfdc 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -342,7 +342,7 @@ void Settings::validate() setValue("palette", "standard"); s = getString("launcherfont"); - if(s != "small" && s != "small medium" && s != "medium" && s != "large") + if(s != "small" && s != "small_medium" && s != "medium" && s != "large") setValue("launcherfont", "medium"); s = getString("dbg.fontsize"); @@ -478,7 +478,7 @@ void Settings::usage() const << " -exitlauncher <1|0> On exiting a ROM, go back to the ROM launcher\n" << " -launcherres The resolution to use in ROM launcher mode\n" << " -launcherfont \n" + << " small_medium|large>\n" << " -launcherroms <1|0> Show only ROMs in the launcher (vs. all files)\n" << " -romviewer Show ROM info viewer at given zoom level in ROM\n" << " launcher (use 0 for off)\n" diff --git a/src/gui/UIDialog.cxx b/src/gui/UIDialog.cxx index 1b2cb58e6..287659912 100644 --- a/src/gui/UIDialog.cxx +++ b/src/gui/UIDialog.cxx @@ -217,7 +217,7 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, pwidth = font.getStringWidth("2x (1000x760)"); items.clear(); VarList::push_back(items, "Small", "small"); - VarList::push_back(items, "Small Medium", "small medium"); + VarList::push_back(items, "Small Medium", "small_medium"); VarList::push_back(items, "Medium", "medium"); VarList::push_back(items, "Large", "large"); myLauncherFontPopup = From 1aaea36d2534fabeed7f40374810b1c28f85e7aa Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 14 Mar 2020 23:29:58 +0100 Subject: [PATCH 018/377] add one more intermediate font option to ROM info viewer --- src/emucore/FrameBuffer.cxx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index d75179f86..1cd41c646 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -39,6 +39,10 @@ #include "ConsoleMediumBFont.hxx" #include "StellaMediumFont.hxx" #include "StellaLargeFont.hxx" + #include "Stella12x24Font.hxx" + #include "Stella12x24nFont.hxx" + #include "Stella12x24nbFont.hxx" + #include "Stella16x32Font.hxx" #include "ConsoleFont.hxx" #include "ConsoleBFont.hxx" #include "Launcher.hxx" @@ -130,7 +134,11 @@ bool FrameBuffer::initialize() else if(lf == "medium") myLauncherFont = make_unique(GUI::stellaMediumDesc); // 9x18 else - myLauncherFont = make_unique(GUI::stellaLargeDesc); // 10x20 + //myLauncherFont = make_unique(GUI::stellaLargeDesc); // 10x20 + //myLauncherFont = make_unique(GUI::stella12x24Desc); // 12x24 + myLauncherFont = make_unique(GUI::stella12x24nDesc); // 12x24 + //myLauncherFont = make_unique(GUI::stella12x24nbDesc); // 12x24 + //myLauncherFont = make_unique(GUI::stella16x32Desc); // 16x32 #endif // Determine possible TIA windowed zoom levels From e8ea4ea80d49fab21c3caeb9ecdffad397fbcb27 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 14 Mar 2020 23:37:18 +0100 Subject: [PATCH 019/377] Revert "add one more intermediate font option to ROM info viewer" This reverts commit 1aaea36d2534fabeed7f40374810b1c28f85e7aa. Now the correct file. :) --- src/gui/LauncherDialog.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/gui/LauncherDialog.cxx b/src/gui/LauncherDialog.cxx index d57892f38..eaa0bf608 100644 --- a/src/gui/LauncherDialog.cxx +++ b/src/gui/LauncherDialog.cxx @@ -374,6 +374,10 @@ const GUI::Font& LauncherDialog::getRomInfoFont(const Common::Size& area) const + MIN_ROMINFO_LINES * instance().frameBuffer().launcherFont().getFontHeight()) && area.w >= uInt32(MIN_ROMINFO_CHARS * instance().frameBuffer().launcherFont().getMaxCharWidth())) return instance().frameBuffer().launcherFont(); + else if(area.h >= uInt32(MIN_ROMINFO_ROWS * instance().frameBuffer().font().getLineHeight() + + MIN_ROMINFO_LINES * instance().frameBuffer().font().getFontHeight()) + && area.w >= uInt32(MIN_ROMINFO_CHARS * instance().frameBuffer().font().getMaxCharWidth())) + return instance().frameBuffer().font(); else if(area.h >= uInt32(MIN_ROMINFO_ROWS * instance().frameBuffer().infoFont().getLineHeight() + MIN_ROMINFO_LINES * instance().frameBuffer().infoFont().getFontHeight()) && area.w >= uInt32(MIN_ROMINFO_CHARS * instance().frameBuffer().infoFont().getMaxCharWidth())) From 9f73c7fb50b91dfecf43eacde5097ba3cbba4909 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 15 Mar 2020 08:23:54 +0100 Subject: [PATCH 020/377] trying to fix compile issues --- src/emucore/FrameBuffer.cxx | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 1cd41c646..d75179f86 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -39,10 +39,6 @@ #include "ConsoleMediumBFont.hxx" #include "StellaMediumFont.hxx" #include "StellaLargeFont.hxx" - #include "Stella12x24Font.hxx" - #include "Stella12x24nFont.hxx" - #include "Stella12x24nbFont.hxx" - #include "Stella16x32Font.hxx" #include "ConsoleFont.hxx" #include "ConsoleBFont.hxx" #include "Launcher.hxx" @@ -134,11 +130,7 @@ bool FrameBuffer::initialize() else if(lf == "medium") myLauncherFont = make_unique(GUI::stellaMediumDesc); // 9x18 else - //myLauncherFont = make_unique(GUI::stellaLargeDesc); // 10x20 - //myLauncherFont = make_unique(GUI::stella12x24Desc); // 12x24 - myLauncherFont = make_unique(GUI::stella12x24nDesc); // 12x24 - //myLauncherFont = make_unique(GUI::stella12x24nbDesc); // 12x24 - //myLauncherFont = make_unique(GUI::stella16x32Desc); // 16x32 + myLauncherFont = make_unique(GUI::stellaLargeDesc); // 10x20 #endif // Determine possible TIA windowed zoom levels From fbe90f0b916e59b20e9791da154a7fa093f7ade2 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 15 Mar 2020 17:16:37 +0100 Subject: [PATCH 021/377] add 3 large fonts (Terminus 12x24, 14x28 and 16x32) use 12x24 font for R77 (launcher and dialogs) improve font selection for ROM info viewer minor fix for convbdf.c --- src/emucore/FrameBuffer.cxx | 27 +- src/emucore/Settings.cxx | 3 +- src/gui/LauncherDialog.cxx | 49 +- src/gui/LauncherDialog.hxx | 5 +- src/gui/Stella12x24tFont.hxx | 5553 ++++++++++++++++++++++++++ src/gui/Stella14x28tFont.hxx | 6337 ++++++++++++++++++++++++++++++ src/gui/Stella16x32tFont.hxx | 7121 ++++++++++++++++++++++++++++++++++ src/gui/UIDialog.cxx | 11 +- src/tools/convbdf.c | 2 +- src/unix/r77/SettingsR77.cxx | 2 +- 10 files changed, 19076 insertions(+), 34 deletions(-) create mode 100644 src/gui/Stella12x24tFont.hxx create mode 100644 src/gui/Stella14x28tFont.hxx create mode 100644 src/gui/Stella16x32tFont.hxx diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index d75179f86..922ed9655 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -39,6 +39,9 @@ #include "ConsoleMediumBFont.hxx" #include "StellaMediumFont.hxx" #include "StellaLargeFont.hxx" + #include "Stella12x24tFont.hxx" + #include "Stella14x28tFont.hxx" + #include "Stella16x32tFont.hxx" #include "ConsoleFont.hxx" #include "ConsoleBFont.hxx" #include "Launcher.hxx" @@ -113,24 +116,30 @@ bool FrameBuffer::initialize() // The general font used in all UI elements // This is determined by the size of the framebuffer if(myOSystem.settings().getBool("minimal_ui")) - myFont = make_unique(GUI::stellaLargeDesc); + myFont = make_unique(GUI::stella12x24tDesc); // 12x24 else - myFont = make_unique(GUI::stellaMediumDesc); + myFont = make_unique(GUI::stellaMediumDesc); // 9x18 // The info font used in all UI elements // This is determined by the size of the framebuffer - myInfoFont = make_unique(GUI::consoleDesc); // 8x13 + myInfoFont = make_unique(GUI::consoleDesc); // 8x13 // The font used by the ROM launcher const string& lf = myOSystem.settings().getString("launcherfont"); if(lf == "small") - myLauncherFont = make_unique(GUI::consoleBDesc); // 8x13 - else if(lf == "small_medium") - myLauncherFont = make_unique(GUI::consoleMediumBDesc); // 9x15 + myLauncherFont = make_unique(GUI::consoleBDesc); // 8x13 + else if(lf == "low_medium") + myLauncherFont = make_unique(GUI::consoleMediumBDesc); // 9x15 else if(lf == "medium") - myLauncherFont = make_unique(GUI::stellaMediumDesc); // 9x18 - else - myLauncherFont = make_unique(GUI::stellaLargeDesc); // 10x20 + myLauncherFont = make_unique(GUI::stellaMediumDesc); // 9x18 + else if(lf == "large" || lf == "large10") + myLauncherFont = make_unique(GUI::stellaLargeDesc); // 10x20 + else if(lf == "large12") + myLauncherFont = make_unique(GUI::stella12x24tDesc); // 12x24 + else if(lf == "large14") + myLauncherFont = make_unique(GUI::stella14x28tDesc); // 14x28 + else // "large16" + myLauncherFont = make_unique(GUI::stella16x32tDesc); // 16x32 #endif // Determine possible TIA windowed zoom levels diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index 7588ccfdc..e46b192a3 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -342,7 +342,8 @@ void Settings::validate() setValue("palette", "standard"); s = getString("launcherfont"); - if(s != "small" && s != "small_medium" && s != "medium" && s != "large") + if(s != "small" && s != "low_medium" && s != "medium" && s != "large" + && s != "large12" && s != "large14" && s != "large16") setValue("launcherfont", "medium"); s = getString("dbg.fontsize"); diff --git a/src/gui/LauncherDialog.cxx b/src/gui/LauncherDialog.cxx index eaa0bf608..7a58e215d 100644 --- a/src/gui/LauncherDialog.cxx +++ b/src/gui/LauncherDialog.cxx @@ -41,6 +41,14 @@ #include "Settings.hxx" #include "Widget.hxx" #include "Font.hxx" +#include "StellaFont.hxx" +#include "ConsoleBFont.hxx" +#include "ConsoleMediumBFont.hxx" +#include "StellaMediumFont.hxx" +#include "StellaLargeFont.hxx" +#include "Stella12x24tFont.hxx" +#include "Stella14x28tFont.hxx" +#include "Stella16x32tFont.hxx" #include "Version.hxx" #include "LauncherDialog.hxx" @@ -146,9 +154,9 @@ LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent, // Calculate font area, and in the process the font that can be used Common::Size fontArea(romWidth - 16, myList->getHeight() - imgSize.h - 12); - const GUI::Font& rominfoFont = getRomInfoFont(fontArea); - myRomInfoWidget = new RomInfoWidget(this, rominfoFont, + setRomInfoFont(fontArea); + myRomInfoWidget = new RomInfoWidget(this, *myROMInfoFont, xpos, ypos, romWidth, myList->getHeight(), imgSize); } @@ -365,25 +373,32 @@ float LauncherDialog::getRomInfoZoom(int listHeight) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const GUI::Font& LauncherDialog::getRomInfoFont(const Common::Size& area) const +void LauncherDialog::setRomInfoFont(const Common::Size& area) { // TODO: Perhaps offer a setting to override the font used? + FontDesc FONTS[7] = { + GUI::stella16x32tDesc, GUI::stella14x28tDesc, GUI::stella12x24tDesc, + GUI::stellaLargeDesc, GUI::stellaMediumDesc, + GUI::consoleMediumBDesc, GUI::consoleBDesc + }; + // Try to pick a font that works best, based on the available area - if(area.h >= uInt32(MIN_ROMINFO_ROWS * instance().frameBuffer().launcherFont().getLineHeight() - + MIN_ROMINFO_LINES * instance().frameBuffer().launcherFont().getFontHeight()) - && area.w >= uInt32(MIN_ROMINFO_CHARS * instance().frameBuffer().launcherFont().getMaxCharWidth())) - return instance().frameBuffer().launcherFont(); - else if(area.h >= uInt32(MIN_ROMINFO_ROWS * instance().frameBuffer().font().getLineHeight() - + MIN_ROMINFO_LINES * instance().frameBuffer().font().getFontHeight()) - && area.w >= uInt32(MIN_ROMINFO_CHARS * instance().frameBuffer().font().getMaxCharWidth())) - return instance().frameBuffer().font(); - else if(area.h >= uInt32(MIN_ROMINFO_ROWS * instance().frameBuffer().infoFont().getLineHeight() - + MIN_ROMINFO_LINES * instance().frameBuffer().infoFont().getFontHeight()) - && area.w >= uInt32(MIN_ROMINFO_CHARS * instance().frameBuffer().infoFont().getMaxCharWidth())) - return instance().frameBuffer().infoFont(); - else - return instance().frameBuffer().smallFont(); + for(int i = 0; i < sizeof(FONTS) / sizeof(FontDesc); ++i) + { + // only use fonts <= launcher fonts + if(instance().frameBuffer().launcherFont().getFontHeight() >= FONTS[i].height) + { + if(area.h >= uInt32(MIN_ROMINFO_ROWS * FONTS[i].height + 2 + + MIN_ROMINFO_LINES * FONTS[i].height) + && area.w >= uInt32(MIN_ROMINFO_CHARS * FONTS[i].maxwidth)) + { + myROMInfoFont = make_unique(FONTS[i]); + return; + } + } + } + myROMInfoFont = make_unique(GUI::stellaDesc); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/gui/LauncherDialog.hxx b/src/gui/LauncherDialog.hxx index dc1ce321c..d112f0601 100644 --- a/src/gui/LauncherDialog.hxx +++ b/src/gui/LauncherDialog.hxx @@ -104,7 +104,7 @@ class LauncherDialog : public Dialog void applyFiltering(); float getRomInfoZoom(int listHeight) const; - const GUI::Font& getRomInfoFont(const Common::Size& area) const; + void setRomInfoFont(const Common::Size& area); void loadRom(); void loadRomInfo(); @@ -119,6 +119,9 @@ class LauncherDialog : public Dialog unique_ptr myGlobalProps; unique_ptr myRomDir; + // automatically sized font for ROM info viewer + unique_ptr myROMInfoFont; + ButtonWidget* myStartButton{nullptr}; ButtonWidget* myPrevDirButton{nullptr}; ButtonWidget* myOptionsButton{nullptr}; diff --git a/src/gui/Stella12x24tFont.hxx b/src/gui/Stella12x24tFont.hxx new file mode 100644 index 000000000..88bb67ae4 --- /dev/null +++ b/src/gui/Stella12x24tFont.hxx @@ -0,0 +1,5553 @@ +//============================================================================ +// +// 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. +// +// Generated by src/tools/convbdf on Sun Mar 15 08:31:37 2020. +//============================================================================ + +#ifndef STELLA12X24T_FONT_DATA_HXX +#define STELLA12X24T_FONT_DATA_HXX + +#include "Font.hxx" + +/* Font information: + name: ter-u24b + facename: -xos4-Terminus-Bold-R-Normal--24-240-72-72-C-120-ISO10646-1 + w x h: 12x24 + bbx: 12 24 0 -5 + size: 95 + ascent: 19 + descent: 5 + first char: 32 (0x20) + last char: 126 (0x7e) + default char: 32 (0x20) + proportional: no + Copyright (C) 2014 Dimitar Toshkov Zhekov +*/ + +namespace GUI { + +// Font character bitmap data. +static const uInt16 stella12x24t_font_bits[] = { // NOLINT : too complicated to convert + +/* Character 29 (0x1d): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0b0110011001100000, +0b0110011001100000, +0b0110011001100000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 30 (0x1e): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 31 (0x1f): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 32 (0x20): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 33 (0x21): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0000, +0x0000, +0x0600, +0x0600, +0x0600, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 34 (0x22): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x1980, +0x1980, +0x1980, +0x1980, +0x1980, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 35 (0x23): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ********** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ********** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1980, +0x1980, +0x1980, +0x1980, +0x7fe0, +0x1980, +0x1980, +0x1980, +0x1980, +0x1980, +0x7fe0, +0x1980, +0x1980, +0x1980, +0x1980, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 36 (0x24): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | ** | + | ** | + | ****** | + | ** ** ** | + | ** ** ** | + | ** ** | + | ** ** | + | ** ** | + | ****** | + | ** ** | + | ** ** | + | ** ** | + | ** ** ** | + | ** ** ** | + | ****** | + | ** | + | ** | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0600, +0x0600, +0x1f80, +0x36c0, +0x6660, +0x6600, +0x6600, +0x3600, +0x1f80, +0x06c0, +0x0660, +0x0660, +0x6660, +0x36c0, +0x1f80, +0x0600, +0x0600, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 37 (0x25): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | *** ** | + | ** ** ** | + | ** ** ** | + | *** ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** *** | + | ** ** ** | + | ** ** ** | + | ** *** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x38c0, +0x6cc0, +0x6d80, +0x3980, +0x0300, +0x0300, +0x0600, +0x0600, +0x0c00, +0x0c00, +0x19c0, +0x1b60, +0x3360, +0x31c0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 38 (0x26): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | *** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | *** | + | **** ** | + | ** ** ** | + | ** *** | + | ** ** | + | ** ** | + | ** *** | + | ** ** ** | + | **** ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0e00, +0x1b00, +0x3180, +0x3180, +0x3180, +0x1b00, +0x0e00, +0x1e60, +0x3360, +0x61c0, +0x60c0, +0x60c0, +0x61c0, +0x3360, +0x1e60, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 39 (0x27): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 40 (0x28): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0300, +0x0600, +0x0c00, +0x0c00, +0x1800, +0x1800, +0x1800, +0x1800, +0x1800, +0x1800, +0x1800, +0x0c00, +0x0c00, +0x0600, +0x0300, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 41 (0x29): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1800, +0x0c00, +0x0600, +0x0600, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0600, +0x0600, +0x0c00, +0x1800, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 42 (0x2a): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | ** ** | + | ** ** | + | ** ** | + | *** | + |*********** | + | *** | + | ** ** | + | ** ** | + | ** ** | + | | + | | + | | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x60c0, +0x3180, +0x1b00, +0x0e00, +0xffe0, +0x0e00, +0x1b00, +0x3180, +0x60c0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 43 (0x2b): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ********** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0600, +0x0600, +0x0600, +0x0600, +0x7fe0, +0x0600, +0x0600, +0x0600, +0x0600, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 44 (0x2c): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0600, +0x0600, +0x0600, +0x0600, +0x0c00, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 45 (0x2d): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ********** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7fe0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 46 (0x2e): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0600, +0x0600, +0x0600, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 47 (0x2f): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x00c0, +0x00c0, +0x0180, +0x0180, +0x0300, +0x0300, +0x0600, +0x0600, +0x0c00, +0x0c00, +0x1800, +0x1800, +0x3000, +0x3000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 48 (0x30): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ****** | + | ** ** | + | ** ** | + | ** ** | + | ** *** | + | ** **** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | **** ** | + | *** ** | + | ** ** | + | ** ** | + | ** ** | + | ****** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1f80, +0x30c0, +0x6060, +0x6060, +0x60e0, +0x61e0, +0x6360, +0x6660, +0x6c60, +0x7860, +0x7060, +0x6060, +0x6060, +0x30c0, +0x1f80, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 49 (0x31): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ** | + | *** | + | **** | + | ** ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ******** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0600, +0x0e00, +0x1e00, +0x3600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x3fc0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 50 (0x32): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ****** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ********** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1f80, +0x30c0, +0x6060, +0x6060, +0x6060, +0x0060, +0x00c0, +0x0180, +0x0300, +0x0600, +0x0c00, +0x1800, +0x3000, +0x6000, +0x7fe0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 51 (0x33): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ****** | + | ** ** | + | ** ** | + | ** | + | ** | + | ** | + | ** | + | ***** | + | ** | + | ** | + | ** | + | ** | + | ** ** | + | ** ** | + | ****** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1f80, +0x30c0, +0x6060, +0x0060, +0x0060, +0x0060, +0x00c0, +0x0f80, +0x00c0, +0x0060, +0x0060, +0x0060, +0x6060, +0x30c0, +0x1f80, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 52 (0x34): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ** | + | *** | + | **** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ********** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0060, +0x00e0, +0x01e0, +0x0360, +0x0660, +0x0c60, +0x1860, +0x3060, +0x6060, +0x6060, +0x6060, +0x7fe0, +0x0060, +0x0060, +0x0060, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 53 (0x35): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ********** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ******** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** ** | + | ** ** | + | ****** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x7fe0, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x7f80, +0x00c0, +0x0060, +0x0060, +0x0060, +0x0060, +0x6060, +0x30c0, +0x1f80, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 54 (0x36): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ******* | + | ** | + | ** | + | ** | + | ** | + | ** | + | ******** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ****** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1fc0, +0x3000, +0x6000, +0x6000, +0x6000, +0x6000, +0x7f80, +0x60c0, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x30c0, +0x1f80, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 55 (0x37): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ********** | + | ** ** | + | ** ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x7fe0, +0x6060, +0x6060, +0x0060, +0x00c0, +0x00c0, +0x0180, +0x0180, +0x0300, +0x0300, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 56 (0x38): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ****** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ****** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ****** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1f80, +0x30c0, +0x6060, +0x6060, +0x6060, +0x6060, +0x30c0, +0x1f80, +0x30c0, +0x6060, +0x6060, +0x6060, +0x6060, +0x30c0, +0x1f80, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 57 (0x39): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ****** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ******** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ******* | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1f80, +0x30c0, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x3060, +0x1fe0, +0x0060, +0x0060, +0x0060, +0x0060, +0x00c0, +0x3f80, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 58 (0x3a): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0600, +0x0600, +0x0600, +0x0000, +0x0000, +0x0000, +0x0000, +0x0600, +0x0600, +0x0600, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 59 (0x3b): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0600, +0x0600, +0x0600, +0x0000, +0x0000, +0x0000, +0x0000, +0x0600, +0x0600, +0x0600, +0x0600, +0x0c00, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 60 (0x3c): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x00c0, +0x0180, +0x0300, +0x0600, +0x0c00, +0x1800, +0x3000, +0x6000, +0x3000, +0x1800, +0x0c00, +0x0600, +0x0300, +0x0180, +0x00c0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 61 (0x3d): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ********** | + | | + | | + | | + | | + | ********** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7fe0, +0x0000, +0x0000, +0x0000, +0x0000, +0x7fe0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 62 (0x3e): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x6000, +0x3000, +0x1800, +0x0c00, +0x0600, +0x0300, +0x0180, +0x00c0, +0x0180, +0x0300, +0x0600, +0x0c00, +0x1800, +0x3000, +0x6000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 63 (0x3f): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ****** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1f80, +0x30c0, +0x6060, +0x6060, +0x6060, +0x00c0, +0x0180, +0x0300, +0x0600, +0x0600, +0x0000, +0x0000, +0x0600, +0x0600, +0x0600, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 64 (0x40): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ******* | + | ** ** | + |** ** | + |** ***** | + |** ** ** | + |** ** ** | + |** ** ** | + |** ** ** | + |** ** ** | + |** ** ** | + |** ** ** | + |** ***** | + |** | + | ** | + | ********* | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x3f80, +0x60c0, +0xc060, +0xc3e0, +0xc660, +0xcc60, +0xcc60, +0xcc60, +0xcc60, +0xcc60, +0xc660, +0xc3e0, +0xc000, +0x6000, +0x3fe0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 65 (0x41): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ****** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ********** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1f80, +0x30c0, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x7fe0, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 66 (0x42): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ******** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ******** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ******** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x7f80, +0x60c0, +0x6060, +0x6060, +0x6060, +0x60c0, +0x7f80, +0x60c0, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x60c0, +0x7f80, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 67 (0x43): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ****** | + | ** ** | + | ** ** | + | ** ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** ** | + | ** ** | + | ** ** | + | ****** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1f80, +0x30c0, +0x6060, +0x6060, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6060, +0x6060, +0x30c0, +0x1f80, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 68 (0x44): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ******** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ******** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x7f80, +0x60c0, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x60c0, +0x7f80, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 69 (0x45): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ********** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ******** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ********** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x7fe0, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x7f80, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x7fe0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 70 (0x46): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ********** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ******** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x7fe0, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x7f80, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 71 (0x47): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ****** | + | ** ** | + | ** ** | + | ** ** | + | ** | + | ** | + | ** | + | ** ***** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ****** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1f80, +0x30c0, +0x6060, +0x6060, +0x6000, +0x6000, +0x6000, +0x63e0, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x30c0, +0x1f80, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 72 (0x48): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ********** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x7fe0, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 73 (0x49): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ****** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ****** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1f80, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x1f80, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 74 (0x4a): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ******| + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ***** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x03f0, +0x00c0, +0x00c0, +0x00c0, +0x00c0, +0x00c0, +0x00c0, +0x00c0, +0x00c0, +0x00c0, +0x60c0, +0x60c0, +0x60c0, +0x3180, +0x1f00, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 75 (0x4b): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | **** | + | *** | + | **** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x6060, +0x60c0, +0x6180, +0x6300, +0x6600, +0x6c00, +0x7800, +0x7000, +0x7800, +0x6c00, +0x6600, +0x6300, +0x6180, +0x60c0, +0x6060, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 76 (0x4c): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ********** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x7fe0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 77 (0x4d): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + |* * | + |** ** | + |*** *** | + |**** **** | + |** ** ** ** | + |** *** ** | + |** * ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x8020, +0xc060, +0xe0e0, +0xf1e0, +0xdb60, +0xce60, +0xc460, +0xc060, +0xc060, +0xc060, +0xc060, +0xc060, +0xc060, +0xc060, +0xc060, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 78 (0x4e): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | *** ** | + | **** ** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | ** **** | + | ** *** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x6060, +0x6060, +0x6060, +0x6060, +0x7060, +0x7860, +0x6c60, +0x6660, +0x6360, +0x61e0, +0x60e0, +0x6060, +0x6060, +0x6060, +0x6060, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 79 (0x4f): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ****** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ****** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1f80, +0x30c0, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x30c0, +0x1f80, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 80 (0x50): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ******** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ******** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x7f80, +0x60c0, +0x6060, +0x6060, +0x6060, +0x6060, +0x60c0, +0x7f80, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 81 (0x51): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ****** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** ** | + | ** **** | + | ****** | + | ** | + | ** | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1f80, +0x30c0, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6660, +0x33c0, +0x1f80, +0x00c0, +0x0060, +0x0000, +0x0000, +0x0000, + +/* Character 82 (0x52): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ******** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ******** | + | **** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x7f80, +0x60c0, +0x6060, +0x6060, +0x6060, +0x6060, +0x60c0, +0x7f80, +0x7800, +0x6c00, +0x6600, +0x6300, +0x6180, +0x60c0, +0x6060, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 83 (0x53): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ****** | + | ** ** | + | ** ** | + | ** | + | ** | + | ** | + | ** | + | ****** | + | ** | + | ** | + | ** | + | ** | + | ** ** | + | ** ** | + | ****** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1f80, +0x30c0, +0x6060, +0x6000, +0x6000, +0x6000, +0x3000, +0x1f80, +0x00c0, +0x0060, +0x0060, +0x0060, +0x6060, +0x30c0, +0x1f80, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 84 (0x54): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ********** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x7fe0, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 85 (0x55): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ****** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x30c0, +0x1f80, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 86 (0x56): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | **** | + | **** | + | ** | + | ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x6060, +0x6060, +0x6060, +0x6060, +0x30c0, +0x30c0, +0x30c0, +0x30c0, +0x1980, +0x1980, +0x1980, +0x0f00, +0x0f00, +0x0600, +0x0600, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 87 (0x57): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** * ** | + |** *** ** | + |** ** ** ** | + |**** **** | + |*** *** | + |** ** | + |* * | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0xc060, +0xc060, +0xc060, +0xc060, +0xc060, +0xc060, +0xc060, +0xc060, +0xc460, +0xce60, +0xdb60, +0xf1e0, +0xe0e0, +0xc060, +0x8020, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 88 (0x58): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | **** | + | ** | + | **** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x6060, +0x6060, +0x30c0, +0x30c0, +0x1980, +0x1980, +0x0f00, +0x0600, +0x0f00, +0x1980, +0x1980, +0x30c0, +0x30c0, +0x6060, +0x6060, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 89 (0x59): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | **** | + | **** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x6060, +0x6060, +0x30c0, +0x30c0, +0x1980, +0x1980, +0x0f00, +0x0f00, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 90 (0x5a): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ********** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ********** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x7fe0, +0x0060, +0x0060, +0x0060, +0x00c0, +0x0180, +0x0300, +0x0600, +0x0c00, +0x1800, +0x3000, +0x6000, +0x6000, +0x6000, +0x7fe0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 91 (0x5b): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ***** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ***** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1f00, +0x1800, +0x1800, +0x1800, +0x1800, +0x1800, +0x1800, +0x1800, +0x1800, +0x1800, +0x1800, +0x1800, +0x1800, +0x1800, +0x1f00, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 92 (0x5c): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x3000, +0x3000, +0x1800, +0x1800, +0x0c00, +0x0c00, +0x0600, +0x0600, +0x0300, +0x0300, +0x0180, +0x0180, +0x00c0, +0x00c0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 93 (0x5d): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ***** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ***** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1f00, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x1f00, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 94 (0x5e): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | ** | + | **** | + | ** ** | + | ** ** | + | ** ** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0600, +0x0f00, +0x1980, +0x30c0, +0x6060, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 95 (0x5f): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ********** | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7fe0, +0x0000, +0x0000, +0x0000, + +/* Character 96 (0x60): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +------------+ +*/ +0x1800, +0x0c00, +0x0600, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 97 (0x61): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | ******* | + | ** | + | ** | + | ** | + | ******** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ******** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x3f80, +0x00c0, +0x0060, +0x0060, +0x1fe0, +0x3060, +0x6060, +0x6060, +0x6060, +0x3060, +0x1fe0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 98 (0x62): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ******** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ******** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x6000, +0x6000, +0x6000, +0x6000, +0x7f80, +0x60c0, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x60c0, +0x7f80, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 99 (0x63): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | ****** | + | ** ** | + | ** ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** ** | + | ** ** | + | ****** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1f80, +0x30c0, +0x6060, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6060, +0x30c0, +0x1f80, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 100 (0x64): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ******** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ******** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0060, +0x0060, +0x0060, +0x0060, +0x1fe0, +0x3060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x3060, +0x1fe0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 101 (0x65): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | ****** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ********** | + | ** | + | ** | + | ** | + | ** ** | + | ******* | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1f80, +0x30c0, +0x6060, +0x6060, +0x6060, +0x7fe0, +0x6000, +0x6000, +0x6000, +0x3060, +0x1fc0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 102 (0x66): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ***** | + | ** | + | ** | + | ** | + | ******** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x03e0, +0x0600, +0x0600, +0x0600, +0x3fc0, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 103 (0x67): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | ******** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** *** | + | ******** | + | ** | + | ** | + | ** | + | ******* | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1fe0, +0x3060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x30e0, +0x1fe0, +0x0060, +0x0060, +0x00c0, +0x3f80, +0x0000, + +/* Character 104 (0x68): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ******** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x6000, +0x6000, +0x6000, +0x6000, +0x7f80, +0x60c0, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 105 (0x69): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ** | + | ** | + | ** | + | | + | **** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ****** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0600, +0x0600, +0x0600, +0x0000, +0x1e00, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x1f80, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 106 (0x6a): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ** | + | ** | + | ** | + | | + | **** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** ** | + | ** ** | + | ** ** | + | **** | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x00c0, +0x00c0, +0x00c0, +0x0000, +0x03c0, +0x00c0, +0x00c0, +0x00c0, +0x00c0, +0x00c0, +0x00c0, +0x00c0, +0x00c0, +0x00c0, +0x00c0, +0x30c0, +0x30c0, +0x1980, +0x0f00, +0x0000, + +/* Character 107 (0x6b): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | **** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x3000, +0x3000, +0x3000, +0x3000, +0x3060, +0x30c0, +0x3180, +0x3300, +0x3600, +0x3c00, +0x3600, +0x3300, +0x3180, +0x30c0, +0x3060, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 108 (0x6c): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | **** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ****** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1e00, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x1f80, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 109 (0x6d): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | ******** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7f80, +0x66c0, +0x6660, +0x6660, +0x6660, +0x6660, +0x6660, +0x6660, +0x6660, +0x6660, +0x6660, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 110 (0x6e): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | ******** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7f80, +0x60c0, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 111 (0x6f): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | ****** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ****** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1f80, +0x30c0, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x30c0, +0x1f80, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 112 (0x70): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | ******** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ******** | + | ** | + | ** | + | ** | + | ** | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7f80, +0x60c0, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x60c0, +0x7f80, +0x6000, +0x6000, +0x6000, +0x6000, +0x0000, + +/* Character 113 (0x71): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | ******** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ******** | + | ** | + | ** | + | ** | + | ** | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1fe0, +0x3060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x3060, +0x1fe0, +0x0060, +0x0060, +0x0060, +0x0060, +0x0000, + +/* Character 114 (0x72): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | ** ****** | + | ** ** | + | **** | + | *** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x67e0, +0x6c00, +0x7800, +0x7000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 115 (0x73): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | ******** | + | ** ** | + | ** | + | ** | + | ** | + | ******** | + | ** | + | ** | + | ** | + | ** ** | + | ******** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x3fc0, +0x6060, +0x6000, +0x6000, +0x6000, +0x3fc0, +0x0060, +0x0060, +0x0060, +0x6060, +0x3fc0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 116 (0x74): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ******** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ***** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x7f80, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x07c0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 117 (0x75): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ******** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x3060, +0x1fe0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 118 (0x76): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | **** | + | **** | + | ** | + | ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x6060, +0x6060, +0x6060, +0x30c0, +0x30c0, +0x1980, +0x1980, +0x0f00, +0x0f00, +0x0600, +0x0600, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 119 (0x77): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | ******** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x6060, +0x6060, +0x6060, +0x6060, +0x6660, +0x6660, +0x6660, +0x6660, +0x6660, +0x6660, +0x3fc0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 120 (0x78): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | **** | + | ** | + | **** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x6060, +0x6060, +0x30c0, +0x1980, +0x0f00, +0x0600, +0x0f00, +0x1980, +0x30c0, +0x6060, +0x6060, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 121 (0x79): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** *** | + | ******** | + | ** | + | ** | + | ** | + | ******* | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x6060, +0x30e0, +0x1fe0, +0x0060, +0x0060, +0x00c0, +0x3f80, +0x0000, + +/* Character 122 (0x7a): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | ********** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ********** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7fe0, +0x0060, +0x00c0, +0x0180, +0x0300, +0x0600, +0x0c00, +0x1800, +0x3000, +0x6000, +0x7fe0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 123 (0x7b): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | *** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | *** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | *** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0380, +0x0600, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x3800, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x0600, +0x0380, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 124 (0x7c): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 125 (0x7d): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | *** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | *** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | *** | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x3800, +0x0c00, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0380, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0c00, +0x3800, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 126 (0x7e): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | **** ** | + | ** ** ** | + | ** ** ** | + | ** **** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x3c60, +0x6660, +0x6660, +0x63c0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +}; + +/* Exported structure definition. */ +static const FontDesc stella12x24tDesc = { + "ter-u24b", + 12, + 24, + 12, 24, 0, -5, + 19, + 29, + 98, + stella12x24t_font_bits, + nullptr, /* no encode table*/ + nullptr, /* fixed width*/ + nullptr, /* fixed bbox*/ + 32, + sizeof(stella12x24t_font_bits)/sizeof(uInt16) +}; + +} // End of namespace GUI + +#endif diff --git a/src/gui/Stella14x28tFont.hxx b/src/gui/Stella14x28tFont.hxx new file mode 100644 index 000000000..28151f725 --- /dev/null +++ b/src/gui/Stella14x28tFont.hxx @@ -0,0 +1,6337 @@ +//============================================================================ +// +// 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. +// +// Generated by src/tools/convbdf on Sun Mar 15 08:40:37 2020. +//============================================================================ + +#ifndef STELLA14X28T_FONT_DATA_HXX +#define STELLA14X28T_FONT_DATA_HXX + +#include "Font.hxx" + +/* Font information: + name: ter-u28b + facename: -xos4-Terminus-Bold-R-Normal--28-280-72-72-C-140-ISO10646-1 + w x h: 14x28 + bbx: 14 28 0 -6 + size: 95 + ascent: 22 + descent: 6 + first char: 32 (0x20) + last char: 126 (0x7e) + default char: 32 (0x20) + proportional: no + Copyright (C) 2014 Dimitar Toshkov Zhekov +*/ + +namespace GUI { + +// Font character bitmap data. +static const uInt16 stella14x28t_font_bits[] = { // NOLINT : too complicated to convert + +/* Character 32 (0x20): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0b0011001100110000, +0b0011001100110000, +0b0011001100110000, +0b0011001100110000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 30 (0x1e): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 31 (0x1f): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 32 (0x20): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 33 (0x21): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0000, +0x0000, +0x0300, +0x0300, +0x0300, +0x0300, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 34 (0x22): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x18c0, +0x18c0, +0x18c0, +0x18c0, +0x18c0, +0x18c0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 35 (0x23): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | *********** | + | *********** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | *********** | + | *********** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x18c0, +0x18c0, +0x18c0, +0x18c0, +0x7ff0, +0x7ff0, +0x18c0, +0x18c0, +0x18c0, +0x18c0, +0x18c0, +0x18c0, +0x7ff0, +0x7ff0, +0x18c0, +0x18c0, +0x18c0, +0x18c0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 36 (0x24): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | ** | + | ** | + | ** | + | ******** | + | ********** | + | *** ** *** | + | ** ** ** | + | ** ** | + | ** ** | + | *** ** | + | ********* | + | ********* | + | ** *** | + | ** ** | + | ** ** | + | ** ** ** | + | *** ** *** | + | ********** | + | ******** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0300, +0x0300, +0x0300, +0x1fe0, +0x3ff0, +0x7338, +0x6318, +0x6300, +0x6300, +0x7300, +0x3fe0, +0x1ff0, +0x0338, +0x0318, +0x0318, +0x6318, +0x7338, +0x3ff0, +0x1fe0, +0x0300, +0x0300, +0x0300, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 37 (0x25): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | **** ** | + | ****** ** | + | ** ** ** | + | ****** ** | + | **** ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** **** | + | ** ****** | + | ** ** ** | + | ** ****** | + | ** **** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x3c30, +0x7e30, +0x6660, +0x7e60, +0x3cc0, +0x00c0, +0x0180, +0x0180, +0x0300, +0x0300, +0x0600, +0x0600, +0x0c00, +0x0cf0, +0x19f8, +0x1998, +0x31f8, +0x30f0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 38 (0x26): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | **** | + | ****** | + | *** *** | + | ** ** | + | ** ** | + | *** *** | + | ****** | + | **** | + | *** | + | ***** ** | + | *** *** *** | + | *** ***** | + | ** *** | + | ** *** | + | ** *** | + | *** ***** | + | ******* *** | + | ***** ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0f00, +0x1f80, +0x39c0, +0x30c0, +0x30c0, +0x39c0, +0x1f80, +0x0f00, +0x0e00, +0x1f18, +0x3bb8, +0x71f0, +0x60e0, +0x60e0, +0x60e0, +0x71f0, +0x3fb8, +0x1f18, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 39 (0x27): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 40 (0x28): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0180, +0x0300, +0x0600, +0x0600, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x0600, +0x0600, +0x0300, +0x0180, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 41 (0x29): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0c00, +0x0600, +0x0300, +0x0300, +0x0180, +0x0180, +0x0180, +0x0180, +0x0180, +0x0180, +0x0180, +0x0180, +0x0180, +0x0180, +0x0300, +0x0300, +0x0600, +0x0c00, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 42 (0x2a): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | *** *** | + | *** *** | + | ***** | + | *** | + | *********** | + | *********** | + | *** | + | ***** | + | *** *** | + | *** *** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x38e0, +0x1dc0, +0x0f80, +0x0700, +0x7ff0, +0x7ff0, +0x0700, +0x0f80, +0x1dc0, +0x38e0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 43 (0x2b): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ************ | + | ************ | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x7ff8, +0x7ff8, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 44 (0x2c): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0300, +0x0300, +0x0300, +0x0300, +0x0600, +0x0c00, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 45 (0x2d): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | *********** | + | *********** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7ff0, +0x7ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 46 (0x2e): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0300, +0x0300, +0x0300, +0x0300, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 47 (0x2f): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0030, +0x0030, +0x0060, +0x0060, +0x00c0, +0x00c0, +0x0180, +0x0180, +0x0300, +0x0300, +0x0600, +0x0600, +0x0c00, +0x0c00, +0x1800, +0x1800, +0x3000, +0x3000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 48 (0x30): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ******* | + | ********* | + | *** *** | + | ** ** | + | ** *** | + | ** **** | + | ** ***** | + | ** *** ** | + | ** *** ** | + | ** *** ** | + | ***** ** | + | **** ** | + | *** ** | + | ** ** | + | ** ** | + | *** *** | + | ********* | + | ******* | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1fc0, +0x3fe0, +0x7070, +0x6030, +0x6070, +0x60f0, +0x61f0, +0x63b0, +0x6730, +0x6e30, +0x7c30, +0x7830, +0x7030, +0x6030, +0x6030, +0x7070, +0x3fe0, +0x1fc0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 49 (0x31): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ** | + | *** | + | **** | + | ***** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ******** | + | ******** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0300, +0x0700, +0x0f00, +0x1f00, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x1fe0, +0x1fe0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 50 (0x32): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ******* | + | ********* | + | *** *** | + | ** ** | + | ** ** | + | ** ** | + | ** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *********** | + | *********** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1fc0, +0x3fe0, +0x7070, +0x6030, +0x6030, +0x6030, +0x0030, +0x0070, +0x00e0, +0x01c0, +0x0380, +0x0700, +0x0e00, +0x1c00, +0x3800, +0x7000, +0x7ff0, +0x7ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 51 (0x33): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ******* | + | ********* | + | *** *** | + | ** ** | + | ** | + | ** | + | ** | + | *** | + | ******* | + | ******* | + | *** | + | ** | + | ** | + | ** | + | ** ** | + | *** *** | + | ********* | + | ******* | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1fc0, +0x3fe0, +0x7070, +0x6030, +0x0030, +0x0030, +0x0030, +0x0070, +0x0fe0, +0x0fe0, +0x0070, +0x0030, +0x0030, +0x0030, +0x6030, +0x7070, +0x3fe0, +0x1fc0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 52 (0x34): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ** | + | *** | + | **** | + | ***** | + | *** ** | + | *** ** | + | *** ** | + | *** ** | + | *** ** | + | *** ** | + | ** ** | + | ** ** | + | *********** | + | *********** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0030, +0x0070, +0x00f0, +0x01f0, +0x03b0, +0x0730, +0x0e30, +0x1c30, +0x3830, +0x7030, +0x6030, +0x6030, +0x7ff0, +0x7ff0, +0x0030, +0x0030, +0x0030, +0x0030, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 53 (0x35): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | *********** | + | *********** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ********* | + | ********** | + | *** | + | ** | + | ** | + | ** | + | ** | + | ** ** | + | *** *** | + | ********* | + | ******* | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x7ff0, +0x7ff0, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x7fc0, +0x7fe0, +0x0070, +0x0030, +0x0030, +0x0030, +0x0030, +0x6030, +0x7070, +0x3fe0, +0x1fc0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 54 (0x36): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ******** | + | ********* | + | *** | + | ** | + | ** | + | ** | + | ** | + | ********* | + | ********** | + | ** *** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | *** *** | + | ********* | + | ******* | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1fe0, +0x3fe0, +0x7000, +0x6000, +0x6000, +0x6000, +0x6000, +0x7fc0, +0x7fe0, +0x6070, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x7070, +0x3fe0, +0x1fc0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 55 (0x37): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | *********** | + | *********** | + | ** ** | + | ** ** | + | ** ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x7ff0, +0x7ff0, +0x6030, +0x6030, +0x6030, +0x0060, +0x0060, +0x00c0, +0x00c0, +0x0180, +0x0180, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 56 (0x38): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ******* | + | ********* | + | *** *** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | *** *** | + | ********* | + | ********* | + | *** *** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | *** *** | + | ********* | + | ******* | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1fc0, +0x3fe0, +0x7070, +0x6030, +0x6030, +0x6030, +0x6030, +0x7070, +0x3fe0, +0x3fe0, +0x7070, +0x6030, +0x6030, +0x6030, +0x6030, +0x7070, +0x3fe0, +0x1fc0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 57 (0x39): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ******* | + | ********* | + | *** *** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | *** ** | + | ********** | + | ********* | + | ** | + | ** | + | ** | + | ** | + | *** | + | ********* | + | ******** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1fc0, +0x3fe0, +0x7070, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x7030, +0x3ff0, +0x1ff0, +0x0030, +0x0030, +0x0030, +0x0030, +0x0070, +0x3fe0, +0x3fc0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 58 (0x3a): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0300, +0x0300, +0x0300, +0x0300, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0300, +0x0300, +0x0300, +0x0300, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 59 (0x3b): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0300, +0x0300, +0x0300, +0x0300, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0300, +0x0300, +0x0300, +0x0300, +0x0600, +0x0c00, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 60 (0x3c): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0070, +0x00e0, +0x01c0, +0x0380, +0x0700, +0x0e00, +0x1c00, +0x3800, +0x7000, +0x3800, +0x1c00, +0x0e00, +0x0700, +0x0380, +0x01c0, +0x00e0, +0x0070, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 61 (0x3d): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | *********** | + | *********** | + | | + | | + | | + | | + | *********** | + | *********** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7ff0, +0x7ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x7ff0, +0x7ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 62 (0x3e): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7000, +0x3800, +0x1c00, +0x0e00, +0x0700, +0x0380, +0x01c0, +0x00e0, +0x0070, +0x00e0, +0x01c0, +0x0380, +0x0700, +0x0e00, +0x1c00, +0x3800, +0x7000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 63 (0x3f): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ******* | + | ********* | + | *** *** | + | ** ** | + | ** ** | + | ** ** | + | *** | + | *** | + | *** | + | *** | + | ** | + | ** | + | | + | | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1fc0, +0x3fe0, +0x7070, +0x6030, +0x6030, +0x6030, +0x0070, +0x00e0, +0x01c0, +0x0380, +0x0300, +0x0300, +0x0000, +0x0000, +0x0300, +0x0300, +0x0300, +0x0300, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 64 (0x40): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ******** | + | ********** | + | *** *** | + | ** ** | + | ** ****** | + | ** ******* | + | ** *** ** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | ** *** ** | + | ** ******* | + | ** **** * | + | ** | + | *** | + | *********** | + | ********** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1fe0, +0x3ff0, +0x7038, +0x6018, +0x61f8, +0x63f8, +0x6718, +0x6618, +0x6618, +0x6618, +0x6618, +0x6718, +0x63f8, +0x61e8, +0x6000, +0x7000, +0x3ff8, +0x1ff8, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 65 (0x41): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ******* | + | ********* | + | *** *** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | *********** | + | *********** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1fc0, +0x3fe0, +0x7070, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x7ff0, +0x7ff0, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 66 (0x42): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ********* | + | ********** | + | ** *** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ********* | + | ********* | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** *** | + | ********** | + | ********* | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x7fc0, +0x7fe0, +0x6070, +0x6030, +0x6030, +0x6030, +0x6060, +0x7fc0, +0x7fc0, +0x6060, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6070, +0x7fe0, +0x7fc0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 67 (0x43): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ******* | + | ********* | + | *** *** | + | ** ** | + | ** ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** ** | + | ** ** | + | *** *** | + | ********* | + | ******* | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1fc0, +0x3fe0, +0x7070, +0x6030, +0x6030, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6030, +0x6030, +0x7070, +0x3fe0, +0x1fc0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 68 (0x44): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ******* | + | ********* | + | ** *** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** *** | + | ********* | + | ******* | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x7f00, +0x7fc0, +0x60e0, +0x6060, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6060, +0x60e0, +0x7fc0, +0x7f00, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 69 (0x45): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | *********** | + | *********** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ******** | + | ******** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | *********** | + | *********** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x7ff0, +0x7ff0, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x7f80, +0x7f80, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x7ff0, +0x7ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 70 (0x46): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | *********** | + | *********** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ******** | + | ******** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x7ff0, +0x7ff0, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x7f80, +0x7f80, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 71 (0x47): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ******* | + | ********* | + | *** *** | + | ** ** | + | ** ** | + | ** | + | ** | + | ** | + | ** ****** | + | ** ****** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | *** *** | + | ********* | + | ******* | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1fc0, +0x3fe0, +0x7070, +0x6030, +0x6030, +0x6000, +0x6000, +0x6000, +0x63f0, +0x63f0, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x7070, +0x3fe0, +0x1fc0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 72 (0x48): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | *********** | + | *********** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x7ff0, +0x7ff0, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 73 (0x49): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ****** | + | ****** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ****** | + | ****** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0fc0, +0x0fc0, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0fc0, +0x0fc0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 74 (0x4a): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ****** | + | ****** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** ** | + | ** ** | + | ** ** | + | *** *** | + | ******** | + | ****** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x01f8, +0x01f8, +0x0060, +0x0060, +0x0060, +0x0060, +0x0060, +0x0060, +0x0060, +0x0060, +0x0060, +0x0060, +0x6060, +0x6060, +0x6060, +0x70e0, +0x3fc0, +0x1f80, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 75 (0x4b): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ** ** | + | ** *** | + | ** *** | + | ** *** | + | ** *** | + | ** *** | + | ** *** | + | ***** | + | **** | + | **** | + | ***** | + | ** *** | + | ** *** | + | ** *** | + | ** *** | + | ** *** | + | ** *** | + | ** ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x6030, +0x6070, +0x60e0, +0x61c0, +0x6380, +0x6700, +0x6e00, +0x7c00, +0x7800, +0x7800, +0x7c00, +0x6e00, +0x6700, +0x6380, +0x61c0, +0x60e0, +0x6070, +0x6030, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 76 (0x4c): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | *********** | + | *********** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x7ff0, +0x7ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 77 (0x4d): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ** ** | + | ** ** | + | *** *** | + | **** **** | + | ***** ***** | + | ** ****** ** | + | ** **** ** | + | ** ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x6018, +0x6018, +0x7038, +0x7878, +0x7cf8, +0x6fd8, +0x6798, +0x6318, +0x6018, +0x6018, +0x6018, +0x6018, +0x6018, +0x6018, +0x6018, +0x6018, +0x6018, +0x6018, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 78 (0x4e): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | *** ** | + | **** ** | + | ***** ** | + | ** *** ** | + | ** *** ** | + | ** *** ** | + | ** ***** | + | ** **** | + | ** *** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x6030, +0x6030, +0x6030, +0x6030, +0x7030, +0x7830, +0x7c30, +0x6e30, +0x6730, +0x63b0, +0x61f0, +0x60f0, +0x6070, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 79 (0x4f): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ******* | + | ********* | + | *** *** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | *** *** | + | ********* | + | ******* | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1fc0, +0x3fe0, +0x7070, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x7070, +0x3fe0, +0x1fc0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 80 (0x50): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ********* | + | ********** | + | ** *** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** *** | + | ********** | + | ********* | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x7fc0, +0x7fe0, +0x6070, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6070, +0x7fe0, +0x7fc0, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 81 (0x51): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ******* | + | ********* | + | *** *** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** *** ** | + | *** ***** | + | ********* | + | ******** | + | *** | + | *** | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1fc0, +0x3fe0, +0x7070, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x63b0, +0x71f0, +0x3fe0, +0x1fe0, +0x0070, +0x0038, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 82 (0x52): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ********* | + | ********** | + | ** *** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** *** | + | ********** | + | ********* | + | ***** | + | ** *** | + | ** *** | + | ** *** | + | ** *** | + | ** *** | + | ** *** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x7fc0, +0x7fe0, +0x6070, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6070, +0x7fe0, +0x7fc0, +0x7c00, +0x6e00, +0x6700, +0x6380, +0x61c0, +0x60e0, +0x6070, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 83 (0x53): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ******* | + | ********* | + | *** *** | + | ** ** | + | ** | + | ** | + | ** | + | *** | + | ******** | + | ******** | + | *** | + | ** | + | ** | + | ** | + | ** ** | + | *** *** | + | ********* | + | ******* | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1fc0, +0x3fe0, +0x7070, +0x6030, +0x6000, +0x6000, +0x6000, +0x7000, +0x3fc0, +0x1fe0, +0x0070, +0x0030, +0x0030, +0x0030, +0x6030, +0x7070, +0x3fe0, +0x1fc0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 84 (0x54): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ************ | + | ************ | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x7ff8, +0x7ff8, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 85 (0x55): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | *** *** | + | ********* | + | ******* | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x7070, +0x3fe0, +0x1fc0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 86 (0x56): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x6030, +0x6030, +0x6030, +0x6030, +0x3060, +0x3060, +0x3060, +0x3060, +0x18c0, +0x18c0, +0x18c0, +0x18c0, +0x0d80, +0x0d80, +0x0d80, +0x0700, +0x0700, +0x0700, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 87 (0x57): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** ** | + | ** **** ** | + | ** ****** ** | + | ***** ***** | + | **** **** | + | *** *** | + | ** ** | + | ** ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x6018, +0x6018, +0x6018, +0x6018, +0x6018, +0x6018, +0x6018, +0x6018, +0x6018, +0x6018, +0x6318, +0x6798, +0x6fd8, +0x7cf8, +0x7878, +0x7038, +0x6018, +0x6018, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 88 (0x58): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | *** | + | *** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x6030, +0x6030, +0x3060, +0x3060, +0x18c0, +0x18c0, +0x0d80, +0x0d80, +0x0700, +0x0700, +0x0d80, +0x0d80, +0x18c0, +0x18c0, +0x3060, +0x3060, +0x6030, +0x6030, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 89 (0x59): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | **** | + | **** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x6018, +0x6018, +0x3030, +0x3030, +0x1860, +0x1860, +0x0cc0, +0x0cc0, +0x0780, +0x0780, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 90 (0x5a): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | *********** | + | *********** | + | ** | + | ** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | ** | + | ** | + | ** | + | *********** | + | *********** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x7ff0, +0x7ff0, +0x0030, +0x0030, +0x0070, +0x00e0, +0x01c0, +0x0380, +0x0700, +0x0e00, +0x1c00, +0x3800, +0x7000, +0x6000, +0x6000, +0x6000, +0x7ff0, +0x7ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 91 (0x5b): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ****** | + | ****** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ****** | + | ****** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0fc0, +0x0fc0, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x0c00, +0x0fc0, +0x0fc0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 92 (0x5c): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x3000, +0x3000, +0x1800, +0x1800, +0x0c00, +0x0c00, +0x0600, +0x0600, +0x0300, +0x0300, +0x0180, +0x0180, +0x00c0, +0x00c0, +0x0060, +0x0060, +0x0030, +0x0030, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 93 (0x5d): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ****** | + | ****** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ****** | + | ****** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0fc0, +0x0fc0, +0x00c0, +0x00c0, +0x00c0, +0x00c0, +0x00c0, +0x00c0, +0x00c0, +0x00c0, +0x00c0, +0x00c0, +0x00c0, +0x00c0, +0x00c0, +0x00c0, +0x0fc0, +0x0fc0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 94 (0x5e): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | * | + | *** | + | ***** | + | *** *** | + | *** *** | + | *** *** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0200, +0x0700, +0x0f80, +0x1dc0, +0x38e0, +0x7070, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 95 (0x5f): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | *********** | + | *********** | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7ff0, +0x7ff0, +0x0000, +0x0000, +0x0000, + +/* Character 96 (0x60): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | *** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x1c00, +0x0e00, +0x0700, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 97 (0x61): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ******* | + | ******** | + | *** | + | ** | + | ********* | + | ********** | + | *** ** | + | ** ** | + | ** ** | + | ** ** | + | *** ** | + | ********** | + | ********* | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1fc0, +0x1fe0, +0x0070, +0x0030, +0x1ff0, +0x3ff0, +0x7030, +0x6030, +0x6030, +0x6030, +0x7030, +0x3ff0, +0x1ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 98 (0x62): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ********* | + | ********** | + | ** *** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** *** | + | ********** | + | ********* | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x7fc0, +0x7fe0, +0x6070, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6070, +0x7fe0, +0x7fc0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 99 (0x63): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ******* | + | ********* | + | *** *** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | *** *** | + | ********* | + | ******* | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1fc0, +0x3fe0, +0x7070, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x7070, +0x3fe0, +0x1fc0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 100 (0x64): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ********* | + | ********** | + | *** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | *** ** | + | ********** | + | ********* | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0030, +0x0030, +0x0030, +0x0030, +0x0030, +0x1ff0, +0x3ff0, +0x7030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x7030, +0x3ff0, +0x1ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 101 (0x65): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ******* | + | ********* | + | *** *** | + | ** ** | + | ** ** | + | *********** | + | *********** | + | ** | + | ** | + | ** | + | *** *** | + | ********* | + | ******* | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1fc0, +0x3fe0, +0x7070, +0x6030, +0x6030, +0x7ff0, +0x7ff0, +0x6000, +0x6000, +0x6000, +0x7070, +0x3fe0, +0x1fc0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 102 (0x66): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ****** | + | ******* | + | ** | + | ** | + | ** | + | ******** | + | ******** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x03f0, +0x07f0, +0x0600, +0x0600, +0x0600, +0x3fc0, +0x3fc0, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 103 (0x67): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ********* | + | ********** | + | *** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | *** ** | + | ********** | + | ********* | + | ** | + | ** | + | *** | + | ********* | + | ******** | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1ff0, +0x3ff0, +0x7030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x7030, +0x3ff0, +0x1ff0, +0x0030, +0x0030, +0x0070, +0x3fe0, +0x3fc0, +0x0000, + +/* Character 104 (0x68): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ********* | + | ********** | + | ** *** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x7fc0, +0x7fe0, +0x6070, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 105 (0x69): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ** | + | ** | + | ** | + | | + | | + | **** | + | **** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ****** | + | ****** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0300, +0x0300, +0x0300, +0x0000, +0x0000, +0x0f00, +0x0f00, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0fc0, +0x0fc0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 106 (0x6a): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ** | + | ** | + | ** | + | | + | | + | **** | + | **** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** ** | + | ** ** | + | *** *** | + | ******* | + | ***** | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0060, +0x0060, +0x0060, +0x0000, +0x0000, +0x01e0, +0x01e0, +0x0060, +0x0060, +0x0060, +0x0060, +0x0060, +0x0060, +0x0060, +0x0060, +0x0060, +0x0060, +0x0060, +0x3060, +0x3060, +0x38e0, +0x1fc0, +0x0f80, +0x0000, + +/* Character 107 (0x6b): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** *** | + | ** *** | + | ** *** | + | ** *** | + | ** *** | + | ***** | + | **** | + | ***** | + | ** *** | + | ** *** | + | ** *** | + | ** *** | + | ** *** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x3000, +0x3000, +0x3000, +0x3000, +0x3000, +0x3070, +0x30e0, +0x31c0, +0x3380, +0x3700, +0x3e00, +0x3c00, +0x3e00, +0x3700, +0x3380, +0x31c0, +0x30e0, +0x3070, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 108 (0x6c): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | **** | + | **** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ****** | + | ****** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0f00, +0x0f00, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0fc0, +0x0fc0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 109 (0x6d): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ********** | + | *********** | + | ** ** *** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7fe0, +0x7ff0, +0x6338, +0x6318, +0x6318, +0x6318, +0x6318, +0x6318, +0x6318, +0x6318, +0x6318, +0x6318, +0x6318, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 110 (0x6e): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ********* | + | ********** | + | ** *** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7fc0, +0x7fe0, +0x6070, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 111 (0x6f): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ******* | + | ********* | + | *** *** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | *** *** | + | ********* | + | ******* | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1fc0, +0x3fe0, +0x7070, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x7070, +0x3fe0, +0x1fc0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 112 (0x70): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ********* | + | ********** | + | ** *** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** *** | + | ********** | + | ********* | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7fc0, +0x7fe0, +0x6070, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6070, +0x7fe0, +0x7fc0, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x0000, + +/* Character 113 (0x71): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ********* | + | ********** | + | *** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | *** ** | + | ********** | + | ********* | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1ff0, +0x3ff0, +0x7030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x7030, +0x3ff0, +0x1ff0, +0x0030, +0x0030, +0x0030, +0x0030, +0x0030, +0x0000, + +/* Character 114 (0x72): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ** ******* | + | ** ******** | + | ***** | + | **** | + | *** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x67f0, +0x6ff0, +0x7c00, +0x7800, +0x7000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x6000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 115 (0x73): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ******* | + | ********* | + | *** *** | + | ** | + | *** | + | ******** | + | ******** | + | *** | + | ** | + | ** | + | *** *** | + | ********* | + | ******* | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1fc0, +0x3fe0, +0x7070, +0x6000, +0x7000, +0x3fc0, +0x1fe0, +0x0070, +0x0030, +0x0030, +0x7070, +0x3fe0, +0x1fc0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 116 (0x74): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ******** | + | ******** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ****** | + | ***** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x3fc0, +0x3fc0, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x07e0, +0x03e0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 117 (0x75): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | *** ** | + | ********** | + | ********* | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x7030, +0x3ff0, +0x1ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 118 (0x76): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x6030, +0x6030, +0x6030, +0x3060, +0x3060, +0x3060, +0x18c0, +0x18c0, +0x18c0, +0x0d80, +0x0d80, +0x0700, +0x0700, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 119 (0x77): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | ** ** ** | + | *** ** *** | + | ********** | + | ******** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x6018, +0x6018, +0x6018, +0x6018, +0x6318, +0x6318, +0x6318, +0x6318, +0x6318, +0x6318, +0x7338, +0x3ff0, +0x1fe0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 120 (0x78): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ** ** | + | ** ** | + | *** *** | + | *** *** | + | *** *** | + | ***** | + | *** | + | ***** | + | *** *** | + | *** *** | + | *** *** | + | ** ** | + | ** ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x6030, +0x6030, +0x7070, +0x38e0, +0x1dc0, +0x0f80, +0x0700, +0x0f80, +0x1dc0, +0x38e0, +0x7070, +0x6030, +0x6030, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 121 (0x79): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | *** ** | + | ********** | + | ********* | + | ** | + | ** | + | *** | + | ********* | + | ******** | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x6030, +0x7030, +0x3ff0, +0x1ff0, +0x0030, +0x0030, +0x0070, +0x3fe0, +0x3fc0, +0x0000, + +/* Character 122 (0x7a): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | *********** | + | *********** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *********** | + | *********** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7ff0, +0x7ff0, +0x0070, +0x00e0, +0x01c0, +0x0380, +0x0700, +0x0e00, +0x1c00, +0x3800, +0x7000, +0x7ff0, +0x7ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 123 (0x7b): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | *** | + | **** | + | *** | + | ** | + | ** | + | ** | + | ** | + | ** | + | *** | + | *** | + | ** | + | ** | + | ** | + | ** | + | ** | + | *** | + | **** | + | *** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x01c0, +0x03c0, +0x0700, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x1c00, +0x1c00, +0x0600, +0x0600, +0x0600, +0x0600, +0x0600, +0x0700, +0x03c0, +0x01c0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 124 (0x7c): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 125 (0x7d): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | *** | + | **** | + | *** | + | ** | + | ** | + | ** | + | ** | + | ** | + | *** | + | *** | + | ** | + | ** | + | ** | + | ** | + | ** | + | *** | + | **** | + | *** | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1c00, +0x1e00, +0x0700, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x01c0, +0x01c0, +0x0300, +0x0300, +0x0300, +0x0300, +0x0300, +0x0700, +0x1e00, +0x1c00, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 126 (0x7e): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | **** ** | + | ****** ** | + | ** *** ** | + | ** ****** | + | ** **** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x3c30, +0x7e30, +0x6730, +0x63f0, +0x61e0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +}; + +/* Exported structure definition. */ +static const FontDesc stella14x28tDesc = { + "ter-u28b", + 14, + 28, + 14, 28, 0, -6, + 22, + 29, + 98, + stella14x28t_font_bits, + 0, /* no encode table*/ + 0, /* fixed width*/ + 0, /* fixed bbox*/ + 32, + sizeof(stella14x28t_font_bits)/sizeof(uInt16) +}; + +} // End of namespace GUI + +#endif diff --git a/src/gui/Stella16x32tFont.hxx b/src/gui/Stella16x32tFont.hxx new file mode 100644 index 000000000..0f74d3b4e --- /dev/null +++ b/src/gui/Stella16x32tFont.hxx @@ -0,0 +1,7121 @@ +//============================================================================ +// +// 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. +// +// Generated by src/tools/convbdf on Sun Mar 15 08:41:32 2020. +//============================================================================ + +#ifndef STELLA16X32T_FONT_DATA_HXX +#define STELLA16X32T_FONT_DATA_HXX + +#include "Font.hxx" + +/* Font information: + name: ter-u32b + facename: -xos4-Terminus-Bold-R-Normal--32-320-72-72-C-160-ISO10646-1 + w x h: 16x32 + bbx: 16 32 0 -6 + size: 95 + ascent: 26 + descent: 6 + first char: 32 (0x20) + last char: 126 (0x7e) + default char: 32 (0x20) + proportional: no + Copyright (C) 2014 Dimitar Toshkov Zhekov +*/ + +namespace GUI { + +// Font character bitmap data. +static const uInt16 stella16x32t_font_bits[] = { // NOLINT : too complicated to convert + +/* Character 29 (0x1d): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | *** *** *** | + | *** *** *** | + | *** *** *** | + | *** *** *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0b0011100111001110, +0b0011100111001110, +0b0011100111001110, +0b0011100111001110, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 30 (0x1e): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 31 (0x1f): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 32 (0x20): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 33 (0x21): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0000, +0x0000, +0x0000, +0x0380, +0x0380, +0x0380, +0x0380, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 34 (0x22): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1c70, +0x1c70, +0x1c70, +0x1c70, +0x1c70, +0x1c70, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 35 (0x23): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | ************* | + | ************* | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | ************* | + | ************* | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1c70, +0x1c70, +0x1c70, +0x1c70, +0x1c70, +0x7ffc, +0x7ffc, +0x1c70, +0x1c70, +0x1c70, +0x1c70, +0x1c70, +0x1c70, +0x7ffc, +0x7ffc, +0x1c70, +0x1c70, +0x1c70, +0x1c70, +0x1c70, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 36 (0x24): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | *** | + | *** | + | *** | + | ********* | + | *********** | + | **** *** **** | + | *** *** *** | + | *** *** | + | *** *** | + | *** *** | + | **** *** | + | ********** | + | ********** | + | *** **** | + | *** *** | + | *** *** | + | *** *** | + | *** *** *** | + | **** *** **** | + | *********** | + | ********* | + | *** | + | *** | + | *** | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0380, +0x0380, +0x0380, +0x1ff0, +0x3ff8, +0x7bbc, +0x739c, +0x7380, +0x7380, +0x7380, +0x7b80, +0x3ff0, +0x1ff8, +0x03bc, +0x039c, +0x039c, +0x039c, +0x739c, +0x7bbc, +0x3ff8, +0x1ff0, +0x0380, +0x0380, +0x0380, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 37 (0x25): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ***** *** | + | ******* *** | + | *** *** *** | + | *** *** *** | + | ********** | + | ***** *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** ***** | + | ********** | + | *** *** *** | + | *** *** *** | + | *** ******* | + | *** ***** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1f1c, +0x3f9c, +0x3bb8, +0x3bb8, +0x3ff0, +0x1f70, +0x00e0, +0x00e0, +0x01c0, +0x01c0, +0x0380, +0x0380, +0x0700, +0x0700, +0x0ef8, +0x0ffc, +0x1ddc, +0x1ddc, +0x39fc, +0x38f8, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 38 (0x26): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ****** | + | ******** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | ****** | + | ***** | + | ******* *** | + | *** *** *** | + | *** ***** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | **** ***** | + | ********* *** | + | ******* *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0fc0, +0x1fe0, +0x3870, +0x3870, +0x3870, +0x3870, +0x3870, +0x1ce0, +0x0fc0, +0x0f80, +0x1fce, +0x38ee, +0x707c, +0x7038, +0x7038, +0x7038, +0x7038, +0x787c, +0x3fee, +0x1fce, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 39 (0x27): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 40 (0x28): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x00e0, +0x01c0, +0x0380, +0x0700, +0x0700, +0x0e00, +0x0e00, +0x0e00, +0x0e00, +0x0e00, +0x0e00, +0x0e00, +0x0e00, +0x0e00, +0x0e00, +0x0700, +0x0700, +0x0380, +0x01c0, +0x00e0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 41 (0x29): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0e00, +0x0700, +0x0380, +0x01c0, +0x01c0, +0x00e0, +0x00e0, +0x00e0, +0x00e0, +0x00e0, +0x00e0, +0x00e0, +0x00e0, +0x00e0, +0x00e0, +0x01c0, +0x01c0, +0x0380, +0x0700, +0x0e00, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 42 (0x2a): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | *** *** | + | *** *** | + | *** *** | + | ***** | + | *** | + | ************* | + | ************* | + | *** | + | ***** | + | *** *** | + | *** *** | + | *** *** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x3838, +0x1c70, +0x0ee0, +0x07c0, +0x0380, +0x7ffc, +0x7ffc, +0x0380, +0x07c0, +0x0ee0, +0x1c70, +0x3838, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 43 (0x2b): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | *** | + | *** | + | *** | + | *** | + | *** | + | ************* | + | ************* | + | *** | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x7ffc, +0x7ffc, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 44 (0x2c): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0380, +0x0380, +0x0380, +0x0380, +0x0700, +0x0e00, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 45 (0x2d): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ************* | + | ************* | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7ffc, +0x7ffc, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 46 (0x2e): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0380, +0x0380, +0x0380, +0x0380, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 47 (0x2f): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x001c, +0x001c, +0x0038, +0x0038, +0x0070, +0x0070, +0x00e0, +0x00e0, +0x01c0, +0x01c0, +0x0380, +0x0380, +0x0700, +0x0700, +0x0e00, +0x0e00, +0x1c00, +0x1c00, +0x3800, +0x3800, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 48 (0x30): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ********* | + | *********** | + | **** **** | + | *** *** | + | *** *** | + | *** **** | + | *** ***** | + | *** ****** | + | *** *** *** | + | *** *** *** | + | *** *** *** | + | ****** *** | + | ***** *** | + | **** *** | + | *** *** | + | *** *** | + | *** *** | + | **** **** | + | *********** | + | ********* | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1ff0, +0x3ff8, +0x783c, +0x701c, +0x701c, +0x703c, +0x707c, +0x70fc, +0x71dc, +0x739c, +0x771c, +0x7e1c, +0x7c1c, +0x781c, +0x701c, +0x701c, +0x701c, +0x783c, +0x3ff8, +0x1ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 49 (0x31): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *** | + | **** | + | ***** | + | ****** | + | ****** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | ********* | + | ********* | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0380, +0x0780, +0x0f80, +0x1f80, +0x1f80, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x1ff0, +0x1ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 50 (0x32): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ********* | + | *********** | + | **** **** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | ************* | + | ************* | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1ff0, +0x3ff8, +0x783c, +0x701c, +0x701c, +0x701c, +0x701c, +0x001c, +0x0038, +0x0070, +0x00e0, +0x01c0, +0x0380, +0x0700, +0x0e00, +0x1c00, +0x3800, +0x7000, +0x7ffc, +0x7ffc, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 51 (0x33): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ********* | + | *********** | + | **** **** | + | *** *** | + | *** *** | + | *** | + | *** | + | *** | + | **** | + | ********* | + | ********* | + | **** | + | *** | + | *** | + | *** | + | *** *** | + | *** *** | + | **** **** | + | *********** | + | ********* | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1ff0, +0x3ff8, +0x783c, +0x701c, +0x701c, +0x001c, +0x001c, +0x001c, +0x003c, +0x0ff8, +0x0ff8, +0x003c, +0x001c, +0x001c, +0x001c, +0x701c, +0x701c, +0x783c, +0x3ff8, +0x1ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 52 (0x34): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *** | + | **** | + | ***** | + | ****** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | ************* | + | ************* | + | *** | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x001c, +0x003c, +0x007c, +0x00fc, +0x01dc, +0x039c, +0x071c, +0x0e1c, +0x1c1c, +0x381c, +0x701c, +0x701c, +0x701c, +0x7ffc, +0x7ffc, +0x001c, +0x001c, +0x001c, +0x001c, +0x001c, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 53 (0x35): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ************* | + | ************* | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *********** | + | ************ | + | **** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** *** | + | **** *** | + | *********** | + | ********* | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7ffc, +0x7ffc, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7ff0, +0x7ff8, +0x003c, +0x001c, +0x001c, +0x001c, +0x001c, +0x001c, +0x701c, +0x781c, +0x3ff8, +0x1ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 54 (0x36): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ********** | + | *********** | + | **** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *********** | + | ************ | + | *** **** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | **** **** | + | *********** | + | ********* | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1ff8, +0x3ff8, +0x7800, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7ff0, +0x7ff8, +0x703c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x783c, +0x3ff8, +0x1ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 55 (0x37): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ************* | + | ************* | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7ffc, +0x7ffc, +0x701c, +0x701c, +0x701c, +0x7038, +0x0038, +0x0070, +0x0070, +0x00e0, +0x00e0, +0x01c0, +0x01c0, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 56 (0x38): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ********* | + | *********** | + | **** **** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | **** **** | + | *********** | + | *********** | + | **** **** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | **** **** | + | *********** | + | ********* | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1ff0, +0x3ff8, +0x783c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x783c, +0x3ff8, +0x3ff8, +0x783c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x783c, +0x3ff8, +0x1ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 57 (0x39): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ********* | + | *********** | + | **** **** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | **** *** | + | ************ | + | *********** | + | *** | + | *** | + | *** | + | *** | + | *** | + | **** | + | *********** | + | ********** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1ff0, +0x3ff8, +0x783c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x781c, +0x3ffc, +0x1ffc, +0x001c, +0x001c, +0x001c, +0x001c, +0x001c, +0x003c, +0x3ff8, +0x3ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 58 (0x3a): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0380, +0x0380, +0x0380, +0x0380, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0380, +0x0380, +0x0380, +0x0380, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 59 (0x3b): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0380, +0x0380, +0x0380, +0x0380, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0380, +0x0380, +0x0380, +0x0380, +0x0700, +0x0e00, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 60 (0x3c): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x001c, +0x0038, +0x0070, +0x00e0, +0x01c0, +0x0380, +0x0700, +0x0e00, +0x1c00, +0x3800, +0x3800, +0x1c00, +0x0e00, +0x0700, +0x0380, +0x01c0, +0x00e0, +0x0070, +0x0038, +0x001c, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 61 (0x3d): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ************* | + | ************* | + | | + | | + | | + | | + | ************* | + | ************* | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7ffc, +0x7ffc, +0x0000, +0x0000, +0x0000, +0x0000, +0x7ffc, +0x7ffc, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 62 (0x3e): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x3800, +0x1c00, +0x0e00, +0x0700, +0x0380, +0x01c0, +0x00e0, +0x0070, +0x0038, +0x001c, +0x001c, +0x0038, +0x0070, +0x00e0, +0x01c0, +0x0380, +0x0700, +0x0e00, +0x1c00, +0x3800, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 63 (0x3f): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ********* | + | *********** | + | **** **** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | | + | | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1ff0, +0x3ff8, +0x783c, +0x701c, +0x701c, +0x701c, +0x701c, +0x0038, +0x0070, +0x00e0, +0x01c0, +0x0380, +0x0380, +0x0380, +0x0000, +0x0000, +0x0380, +0x0380, +0x0380, +0x0380, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 64 (0x40): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ********** | + | ************ | + | **** *** | + | *** ** | + | *** ******** | + | *** ********* | + | *** **** *** | + | *** *** *** | + | *** *** *** | + | *** *** *** | + | *** *** *** | + | *** *** *** | + | *** *** *** | + | *** **** **** | + | *** ********* | + | *** ***** ** | + | *** | + | **** | + | ************* | + | ************ | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1ff8, +0x3ffc, +0x780e, +0x7006, +0x71fe, +0x73fe, +0x778e, +0x770e, +0x770e, +0x770e, +0x770e, +0x770e, +0x770e, +0x779e, +0x73fe, +0x71f6, +0x7000, +0x7800, +0x3ffe, +0x1ffe, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 65 (0x41): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ********* | + | *********** | + | **** **** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | ************* | + | ************* | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1ff0, +0x3ff8, +0x783c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x7ffc, +0x7ffc, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 66 (0x42): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *********** | + | ************ | + | *** **** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *********** | + | *********** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** **** | + | ************ | + | *********** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7ff0, +0x7ff8, +0x703c, +0x701c, +0x701c, +0x701c, +0x701c, +0x7038, +0x7ff0, +0x7ff0, +0x7038, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x703c, +0x7ff8, +0x7ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 67 (0x43): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ********* | + | *********** | + | **** **** | + | *** *** | + | *** *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** *** | + | *** *** | + | **** **** | + | *********** | + | ********* | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1ff0, +0x3ff8, +0x783c, +0x701c, +0x701c, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x701c, +0x701c, +0x783c, +0x3ff8, +0x1ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 68 (0x44): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ********* | + | *********** | + | *** **** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** **** | + | *********** | + | ********* | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7fc0, +0x7ff0, +0x7078, +0x7038, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x7038, +0x7078, +0x7ff0, +0x7fc0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 69 (0x45): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ************* | + | ************* | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | ********** | + | ********** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | ************* | + | ************* | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7ffc, +0x7ffc, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7fe0, +0x7fe0, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7ffc, +0x7ffc, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 70 (0x46): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ************* | + | ************* | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | ********** | + | ********** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7ffc, +0x7ffc, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7fe0, +0x7fe0, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 71 (0x47): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ********* | + | *********** | + | **** **** | + | *** *** | + | *** *** | + | *** | + | *** | + | *** | + | *** | + | *** ******* | + | *** ******* | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | **** **** | + | *********** | + | ********* | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1ff0, +0x3ff8, +0x783c, +0x701c, +0x701c, +0x7000, +0x7000, +0x7000, +0x7000, +0x71fc, +0x71fc, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x783c, +0x3ff8, +0x1ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 72 (0x48): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | ************* | + | ************* | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x7ffc, +0x7ffc, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 73 (0x49): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ******* | + | ******* | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | ******* | + | ******* | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0fe0, +0x0fe0, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0fe0, +0x0fe0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 74 (0x4a): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ******* | + | ******* | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** *** | + | *** *** | + | *** *** | + | **** **** | + | ********** | + | ******** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x00fe, +0x00fe, +0x0038, +0x0038, +0x0038, +0x0038, +0x0038, +0x0038, +0x0038, +0x0038, +0x0038, +0x0038, +0x0038, +0x0038, +0x7038, +0x7038, +0x7038, +0x7878, +0x3ff0, +0x1fe0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 75 (0x4b): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *** ** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | ****** | + | ***** | + | ***** | + | ****** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** ** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x700c, +0x701c, +0x7038, +0x7070, +0x70e0, +0x71c0, +0x7380, +0x7700, +0x7e00, +0x7c00, +0x7c00, +0x7e00, +0x7700, +0x7380, +0x71c0, +0x70e0, +0x7070, +0x7038, +0x701c, +0x700c, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 76 (0x4c): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | ************* | + | ************* | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7ffc, +0x7ffc, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 77 (0x4d): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *** *** | + | *** *** | + | **** **** | + | ***** ***** | + | ****** ****** | + | ****** ****** | + | *** ****** *** | + | *** **** *** | + | *** **** *** | + | *** ** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x700e, +0x700e, +0x781e, +0x7c3e, +0x7e7e, +0x7e7e, +0x77ee, +0x73ce, +0x73ce, +0x718e, +0x700e, +0x700e, +0x700e, +0x700e, +0x700e, +0x700e, +0x700e, +0x700e, +0x700e, +0x700e, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 78 (0x4e): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | **** *** | + | ***** *** | + | ****** *** | + | *** *** *** | + | *** *** *** | + | *** *** *** | + | *** ****** | + | *** ***** | + | *** **** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x781c, +0x7c1c, +0x7e1c, +0x771c, +0x739c, +0x71dc, +0x70fc, +0x707c, +0x703c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 79 (0x4f): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ********* | + | *********** | + | **** **** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | **** **** | + | *********** | + | ********* | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1ff0, +0x3ff8, +0x783c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x783c, +0x3ff8, +0x1ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 80 (0x50): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *********** | + | ************ | + | *** **** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** **** | + | ************ | + | *********** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7ff0, +0x7ff8, +0x703c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x703c, +0x7ff8, +0x7ff0, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 81 (0x51): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ********* | + | *********** | + | **** **** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** *** | + | **** ******* | + | *********** | + | ********* | + | *** | + | *** | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1ff0, +0x3ff8, +0x783c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x739c, +0x79fc, +0x3ff8, +0x1ff0, +0x0038, +0x001c, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 82 (0x52): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *********** | + | ************ | + | *** **** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** **** | + | ************ | + | *********** | + | ****** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7ff0, +0x7ff8, +0x703c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x703c, +0x7ff8, +0x7ff0, +0x7e00, +0x7700, +0x7380, +0x71c0, +0x70e0, +0x7070, +0x7038, +0x701c, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 83 (0x53): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ********* | + | *********** | + | **** **** | + | *** *** | + | *** *** | + | *** | + | *** | + | *** | + | **** | + | ********** | + | ********** | + | **** | + | *** | + | *** | + | *** | + | *** *** | + | *** *** | + | **** **** | + | *********** | + | ********* | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1ff0, +0x3ff8, +0x783c, +0x701c, +0x701c, +0x7000, +0x7000, +0x7000, +0x7800, +0x3ff0, +0x1ff8, +0x003c, +0x001c, +0x001c, +0x001c, +0x701c, +0x701c, +0x783c, +0x3ff8, +0x1ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 84 (0x54): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ************* | + | ************* | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7ffc, +0x7ffc, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 85 (0x55): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | **** **** | + | *********** | + | ********* | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x783c, +0x3ff8, +0x1ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 86 (0x56): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | ***** | + | ***** | + | ***** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x3838, +0x3838, +0x3838, +0x3838, +0x3838, +0x1c70, +0x1c70, +0x1c70, +0x1c70, +0x0ee0, +0x0ee0, +0x0ee0, +0x07c0, +0x07c0, +0x07c0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 87 (0x57): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** ** *** | + | *** **** *** | + | *** **** *** | + | *** ****** *** | + | ****** ****** | + | ****** ****** | + | ***** ***** | + | **** **** | + | *** *** | + | *** *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x700e, +0x700e, +0x700e, +0x700e, +0x700e, +0x700e, +0x700e, +0x700e, +0x700e, +0x700e, +0x718e, +0x73ce, +0x73ce, +0x77ee, +0x7e7e, +0x7e7e, +0x7c3e, +0x781e, +0x700e, +0x700e, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 88 (0x58): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | ***** | + | ***** | + | ***** | + | ***** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x701c, +0x701c, +0x3838, +0x3838, +0x1c70, +0x1c70, +0x0ee0, +0x0ee0, +0x07c0, +0x07c0, +0x07c0, +0x07c0, +0x0ee0, +0x0ee0, +0x1c70, +0x1c70, +0x3838, +0x3838, +0x701c, +0x701c, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 89 (0x59): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | ***** | + | ***** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x701c, +0x701c, +0x701c, +0x3838, +0x3838, +0x1c70, +0x1c70, +0x0ee0, +0x0ee0, +0x07c0, +0x07c0, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 90 (0x5a): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ************* | + | ************* | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | ************* | + | ************* | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7ffc, +0x7ffc, +0x001c, +0x001c, +0x001c, +0x0038, +0x0070, +0x00e0, +0x01c0, +0x0380, +0x0700, +0x0e00, +0x1c00, +0x3800, +0x7000, +0x7000, +0x7000, +0x7000, +0x7ffc, +0x7ffc, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 91 (0x5b): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ******** | + | ******** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | ******** | + | ******** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0ff0, +0x0ff0, +0x0e00, +0x0e00, +0x0e00, +0x0e00, +0x0e00, +0x0e00, +0x0e00, +0x0e00, +0x0e00, +0x0e00, +0x0e00, +0x0e00, +0x0e00, +0x0e00, +0x0e00, +0x0e00, +0x0ff0, +0x0ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 92 (0x5c): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x3800, +0x3800, +0x1c00, +0x1c00, +0x0e00, +0x0e00, +0x0700, +0x0700, +0x0380, +0x0380, +0x01c0, +0x01c0, +0x00e0, +0x00e0, +0x0070, +0x0070, +0x0038, +0x0038, +0x001c, +0x001c, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 93 (0x5d): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ******** | + | ******** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | ******** | + | ******** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0ff0, +0x0ff0, +0x0070, +0x0070, +0x0070, +0x0070, +0x0070, +0x0070, +0x0070, +0x0070, +0x0070, +0x0070, +0x0070, +0x0070, +0x0070, +0x0070, +0x0070, +0x0070, +0x0ff0, +0x0ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 94 (0x5e): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | *** | + | ***** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0380, +0x07c0, +0x0ee0, +0x1c70, +0x3838, +0x701c, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 95 (0x5f): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ************* | + | ************* | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7ffc, +0x7ffc, +0x0000, +0x0000, +0x0000, + +/* Character 96 (0x60): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x1c00, +0x0e00, +0x0700, +0x0380, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 97 (0x61): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ********** | + | *********** | + | **** | + | *** | + | *** | + | *********** | + | ************ | + | **** *** | + | *** *** | + | *** *** | + | *** *** | + | **** *** | + | ************ | + | *********** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x3ff0, +0x3ff8, +0x003c, +0x001c, +0x001c, +0x1ffc, +0x3ffc, +0x781c, +0x701c, +0x701c, +0x701c, +0x781c, +0x3ffc, +0x1ffc, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 98 (0x62): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *********** | + | ************ | + | *** **** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** **** | + | ************ | + | *********** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7ff0, +0x7ff8, +0x703c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x703c, +0x7ff8, +0x7ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 99 (0x63): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ********* | + | *********** | + | **** **** | + | *** *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** *** | + | **** **** | + | *********** | + | ********* | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1ff0, +0x3ff8, +0x783c, +0x701c, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x701c, +0x783c, +0x3ff8, +0x1ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 100 (0x64): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *********** | + | ************ | + | **** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | **** *** | + | ************ | + | *********** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x001c, +0x001c, +0x001c, +0x001c, +0x001c, +0x001c, +0x1ffc, +0x3ffc, +0x781c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x781c, +0x3ffc, +0x1ffc, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 101 (0x65): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ********* | + | *********** | + | **** **** | + | *** *** | + | *** *** | + | *** *** | + | ************* | + | ************* | + | *** | + | *** | + | *** | + | **** *** | + | ************ | + | ********** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1ff0, +0x3ff8, +0x783c, +0x701c, +0x701c, +0x701c, +0x7ffc, +0x7ffc, +0x7000, +0x7000, +0x7000, +0x781c, +0x3ffc, +0x1ff8, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 102 (0x66): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ******* | + | ******** | + | **** | + | *** | + | *** | + | *** | + | *********** | + | *********** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x00fe, +0x01fe, +0x03c0, +0x0380, +0x0380, +0x0380, +0x3ff8, +0x3ff8, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 103 (0x67): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | *********** | + | ************ | + | **** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | **** *** | + | ************ | + | *********** | + | *** | + | *** | + | *** | + | *********** | + | ********** | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1ffc, +0x3ffc, +0x781c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x781c, +0x3ffc, +0x1ffc, +0x001c, +0x001c, +0x001c, +0x3ff8, +0x3ff0, +0x0000, + +/* Character 104 (0x68): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *********** | + | ************ | + | *** **** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7ff0, +0x7ff8, +0x703c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 105 (0x69): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *** | + | *** | + | *** | + | *** | + | | + | | + | ***** | + | ***** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | ******* | + | ******* | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0380, +0x0380, +0x0380, +0x0380, +0x0000, +0x0000, +0x0f80, +0x0f80, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0fe0, +0x0fe0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 106 (0x6a): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *** | + | *** | + | *** | + | *** | + | | + | | + | ***** | + | ***** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** *** | + | *** *** | + | **** **** | + | ********* | + | ******* | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0038, +0x0038, +0x0038, +0x0038, +0x0000, +0x0000, +0x00f8, +0x00f8, +0x0038, +0x0038, +0x0038, +0x0038, +0x0038, +0x0038, +0x0038, +0x0038, +0x0038, +0x0038, +0x0038, +0x0038, +0x3838, +0x3838, +0x3c78, +0x1ff0, +0x0fe0, +0x0000, + +/* Character 107 (0x6b): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | ****** | + | ****** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x3800, +0x3800, +0x3800, +0x3800, +0x3800, +0x3800, +0x381c, +0x3838, +0x3870, +0x38e0, +0x39c0, +0x3b80, +0x3f00, +0x3f00, +0x3b80, +0x39c0, +0x38e0, +0x3870, +0x3838, +0x381c, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 108 (0x6c): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ***** | + | ***** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | ******* | + | ******* | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0f80, +0x0f80, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0fe0, +0x0fe0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 109 (0x6d): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | *********** | + | ************ | + | *** *** **** | + | *** *** *** | + | *** *** *** | + | *** *** *** | + | *** *** *** | + | *** *** *** | + | *** *** *** | + | *** *** *** | + | *** *** *** | + | *** *** *** | + | *** *** *** | + | *** *** *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7ff0, +0x7ff8, +0x73bc, +0x739c, +0x739c, +0x739c, +0x739c, +0x739c, +0x739c, +0x739c, +0x739c, +0x739c, +0x739c, +0x739c, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 110 (0x6e): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | *********** | + | ************ | + | *** **** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7ff0, +0x7ff8, +0x703c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 111 (0x6f): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ********* | + | *********** | + | **** **** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | **** **** | + | *********** | + | ********* | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1ff0, +0x3ff8, +0x783c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x783c, +0x3ff8, +0x1ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 112 (0x70): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | *********** | + | ************ | + | *** **** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** **** | + | ************ | + | *********** | + | *** | + | *** | + | *** | + | *** | + | *** | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7ff0, +0x7ff8, +0x703c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x703c, +0x7ff8, +0x7ff0, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x0000, + +/* Character 113 (0x71): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | *********** | + | ************ | + | **** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | **** *** | + | ************ | + | *********** | + | *** | + | *** | + | *** | + | *** | + | *** | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1ffc, +0x3ffc, +0x781c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x781c, +0x3ffc, +0x1ffc, +0x001c, +0x001c, +0x001c, +0x001c, +0x001c, +0x0000, + +/* Character 114 (0x72): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | *** ******** | + | *** ********* | + | ****** | + | ***** | + | **** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x73fc, +0x77fc, +0x7e00, +0x7c00, +0x7800, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x7000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 115 (0x73): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ********* | + | *********** | + | **** **** | + | *** | + | *** | + | **** | + | ********** | + | ********** | + | **** | + | *** | + | *** | + | **** **** | + | *********** | + | ********* | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x1ff0, +0x3ff8, +0x783c, +0x7000, +0x7000, +0x7800, +0x3ff0, +0x1ff8, +0x003c, +0x001c, +0x001c, +0x783c, +0x3ff8, +0x1ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 116 (0x74): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *********** | + | *********** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | **** | + | ******** | + | ******* | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0700, +0x0700, +0x0700, +0x0700, +0x0700, +0x0700, +0x7ff0, +0x7ff0, +0x0700, +0x0700, +0x0700, +0x0700, +0x0700, +0x0700, +0x0700, +0x0700, +0x0700, +0x0780, +0x03fc, +0x01fc, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 117 (0x75): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | **** *** | + | ************ | + | *********** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x781c, +0x3ffc, +0x1ffc, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 118 (0x76): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | ***** | + | ***** | + | ***** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x701c, +0x701c, +0x701c, +0x3838, +0x3838, +0x3838, +0x1c70, +0x1c70, +0x1c70, +0x0ee0, +0x0ee0, +0x07c0, +0x07c0, +0x07c0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 119 (0x77): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** *** | + | *** *** *** | + | *** *** *** | + | *** *** *** | + | *** *** *** | + | *** *** *** | + | *** *** *** | + | **** *** **** | + | *********** | + | ********* | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x701c, +0x701c, +0x701c, +0x701c, +0x739c, +0x739c, +0x739c, +0x739c, +0x739c, +0x739c, +0x739c, +0x7bbc, +0x3ff8, +0x1ff0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 120 (0x78): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | ***** | + | ***** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x701c, +0x701c, +0x701c, +0x3838, +0x1c70, +0x0ee0, +0x07c0, +0x07c0, +0x0ee0, +0x1c70, +0x3838, +0x701c, +0x701c, +0x701c, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 121 (0x79): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | *** *** | + | **** *** | + | ************ | + | *********** | + | *** | + | *** | + | **** | + | *********** | + | ********** | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x701c, +0x781c, +0x3ffc, +0x1ffc, +0x001c, +0x001c, +0x003c, +0x3ff8, +0x3ff0, +0x0000, + +/* Character 122 (0x7a): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ************* | + | ************* | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | ************* | + | ************* | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x7ffc, +0x7ffc, +0x0038, +0x0070, +0x00e0, +0x01c0, +0x0380, +0x0700, +0x0e00, +0x1c00, +0x3800, +0x7000, +0x7ffc, +0x7ffc, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 123 (0x7b): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ***** | + | ****** | + | **** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | ***** | + | ***** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | **** | + | ****** | + | ***** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x01f0, +0x03f0, +0x0780, +0x0700, +0x0700, +0x0700, +0x0700, +0x0700, +0x0700, +0x3e00, +0x3e00, +0x0700, +0x0700, +0x0700, +0x0700, +0x0700, +0x0700, +0x0780, +0x03f0, +0x01f0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 124 (0x7c): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 125 (0x7d): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | ***** | + | ****** | + | **** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | ***** | + | ***** | + | *** | + | *** | + | *** | + | *** | + | *** | + | *** | + | **** | + | ****** | + | ***** | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x3e00, +0x3f00, +0x0780, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x01f0, +0x01f0, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0380, +0x0780, +0x3f00, +0x3e00, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + +/* Character 126 (0x7e): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | **** *** | + | ****** *** | + | *** **** *** | + | *** **** *** | + | *** ****** | + | *** **** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x1e1c, +0x3f1c, +0x779c, +0x73dc, +0x71f8, +0x70f0, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +}; + +/* Exported structure definition. */ +static const FontDesc stella16x32tDesc = { + "ter-u32b", + 16, + 32, + 16, 32, 0, -6, + 26, + 29, + 98, + stella16x32t_font_bits, + 0, /* no encode table*/ + 0, /* fixed width*/ + 0, /* fixed bbox*/ + 32, + sizeof(stella16x32t_font_bits)/sizeof(uInt16) +}; + +} // End of namespace GUI + +#endif diff --git a/src/gui/UIDialog.cxx b/src/gui/UIDialog.cxx index 287659912..175b8624b 100644 --- a/src/gui/UIDialog.cxx +++ b/src/gui/UIDialog.cxx @@ -216,10 +216,13 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, // Launcher font pwidth = font.getStringWidth("2x (1000x760)"); items.clear(); - VarList::push_back(items, "Small", "small"); - VarList::push_back(items, "Small Medium", "small_medium"); - VarList::push_back(items, "Medium", "medium"); - VarList::push_back(items, "Large", "large"); + VarList::push_back(items, "Small", "small"); // 8x13 + VarList::push_back(items, "Low Medium", "low_medium"); // 9x15 + VarList::push_back(items, "Medium", "medium"); // 9x18 + VarList::push_back(items, "Large (10pt)", "large"); // 10x20 + VarList::push_back(items, "Large (12pt)", "large12"); // 12x24 + VarList::push_back(items, "Large (14pt)", "large14"); // 14x28 + VarList::push_back(items, "Large (16pt)", "large16"); // 16x32 myLauncherFontPopup = new PopUpWidget(myTab, font, xpos, ypos + 1, pwidth, lineHeight, items, "Launcher font ", lwidth); diff --git a/src/tools/convbdf.c b/src/tools/convbdf.c index c82dfa307..d6c661567 100644 --- a/src/tools/convbdf.c +++ b/src/tools/convbdf.c @@ -980,7 +980,7 @@ int gen_c_source(struct font* pf, char *path) fontname); fprintf(ofp, "\n} // End of namespace GUI\n\n#endif\n"); - fcloise(ofp); + fclose(ofp); return 0; } diff --git a/src/unix/r77/SettingsR77.cxx b/src/unix/r77/SettingsR77.cxx index c3f0d61fd..2b3dc0525 100644 --- a/src/unix/r77/SettingsR77.cxx +++ b/src/unix/r77/SettingsR77.cxx @@ -50,7 +50,7 @@ SettingsR77::SettingsR77() setPermanent("snaploaddir", "/mnt/stella/snapshots"); setPermanent("launcherres", "1280x720"); - setPermanent("launcherfont", "large"); + setPermanent("launcherfont", "large12"); setPermanent("romviewer", "1.6"); setPermanent("exitlauncher", "true"); From 783318876d7fa1fece55133ca516e1a644f8be0c Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sun, 15 Mar 2020 14:02:52 -0230 Subject: [PATCH 022/377] Fixed minor compile warnings, including incorrect output from convbdf tool. --- src/gui/LauncherDialog.cxx | 2 +- src/gui/Stella14x28tFont.hxx | 6 +++--- src/gui/Stella16x32tFont.hxx | 6 +++--- src/tools/convbdf.c | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/gui/LauncherDialog.cxx b/src/gui/LauncherDialog.cxx index 7a58e215d..c33832ce9 100644 --- a/src/gui/LauncherDialog.cxx +++ b/src/gui/LauncherDialog.cxx @@ -384,7 +384,7 @@ void LauncherDialog::setRomInfoFont(const Common::Size& area) }; // Try to pick a font that works best, based on the available area - for(int i = 0; i < sizeof(FONTS) / sizeof(FontDesc); ++i) + for(size_t i = 0; i < sizeof(FONTS) / sizeof(FontDesc); ++i) { // only use fonts <= launcher fonts if(instance().frameBuffer().launcherFont().getFontHeight() >= FONTS[i].height) diff --git a/src/gui/Stella14x28tFont.hxx b/src/gui/Stella14x28tFont.hxx index 28151f725..2ce818d7c 100644 --- a/src/gui/Stella14x28tFont.hxx +++ b/src/gui/Stella14x28tFont.hxx @@ -6325,9 +6325,9 @@ static const FontDesc stella14x28tDesc = { 29, 98, stella14x28t_font_bits, - 0, /* no encode table*/ - 0, /* fixed width*/ - 0, /* fixed bbox*/ + nullptr, /* no encode table*/ + nullptr, /* fixed width*/ + nullptr, /* fixed bbox*/ 32, sizeof(stella14x28t_font_bits)/sizeof(uInt16) }; diff --git a/src/gui/Stella16x32tFont.hxx b/src/gui/Stella16x32tFont.hxx index 0f74d3b4e..15c1e7b4c 100644 --- a/src/gui/Stella16x32tFont.hxx +++ b/src/gui/Stella16x32tFont.hxx @@ -7109,9 +7109,9 @@ static const FontDesc stella16x32tDesc = { 29, 98, stella16x32t_font_bits, - 0, /* no encode table*/ - 0, /* fixed width*/ - 0, /* fixed bbox*/ + nullptr, /* no encode table*/ + nullptr, /* fixed width*/ + nullptr, /* fixed bbox*/ 32, sizeof(stella16x32t_font_bits)/sizeof(uInt16) }; diff --git a/src/tools/convbdf.c b/src/tools/convbdf.c index d6c661567..992095600 100644 --- a/src/tools/convbdf.c +++ b/src/tools/convbdf.c @@ -936,17 +936,17 @@ int gen_c_source(struct font* pf, char *path) if (pf->offset) sprintf(obuf, "%s_sysfont_offset,", fontname); else - sprintf(obuf, "0, /* no encode table*/"); + sprintf(obuf, "nullptr, /* no encode table*/"); if (pf->width) sprintf(buf, "%s_sysfont_width,", fontname); else - sprintf(buf, "0, /* fixed width*/"); + sprintf(buf, "nullptr, /* fixed width*/"); if (pf->bbx) sprintf(bbuf, "%s_sysfont_bbx,", fontname); else - sprintf(bbuf, "0, /* fixed bbox*/"); + sprintf(bbuf, "nullptr, /* fixed bbox*/"); fprintf(ofp, "/* Exported structure definition. */\n" From 51c9ca719e03957c6e8f829e13e1c48586707bc9 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 15 Mar 2020 19:15:27 +0100 Subject: [PATCH 023/377] doc and usage() update for new launcher font sizes --- docs/index.html | 2 +- src/emucore/Settings.cxx | 24 +++++++++++++++--------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/docs/index.html b/docs/index.html index 2f750bde9..7fd6920fc 100644 --- a/docs/index.html +++ b/docs/index.html @@ -2371,7 +2371,7 @@ - + diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index e46b192a3..eabe55dbf 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -410,7 +410,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_overscan <0-10> Add overscan to TIA image in fill fullscreen mode\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" << endl @@ -467,23 +467,27 @@ void Settings::usage() const << " -ssinterval Number of seconds between snapshots in\n" << " continuous snapshot mode\n" << endl - << " -saveonexit \n" + << " -saveonexit emulation\n" << " -autoslot <1|0> Automatically change to next save slot when\n" << " state saving\n" << endl << " -rominfo Display detailed information for the given ROM\n" << " -listrominfo Display contents of stella.pro, one line per ROM\n" << " entry\n" - << " \n" + << endl << " -exitlauncher <1|0> On exiting a ROM, go back to the ROM launcher\n" << " -launcherres The resolution to use in ROM launcher mode\n" - << " -launcherfont \n" + << " -launcherfont \n" << " -launcherroms <1|0> Show only ROMs in the launcher (vs. all files)\n" << " -romviewer Show ROM info viewer at given zoom level in ROM\n" << " launcher (use 0 for off)\n" - << " -lastrom Last played ROM, automatically selected in launcher\n" + << " -lastrom Last played ROM, automatically selected in\n" + << " launcher\n" << " -romloadcount Number of ROM to load next from multicard\n" << " -uipalette \n" @@ -496,9 +500,11 @@ void Settings::usage() const << " UI\n" << " -mdouble Mouse double click speed in UI\n" << " -ctrldelay Delay before controller input is repeated in UI\n" - << " -ctrlrate Rate per second of repeated controller input in UI\n" + << " -ctrlrate Rate per second of repeated controller input in\n" + << " UI\n" << " -basic_settings <0|1> Display only a basic settings dialog\n" - << " -romdir Set the directory where the ROM launcher will start\n" + << " -romdir Set the directory where the ROM launcher will\n" + << " start\n" << " -avoxport The name of the serial port where an AtariVox is\n" << " connected\n" << " -holdreset Start the emulator with the Game Reset switch\n" From 85b5390e5d75e09efab76adabf27d0db53ef055e Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sun, 15 Mar 2020 15:54:31 -0230 Subject: [PATCH 024/377] Make a few games that offer a choice of Joystick/Genesis to use Joystick by default. Remove redundant 'Display.Format' stuff from properties, since it can now be deduced from the ROM name. --- src/emucore/DefProps.hxx | 158 +++++++++++++++++++-------------------- src/emucore/stella.pro | 86 ++------------------- 2 files changed, 85 insertions(+), 159 deletions(-) diff --git a/src/emucore/DefProps.hxx b/src/emucore/DefProps.hxx index b0e4f9a34..0f112214a 100644 --- a/src/emucore/DefProps.hxx +++ b/src/emucore/DefProps.hxx @@ -69,7 +69,7 @@ static const BSPF::array2D DefProps = {{ { "033e21521e0bf4e54e8816873943406d", "20th Century Fox Video Games - Sirius Software, Dan Thompson", "11020", "Earth Dies Screaming, The (1983) (20th Century Fox)", "The Day the Earth Stood Still", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "034c1434280b0f2c9f229777d790d1e1", "Telegames", "5665 A016", "Baseball (1988) (Telegames) (PAL)", "AKA Super Challenge Baseball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0375f589f7da06d2d2be532e0d4d4b94", "", "", "Push (V0.04) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0383dc02cb82302da3d155fd108bfe3a", "AtariAge, Chris Spry", "CX26200", "Princess Rescue (2013) (Sprybug) (PAL60)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "YES", "" }, + { "0383dc02cb82302da3d155fd108bfe3a", "AtariAge, Chris Spry", "CX26200", "Princess Rescue (2013) (Sprybug) (PAL60)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "JOYSTICK", "", "", "", "", "", "YES", "" }, { "038e1e79c3d4410defde4bfe0b99cc32", "Atari, Tod Frye, Gary Shannon", "", "Aquaventure (08-12-1983) (Atari) (Prototype)", "AKA Sea Sentinel", "Unbelievably Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "039cf18b459d33b8a8fca31d06c4c244", "", "", "Demo Image Series #0 (12-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "03b1051c9374678363c899914412cfc5", "", "", "Incoming (30-10-2002) (Ben Larson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -110,7 +110,7 @@ static const BSPF::array2D DefProps = {{ { "0651216c4a4a9c9ac5ada3013a317c72", "Jone Yuan Telephonic Enterprise Co", "", "Fishing Derby (Jone Yuan) (4K) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "06742cf522f23797157f215a1dc8a1a9", "", "", "Healthbars (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0685bd0bcb975ceef7041749a5454a48", "Piero Cavina", "", "11 Sprite Demo (Piero Cavina) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "069c17beb1e8e0557adb8539fdcf6cba", "", "", "Phantom II & Pirate (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "069c17beb1e8e0557adb8539fdcf6cba", "", "", "Phantom II & Pirate (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "06b0194ce992584c365278e0d7323279", "Activision", "", "Unknown Activision Game #2 (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "06b6c5031b8353f3a424a5b86b8fe409", "Activision, Mike Lorenzen - Ariola", "EAX-023 - 711 023-720", "Oink! (1983) (Activision) (PAL)", "AKA Das Schweinchen und der Wolf", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "06cfd57f0559f38b9293adae9128ff88", "Telegames", "4317 A009", "Adventures on GX-12 (1988) (Telegames) (PAL)", "AKA Adventures of Tron", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -140,7 +140,7 @@ static const BSPF::array2D DefProps = {{ { "085322bae40d904f53bdcc56df0593fc", "Parker Brothers, Dave Engman, Dawn Stockbridge", "PB5340", "Tutankham (1983) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0856f202b18cd46e44fd1dc3b42e9bfb", "", "", "Frame Counter 1 (2001) (Jake Patterson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0866e22f6f56f92ea1a14c8d8d01d29c", "Androbot - Western Technologies, Michael Case, Lenny Carlson", "", "AndroMan on the Moon (1984) (Western Tech) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0891252ee4e307689febccf3cfd8a8ab", "Thomas Jentzsch", "", "Centipede - Atari Trak-Ball Hack v1.4 (PAL60) (Half-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "0891252ee4e307689febccf3cfd8a8ab", "Thomas Jentzsch", "", "Centipede - Atari Trak-Ball Hack v1.4 (PAL60) (Half-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0894aa7be77521f9df562be8d9555fe6", "CBS Electronics, Dan Kitchen, Garry Kitchen", "4L1700, 4L1701, 4L1702, 4L1802, 4L2274", "Donkey Kong (1982) (CBS Electronics) (PAL) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "08989fa4ff537f5dbd611aff4019521a", "Atari, Gary Palmer", "CX26163P", "Fun with Numbers (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "08bd4c1dcc843f6a0b563d9fd80b3b11", "Quelle", "343.273 9", "Phantompanzer II (1983) (Quelle) (PAL)", "AKA Thunderground", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -148,7 +148,7 @@ static const BSPF::array2D DefProps = {{ { "08d1b6d75206edb999252caf542a2c7f", "Larry Petit", "", "Super Home Run (2003) (Larry Petit) (Hack)", "Hack of Home Run", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "08d60a58a691c7f690162850302dc0e1", "", "", "Poker Squares (V0.27) (PAL) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "08e5960bb52d9a3e2c9954677b5e4472", "Atari - CCW, Christopher H. Omarzu, Preston Stuart, Bruce Williams", "CX26101", "Oscar's Trash Race (10-20-1982) (Atari) (Prototype)", "Uses the Keypad Controllers", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "08ea2fdaa22e5802c839ee7dfb0483dc", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Atari Trak-Ball Hack v1.2 (PAL60) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "08ea2fdaa22e5802c839ee7dfb0483dc", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Atari Trak-Ball Hack v1.2 (PAL60) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "08f4dc6f118f7c98e2406c180c08e78e", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix - Tug of War (2 of 3) (1983) (Arcadia) (PAL)", "Uses Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "02", "", "", "", "" }, { "08f853e8e01e711919e734d85349220d", "Atari, Jerome Domurat, Michael Sierchio", "CX2667", "RealSports Soccer (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0906c6e0e4bda9c10cfa4c5fc64d2f4b", "Retroactive", "", "Qb (V0.12) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, @@ -194,7 +194,7 @@ static const BSPF::array2D DefProps = {{ { "0c35806ff0019a270a7acae68de89d28", "Froggo", "FG1003", "Task Force (1987) (Froggo)", "AKA Gangster Alley", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0c48e820301251fbb6bcdc89bd3555d9", "Atari, Bill Aspromonte, Andrew Fuchs", "CX26120", "Stargate (1984) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0c54811cf3b1f1573c9164d5f19eca65", "Activision, David Crane - Ariola", "EAG-001, PAG-001, EAG-001-04B, EAG-001-04I - 711 001-715", "Dragster (1980) (Activision) (PAL)", "AKA Dragster Rennen, Drag Strip", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0c72cc3a6658c1abd4b735ef55fa72e4", "Dion Olsthoorn", "v1.3", "Amoeba Jump (2018) (Dionoid) (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "0c72cc3a6658c1abd4b735ef55fa72e4", "Dion Olsthoorn", "v1.3", "Amoeba Jump (2018) (Dionoid) (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0c7926d660f903a2d6910c254660c32c", "Atari, Larry Kaplan", "CX2602, CX2602P", "Air-Sea Battle (1977) (Atari) (PAL)", "AKA Anti-Aircraft", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0c7bd935d9a7f2522155e48315f44fa0", "Carrere Video - Western Technologies, Jeff Corsiglia, Paul Allen Newell, Tom Sloper - Teldec - Prism", "USC1009", "Infernal Tower (1983) (Carrere Video) (PAL)", "AKA Towering Inferno", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "YES", "" }, { "0c80751f6f7a3b370cc9e9f39ad533a7", "Atari, Carla Meninsky", "CX2610", "Warlords (1981) (Atari) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, @@ -202,7 +202,7 @@ static const BSPF::array2D DefProps = {{ { "0cc8224ff1edfe458e8629e9e5fe3f5b", "Thomas Jentzsch", "", "Trick 12 (2001) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0cdd9cc692e8b04ba8eb31fc31d72e5e", "Thomas Jentzsch", "", "Wing War (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0cebb0bb45a856b23f56d21ce7d1bc34", "20th Century Fox Video Games, Bill Aspromonte", "11131", "Crash Dive (1983) (20th Century Fox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0cec9e46a25d338bf595a29aa2606516", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Atari Mouse Hack v1.1 (PAL60) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "0cec9e46a25d338bf595a29aa2606516", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Atari Mouse Hack v1.1 (PAL60) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0cfdd2f3b243cac21f38a0f09f54bead", "", "", "Overhead Adventure Demo 4 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0d07d2c1be1a5eaaea235a533bcda781", "", "", "Scrolling Playfield 1 (Junkosoft) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0d08558f34a47e4eaa39d01c8efb81f0", "Thomas Jentzsch", "", "Missile Control - Atari Mouse Hack v1.15 (NTSC) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -222,7 +222,7 @@ static const BSPF::array2D DefProps = {{ { "0e0808227ef41f6825c06f25082c2e56", "", "", "Candi (Hack) [a]", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0e08cd2c5bcf11c6a7e5a009a7715b6a", "", "", "Boing! (PD) [a1]", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0e224ea74310da4e7e2103400eb1b4bf", "Atari, Peter C. Niday, Gary Shannon, Howard Scott Warshaw", "", "Mind Maze (10-10-1984) (Atari) (Prototype)", "Uses the MindLink controller", "Prototype", "", "", "", "", "", "", "", "", "MINDLINK", "", "", "", "", "", "" }, - { "0e23d0ed4c33b2011ab4cc93a7619683", "Thomas Jentzsch", "", "Centipede - Amiga Mouse Hack v1.4 (PAL60) (Half-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "0e23d0ed4c33b2011ab4cc93a7619683", "Thomas Jentzsch", "", "Centipede - Amiga Mouse Hack v1.4 (PAL60) (Half-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0e4b2b6e014a93ef8be896823da0d4ec", "", "", "Skiing (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0e713d4e272ea7322c5b27d645f56dd0", "Home Vision - Gem International Corp. - VDI", "VCS83105", "Panda Chase (1983) (Home Vision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0e7e73421606873b544e858c59dc283e", "Digivision", "", "Super Soccer (Digivision)", "AKA RealSports Soccer", "", "", "", "F8", "", "", "", "", "", "", "", "", "", "", "YES", "" }, @@ -246,7 +246,7 @@ static const BSPF::array2D DefProps = {{ { "0f8043715d66a4bbed394ef801d99862", "Quelle", "684.733 9", "Robin Hood (1983) (Quelle) (PAL)", "AKA Save Our Ship", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0f95264089c99fc2a839a19872552004", "Activision, David Crane", "AG-009, AG-009-04", "Freeway (1981) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0fba7d8c3520bdb681f75494e498ec36", "", "", "Gunfight 2600 - Final Run (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0fbf618be43d4396856d4244126fe7dc", "Quelle", "805.784 6", "Labyrinth (1983) (Quelle) (PAL)", "AKA Maze Craze", "", "", "", "", "", "", "", "", "", "", "", "", "PAL", "", "", "" }, + { "0fbf618be43d4396856d4244126fe7dc", "Quelle", "805.784 6", "Labyrinth (1983) (Quelle) (PAL)", "AKA Maze Craze", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0fc161704c46e16f7483f92b06c1558d", "CCE", "C-853", "Spider Fighter (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0fcff6fe3b0769ad5d0cf82814d2a6d9", "Suntek", "SS-027", "Zoo Fun (1983) (Suntek) (PAL)", "AKA Panda Chase", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0fd72a13b3b6103fc825a692c71963b4", "Imagic, Rob Fulop", "720104-2A, IA3204P, EIX-008-04I", "Cosmic Ark (1982) (Imagic) (PAL) [selectable starfield]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -255,7 +255,7 @@ static const BSPF::array2D DefProps = {{ { "102672bbd7e25cd79f4384dd7214c32b", "Atari, Alan Miller - Sears", "CX2642 - 6-99814", "Hunt & Score - Memory Match (1978) (Atari)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "103e9d616328969f5d7b4e0a381b25d5", "", "", "Playfield Illustration and Logo Demo (2001) (Jake Patterson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "103f1756d9dc0dd2b16b53ad0f0f1859", "Home Vision, Gem International Corp.", "", "Go Go Home Monster (1983) (Home Vision) (PAL)", "AKA Go Go Home", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "104468e44898b8e9fa4a1500fde8d4cb", "AtariAge, Chris Spry", "CX26200", "Princess Rescue (2013) (Sprybug)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "104468e44898b8e9fa4a1500fde8d4cb", "AtariAge, Chris Spry", "CX26200", "Princess Rescue (2013) (Sprybug)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "JOYSTICK", "", "", "", "", "", "YES", "" }, { "106326c262dfd3e8eaeabd961d2a0519", "", "", "PAL-NTSC Detector (15-11-2002) (CT)[a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "106855474c69d08c8ffa308d47337269", "Atari - Sculptured Software, Adam Clayton", "CX26151", "Dark Chambers (1989) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "107cc025334211e6d29da0b6be46aec7", "Atari, Bob Smith - Sears", "CX2648 - 49-75161", "Video Pinball (1981) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -351,7 +351,7 @@ static const BSPF::array2D DefProps = {{ { "16f494f20af5dc803bc35939ef924020", "Mark De Smet", "", "Video Simon (Mark De Smet)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "170e7589a48739cfb9cc782cbb0fe25a", "M Network - INTV - APh Technological Consulting, Hal Finney", "MT5666", "Astroblast (1982) (M Network) [fixed]", "Can also use left joystick", "Uncommon", "", "", "", "", "", "", "", "PADDLES", "", "YES", "AUTO 55", "", "", "", "" }, { "171cd6b55267573e6a9c2921fb720794", "Kurt Howe", "", "Adventure 34 (Kurt Howe) (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "171ebf135b13ba907f462c10d88a2c25", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Amiga Mouse Hack v1.1 (PAL60) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "171ebf135b13ba907f462c10d88a2c25", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Amiga Mouse Hack v1.1 (PAL60) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1733772165d7b886a94e2b4ed0f74ccd", "", "", "Boring Journey Escape (Hack)", "Hack of Journey - Escape", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1738b2e3f25ab3eef3cecb95e1d0d957", "", "", "Hangman Monkey Biglist1 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "17512d0c38f448712f49f36f9d185c4e", "Retroactive", "", "Qb (Release Candidate #1) (Retroactive)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, @@ -372,7 +372,7 @@ static const BSPF::array2D DefProps = {{ { "18a970bea7ac4d29707c8d5cd559d03a", "", "", "Bridge (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "18b28b386abdadb3a700ac8fb68e639a", "Manuel Polik", "", "Gunfight 2600 (MP) (PAL)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "18b476a34ce5e6db2c032029873ac39b", "Bit Corporation", "R320", "Atlantis (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "18be8981b8201638f3ed8ae92bb4c215", "Thomas Jentzsch", "", "Missile Control - Amiga Mouse Hack v1.15 (PAL60) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "18be8981b8201638f3ed8ae92bb4c215", "Thomas Jentzsch", "", "Missile Control - Amiga Mouse Hack v1.15 (PAL60) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "18bebbbd41c234f82b1717b1905e6027", "", "", "Space Instigators (Public Release) (02-01-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "18d26111cef66dff0c8af8cf0e117843", "", "", "Tunnel Demo (Cycling Colours 2) (29-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "18dc28bc22402f21e1c9b81344b3b8c5", "Atari - GCC, Mark Ackerman, Glenn Parker", "CX2684, CX2684P", "Galaxian (1983) (Atari) (PAL) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -413,7 +413,7 @@ static const BSPF::array2D DefProps = {{ { "1bfae770e089fa81412d04eb299f4c3f", "Thomas Jentzsch", "", "Marble Craze - Atari Mouse Hack v1.0 (NTSC) (TJ)", "Uses Atari Mouse Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1c3f3133a3e5b023c77ecba94fd65995", "CCE", "C-830", "Planet Patrol (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1c5796d277d9e4df3f6648f7012884c4", "Rainbow Vision - Suntek", "SS-012", "Hey! Stop! (1983) (Rainbow Vision) (PAL)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1c666ba5aac19b81671357e76062989b", "Nukey Shay, Omegamatrix", "", "Double Dragon (Genesis) (PAL60) V2", "Genesis controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "1c666ba5aac19b81671357e76062989b", "Nukey Shay, Omegamatrix", "", "Double Dragon (Genesis) (PAL60) V2", "Genesis controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1c6eb740d3c485766cade566abab8208", "Atari, Michael Kosaka, Peter C. Niday, Robert Vieira", "CX26110", "Crystal Castles (1984) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1c85c0fc480bbd69dc301591b6ecb422", "CCE", "", "Super Box (CCE)", "AKA RealSports Boxing", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1c8c42d1aee5010b30e7f1992d69216e", "PlayAround - J.H.M.", "205", "Gigolo (1982) (PlayAround)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, @@ -457,7 +457,7 @@ static const BSPF::array2D DefProps = {{ { "1f773a94d919b2a3c647172bbb97f6b4", "Atari, Jerome Domurat, Peter C. Niday", "CX26115", "Dumbo's Flying Circus (07-11-1983) (Atari) (Prototype) (PAL)", "AKA Dumbo Flies Home", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1fa58679d4a39052bd9db059e8cda4ad", "Imagic, Dan Oliver", "720118-1A, 03208", "Laser Gates (1983) (Imagic)", "AKA Innerspace", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1fa7a42c2c7d6b7a0c6a05d38c7508f4", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (09-04-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1fa86282403fa35d103ab88a9d603c31", "SpiceWare - Darrell Spice Jr.", "", "Stay Frosty (SpiceWare) (PAL60)", "Part of Stella's Stocking 2007 Xmas compilation", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "YES", "" }, + { "1fa86282403fa35d103ab88a9d603c31", "SpiceWare - Darrell Spice Jr.", "", "Stay Frosty (SpiceWare) (PAL60)", "Part of Stella's Stocking 2007 Xmas compilation", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "1fab68fd67fe5a86b2c0a9227a59bb95", "20th Century Fox Video Games - Videa, Lee Actor", "", "Lasercade (1983) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "200309c8fba0f248c13751ed4fc69bab", "Jeffry Johnston", "", "Radial Pong - Version 1 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2008c76deba5953201ef75a09b2ff7dc", "", "", "Fortress (21-04-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -467,7 +467,7 @@ static const BSPF::array2D DefProps = {{ { "203abb713c00b0884206dcc656caa48f", "Imagic, Bob Smith", "720114-1A, 03207, IZ-001-04", "Moonsweeper (1983) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "203b1efc6101d4b9d83bb6cc1c71f67f", "Quelle", "685.996 1", "Teller-Jonglieren! (1983) (Quelle) (PAL)", "AKA Dancing Plate", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "205070b6a0d454961dd9196a8e81d877", "", "", "Hangman Monkey Biglist2 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2058cf3fefad4d2bc03ed817cedddcd4", "Thomas Jentzsch", "", "Reactor - Amiga Mouse Hack v1.3 (PAL60) (Full-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "2058cf3fefad4d2bc03ed817cedddcd4", "Thomas Jentzsch", "", "Reactor - Amiga Mouse Hack v1.3 (PAL60) (Full-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2091af29b4e7b86914d79d9aaa4cbd20", "CBS Electronics - Woodside Design Associates, Harley H. Puthuff Jr.", "4L1802", "Donkey Kong Junior (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "20ae62fb69c6cc6e8098cca8cd080487", "Zirok", "", "Tennis (Zirok)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "20d4457ba22517253fcb62967af11b37", "Atari, Eric Manghise, Mimi Nyden, Joseph Tung", "CX2640", "RealSports Baseball (1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -501,7 +501,7 @@ static const BSPF::array2D DefProps = {{ { "2319922df4d0c820b3e5f15faa870cc3", "Atari - GCC, Mike Feinstein", "CX2681, CX2681P", "Battlezone (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2327456f86d7e0deda94758c518d05b3", "Digitel", "", "Mr. Postman (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2351d26d0bfdee3095bec9c05cbcf7b0", "", "", "Warring Worms (19-01-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2353725ec98e0f0073462109e886efd7", "Champ Games", "CG-03-P", "Scramble (PAL60)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "GENESIS", "", "", "", "PAL60", "", "YES", "" }, + { "2353725ec98e0f0073462109e886efd7", "Champ Games", "CG-03-P", "Scramble (PAL60)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "JOYSTICK", "", "", "", "", "", "YES", "" }, { "235436ab0832370e73677c9c6f0c8b06", "", "", "Beast Invaders (Double Shot) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2365e1534d67f94d8670394ab99150ce", "Thomas Jentzsch", "", "Missile Command (Atari Mouse) (2002) (TJ)", "Uses Atari ST Mouse Controller", "Homebrew", "", "", "", "", "", "", "", "ATARIMOUSE", "ATARIMOUSE", "", "", "", "", "YES", "" }, { "23d445ea19a18fb78d5035878d9fb649", "CBS Electronics - JWDA, Sylvia Day, Todd Marshall, Henry Will IV", "4L1818, 4L1819, 4L1820, 4L1821", "Mouse Trap (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, @@ -541,7 +541,7 @@ static const BSPF::array2D DefProps = {{ { "25d4be3309b89583c6b39d9f93bf654f", "Activision, Bob Whitehead", "AX-015, AX-015-04", "Chopper Command (1982) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "25e73efb9a6edf119114718bd2f646ba", "Atari, Suki Lee", "CX26113", "Miss Piggy's Wedding (1983) (Atari) (Prototype) (4K) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "25f2e760cd7f56b88aac88d63757d41b", "Activision, Bob Whitehead - Ariola", "EAG-002, EAG-002-04I, PAG-002 - 711 002-715", "Boxing (1980) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "25f879ff678130fea615ac418e7943f1", "Activision, Garry Kitchen", "EAX-025", "Keystone Kapers (1983) (Activision) (SECAM)", "", "", "", "", "", "", "", "", "", "", "", "", "", "SECAM", "", "", "" }, + { "25f879ff678130fea615ac418e7943f1", "Activision, Garry Kitchen", "EAX-025", "Keystone Kapers (1983) (Activision) (SECAM)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "25f9cf703575c5d63048c222f5463758", "", "", "Multi-Sprite Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "260c787e8925bf3649c8aeae5b97dcc0", "Thomas Jentzsch", "", "Hell Driver (Thomas Jentzsch)", "NTSC Conversion, joystick ports swapped", "Homebrew", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "" }, { "262ccb882ff617d9b4b51f24aee02cbe", "Atari, Douglas Neubauer", "CX26154, CX26154P", "Super Football (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -552,7 +552,7 @@ static const BSPF::array2D DefProps = {{ { "26bc2bdf447a17376aea7ef187ff6e44", "", "", "Amanda Invaders (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "26f4f8b098609164effef7809e0121e1", "", "", "Oystron (V2.7) (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "270229c6d5578446e6a588492e4e5910", "", "", "Space Invaders 2 (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2712e91f6f1dc55e90e2b14b27c042ac", "Omegamatrix", "", "SpaceMaster X-7 (Amiga Mouse) (PAL60) (Omegamatrix)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "2712e91f6f1dc55e90e2b14b27c042ac", "Omegamatrix", "", "SpaceMaster X-7 (Amiga Mouse) (PAL60) (Omegamatrix)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "271bfd5dc2673d382019f1fb6cab9332", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (Preview) (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "273ce50db5a0d6da7ea827a54f44dee9", "", "", "Island Flyer Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "274d17ccd825ef9c728d68394b4569d2", "Playaround - J.H.M.", "202", "Bachelorette Party (1982) (Playaround)", "AKA Bachelor Party, Uses the paddle controllers", "Extremely Rare", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "AUTO 65", "", "", "YES", "" }, @@ -563,7 +563,7 @@ static const BSPF::array2D DefProps = {{ { "2783006ee6519f15cbc96adae031c9a9", "Telegames", "", "Night Stalker (1989) (Telegames) (PAL) [a]", "AKA Dark Cavern", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "278531cc31915747018d22145823d2c9", "", "", "Defender MegaDrive (PAL) (Genesis)", "Genesis controller (C is smartbomb)", "Hack of Defender", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "278f14887d601b5e5b620f1870bc09f6", "Thomas Jentzsch", "", "SWOOPS! (v0.96) (TJ)", "Uses the Joystick (L) and Paddle (R) Controllers", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "27a5d2d0c74c8e4b2c05b94c9f098eea", "Atari, Omegamatrix", "", "Video Olympics Menu (2020) (PAL60) (Hack)", "Hack of Video Olympics", "", "", "", "", "", "", "", "", "", "", "YES", "AUTO 60", "PAL60", "", "", "" }, + { "27a5d2d0c74c8e4b2c05b94c9f098eea", "Atari, Omegamatrix", "", "Video Olympics Menu (2020) (PAL60) (Hack)", "Hack of Video Olympics", "", "", "", "", "", "", "", "", "", "", "YES", "AUTO 60", "", "", "", "" }, { "27baecd618e7e53dc11f2a9c559f529d", "Omegamatrix", "", "Star Wars Arcade (Atari Trak-Ball) v4 (Omegamatrix)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "27c4c2af4b46394bb98638af8e0f6e9d", "Atari, Jerome Domurat, Peter C. Niday, Robert Vieira", "CX26109", "Sorcerer's Apprentice (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "27c6a2ca16ad7d814626ceea62fa8fb4", "Parker Brothers, Mark Lesser", "PB5590", "Frogger II (1984) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, @@ -632,7 +632,7 @@ static const BSPF::array2D DefProps = {{ { "2c3b9c171e214e9e46bbaa12bdf8977e", "Bit Corporation", "R320", "Othello (32 in 1) (BitCorp)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2c45c3eb819a797237820a1816c532eb", "Atari", "CX26163P", "Boxing (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2c8835aed7f52a0da9ade5226ee5aa75", "Arcadia Corporation, Stephen H. Landrum", "AR-4101", "Communist Mutants from Space (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2c8c11295d8613f875b7bcf5253ab9bb", "Fabrizio Zavagli", "", "Kool Aid Man (PAL Conversion) (16-11-2002) (Fabrizio Zavagli) (PAL60)", "PAL60 Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "2c8c11295d8613f875b7bcf5253ab9bb", "Fabrizio Zavagli", "", "Kool Aid Man (PAL Conversion) (16-11-2002) (Fabrizio Zavagli) (PAL60)", "PAL60 Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2c9fadd510509cc7f28f1ccba931855f", "", "", "Hangman Invader Biglist1 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2ca6445204ffb7686ddee3e33ba64d5b", "Alex Herbert", "", "AtariVox Test ROM", "Uses the AtariVox controller", "", "", "", "", "", "", "", "", "", "ATARIVOX", "", "", "", "", "", "" }, { "2cb42cf62b2f25f59f909b5447821b14", "Atari, Christopher H. Omarzu - Children's Computer Workshop", "CX26104", "Big Bird's Egg Catch (1983) (Atari) (PAL) [a]", "Uses Kids/Keypad Controllers", "", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "" }, @@ -659,7 +659,7 @@ static const BSPF::array2D DefProps = {{ { "2dbc92688f9ba92a7e086d62be9df79d", "", "", "How to Draw a Playfield (1997) (Jim Crawford) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2dbdca3058035d2b40c734dcf06a86d9", "Thomas Jentzsch", "", "Asteroids DC+ (Thomas Jentzsch) (Hack)", "Uses the Joystick (left) or Driving (right) Controller", "Hack", "", "", "", "", "", "", "", "", "DRIVING", "", "58", "", "", "YES", "" }, { "2dcf9ce486393cd36ca0928cd53b96cb", "Atari - GCC, Mike Feinstein, John Allred", "CX2688, CX2688P", "Jungle Hunt (1983) (Atari) (PAL) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2de41a11c6767e54a5ee9ebaffec72af", "Gray Games & AtariAge", "", "E.T. Book Cart (PAL60)", "Charles F. Gray & Michael Rideout", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "YES", "55" }, + { "2de41a11c6767e54a5ee9ebaffec72af", "Gray Games & AtariAge", "", "E.T. Book Cart (PAL60)", "Charles F. Gray & Michael Rideout", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "55" }, { "2dfec1615c49501fefc02165c81955e6", "", "", "Song (05-11-2002) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "2e0aed5bb619edcefa3fafb4fbe7c551", "", "", "Qb (2.06) (Retroactive) (NTSC)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "2e2acef8513edcca991e7e5149412e11", "Parker Brothers, Larry Gelberg, Gary Goltz", "PB5065", "Star Wars - Ewok Adventure (1983) (Parker Bros) (Prototype) (16K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -797,7 +797,7 @@ static const BSPF::array2D DefProps = {{ { "37b98344c8e0746c486caf5aaeec892a", "K-Tel Vision", "6", "Spider Maze (1982) (K-Tel Vision) (PAL)", "AKA Spider Kong", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "37e828675d556775ae8285c0caf7d11c", "AtariAge - Fred Quimby", "", "Gingerbread Man (Fred Quimby) (Genesis)", "Genesis controller (C throws cookie)", "New Release", "", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "" }, { "37f42ab50018497114f6b0f4f01aa9a1", "", "", "Droid Demo 2-M (David Conrad Schweinsberg) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "37fd7fa52d358f66984948999f1213c5", "Rainbow Vision - Suntek", "SS-004", "Pyramid War (1983) (Rainbow Vision) (PAL) [a2]", "AKA Chopper Command", "", "", "", "", "", "", "", "", "", "", "", "", "PAL", "", "", "" }, + { "37fd7fa52d358f66984948999f1213c5", "Rainbow Vision - Suntek", "SS-004", "Pyramid War (1983) (Rainbow Vision) (PAL) [a2]", "AKA Chopper Command", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "384db97670817103dd8c0bbdef132445", "Atari - Sears", "CX2626 - 6-99829, 49-75116", "Miniature Golf (1979) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "384f5fbf57b5e92ed708935ebf8a8610", "20th Century Fox Video Games, John W.S. Marvin", "11009", "Crypts of Chaos (1983) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3856b9425cc0185ed770376a62af0282", "Kyle Pittman", "", "Yellow Submarine (Kyle Pittman) (Hack)", "Hack of Bermuda Triangle", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -1004,7 +1004,7 @@ static const BSPF::array2D DefProps = {{ { "470878b9917ea0348d64b5750af149aa", "Atari, Suki Lee - Sears", "CX2658 - 49-75128", "Math Gran Prix (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "471f7bdc933e8db0e44aa3dde2dd92af", "Omegamatrix", "", "Millipede (Atari Mouse) v6.5 (Omegamatrix)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "47464694e9cce07fdbfd096605bf39d4", "Activision, Dan Kitchen", "EAK-050-04", "Double Dragon (1989) (Activision) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "47585c047802dd9af888b998fb921f32", "Omegamatrix", "", "Star Wars Arcade (Atari Trak-Ball) v4 (PAL60) (Omegamatrix)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "47585c047802dd9af888b998fb921f32", "Omegamatrix", "", "Star Wars Arcade (Atari Trak-Ball) v4 (PAL60) (Omegamatrix)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4767356fa0ed3ebe21437b4473d4ee28", "Atari, Dan Hitchens, Mimi Nyden", "CX2685", "Gravitar (04-12-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "47711c44723da5d67047990157dcb5dd", "CCE", "", "Ice Hockey (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "47911752bf113a2496dbb66c70c9e70c", "Atari - CCW, Christopher H. Omarzu, Preston Stuart, Bruce Williams", "CX26101", "Oscar's Trash Race (1984) (Atari) (PAL)", "Uses the Keypad Controllers", "", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "" }, @@ -1036,7 +1036,7 @@ static const BSPF::array2D DefProps = {{ { "493de059b32f84ab29cde6213964aeee", "Atari, Bill Aspromonte, Andrew Fuchs", "CX26120", "Stargate (1984) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "493e90602a4434b117c91c95e73828d1", "Telegames", "", "Lock 'n' Chase (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4947c9de2e28b2f5f3b0c40ce7e56d93", "", "", "3-D Corridor Demo 2 (29-03-2003) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "494cda91cc640551b4898c82be058dd9", "Andreas Dietrich", "", "Donkey Kong VCS (2017) (1.0) (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "YES", "" }, + { "494cda91cc640551b4898c82be058dd9", "Andreas Dietrich", "", "Donkey Kong VCS (2017) (1.0) (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "49571b26f46620a85f93448359324c28", "", "", "Save Our Ship (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "497c811026367c08fd838c9c59e5041d", "Omegamatrix", "", "SpaceMaster X-7 (Atari Trak-Ball) (Omegamatrix)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "497f3d2970c43e5224be99f75e97cbbb", "CommaVid, John Bronstein", "CM-002", "Video Life (1984) (CommaVid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, @@ -1063,7 +1063,7 @@ static const BSPF::array2D DefProps = {{ { "4b143d7dcf6c96796c37090cba045f4f", "Atari, Jim Huether - Sears", "CX2644 - 6-99824", "Flag Capture (1978) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4b205ef73a5779acc5759bde3f6d33ed", "", "", "Berzerk (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4b27f5397c442d25f0c418ccdacf1926", "Atari, Warren Robinett", "CX2613, 49-75154", "Adventure (1980) (Atari) (PAL)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4b379b885e2694f992c6cc932f18327f", "Omegamatrix", "", "SpaceMaster X-7 (Atari Mouse) (PAL60) (Omegamatrix)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "4b379b885e2694f992c6cc932f18327f", "Omegamatrix", "", "SpaceMaster X-7 (Atari Mouse) (PAL60) (Omegamatrix)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4b71197153d651480830638cb6a03249", "Atari, Larry Kaplan", "CX26163P", "Bowling (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4b753a97aee91e4b3e4e02f5e9758c72", "Glenn Saunders, Roger Williams", "", "Asymmetric Reflected Playfield (Glenn Saunders)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4b94fd272785d7ec6c95fb7279d0f522", "Atari - CCW, Christopher H. Omarzu, Preston Stuart, Bruce Williams", "CX26101", "Oscar's Trash Race (12-03-1982) (Atari) (Prototype)", "Uses the Keypad Controllers", "Prototype", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "" }, @@ -1129,7 +1129,7 @@ static const BSPF::array2D DefProps = {{ { "4faeb04b1b7fb0fa25db05753182a898", "", "", "2600 Digital Clock (V x.xx) (PD) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4fbe0f10a6327a76f83f83958c3cbeff", "CCE", "C-816", "Keystone Kappers (1983) (CCE)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4fc1b85b8074b4b9436d097900e34f29", "John K. Harvey", "", "John K. Harvey's Equalizer (John K. Harvey)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "50200f697aeef38a3ce31c4f49739551", "Mystique - American Multiple Industries, Joel H. Martin", "", "Custer's Revenge (1982) (Mystique) (PAL60)", "", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "50200f697aeef38a3ce31c4f49739551", "Mystique - American Multiple Industries, Joel H. Martin", "", "Custer's Revenge (1982) (Mystique) (PAL60)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "502044b1ac111b394e6fbb0d821fca41", "", "", "Hangman Invader 4letter (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "502168660bfd9c1d2649d415dc89c69d", "Activision, Bob Whitehead - Ariola", "EAG-019, EAG-019-04I - 711 019-715", "Sky Jinks (1982) (Activision) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "504688d49a41bf03d8a955512609f3f2", "Thomas Jentzsch", "", "SWOOPS! (v0.94) (TJ)", "Uses the Joystick (L) and Paddle (R) Controllers", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -1216,7 +1216,7 @@ static const BSPF::array2D DefProps = {{ { "5643ee916f7dc760148fca4db3aa7d10", "", "", "Moon Patrol (Genesis)", "Genesis controller (C is jump)", "Hack of Moon Patrol", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5678ebaa09ca3b699516dba4671643ed", "Coleco, Sylvia Day, Henry Will IV", "2459", "Mouse Trap (1982) (Coleco)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "568371fbae6f5e5b936af80031cd8888", "", "", "Robotfindskitten2600 (26-04-2003) (Jeremy Penner)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "56f72247eb9ebfd33bfd0cca23ab7ef4", "Omegamatrix", "", "Star Wars Arcade (Amiga Mouse) v4 (PAL60) (Omegamatrix)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "56f72247eb9ebfd33bfd0cca23ab7ef4", "Omegamatrix", "", "Star Wars Arcade (Amiga Mouse) v4 (PAL60) (Omegamatrix)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "571c6d9bc71cb97617422851f787f8fe", "Activision, David Crane - Ariola", "EAG-004, PAG-004 - 711 004-715", "Fishing Derby (1980) (Activision) (PAL)", "AKA Schneller als der Hai", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "572d0a4633d6a9407d3ba83083536e0f", "Funvision - Fund. International Co.", "", "Busy Police (Funvision)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "575c0fb61e66a31d982c95c9dea6865c", "", "", "Blackjack (Unknown) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "", "", "" }, @@ -1232,7 +1232,7 @@ static const BSPF::array2D DefProps = {{ { "5864cab0bc21a60be3853b6bcd50c59f", "", "", "Commando Raid (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "58746219d8094edff869f0f5c2aeaad5", "Jone Yuan Telephonic Enterprise Co", "", "Bowling (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5894c9c0c1e7e29f3ab86c6d3f673361", "Activision - Woodside Design Associates, Steve 'Jessica Stevens' Kitchen", "AZ-033, AZ-033-04", "Space Shuttle (1983) (Activision)", "A Journey Into Space", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "589c73bbcd77db798cb92a992b4c06c3", "Xonox - K-Tel Software - Action Graphics, Michael Schwartz, David Thiel", "6230, 7210, 06004, 99004", "Artillery Duel (1983) (Xonox) (PAL60)", "", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "589c73bbcd77db798cb92a992b4c06c3", "Xonox - K-Tel Software - Action Graphics, Michael Schwartz, David Thiel", "6230, 7210, 06004, 99004", "Artillery Duel (1983) (Xonox) (PAL60)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "58a82e1da64a692fd727c25faef2ecc9", "CCE", "C-824", "Jaw Breaker (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "58c396323ea3e85671e34c98eb54e2a4", "Brian Watson", "", "Color Tweaker (B. Watson)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "58d331c23297ed98663d11b869636f16", "", "", "Fu Kung! (V0.09) (26-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -1250,7 +1250,7 @@ static const BSPF::array2D DefProps = {{ { "59e53894b3899ee164c91cfa7842da66", "Data Age", "", "Survival Run (1983) (Data Age) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "59e96de9628e8373d1c685f5e57dcf10", "PlayAround - J.H.M.", "204", "Beat 'Em & Eat 'Em (1982) (PlayAround)", "Uses the Paddle Controllers", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "AUTO 45", "", "", "", "" }, { "59f596285d174233c84597dee6f34f1f", "CCE", "C-811", "River Raid (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5a0ff99ba10bd26d542e1d6f59f56850", "Champ Games", "CG-04-P", "Super Cobra Arcade (PAL60)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "GENESIS", "", "", "", "PAL60", "", "YES", "" }, + { "5a0ff99ba10bd26d542e1d6f59f56850", "Champ Games", "CG-04-P", "Super Cobra Arcade (PAL60)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "JOYSTICK", "", "", "", "", "", "YES", "" }, { "5a17e30e6e911e74ccd7b716d02b16c6", "Activision, Dan Kitchen", "AX-029", "Crackpots (1983) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5a272012a62becabcd52920348c7c60b", "Star Game", "", "Pitfall (Star Game)", "AKA Pitfall!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5a2f2dcd775207536d9299e768bcd2df", "Otto Versand", "781698", "Flippern (Double-Game Package) (1983) (Otto Versand) (PAL)", "AKA Video Pinball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -1298,7 +1298,7 @@ static const BSPF::array2D DefProps = {{ { "5ced13931c21ef4fc77d3fe801a1cbfa", "CCE", "C-828", "Missile Command (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5d0e8a25cbd23e76f843c75a86b7e15b", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (09-07-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5d132d121aabc5235dd039dfc46aa024", "", "", "Basketball (208 in 1) (Unknown) (PAL) (Hack)", "Console ports are swapped", "Hack", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "" }, - { "5d25df9dc2cde746ceac48e834cf84a7", "Activision - Woodside Design Associates, Steve 'Jessica Stevens' Kitchen", "EAZ-033", "Space Shuttle (1983) (Activision) (SECAM)", "A Journey Into Space", "", "", "", "FE", "", "", "", "", "", "", "", "", "SECAM", "", "", "" }, + { "5d25df9dc2cde746ceac48e834cf84a7", "Activision - Woodside Design Associates, Steve 'Jessica Stevens' Kitchen", "EAZ-033", "Space Shuttle (1983) (Activision) (SECAM)", "A Journey Into Space", "", "", "", "FE", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5d2cc33ca798783dee435eb29debf6d6", "Activision - Imagineering, Mike Reidel", "AK-043-04", "Commando (1988) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5d7293f1892b66c014e8d222e06f6165", "Atari - Axlon, Tod Frye - Heuristica, Agustin Ortiz", "CX26169", "Shooting Arcade (03-07-1989) (Atari) (Prototype) [a1]", "Uses the Light Gun Controller (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5d799bfa9e1e7b6224877162accada0d", "Spectravision - Spectravideo - Sirius Software, David Lubar", "SA-206", "Challenge of.... Nexar, The (1982) (Spectravision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -1460,11 +1460,11 @@ static const BSPF::array2D DefProps = {{ { "67cdde4176e0447fc45a71e0a1cdd288", "Telegames - VSS, Ed Salvo", "5665 A016", "Glacier Patrol (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "67ce6cdf788d324935fd317d064ed842", "Retroactive", "", "Qb (V2.09) (Stella) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "67cf913d1df0bf2d7ae668060d0b6694", "", "", "Hangman Monkey 4letter (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "67f90d74fd0b72fdc6d9b92436780ea9", "Omegamatrix", "", "SpaceMaster X-7 (Atari Trak-Ball) (PAL60) (Omegamatrix)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "67f90d74fd0b72fdc6d9b92436780ea9", "Omegamatrix", "", "SpaceMaster X-7 (Atari Trak-Ball) (PAL60) (Omegamatrix)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6803fa7c2c094b428b859a58dc1dd06a", "Retroactive", "", "Qb (0.11) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "6805734a0b7bcc8925d9305b071bf147", "Bit Corporation", "PGP229", "Kung Fu (4 Game in One Dark Green) (1983) (BitCorp) (PAL)", "AKA Karate", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "681206a6bde73e71c19743607e96c4bb", "", "", "Casino (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6833c26f385e866f3a0fa0dff311216e", "Thomas Jentzsch", "", "Centipede - Atari Mouse Hack v1.4 (PAL60) (Full-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "6833c26f385e866f3a0fa0dff311216e", "Thomas Jentzsch", "", "Centipede - Atari Mouse Hack v1.4 (PAL60) (Full-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "683bb0d0f0c5df58557fba9dffc32c40", "Arcadia Corporation, Scott Nelson", "AR-4300", "Fireball (1982) (Arcadia) [a]", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "01", "", "", "", "" }, { "683dc64ef7316c13ba04ee4398e2b93a", "Ed Federmeyer", "", "Edtris (1995) (Ed Federmeyer)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "68449e4aaba677abcd7cde4264e02168", "", "", "Horizonal Color Bars Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -1614,7 +1614,7 @@ static const BSPF::array2D DefProps = {{ { "72876fd7c7435f41d571f1101fc456ea", "Quelle", "688.383 9", "Die Ente und der Wolf (1983) (Quelle) (PAL)", "AKA Pooyan", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "72a46e0c21f825518b7261c267ab886e", "Xonox - K-Tel Software - Computer Magic", "99005, 6220, 6250", "Robin Hood (1983) (Xonox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "72a5b5052272ac785fa076709d16cef4", "", "", "KC Munckin (29-01-2003) (J. Parlee)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "72a63bcb5eb31bd0fd5e98ed05125ec1", "Thomas Jentzsch", "", "Missile Control - Atari Trak-Ball Hack v1.15 (PAL60) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "72a63bcb5eb31bd0fd5e98ed05125ec1", "Thomas Jentzsch", "", "Missile Control - Atari Trak-Ball Hack v1.15 (PAL60) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "72bda70c75dfa2365b3f8894bace9e6a", "Thomas Jentzsch", "", "Atlantis (TJ) (Hack)", "Hack of Atlantis", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "72d0acb5de0db662de0360a6fc59334d", "", "", "Cosmic Ark (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "72db1194b1cc7d45b242f25eb1c148d3", "", "", "Pac-Man (1981) (Atari) (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -1657,7 +1657,7 @@ static const BSPF::array2D DefProps = {{ { "7574480ae2ab0d282c887e9015fdb54c", "Atari, Jerome Domurat, Steve Woita", "CX2699", "Taz (1984) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7576dd46c2f8d8ab159d97e3a3f2052f", "Goliath - Hot Shot", "83-112", "Time Machine (1983) (Goliath) (PAL)", "AKA Asteroid Fire", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "757f529026696e13838364dea382a4ed", "Activision, David Crane - Ariola", "EAX-014, PAX-014, EAX-014-04B, EAX-014-04I - 711 014-720", "Grand Prix (1982) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "75893a9dc5de4b91cc426959b82a1da0", "Champ Games", "CG-02-P", "Conquest Of Mars (2010) (PAL60)", "Rev 2 release", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "75893a9dc5de4b91cc426959b82a1da0", "Champ Games", "CG-02-P", "Conquest Of Mars (2010) (PAL60)", "Rev 2 release", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "75a303fd46ad12457ed8e853016815a0", "ZiMAG - Emag - Vidco", "715-111 - GN-060", "Immies & Aggies (1983) (ZiMAG) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "75b22fdf632d76e246433db1ebccd3c4", "", "", "Skeleton+ (05-05-2003) (Eric Ball) (PAL)", "", "", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "75b557be7f08db84ec5b242207b9f241", "", "", "Space Treat (30-12-2002) (Fabrizio Zavagli) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -1735,7 +1735,7 @@ static const BSPF::array2D DefProps = {{ { "7b33407b2b198af74906b936ce1eecbb", "King Atari", "", "Ghostbuster 2 (King Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "7b3cf0256e1fa0fdc538caf3d5d86337", "CommaVid, Joseph Biel", "CM-009", "Stronghold (1983) (CommaVid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7b43c32e3d4ff5932f39afcb4c551627", "Syncro, Daniel Wolf", "", "Kamikaze Saucers (1983) (Syncro) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7b4be337ac4d73eda75c848355f6f480", "Omegamatrix", "", "Star Wars Arcade (Atari Trak-Ball) (Y Inverted) (PAL60) v4 (Omegamatrix)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "7b4be337ac4d73eda75c848355f6f480", "Omegamatrix", "", "Star Wars Arcade (Atari Trak-Ball) (Y Inverted) (PAL60) v4 (Omegamatrix)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7b5207e68ee85b16998bea861987c690", "Atari, Carol Shaw", "CX26163P", "3-D Tic-Tac-Toe (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7b57318c489ff178f7ff500da1ec9e8c", "Thomas Jentzsch", "", "Reactor - Amiga Mouse Hack v1.3 (PAL) (Full-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7b6f3348dbf71ada88db0fdaf7feefe0", "", "", "3-D Corridor (Pink Spiral) (31-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -1758,7 +1758,7 @@ static const BSPF::array2D DefProps = {{ { "7cd900e9eccbb240fe9c37fa28f917b5", "Jone Yuan Telephonic Enterprise Co", "", "Bi! Bi! (Jone Yuan) (PAL)", "AKA Skindiver", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7ced6709f091e79a2ab9575d3516a4ac", "Activision, Steve Cartwright - Ariola", "EAX-027 - 711 027-722", "Plaque Attack (1983) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7cedffa0db65d610568b90aeca705ac6", "Atari, Rob Fulop - Sears", "CX2638 - 49-75166", "Missile Command (1981) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7cf3a9267cdb95aba91abc5838d61cc5", "Thomas Jentzsch", "", "Centipede - Atari Mouse Hack v1.4 (PAL60) (Half-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "7cf3a9267cdb95aba91abc5838d61cc5", "Thomas Jentzsch", "", "Centipede - Atari Mouse Hack v1.4 (PAL60) (Half-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7d0b49ea4fe3a5f1e119a6d14843db17", "Gameworld, J. Ray Dettling", "133-008", "Frankenstein's Monster (1983) (Gameworld) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7d1034bcb38c9b746ea2c0ae37d9dff2", "Atari, Brad Stewart", "", "Morse Code Tutor (1979) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7d3cdde63b16fa637c4484e716839c94", "CCE", "", "Road Runner (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -1826,7 +1826,7 @@ static const BSPF::array2D DefProps = {{ { "80e5400470ac788143e6db9bc8dd88cf", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (06-XX-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "80f7bf7418a462e8687ecefeaf6eb9c2", "Thomas Jentzsch", "", "Reactor - Atari Trak-Ball Hack v1.3 (NTSC) (Half-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8101efafcf0af32fedda4579c941e6f4", "", "", "Okie Dokie (4K) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "81073d0377a2badef8d5e74fc44fc323", "Thomas Jentzsch", "", "Sadoom (TJ) (PAL60) (Hack)", "Hack of Kaboom!", "Hack", "", "", "", "", "", "", "", "", "", "", "01 50", "PAL60", "", "", "" }, + { "81073d0377a2badef8d5e74fc44fc323", "Thomas Jentzsch", "", "Sadoom (TJ) (PAL60) (Hack)", "Hack of Kaboom!", "Hack", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, { "8108162bc88b5a14adc3e031cf4175ad", "Suntek", "SS-030", "Skydiver (1983) (Suntek) (PAL)", "AKA Parachute", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8108ad2679bd055afec0a35a1dca46a4", "", "", "Maze Craze (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "NTSC", "", "", "" }, { "810d8952af5a6036fca8d0c4e1b23db6", "Tiger Vision - Eram", "", "Keystone (Tiger Vision)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -1863,7 +1863,7 @@ static const BSPF::array2D DefProps = {{ { "83f50fa0fbae545e4b88bb53b788c341", "Atari, Larry Kaplan - Sears", "CX2643 - 6-99815", "Codebreaker (1978) (Atari) (4K)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "83fafd7bd12e3335166c6314b3bde528", "Epyx, Steven A. Baker, Tod Frye, Peter Engelbrite", "80561-00251", "Winter Games (1987) (Epyx)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "840a5a2eaea24d95d289f514fd12f9bb", "", "", "GBImprov (Hack)", "Hack of Ghostbusters", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "841057f83ce3731e6bbfda1707cbca58", "Champ Games", "CG-04-N", "Super Cobra Arcade (NTSC)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "YES", "" }, + { "841057f83ce3731e6bbfda1707cbca58", "Champ Games", "CG-04-N", "Super Cobra Arcade (NTSC)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "JOYSTICK", "", "", "", "", "", "YES", "" }, { "841b7bc1cad05f5408302308777d49dc", "Activision", "", "Unknown Activision Game (10-22-1982) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "84290e333ff7567c2380f179430083b8", "Imagic, Dave Johnson", "13211, EIX-004-04I", "Quick Step! (1983) (Imagic) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "843435eb360ed72085f7ab9374f9749a", "Joe Grand", "", "SCSIcide (1.31) (Joe Grand)", "Uses the Paddle Controllers", "New Release", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "AUTO 65", "", "", "", "" }, @@ -1887,7 +1887,7 @@ static const BSPF::array2D DefProps = {{ { "8597f66dd37d9c855663804669d69d7a", "Tigervision, Warren Schwader", "7-003", "Threshold (1982) (Tigervision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "85a4133f6dcf4180e36e70ad0fca0921", "CCE", "C-827", "Chopper Command (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "85b1bca93e69f13905107cc802a02470", "Atari, Craig Nelson", "CX2617, CX2617P", "Backgammon (1979) (Atari) (PAL)", "Uses the Paddle Controllers", "Extremely Rare", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "AUTO 80", "", "", "", "" }, - { "85bbefb90e16bf386b304c1e9a1f6084", "Champ Games", "CG-02-P", "Conquest Of Mars (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "85bbefb90e16bf386b304c1e9a1f6084", "Champ Games", "CG-02-P", "Conquest Of Mars (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "85e48d68c8d802e3ba9d494a47d6e016", "", "", "Ship Demo (V 15) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "85e564dae5687e431955056fbda10978", "Milton Bradley Company - Renaissance Technology, Ty Roberts", "4362", "Survival Run (1983) (Milton Bradley)", "AKA Cosmic Commander", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "86128001e69ab049937f265911ce7e8a", "Apollo - Games by Apollo, Steve Stringfellow", "AP-2005", "Lochjaw (1982) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -1965,8 +1965,8 @@ static const BSPF::array2D DefProps = {{ { "8bebac614571135933116045204f0f00", "Thomas Jentzsch", "", "Missile Command (Trakball) (2002) (TJ) (PAL)", "Uses the Trakball Controller", "Homebrew", "", "", "", "", "", "", "", "TRAKBALL", "TRAKBALL", "", "", "", "", "YES", "" }, { "8c103a79b007a2fd5af602334937b4e1", "Thomas Jentzsch", "", "Laser Base (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8c136e97c0a4af66da4a249561ed17db", "", "", "Poker Squares (V0.27) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8c146c61817edd376bc1354c7f1ddc63", "Omegamatrix", "", "Star Wars Arcade (Amiga Mouse) (Y Inverted) (PAL60) v4 (Omegamatrix)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, - { "8c1cc284edba691139d6626d062c606f", "Atari, Omegamatrix", "", "Super Breakout Menu (2020) (PAL60) (Hack)", "Hack of Super Breakout", "", "", "", "", "", "", "", "", "", "", "", "AUTO 45", "PAL60", "", "", "" }, + { "8c146c61817edd376bc1354c7f1ddc63", "Omegamatrix", "", "Star Wars Arcade (Amiga Mouse) (Y Inverted) (PAL60) v4 (Omegamatrix)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8c1cc284edba691139d6626d062c606f", "Atari, Omegamatrix", "", "Super Breakout Menu (2020) (PAL60) (Hack)", "Hack of Super Breakout", "", "", "", "", "", "", "", "", "", "", "", "AUTO 45", "", "", "", "" }, { "8c2fa33048f055f38358d51eefe417db", "Home Vision - Gem International Corp. - VDI", "VCS83137", "Teddy Apple (1983) (Home Vision) (PAL)", "AKA Open, Sesame!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "8c36ed2352801031516695d1eeefe617", "Epyx, Steven A. Baker, Tod Frye, Peter Engelbrite", "80561-00251", "Winter Games (1987) (Epyx) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8c7e5e2329f4f4e06cbcc994a30fd352", "Data Age", "DA1004", "Airlock (1982) (Data Age) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -1994,12 +1994,12 @@ static const BSPF::array2D DefProps = {{ { "8e7241bfc8380aac3c0ef1b6881cdded", "Atari, Howard Scott Warshaw - Sears", "CX2655 - 49-75167", "Yars' Revenge (09-01-81) (Atari) (Prototype)", "Time Freeze", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "8e737a88a566cc94bd50174c2d019593", "Quelle", "343.173 1", "Feuerwehr im Einsatz (1983) (Quelle) (PAL)", "AKA Fire Fighter", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8e822b39a71c84ac875f0107fb61d6f0", "", "", "Hangman Ghost Original Words (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8e879aa58db41edb67cbf318b77766c4", "Thomas Jentzsch", "", "Cosmic Commuter (Thomas Jentzsch) (PAL60)", "NTSC Conversion", "Hack", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "8e879aa58db41edb67cbf318b77766c4", "Thomas Jentzsch", "", "Cosmic Commuter (Thomas Jentzsch) (PAL60)", "NTSC Conversion", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8e887d1ba5f3a71ae8a0ea16a4af9fc9", "", "", "Skeleton (V1.1) (PAL) (24-10-2002) (Eric Ball)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8ed5a746c59571feb255eaa7d6d0cf98", "", "", "Carnival (208 in 1) (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8ed73106e2f42f91447fb90b6f0ea4a4", "Spectravision - Spectravideo", "SA-204", "Tapeworm (1982) (Spectravision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "8ee3f64dc0f349adc893fe93df5245d8", "", "", "Euchre (20-07-2001) (Eric Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8ef96ace4a1d6dfb65926c1e868b0188", "Thomas Jentzsch", "", "Reactor - Amiga Mouse Hack v1.3 (PAL60) (Half-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "8ef96ace4a1d6dfb65926c1e868b0188", "Thomas Jentzsch", "", "Reactor - Amiga Mouse Hack v1.3 (PAL60) (Half-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8f33bce5ba1053dcf4cea9c1c69981e4", "", "", "Jawbreaker (Unknown) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8f53a3b925f0fd961d9b8c4d46ee6755", "", "", "Astrowar (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8f5ac5139419c5d49bacc296e342a247", "Atari - CCW, Michael Callahan, Preston Stuart", "CX26103", "Alpha Beam with Ernie (12-22-1982) (Atari) (Prototype)", "Uses Keypad Controllers", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -2017,7 +2017,7 @@ static const BSPF::array2D DefProps = {{ { "9048ccb7e0802cd8fa5bfc2609f292d8", "Tigervision, Robert H. O'Neil", "7-007", "Polaris (1983) (Tigervision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9057694dce8449521e6164d263702185", "Activision, Bob Whitehead", "AG-011", "Stampede (1981) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "90578a63441de4520be5324e8f015352", "Bit Corporation", "PGP204", "Open Sesame (4 Game in One) (1983) (BitCorp) (PAL)", "AKA Open, Sesame!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "9072c142728a3a3d994956d03bfacba2", "Fabrizio Zavagli", "", "Crash Dive (Fabrizio Zavagli) (PAL60)", "NTSC Conversion", "Hack", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "9072c142728a3a3d994956d03bfacba2", "Fabrizio Zavagli", "", "Crash Dive (Fabrizio Zavagli) (PAL60)", "NTSC Conversion", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "90a3c3255f2a54225cdcb50831f8793a", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Atari Trak-Ball Hack v1.1 (PAL) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "90b1799dddb8bf748ee286d22e609480", "", "", "Ship Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "90b647bfb6b18af35fcf613573ad2eec", "AtariAge (Chris Walton)", "", "Juno First (2009)", "AtariVox supported", "Homebrew", "", "", "", "", "", "", "", "", "ATARIVOX", "", "", "", "", "YES", "" }, @@ -2060,7 +2060,7 @@ static const BSPF::array2D DefProps = {{ { "93c52141d3c4e1b5574d072f1afde6cd", "Imagic, Mark Klein", "720112-1A, 03213", "Subterranea (1983) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "93c8d9d24f9c5f1f570694848d087df7", "Digivision", "", "Galaxian (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "93c9f9239a4e5c956663dd7affa70da2", "Quelle", "626.610 0", "Billard (1983) (Quelle) (PAL)", "AKA Trick Shot", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "93db185c3b3dc382f3aecd6a2fea7fd9", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Atari Trak-Ball Hack v1.1 (PAL60) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "93db185c3b3dc382f3aecd6a2fea7fd9", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Atari Trak-Ball Hack v1.1 (PAL60) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "93dc15d15e77a7b23162467f95a5f22d", "CCE", "", "Sky Jinks (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "93e276172b521c4491097f8b1393eea7", "Atari", "", "Diagnostic Test Cartridge 4.2 (06-01-1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "93eb1795c8b1065b1b3d62bb9ec0ccdc", "JSK", "", "Custer's Viagra (JSK) (Hack)", "Hack of Custer's Revenge", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -2068,7 +2068,7 @@ static const BSPF::array2D DefProps = {{ { "9433770890f087bfcf3e50122694d8c0", "Omegamatrix", "", "Star Wars Arcade (Amiga Mouse) (Y Inverted) v4 (Omegamatrix)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9436b7ad131b5a1f7753ce4309ba3dee", "Kyle Pittman", "", "War of The Worlds (Kyle Pittman) (Hack)", "Hack of Defender", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "943798452ceba9357e2c56303cadb4f7", "Thomas Jentzsch, Paul Slocum", "", "Thrust+ Platinum (v1.28)", "", "New Release, supports BoosterGrip and Genesis (switched by Color/B+W)", "", "", "", "", "", "", "", "JOYSTICK", "DRIVING", "", "", "", "", "", "" }, - { "9446940866c9417f210f8552cf6c3078", "Thomas Jentzsch", "", "Marble Craze - Amiga Mouse Hack v1.0 (PAL60) (TJ)", "Uses Amiga Mouse Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "9446940866c9417f210f8552cf6c3078", "Thomas Jentzsch", "", "Marble Craze - Amiga Mouse Hack v1.0 (PAL60) (TJ)", "Uses Amiga Mouse Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "94507dee401b0a072a481c00d7699ffe", "Thomas Jentzsch", "", "Missile Control - Atari Trak-Ball Hack v1.15 (PAL) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9469d18238345d87768e8965f9f4a6b2", "CCE", "", "Ms. Pac-Man (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "947317a89af38a49c4864d6bdd6a91fb", "CBS Electronics, Bob Curtiss", "4L 2487 5000", "Solar Fox (1983) (CBS Electronics)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -2163,7 +2163,7 @@ static const BSPF::array2D DefProps = {{ { "9c40bf810f761ffc9c1b69c4647a8b84", "", "", "2 in 1 - Frostbite, River Raid (Unknown)", "", "", "", "", "2IN1", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9c6d65bd3b477aace0376f705b354d68", "", "", "RPG Kernal (18-04-2003) (Paul Slocum) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "9c6faa4ff7f2ae549bbcb14f582b70e4", "U.S. Games Corporation, Garry Kitchen, Paul Willson - Vidtec", "VC1002", "Sneak 'n Peek (1982) (U.S. Games)", "AKA Hide 'n Seek", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9c6fd6ed3599978ab7b6f900484b9be6", "Andrew Wallace", "", "Laseresal 2002 (PAL60) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "9c6fd6ed3599978ab7b6f900484b9be6", "Andrew Wallace", "", "Laseresal 2002 (PAL60) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9c729017dd2f9ccbadcb511187f80e6b", "", "", "J-Pac (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9c7fa3cfcaaafb4e6daf1e2517d43d88", "", "", "PIEROXM Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9ca2deb61318eba4fb784d4bf7441d8b", "", "", "Purple Bar Demo 2 (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -2198,7 +2198,7 @@ static const BSPF::array2D DefProps = {{ { "9f48eeb47836cf145a15771775f0767a", "Atari, Warren Robinett", "CX2620", "Basic Programming (1979) (Atari)", "Uses Keypad Controllers", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "9f5096a6f1a5049df87798eb59707583", "20th Century Fox Video Games, Mark Klein", "11036", "Entity, The (1983) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9f52271759f8a2004d207b2247ae0bb3", "Parker Brothers", "PB5820", "Mr. Do!'s Castle (03-12-84) (Parker Bros) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "9f59eddf9ba91a7d93bce7ee4b7693bc", "Thomas Jentzsch", "", "Montezuma's Revenge (Thomas Jentzsch) (PAL60)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "9f59eddf9ba91a7d93bce7ee4b7693bc", "Thomas Jentzsch", "", "Montezuma's Revenge (Thomas Jentzsch) (PAL60)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9f8fad4badcd7be61bbd2bcaeef3c58f", "Parker Brothers, Charlie Heath", "PB5330", "Reactor (1983) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "9f901509f0474bf9760e6ebd80e629cd", "Atari, Bob Whitehead - Sears", "CX2623 - 6-99819, 49-75108, 49-75125", "Home Run (1978) (Atari) (4K)", "", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "" }, { "9f93734c68f6479eb022cab40814142e", "", "", "Push (V0.07) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -2243,11 +2243,11 @@ static const BSPF::array2D DefProps = {{ { "a29fc854838e08c247553a7d883dd65b", "Activision, Steve Cartwright", "AX-013", "Barnstorming (1982) (Activision) (16K)", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a2a384d3a16d5be50afd12906f146827", "Bit Corporation", "R320", "Flash Gordon (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a2aae759e4e76f85c8afec3b86529317", "", "", "Boom Bang (Unknown)", "AKA Crackpots", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a2d7cc2e5419a9e4ab91fdb26339b726", "Omegamatrix", "", "Star Wars Arcade (Atari Mouse) (Y Inverted) (PAL60) v4 (Omegamatrix)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "a2d7cc2e5419a9e4ab91fdb26339b726", "Omegamatrix", "", "Star Wars Arcade (Atari Mouse) (Y Inverted) (PAL60) v4 (Omegamatrix)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a2de0fc85548871279ed2a3c1325c13e", "George Veeder", "", "Cat and Mouse (George Veeder) (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a2eb84cfeed55acd7fece7fefdc83fbb", "", "", "Kool Aid Man (Fixed) (15-11-2002) (CT)", "HMOVE handling fixed in this version", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a2f296ea2d6d4b59979bac5dfbf4edf0", "", "", "Warring Worms (28-01-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a2f9e3b6aaa23b6dc06099cdd5b51b31", "Nukey Shay", "", "Montezuma's Revenge (Genesis) (PAL60) (F6_Conversion)", "Genesis controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "a2f9e3b6aaa23b6dc06099cdd5b51b31", "Nukey Shay", "", "Montezuma's Revenge (Genesis) (PAL60) (F6_Conversion)", "Genesis controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a302b922a8dbec47743f28b7f91d4cd8", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (Preview) (1982) (Starpath)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a30ece6dc4787e474fbc4090512838dc", "Zellers", "", "Circus (Zellers)", "AKA Circus Atari", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a310494ad5ba2b5b221a30d7180a0336", "", "", "Demo Image Series #6 - Mario (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -2261,7 +2261,7 @@ static const BSPF::array2D DefProps = {{ { "a3d7c299fbcd7b637898ee0fdcfc47fc", "Arcadia Corporation, Scott Nelson", "AR-4300", "Fireball (Preview) (1982) (Arcadia) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "01", "", "", "", "" }, { "a3f2a0fcf74bbc5fa763b0ee979b05b1", "Quelle", "873.790 0", "Eishockey-Fieber (1983) (Quelle) (PAL)", "AKA Ice Hockey", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a3f8aebb38182749cb8da85cfbc63d7c", "", "", "Tennis (208 in 1) (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a3fee8ce15525ea00d45a06f04c215d1", "Aaron Curtis", "", "AStar (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "a3fee8ce15525ea00d45a06f04c215d1", "Aaron Curtis", "", "AStar (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a406d2f6d84e61d842f4cb13b2b1cfa7", "Tigervision, John Harris - Teldec", "7-002", "Jawbreaker (1982) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a412c8577b2d57b09185ae51739ac54f", "Arcadia Corporation, Dennis Caswell", "AR-4000", "Phaser Patrol (1982) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "a41450333f8dd0e96e5e9f0af3770ae9", "", "", "Basic Math (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -2270,7 +2270,7 @@ static const BSPF::array2D DefProps = {{ { "a47878a760f5fa3aa99f95c3fdc70a0b", "", "", "Demo Image Series #5 - Baboon (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a4790224bd5afabd53cbe93e46a7f241", "Activision, Bob Whitehead", "AG-019", "Sky Jinks (1982) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a47e26096de6f6487bf5dd2d1cced294", "Atari", "CX2643", "Codebreaker (1978) (Atari) (PAL)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a484638990de7b12c62947c79dafa4c6", "Thomas Jentzsch", "", "Marble Craze - Atari Mouse Hack v1.0 (PAL60) (TJ)", "Uses Atari Mouse Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "a484638990de7b12c62947c79dafa4c6", "Thomas Jentzsch", "", "Marble Craze - Atari Mouse Hack v1.0 (PAL60) (TJ)", "Uses Atari Mouse Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a499d720e7ee35c62424de882a3351b6", "SEGA - Beck-Tech, Steve Beck, Phat Ho", "009-01", "Up 'n Down (1984) (SEGA)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a4aa7630e4c0ad7ebb9837d2d81de801", "", "", "Atari 2600 Invaders (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a4ab331e8768eafdc20ce8b0411ff77a", "", "", "Demo Image Series #1 - Sam (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -2340,7 +2340,7 @@ static const BSPF::array2D DefProps = {{ { "a98b649912b6ca19eaf5c2d2faf38562", "", "", "This Planet Sucks (Greg Troutman) (PAL) [!]", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a995b6cbdb1f0433abc74050808590e6", "Imagic, Rob Fulop, Bob Smith", "720106-1A, IA3600", "Riddle of the Sphinx (1982) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a9cb638cd2cb2e8e0643d7a67db4281c", "M Network - INTV - APh Technological Consulting, Larry Zwick", "MT5861", "Air Raiders (1983) (M Network)", "AKA Air Battle", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a9d9e19d0c89fb31780b5d63e1f8c6a4", "AtariAge, Chris Spry", "CX26201", "Zippy the Porcupine (2014) (Sprybug) (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "a9d9e19d0c89fb31780b5d63e1f8c6a4", "AtariAge, Chris Spry", "CX26201", "Zippy the Porcupine (2014) (Sprybug) (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a9e3c23599c0d77151602f8e31daf879", "", "", "Kung Fu Master (Genesis)", "Genesis controller (C is extra kick modes)", "Hack of Kung Fu Master", "", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "" }, { "aa1c41f86ec44c0a44eb64c332ce08af", "Spectravideo, David Lubar", "SA-218", "Bumper Bash (1983) (Spectravideo)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "PADDLES", "", "", "", "", "", "", "" }, { "aa2c4b32656bde9a75042a4d158583e1", "", "", "Oystron X (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -2385,7 +2385,7 @@ static const BSPF::array2D DefProps = {{ { "ace319dc4f76548659876741a6690d57", "Atari, Steve Wright", "CX2616", "Pele's Soccer (1981) (Atari)", "AKA Pele's Championship Soccer", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ad2e6bfb3b9b9b36ba8bf493ce764c49", "", "", "2600 Collison Demo 1 (Piero Cavina) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ad42e3ca3144e2159e26be123471bffc", "Atari", "CX26163P", "Human Cannonball (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ad72d616030a17634ff29ce8680d3c4c", "Thomas Jentzsch", "", "Reactor - Atari Trak-Ball Hack v1.3 (PAL60) (Full-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "ad72d616030a17634ff29ce8680d3c4c", "Thomas Jentzsch", "", "Reactor - Atari Trak-Ball Hack v1.3 (PAL60) (Full-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ad7e97c19bd25d5aa3999430845c755b", "", "", "Sprite Demo 5 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ad8072675109d13fdd31a2e0403d5cff", "Funvision - Fund. International Co.", "", "Tank City (Funvision)", "AKA Thunderground", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "adb770ff70e9adf08bbb907a7eccd240", "", "", "Inv Demo 3 (2001) (Erik Mooney) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -2438,7 +2438,7 @@ static const BSPF::array2D DefProps = {{ { "b15026b43c6758609667468434766dd8", "Retroactive", "", "Qb (0.06) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b16cd9784589219391c839cb68c47b9c", "Video Soft, Jerry Lawson, Dan McElroy", "", "Golf Diagnostic (1983) (Video Soft) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b17b9cc4103844dcda54f77f44acc93a", "Quelle", "377.943 6", "Stopp die Gangster (1983) (Quelle) (PAL)", "AKA Gangster Alley", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b182d9708e00709830caab9cf8205ca0", "Thomas Jentzsch", "", "Reactor - Atari Mouse Hack v1.3 (PAL60) (Half-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "b182d9708e00709830caab9cf8205ca0", "Thomas Jentzsch", "", "Reactor - Atari Mouse Hack v1.3 (PAL60) (Half-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b1a6c96e9093352106bc335e96caa154", "Joe Grand", "", "SCSIcide Pre-release 1 (Joe Grand)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b1b20536aef4eed9c79dc5804f077862", "", "", "Euchre (NTSC) (09-11-2001) (Erik Eid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b1c14b5ac896400cc91c8e5dd67acb59", "", "", "River Raid (208 in 1) (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -2463,7 +2463,7 @@ static const BSPF::array2D DefProps = {{ { "b3017e397f74efd53caf8fae0a38e3fe", "Retroactive", "", "Qb (2.12) (Retroactive) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b311ab95e85bc0162308390728a7361d", "Parker Brothers - Roklan, Joe Gaucher", "PB5080", "Gyruss (1984) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b31dc989f594764eacfa7931cead0050", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (2 of 3) (1983) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b31e9487efc06f18dfc3d7ebadf54416", "Omegamatrix", "", "Star Wars Arcade (Atari Mouse) v4 (PAL60) (Omegamatrix)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "b31e9487efc06f18dfc3d7ebadf54416", "Omegamatrix", "", "Star Wars Arcade (Atari Mouse) v4 (PAL60) (Omegamatrix)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b31f178aa0d569cccac7959f84e0a724", "Atari, Jerome Domurat, Steve Woita", "CX2699", "Taz (07-13-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b3203e383b435f7e43f9492893c7469f", "Gameworld", "133-003", "Sssnake (1983) (Gameworld) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b36040a2f9ecafa73d835d804a572dbf", "Digitel", "", "Pac Man (1983) (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -2507,12 +2507,12 @@ static const BSPF::array2D DefProps = {{ { "b7345220a0c587f3b0c47af33ebe533c", "Quelle", "176.433 1", "Landungskommando (1983) (Quelle) (PAL)", "AKA Strategy X", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b76fbadc8ffb1f83e2ca08b6fb4d6c9f", "Activision, Bob Whitehead", "AG-005, CAG-005, AG-005-04", "Skiing (1980) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b77468d586957d1b7fb4cccda2684f47", "Atari", "CX26163P", "Boxing (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b7903268e235310dc346a164af4c7022", "Thomas Jentzsch", "", "Cat Trax (Thomas Jentzsch) (PAL60)", "NTSC Conversion", "Hack", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "YES", "" }, + { "b7903268e235310dc346a164af4c7022", "Thomas Jentzsch", "", "Cat Trax (Thomas Jentzsch) (PAL60)", "NTSC Conversion", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b79fe32320388a197ac3a0b932cc2189", "Imagic, Bob Smith", "13207, EIZ-001-04I", "Moonsweeper (1983) (Imagic) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b7a7e34e304e4b7bc565ec01ba33ea27", "Parker Brothers", "PB5820", "Mr. Do!'s Castle (1984) (Parker Bros) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b7b1d3ce07e75976c43a2dca3866237e", "Atari", "CX26163P", "Freeway Chicken (32 in 1) (1988) (Atari) (PAL) (4K)", "AKA Freeway", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b7d0aae399781b3c18679debda6d32b1", "Thomas Jentzsch", "", "Three.s (v1.02)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b7d7c76e37f372f4e4979b380ed95a58", "AtariAge - Michael Haas", "RC2", "Flappy (2014) (AtariAge) (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "b7d7c76e37f372f4e4979b380ed95a58", "AtariAge - Michael Haas", "RC2", "Flappy (2014) (AtariAge) (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b7e459d5416eeb196aaa8e092db14463", "", "", "Push (V0.02) (1998) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b7f184013991823fc02a6557341d2a7a", "", "", "Blue Rod Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b80d50ecee73919a507498d0a4d922ae", "20th Century Fox Video Games - Sirius Software, David Lubar", "11008", "Fantastic Voyage (1982) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -2529,7 +2529,7 @@ static const BSPF::array2D DefProps = {{ { "b8ed78afdb1e6cfe44ef6e3428789d5f", "Data Age, J. Ray Dettling", "112-007", "Bermuda Triangle (1983) (Data Age)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b9232c1de494875efe1858fc8390616d", "Panda", "110", "Harbor Escape (1983) (Panda)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b9336ed6d94a5cc81a16483b0a946a73", "Atari, Jerome Domurat, Michael Sierchio", "CX2667, CX2667P", "RealSports Soccer (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "b955eb0e2baf7a437c186bddd4c49958", "Atari, Omegamatrix", "", "Space Invaders Menu (2020) (PAL60) (Hack)", "Hack of Space Invaders", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "b955eb0e2baf7a437c186bddd4c49958", "Atari, Omegamatrix", "", "Space Invaders Menu (2020) (PAL60) (Hack)", "Hack of Space Invaders", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b958d5fd9574c5cf9ece4b9421c28ecd", "Piero Cavina", "", "Multi-Sprite Game V1.0 (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b95a6274ca0e0c773bfdc06b4c3daa42", "Paul Slocum", "", "3-D Corridor (29-03-2003) (Paul Slocum)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b98cc2c6f7a0f05176f74f0f62c45488", "Spectravideo", "SV-010", "CompuMate (1983) (Spectravideo)", "", "", "", "", "CM", "", "", "", "", "COMPUMATE", "COMPUMATE", "", "", "", "", "YES", "" }, @@ -2547,7 +2547,7 @@ static const BSPF::array2D DefProps = {{ { "bae66907c3200bc63592efe5a9a69dbb", "Spectravision - Spectravideo - Quelle", "SA-201 - 412.783 3", "Gangster Alley (1982) (Spectravision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "baf4ce885aa281fd31711da9b9795485", "Atari, Douglas Neubauer", "CX26176", "Radar Lock (1989) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bb18189021d58362d9e4d317cd2e28b7", "Activision, David Crane - Ariola", "EAG-001, PAG-001, EAG-001-04B, EAG-001-04I - 711 001-715", "Dragster (1980) (Activision) (PAL) (4K)", "AKA Dragster Rennen", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bb2b83fff97604f74ada565e0b5bae94", "Thomas Jentzsch", "", "Missile Control - Atari Mouse Hack v1.15 (PAL60) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "bb2b83fff97604f74ada565e0b5bae94", "Thomas Jentzsch", "", "Missile Control - Atari Mouse Hack v1.15 (PAL60) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bb5049e4558daade0f87fed69a244c59", "Atari, Brad Stewart", "CX2649, CX2649P", "Asteroids (1981) (Atari) (PAL) [no copyright]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "bb579404924c40ca378b4aff6ccf302d", "", "", "Lightbulb Lightens, The (PD) (Non Functional)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bb6a5a2f7b67bee5d1f237f62f1e643f", "", "", "Demo Image Series #5 - Animegirl (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -2564,7 +2564,7 @@ static const BSPF::array2D DefProps = {{ { "bc703ea6afb20bc089f04d8c9d79a2bd", "", "", "Gunfight 2600 - Not mergeable with Colbert wizardry... (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bc97d544f1d4834cc72bcc92a37b8c1b", "", "", "Sky Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bcb31f22856b0028c00d12f0e4c0a952", "Canal 3 - Intellivision", "", "Thunderground (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bcb73b534ed7c613ac379ecd726effb5", "Bob Montgomery (aka vdub_bobby)", "", "Squish 'Em (2007) (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "bcb73b534ed7c613ac379ecd726effb5", "Bob Montgomery (aka vdub_bobby)", "", "Squish 'Em (2007) (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bccb4e2cfad5efc93f6d55dc992118ce", "Activision, Carol Shaw", "AX-020, AX-020-04", "River Raid (1982) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bce4c291d0007f16997faa5c4db0a6b8", "Quelle", "292.651 7", "Weltraumtunnel (1983) (Quelle) (PAL)", "AKA Innerspace", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bce93984b920e9b56cf24064f740fe78", "Atari", "CX26163P", "Checkers (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -2600,7 +2600,7 @@ static const BSPF::array2D DefProps = {{ { "bffe34516aaa3cbf5d307eab382a7e95", "", "", "Euchre (Release Candidate) (PAL) (28-09-2002) (Erik Eid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c00734a2233ef683d9b6e622ac97a5c8", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX26133", "A-Team, The (03-30-1984) (Atari) (Prototype)", "AKA Saboteur", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c00b65d1bae0aef6a1b5652c9c2156a1", "Atari, Joe Decuir - Sears", "CX2621 - 99806, 6-99806, 49-75104", "Video Olympics (1977) (Atari) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "YES", "AUTO 60", "", "", "", "" }, - { "c02e1afa0671e438fd526055c556d231", "Atari", "", "A-Team (Atari) (Prototype) (PAL60)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "c02e1afa0671e438fd526055c556d231", "Atari", "", "A-Team (Atari) (Prototype) (PAL60)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c032c2bd7017fdfbba9a105ec50f800e", "Activision, Charlie Heath", "", "Thwocker (04-09-1984) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c033dc1d7b6fde41b9cadce9638909bb", "", "", "Skeleton (V1.1) (06-09-2002) (Eric Ball)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c0589bb73858924389077fa3c2e9441a", "SOLID Corp. (D. Scott Williamson)", "CX2655-014", "Star Castle 2600 (SolidCorp) [014]", "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, @@ -2724,10 +2724,10 @@ static const BSPF::array2D DefProps = {{ { "c8c7da12f087e8d16d3e6a21b371a5d3", "", "", "Demo Image Series #9 - Genius (28-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c8e90fc944596718c84c82b55139b065", "Atari - Roklan, Bob Curtiss", "", "Firefox (1983) (Atari) (Prototype) [a]", "AKA Combat II, Fighter Command", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c8fa5d69d9e555eb16068ef87b1c9c45", "Atari", "CX26144", "Donkey Kong Junior (1987) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c90788d9aa71a78bcc78c015edb22c54", "Thomas Jentzsch", "", "Marble Craze - Atari Trak-Ball Hack v1.0 (PAL60) (TJ)", "Uses Atari Trak-Ball Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "c90788d9aa71a78bcc78c015edb22c54", "Thomas Jentzsch", "", "Marble Craze - Atari Trak-Ball Hack v1.0 (PAL60) (TJ)", "Uses Atari Trak-Ball Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c9196e28367e46f8a55e04c27743148f", "Atari", "CX26163P", "Stampede (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c92cfa54b5d022637fdcbdc1ef640d82", "Retroactive", "", "Qb (V2.05) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "c98e8c918a40b4d3a243dd6c49196330", "AtariAge, Omegamatrix", "", "Venture Reloaded (2019) (AtariAge) (PAL60) (Hack)", "Transformative hack of Venture", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "YES", "" }, + { "c98e8c918a40b4d3a243dd6c49196330", "AtariAge, Omegamatrix", "", "Venture Reloaded (2019) (AtariAge) (PAL60) (Hack)", "Transformative hack of Venture", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "c9b7afad3bfd922e006a6bfc1d4f3fe7", "Atari, Larry Kaplan - Sears", "CX2628 - 6-99842, 49-75117", "Bowling (1979) (Atari)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c9c25fc536de9a7cdc5b9a916c459110", "Activision, Mike Lorenzen", "AX-023", "Oink! (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c9d02d3cfeef8b48fb71cb4520a4aa84", "", "", "Euchre (More for less) (PAL) (22-08-2002) (Erik Eid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -2786,12 +2786,12 @@ static const BSPF::array2D DefProps = {{ { "cd4ded1ede63c4dd09f3dd01bda7458c", "Future Video Games", "", "Laser Gate (Future Video Games) (PAL)", "AKA Innerspace", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cd568d6acb2f14477ebf7e59fb382292", "Videospielkassette - Ariola", "PGP235", "Fussball (Ariola) (PAL)", "AKA International Soccer", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cd5af682685cfecbc25a983e16b9d833", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX26133", "A-Team, The (05-08-1984) (Atari) (Prototype)", "AKA Saboteur", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cd88ef1736497288c4533bcca339f881", "SEGA - Teldec", "005-10", "Buck Rogers - Planet of Zoom (1983) (SEGA) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "PAL", "", "YES", "" }, + { "cd88ef1736497288c4533bcca339f881", "SEGA - Teldec", "005-10", "Buck Rogers - Planet of Zoom (1983) (SEGA) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "cd8fa2e9f6255ef3d3b9b5a4f24a54f7", "", "", "Daredevil (V2) (Stunt_Cycle_Rules!) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cd98be8a48ebf610c9609a688b9c57f2", "Arcadia Corporation, Steve Hales, Stephen H. Landrum", "4 AR-4102", "Suicide Mission (1982) (Arcadia) (Prototype)", "AKA Meteoroids", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "cd9fea12051e414a6dfe17052067da8e", "Paul Slocum", "", "Marble Craze Demo (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cda38714267978b9a8b0b24bee3529ae", "", "", "Space Instigators (V1.6) (17-10-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cdadb57b34438805ee322ff05bd3d43e", "Thomas Jentzsch", "", "Centipede - Amiga Mouse Hack v1.4 (PAL60) (Full-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "cdadb57b34438805ee322ff05bd3d43e", "Thomas Jentzsch", "", "Centipede - Amiga Mouse Hack v1.4 (PAL60) (Full-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cdb81bf33d830ee4ee0606ee99e84dba", "Arcadia Corporation, Scott Nelson", "AR-4300", "Fireball (1982) (Arcadia) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "01", "", "", "", "" }, { "cdc1a5c61d7488eadc9aba36166b253d", "Retroactive", "", "Qb (V0.12) (Stella) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "cddabfd68363a76cd30bee4e8094c646", "Computer Magic - CommaVid, John Bronstein", "CM-001", "MagiCard (1981) (CommaVid)", "Uses the Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -2808,7 +2808,7 @@ static const BSPF::array2D DefProps = {{ { "ce89529d6e98a13ddf3d84827bbdfe68", "", "", "Kung Fu Sprite Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "ce904c0ae58d36d085cd506989116b0b", "Telegames", "5687 A279", "International Soccer (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cea9f72036dc6f7af5eff52459066290", "Retroactive", "", "Qb (2.07) (Retroactive) (Stella)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "ceba7965a93c689bdecdb46a5b2ac0c1", "Thomas Jentzsch", "", "Reactor - Atari Trak-Ball Hack v1.3 (PAL60) (Half-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "ceba7965a93c689bdecdb46a5b2ac0c1", "Thomas Jentzsch", "", "Reactor - Atari Trak-Ball Hack v1.3 (PAL60) (Half-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cedbd67d1ff321c996051eec843f8716", "Ultravision", "1044", "Karate (1982) (Ultravision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cef01595000627ee50863d4290372c27", "", "", "Many Blue Bars and Text Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cef2287d5fd80216b2200fb2ef1adfa8", "Milton Bradley Company", "4363", "Spitfire Attack (1983) (Milton Bradley)", "AKA Flight Commander)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -2833,7 +2833,7 @@ static const BSPF::array2D DefProps = {{ { "cff1e9170bdbc29859b815203edf18fa", "Retroactive", "", "Push (V0.01) (1998) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "cff578e5c60de8caecbee7f2c9bbb57b", "George Veeder", "", "Suicide Adventure (George Veeder) (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cff9950d4e650094f65f40d179a9882d", "Paul Slocum", "", "Mr. Roboto (Paul Slocum) (Hack)", "Hack of Berzerk", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "cfffc4b97d01cc3e7b9f47575f7b11ec", "Xonox - K-Tel Software, Anthony R. Henderson", "99007, 6240", "Tomarc the Barbarian (1983) (Xonox) (PAL60)", "Genesis controller (B is jump and throw, C switches between players)", "Hack of Tomarc the Barbarian", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "cfffc4b97d01cc3e7b9f47575f7b11ec", "Xonox - K-Tel Software, Anthony R. Henderson", "99007, 6240", "Tomarc the Barbarian (1983) (Xonox) (PAL60)", "Genesis controller (B is jump and throw, C switches between players)", "Hack of Tomarc the Barbarian", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d00f6f8ba89559e4b20972a478fc0370", "Spiceware", "SW-01", "Medieval Mayhem (PAL)", "", "Homebrew", "STEREO", "", "", "", "", "", "", "", "", "", "AUTO 55", "", "", "", "" }, { "d010e3dfe7366e47561c088079a59439", "Retroactive", "", "Qb (V0.10) (Stella) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "d026716b3c5be2c951cc4c064317c524", "", "", "Fu Kung! (V0.06) (14-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -2896,7 +2896,7 @@ static const BSPF::array2D DefProps = {{ { "d45bf71871b196022829aa3b96bfcfd4", "Activision, Steve Cartwright", "AX-017, AX-017-04", "MegaMania (1982) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d45ebf130ed9070ea8ebd56176e48a38", "SEGA, Jeff Lorenz", "001-01", "Tac-Scan (1983) (SEGA)", "Uses the Paddle Controllers (right only)", "", "", "", "", "", "", "", "YES", "", "", "YES", "AUTO 60", "", "", "YES", "" }, { "d47387658ed450db77c3f189b969cc00", "PlayAround - J.H.M.", "206", "Westward Ho (1982) (PlayAround) (PAL)", "AKA Custer's Revenge", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d4806775693fcaaa24cf00fc00edcdf3", "Atari - Bobco, Robert C. Polaro", "CX26140, CX26140P", "Desert Falcon (1987) (Atari) (PAL)", "AKA Nile Flyer, Sphinx", "", "", "", "", "", "", "", "", "", "", "", "", "PAL", "", "", "" }, + { "d4806775693fcaaa24cf00fc00edcdf3", "Atari - Bobco, Robert C. Polaro", "CX26140, CX26140P", "Desert Falcon (1987) (Atari) (PAL)", "AKA Nile Flyer, Sphinx", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d483f65468d9a265661917bae1a54f3e", "Joe Grand", "", "SCSIcide Pre-release 3 (Joe Grand)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d4942f4b55313ff269488527d84ce35c", "Atari - GCC, Mark Ackerman, Glenn Parker", "CX2675, CX2675P", "Ms. Pac-Man (1982) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d49aff83f77a1b9041ad7185df3c2277", "", "", "Space Treat (60% complete) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -2913,7 +2913,7 @@ static const BSPF::array2D DefProps = {{ { "d5aa7472e7f2cc17e893a1a36f8dadf0", "", "", "Overhead Adventure Demo 5 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d5c6b81212ad86fd9542a1fedaf57cae", "", "", "Sprite Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d5d2d44fb73785996ccc24ae3a0f5cef", "Robby", "", "Grand Prix (Robby)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d5e17022d1ecc20fd9b53dc464c302f1", "Activision, Carol Shaw", "EAX-020", "River Raid (1982) (Activision) (SECAM)", "", "", "", "", "", "", "", "", "", "", "", "", "", "SECAM", "", "", "" }, + { "d5e17022d1ecc20fd9b53dc464c302f1", "Activision, Carol Shaw", "EAX-020", "River Raid (1982) (Activision) (SECAM)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d5e27051512c1e7445a9bf91501bda09", "Activision, David Crane", "AG-008", "Laser Blast (1981) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d5e5b3ec074fff8976017ef121d26129", "Star Game", "003", "River Raid (Star Game)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d5f965c159e26a1fb49a22a47fbd1dd0", "Supergame", "", "River Raid II (Supergame)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -2975,7 +2975,7 @@ static const BSPF::array2D DefProps = {{ { "da6465a34d2e44d26aa9a2a0cd1bce4d", "Absolute Entertainment, Alex DeMeo", "AG-041-04", "Title Match Pro Wrestling (1987) (Absolute) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "da66d75e4b47fab99733529743f86f4f", "Digitel", "", "Chopper Command (1983) (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "da732c57697ad7d7af414998fa527e75", "Atari - Glenn Axworthy", "CX26129", "Midnight Magic (1986) (Atari) (PAL)", "AKA Pinball Wizard", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "da79aad11572c80a96e261e4ac6392d0", "Salu - Ubi Soft, Dennis M. Kiss", "460673", "Pick 'n' Pile (1990) (Salu) (PAL)", "", "", "", "", "", "", "", "", "YES", "", "", "", "", "PAL", "", "YES", "" }, + { "da79aad11572c80a96e261e4ac6392d0", "Salu - Ubi Soft, Dennis M. Kiss", "460673", "Pick 'n' Pile (1990) (Salu) (PAL)", "", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "YES", "" }, { "da7a17dcdaa62d6971393c0a6faf202a", "", "", "Flag Capture (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dab844deed4c752632b5e786b0f47999", "", "", "Super Challenge Baseball (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dac38b4dd3da73bb7b2e9d70c61d2b7c", "", "", "Hangman Monkey Biglist3 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -3129,7 +3129,7 @@ static const BSPF::array2D DefProps = {{ { "e40a818dac4dd851f3b4aafbe2f1e0c1", "Atari, Bill Aspromonte, Dr. Lee Salk", "CX26135", "Peek-A-Boo (1984) (Atari) (Prototype)", "Uses the Keypad Controllers", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e42b937c30c617241ca9e01e4510c3f6", "", "", "Pitfall! (No Walls Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e434c0e161dd3c3fb435eb6bad2e182c", "Atari - GCC, Mike Feinstein, Brad Rice", "CX2681", "Battlezone (05-02-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e48d3a4056ede9393586421996db1ae8", "Thomas Jentzsch", "", "Centipede - Atari Trak-Ball Hack v1.4 (PAL60) (Full-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "e48d3a4056ede9393586421996db1ae8", "Thomas Jentzsch", "", "Centipede - Atari Trak-Ball Hack v1.4 (PAL60) (Full-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e49ac0ec879a0d7820bc2598fc2cfcd4", "CCE", "", "Kaboom! (CCE) (4K)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, { "e4a0b28befaaa2915df1fa01238b1e29", "", "", "Gunfight 2600 - Red River (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e4afe157c09962cf39cdb25845d83d47", "Activision, David Crane - Ariola", "EAG-009, PAG-009 - 711 009-720", "Freeway (1981) (Activision) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -3211,7 +3211,7 @@ static const BSPF::array2D DefProps = {{ { "e9db2f91efe6ff7ea3546e2c2578fb09", "Omegamatrix", "", "Millipede (Atari Mouse) v6.5 (Omegamatrix)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, { "e9e646f730b8400cd5da08c849ef3e3b", "Tron", "", "Enduro (Tron)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e9e6ad30549a6e2cd89fe93b7691d447", "Atari - Bobco, Robert C. Polaro", "CX26140, CX26140P", "Desert Falcon (05-27-1987) (Atari) (Prototype) (PAL)", "AKA Nile Flyer, Sphinx", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e9f25c7af4f27c9e1b5b8f6fe6141e8c", "Champ Games", "CG-03-N", "Scramble (NTSC)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "YES", "" }, + { "e9f25c7af4f27c9e1b5b8f6fe6141e8c", "Champ Games", "CG-03-N", "Scramble (NTSC)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "JOYSTICK", "", "", "", "", "", "YES", "" }, { "ea38fcfc06ad87a0aed1a3d1588744e4", "Atari, Lou Harp", "CX26122", "Sinistar (01-XX-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ea6d40db5498d6386571a76df448aa4c", "", "", "Vertical Playfield Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ea7e25ade3fe68f5b786ee0aa82b1fe5", "", "", "Galatic (208 in 1) (Unknown) (PAL)", "AKA Challenge of.... Nexar, The", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -3231,7 +3231,7 @@ static const BSPF::array2D DefProps = {{ { "eb634650c3912132092b7aee540bbce3", "Atari, Eric Manghise, Mimi Nyden, Joseph Tung", "CX2640", "RealSports Baseball (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "eb6d6e22a16f30687ade526d7a6f05c5", "Atari", "CX26150P", "Q-bert (1987) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "eb71743c6c7ccce5b108fad70a326ad9", "", "", "Euchre (25-11-2001) (Erik Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "eb7934360658a29c50aeaff20bfda23b", "Activision, John Van Ryzin", "EAZ-036-04", "H.E.R.O. (1984) (Activision) (SECAM)", "", "", "", "", "", "", "", "", "", "", "", "", "", "SECAM", "", "", "" }, + { "eb7934360658a29c50aeaff20bfda23b", "Activision, John Van Ryzin", "EAZ-036-04", "H.E.R.O. (1984) (Activision) (SECAM)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "eb92193f06b645df0b2a15d077ce435f", "Starpath Corporation, Steve Hales, Stephen H. Landrum", "4 AR-4102", "Suicide Mission (1982) (Starpath) (PAL)", "AKA Meteoroids", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "eb9712e423b57f0b07ccd315bb9abf61", "Retroactive", "", "Qb (V2.04) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "eb9f8b84c193d9d93a58fca112aa39ed", "", "", "Register Twiddler Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -3245,7 +3245,7 @@ static const BSPF::array2D DefProps = {{ { "ec407a206b718a0a9f69b03e920a0185", "Quelle", "876.482 1", "Landung in der Normandie (1983) (Quelle) (PAL)", "AKA Commando Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ec5c861b487a5075876ab01155e74c6c", "Apollo - Games by Apollo, Ed Salvo, Byron Parks", "AP-2001", "Spacechase (1982) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ece463abde92e8b89bcd867ec71751b8", "Puzzy - Bit Corporation", "PG205", "Dancing Plate (1982) (Puzzy) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "ece908d77ab944f7bac84322b9973549", "", "", "Tom Boy (Unknown) (PAL60)", "AKA Pitfall!", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "ece908d77ab944f7bac84322b9973549", "", "", "Tom Boy (Unknown) (PAL60)", "AKA Pitfall!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ecf51385384b468834611d44a8429c03", "20th Century Fox Video Games, Douglas 'Dallas North' Neubauer", "11105", "Mega Force (1982) (20th Century Fox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ecfa04523dde82fe42cdc7315a8f61b6", "Activision, David Crane - Ariola", "EAG-004, PAG-004 - 711 004-715", "Fishing Derby (1980) (Activision) (PAL) (4K)", "AKA Schneller als der Hai", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ed014beeeb77dbb2bbcf9b5f6850b2f4", "", "", "Green Bar Text Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -3254,11 +3254,11 @@ static const BSPF::array2D DefProps = {{ { "ed1306436ce237afc5a7ed3f77134202", "HES", "771-341", "2 Pak Special - Dolphin, Pigs n' Wolf (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ed1492d4cafd7ebf064f0c933249f5b0", "CCE", "", "Video Cube (CCE)", "AKA Atari Video Cube", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ed1a784875538c7871d035b7a98c2433", "Bit Corporation", "R320", "Save Our Ship (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ed2218b3075d15eaa34e3356025ccca3", "Atari, Richard Maurer", "CX2635, CX2635P", "Maze Craze (1980) (Atari) (PAL)", "AKA A Game of Cops 'n Robbers", "", "", "", "", "", "", "", "", "", "", "", "", "PAL", "", "", "" }, + { "ed2218b3075d15eaa34e3356025ccca3", "Atari, Richard Maurer", "CX2635, CX2635P", "Maze Craze (1980) (Atari) (PAL)", "AKA A Game of Cops 'n Robbers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ed5ccfc93ad4561075436ee42a15438a", "Atari, Tom Reuterdahl", "CX2626, CX2626P", "Miniature Golf (1979) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ed8f319e82d355832195eb7715644795", "Activision, Larry Kaplan, David Crane", "AG-010, AG-010-04", "Kaboom! (1981) (Activision) (8K)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, { "eddef10fdc0029301064115ae0cd41d4", "CCE", "", "Freeway (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ede4ab11ca346bd023b2c21d941e0c50", "Activision, David Crane", "EAZ-030", "Decathlon (1983) (Activision) (SECAM)", "", "", "", "", "", "", "", "", "", "", "", "", "", "SECAM", "", "", "" }, + { "ede4ab11ca346bd023b2c21d941e0c50", "Activision, David Crane", "EAZ-030", "Decathlon (1983) (Activision) (SECAM)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ede7e8bf865b0afb4744f86d13624f9a", "", "", "Demo Image Series #2 - Clown (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "edf69b123e06eaf8663cc78d8aeba06e", "SpkSoft 98", "", "River Raid (SpkSoft 98) [h1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ee28424af389a7f3672182009472500c", "Atari, Carol Shaw - Ralph Lauren", "", "Polo (1978) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -3304,7 +3304,7 @@ static const BSPF::array2D DefProps = {{ { "f0cacae1d1b79ee92f0dc035f42e0560", "", "", "Boring Donkey Kong (Hack)", "Hack of Donkey Kong", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f0d393dbf4164a688b2346770c9bbd12", "", "", "Racquetball (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "f0daaa966199ef2b49403e9a29d12c50", "", "", "Mr. Postman (Unknown)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f0de4f49e95d529569e8788d5a7b4d30", "Thomas Jentzsch", "", "Reactor - Atari Mouse Hack v1.3 (PAL60) (Full-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "f0de4f49e95d529569e8788d5a7b4d30", "Thomas Jentzsch", "", "Reactor - Atari Mouse Hack v1.3 (PAL60) (Full-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f0e0addc07971561ab80d9abe1b8d333", "Imagic, Rob Fulop", "720000-200, 720101-1B, 720101-1C, IA3200, IA3200C, IX-006-04", "Demon Attack (1982) (Imagic)", "AKA Death from Above", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f0ef9a1e5d4027a157636d7f19952bb5", "Atari - Axlon, Tod Frye - Heuristica, Agustin Ortiz", "CX26169", "Shooting Arcade (03-07-1989) (Atari) (Prototype) [a5]", "Uses the Light Gun Controller (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f10e3f45fb01416c87e5835ab270b53a", "Suntek", "SS-024", "Ski Run (1983) (Suntek) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -3312,7 +3312,7 @@ static const BSPF::array2D DefProps = {{ { "f11cfab087fcbd930ab8b0becc5b2e5a", "Canal 3 - Intellivision", "", "River Raid (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f12afbffa080dd3b2801dd14d4837cf6", "Atari, Michael Kosaka, Peter C. Niday, Robert Vieira", "CX26110", "Crystal Castles (01-04-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "f137211537438b1fce3d811baef25457", "", "", "Incoming (02-10-2002) (Ben Larson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f1489e27a4539a0c6c8529262f9f7e18", "Champ Games", "CG-01-P", "Lady Bug (PAL60)", "", "Homebrew", "", "", "", "", "A", "", "", "", "", "", "", "PAL60", "", "YES", "" }, + { "f1489e27a4539a0c6c8529262f9f7e18", "Champ Games", "CG-01-P", "Lady Bug (PAL60)", "", "Homebrew", "", "", "", "", "A", "", "", "", "", "", "", "", "", "YES", "" }, { "f14d5e96ec3380aef57a4b70132c6677", "Goliath - Hot Shot", "83-414", "Pac Kong (1983) (Goliath) (PAL)", "AKA Inca Gold", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f1554569321dc933c87981cf5c239c43", "Atari - Glenn Axworthy", "CX26129", "Midnight Magic (1986) (Atari)", "AKA Pinball Wizard", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "f16c709df0a6c52f47ff52b9d95b7d8d", "Atari, Alan Miller - Sears", "CX2662 - 6-99811", "Hangman (1978) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -3459,7 +3459,7 @@ static const BSPF::array2D DefProps = {{ { "fa6fe97a10efb9e74c0b5a816e6e1958", "ZiMAG - Emag - Vidco", "707-111 - GN-030", "Tanks But No Tanks (1983) (ZiMAG)", "AKA Phantom Tank", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fa7ce62e7fd77e02b3e2198d70742f80", "Atari, Peter C. Niday", "CX26108", "Donald Duck's Speedboat (04-18-1983) (Atari) (Prototype) (PAL)", "AKA Donald Duck's Regatta", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fa7e11a3dbea4365975cd2f094e61d25", "Tim Snider", "", "Mystery Science Theater 2600 (1999) (Tim Snider) (Hack)", "Hack of Megamania", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fa98d48cd609c9babc819e0a1bd8d598", "AtariAge (Chris Walton)", "", "Juno First (2009) (PAL60)", "AtariVox supported", "Homebrew", "", "", "", "", "", "", "", "", "ATARIVOX", "", "", "PAL60", "", "YES", "" }, + { "fa98d48cd609c9babc819e0a1bd8d598", "AtariAge (Chris Walton)", "", "Juno First (2009) (PAL60)", "AtariVox supported", "Homebrew", "", "", "", "", "", "", "", "", "ATARIVOX", "", "", "", "", "YES", "" }, { "fab7b04b9f42df761eb6f2bc445eaa99", "20th Century Fox Video Games - Sirius Software, David Lubar", "11008", "Fantastic Voyage (11-04-1982) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fabca526d57de46768b392f758f1a008", "", "", "Laseresal 2600 (16-12-2001) (Andrew Wallace) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fac28963307b6e85082ccd77c88325e7", "CCE", "", "Berzerk (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, diff --git a/src/emucore/stella.pro b/src/emucore/stella.pro index 42d4cc186..8fec4e33d 100644 --- a/src/emucore/stella.pro +++ b/src/emucore/stella.pro @@ -252,7 +252,7 @@ "Cart.Name" "Princess Rescue (2013) (Sprybug) (PAL60)" "Cart.Note" "Compatible with Genesis controller" "Cart.Rarity" "Homebrew" -"Display.Format" "PAL60" +"Controller.Left" "JOYSTICK" "Display.Phosphor" "YES" "" @@ -495,7 +495,6 @@ "Cart.MD5" "069c17beb1e8e0557adb8539fdcf6cba" "Cart.Name" "Phantom II & Pirate (PAL60)" "Cart.Rarity" "Homebrew" -"Display.Format" "PAL60" "" "Cart.MD5" "06b0194ce992584c365278e0d7323279" @@ -679,7 +678,6 @@ "Cart.Manufacturer" "Thomas Jentzsch" "Cart.Name" "Centipede - Atari Trak-Ball Hack v1.4 (PAL60) (Half-Speed) (TJ)" "Cart.Note" "Uses Atari Trak-Ball Controller" -"Display.Format" "PAL60" "" "Cart.MD5" "0894aa7be77521f9df562be8d9555fe6" @@ -733,7 +731,6 @@ "Cart.Manufacturer" "Thomas Jentzsch" "Cart.Name" "Challenge of... Nexar, The - Atari Trak-Ball Hack v1.2 (PAL60) (TJ)" "Cart.Note" "Uses Atari Trak-Ball Controller" -"Display.Format" "PAL60" "" "Cart.MD5" "08f4dc6f118f7c98e2406c180c08e78e" @@ -1027,7 +1024,6 @@ "Cart.ModelNo" "v1.3" "Cart.Name" "Amoeba Jump (2018) (Dionoid) (PAL60)" "Cart.Rarity" "Homebrew" -"Display.Format" "PAL60" "" "Cart.MD5" "0c7926d660f903a2d6910c254660c32c" @@ -1081,7 +1077,6 @@ "Cart.Manufacturer" "Thomas Jentzsch" "Cart.Name" "Challenge of... Nexar, The - Atari Mouse Hack v1.1 (PAL60) (TJ)" "Cart.Note" "Uses Atari Mouse Controller" -"Display.Format" "PAL60" "" "Cart.MD5" "0cfdd2f3b243cac21f38a0f09f54bead" @@ -1194,7 +1189,6 @@ "Cart.Manufacturer" "Thomas Jentzsch" "Cart.Name" "Centipede - Amiga Mouse Hack v1.4 (PAL60) (Half-Speed) (TJ)" "Cart.Note" "Uses Amiga Mouse Controller" -"Display.Format" "PAL60" "" "Cart.MD5" "0e4b2b6e014a93ef8be896823da0d4ec" @@ -1342,7 +1336,6 @@ "Cart.ModelNo" "805.784 6" "Cart.Name" "Labyrinth (1983) (Quelle) (PAL)" "Cart.Note" "AKA Maze Craze" -"Display.Format" "PAL" "" "Cart.MD5" "0fc161704c46e16f7483f92b06c1558d" @@ -1399,6 +1392,7 @@ "Cart.Name" "Princess Rescue (2013) (Sprybug)" "Cart.Note" "Compatible with Genesis controller" "Cart.Rarity" "Homebrew" +"Controller.Left" "JOYSTICK" "Display.Phosphor" "YES" "" @@ -1975,7 +1969,6 @@ "Cart.Manufacturer" "Thomas Jentzsch" "Cart.Name" "Challenge of... Nexar, The - Amiga Mouse Hack v1.1 (PAL60) (TJ)" "Cart.Note" "Uses Amiga Mouse Controller" -"Display.Format" "PAL60" "" "Cart.MD5" "1733772165d7b886a94e2b4ed0f74ccd" @@ -2112,7 +2105,6 @@ "Cart.Manufacturer" "Thomas Jentzsch" "Cart.Name" "Missile Control - Amiga Mouse Hack v1.15 (PAL60) (TJ)" "Cart.Note" "Uses Amiga Mouse Controller" -"Display.Format" "PAL60" "" "Cart.MD5" "18bebbbd41c234f82b1717b1905e6027" @@ -2354,7 +2346,6 @@ "Cart.Manufacturer" "Nukey Shay, Omegamatrix" "Cart.Name" "Double Dragon (Genesis) (PAL60) V2" "Cart.Note" "Genesis controller" -"Display.Format" "PAL60" "" "Cart.MD5" "1c6eb740d3c485766cade566abab8208" @@ -2638,7 +2629,6 @@ "Cart.Name" "Stay Frosty (SpiceWare) (PAL60)" "Cart.Note" "Part of Stella's Stocking 2007 Xmas compilation" "Cart.Rarity" "Homebrew" -"Display.Format" "PAL60" "Display.Phosphor" "YES" "" @@ -2701,7 +2691,6 @@ "Cart.Manufacturer" "Thomas Jentzsch" "Cart.Name" "Reactor - Amiga Mouse Hack v1.3 (PAL60) (Full-Speed) (TJ)" "Cart.Note" "Uses Amiga Mouse Controller" -"Display.Format" "PAL60" "" "Cart.MD5" "2091af29b4e7b86914d79d9aaa4cbd20" @@ -2898,8 +2887,7 @@ "Cart.Name" "Scramble (PAL60)" "Cart.Note" "Compatible with Genesis controller" "Cart.Rarity" "Homebrew" -"Controller.Left" "GENESIS" -"Display.Format" "PAL60" +"Controller.Left" "JOYSTICK" "Display.Phosphor" "YES" "" @@ -3157,7 +3145,6 @@ "Cart.Manufacturer" "Activision, Garry Kitchen" "Cart.ModelNo" "EAX-025" "Cart.Name" "Keystone Kapers (1983) (Activision) (SECAM)" -"Display.Format" "SECAM" "" "Cart.MD5" "25f9cf703575c5d63048c222f5463758" @@ -3218,7 +3205,6 @@ "Cart.Manufacturer" "Omegamatrix" "Cart.Name" "SpaceMaster X-7 (Amiga Mouse) (PAL60) (Omegamatrix)" "Cart.Note" "Uses Amiga Mouse Controller" -"Display.Format" "PAL60" "" "Cart.MD5" "271bfd5dc2673d382019f1fb6cab9332" @@ -3294,7 +3280,6 @@ "Cart.Note" "Hack of Video Olympics" "Controller.SwapPaddles" "YES" "Controller.MouseAxis" "AUTO 60" -"Display.Format" "PAL60" "" "Cart.MD5" "27baecd618e7e53dc11f2a9c559f529d" @@ -3721,7 +3706,6 @@ "Cart.Name" "Kool Aid Man (PAL Conversion) (16-11-2002) (Fabrizio Zavagli) (PAL60)" "Cart.Note" "PAL60 Conversion" "Cart.Rarity" "Homebrew" -"Display.Format" "PAL60" "" "Cart.MD5" "2c9fadd510509cc7f28f1ccba931855f" @@ -3889,7 +3873,6 @@ "Cart.Manufacturer" "Gray Games & AtariAge" "Cart.Name" "E.T. Book Cart (PAL60)" "Cart.Note" "Charles F. Gray & Michael Rideout" -"Display.Format" "PAL60" "Display.Phosphor" "YES" "Display.PPBlend" "55" "" @@ -4726,7 +4709,6 @@ "Cart.ModelNo" "SS-004" "Cart.Name" "Pyramid War (1983) (Rainbow Vision) (PAL) [a2]" "Cart.Note" "AKA Chopper Command" -"Display.Format" "PAL" "" "Cart.MD5" "384db97670817103dd8c0bbdef132445" @@ -5967,7 +5949,6 @@ "Cart.Manufacturer" "Omegamatrix" "Cart.Name" "Star Wars Arcade (Atari Trak-Ball) v4 (PAL60) (Omegamatrix)" "Cart.Note" "Uses Atari Trak-Ball Controller" -"Display.Format" "PAL60" "" "Cart.MD5" "4767356fa0ed3ebe21437b4473d4ee28" @@ -6173,7 +6154,6 @@ "Cart.Manufacturer" "Andreas Dietrich" "Cart.Name" "Donkey Kong VCS (2017) (1.0) (PAL60)" "Cart.Rarity" "Homebrew" -"Display.Format" "PAL60" "Display.Phosphor" "YES" "" @@ -6332,7 +6312,6 @@ "Cart.Manufacturer" "Omegamatrix" "Cart.Name" "SpaceMaster X-7 (Atari Mouse) (PAL60) (Omegamatrix)" "Cart.Note" "Uses Atari Mouse Controller" -"Display.Format" "PAL60" "" "Cart.MD5" "4b71197153d651480830638cb6a03249" @@ -6738,7 +6717,6 @@ "Cart.MD5" "50200f697aeef38a3ce31c4f49739551" "Cart.Manufacturer" "Mystique - American Multiple Industries, Joel H. Martin" "Cart.Name" "Custer's Revenge (1982) (Mystique) (PAL60)" -"Display.Format" "PAL60" "" "Cart.MD5" "502044b1ac111b394e6fbb0d821fca41" @@ -7280,7 +7258,6 @@ "Cart.Manufacturer" "Omegamatrix" "Cart.Name" "Star Wars Arcade (Amiga Mouse) v4 (PAL60) (Omegamatrix)" "Cart.Note" "Uses Amiga Mouse Controller" -"Display.Format" "PAL60" "" "Cart.MD5" "571c6d9bc71cb97617422851f787f8fe" @@ -7376,7 +7353,6 @@ "Cart.Manufacturer" "Xonox - K-Tel Software - Action Graphics, Michael Schwartz, David Thiel" "Cart.ModelNo" "6230, 7210, 06004, 99004" "Cart.Name" "Artillery Duel (1983) (Xonox) (PAL60)" -"Display.Format" "PAL60" "" "Cart.MD5" "58a82e1da64a692fd727c25faef2ecc9" @@ -7486,8 +7462,7 @@ "Cart.Name" "Super Cobra Arcade (PAL60)" "Cart.Note" "Compatible with Genesis controller" "Cart.Rarity" "Homebrew" -"Controller.Left" "GENESIS" -"Display.Format" "PAL60" +"Controller.Left" "JOYSTICK" "Display.Phosphor" "YES" "" @@ -7784,7 +7759,6 @@ "Cart.Name" "Space Shuttle (1983) (Activision) (SECAM)" "Cart.Note" "A Journey Into Space" "Cart.Type" "FE" -"Display.Format" "SECAM" "" "Cart.MD5" "5d2cc33ca798783dee435eb29debf6d6" @@ -8772,7 +8746,6 @@ "Cart.Manufacturer" "Omegamatrix" "Cart.Name" "SpaceMaster X-7 (Atari Trak-Ball) (PAL60) (Omegamatrix)" "Cart.Note" "Uses Atari Trak-Ball Controller" -"Display.Format" "PAL60" "" "Cart.MD5" "6803fa7c2c094b428b859a58dc1dd06a" @@ -8796,7 +8769,6 @@ "Cart.Manufacturer" "Thomas Jentzsch" "Cart.Name" "Centipede - Atari Mouse Hack v1.4 (PAL60) (Full-Speed) (TJ)" "Cart.Note" "Uses Atari Mouse Controller" -"Display.Format" "PAL60" "" "Cart.MD5" "683bb0d0f0c5df58557fba9dffc32c40" @@ -9709,7 +9681,6 @@ "Cart.Manufacturer" "Thomas Jentzsch" "Cart.Name" "Missile Control - Atari Trak-Ball Hack v1.15 (PAL60) (TJ)" "Cart.Note" "Uses Atari Trak-Ball Controller" -"Display.Format" "PAL60" "" "Cart.MD5" "72bda70c75dfa2365b3f8894bace9e6a" @@ -9967,7 +9938,6 @@ "Cart.Name" "Conquest Of Mars (2010) (PAL60)" "Cart.Note" "Rev 2 release" "Cart.Rarity" "Homebrew" -"Display.Format" "PAL60" "" "Cart.MD5" "75a303fd46ad12457ed8e853016815a0" @@ -10443,7 +10413,6 @@ "Cart.Manufacturer" "Omegamatrix" "Cart.Name" "Star Wars Arcade (Atari Trak-Ball) (Y Inverted) (PAL60) v4 (Omegamatrix)" "Cart.Note" "Uses Atari Trak-Ball Controller" -"Display.Format" "PAL60" "" "Cart.MD5" "7b5207e68ee85b16998bea861987c690" @@ -10578,7 +10547,6 @@ "Cart.Manufacturer" "Thomas Jentzsch" "Cart.Name" "Centipede - Atari Mouse Hack v1.4 (PAL60) (Half-Speed) (TJ)" "Cart.Note" "Uses Atari Mouse Controller" -"Display.Format" "PAL60" "" "Cart.MD5" "7d0b49ea4fe3a5f1e119a6d14843db17" @@ -11001,7 +10969,6 @@ "Cart.Note" "Hack of Kaboom!" "Cart.Rarity" "Hack" "Controller.MouseAxis" "01 50" -"Display.Format" "PAL60" "" "Cart.MD5" "8108162bc88b5a14adc3e031cf4175ad" @@ -11225,7 +11192,7 @@ "Cart.Name" "Super Cobra Arcade (NTSC)" "Cart.Note" "Compatible with Genesis controller" "Cart.Rarity" "Homebrew" -"Controller.Left" "GENESIS" +"Controller.Left" "JOYSTICK" "Display.Phosphor" "YES" "" @@ -11384,7 +11351,6 @@ "Cart.ModelNo" "CG-02-P" "Cart.Name" "Conquest Of Mars (PAL60)" "Cart.Rarity" "Homebrew" -"Display.Format" "PAL60" "" "Cart.MD5" "85e48d68c8d802e3ba9d494a47d6e016" @@ -11855,7 +11821,6 @@ "Cart.Manufacturer" "Omegamatrix" "Cart.Name" "Star Wars Arcade (Amiga Mouse) (Y Inverted) (PAL60) v4 (Omegamatrix)" "Cart.Note" "Uses Amiga Mouse Controller" -"Display.Format" "PAL60" "" "Cart.MD5" "8c1cc284edba691139d6626d062c606f" @@ -11863,7 +11828,6 @@ "Cart.Name" "Super Breakout Menu (2020) (PAL60) (Hack)" "Cart.Note" "Hack of Super Breakout" "Controller.MouseAxis" "AUTO 45" -"Display.Format" "PAL60" "" "Cart.MD5" "8c2fa33048f055f38358d51eefe417db" @@ -12042,7 +12006,6 @@ "Cart.Name" "Cosmic Commuter (Thomas Jentzsch) (PAL60)" "Cart.Note" "NTSC Conversion" "Cart.Rarity" "Hack" -"Display.Format" "PAL60" "" "Cart.MD5" "8e887d1ba5f3a71ae8a0ea16a4af9fc9" @@ -12069,7 +12032,6 @@ "Cart.Manufacturer" "Thomas Jentzsch" "Cart.Name" "Reactor - Amiga Mouse Hack v1.3 (PAL60) (Half-Speed) (TJ)" "Cart.Note" "Uses Amiga Mouse Controller" -"Display.Format" "PAL60" "" "Cart.MD5" "8f33bce5ba1053dcf4cea9c1c69981e4" @@ -12177,7 +12139,6 @@ "Cart.Name" "Crash Dive (Fabrizio Zavagli) (PAL60)" "Cart.Note" "NTSC Conversion" "Cart.Rarity" "Hack" -"Display.Format" "PAL60" "" "Cart.MD5" "90a3c3255f2a54225cdcb50831f8793a" @@ -12439,7 +12400,6 @@ "Cart.Manufacturer" "Thomas Jentzsch" "Cart.Name" "Challenge of... Nexar, The - Atari Trak-Ball Hack v1.1 (PAL60) (TJ)" "Cart.Note" "Uses Atari Trak-Ball Controller" -"Display.Format" "PAL60" "" "Cart.MD5" "93dc15d15e77a7b23162467f95a5f22d" @@ -12488,7 +12448,6 @@ "Cart.Manufacturer" "Thomas Jentzsch" "Cart.Name" "Marble Craze - Amiga Mouse Hack v1.0 (PAL60) (TJ)" "Cart.Note" "Uses Amiga Mouse Controllers" -"Display.Format" "PAL60" "" "Cart.MD5" "94507dee401b0a072a481c00d7699ffe" @@ -13050,7 +13009,6 @@ "Cart.Manufacturer" "Andrew Wallace" "Cart.Name" "Laseresal 2002 (PAL60) (PD)" "Cart.Rarity" "New Release" -"Display.Format" "PAL60" "" "Cart.MD5" "9c729017dd2f9ccbadcb511187f80e6b" @@ -13265,7 +13223,6 @@ "Cart.Name" "Montezuma's Revenge (Thomas Jentzsch) (PAL60)" "Cart.Note" "NTSC Conversion" "Cart.Rarity" "Homebrew" -"Display.Format" "PAL60" "" "Cart.MD5" "9f8fad4badcd7be61bbd2bcaeef3c58f" @@ -13539,7 +13496,6 @@ "Cart.Manufacturer" "Omegamatrix" "Cart.Name" "Star Wars Arcade (Atari Mouse) (Y Inverted) (PAL60) v4 (Omegamatrix)" "Cart.Note" "Uses Atari Mouse Controller" -"Display.Format" "PAL60" "" "Cart.MD5" "a2de0fc85548871279ed2a3c1325c13e" @@ -13562,7 +13518,6 @@ "Cart.Manufacturer" "Nukey Shay" "Cart.Name" "Montezuma's Revenge (Genesis) (PAL60) (F6_Conversion)" "Cart.Note" "Genesis controller" -"Display.Format" "PAL60" "" "Cart.MD5" "a302b922a8dbec47743f28b7f91d4cd8" @@ -13644,7 +13599,6 @@ "Cart.Manufacturer" "Aaron Curtis" "Cart.Name" "AStar (PAL60)" "Cart.Rarity" "Homebrew" -"Display.Format" "PAL60" "" "Cart.MD5" "a406d2f6d84e61d842f4cb13b2b1cfa7" @@ -13697,7 +13651,6 @@ "Cart.Manufacturer" "Thomas Jentzsch" "Cart.Name" "Marble Craze - Atari Mouse Hack v1.0 (PAL60) (TJ)" "Cart.Note" "Uses Atari Mouse Controllers" -"Display.Format" "PAL60" "" "Cart.MD5" "a499d720e7ee35c62424de882a3351b6" @@ -14116,7 +14069,6 @@ "Cart.ModelNo" "CX26201" "Cart.Name" "Zippy the Porcupine (2014) (Sprybug) (PAL60)" "Cart.Rarity" "Homebrew" -"Display.Format" "PAL60" "" "Cart.MD5" "a9e3c23599c0d77151602f8e31daf879" @@ -14388,7 +14340,6 @@ "Cart.Manufacturer" "Thomas Jentzsch" "Cart.Name" "Reactor - Atari Trak-Ball Hack v1.3 (PAL60) (Full-Speed) (TJ)" "Cart.Note" "Uses Atari Trak-Ball Controller" -"Display.Format" "PAL60" "" "Cart.MD5" "ad7e97c19bd25d5aa3999430845c755b" @@ -14720,7 +14671,6 @@ "Cart.Manufacturer" "Thomas Jentzsch" "Cart.Name" "Reactor - Atari Mouse Hack v1.3 (PAL60) (Half-Speed) (TJ)" "Cart.Note" "Uses Atari Mouse Controller" -"Display.Format" "PAL60" "" "Cart.MD5" "b1a6c96e9093352106bc335e96caa154" @@ -14879,7 +14829,6 @@ "Cart.Manufacturer" "Omegamatrix" "Cart.Name" "Star Wars Arcade (Atari Mouse) v4 (PAL60) (Omegamatrix)" "Cart.Note" "Uses Atari Mouse Controller" -"Display.Format" "PAL60" "" "Cart.MD5" "b31f178aa0d569cccac7959f84e0a724" @@ -15145,7 +15094,6 @@ "Cart.Name" "Cat Trax (Thomas Jentzsch) (PAL60)" "Cart.Note" "NTSC Conversion" "Cart.Rarity" "Hack" -"Display.Format" "PAL60" "Display.Phosphor" "YES" "" @@ -15181,7 +15129,6 @@ "Cart.ModelNo" "RC2" "Cart.Name" "Flappy (2014) (AtariAge) (PAL60)" "Cart.Rarity" "Homebrew" -"Display.Format" "PAL60" "" "Cart.MD5" "b7e459d5416eeb196aaa8e092db14463" @@ -15286,7 +15233,6 @@ "Cart.Manufacturer" "Atari, Omegamatrix" "Cart.Name" "Space Invaders Menu (2020) (PAL60) (Hack)" "Cart.Note" "Hack of Space Invaders" -"Display.Format" "PAL60" "" "Cart.MD5" "b958d5fd9574c5cf9ece4b9421c28ecd" @@ -15401,7 +15347,6 @@ "Cart.Manufacturer" "Thomas Jentzsch" "Cart.Name" "Missile Control - Atari Mouse Hack v1.15 (PAL60) (TJ)" "Cart.Note" "Uses Atari Mouse Controller" -"Display.Format" "PAL60" "" "Cart.MD5" "bb5049e4558daade0f87fed69a244c59" @@ -15492,7 +15437,6 @@ "Cart.Manufacturer" "Bob Montgomery (aka vdub_bobby)" "Cart.Name" "Squish 'Em (2007) (PAL60)" "Cart.Rarity" "Homebrew" -"Display.Format" "PAL60" "" "Cart.MD5" "bccb4e2cfad5efc93f6d55dc992118ce" @@ -15709,7 +15653,6 @@ "Cart.Manufacturer" "Atari" "Cart.Name" "A-Team (Atari) (Prototype) (PAL60)" "Cart.Rarity" "Prototype" -"Display.Format" "PAL60" "" "Cart.MD5" "c032c2bd7017fdfbba9a105ec50f800e" @@ -16487,7 +16430,6 @@ "Cart.Manufacturer" "Thomas Jentzsch" "Cart.Name" "Marble Craze - Atari Trak-Ball Hack v1.0 (PAL60) (TJ)" "Cart.Note" "Uses Atari Trak-Ball Controllers" -"Display.Format" "PAL60" "" "Cart.MD5" "c9196e28367e46f8a55e04c27743148f" @@ -16506,7 +16448,6 @@ "Cart.Manufacturer" "AtariAge, Omegamatrix" "Cart.Name" "Venture Reloaded (2019) (AtariAge) (PAL60) (Hack)" "Cart.Note" "Transformative hack of Venture" -"Display.Format" "PAL60" "Display.Phosphor" "YES" "" @@ -16873,7 +16814,6 @@ "Cart.Manufacturer" "SEGA - Teldec" "Cart.ModelNo" "005-10" "Cart.Name" "Buck Rogers - Planet of Zoom (1983) (SEGA) (PAL)" -"Display.Format" "PAL" "Display.Phosphor" "YES" "" @@ -16903,7 +16843,6 @@ "Cart.Manufacturer" "Thomas Jentzsch" "Cart.Name" "Centipede - Amiga Mouse Hack v1.4 (PAL60) (Full-Speed) (TJ)" "Cart.Note" "Uses Amiga Mouse Controller" -"Display.Format" "PAL60" "" "Cart.MD5" "cdb81bf33d830ee4ee0606ee99e84dba" @@ -17009,7 +16948,6 @@ "Cart.Manufacturer" "Thomas Jentzsch" "Cart.Name" "Reactor - Atari Trak-Ball Hack v1.3 (PAL60) (Half-Speed) (TJ)" "Cart.Note" "Uses Atari Trak-Ball Controller" -"Display.Format" "PAL60" "" "Cart.MD5" "cedbd67d1ff321c996051eec843f8716" @@ -17162,7 +17100,6 @@ "Cart.Name" "Tomarc the Barbarian (1983) (Xonox) (PAL60)" "Cart.Note" "Genesis controller (B is jump and throw, C switches between players)" "Cart.Rarity" "Hack of Tomarc the Barbarian" -"Display.Format" "PAL60" "" "Cart.MD5" "d00f6f8ba89559e4b20972a478fc0370" @@ -17552,7 +17489,6 @@ "Cart.ModelNo" "CX26140, CX26140P" "Cart.Name" "Desert Falcon (1987) (Atari) (PAL)" "Cart.Note" "AKA Nile Flyer, Sphinx" -"Display.Format" "PAL" "" "Cart.MD5" "d483f65468d9a265661917bae1a54f3e" @@ -17649,7 +17585,6 @@ "Cart.Manufacturer" "Activision, Carol Shaw" "Cart.ModelNo" "EAX-020" "Cart.Name" "River Raid (1982) (Activision) (SECAM)" -"Display.Format" "SECAM" "" "Cart.MD5" "d5e27051512c1e7445a9bf91501bda09" @@ -18008,7 +17943,6 @@ "Cart.ModelNo" "460673" "Cart.Name" "Pick 'n' Pile (1990) (Salu) (PAL)" "Console.SwapPorts" "YES" -"Display.Format" "PAL" "Display.Phosphor" "YES" "" @@ -18933,7 +18867,6 @@ "Cart.Manufacturer" "Thomas Jentzsch" "Cart.Name" "Centipede - Atari Trak-Ball Hack v1.4 (PAL60) (Full-Speed) (TJ)" "Cart.Note" "Uses Atari Trak-Ball Controller" -"Display.Format" "PAL60" "" "Cart.MD5" "e49ac0ec879a0d7820bc2598fc2cfcd4" @@ -19430,7 +19363,7 @@ "Cart.Name" "Scramble (NTSC)" "Cart.Note" "Compatible with Genesis controller" "Cart.Rarity" "Homebrew" -"Controller.Left" "GENESIS" +"Controller.Left" "JOYSTICK" "Display.Phosphor" "YES" "" @@ -19549,7 +19482,6 @@ "Cart.Manufacturer" "Activision, John Van Ryzin" "Cart.ModelNo" "EAZ-036-04" "Cart.Name" "H.E.R.O. (1984) (Activision) (SECAM)" -"Display.Format" "SECAM" "" "Cart.MD5" "eb92193f06b645df0b2a15d077ce435f" @@ -19638,7 +19570,6 @@ "Cart.MD5" "ece908d77ab944f7bac84322b9973549" "Cart.Name" "Tom Boy (Unknown) (PAL60)" "Cart.Note" "AKA Pitfall!" -"Display.Format" "PAL60" "" "Cart.MD5" "ecf51385384b468834611d44a8429c03" @@ -19695,7 +19626,6 @@ "Cart.ModelNo" "CX2635, CX2635P" "Cart.Name" "Maze Craze (1980) (Atari) (PAL)" "Cart.Note" "AKA A Game of Cops 'n Robbers" -"Display.Format" "PAL" "" "Cart.MD5" "ed5ccfc93ad4561075436ee42a15438a" @@ -19721,7 +19651,6 @@ "Cart.Manufacturer" "Activision, David Crane" "Cart.ModelNo" "EAZ-030" "Cart.Name" "Decathlon (1983) (Activision) (SECAM)" -"Display.Format" "SECAM" "" "Cart.MD5" "ede7e8bf865b0afb4744f86d13624f9a" @@ -19990,7 +19919,6 @@ "Cart.Manufacturer" "Thomas Jentzsch" "Cart.Name" "Reactor - Atari Mouse Hack v1.3 (PAL60) (Full-Speed) (TJ)" "Cart.Note" "Uses Atari Mouse Controller" -"Display.Format" "PAL60" "" "Cart.MD5" "f0e0addc07971561ab80d9abe1b8d333" @@ -20043,7 +19971,6 @@ "Cart.Name" "Lady Bug (PAL60)" "Cart.Rarity" "Homebrew" "Console.RightDiff" "A" -"Display.Format" "PAL60" "Display.Phosphor" "YES" "" @@ -20942,7 +20869,6 @@ "Cart.Note" "AtariVox supported" "Cart.Rarity" "Homebrew" "Controller.Right" "ATARIVOX" -"Display.Format" "PAL60" "Display.Phosphor" "YES" "" From 2e81c501661e91e132889f2e4a72bcac0eb083eb Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 15 Mar 2020 19:54:45 +0100 Subject: [PATCH 025/377] use R77 screen size as maximum for StellaSettingsDialog --- src/gui/Menu.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/Menu.cxx b/src/gui/Menu.cxx index c47525da9..fa2a569c6 100644 --- a/src/gui/Menu.cxx +++ b/src/gui/Menu.cxx @@ -43,7 +43,7 @@ Dialog* Menu::baseDialog() { if (stellaSettingDialog == nullptr) stellaSettingDialog = new StellaSettingsDialog(myOSystem, *this, myOSystem.frameBuffer().font(), - FBMinimum::Width, FBMinimum::Height, AppMode::emulator); + 1280, 720, AppMode::emulator); return stellaSettingDialog; } else From 2e1015ad36648bb13d0ff802ba8fd849ce447bd2 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sun, 15 Mar 2020 18:11:52 -0230 Subject: [PATCH 026/377] Fix a few compile warnings in Xcode, and add missing files. --- src/debugger/gui/TiaInfoWidget.cxx | 6 +++--- src/macos/stella.xcodeproj/project.pbxproj | 12 ++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/debugger/gui/TiaInfoWidget.cxx b/src/debugger/gui/TiaInfoWidget.cxx index 788f28c27..33ea5c7cf 100644 --- a/src/debugger/gui/TiaInfoWidget.cxx +++ b/src/debugger/gui/TiaInfoWidget.cxx @@ -143,10 +143,10 @@ void TiaInfoWidget::loadConfig() uInt64 total = tia.cyclesLo() + (uInt64(tia.cyclesHi()) << 32); uInt64 totalOld = oldTia.info[2] + (uInt64(oldTia.info[3]) << 32); - myTotalCycles->setText(Common::Base::toString(total / 1000000, Common::Base::Fmt::_10_6) + "e6", + myTotalCycles->setText(Common::Base::toString(uInt32(total) / 1000000, Common::Base::Fmt::_10_6) + "e6", total != totalOld); - uInt32 delta = total - totalOld; - myDeltaCycles->setText(Common::Base::toString(delta, Common::Base::Fmt::_10_8)); // no coloring + uInt64 delta = total - totalOld; + myDeltaCycles->setText(Common::Base::toString(uInt32(delta), Common::Base::Fmt::_10_8)); // no coloring int clk = tia.clocksThisLine(); myScanlineCount->setText(Common::Base::toString(tia.scanlines(), Common::Base::Fmt::_10_3), diff --git a/src/macos/stella.xcodeproj/project.pbxproj b/src/macos/stella.xcodeproj/project.pbxproj index 4f96dff80..33eccde69 100644 --- a/src/macos/stella.xcodeproj/project.pbxproj +++ b/src/macos/stella.xcodeproj/project.pbxproj @@ -375,6 +375,9 @@ DC6F394A21B897C700897AD8 /* FatalEmulationError.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC6F394821B897C700897AD8 /* FatalEmulationError.hxx */; }; DC6F394D21B897F300897AD8 /* ThreadDebugging.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC6F394B21B897F300897AD8 /* ThreadDebugging.cxx */; }; DC6F394E21B897F300897AD8 /* ThreadDebugging.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC6F394C21B897F300897AD8 /* ThreadDebugging.hxx */; }; + DC70065C241EC97900A459AB /* Stella12x24tFont.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC700659241EC97900A459AB /* Stella12x24tFont.hxx */; }; + DC70065D241EC97900A459AB /* Stella16x32tFont.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC70065A241EC97900A459AB /* Stella16x32tFont.hxx */; }; + DC70065E241EC97900A459AB /* Stella14x28tFont.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC70065B241EC97900A459AB /* Stella14x28tFont.hxx */; }; DC71C399221623D9005DE92F /* ControllerDetector.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC71C397221623D8005DE92F /* ControllerDetector.hxx */; }; DC71C39A221623D9005DE92F /* ControllerDetector.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC71C398221623D9005DE92F /* ControllerDetector.cxx */; }; DC71EA9D1FDA06D2008827CB /* CartE78K.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC71EA991FDA06D2008827CB /* CartE78K.cxx */; }; @@ -1111,6 +1114,9 @@ DC6F394821B897C700897AD8 /* FatalEmulationError.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = FatalEmulationError.hxx; path = exception/FatalEmulationError.hxx; sourceTree = ""; }; DC6F394B21B897F300897AD8 /* ThreadDebugging.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ThreadDebugging.cxx; sourceTree = ""; }; DC6F394C21B897F300897AD8 /* ThreadDebugging.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ThreadDebugging.hxx; sourceTree = ""; }; + DC700659241EC97900A459AB /* Stella12x24tFont.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Stella12x24tFont.hxx; sourceTree = ""; }; + DC70065A241EC97900A459AB /* Stella16x32tFont.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Stella16x32tFont.hxx; sourceTree = ""; }; + DC70065B241EC97900A459AB /* Stella14x28tFont.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Stella14x28tFont.hxx; sourceTree = ""; }; DC71C397221623D8005DE92F /* ControllerDetector.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ControllerDetector.hxx; sourceTree = ""; }; DC71C398221623D9005DE92F /* ControllerDetector.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ControllerDetector.cxx; sourceTree = ""; }; DC71EA991FDA06D2008827CB /* CartE78K.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartE78K.cxx; sourceTree = ""; }; @@ -2081,6 +2087,9 @@ 2DDBEACB084578BF00812C11 /* ScrollBarWidget.hxx */, DCDE17F817724E5D00EB1AC6 /* SnapshotDialog.cxx */, DCDE17F917724E5D00EB1AC6 /* SnapshotDialog.hxx */, + DC700659241EC97900A459AB /* Stella12x24tFont.hxx */, + DC70065B241EC97900A459AB /* Stella14x28tFont.hxx */, + DC70065A241EC97900A459AB /* Stella16x32tFont.hxx */, DC5D2C4F0F117CFD004D1660 /* StellaFont.hxx */, DC5D2C500F117CFD004D1660 /* StellaLargeFont.hxx */, DC5D2C510F117CFD004D1660 /* StellaMediumFont.hxx */, @@ -2506,6 +2515,7 @@ 2D91746409BA90380026E9FF /* TiaZoomWidget.hxx in Headers */, DC1BC6672066B4390076F74A /* PKeyboardHandler.hxx in Headers */, 2D91746609BA90380026E9FF /* AudioWidget.hxx in Headers */, + DC70065E241EC97900A459AB /* Stella14x28tFont.hxx in Headers */, 2D91746909BA90380026E9FF /* EventMappingWidget.hxx in Headers */, 2D91746A09BA90380026E9FF /* InputDialog.hxx in Headers */, DC47455609C34BFA00EDDA3A /* BankRomCheat.hxx in Headers */, @@ -2534,6 +2544,7 @@ DC4613680D92C03600D8DAB9 /* RomAuditDialog.hxx in Headers */, DC487FB70DA5350900E12499 /* AtariVox.hxx in Headers */, DC11F78E0DB36933003B505E /* MT24LC256.hxx in Headers */, + DC70065C241EC97900A459AB /* Stella12x24tFont.hxx in Headers */, DCA00FF80DBABCAD00C3823D /* RiotDebug.hxx in Headers */, DC4AC6F00DC8DACB00CD3AD2 /* RiotWidget.hxx in Headers */, DCA233B123B583FE0032ABF3 /* PhosphorHandler.hxx in Headers */, @@ -2637,6 +2648,7 @@ DC6DC921205DB879004A5FC3 /* PJoystickHandler.hxx in Headers */, DCAAE5DF1715887B0080BB82 /* CartEFSCWidget.hxx in Headers */, DCAAE5E11715887B0080BB82 /* CartEFWidget.hxx in Headers */, + DC70065D241EC97900A459AB /* Stella16x32tFont.hxx in Headers */, DCDFF08220B781B0001227C0 /* DispatchResult.hxx in Headers */, DCF8621A21C9D43300F95F52 /* StaggeredLogger.hxx in Headers */, DCAAE5E31715887B0080BB82 /* CartF0Widget.hxx in Headers */, From fe33c0e530419cdc05fd64fb6ac967bceb7d55ef Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sun, 15 Mar 2020 19:14:57 -0230 Subject: [PATCH 027/377] Fix 'ROM Audit' mode not getting current active directory. --- src/gui/Launcher.cxx | 4 ++-- src/gui/Launcher.hxx | 4 ++-- src/gui/LauncherDialog.cxx | 6 ++++++ src/gui/LauncherDialog.hxx | 11 +++++++++-- src/gui/RomAuditDialog.cxx | 2 +- 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/gui/Launcher.cxx b/src/gui/Launcher.cxx index eb1324f9f..379d9841e 100644 --- a/src/gui/Launcher.cxx +++ b/src/gui/Launcher.cxx @@ -75,9 +75,9 @@ const string& Launcher::selectedRomMD5() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const FilesystemNode& Launcher::currentNode() const +const FilesystemNode& Launcher::currentDir() const { - return (static_cast(myBaseDialog))->currentNode(); + return (static_cast(myBaseDialog))->currentDir(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/gui/Launcher.hxx b/src/gui/Launcher.hxx index 7a1b57fa7..af0e91f8b 100644 --- a/src/gui/Launcher.hxx +++ b/src/gui/Launcher.hxx @@ -55,9 +55,9 @@ class Launcher : public DialogContainer const string& selectedRomMD5(); /** - Wrapper for LauncherDialog::currentNode() method. + Wrapper for LauncherDialog::currentDir() method. */ - const FilesystemNode& currentNode() const; + const FilesystemNode& currentDir() const; /** Wrapper for LauncherDialog::reload() method. diff --git a/src/gui/LauncherDialog.cxx b/src/gui/LauncherDialog.cxx index c33832ce9..3003a04a3 100644 --- a/src/gui/LauncherDialog.cxx +++ b/src/gui/LauncherDialog.cxx @@ -261,6 +261,12 @@ const FilesystemNode& LauncherDialog::currentNode() const return myList->selected(); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const FilesystemNode& LauncherDialog::currentDir() const +{ + return myList->currentDir(); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LauncherDialog::reload() { diff --git a/src/gui/LauncherDialog.hxx b/src/gui/LauncherDialog.hxx index d112f0601..d734cdba5 100644 --- a/src/gui/LauncherDialog.hxx +++ b/src/gui/LauncherDialog.hxx @@ -74,12 +74,19 @@ class LauncherDialog : public Dialog const string& selectedRomMD5(); /** - Get node for the currently selected directory. + Get node for the currently selected entry. - @return FilesystemNode currently active + @return FilesystemNode currently selected */ const FilesystemNode& currentNode() const; + /** + Get node for the current directory. + + @return FilesystemNode (directory) currently active + */ + const FilesystemNode& currentDir() const; + /** Reload the current listing */ diff --git a/src/gui/RomAuditDialog.cxx b/src/gui/RomAuditDialog.cxx index 25cf78220..f83586d45 100644 --- a/src/gui/RomAuditDialog.cxx +++ b/src/gui/RomAuditDialog.cxx @@ -99,7 +99,7 @@ RomAuditDialog::~RomAuditDialog() void RomAuditDialog::loadConfig() { const string& currentdir = - instance().launcher().currentNode().getShortPath(); + instance().launcher().currentDir().getShortPath(); const string& path = currentdir == "" ? instance().settings().getString("romdir") : currentdir; From c0e84f9420286ccc5bc2805fd71756b5d9dfa697 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sun, 15 Mar 2020 19:18:14 -0230 Subject: [PATCH 028/377] Added "Stay Frosty 2" to properties database, and have it default to joysticks. --- src/emucore/DefProps.hxx | 4 +++- src/emucore/stella.pro | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/emucore/DefProps.hxx b/src/emucore/DefProps.hxx index 0f112214a..bb834d812 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 = 3508; +static constexpr uInt32 DEF_PROPS_SIZE = 3510; static const BSPF::array2D DefProps = {{ { "000509d1ed2b8d30a9d94be1b3b5febb", "Greg Zumwalt", "", "Jungle Jane (2003) (Greg Zumwalt) (Hack)", "Hack of Pitfall!", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -1188,6 +1188,7 @@ static const BSPF::array2D DefProps = {{ { "53f147b9746fdc997c62f3dd67888ee5", "Activision, Bob Whitehead", "AG-011", "Stampede (1981) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "540075f657d4b244a1f74da1b9e4bf92", "Bit Corporation", "PGP230", "Festival (4 Game in One Dark Green) (1983) (BitCorp) (PAL)", "AKA Carnival", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5409d20c1aea0b89c56993aec5dc5740", "", "", "Carnival Shooter (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "541cac55ebcf7891d9d51c415922303f", "SpiceWare - Darrell Spice Jr.", "SW-05", "Stay Frosty 2", "AtariAge Holiday Greetings 2014", "Homebrew", "", "", "", "", "", "", "", "JOYSTICK", "", "", "", "", "", "YES", "" }, { "5428cdfada281c569c74c7308c7f2c26", "Activision, Larry Kaplan, David Crane", "AG-010, AG-010-04", "Kaboom! (1981) (Activision)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, { "542c6dd5f7280179b51917a4cba4faff", "ZiMAG - Emag - Vidco", "GN-080", "Spinning Fireball (1983) (ZiMAG) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5438e84b90e50a5362f01cc843b358d4", "Arcadia Corporation, Scott Nelson", "3 AR-4300", "Fireball (1982) (Arcadia) (Prototype)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -1701,6 +1702,7 @@ static const BSPF::array2D DefProps = {{ { "78c2de58e42cd1faac2ea7df783eaeb3", "", "", "Fu Kung! (V0.07) (25-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "79004f84bdeee78d142e445057883169", "CCE", "C-830", "Planet Patrol (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "791bc8aceb6b0f4d9990d6062b30adfa", "Activision, David Crane - Ariola", "EAX-018, EAX-018-04B, EAX-018-04I - 711 018-725", "Pitfall! (1982) (Activision) (PAL)", "Abenteuer im Urwald (Jungle Runner)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "791c88eca9836af8c34bf32b07cb58a7", "SpiceWare - Darrell Spice Jr.", "SW-05", "Stay Frosty 2 (PAL60)", "AtariAge Holiday Greetings 2014", "Homebrew", "", "", "", "", "", "", "", "JOYSTICK", "", "", "", "", "", "YES", "" }, { "7926083ad423ed685de3b3a04a914315", "Barry Laws Jr.", "", "Face Invaders 2 (Barry Laws Jr.) (Hack)", "Hack of Astroblast", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "792b1d93eb1d8045260c840b0688ec8f", "Kroko", "", "3E Bankswitch Test (TIA @ $00)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7972e5101fa548b952d852db24ad6060", "Atari - Sears", "CX2627 - 6-99841", "Human Cannonball (1979) (Atari)", "AKA Cannon Man", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, diff --git a/src/emucore/stella.pro b/src/emucore/stella.pro index 8fec4e33d..4a8ba020e 100644 --- a/src/emucore/stella.pro +++ b/src/emucore/stella.pro @@ -21330,3 +21330,22 @@ "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" +"" From 9c7b8158601200fb9f31bbbf7f6ffa867191adc9 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sun, 15 Mar 2020 19:34:53 -0230 Subject: [PATCH 029/377] More fixes for DPC+ jitter issues, thanks to Spiceware. --- Changes.txt | 4 ++++ src/debugger/gui/CartDPCPlusWidget.cxx | 3 ++- src/emucore/CartDPCPlus.cxx | 17 ++++++++++++++--- src/emucore/CartDPCPlus.hxx | 4 ++++ 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/Changes.txt b/Changes.txt index 056572a76..693f3719c 100644 --- a/Changes.txt +++ b/Changes.txt @@ -181,6 +181,10 @@ * Fixed bug in DPC+ scheme; 'fast fetch mode' was enabled at startup, when it should be disabled by default. + * Some more work on DPC+ playfield 'jitter' effect for certain older DPC+ + driver versions; more ROMs are now detected properly. Special thanks + to SpiceWare for his research in this area. + * Added proper Retron77 port. * Added proper libretro port, and fixed display for OpenGLES renderers. diff --git a/src/debugger/gui/CartDPCPlusWidget.cxx b/src/debugger/gui/CartDPCPlusWidget.cxx index e55da1d1c..18166c6af 100644 --- a/src/debugger/gui/CartDPCPlusWidget.cxx +++ b/src/debugger/gui/CartDPCPlusWidget.cxx @@ -35,7 +35,8 @@ CartridgeDPCPlusWidget::CartridgeDPCPlusWidget( << "DPC registers accessible @ $F000 - $F07F\n" << " $F000 - $F03F (R), $F040 - $F07F (W)\n" << "Banks accessible at hotspots $FFF6 to $FFFB\n" - << "Startup bank = " << cart.startBank() << "\n"; + << "Startup bank = " << cart.startBank() << "\n" + << "Ver = " << cart.myDriverMD5; #if 0 // Eventually, we should query this from the debugger/disassembler diff --git a/src/emucore/CartDPCPlus.cxx b/src/emucore/CartDPCPlus.cxx index 9071b69d8..ab7230f78 100644 --- a/src/emucore/CartDPCPlus.cxx +++ b/src/emucore/CartDPCPlus.cxx @@ -57,9 +57,20 @@ CartridgeDPCPlus::CartridgeDPCPlus(const ByteBuffer& image, size_t size, Thumbulator::ConfigureFor::DPCplus, this); - // Currently only one known DPC+ ARM driver exhibits a problem - // with the default mask to use for DFxFRACLOW - if(MD5::hash(image, 3_KB) == "8dd73b44fd11c488326ce507cbeb19d1") + // Currently 4 DPC+ driver versions have been identified: + // 17884ec14f9b1d06fe8d617a1fbdcf47 Jitter Encore Compatible + // 5f80b5a5adbe483addc3f6e6f1b472f8 Stable Encore Compatible + // 8dd73b44fd11c488326ce507cbeb19d1 Stable NOT Encore Compatible + // b328dbdf787400c0f0e2b88b425872a5 Jitter Encore Compatible + // + // Jitter/Stable refers to the appearance of the playfield in bB games if + // the DFxFRACINC registers are not updated before every drawscreen. + // + // The default mask for DFxFRACLOW implements the Jitter behavior. This + // changes the mask to implement the Stable behavior. + myDriverMD5 = MD5::hash(image, 3_KB); + if(myDriverMD5 == "5f80b5a5adbe483addc3f6e6f1b472f8" || + myDriverMD5 == "8dd73b44fd11c488326ce507cbeb19d1" ) myFractionalLowMask = 0x0F0000; setInitialState(); diff --git a/src/emucore/CartDPCPlus.hxx b/src/emucore/CartDPCPlus.hxx index abc14f21d..46b18af99 100644 --- a/src/emucore/CartDPCPlus.hxx +++ b/src/emucore/CartDPCPlus.hxx @@ -272,6 +272,10 @@ class CartridgeDPCPlus : public Cartridge // Indicates the offset into the ROM image (aligns to current bank) uInt16 myBankOffset{0}; + // MD5 value of the 3K DPC+ driver. Used to determine which mask to use, + // and shown in the Cartridge tab of the debugger + string myDriverMD5; + // Older DPC+ driver code had different behaviour wrt the mask used // to retrieve 'DFxFRACLOW' (fractional data pointer low byte) // ROMs built with an old DPC+ driver and using the newer mask can From cb6fa6437b3b905cafb1b385f6edf08310ed8f55 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sun, 15 Mar 2020 19:44:57 -0230 Subject: [PATCH 030/377] Updated Changelog for a patch that was recently added. --- Changes.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changes.txt b/Changes.txt index 693f3719c..2452472df 100644 --- a/Changes.txt +++ b/Changes.txt @@ -198,6 +198,9 @@ * Updated included PNG library to latest stable version. + * Updated UNIX configure script to work with the gcc version 10 and + above. + -Have fun! From 5dff886ec4f90522c591e98de24d49eb83442d71 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 16 Mar 2020 09:04:35 +0100 Subject: [PATCH 031/377] StellaSettingsDialog font parameter cleanup --- src/gui/LauncherDialog.cxx | 2 +- src/gui/Menu.cxx | 4 +- src/gui/MinUICommandDialog.cxx | 2 +- src/gui/StellaSettingsDialog.cxx | 73 ++++++++++++++++---------------- src/gui/StellaSettingsDialog.hxx | 8 ++-- 5 files changed, 44 insertions(+), 45 deletions(-) diff --git a/src/gui/LauncherDialog.cxx b/src/gui/LauncherDialog.cxx index 3003a04a3..2bad88ef0 100644 --- a/src/gui/LauncherDialog.cxx +++ b/src/gui/LauncherDialog.cxx @@ -645,7 +645,7 @@ void LauncherDialog::openSettings() { if (myStellaSettingsDialog == nullptr) myStellaSettingsDialog = make_unique(instance(), parent(), - instance().frameBuffer().launcherFont(), _w, _h, Menu::AppMode::launcher); + _w, _h, Menu::AppMode::launcher); myStellaSettingsDialog->open(); } else diff --git a/src/gui/Menu.cxx b/src/gui/Menu.cxx index fa2a569c6..c2976857f 100644 --- a/src/gui/Menu.cxx +++ b/src/gui/Menu.cxx @@ -42,8 +42,8 @@ Dialog* Menu::baseDialog() if (myOSystem.settings().getBool("basic_settings")) { if (stellaSettingDialog == nullptr) - stellaSettingDialog = new StellaSettingsDialog(myOSystem, *this, myOSystem.frameBuffer().font(), - 1280, 720, AppMode::emulator); + stellaSettingDialog = new StellaSettingsDialog(myOSystem, *this, + 1280, 720, AppMode::emulator); return stellaSettingDialog; } else diff --git a/src/gui/MinUICommandDialog.cxx b/src/gui/MinUICommandDialog.cxx index e6cab4fba..dbb17870a 100644 --- a/src/gui/MinUICommandDialog.cxx +++ b/src/gui/MinUICommandDialog.cxx @@ -307,7 +307,7 @@ void MinUICommandDialog::openSettings() { if (myStellaSettingsDialog == nullptr) myStellaSettingsDialog = make_unique(instance(), parent(), - instance().frameBuffer().launcherFont(), FBMinimum::Width, FBMinimum::Height, Menu::AppMode::launcher); + 1280, 720, Menu::AppMode::launcher); myStellaSettingsDialog->open(); } else diff --git a/src/gui/StellaSettingsDialog.cxx b/src/gui/StellaSettingsDialog.cxx index 26f5cbde8..951f28ad9 100644 --- a/src/gui/StellaSettingsDialog.cxx +++ b/src/gui/StellaSettingsDialog.cxx @@ -29,16 +29,16 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - StellaSettingsDialog::StellaSettingsDialog(OSystem& osystem, DialogContainer& parent, - const GUI::Font& font, int max_w, int max_h, Menu::AppMode mode) - : Dialog(osystem, parent, font, "Basic settings"), + int max_w, int max_h, Menu::AppMode mode) + : Dialog(osystem, parent, osystem.frameBuffer().font(), "Basic settings"), myMode(mode) { const int VBORDER = 8; const int HBORDER = 10; const int INDENT = 20; - const int buttonHeight = font.getLineHeight() + 6, - lineHeight = font.getLineHeight(), - fontWidth = font.getMaxCharWidth(), + const int buttonHeight = _font.getLineHeight() + 6, + lineHeight = _font.getLineHeight(), + fontWidth = _font.getMaxCharWidth(), buttonWidth = _font.getStringWidth("Help" + ELLIPSIS) + 32; const int VGAP = 5; int xpos, ypos; @@ -53,50 +53,50 @@ StellaSettingsDialog::StellaSettingsDialog(OSystem& osystem, DialogContainer& pa xpos = HBORDER; ypos = VBORDER + _th; - bw = new ButtonWidget(this, font, xpos, ypos, _w - HBORDER * 2 - buttonWidth - 8, buttonHeight, + bw = new ButtonWidget(this, _font, xpos, ypos, _w - HBORDER * 2 - buttonWidth - 8, buttonHeight, "Use Advanced Settings" + ELLIPSIS, kAdvancedSettings); wid.push_back(bw); - bw = new ButtonWidget(this, font, bw->getRight() + 8, ypos, buttonWidth, buttonHeight, + bw = new ButtonWidget(this, _font, bw->getRight() + 8, ypos, buttonWidth, buttonHeight, "Help" + ELLIPSIS, kHelp); wid.push_back(bw); ypos += lineHeight + VGAP*4; - new StaticTextWidget(this, font, xpos, ypos + 1, "Global settings:"); + new StaticTextWidget(this, _font, xpos, ypos + 1, "Global settings:"); xpos += INDENT; ypos += lineHeight + VGAP; - addUIOptions(wid, xpos, ypos, font); + addUIOptions(wid, xpos, ypos); ypos += VGAP * 4; - addVideoOptions(wid, xpos, ypos, font); + addVideoOptions(wid, xpos, ypos); ypos += VGAP * 4; xpos -= INDENT; - myGameSettings = new StaticTextWidget(this, font, xpos, ypos + 1, "Game settings:"); + myGameSettings = new StaticTextWidget(this, _font, xpos, ypos + 1, "Game settings:"); xpos += INDENT; ypos += lineHeight + VGAP; - addGameOptions(wid, xpos, ypos, font); + addGameOptions(wid, xpos, ypos); // Add Defaults, OK and Cancel buttons - addDefaultsOKCancelBGroup(wid, font); + addDefaultsOKCancelBGroup(wid, _font); addToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void StellaSettingsDialog::addUIOptions(WidgetArray& wid, int& xpos, int& ypos, const GUI::Font& font) +void StellaSettingsDialog::addUIOptions(WidgetArray& wid, int& xpos, int& ypos) { const int VGAP = 4; - const int lineHeight = font.getLineHeight(); + const int lineHeight = _font.getLineHeight(); VariantList items; - int pwidth = font.getStringWidth("Right bottom"); // align width with other popup + int pwidth = _font.getStringWidth("Right bottom"); // align width with other popup ypos += 1; VarList::push_back(items, "Standard", "standard"); VarList::push_back(items, "Classic", "classic"); VarList::push_back(items, "Light", "light"); - myThemePopup = new PopUpWidget(this, font, xpos, ypos, pwidth, lineHeight, items, "UI theme "); + myThemePopup = new PopUpWidget(this, _font, xpos, ypos, pwidth, lineHeight, items, "UI theme "); wid.push_back(myThemePopup); ypos += lineHeight + VGAP; @@ -107,24 +107,23 @@ void StellaSettingsDialog::addUIOptions(WidgetArray& wid, int& xpos, int& ypos, VarList::push_back(items, "Right top", 2); VarList::push_back(items, "Right bottom", 3); VarList::push_back(items, "Left bottom", 4); - myPositionPopup = new PopUpWidget(this, font, xpos, ypos, pwidth, lineHeight, + myPositionPopup = new PopUpWidget(this, _font, xpos, ypos, pwidth, lineHeight, items, "Dialogs position "); wid.push_back(myPositionPopup); ypos += lineHeight + VGAP; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void StellaSettingsDialog::addVideoOptions(WidgetArray& wid, int& xpos, int& ypos, - const GUI::Font& font) +void StellaSettingsDialog::addVideoOptions(WidgetArray& wid, int& xpos, int& ypos) { const int VGAP = 4; const GUI::Font& ifont = instance().frameBuffer().infoFont(); - const int lineHeight = font.getLineHeight(), - fontWidth = font.getMaxCharWidth(); + const int lineHeight = _font.getLineHeight(), + fontWidth = _font.getMaxCharWidth(); VariantList items; // TV effects options - int swidth = font.getMaxCharWidth() * 11; + int swidth = _font.getMaxCharWidth() * 11; // TV Mode VarList::push_back(items, "Disabled", static_cast(NTSCFilter::Preset::OFF)); @@ -132,16 +131,16 @@ void StellaSettingsDialog::addVideoOptions(WidgetArray& wid, int& xpos, int& ypo VarList::push_back(items, "S-Video", static_cast(NTSCFilter::Preset::SVIDEO)); VarList::push_back(items, "Composite", static_cast(NTSCFilter::Preset::COMPOSITE)); VarList::push_back(items, "Bad adjust", static_cast(NTSCFilter::Preset::BAD)); - int pwidth = font.getStringWidth("Right bottom"); - int lwidth = font.getStringWidth("Scanline intensity "); + int pwidth = _font.getStringWidth("Right bottom"); + int lwidth = _font.getStringWidth("Scanline intensity "); - myTVMode = new PopUpWidget(this, font, xpos, ypos, pwidth, lineHeight, + myTVMode = new PopUpWidget(this, _font, xpos, ypos, pwidth, lineHeight, items, "TV mode "); wid.push_back(myTVMode); ypos += lineHeight + VGAP; // Scanline intensity - myTVScanIntense = new SliderWidget(this, font, xpos, ypos-1, swidth, lineHeight, + myTVScanIntense = new SliderWidget(this, _font, xpos, ypos-1, swidth, lineHeight, "Scanline intensity", lwidth, kScanlinesChanged, fontWidth * 3); myTVScanIntense->setMinValue(0); myTVScanIntense->setMaxValue(10); myTVScanIntense->setTickmarkIntervals(2); @@ -149,7 +148,7 @@ void StellaSettingsDialog::addVideoOptions(WidgetArray& wid, int& xpos, int& ypo ypos += lineHeight + VGAP; // TV Phosphor blend level - myTVPhosLevel = new SliderWidget(this, font, xpos, ypos-1, swidth, lineHeight, + myTVPhosLevel = new SliderWidget(this, _font, xpos, ypos-1, swidth, lineHeight, "Phosphor blend ", lwidth, kPhosphorChanged, fontWidth * 3); myTVPhosLevel->setMinValue(0); myTVPhosLevel->setMaxValue(10); myTVPhosLevel->setTickmarkIntervals(2); @@ -157,7 +156,7 @@ void StellaSettingsDialog::addVideoOptions(WidgetArray& wid, int& xpos, int& ypo ypos += lineHeight + VGAP; // FS overscan - myTVOverscan = new SliderWidget(this, font, xpos, ypos - 1, swidth, lineHeight, + myTVOverscan = new SliderWidget(this, _font, xpos, ypos - 1, swidth, lineHeight, "Overscan (*) ", lwidth, kOverscanChanged, fontWidth * 3); myTVOverscan->setMinValue(0); myTVOverscan->setMaxValue(10); myTVOverscan->setTickmarkIntervals(2); @@ -169,10 +168,10 @@ void StellaSettingsDialog::addVideoOptions(WidgetArray& wid, int& xpos, int& ypo } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void StellaSettingsDialog::addGameOptions(WidgetArray& wid, int& xpos, int& ypos, const GUI::Font& font) +void StellaSettingsDialog::addGameOptions(WidgetArray& wid, int& xpos, int& ypos) { const int VGAP = 4; - const int lineHeight = font.getLineHeight(); + const int lineHeight = _font.getLineHeight(); const GUI::Font& ifont = instance().frameBuffer().infoFont(); VariantList ctrls; @@ -187,9 +186,9 @@ void StellaSettingsDialog::addGameOptions(WidgetArray& wid, int& xpos, int& ypos VarList::push_back(ctrls, "Trakball", "TRAKBALL"); VarList::push_back(ctrls, "Sega Genesis", "GENESIS"); - int pwidth = font.getStringWidth("Sega Genesis"); - myLeftPortLabel = new StaticTextWidget(this, font, xpos, ypos + 1, "Left port "); - myLeftPort = new PopUpWidget(this, font, myLeftPortLabel->getRight(), + int pwidth = _font.getStringWidth("Sega Genesis"); + myLeftPortLabel = new StaticTextWidget(this, _font, xpos, ypos + 1, "Left port "); + myLeftPort = new PopUpWidget(this, _font, myLeftPortLabel->getRight(), myLeftPortLabel->getTop() - 1, pwidth, lineHeight, ctrls, "", 0, kLeftCChanged); wid.push_back(myLeftPort); ypos += lineHeight + VGAP; @@ -198,8 +197,8 @@ void StellaSettingsDialog::addGameOptions(WidgetArray& wid, int& xpos, int& ypos "Sega Genesis detected"); ypos += ifont.getLineHeight() + VGAP; - myRightPortLabel = new StaticTextWidget(this, font, xpos, ypos + 1, "Right port "); - myRightPort = new PopUpWidget(this, font, myRightPortLabel->getRight(), + myRightPortLabel = new StaticTextWidget(this, _font, xpos, ypos + 1, "Right port "); + myRightPort = new PopUpWidget(this, _font, myRightPortLabel->getRight(), myRightPortLabel->getTop() - 1, pwidth, lineHeight, ctrls, "", 0, kRightCChanged); wid.push_back(myRightPort); ypos += lineHeight + VGAP; @@ -415,7 +414,7 @@ void StellaSettingsDialog::switchSettingsMode() msg.push_back("proceed with the switch, click"); msg.push_back("'OK', otherwise click 'Cancel'."); - myConfirmMsg = make_unique(this, instance().frameBuffer().font(), msg, + myConfirmMsg = make_unique(this, _font, msg, _w-16, _h, kConfirmSwitchCmd, "OK", "Cancel", "Switch settings mode", false); myConfirmMsg->show(); } diff --git a/src/gui/StellaSettingsDialog.hxx b/src/gui/StellaSettingsDialog.hxx index cad6c9fbc..791db381c 100644 --- a/src/gui/StellaSettingsDialog.hxx +++ b/src/gui/StellaSettingsDialog.hxx @@ -39,7 +39,7 @@ class StellaSettingsDialog : public Dialog { public: StellaSettingsDialog(OSystem& osystem, DialogContainer& parent, - const GUI::Font& font, int max_w, int max_h, Menu::AppMode mode); + int max_w, int max_h, Menu::AppMode mode); virtual ~StellaSettingsDialog() = default; private: @@ -47,9 +47,9 @@ class StellaSettingsDialog : public Dialog void saveConfig() override; void setDefaults() override; - void addVideoOptions(WidgetArray& wid, int& xpos, int& ypos, const GUI::Font& font); - void addUIOptions(WidgetArray& wid, int& xpos, int& ypos, const GUI::Font& font); - void addGameOptions(WidgetArray& wid, int& xpos, int& ypos, const GUI::Font& font); + void addVideoOptions(WidgetArray& wid, int& xpos, int& ypos); + void addUIOptions(WidgetArray& wid, int& xpos, int& ypos); + void addGameOptions(WidgetArray& wid, int& xpos, int& ypos); void handleCommand(CommandSender* sender, int cmd, int data, int id) override; void handleOverscanChange(); From b9169aaca3a4e41fd330bd0d47e2c870164912ab Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 16 Mar 2020 09:26:45 +0100 Subject: [PATCH 032/377] larger infoFont for minimal UI dialogs --- src/emucore/FrameBuffer.cxx | 13 ++++++++++--- src/gui/StellaSettingsDialog.cxx | 6 ++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 922ed9655..68b6e8caa 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -116,13 +116,20 @@ bool FrameBuffer::initialize() // The general font used in all UI elements // This is determined by the size of the framebuffer if(myOSystem.settings().getBool("minimal_ui")) + { myFont = make_unique(GUI::stella12x24tDesc); // 12x24 + // The info font used in all UI elements + // This is determined by the size of the framebuffer + myInfoFont = make_unique(GUI::stellaLargeDesc); // 10x20 + } else + { myFont = make_unique(GUI::stellaMediumDesc); // 9x18 + // The info font used in all UI elements + // This is determined by the size of the framebuffer + myInfoFont = make_unique(GUI::consoleDesc); // 8x13 + } - // The info font used in all UI elements - // This is determined by the size of the framebuffer - myInfoFont = make_unique(GUI::consoleDesc); // 8x13 // The font used by the ROM launcher const string& lf = myOSystem.settings().getString("launcherfont"); diff --git a/src/gui/StellaSettingsDialog.cxx b/src/gui/StellaSettingsDialog.cxx index 951f28ad9..bc187b750 100644 --- a/src/gui/StellaSettingsDialog.cxx +++ b/src/gui/StellaSettingsDialog.cxx @@ -39,7 +39,8 @@ StellaSettingsDialog::StellaSettingsDialog(OSystem& osystem, DialogContainer& pa const int buttonHeight = _font.getLineHeight() + 6, lineHeight = _font.getLineHeight(), fontWidth = _font.getMaxCharWidth(), - buttonWidth = _font.getStringWidth("Help" + ELLIPSIS) + 32; + buttonWidth = _font.getStringWidth("Help" + ELLIPSIS) + 32, + iLineHeight = instance().frameBuffer().infoFont().getLineHeight(); const int VGAP = 5; int xpos, ypos; ButtonWidget* bw = nullptr; @@ -48,7 +49,8 @@ StellaSettingsDialog::StellaSettingsDialog(OSystem& osystem, DialogContainer& pa VariantList items; // Set real dimensions - setSize(35 * fontWidth + HBORDER * 2 + 3, 15 * (lineHeight + VGAP) + VGAP * 9 + 10 + _th, max_w, max_h); + setSize(35 * fontWidth + HBORDER * 2 + 3, 10 * (lineHeight + VGAP) + 3 * (iLineHeight + VGAP) + + VGAP * (12 + 2) + buttonHeight * 2 + _th, max_w, max_h); xpos = HBORDER; ypos = VBORDER + _th; From ce47e63549ea675af9b6ef0e6caaa38b92b99a09 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 16 Mar 2020 09:58:06 +0100 Subject: [PATCH 033/377] StellaSettingsDialog sizes fine tuning --- src/gui/StellaSettingsDialog.cxx | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/gui/StellaSettingsDialog.cxx b/src/gui/StellaSettingsDialog.cxx index bc187b750..fbd93dc7d 100644 --- a/src/gui/StellaSettingsDialog.cxx +++ b/src/gui/StellaSettingsDialog.cxx @@ -33,15 +33,16 @@ StellaSettingsDialog::StellaSettingsDialog(OSystem& osystem, DialogContainer& pa : Dialog(osystem, parent, osystem.frameBuffer().font(), "Basic settings"), myMode(mode) { - const int VBORDER = 8; - const int HBORDER = 10; - const int INDENT = 20; - const int buttonHeight = _font.getLineHeight() + 6, + const int buttonHeight = _font.getLineHeight() + _font.getLineHeight() / 5, lineHeight = _font.getLineHeight(), fontWidth = _font.getMaxCharWidth(), - buttonWidth = _font.getStringWidth("Help" + ELLIPSIS) + 32, + buttonWidth = _font.getStringWidth(" Help " + ELLIPSIS), iLineHeight = instance().frameBuffer().infoFont().getLineHeight(); - const int VGAP = 5; + + const int VBORDER = _font.getFontHeight() / 2; + const int HBORDER = fontWidth; + const int INDENT = fontWidth * 2; + const int VGAP = _font.getFontHeight() / 4; int xpos, ypos; ButtonWidget* bw = nullptr; @@ -49,8 +50,9 @@ StellaSettingsDialog::StellaSettingsDialog(OSystem& osystem, DialogContainer& pa VariantList items; // Set real dimensions - setSize(35 * fontWidth + HBORDER * 2 + 3, 10 * (lineHeight + VGAP) + 3 * (iLineHeight + VGAP) - + VGAP * (12 + 2) + buttonHeight * 2 + _th, max_w, max_h); + setSize(35 * fontWidth + HBORDER * 2 + 5, + VBORDER * 2 +_th + 10 * (lineHeight + VGAP) + 3 * (iLineHeight + VGAP) + + VGAP * 12 + buttonHeight * 2, max_w, max_h); xpos = HBORDER; ypos = VBORDER + _th; @@ -62,7 +64,7 @@ StellaSettingsDialog::StellaSettingsDialog(OSystem& osystem, DialogContainer& pa "Help" + ELLIPSIS, kHelp); wid.push_back(bw); - ypos += lineHeight + VGAP*4; + ypos += buttonHeight + VGAP * 2; new StaticTextWidget(this, _font, xpos, ypos + 1, "Global settings:"); xpos += INDENT; @@ -89,7 +91,7 @@ StellaSettingsDialog::StellaSettingsDialog(OSystem& osystem, DialogContainer& pa // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void StellaSettingsDialog::addUIOptions(WidgetArray& wid, int& xpos, int& ypos) { - const int VGAP = 4; + const int VGAP = _font.getFontHeight() / 4; const int lineHeight = _font.getLineHeight(); VariantList items; int pwidth = _font.getStringWidth("Right bottom"); // align width with other popup @@ -118,7 +120,7 @@ void StellaSettingsDialog::addUIOptions(WidgetArray& wid, int& xpos, int& ypos) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void StellaSettingsDialog::addVideoOptions(WidgetArray& wid, int& xpos, int& ypos) { - const int VGAP = 4; + const int VGAP = _font.getFontHeight() / 4; const GUI::Font& ifont = instance().frameBuffer().infoFont(); const int lineHeight = _font.getLineHeight(), fontWidth = _font.getMaxCharWidth(); @@ -172,7 +174,7 @@ void StellaSettingsDialog::addVideoOptions(WidgetArray& wid, int& xpos, int& ypo // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void StellaSettingsDialog::addGameOptions(WidgetArray& wid, int& xpos, int& ypos) { - const int VGAP = 4; + const int VGAP = _font.getFontHeight() / 4; const int lineHeight = _font.getLineHeight(); const GUI::Font& ifont = instance().frameBuffer().infoFont(); VariantList ctrls; From 12d29a0f387ebd7d710cdb62fdd3834a5bfe1386 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Thu, 19 Mar 2020 11:02:53 -0230 Subject: [PATCH 034/377] Add fonts to Visual Studio project file. --- src/windows/Stella.vcxproj | 3 +++ src/windows/Stella.vcxproj.filters | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/src/windows/Stella.vcxproj b/src/windows/Stella.vcxproj index b3aa05584..e15336141 100644 --- a/src/windows/Stella.vcxproj +++ b/src/windows/Stella.vcxproj @@ -1260,6 +1260,9 @@ + + + diff --git a/src/windows/Stella.vcxproj.filters b/src/windows/Stella.vcxproj.filters index b14161f0f..4a2fe6691 100644 --- a/src/windows/Stella.vcxproj.filters +++ b/src/windows/Stella.vcxproj.filters @@ -2054,6 +2054,15 @@ Header Files\gui + + Header Files\gui + + + Header Files\gui + + + Header Files\gui + From 1a91ba48fe1ba2c84335bc94a4067b0e010ff8bc Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Thu, 19 Mar 2020 22:48:36 +0000 Subject: [PATCH 035/377] R77: use QIS for scanlines w/o TV effects. --- src/emucore/TIASurface.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/emucore/TIASurface.cxx b/src/emucore/TIASurface.cxx index d0c4ffe2c..a98f21a4a 100644 --- a/src/emucore/TIASurface.cxx +++ b/src/emucore/TIASurface.cxx @@ -32,7 +32,7 @@ namespace { // Witv TV / and or scanline interpolation, the image has a height of ~480px. THe R77 runs at 720p, so there // is no benefit from QIS in y-direction. In addition, QIS on the R77 has performance issues if TV effects are // enabled. - return settings.getBool("tia.inter") || settings.getInt("tv.filter") != 0 || settings.getInt("tv.scanlines") != 0 + return settings.getBool("tia.inter") || settings.getInt("tv.filter") != 0 ? FrameBuffer::ScalingInterpolation::blur : FrameBuffer::ScalingInterpolation::sharp; #else From d794d214aa2928c55f66affb2966299e36cd9a1b Mon Sep 17 00:00:00 2001 From: thrust26 Date: Fri, 20 Mar 2020 09:37:49 +0100 Subject: [PATCH 036/377] minor debugger doc update --- docs/debugger.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/debugger.html b/docs/debugger.html index 19af56cdf..80246c1c4 100644 --- a/docs/debugger.html +++ b/docs/debugger.html @@ -1193,6 +1193,8 @@ the reason will be shown as follows:
  • "WTrap:" for write traps
  • "RTrapIf:" for conditional read traps
  • "WTrapIf:" for conditional write traps
  • +
  • "RWP:" for reads from write ports
  • +
  • "WRP:" for writes to read ports
  • See the Breakpoints, watches and traps... From 48c2921c9ae6854d0048c76ad16f1c0bb7ee3ee6 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Fri, 20 Mar 2020 09:42:26 +0100 Subject: [PATCH 037/377] update 6.1 date in doc to March 2020 --- docs/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.html b/docs/index.html index 7fd6920fc..68be48e0d 100644 --- a/docs/index.html +++ b/docs/index.html @@ -70,7 +70,7 @@


    -
    February 1999 - January 2020
    +
    February 1999 - March 2020
    The Stella Team
    Stella Homepage
    From 1706b537cfccff33d8dad4899e6fd29589f48933 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sat, 21 Mar 2020 17:18:05 -0230 Subject: [PATCH 038/377] (Semi) Final update for 6.1 release. I'm sure there's something we've missed. --- Changes.txt | 2 +- debian/changelog | 7 +++++++ docs/index_r77.html | 2 +- src/common/StateManager.hxx | 2 +- src/common/Version.hxx | 4 ++-- src/emucore/Console.cxx | 2 +- src/emucore/tia/frame-manager/FrameManager.cxx | 2 +- src/unix/stella.spec | 2 +- 8 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Changes.txt b/Changes.txt index 2452472df..2952f2ae0 100644 --- a/Changes.txt +++ b/Changes.txt @@ -12,7 +12,7 @@ Release History =========================================================================== -6.0.2 to 6.1: (MM dd, 2020) +6.0.2 to 6.1: (March 22, 2020) * IMPORTANT NOTES: - Because of major event remapping changes, all remappings will be reset diff --git a/debian/changelog b/debian/changelog index 3d045e4ef..553ddda1b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +stella (6.1-1) stable; urgency=high + + * Version 6.1 release + + -- Stephen Anthony Sun, 22 Mar 2020 17:09:59 -0230 + + stella (6.0.2-1) stable; urgency=high * Version 6.0.2 release diff --git a/docs/index_r77.html b/docs/index_r77.html index 6050d1367..710f5e561 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 Beta 1
    +
    Release 6.1

    Quick Navigation Guide


    diff --git a/src/common/StateManager.hxx b/src/common/StateManager.hxx index 41bed3517..09de785fb 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 "06000008state" +#define STATE_HEADER "06010000state" class OSystem; class RewindManager; diff --git a/src/common/Version.hxx b/src/common/Version.hxx index 2c534019a..51da31362 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.1_rc1" -#define STELLA_BUILD "5657" +#define STELLA_VERSION "6.1" +#define STELLA_BUILD "5729" #endif diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 3a7e0841e..5a2617409 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -745,7 +745,7 @@ void Console::updateVcenter(Int32 vcenter) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::changeScanlineAdjust(int direction) { - Int32 newAdjustVSize = myTIA->adjustVSize();; + Int32 newAdjustVSize = myTIA->adjustVSize(); if (direction != -1 && direction != +1) return; diff --git a/src/emucore/tia/frame-manager/FrameManager.cxx b/src/emucore/tia/frame-manager/FrameManager.cxx index 81d8d75d7..477f0fd2f 100644 --- a/src/emucore/tia/frame-manager/FrameManager.cxx +++ b/src/emucore/tia/frame-manager/FrameManager.cxx @@ -236,7 +236,7 @@ void FrameManager::recalculateMetrics() { throw runtime_error("frame manager: invalid TV mode"); } - myHeight = BSPF::clamp(roundf(static_cast(baseHeight) * (1.f - myVSizeAdjust / 100.f)), 0, myFrameLines); + myHeight = BSPF::clamp(roundf(static_cast(baseHeight) * (1.F - myVSizeAdjust / 100.F)), 0, myFrameLines); myYStart = BSPF::clamp(ystartBase + (baseHeight - static_cast(myHeight)) / 2 - myVcenter, 0, myFrameLines); // TODO: why "- 1" here: ??? myMaxVcenter = BSPF::clamp(ystartBase + (baseHeight - static_cast(myHeight)) / 2 - 1, 0, TIAConstants::maxVcenter); diff --git a/src/unix/stella.spec b/src/unix/stella.spec index e4f1dbe65..09d4d2827 100644 --- a/src/unix/stella.spec +++ b/src/unix/stella.spec @@ -100,7 +100,7 @@ rm -rf $RPM_BUILD_DIR/%{name}-%{version} %_datadir/icons/large/%{name}.png %changelog -* ddd Jan d 2020 Stephen Anthony 6.1-1 +* Sun Mar 22 2020 Stephen Anthony 6.1-1 - Version 6.1 release * Fri Oct 11 2019 Stephen Anthony 6.0.2-1 From bf1f9da3fb33f54f3792b52c18c1a25bd6f2eb60 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sat, 21 Mar 2020 18:35:12 -0230 Subject: [PATCH 039/377] libretro: Pass the filename to the underlying emulation, since we can detect things based on what it contains. --- src/libretro/StellaLIBRETRO.cxx | 8 +++++--- src/libretro/StellaLIBRETRO.hxx | 3 ++- src/libretro/libretro.cxx | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/libretro/StellaLIBRETRO.cxx b/src/libretro/StellaLIBRETRO.cxx index f475fbc0b..e3cb5073a 100644 --- a/src/libretro/StellaLIBRETRO.cxx +++ b/src/libretro/StellaLIBRETRO.cxx @@ -61,8 +61,6 @@ bool StellaLIBRETRO::create(bool logging) { system_ready = false; - FilesystemNode rom("rom"); - // build play system destroy(); @@ -115,6 +113,8 @@ bool StellaLIBRETRO::create(bool logging) settings.setValue(AudioSettings::SETTING_VOLUME, 100); settings.setValue(AudioSettings::SETTING_STEREO, audio_mode); + FilesystemNode rom(rom_path); + if(myOSystem->createConsole(rom) != EmptyString) return false; @@ -334,8 +334,10 @@ bool StellaLIBRETRO::getVideoResize() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void StellaLIBRETRO::setROM(const void* data, size_t size) +void StellaLIBRETRO::setROM(const char* path, const void* data, size_t size) { + rom_path = path; + memcpy(rom_image.get(), data, size); rom_size = static_cast(size); diff --git a/src/libretro/StellaLIBRETRO.hxx b/src/libretro/StellaLIBRETRO.hxx index 79ea4da0b..f48a13708 100644 --- a/src/libretro/StellaLIBRETRO.hxx +++ b/src/libretro/StellaLIBRETRO.hxx @@ -96,7 +96,7 @@ class StellaLIBRETRO Int16* getAudioBuffer() { return audio_buffer.get(); } public: - void setROM(const void* data, size_t size); + void setROM(const char* path, const void* data, size_t size); void setConsoleFormat(uInt32 mode); @@ -139,6 +139,7 @@ class StellaLIBRETRO unique_ptr rom_image; uInt32 rom_size; + string rom_path; ConsoleTiming console_timing; string console_format; diff --git a/src/libretro/libretro.cxx b/src/libretro/libretro.cxx index 6d1dc0f89..6babbf07f 100644 --- a/src/libretro/libretro.cxx +++ b/src/libretro/libretro.cxx @@ -574,7 +574,7 @@ bool retro_load_game(const struct retro_game_info *info) } - stella.setROM(info->data, info->size); + stella.setROM(info->path, info->data, info->size); return reset_system(); } From ea6d631eb72058e0f6aa3f4604255dd71e3168d6 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 24 Mar 2020 12:02:51 +0100 Subject: [PATCH 040/377] fixed #537 (writes to read ports) --- src/emucore/Cart3EPlus.cxx | 20 ++++++++++++++---- src/emucore/CartCV.cxx | 17 ++++++++++++++-- src/emucore/CartCVPlus.cxx | 17 ++++++++++++++-- src/emucore/CartDASH.cxx | 20 ++++++++++++++---- src/emucore/CartMNetwork.cxx | 39 +++++++++++++++++++++++++++++++----- 5 files changed, 96 insertions(+), 17 deletions(-) diff --git a/src/emucore/Cart3EPlus.cxx b/src/emucore/Cart3EPlus.cxx index 23f833976..139cda4b7 100644 --- a/src/emucore/Cart3EPlus.cxx +++ b/src/emucore/Cart3EPlus.cxx @@ -143,10 +143,22 @@ bool Cartridge3EPlus::poke(uInt16 address, uInt8 value) if(whichBankIsThere & BITMASK_ROMRAM) { - uInt32 byteOffset = address & BITMASK_RAM_BANK; - uInt32 baseAddress = ((whichBankIsThere & BIT_BANK_MASK) << RAM_BANK_TO_POWER) + byteOffset; - pokeRAM(myRAM[baseAddress], address, value); - changed = true; + if(address & RAM_BANK_SIZE) + { + uInt32 byteOffset = address & BITMASK_RAM_BANK; + uInt32 baseAddress = ((whichBankIsThere & BIT_BANK_MASK) << RAM_BANK_TO_POWER) + byteOffset; + pokeRAM(myRAM[baseAddress], address, value); + changed = true; + } + else + { + // Writing to the read port should be ignored, but trigger a break if option enabled + uInt8 dummy; + + pokeRAM(dummy, address, value); + myRamWriteAccess = address; + changed = false; + } } } diff --git a/src/emucore/CartCV.cxx b/src/emucore/CartCV.cxx index 73c55954b..e5ca47788 100644 --- a/src/emucore/CartCV.cxx +++ b/src/emucore/CartCV.cxx @@ -104,8 +104,21 @@ uInt8 CartridgeCV::peek(uInt16 address) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCV::poke(uInt16 address, uInt8 value) { - pokeRAM(myRAM[address & 0x03FF], address, value); - return true; + + if(address & 0x0400) + { + pokeRAM(myRAM[address & 0x03FF], address, value); + return true; + } + else + { + // Writing to the read port should be ignored, but trigger a break if option enabled + uInt8 dummy; + + pokeRAM(dummy, address, value); + myRamWriteAccess = address; + return false; + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartCVPlus.cxx b/src/emucore/CartCVPlus.cxx index eb3bb1023..c70c53b0d 100644 --- a/src/emucore/CartCVPlus.cxx +++ b/src/emucore/CartCVPlus.cxx @@ -104,9 +104,22 @@ bool CartridgeCVPlus::poke(uInt16 address, uInt8 value) return mySystem->tia().poke(address, value); } else - pokeRAM(myRAM[address & 0x03FF], pokeAddress, value); + { + if(address & 0x0400) + { + pokeRAM(myRAM[address & 0x03FF], pokeAddress, value); + return true; + } + else + { + // Writing to the read port should be ignored, but trigger a break if option enabled + uInt8 dummy; - return true; + pokeRAM(dummy, pokeAddress, value); + myRamWriteAccess = pokeAddress; + return false; + } + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartDASH.cxx b/src/emucore/CartDASH.cxx index f721a1edb..2c85ada47 100644 --- a/src/emucore/CartDASH.cxx +++ b/src/emucore/CartDASH.cxx @@ -135,10 +135,22 @@ bool CartridgeDASH::poke(uInt16 address, uInt8 value) if(whichBankIsThere & BITMASK_ROMRAM) { - uInt32 byteOffset = address & BITMASK_RAM_BANK; - uInt32 baseAddress = ((whichBankIsThere & BIT_BANK_MASK) << RAM_BANK_TO_POWER) + byteOffset; - pokeRAM(myRAM[baseAddress], address, value); - changed = true; + if(address & RAM_BANK_SIZE) + { + uInt32 byteOffset = address & BITMASK_RAM_BANK; + uInt32 baseAddress = ((whichBankIsThere & BIT_BANK_MASK) << RAM_BANK_TO_POWER) + byteOffset; + pokeRAM(myRAM[baseAddress], address, value); + changed = true; + } + else + { + // Writing to the read port should be ignored, but trigger a break if option enabled + uInt8 dummy; + + pokeRAM(dummy, address, value); + myRamWriteAccess = address; + changed = false; + } } } diff --git a/src/emucore/CartMNetwork.cxx b/src/emucore/CartMNetwork.cxx index cffec53b6..b433c4d72 100644 --- a/src/emucore/CartMNetwork.cxx +++ b/src/emucore/CartMNetwork.cxx @@ -137,13 +137,42 @@ bool CartridgeMNetwork::poke(uInt16 address, uInt8 value) // All RAM writes are mapped here if((myCurrentSlice[0] == myRAMSlice) && (address < BANK_SIZE / 2)) { - pokeRAM(myRAM[address & (BANK_SIZE / 2 - 1)], pokeAddress, value); - return true; + // RAM slices + if(!(address & 0x0400)) + { + pokeRAM(myRAM[address & (BANK_SIZE / 2 - 1)], pokeAddress, value); + return true; + } + else + { + // Writing to the read port should be ignored, but trigger a break if option enabled + uInt8 dummy; + + pokeRAM(dummy, pokeAddress, value); + myRamWriteAccess = pokeAddress; + return false; + } } - else if((address >= 0x0800) && (address <= 0x08FF)) + else { - pokeRAM(myRAM[0x0400 + (myCurrentRAM << 8) + (address & 0x00FF)], pokeAddress, value); - return true; + // fixed 256 bytes of RAM + if((address >= 0x0800) && (address <= 0x09FF)) + { + if(!(address & 0x100)) + { + pokeRAM(myRAM[0x0400 + (myCurrentRAM << 8) + (address & 0x00FF)], pokeAddress, value); + return true; + } + else + { + // Writing to the read port should be ignored, but trigger a break if option enabled + uInt8 dummy; + + pokeRAM(dummy, pokeAddress, value); + myRamWriteAccess = pokeAddress; + return false; + } + } } return false; From e5afebbc4714745b90d59678e9ac47f4726a769d Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 24 Mar 2020 17:02:27 +0100 Subject: [PATCH 041/377] improve alignment of some sliders and labels in InputDialog --- src/gui/InputDialog.cxx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/gui/InputDialog.cxx b/src/gui/InputDialog.cxx index fa3a38340..225657b3e 100644 --- a/src/gui/InputDialog.cxx +++ b/src/gui/InputDialog.cxx @@ -139,7 +139,7 @@ void InputDialog::addDevicePortTab(const GUI::Font& font) // Add joystick deadzone setting ypos += lineHeight + VGAP*3; - myDeadzone = new SliderWidget(myTab, font, HBORDER, ypos, 13 * fontWidth, lineHeight, + myDeadzone = new SliderWidget(myTab, font, HBORDER, ypos - 1, 13 * fontWidth, lineHeight, "Joystick deadzone size ", lwidth, kDeadzoneChanged); myDeadzone->setMinValue(0); myDeadzone->setMaxValue(29); myDeadzone->setTickmarkIntervals(4); @@ -149,14 +149,14 @@ void InputDialog::addDevicePortTab(const GUI::Font& font) // Add dejitter (Stelladaptor emulation for now only) ypos += lineHeight + VGAP; - myDejitterBase = new SliderWidget(myTab, font, HBORDER, ypos, 6 * fontWidth, lineHeight, + myDejitterBase = new SliderWidget(myTab, font, HBORDER, ypos - 1, 6 * fontWidth, lineHeight, "Paddle dejitter strength", lwidth, kDejitterChanged); myDejitterBase->setMinValue(Paddles::MIN_DEJITTER); myDejitterBase->setMaxValue(Paddles::MAX_DEJITTER); myDejitterBase->setTickmarkIntervals(2); - xpos = HBORDER + myDejitterBase->getWidth() + fontWidth; + xpos = HBORDER + myDejitterBase->getWidth() + fontWidth - 4; wid.push_back(myDejitterBase); - myDejitterDiff = new SliderWidget(myTab, font, xpos, ypos, 6 * fontWidth, lineHeight, + myDejitterDiff = new SliderWidget(myTab, font, xpos, ypos - 1, 6 * fontWidth, lineHeight, "", 0, kDejitterChanged); myDejitterDiff->setMinValue(Paddles::MIN_DEJITTER); myDejitterDiff->setMaxValue(Paddles::MAX_DEJITTER); myDejitterDiff->setTickmarkIntervals(2); @@ -167,7 +167,7 @@ void InputDialog::addDevicePortTab(const GUI::Font& font) // Add paddle speed (digital emulation) ypos += lineHeight + VGAP; - myDPaddleSpeed = new SliderWidget(myTab, font, HBORDER, ypos, 13 * fontWidth, lineHeight, + myDPaddleSpeed = new SliderWidget(myTab, font, HBORDER, ypos - 1, 13 * fontWidth, lineHeight, "Digital paddle sensitivity ", lwidth, kDPSpeedChanged); myDPaddleSpeed->setMinValue(1); myDPaddleSpeed->setMaxValue(20); @@ -178,7 +178,7 @@ void InputDialog::addDevicePortTab(const GUI::Font& font) // Add paddle speed (mouse emulation) ypos += lineHeight + VGAP; - myMPaddleSpeed = new SliderWidget(myTab, font, HBORDER, ypos, 13 * fontWidth, lineHeight, + myMPaddleSpeed = new SliderWidget(myTab, font, HBORDER, ypos - 1, 13 * fontWidth, lineHeight, "Mouse paddle sensitivity ", lwidth, kMPSpeedChanged); myMPaddleSpeed->setMinValue(1); myMPaddleSpeed->setMaxValue(20); @@ -189,7 +189,7 @@ void InputDialog::addDevicePortTab(const GUI::Font& font) // Add trackball speed ypos += lineHeight + VGAP; - myTrackBallSpeed = new SliderWidget(myTab, font, HBORDER, ypos, 13 * fontWidth, lineHeight, + myTrackBallSpeed = new SliderWidget(myTab, font, HBORDER, ypos - 1, 13 * fontWidth, lineHeight, "Trackball sensitivity ", lwidth, kTBSpeedChanged); myTrackBallSpeed->setMinValue(1); myTrackBallSpeed->setMaxValue(20); From 8e78297e74e33d7cfc502d391fe93abe8a481297 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 25 Mar 2020 09:32:12 +0100 Subject: [PATCH 042/377] First shot at configurable paddle input (#522) --- Changes.txt | 8 + src/common/MouseControl.cxx | 2 +- src/emucore/Console.cxx | 4 + src/emucore/Paddles.cxx | 30 ++- src/emucore/Paddles.hxx | 24 ++- src/emucore/Settings.cxx | 19 +- src/gui/InputDialog.cxx | 368 +++++++++++++++++++++--------------- src/gui/InputDialog.hxx | 20 +- 8 files changed, 310 insertions(+), 165 deletions(-) diff --git a/Changes.txt b/Changes.txt index 2952f2ae0..5d8291b4f 100644 --- a/Changes.txt +++ b/Changes.txt @@ -12,6 +12,14 @@ Release History =========================================================================== +6.1 to 6.2: (??? ??, 2020) + * Paddle centering and sensitivity can be adjusted now + + * 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. + + 6.0.2 to 6.1: (March 22, 2020) * IMPORTANT NOTES: diff --git a/src/common/MouseControl.cxx b/src/common/MouseControl.cxx index 35d8941f9..ee960c6bb 100644 --- a/src/common/MouseControl.cxx +++ b/src/common/MouseControl.cxx @@ -124,7 +124,7 @@ MouseControl::MouseControl(Console& console, const string& mode) int m_range = 100; if(!(m_axis >> m_range)) m_range = 100; - Paddles::setPaddleRange(m_range); + Paddles::setDigitalPaddleRange(m_range); // If the mouse isn't used at all, we still need one item in the list if(myModeList.size() == 0) diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 5a2617409..be6f00f43 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -923,6 +923,10 @@ unique_ptr Console::getControllerPort(const Controller::Type type, swapAxis = true; else if(type == Controller::Type::PaddlesIAxDr) swapAxis = swapDir = true; + + Paddles::setAnalogCenter(myOSystem.settings().getInt("pcenter")); + Paddles::setAnalogSensitivity(myOSystem.settings().getInt("psense")); + controller = make_unique(port, myEvent, *mySystem, swapPaddles, swapAxis, swapDir); break; diff --git a/src/emucore/Paddles.cxx b/src/emucore/Paddles.cxx index d8e60365a..b4782cfb8 100644 --- a/src/emucore/Paddles.cxx +++ b/src/emucore/Paddles.cxx @@ -234,12 +234,14 @@ void Paddles::update() new_val = sa_xaxis * (1 - dejitter) + myLastAxisX * dejitter; // only use new dejittered value for larger differences - if (abs(new_val - sa_xaxis) > 10) + if(abs(new_val - sa_xaxis) > 10) sa_xaxis = new_val; - setPin(AnalogPin::Nine, Int32(MAX_RESISTANCE * ((32767 - Int16(sa_xaxis)) / 65536.0))); + setPin(AnalogPin::Nine, Int32(MAX_RESISTANCE * + (BSPF::clamp(32768 - Int32(Int32(sa_xaxis) * SENSITIVITY + CENTER), 0, 65536) / 65536.0))); sa_changed = true; } + if(abs(myLastAxisY - sa_yaxis) > 10) { // dejitter, suppress small changes only @@ -250,7 +252,8 @@ void Paddles::update() if (abs(new_val - sa_yaxis) > 10) sa_yaxis = new_val; - setPin(AnalogPin::Five, Int32(MAX_RESISTANCE * ((32767 - Int16(sa_yaxis)) / 65536.0))); + setPin(AnalogPin::Five, Int32(MAX_RESISTANCE * + (BSPF::clamp(32768 - Int32(Int32(sa_yaxis) * SENSITIVITY + CENTER), 0, 65536) / 65536.0))); sa_changed = true; } myLastAxisX = sa_xaxis; @@ -379,6 +382,22 @@ bool Paddles::setMouseControl( return true; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Paddles::setAnalogCenter(int center) +{ + // TODO: convert into ~5 pixel (also in Input Dialog!) + CENTER = BSPF::clamp(center, MIN_ANALOG_CENTER, MAX_ANALOG_CENTER) * 860; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +float Paddles::setAnalogSensitivity(int sensitivity) +{ + // BASE_ANALOG_SENSE * (1.1 ^ 20) = 1.0 + SENSITIVITY = BASE_ANALOG_SENSE * std::pow(1.1, BSPF::clamp(sensitivity, 0, MAX_ANALOG_SENSE)); + + return SENSITIVITY; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Paddles::setDejitterBase(int strength) { @@ -405,13 +424,16 @@ void Paddles::setMouseSensitivity(int sensitivity) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Paddles::setPaddleRange(int range) +void Paddles::setDigitalPaddleRange(int range) { range = BSPF::clamp(range, 1, 100); TRIGRANGE = int(TRIGMAX * (range / 100.0)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int Paddles::CENTER = 0; +float Paddles::SENSITIVITY = 1.0; + int Paddles::TRIGRANGE = Paddles::TRIGMAX; int Paddles::DIGITAL_SENSITIVITY = -1; int Paddles::DIGITAL_DISTANCE = -1; diff --git a/src/emucore/Paddles.hxx b/src/emucore/Paddles.hxx index 2f64a4df2..0a8adc9c9 100644 --- a/src/emucore/Paddles.hxx +++ b/src/emucore/Paddles.hxx @@ -48,6 +48,10 @@ class Paddles : public Controller virtual ~Paddles() = default; public: + static constexpr float BASE_ANALOG_SENSE = 0.148643628f; + static constexpr int MAX_ANALOG_SENSE = 30; + static constexpr int MIN_ANALOG_CENTER = -20; + static constexpr int MAX_ANALOG_CENTER = 20; static constexpr int MAX_DIGITAL_SENSE = 20; static constexpr int MAX_MOUSE_SENSE = 20; static constexpr int MIN_DEJITTER = 0; @@ -88,6 +92,21 @@ class Paddles : public Controller bool setMouseControl(Controller::Type xtype, int xid, Controller::Type ytype, int yid) override; + /** + Sets the center for analog paddles. + + @param center Value from -20 to 20, representing the center offset/860 + */ + static void setAnalogCenter(int center); + + /** + Sets the sensitivity for analog paddles. + + @param sensitivity Value from 0 to 30, where 20 equals 1 + @return Resulting sensitivity + */ + static float setAnalogSensitivity(int sensitivity); + /** @param strength Value from 0 to 10 */ @@ -127,7 +146,7 @@ class Paddles : public Controller @param range Value from 1 to 100, representing the percentage of the range to use */ - static void setPaddleRange(int range); + static void setDigitalPaddleRange(int range); static constexpr double MAX_RESISTANCE = 1400000.0; @@ -156,6 +175,9 @@ class Paddles : public Controller int myLastAxisX{0}, myLastAxisY{0}; int myAxisDigitalZero{0}, myAxisDigitalOne{0}; + static int CENTER; + static float SENSITIVITY; + static int DIGITAL_SENSITIVITY, DIGITAL_DISTANCE; static int DEJITTER_BASE, DEJITTER_DIFF; static int MOUSE_SENSITIVITY; diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index eabe55dbf..0e3de3de8 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -21,6 +21,7 @@ #include "Version.hxx" #include "Logger.hxx" #include "AudioSettings.hxx" +#include "Paddles.hxx" #ifdef DEBUGGER_SUPPORT #include "DebuggerDialog.hxx" @@ -102,6 +103,8 @@ Settings::Settings() setPermanent("dejitter.base", "0"); setPermanent("dejitter.diff", "0"); setPermanent("dsense", "10"); + setPermanent("pcenter", "0"); + setPermanent("psense", "20"); setPermanent("msense", "10"); setPermanent("tsense", "10"); setPermanent("saport", "lr"); @@ -321,6 +324,14 @@ void Settings::validate() if(i < 0 || i > 3) setValue("cursor", "2"); + i = getInt("pcenter"); + if(i < Paddles::MIN_ANALOG_CENTER || i > Paddles::MAX_ANALOG_CENTER) + setValue("pcenter", "0"); + + i = getInt("psense"); + if(i < 0|| i > Paddles::MAX_ANALOG_SENSE) + setValue("psense", "20"); + i = getInt("dsense"); if(i < 1 || i > 20) setValue("dsense", "10"); @@ -445,8 +456,10 @@ void Settings::usage() const << " properties in given mode(see manual)\n" << " -grabmouse <1|0> Locks the mouse cursor in the TIA window\n" << " -cursor <0,1,2,3> Set cursor state in UI/emulation modes\n" - << " -dejitter.base <0-10> Strength of paddle value averaging\n" - << " -dejitter.diff <0-10> Strength of paddle reaction to fast movements\n" + << " -dejitter.base <0-10> Strength of analog paddle value averaging\n" + << " -dejitter.diff <0-10> Strength of analog paddle reaction to fast movements\n" + << " -pcenter <-20-20> Center of analog paddle\n" + << " -psense <0-30> Sensitivity of analog paddle movement\n" << " -dsense <1-20> Sensitivity of digital emulated paddle movement\n" << " -msense <1-20> Sensitivity of mouse emulated paddle movement\n" << " -tsense <1-20> Sensitivity of mouse emulated trackball movement\n" @@ -486,7 +499,7 @@ void Settings::usage() const << " -launcherroms <1|0> Show only ROMs in the launcher (vs. all files)\n" << " -romviewer Show ROM info viewer at given zoom level in ROM\n" << " launcher (use 0 for off)\n" - << " -lastrom Last played ROM, automatically selected in\n" + << " -lastrom Last played ROM, automatically selected in\n" << " launcher\n" << " -romloadcount Number of ROM to load next from multicard\n" << " -uipalette addTab(" Emulation Events ", TabWidget::AUTO_WIDTH); - myEmulEventMapper = new EventMappingWidget(myTab, font, 2, 2, + tabID = myTab->addTab(" Emul. Events ", TabWidget::AUTO_WIDTH); + myEmulEventMapper = new EventMappingWidget(myTab, _font, 2, 2, myTab->getWidth(), myTab->getHeight() - 4, EventMode::kEmulationMode); @@ -66,8 +66,8 @@ InputDialog::InputDialog(OSystem& osystem, DialogContainer& parent, addToFocusList(myEmulEventMapper->getFocusList(), myTab, tabID); // 2) Event mapper for UI actions - tabID = myTab->addTab(" UI Events ", TabWidget::AUTO_WIDTH); - myMenuEventMapper = new EventMappingWidget(myTab, font, 2, 2, + tabID = myTab->addTab(" UI Events ", TabWidget::AUTO_WIDTH); + myMenuEventMapper = new EventMappingWidget(myTab, _font, 2, 2, myTab->getWidth(), myTab->getHeight() - 4, EventMode::kMenuMode); @@ -75,7 +75,10 @@ InputDialog::InputDialog(OSystem& osystem, DialogContainer& parent, addToFocusList(myMenuEventMapper->getFocusList(), myTab, tabID); // 3) Devices & ports - addDevicePortTab(font); + addDevicePortTab(); + + // 4) Mouse + addMouseTab(); // Finalize the tabs, and activate the first tab myTab->activateTabs(); @@ -83,7 +86,7 @@ InputDialog::InputDialog(OSystem& osystem, DialogContainer& parent, // Add Defaults, OK and Cancel buttons WidgetArray wid; - addDefaultsOKCancelBGroup(wid, font); + addDefaultsOKCancelBGroup(wid, _font); addBGroupToFocusList(wid); } @@ -93,135 +96,109 @@ InputDialog::~InputDialog() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void InputDialog::addDevicePortTab(const GUI::Font& font) +void InputDialog::addDevicePortTab() { - const int lineHeight = font.getLineHeight(), - fontWidth = font.getMaxCharWidth(), - fontHeight = font.getFontHeight(); - int xpos, ypos, lwidth, pwidth, tabID; + const int lineHeight = _font.getLineHeight(), + fontWidth = _font.getMaxCharWidth(), + fontHeight = _font.getFontHeight(); + int xpos, ypos, lwidth, tabID; WidgetArray wid; - VariantList items; const int VGAP = 4; - const int VBORDER = 9; + const int VBORDER = 8; const int HBORDER = 8; // Devices/ports - tabID = myTab->addTab(" Devices & Ports ", TabWidget::AUTO_WIDTH); + tabID = myTab->addTab("Devices & Ports", TabWidget::AUTO_WIDTH); ypos = VBORDER; - lwidth = font.getStringWidth("Digital paddle sensitivity "); // was: "Use mouse as a controller " - pwidth = font.getStringWidth("-UI, -Emulation"); - - // Use mouse as controller - items.clear(); - VarList::push_back(items, "Always", "always"); - VarList::push_back(items, "Analog devices", "analog"); - VarList::push_back(items, "Never", "never"); - myMouseControl = new PopUpWidget(myTab, font, HBORDER, ypos, pwidth, lineHeight, items, - "Use mouse as a controller ", lwidth); - wid.push_back(myMouseControl); - - // Mouse cursor state - ypos += lineHeight + VGAP; - items.clear(); - VarList::push_back(items, "-UI, -Emulation", "0"); - VarList::push_back(items, "-UI, +Emulation", "1"); - VarList::push_back(items, "+UI, -Emulation", "2"); - VarList::push_back(items, "+UI, +Emulation", "3"); - myCursorState = new PopUpWidget(myTab, font, HBORDER, ypos, pwidth, lineHeight, items, - "Mouse cursor visibility ", lwidth, kCursorStateChanged); - wid.push_back(myCursorState); -#ifndef WINDOWED_SUPPORT - myCursorState->clearFlags(Widget::FLAG_ENABLED); -#endif - - lwidth = font.getStringWidth("Digital paddle sensitivity "); + lwidth = _font.getStringWidth("Digital paddle sensitivity "); // Add joystick deadzone setting - ypos += lineHeight + VGAP*3; - myDeadzone = new SliderWidget(myTab, font, HBORDER, ypos - 1, 13 * fontWidth, lineHeight, - "Joystick deadzone size ", lwidth, kDeadzoneChanged); + myDeadzone = new SliderWidget(myTab, _font, HBORDER, ypos - 1, 13 * fontWidth, lineHeight, + "Joystick deadzone size", lwidth, kDeadzoneChanged, 5 * fontWidth); myDeadzone->setMinValue(0); myDeadzone->setMaxValue(29); myDeadzone->setTickmarkIntervals(4); xpos = HBORDER + myDeadzone->getWidth() + 5; - myDeadzoneLabel = new StaticTextWidget(myTab, font, xpos, ypos+1, 5*fontWidth, lineHeight, ""); wid.push_back(myDeadzone); + xpos = HBORDER; ypos += lineHeight + VGAP * 2; + new StaticTextWidget(myTab, _font, xpos, ypos+1, "Analog paddle:"); + + // Add paddle center + xpos += fontWidth * 2; + ypos += lineHeight + VGAP; + + myPaddleCenter = new SliderWidget(myTab, _font, xpos, ypos - 1, 13 * fontWidth, lineHeight, + "Center", + lwidth - fontWidth * 2, kPCenterChanged, 6 * fontWidth, "px", 0, true); + myPaddleCenter->setMinValue(Paddles::MIN_ANALOG_CENTER); + myPaddleCenter->setMaxValue(Paddles::MAX_ANALOG_CENTER); + myPaddleCenter->setTickmarkIntervals(4); + wid.push_back(myPaddleCenter); + + // Add paddle sensitivity + ypos += lineHeight + VGAP; + myPaddleSpeed = new SliderWidget(myTab, _font, xpos, ypos - 1, 13 * fontWidth, lineHeight, + "Sensitivity", + lwidth - fontWidth * 2, kPSpeedChanged, 4 * fontWidth, "%"); + myPaddleSpeed->setMinValue(0); myPaddleSpeed->setMaxValue(Paddles::MAX_ANALOG_SENSE); + myPaddleSpeed->setTickmarkIntervals(3); + wid.push_back(myPaddleSpeed); + + // Add dejitter (Stelladaptor emulation for now only) ypos += lineHeight + VGAP; - myDejitterBase = new SliderWidget(myTab, font, HBORDER, ypos - 1, 6 * fontWidth, lineHeight, - "Paddle dejitter strength", lwidth, kDejitterChanged); - myDejitterBase->setMinValue(Paddles::MIN_DEJITTER); myDejitterBase->setMaxValue(Paddles::MAX_DEJITTER); + myDejitterBase = new SliderWidget(myTab, _font, xpos, ypos - 1, 6 * fontWidth, lineHeight, + "Dejitter strength", lwidth - fontWidth * 2, kDejitterChanged); + myDejitterBase->setMinValue(Paddles::MIN_DEJITTER); + myDejitterBase->setMaxValue(Paddles::MAX_DEJITTER); myDejitterBase->setTickmarkIntervals(2); - xpos = HBORDER + myDejitterBase->getWidth() + fontWidth - 4; + xpos += myDejitterBase->getWidth() + fontWidth - 4; wid.push_back(myDejitterBase); - myDejitterDiff = new SliderWidget(myTab, font, xpos, ypos - 1, 6 * fontWidth, lineHeight, + myDejitterDiff = new SliderWidget(myTab, _font, xpos, ypos - 1, 6 * fontWidth, lineHeight, "", 0, kDejitterChanged); - myDejitterDiff->setMinValue(Paddles::MIN_DEJITTER); myDejitterDiff->setMaxValue(Paddles::MAX_DEJITTER); + myDejitterDiff->setMinValue(Paddles::MIN_DEJITTER); + myDejitterDiff->setMaxValue(Paddles::MAX_DEJITTER); myDejitterDiff->setTickmarkIntervals(2); - xpos += myDejitterDiff->getWidth() + 5; + xpos += myDejitterDiff->getWidth(); wid.push_back(myDejitterDiff); - myDejitterLabel = new StaticTextWidget(myTab, font, xpos, ypos + 1, 7 * fontWidth, lineHeight, ""); + myDejitterLabel = new StaticTextWidget(myTab, _font, xpos, ypos + 1, 7 * fontWidth, lineHeight, ""); // Add paddle speed (digital emulation) - ypos += lineHeight + VGAP; - myDPaddleSpeed = new SliderWidget(myTab, font, HBORDER, ypos - 1, 13 * fontWidth, lineHeight, - "Digital paddle sensitivity ", - lwidth, kDPSpeedChanged); + ypos += lineHeight + VGAP * 4; + myDPaddleSpeed = new SliderWidget(myTab, _font, HBORDER, ypos - 1, 13 * fontWidth, lineHeight, + "Digital paddle sensitivity", + lwidth, kDPSpeedChanged, 4 * fontWidth, "%"); myDPaddleSpeed->setMinValue(1); myDPaddleSpeed->setMaxValue(20); myDPaddleSpeed->setTickmarkIntervals(4); - xpos = HBORDER + myDPaddleSpeed->getWidth() + 5; - myDPaddleLabel = new StaticTextWidget(myTab, font, xpos, ypos+1, 24, lineHeight, ""); wid.push_back(myDPaddleSpeed); - // Add paddle speed (mouse emulation) - ypos += lineHeight + VGAP; - myMPaddleSpeed = new SliderWidget(myTab, font, HBORDER, ypos - 1, 13 * fontWidth, lineHeight, - "Mouse paddle sensitivity ", - lwidth, kMPSpeedChanged); - myMPaddleSpeed->setMinValue(1); myMPaddleSpeed->setMaxValue(20); - myMPaddleSpeed->setTickmarkIntervals(4); - xpos = HBORDER + myMPaddleSpeed->getWidth() + 5; - myMPaddleLabel = new StaticTextWidget(myTab, font, xpos, ypos+1, 24, lineHeight, ""); - wid.push_back(myMPaddleSpeed); - // Add trackball speed - ypos += lineHeight + VGAP; - myTrackBallSpeed = new SliderWidget(myTab, font, HBORDER, ypos - 1, 13 * fontWidth, lineHeight, - "Trackball sensitivity ", - lwidth, kTBSpeedChanged); + ypos += lineHeight + VGAP * 2; + myTrackBallSpeed = new SliderWidget(myTab, _font, HBORDER, ypos - 1, 13 * fontWidth, lineHeight, + "Trackball sensitivity", + lwidth, kTBSpeedChanged, 4 * fontWidth, "%"); myTrackBallSpeed->setMinValue(1); myTrackBallSpeed->setMaxValue(20); myTrackBallSpeed->setTickmarkIntervals(4); - xpos = HBORDER + myTrackBallSpeed->getWidth() + 5; - myTrackBallLabel = new StaticTextWidget(myTab, font, xpos, ypos+1, 24, lineHeight, ""); wid.push_back(myTrackBallSpeed); // Add 'allow all 4 directions' for joystick - ypos += lineHeight + VGAP*3; - myAllowAll4 = new CheckboxWidget(myTab, font, HBORDER, ypos, + ypos += lineHeight + VGAP * 4; + myAllowAll4 = new CheckboxWidget(myTab, _font, HBORDER, ypos, "Allow all 4 directions on joystick"); wid.push_back(myAllowAll4); - // Grab mouse (in windowed mode) - ypos += lineHeight + VGAP; - myGrabMouse = new CheckboxWidget(myTab, font, HBORDER, ypos, - "Grab mouse in emulation mode"); - wid.push_back(myGrabMouse); -#ifndef WINDOWED_SUPPORT - myGrabMouse->clearFlags(Widget::FLAG_ENABLED); -#endif - // Enable/disable modifier key-combos ypos += lineHeight + VGAP; - myModCombo = new CheckboxWidget(myTab, font, HBORDER, ypos, - "Use modifier key combos"); + myModCombo = new CheckboxWidget(myTab, _font, HBORDER, ypos, + "Use modifier key combos"); wid.push_back(myModCombo); ypos += lineHeight + VGAP; // Stelladaptor mappings - mySAPort = new CheckboxWidget(myTab, font, HBORDER, ypos, + mySAPort = new CheckboxWidget(myTab, _font, HBORDER, ypos, "Swap Stelladaptor ports"); wid.push_back(mySAPort); @@ -229,37 +206,101 @@ void InputDialog::addDevicePortTab(const GUI::Font& font) // Add EEPROM erase (part 1/2) ypos += VGAP*4; - fwidth = font.getStringWidth("AtariVox/SaveKey"); - lwidth = font.getStringWidth("AtariVox/SaveKey"); - new StaticTextWidget(myTab, font, _w - HBORDER - 4 - (fwidth + lwidth) / 2, ypos, + fwidth = _font.getStringWidth("AtariVox/SaveKey"); + lwidth = _font.getStringWidth("AtariVox/SaveKey"); + new StaticTextWidget(myTab, _font, _w - HBORDER - 4 - (fwidth + lwidth) / 2, ypos, "AtariVox/SaveKey"); // Show joystick database ypos += lineHeight; - myJoyDlgButton = new ButtonWidget(myTab, font, HBORDER, ypos, 20, + myJoyDlgButton = new ButtonWidget(myTab, _font, HBORDER, ypos, 20, "Joystick Database" + ELLIPSIS, kDBButtonPressed); wid.push_back(myJoyDlgButton); // Add EEPROM erase (part 1/2) - myEraseEEPROMButton = new ButtonWidget(myTab, font, _w - HBORDER - 4 - fwidth, ypos, + myEraseEEPROMButton = new ButtonWidget(myTab, _font, _w - HBORDER - 4 - fwidth, ypos, fwidth, lineHeight+4, "Erase EEPROM", kEEButtonPressed); wid.push_back(myEraseEEPROMButton); // Add AtariVox serial port - ypos += lineHeight + VGAP*2; - lwidth = font.getStringWidth("AVox serial port "); + ypos += lineHeight + VGAP * 2; + lwidth = _font.getStringWidth("AVox serial port "); fwidth = _w - HBORDER * 2 - 4 - lwidth; - new StaticTextWidget(myTab, font, HBORDER, ypos + 2, "AVox serial port "); - myAVoxPort = new EditTextWidget(myTab, font, HBORDER + lwidth, ypos, + new StaticTextWidget(myTab, _font, HBORDER, ypos + 2, "AVox serial port "); + myAVoxPort = new EditTextWidget(myTab, _font, HBORDER + lwidth, ypos, fwidth, fontHeight); - wid.push_back(myAVoxPort); // Add items for virtual device ports addToFocusList(wid, myTab, tabID); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void InputDialog::addMouseTab() +{ + const int lineHeight = _font.getLineHeight(), + fontWidth = _font.getMaxCharWidth(), + fontHeight = _font.getFontHeight(); + int ypos, lwidth, pwidth, tabID; + WidgetArray wid; + VariantList items; + const int VGAP = 4; + const int VBORDER = 8; + const int HBORDER = 8; + + // Mouse + tabID = myTab->addTab(" Mouse ", TabWidget::AUTO_WIDTH); + + ypos = VBORDER; + lwidth = _font.getStringWidth("Use mouse as a controller "); + pwidth = _font.getStringWidth("-UI, -Emulation"); + + // Use mouse as controller + VarList::push_back(items, "Always", "always"); + VarList::push_back(items, "Analog devices", "analog"); + VarList::push_back(items, "Never", "never"); + myMouseControl = new PopUpWidget(myTab, _font, HBORDER, ypos, pwidth, lineHeight, items, + "Use mouse as a controller ", lwidth, kMouseCtrlChanged); + wid.push_back(myMouseControl); + + // Add paddle speed (mouse emulation) + ypos += lineHeight + VGAP; + myMPaddleSpeed = new SliderWidget(myTab, _font, HBORDER, ypos - 1, 13 * fontWidth, lineHeight, + "Mouse paddle sensitivity ", + lwidth, kMPSpeedChanged, 4 * fontWidth, "%"); + myMPaddleSpeed->setMinValue(1); myMPaddleSpeed->setMaxValue(20); + myMPaddleSpeed->setTickmarkIntervals(4); + wid.push_back(myMPaddleSpeed); + + + // Mouse cursor state + ypos += lineHeight + VGAP * 4; + items.clear(); + VarList::push_back(items, "-UI, -Emulation", "0"); + VarList::push_back(items, "-UI, +Emulation", "1"); + VarList::push_back(items, "+UI, -Emulation", "2"); + VarList::push_back(items, "+UI, +Emulation", "3"); + myCursorState = new PopUpWidget(myTab, _font, HBORDER, ypos, pwidth, lineHeight, items, + "Mouse cursor visibility ", lwidth, kCursorStateChanged); + wid.push_back(myCursorState); +#ifndef WINDOWED_SUPPORT + myCursorState->clearFlags(Widget::FLAG_ENABLED); +#endif + + // Grab mouse (in windowed mode) + ypos += lineHeight + VGAP; + myGrabMouse = new CheckboxWidget(myTab, _font, HBORDER, ypos, + "Grab mouse in emulation mode"); + wid.push_back(myGrabMouse); +#ifndef WINDOWED_SUPPORT + myGrabMouse->clearFlags(Widget::FLAG_ENABLED); +#endif + + // Add items for mouse + addToFocusList(wid, myTab, tabID); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputDialog::loadConfig() { @@ -269,6 +310,7 @@ void InputDialog::loadConfig() // Use mouse as a controller myMouseControl->setSelected( instance().settings().getString("usemouse"), "analog"); + handleMouseControlState(); // Mouse cursor state myCursorState->setSelected(instance().settings().getString("cursor"), "2"); @@ -276,20 +318,20 @@ void InputDialog::loadConfig() // Joystick deadzone myDeadzone->setValue(instance().settings().getInt("joydeadzone")); - myDeadzoneLabel->setValue(Joystick::deadzone()); + + // Paddle center & speed (analog) + myPaddleCenter->setValue(instance().settings().getInt("pcenter")); + myPaddleSpeed->setValue(instance().settings().getInt("psense")); // Paddle speed (digital and mouse) myDejitterBase->setValue(instance().settings().getInt("dejitter.base")); myDejitterDiff->setValue(instance().settings().getInt("dejitter.diff")); updateDejitter(); myDPaddleSpeed->setValue(instance().settings().getInt("dsense")); - myDPaddleLabel->setLabel(instance().settings().getString("dsense")); myMPaddleSpeed->setValue(instance().settings().getInt("msense")); - myMPaddleLabel->setLabel(instance().settings().getString("msense")); // Trackball speed myTrackBallSpeed->setValue(instance().settings().getInt("tsense")); - myTrackBallLabel->setLabel(instance().settings().getString("tsense")); // AtariVox serial port myAVoxPort->setText(instance().settings().getString("avoxport")); @@ -334,6 +376,16 @@ void InputDialog::saveConfig() instance().settings().setValue("joydeadzone", deadzone); Joystick::setDeadZone(deadzone); + // Paddle center (analog) + int center = myPaddleCenter->getValue(); + instance().settings().setValue("pcenter", center); + Paddles::setAnalogCenter(center); + + // Paddle speed (analog) + int sensitivity = myPaddleSpeed->getValue(); + instance().settings().setValue("psense", sensitivity); + Paddles::setAnalogSensitivity(sensitivity); + // Paddle speed (digital and mouse) int dejitter = myDejitterBase->getValue(); instance().settings().setValue("dejitter.base", dejitter); @@ -342,7 +394,7 @@ void InputDialog::saveConfig() instance().settings().setValue("dejitter.diff", dejitter); Paddles::setDejitterDiff(dejitter); - int sensitivity = myDPaddleSpeed->getValue(); + sensitivity = myDPaddleSpeed->getValue(); instance().settings().setValue("dsense", sensitivity); Paddles::setDigitalSensitivity(sensitivity); @@ -394,26 +446,19 @@ void InputDialog::setDefaults() myMenuEventMapper->setDefaults(); break; - case 2: // Virtual devices - { + case 2: // Devices & Ports // Left & right ports mySAPort->setState(false); - // Use mouse as a controller - myMouseControl->setSelected("analog"); - - // Mouse cursor state - myCursorState->setSelected("2"); - // Joystick deadzone myDeadzone->setValue(0); - myDeadzoneLabel->setValue(3200); - // Paddle speed (digital and mouse) + // Paddle center & speed (analog) + myPaddleCenter->setValue(0); + myPaddleSpeed->setValue(20); + + // Paddle speed (digital) myDPaddleSpeed->setValue(10); - myDPaddleLabel->setLabel("10"); - myMPaddleSpeed->setValue(10); - myMPaddleLabel->setLabel("10"); #if defined(RETRON77) myDejitterBase->setValue(2); myDejitterDiff->setValue(6); @@ -423,7 +468,6 @@ void InputDialog::setDefaults() #endif updateDejitter(); myTrackBallSpeed->setValue(10); - myTrackBallLabel->setLabel("10"); // AtariVox serial port myAVoxPort->setText(""); @@ -431,16 +475,27 @@ void InputDialog::setDefaults() // Allow all 4 joystick directions myAllowAll4->setState(false); - // Grab mouse - myGrabMouse->setState(true); - // Enable/disable modifier key-combos myModCombo->setState(true); - handleCursorState(); - break; - } + + case 3: // Mouse + // Use mouse as a controller + myMouseControl->setSelected("analog"); + + // Mouse cursor state + myCursorState->setSelected("2"); + + // Grab mouse + myGrabMouse->setState(true); + + // Paddle speed (mouse) + myMPaddleSpeed->setValue(10); + + handleMouseControlState(); + handleCursorState(); + break; default: break; @@ -566,28 +621,28 @@ void InputDialog::handleCommand(CommandSender* sender, int cmd, setDefaults(); break; - case kCursorStateChanged: - handleCursorState(); - break; - case kDeadzoneChanged: - myDeadzoneLabel->setValue(3200 + 1000*myDeadzone->getValue()); + myDeadzone->setValueLabel(3200 + 1000 * myDeadzone->getValue()); break; - case kDPSpeedChanged: - myDPaddleLabel->setValue(myDPaddleSpeed->getValue()); + case kPCenterChanged: + myPaddleCenter->setValueLabel(myPaddleCenter->getValue() * 5); break; - case kMPSpeedChanged: - myMPaddleLabel->setValue(myMPaddleSpeed->getValue()); + case kPSpeedChanged: + myPaddleSpeed->setValueLabel(Paddles::setAnalogSensitivity(myPaddleSpeed->getValue()) * 100.0 + 0.5); break; case kDejitterChanged: updateDejitter(); break; + case kDPSpeedChanged: + myDPaddleSpeed->setValueLabel(myDPaddleSpeed->getValue() * 10); + break; + case kTBSpeedChanged: - myTrackBallLabel->setValue(myTrackBallSpeed->getValue()); + myTrackBallSpeed->setValueLabel(myTrackBallSpeed->getValue() * 10); break; case kDBButtonPressed: @@ -623,20 +678,23 @@ void InputDialog::handleCommand(CommandSender* sender, int cmd, eraseEEPROM(); break; + case kMouseCtrlChanged: + handleMouseControlState(); + break; + + case kCursorStateChanged: + handleCursorState(); + break; + + case kMPSpeedChanged: + myMPaddleSpeed->setValueLabel(myMPaddleSpeed->getValue() * 10); + break; + default: Dialog::handleCommand(sender, cmd, data, 0); } } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void InputDialog::handleCursorState() -{ - int state = myCursorState->getSelected(); - bool enableGrab = state != 1 && state != 3; - - myGrabMouse->setEnabled(enableGrab); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputDialog::updateDejitter() { @@ -659,3 +717,17 @@ void InputDialog::updateDejitter() myDejitterLabel->setLabel(label.str()); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void InputDialog::handleMouseControlState() +{ + myMPaddleSpeed->setEnabled(myMouseControl->getSelected() != 2); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void InputDialog::handleCursorState() +{ + int state = myCursorState->getSelected(); + bool enableGrab = state != 1 && state != 3; + + myGrabMouse->setEnabled(enableGrab); +} diff --git a/src/gui/InputDialog.hxx b/src/gui/InputDialog.hxx index 45fb8ed35..b86155fca 100644 --- a/src/gui/InputDialog.hxx +++ b/src/gui/InputDialog.hxx @@ -59,23 +59,29 @@ class InputDialog : public Dialog void saveConfig() override; void setDefaults() override; - void addDevicePortTab(const GUI::Font& font); + void addDevicePortTab(); + void addMouseTab(); + + void handleMouseControlState(); void handleCursorState(); void updateDejitter(); void eraseEEPROM(); private: enum { - kCursorStateChanged = 'CSch', kDeadzoneChanged = 'DZch', + kPCenterChanged = 'Pcch', + kPSpeedChanged = 'Ppch', kDejitterChanged = 'Pjch', kDPSpeedChanged = 'PDch', - kMPSpeedChanged = 'PMch', kTBSpeedChanged = 'TBch', kDBButtonPressed = 'DBbp', kEEButtonPressed = 'EEbp', - kConfirmEEEraseCmd = 'EEcf' + kConfirmEEEraseCmd = 'EEcf', + kMouseCtrlChanged = 'MCch', + kCursorStateChanged = 'CSch', + kMPSpeedChanged = 'PMch', }; TabWidget* myTab{nullptr}; @@ -90,16 +96,14 @@ class InputDialog : public Dialog EditTextWidget* myAVoxPort{nullptr}; SliderWidget* myDeadzone{nullptr}; - StaticTextWidget* myDeadzoneLabel{nullptr}; + SliderWidget* myPaddleCenter{nullptr}; + SliderWidget* myPaddleSpeed{nullptr}; SliderWidget* myDejitterBase{nullptr}; SliderWidget* myDejitterDiff{nullptr}; SliderWidget* myDPaddleSpeed{nullptr}; SliderWidget* myMPaddleSpeed{nullptr}; SliderWidget* myTrackBallSpeed{nullptr}; StaticTextWidget* myDejitterLabel{nullptr}; - StaticTextWidget* myDPaddleLabel{nullptr}; - StaticTextWidget* myMPaddleLabel{nullptr}; - StaticTextWidget* myTrackBallLabel{nullptr}; CheckboxWidget* myAllowAll4{nullptr}; CheckboxWidget* myGrabMouse{nullptr}; CheckboxWidget* myModCombo{nullptr}; From fceb496442b2ac38aed45fbe8cfcdb89f4e32f05 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 25 Mar 2020 12:00:41 +0100 Subject: [PATCH 043/377] fixes #595 (debugger BK color) --- src/emucore/tia/TIA.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/emucore/tia/TIA.cxx b/src/emucore/tia/TIA.cxx index 60608b765..38beebbcf 100644 --- a/src/emucore/tia/TIA.cxx +++ b/src/emucore/tia/TIA.cxx @@ -568,7 +568,8 @@ bool TIA::poke(uInt16 address, uInt8 value) break; case COLUBK: - myBackground.setColor(value & 0xFE); + value &= 0xFE; + myBackground.setColor(value); myShadowRegisters[address] = value; break; From ae66b54d46c19853f71ab21ca6f0f17d27e3e3ef Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 25 Mar 2020 19:28:39 +0100 Subject: [PATCH 044/377] split X and Y center of paddles add definition of paddles centers via game properties --- src/emucore/Console.cxx | 3 +- src/emucore/DefProps.hxx | 7022 ++++++++++++++++++------------------ src/emucore/OSystem.cxx | 2 + src/emucore/Paddles.cxx | 20 +- src/emucore/Paddles.hxx | 20 +- src/emucore/Props.cxx | 8 + src/emucore/Props.hxx | 2 + src/emucore/Settings.cxx | 8 +- src/gui/GameInfoDialog.cxx | 86 +- src/gui/GameInfoDialog.hxx | 5 + src/gui/InputDialog.cxx | 87 +- src/gui/InputDialog.hxx | 9 +- src/tools/PropSet.pm | 14 +- 13 files changed, 3678 insertions(+), 3608 deletions(-) diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index be6f00f43..518030966 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -924,7 +924,8 @@ unique_ptr Console::getControllerPort(const Controller::Type type, else if(type == Controller::Type::PaddlesIAxDr) swapAxis = swapDir = true; - Paddles::setAnalogCenter(myOSystem.settings().getInt("pcenter")); + Paddles::setAnalogXCenter(BSPF::stringToInt(myProperties.get(PropType::Controller_PaddlesXCenter))); + Paddles::setAnalogYCenter(BSPF::stringToInt(myProperties.get(PropType::Controller_PaddlesYCenter))); Paddles::setAnalogSensitivity(myOSystem.settings().getInt("psense")); controller = make_unique(port, myEvent, *mySystem, diff --git a/src/emucore/DefProps.hxx b/src/emucore/DefProps.hxx index bb834d812..d5bb3533e 100644 --- a/src/emucore/DefProps.hxx +++ b/src/emucore/DefProps.hxx @@ -27,3517 +27,3517 @@ static constexpr uInt32 DEF_PROPS_SIZE = 3510; -static const BSPF::array2D DefProps = {{ - { "000509d1ed2b8d30a9d94be1b3b5febb", "Greg Zumwalt", "", "Jungle Jane (2003) (Greg Zumwalt) (Hack)", "Hack of Pitfall!", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0060a89b4c956b9c703a59b181cb3018", "CommaVid, Irwin Gaines - Ariola", "CM-008 - 712 008-720", "Cakewalk (1983) (CommaVid) (PAL)", "AKA Alarm in der Backstube", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "007d18dedc1f0565f09c42aa61a6f585", "CCE", "C-843", "Worm War I (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "008543ae43497af015e9428a5e3e874e", "Retroactive", "", "Qb (V2.09) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "00b7b4cbec81570642283e7fc1ef17af", "SEGA - Beck-Tech, Steve Beck, Phat Ho", "006-01", "Congo Bongo (1983) (SEGA)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "00ce0bdd43aed84a983bef38fe7f5ee3", "20th Century Fox, Bill Aspromonte", "11012", "Bank Heist (1983) (20th Century Fox)", "AKA Bonnie and Clyde, Cops 'n' Robbers, Holdup, Rooring 20's", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "00ce76ad69cdc2fa36ada01ae092d5a6", "Bit Corporation", "PGP214", "Cosmic Avenger (4 Game in One) (1983) (BitCorp) (PAL)", "AKA StarMaster", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "00dc28b881989c39a6cf87a892bd3c6b", "CCE", "", "Krull (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "00e19ebf9d0817ccfb057e262be1e5af", "Atari, Ed Logg, Carol Shaw", "CX2639, CX2639P", "Othello (1981) (Atari) (PAL) [no grid markers]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "00e55b27fe2e96354cd21b8b698d1e31", "", "", "Phoenix (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "00eaee22034aff602f899b684c107d77", "Rainbow Vision - Suntek - Sunteck Corp", "SS-001", "Time Race (1983) (Rainbow Vision) (PAL)", "AKA Space Jockey", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "00f7985c20b8bdf3c557fac4d3f26775", "Aaron Curtis", "", "AStar (NTSC)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "012020625a3227815e47b37fd025e480", "Rob Kudla", "", "Better Space Invaders (1999) (Rob Kudla) (Hack) [a]", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "01293bd90a4579abb7aed2f7d440681f", "Century", "", "Snoopy (1983) (Century) (PAL)", "AKA Snoopy and the Red Baron", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "01297d9b450455dd716db9658efb2fae", "TechnoVision - Video Technology", "TVS1002", "Save Our Ship (1983) (TechnoVision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "012b8e6ef3b5fd5aabc94075c527709d", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix (1983) (Arcadia)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "01 56", "", "", "", "" }, - { "0164f26f6b38a34208cd4a2d0212afc3", "Coleco, Ed English", "2656", "Mr. Do! (1983) (Coleco)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "0173675d40a8d975763ee493377ca87d", "CBS Electronics, Ed English", "4L1751", "Roc 'n Rope (1984) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "01abcc1d2d3cba87a3aa0eb97a9d7b9c", "Jone Yuan Telephonic Enterprise Co", "", "Topy (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "01b09872dcd9556427761f0ed64aa42a", "Galaga Games", "", "River Raid (1984) (Galaga Games)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "01cb3e8dfab7203a9c62ba3b94b4e59f", "Atari, Mimi Nyden, Scott Smith, Robert Vieira", "CX26127", "Gremlins (1984) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "01e5c81258860dd82f77339d58bc5f5c", "CCE", "", "Corrida da Matematica (CCE)", "AKA Math Gran Prix", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "01e60a109a6a67c70d3c0528381d0187", "ITT Family Games, Perry Rhodan-Serie", "554-33 383", "Fire Birds (1983) (ITT Family Games) (PAL)", "AKA Sky Alien", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "01f584bf67b0e464014a8c8b5ea470e3", "Arcadia Corporation, Dennis Caswell", "5 AR-4200", "Labyrinth (Escape from the Mindmaster Beta) (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "02066b17f29082412c6754c1a2d6302e", "", "", "Demo Image Series #3 - Baboon (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "024365007a87f213cbe8ef5f2e8e1333", "Atari, Frank Hausman, Mimi Nyden, Steve Woita", "CX2686", "Quadrun (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "025668e36a788e8af8ac4f1be7e72043", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX2659", "Raiders of the Lost Ark (06-14-82) (Atari) (Prototype)", "Console ports are swapped", "Prototype", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "" }, - { "026180bf641ff17d8577c33facf0edea", "Activision, Steve Cartwright", "AX-022", "Seaquest (1983) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0277c449fae63f6f1c8f94dedfcf0058", "", "", "Laser Demo (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "027a59a575b78860aed780b2ae7d001d", "CCE", "", "Pressure Cooker (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "028024fb8e5e5f18ea586652f9799c96", "Coleco - Woodside Design Associates, Steve 'Jessica Stevens' Kitchen", "2468", "Carnival (1982) (Coleco)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "02811151906e477d47c135db5b1699c6", "", "", "FlickerSort Demo (Updated) (20-04-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "02a5fc90a0d183f870e8eebac1f16591", "HES", "771-422", "2 Pak Special - Star Warrior, Frogger (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "02ab2c47bc21e7feafa015f90d7df776", "Atari", "MA017600", "Diagnostic Test Cartridge 2.6 (1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "02ced7ea2b7cb509748db6bfa227ebec", "Parker Brothers, Ed English, David Lamkins", "931502", "Frogger (1982) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "02cee0b140d2f1a1efcfb1d482a5c392", "Atari, Ed Logg, Carol Shaw - Sears", "CX2639 - 49-75162", "Othello (1981) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "02dcba28c614fec7ca25955327128abb", "Andrew Wallace", "", "Laseresal 2002 (PAL) (PD) [a]", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "02e3f4ba156fb578bef7d7a0bf3400c1", "", "", "Booster (Junkosoft) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "033e21521e0bf4e54e8816873943406d", "20th Century Fox Video Games - Sirius Software, Dan Thompson", "11020", "Earth Dies Screaming, The (1983) (20th Century Fox)", "The Day the Earth Stood Still", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "034c1434280b0f2c9f229777d790d1e1", "Telegames", "5665 A016", "Baseball (1988) (Telegames) (PAL)", "AKA Super Challenge Baseball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0375f589f7da06d2d2be532e0d4d4b94", "", "", "Push (V0.04) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0383dc02cb82302da3d155fd108bfe3a", "AtariAge, Chris Spry", "CX26200", "Princess Rescue (2013) (Sprybug) (PAL60)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "JOYSTICK", "", "", "", "", "", "YES", "" }, - { "038e1e79c3d4410defde4bfe0b99cc32", "Atari, Tod Frye, Gary Shannon", "", "Aquaventure (08-12-1983) (Atari) (Prototype)", "AKA Sea Sentinel", "Unbelievably Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "039cf18b459d33b8a8fca31d06c4c244", "", "", "Demo Image Series #0 (12-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "03b1051c9374678363c899914412cfc5", "", "", "Incoming (30-10-2002) (Ben Larson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "03c3f7ba4585e349dd12bfa7b34b7729", "SEGA, Jeff Lorenz", "004-01", "Star Trek - Strategic Operations Simulator (1983) (SEGA)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "03fbcee0bc80e31f27254aea3d920510", "Bit Corporation", "R320", "Trick Shot (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "03ff9e8a7af437f16447fe88cea3226c", "Bomb - Onbase", "CA285", "Wall-Defender (1983) (Bomb)", "AKA Wall Break", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "04014d563b094e79ac8974366f616308", "Atari, Andrew Fuchs, Courtney Granner, Jeffrey Gusman, Mark R. Hahn", "CX2690", "Pengo (1984) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "041b5e56bbc650db574bd8db3fae2696", "Thomas Jentzsch", "", "Thrust (V1.0) (2000) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "043f165f384fbea3ea89393597951512", "Spectravision - Spectravideo", "SA-202", "Planet Patrol (1982) (Spectravision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0443cfa9872cdb49069186413275fa21", "M Network - INTV, Patricia Lewis Du Long, Ron Surratt", "MT4518", "BurgerTime (1983) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "045035f995272eb2deb8820111745a07", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (1983) (Arcadia)", "AKA Jungle Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "047ac3b9faea64522b7a23c4465a7aa8", "", "", "Defender (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "04856e3006a4f5f7b4638da71dad3d88", "Atari, Douglas Neubauer", "CX26176", "Radar Lock (1989) (Atari) (PAL)", "AKA Dog Fight", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "049626cbfb1a5f7a5dc885a0c4bb758e", "", "", "MegaMania (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "04b488d4eef622d022a0021375e7e339", "Home Vision - Gem International Corp. - VDI", "VCS83107", "Tennis (1983) (Home Vision) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "04cf9e6898007024622ed6a0b295961f", "Bit Corporation", "R320", "Tennis (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "04dfb4acac1d0909e4c360fd2ac04480", "Thomas Jentzsch", "", "Jammed (2001) (XYPE) (NTSC)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "04e737c9d53cd84bfd5ee679954e4706", "Jone Yuan Telephonic Enterprise Co", "", "Checkers (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "04fccc7735155a6c1373d453b110c640", "HES - Imagineering, David Lubar", "535", "My Golf (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0519f395d5f7d76be813b834aa51c0be", "Atari, Ian Shepard", "CX2604", "Space War (1978) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0546f4e6b946f38956799dd00caab3b1", "Thomas Jentzsch", "", "My Golf (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "056f5d886a4e7e6fdd83650554997d0d", "Parker Brothers, Ed Temple", "931504", "Amidar (1982) (Parker Bros) (PAL)", "", "Uncommon", "", "", "", "A", "A", "", "", "", "", "", "", "", "", "", "" }, - { "056ff67dd9715fafa91fb8b0ddcc4a46", "", "", "Frisco (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "05824fcbe615dbca836d061a140a50e0", "Jeffry Johnston", "", "Radial Pong - Version 9 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "05aedf04803c43eb5e09dfd098d3fd01", "", "", "Keystone Kapers (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "05aff8f626ef870432ae3b3d9d5aa301", "Activision, Bob Whitehead", "AG-019", "Sky Jinks (1982) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "05b45ba09c05befa75ac70476829eda0", "Parker Brothers, Rex Bradford", "931507", "Star Wars - Jedi Arena (1983) (Parker Bros) (PAL)", "Uses the Paddle Controllers (swapped)", "", "", "", "", "", "", "", "", "", "", "YES", "10 50", "", "", "", "" }, - { "05c60458ec69e7fe8b1be973852d84f1", "", "", "Test (1996) (J.V. Matthews) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "05c765a63e61882abd1c2d627b652225", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Amiga Mouse Hack v1.1 (NTSC) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "05ccf96247af12eef59698f1a060a54f", "Otto Versand", "600273", "King Arthur (1983) (Otto Versand) (PAL)", "AKA Dragonfire (Double-Game Package)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "05d61b925d3d2474bab83f0a79bb5df1", "Eckhard Stolberg", "", "Cosmic Ark Stars (1997) (Eckhard Stolberg)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "05eb4347f0ec8f4783983ca35ffd8d1b", "", "", "Qb (2.06) (Retroactive) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "05ebd183ea854c0a1b56c218246fbbae", "Atari, Dan Hitchens", "CX2656", "SwordQuest - EarthWorld (1982) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "05f11fb2e45c4e47424d3cb25414d278", "", "", "Boring (NTSC) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "060c865c782debb047e6fd101c8923fc", "Atari", "CX26163P", "Freeway Rabbit (32 in 1) (1988) (Atari) (PAL) (4K)", "AKA Freeway", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0614ed51acd027d531e7c85c4f435292", "", "", "Narnia (Glenn Saunders) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0619e1c3286bbfbace040b8c3ec5add2", "Omegamatrix", "", "Millipede (Atari Trak-Ball) v6.5 (Omegamatrix)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, - { "0651216c4a4a9c9ac5ada3013a317c72", "Jone Yuan Telephonic Enterprise Co", "", "Fishing Derby (Jone Yuan) (4K) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "06742cf522f23797157f215a1dc8a1a9", "", "", "Healthbars (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0685bd0bcb975ceef7041749a5454a48", "Piero Cavina", "", "11 Sprite Demo (Piero Cavina) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "069c17beb1e8e0557adb8539fdcf6cba", "", "", "Phantom II & Pirate (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "06b0194ce992584c365278e0d7323279", "Activision", "", "Unknown Activision Game #2 (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "06b6c5031b8353f3a424a5b86b8fe409", "Activision, Mike Lorenzen - Ariola", "EAX-023 - 711 023-720", "Oink! (1983) (Activision) (PAL)", "AKA Das Schweinchen und der Wolf", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "06cfd57f0559f38b9293adae9128ff88", "Telegames", "4317 A009", "Adventures on GX-12 (1988) (Telegames) (PAL)", "AKA Adventures of Tron", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "06d2f7674cea977607f74c464ce600a2", "CBS Electronics, Alex Nevelson", "4L 2737 0000", "Omega Race (1983) (CBS Electronics) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "BOOSTERGRIP", "", "", "", "", "", "", "" }, - { "06db908011065e5ebb37f4e253c2a0b0", "", "", "Gopher (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "06e5dc181a8eda1c31cc7c581c68b6ef", "", "", "Tac-Scan (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "071f84d10b343c7c05ce3e32af631687", "Rainbow Vision - Suntek", "SS-019", "Curtiss (1983) (Rainbow Vision) (PAL)", "AKA Atlantis", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "072a6ea2181ca0df88ac0dedc67b239d", "", "", "Multiple Missiles Demo (19-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "073cb76b006af034fd150be3f5e0e7e6", "", "", "Mobile 48 Sprite Kernel (Bug Fixed) (10-01-2003) (Eric Ball)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "073d7aff37b7601431e4f742c36c0dc1", "", "", "Bermuda (Unknown) (PAL)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "074ec425ec20579e64a7ded592155d48", "Atari - Sculptured Software, Steve Aguirre", "CX26162", "Fatal Run (Ultimate Driving) (1991) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "075069ad80cde15eca69e3c98bd66714", "CCE", "C-803", "Bobby Is Going Home (1983) (CCE)", "AKA Bobby Vai Para Casa", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0751f342ee4cf28f2c9a6e8467c901be", "Atari, Mimi Nyden, Joseph Tung", "CX26152", "Super Baseball (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "07973be3ecfd55235bf59aa56bdef28c", "Suntek", "SS-036", "Criminal Pursuit (1983) (Suntek) (PAL)", "AKA A Mysterious Thief", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "079fe9103515d15bc108577e234a484d", "", "", "Multi-Color Demo 0 (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "07a3af1e18b63765b6807876366f5e8a", "Joe Grand", "", "SCSIcide Pre-release 2 (Joe Grand)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "07c76f2d88552d20ad2c0ed7aef406c6", "Cody Pittman", "", "Blob (Cody Pittman) (Hack)", "Hack of Halloween", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "07f42847a79e4f5ae55cc03304b18c25", "Zellers", "", "Sea Hawk (Zellers)", "AKA Seahawk", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "07f84db31e97ef8d08dc9fa8a5250755", "Supergame", "", "Enduro (1984) (Supergame)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "07f91e33e76f53bb9d2731fd5d8a35a5", "Atari", "CX2632", "Space Invaders (1978) (Atari) [t1]", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0805366f1b165a64b6d4df20d2c39d25", "Atari, Dan Hitchens", "CX2650", "Berzerk (1982) (Atari) (PAL)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "08188785e2b8300983529946dbeff4d2", "Atari, Carla Meninsky, Ed Riddle - Sears", "CX2611 - 99821, 49-75149", "Indy 500 (1977) (Atari) (4K)", "Uses the Driving Controllers", "", "", "", "", "", "", "", "", "DRIVING", "DRIVING", "", "45", "", "", "", "" }, - { "081e2c114c9c20b61acf25fc95c71bf4", "Parker Brothers, Ed English, David Lamkins", "PB5300", "Frogger (1982) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "082fdc8bd47fef01482ce5883c4ffdb8", "Charles Morgan", "", "Tanks DX (Charles Morgan) (Hack)", "Hack of Tanks But No Tanks", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0832fb2ee654bf9382bc57d2b16d2ffc", "Apollo - Games by Apollo, Ed Salvo", "AP-1001", "Skeet Shoot (1981) (Apollo) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "083e7cae41a874b2f9b61736c37d2ffe", "Imagic, Rob Fulop, Bob Smith", "720106-2A, IA3600P, EIX-009-04I", "Riddle of the Sphinx (1982) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "085322bae40d904f53bdcc56df0593fc", "Parker Brothers, Dave Engman, Dawn Stockbridge", "PB5340", "Tutankham (1983) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0856f202b18cd46e44fd1dc3b42e9bfb", "", "", "Frame Counter 1 (2001) (Jake Patterson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0866e22f6f56f92ea1a14c8d8d01d29c", "Androbot - Western Technologies, Michael Case, Lenny Carlson", "", "AndroMan on the Moon (1984) (Western Tech) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0891252ee4e307689febccf3cfd8a8ab", "Thomas Jentzsch", "", "Centipede - Atari Trak-Ball Hack v1.4 (PAL60) (Half-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0894aa7be77521f9df562be8d9555fe6", "CBS Electronics, Dan Kitchen, Garry Kitchen", "4L1700, 4L1701, 4L1702, 4L1802, 4L2274", "Donkey Kong (1982) (CBS Electronics) (PAL) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "08989fa4ff537f5dbd611aff4019521a", "Atari, Gary Palmer", "CX26163P", "Fun with Numbers (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "08bd4c1dcc843f6a0b563d9fd80b3b11", "Quelle", "343.273 9", "Phantompanzer II (1983) (Quelle) (PAL)", "AKA Thunderground", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "08bf437d012db07b05ff57a0c745c49e", "Arcadia Corporation, Steve Hales, Stephen H. Landrum", "4 AR-4102", "Meteoroids (1982) (Arcadia) (Prototype)", "Suicide Mission Beta", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "08d1b6d75206edb999252caf542a2c7f", "Larry Petit", "", "Super Home Run (2003) (Larry Petit) (Hack)", "Hack of Home Run", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "08d60a58a691c7f690162850302dc0e1", "", "", "Poker Squares (V0.27) (PAL) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "08e5960bb52d9a3e2c9954677b5e4472", "Atari - CCW, Christopher H. Omarzu, Preston Stuart, Bruce Williams", "CX26101", "Oscar's Trash Race (10-20-1982) (Atari) (Prototype)", "Uses the Keypad Controllers", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "08ea2fdaa22e5802c839ee7dfb0483dc", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Atari Trak-Ball Hack v1.2 (PAL60) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "08f4dc6f118f7c98e2406c180c08e78e", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix - Tug of War (2 of 3) (1983) (Arcadia) (PAL)", "Uses Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "02", "", "", "", "" }, - { "08f853e8e01e711919e734d85349220d", "Atari, Jerome Domurat, Michael Sierchio", "CX2667", "RealSports Soccer (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0906c6e0e4bda9c10cfa4c5fc64d2f4b", "Retroactive", "", "Qb (V0.12) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "090f0a7ef8a3f885048d213faa59b2f8", "Carrere Video - Western Technologies, John Hall - Teldec - Prism", "USC1012", "M.A.D. (1983) (Carrere Video) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "09274c3fc1c43bf1e362fda436651fd8", "Thomas Jentzsch", "", "Acid Drop (TJ)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "09388bf390cd9a86dc0849697b96c7dc", "Absolute Entertainment, Alex DeMeo", "AG-045-04, AK-045-04", "Pete Rose Baseball (1988) (Absolute)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0945081a6bd00345ff3d58eb7a07330a", "", "", "Stampede (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0956285e24a18efa10c68a33846ca84d", "Dismac", "", "Viagem Espacial (Dismac)", "AKA Star Voyager", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0963aa9f7f6cf5a36ff700001583624e", "Franklin Cruz", "", "Space Invaders 2 (Hack) [o1]", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "096649575e451508006b17e0353259a5", "Justin J. Scott", "", "Yar Vs. Yar (2002) (Justin J. Scott) (Hack)", "Hack of Yars' Revenge", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "097074f24cde141fe6a0f26a10333265", "", "", "Marble Craze (V0.90) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "097936b07e0e0117b9026ae6835eb168", "Imagic, Dennis Koble", "720100-2B, IA3000P", "Trick Shot (1982) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "09abfe9a312ce7c9f661582fdf12eab6", "Atari, Douglas Neubauer", "CX26154", "Super Football (1988) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "09e1ecf9bd2a3030d5670dba7a65e78d", "Atari, James Andreasen", "CX2654", "Haunted House (1982) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "09e9ba0762fd0c3cf3c2e072cff79cac", "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart", "PB5540", "Star Wars - The Arcade Game (1984) (Parker Bros) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "09f89bbfa2ab00f1964d200e12d7ced0", "Atari", "MA017600", "Diagnostic Test Cartridge 2.6 (1982) (Atari) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0a1b98937911d621b004b1617446d124", "", "", "Hangman Pac-Man Biglist1 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0a981c03204ac2b278ba392674682560", "Atari, Bob Whitehead - Sears", "CX2651 - 99805, 49-75602", "Blackjack (1977) (Atari)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "", "", "" }, - { "0aa208060d7c140f20571e3341f5a3f8", "U.S. Games Corporation - Western Technologies, Jeff Corsiglia, Paul Allen Newell, Tom Sloper", "VC1009", "Towering Inferno (1982) (U.S. Games)", "Uses the Joystick Controllers (swapped)", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "YES", "" }, - { "0abf64ca504a116adca80f77f85e00fb", "", "", "Cube Conquest (Billy Eno) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0ac0d491763153fac75f5337ce32a9d6", "", "", "SPAM Image Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0acaf71e60b89f6b6eab63db6ab84510", "", "", "This Planet Sucks (Greg Troutman) [a2]", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0aceb7c3bd13fe048b77a1928ed4267d", "Imagic, Bob Smith", "720102-2B, IA3201P, EIX-011-04I", "Star Voyager (1982) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0ad9a358e361256b94f3fb4f2fa5a3b1", "Atari, Carol Shaw, Nick 'Sandy Maiwald' Turner - Sears", "CX2608 - 49-75165", "Super Breakout (1982 - 1981) (Atari) [a]", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "01 45", "", "", "", "" }, - { "0adb21206de92e8aec5ef295805ebb90", "", "", "Solaris (Genesis)", "Genesis controller (C switches to map mode)", "Hack of Solaris", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0ae3497e731ca0bf6a77b23441d9d9f9", "", "", "Analog Clock (V0.0) (20-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0af51ceb4aecc7a8fc89781ac44a1973", "Barry Laws Jr.", "", "Face Invaders Deluxe (Barry Laws Jr.) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0afe6ae18966795b89314c3797dd2b1e", "Atari - GCC, Mark Ackerman, Noellie Alito", "CX2692, CX2692P", "Moon Patrol (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0b01909ba84512fdaf224d3c3fd0cf8d", "", "", "Revenge of the Apes (Hack)", "Hack of Planet of the Apes", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0b1056f1091cfdc5eb0e2301f47ac6c3", "Tigervision - Software Electronics Corp., Karl T. Olinger - Teldec", "7-001 - 3.60001 VE", "King Kong (1982) (Tigervision) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0b17ed42984000da8b727ca46143f87a", "Atari - CCW, Christopher H. Omarzu", "CX26104", "Big Bird's Egg Catch (05-17-1983) (Atari) (Prototype)", "Uses the Keypad Controller", "Prototype", "", "", "", "", "", "", "", "KEYBOARD", "", "", "", "", "", "", "" }, - { "0b24658714f8dff110a693a2052cc207", "CCE", "C-815", "Seaquest (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0b33252b680b65001e91a411e56e72e9", "CCE", "C-832", "Atlantis (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0b4e793c9425175498f5a65a3e960086", "CCE", "", "Kung Fu Master (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0b55399cf640a2a00ba72dd155a0c140", "Imagic, Wilfredo Aguilar, Michael Becker, Rob Fulop", "720111-1A, 03205", "Fathom (1983) (Imagic)", "AKA Scuba", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "0b577e63b0c64f9779f315dca8967587", "Videospielkassette - Ariola", "PGP236", "Raketen-Angriff (Ariola) (PAL)", "AKA Missile Control", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0b8d3002d8f744a753ba434a4d39249a", "Sears Tele-Games, Robert Zdybel", "CX2619 - 49-75159", "Stellar Track (1981) (Sears)", "AKA Stella Trak", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "0bf19e40d5cd8aa5afb33b16569313e6", "Atari, Jerome Domurat, Andrew Fuchs, Dave Staugas, Robert Vieira", "CX26118", "Millipede (01-04-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0bf1e354304f46c0caf8fc0f6f5e9525", "Arcadia Corporation, Stephen Harland Landrum", "AR-4105", "Official Frogger (1983) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0bfabf1e98bdb180643f35f2165995d0", "Atari, Bob Whitehead - Sears", "CX2623 - 6-99819, 49-75108, 49-75125", "Home Run (1978) (Atari)", "", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "" }, - { "0c0392db94a20e4d006d885abbe60d8e", "", "", "Dodge Demo 3 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0c336f83b0e6e3bc86c77f368448e77b", "Bit Corporation", "R320", "Circus Atari (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0c35806ff0019a270a7acae68de89d28", "Froggo", "FG1003", "Task Force (1987) (Froggo)", "AKA Gangster Alley", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0c48e820301251fbb6bcdc89bd3555d9", "Atari, Bill Aspromonte, Andrew Fuchs", "CX26120", "Stargate (1984) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0c54811cf3b1f1573c9164d5f19eca65", "Activision, David Crane - Ariola", "EAG-001, PAG-001, EAG-001-04B, EAG-001-04I - 711 001-715", "Dragster (1980) (Activision) (PAL)", "AKA Dragster Rennen, Drag Strip", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0c72cc3a6658c1abd4b735ef55fa72e4", "Dion Olsthoorn", "v1.3", "Amoeba Jump (2018) (Dionoid) (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0c7926d660f903a2d6910c254660c32c", "Atari, Larry Kaplan", "CX2602, CX2602P", "Air-Sea Battle (1977) (Atari) (PAL)", "AKA Anti-Aircraft", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0c7bd935d9a7f2522155e48315f44fa0", "Carrere Video - Western Technologies, Jeff Corsiglia, Paul Allen Newell, Tom Sloper - Teldec - Prism", "USC1009", "Infernal Tower (1983) (Carrere Video) (PAL)", "AKA Towering Inferno", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "YES", "" }, - { "0c80751f6f7a3b370cc9e9f39ad533a7", "Atari, Carla Meninsky", "CX2610", "Warlords (1981) (Atari) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, - { "0cb7af80fd0ddef84844481d85e5d29b", "", "", "Mr. Pac-Man (El Destructo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0cc8224ff1edfe458e8629e9e5fe3f5b", "Thomas Jentzsch", "", "Trick 12 (2001) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0cdd9cc692e8b04ba8eb31fc31d72e5e", "Thomas Jentzsch", "", "Wing War (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0cebb0bb45a856b23f56d21ce7d1bc34", "20th Century Fox Video Games, Bill Aspromonte", "11131", "Crash Dive (1983) (20th Century Fox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0cec9e46a25d338bf595a29aa2606516", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Atari Mouse Hack v1.1 (PAL60) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0cfdd2f3b243cac21f38a0f09f54bead", "", "", "Overhead Adventure Demo 4 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0d07d2c1be1a5eaaea235a533bcda781", "", "", "Scrolling Playfield 1 (Junkosoft) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0d08558f34a47e4eaa39d01c8efb81f0", "Thomas Jentzsch", "", "Missile Control - Atari Mouse Hack v1.15 (NTSC) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0d09cff0d28033c02c3290edfc3a5cea", "Atari, Jerome Domurat, Steve Woita", "CX2699", "Taz (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0d1b3abf681a2fc9a6aa31a9b0e8b445", "Atari", "CX26163P", "Laser Blast (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0d27c7f5db349b592f70f68daf5e8f3b", "", "", "Space Instigators (21-10-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0d35618b6d76ddd46d2626e9e3e40db5", "", "", "X-Doom V.26 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0d5af65ad3f19558e6f8e29bf2a9d0f8", "Atari - Sculptured Software, Adam Clayton", "CX26151, CX26151P", "Dark Chambers (1989) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "0d6b974fe58a1bdd453600401c407856", "Atari", "", "128-in-1 Junior Console (Chip 3 or 4) (1991) (Atari) (PAL)", "Actually contains only 16 games, not 32", "", "", "", "16IN1", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0d786a41695e5fc8cffd05a6dbb3f659", "", "", "Scrolling Playfield With Score (10-02-2003) (Aaron Bergstrom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0d7e630a14856f4d52c9666040961d4d", "", "", "Wavy Line Test (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0d90a0ee73d55539b7def24c88caa651", "Activision, Bob Whitehead", "AG-005, CAG-005, AG-005-04", "Skiing (1980) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0db4f4150fecf77e4ce72ca4d04c052f", "Atari, Carol Shaw - Sears", "CX2618 - 49-75123", "3-D Tic-Tac-Toe (1980) (Atari)", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0dd4c69b5f9a7ae96a7a08329496779a", "Tigervision - Software Electronics Corp., Karl T. Olinger - Teldec", "7-001 - 3.60001 VE", "King Kong (1982) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0de53160a8b54c3aa5aed8d68c970b62", "Quelle", "806.174 9", "Fuchs & Schweinchen Schlau (1983) (Quelle) (PAL)", "AKA Oink!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0dfbdadf8f1bc718e7e1bb3ccd5fef3d", "", "", "Mr. Pac-Man (New start tune) (El Destructo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0e0808227ef41f6825c06f25082c2e56", "", "", "Candi (Hack) [a]", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0e08cd2c5bcf11c6a7e5a009a7715b6a", "", "", "Boing! (PD) [a1]", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0e224ea74310da4e7e2103400eb1b4bf", "Atari, Peter C. Niday, Gary Shannon, Howard Scott Warshaw", "", "Mind Maze (10-10-1984) (Atari) (Prototype)", "Uses the MindLink controller", "Prototype", "", "", "", "", "", "", "", "", "MINDLINK", "", "", "", "", "", "" }, - { "0e23d0ed4c33b2011ab4cc93a7619683", "Thomas Jentzsch", "", "Centipede - Amiga Mouse Hack v1.4 (PAL60) (Half-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0e4b2b6e014a93ef8be896823da0d4ec", "", "", "Skiing (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0e713d4e272ea7322c5b27d645f56dd0", "Home Vision - Gem International Corp. - VDI", "VCS83105", "Panda Chase (1983) (Home Vision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0e7e73421606873b544e858c59dc283e", "Digivision", "", "Super Soccer (Digivision)", "AKA RealSports Soccer", "", "", "", "F8", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "0e86470791b26292abe1c64545c47985", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix - Down on the Line (3 of 3) (1983) (Arcadia) (PAL)", "Uses Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "01 70", "", "", "", "" }, - { "0ec93f519bb769e0d9f80e61f6cc8023", "Atari - GCC, John Allred, Mike Feinstein", "CX2688", "Jungle Hunt (02-25-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0ecdb07bf9b36ef18f3780ef48e6c709", "Bit Corporation", "PG209", "Mr. Postman (1983) (BitCorp)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0eebfb60d437796d536039701ec43845", "Fabrizio Zavagli", "", "Cakewalk (Fabrizio Zavagli)", "NTSC Conversion", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0eecb5f58f55de9db4eedb3a0f6b74a8", "Xonox - Beck-Tech", "6210, 06002, 06004, 99002", "Ghost Manor (1983) (Xonox) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0ef64cdbecccb7049752a3de0b7ade14", "Atari, Joe Decuir, Larry Caplan, Steve Mayer, Larry Wagner", "CX26163P", "Combat (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0efc91e45f61023cda9d086a7d3c402f", "B.J. Best (aka bjbest60)", "", "Space Cactus Canyon (2017)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "0effef4a341f8eebab65621c60c48787", "Thomas Jentzsch", "", "Reactor - Atari Trak-Ball Hack v1.3 (PAL) (Full-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0f14c03050b35d6b1d8850b07578722d", "Jeffry Johnston", "", "Radial Pong - Version 10 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0f24ca5668b4ab5dfaf217933c505926", "", "", "Fantastic Voyage (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0f2e09c71cc216f79d22a804152ba24b", "Bob Colbert", "", "Scroller Demo (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "0f341d1f4e144e3163d9a5fc5a662b79", "", "", "RUN Platform Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "0f39fc03d579d0d93a6b729a3746843e", "Atari, Sam Comstock, Richard Dobbis, Nick 'Sandy Maiwald' Turner", "CX26111", "Snoopy and the Red Baron (05-27-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0f604cd4c9d2795cf5746e8af7948064", "Champ Games", "CG-02-N", "Conquest Of Mars (2010) (NTSC)", "Rev 2 release", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0f643c34e40e3f1daafd9c524d3ffe64", "Atari, Robert C. Polaro, Alan J. Murphy - Sears", "CX2609 - 49-75186", "Defender (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0f6676b05621f80c670966e2995b227a", "", "", "Globe Trotter Demo 1 (24-03-2003) (Weston)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0f738dc44437557624eb277ed7ad91c9", "", "", "Grand Prix (Unknown) (PAL)", "AKA Grand Prix", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0f8043715d66a4bbed394ef801d99862", "Quelle", "684.733 9", "Robin Hood (1983) (Quelle) (PAL)", "AKA Save Our Ship", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0f95264089c99fc2a839a19872552004", "Activision, David Crane", "AG-009, AG-009-04", "Freeway (1981) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0fba7d8c3520bdb681f75494e498ec36", "", "", "Gunfight 2600 - Final Run (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0fbf618be43d4396856d4244126fe7dc", "Quelle", "805.784 6", "Labyrinth (1983) (Quelle) (PAL)", "AKA Maze Craze", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0fc161704c46e16f7483f92b06c1558d", "CCE", "C-853", "Spider Fighter (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0fcff6fe3b0769ad5d0cf82814d2a6d9", "Suntek", "SS-027", "Zoo Fun (1983) (Suntek) (PAL)", "AKA Panda Chase", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0fd72a13b3b6103fc825a692c71963b4", "Imagic, Rob Fulop", "720104-2A, IA3204P, EIX-008-04I", "Cosmic Ark (1982) (Imagic) (PAL) [selectable starfield]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "0fee596b974c9d3e70b367a3671599b6", "Bit Corporation", "R320", "Name This Game (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "101ab60f4000a5d13792ef0abad5f74b", "Atari, Jerome Domurat, Peter C. Niday, Robert Vieira", "CX26109", "Sorcerer's Apprentice (1983) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "102672bbd7e25cd79f4384dd7214c32b", "Atari, Alan Miller - Sears", "CX2642 - 6-99814", "Hunt & Score - Memory Match (1978) (Atari)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "103e9d616328969f5d7b4e0a381b25d5", "", "", "Playfield Illustration and Logo Demo (2001) (Jake Patterson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "103f1756d9dc0dd2b16b53ad0f0f1859", "Home Vision, Gem International Corp.", "", "Go Go Home Monster (1983) (Home Vision) (PAL)", "AKA Go Go Home", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "104468e44898b8e9fa4a1500fde8d4cb", "AtariAge, Chris Spry", "CX26200", "Princess Rescue (2013) (Sprybug)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "JOYSTICK", "", "", "", "", "", "YES", "" }, - { "106326c262dfd3e8eaeabd961d2a0519", "", "", "PAL-NTSC Detector (15-11-2002) (CT)[a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "106855474c69d08c8ffa308d47337269", "Atari - Sculptured Software, Adam Clayton", "CX26151", "Dark Chambers (1989) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "107cc025334211e6d29da0b6be46aec7", "Atari, Bob Smith - Sears", "CX2648 - 49-75161", "Video Pinball (1981) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1086ff69f82b68d6776634f336fb4857", "Activision, David Crane", "AG-009", "Bloody Human Freeway (1981) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "10958cd0a1a81d599005f1797ab0e51d", "", "", "Centipede 2k (2000) (PD) (Hack)", "Hack of Centipede", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "10a3cd14e5dcfdde6ff216a14ce7b7dd", "Atari", "CX262, CX2627P", "Human Cannonball (1979) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "10af8728f975aa35a99d0965de8f714c", "Dinatronic", "", "Seaquest (Dinatronic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "10c47acca2ecd212b900ad3cf6942dbb", "Atari - Axlon, Tod Frye - Heuristica, Agustin Ortiz", "CX26169", "Shooting Arcade (03-07-1989) (Atari) (Prototype) [a4]", "Uses the Light Gun Controller (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "10c8cfd8c37522f11d47540ff024e5f9", "Canal 3 - Intellivision", "C 3016", "Demon Attack (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "10eae73a07b3da044b72473d8d366267", "Funvision - Fund. Int'l Co.", "", "Karate (1982) (Funvision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "10f0ecaf962aef1fc28abed870b01b65", "Atari, Paul Donaldson", "", "Bionic Breakthrough (06-22-1984) (Atari) (Prototype)", "Uses the Mindlink Controller", "Prototype", "", "", "", "", "", "", "", "MINDLINK", "", "", "", "", "", "", "" }, - { "10f62443f1ae087dc588a77f9e8f43e9", "Atari, Carla Meninsky", "CX2637, CX2637P", "Dodge 'Em (1980) (Atari) (PAL) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "110ac8ecaf1b69f41bc94c59dfcb8b2d", "", "", "Demon Attack (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "111029770226b319524134193886a10e", "Hozer Video Games", "", "Gunfight 2600 - One Limit Reached! (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "11330eaa5dd2629052fac37cfe1a0b7d", "128-in-1 Junior Console", "", "Human Cannonball (128-in-1 Junior Console) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "113cd09c9771ac278544b7e90efe7df2", "Atari, Ed Logg, Carol Shaw - Sears", "CX2639 - 49-75162", "Othello (1981) (Atari) [no grid markers]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "114c599454d32f74c728a6e1f71012ba", "Activision, Bob Whitehead - Ariola", "EAX-015, EAX-015-04I - 711 015-725", "Chopper Command (1982) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "11bcf5c752088b5aaf86d6c7a6a11e8d", "Atari, Jerome Domurat, Andrew Fuchs, Dave Staugas, Robert Vieira", "CX26118", "Millipede (1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "11e7e0d9437ec98fa085284cf16d0eb4", "", "", "Bowling (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "11f9532557e4c9569f4b242164006161", "Chris Walton, Justin Hairgrove, Tony Morse", "", "Hunchy II (2005) (PAL)", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1201c18cf00d2c236f42e4d7d8c86aa1", "", "", "Nick Bensema Demo (Nick Bensema)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "12080205f669b8e7783b976f8cf3d8bb", "Omegamatrix", "", "Star Wars Arcade (Amiga Mouse) v4 (Omegamatrix)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "12123b534bdee79ed7563b9ad74f1cbd", "Absolute Entertainment, Alex DeMeo", "AG-041-04", "Title Match Pro Wrestling (1987) (Absolute)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1228c01cd3c4b9c477540c5adb306d2a", "Atari, Alan Miller", "CX26163P", "Basketball (32 in 1) (1988) (Atari) (PAL)", "Console ports are swapped", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "" }, - { "1266b3fd632c981f3ef9bdbf9f86ce9a", "Activision, Bob Whitehead", "EAZ-034-04, EAZ-034-04I", "Private Eye (1984) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1267e3c6ca951ff1df6f222c8f813d97", "", "", "Dragonfire (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "126f7f64b7b00e25dcf5e3710b4cf8b8", "Atari - GCC", "CX2676", "Centipede (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1278f74ca1dfaa9122df3eca3c5bcaad", "Rainbow Vision - Suntek", "SS-013", "Bi! Bi! (Rainbow Vision) (PAL)", "AKA Skindiver", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1287535256bf5dff404839ac9e25c3e7", "PacManPlus", "Rev 2", "Alien Pac-Man (PacManPlus) (Hack)", "Hack of Alien", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "12937db3d4a80da5c4452b752891252d", "Digitel", "", "Megamania (1983) (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "12bca8305d5ab8ea51fe1cfd95d7ab0e", "Epyx, Steven A. Baker, Tod Frye, Peter Engelbrite", "80561-00250", "Summer Games (1987) (Epyx) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "12d7e0d6b187889f8d150bf7034d1db2", "", "", "Poker Squares (V0.0e) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "130c5742cd6cbe4877704d733d5b08ca", "Home Vision - Gem International Corp. - VDI", "VCS83109", "World End (1983) (Home Vision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1323c45d660f5a5b6d5ea45c6c4cbe4a", "Canal 3 - Intellivision", "", "Enduro (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "133456269a03e3fdae6cddd65754c50d", "Tigervision - Software Electronics Corporation - Teldec", "7-006 - 3.60008 VG", "Springer (1983) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "133a4234512e8c4e9e8c5651469d4a09", "Atari, Andrew Fuchs, Jeffrey Gusman, Dave Jolly, Suki Lee", "CX26117", "Obelix (1984) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "133b56de011d562cbab665968bde352b", "Activision, John Van Ryzin", "AG-038-04", "Cosmic Commuter (1984) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1343de49c2a50d99176255f99f0d0234", "Gray Games & AtariAge", "", "E.T. Book Cart (PAL)", "Charles F. Gray & Michael Rideout", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "55" }, - { "13448eb5ba575e8d7b8d5b280ea6788f", "Digivision", "", "Crackpots (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1345e972dbe08ea3e70850902e20e1a5", "Greg Troutman", "", "Dark Mage (rough beta) (Greg Troutman) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "1351c67b42770c1bd758c3e42f553fea", "Digivision", "", "Keystone Kapers (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "135708b9a7dd20576c1b66ab2a41860d", "", "", "Hangman Man Biglist1 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "13584411da0a8d431991035423fdc0dc", "Jone Yuan Telephonic Enterprise Co", "", "Skiing (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1367e41858be525710eb04d0dab53505", "Kyle Pittman", "", "Zelda (2003) (Kyle Pittman) (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "136f75c4dd02c29283752b7e5799f978", "Atari, Dan Hitchens - Sears", "CX2650 - 49-75168", "Berzerk (1982) (Atari)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "13895ef15610af0d0f89d588f376b3fe", "Tigervision, Rorke Weigandt", "7-005", "Marauder (1982) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "13a37cf8170a3a34ce311b89bde82032", "Atari - GCC, Mark Ackerman, Tom Calderwood, Glenn Parker", "CX2684, CX2684P", "Galaxian (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "13a991bc9c2ff03753aeb322d3e3e2e5", "Funvision - Fund. International Co.", "", "Galactic (Funvision) (PAL)", "AKA Condor Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "13aa1f9ac4249947e4af61319d9a08f2", "Atari - GCC", "CX2680, CX2680P", "RealSports Tennis (1983) (Atari) (PAL) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "13abc32f803165c458bb086fa57195fb", "Christian Samuel", "", "E.T. The Extra-Testical (Christian Samuel) (Hack)", "Hack of E.T. The Extra-Terrestrial", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "13ccc692f111d52fec75d83df16192e2", "Canal 3 - Intellivision", "", "Fishing Derby (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "13d8326bf5648db4dafce45d25e62ddd", "", "", "Atari Logo Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "13dfb095e519a555a5b60b7d9d7169f9", "", "", "Red Line Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "140909d204abd6841c64cdad4d7765b4", "", "", "Moving Blue Ladder Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "14163eb2a3ddd35576bd8527eae3b45e", "", "", "Multi-Color Demo 6 (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1423f560062c4f3c669d55891a2bcbe7", "CCE", "C-859", "MASH (1983) (CCE) [a]", "AKA M.A.S.H", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1428029e762797069ad795ce7c6a1a93", "", "", "Thunderground (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "143918368f4f4dfff90999188c0197c9", "", "", "Unknown Title (bin00016 (200110)) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1442d1b35a6478fba22ae7dd1fcb5634", "Thomas Jentzsch", "", "Thrust (V0.2) (2000) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "148471144ccebd7f6aa9aa9215896533", "Parker Brothers - JWDA, Todd Marshall", "PB5550", "Q-bert's Qubes (1984) (Parker Bros) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "149b543c917c180a1b02d33c12415206", "CCE", "C-857", "Superman (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "14a56b493a8d9d10e94a3e100362e3a2", "Hozer Video Games", "", "Gunfight 2600 - Early Play-kernel (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "14b1e30982962c72f426e2e763eb4274", "Atari, Carol Shaw - Ralph Lauren", "", "Polo (1978) (Atari) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "14c2548712099c220964d7f044c59fd9", "First Star Software, Alex Leavens, Shirley Ann Russell", "", "Boing! (1983) (First Star Software)", "AKA Bubbles, Soap Suds, The Emphysema Game", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "14d365bbfaac3d20c6119591f57acca4", "", "", "Video Life (Unknown) (4K) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "14dbb3686dd31964332dc2ef0c55cad0", "", "", "Demo Image Series #15 - Three Marios (PAL) (Non-Interleave) (06-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "151c33a71b99e6bcffb34b43c6f0ec23", "Parker Brothers, Laura Nikolich", "", "Care Bears (1983) (Parker Bros) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "151fa3218d8d7600114eb5bcd79c85cb", "Atari - CCW, Christopher H. Omarzu", "CX26104", "Big Bird's Egg Catch (05-02-1983) (Atari) (Prototype)", "Uses the Keypad Controller", "Prototype", "", "", "", "", "", "", "", "KEYBOARD", "", "", "", "", "", "", "" }, - { "152c253478b009c275e18cd731b48561", "", "", "Quest (11-10-2002) (Chris Larkin)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "153f40e335e5cb90f5ce02e54934ab62", "Absolute Entertainment, Alex DeMeo", "EAZ-041-04I", "Title Match Pro Wrestling (1987) (Absolute) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1542662f665d2ffaa77b4b897dd2e2af", "", "", "Starfield (V1.0) (2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "155fa7f479dcba3b10b1494e236d6010", "Skyworks", "", "Tomcat (2002) (Skyworks) (PAL)", "AKA The F-14 Flight Simulator", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "157356f80c709ab675961d8b8b207e20", "", "", "Multi-Sprite Game V2.5 (Piero Cavina) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "157bddb7192754a45372be196797f284", "Atari, Warren Robinett - Sears", "CX2613, 49-75154", "Adventure (1980) (Atari)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "159e5cd6ccb968015f49aed5adbc91eb", "Justin J. Scott", "", "Yar's Defeat (2002) (Justin J. Scott) (Hack)", "Hack of Yars' Revenge", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "15a0d59304dece2c7d0580f3ea3527f0", "Atari, Jerome Domurat, Peter C. Niday", "CX26115", "Dumbo's Flying Circus (04-04-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "15b498199ed0ed28057bf0dbdce9b8d8", "Thomas Jentzsch", "", "Jammed (V0.2) (Demo) (2001) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "15b9f5e2439bfaa08874b5184261c777", "Bit Corporation", "R320", "Space Invaders (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "15bcd74f2f1f2a63e1aa93e90d2c0555", "", "", "Incoming (22-08-2002) (Ben Larson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "15bf2ef7583bfcbbba630847a1dc5539", "Erik Eid", "", "Euchre (Jul 15) (2002) (Eric Eid) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "15c11ab6e4502b2010b18366133fc322", "Atari - Axlon, Tod Frye - Heuristica, Augustin Ortiz", "CX26169", "Shooting Arcade (09-19-1989) (Atari) (Prototype)", "Uses the Light Gun Controller (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "15dd21c2608e0d7d9f54c0d3f08cca1f", "Data Age, J. Ray Dettling", "112-008", "Frankenstein's Monster (1983) (Data Age)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "15fe28d0c8893be9223e8cb2d032e557", "", "", "Towering Inferno (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "1619bc27632f9148d8480cd813aa74c3", "Thomas Jentzsch", "", "Steeple Chase (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "A", "", "", "", "", "", "", "", "", "YES", "" }, - { "161ded4a85d3c78e44fffd40426f537f", "Thomas Jentzsch", "", "JtzBall (Alpha) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "163e7e757e2dc44469123ff0e5daec5e", "", "", "Many Blue Bars and Text Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "169d4c7bd3a4d09e184a3b993823d048", "", "", "Superman (Unknown) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "16cb43492987d2f32b423817cdaaf7c4", "Atari, Larry Kaplan - Sears", "CX2602 - 99802, 6-99802, 49-75102", "Air-Sea Battle (1977) (Atari)", "AKA Target Fun (Anti-Aircraft)", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "16cc6d1b4ddce51c767a1ba8e5ff196c", "", "", "Big - Move This Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "16d69f71bf5846639be5ff16483f0498", "Bit Corporation", "R320", "Golf (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "16e04823887c547dc24bc70dff693df4", "Atari", "CX26163P", "Tennis (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "16ee443c990215f61f7dd1e55a0d2256", "Spectravideo, David Lubar", "SA-218, SA-218C", "Bumper Bash (1983) (Spectravideo) (PAL)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "PADDLES", "", "", "", "", "", "", "" }, - { "16f494f20af5dc803bc35939ef924020", "Mark De Smet", "", "Video Simon (Mark De Smet)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "170e7589a48739cfb9cc782cbb0fe25a", "M Network - INTV - APh Technological Consulting, Hal Finney", "MT5666", "Astroblast (1982) (M Network) [fixed]", "Can also use left joystick", "Uncommon", "", "", "", "", "", "", "", "PADDLES", "", "YES", "AUTO 55", "", "", "", "" }, - { "171cd6b55267573e6a9c2921fb720794", "Kurt Howe", "", "Adventure 34 (Kurt Howe) (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "171ebf135b13ba907f462c10d88a2c25", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Amiga Mouse Hack v1.1 (PAL60) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1733772165d7b886a94e2b4ed0f74ccd", "", "", "Boring Journey Escape (Hack)", "Hack of Journey - Escape", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1738b2e3f25ab3eef3cecb95e1d0d957", "", "", "Hangman Monkey Biglist1 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "17512d0c38f448712f49f36f9d185c4e", "Retroactive", "", "Qb (Release Candidate #1) (Retroactive)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "17515a4d0b7ea5029ffff7dfa8456671", "Piero Cavina", "", "Multi-Sprite Demo V1.1 (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "176d3fba7d687f2b23158098e103c34a", "Zach Matley", "", "Combat AI (16-02-2003) (Zach Matley)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "177504abd4260c4265e1338955e9fa47", "HCC Software", "", "Pitfall! (Steroids Hack)", "Hack of Pitfall! (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1782929e1c214b70fb6884f77c207a55", "Activision, David Crane", "AX-018, AX-018-04", "Pitfall! (1982) (Activision) (Prototype)", "Pitfall Harry's Jungle Adventure (Jungle Runner)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "17ba72433dd41383065d4aa6dedb3d91", "", "", "SCSIcide (09-06-2001) (Joe Grand)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "17badbb3f54d1fc01ee68726882f26a6", "M Network - INTV - APh Technological Consulting, Hal Finney, Bruce Pedersen", "MT5659", "Space Attack (1982) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "17bbe288c3855c235950fea91c9504e9", "Dismac", "", "Pega Ladrao (Dismac)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "17c0a63f9a680e7a61beba81692d9297", "U.S. Games Corporation - Western Technologies, Jeff Corsiglia, David Johnson, Tom Sloper", "VC2004", "Picnic (1983) (U.S. Games)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "AUTO 45", "", "", "", "" }, - { "17d000a2882f9fdaa8b4a391ad367f00", "Atari - GCC", "CX2676", "Centipede (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "17ee158d15e4a34f57a837bc1ce2b0ce", "Atari - GCC, Mike Feinstein, Kevin Osborn", "CX2691, CX2691P", "Joust (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "17ee23e5da931be82f733917adcb6386", "Salu, Dennis M. Kiss", "460758", "Acid Drop (1992) (Salu) (PAL)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1802cc46b879b229272501998c5de04f", "Atari - CCW, Christopher H. Omarzu", "CX26104", "Big Bird's Egg Catch (1983) (Atari)", "Uses Kids/Keypad Controllers", "Rare", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "" }, - { "183020a80848e06a1238a1ab74079d52", "Thomas Jentzsch", "", "Missile Command (Amiga Mouse) (2002) (TJ) (PAL)", "Uses Amiga Mouse Controller", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "1862fca4f98e66f363308b859b5863af", "Atari", "", "128-in-1 Junior Console (Chip 1 of 4) (1991) (Atari) (PAL)", "Actually contains only 16 games, not 32", "", "", "", "16IN1", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "18a970bea7ac4d29707c8d5cd559d03a", "", "", "Bridge (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "18b28b386abdadb3a700ac8fb68e639a", "Manuel Polik", "", "Gunfight 2600 (MP) (PAL)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "18b476a34ce5e6db2c032029873ac39b", "Bit Corporation", "R320", "Atlantis (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "18be8981b8201638f3ed8ae92bb4c215", "Thomas Jentzsch", "", "Missile Control - Amiga Mouse Hack v1.15 (PAL60) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "18bebbbd41c234f82b1717b1905e6027", "", "", "Space Instigators (Public Release) (02-01-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "18d26111cef66dff0c8af8cf0e117843", "", "", "Tunnel Demo (Cycling Colours 2) (29-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "18dc28bc22402f21e1c9b81344b3b8c5", "Atari - GCC, Mark Ackerman, Glenn Parker", "CX2684, CX2684P", "Galaxian (1983) (Atari) (PAL) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "18ed63e3ce5bc3dd2d8bd188b807f1a2", "", "", "Stell-A-Sketch (Bob Colbert) (PD) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "18f299edb5ba709a64c80c8c9cec24f2", "Home Vision - Gem International Corp. - VDI", "VCS83111", "Asteroid Fire (1983) (Home Vision) (PAL)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "19098c46da0640f2b5763167dea6c716", "Andrew Wallace", "", "Laseresal 2002 (NTSC) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "191449e40b0c56411c70772706f79224", "", "", "Multi-Color Demo 2 (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "19162393786098d50587827588198a86", "Jone Yuan Telephonic Enterprise Co", "", "Flag Capture (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "191ac4eec767358ee3ec3756c120423a", "", "", "Checkers (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "192aa2e8c795c9e10a7913e5d41feb81", "Atari - GCC, Jaques Hugon, Seth Lipkin", "CX26125", "Los Angeles 1984 Games (1984) (Atari) (Prototype) (PAL)", "AKA Track and Field (Uses Track & Field Controller)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "193f060553ba0a2a2676f91d9ec0c555", "Atari, Carol Shaw", "CX2636, CX2636P", "Video Checkers (1980) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1942bdb7abc75e412068330a9082b0ff", "Atari, Omegamatrix", "", "Super Breakout Menu (2020) (PAL) (Hack)", "Hack of Super Breakout", "", "", "", "", "", "", "", "", "", "", "", "AUTO 55", "", "", "", "" }, - { "1986f864e32e3e8d198b5becf3022257", "Thomas Jentzsch", "", "Reactor - Atari Trak-Ball Hack v1.3 (PAL) (Half-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "199985cae1c0123ab1aef921daace8be", "", "", "Euchre (Release Candidate 2) (PAL) (01-10-2002) (Erik Eid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "199eb0b8dce1408f3f7d46411b715ca9", "Parker Brothers, David Lamkins, Laura Nikolich", "PB5900", "Spider-Man (1982) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "19a9d3f9fa1b1358fb53009444247aaf", "", "", "Blackjack (Unknown) (PAL) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "", "", "" }, - { "19abaf2144b6a7b281c4112cff154904", "Atari, Brad Stewart", "CX2649, CX2649P", "Asteroids (1981) (Atari) (PAL) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "19b3b807507653516985ba95da92499d", "Joe Gaucher", "", "VCS Draw Demo (Joe Gaucher)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "19d6956ff17a959c48fcd8f4706a848d", "PlayAround - J.H.M.", "202", "Burning Desire (1982) (PlayAround)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "19d9b5f8428947eae6f8e97c7f33bf44", "", "", "Fortress (Dual Version) (20-04-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "19e739c2764a5ab9ed08f9095aa2af0b", "Atari, Andrew Fuchs, Jeffrey Gusman, Dave Jolly, Suki Lee", "CX26117", "Obelix (1984) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "19e761e53e5ec8e9f2fceea62715ca06", "Panda", "104", "Scuba Diver (1983) (Panda)", "AKA Skindiver", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1a23540d91f87584a04f184304a00648", "", "", "Race Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1a613ce60fc834d4970e1e674b9196b3", "Home Vision - Gem International Corp. - VDI", "VCS83135", "Tanks War (1983) (Home Vision) (PAL)", "AKA Phantom Tank", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1a624e236526c4c8f31175e9c89b2a22", "Rainbow Vision - Suntek", "SS-007", "Space Raid (1983) (Rainbow Vision) (PAL) [a]", "AKA MegaMania", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1a8204a2bcd793f539168773d9ad6230", "Atari, Rob Fulop - Sears", "CX2638 - 49-75166", "Missile Command (1981) (Atari) [no initials]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1aa7344b563c597eecfbfcf8e7093c27", "David Marli", "", "Slot Invaders (David Marli) (Hack)", "Hack of Slot Machine", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1b0f3d7af668eeea38ddd6182d8f48fb", "Jone Yuan Telephonic Enterprise Co", "", "Cosmic Swarm (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "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]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1bc2427ac9b032a52fe527c7b26ce22c", "Intellivision Productions - M Network - APh Technological Consulting, Bruce Pedersen, Larry Zwick", "MT5860", "Sea Battle (1983) (M Network)", "High Seas", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1bef389e3dd2d4ca4f2f60d42c932509", "Dimax - Sinmax", "SM8001", "Space Robot (1983) (Dimax - Sinmax) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "1bf503c724001b09be79c515ecfcbd03", "", "", "Bumper Bash (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1bfae770e089fa81412d04eb299f4c3f", "Thomas Jentzsch", "", "Marble Craze - Atari Mouse Hack v1.0 (NTSC) (TJ)", "Uses Atari Mouse Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1c3f3133a3e5b023c77ecba94fd65995", "CCE", "C-830", "Planet Patrol (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1c5796d277d9e4df3f6648f7012884c4", "Rainbow Vision - Suntek", "SS-012", "Hey! Stop! (1983) (Rainbow Vision) (PAL)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1c666ba5aac19b81671357e76062989b", "Nukey Shay, Omegamatrix", "", "Double Dragon (Genesis) (PAL60) V2", "Genesis controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1c6eb740d3c485766cade566abab8208", "Atari, Michael Kosaka, Peter C. Niday, Robert Vieira", "CX26110", "Crystal Castles (1984) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1c85c0fc480bbd69dc301591b6ecb422", "CCE", "", "Super Box (CCE)", "AKA RealSports Boxing", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1c8c42d1aee5010b30e7f1992d69216e", "PlayAround - J.H.M.", "205", "Gigolo (1982) (PlayAround)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "1cad3b56cc0e6e858554e46d08952861", "Jone Yuan Telephonic Enterprise Co", "", "Chopper Command (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1cafa9f3f9a2fce4af6e4b85a2bbd254", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX2659", "Raiders of the Lost Ark (1982) (Atari) (PAL)", "Console ports are swapped", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "" }, - { "1cca2197d95c5a41f2add49a13738055", "Atari, Larry Kaplan - Sears", "CX2664 - 6-99818", "Brain Games (1978) (Atari)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "" }, - { "1cf59fc7b11cdbcefe931e41641772f6", "SEGA", "005-01", "Buck Rogers - Planet of Zoom (1983) (SEGA)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "1d1d2603ec139867c1d1f5ddf83093f1", "Atari, Larry Kaplan - Sears", "CX2602 - 99802, 6-99802, 49-75102", "Air-Sea Battle (1977) (Atari) (4K)", "AKA Target Fun (Anti-Aircraft)", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1d284d6a3f850bafb25635a12b316f3d", "CCE", "", "H.E.R.O. (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1d2a28eb8c95da0d6d6b18294211839f", "", "", "Fishing Derby (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1d4e0a034ad1275bc4d75165ae236105", "20th Century Fox Video Games, Mark Klein", "11034", "Pick Up (1983) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1d5eac85e67b8cff1377c8dba1136929", "", "", "Chronocolor Donkey Kong Sideways (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1d6ed6fe9dfbde32708e8353548cbb80", "Jone Yuan Telephonic Enterprise Co", "", "Super Challenge Baseball (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1d72cc6ee466a4af1b27587b900ed430", "Atari, Omegamatrix", "", "Space Invaders Menu (2020) (Hack)", "Hack of Space Invaders", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1da2da7974d2ca73a823523f82f517b3", "Spectravision - Spectravideo - Sirius Software, David Lubar", "SA-206", "Challenge of.... Nexar, The (1982) (Spectravision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1db3bc4601f22cf43be7ce015d74f59a", "", "", "Ship Demo (V 10) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1e060a8025512ad2127e3da11e212ccc", "Arcadia Corporation, Scott Nelson", "13", "Sweat! - The Decathlon Game (3 of 3) (1983) (Arcadia) (Prototype)", "Uses the Paddle Controllers (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1e0ef01e330e5b91387f75f700ccaf8f", "Quelle - Otto Versand", "686.561 2 - 781627", "Mein Weg (1983) (Quelle) (PAL)", "AKA Challenge", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "1e1290ea102e12d7ac52820961457e2b", "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart", "PB5540", "Star Wars - The Arcade Game (12-15-1983) (Parker Bros) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "1e272d09c0e55f5ef14fcb76a735f6d7", "Atari, David Crane", "CX26163P", "Slot Machine (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1e31b3a48865ba98d4d1aa5205115983", "Atari - Roklan, Bob Curtiss", "", "Firefox (1983) (Atari) (Prototype)", "AKA Combat II, Fighter Command", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1e587ca91518a47753a28217cd4fd586", "Telesys, Jim Rupp, Jack Woodman", "1001", "Coco Nuts (1982) (Telesys)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1e750000af77cc76232f4d040f4ab060", "Jone Yuan Telephonic Enterprise Co", "", "Raft Rider (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1e85f8bccb4b866d4daa9fcf89306474", "Atari, Lou Harp", "CX26122", "Sinistar (02-13-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1e89f722494608d6ea15a00d99f81337", "", "", "River Raid (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "NTSC50", "", "", "" }, - { "1ea1abcd2d3d3d628f59a99a9d41b13b", "Jone Yuan Telephonic Enterprise Co", "", "Stampede (Jone Yuan) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1ea980574416bfd504f62575ba524005", "Atari - GCC, Mark Ackerman, Glenn Parker", "CX2675", "Ms. Pac-Man (1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1ec57bbd27bdbd08b60c391c4895c1cf", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX26119", "Saboteur (09-02-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1ec5bef77b91e59313cba205f15b06d7", "", "", "Overhead Adventure Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1ede4f365ce1386d58f121b15a775e24", "Parker Brothers, Dave Hampton, Tom Sloper", "931517", "Q-bert (1983) (Parker Bros) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1ee2cfc7d0333b96bd11f7f3ec8ce8bc", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (4 of 4) (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1ee9c1ba95cef2cf987d63f176c54ac3", "Atari - GCC, Mark Ackerman, Glenn Parker", "CX2675, CX2675P", "Ms. Pac-Man (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1ef04e7e508296a8d9eb61cc7dae2e5d", "SOLID Corp. (D. Scott Williamson)", "CX2655-069", "Star Castle 2600 (SolidCorp) [069]", "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "1f21666b8f78b65051b7a609f1d48608", "K-Tel Vision", "", "Vulture Attack (1982) (K-Tel Vision)", "AKA Condor Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1f2ae0c70a04c980c838c2cdc412cf45", "Atari - GCC", "CX2698", "Rubik's Cube (1984) (Atari)", "AKA Atari Video Cube", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1f349dd41c3f93c4214e5e308dccb056", "", "", "Virtual Pet Demo 2 (CRACKERS) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1f40eefc7447336ae6cd8ffa5eb325be", "Atari, Chris Crawford", "", "Wizard (1980) (Atari) (Prototype) (4K) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1f562b89d081e36d58e6fc943512ec05", "", "", "Hangman Man Biglist2 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1f5a2927a0b2faf87540b01d9d7d7fd1", "Pet Boat", "", "Tennis (Pet Boat) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1f60e48ad98b659a05ce0c1a8e999ad9", "", "", "Mondo Pong V2 (Piero Cavina) (PD)", "Uses the Paddle Controllers", "New Release", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "01", "", "", "", "" }, - { "1f773a94d919b2a3c647172bbb97f6b4", "Atari, Jerome Domurat, Peter C. Niday", "CX26115", "Dumbo's Flying Circus (07-11-1983) (Atari) (Prototype) (PAL)", "AKA Dumbo Flies Home", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1fa58679d4a39052bd9db059e8cda4ad", "Imagic, Dan Oliver", "720118-1A, 03208", "Laser Gates (1983) (Imagic)", "AKA Innerspace", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1fa7a42c2c7d6b7a0c6a05d38c7508f4", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (09-04-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "1fa86282403fa35d103ab88a9d603c31", "SpiceWare - Darrell Spice Jr.", "", "Stay Frosty (SpiceWare) (PAL60)", "Part of Stella's Stocking 2007 Xmas compilation", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "1fab68fd67fe5a86b2c0a9227a59bb95", "20th Century Fox Video Games - Videa, Lee Actor", "", "Lasercade (1983) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "200309c8fba0f248c13751ed4fc69bab", "Jeffry Johnston", "", "Radial Pong - Version 1 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2008c76deba5953201ef75a09b2ff7dc", "", "", "Fortress (21-04-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "200a9d2a7cb4441ce4f002df6aa47e38", "", "", "Doomzerk (PD) (Hack)", "Hack of Berzerk", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2016726db38ad6a68b4c48ba6fe51557", "Piero Cavina, Erik Mooney", "", "INV 2 (Piero Cavina, Erik Mooney)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "203049f4d8290bb4521cc4402415e737", "Tigervision, Robert H. O'Neil - Teldec", "7-007 - 3.60005 VG", "Polaris (1983) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "203abb713c00b0884206dcc656caa48f", "Imagic, Bob Smith", "720114-1A, 03207, IZ-001-04", "Moonsweeper (1983) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "203b1efc6101d4b9d83bb6cc1c71f67f", "Quelle", "685.996 1", "Teller-Jonglieren! (1983) (Quelle) (PAL)", "AKA Dancing Plate", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "205070b6a0d454961dd9196a8e81d877", "", "", "Hangman Monkey Biglist2 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2058cf3fefad4d2bc03ed817cedddcd4", "Thomas Jentzsch", "", "Reactor - Amiga Mouse Hack v1.3 (PAL60) (Full-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2091af29b4e7b86914d79d9aaa4cbd20", "CBS Electronics - Woodside Design Associates, Harley H. Puthuff Jr.", "4L1802", "Donkey Kong Junior (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "20ae62fb69c6cc6e8098cca8cd080487", "Zirok", "", "Tennis (Zirok)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "20d4457ba22517253fcb62967af11b37", "Atari, Eric Manghise, Mimi Nyden, Joseph Tung", "CX2640", "RealSports Baseball (1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "20dca534b997bf607d658e77fbb3c0ee", "Mythicon, Bill Bryner, Bruce de Graaf", "MA1002", "Fire Fly (1983) (Mythicon)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "20edcc3aa6c189259fa7e2f044a99c49", "Spectravision - Spectravideo", "SA-201", "Gangster Alley (1982) (Spectravision) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "211774f4c5739042618be8ff67351177", "Atari - GCC, Mark Ackerman, Tom Calderwood, Glenn Parker", "CX2684", "Galaxian (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "211f76dff0b7dad3f6fcac9d938ee61a", "JSK", "", "Custer's Viagra (JSK) (Hack) [a]", "Hack of Custer's Revenge", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "211fbbdbbca1102dc5b43dc8157c09b3", "Apollo", "AP-2009", "Final Approach (1982) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2124cf92978c46684b6c39ccc2e33713", "", "", "Sea Monster (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "21299c8c3ac1d54f8289d88702a738fd", "K-Tel Vision", "", "Spider Maze (1982) (K-Tel Vision)", "AKA Spider Kong", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "212d0b200ed8b45d8795ad899734d7d7", "Atari, Richard Maurer, Christopher H. Omarzu - Coca Cola", "", "Pepsi Invaders (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "213e5e82ecb42af237cfed8612c128ac", "Sancho - Tang's Electronic Co.", "TEC006", "Forest (1983) (Sancho) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "2162266b906c939b35c84ff9a0f50ad1", "Atari, Larry Kaplan", "CX2664, CX2664P", "Brain Games (1978) (Atari) (PAL) (4K)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "" }, - { "2179dfd7edee76efafe698c1bc763735", "", "", "Yellow Submarine (Cody Pittman) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "217b1452881264ac75126bf77b8d0db8", "Thomas Jentzsch", "", "Centipede - Atari Trak-Ball Hack v1.4 (NTSC) (Full-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "218b76f5a4142dc2ea9051a768583d70", "Atari - GCC, Mark Ackerman, Glenn Parker", "CX2684, CX2684P", "Galaxian (1983) (Atari) (PAL) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "218c0fe53dfaaa37f3c823f66eafd3fc", "Atari, Alan Miller", "CX2624, CX2624P", "Basketball (1978) (Atari) (PAL)", "Console ports are swapped", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "" }, - { "21a96301bb0df27fde2e7eefa49e0397", "Data Age", "DA1003", "Sssnake (1982) (Data Age)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "21b09c40295c2d7074a83ae040f22edf", "", "", "Marble Craze (V0.90) (Easy Version) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "21d2c435bcccde7792d82844b3cf60f4", "Atari - GCC, Doug Macrae", "CX2677, CX2677P", "Dig Dug (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "21d7334e406c2407e69dbddd7cec3583", "Activision, Bob Whitehead", "AG-011", "Stampede (1981) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2228c67d25e507603d4873d3934f0757", "", "", "Fu Kung! (V0.10) (28-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "22319be7a640af5314ec3c482cceb676", "", "", "Joustpong (05-07-2002) (Kirk Israel) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2240655247d6de1c585564004a853ab7", "", "", "Fu Kung! (V0.17) (07-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "225522777dc7155627808bde0c1d0ef0", "", "", "This Planet Sucks Demo 1 (Greg Troutman) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "22675cacd9b71dea21800cbf8597f000", "Atari, David Crane", "CX2605, CX2605P", "Outlaw (1978) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "227532d82505c3c185a878273c285d5f", "", "", "Hangman Man Original Words (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "22abbdcb094d014388d529352abe9b4b", "Apollo", "AP-2012", "Squoosh (1983) (Apollo) (Prototype) [a]", "AKA Vat's Incredible!, The Grape Escape", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "22b22c4ce240303012e8a9596ae8d189", "", "", "Skeleton+ (03-05-2003) (Eric Ball) (PAL)", "", "", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "22f6b40fc82110d68e50a1208ae0bb97", "", "", "Purple Bar Demo (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2319922df4d0c820b3e5f15faa870cc3", "Atari - GCC, Mike Feinstein", "CX2681, CX2681P", "Battlezone (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2327456f86d7e0deda94758c518d05b3", "Digitel", "", "Mr. Postman (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2351d26d0bfdee3095bec9c05cbcf7b0", "", "", "Warring Worms (19-01-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2353725ec98e0f0073462109e886efd7", "Champ Games", "CG-03-P", "Scramble (PAL60)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "JOYSTICK", "", "", "", "", "", "YES", "" }, - { "235436ab0832370e73677c9c6f0c8b06", "", "", "Beast Invaders (Double Shot) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2365e1534d67f94d8670394ab99150ce", "Thomas Jentzsch", "", "Missile Command (Atari Mouse) (2002) (TJ)", "Uses Atari ST Mouse Controller", "Homebrew", "", "", "", "", "", "", "", "ATARIMOUSE", "ATARIMOUSE", "", "", "", "", "YES", "" }, - { "23d445ea19a18fb78d5035878d9fb649", "CBS Electronics - JWDA, Sylvia Day, Todd Marshall, Henry Will IV", "4L1818, 4L1819, 4L1820, 4L1821", "Mouse Trap (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "23e4ca038aba11982e1694559f3be10f", "", "", "Big Dig (V3) (20-10-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "23fad5a125bcd4463701c8ad8a0043a9", "CCE", "C-840", "Stone Age (1983) (CCE)", "Uses the Joystick Controllers (swapped)", "", "", "", "", "A", "A", "", "YES", "", "", "", "", "", "", "YES", "" }, - { "240bfbac5163af4df5ae713985386f92", "Activision, Steve Cartwright", "AX-022", "Seaquest (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2432f33fd278dea5fe6ae94073627fcc", "CBS Electronics, Tom DiDomenico", "4L2477, 4L2482, 4L2485, 4L4171", "Blueprint (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "2434102f30eeb47792cf0825e368229b", "Sparrow - Enter-Tech, Paul Walters, Rick Harris, George Hefner, Barbara Ultis", "", "Arkyology (1983) (Sparrow) (Prototype)", "ROM must be started in bank 0", "Prototype", "", "0", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "24385ba7f5109fbe76aadc0a375de573", "CCE", "", "Xevious (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "2447e17a4e18e6b609de498fe4ab52ba", "CCE", "", "Super Futebol (CCE)", "AKA RealSports Soccer", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "244c6de27faff527886fc7699a41c3be", "", "", "Matt Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2450dfa1df70d12b60683185775efed8", "Jeffry Johnston", "", "Radial Pong - Version 7 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "24544ee5d76f579992d9522e9b238955", "Carrere Video - Western Technologies, Jeff Corsiglia, David Johnson, Tom Sloper - Teldec - Prism", "USC2004", "Picnic (1983) (Carrere Video) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "AUTO 45", "", "", "", "" }, - { "245f07c8603077a0caf5f83ee6cf8b43", "Home Vision - Thomas Jentzsch", "", "Parachute (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "24759be31e8fe55d2829fd86bdf3181f", "Hozer Video Games", "", "Gunfight 2600 - Worst Nightmare... (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "247fa1a29ad90e64069ee13d96fea6d6", "CCE", "C-867", "Radar (1983) (CCE)", "AKA Exocet", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "248668b364514de590382a7eda2c9834", "CBS Electronics, Richard K. Balaska Jr., Bob Curtiss, Alex Leavens, Alex Nevelson", "", "Kick-Man (01-08-82) (CBS Electronics) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2496d404bfc561a40a80bea6a69695c3", "CCE", "C-1007", "Jungle Hunt (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "24ad538291eb5f5cac4b9998f3b851c3", "", "", "Gunfight 2600 - This time it's your decission! (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "24aff972d58990f9b88a6d787c796f1e", "CBS Electronics", "4L1767, 4L1768, 4L1769, 4L1770", "Smurf (1982) (CBS Electronics) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "24b5f4bbdb853eca38ea0cae2dfe73a1", "", "", "Home Run (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "" }, - { "24b9adac1b4f85b0bac9bf9b9e180906", "Angelino", "", "Space 2002 (Angelino) (Hack)", "Hack of Space Jockey", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "24d018c4a6de7e5bd19a36f2b879b335", "Activision, Larry Miller", "AX-021", "Spider Fighter (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "24d9a55d8f0633e886a1b33ee1e0e797", "Thomas Jentzsch", "", "Dragon Defender (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "24df052902aa9de21c2b2525eb84a255", "Imagic, Dennis Koble", "720000-100, 720100-1B, IA3000, IA3000C", "Trick Shot (1982) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "24fbf8250a71611e40ef18552e61b009", "", "", "Movable Grid Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2516f4f4b811ede4ecf6fbeb5d54a299", "Quelle", "701.134 9", "Schiessbude (1983) (Quelle) (PAL)", "AKA Carnival", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2517827950fee41a3b9de60275c8aa6a", "Atari", "CX26163P", "Fishing (32 in 1) (1988) (Atari) (PAL)", "AKA Fishing Derby", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "25265d0e7f88b3026003809f25ee025e", "Atari - GCC, Ava-Robin Cohen", "CX26123", "Jr. Pac-Man (1984) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "25472dfdeef6a42581a231d631d6b04d", "", "", "Gunfight 2600 - Design thoughts (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "25710bde8fa181b0c5cf0846b983bec1", "", "", "Demo Image Series #15 - Three Marios (NTSC) (06-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "257bc3b72a6b5db3fd0d47619125b387", "CBS Electronics", "4L 2737 0000", "Omega Race (1983) (CBS Electronics) [a]", "Set right difficulty to 'A' for BoosterGrip in both ports", "", "", "", "", "", "", "", "", "BOOSTERGRIP", "BOOSTERGRIP", "", "", "", "", "", "" }, - { "25a21c47afe925a3ca0806876a2b4f3f", "Quelle", "685.640 5", "Der kleine Baer (1983) (Quelle) (PAL)", "AKA Frostbite", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "25b52bf8dd215bcbd59c9abdb55c44f8", "Atari - GCC, Betty Ryan Tylko, Doug Macrae", "CX2694, CX2694P", "Pole Position (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "25b6dc012cdba63704ea9535c6987beb", "Avalon Hill, Jean Baer, Bill Hood", "5004002", "Shuttle Orbiter (1983) (Avalon Hill)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "25bb080457351be724aac8a02021aa92", "CBS Electronics", "4L1784, 4L1786, 4L1787, 4L2277", "Zaxxon (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "25d4be3309b89583c6b39d9f93bf654f", "Activision, Bob Whitehead", "AX-015, AX-015-04", "Chopper Command (1982) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "25e73efb9a6edf119114718bd2f646ba", "Atari, Suki Lee", "CX26113", "Miss Piggy's Wedding (1983) (Atari) (Prototype) (4K) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "25f2e760cd7f56b88aac88d63757d41b", "Activision, Bob Whitehead - Ariola", "EAG-002, EAG-002-04I, PAG-002 - 711 002-715", "Boxing (1980) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "25f879ff678130fea615ac418e7943f1", "Activision, Garry Kitchen", "EAX-025", "Keystone Kapers (1983) (Activision) (SECAM)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "25f9cf703575c5d63048c222f5463758", "", "", "Multi-Sprite Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "260c787e8925bf3649c8aeae5b97dcc0", "Thomas Jentzsch", "", "Hell Driver (Thomas Jentzsch)", "NTSC Conversion, joystick ports swapped", "Homebrew", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "" }, - { "262ccb882ff617d9b4b51f24aee02cbe", "Atari, Douglas Neubauer", "CX26154, CX26154P", "Super Football (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "265a85f66544eaf95fda06c3d9e48abf", "", "", "Tunnel Demo (Cycling Colours) (29-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "265c74a956500bd31efd24adc6d5ccf6", "Activision, Larry Miller", "AX-026, AX-026-04", "Enduro (1983) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2683d29a282dd059535ac3bb250f540d", "", "", "Space Treat (12-01-2003) (Fabrizio Zavagli)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "268f46038e29301568fa9e443e16e960", "Atarius Maximum", "", "Pitfall Unlimited (Atarius Maximus) (Hack)", "Hack of Pitfall", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "26bc2bdf447a17376aea7ef187ff6e44", "", "", "Amanda Invaders (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "26f4f8b098609164effef7809e0121e1", "", "", "Oystron (V2.7) (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "270229c6d5578446e6a588492e4e5910", "", "", "Space Invaders 2 (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2712e91f6f1dc55e90e2b14b27c042ac", "Omegamatrix", "", "SpaceMaster X-7 (Amiga Mouse) (PAL60) (Omegamatrix)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "271bfd5dc2673d382019f1fb6cab9332", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (Preview) (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "273ce50db5a0d6da7ea827a54f44dee9", "", "", "Island Flyer Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "274d17ccd825ef9c728d68394b4569d2", "Playaround - J.H.M.", "202", "Bachelorette Party (1982) (Playaround)", "AKA Bachelor Party, Uses the paddle controllers", "Extremely Rare", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "AUTO 65", "", "", "YES", "" }, - { "277c7281ac945b8331e2e6fcad560c11", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (2 of 3) (1983) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "277cca62014fceebb46c549bac25a2e3", "Activision, Bob Whitehead", "AG-002, CAG-002, AG-002-04", "Boxing (1980) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "277fa4b9a6bb7a8dcea2c5f38a4c25f0", "Atari, Alan J. Murphy, Robert Zdybel", "CX2668", "RealSports Football (1982) (Atari) (Prototype)", "AKA Football II", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "278155fc9956e9b6ef2359eb238f7c7f", "", "", "Donkey Kong Junior (Unknown) (Hack)", "Hack of Donkey Kong Junior", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2783006ee6519f15cbc96adae031c9a9", "Telegames", "", "Night Stalker (1989) (Telegames) (PAL) [a]", "AKA Dark Cavern", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "278531cc31915747018d22145823d2c9", "", "", "Defender MegaDrive (PAL) (Genesis)", "Genesis controller (C is smartbomb)", "Hack of Defender", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "278f14887d601b5e5b620f1870bc09f6", "Thomas Jentzsch", "", "SWOOPS! (v0.96) (TJ)", "Uses the Joystick (L) and Paddle (R) Controllers", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "27a5d2d0c74c8e4b2c05b94c9f098eea", "Atari, Omegamatrix", "", "Video Olympics Menu (2020) (PAL60) (Hack)", "Hack of Video Olympics", "", "", "", "", "", "", "", "", "", "", "YES", "AUTO 60", "", "", "", "" }, - { "27baecd618e7e53dc11f2a9c559f529d", "Omegamatrix", "", "Star Wars Arcade (Atari Trak-Ball) v4 (Omegamatrix)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "27c4c2af4b46394bb98638af8e0f6e9d", "Atari, Jerome Domurat, Peter C. Niday, Robert Vieira", "CX26109", "Sorcerer's Apprentice (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "27c6a2ca16ad7d814626ceea62fa8fb4", "Parker Brothers, Mark Lesser", "PB5590", "Frogger II (1984) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "27f9e2e1b92af9dc17c6155605c38e49", "CCE", "", "Nightmare (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2808dc745ff4321dc5c8122abef6711f", "Retroactive", "", "Qb (2.11) (Retroactive) (Stella)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "28148a52b1955ce12c7a74d3a3e620a4", "CCE", "", "Freeway (CCE) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "281ff9bd0470643853de5cbd6d9e17f5", "Eckhard Stolberg", "", "Cubis (EM) (1997) (Eckhard Stolberg)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2823364702595feea24a3fbee138a243", "Bit Corporation", "PG206", "Bobby Is Going Home (1983) (BitCorp) (PAL)", "AKA Bobby geht Heim", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2825f4d068feba6973e61c84649489fe", "", "", "Boom Bang (Unknown) (PAL)", "AKA Crackpots", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "282a77841cb3d33af5b56151acba770e", "Otto Versand", "311388", "Black Hole (1983) (Otto Versand) (PAL)", "AKA Cosmic Ark (Double-Game Package)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "283cb03ee031c842beabdad1aa4e7dbc", "Bit Corporation", "R320", "Demon Attack (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "283dee88f295834c4c077d788f151125", "Retroactive", "", "Qb (2.11) (Retroactive) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "284ca61b2407bdba3938048b0a559015", "Atari, Tod Frye", "CX2695", "Xevious (05-25-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "2854e5dfb84173fafc5bf485c3e69d5a", "Canal 3 - Intellivision", "C 3004", "Moon Patrol (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2880c6b59bd54b153174676e465167c7", "Tron", "", "Donkey Kong Jr. (Tron)", "AKA Donkey Kong Junior", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "28a2bea8f84936cb2e063f857414cda0", "Thiago Paiva", "", "Mega Mania Raid (1999) (Thiago Paiva) (Hack)", "Hack of Megamania", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "28a4cd87fb9de4ee91693a38611cb53c", "", "", "Skeleton (V1.1) (NTSC) (24-10-2002) (Eric Ball)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "28d5df3ed036ed63d33a31d0d8b85c47", "Bit Corporation", "PG204", "Open, Sesame! (1983) (BitCorp) (PAL)", "AKA Sesam, Offne Dich", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "2903896d88a341511586d69fcfc20f7d", "Activision, David Crane", "AX-014, AX-014-04", "Grand Prix (1982) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "291bcdb05f2b37cdf9452d2bf08e0321", "Atari", "CX26163P", "32 in 1 Game Cartridge (1988) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "32IN1", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "291cc37604bc899e8e065c30153fc4b9", "Activision, Carol Shaw", "AX-020, AX-020-04", "River Raid (1982) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "291dd47588b9158beebe4accc3a093a6", "Atari", "", "32 in 1 Console ROM (02-10-1989) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "32IN1", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "292a0bb975b2587f9ac784c960e1b453", "", "", "Qb (05-02-2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "292f2446a0325b7b423e88a2ebfeb5a0", "", "", "Cube Conquest (Non Interlaced) (Billy Eno) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "29396db58406084e416032c372734a3e", "", "", "Gunfight 2600 - Fixed Beta Release! (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2942680c47beb9bf713a910706ffabfe", "", "", "Blue Line Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "294762000e853b4319f9991c1ced5dfc", "", "", "T.F. Space Invaders (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "295f3679bdf91ca5e37da3f787b29997", "", "", "Exorcise (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "29630a20d356fb58685b150bfa8f00c3", "M Network, Kevin Miller", "MT5687", "International Soccer (1982) (Mattel) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "297236cb9156be35679f83c4e38ee169", "Exus Corporation", "", "Video Reflex (1983) (Exus) [no roman numbers]", "AKA Foot Craz (no roman numbers)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "297c405afd01f3ac48cdb67b00d273fe", "Atari - GCC, Ava-Robin Cohen", "CX26123, CX26123P", "Jr. Pac-Man (1986) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2982e655dffc89d218a0a3072cfc6811", "", "", "Mini Golf 812631 (Hack)", "Hack of Miniature Golf", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "298387b0637173d2002770a649b4fbca", "", "", "S.I.PLIX 2 (Hack) [a]", "Hack of Kaboom!", "Hack", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, - { "29843f43b81f3736bf35c00b1bb88fb2", "Gray Games & AtariAge", "", "E.T. Book Cart (NTSC)", "Charles F. Gray & Michael Rideout", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "55" }, - { "29949f893ef6cb9e8ecb368b9e99eee4", "Erik Eid", "", "Euchre (Alpha) (NTSC) (31-08-2002) (Erik Eid)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "29dfa26b7988af9984d617708e4fc6e2", "", "", "Boulderdash Demo (05-04-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2a0ba55e56e7a596146fa729acf0e109", "Activision, Bob Whitehead", "AG-019", "Sky Jinks (1982) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2a10053fd08664c7cfbbb104386ed77f", "", "", "Alpha Demo - The Beta Demo (2000) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2a1b454a5c3832b0240111e7fd73de8a", "Tigervision, Bill Hogue", "7-011", "Miner 2049er Volume II (1983) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "2a2f46b3f4000495239cbdad70f17c59", "CommaVid, John Bronstein - Ariola", "CM-003 - 712 003-720", "Cosmic Swarm (1982) (CommaVid) (PAL)", "AKA Angriff der Termiten", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "2a33e21447bf9e13dcfed85077ff6b40", "", "", "Backwards Cannonball v2 (Hack)", "Hack of Human Cannonball", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2a360bc85bf22de438651cf92ffda1de", "Bit Corporation", "PGP213", "Spy Vs. Spy (4 Game in One) (1983) (BitCorp) (PAL)", "AKA Chopper Command", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2a9f9001540c55a302befd8e9d54b47b", "Atari, Dan Hitchens", "CX2697, CX2697P", "Mario Bros. (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2aa5e56d36c2e58b6f2856109f2099a9", "Atari, Larry Kaplan - Sears", "CX2628 - 6-99842, 49-75117", "Bowling (1979) (Atari) (4K) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2aba6a1b01a5859e96d6a66d2286772f", "Activision, Steve Cartwright", "AX-027", "Plaque Attack (1983) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2abc3d46b3f2140160759e2e10bc86d9", "", "", "Gunfight 2600 - Beta Release! (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2ac3a08cfbf1942ba169c3e9e6c47e09", "Activision, Dan Kitchen", "EAK-046-04B", "Fighter Pilot (1988) (Activision) (PAL)", "AKA Tomcat - The F-14 Fighter Simulator", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2ae700c9dba843a68dfdca40d7d86bd6", "TechnoVision - Thomas Jentzsch", "", "Pharaoh's Curse (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "2aeedcc6eb1602efb77161b0cef832ab", "SOLID Corp. (D. Scott Williamson)", "CX2655-025", "Star Castle 2600 (SolidCorp) [025]", "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "2b1589c7e1f394ae6a1c046944f06688", "Carrere Video - JWDA, Todd Marshall, Robin McDaniel, Wes Trager, Henry Will IV - Teldec - Prism", "USC2003", "Eggomania (1983) (Carrere Video) (PAL)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "AUTO 60", "", "", "", "" }, - { "2b27eb194e13f3b38d23c879cc1e3abf", "Quelle", "402.272 9", "Super-Ferrari (1983) (Quelle) (PAL)", "AKA Enduro", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2b42da79a682ed6e2d735facbf70107e", "", "", "DKjr Improved (Hack)", "Hack of Donkey Kong Jr.", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2b430c00dc79e495762ac59b2f9b4fcd", "Activision, David Crane", "AX-018, AX-018-04", "Pitfall! (1982) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2b71a59a53be5883399917bf582b7772", "Greg Troutman", "", "Dark Mage (final beta) (Greg Troutman) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "2ba02f509a4991aa176ba8d9e540df3d", "Atari, Mark R. Hahn", "CX2678", "Dukes of Hazzard (1983) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2bb0a1f1dee5226de648eb5f1c97f067", "Robby", "", "Enduro (Robby)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2bb9f4686f7e08c5fcc69ec1a1c66fe7", "Atari - GCC, John Allred, Mike Feinstein", "CX2688", "Jungle Hunt (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2bc26619e31710a9884c110d8430c1da", "Atari, Bob Whitehead", "CX2652, CX2652P", "Casino (1979) (Atari) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "", "", "" }, - { "2bc6c53b19e0097a242f22375a6a60ff", "", "", "Droid Demo 2 (David Conrad Schweinsberg) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2bee7f226d506c217163bad4ab1768c0", "Xonox - K-Tel Software - Beck-Tech, Steve Beck", "6210, 06002, 06004, 99002", "Ghost Manor (1983) (Xonox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2bf34b6ad7d2317a2d0808b3fb93571b", "", "", "Easy Playfield Graphics (1997) (Chris Cracknell)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2c0dc885d5ede94aa664bf3081add34e", "", "", "Earth Dies Screaming, The (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2c29182edf0965a7f56fe0897d2f84ba", "Atari - Axlon, Steve DeFrisco", "CX26192", "Klax (08-18-1990) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2c2aea31b01c6126c1a43e10cacbfd58", "Paul Slocum", "", "Synthcart (2002) (Paul Slocum)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "2c3b2843295c9d6b16996971180a3fe9", "HES - Activision", "", "Sports Action Pak - Enduro, Ice Hockey, Fishing Derby, Dragster (1988) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2c3b9c171e214e9e46bbaa12bdf8977e", "Bit Corporation", "R320", "Othello (32 in 1) (BitCorp)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2c45c3eb819a797237820a1816c532eb", "Atari", "CX26163P", "Boxing (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2c8835aed7f52a0da9ade5226ee5aa75", "Arcadia Corporation, Stephen H. Landrum", "AR-4101", "Communist Mutants from Space (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2c8c11295d8613f875b7bcf5253ab9bb", "Fabrizio Zavagli", "", "Kool Aid Man (PAL Conversion) (16-11-2002) (Fabrizio Zavagli) (PAL60)", "PAL60 Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2c9fadd510509cc7f28f1ccba931855f", "", "", "Hangman Invader Biglist1 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2ca6445204ffb7686ddee3e33ba64d5b", "Alex Herbert", "", "AtariVox Test ROM", "Uses the AtariVox controller", "", "", "", "", "", "", "", "", "", "ATARIVOX", "", "", "", "", "", "" }, - { "2cb42cf62b2f25f59f909b5447821b14", "Atari, Christopher H. Omarzu - Children's Computer Workshop", "CX26104", "Big Bird's Egg Catch (1983) (Atari) (PAL) [a]", "Uses Kids/Keypad Controllers", "", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "" }, - { "2cc3049b7feb8e92f1870f1972629757", "Video Soft", "", "Atom Smasher (1984) (Video Soft) (Prototype) [stack pointer fix]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2cccc079c15e9af94246f867ffc7e9bf", "PlayAround - J.H.M.", "203", "Jungle Fever (1982) (PlayAround)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "2cefa695df2ed020899a7df7bb1e3a95", "Manuel Polik, Fabrizio Zavagli", "", "A-Team (2002) (Manuel Polik) (Hack)", "Hack of A-Team", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2cf20f82abcae2decff88db99331e071", "Activision, Mike Lorenzen", "AX-023", "Oink! (1983) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2cfb188c1091cc7ec2a7e60064d2a758", "", "", "Space Invaders Hack Demo (2003) (SnailSoft)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2d15b092e8350912ec4b2e5e750fa1c6", "Wizard Video Games, Bob Davis, Robert H. O'Neil", "", "Texas Chainsaw Massacre, The (1982) (Wizard Video Games) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2d16a8b59a225ea551667be45f554652", "Quelle", "802.744 3", "Der Geheimkurier (1983) (Quelle) (PAL)", "AKA Mr. Postman", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2d1cf85fbc732856bf76470cd4060f4a", "", "", "Daredevil (V1) (Stunt_Cycle_Rules!) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2d2c5f0761e609e3c5228766f446f7f8", "Atari - Axlon, Steve DeFrisco", "CX26170, CX26170P", "Secret Quest (1989) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2d33a44e82f88d05f6c50577218c0cae", "AtariAge - Michael Haas", "RC2", "Flappy (2014) (AtariAge)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2d38a96f92952b301eefdf25a5e6976b", "Omegamatrix", "", "Star Wars Arcade (Atari Mouse) (Y_Inverted) v4 (Omegamatrix)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2d405da70af82b20a6b3ecc3d1d2c4ec", "Genus", "", "Pitfall (Genus)", "AKA Pitfall!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2d6388a8389f1d59108fd169c3356d79", "Thomas Jentzsch", "", "Reactor - Atari Mouse Hack v1.3 (NTSC) (Half-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2d63b452f897818c52b3fceeb080a4d0", "HES - Absolute Entertainment", "", "Pete Rose Baseball (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2d6741cda3000230f6bbdd5e31941c01", "CBS Electronics - VSS", "80110", "Targ (1983) (CBS Electronics) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2d69a5f23784f1c2230143292a073b53", "", "", "Qb (Fixed background animation) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "2d6da0eb85eabc93270e5bb8a466ca51", "", "", "Sprite Demo 7 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2d76c5d1aad506442b9e9fb67765e051", "Apollo - Games by Apollo, Larry Minor, Ernie Runyon, Ed Salvo", "AP-2004", "Lost Luggage (1982) (Apollo) [no opening scene]", "AKA Airport Mayhem", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2d9e5d8d083b6367eda880e80dfdfaeb", "QDI, Mike Montana, Rich Montana - Selchow & Righter", "87", "Glib (1983) (QDI)", "AKA Video Word Game", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2d9e65959808a6098c16c82a59c9d9dc", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (1 of 3) (1982) (Starpath) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2dbc92688f9ba92a7e086d62be9df79d", "", "", "How to Draw a Playfield (1997) (Jim Crawford) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2dbdca3058035d2b40c734dcf06a86d9", "Thomas Jentzsch", "", "Asteroids DC+ (Thomas Jentzsch) (Hack)", "Uses the Joystick (left) or Driving (right) Controller", "Hack", "", "", "", "", "", "", "", "", "DRIVING", "", "58", "", "", "YES", "" }, - { "2dcf9ce486393cd36ca0928cd53b96cb", "Atari - GCC, Mike Feinstein, John Allred", "CX2688, CX2688P", "Jungle Hunt (1983) (Atari) (PAL) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2de41a11c6767e54a5ee9ebaffec72af", "Gray Games & AtariAge", "", "E.T. Book Cart (PAL60)", "Charles F. Gray & Michael Rideout", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "55" }, - { "2dfec1615c49501fefc02165c81955e6", "", "", "Song (05-11-2002) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "2e0aed5bb619edcefa3fafb4fbe7c551", "", "", "Qb (2.06) (Retroactive) (NTSC)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "2e2acef8513edcca991e7e5149412e11", "Parker Brothers, Larry Gelberg, Gary Goltz", "PB5065", "Star Wars - Ewok Adventure (1983) (Parker Bros) (Prototype) (16K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2e3728f3086dc3e71047ffd6b2d9f015", "Atari, David Crane", "CX26163P", "Outlaw (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2e5b184da8a27c4d362b5a81f0b4a68f", "Atari", "", "Rabbit Transit (08-29-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2e663eaa0d6b723b645e643750b942fd", "Atari, Tom Rudadahl - Sears", "CX2634 - 49-75121", "Golf (1980) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2e7e9c6dcfcceaffc6fa73f0d08a402a", "CCE", "C-818", "Star Voyager (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2e82a1628ef6c735c0ab8fa92927e9b0", "Atari, Jerome Domurat, Peter C. Niday, Robert Vieira", "CX26109", "Sorcerer's Apprentice (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2e842c2ee22e9dad9df16eed091315c4", "HES", "701-157", "2 Pak Special - Moto-cross, Boom Bang (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2eaf8fa9e9fdf1fcfc896926a4bdbf85", "Arcadia Corporation, Stephen H. Landrum", "AR-4400", "Excalibur Version 39 (Dragonstomper Beta) (1982) (Arcadia) (Prototype)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2ec6b045cfd7bc52d9cdfd1b1447d1e5", "Activision, David Crane - Ariola", "EAG-009, PAG-009 - 711 009-720", "Freeway (1981) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2eda6a49a49fcb2b674ea9e160b6a617", "Kyle Pittman", "", "Rambo in Afghanistan (Kyle Pittman) (Hack)", "Hack of Riddle of the Sphinx", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2ef36341d1bf42e02c7ea2f71e024982", "", "", "Space Invaders (Explosion Hack)", "Hack of Space Invaders (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2f0546c4d238551c7d64d884b618100c", "SEGA, Jeff Lorenz", "", "Ixion (1984) (SEGA) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2f0a8bb4e18839f9b1dcaa2f5d02fd1d", "CCE", "", "Super Futebol (CCE) [a]", "AKA RealSports Football", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "2f11ba54609777e2c6a5da9b302c98e8", "Atari - GCC", "CX2676", "Centipede (1982) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2f16663b01591539624d0ef52934a17d", "M Network", "", "Rocky and Bullwinkle", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2f2f9061398a74c80420b99ddecf6448", "Rentacom - Brazil", "", "Bobby Is Going Home (Rentacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2f66ebf037321ed0442ac4b89ce22633", "Baroque Gaming (Brian Eno)", "", "Warring Worms (Beta 2) (2002) (Baroque Gaming)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2f7772879a1ed04f660aa9d77a86a4bd", "", "", "Yars' Revenge (Genesis)", "Genesis controller (C is zorlon cannon)", "Hack of Yars' Revenge", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "2f77f015fc880b05f28e84156f989a0c", "", "", "Plane Demo (Gonzalo) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2f7949f71076db42480d3f5036b4a332", "", "", "Name This Game (208 in 1) (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "2facd460a6828e0e476d3ac4b8c5f4f7", "Sancho - Tang's Electronic Co.", "", "Words-Attack (1983) (Sancho) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "3025bdc30b5aec9fb40668787f67d24c", "", "", "Demo Image Series #14 - Two Marios (4K Interleaved Chronocolour Vertical Movement) (05-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "303242c239474f2d7763b843de58c1c3", "CCE", "", "Laser Blast (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "304512528a5530a9361e8a231ed9a6de", "Thomas Jentzsch", "", "River Raid Plus (Thomas Jentzsch) (Hack)", "Hack of River Raid", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "30512e0e83903fc05541d2f6a6a62654", "Atari, Jim Huether - Sears", "CX2644 - 6-99824", "Flag Capture (1978) (Atari)", "AKA Capture the Flag", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "30516cfbaa1bc3b5335ee53ad811f17a", "Wizard Video Games - MicroGraphic Image, Robert Barber, Tim Martin", "007", "Halloween (1983) (Wizard Video Games)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3051b6071cb26377cd428af155e1bfc4", "Atari, David Crane - Sears", "CX2607 - 6-99828, 49-75115", "Canyon Bomber (1979) (Atari) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "YES", "10", "", "", "", "" }, - { "30685b9b6ebd9ba71536dd7632a1e3b6", "Dactari - Milmar", "", "Tennis (Dactari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3091af0ef1a61e801f4867783c21d45c", "CCE", "C-862", "Crackpots (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "30997031b668e37168d4d0e299ccc46f", "", "", "John K Harvey's Equalizer (PAL) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "30c92c685224dc7a72b9bbe5eb62d004", "", "", "Hangman Monkey Original Words (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "30e012e8d50330c8972f126b8e913bc4", "", "", "Indy 500 (Hack) [a2]", "Hack of Indy 500", "Hack", "", "", "", "", "", "", "", "DRIVING", "DRIVING", "", "", "", "", "", "" }, - { "30e0ab8be713208ae9a978b34e9e8e8c", "Atari, Mike Lorenzen", "CX2630, CX2630P", "Circus Atari (1980) (Atari) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "01 55", "", "", "", "" }, - { "30f0b49661cfcfd4ec63395fab837dc3", "SEGA, Jeff Lorenz - Teldec", "004-01", "Star Trek - Strategic Operations Simulator (1983) (SEGA) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "3105967f7222cc36a5ac6e5f6e89a0b4", "SEGA, Jeff Lorenz", "011-01, 011-02", "Spy Hunter (1984) (SEGA)", "Uses Joystick Coupler (Dual Control Module)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "310ba30e25ea8957e58180b663503c0c", "Ed Federmeyer", "", "Sound X6 (1994) (Ed Federmeyer)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "31235a27b065c2863048fa84db330dc6", "Thomas Jentzsch", "", "Missile Control - Amiga Mouse Hack v1.15 (PAL) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "313243fc41e49ef6bd3aa9ebc0d372dd", "", "", "Fast Food (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "31512cdfadfd82bfb6f196e3b0fd83cd", "Tigervision", "7-004", "River Patrol (1984) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3177cc5c04c1a4080a927dfa4099482b", "Atari - Imagineering, Alex DeMeo", "CX26135", "RealSports Boxing (1987) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "317a4cdbab090dcc996833d07cb40165", "Goliath - Hot Shot", "83-312", "Missile War (1983) (Goliath) (PAL)", "AKA Astrowar", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "318046ae3711c05fd16e479b298e5fcc", "Retroactive", "", "Qb (V2.08) (Stella) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "318a9d6dda791268df92d72679914ac3", "Activision, Steve Cartwright", "AX-017, AX-017-04", "MegaMania (1982) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "319a142aab6260842ab616382848c204", "", "", "Marble Craze (05-02-2002) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "31bb9b8ceed46cb3e506777a9e65f3ce", "Bit Corporation", "", "4 Game in One Light Green (1983) (BitCorp) (PAL)", "Phantom UFO, Ice Hockey, Cosmic Avenger, Spy Vs. Spy", "", "", "", "4IN1", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "31c5fd55a39db5ff30a0da065f86c140", "Dactari - Milmar", "", "Enduro (Dactari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "31d08cb465965f80d3541a57ec82c625", "Atari, Alan Miller - Sears", "CX2641 - 99807, 49-75105", "Surround (1977) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "31df1c50c4351e144c9a378adb8c10ba", "Quelle", "687.463 0", "Die Ratte und die Karotten (1983) (Quelle) (PAL)", "AKA Gopher", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "31e518debba46df6226b535fa8bd2543", "Atari, Douglas 'Solaris' Neubauer, Mimi Nyden", "CX26134", "Last Starfighter (1984) (Atari) (Prototype)", "Solaris Beta", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "31f4692ee2ca07a7ce1f7a6a1dab4ac9", "Atari, Alan Miller", "CX2642", "Game of Concentration (1980) (Atari) (4K)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "31fcbce1cfa6ec9f5b6de318e1f57647", "Atari, Jerome Domurat, Peter C. Niday", "CX26115", "Dumbo's Flying Circus (1983) (Atari) (Prototype) (PAL)", "AKA Dumbo Flies Home", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "32199271dc980eb31a2cc96e10a9e244", "", "", "Radial Pong - Version 12 (Jeffry Johnston) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "321c3451129357af42a375d12afd4450", "Atari - Imagineering, Dan Kitchen", "CX26177", "Ikari Warriors (1991) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "32244e55ce6ec6bfbd763f33384bdc2e", "Activision, Steve Cartwright", "AX-027", "Plaque Attack (1983) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3225676f5c0c577aeccfaa7e6bedd765", "CCE", "C-1002", "Pole Position (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "322b29e84455aa41e7cc9af463bffa89", "Atari - Bobco, Robert C. Polaro", "CX2663", "Road Runner (06-25-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "324cb4a749bcac4f3db9da842b85d2f7", "Dennis Debro", "", "Climber 5 (01-05-2003) (Dennis Debro)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "327468d6c19697e65ab702f06502c7ed", "Charles Morgan", "", "Aster-Hawk (2002) (Charles Morgan) (Hack)", "Hack of Asteroids", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "3276c777cbe97cdd2b4a63ffc16b7151", "Atari - GCC, Mike Feinstein, Kevin Osborn", "CX2691", "Joust (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "3278158e5c1f7eb5c5d28ccfd7285250", "Dactari - Milmar", "", "Megamania (Dactari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "327fe8cf94f3a45c35a840a453df1235", "", "", "Spice Girls Rule Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "328949872e454181223a80389d03c122", "", "", "Home Run (Unknown) (PAL)", "", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "" }, - { "32ae78abbb5e677e2aabae5cc86cec29", "Atari, Christopher H. Omarzu, Courtney Granner", "CX26112", "Good Luck, Charlie Brown (04-18-1984) (Atari) (Prototype)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "32d1260ea682e1bb10850fa94c04ec5f", "Atari, Alan Miller", "CX26163P", "Basketball (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "32dcd1b535f564ee38143a70a8146efe", "Xonox - K-Tel Software - Product Guild, Anthony R. Henderson", "99007, 6240", "Tomarc the Barbarian (1983) (Xonox)", "AKA Thundarr the Barbarian", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "32e65d1e4dfcbcd9b57fee72cafe074c", "", "", "Eckhard Stolberg's Scrolling Text Demo 3 (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "32ecb5a652eb73d287e883eea751d99c", "Dactar - Milmar", "", "Bowling (Dactar - Milmar)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "32f4e47a71601ab06cfb59e1c6a0b846", "Ed Federmeyer", "", "Sound X (1994) (Ed Federmeyer)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3316ee2f887e9cb9b54dd23c5b98c3e2", "", "", "Texas Golf (miniature Gold Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "331938989f0f33ca39c10af4c09ff640", "Zach Matley", "", "Combat - Tank AI (19-04-2003) (Zach Matley)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "332f01fd18e99c6584f61aa45ee7791e", "", "", "X'Mission (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "3347a6dd59049b15a38394aa2dafa585", "Parker Brothers - JWDA, Henry Will IV", "PB5760", "Montezuma's Revenge (1984) (Parker Bros)", "Featuring Panama Joe", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "335793736cbf6fc99c9359ed2a32a49d", "", "", "Analog Clock (V0.0) (20-01-2003) (AD) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "335a7c5cfa6fee0f35f5824d1fa09aed", "SEGA - Beck-Tech, Steve Beck, Phat Ho - Teldec", "006-01 - 3.60105 VG", "Congo Bongo (1983) (SEGA) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3367eeba3269aa04720abe6169767502", "", "", "Space Treat (30-12-2002) (Fabrizio Zavagli)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "336ea20d38f98926919d4b4651d1a03f", "Omegamatrix", "", "Omega Race (Genesis) V2", "Genesis controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3391f7c4c656793f92299f4187e139f7", "Commavid, Ben Burch", "CM-010", "Rush Hour (1983) (Commavid) (Prototype) [a4]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "33cac5e767a534c95d292b04f439dc37", "Jone Yuan Telephonic Enterprise Co", "", "Tapeworm (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "33d68c3cd74e5bc4cf0df3716c5848bc", "CBS Electronics, Tom DiDomenico", "4L 2486 5000", "Blueprint (1983) (CBS Electronics)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "33ed6dfac4b9ea2f81f778ceddbb4a75", "Activision", "", "River Raid (1982) (SpkSoft) [t1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "340f546d59e72fb358c49ac2ca8482bb", "Sancho - Tang's Electronic Co.", "TEC003", "Skindiver (1983) (Sancho) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "34340c8eecd1e557314789cc6477e650", "Joe Grand", "", "SCSIcide Pre-release 4 (Joe Grand)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "345488d3b014b684a181108f0ef823cb", "CBS Electronics, Tom DiDomenico", "4L 2486 5000", "Blueprint (1983) (CBS Electronics) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "345758747b893e4c9bdde8877de47788", "CBS Electronics, Joseph Biel", "4L1802, 4L1803, 4L1804, 4L2278", "Venture (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "345769d085113d57937198262af52298", "Rainbow Vision - Suntek", "SS-007", "Space Raid (1983) (Rainbow Vision) (PAL)", "AKA MegaMania", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "346555779a2d51b48833463b5433472f", "Thomas Jentzsch", "", "Thrust (V0.1) (2000) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "348615ffa30fab3cec1441b5a76e9460", "Activision, Alan Miller - Ariola", "EAX-016, PAX-016 - 711 016-725", "StarMaster (1982) (Activision) (PAL) [fixed]", "Use Color/BW switch to change between galactic chart and front views", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "34b269387fa1aa5a396636f5ecdd63dd", "", "", "Marble Craze (mc7_23) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "34c808ad6577dbfa46169b73171585a3", "Apollo", "AP-2012", "Squoosh (1983) (Apollo) (Prototype)", "AKA Vat's Incredible!, The Grape Escape", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "34ca2fcbc8ba4a0b544acd94991cfb50", "Atari, Robert C. Polaro", "", "Dukes of Hazzard (1980) (Atari) (Prototype) (4K)", "AKA Stunt Cycle", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "34e37eaffc0d34e05e40ed883f848b40", "Retroactive", "", "Qb (2.15) (Retroactive) (Stella)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "34f4b1d809aa705ace6e46b13253fd3b", "Aaron Bergstrom", "", "Nothern Alliance (Aaron Bergstrom) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "34fd4fcb40ff5babce67f8b806d5969c", "", "", "Boxing (Dactari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "350e0f7b562ec5e457b3f5af013648db", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX26119", "Saboteur (06-09-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "35156407e54f67eb1f625450d5c093e1", "", "", "Mouse Trap (Genesis)", "Genesis controller (C changes to dog)", "Hack of Mouse Trap", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "35163b56f4a692a232ae96ad3e23310f", "Retroactive", "", "Qb (2.12) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "3545eb3b8b1e7dc19f87d231ab0b1d4c", "CBS Electronics - Roklan, Joe Hellesen, Joe Wagner", "M8774, M8794", "Wizard of Wor (1982) (CBS Electronics) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3556e125681aea864e17b09f3f3b2a75", "", "", "Incoming (2 Player Demo) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3576037c9281656655fa114a835be553", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (1 of 4) (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3577e19714921912685bb0e32ddf943c", "TechnoVision - Video Technology", "TVS1003", "Pharaoh's Curse (1983) (TechnoVision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "35ae903dff7389755ad4a07f2fb7400c", "", "", "Colored Wall Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "35b10a248a7e67493ec43aeb9743538c", "Dor-x", "", "Defender (Dor-x) (Hack)", "Hack of Defender", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "35b43b54e83403bb3d71f519739a9549", "Parker Brothers, Dave Engman, Isabel Garret", "", "McDonald's (06-06-1983) (Parker Bros) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "35be55426c1fec32dfb503b4f0651572", "Men-A-Vision", "", "Air Raid (Men-A-Vision) (PAL)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "35fa32256982774a4f134c3347882dff", "Retroactive", "", "Qb (V0.05) (Macintosh) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "360ba640f6810ec902b01a09cc8ab556", "Atari, Jerome Domurat, Steve Woita", "CX2699", "Taz (06-15-1983) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "360c0dcb11506e73bd0b77207c81bc62", "Digitel", "", "Enduro (1983) (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3619786f6a32efc1e4a262d5aca8a070", "Atari, John Dunn - Sears", "CX2631 - 49-75152", "Superman (1979) (Atari) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3624e5568368929fabb55d7f9df1022e", "Activision - Imagineering, Donald Hahn, Dan Kitchen", "EAK-050-04", "Double Dragon (1989) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "36306070f0c90a72461551a7a4f3a209", "U.S. Games Corporation - JWDA, Roger Booth, Sylvia Day, Ron Dubren, Todd Marshall, Robin McDaniel, Wes Trager, Henry Will IV", "VC1007", "Name This Game (1983) (U.S. Games)", "AKA Octopussy", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "36547bc6faa5132b87504e18d088e1d7", "", "", "Cosmic Swarm (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "367411b78119299234772c08df10e134", "Atari", "CX26163P", "Skiing (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3685060707df27d4091ba0ea2dc4b059", "", "", "PezZerk - PezMan in Ghost Manor (Hack)", "Hack of Berzerk", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "368d88a6c071caba60b4f778615aae94", "Atari, Matthew L. Hubbard", "CX26159", "Double Dunk (1989) (Atari)", "AKA Super Basketball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "36a701c60a9f9768d057bc2a83526a80", "", "", "Cube Conquest (Interlaced) (Billy Eno) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "36b20c427975760cb9cf4a47e41369e4", "Coleco - Woodside Design Associates - Imaginative Systems Software, Garry Kitchen", "2451", "Donkey Kong (1982) (Coleco)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "36c29ceee2c151b23a1ad7aa04bd529d", "Atari - GCC, Ava-Robin Cohen", "CX26123", "Jr. Pac-Man (1986) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "36c31bb5daeb103f488c66de67ac5075", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix - Bop a Buggy (1 of 3) (1983) (Arcadia)", "Uses Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "01 56", "", "", "", "" }, - { "36c993dc328933e4dd6374a8ffe224f4", "Gameworld, J. Ray Dettling", "133-007", "Bermuda Triangle (1983) (Gameworld) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "36e47ed74968c365121eab60f48c6517", "Quelle", "343.373 7", "Master Builder (1983) (Quelle) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "36edef446ab4c2395666efc672b92ed0", "Atari - Axlon, John Vifian", "CX26168", "Off the Wall (1989) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "36f9a953ebdd9a8be97ccf27a2041903", "", "", "Chinese Character Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "37252757a79dc5b174e3c03d6ea0bdcb", "", "", "Sky Diver (Unknown) (PAL) (4K) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "372bddf113d088bc572f94e98d8249f5", "Bomb - Onbase", "CA285", "Wall-Defender (1983) (Bomb) (PAL)", "AKA Wall Break", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "373b8a081acd98a895db0cb02df35673", "", "", "Demo Image Series #5 - Boofly (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3750f2375252b6a20e4628692e94e8b1", "Dismac", "", "Ases do Ar (Dismac)", "AKA Sky Jinks", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "37527966823ee9243d34c7da8302774f", "", "", "Word Zapper (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "376944889dcfa96c73d3079f308e3d32", "Retroactive", "", "Qb (0.11) (Retroactive) (Stella)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "3783f12821b88b08814da8adb1a9f220", "", "", "Mission Survive (PAL) (Genesis)", "Genesis controller (C is vertical fire)", "Hack of Mission Survive)", "", "", "", "", "A", "", "", "", "", "", "", "", "", "YES", "" }, - { "378a62af6e9c12a760795ff4fc939656", "Atari - Axlon, Steve DeFrisco", "CX26171", "MotoRodeo (1991) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "378c118b3bda502c73e76190ca089eef", "Atari, Alan Miller", "CX2662P", "Hangman (1978) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "37ab3affc7987995784b59fcd3fcbd31", "", "", "Sprite Test (29-11-2002) (Eric Ball)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "37b98344c8e0746c486caf5aaeec892a", "K-Tel Vision", "6", "Spider Maze (1982) (K-Tel Vision) (PAL)", "AKA Spider Kong", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "37e828675d556775ae8285c0caf7d11c", "AtariAge - Fred Quimby", "", "Gingerbread Man (Fred Quimby) (Genesis)", "Genesis controller (C throws cookie)", "New Release", "", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "" }, - { "37f42ab50018497114f6b0f4f01aa9a1", "", "", "Droid Demo 2-M (David Conrad Schweinsberg) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "37fd7fa52d358f66984948999f1213c5", "Rainbow Vision - Suntek", "SS-004", "Pyramid War (1983) (Rainbow Vision) (PAL) [a2]", "AKA Chopper Command", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "384db97670817103dd8c0bbdef132445", "Atari - Sears", "CX2626 - 6-99829, 49-75116", "Miniature Golf (1979) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "384f5fbf57b5e92ed708935ebf8a8610", "20th Century Fox Video Games, John W.S. Marvin", "11009", "Crypts of Chaos (1983) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3856b9425cc0185ed770376a62af0282", "Kyle Pittman", "", "Yellow Submarine (Kyle Pittman) (Hack)", "Hack of Bermuda Triangle", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "386ff28ac5e254ba1b1bac6916bcc93a", "Arcadia Corporation, Scott Nelson", "AR-4300", "Fireball (1982) (Arcadia)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "01", "", "", "", "" }, - { "3882224adbd0ca7c748b2a1c9b87263e", "Atari, Tod Frye", "CX2657", "SwordQuest - FireWorld (1982) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3889351c6c2100b9f3aef817a7e17a7a", "CCE", "", "Dolphin (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3897744dd3c756ea4b1542e5e181e02a", "Atari, Jerome Domurat, Peter C. Niday", "CX26115", "Dumbo's Flying Circus (05-05-1983) (Atari) (Prototype)", "AKA Dumbo Flies Home", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "38bd172da8b2a3a176e517c213fcd5a6", "Atari", "MA017600", "Diagnostic Test Cartridge 2.6 (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "38c362dcd5cad5a62e73ae52631bd9d8", "Jake Patterson", "", "Baubles (14-11-2001) (Jake Patterson) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "38cf93eacfb2fa9a2c5e39059ff35a74", "Greg Zumwalt", "", "WacMan (2003) (Greg Zumwalt) (Hack)", "Hack of Ms. Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "38de7b68379770b9bd3f7bf000136eb0", "Imagic, Mark Klein", "EIZ-003-04I", "Subterranea (1983) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "391764720140c432aec454a468f77a40", "Video Game Program", "", "Miss Pack Man (Video Game Program) (PAL)", "AKA Ms. Pac-Man", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "392d34c0498075dd58df0ce7cd491ea2", "Atari, Frank Hausman, Mimi Nyden, Steve Woita", "CX2686", "Quadrun (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "392f00fd1a074a3c15bc96b0a57d52a1", "Atari, Rob Fulop - Sears", "CX2633 - 49-75119", "Night Driver (1980) (Atari)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "AUTO 65", "", "", "YES", "" }, - { "393948436d1f4cc3192410bb918f9724", "Activision, Carol Shaw", "AX-020, AX-020-04", "River Raid (1982) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "393e41ca8bdd35b52bf6256a968a9b89", "U.S. Games Corporation - Western Technologies, John Hall", "VC1012", "M.A.D. (1983) (U.S. Games)", "AKA Missile Intercept, Mutually Assured Destruction", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3947eb7305b0c904256cdbc5c5956c0f", "Jone Yuan Telephonic Enterprise Co", "", "Lilly Adventure (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "396f7bc90ab4fa4975f8c74abe4e81f0", "Atari, Larry Kaplan - Sears", "CX2612 - 99804, 49-75103", "Street Racer (1977) (Atari)", "Uses the Paddle Controllers (swapped)", "", "", "", "", "", "", "", "", "", "", "YES", "AUTO 60", "", "", "", "" }, - { "3974e2d1f614fbd3a092533ecae2e84d", "Alessandro Ciceri", "", "MagiCard+ (alex_79) WIP_20150118", "MagiCard hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "39790a2e9030751d7db414e13f1b6960", "", "", "Robotfindskitten2600 (26-04-2003) (Jeremy Penner) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "39a6a5a2e1f6297cceaa48bb03af02e9", "", "", "Pitfall 2 Plus (Hack)", "Hack of Pitfall 2", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "39b94d41bd3b01c12b4054c1a8733783", "SOLID Corp. (D. Scott Williamson)", "CX2655-016", "Star Castle 2600 (SolidCorp) [016]", "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "39c78d682516d79130b379fa9deb8d1c", "Apollo - Games by Apollo, Ed Salvo", "AP-1001", "Skeet Shoot (1981) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "39d36366ae7e6dfd53393fb9ebab02a0", "CCE", "C-811", "River Raid (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "39da69ff9833f8c143f03b6e0e7a996b", "Charles Morgan", "", "Ventrra Invaders 2002 (Charles Morgan) (Hack)", "Hack of Megamania", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "39fe316952134b1277b6a81af8e05776", "Robby", "18", "River Raid (Robby)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3a10562937a766cbbb77203d029b00e1", "Carrere Video - JWDA, Garry Kitchen, Paul Willson - Teldec - Prism", "USC1002", "Sneak 'n Peek (1983) (Carrere Video) (PAL)", "AKA Der Unsichtbare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3a2e2d0c6892aa14544083dfb7762782", "Atari, Rob Fulop - Sears", "CX2638 - 49-75166", "Missile Command (1981) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "3a35d7f1dc2a33565c8dca52baa86bc4", "", "", "Rubik's Cube Demo 2 (23-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3a51a6860848e36e6d06ffe01b71fb13", "Retroactive", "", "Qb (2.07) (Retroactive) (NTSC)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "3a521b7e29123b2d38e34e3ff8dc255c", "Thomas Jentzsch", "", "Centipede - Atari Mouse Hack v1.4 (NTSC) (Full-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3a526e6a1f9fe918af0f2ce997dfea73", "CBS Electronics, Dan Kitchen, Garry Kitchen", "4L1700, 4L1701, 4L1702, 4L1802, 4L2274", "Donkey Kong (1982) (CBS Electronics) (PAL) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3a53963f053b22599db6ac9686f7722f", "", "", "Word Zapper (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3a771876e4b61d42e3a3892ad885d889", "Atari, Bill Aspromonte, Andrew Fuchs", "CX26120", "Defender II (1987) (Atari)", "AKA Stargate", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3aad0ef62885736a5b8c6ccac0dbe00c", "Dynacom", "", "Atlantis (1983) (Dynacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3ab5d138e26d88c8190e7cc629a89493", "", "", "Phased Color Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "3ac6c50a8e62d4ce71595134cbd8035e", "Absolute Entertainment, Dan Kitchen", "AK-046-04", "Tomcat (1988) (Absolute)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3ad3dc799211ccd424d7c6d454401436", "Probe 2000 - NAP", "", "Power Lords (1983) (Probe) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3ad58b53a1e972396890bd86c735e78d", "Arcadia Corporation, Stephen H. Landrum", "AR-4400", "Excalibur Version 36 (Dragonstomper Beta) (1982) (Arcadia) (Prototype)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3b040ed7d1ef8acb4efdeebebdaa2052", "Tigervision", "7-008", "Miner 2049er (1983) (Tigervision) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3b097a7ed5bd2a84dc3d3ed361e9c31c", "", "", "Interleaved ChronoColour Demo (PAL) (05-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3b10106836565e5db28c7823c0898fbb", "Xonox - Beck-Tech", "6210, 06002, 06004, 99002", "Ghost Manor (1983) (Xonox) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3b2c32fcd331664d037952bcaa62df94", "Xonox", "6230, 6250", "Super Kung-Fu (1983) (Xonox) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3b5751a8d20f7de41eb069f76fecd5d7", "", "", "Eckhard Stolberg's Scrolling Text Demo 4 (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3b64a00ce147c3c29f7f8f8e531d08d8", "", "", "This Planet Sucks (16K) (Greg Troutman)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3b69f8929373598e1752f43f8da61aa4", "Apollo - Games by Apollo - RCA Video Jeux", "AP-2006", "Infiltrate (1921) (Apollo) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "3b6dba1a24bb2893bd3bd0593f92016b", "CBS Electronics / Thomas Jentzsch", "", "Omega Race JS (TJ)", "Hack of Omega Race (CBS Electronics)", "New Release (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3b76242691730b2dd22ec0ceab351bc6", "M Network - INTV, Connie Goldman, Joe King, Patricia Lewis Du Long, Gerald Moore, Mike Sanders, Jossef Wagner", "MT4319", "Masters of the Universe (1983) (M Network)", "", "", "", "", "", "", "A", "", "", "", "", "", "", "", "", "YES", "" }, - { "3b80b8f52a0939e16b5059f93a3fc19a", "V007", "", "Virtual Pet (V007) (after Demo 2) (CRACKERS) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3b86a27132fb74d9b35d4783605a1bcb", "Atari, Chris Crawford", "", "Wizard (1980) (Atari) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3b8aacf5f5638492b926b5124de19f18", "Atari, Tod Frye - Sears", "CX2646 - 49-75185", "Pac-Man (1981) (Atari) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3b91c347d8e6427edbe942a7a405290d", "Parker Brothers", "PB5350", "Sky Skipper (1983) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3b9480bb6fb1e358c9c0a64e86945aee", "", "", "Title Match Pro Wrestling (2002) (Skyworks)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3b966bf3c2ca34ac6ca1de4cf6383582", "", "", "Double-Height 6-Digit Score Display (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3bb9793c60c92911895cf44530846136", "Jone Yuan Telephonic Enterprise Co", "", "Dragster (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3c21a89bc38d8cd0b010a2916bcff5c2", "", "", "Colony 7 - CX-22 Hack v0.4 (NTSC)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "50" }, - { "3c3a2bb776dec245c7d6678b5a56ac10", "", "", "Unknown Title (bin00003) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3c4223316c835ceaad619651e25df0f9", "", "", "Defender (Genesis)", "Genesis controller (C is smartbomb)", "Hack of Defender", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3c4a6f613ca8ba27ce9e43c6c92a3128", "", "", "Qb (V0.04) (Non-Lax Version) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "3c57748c8286cf9e821ecd064f21aaa9", "Atari, Jerome Domurat, Andrew Fuchs, Dave Staugas, Robert Vieira", "CX26118", "Millipede (1984) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3c72ddaf41158fdd66e4f1cb90d4fd29", "Dismac", "", "Comando Suicida (Dismac)", "AKA Chopper Command", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3c7a7b3a0a7e6319b2fa0f923ef6c9af", "Atari - Roklan, Joe Gaucher", "", "Racer (1982) (Atari) (Prototype)", "ROM must be started in bank 0", "Prototype", "", "0", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3c7a96978f52b2b15426cdd50f2c4048", "", "", "Overhead Adventure Demo 3 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3c82e808fe0e6a006dc0c4e714d36209", "Activision, David Crane", "AG-004", "Fishing Derby (1980) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3c853d864a1d5534ed0d4b325347f131", "Telesys, Don 'Donyo' Ruffcorn", "1002", "Cosmic Creeps (1982) (Telesys)", "AKA Space Maze, Spaze Maze", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "3c8e57a246742fa5d59e517134c0b4e6", "Parker Brothers, Rex Bradford, Sam Kjellman", "PB5050", "Star Wars - The Empire Strikes Back (1982) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3ca51b5c08f5a0ecfb17d0c1ec6d0942", "Atari, James Andreasen - Sears", "CX2654 - 49-75141", "Haunted House (09-28-81) (Atari) (Prototype)", "AKA Mystery Mansion, Graves' Manor, Nightmare Manor", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3caa902ac0ce4509308990645876426a", "Atari - GCC, Dave Payne", "CX2669, CX2669P", "Vanguard (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3cbdf71bb9fd261fbc433717f547d738", "CCE", "C-803", "Bobby Is Going Home (1983) (CCE) (PAL)", "AKA Bobby Vai Para Casa", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3cdd91e1c28d28e856c0063d602da166", "", "", "Stell-A-Sketch (03-11-1997) (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "3d1e83afdb4265fa2fb84819c9cfd39c", "Coleco - JWDA, Todd Marshall, Robin McDaniel, Henry Will IV", "2465", "Smurf - Rescue in Gargamel's Castle (1983) (Coleco)", "AKA Smurf, Smurf Action", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3d2367b2b09c28f1659c082bb46a7334", "Imagic, Dennis Koble", "720103-2A, IA3203P, EIX-010-04I", "Atlantis (1982) (Imagic) (PAL)", "AKA Lost City of Atlantis", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3d2652cbea462a886a41791dd7c8d073", "", "", "Ritorno dei frattelli di Mario (Mario Bros Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3d48b8b586a09bdbf49f1a016bf4d29a", "Video Game Cartridge - Ariola", "TP-606", "Hole Hunter (Video Game Cartridge)", "AKA Topy", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3d6fc7a19be76d808aa233415cb583fc", "CCE", "C-833", "Target Practice (1983) (CCE)", "AKA Carnival", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3d7749fb9c2f91a276dfe494495234c5", "Jone Yuan Telephonic Enterprise Co", "", "Checkers (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3d7aad37c55692814211c8b590a0334c", "Atari, Dan Oliver", "", "Telepathy (1983) (Atari) (Prototype)", "Uses both left joystick and right Mindlink controllers (press Fire on respective controller to begin)", "Prototype", "", "", "", "", "", "", "", "", "MINDLINK", "", "78", "", "", "", "" }, - { "3d8a2d6493123a53ade45e3e2c5cafa0", "Atari, Jim Huether - Sears", "CX2629 - 6-99843, 49-75118", "Sky Diver (1979) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3d934bb980e2e63e1ead3e7756928ccd", "Activision, Steve Cartwright - Ariola", "EAX-017, EAX-017-04I - 711 017-720", "MegaMania (1982) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3d9c2fccf8b11630762ff00811c19277", "", "", "Challenge of.... Nexar, The (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3da7cc7049d73d34920bb73817bd05a9", "Activision, Mike Lorenzen", "AX-023", "Oink! (1983) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3dfb7c1803f937fadc652a3e95ff7dc6", "Dimax - Sinmax", "SM8001", "Space Robot (Dimax - Sinmax)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "3e03086da53ecc29d855d8edf10962cb", "CBS Electronics - Roklan, Joe Gaucher, Alex Leavens", "4L1751, 4L1752, 4L1753, 4L2275", "Gorf (1982) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "3e1682ddaec486d8b6b90b527aaa0fc4", "Thomas Jentzsch", "", "Robot City (V0.12) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3e22c7eaf6459b67388602e4bebbb3a8", "CommaVid, John Bronstein - Ariola", "CM-003 - 712 003-720", "Cosmic Swarm (1982) (CommaVid) (PAL) (4K)", "AKA Angriff der Termiten", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3e33ac10dcf2dff014bc1decf8a9aea4", "Spectravideo - Video Games Industries Corporation, Michael Schwartz - Ralston Purina", "", "Chase the Chuckwagon (1983) (Spectravideo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "3e49da621193d2611a4ea152d5d5ca3a", "", "", "Atari Logo Demo 3 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3e4b1137433cc1e617b5508619e13063", "", "", "Asteroids (Genesis)", "Genesis controller (C is hyperspace)", "Hack of Asteroids", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "3e5ca1afaa27c5da3c54c9942fec528b", "", "", "2600 Digital Clock (Demo 2) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3e6dab92009d6034618cb6b7844c5216", "", "", "Ed Invaders (Hack)", "Hack of Pepsi Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3e7d10d0a911afc4b492d06c99863e65", "VGS", "", "Super Tenis (VGS)", "AKA RealSports Tennis", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3e88cca5b860d0bd8947479e74c44284", "Atari, Lou Harp", "CX26122", "Sinistar (01-23-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3e899eba0ca8cd2972da1ae5479b4f0d", "Coleco, Joseph Biel", "2457", "Venture (1982) (Coleco)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "3e90cf23106f2e08b2781e41299de556", "Activision, David Crane", "AX-018, AX-018-04", "Pitfall! (1982) (Activision)", "Pitfall Harry's Jungle Adventure (Jungle Runner)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3eae062a9b722bda1255d474a87eca5c", "Atari, David Crane", "CX2605, CX2605P", "Outlaw (1978) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3eb1e34a4f0eec36f12e7336badcecf2", "Jake Patterson", "", "Baubles (V0.001) (2001) (Jake Patterson) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3eb21313ea5d5764c5ed9160a5a55a83", "Activision, Alan Miller", "AX-012, CAX-012, AX-012-04", "Ice Hockey (1981) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3ec12372ca3e870b11ca70edc7ec26a4", "CommaVid, John Bronstein", "CM-002", "Video Life (1981) (CommaVid) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "3eccf9f363f5c5de0c8b174a535dc83b", "", "", "Plaque Attack (Unknown) (PAL)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3ef9573536730dcd6d9c20b6822dbdc4", "Atari, Larry Wagner, Bob Whitehead", "CX2645, CX2645P", "Video Chess (1979) (Atari) (PAL)", "AKA Computer Chess", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3f01bd6d059396f495a4cde7de0ab180", "", "", "Qb (Special Edition) (NTSC) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "3f039981255691d3859d04ef813a1264", "Xonox, John Perkins", "6230, 7210, 06004, 99004", "Artillery Duel (1983) (Xonox) [a]", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3f251c50aa7237e61a38ab42315ebed4", "Thomas Jentzsch", "", "Ikari Warriors (1990) (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3f3ad2765c874ca13c015ca6a44a40a1", "CCE", "C-862", "Crackpots (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3f540a30fdee0b20aed7288e4a5ea528", "Atari - GCC", "CX2670", "Atari Video Cube (1983) (Atari)", "AKA Atari Cube, Video Cube", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3f58f972276d1e4e0e09582521ed7a5b", "Telegames", "6082 A145", "Kung Fu Superkicks (1988) (Telegames)", "AKA Chuck Norris Superkicks", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3f5a43602f960ede330cd2f43a25139e", "Activision, Alan Miller", "AG-003", "Checkers (1980) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3f6938aa6ce66e6f42e582c1eb19b18c", "Jone Yuan Telephonic Enterprise Co", "", "Laser Blast (Jone Yuan) (4K) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3f6dbf448f25e2bd06dea44248eb122d", "", "5687 A279", "Soccer (1988) (Telegames)", "AKA International Soccer", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3f75a5da3e40d486b21dfc1c8517adc0", "Atari, Jim Huether", "CX26163P", "Sky Diver (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3f9431cc8c5e2f220b2ac14bbc8231f4", "", "", "Colors Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3f96eb711928a6fac667c04ecd41f59f", "Bit Corporation", "PGP218", "Rodeo Champ (4 Game in One Dark Green) (1983) (BitCorp) (PAL)", "AKA Stampede", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3f9cb1aba8ec20e2c243ae642f9942bf", "", "", "New Questions (1998) (John K. Harvey) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3fd1f9d66a418c9f787fc5799174ddb7", "Aaron Curtis", "", "AStar (PAL)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3fd53bfeee39064c945a769f17815a7f", "CCE", "", "Sea Hawk (CCE)", "AKA Seahawk", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3fe43915e5655cf69485364e9f464097", "CCE", "C-863", "Fisher Price (1983) (CCE)", "AKA Skindiver", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "3ff5165378213dab531ffa4f1a41ae45", "Otto Versand", "311377", "Pygmy (1983) (Otto Versand) (PAL)", "AKA Lock 'n' Chase (Double-Game Package)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4026ad38ba5ce486e88383dc27d7a46f", "Nukey Shay, Omegamatrix", "", "Double Dragon (Genesis) V2", "Genesis controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "402b1ca3c230a60fb279d4a2a10fa677", "", "", "3-D Tic-Tac-Toe (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "402d876ec4a73f9e3133f8f7f7992a1e", "Alex Herbert", "", "Man Goes Down (2006) (A. Herbert) (Prototype)", "Uses AtariVox controller", "Homebrew", "", "", "", "", "", "", "", "", "ATARIVOX", "", "", "", "", "", "" }, - { "405f8591b6941cff56c9b392c2d5e4e5", "Telegames", "", "Star Strike (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4066309eb3fa3e7a725585b9814bc375", "", "", "Multi Ball Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4066d7d88ec4a2c656127a67fa52dcf1", "", "", "Overhead Adventure Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "407a0c6cc0ff777f67b669440d68a242", "Erik Eid", "", "Euchre (Alpha) (PAL) (31-08-2002) (Erik Eid)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4093382187f8387e6d011883e8ea519b", "", "", "Go Go Home (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "40aa851e8d0f1c555176a5e209a5fabb", "", "", "Euchre (More for less) (NTSC) (22-08-2002) (Erik Eid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "40b1832177c63ebf81e6c5b61aaffd3a", "Atari, Peter C. Niday", "", "Rubik's Cube 3-D (1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "40b59249e05135bca33861e383735e9e", "Atari", "CX26163P", "Skiing (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "40d8ed6a5106245aa79f05642a961485", "Xonox - K-Tel Software - Beck-Tech, Steve Beck", "6210, 06002, 06004, 99002", "Ghost Manor (1983) (Xonox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "40d9f5709877ecf3dd1184f9791dd35e", "Dactari - Milmar", "", "Skiing (Dactari - Milmar)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "40e12c008037a323a1290c8fa4d2fe7f", "", "", "Skeleton (NTSC) (06-09-2002) (Eric Ball)", "", "", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "40eb4e263581b3dfec6dd8920b68e00f", "Sears Tele-Games, Marilyn Churchill, Matthew L. Hubbard", "CX2647 - 49-75142", "Seawolf 3 (03-23-1981) (Sears) (Prototype) (PAL)", "Submarine Commander Beta", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "413c925c5fdcea62842a63a4c671a5f2", "Activision, Larry Kaplan", "AX-006", "Bridge (1980) (Activision) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4153dd2beed648e9dc082140ebe8e836", "Thomas Jentzsch", "", "Coke Zero (v1.0) (NTSC)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "415c11fcac66bbd2ace2096687774b5a", "", "", "Fu Kung! (V0.00) (07-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4181087389a79c7f59611fb51c263137", "Atari, Suki Lee", "CX26113", "Miss Piggy's Wedding (06-24-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "41810dd94bd0de1110bedc5092bef5b0", "Funvision - Fund. International Co.", "", "Dragon Treasure (Funvision)", "AKA Dragonfire", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "41818738ab1745e879024a17784d71f5", "CCE", "C-832", "Atlantis (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4189adfc1b30c121248876e3a1a3ac7e", "Eric Ball", "", "Skeleton (Complete) (06-09-2002) (Eric Ball)", "", "New Release", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4191b671bcd8237fc8e297b4947f2990", "Exus Corporation", "", "Video Jogger (1983) (Exus)", "AKA Foot Craz", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "41b554c6970b18670acc7b6baef8ed2e", "Thomas Jentzsch", "", "Reactor - Amiga Mouse Hack v1.3 (PAL) (Half-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "41c4e3d45a06df9d21b7aae6ae7e9912", "CCE", "C-826", "Grand Prix (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "41f252a66c6301f1e8ab3612c19bc5d4", "Atari - GCC, Mike Feinstein, Brad Rice", "CX2681", "Battlezone (1983) (Atari)", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4209e9dcdf05614e290167a1c033cfd2", "CommaVid, John Bronstein", "CM-002", "Video Life (1984) (CommaVid) [higher sounds]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "42249ec8043a9a0203dde0b5bb46d8c4", "CCE", "", "Resgate Espacial (CCE)", "AKA Moonsweeper", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "4233eb824c2b4811abef9b6d00355ae9", "Retroactive", "", "Qb (V0.10) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "4251b4557ea6953e88afb22a3a868724", "Thomas Jentzsch", "", "Robot City (V1.1) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "425ee444a41d218598893d6b6e03431a", "Thomas Jentzsch", "", "Invaders Demo (2001) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4279485e922b34f127a88904b31ce9fa", "", "", "Enduro (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "428b2d36f5d716765460701f7016ac91", "Andrew Wallace", "", "Brooni (2001) (Andrew Wallace) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "42ae81ae8ac51e5c238639f9f77d91ae", "", "", "Multi-Sprite Demo 2 (Piero Cavina) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "42b2c3b4545f1499a083cfbc4a3b7640", "U.S. Games Corporation - JWDA, Todd Marshall, Robin McDaniel, Wes Trager, Henry Will IV", "VC2003", "Eggomania (1982) (U.S. Games)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "AUTO 60", "", "", "", "" }, - { "42b3ab3cf661929bdc77b621a8c37574", "Robby", "", "Volleyball (Robby)", "AKA RealSports Volleyball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "42b5e3a35b032f033809afb0ea28802d", "Atari, Mimi Nyden, Scott Smith, Robert Vieira", "CX26127", "Gremlins (03-12-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "42cdd6a9e42a3639e190722b8ea3fc51", "Activision, Alan Miller", "AG-007, CAG-007", "Tennis (1981) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "42dcc02777b0bcfacd85aeb61d33558a", "", "", "Human Cannonball (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "42e0ec5ab8f5deba53e4169ff2a5efbe", "", "", "Atari Logo Demo 5 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4311a4115fb7bc68477c96cf44cebacf", "", "", "Challenge (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4326edb70ff20d0ee5ba58fa5cb09d60", "Atari - GCC, Kevin Osborn", "CX2689", "Kangaroo (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "435fd469f088468c4d66be6b5204d887", "Atari - GCC", "CX2680, CX2680P", "RealSports Tennis (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "438968a26b7cfe14a499f5bbbbf844db", "", "", "Raft Rider (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "43adf60ebdd6b5a0fae21594ecf17154", "Jone Yuan Telephonic Enterprise Co", "", "Stampede (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "43c6cfffeddab6b3787357fed9d44529", "20th Century Fox Video Games, Frank Cohen, Douglas 'Dallas North' Neubauer", "11111", "M.A.S.H (1983) (20th Century Fox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "43f33c6dfdeaf5138ce6e6968ad7c5ce", "Jeffry Johnston", "", "Radial Pong - Version 11 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "43f8459d39fb4eddf9186d62722ff795", "", "", "Skeleton+ (17-04-2003) (Eric Ball) (PAL)", "", "", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "442602713cb45b9321ee93c6ea28a5d0", "", "", "Demon Attack (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4427f06085bb4c22ff047027f7acecc2", "Parker Brothers, Rex Bradford", "PB5000", "Star Wars - Jedi Arena (1983) (Parker Bros) (Prototype)", "Uses the Paddle Controllers (swapped)", "Prototype", "", "", "", "", "", "", "", "", "", "YES", "10 50", "", "", "", "" }, - { "442b7863683e5f084716fda050474feb", "Eckhard Stolberg", "", "Frame Timed Sound Effects-EM (Eckhard Stolberg)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4431428a7500c96fc0e2798a5dbd36d6", "", "", "Kangaroo (Genesis)", "Genesis controller (B is punch, C is jump)", "Hack of Kangaroo", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4474b3ad3bf6aabe719a2d7f1d1fb4cc", "Activision - Imagineering, Dan Kitchen, Garry Kitchen", "EAX-039-04B, EAX-039-04I", "Kung-Fu Master (1987) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4476c39736090dabac09f6caf835fc49", "", "", "Text Screen (25-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "448c2a175afc8df174d6ff4cce12c794", "Activision, David Crane", "AB-035-04", "Pitfall II (1983) (Activision) [a2]", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "44e9c4a047c348dbeb7ace60f45484b4", "", "", "Moon Patrol Arcade (Genesis)", "Genesis controller (C is jump)", "Hack of Moon Patrol", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "44f71e70b89dcc7cf39dfd622cfb9a27", "Tigervision, Robert H. O'Neil", "7-007", "Polaris (1983) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "45027dde2be5bdd0cab522b80632717d", "Epyx, Steven A. Baker, Tod Frye, Peter Engelbrite", "80561-00250", "Summer Games (1987) (Epyx)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "45040679d72b101189c298a864a5b5ba", "20th Century Fox Video Games - Sirius Software, David Lubar", "11022", "SpaceMaster X-7 (1983) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4543b7691914dfd69c3755a5287a95e1", "CommaVid, Irwin Gaines", "CM-005", "Mines of Minos (1982) (CommaVid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "456453a54ca65191781aef316343ae00", "", "", "Full Screen Bitmap (3-D Green) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4565c1a7abce773e53c75b35414adefd", "Arcadia Corporation", "", "Supercharger BIOS (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "457b03cd48ff6d895795ef043c6b0f1e", "AtariAge, Chris Spry", "CX26201", "Zippy the Porcupine (2014) (Sprybug)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "457e7d4fcd56ebc47f5925dbea3ee427", "Carrere Video - JWDA, Garry Kitchen - Teldec - Prism", "USC1001", "Space Jockey (1983) (Carrere Video) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "457f4ad2cda5f4803f122508bfbde3f5", "", "", "Canyon Bomber (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "458883f1d952cd772cf0057abca57497", "", "", "Fishing Derby (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "45a095645696a217e416e4bd2baea723", "Digivision", "", "Snoopy (Digivision)", "AKA Snoopy and the Red Baron", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "45a4f55bb9a5083d470ad479afd8bca2", "CommaVid, Joseph Biel", "", "Frog Demo (1983) (CommaVid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "45beef9da1a7e45f37f3f445f769a0b3", "Atari, Suki Lee", "CX2658", "Math Gran Prix (1982) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "45c4413dd703b9cfea49a13709d560eb", "Jone Yuan Telephonic Enterprise Co", "", "Challenge of.... Nexar, The (Jone Yuan) (Hack)", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "45cb0f41774b78def53331e4c3bf3362", "Carrere Video - JWDA, Roger Booth, Sylvia Day, Todd Marshall, Robin McDaniel, Wes Trager, Henry Will IV - Teldec - Prism", "USC1007", "Octopus (1983) (Carrere Video) (PAL)", "AKA Name This Game", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4605a00f5b44a9cbd5803a7a55de150e", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (07-03-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "461029ab23800833e9645be3e472d470", "", "", "Combat TC (v0.1)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "46258bd92b1f66f4cb47864d7654f542", "Zellers", "", "Turmoil (Zellers)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "463dd4770506e6c0ef993a40c52c47be", "Arcadia Corporation, Steve Hales, Stephen H. Landrum", "4 AR-4102", "Suicide Mission (Preview) (1982) (Arcadia)", "AKA Meteoroids", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "463e66ad98806a49106cffa49c08e2ed", "", "", "Interlace Game Demo (01-09-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "467340a18158649aa5e02a4372dcfccd", "Activision, John Van Ryzin - Ariola", "EAZ-036-04, EAZ-036-04B, EAZ-036-04I - 711 036-720", "H.E.R.O. (1984) (Activision) (PAL) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4689081b7363721858756fe781cc7713", "", "", "Oystron (V2.6) (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "468f2dec984f3d4114ea84f05edf82b6", "Tigervision - Teldec", "7-011 - 3.60015 VG", "Miner 2049er Volume II (1983) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "4690fdb70c86604bb35da26696818667", "", "", "Euchre (Release Candidate) (NTSC) (28-09-2002) (Erik Eid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "469473ff6fed8cc8d65f3c334f963aab", "Atari, Bruce Poehlman, Gary Stark", "", "Dune (07-10-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "46c021a3e9e2fd00919ca3dd1a6b76d8", "Atari, Jim Huether - Sears", "CX2629 - 6-99843, 49-75118", "Sky Diver (1979) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "46c43fdcbce8fde3a91ebeafc05b7cbd", "", "", "Invaders Demo (PAL) (2001) (Eckhard Stolberg)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "46dc526773808c8b9bb2111f24e5704c", "Omegamatrix", "", "SpaceMaster X-7 (Atari Mouse) (Omegamatrix)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "46e9428848c9ea71a4d8f91ff81ac9cc", "Telegames", "", "Astroblast (1988) (Telegames) (PAL)", "Can also use left joystick", "", "", "", "", "", "", "", "", "PADDLES", "", "YES", "AUTO 55", "", "", "", "" }, - { "4702d8d9b48a332724af198aeac9e469", "Atari, Jerome Domurat, Steve Woita", "CX2699", "Taz (1983) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "470878b9917ea0348d64b5750af149aa", "Atari, Suki Lee - Sears", "CX2658 - 49-75128", "Math Gran Prix (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "471f7bdc933e8db0e44aa3dde2dd92af", "Omegamatrix", "", "Millipede (Atari Mouse) v6.5 (Omegamatrix)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "47464694e9cce07fdbfd096605bf39d4", "Activision, Dan Kitchen", "EAK-050-04", "Double Dragon (1989) (Activision) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "47585c047802dd9af888b998fb921f32", "Omegamatrix", "", "Star Wars Arcade (Atari Trak-Ball) v4 (PAL60) (Omegamatrix)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4767356fa0ed3ebe21437b4473d4ee28", "Atari, Dan Hitchens, Mimi Nyden", "CX2685", "Gravitar (04-12-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "47711c44723da5d67047990157dcb5dd", "CCE", "", "Ice Hockey (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "47911752bf113a2496dbb66c70c9e70c", "Atari - CCW, Christopher H. Omarzu, Preston Stuart, Bruce Williams", "CX26101", "Oscar's Trash Race (1984) (Atari) (PAL)", "Uses the Keypad Controllers", "", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "" }, - { "4799a40b6e889370b7ee55c17ba65141", "Konami", "RC 100-X 02", "Pooyan (1983) (Konami)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "47aad247cce2534fd70c412cb483c7e0", "Rainbow Vision - Suntek", "SS-010", "Mafia (1983) (Rainbow Vision) (PAL)", "AKA Gangster Alley", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "47abfb993ff14f502f88cf988092e055", "Zellers", "", "Inca Gold (Zellers)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "47aef18509051bab493589cb2619170b", "", "", "Stell-A-Sketch (Bob Colbert) (PD)", "Uses Driving, Joystick, or Amiga/Atari ST Mouse Controllers", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "47b82d47e491ac7fdb5053a88fccc832", "Atari Freak 1, Franklin Cruz", "", "Asteroid 2 (Atari Freak 1) (Hack)", "Hack of Asteroids", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "47cd61f83457a0890de381e478f5cf5f", "Imagic, Wilfredo Aguilar, Michael Becker, Rob Fulop", "720111-2A, 13205", "Fathom (1983) (Imagic) (PAL)", "AKA Scuba", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "481d20ec22e7a63e818d5ef9679d548b", "Atari", "CX26163P", "Freeway Rabbit (32 in 1) (1988) (Atari) (PAL)", "AKA Freeway", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "481f9a742052801cc5f3defb41cb638e", "Jeffry Johnston", "", "Radial Pong - Version 4 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "48287a9323a0ae6ab15e671ac2a87598", "Zellers", "", "Laser Volley (Zellers)", "AKA Innerspace", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4834b7b28ea862227ac7e40053fb52a5", "Nukey Shay", "", "Montezuma's Revenge (Genesis) (F6_Conversion)", "Genesis controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "48411c9ef7e2cef1d6b2bee0e6055c27", "Telesys, Don Ruffcorn, Jack Woodman", "1003", "Fast Food (1982) (Telesys) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "484b0076816a104875e00467d431c2d2", "Atari", "CX26150", "Q-bert (1987) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4857f8bb88bb63c640d3ea5aac7f5d6d", "Atari, James Andreasen - Sears", "CX2654 - 49-75141", "Haunted House (08-12-81) (Atari) (Prototype)", "AKA Mystery Mansion, Graves' Manor, Nightmare Manor", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4868a81e1b6031ed66ecd60547e6ec85", "Eric Mooney", "", "Invaders by Erik Mooney (V2.1) (1-3-98) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "487193a7b7fe57a1bbc2f431f628bd5f", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Atari Trak-Ball Hack v1.1 (NTSC) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4884b1297500bd1243659e43c7e7579e", "Atari - Axlon, Tod Frye", "CX26178", "Save Mary! (10-24-1991) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4892b85c248131d6a42c66a4163a40d0", "Canal 3 - Intellivision", "", "Tac-Scan (Canal 3)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "YES", "", "", "YES", "AUTO 60", "", "", "", "" }, - { "48bcf2c5a8c80f18b24c55db96845472", "Activision, John Van Ryzin - Ariola", "EAZ-036-04, EAZ-036-04B, EAZ-036-04I - 711 036-720", "H.E.R.O. (1984) (Activision) (PAL) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "48e5c4ae4f2d3b62b35a87bca18dc9f5", "Quelle", "476.774 5", "Bobby geht nach Hause (1983) (Quelle) (PAL)", "AKA Bobby Is Going Home", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "48f18d69799a5f5451a5f0d17876acef", "ZiMAG - Emag - Vidco", "GN-070", "Mysterious Thief, A (1983) (ZiMAG) (Prototype) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "4901c05068512828367fde3fb22199fe", "Imagic, Rob Fulop", "720101-2B, IA3200P, EIX-006-04I", "Demon Attack (1982) (Imagic) (PAL)", "AKA Death from Above", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4904a2550759b9b4570e886374f9d092", "Parker Brothers, Charlie Heath", "931506", "Reactor (1983) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "490e3cc59d82f85fae817cdf767ea7a0", "", "", "Berzerk (Unknown) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "490eed07d4691b27f473953fbea6541a", "Activision, Steve Cartwright, David Crane", "AB-035-04", "Pitfall II (1983) (Activision) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "493daaf9fb1ba450eba6b8ed53ffb37d", "", "", "3-D Corridor Demo (27-03-2003) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "493de059b32f84ab29cde6213964aeee", "Atari, Bill Aspromonte, Andrew Fuchs", "CX26120", "Stargate (1984) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "493e90602a4434b117c91c95e73828d1", "Telegames", "", "Lock 'n' Chase (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4947c9de2e28b2f5f3b0c40ce7e56d93", "", "", "3-D Corridor Demo 2 (29-03-2003) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "494cda91cc640551b4898c82be058dd9", "Andreas Dietrich", "", "Donkey Kong VCS (2017) (1.0) (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "49571b26f46620a85f93448359324c28", "", "", "Save Our Ship (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "497c811026367c08fd838c9c59e5041d", "Omegamatrix", "", "SpaceMaster X-7 (Atari Trak-Ball) (Omegamatrix)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "497f3d2970c43e5224be99f75e97cbbb", "CommaVid, John Bronstein", "CM-002", "Video Life (1984) (CommaVid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "4981cefe5493ea512284e7f9f27d1e54", "Home Vision - Gem International Corp. - VDI", "VCS83136", "Cosmic War (1983) (Home Vision) (PAL)", "AKA Space Tunnel", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4999b45be0ab5a85bac1b7c0e551542b", "CCE", "", "Double Dragon (CCE) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "499b612f6544ae71d4915aa63e403e10", "Atari, Carol Shaw", "CX26163P", "Checkers (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "49f2cef5269fd06218be9f9474c74f8d", "Rentacom", "", "Time Pilot (Rentacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4a196713a21ef07a3f74cf51784c6b12", "Jone Yuan Telephonic Enterprise Co", "", "Frogs and Flies (Jone Yuan) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4a2fe6f0f6317f006fd6d4b34515448b", "", "", "Warring Worms (Midwest Classic Edition) (08-06-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4a45c6d75b1ba131f94a9c13194d8e46", "", "", "How to Draw a Playfield II (Joystick Hack) (1997) (Eric Bacher) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4a5fddf89801336637ac8e57a7c9a881", "Amiga", "1125", "Power Play Arcade Video Game Album IV (1984) (Amiga) (Prototype)", "Atlantis, Cosmic Ark, Dragonfire", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4a6be79310f86f0bebc7dfcba4d74161", "", "", "Demolition Herby (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "4a7eee19c2dfb6aeb4d9d0a01d37e127", "Hozer Video Games", "", "Crazy Valet (Hozer Video Games)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4a8c743396b8ad69d97e6fd3dd3e3132", "Arcadia Corporation", "", "Supercharger BIOS (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4a9009620038f7f30aaeb2a00ae58fde", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (3 of 3) (1983) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4ab2ebd95a8f861ea451abebdad914a5", "Nukey Shay, Thomas Jentzsch", "PAL conversion (F6)", "Montezuma's Revenge (PAL) (Genesis)", "Genesis controller (B jumps left, C jumps right)", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4ab4af3adcdae8cdacc3d06084fc8d6a", "Nick Bensema", "", "Sucky Zepplin (Nick Bensema) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4abb4c87a4c5f5d0c14ead2bb36251be", "Atari - Imagineering, Alex DeMeo", "CX26135, CX26135P", "RealSports Boxing (1987) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4ac9f40ddfcf194bd8732a75b3f2f214", "Atari - CCW, Stephan R. Keith, Laura Scholl, Preston Stuart", "CX26106", "Grover's Music Maker (12-29-1982) (Atari) (Prototype)", "Uses Keypad Controller", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4ae8c76cd6f24a2e181ae874d4d2aa3d", "", "", "Flash Gordon (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4af4103759d603c82b1c9c5acd2d8faf", "Imagic, Bob Smith", "720114-2A, 13207, EIZ-001-04I", "Moonsweeper (1983) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "4afa7f377eae1cafb4265c68f73f2718", "Ed Fries", "", "Halo 2600 (2010) (Ed Fries)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4afe528a082f0d008e7319ebd481248d", "", "", "Multi-Color Demo 1 (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4b143d7dcf6c96796c37090cba045f4f", "Atari, Jim Huether - Sears", "CX2644 - 6-99824", "Flag Capture (1978) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4b205ef73a5779acc5759bde3f6d33ed", "", "", "Berzerk (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4b27f5397c442d25f0c418ccdacf1926", "Atari, Warren Robinett", "CX2613, 49-75154", "Adventure (1980) (Atari) (PAL)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4b379b885e2694f992c6cc932f18327f", "Omegamatrix", "", "SpaceMaster X-7 (Atari Mouse) (PAL60) (Omegamatrix)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4b71197153d651480830638cb6a03249", "Atari, Larry Kaplan", "CX26163P", "Bowling (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4b753a97aee91e4b3e4e02f5e9758c72", "Glenn Saunders, Roger Williams", "", "Asymmetric Reflected Playfield (Glenn Saunders)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4b94fd272785d7ec6c95fb7279d0f522", "Atari - CCW, Christopher H. Omarzu, Preston Stuart, Bruce Williams", "CX26101", "Oscar's Trash Race (12-03-1982) (Atari) (Prototype)", "Uses the Keypad Controllers", "Prototype", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "" }, - { "4b9581c3100a1ef05eac1535d25385aa", "", "", "IQ 180 (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4baada22435320d185c95b7dd2bcdb24", "Atari, Jerome Domurat, Dave Staugas", "CX2682", "Krull (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4bcc7f6ba501a26ee785b7efbfb0fdc8", "Atari, Andrew Fuchs, Courtney Granner, Jeffrey Gusman, Mark R. Hahn", "CX2690", "Pengo (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4bdae9246d6ee258c26665512c1c8de3", "Atari", "CX26163P", "Human Cannonball (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4bdf54a454470ba015a217a8f5e61320", "Omegamatrix", "", "Millipede (Amiga Mouse) v6.5 (Omegamatrix)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, - { "4c030667d07d1438f0e5c458a90978d8", "Retroactive", "", "Qb (V2.03) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "4c0fb2544ae0f8b5f7ae8bce7bd7f134", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix (Preview) (1983) (Arcadia)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4c205f166157154df2f1ef60d87e552f", "", "", "Single-Scanline Positioning Demo 2 (2001) (Roger Williams)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4c39a2c97917d3d71739b3e21f60bba5", "", "", "Whale (Sub Scan Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4c462b2b6fb0a19a1437eb2c3dc20783", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (1 of 3) (1983) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4c4ce802cbfd160f7b3ec0f13f2a29df", "", "", "Beta Demo (V1.1) (26-09-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4c606235f4ec5d2a4b89139093a69437", "Andrew Davies", "", "Andrew Davies early notBoulderDash demo (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "4c6afb8a44adf8e28f49164c84144bfe", "CCE", "C-806", "Mission 3,000 A.D. (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4c8832ed387bbafc055320c05205bc08", "Atari, Joe Decuir, Steve Mayer, Larry Wagner - Sears", "CX2601 - 99801, 6-99801, 49-75124", "Combat (1977) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4c8970f6c294a0a54c9c45e5e8445f93", "Xonox - K-Tel Software - Product Guild, Anthony R. Henderson", "99006, 6220", "Sir Lancelot (1983) (Xonox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4c9307de724c36fd487af6c99ca078f2", "Imagic, Brad Stewart", "720106-1A, IA3409", "Sky Patrol (1982) (Imagic) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4ca0959f846d2beada18ecf29efe137e", "Atari, Jim Huether, Alan J. Murphy, Robert C. Polaro", "CX2666, CX2666P", "RealSports Volleyball (1982) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4ca73eb959299471788f0b685c3ba0b5", "Activision, Steve Cartwright", "AX-031", "Frostbite (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4ca90ba45eced6f5ad560ea8938641b2", "", "", "Hangman Man Wordlist (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4cabc895ea546022c2ecaa5129036634", "Funvision - Fund. International Co.", "", "Ocean City (Funvision)", "AKA Atlantis", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4cd796b5911ed3f1062e805a3df33d98", "Tigervision - Software Electronics Corporation - Teldec", "7-006", "Springer (1983) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4d06f72cc3d8934579c11ff8f375c260", "Bit Corporation", "R320", "Bowling (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4d0a28443f7df5f883cf669894164cfa", "", "", "Beast Invaders (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4d2cef8f19cafeec72d142e34a1bbc03", "HES", "771-422", "2 Pak Special - Star Warrior, Frogger (1990) (HES) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4d38e1105c3a5f0b3119a805f261fcb5", "Bit Corporation", "PGP212", "Phantom UFO (4 Game in One Light Green) (1983) (BitCorp) (PAL)", "AKA Spider Fighter", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4d502d6fb5b992ee0591569144128f99", "Atari - Axlon, Tod Frye", "CX26178", "Save Mary! (11-21-1989) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4d5f6db55f7f44fd0253258e810bde21", "Fabrizio Zavagli", "", "Betterblast (Fabrizio Zavagli) (Hack)", "Hack of Astroblast", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4d7517ae69f95cfbc053be01312b7dba", "Atari, Alan Miller - Sears", "CX2641 - 99807, 49-75105", "Surround (1977) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4d77f291dca1518d7d8e47838695f54b", "Data Age", "DA1004", "Airlock (1982) (Data Age)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4d8396deeabb40b5e8578276eb5a8b6d", "Otto Versand", "781698", "Volleyball (1983) (Otto Versand) (PAL)", "AKA RealSports Volleyball (Double-Game Package)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4dbd7e8b30e715efc8d71d215aec7fe7", "Bit Corporation", "R320", "Air Raiders (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4dbf47c7f5ac767a3b07843a530d29a5", "Ric Pryor", "", "Breaking News (2002) (Ric Pryor) (Hack)", "Hack of Bump 'n' Jump", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4dcc7e7c2ec0738e26c817b9383091af", "", "", "Unknown Title (bin00026 (200110)) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4dd6c7ab9ef77f2b4950d8fc7cd42ee1", "Retroactive", "", "Qb (V2.04) (Stella) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "4df6124093ccb4f0b6c26a719f4b7706", "Atari, Brad Stewart - Sears", "CX2622 - 6-99813, 49-75107", "Breakout (1978) (Atari) [a]", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "01 60", "", "", "", "" }, - { "4df9d7352a56a458abb7961bf10aba4e", "", "", "Racing Car (Unknown)", "", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "" }, - { "4e01d9072c500331e65bb87c24020d3f", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX26119", "Saboteur (06-15-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4e02880beeb8dbd4da724a3f33f0971f", "Imagic, Michael Greene", "EIZ-002-04I", "Wing War (1983) (Imagic) (PAL)", "AKA Flap!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4e15ddfd48bca4f0bf999240c47b49f5", "Avalon Hill, Jean Baer, Jim Jacob", "5001002", "Death Trap (1983) (Avalon Hill)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "4e2c884d04b57b43f23a5a2f4e9d9750", "", "", "Baby Center Animation (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "4e37992a37ea36489283f7eb90913bbc", "Kris", "", "Hangman Ghost Halloween (Kris) (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4e4895c3381aa4220f8c2795d6338237", "", "", "Backwards Cannonball v1 (Hack)", "Hack of Human Cannonball", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4e66c8e7c670532569c70d205f615dad", "Atari - GCC", "CX2680, CX2680P", "RealSports Tennis (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4e86866d9cde738d1630e2e35d7288ce", "Supergame", "", "River Raid III (Supergame)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4e99ebd65a967cabf350db54405d577c", "Coleco", "2663", "Time Pilot (1983) (Coleco) [b1]", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4eb4fd544805babafc375dcdb8c2a597", "Inspirational Video Concepts, Steve Shustack", "321430", "Red Sea Crossing (1983) (Inspirational Video Concepts)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4edb251f5f287c22efc64b3a2d095504", "Atari", "", "Atari VCS Point-of-Purchase ROM (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4f0071946e80ca68edfdccbac86dcce0", "", "", "Virtual Pet Demo 1 (CRACKERS) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4f2d47792a06da224ba996c489a87939", "HES - Activision", "223", "Super Action Pak - Pitfall, Barnstorming, Grand Prix, Laser Blast (1988) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4f32b24869d8c1310fecf039c6424db6", "U.S. Games Corporation - JWDA, Todd Marshall", "", "3-D Zapper (12-15-82) (U.S. Games) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "4f618c2429138e0280969193ed6c107e", "Activision, Alan Miller", "AZ-028, AG-028-04", "Robot Tank (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4f634893d54e9cabe106e0ec0b7bdcdf", "Retroactive", "", "Qb (2.14) (Retroactive) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "4f64d6d0694d9b7a1ed7b0cb0b83e759", "20th Century Fox Video Games, John Russell", "11016", "Revenge of the Beefsteak Tomatoes (1983) (20th Century Fox)", "AKA Revenge of the Cherry Tomatoes", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4f6702c3ba6e0ee2e2868d054b00c064", "Activision - Woodside Design Associates, Steve 'Jessica Stevens' Kitchen - Ariola", "EAZ-033 - 711 033-725", "Space Shuttle (1983) (Activision) (PAL)", "A Journey Into Space, Eine Reise ins All", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4f781f0476493c50dc578336f1132a67", "", "", "Indy 500 (Unknown) (PAL) (4K)", "Uses Driving Controllers", "", "", "", "", "", "", "", "", "DRIVING", "DRIVING", "", "45", "", "", "", "" }, - { "4f7b07ec2bef5ccffe06403a142f80db", "Apollo - Games by Apollo, Ed Salvo, Byron Parks", "AP-2003", "Racquetball (1982) (Apollo) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "4f82d8d78099dd71e8e169646e799d05", "", "", "Miniature Golf (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4f89b897444e7c3b36aed469b8836839", "Atari", "CX26190", "BMX Air Master (1989) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4fae08027365d31c558e400b687adf21", "", "", "Qb (V2.17) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "4faeb04b1b7fb0fa25db05753182a898", "", "", "2600 Digital Clock (V x.xx) (PD) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4fbe0f10a6327a76f83f83958c3cbeff", "CCE", "C-816", "Keystone Kappers (1983) (CCE)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "4fc1b85b8074b4b9436d097900e34f29", "John K. Harvey", "", "John K. Harvey's Equalizer (John K. Harvey)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "50200f697aeef38a3ce31c4f49739551", "Mystique - American Multiple Industries, Joel H. Martin", "", "Custer's Revenge (1982) (Mystique) (PAL60)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "502044b1ac111b394e6fbb0d821fca41", "", "", "Hangman Invader 4letter (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "502168660bfd9c1d2649d415dc89c69d", "Activision, Bob Whitehead - Ariola", "EAG-019, EAG-019-04I - 711 019-715", "Sky Jinks (1982) (Activision) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "504688d49a41bf03d8a955512609f3f2", "Thomas Jentzsch", "", "SWOOPS! (v0.94) (TJ)", "Uses the Joystick (L) and Paddle (R) Controllers", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "50568c80ac61cab789d9923c9b05b68e", "Ebivision", "", "Merlin's Walls - Standard Edition (1999) (Ebivision)", "Image rotated 90 degrees CW", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5069fecbe4706371f17737b0357cfa68", "Apollo - Games by Apollo, Steve Stringfellow", "AP-2005", "Shark Attack (1982) (Apollo) (PAL)", "AKA Lochjaw", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5079bfbc7b8f5770f84215ed2e3bdd1b", "Omegamatrix (2012)", "", "Genesis Button Tester", "", "Homebrew", "", "", "", "", "", "", "", "GENESIS", "GENESIS", "", "", "", "", "", "" }, - { "50a410a5ded0fc9aa6576be45a04f215", "Activision, Bob Whitehead - Ariola", "EAG-019, EAG-019-04I - 711 019-715", "Sky Jinks (1982) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "50c7edc9f9dc0369abcdab3b4efeb5e9", "U.S. Games Corporation - JWDA, Todd Marshall", "", "3-D Zapper (U.S. Games) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "50ef88f9a5e0e1e6b86e175362a27fdb", "", "", "Multi-Sprite Game V2.4 (Piero Cavina) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "512e874a240731d7378586a05f28aec6", "Tigervision, Rorke Weigandt - Teldec", "7-005", "Marauder (1982) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5131ab3797fe8c127e3e135b18b4d2c8", "Activision, David Crane", "AG-004", "Fishing Derby (1980) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "514f911ecff2be5eeff2f39c49a9725c", "Parker Brothers", "931510", "Sky Skipper (1983) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "515046e3061b7b18aa3a551c3ae12673", "Atari - GCC, Mark Ackerman, Noellie Alito", "CX2692", "Moon Patrol (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "516ffd008057a1d78d007c851e6eff37", "Parker Brothers, Dawn Stockbridge", "PB5910", "Strawberry Shortcake - Musical Match-Ups (1983) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "517592e6e0c71731019c0cebc2ce044f", "Parker Brothers - JWDA, Todd Marshall", "PB5550", "Q-bert's Qubes (1984) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "517923e655755086a3b72c0b17b430e6", "Tron", "", "Super Tennis (Tron)", "AKA RealSports Tennis", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5188fee071d3c5ef0d66fb45c123e4a5", "Gameworld", "133-001", "Encounter at L-5 (1983) (Gameworld) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "AUTO 50", "", "", "", "" }, - { "519f007c0e14fb90208dbb5199dfb604", "Amiga - Video Soft", "", "Depth Charge (1983) (Amiga) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "51c1ddc9d6d597f71fb7efb56012abec", "Bit Corporation", "R320", "Lock 'n' Chase (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "51de328e79d919d7234cf19c1cd77fbc", "Atari, Mark R. Hahn", "CX2678", "Dukes of Hazzard (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "51e390424f20e468d2b480030ce95d7b", "Video Game Program", "", "Fire Bird (Video Game Program) (PAL)", "AKA Phoenix", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "51f15b39d9f502c2361b6ba6a73464d4", "", "", "Amanda Invaders (PD) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "51f211c8fc879391fee26edfa7d3f11c", "Activision, Bob Whitehead", "AX-015, AX-015-04", "Chopper Command (1982) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "521f4dd1eb84a09b2b19959a41839aad", "Bit Corporation", "PG206", "Bobby Is Going Home (1983) (BitCorp)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "522b27a8afeb951b5a5a667f8d1a46a1", "Omegamatrix", "", "Millipede (Amiga Mouse) v6.5 (Omegamatrix)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "522c9cf684ecd72db2f85053e6f6f720", "Rainbow Vision - Suntek", "SS-008", "Year 1999, The (1983) (Rainbow Vision) (PAL)", "AKA Condor Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "52385334ac9e9b713e13ffa4cc5cb940", "CCE", "C-804", "Open, Sesame! (1983) (CCE)", "AKA Abre-te, Sesamo!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "523f5cbb992f121e2d100f0f9965e33f", "Joe Grand", "", "SCSIcide (1.30) (CGE 2001 Release) (Joe Grand)", "Uses the Paddle Controllers", "New Release", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "AUTO 65", "", "", "", "" }, - { "524693b337f7ecc9e8b9126e04a232af", "", "", "Euchre (19-08-2001) (Eric Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5256f68d1491986aae5cfdff539bfeb5", "Atari - GCC, Mark Ackerman, Noellie Alito", "CX2692", "Moon Patrol (07-26-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "525ea747d746f3e80e3027720e1fa7ac", "Activision, Garry Kitchen - Ariola", "EAZ-032 - 771 032-712", "Pressure Cooker (1983) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "525f2dfc8b21b0186cff2568e0509bfc", "Activision, David Crane", "AG-930-04, AZ-030", "Decathlon (1983) (Activision) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "52615ae358a68de6e76467e95eb404c7", "", "", "DJdsl-wopd (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "528400fad9a77fd5ad7fc5fdc2b7d69d", "Starpath Corporation, Stephen H. Landrum, Jon Leupp", "11 AR-4201", "Sword of Saros (1983) (Starpath)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "52a0003efb3b1c49fcde4dbc2c685d8f", "Atari, Alan Miller - Sears", "CX2641 - 99807, 49-75105", "Surround (1977) (Atari) (4K) [a]", "", "", "", "", "2K", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "52b448757081fd9fabf859f4e2f91f6b", "", "", "Worm War I (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "52bae1726d2d7a531c9ca81e25377fc3", "", "", "Space Instigators (V1.8 Fixed) (20-10-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "52e1954dc01454c03a336b30c390fb8d", "Retroactive", "", "Qb (2.14) (Retroactive) (Stella)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "52e9db3fe8b5d336843acac234aaea79", "", "", "Fu Kung! (V0.11) (28-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5305f69fbf772fac4760cdcf87f1ab1f", "Jone Yuan Telephonic Enterprise Co", "", "Ski Run (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5324cf5b6dc17af4c64bf8696c39c2c1", "Imagic, Dennis Koble", "IA3203, IX-010-04", "Atlantis (1982) (Imagic) (8K)", "AKA Lost City of Atlantis", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "533661e9bccd8a9f80ce3765f282c92f", "Omegamatrix", "", "Star Wars Arcade (Atari Trak-Ball) (Y Inverted) v4 (Omegamatrix)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5336f86f6b982cc925532f2e80aa1e17", "Parker Brothers - JWDA, Todd Marshall, Robin McDaniel, Ray Miller", "PB5060", "Star Wars - Death Star Battle (1983) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "534e23210dd1993c828d944c6ac4d9fb", "M Network, Stephen Tatsumi, Jane Terjung - Kool Aid", "MT4648", "Kool-Aid Man (1983) (M Network)", "AKA Kool Aid Pitcher Man", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5355f80cacf0e63a49cbf4ade4e27034", "Christian Samuel", "", "Cute Dead Things House (Christian Samuel) (Hack)", "Hack of Haunted House", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5360693f1eb90856176bd1c0a7b17432", "", "", "Oystron (V2.85) (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "536bf56baa70acb17113884ac41f2820", "Atari, Omegamatrix", "", "Video Olympics Menu (2020) (PAL) (Hack)", "Hack of Video Olympics", "", "", "", "", "", "", "", "", "", "", "YES", "AUTO 60", "", "", "", "" }, - { "537ed1e0d80e6c9f752b33ea7acbe079", "", "", "A-VCS-tec Challenge (beta 5) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5385cf2a04de1d36ab55c73174b84db0", "Paul Slocum", "", "Combat Rock (PD) (Hack)", "Hack of Combat", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "539d26b6e9df0da8e7465f0f5ad863b7", "Atari, Carol Shaw - Sears", "CX2636 - 49-75156", "Video Checkers (1980) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "539f3c42c4e15f450ed93cb96ce93af5", "Dion Olsthoorn", "v1.3", "Amoeba Jump (2018) (Dionoid)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "53b66f11f67c3b53b2995e0e02017bd7", "CCE", "C-1005", "Super Tennis (1983) (CCE)", "AKA RealSports Tennis", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "53bd1c7c972ae634c912331a9276c6e3", "Atari, Nick 'Sandy Maiwald' Turner", "CX2665", "Frog Pond (1982) (Atari) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "53d181cde2e0219b5754caad246fcb66", "", "", "Missile Demo (1998) (Ruffin Bailey) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "53e03df47e76329b701641f8bdc206f5", "Thomas Jentzsch", "", "Centipede - Atari Trak-Ball Hack v1.4 (PAL) (Half-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "53f147b9746fdc997c62f3dd67888ee5", "Activision, Bob Whitehead", "AG-011", "Stampede (1981) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "540075f657d4b244a1f74da1b9e4bf92", "Bit Corporation", "PGP230", "Festival (4 Game in One Dark Green) (1983) (BitCorp) (PAL)", "AKA Carnival", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5409d20c1aea0b89c56993aec5dc5740", "", "", "Carnival Shooter (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "541cac55ebcf7891d9d51c415922303f", "SpiceWare - Darrell Spice Jr.", "SW-05", "Stay Frosty 2", "AtariAge Holiday Greetings 2014", "Homebrew", "", "", "", "", "", "", "", "JOYSTICK", "", "", "", "", "", "YES", "" }, - { "5428cdfada281c569c74c7308c7f2c26", "Activision, Larry Kaplan, David Crane", "AG-010, AG-010-04", "Kaboom! (1981) (Activision)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, - { "542c6dd5f7280179b51917a4cba4faff", "ZiMAG - Emag - Vidco", "GN-080", "Spinning Fireball (1983) (ZiMAG) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5438e84b90e50a5362f01cc843b358d4", "Arcadia Corporation, Scott Nelson", "3 AR-4300", "Fireball (1982) (Arcadia) (Prototype)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "543b4b8ff1d616fa250c648be428a75c", "Warren Robinett", "", "Adventure (1978) (Warren Robinett) (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "545048ccb045f9efc6cf2b125cd0dfa8", "Arcadia Corporation, Stephen Harland Landrum, Jon Leupp", "AR-4201", "Sword of Saros (1983) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "54785fa29e28aae6038929ba29d33d38", "", "", "Poker Squares (V0.19) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "54836a8f23913e9a77c7f2665baf36ac", "Bit Corporation", "PG204", "Open, Sesame! (1982) (BitCorp)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5494b9ee403d9757f0fd1f749e80214a", "Larry Petit", "", "Xenophobe Arcade (2003) (Larry Petit) (Hack)", "Hack of Xenophobe", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "54a1c1255ed45eb8f71414dadb1cf669", "Spectravideo", "SA-212", "Mangia' (1983) (Spectravideo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "54bafc299423f5a50b8bc3a797914706", "SOLID Corp. (D. Scott Williamson)", "CX2655*", "Star Castle 2600 (SolidCorp) (PAL)", "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "54da3b0b3f43f5b37911c135b9432b49", "", "", "Halloween III Revision (Hack)", "Hack of Kaboom!", "Hack", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, - { "54f7efa6428f14b9f610ad0ca757e26c", "Apollo - Games by Apollo, Steve Stringfellow", "AP-2005", "Shark Attack (1982) (Apollo)", "AKA Lochjaw", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "551a64a945d7d6ece81e9c1047acedbc", "Matthias Jaap", "", "Coffee Cup Soccer (Matthias Jaap) (Hack)", "Hack of Pele's Soccer", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5524718a19107a04ec3265c93136a7b5", "Thomas Jentzsch", "", "RealSports Basketball (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "553dbf9358cfd2195e2fa0e08b01fb6a", "Atari - GCC, Mike Feinstein, Kevin Osborn", "CX2691", "Joust (07-05-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "554fd5775ca6d544818c96825032cf0d", "Atari - Roklan, Bob Curtiss", "", "Firefox (06-01-83) (Atari) (Prototype)", "AKA Combat II, Fighter Command", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "557e893616648c37a27aab5a47acbf10", "Atari - Axlon, Tod Frye - Heuristica, Augustin Ortiz", "CX26169", "Shooting Arcade (01-16-1990) (Atari) (Prototype) (PAL)", "Uses the Light Gun Controller (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "559317712f989f097ea464517f1a8318", "Panda", "100", "Space Canyon (1983) (Panda)", "AKA Space Cavern", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "55949cb7884f9db0f8dfcf8707c7e5cb", "Atari, Ed Logg, Carol Shaw - Sears", "CX2639 - 49-75162", "Othello (1981) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "55ace3c775f42eb46f08bb1dca9114e7", "", "", "Shadow Keep (04-03-2003) (Andrew Towers)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "55ef6ab2321ca0c3d369e63d59c059c8", "", "", "Pitfall! (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "55ef7b65066428367844342ed59f956c", "Atari - Roklan, Joe Gaucher, Alex Leavens", "CX2683", "Crazy Climber (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "56210a3b9ea6d5dd8f417a357ed8ca92", "Probe 2000 - NAP, Roger Booth, Todd Marshall, Robin McDaniel, Jim Wickstead", "3152VC", "Pursuit of the Pink Panther (Probe) (Prototype) [bad dump]", "AKA Adventures of the Pink Panther", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "56300ed31fef018bd96768ccc982f7b4", "HES - Activision", "559", "Rad Action Pak - Kung-Fu Master, Freeway, Frostbite (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5641c0ff707630d2dd829b26a9f2e98f", "Joystik", "", "Motocross (Joystik)", "AKA Motocross Racer", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5643ee916f7dc760148fca4db3aa7d10", "", "", "Moon Patrol (Genesis)", "Genesis controller (C is jump)", "Hack of Moon Patrol", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5678ebaa09ca3b699516dba4671643ed", "Coleco, Sylvia Day, Henry Will IV", "2459", "Mouse Trap (1982) (Coleco)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "568371fbae6f5e5b936af80031cd8888", "", "", "Robotfindskitten2600 (26-04-2003) (Jeremy Penner)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "56f72247eb9ebfd33bfd0cca23ab7ef4", "Omegamatrix", "", "Star Wars Arcade (Amiga Mouse) v4 (PAL60) (Omegamatrix)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "571c6d9bc71cb97617422851f787f8fe", "Activision, David Crane - Ariola", "EAG-004, PAG-004 - 711 004-715", "Fishing Derby (1980) (Activision) (PAL)", "AKA Schneller als der Hai", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "572d0a4633d6a9407d3ba83083536e0f", "Funvision - Fund. International Co.", "", "Busy Police (Funvision)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "575c0fb61e66a31d982c95c9dea6865c", "", "", "Blackjack (Unknown) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "", "", "" }, - { "57939b326df86b74ca6404f64f89fce9", "Atari, Sam Comstock, Richard Dobbis, Nick 'Sandy Maiwald' Turner", "CX26111", "Snoopy and the Red Baron (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "579baa6a4aa44f035d245908ea7a044d", "Jess Ragan", "", "Galaxian Enhanced Graphics (Jess Ragan) (Hack)", "Hack of Galaxian", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "57a66b6db7efc5df17b0b0f2f2c2f078", "Retroactive", "", "Qb (V2.08) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "57c5b351d4de021785cf8ed8191a195c", "Atari - CCW, Gary Stark", "CX26102", "Cookie Monster Munch (1983) (Atari)", "Uses Kids/Keypad Controllers", "", "", "", "", "", "", "", "", "", "KEYBOARD", "", "", "", "", "", "" }, - { "5835a78a88f97acea38c964980b7dbc6", "", "", "Cosmic Creeps (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "5846b1d34c296bf7afc2fa05bbc16e98", "Atari - Sears", "CX2643 - 6-99815", "Codebreaker (1978) (Atari)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "58513bae774360b96866a07ca0e8fd8e", "Mystique - American Multiple Industries, Joel H. Martin", "1001", "Custer's Revenge (1982) (Mystique)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "585600522b1f22f617652c962e358a5d", "", "", "Multi-Sprite Game V2.2 (Piero Cavina) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "585f73010e205ae5b04ee5c1a67e632d", "", "", "Daredevil (V3) (Stunt_Cycle_Rules!) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5864cab0bc21a60be3853b6bcd50c59f", "", "", "Commando Raid (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "58746219d8094edff869f0f5c2aeaad5", "Jone Yuan Telephonic Enterprise Co", "", "Bowling (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5894c9c0c1e7e29f3ab86c6d3f673361", "Activision - Woodside Design Associates, Steve 'Jessica Stevens' Kitchen", "AZ-033, AZ-033-04", "Space Shuttle (1983) (Activision)", "A Journey Into Space", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "589c73bbcd77db798cb92a992b4c06c3", "Xonox - K-Tel Software - Action Graphics, Michael Schwartz, David Thiel", "6230, 7210, 06004, 99004", "Artillery Duel (1983) (Xonox) (PAL60)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "58a82e1da64a692fd727c25faef2ecc9", "CCE", "C-824", "Jaw Breaker (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "58c396323ea3e85671e34c98eb54e2a4", "Brian Watson", "", "Color Tweaker (B. Watson)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "58d331c23297ed98663d11b869636f16", "", "", "Fu Kung! (V0.09) (26-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "58e313e2b5613b2439b5f12bb41e3eef", "", "", "Cube Conquest (Demo Interlace) (Billy Eno) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "590ac71fa5f71d3eb29c41023b09ade9", "Atari - GCC, Mark Ackerman, Tom Calderwood, Glenn Parker", "CX2684", "Galaxian (01-05-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "59135f13985b84c4f13cc9e55eec869a", "", "", "Multi-Sprite Game V2.0 (Piero Cavina) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "594437a35603c3e857b5af75b9718b61", "HES - Activision", "", "Robot Tank (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "594dbc80b93fa5804e0f1368c037331d", "Telesys, Alex Leavens", "", "Bouncin' Baby Bunnies (1983) (Telesys) (Prototype)", "AKA Baby Boom Boom, Bouncing Baby Monkeys", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5961d259115e99c30b64fe7058256bcf", "Universal Gamex Corporation, Miguel Castillo, H.K. Poon", "GX-001", "X-Man (1983) (Universal)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "59734e1cc41822373845a09c51e6ba21", "Activision, John Van Ryzin", "AG-038-04", "Cosmic Commuter (1984) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "598a4e6e12f8238b7e7555f5a7777b46", "Tigervision", "7-008", "Miner 2049er (1983) (Tigervision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "599cbf919d47a05af975ad447df29497", "Jake Patterson", "", "Baubles (V0.002) (2001) (Jake Patterson) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "59b70658f9dd0e2075770b07be1a35cf", "Thomas Jentzsch", "", "Surfer's Paradise (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "59d33e00c07665395209c1e55da0b139", "", "", "Imagic Selector ROM (1982) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "59e53894b3899ee164c91cfa7842da66", "Data Age", "", "Survival Run (1983) (Data Age) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "59e96de9628e8373d1c685f5e57dcf10", "PlayAround - J.H.M.", "204", "Beat 'Em & Eat 'Em (1982) (PlayAround)", "Uses the Paddle Controllers", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "AUTO 45", "", "", "", "" }, - { "59f596285d174233c84597dee6f34f1f", "CCE", "C-811", "River Raid (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5a0ff99ba10bd26d542e1d6f59f56850", "Champ Games", "CG-04-P", "Super Cobra Arcade (PAL60)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "JOYSTICK", "", "", "", "", "", "YES", "" }, - { "5a17e30e6e911e74ccd7b716d02b16c6", "Activision, Dan Kitchen", "AX-029", "Crackpots (1983) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5a272012a62becabcd52920348c7c60b", "Star Game", "", "Pitfall (Star Game)", "AKA Pitfall!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5a2f2dcd775207536d9299e768bcd2df", "Otto Versand", "781698", "Flippern (Double-Game Package) (1983) (Otto Versand) (PAL)", "AKA Video Pinball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5a4205aeedd3b0588f973f38bbd9dfd4", "Thomas Jentzsch", "", "Centipede - Amiga Mouse Hack v1.4 (PAL) (Full-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5a5390f91437af9951a5f8455b61cd43", "Retroactive", "", "Qb (0.11) (Retroactive) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "5a6febb9554483d8c71c86a84a0aa74e", "CCE", "C-1003", "Donkey Kong Jr (1983) (CCE)", "AKA Donkey Kong Junior", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5a734779d797ccef25dc8acfa47244c7", "", "", "Oh No! (Version 2) (18-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5a80b857eb8b908ab477ec4ef902edc8", "Activision, Bob Whitehead", "AG-002, CAG-002, AG-002-04", "Boxing (1980) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5a81ad4e184050851e63c8e16e3dac77", "Jone Yuan Telephonic Enterprise Co", "Hack", "Sky Diver (Jone Yuan) (Hack)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5a8afe5422abbfb0a342fb15afd7415f", "Atari - Bobco, Robert C. Polaro", "CX26155", "Sprint Master (1988) (Atari)", "AKA Sprint 88, Sprint 2000", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5a93265095146458df2baf2162014889", "Activision, Steve Cartwright - Ariola", "EAX-031, EAX-031-04B - 711 031-717", "Frostbite (1983) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5a9685c4d51a6c1d6a9544946d9e8dc3", "AtariAge", "", "Grandma's Revenge (AtariAge)", "Can use Driving Controller in right port", "", "", "", "", "", "", "", "", "", "DRIVING", "", "", "", "", "", "" }, - { "5a9d188245aff829efde816fcade0b16", "CCE", "C-808", "Phantom Tank (1983) (CCE) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5acf9865a72c0ce944979f76ff9610f0", "", "", "Dodge Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5ae73916fa1da8d38ceff674fa25a78a", "CCE", "", "Barnstorming (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5aea9974b975a6a844e6df10d2b861c4", "Atari, Dan Hitchens. Mimi Nyden", "CX2656", "SwordQuest - EarthWorld (1982) (Atari)", "AKA Adventure I, SwordQuest I - EarthWorld", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5af9cd346266a1f2515e1fbc86f5186a", "SEGA", "002-01", "Sub-Scan (1983) (SEGA)", "AKA Subterfuge", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5b124850de9eea66781a50b2e9837000", "PlayAround - J.H.M.", "205", "Bachelor Party (1982) (PlayAround)", "Uses the paddle controllers", "Extremely Rare", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "AUTO 65", "", "", "YES", "" }, - { "5b574faa56836da0866ba32ae32547f2", "", "", "Tomb Raider 2600 [REV 03] (Montezuma's Revenge Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5b5d04887922b430de0b7b2a21f9cd25", "", "", "Omega Race (Genesis)", "Genesis controller (B is thrust, C is fire)", "Hack of Omega Race", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5b6f5bcbbde42fc77d0bdb3146693565", "", "", "Seaquest (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5b7ea6aa6b35dc947c65ce665fde624b", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (2 of 3) (1982) (Starpath)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5b85e987e2b1618769d97ba9182333d0", "Atari - GCC, Mike Feinstein, Brad Rice", "CX2681", "Battlezone (05-12-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5b92a93b23523ff16e2789b820e2a4c5", "Activision - Imagineering, Dan Kitchen, Garry Kitchen", "AG-039-04", "Kung-Fu Master (1987) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5b98e0536c3f60547dd708ae22adb04b", "Ben Hudman", "", "Donkey Kong Gingerbread Man (Ben Hudman) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5b9c2e0012fbfd29efd3306359bbfc4a", "HES", "", "2 Pak Special - Hoppy, Alien Force (1992) (HES) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5babe0cad3ec99d76b0aa1d36a695d2f", "Coleco - Individeo, Ed Temple", "2654", "Looping (1983) (Coleco) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5bba254e18257e578c245ed96f6b003b", "", "", "Music Effects Demo (21-01-2003) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "5bbab3f3e4b47e3e23f9820765dbb45c", "", "", "Pitfall! (says 1985) [h1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5bbb75b49b2bccef9c91ff84bb249c80", "Thomas Jentzsch", "", "Missile Control - Atari Trak-Ball Hack v1.15 (NTSC) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5bc9998b7e9a970e31d2cb60e8696cc4", "Jack Kortkamp", "", "Borgwars Asteroids (2003) (Jack Kortkamp) (Hack)", "Hack of Asteroids", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "5bcc83677d68f7ef74c1b4a0697ba2a8", "Activision, Alan Miller", "AX-012, CAX-012, AX-012-04", "Ice Hockey (1981) (Activision) (16K)", "", "", "", "", "4K", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5bd79139a0c03b63f6f2cf00a7d385d2", "Marc de Smet", "", "An Exercise In Minimalism (V1) (1999) (Marc de Smet) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5be03a1fe7b2c114725150be04b38704", "Atari, Alan Miller", "CX2642", "Hunt & Score (1978) (Atari) (PAL)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5c0227ad63300670a647fcebf595ea37", "Josh", "", "Battle for Naboo (Josh) (Hack)", "Hack of Atlantis", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5c0520c00163915a4336e481ca4e7ef4", "Rainbow Vision - Suntek", "SS-004", "Pyramid War (1983) (Rainbow Vision) (PAL) [a1]", "AKA Chopper Command", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5c19f6da638c4c7c1f98d09e63df43e4", "Canal 3 - Intellivision", "", "Cosmic Ark (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5c1b1aa78b7609d43c5144c3b3b60adf", "", "", "Demo Image Series #8 - Two Marios (Different Interlacing) (27-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5c3a6d27c026f59a96b7af91e8b1bf26", "PlayAround - J.H.M.", "", "PlayAround Demo (PlayAround) (1982)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5c618a50dfa23daac97ba459b9ff5206", "Steve Engelhardt", "", "Berzerk Renegade (2002) (Steve Engelhardt) (Hack)", "Hack of Room of Doom", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "5c73693a89b06e5a09f1721a13176f95", "", "", "Wavy Line Test 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5c86e938e0845b9d61f458539e9a552b", "Atari, Alan Miller", "CX26163P", "Surround (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5cbd7c31443fb9c308e9f0b54d94a395", "Spectravideo, Mark Turmell", "SA-217", "Gas Hog (1983) (Spectravideo) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5ce98f22ade915108860424d8dde0d35", "", "", "Hangman Man Biglist3 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5ced13931c21ef4fc77d3fe801a1cbfa", "CCE", "C-828", "Missile Command (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5d0e8a25cbd23e76f843c75a86b7e15b", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (09-07-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5d132d121aabc5235dd039dfc46aa024", "", "", "Basketball (208 in 1) (Unknown) (PAL) (Hack)", "Console ports are swapped", "Hack", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "" }, - { "5d25df9dc2cde746ceac48e834cf84a7", "Activision - Woodside Design Associates, Steve 'Jessica Stevens' Kitchen", "EAZ-033", "Space Shuttle (1983) (Activision) (SECAM)", "A Journey Into Space", "", "", "", "FE", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5d2cc33ca798783dee435eb29debf6d6", "Activision - Imagineering, Mike Reidel", "AK-043-04", "Commando (1988) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5d7293f1892b66c014e8d222e06f6165", "Atari - Axlon, Tod Frye - Heuristica, Agustin Ortiz", "CX26169", "Shooting Arcade (03-07-1989) (Atari) (Prototype) [a1]", "Uses the Light Gun Controller (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5d799bfa9e1e7b6224877162accada0d", "Spectravision - Spectravideo - Sirius Software, David Lubar", "SA-206", "Challenge of.... Nexar, The (1982) (Spectravision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5d8f1ab95362acdf3426d572a6301bf2", "Thomas Jentzsch", "", "SWOOPS! (v0.96) (TJ) (PAL)", "Uses the Joystick (L) and Paddle (R) Controllers", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5d8fb14860c2f198472b233874f6b0c9", "", "", "Boing! (PD) [a2]", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5d9592756425192ec621d2613d0e683d", "CCE", "C-839", "Misterious Thief, A (1983) (CCE) [a]", "AKA A Mysterious Thief", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5da8fd0b5ed33a360bff37f8b5d0cd58", "Tron", "", "Pole Position (Tron)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5dae540347cf0a559962d62604ecf750", "Canal 3 - Intellivision", "", "Freeway (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5db9e5bf663cad6bf159bc395f6ead53", "Goliath - Hot Shot", "83-212", "Time Race (1983) (Goliath) (PAL)", "AKA Space Jockey", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5dccf215fdb9bbf5d4a6d0139e5e8bcb", "Froggo", "FG1009", "Sea Hunt (1987) (Froggo)", "AKA Skindiver", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5de8803a59c36725888346fdc6e7429d", "Atari, John Dunn - Sears", "CX2631 - 49-75152", "Superman (1979) (Atari) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5df32450b9fbcaf43f9d83bd66bd5a81", "Eric Ball", "", "Atari Logo Playfield Demo (2001) (Eric Ball) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5df559a36347d8572f9a6e8075a31322", "Digivision", "", "Enduro (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5e0c37f534ab5ccc4661768e2ddf0162", "Telegames - VSS, Ed Salvo", "5667 A106", "Glacier Patrol (1988) (Telegames)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5e1b4629426f4992cf3b2905a696e1a7", "Activision - Bobco, Robert C. Polaro", "AK-049-04", "Rampage! (1989) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5e1b7a6078af428ef056fe85a37a95ca", "Activision, David Crane", "AX-014, AX-014-04", "Grand Prix (1982) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5e1cd11a6d41fc15cf4792257400a31e", "Philip R. Frey", "", "Return of Mario Bros (Philip R. Frey) (Hack)", "Hack of Mario Bros.", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5e201d6bfc520424a28f129ee5e56835", "Universal Gamex Corporation, Miguel Castillo, H.K. Poon", "GX-001", "X-Man (1983) (Universal) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5e2495d43b981010304af55efed1e798", "Jone Yuan Telephonic Enterprise Co", "", "Math Gran Prix (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5e43c0391f7412ae64fae6f3742d6ee9", "Thomas Jentzsch, Paul Slocum", "", "Thrust+ Platinum (v1.27)", "", "New Release, supports BoosterGrip", "", "", "", "", "", "", "", "BOOSTERGRIP", "DRIVING", "", "", "", "", "", "" }, - { "5e99aa93d0acc741dcda8752c4e813ce", "", "", "2600 Digital Clock (V b2) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5ec73ac7d2ac95ac9530c6d33e713d14", "Arcadia Corporation, Scott Nelson", "13", "Sweat! - The Decathlon Game (2 of 3) (1983) (Arcadia) (Prototype)", "Uses the Paddle Controllers (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5eeb81292992e057b290a5cd196f155d", "Wizard Video Games - VSS, Ed Salvo", "008", "Texas Chainsaw Massacre, The (1983) (Wizard Video)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5ef303b9f0aa8cf20720c560e5f9baa1", "Atari, Jim Huether", "CX2629, CX2629P", "Sky Diver (1979) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5f1b7d5fa73aa071ba0a3c2819511505", "CCE", "", "Cosmic Commuter (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5f2b4c155949f01c06507fb32369d42a", "Apollo, Ed Salvo", "AP-1001", "Skeet Shoot (1981) (Apollo) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5f316973ffd107f7ab9117e93f50e4bd", "", "", "Commando Raid (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5f39353f7c6925779b0169a87ff86f1e", "Atari - GCC, John Allred, Douglas B. Macrae, Betty Ryan Tylko", "CX2694", "Pole Position (1983) (Atari) [a]", "AKA RealSports Driving", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5f46d1ff6d7cdeb4b09c39d04dfd50a1", "Atari, Gary Palmer", "CX2661P", "Fun with Numbers (1980) (Atari) (PAL)", "AKA Basic Math", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5f4ebf8a1e5f5f7b9ff3e3c6affff3e6", "Bit Corporation", "R320", "Donkey Kong (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5f560837396387455c9dcb05cdd4b053", "Canal 3 - Intellivision", "", "Eggomania (Canal 3)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "AUTO 60", "", "", "", "" }, - { "5f681403b1051a0822344f467b05a94d", "Atari, Howard Scott Warshaw - Sears", "CX2655 - 49-75167", "Yars' Revenge (1982) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "5f708ca39627697e859d1c53f8d8d7d2", "Atari, Warren Robinett - Sears", "CX2606 - 6-99825, 49-75112", "Slot Racers (1978) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5f73e7175474c1c22fb8030c3158e9b3", "Atari, Nick 'Sandy Maiwald' Turner", "CX2665", "Frog Pond (1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5f786b67e05fb9985b77d4beb35e06ee", "Atari, Bill Aspromonte, Andrew Fuchs", "CX26120", "Defender II (1987) (Atari) (PAL)", "AKA Stargate", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5f7ae9a7f8d79a3b37e8fc841f65643a", "Atari, Jerome Domurat, Peter C. Niday, Robert Vieira", "CX26109", "Sorcerer's Apprentice (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5f7de62a408b9de3a1168898298fd31d", "", "", "Super Cobra (Genesis)", "Genesis controller (B is bomb, C is laser)", "Hack of Super Cobra", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5f950a2d1eb331a1276819520705df94", "20th Century Fox Video Games - Micro Computer Technologies, Jim Collas", "", "Heart Like a Wheel (1983) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "5f9b62350b31be8bd270d9a241cbd50e", "Telegames", "5658 A088", "Football (1988) (Telegames) (PAL)", "AKA Super Challenge Football", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5faffe1c4c57430978dec5ced32b9f4a", "Dactari - Milmar", "", "Volleyball (Dactari - Milmar)", "AKA RealSports Volleyball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "5fb71cc60e293fe10a5023f11c734e55", "", "", "This Planet Sucks (Fix) (27-12-2002) (Greg Troutman)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "600d48eef5c0ec27db554b7328b3251c", "", "", "Bars and Text Demo 3 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6015a9cef783e97e98a2aa2cf070ae06", "Thomas Jentzsch", "", "Battlezone TC (Thomas Jentzsch) (Hack)", "Uses two simultaneous Joystick Controllers, Hack of Battlezone", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "60358edf0c2cc76b1e549e031e50e130", "Manuel Polik", "", "Cyber Goth Galaxian (Manuel Polik) (Hack)", "Hack of Galaxian", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "603c7a0d12c935df5810f400f3971b67", "Bit Corporation", "PG209", "Mr. Postman (1983) (BitCorp) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6041f400b45511aa3a69fab4b8fc8f41", "Apollo, Ban Tran", "AP-2010", "Wabbit (1982) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "604e09724555807c28108049efe34a13", "", "", "Sokoban (01-01-2003) (Adam Wozniak)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6058e40ce79d7434c7f7477b29abd4a5", "", "", "Rubik's Cube Demo (23-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "605dcb73d22f4efdb90ef9da2f290f7c", "Atari, Larry Kaplan", "CX26163P", "Air-Sea Battle (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "605fd59bfef88901c8c4794193a4cbad", "Data Age", "", "Secret Agent (1983) (Data Age) (Prototype)", "Uses the Paddle Controllers", "Prototype", "", "", "", "", "", "", "", "", "", "", "01 45", "", "", "", "" }, - { "606c2c1753051e03c1f1ac096c9d2832", "Jone Yuan Telephonic Enterprise Co", "", "Crackpots (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6076b187a5d8ea7a2a05111c19b5d5cd", "", "", "Fu Kung! (V0.14) (01-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "60a61da9b2f43dd7e13a5093ec41a53d", "VentureVision, Dan Oliver", "VV2001", "Rescue Terra I (1982) (VentureVision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "60bbd425cb7214ddb9f9a31948e91ecb", "Activision, Bob Whitehead", "AG-005, CAG-005, AG-005-04", "Skiing (1980) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "60cd61a2dfccb0e2736434f9792c1672", "Amiga - Video Soft, Frank Ellis, Jerry Lawson", "2110", "3-D Havoc (1983) (Amiga) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "60d304582d33e2957b73eb300a7495bb", "", "", "Jam Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "60e0ea3cbe0913d39803477945e9e5ec", "Atari, Joe Decuir - Sears", "CX2621 - 99806, 6-99806, 49-75104", "Video Olympics (1977) (Atari)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXDR", "PADDLES_IAXDR", "YES", "AUTO 60", "", "", "", "" }, - { "613abf596c304ef6dbd8f3351920c37a", "", "", "Boring Pac-Man (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6141c095d0aee4e734bebfaac939030a", "Rainbow Vision - Suntek", "SS-017", "Mariana (1983) (Rainbow Vision) (PAL)", "AKA Seaquest", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "61426cee013306e7f7367534ab124747", "", "", "One Blue Bar Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "615a3bf251a38eb6638cdc7ffbde5480", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX2674", "E.T. - The Extra-Terrestrial (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "61621a556ad3228f0234f5feb3ab135c", "", "", "Fu Kung! (V0.05 Cuttle Card Compattle Revision) (14-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "61631c2f96221527e7da9802b4704f93", "Activision - Imagineering, Mike Reidel", "AK-043-04", "Commando (1988) (Activision) [different logo]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "61719a8bdafbd8dab3ca9ce7b171b9e2", "", "", "Enduro (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "61728c6cfb052e62a9ed088c5bf407ba", "", "", "Sprite Demo 4 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "619de46281eb2e0adbb98255732483b4", "", "", "Time Warp (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "61dbe94f110f30ca4ec524ae5ce2d026", "CCE", "C-820", "Space Invaders (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "61e0f5e1cc207e98704d0758c68df317", "Star Game", "007", "Tennis (Star Game)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "61ef8c2fc43be9a04fe13fdb79ff2bd9", "", "", "Gas Gauge Demo - Revisited (2001) (Joe Grand) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6205855cc848d1f6c4551391b9bfa279", "", "", "Euchre (Release Candidate 2) (NTSC) (01-10-2002) (Erik Eid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6238ac888871fec301d1b9fc4fc613c9", "Thomas Jentzsch", "", "Marble Craze - Atari Mouse Hack v1.0 (PAL) (TJ)", "Uses Atari Mouse Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "624e0a77f9ec67d628211aaf24d8aea6", "Panda", "108", "Sea Hawk (1983) (Panda)", "AKA Seahawk", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "626d67918f4b5e3f961e4b2af2f41f1d", "Atari", "50008", "Diagnostic Test Cartridge 2.0 (1980) (Atari) (Prototype)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6272f348a9a7f2d500a4006aa93e0d08", "Atari, Jerome Domurat, Michael Sierchio", "CX2667, CX2667P", "RealSports Soccer (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "62899430338e0538ee93397867d85957", "Gameworld", "133-004", "Airlock (1983) (Gameworld) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "62921652f6634eb1a0940ed5489c7e18", "", "", "SCSIcide (V1.09) (2001) (Joe Grand)", "", "", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "AUTO 65", "", "", "", "" }, - { "62992392ea651a16aa724a92e4596ed6", "Eric Mooney", "", "Invaders by Erik Mooney (Beta) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "62d1f50219edf9a429a9f004c19f31b3", "JWDA, Todd Marshall", "", "Euro Gen (02-01-83) (JWDA) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "62ee2b8f59e9cd6285bbdb674a952e8b", "Probe 2000 - NAP, Roger Booth, Todd Marshall, Robin McDaniel, Jim Wickstead", "3152VC", "Pursuit of the Pink Panther (Probe) (Prototype)", "AKA Adventures of the Pink Panther", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "62f74a2736841191135514422b20382d", "", "", "Pharaoh's Curse (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "YES", "" }, - { "62ffd175cac3f781ef6e4870136a2520", "", "", "2600 Digital Clock (V x.xx) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "63166867f75869a3592b7a94ea62d147", "", "", "Indy 500 (Hack) [a1]", "Hack of Indy 500", "Hack", "", "", "", "", "", "", "", "DRIVING", "DRIVING", "", "", "", "", "", "" }, - { "6333ef5b5cbb77acd47f558c8b7a95d3", "Greg Troutman", "", "Dark Mage (Greg Troutman) (PD) (8K)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "6337927ad909aa739d6d0044699a916d", "Jeffry Johnston", "", "Radial Pong - Version 2 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6339d28c9a7f92054e70029eb0375837", "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart", "PB5540", "Star Wars - The Arcade Game (1984) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "6342afe9c9ad1b6120b8f6fb040d0926", "", "", "Move a Blue Blob Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6354f9c7588a27109c66905b0405825b", "Thomas Jentzsch", "", "Amidar DS (2003) (TJ) (Hack)", "Hack of Amidar", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6358f7f8bf0483402a080efccf250d61", "CommaVid, John Bronstein", "CM-003", "Cosmic Swarm (1982) (CommaVid) (Prototype)", "AKA Termite", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "635cc7a0db33773959d739d04eff96c2", "", "", "Minesweeper (V.90) (Soren Gust) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6362396c8344eec3e86731a700b13abf", "Panda", "109", "Exocet (1983) (Panda)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "637efac676ff063f2fbb0abff77c4fa5", "", "", "Noize Maker Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "63811ed69bdbc35c69d8aa7806c3d6e9", "Atari", "CX26163P", "Homerun (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "638cc82ea96f67674595ba9ae05da6c6", "Rainbow Vision - Suntek", "SS-011", "Super Ferrari (1983) (Rainbow Vision) (PAL)", "AKA Enduro", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "63a6eda1da30446569ac76211d0f861c", "Activision, David Crane", "AG-001", "Dragster (1980) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "63a7445b1d3046d3cdcdbd488dca38d9", "Rob Kudla", "", "Better Space Invaders (1999) (Rob Kudla) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "63c5fef3208bb1424d26cf1ab984b40c", "", "", "Analog Clock (V0.1) (20-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "63c7395d412a3cd095ccdd9b5711f387", "Eric Ball", "ELB005", "Skeleton+ (PAL)", "Stereo sound", "Homebrew", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "63d6247f35902ba32aa49e7660b0ecaa", "", "", "Space War (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "63e42d576800086488679490a833e097", "Telesys, Jim Rupp", "1004", "Ram It (1983) (Telesys) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "63e783994df824caf289b69a084cbf3e", "David Marli", "", "Fat Albert (David Marli) (Hack)", "Hack of Fast Food", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "63e9e612bbee31045f8d184a4e53f8ec", "ATARITALIA", "", "Moby Blues (2002) (ATARITALIA) (Hack)", "Hack of Mario Bros", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "640a08e9ca019172d612df22a9190afb", "Atari - GCC, Mike Feinstein, Kevin Osborn", "CX2691, CX2691P", "Joust (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "64198bb6470c78ac24fcf13fe76ab28c", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (1982) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "643e6451eb6b8ab793eb60ba9c02e000", "Salu - Avantgarde Software, Michael Buetepage", "460741", "Ghostbusters II (1992) (Salu) (PAL) [different tune]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "645bf7f9146f0e4811ff9c7898f5cd93", "Xonox - K-Tel Software - VSS, Robert Weatherby", "6230, 6250", "Super Kung-Fu (1983) (Xonox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6468d744be9984f2a39ca9285443a2b2", "Atari, Ed Logg, Carol Shaw", "CX26163P", "Reversi (32 in 1) (1988) (Atari) (PAL)", "AKA Othello", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "647162cceb550fd49820e2206d9ee7e8", "", "", "Skeleton (NTSC) (2002) (Eric Ball)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "64b8e19c767191ccdc97acc6904c397b", "Jeffry Johnston", "", "Radial Pong - Version 6 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "64ca518905311d2d9aeb56273f6caa04", "CCE", "", "Cubo Magico (CCE)", "AKA Cubicolor", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "64d43859258dc8ca54949e9ff4174202", "Thomas Jentzsch", "", "Lilly Adventure (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "64fab9d15df937915b1c392fc119b83b", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX26119", "Saboteur (05-20-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "650df778c6ce22d3fd1a7c33c565bcc3", "Atari - GCC, Betty Ryan Tylko, Douglas B. Macrae", "CX2694", "Pole Position (1983) (Atari)", "Genesis controller (B is high gear, C is low gear, left difficulty switch swaps gear buttons)", "Hack of Pole Position", "", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "" }, - { "651d2b6743a3a18b426bce2c881af212", "CCE", "C-812", "Pac Man (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6522717cfd75d1dba252cbde76992090", "Home Vision - Gem International Corp. - VDI", "VCS83102", "War 2000 (1983) (Home Vision) (PAL)", "AKA Astrowar", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6538e454b0498ad2befe1ef0f87815c0", "Joe Grand", "", "SCSIcide (v1.2) (2001) (Joe Grand)", "", "New Release", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "AUTO 65", "", "", "", "" }, - { "65490d61922f3e3883ee1d583ce10855", "Atari - GCC, Mark Ackerman, Noellie Alito", "CX2692, CX2692P", "Moon Patrol (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "65562f686b267b21b81c4dddc129d724", "", "", "Euchre (28-07-2001) (Eric Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "655c84e5b951258c9d20f0bf2b9d496d", "", "", "2600_2003 Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "656dc247db2871766dffd978c71da80c", "Sears Tele-Games, Jim Huether", "CX2614 - 49-75126", "Steeplechase (1981) (Sears)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "AUTO 60", "", "", "", "" }, - { "6588d192d9a8afce27b44271a2072325", "Bit Corporation", "R320", "Basketball (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "65917ae29a8c9785bb1f2acb0d6aafd0", "", "", "Junkosoft One Year Demo (1999) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6596b3737ae4b976e4aadb68d836c5c7", "Digivision", "", "Defender (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "659a20019de4a23c748ec2292ea5f221", "Retroactive", "", "Qb (V2.05) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "65c6406f5af934590097c8c032ebb482", "", "", "Three Hugger (Pave Demo) (20-12-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6604f72a966ca6b2df6a94ee4a68eb82", "", "", "MegaMania (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "662eca7e3d89175ba0802e8e3425dedb", "", "", "Hangman Pac-Man Biglist3 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "66362890eb78d6ea65301592cce65f5b", "", "", "Euchre (13-07-2001) (Eric Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "663ef22eb399504d5204c543b8a86bcd", "CBS Electronics - Roklan, Joe Hellesen, Joe Wagner", "4L1720, 4L1721, 4L1722, 4L2276", "Wizard of Wor (1982) (CBS Electronics) (PAL)", "Uses the Joystick Controllers (swapped)", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "YES", "" }, - { "664d9bfda6f32511f6b4aa0159fd87f5", "Atari - Roklan, Joe Gaucher", "", "Racer (1982) (Atari) (Prototype) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6651e2791d38edc02c5a5fd7b47a1627", "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart", "PB5540", "Star Wars - The Arcade Game (04-05-1984) (Parker Bros) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "665b8f8ead0eef220ed53886fbd61ec9", "Telesys, Don Ruffcorn, Jack Woodman", "1003", "Fast Food (1982) (Telesys)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "66706459e62514d0c39c3797cbf73ff1", "Video Gems", "VG-05", "Treasure Below (1983) (Video Gems) (PAL)", "", "", "", "", "", "", "A", "", "", "", "", "", "", "", "", "", "" }, - { "6672de8f82c4f7b8f7f1ef8b6b4f614d", "Videospielkassette - Ariola", "PGP237", "Angeln I (Ariola) (PAL)", "AKA Fishing Derby", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "667a70b028f581d87648693b873bc962", "Parker Brothers - Roklan, Joe Gaucher", "PB5370", "Popeye (1983) (Parker Bros) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "668dc528b7ea9345140f4fcfbecf7066", "Gakken", "001", "Pooyan (1983) (Gakken) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6697f177847c70505824422e76aad586", "", "", "Tennis (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "669840b0411bfbab5c05b786947d55d4", "Atari, Andrew Fuchs, Jeffrey Gusman, Dave Jolly, Suki Lee", "CX26117", "Obelix (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "66b89ba44e7ae0b51f9ef000ebba1eb7", "Atari - CCW, Stephan R. Keith, Laura Scholl, Preston Stuart", "CX26106", "Grover's Music Maker (01-18-1983) (Atari) (Prototype)", "Uses Keypad Controller", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "66b92ede655b73b402ecd1f4d8cd9c50", "Activision, John Van Ryzin - Ariola", "EAZ-036-04, EAZ-036-04B, EAZ-036-04I - 711 036-720", "H.E.R.O. (1984) (Activision) (PAL) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "66bc1bef269ea59033928bac2d1d81e6", "Arcadia Corporation, Scott Nelson", "AR-4300", "Fireball (Preview) (1982) (Arcadia)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "01", "", "", "", "" }, - { "66c2380c71709efa7b166621e5bb4558", "Parker Brothers, Dave Engman, Dawn Stockbridge", "931509", "Tutankham (1983) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "66c4e0298d4120df333bc2f3e163657e", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (2 of 3) (1982) (Starpath) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "66f49b3248791b9803fa3e2f4165d072", "Bit Corporation", "R320", "Football (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "66fcf7643d554f5e15d4d06bab59fe70", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (09-13-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6706a00f9635508cfeda20639156e66e", "Atari, Jerome Domurat, Michael Sierchio", "CX2667", "RealSports Soccer (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "672012d40336b403edea4a98ce70c76d", "", "", "Spider Kong (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "675ae9c23fa1aae376cea86cad96f9a5", "", "", "Poker Squares (V0.25) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "67631ea5cfe44066a1e76ddcb6bcb512", "", "", "Termool (Unknown) (PAL)", "AKA Turmoil", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "67684a1d18c85ffa5d82dab48fd1cb51", "Tigervision, Warren Schwader - Teldec", "7-003", "Threshold (1982) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "678c1d71a1616d9d022f03d8545b64bb", "", "", "Demo Image Series #11 - Donald And Mario (28-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "67931b0d37dc99af250dd06f1c095e8d", "CommaVid, Irwin Gaines", "CM-004", "Room of Doom (1982) (CommaVid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "679d30c7886b283cbe1db4e7dbe5f2a6", "Colin Hughes", "", "Puzzle (Colin Hughes) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "679e910b27406c6a2072f9569ae35fc8", "Data Age", "DA1002", "Warplock (1982) (Data Age)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "01 40", "", "", "YES", "" }, - { "67bd3d4dc5ac6a42a99950b4245bdc81", "Retroactive", "", "Qb (2.11) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "67c05ae94bf8b83a666c3ae2c4bc14de", "Atari", "CX26163P", "NFL Football (32 in 1) (1988) (Atari) (PAL) (4K)", "AKA Football", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "67cdde4176e0447fc45a71e0a1cdd288", "Telegames - VSS, Ed Salvo", "5665 A016", "Glacier Patrol (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "67ce6cdf788d324935fd317d064ed842", "Retroactive", "", "Qb (V2.09) (Stella) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "67cf913d1df0bf2d7ae668060d0b6694", "", "", "Hangman Monkey 4letter (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "67f90d74fd0b72fdc6d9b92436780ea9", "Omegamatrix", "", "SpaceMaster X-7 (Atari Trak-Ball) (PAL60) (Omegamatrix)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6803fa7c2c094b428b859a58dc1dd06a", "Retroactive", "", "Qb (0.11) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "6805734a0b7bcc8925d9305b071bf147", "Bit Corporation", "PGP229", "Kung Fu (4 Game in One Dark Green) (1983) (BitCorp) (PAL)", "AKA Karate", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "681206a6bde73e71c19743607e96c4bb", "", "", "Casino (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6833c26f385e866f3a0fa0dff311216e", "Thomas Jentzsch", "", "Centipede - Atari Mouse Hack v1.4 (PAL60) (Full-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "683bb0d0f0c5df58557fba9dffc32c40", "Arcadia Corporation, Scott Nelson", "AR-4300", "Fireball (1982) (Arcadia) [a]", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "01", "", "", "", "" }, - { "683dc64ef7316c13ba04ee4398e2b93a", "Ed Federmeyer", "", "Edtris (1995) (Ed Federmeyer)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "68449e4aaba677abcd7cde4264e02168", "", "", "Horizonal Color Bars Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6847ce70819b74febcfd03e99610243b", "", "", "Ruby Runner 4A50", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "68489e60268a5e6e052bad9c62681635", "Bit Corporation", "PG201", "Sea Monster (1982) (BitCorp) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "68597264c8e57ada93be3a5be4565096", "Data Age", "DA1005", "Bugs (1982) (Data Age)", "Uses the Paddle Controllers", "Uncommon", "", "", "", "", "", "", "", "", "", "", "AUTO 50", "", "", "", "" }, - { "685e9668dc270b6deeb9cfbfd4d633c3", "CommaVid, Irwin Gaines - Ariola", "CM-004 - 712 004-720", "Room of Doom (1982) (CommaVid) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "68760b82fc5dcf3fedf84376a4944bf9", "CCE", "C-860", "Laser Gate (1983) (CCE)", "AKA Innerspace", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "687c23224e26f81c56e431c24faea36d", "", "", "Qb (Simple Background Animation) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "68878250e106eb6c7754bc2519d780a0", "CCE", "C-809", "Squirrel (1983) (CCE)", "AKA Snail Against Squirrel", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "68ac69b8e1ba83af8792f693f5ae7783", "Digivision", "", "Fathon (Digivision)", "AKA Fathom", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "68c80e7e1d30df98a0cf67ecbf39cc67", "Hozer Video Games", "", "Gunfight 2600 - One Step Forward & Two Steps Back (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "68c938a2a2b45c37db50509f1037fe6e", "Omegamatrix", "", "Star Wars Arcade (Atari Mouse) v4 (Omegamatrix)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "68cd2adc6b1fc9a1f263ab4561112f30", "Thomas Jentzsch", "", "Boulderdash Demo (09-12-2002) (TJ)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "68feb6d6ff63e80df1302d8547979aec", "", "", "Starfield Demo 2 (20-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "690a6049db78b9400c13521646708e9c", "King Tripod Enterprise Co.", "SS - 007", "Space Raid (King Tripod) (PAL)", "AKA Challenge of.... Nexar, The", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6913c90002636c1487538d4004f7cac2", "Atari - CCW", "CX26131", "Monster Cise (1984) (Atari) (Prototype)", "Uses the Keypad Controllers (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "691d67910b08b63de8631901d1887c1f", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (1983) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "692202772d8b38ccf85a90c8003a1324", "", "", "Zi - The Flie Buster (2002) (Fernando Mora) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "693137592a7f5ccc9baae2d1041b7a85", "", "", "Qb (V2.02) (Stella) (2001) (Retroactive) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "6936aa6763835f62ac13d1aaa79b9f91", "Thomas Jentzsch", "", "Centipede - Atari Trak-Ball Hack v1.4 (NTSC) (Half-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6979f30204149be3e227558cffe21c1d", "Atari", "CX26163P", "Miniaturer Golf (32 in 1) (1988) (Atari) (PAL) (4K)", "AKA Miniature Golf", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6982854657a2cc87d712f718e402bf85", "Zellers", "", "Earth Attack (Zellers)", "AKA Defender", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "69877da5caded48315e3e45882a303d5", "Atari - Roklan, Joe Gaucher, Alex Leavens", "CX2683", "Crazy Climber (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "698f569eab5a9906eec3bc7c6b3e0980", "SpkLeader", "", "Demons! (2003) (SpkLeader) (Hack)", "Hack of Phoenix", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "69974dd5d6420b90898cde50aec5ef39", "Activision, David Crane", "AG-009, AG-009-04", "Freeway (1981) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "69df0411d4d176e558017f961f5c5849", "CCE", "C-831", "Cosmic Ark (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "69e79b1352b9ee1754bbe63b4a7062c3", "Barry Laws Jr.", "", "Pink Floyd - The Wall (2003) (Barry Laws Jr.) (Hack)", "Hack of Berzerk", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "69ebf910ab9b63e5b8345f016095003b", "", "", "Maze Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "69edfb4e1810a523311b3e250fc1e275", "Thomas Jentzsch", "", "Missile Command Atari Trak-Ball Hack v1.3 (PAL) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "69fac82cd2312dd9ce5d90e22e2f070a", "Spectravision - Spectravideo - Quelle", "SA-202 - 412.851 8", "Planet Patrol (1982) (Spectravision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6a03c28d505bab710bf20b954e14d521", "", "", "Pressure Gauge 2 Beta (Hozer Video Games)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6a07836c382195dd5305ce61d992aaa6", "Apollo, Larry Martin", "AP-2008", "Guardian (1982) (Apollo) (Prototype)", "Uses the Paddle Controller (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "01", "", "", "", "" }, - { "6a091b8ffeacd0939850da2094b51564", "", "", "Vertically Scrolling Playfield (02-02-2003) (Aaron Bergstrom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6a222c26bcece3a510ddda21398f72c6", "Bit Corporation", "PG203", "Phantom Tank (1982) (BitCorp)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6a2c68f7a77736ba02c0f21a6ba0985b", "Atari, Larry Wagner, Bob Whitehead", "", "Computer Chess (07-07-1978) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6a3b0c33cf74b1e213a629e3c142b73c", "Cody Pittman", "", "Cory The Interviewer (Cody Pittman) (Hack)", "Hack of Ghostbusters", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6a76d5f0ed721639474aa9bbde69ebf0", "", "", "Play Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "6a82b8ecc663f371b19076d99f46c598", "Activision, Larry Miller - Ariola", "EAX-026, EAX-026-04B, EAX-026-04I - 711 026-725", "Enduro (1983) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6a882fb1413912d2ce5cf5fa62cf3875", "Video Game Cartridge - Ariola", "TP-605", "Dragon Defender (Ariola) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "6a8c6940d3be6fd01274363c4d4b298e", "", "", "Spy Hunter (Genesis)", "Genesis controller (C is oil/smoke)", "Hack of Spy Hunter", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6a9b30ca46b0dba9e719f4cbd340e01c", "", "", "Frostbite (Unknown) (PAL) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6a9e0c72fab92df70084eccd9061fdbd", "CCE", "C-835", "Beany Bopper (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6aa66e9c3eea76a0c40ef05513497c40", "", "", "Hangman Ghost Biglist2 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6ac3fd31a51730358708c7fdc62487f8", "Matthias Jaap", "", "PC Invaders (Matthias Jaap) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6aca52e11b597ab84b33d5252e1cd9d1", "Bit Corporation", "R320", "Tac-Scan (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "AUTO 60", "", "", "", "" }, - { "6ae4dc6d7351dacd1012749ca82f9a56", "Atari - GCC, Jaques Hugon, Seth Lipkin", "CX26125, CX26127", "Track and Field (1984) (Atari)", "Uses the Track & Field Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6b01a519b413f8cfa2f399f4d2841b42", "", "", "Aphex Invaders (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6b1fc959e28bd71aed7b89014574bdc2", "Bit Corporation", "PG203", "Phantom Tank (1982) (BitCorp) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6b4eb5b3df80995b8d9117cb7e9aeb3c", "Gameworld, J. Ray Dettling", "133-006", "Journey Escape (1983) (Gameworld) (PAL)", "AKA Rock 'n' Roll Escape", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "6b683be69f92958abe0e2a9945157ad5", "U.S. Games Corporation - Western Technologies, Jeff Corsiglia, Paul Allen Newell, Steven B. Sidley, Tom Sloper", "VC2007", "Entombed (1983) (U.S. Games)", "Released as Name That Game for a contest (winning name was Entombed)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "6b6ca32228ae352b4267e4bd2cddf10c", "", "", "Pac-Man 4 (Pac-Man Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6b71f20c857574b732e7a8e840bd3cb2", "", "", "Frostbite (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6b72b691ea86f61438ed0d84c4d711de", "", "", "Fishing Derby (Unknown) (PAL) (4K) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6b75f8fa4fd011a6698c58315f83d2ac", "Thomas Jentzsch", "", "Sprintmaster DC (TJ)", "Uses the Driving Controllers, Hack of Sprintmaster (Atari)", "New Release (Hack)", "", "", "", "", "", "", "", "DRIVING", "DRIVING", "", "45", "", "", "", "" }, - { "6b7a56b6ac2ca4bf9254474bf6ed7d80", "", "", "Horizonal Color Bars Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6b7e1c11448c4d3f28160d2de884ebc8", "Zirok", "", "Fast Food (Zirok)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6b8fb021bb2e1f1e9bd7ee57f2a8e709", "Paul Slocum", "", "3-D Corridor (29-03-2003) (Paul Slocum) (PD) [a]", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6bb09bc915a7411fe160d0b2e4d66047", "Atari", "CX26163P", "UFO (32 in 1) (1988) (Atari) (PAL)", "AKA Space Jockey", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6bb22efa892b89b69b9bf5ea547e62b8", "Dynacom", "", "Megamania (1982) (Dynacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6bde3f6ac31aceef447ce57d4d2c2ec0", "Piero Cavina", "", "Mondo Pong V1 (Piero Cavina) (PD)", "Uses the Paddle Controllers", "New Release", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "01", "", "", "", "" }, - { "6c128bc950fcbdbcaf0d99935da70156", "Digitel", "", "Volleyball (1983) (Digitel)", "AKA RealSports Volleyball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6c1553ca90b413bf762dfc65f2b881c7", "Quelle", "343.073 3", "Winterjagd (1983) (Quelle) (PAL)", "AKA Ski Hunt", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6c1f3f2e359dbf55df462ccbcdd2f6bf", "Activision, Garry Kitchen - Ariola", "EAX-025, EAX-025-04I - 711 025-725", "Keystone Kapers (1983) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6c25f58fd184632ca76020f589bb3767", "Dynacom", "", "Beat 'Em & Eat 'Em (1983) (Dynacom)", "Uses the Paddle Controller (left only)", "", "", "", "", "", "", "", "", "", "", "", "AUTO 45", "", "", "", "" }, - { "6c449db9bbbd90972ad1932d6af87330", "", "", "20 Sprites at Once Demo 3 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6c658b52d03e01828b9d2d4718a998ac", "", "", "Hangman Invader Biglist2 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6c76fe09aa8b39ee52035e0da6d0808b", "Atari, Brad Stewart", "CX2622, CX2622P", "Breakout (1978) (Atari) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "01 60", "", "", "", "" }, - { "6c85098518d3f94f7622c42fd1d819ac", "Suntek", "SS-028", "Firebug (1983) (Suntek) (PAL)", "AKA Spinning Fireball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6c91ac51421cb9fc72c9833c4f440d65", "ITT Family Games", "554-33 375", "Cosmic Town (1983) (ITT Family Games) (PAL)", "AKA Base Attack (Perry Rhodan-Serie)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6c9a32ad83bcfde3774536e52be1cce7", "", "", "Space Treat (NTSC) (13-08-2002) (Fabrizio Zavagli)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6cab04277e7cd552a3e40b3c0e6e1e3d", "Telegames - VSS", "7062 A305", "Universal Chaos (1988) (Telegames) (Prototype)", "AKA Targ", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6cbe945e16d9f827d0d295546ac11b22", "", "", "Gunfight 2600 - AI (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6ccd8ca17a0e4429b446cdcb66327bf1", "", "", "RPG Engine (12-05-2003) (Paul Slocum) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "6cd1dc960e3e8d5c5e0fbe67ab49087a", "", "", "Vertical Playfield Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6cd506509e8fd5627f55603780e862a8", "Greg Troutman", "", "Dark Mage (SuperCharger) (Greg Troutman) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "6ce2110ac5dd89ab398d9452891752ab", "Funvision - Fund. International Co.", "", "Persian Gulf War (Funvision)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6cea35ded079863a846159c3a1101cc7", "", "", "Atlantis (208 in 1) (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6ceb7d6a54e9a5e62d26874d1cc88dbc", "Video Soft", "", "Atom Smasher (1984) (Video Soft) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6cf054cd23a02e09298d2c6f787eb21d", "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart", "PB5540", "Star Wars - The Arcade Game (1984) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "6d218dafbf5a691045cdc1f67ceb6a8f", "Robin Harbron", "", "6 Digit Score Display (1998) (Robin Harbron) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6d475019ea30d0b29f695e9dcfd8f730", "Eric Mooney", "", "Invaders by Erik Mooney (Alpha 2) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6d74ebaba914a5cfc868de9dd1a5c434", "", "", "Fortress (Smooth Version) (20-04-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6d842c96d5a01967be9680080dd5be54", "Activision, Steve Cartwright, David Crane", "AB-035-04", "Pitfall II (1984) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6d8a04ee15951480cb7c466e5951eee0", "Zirok", "", "Kanguru (1983) (Zirok)", "AKA Kangaroo", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6d9afd70e9369c2a6bff96c4964413b7", "", "", "Time Warp (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6dda84fb8e442ecf34241ac0d1d91d69", "Atari - GCC, Douglas B. Macrae", "CX2677", "Dig Dug (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6de924c2297c8733524952448d54a33c", "CCE", "C-1006", "Moon Patrol (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6dfad2dd2c7c16ac0fa257b6ce0be2f0", "Parker Brothers, Larry Gelberg", "PB5065", "Star Wars - Ewok Adventure (1983) (Parker Bros) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6e179eee3d4631a7434d40cf7aeea6e8", "Wizard Video Games - MicroGraphic Image, Robert Barber, Tim Martin", "007", "Halloween (1983) (Wizard Video Games) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6e19428387686a77d8c8d2f731cb09e0", "", "", "Purple Cross Demo (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6e372f076fb9586aff416144f5cfe1cb", "Atari, Tod Frye - Sears", "CX2646 - 49-75185", "Pac-Man (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6e59dd52f88c00d5060eac56c1a0b0d3", "Atari, Bob Smith", "CX2648", "Video Pinball (1981) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6e5d5ba193d2540aec2e847aafb2a5fb", "Retroactive", "", "Qb (2.14) (Retroactive) (NTSC)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "6e7ed74082f39ad4166c823765a59909", "", "", "Poker Squares (V0.14) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6e7efb0ed13ec28a00d19572de9c9f03", "Apollo - Games by Apollo", "AP-2006", "Infiltrate (1982) (Apollo) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6eb10fd23c7161751d18b9e8484c0004", "Coleco - JWDA, Todd Marshall, Robin McDaniel, Henry Will IV", "2465", "Smurf - Rescue in Gargamel's Castle (1983) (Coleco) (Prototype)", "AKA Smurf, Smurf Action", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6ed5012793f5ddf4353a48c11ea9b8d3", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix - Down on the Line (3 of 3) (1983) (Arcadia)", "Uses Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "01 70", "", "", "", "" }, - { "6ed6bda5c42b2eb7a21c54e5b3ace3e3", "Canal 3 - Intellivision", "", "Ice Hockey (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6efe876168e2d45d4719b6a61355e5fe", "Bit Corporation", "PG207", "Mission 3,000 A.D. (1983) (BitCorp) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "6f084daf265599f65422ef4173b69bc7", "", "", "Music Kit (V2.0) - Song Player (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "6f2aaffaaf53d23a28bf6677b86ac0e3", "U.S. Games Corporation - Vidtec - JWDA, Garry Kitchen", "VC1001", "Space Jockey (1982) (U.S. Games)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6f3e3306da2aa6e74a5e046ff43bf028", "", "", "Defender Arcade (Genesis)", "Genesis controller (C is smartbomb)", "Hack of Defender 2", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6f744f14aac04f7e1ea0d3f4bafcb3e4", "Atari - Roklan, Joe Gaucher, Alex Leavens", "CX2683", "Crazy Climber (1983) (Atari) (Prototype) [a3]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6f74ed915ffe73b524ef0f63819e2a1d", "Eckhard Stolberg", "", "An Exercise In Minimalism (V2) (1999) (Eckhard Stolberg)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6fa0ac6943e33637d8e77df14962fbfc", "Imagic, Rob Fulop", "", "Cubicolor (1982) (Imagic) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6fac680fc9a72e0e54255567c72afe34", "", "", "Superman (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6fbd05b0ad65b2a261fa154b34328a7f", "", "", "Boardgame Demo (20-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6fc0176ccf53d7bce249aeb56d59d414", "Rainbow Vision - Suntek", "SS-004", "Pyramid War (1983) (Rainbow Vision) (PAL)", "AKA Chopper Command", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6fc27a9233fc69d28d3f190b4ff80f03", "", "", "UFO #6 (Charles Morgan) (Hack)", "Hack of Pepsi Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6fc394dbf21cf541a60e3b3631b817f1", "Imagic, Bob Smith", "720020-2A, IA3611P", "Dragonfire (1982) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "6fd7c7057eeab273b29c7aafc7429a96", "Activision, David Crane", "AX-018, AX-018-04", "Pitfall! (1982) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6fe67f525c39200a798985e419431805", "Atari - GCC, Kevin Osborn", "CX2689, CX2689P", "Kangaroo (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "6ff4156d10b357f61f09820d03c0f852", "Atari, Larry Kaplan - Sears", "CX2612 - 99804, 49-75103", "Street Racer (1977) (Atari) (4K)", "Uses the Paddle Controllers (swapped)", "", "", "", "", "", "", "", "", "", "", "YES", "10 60", "", "", "", "" }, - { "6ffc95108e5add6f9b8abcaf330be835", "Charles Morgan", "", "TP Bug (Charles Morgan) (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "700a786471c8a91ec09e2f8e47f14a04", "Activision", "", "Hard-Head (1983) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "703d32062436e4c20c48313dff30e257", "", "", "Moving Maze Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "703f0f7af350b0fa29dfe5fbf45d0d75", "Bit Corporation", "P460", "4 Game in One Dark Green (1983) (BitCorp) (PAL)", "Rodeo Champ, Bobby is Going Home, Open Sesame, Festival", "", "", "", "4IN1", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "705fe719179e65b0af328644f3a04900", "Atari, David Crane - Sears", "CX2653 - 6-99823, 49-75111", "Slot Machine (1979) (Atari) (4K) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "706e3cc4931f984447213b92d1417aff", "", "", "Joustpong (06-07-2002) (Kirk Israel) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "707ecd80030e85751ef311ced66220bc", "", "", "Double-Height 6-Digit Score Display (Background Color Change) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7096a198531d3f16a99d518ac0d7519a", "Telesys, Jim Rupp", "1004", "Ram It (1983) (Telesys)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "709910c2e83361bc4bf8cd0c20c34fbf", "Rainbow Vision - Suntek", "SS-006", "Netmaker (1983) (Rainbow Vision) (PAL)", "AKA Amidar", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "70a43fbdb1c039283ee5048d99842469", "Thomas Jentzsch", "", "Reactor - Atari Mouse Hack v1.3 (PAL) (Half-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "70a8480cfaf08776e5420365732159d2", "Rob Kudla", "", "Horizontally Scrolling Playfield Thing (Rob Kudla) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "70ce036e59be92821c4c7fd735ec6f68", "Activision, Steve Cartwright - Ariola", "EAX-031, EAX-031-04B - 711 031-717", "Frostbite (1983) (Activision) (PAL) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "70d14c66c319683b4c19abbe0e3db57c", "", "", "Oystron (V2.82) (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "710497df2caab69cdcc45e919c69e13f", "Arcadia Corporation, Dennis Caswell", "5 AR-4200", "Labyrinth (Escape from the Mindmaster Beta) (1982) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "713fde2af865b6ec464dfd72e2ebb83e", "", "", "Challenge (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "71464c54da46adae9447926fdbfc1abe", "M Network - INTV - APh Technological Consulting, Bruce Pedersen", "MT5663", "Lock 'n' Chase (1982) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "714e13c08508ee9a7785ceac908ae831", "Home Vision - Gem International Corp. - VDI", "VCS83123", "Parachute (1983) (Home Vision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "715dbf2e39ba8a52c5fe5cdd927b37e0", "Amiga - Video Soft", "3135", "S.A.C. Alert (1983) (Amiga) (Prototype)", "Uses Joyboard", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "715dd9e0240638d441a3add49316c018", "Atari", "", "128-in-1 Junior Console (Chip 2 of 4) (1991) (Atari) (PAL)", "Actually contains only 16 games, not 32", "", "", "", "16IN1", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7187118674ff3c0bb932e049d9dbb379", "Zirok", "", "Keystone Keypers (1983) (Zirok)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "718ae62c70af4e5fd8e932fee216948a", "Data Age, J. Ray Dettling", "112-006", "Journey Escape (1983) (Data Age)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "718ee85ea7ec27d5bea60d11f6d40030", "Thomas Jentzsch", "", "Ghostbusters II (1992) (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "7197b6cbde6ecd10376155e6b848e80d", "Piero Cavina", "", "Multi-Sprite Game V2.1 (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "71b193f46c88fb234329855452dfac5b", "Digitel", "", "Atlantis (1983) (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "71d005b60cf6e608d04efb99a37362c3", "Atari, Larry Kaplan", "CX2643", "Codebreaker (1978) (Atari) (PAL) (4K) [a]", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "71f09f128e76eb14e244be8f44848759", "Funvision - Fund. International Co.", "", "Time Race (Funvision) (PAL)", "AKA Time Warp", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "71f8bacfbdca019113f3f0801849057e", "Atari, Dan Hitchens", "CX26126", "Elevator Action (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "72097e9dc366900ba2da73a47e3e80f5", "", "", "Euchre (15-06-2001) (Eric Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "721a5567f76856f6b50a6707aa8f8316", "Activision, David Crane, Dan Kitchen", "EAG-108-04, EAZ-108-04B", "Ghostbusters (1985) (Activision) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "72305c997f2cec414fe6f8c946172f83", "Arcadia Corporation, Dennis Caswell", "AR-4000, AR-4100", "Phaser Patrol (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "724613effaf7743cbcd695fab469c2a8", "", "", "Super-Ferrari (Unknown)", "AKA Enduro", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "728152f5ae6fdd0d3a9b88709bee6c7a", "Spectravideo, Mark Turmell", "SA-217", "Gas Hog (1983) (Spectravideo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "72876fd7c7435f41d571f1101fc456ea", "Quelle", "688.383 9", "Die Ente und der Wolf (1983) (Quelle) (PAL)", "AKA Pooyan", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "72a46e0c21f825518b7261c267ab886e", "Xonox - K-Tel Software - Computer Magic", "99005, 6220, 6250", "Robin Hood (1983) (Xonox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "72a5b5052272ac785fa076709d16cef4", "", "", "KC Munckin (29-01-2003) (J. Parlee)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "72a63bcb5eb31bd0fd5e98ed05125ec1", "Thomas Jentzsch", "", "Missile Control - Atari Trak-Ball Hack v1.15 (PAL60) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "72bda70c75dfa2365b3f8894bace9e6a", "Thomas Jentzsch", "", "Atlantis (TJ) (Hack)", "Hack of Atlantis", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "72d0acb5de0db662de0360a6fc59334d", "", "", "Cosmic Ark (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "72db1194b1cc7d45b242f25eb1c148d3", "", "", "Pac-Man (1981) (Atari) (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "72fd08deed1d6195942e0c6f392e9848", "HES", "0701-406", "2 Pak Special - Wall Defender, Planet Patrol (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "72ffbef6504b75e69ee1045af9075f66", "Atari, Richard Maurer - Sears", "CX2632 - 49-75153", "Space Invaders (1980) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "73158ea51d77bf521e1369311d26c27b", "Zellers", "", "Challenge (Zellers)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "73521c6b9fed6a243d9b7b161a0fb793", "Atari, Tom Reuterdahl", "CX26163P", "Miniaturer Golf (32 in 1) (1988) (Atari) (PAL)", "AKA Miniature Golf", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "736388d73198552d77d423962000006f", "Dactari", "", "Tennis (Dactari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "73a710e621d44e97039d640071908aef", "", "", "Barber Pole Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "73aa02458b413091ac940c0489301710", "Rainbow Vision - Suntek", "SS-016", "Boom Bang (1983) (Rainbow Vision) (PAL)", "AKA Crackpots", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "73b4e8f8b04515d91937510e680214bc", "", "", "Rubik's Cube Demo 3 (24-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "73c545db2afd5783d37c46004e4024c2", "CBS Electronics - JWDA, Todd Marshall, Robin McDaniel, Henry Will IV", "4L1767, 4L1768, 4L1769, 4L1770", "Smurf - Schtroumpfs (1983) (CBS Electronics) (PAL)", "Pitufo", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "73c839aff6a055643044d2ce16b3aaf7", "Activision, Alan Miller - Ariola", "EAX-016, PAX-016 - 711 016-725", "StarMaster (1982) (Activision) (PAL)", "Use Color/BW switch to change between galactic chart and front views", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "73cb1f1666f3fd30b52b4f3d760c928f", "", "", "Mines of Minos (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "73e66e82ac22b305eb4d9578e866236e", "Jone Yuan Telephonic Enterprise Co", "", "Unknown Datatech Game (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "73efa9f3cbe197f26e0fb87132829232", "CCE", "C-858", "Tennis (1983) (CCE) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "74023e0f2e739fc5a9ba7caaeeee8b6b", "Jone Yuan Telephonic Enterprise Co", "", "Fishing Derby (Jone Yuan) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "740a7fa80f52cc7287ba37677afb6b21", "", "", "Double Dragon (PAL) (Genesis)", "Genesis controller (C is jumpkick)", "Hack of Double Dragon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "740b47df422372fbef700b42cea4e0bf", "", "", "Dizzy Wiz (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "740f39e71104e90416c29a73560b9c6b", "Atari", "TE016643", "Diagnostic Test Cartridge 2.6P (1982) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7412f6788087d7e912c33ba03b36dd1b", "AtariAge, Omegamatrix", "", "Venture Reloaded (2019) (AtariAge) (Hack)", "Transformative hack of Venture", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "742de93b8d849220f266b627fbabba82", "", "", "SCSIcide (25-02-2001) (Chris Wilkson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7450ae4e10ba8380c55b259d7c2b13e8", "", "", "Register Twiddler Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7454786af7126ccc7a0c31fcf5af40f1", "", "", "Phantom Tank (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7465b06b6e25a4a6c6d77d02242af6d6", "Atari", "CX26193", "8 in 1 (01-16-92) (Atari) (Prototype)", "Game 2 is Centipede, but doesn't work", "Prototype", "", "", "8IN1", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7481f0771bff13885b2ff2570cf90d7b", "Arcadia Corporation, Brian McGhie", "AR-4104", "Rabbit Transit (1983) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "749fec9918160921576f850b2375b516", "Spectravision - Spectravideo", "SA-205", "China Syndrome (1982) (Spectravision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "74d072e8a34560c36cacbc57b2462360", "Sancho - Tang's Electronic Co.", "TEC002", "Seahawk (1982) (Sancho) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "74ebaca101cc428cf219f15dda84b6f8", "Activision, Alan Miller", "AG-007, CAG-007", "Tennis (1981) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "74f623833429d35341b7a84bc09793c0", "Zellers", "", "Radar (Zellers)", "AKA Exocet", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "75028162bfc4cc8e74b04e320f9e6a3f", "Atari, Greg Easter, Mimi Nyden", "CX26107", "Snow White (02-09-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7511c34518a9a124ea773f5b0b5c9a48", "", "", "Donkey Kong (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "75169c08b56e4e6c36681e599c4d8cc5", "M Network - INTV - APh Technological Consulting, Hal Finney", "MT5666", "Astroblast (1982) (M Network)", "Can also use left joystick", "Uncommon", "", "", "", "", "", "", "", "PADDLES", "", "YES", "AUTO 55", "", "", "", "" }, - { "752da1c0acd7d132ccfb0b1067f53cf6", "Thomas Jentzsch", "", "Reactor - Atari Mouse Hack v1.3 (PAL) (Full-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "753375d183c713cfa0aa7298d1f3067b", "Arcadia Corporation, Steve Hales, Stephen Harland Landrum", "AR-4102", "Suicide Mission (1982) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "7550b821ee56fb5833dca2be88622d5a", "", "", "Multiple Moving Objects Demo (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "75511bb694662301c9e71df645f4b5a7", "Activision, Bob Whitehead - Ariola", "EAG-011, PAG-011 - 711 011-715", "Stampede (1981) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "755fed16b48e81de05130708a905d00d", "SnailSoft", "", "Comitoid beta 3 (SnailSoft)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "756ca07a65a4fbbedeb5f0ddfc04d0be", "Atari, Jim Huether", "CX2629, CX2629P", "Sky Diver (1979) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7574480ae2ab0d282c887e9015fdb54c", "Atari, Jerome Domurat, Steve Woita", "CX2699", "Taz (1984) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7576dd46c2f8d8ab159d97e3a3f2052f", "Goliath - Hot Shot", "83-112", "Time Machine (1983) (Goliath) (PAL)", "AKA Asteroid Fire", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "757f529026696e13838364dea382a4ed", "Activision, David Crane - Ariola", "EAX-014, PAX-014, EAX-014-04B, EAX-014-04I - 711 014-720", "Grand Prix (1982) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "75893a9dc5de4b91cc426959b82a1da0", "Champ Games", "CG-02-P", "Conquest Of Mars (2010) (PAL60)", "Rev 2 release", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "75a303fd46ad12457ed8e853016815a0", "ZiMAG - Emag - Vidco", "715-111 - GN-060", "Immies & Aggies (1983) (ZiMAG) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "75b22fdf632d76e246433db1ebccd3c4", "", "", "Skeleton+ (05-05-2003) (Eric Ball) (PAL)", "", "", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "75b557be7f08db84ec5b242207b9f241", "", "", "Space Treat (30-12-2002) (Fabrizio Zavagli) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "75e276ba12dc4504659481c31345703a", "Arcadia Corporation, Kevin Norman", "AR-4103", "Killer Satellites (1983) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "75e8d8b9e9c5c67c2226dbfd77dcfa7d", "", "", "2600 Digital Clock (V b1) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "75ea128ba96ac6db8edf54b071027c4e", "Atari, David Crane", "CX26163P", "Slot Machine (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "75ea60884c05ba496473c23a58edf12f", "Atari, Howard Scott Warshaw - Sears", "CX2655 - 49-75167", "Yars' Revenge (1982) (Atari) (PAL) [a]", "ROM must be started in bank 0", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "75ee371ccfc4f43e7d9b8f24e1266b55", "Atari, Greg Easter, Mimi Nyden", "CX26107", "Snow White (11-09-1982) (Atari) (Prototype)", "ROM must be started in bank 0", "Prototype", "", "0", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7608abdfd9b26f4a0ecec18b232bea54", "Atari, Bob Whitehead", "CX26163P", "NFL Football (32 in 1) (1988) (Atari) (PAL)", "AKA Football", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7623a639a6fffdb246775fe2eabc8d01", "Activision, Bob Whitehead", "AG-005, CAG-005, AG-005-04", "Skiing (1980) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7628d3cadeee0fd2e41e68b3b8fbe229", "Atari", "CX26163P", "Fishing Derby (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7648e72a5b5899076688df18a1ddcf72", "CBS Electronics, Richard K. Balaska Jr., Andy Frank, Stuart Ross", "4L 2520 5000", "Tunnel Runner (1983) (CBS Electronics) (Prototype)", "Black Box", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "764ce6801f28a9ad36f11de3e57c053b", "Atari, Jim Huether, Alan J. Murphy, Robert C. Polaro", "CX2666", "RealSports Volleyball (1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "76809eb1ee0db8a318308a5cdda0f4e2", "Atari, Jerome Domurat, Steve Woita", "CX2699", "Taz (1983) (Atari) (Prototype) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "769ddc995dbb9edb8167efcea9f34a7c", "", "", "H.E.R.O. (Genesis)", "Genesis controller (B is laser, C is dynamite)", "Hack of H.E.R.0.", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "76a9bf05a6de8418a3ebc7fc254b71b4", "VideoSoft, Jerry Lawson, Dan McElroy", "VS1008", "Color Bar Generator (1984) (VideoSoft)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "76c685d1a60c0107aa54a772113a2972", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (3 of 3) (1983) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "76c88341017eae660efc6e49c4b6ab40", "", "", "Indiana Pitfall (Hack)", "Hack of Pitfall!", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "76ee917d817ef9a654bc4783e0273ac4", "Otto Versand", "311377", "Fox & Goat (Double-Game Package) (1983) (Otto Versand) (PAL)", "AKA Nuts", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "76f53abbbf39a0063f24036d6ee0968a", "M Network, David Akers, Joe 'Ferreira' King, Patricia Lewis Du Long, Jeff Ratcliff - INTV", "MT7045", "Bump 'n' Jump (1983) (M Network)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "76f66ce3b83d7a104a899b4b3354a2f2", "UA Limited", "", "Cat Trax (1983) (UA Limited) (1)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "77057d9d14b99e465ea9e29783af0ae3", "Activision, David Crane", "AG-001", "Dragster (1980) (Activision)", "AKA Drag Strip", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7732e4e4cc2644f163d6650ddcc9d9df", "HES", "771-333", "2 Pak Special - Challenge, Surfing (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7761418d46af069b8cd80c29fe6cd814", "Dion Olsthoorn", "RetroN 77 edition", "Amoeba Jump (R77) (DionoiD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7778ac65d775a079f537e97cbdad541c", "", "", "Spider Fighter (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "777aece98d7373998ffb8bc0b5eff1a2", "", "", "2600 Collison Demo 2 (Piero Cavina) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "77887e4192a6b0a781530e6cf9be7199", "Atari", "CX2604", "Space War (1978) (Atari) [b1]", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "77be57d872e3f5b7ecf8d19d97f73281", "", "", "Basketball (208 in 1) (Unknown) (PAL)", "Console ports are swapped", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "" }, - { "77cd9a9dd810ce8042bdb9d40e256dfe", "Kyle Pittman", "", "Evil Dead (2003) (Kyle Pittman) (Hack)", "Hack of Haunted House", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "77d0a577636e1c9212aeccde9d0baa4b", "Atari, Joe Decuir", "CX2621, CX2621P", "Video Olympics (1977) (Atari) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXDR", "PADDLES_IAXDR", "YES", "AUTO 60", "", "", "", "" }, - { "78297db7f416af3052dd793b53ff014e", "", "", "Poker Squares (V0.17) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7836794b79e8060c2b8326a2db74eef0", "", "", "RIOT RAM Test (26-11-2002) (Dennis Debro)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "784176346e9422733d55c427230e5bad", "Activision, Alex DeMeo", "", "Title Match Pro Wrestling (1989) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "784abfdb31d5341e5bd404d8d2a71c3b", "Alessandro Ciceri", "", "MagiCard (TV format conversion) (alex_79) (PAL)", "MagiCard PAL conversion hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7860716fa5dbc0fffab93fb9a4cb4132", "", "", "Hangman Monkey Wordlist (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7867ee819b53d69cfcfe740f7ddca574", "Arcadia Corporation, Dennis Caswell", "1 AR-4000, AR-4100", "Phaser Patrol (1982) (Arcadia) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "787ebc2609a31eb5c57c4a18837d1aee", "Prescott", "", "Vault Assault (19xx) (Prescott)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "78821ef76ebc3934850d1bc1b9e4f4b0", "HES - Activision", "542", "Hot Action Pak - Ghostbusters, Tennis, Plaque Attack (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "78963290052fd17c6c7998305ab3a6a0", "", "", "Push (V0.08) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "78b84cfb1c57b0488d674d2374e656e6", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (1 of 3) (1982) (Starpath)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "78c2de58e42cd1faac2ea7df783eaeb3", "", "", "Fu Kung! (V0.07) (25-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "79004f84bdeee78d142e445057883169", "CCE", "C-830", "Planet Patrol (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "791bc8aceb6b0f4d9990d6062b30adfa", "Activision, David Crane - Ariola", "EAX-018, EAX-018-04B, EAX-018-04I - 711 018-725", "Pitfall! (1982) (Activision) (PAL)", "Abenteuer im Urwald (Jungle Runner)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "791c88eca9836af8c34bf32b07cb58a7", "SpiceWare - Darrell Spice Jr.", "SW-05", "Stay Frosty 2 (PAL60)", "AtariAge Holiday Greetings 2014", "Homebrew", "", "", "", "", "", "", "", "JOYSTICK", "", "", "", "", "", "YES", "" }, - { "7926083ad423ed685de3b3a04a914315", "Barry Laws Jr.", "", "Face Invaders 2 (Barry Laws Jr.) (Hack)", "Hack of Astroblast", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "792b1d93eb1d8045260c840b0688ec8f", "Kroko", "", "3E Bankswitch Test (TIA @ $00)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7972e5101fa548b952d852db24ad6060", "Atari - Sears", "CX2627 - 6-99841", "Human Cannonball (1979) (Atari)", "AKA Cannon Man", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "798b8921276eec9e332dfcb47a2dbb17", "Atari - CCW, Gary Stark", "CX26102", "Cookie Monster Munch (1983) (Atari) (PAL) [a]", "Uses Kids/Keypad Controllers", "", "", "", "", "", "", "", "", "", "KEYBOARD", "", "", "", "", "", "" }, - { "798cc114f1623c14085868cd3494fe8e", "", "", "Pins Revenge (Atari Freak 1)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7991e1797e5e9f311fd957e62d889dff", "Joe Grand", "", "SCSIcide (v1.1) (2001) (Joe Grand)", "", "New Release", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "AUTO 65", "", "", "", "" }, - { "7996b8d07462a19259baa4c811c2b4b4", "", "", "Math Gran Prix (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "79ab4123a83dc11d468fb2108ea09e2e", "Activision - Cheshire Engineering, David Rolfe, Larry Zwick", "AZ-037-04", "Beamrider (1984) (Activision)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "79b649fb812c50b4347d12e7ddbb8400", "", "", "Red Pong Number 2 Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "79c27f90591e3fdc7d2ed020ecbedeb3", "CCE", "C-815", "Seaquest (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "79d4af56036ec28f298cad964a2e2494", "", "", "Hangman Pac-Man Wordlist (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "79d6f61da3c64688ac8e075667f8a39f", "", "", "Tie-Fighters (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "79e5338dbfa6b64008bb0d72a3179d3c", "M Network - INTV, David Akers, Patricia Lewis Du Long", "MT4313", "Star Strike (1983) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "79fcdee6d71f23f6cf3d01258236c3b9", "Atari - GCC, Mike Feinstein, John Mracek", "CX2673, CX2673P", "Phoenix (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7a09299f473105ae1ef3ad6f9f2cd807", "Atari, Steve Wright", "CX2616P", "Pele's Soccer (1981) (Atari) (PAL)", "AKA Pele's Championship Soccer", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7a2af383014f5d810ad26d322823549d", "", "", "FlickerSort Demo (20-04-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7a5463545dfb2dcfdafa6074b2f2c15e", "20th Century Fox Video Games - Sirius Software, Mark Turmell", "11007", "Turmoil (1982) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7a63d7ea3f2851bcf04f0bb4ba1a3929", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (3 of 4) (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7a64a8b727c8215d945e37d565ca95a5", "Atari, Warren Robinett", "CX2606", "Slot Racers (1978) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7a64b5a6e90619c6aacf244cdd7502f8", "Baroque Gaming (Brian Eno)", "", "Warring Worms (Beta 1) (2002) (Baroque Gaming)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7a7f6ab9215a3a6b5940b8737f116359", "Arcadia Corporation, Kevin Norman", "AR-4103", "Killer Satellites (1983) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7a93d0c029eaa72236523eedc3f19645", "", "", "20 Sprites at Once Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7ab0917107b6ec768a5ebaadf28c497a", "", "", "Santa's Helper (Hack)", "Hack of Kaboom!", "Hack", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, - { "7ab210f448de518fa61a5924120ba872", "", "", "Fortress (20-04-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7ab2f190d4e59e8742e76a6e870b567e", "Apollo, Larry Martin", "AP-2008", "Guardian (1982) (Apollo)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "01 65", "", "", "", "" }, - { "7ac4f4fb425db38288fa07fb8ff4b21d", "Goliath", "83-213", "Space Eagle (1983) (Goliath) (PAL)", "AKA Exocet", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7ad257833190bc60277c1ca475057051", "Atari, Alan J. Murphy, Robert Zdybel", "CX2668", "RealSports Football (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "7ad782952e5147b88b65a25cadcdf9e0", "Imagic, Dave Johnson", "720119-1A, 03211", "Kwibble (1983) (Imagic) (Prototype)", "AKA Quick Step! Beta", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7adbcf78399b19596671edbffc3d34aa", "Atari, Mimi Nyden, Joseph Tung", "CX26152", "Super Baseball (1988) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7af40c1485ce9f29b1a7b069a2eb04a7", "Amiga - Video Soft", "3120", "Mogul Maniac (1983) (Amiga)", "Uses the Amiga Joyboard", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7b24bfe1b61864e758ada1fe9adaa098", "Atari, Chris Crawford", "", "Wizard (1980) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7b33407b2b198af74906b936ce1eecbb", "King Atari", "", "Ghostbuster 2 (King Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "7b3cf0256e1fa0fdc538caf3d5d86337", "CommaVid, Joseph Biel", "CM-009", "Stronghold (1983) (CommaVid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7b43c32e3d4ff5932f39afcb4c551627", "Syncro, Daniel Wolf", "", "Kamikaze Saucers (1983) (Syncro) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7b4be337ac4d73eda75c848355f6f480", "Omegamatrix", "", "Star Wars Arcade (Atari Trak-Ball) (Y Inverted) (PAL60) v4 (Omegamatrix)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7b5207e68ee85b16998bea861987c690", "Atari, Carol Shaw", "CX26163P", "3-D Tic-Tac-Toe (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7b57318c489ff178f7ff500da1ec9e8c", "Thomas Jentzsch", "", "Reactor - Amiga Mouse Hack v1.3 (PAL) (Full-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7b6f3348dbf71ada88db0fdaf7feefe0", "", "", "3-D Corridor (Pink Spiral) (31-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7b79beb378d1b4471def90ceccf413de", "", "", "Pitfall Cupcake (Hack)", "Hack of Pitfall", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7b7b4ac05232490c28f9b680c72998f9", "Zellers", "", "Freeway (Zellers)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7b8a481e0c5aa78150b5555dff01f64e", "Atari - GCC, Mark Ackerman, Noellie Alito", "CX2692", "Moon Patrol (05-12-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7b938c7ddf18e8362949b62c7eaa660a", "Atari, Bob Whitehead - Sears", "CX2603 - 99803, 49-75601", "Star Ship (1977) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7ba07d4ea18bf3b3245c374d8720ad30", "Starpath Corporation, Stephen H. Landrum", "AR-4101", "Communist Mutants from Space (Preview) (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7bb286cb659d146af3966d699b51f509", "Atari - Axlon, Tod Frye", "CX26178", "Save Mary! (04-03-1989) (Atari) (Prototype)", "AKA Saving Mary", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7bc4fd254ec8c0a25a13f02fd3f762ff", "Retroactive", "", "Qb (V1.00) (Stella) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "7c00e7a205d3fda98eb20da7c9c50a55", "Apollo - Games by Apollo, Larry Minor, Ernie Runyon, Ed Salvo", "AP-2004", "Lost Luggage (1982) (Apollo)", "AKA Airport Mayhem", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7c4a499d343fca0cef2d59dd16af621a", "", "", "Poker Card Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7c757bb151269b2a626c907a22f5dae7", "TNT Games - Sculptured Software, Adam Clayton", "26192", "BMX Air Master (1989) (TNT Games) (PAL)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7c7a4a2d505c2d0c75337c44711d8d54", "Atari, Warren Robinett", "", "Elf Adventure (04-22-83) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7c9b3b8b25acf2fe3b8da834f69629c6", "", "", "I Robot (1984) (Atari) (Prototype) [!]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7ca7a471d70305c673fedd08174a81e8", "Tim Snider", "", "Venture II (2001) (Tim Snider)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "7cc77f6745e1f2b20df4a4327d350545", "Atari, Richard Maurer", "CX2632, CX2632P", "Space Invaders (1980) (Atari) (PAL) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7ccf350354ee15cd9b85564a2014b08c", "", "", "Big Dig (13-04-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7cd379da92c93679f3b6d2548617746a", "", "", "Demo Image Series #5 - Clown (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7cd900e9eccbb240fe9c37fa28f917b5", "Jone Yuan Telephonic Enterprise Co", "", "Bi! Bi! (Jone Yuan) (PAL)", "AKA Skindiver", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7ced6709f091e79a2ab9575d3516a4ac", "Activision, Steve Cartwright - Ariola", "EAX-027 - 711 027-722", "Plaque Attack (1983) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7cedffa0db65d610568b90aeca705ac6", "Atari, Rob Fulop - Sears", "CX2638 - 49-75166", "Missile Command (1981) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7cf3a9267cdb95aba91abc5838d61cc5", "Thomas Jentzsch", "", "Centipede - Atari Mouse Hack v1.4 (PAL60) (Half-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7d0b49ea4fe3a5f1e119a6d14843db17", "Gameworld, J. Ray Dettling", "133-008", "Frankenstein's Monster (1983) (Gameworld) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7d1034bcb38c9b746ea2c0ae37d9dff2", "Atari, Brad Stewart", "", "Morse Code Tutor (1979) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7d3cdde63b16fa637c4484e716839c94", "CCE", "", "Road Runner (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7d483b702c44ee65cd2df22cbcc8b7ed", "Atari, Warren Robinett", "", "Elf Adventure (05-25-83) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7d5c3b7b908752b98e30690e2a3322c2", "Dactari - Milmar", "", "Freeway (Dactari - Milmar)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7d726fa494f706784bafeb1b50d87f23", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (07-27-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7d8287e8423a56d4f8cef10435d97179", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Atari Trak-Ball Hack v1.2 (NTSC) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7d903411807704e725cf3fafbeb97255", "Imagic, Rob Fulop", "720104-1A, 720104-1B, IA3204", "Cosmic Ark (Reaction) (1982) (Imagic) [selectable starfield]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7d93071b3e3616093a6b5a98b0315751", "", "", "Gunfight 2600 - Music & Bugfixes 2 (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7d940d749e55b96b7b746519fa06f2de", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix (Preview) (1983) (Arcadia) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7d9c96b215d1941e87b6fb412eb9204f", "", "", "Othello (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7da9de8d62fcdd3a2c545b2e720c2a61", "CommaVid, John Bronstein", "CM-001", "MagiCard (1981) (CommaVid) (4K)", "Uses the Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7dbc8fa2e488e3f6b87fbe0f76c5b89f", "Ed Federmeyer", "", "Sound X (1996) (Ed Federmeyer)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7dc03a1f56d0e6a8aae3e3e50d654a08", "", "", "Hozer Video Demo (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7dcbfd2acc013e817f011309c7504daa", "Arcadia Corporation, Dennis Caswell", "AR-4000, AR-4100", "Phaser Patrol (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "7dd9c5284422f729066ab22a284c8283", "CCE", "C-833", "Target Practice (1983) (CCE) [a]", "AKA Carnival", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7ded20e88b17c8149b4de0d55c795d37", "Thomas Jentzsch, Paul Slocum", "", "Thrust+ Platinum (v1.26)", "", "New Release, supports BoosterGrip", "", "", "", "", "", "", "", "BOOSTERGRIP", "DRIVING", "", "", "", "", "", "" }, - { "7dfd100bda9abb0f3744361bc7112681", "Telesys, Don Ruffcorn", "1006", "Demolition Herby (1983) (Telesys) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "7e2fe40a788e56765fe56a3576019968", "Activision - Imagineering, Donald Hahn, Dan Kitchen", "AK-050-04", "Double Dragon (1989) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7e464186ba384069582d9f0c141f7491", "PlayAround - J.H.M.", "206", "General Re-Treat (1982) (PlayAround) (PAL)", "AKA Custer's Revenge", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7e4783a59972ae2cd8384f231757ea0b", "Atari - Imagineering, Dan Kichen", "CX26139P", "Crossbow (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7e51a58de2c0db7d33715f518893b0db", "CBS Electronics, E.F. Dreyer, Ed Salvo", "4L 2738 0000", "Mountain King (1983) (CBS Electronics) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "7e52a95074a66640fcfde124fffd491a", "Atari - GCC, Mike Feinstein, John Mracek", "CX2673", "Phoenix (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7e7c4c59d55494e66eef5e04ec1c6157", "Baroque Gaming (Brian Eno)", "", "Warring Worms (2002) (Baroque Gaming)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7e8aa18bc9502eb57daaf5e7c1e94da7", "CBS Electronics - Roklan, Joe Hellesen, Joe Wagner", "M8774, M8794", "Wizard of Wor (1982) (CBS Electronics)", "Uses the Joystick Controllers (swapped)", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "YES", "" }, - { "7e9da5cb84d5bc869854938fe3e85ffa", "Atari, Ian Shepard - Sears", "CX2604 - 6-99812, 49-75106", "Space War (1978) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7e9f088e15b2af9ff3411991393e6b1f", "Atari - Roklan, Joe Gaucher", "CX2679", "RealSports Basketball (12-28-1982) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7eab0284a0cd1043461d446a08d08cec", "Jone Yuan Telephonic Enterprise Co", "", "Basic Math (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7ead257e8b5a44cac538f5f54c7a0023", "Xonox, Anthony R. Henderson", "99006, 6220", "Sir Lancelot (1983) (Xonox) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7eaf009a892f03d90682dc1e67e85f07", "Fabrizio Zavagli", "", "Bounce! (18-03-2003) (Fabrizio Zavagli)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "7eafc9827e8d5b1336905939e097aae7", "Atari, Mark R. Hahn", "", "Elk Attack (1987) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7eba20c2291a982214cc7cbe8d0b47cd", "Imagic, Dave Johnson", "720119-1A, 03211", "Quick Step! (1983) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7ed61a18cebdeca0a93be1f5461731e5", "Dactari", "", "Skiing (Dactari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7ed7130a6e4020161836414332b11983", "", "", "Fu Kung! (V0.05 Cuttle Card Compatible) (13-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7edc8fcb319b3fb61cac87614afd4ffa", "Activision, Alan Miller", "AG-003", "Checkers (1980) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7ef3ca08abde439c6ccca84693839c57", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix (1983) (Arcadia) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "01", "", "", "", "" }, - { "7ef74879d7cb9fa0ef161b91ad55b3bb", "CCE", "", "Vanguard (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7f0209cfcc3d181715463f4d6451cecf", "Atari - GCC, John Allred, Douglas B. Macrae, Betty Ryan Tylko", "CX2694", "Pole Position (05-15-1983) (Atari) (Prototype)", "AKA RealSports Driving", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7f07cd2e89dda5a3a90d3ab064bfd1f6", "Videospielkassette - Ariola", "PGP234", "Boxen (Ariola) (PAL)", "AKA Boxing", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7f430c33044e0354815392b53a9a772d", "HES", "773-891", "2 Pak Special - Cavern Blaster, City War (1992) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7f525b07bc98080cc8950f7284e52ede", "Atari", "", "128-in-1 Junior Console (Chip 4 of 4) (1991) (Atari) (PAL)", "Actually contains only 16 games, not 32", "", "", "", "16IN1", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7f54fa6aa824001af415503c313262f2", "HES", "", "Boom Bang (HES) (PAL)", "AKA Crackpots", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7f6533386644c7d6358f871666c86e79", "CommaVid, Irwin Gaines", "CM-008", "Cakewalk (1983) (CommaVid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7f790939f7eaa8c47a246c4283981f84", "", "", "This Planet Sucks Demo 3 (Greg Troutman) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "7f819454734ddf93f83fefcffcd3e212", "Jone Yuan Telephonic Enterprise Co", "", "Outlaw (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7f9fbe3e00a21ea06e6ae5e0e5db2143", "", "", "Skate Boardin' (2002) (Skyworks)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7fcd1766de75c614a3ccc31b25dd5b7a", "PlayAround - J.H.M.", "203", "Knight on the Town (1982) (PlayAround)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "7fcd5fb59e88fc7b8473c641f44226c3", "CCE", "C-807", "Space Tunnel (1983) (CCE)", "AKA O Tunel Espacial", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7ff53f6922708119e7bf478d7d618c86", "Suntek", "SS-032", "Walker (1983) (Suntek) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "7ffc2d80fd49a124808315306d19868e", "Ishido", "", "Domino (Ishido) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "801ba40f3290fc413e8c816c467c765c", "Hozer Video Games", "", "Gunfight 2600 - Westward Ho! (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "803393ed29a9e9346569dd1bf209907b", "Atari - GCC, Mark Ackerman, Tom Calderwood, Glenn Parker", "CX2684", "Galaxian (02-04-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "804ed85eadf1ce3e93721547cbea7592", "CCE", "", "Fishing Derby (CCE) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8055b9c2622136fd91edfea6df642daf", "Activision", "", "Unknown Activision Game #1 (1983) (Activision) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "805f9a32ef97ac25f999a25014dc5c23", "SnailSoft", "", "Balthazar (SnailSoft)", "AKA Babylon 5", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "8068e07b484dfd661158b3771d6621ca", "Epyx, Steven A. Baker, Peter Engelbrite", "80561-00286", "California Games (1987) (Epyx) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "807841df228ee8aab0a06ee639ce5a8a", "Coleco - Project Guild - GMA, Michael Green, Anthony R. Henderson, Gary Littleton", "2455", "Turbo (1982) (Coleco) (Prototype)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "807a8ff6216b00d52aba2dfea5d8d860", "John Payson", "", "Strat-O-Gems Deluxe (2005) (J. Payson)", "Uses the AtariVox controller", "Homebrew", "", "", "", "", "", "", "", "", "ATARIVOX", "", "", "", "", "", "" }, - { "808c3b1e60ee0e7c65205fa4bd772221", "CCE", "", "Defender (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "80cd42881e670e4b74a9ccd10d0d7b2e", "20th Century Fox Video Games - Sirius, Ed Hodapp", "11004", "Deadly Duck (1982) (20th Century Fox) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "80cec82239913cb8c4016eb13749de44", "David Marli", "", "Invaders from Space by David Marli (Space Invaders Hack)", "Hack of Space Invaders (Atari)", "New Release (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "80dcbe1b55f12be731a224a53ee4ad5f", "Bit Corporation", "R320", "Amidar (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "80e1410ec98089e0733cc09e584dba4b", "Dynamics", "DY-293005", "Jumping Jack (1983) (Dynamics) (PAL)", "AKA Bobby Is Going Home", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "80e52315919bd8a8b82a407ccd9bb13f", "", "", "Euchre (Jul 28) (2002) (Eric Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "80e5400470ac788143e6db9bc8dd88cf", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (06-XX-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "80f7bf7418a462e8687ecefeaf6eb9c2", "Thomas Jentzsch", "", "Reactor - Atari Trak-Ball Hack v1.3 (NTSC) (Half-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8101efafcf0af32fedda4579c941e6f4", "", "", "Okie Dokie (4K) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "81073d0377a2badef8d5e74fc44fc323", "Thomas Jentzsch", "", "Sadoom (TJ) (PAL60) (Hack)", "Hack of Kaboom!", "Hack", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, - { "8108162bc88b5a14adc3e031cf4175ad", "Suntek", "SS-030", "Skydiver (1983) (Suntek) (PAL)", "AKA Parachute", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8108ad2679bd055afec0a35a1dca46a4", "", "", "Maze Craze (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "NTSC", "", "", "" }, - { "810d8952af5a6036fca8d0c4e1b23db6", "Tiger Vision - Eram", "", "Keystone (Tiger Vision)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "81254ebce88fa46c4ff5a2f4d2bad538", "Atari, David Crane - Sears", "CX2653 - 6-99823, 49-75111", "Slot Machine (1979) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "81341f00b61ab37d19d1529f483d496d", "", "", "Fu Kung! (V0.04) (10-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "813985a940aa739cc28df19e0edd4722", "Imagic, Bob Smith", "720000-201, 720102-1B, IA3201", "Star Voyager (1982) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "81414174f1816d5c1e583af427ac89fc", "Thomas Jentzsch", "", "Treasure Below (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "A", "", "", "", "", "", "", "", "", "", "" }, - { "814210c0e121f7dbc25661b93c06311c", "", "", "Joustpong (16-09-2002) (Kirk Israel) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "81591a221419024060b890665beb0fb8", "Atari, Carla Meninsky, Ed Riddle", "CX2611, CX2611P", "Indy 500 (1977) (Atari) (PAL)", "Uses the Driving Controllers", "", "", "", "", "", "", "", "", "DRIVING", "DRIVING", "", "45", "", "", "", "" }, - { "8190b403d67bf9792fe22fa5d22f3556", "", "", "Sky Diver (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "819aeeb9a2e11deb54e6de334f843894", "Atari, Gary Palmer", "CX2661", "Fun with Numbers (1980) (Atari)", "AKA Basic Math", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "81a010abdba1a640f7adf7f84e13d307", "Telegames - VSS", "7062 A305", "Universal Chaos (1988) (Telegames)", "AKA Targ", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "81b3bf17cf01039d311b4cd738ae608e", "CBS Electronics - Roklan, Joe Gaucher, Alex Leavens", "M8776, M8793", "Gorf (1982) (CBS Electronics)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "81f4f0285f651399a12ff2e2f35bab77", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "822a950f27ff0122870558a89a49cad3", "", "", "Space Jockey (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "82337e5fe0f418ca9484ca851dfc226a", "Thomas Jentzsch", "", "Robot City (V1.0) (Alpha) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "826481f6fc53ea47c9f272f7050eedf7", "Imagic, Dennis Koble", "720103-1A, IA3203", "Atlantis II (1982) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "827a22b9dffee24e93ed0df09ff8414a", "CBS Electronics, Stuart Ross", "", "Wings (10-10-1983) (CBS Electronics) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "8290daea8391f96d7c8e1482e184d19c", "Eckhard Stolberg", "", "Frame Timed Sound Effects (Eckhard Stolberg)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "82bf0dff20cee6a1ed4bb834b00074e6", "Suntek", "SS-035", "Panda (1983) (Quest) (Suntek) (PAL)", "AKA Panda Chase", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "82c25d1c35e6ac6f893d1d7c2fc2f9c8", "Atari, Larry Kaplan", "CX2628, CX2628P", "Bowling (1979) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "82de957d155fc041fc6afb8315a28550", "Coleco, Joseph Biel", "2457", "Venture (1982) (Coleco) (Prototype)", "2K", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "82e7aab602c378cffdd8186a099e807e", "", "", "Space Robot (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "82efe7984783e23a7c55266a5125c68e", "CCE", "C-837", "Pizza Chef (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "834a2273e97aec3181ee127917b4b269", "Quelle", "043.151 0, 874.382 5", "Die hungrigen Froesche (1983) (Quelle) (PAL)", "AKA Frogs and Flies", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "835759ff95c2cdc2324d7c1e7c5fa237", "20th Century Fox Video Games, Frank Cohen, Douglas 'Dallas North' Neubauer", "11011", "M.A.S.H (1983) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8372eec01a08c60dbed063c5524cdfb1", "", "", "Cross Force (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8388d6fe59c38c0b3a6ab2c58420036a", "Atari, Frank Hausman, Mimi Nyden, Steve Woita", "CX2686", "Quadrun (12-06-1982) (Atari) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "83b8c01c72306d60dd9b753332ebd276", "", "", "Bank Heist (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "83bdc819980db99bf89a7f2ed6a2de59", "Atari, Carla Meninsky - Sears", "CX2637 - 49-75158", "Dodge 'Em (1980) (Atari) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "83d15fb9843d9f84aa3710538403f434", "", "", "Gunfight 2600 - Release Candidate (2001) (MP) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "83e1b9f22f29259679e1018bc04cc018", "Bit Corporation", "R320", "Fast Eddie (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "83f05ececae8be59ba1e51135f4bdcbf", "", "", "Demo Image Series #13 - Mario (4K Interleaved Chronocolour) (05-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "83f50fa0fbae545e4b88bb53b788c341", "Atari, Larry Kaplan - Sears", "CX2643 - 6-99815", "Codebreaker (1978) (Atari) (4K)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "83fafd7bd12e3335166c6314b3bde528", "Epyx, Steven A. Baker, Tod Frye, Peter Engelbrite", "80561-00251", "Winter Games (1987) (Epyx)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "840a5a2eaea24d95d289f514fd12f9bb", "", "", "GBImprov (Hack)", "Hack of Ghostbusters", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "841057f83ce3731e6bbfda1707cbca58", "Champ Games", "CG-04-N", "Super Cobra Arcade (NTSC)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "JOYSTICK", "", "", "", "", "", "YES", "" }, - { "841b7bc1cad05f5408302308777d49dc", "Activision", "", "Unknown Activision Game (10-22-1982) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "84290e333ff7567c2380f179430083b8", "Imagic, Dave Johnson", "13211, EIX-004-04I", "Quick Step! (1983) (Imagic) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "843435eb360ed72085f7ab9374f9749a", "Joe Grand", "", "SCSIcide (1.31) (Joe Grand)", "Uses the Paddle Controllers", "New Release", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "AUTO 65", "", "", "", "" }, - { "84535afb9a69712ec0af4947329e08b8", "CCE", "C-868", "Bingo (1983) (CCE) (PAL)", "AKA Dice Puzzle", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "8454ed9787c9d8211748ccddb673e920", "Froggo", "FG1002", "Spiderdroid (1987) (Froggo)", "AKA Amidar", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8490e1014c2baa0d3a3a08854e5d68b3", "Xonox, Anthony R. Henderson", "99006, 6220", "Sir Lancelot (1983) (Xonox) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "84db818cd4111542a15c2a795369a256", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (1983) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "850ffd5849c911946b24544ea1e60496", "", "", "Invasion (07-10-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "851cc1f3c64eaedd10361ea26345acea", "Activision, David Crane", "AG-009, AG-009-04", "Freeway (1981) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "85227160f37aaa29f5e3a6c7a3219f54", "Activision, David Crane", "AG-004", "Fishing Derby (1980) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8530caaaf40acbdcd118c282b5f8a37a", "", "", "This Planet Sucks Demo 2 (Greg Troutman) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8538c5e3ee83267774480649f83fa8d6", "", "", "Escape Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "853c11c4d07050c22ef3e0721533e0c5", "", "", "Oink! (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "85470dcb7989e5e856f36b962d815537", "Atari - Sculptured Software, Inc., Steve Aguirre", "CX26162", "Fatal Run (1989) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "85478bb289dfa5c63726b9153992a920", "", "", "Candi (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "854b68b93e7123a3be42b5a2a41f75d7", "Atari, Carol Shaw", "CX2618, CX2618P", "3-D Tic-Tac-Toe (1980) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "85502d69fe46b7f54ef2598225678b47", "Jone Yuan Telephonic Enterprise Co", "", "Super-Ferrari (Jone Yuan)", "AKA Enduro", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "85564dd0665aa0a1359037aef1a48d58", "ITT Family Games", "554-33 367", "Laser Base (1983) (ITT Family Games) (PAL) [a]", "AKA The End of the World (Perry Rhodan-Serie)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "8556b42aa05f94bc29ff39c39b11bff4", "Atari, Craig Nelson - Sears", "CX2617 - 49-75183", "Backgammon (1979) (Atari)", "Uses the Paddle Controllers", "Extremely Rare", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "AUTO 80", "", "", "", "" }, - { "855a42078b14714bcfd490d2cf57e68d", "Atari, Suki Lee", "CX26113", "Miss Piggy's Wedding (1983) (Atari) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8597f66dd37d9c855663804669d69d7a", "Tigervision, Warren Schwader", "7-003", "Threshold (1982) (Tigervision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "85a4133f6dcf4180e36e70ad0fca0921", "CCE", "C-827", "Chopper Command (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "85b1bca93e69f13905107cc802a02470", "Atari, Craig Nelson", "CX2617, CX2617P", "Backgammon (1979) (Atari) (PAL)", "Uses the Paddle Controllers", "Extremely Rare", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "AUTO 80", "", "", "", "" }, - { "85bbefb90e16bf386b304c1e9a1f6084", "Champ Games", "CG-02-P", "Conquest Of Mars (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "85e48d68c8d802e3ba9d494a47d6e016", "", "", "Ship Demo (V 15) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "85e564dae5687e431955056fbda10978", "Milton Bradley Company - Renaissance Technology, Ty Roberts", "4362", "Survival Run (1983) (Milton Bradley)", "AKA Cosmic Commander", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "86128001e69ab049937f265911ce7e8a", "Apollo - Games by Apollo, Steve Stringfellow", "AP-2005", "Lochjaw (1982) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8619da7f6796cedff59e5aa20712fb4e", "Thomas Jentzsch", "", "Sadistroids (v1.2) (2003) (Thomas Jentzsch)", "Supports Driving Controller in right port", "", "", "", "", "", "", "", "", "", "DRIVING", "", "", "", "", "YES", "30" }, - { "862cf669cbced78f9ed31a5d375b2ebe", "", "", "Gunfight 2600 - Flicker acceptance (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8644352b806985efde499ae6fc7b0fec", "CCE", "C-801", "Mr. Postman (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8654d7f0fb351960016e06646f639b02", "Home Vision, R.J.P.G. - Gem International Corp. - VDI", "VCS83106", "Ski Hunt (1983) (Home Vision) (PAL)", "AKA Skiiing Hunt", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "866e5150c995c4ae5172e5207ba948c7", "Canal 3 - Intellivision", "", "Stampede (Canal 3) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "869abe0426e6e9fcb6d75a3c2d6e05d1", "", "", "Stampede (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "86b4aa76bbeb70e1a4f9211a9880ba8e", "", "", "Incoming (1 Player Version) (05-11-2002) (Ben Larson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8712cceec5644aacc2c21203d9ebe2ec", "Retroactive", "", "Qb (V0.10) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "8726c17ee7b559cb7bf2330d20972ad0", "", "", "Cave Demo (21-04-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "873fb75a7788ba0f4ae715229a05545e", "", "", "Euchre (Improved Colors) (PAL) (26-09-2002) (Erik Eid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8747ba79cd39fa83a529bb26010db21b", "Atari, Richard Maurer", "CX2632, CX2632P", "Space Invaders (1980) (Atari) (PAL) [different speed and colors]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8749a0d088df25218c149dc325abc7ca", "Commavid, Ben Burch", "CM-010", "Rush Hour (1983) (Commavid) (Prototype) [a5]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "874c76726f68c166fcfac48ce78eef95", "", "", "Red Pong Number 2 Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "8764462d7d19a33b0717af22b99fc88f", "CCE", "", "Sky Jinks (CCE) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "87662815bc4f3c3c86071dc994e3f30e", "Intellivision Productions - M Network, Patricia Lewis Du Long, Stephen Tatsumi", "", "Swordfight (1983) (Intellivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "876a953daae0e946620cf05ed41989f4", "Retroactive", "", "Qb (V2.08) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "877a5397f3f205bf6750398c98f33de1", "Erik Eid", "", "Euchre (Beta) (PAL) (12-09-2002) (Erik Eid)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8786c1e56ef221d946c64f6b65b697e9", "20th Century Fox Video Games, David Lubar", "11015", "AKA Space Adventure", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8786f229b974c393222874f73a9f3206", "Activision, Larry Miller - Ariola", "EAX-021, EAX-021-04I - 711 021-720", "Spider Fighter (1983) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8786f4609a66fbea2cd9aa48ca7aa11c", "Goliath", "5", "Open Sesame (1983) (Goliath) (PAL)", "AKA Open, Sesame!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "87b460df21b7bbcfc57b1c082c6794b0", "Dennis Debro", "", "Climber 5 (20-03-2003) (Dennis Debro)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "87b6a17132fc32f576bc49ea18729506", "Atari, Andrew Fuchs, Courtney Granner, Jeffrey Gusman, Mark R. Hahn", "CX2690", "Pengo (1984) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "87bea777a34278d29b3b6029833c5422", "Thomas Jentzsch", "", "Polaris (1983) (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "87e79cd41ce136fd4f72cc6e2c161bee", "Atari - GCC, Mark Ackerman, Glenn Parker", "CX2675", "Ms. Pac-Man (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "87f020daa98d0132e98e43db7d8fea7e", "20th Century Fox Video Games - Sirius, David Lubar", "11001", "Worm War I (1982) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "883258dcd68cefc6cd4d40b1185116dc", "Activision, David Crane - Ariola", "EAZ-030, EAZ-030-04B, EAZ-030-04I - 711 030-725", "Decathlon (1983) (Activision) (PAL)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8874b68751fd2ba6d3306a263ae57a7d", "Eric Mooney", "", "Invaders by Erik Mooney (Alpha 1) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8885d0ce11c5b40c3a8a8d9ed28cefef", "Atari, Carol Shaw, Nick 'Sandy Maiwald' Turner - Sears", "CX2608 - 49-75165", "Super Breakout (1982 - 1981) (Atari)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "01 45", "", "", "", "" }, - { "888debb162d7d1ae71025b4ab794257f", "", "", "Interleaved ChronoColour - Nude Art (17-04-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "88a6c9c88cb329ee5fa7d168bd6c7c63", "CCE", "C-1007", "Jungle Hunt (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "88d300a38bdd7cab9edad271c18cd02b", "Funvision - Fund. Int'l Co.", "", "Pac Kong (Funvision) (PAL)", "AKA Inca Gold", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "88d7b6b3967de0db24cdae1c7f7181bd", "Atari - GCC, Dave Payne", "CX2669", "Vanguard (1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "88d8a1accab58cf1abb043613cf185e9", "Ultravison", "", "Sabotage (Ultravison)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "88dce4037471424bb38ab6841aaa8cab", "", "", "Double-Height 6-Digit Score Display (Two Background Color Change) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "88ed87c011f699dd27321dbe404db6c8", "Activision, Dan Kitchen", "AX-029", "Crackpots (1983) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "88f74ec75ef696e7294b7b6ac5ca465f", "Activision, Bob Whitehead", "AG-002, CAG-002, AG-002-04", "Boxing (1980) (Activision) (16K)", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8905d54f48b8024fc718ed643e9033f7", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (05-24-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "890c13590e0d8d5d6149737d930e4d95", "Atari, David Crane - Sears", "CX2605 - 6-99822, 49-75109", "Outlaw (1978) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8917f7c1ac5eb05b82331cf01c495af2", "Bit Corporation", "PG202", "Space Tunnel (1982) (BitCorp) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8933976f2029c0d8492ebd8f4eb21492", "", "", "Synthcart Plus (09-02-2003) (Paul Slocum)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8953bc11352d794431d3303e31d3b892", "Tigervision, Robert H. O'Neil", "7-007", "Polaris (02-17-1983) (Tigervision) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "896ec58f26e930e02f5e4f046602c3a1", "", "", "Synthcart (Beta) (2002) (Paul Slocum)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "898143773824663efe88d0a3a0bb1ba4", "Activision - Woodside Design Associates, Steve 'Jessica Stevens' Kitchen", "AZ-033, AZ-033-04", "Space Shuttle (1983) (Activision) [FE]", "A Journey Into Space", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "898748d5eaac3164b0391a64ae1e0e32", "", "", "Hangman Man 4letter (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "898b5467551d32af48a604802407b6e8", "Bit Corporation", "PG208", "Snail Against Squirrel (1983) (BitCorp) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "89a65b83203980d5d4d60f52a584a5b8", "", "", "Marble Craze (PAL) (02-02-2003) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "89a68746eff7f266bbf08de2483abe55", "Atari, Jerome Domurat, Steve Woita", "CX2696", "Asterix (1984) (Atari)", "AKA Taz", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "89afff4a10807093c105740c73e9b544", "", "", "Pooyan (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "89eaba47a59cbfd26e74aad32f553cd7", "Apollo - Games by Apollo, Ed Salvo, Byron Parks", "AP-2001", "Spacechase (1982) (Apollo) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8a159ee58b2f0a54805162984b0f07e5", "Atari - Sculptured Software, Inc., Steve Aguirre", "CX26162", "Fatal Run (1989) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8a183b6357987db5170c5cf9f4a113e5", "Atari - Roklan, Joe Gaucher", "CX2679", "RealSports Basketball (01-11-1983) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8a42e2c7266439d8997a55d0124c912c", "", "", "Hangman Invader Wordlist (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8a49cf1785e3dea2012d331a3ad476e1", "", "", "Boulderdash (10 Blocks Wide) (02-04-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8a6c84f481acf42abcb78ba5064ad755", "128-in-1 Junior Console", "", "Street Racer (128-in-1 Junior Console) (PAL) (4K)", "Uses the Paddle Controllers (swapped)", "", "", "", "", "", "", "", "", "", "", "YES", "10 75", "", "", "", "" }, - { "8a8e401369e2b63a13e18a4d685387c6", "Activision, David Crane - Ariola", "EAG-008, PAG-008, EAG-008-04I - 711 008-720", "Laser Blast (1981) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8a9d874a38608964f33ec0c35cab618d", "Chris Cracknell", "", "Rescue Bira Bira (Chris Cracknell)", "Hack of Jungle Fever", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "8a9d953ac3db52a313a90d6a9b139c76", "", "", "Hangman Invader Biglist3 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8aad33da907bed78b76b87fceaa838c1", "Atari, Larry Kaplan", "CX26163P", "Air-Sea Battle (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8ac18076d01a6b63acf6e2cab4968940", "Atari, Dan Hitchens, Mimi Nyden", "CX2685", "Gravitar (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8af58a9b90b25907da0251ec0facf3b8", "Jone Yuan Telephonic Enterprise Co", "", "Cosmic Swarm (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "8b04e9d132b8e30d447acaa6bd049c32", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (1982) (Starpath) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8b40a9ca1cfcd14822e2547eaa9df5c1", "Parker Brothers - Western Technologies, Dave Hampton, Tom Sloper", "931517", "Q-bert (1983) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8b504b417c8626167a7e02f44229f0e7", "Retroactive", "", "Qb (V1.00) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "8b556c3d9ca8e5e6e665bd759b93ffae", "", "", "Synthcart (2002) (Paul Slocum) (PAL) [!]", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "8b5b1e3a434ebbdc2c2a49dc68f46360", "CBS Electronics - Woodside Design Associates - Imaginative Systems Software, Garry Kitchen", "4L1700, 4L1701, 4L1702, 4L1802, 4L2274", "Donkey Kong (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8b7ca29a55432f886cee3d452fb00481", "Starpath Corporation, Stephen H. Landrum, Jon Leupp", "11 AR-4201", "Sword of Saros (1983) (Starpath) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8b8152d6081f31365406cb716bd95567", "Atari", "CX2626, CX2626P", "Miniature Golf (1979) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8b8789c6669a4cee86c579a65332f852", "Digivision", "", "Plaque Attack (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8bbfd951c89cc09c148bfabdefa08bec", "UA Limited", "", "Pleiades (1983) (UA Limited) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "8bc0d2052b4f259e7a50a7c771b45241", "Xonox - K-Tel Software, Anthony R. Henderson", "99007, 6240", "Tomarc the Barbarian (1983) (Xonox) [a]", "AKA Thundarr the Barbarian", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8bd8f65377023bdb7c5fcf46ddda5d31", "Activision, Bob Whitehead", "AG-019", "Sky Jinks (1982) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8bebac614571135933116045204f0f00", "Thomas Jentzsch", "", "Missile Command (Trakball) (2002) (TJ) (PAL)", "Uses the Trakball Controller", "Homebrew", "", "", "", "", "", "", "", "TRAKBALL", "TRAKBALL", "", "", "", "", "YES", "" }, - { "8c103a79b007a2fd5af602334937b4e1", "Thomas Jentzsch", "", "Laser Base (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8c136e97c0a4af66da4a249561ed17db", "", "", "Poker Squares (V0.27) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8c146c61817edd376bc1354c7f1ddc63", "Omegamatrix", "", "Star Wars Arcade (Amiga Mouse) (Y Inverted) (PAL60) v4 (Omegamatrix)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8c1cc284edba691139d6626d062c606f", "Atari, Omegamatrix", "", "Super Breakout Menu (2020) (PAL60) (Hack)", "Hack of Super Breakout", "", "", "", "", "", "", "", "", "", "", "", "AUTO 45", "", "", "", "" }, - { "8c2fa33048f055f38358d51eefe417db", "Home Vision - Gem International Corp. - VDI", "VCS83137", "Teddy Apple (1983) (Home Vision) (PAL)", "AKA Open, Sesame!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "8c36ed2352801031516695d1eeefe617", "Epyx, Steven A. Baker, Tod Frye, Peter Engelbrite", "80561-00251", "Winter Games (1987) (Epyx) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8c7e5e2329f4f4e06cbcc994a30fd352", "Data Age", "DA1004", "Airlock (1982) (Data Age) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8c8a26ed57870daba8e13162d497bad1", "HES", "", "2 Pak Special - Dolphin, Oink (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8c8b15b3259e60757987ed13cdd74d41", "Supergame", "71", "River Raid (1984) (Supergame)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8c941fa32c7718a10061d8c328909577", "Digivision", "", "River Raid (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8ccaa442d26b09139685f5b22bf189c4", "Retroactive", "", "Qb (V1.01) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "8ccf63141a029603572d1056e772990e", "Thomas Jentzsch", "", "Centipede - Amiga Mouse Hack v1.4 (NTSC) (Full-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8cd26dcf249456fe4aeb8db42d49df74", "Atari - Imagineering, Dan Kichen", "CX26139", "Crossbow (1988) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8ce9126066f2ddd5173e9f1f9ce1494e", "Thomas Jentzsch", "", "Missile Command (Trakball) (2002) (TJ)", "Uses the Trakball Controller", "Homebrew", "", "", "", "", "", "", "", "TRAKBALL", "TRAKBALL", "", "", "", "", "YES", "" }, - { "8cf0d333bbe85b9549b1e6b1e2390b8d", "Atari, Brad Stewart", "CX2649, CX2649P", "Asteroids (1981) (Atari) (PAL)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "8d00a38f4c8f8800f1c237215ac243fc", "", "", "3-D Corridor (Green) (30-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8d1e2a6d2885966e6d86717180938f87", "Thomas Jentzsch", "", "Missile Command (Amiga Mouse) (2002) (TJ)", "Uses Amiga Mouse Controller", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "8d8b7d7b983f75debbdaac651e814768", "", "", "Demo Image Series #15 - Three Marios (PAL) (06-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8d9a06101ebb0f147936356e645309b8", "", "", "Grid Pattern Demo 2 (20-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8da51e0c4b6b46f7619425119c7d018e", "Atari - Imagineering, David Lubar", "CX26183", "Sentinel (1991) (Atari)", "Uses the Light Gun Controller (left only)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8db152458abaef3cfa7a4e420ddbda59", "", "", "Keystone Kapers (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8df4be9ddc54ac363b13dc57ceaf161a", "Scott Stilphen", "", "Asteroids SS (Scott Stilphen) (Hack)", "Hack of Asteroids", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "8e0ab801b1705a740b476b7f588c6d16", "Activision, David Crane", "AG-009, AG-009-04", "Freeway (1981) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8e42674972d6805068fc653e014370fd", "", "", "Skeleton (PAL) (15-10-2002) (Eric Ball)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8e48ea6ea53709b98e6f4bd8aa018908", "CBS Electronics, Stuart Ross", "", "Wings (06-03-1983) (CBS Electronics) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "8e4cd60d93fcde8065c1a2b972a26377", "Imagic, Dan Oliver", "720118-2A, 13208, EIX-007-04I", "Laser Gates (1983) (Imagic) (PAL)", "AKA Innerspace", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8e4fa8c6ad8d8dce0db8c991c166cdaa", "Atari, Bill Aspromonte, John Russell, Michael Sierchio, Robert Zdybel", "CX26114", "Pigs in Space (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8e512ad4506800458f99dec084fc2c64", "Bob Montgomery, Nathan Strum", "", "Reindeer Rescue (2005)", "2005 AtariAge Holiday Cart", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8e7241bfc8380aac3c0ef1b6881cdded", "Atari, Howard Scott Warshaw - Sears", "CX2655 - 49-75167", "Yars' Revenge (09-01-81) (Atari) (Prototype)", "Time Freeze", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "8e737a88a566cc94bd50174c2d019593", "Quelle", "343.173 1", "Feuerwehr im Einsatz (1983) (Quelle) (PAL)", "AKA Fire Fighter", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8e822b39a71c84ac875f0107fb61d6f0", "", "", "Hangman Ghost Original Words (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8e879aa58db41edb67cbf318b77766c4", "Thomas Jentzsch", "", "Cosmic Commuter (Thomas Jentzsch) (PAL60)", "NTSC Conversion", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8e887d1ba5f3a71ae8a0ea16a4af9fc9", "", "", "Skeleton (V1.1) (PAL) (24-10-2002) (Eric Ball)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8ed5a746c59571feb255eaa7d6d0cf98", "", "", "Carnival (208 in 1) (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8ed73106e2f42f91447fb90b6f0ea4a4", "Spectravision - Spectravideo", "SA-204", "Tapeworm (1982) (Spectravision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "8ee3f64dc0f349adc893fe93df5245d8", "", "", "Euchre (20-07-2001) (Eric Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8ef96ace4a1d6dfb65926c1e868b0188", "Thomas Jentzsch", "", "Reactor - Amiga Mouse Hack v1.3 (PAL60) (Half-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8f33bce5ba1053dcf4cea9c1c69981e4", "", "", "Jawbreaker (Unknown) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8f53a3b925f0fd961d9b8c4d46ee6755", "", "", "Astrowar (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8f5ac5139419c5d49bacc296e342a247", "Atari - CCW, Michael Callahan, Preston Stuart", "CX26103", "Alpha Beam with Ernie (12-22-1982) (Atari) (Prototype)", "Uses Keypad Controllers", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8f60551db6d1535ef0030f155018c738", "", "", "Space War (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8f613ea7c32a587d6741790e32872ddd", "", "", "Troll Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8f88309afad108936ca70f8b2b084718", "Spectravision - Spectravideo - Quelle", "SA-203 - 413.223 9", "Cross Force (1982) (Spectravision) (PAL)", "AKA Kreuzfeuer (Cross Fire)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8f90590dba143d783df5a6cff2000e4d", "", "", "Gopher (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8f98519a91dbbf4864f135a10050d9ed", "Silvio Mogno", "", "Rainbow Invaders (non-playable demo) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8fa47e5242776e841df7e708b12eb998", "", "", "Sea Hawk (Genesis)", "Genesis controller (C drops bomb)", "Hack of Sea Hawk", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8fbabaa87941cdf3a377c15e95bdb0f3", "", "", "Meteor Smasher (SnailSoft)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8fe00172e7fff4c1878dabcf11bb8dce", "Quelle", "689.302 8", "Hili Ball (1983) (Quelle) (PAL)", "AKA Racquetball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "8febdd9142960d084ab6eeb1d3e88969", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX2674", "E.T. - The Extra-Terrestrial (1982) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "8fffc8f15bb2e6d24e211884a5479aa5", "Retroactive", "", "Qb (V1.00) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "9007c3cbb55ce05ad7d1c34d4906750a", "Activision, David Crane", "AX-018, AX-018-04", "Pitfall! (03-18-1983) (Activision) (Prototype)", "Pitfall Harry's Jungle Adventure (Jungle Runner)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9048ccb7e0802cd8fa5bfc2609f292d8", "Tigervision, Robert H. O'Neil", "7-007", "Polaris (1983) (Tigervision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9057694dce8449521e6164d263702185", "Activision, Bob Whitehead", "AG-011", "Stampede (1981) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "90578a63441de4520be5324e8f015352", "Bit Corporation", "PGP204", "Open Sesame (4 Game in One) (1983) (BitCorp) (PAL)", "AKA Open, Sesame!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "9072c142728a3a3d994956d03bfacba2", "Fabrizio Zavagli", "", "Crash Dive (Fabrizio Zavagli) (PAL60)", "NTSC Conversion", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "90a3c3255f2a54225cdcb50831f8793a", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Atari Trak-Ball Hack v1.1 (PAL) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "90b1799dddb8bf748ee286d22e609480", "", "", "Ship Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "90b647bfb6b18af35fcf613573ad2eec", "AtariAge (Chris Walton)", "", "Juno First (2009)", "AtariVox supported", "Homebrew", "", "", "", "", "", "", "", "", "ATARIVOX", "", "", "", "", "YES", "" }, - { "90ccf4f30a5ad8c801090b388ddd5613", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (1982) (Starpath)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "90d77e966793754ab4312c47b42900b1", "Imagic, Brad Stewart", "720105-2A, IA3400P, EIX-005-04I", "Fire Fighter (1982) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "90f502cbf4438a95f69f848cef36eb64", "Digitel", "", "River Raid II (1985) (Digitel)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "910dd9bf98cc5bc080943e5128b15bf5", "", "", "Gunfight 2600 - Improved AI (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "911d385ee0805ff5b8f96c5a63da7de5", "Thomas Jentzsch", "", "Jammed (V0.1) (Demo) (2001) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "913d5d959b5021f879033c89797bab5e", "", "", "Robot Player Graphic (1996) (J.V. Matthews) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "914a8feaf6d0a1bbed9eb61d33817679", "Atari", "CX26163P", "Freeway Chicken (32 in 1) (1988) (Atari) (PAL)", "AKA Freeway", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "91925abce3a29e33b6a8b81482f4f5af", "Activision, Garry Kitchen - Ariola", "EAX-025, EAX-025-04I - 711 025-725", "Keystone Kapers (1983) (Activision) (PAL) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9193b6fff6897d43274741d4f9855b6d", "", "", "M.A.S.H (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "91a3749ff7b7e72b7fa09e05396a0e7b", "", "", "Gunfight 2600 - Final Run Part 2 (2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "91b007f33f9b790be64f57220ec52e80", "Jone Yuan Telephonic Enterprise", "", "Laser Blast (Jone Yuan) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "91c2098e88a6b13f977af8c003e0bca5", "Atari - GCC", "CX2676", "Centipede (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "91d1c82ceaf8af2add3973a3c34bc0cb", "", "", "Starfield Demo 1 (20-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "91f0a708eeb93c133e9672ad2c8e0429", "", "", "Oystron (V2.9) (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "91fdb6541f70c40b16aabf8308123be8", "", "", "Interlacing Game (19-08-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9222b25a0875022b412e8da37e7f6887", "Panda", "106", "Dice Puzzle (1983) (Panda)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "9245a84e9851565d565cb6c9fac5802b", "Bomb - Onbase", "CA282", "Great Escape (1983) (Bomb)", "AKA Asteroid Fire", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "927d422d6335018da469a9a07cd80390", "Activision, Carol Shaw - Ariola", "EAX-020, EAX-020-04B, EAX-020-04I - 711 020-720", "River Raid (1982) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9281eccd7f6ef4b3ebdcfd2204c9763a", "Retroactive", "", "Qb (2.15) (Retroactive) (PAL)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "9295570a141cdec18074c55dc7229d08", "Telegames", "7045 A015", "Bump 'n' Jump (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "929e8a84ed50601d9af8c49b0425c7ea", "Bit Corporation", "PG205", "Dancing Plate (1982) (BitCorp) (PAL)", "AKA Dishaster, Dancing Plates, Tanzende Teller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "92a1a605b7ad56d863a56373a866761b", "U.S. Games Corporation - Western Technologies, Dave Hampton", "VC2006", "Raft Rider (1983) (U.S. Games)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "92d1b6cb8a1b615266c4088a58464779", "Bit Corporation", "R320", "Fishing Derby (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "92d1f6ac179ebe5963868d6bc1bdda8d", "HES", "498", "Smash Hit Pak - Frogger, Boxing, Seaquest, Skiing, Stampede (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "92e72f7cc569584c44c9530d645ae04e", "Canal 3 - Intellivision", "", "Spider Fighter (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "931b91a8ea2d39fe4dca1a23832b591a", "Activision, David Crane", "AG-008", "Laser Blast (1981) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9333172e3c4992ecf548d3ac1f2553eb", "Konami", "RC 101-X 02", "Strategy X (1983) (Konami)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "93420cc4cb1af1f2175c63e52ec18332", "Tim Snider", "", "Blair Witch Project (Tim Snider) (Hack)", "Hack of Haunted House", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9364ad51c321e0f15c96a8c0aff47ceb", "Atari, Rob Fulop", "CX2638", "Missile Command (1981) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "936ef1d6f8a57b9ff575dc195ee36b80", "", "", "Pac Kong (Unknown)", "AKA Inca Gold", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "936f555b4b1a2cd061b659ff63f4f5f2", "HES, David Lubar", "535", "My Golf (1990) (HES) (PAL) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "937736d899337036de818391a87271e0", "Atari, Peter C. Niday", "CX26108", "Donald Duck's Speedboat (04-12-1983) (Atari) (Prototype)", "AKA Donald Duck's Regatta", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "939ce554f5c0e74cc6e4e62810ec2111", "ZiMAG - Emag - Vidco", "711-111 - GN-020", "Dishaster (1983) (ZiMAG)", "AKA Dancing Plate", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "93acd5020ae8eb5673601e2edecbc158", "Chris Cracknell", "", "Video Time Machine (Chris Cracknell)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "93b9229fc0ea4fb959d604f83f8f603c", "Thomas Jentzsch", "", "Amidar DS (Fast Enemies) (2003) (TJ) (Hack)", "Hack of Amidar", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "93c4b910f7649b3e998bb6d8527c6f4a", "Sparrow - Enter-Tech, Paul Walters, Rick Harris, George Hefner, Barbara Ultis", "", "Arkyology (1983) (Sparrow) (Prototype) [fixed]", "Fix for un-initialized 'X' register", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "93c52141d3c4e1b5574d072f1afde6cd", "Imagic, Mark Klein", "720112-1A, 03213", "Subterranea (1983) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "93c8d9d24f9c5f1f570694848d087df7", "Digivision", "", "Galaxian (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "93c9f9239a4e5c956663dd7affa70da2", "Quelle", "626.610 0", "Billard (1983) (Quelle) (PAL)", "AKA Trick Shot", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "93db185c3b3dc382f3aecd6a2fea7fd9", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Atari Trak-Ball Hack v1.1 (PAL60) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "93dc15d15e77a7b23162467f95a5f22d", "CCE", "", "Sky Jinks (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "93e276172b521c4491097f8b1393eea7", "Atari", "", "Diagnostic Test Cartridge 4.2 (06-01-1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "93eb1795c8b1065b1b3d62bb9ec0ccdc", "JSK", "", "Custer's Viagra (JSK) (Hack)", "Hack of Custer's Revenge", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "94102febc53b4a78342d11b645342ed4", "", "", "Joustpong (14-07-2002) (Kirk Israel) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9433770890f087bfcf3e50122694d8c0", "Omegamatrix", "", "Star Wars Arcade (Amiga Mouse) (Y Inverted) v4 (Omegamatrix)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9436b7ad131b5a1f7753ce4309ba3dee", "Kyle Pittman", "", "War of The Worlds (Kyle Pittman) (Hack)", "Hack of Defender", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "943798452ceba9357e2c56303cadb4f7", "Thomas Jentzsch, Paul Slocum", "", "Thrust+ Platinum (v1.28)", "", "New Release, supports BoosterGrip and Genesis (switched by Color/B+W)", "", "", "", "", "", "", "", "JOYSTICK", "DRIVING", "", "", "", "", "", "" }, - { "9446940866c9417f210f8552cf6c3078", "Thomas Jentzsch", "", "Marble Craze - Amiga Mouse Hack v1.0 (PAL60) (TJ)", "Uses Amiga Mouse Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "94507dee401b0a072a481c00d7699ffe", "Thomas Jentzsch", "", "Missile Control - Atari Trak-Ball Hack v1.15 (PAL) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9469d18238345d87768e8965f9f4a6b2", "CCE", "", "Ms. Pac-Man (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "947317a89af38a49c4864d6bdd6a91fb", "CBS Electronics, Bob Curtiss", "4L 2487 5000", "Solar Fox (1983) (CBS Electronics)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "94b92a882f6dbaa6993a46e2dcc58402", "Activision, Larry Miller", "AX-026, AX-026-04", "Enduro (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "94d90f63678e086f6b6d5e1bc6c4c8c2", "Digivision", "", "Seaquest (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "94e3fbc19107a169909e274187247a9d", "", "2402-044-01", "2-in-1 Freeway and Tennis (Unknown)", "", "", "", "", "2IN1", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "94e4c9b924286038527f49cdc20fda69", "Retroactive", "", "Qb (V2.12) (Stella) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "94e7cc6342d11e508e7e8b2ddf53c255", "", "", "Missile Command (208 in 1) (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "94ff6b7489ed401dcaaf952fece10f67", "Atari - GCC, Mark Ackerman, Noellie Alito", "CX2692", "Moon Patrol (07-31-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "951e8cec7a1a1d6c01fd649e7ff7743a", "Atari - Sculptured Software, Adam Clayton", "CX26151, CX26151P", "Dark Chambers (1988) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9526e3db3bdfbc27989a9cbfd0ee34bf", "", "", "Atari Logo Demo 6 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "95351b46fa9c45471d852d28b9b4e00b", "Atari, Tom Rudadahl", "CX26163P", "Golf (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "955c408265ad6994f61f9b66657bbae9", "", "", "Quadrun (Video Conversion) (Fabrizio Zavagli)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "956496f81775de0b69a116a0d1ad41cc", "CCE", "", "Alien (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "956b99511c0f47b3a11d18e8b7ac8d47", "", "", "Bones (Arcade Golf Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "95956108289a917f80667eccd3ce98a9", "Atari, Ed Logg, Carol Shaw", "CX2639, CX2639P", "Othello (1981) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "95a69cf8c08ef1522b050529464f0bca", "", "", "Grid Pattern Demo 1 (20-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "95a89d1bf767d7cc9d0d5093d579ba61", "PlayAround - J.H.M.", "204", "Lady in Wading (1982) (PlayAround)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "95e1d834c57cdd525dd0bd6048a57f7b", "Atari, Bill Aspromonte, John Russell, Michael Sierchio, Robert Zdybel", "CX26114", "Pigs in Space (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "95e542a7467c94b1e4ab24a3ebe907f1", "Suntek", "SS-021", "Dragon Defender (1983) (Suntek) (PAL)", "", "", "", "", "", "", "", "", "", "MINDLINK", "", "", "", "", "", "YES", "" }, - { "95fd6097dc27c20666f039cfe34f7c69", "", "", "Oh No! (Version 1) (17-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "961112b74a920a5242e233480326c356", "Activision, Alan Miller", "AG-007, CAG-007", "Tennis (1981) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "962ffd3eaf865230a7a312b80e6c5cfd", "Imagic, Wilfredo 'Willy' Aguilar, Michael Becker, Rob Fulop", "13205", "Fathom (1983) (Imagic) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "96662271ae50b6859017bffbdda75525", "Andrew Davie & Thomas Jentzsch", "", "Boulder Dash - Demo (2011)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "96670d0bf3610da2afcabd8e21d8eabf", "", "", "Boring Pitfall (Hack)", "Hack of Pitfall!", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "966b11d3c147d894dd9e4ebb971ea309", "", "", "Marble Craze Song (Paul Slocum) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "966c955e4aaca7082d9ffb9a68e3f3ed", "Thomas Jentzsch", "", "Centipede - Atari Mouse Hack v1.4 (PAL) (Full-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9671b658286e276cc4a3d02aa25931d2", "", "", "Hangman Ghost Wordlist (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "968efc79d500dce52a906870a97358ab", "TNT Games - Sculptured Software, Adam Clayton", "26192", "BMX Air Master (1989) (TNT Games)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "969b968383d9f0e9d8ffd1056bcaef49", "Atari, Larry Kaplan", "CX2628, CX2628P", "Bowling (1979) (Atari) (PAL)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "96bcb3d97ce4ff7586326d183ac338a2", "", "", "Revenge of the Apes (Hack) [h2]", "Hack of Planet of the Apes", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "96e798995af6ed9d8601166d4350f276", "20th Century Fox Video Games - Videa, David Ross", "11029", "Meltdown (1983) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "96eccc2277043508a6c481ea432d7dd9", "Thomas Jentzsch", "", "Missile Command (Atari Mouse) (2002) (TJ) (PAL)", "Uses Atari ST Mouse Controller", "Homebrew", "", "", "", "", "", "", "", "ATARIMOUSE", "ATARIMOUSE", "", "", "", "", "YES", "" }, - { "96f806fc62005205d851e758d050dfca", "", "", "Push (V0.05) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "97184b263722748757cfdc41107ca5c0", "Parker Brothers", "PB5820", "Mr. Do!'s Castle (1984) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "9718b85ac5a55cbc7348963c63ffa35a", "Robby", "", "Demon Attack (Robby)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "972486110933623039a3581db308fda6", "", "", "Xeno Plus (Hack)", "Hack of Xenophobe", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "97327d6962f8c64e6f926f79cd01c6b9", "", "", "Jawbreaker (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "977294ae6526c31c7f9a166ee00964ad", "Atari - GCC, Douglas B. Macrae", "CX2677, CX2677P", "Dig Dug (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9784290f422e7aeeab4d542318bd9a1f", "AtariAge, Chris Walton", "1.0 (Release)", "Chetiry (2011) (AtariAge) (60k)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "50" }, - { "97842fe847e8eb71263d6f92f7e122bd", "Imagic, Wilfredo Aguilar, Michael Becker, Dennis Koble", "720113-1A, 03206", "Solar Storm (1983) (Imagic)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "01 45", "", "", "", "" }, - { "97933c9f20873446e4c1f8a4da21575f", "", "", "Racquetball (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "97a9bb5c3679d67f5c2cd17f30b85d95", "Atari", "", "Colors (1980) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "97cd63c483fe3c68b7ce939ab8f7a318", "Thomas Jentzsch", "", "Robot City (V0.21) (15-09-2002) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "97d0151beb84acbe82aa6db18cd91b98", "Steve Engelhardt", "", "Lunar Attack (2002) (Steve Engelhardt) (Hack)", "Hack of Z-Tack", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "97d079315c09796ff6d95a06e4b70171", "Activision, Garry Kitchen", "AZ-032", "Pressure Cooker (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "97e47512f89e79818d988d078dc90410", "Thomas Jentzsch", "", "Missile Control - Amiga Mouse Hack v1.15 (NTSC) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "97f4da9f1031486f4e588f1e53572e53", "SpiceWare - Darrell Spice Jr.", "", "Draconian", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "9813b9e4b8a6fd919c86a40c6bda8c93", "Atari", "CX26177", "Ikari Warriors (1989) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9831efc7f4cb8ffb4df0082bab2f07a3", "Activision, Steve Cartwright - Ariola", "EAX-031, EAX-031-04B - 711 031-717", "Frostbite (1983) (Activision) (PAL) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9848b5ef7a0c02fe808b920a2ac566d2", "Skyworks Technology Inc.", "", "Baseball (2002) (Skyworks)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9853089672116117258097dbbdb939b7", "Hozer Video Games", "", "Gunfight 2600 - Cowboy Hair (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "98555b95cb38e0e0b22b482b2b60a5b6", "", "", "Spinning Fireball (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "98ba601a60172cb46c5bf9a962fd5b1f", "", "", "Gorilla Kong (Hack)", "Hack of Donkey Kong", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "98ccd15345b1aee6caf51e05955f0261", "Retroactive", "", "Qb (V2.03) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "98e5e4d5c4dd9a986d30fd62bd2f75ae", "", "", "Air-Sea Battle (Unknown) (Hack) (4K)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "98e6e34af45a0664597972c3bb31180f", "", "", "Space Instigators (V1.7) (17-10-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "98e7caaab8ec237558378d2776c66616", "Bradford W. Mott", "", "HMOVE Test (Bradford W. Mott) (1998) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "98ea10c47c13f1b3306c7b13db304865", "", "", "Jam Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "98ec0fa4199b9c01f7b8fa3732e43372", "Activision, David Crane", "AX-018, AX-018-04", "Pitfall! (1982) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "98ef1593624b409b9fb83a1c272a0aa7", "CCE", "C-831", "Cosmic Ark (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "98f63949e656ff309cefa672146dc1b8", "Atari - Axlon, John Vifian", "CX26168", "Off the Wall (1989) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "98fa3ad778a668a79449350de4b3b95b", "Thomas Jentzsch", "", "Thrust (V1.1) (2000) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9905f9f4706223dadee84f6867ede8e3", "HES", "", "Challenge (HES) (PAL)", "Surfer's Paradise if right difficulty = 'A'", "", "", "0", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9912d06eea42200a198dd3e2be18c601", "Imagic, Michael Greene", "IA3312", "No Escape! (1982) (Imagic) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "991d57bbcd529ad62925098e0aec1241", "", "", "Gunfight 2600 - The Final Kernel (MP) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9945a22f60bbaf6d04a8d73b3cf3db75", "Activision, Dan Kitchen", "EAX-039-04B, EAX-039-04I", "Kung-Fu Master (1987) (Activision) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9947f1ebabb56fd075a96c6d37351efa", "CBS Electronics", "4L 2737 0000", "Omega Race (1983) (CBS Electronics)", "Set right difficulty to 'A' for BoosterGrip in both ports", "", "", "", "", "", "A", "", "", "BOOSTERGRIP", "BOOSTERGRIP", "", "", "", "", "", "" }, - { "9962034ea7b3d4a905d0991804670087", "", "", "Grid Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9989f974c3cf9c641db6c8a70a2a2267", "Eckhard Stolberg", "", "Colours Selector (Eckhard Stolberg)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "99a24d7bb31d49b720b422550b32c35f", "", "", "Hangman Ghost Biglist1 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "99ac89241365b692255ba95d745edd91", "Atari, Frank Hausman, Mimi Nyden, Steve Woita", "CX2686", "Quadrun (18-03-1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "99f7c6c26046bbe95f1c604b25da8360", "SnailSoft", "", "Comitoid beta 2 (SnailSoft)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9a01115206f32eb0b539c7e5a47ccafa", "Atari, Jerome Domurat, Steve Woita", "CX2699", "Taz (07-15-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9a165c39af3f050fdee6583fdfcdc9be", "Zirok", "", "Mario Bros. (Zirok)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9a21fba9ee9794e0fadd7c7eb6be4e12", "Atari - Imagineering, Dan Kitchen", "CX26177", "Ikari Warriors (1991) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9a25b3cfe2bbb847b66a97282200cca2", "Atari, Brad Stewart - Sears", "CX2622 - 6-99813, 49-75107", "Breakout (1978) (Atari) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "01 60", "", "", "", "" }, - { "9a4274409216ff09ecde799f2a56ac73", "CCE", "C-801", "Mr. Postman (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9ab72d3fd2cc1a0c9adb504502579037", "Epyx, Steven A. Baker, Peter Engelbrite", "80561-00286", "California Games (1987) (Epyx)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9ad362179c2eea4ea115c7640b4b003e", "", "", "Barnstorming (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "NTSC50", "", "", "" }, - { "9ad36e699ef6f45d9eb6c4cf90475c9f", "Imagic, Dennis Koble", "720103-1A, 720103-1B, IA3203, IX-010-04", "Atlantis (1982) (Imagic)", "AKA Lost City of Atlantis", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9aeb5206c5bf974892a9cc59f1478db3", "Activision, Steve Cartwright", "AX-013", "Barnstorming (1982) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9af615951e9719df2244bc77fc50cb95", "Dactari - Milmar", "", "Defender (Dactari - Milmar)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9afdfe1cff7f37f1c971fe3f0c900606", "Funvision - Fund. International Co.", "", "Plug Attack (Funvision)", "AKA Plaque Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9b150a42fc788960fbb4cbe250259ee2", "Kroko", "", "3E Bankswitch Test (TIA @ $40)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9b21d8fc78cc4308990d99a4d906ec52", "CCE", "C-838", "Immies & Aggies (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9b246683f44c963a50e41d6b485bee77", "", "", "Boring (PAL) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9bb136b62521c67ac893213e01dd338f", "Xonox - Beck-Tech", "6210, 7210, 06003. 99001", "Spike's Peak (1983) (Xonox) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9bd4e0d5f28ba6da417c26649171f8e4", "", "", "Hangman Pac-Man Original Words (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9be58a14e055b0e7581fc4d6c2f6b31d", "", "", "Adventure (Color Scrolling) (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9c27ef3bd01c611cdb80182a59463a82", "Arcadia Corporation, Kevin Norman", "AR-4103", "Killer Satellites (1983) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9c40bf810f761ffc9c1b69c4647a8b84", "", "", "2 in 1 - Frostbite, River Raid (Unknown)", "", "", "", "", "2IN1", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9c6d65bd3b477aace0376f705b354d68", "", "", "RPG Kernal (18-04-2003) (Paul Slocum) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "9c6faa4ff7f2ae549bbcb14f582b70e4", "U.S. Games Corporation, Garry Kitchen, Paul Willson - Vidtec", "VC1002", "Sneak 'n Peek (1982) (U.S. Games)", "AKA Hide 'n Seek", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9c6fd6ed3599978ab7b6f900484b9be6", "Andrew Wallace", "", "Laseresal 2002 (PAL60) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9c729017dd2f9ccbadcb511187f80e6b", "", "", "J-Pac (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9c7fa3cfcaaafb4e6daf1e2517d43d88", "", "", "PIEROXM Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9ca2deb61318eba4fb784d4bf7441d8b", "", "", "Purple Bar Demo 2 (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9cbb07f1993a027bc2f87d5205457ec9", "", "", "Eckhard Stolberg's Scrolling Text Demo 1 (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9d0befa555f003069a21d2f6847ad962", "Atari - GCC, Dave Payne", "CX2669", "Vanguard (1982) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9d1556ae5890398be7e3d57449774b40", "Activision, David Crane", "AG-001", "Dragster (1980) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9d2938eb2b17bb73e9a79bbc06053506", "Imagic, Michael Greene", "EIZ-002-04I", "Wing War (1983) (Imagic) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9d2f05d0fe8b2dfcf770b02eda066fc1", "", "", "Push (V0.06) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9d33d31fb1de58c5460d8a67b57b36da", "", "", "Star Voyager (Genesis)", "Genesis controller (C is secondary lasers)", "Hack of Star Voyager", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9d37a1be4a6e898026414b8fee2fc826", "M Network - INTV - APh Technological Consulting, David Rolfe", "MT5665", "Super Challenge Baseball (1982) (M Network)", "AKA Big League Baseball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9d4bc7c6fe9a7c8c4aa24a237c340adb", "Dennis Debro", "", "Climber 5 (16-04-2003) (Dennis Debro)", "For Philly Classic 4", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9d522a3759aa855668e75962c84546f7", "Atari, Tom Rudadahl", "CX2634, CX2634P", "Golf (1980) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9d7f04618bb4043f531d087e3aaa7ac8", "Parker Brothers, Larry Gelberg, Gary Goltz", "PB5065", "Star Wars - Ewok Adventure (1983) (Parker Bros) (Prototype) (PAL) (16K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9de0d45731f90a0a922ab09228510393", "20th Century Fox Video Games - Sirius, Mark Turmell", "11003", "Fast Eddie (1982) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9dec0be14d899e1aac4337acef5ab94a", "CommaVid, John Bronstein", "CM-003", "Cosmic Swarm (1982) (CommaVid) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "9e01f7f95cb8596765e03b9a36e8e33c", "Atari - CCW, Michael Callahan, Preston Stuart", "CX26103", "Alpha Beam with Ernie (1983) (Atari)", "Uses Keypad Controllers", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9e135f5dce61e3435314f5cddb33752f", "Fabrizio Zavagli", "", "Space Treat Deluxe (2003)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9e192601829f5f5c2d3b51f8ae25dbe5", "PlayAround - J.H.M.", "201", "Cathouse Blues (1982) (PlayAround)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "9e2c7299c69b602443d327c7dad51cbf", "Charles Morgan", "", "Xaxyrax Road (Charles Morgan) (Hack)", "Hack of Freeway", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9e437229136f1c5e6ef4c5f36178ed18", "Funvision - Fund. International Co.", "", "Grand Prize (Funvision)", "AKA Enduro", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9e5007131695621d06902ab3c960622a", "Sega", "", "Tac Scan (1983) (Sega) [h1]", "", "", "", "", "", "", "", "", "", "", "", "", "AUTO 60", "", "", "YES", "" }, - { "9e792a59f8795664cbaaff1ba152d731", "", "", "Bullet Demo (20-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9e904e2eaa471c050c491289b8b80f60", "", "", "How to Draw a Playfield II (1997) (Erik Mooney) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9ea8ed9dec03082973244a080941e58a", "Eric Mooney, Piero Cavina", "", "INV+", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9ec1b259a1bcffa63042a3c2b3b90f0a", "Activision, David Crane", "AG-008", "Laser Blast (1981) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9eca521db1959156a115dee85a405194", "", "", "Fu Kung! (V0.08) (2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9ed0f2aa226c34d4f55f661442e8f22a", "", "", "Nuts (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9eeb40f04a27efb1c68ba1d25e606607", "Kyle Pittman", "", "Rambo II (2003) (Kyle Pittman) (Hack)", "Hack of Double Dragon", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9efa877a98dd5a075e058214da428abb", "Hozer Video Games", "", "SCSIcide (1.32) (Hozer Video Games)", "Uses the Paddle Controllers", "New Release", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "AUTO 65", "", "", "", "" }, - { "9efb4e1a15a6cdd286e4bcd7cd94b7b8", "20th Century Fox Video Games, John W.S. Marvin", "", "Planet of the Apes (1983) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9f2d58dce1b81c6ba201ed103507c025", "", "", "Fu Kung! (V0.02) (2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9f48eeb47836cf145a15771775f0767a", "Atari, Warren Robinett", "CX2620", "Basic Programming (1979) (Atari)", "Uses Keypad Controllers", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "9f5096a6f1a5049df87798eb59707583", "20th Century Fox Video Games, Mark Klein", "11036", "Entity, The (1983) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9f52271759f8a2004d207b2247ae0bb3", "Parker Brothers", "PB5820", "Mr. Do!'s Castle (03-12-84) (Parker Bros) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "9f59eddf9ba91a7d93bce7ee4b7693bc", "Thomas Jentzsch", "", "Montezuma's Revenge (Thomas Jentzsch) (PAL60)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9f8fad4badcd7be61bbd2bcaeef3c58f", "Parker Brothers, Charlie Heath", "PB5330", "Reactor (1983) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "9f901509f0474bf9760e6ebd80e629cd", "Atari, Bob Whitehead - Sears", "CX2623 - 6-99819, 49-75108, 49-75125", "Home Run (1978) (Atari) (4K)", "", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "" }, - { "9f93734c68f6479eb022cab40814142e", "", "", "Push (V0.07) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9f982421b9b4320ede00fe4aa2e812f4", "Atari, Omegamatrix", "", "Super Breakout Menu (2020) (Hack)", "Hack of Super Breakout", "", "", "", "", "", "", "", "", "", "", "", "AUTO 45", "", "", "", "" }, - { "9f9ee0f60c119c831e80694b6678ca1a", "Jeffry Johnston", "", "Radial Pong - Version 8 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9fa0c664b157a0c27d10319dbbca812c", "Chris Walton, Justin Hairgrove, Tony Morse", "", "Hunchy II (2005)", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "9fc2d1627dcdd8925f4c042e38eb0bc9", "Atari - GCC, John Allred, Mike Feinstein", "CX2688, CX2688P", "Jungle Hunt (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "E68E28752D3C54EDD3CCDA42C27E320C", "Xonox - K-Tel Software, Anthony R. Henderson", "99007, 6240", "Tomarc the Barbarian (1983) (Xonox)", "Genesis controller (B is jump and throw, C switches between players)", "Hack of Tomarc the Barbarian", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a0028f057d496f22b549fd8deecc6f78", "Joe Grand", "", "SCSIcide Pre-release 6 (Joe Grand)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a00ec89d22fcc0c1a85bb542ddcb1178", "CCE", "C-1012", "Phoenix (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a00ee0aed5c8979add4c170f5322c706", "Barry Laws Jr.", "", "Egghead (Barry Laws Jr.) (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a0185c06297b2818f786d11a3f9e42c3", "", "", "International Soccer (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a025a8f83a42a4d6d46c4887e799bfac", "Hozer Video Games", "", "Gunfight 2600 - Descissions had to be made (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a0297c4788f9e91d43e522f4c561b4ad", "Atari - CCW, Gary Stark", "CX26102", "Cookie Monster Munch (1983) (Atari) (PAL)", "Uses Kids/Keypad Controllers", "", "", "", "", "", "", "", "", "", "KEYBOARD", "", "", "", "", "", "" }, - { "a0563dd6d8215c38c488fbbd61435626", "", "", "Ship Demo (V 1501) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a0675883f9b09a3595ddd66a6f5d3498", "Telegames - VSS", "6057 A227", "Quest for Quintana Roo (1988) (Telegames)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a075ad332942740c386f4c3814925ece", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (2 of 4) (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a0d502dc8b90b1d7daa5f6effb10d349", "", "", "Demo Image Series #5 - Sam (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a0e2d310e3e98646268200c8f0f08f46", "Atari, Ed Logg, Carol Shaw", "CX2639, CX2639P", "Othello (1981) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a100eff2d7ae61ca2b8e65baf7e2aae8", "David Marli", "", "Muncher (David Marli) (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a11099b6ec24e4b00b8795744fb12005", "Activision - Bobco, Robert C. Polaro", "EAK-049-04B", "Rampage! (1989) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a1403fef01641dcd3980cac9f24d63f9", "Dactari - Milmar", "", "Atlantis (Dactari - Milmar)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a14d8a388083c60283e00592b18d4c6c", "", "", "Tunnel Demo (28-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a15b5831a1fab52e4c416068c85ec011", "Hozer Video Games", "", "Gunfight 2600 - The Good, The Bad, The Ugly (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a174cece06b3abc0aec3516913cdf9cc", "Sears Tele-Games, Jim Huether", "CX2614 - 49-75126", "Steeplechase (1980) (Sears) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "", "", "" }, - { "a1770ef47146ab7b12e2c4beccd68806", "Digitel", "", "Kaystone Kapers (1983) (Digitel)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a184846d8904396830951217b47d13d9", "Activision, Dan Kitchen", "AX-029", "Crackpots (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a189f280521f4e5224d345efb4e75506", "Atari - Thomas Jentzsch", "", "Obelix (1983) (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a1bcbe0bfe6570da2661fc4de2f74e8a", "Imagic - Advanced Program Technology, Rob Fulop", "", "Actionauts (Microbots) (1984-2008) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a1ca372388b6465a693e4626cc98b865", "Quelle", "176.543 7", "Der Vielfrass (1983) (Quelle) (PAL)", "AKA Fast Food", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a1ead9c181d67859aa93c44e40f1709c", "American Videogame - Dunhill Electronics, Darrell Wagner, Todd Clark Holm, John Simonds", "", "Tax Avoiders (1986) (American Videogame)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a1f9159121142d42e63e6fb807d337aa", "Quelle - Otto Versand", "700.223 1 - 781627", "Der moderne Ritter (1983) (Quelle) (PAL)", "AKA Fast Eddie", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a204cd4fb1944c86e800120706512a64", "Coleco, Rob Harris", "2511", "Smurfs Save the Day (1983) (Coleco)", "Uses the Kid Vid Controller", "", "", "", "", "", "", "", "", "", "KIDVID", "", "", "", "", "", "" }, - { "a20b7abbcdf90fbc29ac0fafa195bd12", "Quelle - Otto Versand", "719.383 2 - 649635, 781393, 781784, 986404", "Motocross (1983) (Quelle) (PAL)", "AKA Motorcross", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a20d931a8fddcd6f6116ed21ff5c4832", "Apollo - Games by Apollo, Ed Salvo, Byron Parks", "AP-2003", "Racquetball (1982) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "a2170318a8ef4b50a1b1d38567c220d6", "Amiga - Video Soft", "3125", "Surf's Up (1983) (Amiga) (Prototype) [a1]", "Uses the Joyboard controller", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a2276822c772f72073a8a40a72a1ca52", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Atari Mouse Hack v1.1 (NTSC) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a2424c1a0c783d7585d701b1c71b5fdc", "", "", "Video Pinball (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a25bb76e9e773117e567fd4300b1bb23", "", "", "Interleaved ChronoColour Demo (NTSC) (05-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a28d872fc50fa6b64eb35981d0f4bb8d", "Atari, Larry Kaplan - Sears", "CX2628 - 6-99842, 49-75117", "Bowling (1979) (Atari) (4K)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a29df35557f31dfea2e2ae4609c6ebb7", "Atari", "", "Circus Atari (1980) (Atari) (Joystick)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a29fc854838e08c247553a7d883dd65b", "Activision, Steve Cartwright", "AX-013", "Barnstorming (1982) (Activision) (16K)", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a2a384d3a16d5be50afd12906f146827", "Bit Corporation", "R320", "Flash Gordon (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a2aae759e4e76f85c8afec3b86529317", "", "", "Boom Bang (Unknown)", "AKA Crackpots", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a2d7cc2e5419a9e4ab91fdb26339b726", "Omegamatrix", "", "Star Wars Arcade (Atari Mouse) (Y Inverted) (PAL60) v4 (Omegamatrix)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a2de0fc85548871279ed2a3c1325c13e", "George Veeder", "", "Cat and Mouse (George Veeder) (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a2eb84cfeed55acd7fece7fefdc83fbb", "", "", "Kool Aid Man (Fixed) (15-11-2002) (CT)", "HMOVE handling fixed in this version", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a2f296ea2d6d4b59979bac5dfbf4edf0", "", "", "Warring Worms (28-01-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a2f9e3b6aaa23b6dc06099cdd5b51b31", "Nukey Shay", "", "Montezuma's Revenge (Genesis) (PAL60) (F6_Conversion)", "Genesis controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a302b922a8dbec47743f28b7f91d4cd8", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (Preview) (1982) (Starpath)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a30ece6dc4787e474fbc4090512838dc", "Zellers", "", "Circus (Zellers)", "AKA Circus Atari", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a310494ad5ba2b5b221a30d7180a0336", "", "", "Demo Image Series #6 - Mario (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a336beac1f0a835614200ecd9c41fd70", "Atari, Christopher H. Omarzu, Robert Vieira", "CX26121", "Zoo Keeper Sounds (1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a34560841e0878c7b14cc65f79f6967d", "Multivision, Michael Case", "", "Harem (1982) (Multivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a3486c0b8110d9d4b1db5d8a280723c6", "Atari, Alan J. Murphy, Robert C. Polaro", "CX26100", "Bugs Bunny (08-04-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a35d47898b2b16ec641d1dfa8a45c2b7", "Activision, Steve Cartwright", "AX-017, AX-017-04", "MegaMania (1982) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a3873d7c544af459f40d58dfcfb78887", "", "", "Tennis (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a3b9d2be822eab07e7f4b10593fb5eaa", "", "", "GREGXM Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a3c1c70024d7aabb41381adbfb6d3b25", "Telesys, Alex Leavens", "1005", "Stargunner (1983) (Telesys)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a3d7c299fbcd7b637898ee0fdcfc47fc", "Arcadia Corporation, Scott Nelson", "AR-4300", "Fireball (Preview) (1982) (Arcadia) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "01", "", "", "", "" }, - { "a3f2a0fcf74bbc5fa763b0ee979b05b1", "Quelle", "873.790 0", "Eishockey-Fieber (1983) (Quelle) (PAL)", "AKA Ice Hockey", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a3f8aebb38182749cb8da85cfbc63d7c", "", "", "Tennis (208 in 1) (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a3fee8ce15525ea00d45a06f04c215d1", "Aaron Curtis", "", "AStar (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a406d2f6d84e61d842f4cb13b2b1cfa7", "Tigervision, John Harris - Teldec", "7-002", "Jawbreaker (1982) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a412c8577b2d57b09185ae51739ac54f", "Arcadia Corporation, Dennis Caswell", "AR-4000", "Phaser Patrol (1982) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "a41450333f8dd0e96e5e9f0af3770ae9", "", "", "Basic Math (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a422194290c64ef9d444da9d6a207807", "M Network - APh Technological Consulting, Hal Finney", "MT5667", "Dark Cavern (1982) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a428068d3e51498907d97cec40000515", "Bit Corporation", "R320", "Sky Alien (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a47878a760f5fa3aa99f95c3fdc70a0b", "", "", "Demo Image Series #5 - Baboon (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a4790224bd5afabd53cbe93e46a7f241", "Activision, Bob Whitehead", "AG-019", "Sky Jinks (1982) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a47e26096de6f6487bf5dd2d1cced294", "Atari", "CX2643", "Codebreaker (1978) (Atari) (PAL)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a484638990de7b12c62947c79dafa4c6", "Thomas Jentzsch", "", "Marble Craze - Atari Mouse Hack v1.0 (PAL60) (TJ)", "Uses Atari Mouse Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a499d720e7ee35c62424de882a3351b6", "SEGA - Beck-Tech, Steve Beck, Phat Ho", "009-01", "Up 'n Down (1984) (SEGA)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a4aa7630e4c0ad7ebb9837d2d81de801", "", "", "Atari 2600 Invaders (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a4ab331e8768eafdc20ce8b0411ff77a", "", "", "Demo Image Series #1 - Sam (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a4b9423877a0b86ca35b52ca3c994ac5", "CCE", "C-805", "Sea Monster (1983) (CCE)", "O Monstro Marinho", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a4b99aa5ed85cfdb7d101923147de035", "Jim Goebel", "", "Pac-Law (Jim Goebel) (Hack)", "Hack of Outlaw", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a4c08c4994eb9d24fb78be1793e82e26", "Activision, Alan Miller", "AX-012, CAX-012, AX-012-04", "Ice Hockey (1981) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a4d026a5c200ef98518ebb77719fe8dc", "Kyle Pittman", "", "SpongeBob SquarePants (2003) (Kyle Pittman) (Hack)", "Hack of Revenge of the Beefsteak Tomatoes", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a4e885726af9d97b12bb5a36792eab63", "Xonox - K-Tel Software - Beck-Tech, Steve Beck", "6210, 7210, 06003. 99001", "Spike's Peak (1983) (Xonox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a4ecb54f877cd94515527b11e698608c", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX26119", "Saboteur (12-20-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a4f1cea2c8479284e2a2292f8d51b5fa", "", "", "Gunfight 2600 - The Final Kernel Part 2 (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a4ff39d513b993159911efe01ac12eba", "Atari - GCC, John Allred, Douglas B. Macrae, Betty Ryan Tylko", "CX2694", "Pole Position (1983) (Atari)", "AKA RealSports Driving", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a511f7ee13e4b35512f9217a677b4028", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX2674", "E.T. - The Extra-Terrestrial (1982) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a5262fe6d01d6a1253692682a47f79dd", "", "", "JKH Text Scrolling Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a537879d8e82e1061d3ad800479d3b84", "Andrew Wallace", "", "Brooni (2001) (Andrew Wallace) (PD) (PAL)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a539b9fd1ba57e46442b3e9351e6383b", "", "", "River Raid (208 in 1) (Unknown) (PAL) (Hack) [a]", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a56b642a3d3ab9bbeee63cd44eb73216", "Carrere Video - JWDA, Sylvia Day, Todd Marshall, Robin McDaniel, Henry Will IV - Teldec - Prism", "USC2001", "Gopher (1983) (Carrere Video) (PAL)", "AKA Vossicht Whlmaus!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a5855d73d304d83ef07dde03e379619f", "Atari, David Crane", "", "Boggle (08-07-1978) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "a58b11148c18d85e4c2aef4ff46ade67", "", "", "Video Chess (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a591b5e8587aae0d984a0f6fe2cc7d1c", "", "", "Globe Trotter Demo (24-03-2003) (Weston)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a5b7f420ca6cc1384da0fed523920d8e", "", "", "Adventure (New Graphics) (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a5c96b046d5f8b7c96daaa12f925bef8", "Activision, Alan Miller - Ariola", "EAG-007, EAG-007-04I, PAG-007 - 711 007-720", "Tennis (1981) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a5e9ed3033fb2836e80aa7a420376788", "Atari, Carla Meninsky", "CX2637, CX2637P", "Dodge 'Em (1980) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a60598ad7ee9c5ccad42d5b0df1570a1", "Atari, Alan Miller", "CX26163P", "Surround (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a6127f470306eed359d85eb4a9cf3c96", "Atari, Michael Kosaka, Peter C. Niday, Robert Vieira", "CX26110", "Crystal Castles (1984) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a6239810564638de7e4c54e66b3014e4", "Personal Games Company, Robert Anthony Tokar", "", "Birthday Mania (1984) (Personal Games)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a62e3e19280ff958407e05ca0a2d5ec7", "", "", "Hangman Ghost Biglist3 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a6737c81542a99ee71cb5f5ff14703d9", "", "", "Scrolling Playfield 3 (Junkosoft) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a69f5b1761a8a11c98e706ec7204937f", "", "", "Pharaoh's Curse (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "a6ed8d72ed691fd3aad5b6974fa17978", "Bit Corporation", "R320", "Bank Heist (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a74689a08746a667a299b0507e1e6dd9", "Starpath Corporation, Stephen H. Landrum", "9 AR-4105", "Official Frogger, The (1983) (Starpath) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a7523db9a33e9417637be0e71fa4377c", "Videospielkassette - Ariola", "PGP238", "Gangster (Ariola) (PAL)", "AKA Outlaw", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a7673809068062106db8e9d10b56a5b3", "Atari, Jerome Domurat, Andrew Fuchs, Dave Staugas, Robert Vieira", "CX26118, CX26118P", "Millipede (1984) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a779b9fa02c62d00d7c31ed51268f18a", "Arcadia Corporation, Brian McGhie", "AR-4104", "Rabbit Transit (1983) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a7a58e9291aefa1064e933071f60d4ef", "Arcadia Corporation, Dennis Caswell", "1 AR-4000, AR-4100", "Phaser Patrol (1982) (Arcadia) (Prototype) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "a7b584937911d60c120677fe0d47f36f", "M Network - INTV - APh Technological Consulting, Hal Finney", "MT5661", "Armor Ambush (1982) (M Network)", "AKA Tank Battle", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a7b96a8150600b3e800a4689c3ec60a2", "Atari, Mike Lorenzen - Sears", "CX2630 - 49-75122", "Circus Atari (1980) (Atari)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "01 55", "", "", "", "" }, - { "a7bf8353f77caca407ef85c2698fdff2", "Atari, Suki Lee - Sears", "CX2658 - 49-75128", "Math Gran Prix (1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a7cf2b9afdbb3a161bf418dbcf0321dc", "Barry Laws Jr.", "", "Attack Of The Mutant Space Urchins (2002) (Barry Laws Jr.) (Hack)", "Hack of Alien", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "a7d2e9408bb7cd70139ecced407ff238", "Atari - Roklan, Joe Gaucher, Alex Leavens", "CX2683", "Crazy Climber (1983) (Atari) (Prototype) [a1]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a7ed7dc5cbc901388afa59030fb11d26", "Atari, Warren Robinett", "CX2606, CX2606P", "Slot Racers (1978) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a7ef44ccb5b9000caf02df3e6da71a92", "Atari, Ian Shepard - Sears", "CX2604 - 6-99812, 49-75106", "Space War (1978) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a8101cb667e50a46165c6fb48c608b6b", "", "", "Kung Fu Sprite Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "a81697b0c8bbc338ae4d0046ede0646b", "CCE", "", "Gravitar (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a81b29177f258494b499fbac69789cef", "Greg Thompson", "", "Console Wars (Greg Thompson) (Hack)", "Hack of Space Jockey", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a83b070b485cf1fb4d5a48da153fdf1a", "Apollo", "AP-2011", "Pompeii (1983) (Apollo) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a8435ec570141de5d833c4abec499e55", "", "", "Happy Birthday Demo (2001) (Dennis Debro) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a8633050a686270fcf6c0cc4dcbad630", "Zirok", "", "Phoenix (Zirok)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a867b76098786c4091dba2fcee5084c3", "", "", "Dragrace (Hack)", "Hack of Dragster", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a875f0a919129b4f1b5103ddd200d2fe", "Atari, Dan Hitchens. Mimi Nyden", "CX2656", "SwordQuest - EarthWorld (1982) (Atari) (PAL)", "AKA Adventure I, SwordQuest I - EarthWorld", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a8916734ff8c64ec3342f4c73fd5b57d", "Atari", "", "Stand Alone Test Cart (1982) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a89a3e0547d6887279c34aba4b17a560", "M Network, Steve Crandall, Patricia Lewis Du Long", "MT4646", "Rocky & Bullwinkle (1983) (Mattel) (Prototype)", "", "Prototype", "", "", "4K", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a8a703e073183a89c94d4d99b9661b7f", "Franklin Cruz", "", "Spice Invaders (Franklin Cruz) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a8b3ea6836b99bea77c8f603cf1ea187", "CCE", "C-861", "Boxing (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a8c48b4e0bf35fe97cc84fdd2c507f78", "Puzzy - Bit Corporation", "PG201", "Seamonster (1982) (Puzzy)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a8d0a4a77cd71ac601bd71df5a060e4c", "", "", "Space Shuttle (1983) (Activision) [t2] (Fuel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a8d4a9500b18b0a067a1f272f869e094", "", "", "Red And White Checkerboard Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a8e49d7e24ce293629ca29614862821b", "", "", "Enduro (Genesis)", "Genesis controller (B is acceleration, C is brakes)", "Hack of Enduro", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a91d0858a52de3a2e6468437212d93e8", "", "", "Q-bert (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a936d80083e99d48752ad15c2b5f7c96", "", "", "Room of Doom (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "a93e8ea1f565c3c1e86b708cf0dc2fa9", "Jess Ragan", "", "Kabul! (Jess Ragan) (Hack)", "Hack of Kaboom!", "Hack", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, - { "a94528ae05dd051894e945d4d2349b3b", "Genus", "", "River Raid (Genus)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a94b8ca630f467b574b614808d813919", "HES", "773-883", "2 Pak Special - Space Voyage, Fire Alert (1992) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a9531c763077464307086ec9a1fd057d", "Atari, John Dunn - Sears", "CX2631 - 49-75152", "Superman (1979) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a957dbe7d85ea89133346ad56fbda03f", "Atari, Brad Stewart", "CX2649, CX2649P", "Asteroids (1981) (Atari) (PAL) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "a97733b0852ee3096300102cb0689175", "CCE", "C-834", "Fast Eddie (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a9784c24cddb33bd0d14442b97784f3d", "Thomas Jentzsch", "", "Omega Race DC (2003) (TJ) (Omega Race Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a98b649912b6ca19eaf5c2d2faf38562", "", "", "This Planet Sucks (Greg Troutman) (PAL) [!]", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a995b6cbdb1f0433abc74050808590e6", "Imagic, Rob Fulop, Bob Smith", "720106-1A, IA3600", "Riddle of the Sphinx (1982) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a9cb638cd2cb2e8e0643d7a67db4281c", "M Network - INTV - APh Technological Consulting, Larry Zwick", "MT5861", "Air Raiders (1983) (M Network)", "AKA Air Battle", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a9d9e19d0c89fb31780b5d63e1f8c6a4", "AtariAge, Chris Spry", "CX26201", "Zippy the Porcupine (2014) (Sprybug) (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "a9e3c23599c0d77151602f8e31daf879", "", "", "Kung Fu Master (Genesis)", "Genesis controller (C is extra kick modes)", "Hack of Kung Fu Master", "", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "" }, - { "aa1c41f86ec44c0a44eb64c332ce08af", "Spectravideo, David Lubar", "SA-218", "Bumper Bash (1983) (Spectravideo)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "PADDLES", "", "", "", "", "", "", "" }, - { "aa2c4b32656bde9a75042a4d158583e1", "", "", "Oystron X (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "aa5cfe3b20395aba1d479135943ad85c", "", "", "Defender (Hack) (Unknown)", "", "Hack of Defender", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "aa7bb54d2c189a31bb1fa20099e42859", "CBS Electronics, Ed English", "4L4478", "Mr. Do! (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "aa8c75d6f99548309949916ad6cf33bc", "Bob Montgomery (aka vdub_bobby)", "", "Squish 'Em (2007)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "aa8e4b2cb8a78ffe6b20580033f4dec9", "", "", "Bitmap Demo (13-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "aaac0d277eda054861e613c59c2e4ff2", "JWDA, Todd Marshall", "", "Music Demo (JWDA)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "aab840db22075aa0f6a6b83a597f8890", "Home Vision, R.J.P.G. - Gem International Corp. - VDI", "VCS83124", "Racing Car (1983) (Home Vision) (PAL)", "", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "" }, - { "aad61898633f470ce528e3d7ef3d0adb", "Commavid, Ben Burch", "CM-010", "Rush Hour (1983) (Commavid) (Prototype) [a1]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "aad91be0bf78d33d29758876d999848a", "Activision, David Crane", "AX-018, AX-018-04", "Pitfall! (1981) (Activision) (Prototype)", "Pitfall Harry's Jungle Adventure (Jungle Runner)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "aaea37b65db9e492798f0105a6915e96", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix - Tug of War (2 of 3) (1983) (Arcadia)", "Uses Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "02", "", "", "", "" }, - { "aafc79ffc32c4c9b2d73c8ada7602cfe", "", "", "Planet Patrol (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ab10f2974dee73dab4579f0cab35fca6", "ITT Family Games", "", "Wilma Wanderer (1983) (ITT Family Games) (PAL)", "AKA Lilly Adventure", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ab2cfcaad3daaf673b2b14fdbb8dac33", "M Network - INTV, David Akers, Joe King, Patricia Lewis Du Long, Jeff Ratcliff", "MT7045", "Bump 'n' Jump (1983) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ab2ea35dcc1098c87455bb8210b018cf", "", "", "Fu Kung! (V0.04 Single Line Resolution) (10-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ab301d3d7f2f4fe3fdd8a3540b7a74f5", "Jone Yuan Telephonic Enterprise Co", "", "IQ 180 (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ab434f4c942d6472e75d5490cc4dd128", "HES", "773-875", "2 Pak Special - Hoppy, Alien Force (1992) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ab48c4af46c8b34c3613d210e1206132", "Andrew Davie & Thomas Jentzsch", "", "Boulder Dash - Demo V2 (2014)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ab4ac994865fb16ebb85738316309457", "Atari, Alan Miller - Sears", "CX2624 - 6-99826, 49-75113", "Basketball (1978) (Atari)", "Console ports are swapped", "Common", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "" }, - { "ab56f1b2542a05bebc4fbccfc4803a38", "Activision - Imagineering, Dan Kitchen, David Lubar", "AK-048-04", "River Raid II (1988) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ab5bf1ef5e463ad1cbb11b6a33797228", "Imagic, Rob Fulop", "720104-1A, 720104-1B, IA3204", "Cosmic Ark (1982) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ab60ea7b707c58d356cad858eb18db43", "", "", "Tazer (John K. Harvey)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ab8d318da4addd39c65b7f9c408df2a6", "", "", "Star Trek (Genesis)", "Genesis controller (B is phaser, C is warp)", "Hack of Star Trek", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "abb740bea0a6842831b4f53112fb8145", "", "", "Qb (V1.01) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "abb741c83f665d73c86d90a7d9292a9b", "Telegames", "", "Space Attack (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "abc64037ca5d5b04ae8a7eedbca3ed74", "", "", "Green and Yellow Number 1 Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "abe40542e4ff2d1c51aa2bb033f09984", "Absolute Entertainment, David Crane", "EAZ-042-04B, EAZ-042-04I", "Skate Boardin' (1987) (Absolute) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ac05c0e53a5e7009ddd75ed4b99949fc", "Atari, Joe Decuir, Steve Mayer, Larry Wagner - Sears", "CX2601 - 99801, 6-99801, 49-75124", "Combat (1977) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ac0ddbcff34d064009591607746e33b8", "Thomas Jentzsch", "", "Atlantis FH (2003) (TJ) (Hack)", "Hack of Atlantis", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ac26d7d37248d1d8eac5eccacdbef8db", "", "", "Snail Against Squirrel (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ac3dd22dd945724be705ddd2785487c2", "Atari - GCC, Mark Ackerman, Noellie Alito", "CX2692", "Moon Patrol (06-15-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ac53b83e1b57a601eeae9d3ce1b4a458", "Retroactive", "", "Qb (2.15) (Retroactive) (NTSC)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "ac5f78bae0638cf3f2a0c8d07eb4df69", "", "", "Minesweeper (V.99) (Soren Gust) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ac7c2260378975614192ca2bc3d20e0b", "Activision, David Crane", "AG-930-04, AZ-030", "Decathlon (1983) (Activision)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ac9adbd6de786a242e19d4bec527982b", "Activision, Alan Miller - Ariola", "EAG-012-04I, EAX-012, EAX-012-04B - 711 012-720", "Ice Hockey (1981) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "aca09ffea77174b148b96b205109db4d", "Activision, Alan Miller", "AG-007, CAG-007", "Tennis (1981) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "acaa27d214039d89d7031609aafa55c3", "", "", "Sprite Demo 6 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "acb6787b938079f4e74313a905ec3ceb", "", "", "Chronocolor Donkey Kong (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "acb7750b4d0c4bd34969802a7deb2990", "Parker Brothers, Ed Temple", "PB5310", "Amidar (1982) (Parker Bros)", "", "Uncommon", "", "", "", "A", "A", "", "", "", "", "", "", "", "", "", "" }, - { "acb962473185d7a652f90ed6591ae13b", "Imagic, Dennis Koble", "IA3203, IX-010-04", "Atlantis (1982) (Imagic) (16K)", "AKA Lost City of Atlantis", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ace319dc4f76548659876741a6690d57", "Atari, Steve Wright", "CX2616", "Pele's Soccer (1981) (Atari)", "AKA Pele's Championship Soccer", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ad2e6bfb3b9b9b36ba8bf493ce764c49", "", "", "2600 Collison Demo 1 (Piero Cavina) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ad42e3ca3144e2159e26be123471bffc", "Atari", "CX26163P", "Human Cannonball (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ad72d616030a17634ff29ce8680d3c4c", "Thomas Jentzsch", "", "Reactor - Atari Trak-Ball Hack v1.3 (PAL60) (Full-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ad7e97c19bd25d5aa3999430845c755b", "", "", "Sprite Demo 5 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ad8072675109d13fdd31a2e0403d5cff", "Funvision - Fund. International Co.", "", "Tank City (Funvision)", "AKA Thunderground", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "adb770ff70e9adf08bbb907a7eccd240", "", "", "Inv Demo 3 (2001) (Erik Mooney) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "adb79f9ac1a633cdd44954e2eac14774", "Digivision", "", "Frostbite (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "adf1afac3bdd7b36d2eda5949f1a0fa3", "Quelle - Otto Versand", "495.463 2 - 746381", "Angriff der Luftflotten (1983) (Quelle) (PAL)", "AKA Paris Attack, M.A.D.", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "adfbd2e8a38f96e03751717f7422851d", "Champ Games", "CG-01-N", "Lady Bug (NTSC)", "", "Homebrew", "", "", "", "", "A", "", "", "", "", "", "", "", "", "YES", "" }, - { "ae047e9468bda961d8e9e9d8ff52980f", "", "", "Tunnel Demo (Red Spiral) (30-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ae0d4f3396cb49de0fabdff03cb2756f", "Retroactive", "", "Qb (V2.02) (PAL) (2001) (Retroactive)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "ae10527840a1ac24de43730645ed508d", "Charles Morgan", "", "Planet Invaders (Charles Morgan) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ae18c11e4d7ed2437f0bf5d167c0e96c", "", "", "Multi-Color Demo 3 (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ae2f1f69bb38355395c1c75c81acc644", "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart", "PB5540", "Star Wars - The Arcade Game (12-23-1983) (Parker Bros) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "ae465044dfba287d344ba468820995d7", "", "", "Inca Gold (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ae4be3a36b285c1a1dff202157e2155d", "Spectravideo", "SA-210", "Master Builder (1983) (Spectravideo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ae682886058cd6981c4b8e93e7b019cf", "Retroactive", "", "Qb (V0.12) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "ae6cb335470788b94beb5787976e8818", "", "", "Mortal Kurling (02-01-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ae83541cf4a4c0bce0adccd2c1bf6288", "", "", "Maze 003 Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ae97cf8ed21f4154b4360a3cf6c95c5e", "", "", "Teleterm 2600 (John K. Harvey) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "aeb104f1e7b166bc0cbaca0a968fde51", "", "", "Ms. Pac-Man (1999) (Hack)", "Hack of Ms. Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "aec9b885d0e8b24e871925630884095c", "Amiga - Video Soft", "3125", "Surf's Up (1983) (Amiga) (Prototype)", "Uses the Joyboard controller", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "aed0b7bd64cc384f85fdea33e28daf3b", "Atari, Jim Huether, Alan J. Murphy, Robert C. Polaro", "CX2666", "RealSports Volleyball (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "aed82052f7589df05a3f417bb4e45f0c", "Atari, Warren Robinett - Sears", "CX2606 - 6-99825, 49-75112", "Slot Racers (1978) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "af6ab88d3d7c7417db2b3b3c70b0da0a", "Activision, Larry Kaplan, David Crane", "AG-010, AG-010-04", "Kaboom! (1981) (Activision) (4K)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, - { "af6f3e9718bccfcd8afb421f96561a34", "Atari, Tod Frye", "CX2695", "Xevious (01-18-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "afb3bc45c6a82739cc82582127cd96e6", "Atari - Sculptured Software, Adam Clayton", "CX26151, CX26151P", "Dungeon (11-22-1985) (Atari) (Prototype)", "Dark Chambers Beta", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "afc194534c1b346609ef05eff6d3cef6", "Jone Yuan Telephonic Enterprise Co", "", "Boxing (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "afd2cf258d51ae4965ee21abba3627ab", "Atari - CCW, Christopher H. Omarzu", "CX26104", "Big Bird's Egg Catch (12-08-1982) (Atari) (Prototype)", "Uses the Keypad Controller", "Prototype", "", "", "", "", "", "", "", "KEYBOARD", "", "", "", "", "", "", "" }, - { "afe4eefc7d885c277fc0649507fbcd84", "Atari", "CX26163P", "Ant Party (32 in 1) (1988) (Atari) (PAL)", "AKA Cosmic Swarm", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "afe776db50e3378cd6f29c7cdd79104a", "Thomas Jentzsch", "", "Bobby is Going Home (TJ)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "afe88aae81d99e0947c0cfb687b16251", "Apollo - Games by Apollo", "AP-2006", "Infiltrate (1982) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "aff8cba0f2d2eb239953dd7116894a08", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (3 of 3) (1982) (Starpath) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b00088418fc891f3faa3d4ddde6ace94", "", "", "Unknown Title (bin00007 (200102)) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b00a8bc9d7fe7080980a514005cbad13", "K-Tel Vision", "", "Vulture Attack (1982) (K-Tel Vision) (PAL)", "AKA Condor Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b00e8217633e870bf39d948662a52aac", "Konami", "RC 102-X 02", "Marine Wars (1983) (Konami)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b011d8fdc450597c0762c2c0010a9b17", "Thomas Jentzsch", "", "Reactor - Amiga Mouse Hack v1.3 (NTSC) (Half-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b049fc8ac50be7c2f28418817979c637", "Activision - Imagineering, Dan Kitchen, David Lubar", "EAK-048-04, EAK-048-04B", "River Raid II (1988) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b06050f686c6b857d0df1b79fea47bb4", "Activision", "AIZ-001", "Moonsweeper (1988) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "b061e98a4c854a672aadefa233236e51", "Atari, Warren Robinett", "CX2620, CX2620P", "Basic Programming (1979) (Atari) (PAL)", "Uses Keypad Controllers", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "b095009004df341386d22b2a3fae3c81", "", "", "Sub-Scan (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b09b79c9628878be051e89f7f1e77378", "Activision, Larry Kaplan, David Crane - Ariola", "EAG-010, PAG-010 - 711 010-720", "Kaboom! (1981) (Activision) (PAL) (4K)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, - { "b0a9c6f6c8014c4023e0341ba11ca35e", "The Atari 2600 Connection - John K. Harvey, Tim Duarte", "v75", "Mean Santa (2009) (PAL)", "Released in 2019", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b0ba51723b9330797985808db598fc31", "Atari, Michael Callahan, Preston Stuart", "CX26103", "Alpha Beam with Ernie (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b0c47e426c7f799aee2c40422df8f56a", "", "", "Space Treat (PAL) (Fabrizio Zavagli)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b0c9cf89a6d4e612524f4fd48b5bb562", "Atari - GCC", "CX2663", "Combat Two (1982) (Atari) (Prototype)", "AKA Super Combat", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b0e1ee07fbc73493eac5651a52f90f00", "Colin Hughes", "", "Tetris 2600 (Colin Hughes)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "b1276417fb0f79bc52e741bb8f4d8360", "Thomas Jentzsch", "", "Marble Craze - Amiga Mouse Hack v1.0 (NTSC) (TJ)", "Uses Amiga Mouse Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b129d7541cff79ebe33852a83057c524", "Thomas Jentzsch", "", "Marble Craze - Atari Trak-Ball Hack v1.0 (NTSC) (TJ)", "Uses Atari Trak-Ball Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b12a7f63787a6bb08e683837a8ed3f18", "Imagic, Rob Fulop", "720000-200, 720101-1B, 720101-1C, IA3200, IA3200C, IX-006-04", "Demon Attack (1982) (Imagic) [fixed]", "AKA Death from Above", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b1339c56a9ea63122232fe4328373ac5", "Goliath - Hot Shot", "83-215", "Dream Flight (1983) (Goliath) (PAL)", "AKA Nightmare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b1486e12de717013376447ac6f7f3a80", "Spectravideo, Mark Turmell, Quelle", "SA-217, SA-217C - 413.723 8", "Gas Hog - Piraten Schiff (1983) (Spectravideo) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b15026b43c6758609667468434766dd8", "Retroactive", "", "Qb (0.06) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "b16cd9784589219391c839cb68c47b9c", "Video Soft, Jerry Lawson, Dan McElroy", "", "Golf Diagnostic (1983) (Video Soft) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b17b9cc4103844dcda54f77f44acc93a", "Quelle", "377.943 6", "Stopp die Gangster (1983) (Quelle) (PAL)", "AKA Gangster Alley", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b182d9708e00709830caab9cf8205ca0", "Thomas Jentzsch", "", "Reactor - Atari Mouse Hack v1.3 (PAL60) (Half-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b1a6c96e9093352106bc335e96caa154", "Joe Grand", "", "SCSIcide Pre-release 1 (Joe Grand)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b1b20536aef4eed9c79dc5804f077862", "", "", "Euchre (NTSC) (09-11-2001) (Erik Eid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b1c14b5ac896400cc91c8e5dd67acb59", "", "", "River Raid (208 in 1) (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b1d1e083dc9e7d9a5dc1627869d2ade7", "CCE", "C-1004", "Mario's Bros. (1983) (CCE)", "AKA Mario Bros.", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b1e2d5dc1353af6d56cd2fe7cfe75254", "Atari - Axlon, Steve DeFrisco", "CX26171", "MotoRodeo (1991) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "b1fd0b71de9f6eeb5143a97963674cb6", "", "", "Multi-Color Demo 7 (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b227175699e372b8fe10ce243ad6dda5", "Atari, Brad Stewart - Sears", "CX2649, 49-75163", "Asteroids (1981) (Atari) [a1]", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "b23ebf427713dd0198b7ef47dbd07ef4", "Jone Yuan Telephonic Enterprise Co", "", "Sky Diver (Jone Yuan) (4K) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b24f6a5820a4b7763a3d547e3e07441d", "CCE", "C-823", "Demon Attack (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b25841173f058380b1771aacd5e7cdf3", "Bit Corporation", "PG205", "Dancing Plate (1982) (BitCorp)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b26506fbf411009e5e3f7365f442960e", "Atari, Alan Miller", "CX2642", "Hunt & Score (1978) (Atari) (PAL) (4K)", "Uses the Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b2737034f974535f5c0c6431ab8caf73", "CBS Electronics, Richard K. Balaska Jr., Andy Frank, Stuart Ross", "4L 2520 5000", "Tunnel Runner (1983) (CBS Electronics)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b2761efb8a11fc59b00a3b9d78022ad6", "Atari, Bob Whitehead - Sears", "CX2651 - 99805, 49-75602", "Blackjack (1977) (Atari) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "", "", "" }, - { "b290c2b139344fcff5b312c71b9ac3b2", "Atari", "CX26163P", "UFO (32 in 1) (1988) (Atari) (PAL) (4K)", "AKA Space Jockey", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b29359f7de62fed6e6ad4c948f699df8", "Goliath", "3", "Phantom Tank (1983) (Goliath) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b2a6f31636b699aeda900f07152bab6e", "", "", "Space Instigators (Public Release 2) (06-01-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b2ab209976354ad4a0e1676fc1fe5a82", "Atari - Axlon, Tod Frye - Heuristica, Agustin Ortiz", "CX26169", "Shooting Arcade (03-07-1989) (Atari) (Prototype) [a3]", "Uses the Light Gun Controller (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b2d1e63f7f22864096b7b6c154151d55", "Fabrizio Zavagli", "", "Bounce! (17-03-2003) (Fabrizio Zavagli)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "b2d3bcee001cff2bd2d8a21b2cb55109", "Atari - GCC, Mike Feinstein, Kevin Osborn", "CX2691", "Joust (08-09-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "b2d5d200f0af8485413fad957828582a", "Atari - Bobco, Robert C. Polaro", "CX26155P", "Sprint Master (1988) (Atari) (PAL)", "AKA Sprint 88, Sprint 2000", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b2f0d7217147160b2f481954cedf814b", "", "", "Marquee Drawer (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "b3017e397f74efd53caf8fae0a38e3fe", "Retroactive", "", "Qb (2.12) (Retroactive) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "b311ab95e85bc0162308390728a7361d", "Parker Brothers - Roklan, Joe Gaucher", "PB5080", "Gyruss (1984) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "b31dc989f594764eacfa7931cead0050", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (2 of 3) (1983) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b31e9487efc06f18dfc3d7ebadf54416", "Omegamatrix", "", "Star Wars Arcade (Atari Mouse) v4 (PAL60) (Omegamatrix)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b31f178aa0d569cccac7959f84e0a724", "Atari, Jerome Domurat, Steve Woita", "CX2699", "Taz (07-13-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b3203e383b435f7e43f9492893c7469f", "Gameworld", "133-003", "Sssnake (1983) (Gameworld) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b36040a2f9ecafa73d835d804a572dbf", "Digitel", "", "Pac Man (1983) (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b37f0fe822b92ca8f5e330bf62d56ea9", "Xonox - K-Tel Software - Beck-Tech, Steve Beck", "6210, 7210, 06003. 99001", "Spike's Peak (1983) (Xonox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b392964e8b1c9c2bed12246f228011b2", "", "", "Name This Game (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b4030c38a720dd84b84178b6ce1fc749", "M Network - APh Technological Consulting, Kevin Miller", "MT5687", "International Soccer (1982) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b40dea357d41c5408546e4e4d5f27779", "Digivision", "", "Spider Fighter (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b41fdd4a522e1d5a2721840028684ac2", "", "", "Green and Yellow Number 1 Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "b42df8d92e3118dc594cecd575f515d7", "Mystique - American Multiple Industries", "1003", "Burning Desire (1982) (Mystique) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "b438a6aa9d4b9b8f0b2ddb51323b21e4", "Telegames", "5861 A030", "Bogey Blaster (1988) (Telegames) (PAL)", "AKA Air Raiders", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b451307b8b5e29f1c5f2cf064f6c7227", "", "", "Demo Image Series #6 - Mario (Fixed) (26-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b49331b237c8f11d5f36fe2054a7b92b", "", "", "Condor Attack (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b4a4c87840613f102acb5b3a647d0a67", "", "", "Mobile 48 Sprite Kernel (04-01-2003) (Eric Ball)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b4daedb43511521db9036d503b3c1b69", "", "", "Sokoban (01-01-2003) (Adam Wozniak) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b4e2fd27d3180f0f4eb1065afc0d7fc9", "Avalon Hill, Jean Baer, Bill 'Rebecca Ann' Heineman, William O. Sheppard", "5002002", "London Blitz (1983) (Avalon Hill)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b4f05e544834d0238a0c263491775edf", "Starpath Corporation, Steve Hales, Stephen H. Landrum", "4 AR-4102", "Suicide Mission (Preview) (1982) (Starpath) (PAL)", "AKA Meteoroids", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "b4f31ea8a6cc9f1fd4d5585a87c3b487", "Mystique - American Multiple Industries, Joel H. Martin", "", "Beat 'Em & Eat 'Em (1982) (Mystique) (PAL)", "Uses the Paddle Controller (left only)", "", "", "", "", "", "", "", "", "", "", "", "AUTO 45", "", "", "", "" }, - { "b4f87ce75f7329c18301a2505fe59cd3", "Videospielkassett - Ariola", "PGP232", "Autorennen (Ariola) (PAL)", "AKA Grand Prix", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b50ae55aac93fbed258bc5a873edd2cb", "Recompile", "", "E.T. The Extra-Terrestrial (Recompile) (Hack)", "www.neocomputer.org/projects/et", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b5110f55ed99d5279f18266d001a8cd5", "Eckhard Stolberg", "", "Auto-mobile Demo (2001) (Eckhard Stolberg)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b56264f738b2eb2c8f7cf5a2a75e5fdc", "Atari - GCC, John Allred, Douglas B. Macrae, Betty Ryan Tylko", "CX2694, CX2694P", "Pole Position (1983) (Atari) (PAL)", "AKA RealSports Driving", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b5657d4c1c732fbb6af150668464247f", "Arcadia Corporation, Stephen H. Landrum", "AR-4400", "Excalibur (Dragonstomper Beta) (1982) (Arcadia) (Prototype)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b59417d083b0be2d49a7d93769880a4b", "Pet Boat", "", "Donkey Kong (1983) (Pet Boat) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b59fd465abf76f64c85652ff29d5952d", "VentureVision, Dan Oliver", "", "Innerspace (1983) (VentureVision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b5a1a189601a785bdb2f02a424080412", "Imagic, Dennis Koble", "720021-1A, IA3410", "Shootin' Gallery (1983) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b5cb9cf6e668ea3f4cc2be00ea70ec3c", "CommaVid, Irwin Gaines - Ariola", "CM-005 - 712 005-720", "Mines of Minos (1982) (CommaVid) (PAL)", "AKA Im Labyrinth des Roboters", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "b5cdbab514ea726a14383cff6db40e26", "Video Gems", "VG-04", "Mission Survive (1983) (Video Gems) (PAL) [a]", "", "", "", "", "", "", "A", "", "", "", "", "", "", "", "", "YES", "" }, - { "b5efe0271d2214e4d5dc798881486884", "Atari - Axlon, Steve DeFrisco", "CX26192", "Klax (06-14-1990) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b6166f15720fdf192932f1f76df5b65d", "Amiga - Video Soft", "3130", "Off Your Rocker (1983) (Amiga) (Prototype)", "Uses the Amiga Joyboard", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b64426e787f04ff23ee629182c168603", "Dynacom", "", "Plaque Attack (1983) (Dynacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b65d4a38d6047735824ee99684f3515e", "Dynacom", "", "MegaBoy (Dynacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b676a9b7094e0345a76ef027091d916b", "Thomas Jentzsch", "", "Mission Survive (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "A", "", "", "", "", "", "", "", "", "YES", "" }, - { "b6812eaf87127f043e78f91f2028f9f4", "Simage", "", "Eli's Ladder (1984) (Simage)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b6821ac51c4c1dcb283f01be2f047dc1", "Thomas Jentzsch", "", "Rubik's Cube 3D Demo (25-11-2002) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b6960be26bee87d53ba4e2e71cfe772f", "", "", "3-D Corridor (Spiral Words) (31-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b6d52a0cf53ad4216feb04147301f87d", "Imagic, Michael Greene", "720055-1A, IA3312", "No Escape! (1983) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b6e40bce550672e5495a8cdde7075b8b", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (1 of 3) (1983) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b702641d698c60bcdc922dbd8c9dd49c", "Atari, Ian Shepard", "CX26163P", "Space War (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b719ada17771a8d206c7976553825139", "Ron Corcoran", "", "DUP Space Invaders (Ron Corcoran) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b731d35e4ac6b3b47eba5dd0991f452f", "Thomas Jentzsch", "", "Rubik's Cube 3D Demo (Final) (08-01-2003) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b7345220a0c587f3b0c47af33ebe533c", "Quelle", "176.433 1", "Landungskommando (1983) (Quelle) (PAL)", "AKA Strategy X", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b76fbadc8ffb1f83e2ca08b6fb4d6c9f", "Activision, Bob Whitehead", "AG-005, CAG-005, AG-005-04", "Skiing (1980) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b77468d586957d1b7fb4cccda2684f47", "Atari", "CX26163P", "Boxing (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b7903268e235310dc346a164af4c7022", "Thomas Jentzsch", "", "Cat Trax (Thomas Jentzsch) (PAL60)", "NTSC Conversion", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "b79fe32320388a197ac3a0b932cc2189", "Imagic, Bob Smith", "13207, EIZ-001-04I", "Moonsweeper (1983) (Imagic) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "b7a7e34e304e4b7bc565ec01ba33ea27", "Parker Brothers", "PB5820", "Mr. Do!'s Castle (1984) (Parker Bros) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "b7b1d3ce07e75976c43a2dca3866237e", "Atari", "CX26163P", "Freeway Chicken (32 in 1) (1988) (Atari) (PAL) (4K)", "AKA Freeway", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b7d0aae399781b3c18679debda6d32b1", "Thomas Jentzsch", "", "Three.s (v1.02)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b7d7c76e37f372f4e4979b380ed95a58", "AtariAge - Michael Haas", "RC2", "Flappy (2014) (AtariAge) (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b7e459d5416eeb196aaa8e092db14463", "", "", "Push (V0.02) (1998) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b7f184013991823fc02a6557341d2a7a", "", "", "Blue Rod Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b80d50ecee73919a507498d0a4d922ae", "20th Century Fox Video Games - Sirius Software, David Lubar", "11008", "Fantastic Voyage (1982) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b816296311019ab69a21cb9e9e235d12", "Atari, Bob Whitehead - Sears", "CX2652 - 6-99816, 49-75151", "Casino (1979) (Atari)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "", "", "" }, - { "b822fba8b7c8a97ea4e92aeb2c455ef9", "Dactari", "", "Freeway (Dactari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b83579c4450fcbdf2b108903731fa734", "", "", "Mission 3,000 A.D. (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "b83df1f32b4539c324bdf94851b4db55", "Angelino", "", "One On One by Angelino (Basketball Hack)", "Hack of Basketball (1978) (Atari)", "New Release (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b86552198f52cfce721bafb496363099", "Apollo, Tim Martin", "AP-2007", "Kyphus (1982) (Apollo) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b86a12e53ab107b6caedd4e0272aa034", "Funvision - Fund. International Co.", "", "Treasure Hunting (Funvision)", "AKA Pitfall!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b879e13fd99382e09bcaf1d87ad84add", "Zellers", "", "Time Warp (Zellers)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b8865f05676e64f3bec72b9defdacfa7", "Activision, David Crane", "AG-004", "Fishing Derby (1980) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b897f9e3f939b9f21566d56db812a84e", "Atari, Jim Huether", "CX26163P", "Flag Capture (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b8e715223ba65cf716b3620a90ca3ec1", "Parker Brothers", "PB5820", "Mr. Do!'s Castle (1984) (Parker Bros) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "b8ed78afdb1e6cfe44ef6e3428789d5f", "Data Age, J. Ray Dettling", "112-007", "Bermuda Triangle (1983) (Data Age)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b9232c1de494875efe1858fc8390616d", "Panda", "110", "Harbor Escape (1983) (Panda)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b9336ed6d94a5cc81a16483b0a946a73", "Atari, Jerome Domurat, Michael Sierchio", "CX2667, CX2667P", "RealSports Soccer (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "b955eb0e2baf7a437c186bddd4c49958", "Atari, Omegamatrix", "", "Space Invaders Menu (2020) (PAL60) (Hack)", "Hack of Space Invaders", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b958d5fd9574c5cf9ece4b9421c28ecd", "Piero Cavina", "", "Multi-Sprite Game V1.0 (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b95a6274ca0e0c773bfdc06b4c3daa42", "Paul Slocum", "", "3-D Corridor (29-03-2003) (Paul Slocum)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b98cc2c6f7a0f05176f74f0f62c45488", "Spectravideo", "SV-010", "CompuMate (1983) (Spectravideo)", "", "", "", "", "CM", "", "", "", "", "COMPUMATE", "COMPUMATE", "", "", "", "", "YES", "" }, - { "b9b4612358a0b2c1b4d66bb146767306", "Commavid, Ben Burch", "CM-010", "Rush Hour (1983) (Commavid) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b9d1e3be30b131324482345959aed5e5", "Activision - Boston Design Center, Rex Bradford", "", "Kabobber (07-25-1983) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "b9f6fa399b8cd386c235983ec45e4355", "Parker Brothers, John Emerson", "931511", "Action Force (1983) (Parker Bros) (PAL)", "AKA G.I. Joe - Cobra Strike", "", "", "", "", "", "", "", "", "", "", "", "01 55", "", "", "", "" }, - { "b9f9c0fed0db08c34346317f3957a945", "SuperVision", "405, 427, 806, 808, 813, 816", "Chopper Command (SuperVision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ba257438f8a78862a9e014d831143690", "U.S. Games Corporation - JWDA, Todd Marshall, Robin McDaniel, Henry Will IV", "VC2002", "Squeeze Box (1983) (U.S. Games)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ba317f83cdfcd58cbc65aac1ccb87bc5", "Thomas Jentzsch", "", "Jammed (2001) (XYPE) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ba3a17efd26db8b4f09c0cf7afdf84d1", "Activision, Larry Miller", "AX-021", "Spider Fighter (1983) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ba3b0eebccc7b791107de5b4abb671b4", "Thomas Jentzsch", "", "Thrust (V0.9) (2000) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ba657d940a11e807ff314bba2c8b389b", "Activision, John Van Ryzin", "AG-038-04", "Cosmic Commuter (1984) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bac28d06dfc03d3d2f4a7c13383e84ee", "Supergame", "", "Demon Attack (Supergame)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bae1a23f9b6acdadf465cfb330ba0acb", "Atari - GCC, Doug Macrae", "CX2677", "Dig Dug (1983) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bae66907c3200bc63592efe5a9a69dbb", "Spectravision - Spectravideo - Quelle", "SA-201 - 412.783 3", "Gangster Alley (1982) (Spectravision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "baf4ce885aa281fd31711da9b9795485", "Atari, Douglas Neubauer", "CX26176", "Radar Lock (1989) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bb18189021d58362d9e4d317cd2e28b7", "Activision, David Crane - Ariola", "EAG-001, PAG-001, EAG-001-04B, EAG-001-04I - 711 001-715", "Dragster (1980) (Activision) (PAL) (4K)", "AKA Dragster Rennen", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bb2b83fff97604f74ada565e0b5bae94", "Thomas Jentzsch", "", "Missile Control - Atari Mouse Hack v1.15 (PAL60) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bb5049e4558daade0f87fed69a244c59", "Atari, Brad Stewart", "CX2649, CX2649P", "Asteroids (1981) (Atari) (PAL) [no copyright]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "bb579404924c40ca378b4aff6ccf302d", "", "", "Lightbulb Lightens, The (PD) (Non Functional)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bb6a5a2f7b67bee5d1f237f62f1e643f", "", "", "Demo Image Series #5 - Animegirl (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bb745c893999b0efc96ea9029e3c62ca", "Play Video", "", "Planet Patrol (1982) (Play Video) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bb756aa98b847dddc8fc170bc79f92b2", "", "", "Golf (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bb9112d478a1a922d2c289a752bba695", "Omegamatrix", "", "SpaceMaster X-7 (Amiga Mouse) (Omegamatrix)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bbf8c7c9ed280151934aabe138e41ba7", "Amiga", "1130", "Power Play Arcade Video Game Album V (1984) (Amiga) (Prototype)", "Mogul Maniac, Surf's Up, Off Your Rocker, S.A.C. Alert", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bc24440b59092559a1ec26055fd1270e", "", "", "Private Eye (1984) (Activision) [a]", "", "", "", "0", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bc3057a35319aae3a5cd87a203736abe", "CCE", "C-845", "Time Warp (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bc33c685e6ffced83abe7a43f30df7f9", "Dynacom", "", "Seaquest (1983) (Dynacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bc4cf38a4bee45752dc466c98ed7ad09", "Atari, Douglas Neubauer, Mimi Nyden", "CX26136", "Solaris (1986) (Atari) (PAL)", "AKA Universe, Star Raiders II, The Last Starfighter", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bc526185ad324241782dc68ba5d0540b", "", "", "Dodge Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bc5389839857612cfabeb810ba7effdc", "Atari, Tod Frye", "CX2671", "SwordQuest - WaterWorld (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bc703ea6afb20bc089f04d8c9d79a2bd", "", "", "Gunfight 2600 - Not mergeable with Colbert wizardry... (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bc97d544f1d4834cc72bcc92a37b8c1b", "", "", "Sky Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bcb31f22856b0028c00d12f0e4c0a952", "Canal 3 - Intellivision", "", "Thunderground (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bcb73b534ed7c613ac379ecd726effb5", "Bob Montgomery (aka vdub_bobby)", "", "Squish 'Em (2007) (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bccb4e2cfad5efc93f6d55dc992118ce", "Activision, Carol Shaw", "AX-020, AX-020-04", "River Raid (1982) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bce4c291d0007f16997faa5c4db0a6b8", "Quelle", "292.651 7", "Weltraumtunnel (1983) (Quelle) (PAL)", "AKA Innerspace", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bce93984b920e9b56cf24064f740fe78", "Atari", "CX26163P", "Checkers (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bcef7880828a391cf6b50d5a6dcef719", "Rainbow Vision - Suntek", "SS-009", "Bermuda, The (1983) (Rainbow Vision) (PAL)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bd1bd6f6b928df17a702def0302f46f4", "", "", "Binary To Decimal Routine (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bd39598f067a1193ae81bd6182e756d1", "Telegames", "", "Night Stalker (1988) (Telegames) (PAL)", "AKA Dark Cavern", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bd430c2193045c68d1a20a018a976248", "", "", "Pac Ghost Sprite Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bd551ff1264f5c367a3ad7cf0d2f266c", "Bit Corporation", "R320", "SpaceMaster X-7 (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bda1463e02ae3a6e1107ffe1b572efd2", "Atari, Nick 'Sandy Maiwald' Turner", "CX26111", "Snoopy and the Red Baron (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bdb4b584ddc90c9d2ec7e21632a236b6", "Atari Freak 1", "", "Nitemare at Sunshine Bowl-a-Rama (Atari Freak 1) (Hack)", "Hack of Pac-Man Jr.", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bdbaeff1f7132358ea64c7be9e46c1ac", "20th Century Fox Video Games, Douglas 'Dallas North' Neubauer", "11105", "Mega Force (1982) (20th Century Fox) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bdc381baf7c252c63739c5e9ed087a5c", "", "", "Vertical Ship Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bdecc81f740200780db04a107c3a1eba", "Quelle", "874.254 6", "Super-Cowboy beim Rodeo (1983) (Quelle) (PAL)", "AKA Stampede", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bdf1996e2dd64baf8eff5511811ca6ca", "Tron", "", "H.E.R.O. (Tron)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "be060a704803446c02e6f039ab12eb91", "Parker Brothers, Rex Bradford, Sam Kjellman", "931501", "Star Wars - The Empire Strikes Back (1982) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "be1922bd8e09d74da471287e1e968653", "Cropsy", "", "Hangman Pacman Demo (Cropsy) (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "be2870a0120fd28d25284e9ccdcbdc99", "", "", "Tomb Raider 2600 [REV 01] (Montezuma's Revenge Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "be35d8b37bbc03848a5f020662a99909", "Atari, Joe Decuir, Steve Mayer, Larry Wagner - Sears", "CX2601 - 99801, 6-99801, 49-75124", "Combat (1977) (Atari) (4K) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "be3f0e827e2f748819dac2a22d6ac823", "Puzzy - Bit Corporation", "PG202", "Space Tunnel (1982) (Puzzy)", "AKA Le Tunnel de L'Estace", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "be41463cd918daef107d249f8cde3409", "", "", "Berzerk (Voice Enhanced) (Hack)", "Hack of Berzerk", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "be561b286b6432cac71bccbae68002f7", "", "", "Counter Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "be929419902e21bd7830a7a7d746195d", "Activision, Garry Kitchen", "AX-025, AX-025-04", "Keystone Kapers (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "becd908f9d7bb361982c3dc02d6475c6", "Kyle Pittman", "", "THX-1138 (Kyle Pittman) (Hack)", "Hack of Berserk", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bedfbde71fb606601f936b5b057f26f7", "Activision, Garry Kitchen - Ariola", "EAX-025, EAX-025-04I - 711 025-725", "Keystone Kapers (1983) (Activision) (PAL) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "befce0de2012b24fd6cb8b53c17c8271", "", "", "Push (V0.03) (No Illegal Opcodes) (1998) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bf1970b692275b42c4ec0683588eb062", "Thomas Jentzsch", "", "Reactor - Amiga Mouse Hack v1.3 (NTSC) (Full-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bf52327c2197d9d2c4544be053caded1", "HES - Activision", "AG-930-04, AZ-030", "Decathlon (HES) (PAL) (16K)", "AKA Activision Decathlon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bf84f528de44225dd733c0e6a8e400a0", "CCE", "", "Demons to Diamonds (CCE)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "YES", "10 57", "", "", "", "" }, - { "bf976cf80bcf52c5f164c1d45f2b316b", "Atari, Tod Frye, Mimi Nyden", "CX2657", "SwordQuest - FireWorld (1982) (Atari) (PAL)", "AKA Adventure II, SwordQuest II - FireWorld", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bfa58198c6b9cd8062ee76a2b38e9b33", "", "", "20 Sprites at Once Demo 4 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bfb73aabb2489316cd5882c3cd11d9f9", "AtariAge, Chris Walton & Thomas Jentzsch", "165", "Star Castle Arcade (2014) (AtariAge)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "bff8f8f53a8aeb1ee804004ccbb08313", "", "", "Droid Demo 22 (David Conrad Schweinsberg) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "bffe34516aaa3cbf5d307eab382a7e95", "", "", "Euchre (Release Candidate) (PAL) (28-09-2002) (Erik Eid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c00734a2233ef683d9b6e622ac97a5c8", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX26133", "A-Team, The (03-30-1984) (Atari) (Prototype)", "AKA Saboteur", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c00b65d1bae0aef6a1b5652c9c2156a1", "Atari, Joe Decuir - Sears", "CX2621 - 99806, 6-99806, 49-75104", "Video Olympics (1977) (Atari) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "YES", "AUTO 60", "", "", "", "" }, - { "c02e1afa0671e438fd526055c556d231", "Atari", "", "A-Team (Atari) (Prototype) (PAL60)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c032c2bd7017fdfbba9a105ec50f800e", "Activision, Charlie Heath", "", "Thwocker (04-09-1984) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c033dc1d7b6fde41b9cadce9638909bb", "", "", "Skeleton (V1.1) (06-09-2002) (Eric Ball)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c0589bb73858924389077fa3c2e9441a", "SOLID Corp. (D. Scott Williamson)", "CX2655-014", "Star Castle 2600 (SolidCorp) [014]", "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "c05f367fa4767ceb27abadf0066df7f4", "Thomas Jentzsch", "", "TomInv (31-07-2001) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c08d0cee43077d3055febb00e5745c1d", "HES - Activision", "", "Super Hit Pak - River Raid, Sky Jinks, Grand Prix, Fishing Derby, Checkers (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c0a68837c60e15d1fc5a40c9a62894bc", "Arcadia Corporation, Kevin Norman", "7 AR-4103", "Killer Satellites (1983) (Arcadia) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c0c7eddefce9015346db88ade3e1e096", "CBS Electronics, Bob Curtiss", "4L 2487 5000", "Solar Fox (1983) (CBS Electronics) (Prototype) (4K)", "RAM must be zero'ed to start correctly", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "c0d2434348de72fa6edcc6d8e40f28d7", "SEGA - Beck-Tech, Steve Beck", "010-01", "Tapper (1984) (SEGA)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c1034a5bfb0bb13cc5bdf86cc58989a7", "Atari, Nick 'Sandy Maiwald' Turner", "CX2665", "Frog Pond (1982) (Atari) (Prototype) (4K) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c118854d670289a8b5d5156aa74b0c49", "Jone Yuan Telephonic Enterprise Co", "", "Skiing (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c11e8473c652619ac6166900150ce215", "AtariAge, Chris Walton", "1.0 (Release)", "Chetiry (2011) (AtariAge) (60k) (PAL)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "50" }, - { "c126656df6badfa519cc63e681fb3596", "Ron Corcoran", "", "Space Invaders (2002) (Ron Corcoran) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c15042e54c7408498f051d782aaa8945", "Omegamatrix", "", "Millipede (Atari Trak-Ball) v6.5 (Omegamatrix)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c150c76cbde2c9b5a97eb5399d46c64f", "", "", "Unknown Title (xxx00000 (200203)) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c16c79aad6272baffb8aae9a7fff0864", "U.S. Games Corporation - JWDA, Sylvia Day, Todd Marshall, Robin McDaniel, Henry Will IV", "VC2001", "Gopher (1982) (U.S. Games)", "AKA Gopher Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c16fbfdbfdf5590cc8179e4b0f5f5aeb", "", "", "Wall Break (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c17bdc7d14a36e10837d039f43ee5fa3", "Spectravision - Spectravideo", "SA-203", "Cross Force (1982) (Spectravision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c1a83f44137ea914b495fc6ac036c493", "Atari, Carla Meninsky", "CX2660", "Star Raiders (1982) (Atari) (PAL)", "Uses Joystick (left) and Keypad (right) Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c1b038ce5cb6d85e956c5509b0e0d0d8", "", "", "Rotating Colors Demo 2 (Junkosoft) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c1b1049b88bcd98437d8872d1d62ba31", "", "", "Demo Image Series #4 - Donald (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c1b7aeabc3ec41556d924c8372a9ba5b", "Atari, Robert C. Polaro", "", "Dukes of Hazard (1980) (Atari) (Prototype)", "AKA Stunt Cycle", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c1cb228470a87beb5f36e90ac745da26", "Activision, Bob Whitehead", "AX-015, AX-015-04", "Chopper Command (1982) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c1e6e4e7ef5f146388a090f1c469a2fa", "Bomb - Onbase", "CA283", "Z-Tack (1983) (Bomb)", "AKA Base Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c1f209d80f0624dada5866ce05dd3399", "Telegames", "", "Deadly Discs (1988) (Telegames) (PAL)", "AKA TRON - Deadly Discs", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c1fdd44efda916414be3527a47752c75", "Parker Brothers, John Emerson", "PB5920", "G.I. Joe - Cobra Strike (1983) (Parker Bros)", "Uses the Paddle (left) and Joystick (right) Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c20f15282a1aa8724d70c117e5c9709e", "Video Gems", "VG-02", "Surfer's Paradise (1983) (Video Gems) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c21450c21efb7715746e9fa87ad6f145", "Hozer Video Games", "", "Gunfight 2600 - It could've been soooo cool, but... (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c216b91f5db21a093ded6a5aaec85709", "Jone Yuan Telephonic Enterprise Co", "", "Dragster (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c221607529cabc93450ef25dbac6e8d2", "Eckhard Stolberg", "", "Color Test (26-09-2002) (Eckhard Stolberg)", "", "Homebrew", "", "", "", "", "A", "", "", "", "", "", "", "", "", "", "" }, - { "c225379e7c4fb6f886ef9c8c522275b4", "Video Mania", "", "Frostbite (1983) (Video Mania)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c225abfb584960efe1f359fc94b73379", "", "", "Joustpong (21-09-2002) (Kirk Israel) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c2410d03820e0ff0a449fa6170f51211", "", "", "Pac-Man (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c246e05b52f68ab2e9aee40f278cd158", "Thomas Jentzsch", "", "Star Wars - Ewok Adventure (Thomas Jentzsch) (Prototype)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c2778507b83d9540e9be5713758ff945", "", "", "Island Flyer Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c28b29764c2338b0cf95537cc9aad8c9", "", "", "Multi-Color Demo 4 (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c29d17eef6b0784db4586c12cb5fd454", "Jone Yuan Telephonic Enterprise Co", "", "River Raid (Jone Yuan) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c29f8db680990cb45ef7fef6ab57a2c2", "Parker Brothers - Roklan, Paul Crowley, Bob Curtiss", "931505", "Super Cobra (1983) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c2a37f1c7603c5fd97df47d6c562abfa", "Roger Williams", "", "Bar-Score Demo (2001) (Roger Williams)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c2b5c50ccb59816867036d7cf730bf75", "Salu - Avantgarde Software, Michael Buetepage", "460741", "Ghostbusters II (1992) (Salu) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "c2bcd8f2378c3779067f3a551f662bb7", "Activision, Bob Whitehead - Ariola", "EAG-002, EAG-002-04I, PAG-002 - 711 002-715", "Boxing (1980) (Activision) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c2c7a11717e255593e54d0acaf653ee5", "", "", "Chopper Command (208 in 1) (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c2c8eb642765137bb82b83a65232961f", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Atari Mouse Hack v1.1 (PAL) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c2dea467f4a02fa1f06d66f52bc12e6e", "Thomas Jentzsch", "", "Missile Command Atari Trak-Ball Hack v1.3 (NTSC) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c2fbef02b6eea37d8df3e91107f89950", "Champ Games", "CG-02-N", "Conquest Of Mars (NTSC)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c31a17942d162b80962cb1f7571cd1d5", "Home Vision - Gem International Corp. - VDI", "VCS83112", "Sky Alien (1983) (Home Vision) (PAL)", "AKA Sky Aliem", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c3205e3707f646e1a106e09c5c49c1bf", "", "", "Unknown Title (bin00003 (200206)) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c3472fa98c3b452fa2fd37d1c219fb6f", "Atari, Carla Meninsky - Sears", "CX2637 - 49-75158", "Dodge 'Em (1980) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c370c3268ad95b3266d6e36ff23d1f0c", "Atari, Alan Miller", "CX2641, CX2641P", "Surround (1977) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c3a9550f6345f4c25b372c42dc865703", "Atari - Bobco, Robert C. Polaro", "CX2663", "Road Runner (1989) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c3aeb796fdaf9429e8cd6af6346f337e", "", "", "If It's Not One Thing It's Another (1997) (Chris Cracknell)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c3bbc673acf2701b5275e85d9372facf", "Atari, Robert C. Polaro", "CX26157", "Stunt Cycle (07-21-1980) (Atari) (Prototype)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c3e4aa718f46291311f1cce53e6ccd79", "", "", "Hangman Ghost 4letter (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c3ef5c4653212088eda54dc91d787870", "Activision, Bob Whitehead", "AG-002, CAG-002, AG-002-04", "Boxing (1980) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c3f53993ade534b0982ca3a286c85bb5", "", "", "Full Screen Bitmap Drawing System (12-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c4060a31d61ba857e756430a0a15ed2e", "Thomas Jentzsch", "", "Pick 'n Pile (2003) (TJ)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "c41e7735f6701dd50e84ee71d3ed1d8f", "Dynacom", "", "Spider Fighter (1983) (Dynacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c43bd363e1f128e73ba5f0380b6fd7e3", "Atari, Chris Crawford", "", "Wizard (1980) (Atari) (Prototype) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c446288fe62c0c2737639fd788ae4a21", "", "", "Mark's Sound Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "c450a285daa7a3b65188c2c3cf04fb3e", "Wizard Video Games", "007", "Halloween (1983) (Wizard Video Games) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c469151655e333793472777052013f4f", "", "", "Base Attack (Unknown) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c471b97446a85304bbac021c57c2cb49", "First Star Software, Alex Leavens, Shirley Ann Russell", "", "Boing! (1983) (First Star Software) (PAL)", "AKA Bubbles, Soap Suds, The Emphysema Game", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "c47244f5557ae12c61e8e01c140e2173", "Atari - GCC, Mike Feinstein, John Allred", "CX2688, CX2688P", "Jungle Hunt (1983) (Atari) (PAL) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c47b7389e76974fd0de3f088fea35576", "Funvision - Fund. International Co.", "", "Mighty Mouse (Funvision)", "AKA Gopher", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c482f8eebd45e0b8d479d9b71dd72bb8", "Retroactive", "", "Push (V0.03) (1998) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "c49fe437800ad7fd9302f3a90a38fb7d", "Atari, Dan Hitchens, Mimi Nyden", "CX2697, CX2697P", "Mario Bros. (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c4b73c35bc2f54b66cd786f55b668a82", "Arcadia Corporation, Stephen Harland Landrum", "AR-4101", "Communist Mutants from Space (1982) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c4bbbb0c8fe203cbd3be2e318e55bcc0", "", "", "Atlantis (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c4bc8c2e130d76346ebf8eb544991b46", "Imagic", "", "Imagic Selector ROM (1982) (Imagic) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c4d888bcf532e7c9c5fdeafbb145266a", "", "", "Space Robot (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "c504a71c411a601d1fc3173369cfdca4", "Retroactive", "", "Qb (V2.02) (Stella) (2001) (Retroactive)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "c5124e7d7a8c768e5a18bde8b54aeb1d", "Imagic, Rob Fulop", "720104-2A, IA3204P, EIX-008-04I", "Cosmic Ark (1982) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c517144e3d3ac5c06f2f682ebf212dd7", "Tigervision - Teldec", "7-008 - 3.60006 VG", "Miner 2049er (1983) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c529e63013698064149b9e0468afd941", "", "", "S.I.PLIX 2 (Hack)", "Hack of Kaboom!", "Hack", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, - { "c52d9bbdc5530e1ef8e8ba7be692b01e", "Atari, Robert C. Polaro", "CX26130", "Holey Moley (02-29-1984) (Atari) (Prototype)", "Uses Keypad Controllers", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c5301f549d0722049bb0add6b10d1e09", "Atari, Carla Meninsky, Ed Riddle - Sears", "CX2611 - 99821, 49-75149", "Indy 500 (1977) (Atari)", "Uses the Driving Controllers", "", "", "", "", "", "", "", "", "DRIVING", "DRIVING", "", "45", "", "", "", "" }, - { "c5387fc1aa71f11d2fa82459e189a5f0", "Bit Corporation", "PG202", "Space Tunnel (1982) (BitCorp) (PAL)", "AKA Weltraum-Tunnel", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c53c0d10c74325deae9ba84074281983", "The Atari 2600 Connection - John K. Harvey, Tim Duarte", "v75", "Mean Santa (2009)", "Released in 2019", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c541a5f6fc23b40a211196dd78233780", "Atari, Carla Meninsky - Sears", "CX2660 - 49-75187", "Star Raiders (1981) (Atari) (Prototype) (4K)", "Uses Joystick (left) and Keypad (right) Controllers", "Prototype", "", "", "", "", "", "", "", "", "KEYBOARD", "", "", "", "", "", "" }, - { "c54b4207ce1d4bf72fadbb1a805d4a39", "Billy Eno", "", "Sniper (Feb 30) (2001) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c560a3ecb7b751021953819efcfe5b41", "Omegamatrix", "", "Ghostbusters (Genesis)", "Genesis controller", "", "", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "" }, - { "c569e57dca93d3bee115a49923057fd7", "", "", "Pac-Space (Pac-Man Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c58708c09ccb61625cda9d15ddcd8be6", "SPIKE the Percussionist", "", "NOIZ Invaders (SPIKE) (2002) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c5930d0e8cdae3e037349bfa08e871be", "Atari, Howard Scott Warshaw - Sears", "CX2655 - 49-75167", "Yars' Revenge (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "c59633dbebd926c150fb6d30b0576405", "Telegames", "5861 A030", "Bogey Blaster (1988) (Telegames)", "AKA Air Raiders", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c5a76bafc4676edb76e0126fb9f0fb2d", "Charles Morgan", "", "Zero Patrol (Charles Morgan) (Hack)", "Hack of Moon Patrol", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c5bab953ac13dbb2cba03cd0684fb125", "SpiceWare - Darrell Spice Jr.", "", "Stay Frosty (SpiceWare)", "Part of Stella's Stocking 2007 Xmas compilation", "Homebrew", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "c5bf03028b2e8f4950ec8835c6811d47", "Atari - Axlon, Tod Frye - Heuristica, Agustin Ortiz", "CX26169", "Shooting Arcade (03-07-1989) (Atari) (Prototype) [a2]", "Uses the Light Gun Controller (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c5c7cc66febf2d4e743b4459de7ed868", "Atari, Jerome Domurat, Steve Woita", "CX2696", "Asterix (1983) (Atari) (PAL) [a]", "AKA Taz", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c5d2834bf98e90245e545573eb7e6bbc", "CCE", "", "Snoopy and the Red Baron (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c5dd8399257d8862f3952be75c23e0eb", "Atari - GCC", "CX2680", "RealSports Tennis (1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c5f71dfbdca9cc96b28643ff4d06aa6f", "Thomas Jentzsch", "", "Centipede - Atari Trak-Ball Hack v1.4 (PAL) (Full-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c5fe45f2734afd47e27ca3b04a90213c", "Atari, Brad Stewart", "CX2622, CX2622P", "Breakout (1978) (Atari) (PAL) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "01", "", "", "", "" }, - { "c63a98ca404aa5ee9fcff1de488c3f43", "Atari", "CX26145", "Venture (1987) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "c6556e082aac04260596b4045bc122de", "Atari - GCC, Dave Payne", "CX2669", "Vanguard (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c6688781f4ab844852f4e3352772289b", "Atari, Tod Frye", "CX2695", "Xevious (08-02-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "c67ff409f28f44883bd5251cea79727d", "", "", "Gunfight 2600 - Music & Bugfixes 1 (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c689148ad9275667924ab334107b517e", "Jone Yuan Telephonic Enterprise Co", "", "Space Raid (Jone Yuan)", "AKA MegaMania", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c68a6bafb667bad2f6d020f879be1d11", "Atari, Michael Kosaka, Peter C. Niday, Robert Vieira", "CX26110", "Crystal Castles (1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c6ae21caceaad734987cb24243793bd5", "CCE", "", "Frostbite (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c6c63da3bc2e47291f63280e057061d0", "128-in-1 Junior Console", "", "Human Cannonball (128-in-1 Junior Console) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c6d48c6ae6461e0e82753540a985ac9e", "Ed Federmeyer", "", "Edtris (1994) (Ed Federmeyer)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c6d7fe7a46dc46f962fe8413c6f53fc9", "Parker Brothers, Mark Lesser", "PB5950", "Lord of the Rings (1983) (Parker Bros) (Prototype) [a]", "Journey to Rivendell (The Lord of the Rings I)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c6db733e0b108c2580a1d65211f06dbf", "Atari, Eric Manghise, Mimi Nyden, Joseph Tung", "CX2640", "RealSports Baseball (07-09-1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c738fc3f5aae1e8f86f7249f6c82ac81", "Atari, Brad Stewart - Sears", "CX2622 - 6-99813, 49-75107", "Breakout (1978) (Atari) (16K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "01 60", "", "", "", "" }, - { "c73ae5ba5a0a3f3ac77f0a9e14770e73", "Starpath Corporation, Stephen H. Landrum", "9 AR-4105", "Official Frogger, The (1983) (Starpath)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c745487828a1a6a743488ecebc55ad44", "Rainbow Vision - Suntek", "SS-002", "Galactic (1983) (Rainbow Vision) (PAL)", "AKA The Challenge of.... Nexar", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c74bfd02c7f1877bbe712c1da5c4c194", "Thomas Jentzsch", "", "River Raid Tanks (Thomas Jentzsch) (Hack)", "Hack of River Raid", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c7600d72247c5dfa1ec1a88d23e6c85e", "Arcadia Corporation, Scott Nelson", "13", "Sweat! - The Decathlon Game (1 of 3) (1983) (Arcadia) (Prototype)", "Uses the Paddle Controllers (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c77c35a6fc3c0f12bf9e8bae48cba54b", "Xonox - K-Tel Software - Action Graphics, Michael Schwartz, David Thiel", "6230, 7210, 06004, 99004", "Artillery Duel (1983) (Xonox)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c77d3b47f2293e69419b92522c6f6647", "Panda", "101", "Tank Brigade (1983) (Panda)", "AKA Phantom Tank", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c7900a7fe95a47eef3b325072ad2c232", "Larry Petit", "", "Super Congo Bongo (2003) (Larry Petit) (Hack)", "Hack of Bongo", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c7d5819b26b480a49eb26aeb63cc831e", "Bit Corporation", "PGP210", "Ice Hockey (4 Game in One Light Green) (1983) (BitCorp) (PAL)", "AKA Hockey, Hockey", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c7e43ad79c5e5c029d9f5ffde23e32cf", "", "", "PAL-NTSC Detector (15-11-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c7eab66576696e11e3c11ffff92e13cc", "Atari - GCC", "CX2680, CX2680P", "RealSports Tennis (1983) (Atari) (PAL) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c7f13ef38f61ee2367ada94fdcc6d206", "Parker Brothers - Roklan, Joe Gaucher", "PB5370", "Popeye (1983) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "c82ec00335cbb4b74494aecf31608fa1", "CCE", "", "E.T. - The Extra-Terrestrial (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c830f6ae7ee58bcc2a6712fb33e92d55", "Atari, Michael Kosaka", "CX2687", "Tempest (01-05-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c866c995c0d2ca7d017fef0fc0c2e268", "Retroactive", "", "Qb (2.00) (Retroactive) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "c880c659cdc0f84c4a66bc818f89618e", "Thomas Jentzsch", "", "Open Sesame (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "c89c3138a99fd1fd54367d65f75b0244", "Atari, Omegamatrix", "", "Space Invaders Menu (2020) (PAL) (Hack)", "Hack of Space Invaders", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c8c7da12f087e8d16d3e6a21b371a5d3", "", "", "Demo Image Series #9 - Genius (28-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c8e90fc944596718c84c82b55139b065", "Atari - Roklan, Bob Curtiss", "", "Firefox (1983) (Atari) (Prototype) [a]", "AKA Combat II, Fighter Command", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c8fa5d69d9e555eb16068ef87b1c9c45", "Atari", "CX26144", "Donkey Kong Junior (1987) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c90788d9aa71a78bcc78c015edb22c54", "Thomas Jentzsch", "", "Marble Craze - Atari Trak-Ball Hack v1.0 (PAL60) (TJ)", "Uses Atari Trak-Ball Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c9196e28367e46f8a55e04c27743148f", "Atari", "CX26163P", "Stampede (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c92cfa54b5d022637fdcbdc1ef640d82", "Retroactive", "", "Qb (V2.05) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "c98e8c918a40b4d3a243dd6c49196330", "AtariAge, Omegamatrix", "", "Venture Reloaded (2019) (AtariAge) (PAL60) (Hack)", "Transformative hack of Venture", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "c9b7afad3bfd922e006a6bfc1d4f3fe7", "Atari, Larry Kaplan - Sears", "CX2628 - 6-99842, 49-75117", "Bowling (1979) (Atari)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c9c25fc536de9a7cdc5b9a916c459110", "Activision, Mike Lorenzen", "AX-023", "Oink! (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c9d02d3cfeef8b48fb71cb4520a4aa84", "", "", "Euchre (More for less) (PAL) (22-08-2002) (Erik Eid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c9e721eb29c940c2e743485b044c0a3f", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "c9f6e521a49a2d15dac56b6ddb3fb4c7", "Parker Brothers, Rex Bradford", "PB5000", "Star Wars - Jedi Arena (1983) (Parker Bros)", "Uses the Paddle Controllers (swapped)", "", "", "", "", "", "", "", "", "", "", "YES", "10 50", "", "", "", "" }, - { "ca09fa7406b7d2aea10d969b6fc90195", "Activision, Matthew L. Hubbard, Bob Whitehead", "AX-024", "Dolphin (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ca4f8c5b4d6fb9d608bb96bc7ebd26c7", "M Network - INTV - APh Technological Consulting, Hal Finney, Glenn Hightower, Peter Kaminski", "MT4317", "Adventures of TRON (1983) (M Network)", "AKA Tron Joystick", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ca50cc4b21b0155255e066fcd6396331", "Suntek", "SS-031", "UFO Patrol (1983) (Suntek) (PAL)", "AKA X'Mission", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "ca53fc8fd8b3c4a7df89ac86b222eba0", "CCE", "C-812", "Pac Man (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ca54de69f7cdf4d7996e86f347129892", "PlayAround - J.H.M.", "201", "Philly Flasher (1982) (PlayAround)", "Uses the Paddle Controllers, AKA Beat 'Em & Eat 'Em", "", "", "", "", "", "", "", "", "", "", "", "AUTO 45", "", "", "", "" }, - { "ca7aaebd861a9ef47967d31c5a6c4555", "Atari, Bob Whitehead", "CX26163P", "Homerun (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "" }, - { "ca7abc774a2fa95014688bc0849eee47", "Atari, Michael Kosaka, Peter C. Niday, Robert Vieira", "CX26110", "Crystal Castles (1984) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ca7f166a94eed1a349dec6d6a358bcad", "Activision, Alan Miller - Ariola", "EAG-007, EAG-007-04I, PAG-007 - 711 007-720", "Tennis (1981) (Activision) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cac9928a84e1001817b223f0cecaa3f2", "Amiga - Video Soft, Jerry Lawson, Dan McElroy", "", "3-D Genesis (1983) (Amiga) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "cad982c9b45bc5eff34e4ea982d5f1ca", "", "", "Song (17-02-2003) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "cade123747426df69570a2bc871d3baf", "Gakken", "011", "Marine Wars (1983) (Gakken) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cae8f83c06831ec7bb6a3c07e98e9342", "Colin Hughes", "", "Tetris 2600 (Colin Hughes) [o1]", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "cb18d8d5fbdcb1cd7bd36c5423348859", "", "", "RAM-Pong (NTSC) v1.0", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cb24210dc86d92df97b38cf2a51782da", "Video Gems", "VG-01", "Missile Control (1983) (Video Gems) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cb4a7b507372c24f8b9390d22d54a918", "ITT Family Games", "554-37 338", "Peter Penguin (1983) (ITT Family Games) (PAL)", "AKA Frisco (Pumuckl-Serie)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cb8399dc0d409ff1f531ef86b3b34953", "", "", "Demo Image Series #12 - Luigi And Mario (01-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cb9626517b440f099c0b6b27ca65142c", "Atari, Larry Kaplan - Sears", "CX2664 - 6-99818", "Brain Games (1978) (Atari) (4K)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "" }, - { "cb96b0cf90ab7777a2f6f05e8ad3f694", "Silvio Mogno", "", "Rainbow Invaders", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cb9b2e9806a7fbab3d819cfe15f0f05a", "Parker Brothers - JWDA, Todd Marshall, Robin McDaniel, Ray Miller", "931513", "Star Wars - Death Star Battle (1983) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cba56e939252b05df7b7de87307d12ca", "", "", "Playfield Text Demo (2001) (Roger Williams)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cbad928e10aeee848786cc55394fb692", "", "", "Fu Kung! (V0.06a Cuttle Cart Compatible) (15-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cbb0ee17c1308148823cc6da85bff25c", "", "", "Rotating Colors Demo 1 (Junkosoft) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cbc373fbcb1653b4c56bfabba33ea50d", "CCE", "", "Super Voleyball (CCE)", "AKA RealSports Volleyball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cbced209dd0575a27212d3eee6aee3bc", "Apollo - Games by Apollo, Ed Salvo, Byron Parks", "AP-2003", "Racquetball (1982) (Apollo) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "cbd981a23c592fb9ab979223bb368cd5", "Atari, Carla Meninsky - Sears", "CX2660 - 49-75187", "Star Raiders (1982) (Atari)", "Uses Joystick (left) and Keypad (right) Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cbe5a166550a8129a5e6d374901dffad", "Atari, Carla Meninsky - Sears", "CX2610 - 49-75127", "Warlords (1981) (Atari)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "AUTO 50", "", "", "", "" }, - { "cbeafd37f15e0dddb0540dbe15c545a4", "", "", "Black and White Fast Scolling Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cc03c68b8348b62331964d7a3dbec381", "Jone Yuan Telephonic Enterprise Co", "", "Marauder (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cc12581e079cd18330a89902625b8347", "Dave Neuman", "", "Space Battle (PAL)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cc1939e4769d0c157ace326efcfdcf80", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (3 of 4) (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cc2973680c150886cce1ed8693c3aca2", "Quelle", "874.254 6", "Super-Cowboy beim Rodeo (1983) (Quelle) (PAL) (4K)", "AKA Stampede", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cc3d942c6958bd16b1c602623f59e6e1", "Atari, Bill Aspromonte, John Russell, Michael Sierchio, Robert Zdybel", "CX26114", "Pigs in Space (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cc7138202cd8f6776212ebfc3a820ecc", "Atari - CCW, Christopher H. Omarzu, Preston Stuart, Bruce Williams", "CX26101", "Oscar's Trash Race (03-30-1983) (Atari) (Prototype)", "Uses the Keypad Controllers", "Prototype", "", "", "", "", "", "", "", "", "KEYBOARD", "", "", "", "", "", "" }, - { "cc724ebe74a109e39c0b2784ddc980ca", "Atari, Jerome Domurat, Dave Staugas", "CX2682", "Krull (05-27-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cc74ddb45d7bc4d04c2e6f1907416699", "", "", "Colour Display Programme (1997) (Chris Cracknell)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cca33ae30a58f39e3fc5d80f94dc0362", "", "", "Okie Dokie (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ccb56107ff0492232065b85493daa635", "Bit Corporation", "PG206 [demonstration cartridge]", "Bobby Is Going Home (1983) (BitCorp) (PAL) [demo cart]", "AKA Bobby geht Heim", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ccb5fa954fb76f09caae9a8c66462190", "Answer Software Corporation - TY Associates, Mike Wentz", "ASC1001", "Malagai (1983) (Answer Software)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "ccb807eb79b0ed0f5fdc460445ef703a", "", "", "Superman (Stunt_Cycle_Rules!) (Hack)", "Hack of Superman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ccbd36746ed4525821a8083b0d6d2c2c", "Atari, Brad Stewart - Sears", "CX2649, 49-75163", "Asteroids (1981) (Atari) [no copyright]", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "cccfe9e9a11b1dad04beba46eefb7351", "", "", "Poker Squares (V0.25) (PAL) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ccd6ce508eee4b3fca67212833edcd85", "Otto Versand", "746422", "Hot Wave (Double-Game Package) (1983) (Otto Versand) (PAL)", "AKA Ram It", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ccd92a269a4c2bd64d58cf2c0114423c", "Atari - GCC, Mark Ackerman, Glenn Parker", "CX2675", "Ms. Pac-Man (09-20-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cd032ab6764b55438a7b0bfb5e78595a", "", "", "Hangman Pac-Man 4letter (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cd139ae6d09f3665ad09eb79da3f9e49", "Eric Mooney", "", "Invaders by Erik Mooney (4-24-97) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cd34b3b3ef9e485201e841ba71beb253", "Bradford W. Mott", "", "Hit HMOVE At Various Cycles After WSYNC Test (Bradford W. Mott) (1998) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cd38ad19f51b1048d8e5e99c86a2a655", "", "", "Demo Image Series #5 - Flag (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cd399bc422992a361ba932cc50f48b65", "Arcadia Corporation, Brian McGhie", "AR-4104", "Rabbit Transit (Preview) (1983) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cd3e26786136a4692fd2cb2dfbc1927e", "", "", "Multiple Moving Objects Demo 2 (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cd4423bd9f0763409bae9111f888f7c2", "Jone Yuan Telephonic Enterprise Co", "", "River Raid (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cd4ded1ede63c4dd09f3dd01bda7458c", "Future Video Games", "", "Laser Gate (Future Video Games) (PAL)", "AKA Innerspace", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cd568d6acb2f14477ebf7e59fb382292", "Videospielkassette - Ariola", "PGP235", "Fussball (Ariola) (PAL)", "AKA International Soccer", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cd5af682685cfecbc25a983e16b9d833", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX26133", "A-Team, The (05-08-1984) (Atari) (Prototype)", "AKA Saboteur", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cd88ef1736497288c4533bcca339f881", "SEGA - Teldec", "005-10", "Buck Rogers - Planet of Zoom (1983) (SEGA) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "cd8fa2e9f6255ef3d3b9b5a4f24a54f7", "", "", "Daredevil (V2) (Stunt_Cycle_Rules!) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cd98be8a48ebf610c9609a688b9c57f2", "Arcadia Corporation, Steve Hales, Stephen H. Landrum", "4 AR-4102", "Suicide Mission (1982) (Arcadia) (Prototype)", "AKA Meteoroids", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "cd9fea12051e414a6dfe17052067da8e", "Paul Slocum", "", "Marble Craze Demo (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cda38714267978b9a8b0b24bee3529ae", "", "", "Space Instigators (V1.6) (17-10-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cdadb57b34438805ee322ff05bd3d43e", "Thomas Jentzsch", "", "Centipede - Amiga Mouse Hack v1.4 (PAL60) (Full-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cdb81bf33d830ee4ee0606ee99e84dba", "Arcadia Corporation, Scott Nelson", "AR-4300", "Fireball (1982) (Arcadia) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "01", "", "", "", "" }, - { "cdc1a5c61d7488eadc9aba36166b253d", "Retroactive", "", "Qb (V0.12) (Stella) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "cddabfd68363a76cd30bee4e8094c646", "Computer Magic - CommaVid, John Bronstein", "CM-001", "MagiCard (1981) (CommaVid)", "Uses the Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ce17325834bf8b0a0d0d8de08478d436", "", "", "Boring Freeway (Hack)", "Hack of Freeway", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ce1cbe159b9ae5992dacf09371de5e13", "Atari - GCC, Kevin Osborn", "CX2689", "Kangaroo (01-19-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ce243747bf34a2de366f846b3f4ca772", "Home Vision - Gem International Corp. - VDI", "", "Jacky Jump (1983) (Home Vision) (PAL)", "AKA Bobby Is Going Home", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ce4bbe11d682c15a490ae15a4a8716cf", "", "", "Okie Dokie (Older) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ce5524bb18e3bd8e092273ef22d36cb9", "Carrere Video - JWDA, Todd Marshall, Wes Trager, Henry Will IV - Teldec - Prism", "USC1004", "Commando Raid (1983) (Carrere Video) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ce5cc62608be2cd3ed8abd844efb8919", "Atari - Bobco, Robert C. Polaro", "CX2663", "Road Runner (1989) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ce64812eb83c95723b04fb56d816910b", "Retroactive", "", "Qb (V2.04) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "ce6c4270f605ad3ce5e82678b0fc71f8", "", "", "Vertical Rainbow Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ce82a675c773ff21e0ffc0a4d1c90a71", "", "", "Defender 2 (Genesis)", "Genesis controller (C is smartbomb)", "Hack of Defender 2", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ce8467ae2a3a5bc88ca72a2ce44ce28c", "SOLID Corp. (D. Scott Williamson)", "CX2655-015", "Star Castle 2600 (SolidCorp) (PAL) [015]", "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "ce89529d6e98a13ddf3d84827bbdfe68", "", "", "Kung Fu Sprite Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "ce904c0ae58d36d085cd506989116b0b", "Telegames", "5687 A279", "International Soccer (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cea9f72036dc6f7af5eff52459066290", "Retroactive", "", "Qb (2.07) (Retroactive) (Stella)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "ceba7965a93c689bdecdb46a5b2ac0c1", "Thomas Jentzsch", "", "Reactor - Atari Trak-Ball Hack v1.3 (PAL60) (Half-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cedbd67d1ff321c996051eec843f8716", "Ultravision", "1044", "Karate (1982) (Ultravision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cef01595000627ee50863d4290372c27", "", "", "Many Blue Bars and Text Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cef2287d5fd80216b2200fb2ef1adfa8", "Milton Bradley Company", "4363", "Spitfire Attack (1983) (Milton Bradley)", "AKA Flight Commander)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cf0c593c563c84fdaf0f741adb367445", "Retroactive", "", "Qb (V0.05) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "cf3a9ada2692bb42f81192897752b912", "", "", "Air Raiders (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cf3c2725f736d4bcb84ad6f42de62a41", "Rainbow Vision - Suntek", "SS-009", "Bermuda, The (1983) (Rainbow Vision) (PAL) [a]", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cf507910d6e74568a68ac949537bccf9", "SEGA, Jeff Lorenz", "003-01", "Thunderground (1983) (SEGA)", "AKA Underground", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "cf63ffac9da89ef09c6c973083061a47", "CCE", "C-859", "MASH (1983) (CCE)", "AKA M.A.S.H", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cf9069f92a43f719974ee712c50cd932", "Video Gems", "VG-04", "Mission Survive (1983) (Video Gems) (PAL)", "", "", "", "", "", "", "A", "", "", "", "", "", "", "", "", "YES", "" }, - { "cfad2b9ca8b8fec7fb1611d656cc765b", "Bit Corporation", "PG207", "Mission 3,000 A.D. (1983) (BitCorp) (PAL) [demo cart]", "demonstration cartridge", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "cfb3260c603b0341d49ddfc94051ec10", "Dactari - Milmar", "", "Boxing (Dactari - Milmar)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cfb83a3b0513acaf8be4cae1512281dc", "Starpath Corporation", "", "Going-Up (1983) (Starpath) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cfc226d04d7490b69e155abd7741e98c", "Atari, Matthew L. Hubbard", "CX26159", "Double Dunk (1989) (Atari) (PAL)", "AKA Super Basketball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cfce5596a7e8ca13529e9804cad693ef", "Canal 3 - Intellivision", "", "Tennis (Canal 3) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cfd5518c71552b8bb853b0e461e328d7", "Bit Corporation", "R320", "Spider Fighter (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cfd6a8b23d12b0462baf6a05ef347cd8", "Activision, Larry Kaplan", "AX-006", "Bridge (1980) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cfdb4d0427a1ea8085c6bc6eb90259d8", "", "", "Gunfight 2600 - Release Candidate (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cfe2185f84ce8501933beb5c5e1fd053", "", "", "Football (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cfe62ed7125ff9fae99b4c8a367c0399", "Activision, Larry Miller", "AX-026, AX-026-04", "Enduro (1983) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cfee10bd7119f10b136921ced2ee8972", "", "", "Space Instigators (V1.8) (19-10-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cfef1a2d1f6a5ee7a5e1f43f3056f112", "", "", "Skeleton+ (05-05-2003) (Eric Ball) (NTSC)", "", "", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cff1e9170bdbc29859b815203edf18fa", "Retroactive", "", "Push (V0.01) (1998) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "cff578e5c60de8caecbee7f2c9bbb57b", "George Veeder", "", "Suicide Adventure (George Veeder) (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "cff9950d4e650094f65f40d179a9882d", "Paul Slocum", "", "Mr. Roboto (Paul Slocum) (Hack)", "Hack of Berzerk", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "cfffc4b97d01cc3e7b9f47575f7b11ec", "Xonox - K-Tel Software, Anthony R. Henderson", "99007, 6240", "Tomarc the Barbarian (1983) (Xonox) (PAL60)", "Genesis controller (B is jump and throw, C switches between players)", "Hack of Tomarc the Barbarian", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d00f6f8ba89559e4b20972a478fc0370", "Spiceware", "SW-01", "Medieval Mayhem (PAL)", "", "Homebrew", "STEREO", "", "", "", "", "", "", "", "", "", "AUTO 55", "", "", "", "" }, - { "d010e3dfe7366e47561c088079a59439", "Retroactive", "", "Qb (V0.10) (Stella) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "d026716b3c5be2c951cc4c064317c524", "", "", "Fu Kung! (V0.06) (14-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d0498baca989e792db4b8270a02b9624", "", "", "Pac Ghost Sprite Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d071d2ec86b9d52b585cc0382480b351", "UA Limited", "", "Cat Trax (1983) (UA Limited) (1) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "d078674afdf24a4547b4b32890fdc614", "Jone Yuan Telephonic Enterprise Co", "", "Laser Blast (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d078d25873c5b99f78fa267245a2af02", "SEGA - Beck-Tech, Steve Beck, Phat Ho", "006-01", "Congo Bongo (1983) (SEGA) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d0796a0317abf9018d6745086bef411f", "Edward Smith", "", "Alien Attack (2018)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d08fccfbebaa531c4a4fa7359393a0a9", "Activision, David Crane, Bob Whitehead", "", "Venetian Blinds Demo (1981) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d090836f0a4ea8db9ac7abb7d6adf61e", "Hozer Video Games", "", "Yahtzee (Hozer Video Games)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "d09935802d6760ae58253685ff649268", "Telesys, Don Ruffcorn", "1006", "Demolition Herby (1983) (Telesys)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "d09a7504ee8c8717ac3e24d263e7814d", "Activision, Matthew L. Hubbard, Bob Whitehead", "AX-024", "Dolphin (1983) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d09f1830fb316515b90694c45728d702", "Imagic, Brad Stewart", "720105-1A, IA3400", "Fire Fighter (1982) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d0a379946ed77b1b126230ca68461333", "Ataripoll", "", "Atari Invaders (Ataripoll) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d0af33865512e9b6900714c26db5fa23", "Telegames", "", "Armor Ambush (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d0b26e908370683ad99bc6b52137a784", "Apollo - Games by Apollo, Larry Minor, Ernie Runyon, Ed Salvo - RCA Video Jeux", "AP-2004", "Lost Luggage (1982) (Apollo) (PAL)", "AKA La valise piegee", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d0b9df57bfea66378c0418ec68cfe37f", "20th Century Fox Video Games - Sirius, Grady Ward", "11002", "Beany Bopper (1982) (20th Century Fox)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d0b9f705aa5f61f47a748a66009ae2d2", "", "", "Synthcart (14-01-2002) (Paul Slocum)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "d0cb28e1b7bd6c7f683a0917b59f707e", "Atari, Gary Palmer", "CX2661P", "Fun with Numbers (1980) (Atari) (PAL) (4K)", "AKA Basic Math", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d0cdafcb000b9ae04ac465f17788ad11", "Quelle - Otto Versand", "732.273 8 - 600273, 781644", "Lilly Adventure (1983) (Quelle) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d0e05ba5f10e3df3023c5ee787f760ef", "Thomas Jentzsch", "", "Centipede - Atari Mouse Hack v1.4 (PAL) (Half-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d0e15a3ce322c5af60f07343594392af", "Amiga - Video Soft", "3125", "Surf's Up (1983) (Amiga) (Prototype) (4K)", "Uses the Joyboard controller", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d0e9beb2347595c6c7d158e9d83d2da8", "Retroactive", "", "Qb (2.00) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "d100b11be34a1e5b7832b1b53f711497", "", "", "Robotfindskitten2600 (26-04-2003) (Jeremy Penner) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d15655fe355fa57dd541487dc5725145", "Rentacom", "", "Vanguard (Rentacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d170317ae4c7d997a989c7d6567c2840", "Jone Yuan Telephonic Enterprise Co", "", "Stampede (Jone Yuan) (4K) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d175258b2973b917a05b46df4e1cf15d", "Suntek", "SS-032", "Walker (1983) (Suntek) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d17a671029b1532b197defca5f3649a7", "Hozer Video Games", "", "Gunfight 2600 - Limit broken again! (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d17a8c440d6be79fae393a4b46661164", "", "", "Warring Worms (Beta 3) (2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d1a1841b7f2007a24439ac248374630a", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (1 of 4) (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d1a9478b99d6a55e13a9fd4262da7cd4", "U.S. Games Corporation, Garry Kitchen - Vidtec", "VC1001", "Space Jockey (1982) (U.S. Games) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d1b4075925e8d3031a7616d2f02fdd1f", "", "", "Demo Image Series #7 - Two Marios (27-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d1c3520b57c348bc21d543699bc88e7e", "Gameworld", "133-002", "Warplock (1983) (Gameworld) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "01", "", "", "YES", "" }, - { "d1ca47b262f952413c1234117c4e4e21", "Bit Corporation", "R320", "Missile Command (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d1d704a7146e95709b57b6d4cac3f788", "Atari, Warren Robinett", "CX26163P", "Slot Racers (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d20e61c86ed729780feca162166912ca", "Supergame", "32", "Pitfall (1984) (Supergame)", "AKA Pitfall!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d214c7a734e133a5c18e93229435b57a", "Digivision", "", "Mickey (Digivision)", "AKA Sorcerer's Apprentice", "", "", "", "UASW", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d223bc6f13358642f02ddacfaf4a90c9", "Rainbow Vision - Suntek", "SS-003", "Pac-Kong (1983) (Rainbow Vision) (PAL)", "AKA Inca Gold", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d245e2f27c84016041e9496b66b722fe", "", "", "Gunfight 2600 - The Final Kernel (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d25018349c544320bf3fd5092ee072bc", "Activision, Larry Miller", "AX-021", "Spider Fighter (1983) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d28afe0517a046265c418181fa9dd9a1", "", "", "Dodge 'Em (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d2901c34bb6496bb96c7bc78a9e6142a", "Greg Zumwalt", "", "Fish Revenge (2003) (Greg Zumwalt) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d2c4f8a4a98a905a9deef3ba7380ed64", "Mythicon, Bill Bryner, Bruce de Graaf", "MA1001", "Sorcerer (1983) (Mythicon)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d2c8e6aa8172b16c8aa9aae739ac9c5e", "Activision, David Crane", "08-08-1980", "Laser Blast (08-08-1980) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d2c957dd7746521b51bb09fde25c5774", "Eckhard Stolberg", "", "Cubis (6K) (1997) (Eckhard Stolberg)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d2d8c4f1ea7f347c8bcc7d24f45aa338", "", "", "20 Sprites at Once Demo 5 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d2deddb77c8b823e4be9c57cb3c69adc", "Canal 3 - Intellivision", "C 3007", "Snoopy and the Red Baron (Canal 3)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d2f713c78a9ebba9da6d10aeefc6f20f", "Digivision", "", "Enduro (Digivision) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d3171407c3a8bb401a3a62eb578f48fb", "ZiMAG - Emag - Vidco", "GN-080", "Spinning Fireball (1983) (ZiMAG) (Prototype) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "d326db524d93fa2897ab69c42d6fb698", "Parker Brothers - Roklan, Paul Crowley, Bob Curtiss", "931505", "Super Cobra (1983) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d339b95f273f8c3550dc4daa67a4aa94", "", "", "Laser Blast (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d341d39774277cee6a1d378a013f92ac", "Xonox, John Perkins", "6230, 7210, 06004, 99004", "Artillery Duel (1983) (Xonox) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d3423d7600879174c038f53e5ebbf9d3", "U.S. Games Corporation - Western Technologies", "VC2005", "Piece o' Cake (1983) (U.S. Games)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "AUTO 60", "", "", "", "" }, - { "d3456b4cf1bd1a7b8fb907af1a80ee15", "Avalon Hill, Duncan Scott", "5003002", "Wall Ball (1983) (Avalon Hill)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "d34b933660e29c0a0a04004f15d7e160", "", "", "Multi-Color Demo 5 (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d36308387241e98f813646f346e7f9f7", "King Atari", "", "Ghostbuster 2 (King Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "d39e29b03af3c28641084dd1528aae05", "Funvision - Fund. Int'l Co.", "", "Spider Monster (1982) (Funvision) (PAL)", "AKA Spider Kong", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d3bb42228a6cd452c111c1932503cc03", "UA Limited", "", "Funky Fish (1983) (UA Limited) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "d44d90e7c389165f5034b5844077777f", "Parker Brothers, Larry Gelberg", "PB5065", "Star Wars - Ewok Adventure (1983) (Parker Bros) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d45bf71871b196022829aa3b96bfcfd4", "Activision, Steve Cartwright", "AX-017, AX-017-04", "MegaMania (1982) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d45ebf130ed9070ea8ebd56176e48a38", "SEGA, Jeff Lorenz", "001-01", "Tac-Scan (1983) (SEGA)", "Uses the Paddle Controllers (right only)", "", "", "", "", "", "", "", "YES", "", "", "YES", "AUTO 60", "", "", "YES", "" }, - { "d47387658ed450db77c3f189b969cc00", "PlayAround - J.H.M.", "206", "Westward Ho (1982) (PlayAround) (PAL)", "AKA Custer's Revenge", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d4806775693fcaaa24cf00fc00edcdf3", "Atari - Bobco, Robert C. Polaro", "CX26140, CX26140P", "Desert Falcon (1987) (Atari) (PAL)", "AKA Nile Flyer, Sphinx", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d483f65468d9a265661917bae1a54f3e", "Joe Grand", "", "SCSIcide Pre-release 3 (Joe Grand)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d4942f4b55313ff269488527d84ce35c", "Atari - GCC, Mark Ackerman, Glenn Parker", "CX2675, CX2675P", "Ms. Pac-Man (1982) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d49aff83f77a1b9041ad7185df3c2277", "", "", "Space Treat (60% complete) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d4aa89e96d2902692f5c45f36903d336", "", "", "Euchre (NTSC) (Erik Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d4c590ccfb611a73b3331359700c01a3", "", "", "Sprite Movement Demo 2 (2001) (Roger Williams)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d541b20eae221a8ee321375e5971e766", "Arcadia Corporation, Stephen H. Landrum", "AR-4101", "Communist Mutants from Space (Preview) (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d54cd41ecfd59e4b72d2c086152b9a75", "Amiga - Video Soft - Michael K. Glass, Jerry Lawson", "1110", "Power Play Arcade Video Game Album (1983) (Amiga) (Prototype)", "3-D Ghost Attack only (3-D Genesis & 3-D Havoc missing in ROM)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "d5618464dbdc2981f6aa8b955828eeb4", "CCE", "C-829", "Megamania (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d563ba38151b8204c9f5c9f58e781455", "Atari, Brad Stewart - Sears", "CX2649, 49-75163", "Asteroids (1981) (Atari) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "d573089534ca596e64efef474be7b6bc", "Parker Brothers, John Emerson", "931511", "Action Force (1983) (Parker Bros) (PAL) [a]", "AKA G.I. Joe - Cobra Strike", "", "", "", "", "", "", "", "", "", "", "", "01 55", "", "", "", "" }, - { "d57913088e0c49ac3a716bf9837b284f", "Activision, Garry Kitchen", "EAZ-032", "Pressure Cooker (1983) (Activision) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d57eb282d7540051bc9b5427cf966f03", "Atari Troll", "", "Custer's Viagra (Atari Troll) (Hack)", "Hack of Custer's Revenge", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d597d35c6022c590d6e75e865738558a", "", "", "Sprite Color Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d5aa7472e7f2cc17e893a1a36f8dadf0", "", "", "Overhead Adventure Demo 5 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d5c6b81212ad86fd9542a1fedaf57cae", "", "", "Sprite Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d5d2d44fb73785996ccc24ae3a0f5cef", "Robby", "", "Grand Prix (Robby)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d5e17022d1ecc20fd9b53dc464c302f1", "Activision, Carol Shaw", "EAX-020", "River Raid (1982) (Activision) (SECAM)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d5e27051512c1e7445a9bf91501bda09", "Activision, David Crane", "AG-008", "Laser Blast (1981) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d5e5b3ec074fff8976017ef121d26129", "Star Game", "003", "River Raid (Star Game)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d5f965c159e26a1fb49a22a47fbd1dd0", "Supergame", "", "River Raid II (Supergame)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d605ed12f4eaaaec3dcd5aa909a4bad7", "", "", "Chronocolor Frame Demo (10-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d61629bbbe035f45552e31cef7d591b2", "", "", "Atari Logo Demo (PD) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d62283aed0f4199adb2333de4c263e9c", "Atari, Alan J. Murphy, Nick 'Sandy Maiwald' Turner", "CX2615", "Demons to Diamonds (1982) (Atari) (PAL)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "YES", "10 57", "", "", "", "" }, - { "d62d7d1a974c31c5803f96a8c1552510", "", "", "StarMaster (Unknown) (PAL)", "Use Color/BW switch to change between galactic chart and front views", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d632b74fea533d593af82cf16e7c5e4a", "", "", "Fu Kung! (V0.13) (01-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "d65028524761ef52fbbdebab46f79d0f", "CCE", "", "Galaxian (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d65900fefa7dc18ac3ad99c213e2fa4e", "", "", "Guntest (2000) (Eckhard Stolberg)", "Light Gun Test (based on Sentinel code)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d69559f9c9dc6ef528d841bf9d91b275", "Activision, Alan Miller", "AX-016", "StarMaster (1982) (Activision)", "Use Color/BW switch to change between galactic chart and front views", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d6a44277c3eb4f9d039185e0ecf7bfa6", "", "", "Trick (1997) (Eckhard Stolberg)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d6acff6aed0f04690fe4024d58ff4ce3", "Spectravision - Spectravideo - Quelle", "SA-202 - 412.851 8", "Planet Patrol (1982) (Spectravision) (PAL) [different spaceship]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d6b8beeb05e5b730084d4b8f381bbf8d", "", "", "208 in 1 Game Select ROM (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d6d1ddd21e9d17ea5f325fa09305069c", "Funvision - Fund. International Co.", "", "Time Warp (1982) (Funvision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d6d5dd8fd322d3cf874e651e7b6c1657", "", "", "How to Draw a Playfield (1997) (Nick Bensema) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d6dc9b4508da407e2437bfa4de53d1b2", "Bomb - Onbase", "CA283", "Z-Tack (1983) (Bomb) (PAL)", "AKA Base Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d726621c676552afa503b7942af5afa2", "Atari, Bob Whitehead", "CX26163P", "Blackjack (32 in 1) (1988) (Atari) (PAL) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d73ad614f1c2357997c88f37e75b18fe", "Goliath", "7", "Space Tunnel (1983) (Goliath) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d74a81fcd89c5cf0bd4c88eb207ebd62", "", "", "Poker Squares (V0.00a) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d763e3a9cdcdd56c715ec826106fab6a", "Activision, David Crane", "AG-001", "Dragster (1980) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d7759fa91902edd93f1568a37dc70cdb", "Atari, Robert C. Polaro", "CX26157", "Stunt Cycle (1980) (Atari) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d782543818b6320e4f60d77da2b596de", "Atari", "CX26163P", "Fishing Derby (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d787ec6785b0ccfbd844c7866db9667d", "Retroactive", "", "Qb (V0.04) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "d7891b0faa4c7f764482762d0ed427a5", "", "", "Bars and Text Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d7b2259f6bb57bf37eac82365c1f8ad6", "Parker Brothers, Mike Brodie", "PB5320", "Super Cobra (1983) (Parker Bros) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d7b58303ec8d8c4dbcbf54d3b9734c7e", "", "", "Paddle Demo (Joe Grand) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d7dd56677e4ec1e6627419478a4a9668", "", "", "Shadow Keep (Fixed) (04-03-2003) (Andrew Towers)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d7f5bf138cfc7feab7b8ef1534c8b477", "", "", "Eric Bergstrom's KC-135 (Radar Map) (Aaron Bergstrom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d816fea559b47f9a672604df06f9d2e3", "Atari, Gary Palmer", "CX26163P", "Fun with Numbers (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d81bb6965e6c99b3be99ffd8978740e4", "", "", "Gunfight 2600 - The Final Kernel Part 3 (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d82675ce67caf16afe5ed6b6fac8aa37", "Thomas Jentzsch", "", "Robot City (V0.23) (13-11-2002) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d8295eff5dcc43360afa87221ea6021f", "Spectravideo", "SA-212", "Mangia' (1983) (Spectravideo) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d82c8a58098a6b46c5b81c16180354d1", "Dennis Debro", "", "Climber 5 (30-10-2002) (Dennis Debro) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d85f1e35c5445ac898746719a3d93f09", "Suntek", "SS-034", "Farmyard Fun (1983) (Suntek) (PAL)", "AKA Play Farm", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d86deb100c6abed1588aa84b2f7b3a98", "Atari, Bob Whitehead - Sears", "CX2625 - 6-99827, 49-75114", "Football (1979) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d88691c995008b9ab61a44bb686b32e4", "", "", "Warring Worms (07-02-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d89262907e70c13dff23356c4a9055d0", "Bit Corporation", "R320", "Video Pinball (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d89fedded0436fdeda7c3c37e2fb7cf1", "", "", "Surround (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d8acaa980cda94b65066568dd04d9eb0", "CCE", "", "Sea Hunt (CCE)", "AKA Skindiver", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d8b2c81cea5af04f795eb3dc6573d72b", "", "", "Tunnel Demo 2 (27-03-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d8df256c0d89e494a9fb3e9abb8e44ac", "Imagic, Michael Greene", "IA3312P", "No Escape! (1982) (Imagic) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d8e4c8e2d210270cd1e0f6d1b4582b91", "Imagic, Mark Klein", "EIZ-003-04I", "Subterranea (1983) (Imagic) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d90205e29bb73a4cdf28ea7662ba0c3c", "Thomas Jentzsch", "", "Boulderdash Demo (Brighter Version) (09-12-2002) (TJ)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "d912312349d90e9d41a9db0d5cd3db70", "CCE", "C-818", "Star Voyager (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d9548ad44e67edec202d1b8b325e5adf", "Apollo - Games by Apollo, Dan Oliver - RCA Video Jeux", "AP-2002", "Space Cavern (1982) (Apollo) (PAL)", "AKA Les guerriers de l'espace", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d968de2b4ff18bfe4a95066cde310578", "Thomas Jentzsch", "", "Centipede - Amiga Mouse Hack v1.4 (PAL) (Half-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d97e3d0b4575ce0b9a6132e19cfeac6e", "Fabrizio Zavagli", "", "Space Treat (061002) (PD)", "Won't work with Stella < V1.2", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d97fd5e6e1daacd909559a71f189f14b", "M Network, Steve Crandall, Patricia Lewis Du Long", "MT4646", "Rocky & Bullwinkle (04-20-1983) (M Network) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d9ab6b67a17da51e5ad13717e93fa2e2", "Thomas Jentzsch", "", "Turbo (Coleco) Prototype Fake v0.1 (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d9b49f0678776e04916fa5478685a819", "Activision, John Van Ryzin - Ariola", "EAZ-036-04, EAZ-036-04B, EAZ-036-04I - 711 036-720", "H.E.R.O. (1984) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d9bd343533b61389b270c0787210943b", "Atari, Douglas 'Solaris' Neubauer", "CX26134", "Last Starfighter (1984) (Atari) (Prototype)", "Genesis controller (C switches to map mode)", "Hack of Last Starfighter (Solaris prototype)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "d9c9cece2e769c7985494b1403a25721", "SOLID Corp. (D. Scott Williamson)", "CX2655*", "Star Castle 2600 (SolidCorp)", "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "d9da2ae7c7894a29b43b3c6b79f3b7a2", "Atari, Rob Fulop", "CX2633, CX2633P", "Night Driver (1980) (Atari) (PAL) (4K)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "AUTO 65", "", "", "YES", "" }, - { "d9fbf1113114fb3a3c97550a0689f10f", "ZiMAG - Emag - Vidco", "713-111 - GN-050", "Pizza Chef (1983) (ZiMAG) (Prototype)", "AKA Pizza Time", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "da0fb2a484d0d2d8f79d6e063c94063d", "", "", "Air Raiders (1982) (Unknown) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "da4e3396aa2db3bd667f83a1cb9e4a36", "Activision, Steve Cartwright", "AX-027", "Plaque Attack (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "da5096000db5fdaa8d02db57d9367998", "Digitel", "", "River Raid (1983) (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "da6465a34d2e44d26aa9a2a0cd1bce4d", "Absolute Entertainment, Alex DeMeo", "AG-041-04", "Title Match Pro Wrestling (1987) (Absolute) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "da66d75e4b47fab99733529743f86f4f", "Digitel", "", "Chopper Command (1983) (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "da732c57697ad7d7af414998fa527e75", "Atari - Glenn Axworthy", "CX26129", "Midnight Magic (1986) (Atari) (PAL)", "AKA Pinball Wizard", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "da79aad11572c80a96e261e4ac6392d0", "Salu - Ubi Soft, Dennis M. Kiss", "460673", "Pick 'n' Pile (1990) (Salu) (PAL)", "", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "YES", "" }, - { "da7a17dcdaa62d6971393c0a6faf202a", "", "", "Flag Capture (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dab844deed4c752632b5e786b0f47999", "", "", "Super Challenge Baseball (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dac38b4dd3da73bb7b2e9d70c61d2b7c", "", "", "Hangman Monkey Biglist3 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dac5c0fe74531f077c105b396874a9f1", "Atari - GCC", "CX2680", "RealSports Tennis (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dac762e4d01d445bdef20b7771f6570e", "Atari, Carla Meninsky, Ed Riddle - Sears", "CX2611 - 99821, 49-75149", "Indy 500 (1977) (Atari) (4K) [a]", "Uses the Driving Controllers", "", "", "", "", "", "", "", "", "DRIVING", "DRIVING", "", "45", "", "", "", "" }, - { "dad2ab5f66f98674f12c92abcfbf3a20", "", "", "Blue and White Sprite Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "daeb54957875c50198a7e616f9cc8144", "20th Century Fox Video Games, Douglas 'Dallas North' Neubauer", "11005", "Mega Force (1982) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "daef7d8e5a09981c4aa81573d4dbb380", "Adam Thornton", "", "Lord of the Rings (Adam Thornton) (Hack)", "Hack of Dark Mage", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "dafc3945677ccc322ce323d1e9930beb", "Atari", "", "A-Team (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "db1753cc702c18d3917ec7f3b0e8659f", "", "", "Frame Counter 2 (2001) (Jake Patterson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "db339aea2b65b84c7cfe0eeab11e110a", "", "", "Chronocolor Frame Demo 2 (10-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "db4eb44bc5d652d9192451383d3249fc", "CBS Electronics - E.F. Dreyer - VSS, Ed Salvo", "4L 2738 0000", "Mountain King (1983) (CBS Electronics)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "db5073bd75eb05f7d62a7268396d1e77", "Atari", "CX26163P", "Golf (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "db76f7a0819659d9e585f2cdde9175c7", "Xonox", "99005, 6220, 6250", "Robin Hood (1983) (Xonox) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "db80d8ef9087af4764236f7b5649fa12", "M Network, Steve Crandall, Patricia Lewis Du Long", "MT4646", "Rocky & Bullwinkle (1983) (Mattel) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "db971b6afc9d243f614ebf380af0ac60", "Gammation, Robert L. Esken Jr.", "", "Gamma-Attack (1983) (Gammation)", "Uses right joystick controller", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "" }, - { "dba270850ae997969a18ee0001675821", "Greg Troutman", "", "Dark Mage (Greg Troutman) (PD) (4K)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "dbabb80e92ff18d8eecf615c0539151e", "", "", "Sprite Demo 3 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dbb10b904242fcfb8428f372e00c01af", "Atari, John Dunn", "CX2631, CX2631P", "Superman (1979) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dbba14a0f69f0e13fdccb3fde3baedca", "Thomas Jentzsch", "", "Reactor - Atari Trak-Ball Hack v1.3 (NTSC) (Full-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dbc7485ad5814d466de780a3e7ed3b46", "Kyle Pittman", "", "Pink Floyd (Kyle Pittman) (PD)", "Hack of Adventures of Tron (Mattel)", "New Release (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dbc8829ef6f12db8f463e30f60af209f", "Data Age", "DA1001", "Encounter at L-5 (1982) (Data Age)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "AUTO 50", "", "", "", "" }, - { "dbdaf82f4f0c415a94d1030271a9ef44", "CCE", "", "Kaboom! (CCE)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, - { "dbdd21e1ee3d72119e8cd14d943c585b", "", "", "Slot Machine (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dc13df8420ec69841a7c51e41b9fbba5", "Atari, Mimi Nyden, Steve Woita", "CX26132", "Garfield (06-21-1984) (Atari) (Prototype)", "AKA Garfield on the Run", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dc33479d66615a3b09670775de4c2a38", "Suntek", "SS-033", "I.Q. Memory Teaser (1983) (Suntek) (PAL)", "AKA IQ 180", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dc81c4805bf23959fcf2c649700b82bf", "Imagic, Michael Greene", "720055-2A, IA3312P", "No Escape! (1983) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dc905b22de0f191a029df13eddfcabc4", "Atari, Warren Robinett", "", "Elf Adventure (05-02-83) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dc97cbcf091a5ef4ca7fe95dc0848036", "Atari - Roklan, Joe Gaucher, Alex Leavens", "CX2683", "Crazy Climber (1983) (Atari) (Prototype) [a2]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dca90ea1084a2fdbe300d7178ca1a138", "Imagic, Dennis Koble", "IA3000P", "Trick Shot (1982) (Imagic) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "dca941dab5c6f859b71883b13ade9744", "", "", "Hangman Pac-Man Biglist2 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dcba0e33aa4aed67630a4b292386f405", "Retroactive", "", "Qb (V2.08) (Half Speed Version) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "dcc2956c7a39fdbf1e861fc5c595da0d", "M Network - INTV - APh Technological Consulting, David Rolfe", "MT5664", "Frogs and Flies (1982) (M Network)", "AKA Frogs 'n' Flies", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dcec46a98f45b193f07239611eb878c2", "", "", "Bars and Text Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dd08e18cfee87a0e7fc19a684b36e124", "Atari - GCC, Kevin Osborn", "CX2689, CX2689P", "Kangaroo (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dd0cbe5351551a538414fb9e37fc56e8", "Xonox - K-Tel Software - Product Guild, Anthony R. Henderson", "99006, 6220", "Sir Lancelot (1983) (Xonox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dd0de0f61af2a2a4878e377b880a3933", "SOLID Corp. (D. Scott Williamson)", "CX2655-013", "Star Castle 2600 (SolidCorp) [013]", "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "dd10b5ee37fdbf909423f2998a1f3179", "", "", "Space Instigators (V1.9) (21-10-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dd13a16d14100819f79b1ce3a5bf499c", "Thomas Jentzsch", "", "Missile Control - Atari Mouse Hack v1.15 (PAL) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dd1422ffd538e2e33b339ebeef4f259d", "Atari, Michael Sierchio", "", "Football Demo (1982) (Atari)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dd17711a30ad60109c8beace0d4a76e8", "", "", "Karate (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dd1842ba0f3f9d94dccb21eaa0f069b7", "Bit Corporation", "R320", "Defender (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dd45e370aceff765f1e72c619efd4399", "Bit Corporation", "PG201", "Sea Monster (1982) (BitCorp)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dd4f4e0fbd81762533e39e6f5b55bb3a", "Thomas Jentzsch", "", "Turbo WIP (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dd7598b8bcb81590428900f71b720efb", "Xonox - K-Tel Software - Computer Magic", "99005, 6220, 6250", "Robin Hood (1983) (Xonox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dd7884b4f93cab423ac471aa1935e3df", "Atari, Brad Stewart - Sears", "CX2649, 49-75163", "Asteroids (1981) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "dd8a2124d4eda200df715c698a6ea887", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (3 of 3) (1982) (Starpath)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dd92d6ad50976f881d86b52d38616118", "SpkSoft", "", "River Raid (SpkSoft) [h1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dda23757407c4e217f64962c87ad0c82", "Atari Freak 1", "", "Nitemare at Sunshine Bowl-a-Rama (Atari Freak 1) (Hack) [a]", "Hack of Pac-Man Jr.", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ddd1efc1862cd3eb3baf4cba81ff5050", "", "", "Max3 (2001) (Maxime Beauvais) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "de0173ed6be9de6fd049803811e5f1a8", "Xonox - K-Tel Software - Product Guild, Anthony R. Henderson", "99008, 6240", "Motocross Racer (1983) (Xonox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "de07e9cb43ad8d06a35f6506e22c62e9", "", "", "Oh No! (Version 4) (22-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "de1a636d098349be11bbc2d090f4e9cf", "", "", "Pressure Gauge (Hozer Video Games)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "de1e9fb700baf8d2e5ae242bffe2dbda", "Activision - Imagineering, Mike Reidel", "EAK-043-04I", "Commando (1988) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "de24f700fd28d5b8381de13abd091db9", "CCE", "", "Plaque Attack (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "de29e46dbea003c3c09c892d668b9413", "Coleco - Woodside Design Associates, Steve 'Jessica Stevens' Kitchen", "4L1717, 4L1718, 4L1719, 4L2277", "Carnival (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "de3d0e37729d85afcb25a8d052a6e236", "Spectravision - Spectravideo", "SA-204", "Tapeworm (1982) (Spectravision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "de4436eaa41e5d7b7609512632b90078", "Activision, David Crane", "AX-014, AX-014-04", "Grand Prix (1982) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "de5aab22e5aba5edcb29a3e7491ff319", "Star Game", "001", "Donkey Kong (Star Game)", "AKA Inca Gold", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "de61a0b171e909a5a4cfcf81d146dbcb", "Rainbow Vision - Suntek", "SS-005", "Tom Boy (1983) (Rainbow Vision) (PAL)", "AKA Pitfall!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "de62f8a30298e2325249fe112ecb5c10", "CCE", "C-810", "Enduro (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "de78b3a064d374390ac0710f95edde92", "Bomb - Onbase", "CA281", "Assault (1983) (Bomb)", "AKA Sky Alien", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "de7a64108074098ba333cc0c70eef18a", "", "", "Nuts (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "de7bca4e569ad9d3fd08ff1395e53d2d", "Thomas Jentzsch", "", "Thrust (V1.22) (2000) (TJ)", "Supports BoosterGrip", "New Release", "", "", "", "", "", "", "", "BOOSTERGRIP", "", "", "", "", "", "", "" }, - { "de8443ff47283e7b274a7838cb071fb6", "Atari, Lou Harp", "CX26122", "Sinistar (01-04-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dea0ade296f7093e71185e802b500db8", "CCE", "", "Fishing Derby (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "deb39482e77f984d4ce73be9fd8adabd", "Activision, David Lubar", "AK-048-04", "River Raid II (1988) (Activision) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ded26e1cb17f875a9c17515c900f9933", "", "", "Space Treat (29-12-2002) (Fabrizio Zavagli)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "df12953b919844dad2070ed2e70c9fa2", "Amiga - Video Soft", "3135", "S.A.C. Alert (1983) (Amiga) (Prototype) (PAL)", "Uses Joyboard", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "df2745d585238780101df812d00b49f4", "Bit Corporation", "PG202", "Space Tunnel (1982) (BitCorp)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "df3e6a9b6927cf59b7afb626f6fd7eea", "", "", "Tuby Bird (208 in 1) (Unknown) (PAL)", "AKA Dolphin", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "df40af244a8d68b492bfba9e97dea4d6", "Franklin Cruz", "", "Asteroids 2 (Franlin Cruz) (Hack)", "Hack of Asteroids", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "df5cc5cccdc140eb7107f5b8adfacda1", "Cracker Jack Productions", "", "Lumberman (Cracker Jack) (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "df62a658496ac98a3aa4a6ee5719c251", "Atari, Tom Reuterdahl - Sears", "CX2626 - 6-99829, 49-75116", "Miniature Golf (1979) (Atari)", "AKA Arcade Golf", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "df6a28a89600affe36d94394ef597214", "Apollo - Games by Apollo, Dan Oliver", "AP-2002", "Space Cavern (1982) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "df6a46714960a3e39b57b3c3983801b5", "Puzzy - Bit Corporation", "PG201", "Sea Monster (1982) (Puzzy) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "df753cb87d3af4d03f694ab848638108", "CBS Electronics, Bob Curtiss", "4L1845, 4L1852, 4L1853, 4L1854", "Solar Fox (1983) (CBS Electronics) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "df91277a3569344b89e6e8bd5bebc8d1", "Thomas Jentzsch", "", "Marble Craze - Amiga Mouse Hack v1.0 (PAL) (TJ)", "Uses Amiga Mouse Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "df95e4af466c809619299f49ece92365", "Atari - CCW, Michael Callahan, Preston Stuart", "CX26103", "Alpha Beam with Ernie (06-03-1983) (Atari) (Prototype) (PAL)", "Uses Keypad Controllers", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dfad86dd85a11c80259f3ddb6151f48f", "HES - Imagineering, David Lubar", "535", "My Golf (1990) (HES) (PAL) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dfafa3fa58f5cc3f0342cca475df6095", "", "", "Space Treat (V1.1 Beta) (24-12-2002) (Fabrizio Zavagli)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dfc03ef371cf5163f54c50d8ee73c8cf", "Atari, Gary Palmer", "CX2661", "Fun with Numbers (1980) (Atari) (4K)", "AKA Basic Math", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dfc3dbbb39f05d7dd8ee3ac987478970", "", "", "Imagic Selector ROM (1982) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dfcdd6f593bb7b05dbc2e8e1fc6ee0de", "", "", "Gunfight 2600 - Scenarios complete (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dfe034297200dff672df9533ed1449a9", "", "", "Sprite Movement Demo 1 (2001) (Roger Williams)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dfe6aa7443bb813cefa35a4cf4887422", "", "", "This Planet Sucks (Greg Troutman) [a1]", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "dff33523ccd2fdc8912e84cab8e0d982", "", "", "Fu Kung! (V0.03) (10-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e01e00504e6d4b88fa743c0bbe8a96e5", "", "", "Qb (Special Edition, some bugfixes) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "e020f612255e266a8a6a9795a4df0c0f", "Telegames - VSS", "7062 A305", "Universal Chaos (1988) (Telegames) (PAL)", "AKA Targ", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e02156294393818ff872d4314fc2f38e", "Sancho - Tang's Electronic Co.", "TEC005", "Dice Puzzle (1983) (Sancho) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "e0221c95aa657f5764eeeb64c8429258", "", "", "Tomb Raider 2600 [REV 02] (Montezuma's Revenge Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e03b0b091bea5bc9d3f14ee0221e714d", "CBS Electronics, Bob Curtiss", "4L1852, 4L1853, 4L1854, 4L1855", "Solar Fox (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e040df95a055b18ebdb094e904cb71b2", "", "", "Score Demo (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e04f1c1e4401d584d3f4343410a5bcc4", "Wizard Video Games - MicroGraphic Image, Robert Barber, Tim Martin", "007", "Halloween (1983) (Wizard Video Games) (Prototype) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e0b24c3f40a46cda52e29835ab7ad660", "Quelle - Otto Versand", "626.502 9 - 746381", "Top Gun (1983) (Quelle) (PAL)", "AKA Air Raiders", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e0cf2dcc4c1348c468f5bb1e421c9164", "", "", "Invader Sprites in a Line Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e0de3773f5b867795db557be7b8a703e", "", "", "Boulderdash (13 Blocks Wide) (02-04-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e0eff071f578ecf19edc2ab276644e46", "", "", "Gas Gauge Demo (2001) (Joe Grand) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e1029676edb3d35b76ca943da7434da8", "Atari, Robert C. Polaro, Alan J. Murphy - Sears", "CX2609 - 49-75186", "Defender (10-30-1981) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e10bf1af6bf3b4a253c5bef6577fe923", "Rob Kudla", "", "Space Invaders (1978) (Atari) [h1]", "Hack of Space Invaders (Atari)", "New Release (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e10d2c785aadb42c06390fae0d92f282", "Parker Brothers, Dawn Stockbridge", "PB5910", "Strawberry Shortcake - Musical Match-Ups (1983) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e1143b72a30d4d3fee385eec38b4aa4d", "", "", "Word Zapper (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e12e32dee68201b6765fcd0ed54d6646", "Atari, Larry Kaplan", "CX2612, CX2612P", "Street Racer (1977) (Atari) (PAL)", "Uses the Paddle Controllers (swapped)", "", "", "", "", "", "", "", "", "", "", "YES", "AUTO 75", "", "", "", "" }, - { "e13818a5c0cb2f84dd84368070e9f099", "CCE", "C-839", "Misterious Thief, A (1983) (CCE)", "AKA A Mysterious Thief", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "e13c7627b2e136b9c449d9e8925b4547", "Atari, Alan Miller - Sears", "CX2624 - 6-99826, 49-75113", "Basketball (1978) (Atari) (4K)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e1486c7822c07117b4f94a32e5ed68c1", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (06-14-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e14dc36b24fe22c04fa076e298f2e15f", "Activision, Larry Kaplan, David Crane", "AG-010, AG-010-04", "Kaboom! (1981) (Activision) (16K)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, - { "e14feddeb82f5160ed5cf9ca4078e58d", "", "", "SpaceMaster X-7 (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e150f0d14f013a104b032305c0ce23ef", "Spectravision - Spectravideo", "SA-205", "China Syndrome (1982) (Spectravision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "e15b5525cf8f77297b322838df8d999c", "", "", "Sprite Demo 0 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e171558c51bb3bac97bfa79fa2c1a19c", "", "", "Warring Worms (Tim Strauss Edition) (20-12-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e17699a54c90f3a56ae4820f779f72c4", "Rainbow Vision - Suntek", "SS-020", "Tuby Bird (1983) (Rainbow Vision) (PAL)", "AKA Dolphin", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e18abe87035379c56b435bfe8175077b", "Grimlock", "", "Rumble 2600 (Grimlock) (Hack)", "Hack of Mario Bros.", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e1a51690792838c5c687da80cd764d78", "20th Century Fox, John Russell", "", "Alligator People (1983) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e1b90f1e01b1a316d7bbf141525cc00e", "", "", "Sky Jinks (Unknown) (PAL) (4K) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e1d5c8213e82820128fa9c4775f1e166", "Jess Ragan", "", "Jungle King (2003) (Jess Ragan) (Hack)", "Hack of Jungle Hunt", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e1d79e4e7c150f3861256c541ec715a1", "", "", "Space Jockey (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e1e09e2f280e8e142121a377d0dc1b46", "Thomas Jentzsch", "", "Thrust (V1.21) (2000) (TJ)", "Bugfixed", "New Release", "", "", "", "", "", "", "", "BOOSTERGRIP", "", "", "", "", "", "", "" }, - { "e1efe2ef7664bb6758b1a22ff8ea16a1", "Dynacom", "", "Enduro (1983) (Dynacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e1f88da6da8a7d521ca1dcbf2bc6978b", "Activision, Bob Whitehead - Ariola", "EAG-005, PAG-005, EAG-005-04B - 711 005-715", "Skiing (1980) (Activision) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e21ee3541ebd2c23e817ffb449939c37", "Tigervision - Software Electronics Corp., Karl T. Olinger - Teldec", "7-001", "King Kong (1982) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e227be19f572f6900e314213ae9a4deb", "Atari, Dan Hitchens, Mimi Nyden", "CX2656", "SwordQuest - EarthWorld (1982) (Atari) (Prototype)", "AKA Adventure I, SwordQuest I - EarthWorld", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e237ee91514d5ed535c95a14fc608c11", "Activision, Matthew L. Hubbard, Bob Whitehead", "AX-024", "Dolphin (1983) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e2389c0be5b5b84e0d3ca36ec7e67514", "Retroactive", "", "Qb (V2.09) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "e24d7d879281ffec0641e9c3f52e505a", "Parker Brothers, Mark Lesser", "PB5950", "Lord of the Rings (1983) (Parker Bros) (Prototype)", "Journey to Rivendell (The Lord of the Rings I)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e25e173740f7ecc0e23025445c4591f3", "Greg Zumwalt", "", "Comitoid (Greg Zumwalt)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e275cbe7d4e11e62c3bfcfb38fca3d49", "M Network - INTV - APh Technological Consulting, Ken Smith", "MT5658", "Super Challenge Football (1982) (M Network)", "AKA Pro Football", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e27d518993b0a010f16e92b971ecdcdd", "Manuel Polik", "", "Star Fire (2003) (XYPE) (PAL)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e28113d10c0c14cc3b5f430b0d142fcb", "CCE", "C-816", "Keystone Kappers (1983) (CCE) [a]", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e2846af3e4d172b251ab77cbdd01761e", "Steve Engelhardt", "", "Adventure Plus (2003) (Steve Engelhardt) (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e2904748da63dfefc8816652b924b642", "Jone Yuan Telephonic Enterprise Co", "", "Catch Time (Jone Yuan)", "AKA Plaque Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e2b682f6e6d76b35c180c7d847e93b4f", "", "", "Dodge Demo 4 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e2c1b60eaa8eda131632d73e4e0c146b", "Atari - GCC, Mark Ackerman, Noellie Alito", "CX2692", "Moon Patrol (07-04-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e2c89f270f72cd256ed667507fa038a2", "Starpath Corporation, Stephen H. Landrum", "AR-4101", "Communist Mutants from Space (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e2ca84a2bb63d1a210ebb659929747a9", "Telesys, Don 'Donyo' Ruffcorn", "1002", "Cosmic Creeps (1982) (Telesys) (PAL)", "AKA Space Maze, Spaze Maze", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "e2eccbbe963f80f291cb1f18803bf557", "Atari, Joe Decuir, Steve Mayer, Larry Wagner", "CX26163P", "Combat (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e30f3a37032da52d7815b5a409f6d4b4", "SEGA, Fred Mack", "", "Bear Game Demo (1983) (SEGA)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e314b42761cd13c03def744b4afc7b1b", "Activision, David Crane, Dan Kitchen", "AZ-108-04", "Ghostbusters (1985) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e34c236630c945089fcdef088c4b6e06", "Activision, Steve Cartwright, David Crane - Ariola", "EAB-035-04 - 711 035-721", "Pitfall II (1984) (Activision) (PAL)", "Lost Caverns", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e3533684a7ef930a7fbd0c4dd8ec4847", "CCE", "C-856", "Pimball (1983) (CCE)", "AKA Video Pinball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e3600be9eb98146adafdc12d91323d0f", "Atari, Carol Shaw", "CX2618, CX2618P", "3-D Tic-Tac-Toe (1980) (Atari) (PAL)", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e363e467f605537f3777ad33e74e113a", "Atari, Bob Whitehead - Sears", "CX2603 - 99803, 49-75601", "Star Ship (1977) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e377c3af4f54a51b85efe37d4b7029e6", "20th Century Fox Video Games, Beck-Tech, Steve Beck", "11035", "Save the Whales (1983) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e37c8055d70979af354251ebe9f1b7dd", "HES", "", "Mega Funpak - Gorf, P. Patrol, Pacman, Skeet Shoot (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e38dc1f81a02e325562cd285123f579b", "Atari - GCC, Mike Feinstein", "CX2681, CX2681P", "Battlezone (1983) (Atari) (PAL) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e39843c56b7a4a08b18fa7949ec3ee6b", "", "", "Joshua Invaders (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e39a13b13dc82c5fdbfbbfd55ba1230e", "", "", "Analog Clock (Additional Frame Info) (V0.0) (20-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e3c0451d29dad724231bc5818ec4bae0", "", "", "Single-Scanline Positioning Demo 1 (2001) (Roger Williams)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e3c35eac234537396a865d23bafb1c84", "TechnoVision - Video Technology", "TVS1001", "Nuts (1983) (TechnoVision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e3ed4ba3361756970f076e46e9cad1d2", "", "", "Tennis (Unknown) (PAL) (4K) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e40a818dac4dd851f3b4aafbe2f1e0c1", "Atari, Bill Aspromonte, Dr. Lee Salk", "CX26135", "Peek-A-Boo (1984) (Atari) (Prototype)", "Uses the Keypad Controllers", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e42b937c30c617241ca9e01e4510c3f6", "", "", "Pitfall! (No Walls Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e434c0e161dd3c3fb435eb6bad2e182c", "Atari - GCC, Mike Feinstein, Brad Rice", "CX2681", "Battlezone (05-02-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e48d3a4056ede9393586421996db1ae8", "Thomas Jentzsch", "", "Centipede - Atari Trak-Ball Hack v1.4 (PAL60) (Full-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e49ac0ec879a0d7820bc2598fc2cfcd4", "CCE", "", "Kaboom! (CCE) (4K)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, - { "e4a0b28befaaa2915df1fa01238b1e29", "", "", "Gunfight 2600 - Red River (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e4afe157c09962cf39cdb25845d83d47", "Activision, David Crane - Ariola", "EAG-009, PAG-009 - 711 009-720", "Freeway (1981) (Activision) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e4b12deaafd1dbf5ac31afe4b8e9c233", "Adam Thornton", "", "Lord of the Rings (Adam Thornton) (Hack) [a]", "Hack of Dark Mage", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "e4bff1d5df70163c0428a1ead309c22d", "Atari, Robert C. Polaro, Alan J. Murphy", "CX2609, CX2609P", "Defender (1982) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e4c00beb17fdc5881757855f2838c816", "20th Century Fox Video Games - Sirius, Ed Hodapp", "11004", "Deadly Duck (1982) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e4c2077a18e3c27f4819aa7757903aa0", "", "", "Many Blue Bars Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e5359cbbbff9c6d7fe8aeff5fb471b46", "CCE", "C-849", "Boom Bang (1983) (CCE)", "AKA Crackpots", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e549f1178e038fa88dc6d657dc441146", "Atari, Bob Whitehead - Sears", "CX2625 - 6-99827, 49-75114", "Football (1979) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e556e07cc06c803f2955986f53ef63ed", "Coleco - Individeo, Ed Temple", "2665", "Front Line (1984) (Coleco)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e558be88eef569f33716e8e330d2f5bc", "Shock Vision", "", "Keystone Kapers (Shock Vision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e56da674188ba2f02c7a0a343a01236f", "", "", "This Planet Sucks Demo 4 (Greg Troutman) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e59d022d524d05acc19515598c831e4d", "Alessandro Ciceri", "", "MagiCard+ (alex_79) WIP_20150118 (PAL)", "MagiCard hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e5a6e0bb7d56e2f08b237e15076e5699", "", "", "Color Table Display Helper (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e5bacf526036d3c8c99db5b030cf00e7", "", "", "Starmaster (Genesis)", "Genesis controller (C switches to map mode)", "Hack of Starmaster", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e5d5085123a98c1e61818caa2971e999", "", "", "Euchre (PAL) (Erik Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e5d72ff8bab4450be57785cc9e83f3c0", "Telegames", "6082 A145", "Kung Fu Superkicks (1988) (Telegames) (PAL)", "AKA Chuck Norris Superkicks", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e5ecd78edd24326a968809decbc7b916", "Imagic, Bob Smith", "720020-1A, IA3611", "Cheese (Dragonfire Beta) (05-21-1982) (Imagic) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "e5f17b3e62a21d0df1ca9aee1aa8c7c5", "CommaVid, John Bronstein", "CM-003", "Cosmic Swarm (1982) (CommaVid)", "AKA Termite", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "e5f360226dc552aba3e7e9b202330f48", "Supercat", "", "Mega Bitmap Demo (2007) (Supercat)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "e5f84930aa468db33c0d0f7b26dd8293", "CCE", "C-826", "Grand Prix (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e5fcc62e1d73706be7b895e887e90f84", "", "", "Air-Sea Battle (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e600f5e98a20fafa47676198efe6834d", "Parker Brothers - Roklan, Joe Gaucher", "PB5080", "Gyruss (1984) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "e609e8a007127b8fcff79ffc380da6b1", "", "", "Multi-Sprite Game V2.3 (Piero Cavina) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e61210293b14c9c4ecc91705072c6a7e", "Gameworld", "133-005", "Bugs (1983) (Gameworld) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "AUTO 50", "", "", "", "" }, - { "e62e60a3e6cb5563f72982fcd83de25a", "Jone Yuan Telephonic Enterprise Co", "", "End of the World (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e63a87c231ee9a506f9599aa4ef7dfb9", "Tigervision, Warren Schwader", "7-003", "Threshold (1982) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e63efdfda9a4003dcd77a854a781a06a", "Paul Slocum", "", "Combat Rock (PD) (Hack) [a]", "Hack of Combat", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e643aaec9a9e1c8ab7fe1eae90bc77d7", "Roger Williams", "", "Asymmetric Playfield (Roger Williams)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e64a8008812327853877a37befeb6465", "Answer Software Corporation - TY Associates, Mike Wentz", "ASC1002", "Gauntlet (1983) (Answer Software)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e6508b878145187b87b9cded097293e7", "", "", "Oystron (V2.8) (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e66e5af5dea661d58420088368e4ef0d", "Activision, Bob Whitehead", "AG-011", "Stampede (1981) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e67b0ed32fd9d28d12ab3775d52e8c3a", "Atari, Omegamatrix", "", "Video Olympics Menu (2020) (Hack)", "Hack of Video Olympics", "", "", "", "", "", "", "", "", "", "", "YES", "AUTO 60", "", "", "", "" }, - { "e6d5948f451a24994dfaaca51dfdb4e1", "Jone Yuan Telephonic Enterprise Co", "", "Football (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e6de4ef9ab62e2196962aa6b0dedac59", "Imagic, Wilfredo Aguilar, Michael Becker, Dennis Koble", "720113-2A, 13206", "Solar Storm (1983) (Imagic) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "01 45", "", "", "", "" }, - { "e6e5bb0e4f4350da573023256268313d", "Thomas Jentzsch", "", "Missile Control (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e6f49a1053c79211f82be4d90dc9fe3d", "", "", "Gunfight 2600 - Little progress... (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e723ad8f406cb258b89681ef4cef0eff", "Thomas Jentzsch", "", "Sadoom (TJ) (PAL) (Hack)", "Hack of Kaboom!", "Hack", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, - { "e72eb8d4410152bdcb69e7fba327b420", "Atari, Douglas Neubauer, Mimi Nyden", "CX26136", "Solaris (1986) (Atari)", "AKA Universe, Star Raiders II, The Last Starfighter", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e72ee2d6e501f07ec5e8a0efbe520bee", "Imagic, Dave Johnson", "720119-2A, 13211, EIX-004-04I", "Quick Step! (1983) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e73838c43040bcbc83e4204a3e72eef4", "CCE", "", "Apples and Dolls (CCE)", "AKA Open, Sesame!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "e74022cfe31ec8908844718dfbdedf7a", "", "", "Space Treat (30-12-2002) (Fabrizio Zavagli) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e77ec259e1387bc308b0534647a89198", "Parker Brothers, David Lamkins, Laura Nikolich", "931503", "Spider-Man (1982) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e77f332b71f13884c84771e7a121182d", "Jone Yuan Telephonic Enterprise Co", "", "Hey! Stop! (Jone Yuan)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e784a9d26707cfcd170a4c1c60422a72", "Quelle", "147.443 6", "Gefecht im All (1983) (Quelle) (PAL)", "AKA Space Jockey", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e7864caaf9ec49ed67b1904ce8602690", "", "", "Donkey Kong 2K3 Pic (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e7a758bb0b43d0f7004e92b9abf4bc83", "", "", "Troll's Adventure (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e7dd8c2e6c100044002c1086d02b366e", "Activision, Steve Cartwright - Ariola", "EAX-013, PAX-013, 711 013-720", "Barnstorming (1982) (Activision) (PAL)", "AKA Die tollkeuhnen Flieger", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e7f005ddb6902c648de098511f6ae2e5", "Spectravideo - Universum", "SV-010", "CompuMate (1983) (Spectravideo) (PAL)", "", "", "", "", "CM", "", "", "", "", "COMPUMATE", "COMPUMATE", "", "", "", "", "YES", "80" }, - { "e800e4aec7c6c54c9cf3db0d1d030058", "", "", "Qb (2.06) (Retroactive) (Stella)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "e80a4026d29777c3c7993fbfaee8920f", "", "", "Frisco (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e823b13751e4388f1f2a375d3560a8d7", "Arcadia Corporation, Stephen Harland Landrum", "AR-4105", "Official Frogger (Preview) (1983) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e879b7093ac4cfad74c88d636ca97d00", "", "", "Poker Squares (V0.0f) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e88340f5bd2f03e2e9ce5ecfa9c644f5", "", "", "Lock 'n' Chase (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e8a3473bf786cf796d1336d2d03a0008", "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart", "PB5540", "Star Wars - The Arcade Game (12-05-1983) (Parker Bros) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "e8aa36e3d49e9bfa654c25dcc19c74e6", "Atari, Joe Decuir, Larry Caplan, Steve Mayer, Larry Wagner", "CX2601, CX2601P", "Combat (1977) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e8e7b9bdf4bf04930c2bcaa0278ee637", "", "", "Boring Taz (Hack)", "Hack of Taz", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e8f7679359c4f532f5d5e93af7d8a985", "", "", "Hangman Invader Original Words (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e9034b41741dcee64ab6605aba9de455", "Digivision", "", "Phanton Tank (Digivision)", "AKA Phantom Tank", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e908611d99890733be31733a979c62d8", "Atari, Dan Hitchens, Mimi Nyden", "CX2697", "Mario Bros. (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e91d2ecf8803ae52b55bbf105af04d4b", "Atari, Howard Scott Warshaw", "CX2655, CX2655P", "Yars' Revenge (1982) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "e923001015bedd7901569f035d9c592c", "", "", "Adventure II (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e927ecf80f3784d745abd8368d78f2f3", "", "", "Space Instigators (V1.8) (19-10-2002) (CT) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e932f44fad2a66b6d5faec9addec208e", "", "", "Atari Logo Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e94632b0d863dd76459d689a9865bb33", "Jone Yuan Telephonic Enterprise Co", "", "Combat (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e957eb4612d6bd5940d3492dfa749668", "", "", "Tunnel Demo (27-03-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e959b5a2c882ccaacb43c32790957c2d", "", "", "Phantom II & Pirate (NTSC)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e97eafd0635651d3999cece953c06bd5", "", "", "M.A.S.H (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e9be3e8e4a7e73dd63ed4235a3a1a25f", "", "", "MMetall (Hack)", "Hack of Miniature Golf", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e9c5d04643855949a23ff29349af74ea", "", "", "SCSIcide (Score Hack 2) (24-02-2001) (Joe Grand) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e9c71f8cdba6037521c9a3c70819d171", "Action Hi Tech - Hi-Score", "", "Bank Heist (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e9cb18770a41a16de63b124c1e8bd493", "Parker Brothers - Roklan, Joe Gaucher", "931519", "Popeye (1983) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "e9db2f91efe6ff7ea3546e2c2578fb09", "Omegamatrix", "", "Millipede (Atari Mouse) v6.5 (Omegamatrix)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, - { "e9e646f730b8400cd5da08c849ef3e3b", "Tron", "", "Enduro (Tron)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e9e6ad30549a6e2cd89fe93b7691d447", "Atari - Bobco, Robert C. Polaro", "CX26140, CX26140P", "Desert Falcon (05-27-1987) (Atari) (Prototype) (PAL)", "AKA Nile Flyer, Sphinx", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "e9f25c7af4f27c9e1b5b8f6fe6141e8c", "Champ Games", "CG-03-N", "Scramble (NTSC)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "JOYSTICK", "", "", "", "", "", "YES", "" }, - { "ea38fcfc06ad87a0aed1a3d1588744e4", "Atari, Lou Harp", "CX26122", "Sinistar (01-XX-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ea6d40db5498d6386571a76df448aa4c", "", "", "Vertical Playfield Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ea7e25ade3fe68f5b786ee0aa82b1fe5", "", "", "Galatic (208 in 1) (Unknown) (PAL)", "AKA Challenge of.... Nexar, The", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ea832e2cb6aae6f525f07452c381fa48", "", "", "Polar to Cartesian and VV (2001) (Roger Williams)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ea86176b27ab0da8cce8f0179884bfaa", "", "", "Demo Image Series #10 - It's Art (28-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "eaacfcdc1d4ee1258429b7ae7f084125", "Telegames", "6057 A227", "Quest for Quintana Roo (1989) (Telegames)", "Genesis controller (B is action button, C chooses tool or weapon)", "Hack of Quest for Quintana Roo", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ead60451c28635b55ca8fea198444e16", "Sancho - Tang's Electronic Co.", "TEC004", "Nightmare (1983) (Sancho) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "eada0dd61ce13f8317de774dc1e68604", "", "", "2600 Digital Clock (Demo 1) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "eae0c06ee61c63b81cd016096fc901b0", "Joe Grand", "", "SCSIcide (v1.0) (2001) (Joe Grand)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "eae6a5510055341d3abeb45667bb3e9b", "HES", "", "Wall Defender (HES) (PAL)", "AKA Wall Break (Planet Patrol if right difficulty = 'A')", "", "", "0", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "eaf744185d5e8def899950ba7c6e7bb5", "Atari", "CX26172", "Xenophobe (1991) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "eafe8b40313a65792e88ff9f2fe2655c", "Eric Ball", "ELB004", "Skeleton+ (NTSC)", "Stereo sound", "Homebrew", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "eb3d680699f8762f71f38e28e321234d", "", "", "Fu Kung! (V0.01) (08-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "eb4252faff7a4f2ba5284a98b8f78d1a", "", "", "John K Harvey's Equalizer (NTSC) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "eb46e99ec15858f8cd8c91cef384ce09", "Goliath - Hot Shot", "83-113", "Ground Zero (1983) (Goliath) (PAL)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "eb503cc64c3560cd78b7051188b7ba56", "Star Game", "043", "Moto Laser (Star Game)", "AKA Mega Force", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "eb634650c3912132092b7aee540bbce3", "Atari, Eric Manghise, Mimi Nyden, Joseph Tung", "CX2640", "RealSports Baseball (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "eb6d6e22a16f30687ade526d7a6f05c5", "Atari", "CX26150P", "Q-bert (1987) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "eb71743c6c7ccce5b108fad70a326ad9", "", "", "Euchre (25-11-2001) (Erik Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "eb7934360658a29c50aeaff20bfda23b", "Activision, John Van Ryzin", "EAZ-036-04", "H.E.R.O. (1984) (Activision) (SECAM)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "eb92193f06b645df0b2a15d077ce435f", "Starpath Corporation, Steve Hales, Stephen H. Landrum", "4 AR-4102", "Suicide Mission (1982) (Starpath) (PAL)", "AKA Meteoroids", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "eb9712e423b57f0b07ccd315bb9abf61", "Retroactive", "", "Qb (V2.04) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "eb9f8b84c193d9d93a58fca112aa39ed", "", "", "Register Twiddler Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ebcb084a91d41865b2c1915779001ca7", "JVP", "", "Bob Is Going Home (JVP)", "AKA Bobby Is Going Home", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ebcbc8a181a738e13df6216e5c329230", "Activision, Steve Cartwright", "AX-022", "Seaquest (1983) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ebd2488dcace40474c1a78fa53ebfadf", "Skill Screen Games, Herman Quast", "SSG001", "Extra Terrestrials (1984) (SSG)", "The only Canadian-designed and manufactured Atari 2600 game from the 1980's", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ebdc5716b85c4ff44fa357cb697d6cef", "Thomas Jentzsch", "", "Centipede - Amiga Mouse Hack v1.4 (NTSC) (Half-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ebf2dff78a08733251bf3838f02f7938", "Commavid, Ben Burch", "CM-010", "Rush Hour (1983) (Commavid) (Prototype) [a2]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ebf9038e927e6a0db3e0d170c59911e6", "", "", "Pac-2600 (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ec3beb6d8b5689e867bafb5d5f507491", "U.S. Games Corporation - Vidtec - JWDA, Todd Marshall, Henry Will IV", "VC1003", "Word Zapper (1982) (U.S. Games)", "AKA Word Grabber", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ec407a206b718a0a9f69b03e920a0185", "Quelle", "876.482 1", "Landung in der Normandie (1983) (Quelle) (PAL)", "AKA Commando Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ec5c861b487a5075876ab01155e74c6c", "Apollo - Games by Apollo, Ed Salvo, Byron Parks", "AP-2001", "Spacechase (1982) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ece463abde92e8b89bcd867ec71751b8", "Puzzy - Bit Corporation", "PG205", "Dancing Plate (1982) (Puzzy) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "ece908d77ab944f7bac84322b9973549", "", "", "Tom Boy (Unknown) (PAL60)", "AKA Pitfall!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ecf51385384b468834611d44a8429c03", "20th Century Fox Video Games, Douglas 'Dallas North' Neubauer", "11105", "Mega Force (1982) (20th Century Fox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ecfa04523dde82fe42cdc7315a8f61b6", "Activision, David Crane - Ariola", "EAG-004, PAG-004 - 711 004-715", "Fishing Derby (1980) (Activision) (PAL) (4K)", "AKA Schneller als der Hai", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ed014beeeb77dbb2bbcf9b5f6850b2f4", "", "", "Green Bar Text Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ed0451010d022b96a464febcba70b9c4", "PlayAround - J.H.M.", "203", "Knight on the Town (1982) (PlayAround) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "ed0ab909cf7b30aff6fc28c3a4660b8e", "Panda", "105", "Stunt Man (1983) (Panda)", "AKA Nightmare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ed1306436ce237afc5a7ed3f77134202", "HES", "771-341", "2 Pak Special - Dolphin, Pigs n' Wolf (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ed1492d4cafd7ebf064f0c933249f5b0", "CCE", "", "Video Cube (CCE)", "AKA Atari Video Cube", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ed1a784875538c7871d035b7a98c2433", "Bit Corporation", "R320", "Save Our Ship (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ed2218b3075d15eaa34e3356025ccca3", "Atari, Richard Maurer", "CX2635, CX2635P", "Maze Craze (1980) (Atari) (PAL)", "AKA A Game of Cops 'n Robbers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ed5ccfc93ad4561075436ee42a15438a", "Atari, Tom Reuterdahl", "CX2626, CX2626P", "Miniature Golf (1979) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ed8f319e82d355832195eb7715644795", "Activision, Larry Kaplan, David Crane", "AG-010, AG-010-04", "Kaboom! (1981) (Activision) (8K)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, - { "eddef10fdc0029301064115ae0cd41d4", "CCE", "", "Freeway (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ede4ab11ca346bd023b2c21d941e0c50", "Activision, David Crane", "EAZ-030", "Decathlon (1983) (Activision) (SECAM)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ede7e8bf865b0afb4744f86d13624f9a", "", "", "Demo Image Series #2 - Clown (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "edf69b123e06eaf8663cc78d8aeba06e", "SpkSoft 98", "", "River Raid (SpkSoft 98) [h1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ee28424af389a7f3672182009472500c", "Atari, Carol Shaw - Ralph Lauren", "", "Polo (1978) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ee456542b93fa8d7e6a8c689b5a0413c", "", "", "Chronocolor Donkey Kong Clean (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ee4c186123d31a279ed7a84d3578df23", "Atari, Carol Shaw, Nick 'Sandy Maiwald' Turner", "CX2608", "Super Breakout (1982 - 1981) (Atari) (PAL)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "01 45", "", "", "", "" }, - { "ee659ae50e9df886ac4f8d7ad10d046a", "Exus Corporation", "", "Video Reflex (1983) (Exus)", "AKA Foot Craz", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ee6665683ebdb539e89ba620981cb0f6", "Coleco", "2658", "Berenstain Bears (1983) (Coleco)", "Uses the KidVid Controller", "Unbelievably Rare", "", "", "", "A", "", "", "", "", "KIDVID", "", "", "", "", "", "" }, - { "ee67dc0b01746372d2b983d88f48e24f", "", "", "Scroller Demo (02-01-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ee681f566aad6c07c61bbbfc66d74a27", "Activision", "", "Unknown Activision Game (10-29-1982) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ee6cbedf6c0aac90faa0a8dbc093ffbe", "CCE", "", "My Golf (CCE) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ee8027d554d14c8d0b86f94737d2fdcc", "Canal 3 - Intellivision", "", "Yars' Revenge (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "ee84bdc5dae268e227e407c7b5e6b6b7", "", "", "Marilyn Monroe Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ee9caee4eb958284fb10c277b14537f1", "Carrere Video, Garry Kitchen - Teldec", "USC1001", "Space Jockey (1983) (Carrere Video) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "eea0da9b987d661264cce69a7c13c3bd", "Coleco", "2454", "Zaxxon (1983) (Coleco)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "eeb92f3f46df841487d1504f2896d61a", "Cody Pittman", "", "Corys Adventure (Cody Pittman) (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "eec61cc4250df70939d48fe02d7122ac", "Activision, Bob Whitehead - Ariola", "EAG-005, PAG-005, EAG-005-04B - 711 005-715", "Skiing (1980) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "eed9eaf1a0b6a2b9bc4c8032cb43e3fb", "Atari - Axlon, Steve DeFrisco", "CX26192", "Klax (1991) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "eee7695ae3eea7818321df0b790b31f3", "", "", "Sound Paddle V2 (Dennis Caswell & Jim Nitchals) (PD)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "YES", "", "", "", "01", "", "", "", "" }, - { "ef263d40a23483ab339cac44d9515a56", "Thomas Jentzsch", "", "Fatal Run (TJ)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ef3a4f64b6494ba770862768caf04b86", "Activision, Bob Whitehead", "AG-034-04", "Private Eye (1984) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ef60b06fddb675b0d783afbfa5fc5232", "", "", "Many Blue Bars and Text Demo 4 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ef66af190840871409fe1702d2483554", "Andrew Davie, Paul Slocum, Christopher Tumber", "", "DiscoTech (12-02-2003) (Andrew Davie)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ef71e9fb0d8d477226d8d42261fbf0a7", "Piero Cavina", "", "Multi-Sprite Demo V2.0 (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ef76ea05655a0b62cb1018c92b9b4b7d", "Gakken", "010", "Strategy X (1983) (Gakken) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "efa1098c7d091b940c2543abe372f036", "Scott Stilphen", "", "E.T. The Extra-Terrestrial (Scott Stilphen) (Hack)", "Hack of E.T. The Extra-Terrestrial", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "efb47d70b2965ce689e2c5757616b286", "", "", "Time Test Demo (Eckhard Stolberg) (PAL) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "efd387430a35a659ff569a9a0ec22209", "Atari - GCC", "CX26118", "Millipede (1984) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "efefc02bbc5258815457f7a5b8d8750a", "CBS Electronics, Richard K. Balaska Jr.", "4L 2520 5000", "Tunnel Runner (1983) (CBS Electronics) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "effa3a7ce078c6d83bf43174a7bfdb1f", "Thomas Jentzsch", "", "Centipede - Atari Mouse Hack v1.4 (NTSC) (Half-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "efffafc17b7cb01b9ca35324aa767364", "", "", "Circus Atari (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f02ba8b5292bf3017d10553c9b7b2861", "Atari", "CX26172", "Xenophobe (1991) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f032b2f2d8323404a6b4541f92dd1825", "", "", "Many Blue Bars and Text Demo 3 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f047df70d3d08e331122cd2de61d6af8", "Dave Neuman", "", "Space Battle (NTSC)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f04ee80011d95798006378643650aaa7", "Atari, Bill Aspromonte, John Russell, Michael Sierchio, Robert Zdybel", "CX26114", "Pigs in Space (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f0510abbfbe24ead552e92e3841f63f3", "Thomas Jentzsch", "", "Reactor - Atari Mouse Hack v1.3 (NTSC) (Full-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f0536303f49006806bac3aec15738336", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (4 of 4) (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f0541d2f7cda5ec7bab6d62b6128b823", "Atari, Paul Donaldson", "", "Bionic Breakthrough (1984) (Atari) (Prototype)", "Uses Mindlink Controller (left only)", "Prototype", "", "", "", "", "", "", "", "MINDLINK", "", "", "", "", "", "", "" }, - { "f060826626aac9e0d8cda0282f4b7fc3", "Atari, David Crane - Sears", "CX2605 - 6-99822, 49-75109", "Outlaw (1978) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f0631c6675033428238408885d7e4fde", "Paul Slocum", "", "Test Cart (2002) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "f066bea7ab0a37b83c83c924a87c5b67", "", "", "Air Raiders (1982) (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f0a6e99f5875891246c3dbecbf2d2cea", "Atari, James Andreasen - Sears", "CX2654 - 49-75141", "Haunted House (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f0b7db930ca0e548c41a97160b9f6275", "Atari, Larry Wagner, Bob Whitehead - Sears", "CX2645 - 49-75181", "Video Chess (1979) (Atari)", "AKA Computer Chess", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f0cacae1d1b79ee92f0dc035f42e0560", "", "", "Boring Donkey Kong (Hack)", "Hack of Donkey Kong", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f0d393dbf4164a688b2346770c9bbd12", "", "", "Racquetball (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "f0daaa966199ef2b49403e9a29d12c50", "", "", "Mr. Postman (Unknown)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f0de4f49e95d529569e8788d5a7b4d30", "Thomas Jentzsch", "", "Reactor - Atari Mouse Hack v1.3 (PAL60) (Full-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f0e0addc07971561ab80d9abe1b8d333", "Imagic, Rob Fulop", "720000-200, 720101-1B, 720101-1C, IA3200, IA3200C, IX-006-04", "Demon Attack (1982) (Imagic)", "AKA Death from Above", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f0ef9a1e5d4027a157636d7f19952bb5", "Atari - Axlon, Tod Frye - Heuristica, Agustin Ortiz", "CX26169", "Shooting Arcade (03-07-1989) (Atari) (Prototype) [a5]", "Uses the Light Gun Controller (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f10e3f45fb01416c87e5835ab270b53a", "Suntek", "SS-024", "Ski Run (1983) (Suntek) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f1127ade54037236e75a133b1dfc389d", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (Preview) (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f11cfab087fcbd930ab8b0becc5b2e5a", "Canal 3 - Intellivision", "", "River Raid (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f12afbffa080dd3b2801dd14d4837cf6", "Atari, Michael Kosaka, Peter C. Niday, Robert Vieira", "CX26110", "Crystal Castles (01-04-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "f137211537438b1fce3d811baef25457", "", "", "Incoming (02-10-2002) (Ben Larson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f1489e27a4539a0c6c8529262f9f7e18", "Champ Games", "CG-01-P", "Lady Bug (PAL60)", "", "Homebrew", "", "", "", "", "A", "", "", "", "", "", "", "", "", "YES", "" }, - { "f14d5e96ec3380aef57a4b70132c6677", "Goliath - Hot Shot", "83-414", "Pac Kong (1983) (Goliath) (PAL)", "AKA Inca Gold", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f1554569321dc933c87981cf5c239c43", "Atari - Glenn Axworthy", "CX26129", "Midnight Magic (1986) (Atari)", "AKA Pinball Wizard", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "f16c709df0a6c52f47ff52b9d95b7d8d", "Atari, Alan Miller - Sears", "CX2662 - 6-99811", "Hangman (1978) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f16ef574d2042ed8fe877d6541f4dba4", "Spectravision - Spectravideo", "SA-201", "Gangster Alley (1982) (Spectravision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f1929bb9b5db22d98dd992aa3fe72920", "", "", "Cube Conquest (Improved Interlace) (Billy Eno) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "f19aba18f86e415812480ad2be221425", "Chris Larkin", "", "Solaris Trainer (2002) (Chris Larkin) (Hack)", "Hack of Solaris", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f1a0a23e6464d954e3a9579c4ccd01c8", "20th Century Fox, Douglas 'Dallas North' Neubauer", "11006", "Alien (1982) (20th Century Fox)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "f1ae6305fa33a948e36deb0ef12af852", "Andreas Dietrich", "", "Donkey Kong VCS (2017) (1.0)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "f1b2ea568b3e156e3f2849dac83591f6", "", "", "Sprite Demo (1997) (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f1b7edff81ceef5af7ae1fa76c8590fc", "Atari, Richard Maurer", "CX2632, CX2632P", "Space Invaders (1980) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f1beca5a198cf08190487e5c27b8e540", "", "", "Fu Kung! (V0.16) (2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f1e375d921858467166e53bcec05803f", "Jeffry Johnston", "", "Radial Pong - Version 3 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f1eeeccc4bba6999345a2575ae96508e", "Video Gems", "VG-03", "Steeplechase (1983) (Video Gems) (PAL)", "", "", "", "", "", "", "A", "", "", "", "", "", "", "", "", "YES", "" }, - { "f1fe06ebe2900eac4cdd17799389a102", "Atari, Jim Huether", "CX26163P", "Sky Diver (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f20675c8b98518367b9f5b8ee6f7c8ea", "Atari", "CX26163P", "Stampede (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f20bd756f3990e06c492f53cd0168e68", "", "", "Skeleton+ (03-05-2003) (Eric Ball) (NTSC)", "", "", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f21813aa050437f0dbc8479864acec6d", "", "", "Sneak 'n Peek (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f23d19b73dac50cc6149316912b8ee53", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Amiga Mouse Hack v1.1 (PAL) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f240ba9f8092d2e8a4c7d82c554bf509", "Quelle", "463.860 7", "Strahlen der Teufelsvoegel (1983) (Quelle) (PAL)", "AKA Atlantis", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f280976d69d6e27a48506bd6bad11dcd", "Atari, Larry Kaplan", "CX2664, CX2664P", "Brain Games (1978) (Atari) (PAL)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "" }, - { "f283cc294ece520c2badf9da20cfc025", "Atari - CCW, Christopher H. Omarzu", "CX26104", "Big Bird's Egg Catch (1983) (Atari) (PAL)", "Uses Kids/Keypad Controllers", "Rare", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "" }, - { "f28c07767b3e90a2689ade5b5e305874", "Canal 3 - Intellivision", "C 3014", "Keystone Kapers (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f2d40c70cf3e1d03bc112796315888d9", "Atari - CCW, Michael Callahan, Preston Stuart", "CX26103", "Alpha Beam with Ernie (1983) (Atari) (PAL)", "Uses Keypad Controllers", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f2d4d6187903cac2d5ea8ed90dad120d", "Digimax", "", "River Raid II (Digimax)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f2e4fb2d3600c0f76d05864e658cc57b", "", "", "Marble Craze (Kernel) (17-02-2002) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f2f2cb35fdef063c966c1f5481050ea2", "", "", "Ram It (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f2f59629d7341c97644405daeac08845", "Jone Yuan Telephonic Enterprise Co", "", "Bobby Is Going Home (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f303630a2d7316787aecd67fff6b2e33", "AtariAge - Fred Quimby", "", "Gingerbread Man (Fred Quimby)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f3213a8a702b0646d2eaf9ee0722b51c", "Atari, Carol Shaw - Sears", "CX2618 - 49-75123", "3-D Tic-Tac-Toe (1980) (Atari) (4K)", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f33f1d0f7819c74148dacb48cbf1c597", "Retroactive", "", "Qb (2.00) (Retroactive) (Stella)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "f344ac1279152157d63e64aa39479599", "Tigervision", "7-012", "Espial (1984) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f34dd3b8156aaf113cb621b2e51d90b8", "Joe Grand", "", "SCSIcide Pre-release 5 (Joe Grand)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f34f08e5eb96e500e851a80be3277a56", "Atari, Brad Stewart - Sears", "CX2622 - 6-99813, 49-75107", "Breakout (1978) (Atari)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "01 60", "", "", "", "" }, - { "f367e58667a30e7482175809e3cec4d4", "ZiMAG - Emag - Vidco", "708-111 - GN-040", "Cosmic Corridor (1983) (ZiMAG)", "AKA Space Tunnel", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f38358cd8f5ecfedffd5aca1aa939f18", "Universal Gamex Corporation, Alan Roberts", "1005", "X-Man (1983) (Universal) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f4204fc92d17ed4cb567c40361ad58f1", "Inky", "", "Beanie Baby Bash (Inky) (Hack)", "Hack of Beany Bopper", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f4469178cd8998cb437fa110a228eaca", "Digitel", "", "Frostbite (1983) (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f45644ff82b533a781a1ee50f2e95f3c", "", "", "Overhead Adventure Demo 6 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f457674cef449cfd85f21db2b4f631a7", "U.S. Games Corporation - JWDA, Todd Marshall, Wes Trager, Henry Will IV", "VC1004", "Commando Raid (1982) (U.S. Games)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f473f99e47d4026a7a571184922ebf04", "Philip R. Frey", "", "Donkey Claus (Philip R. Frey) (Hack)", "Hack of Donkey Kong", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f48022230bb774a7f22184b48a3385af", "Atari, Rob Fulop - Sears", "CX2633 - 49-75119", "Night Driver (1980) (Atari) (4K)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "AUTO 65", "", "", "YES", "" }, - { "f48735115ec302ba8bb2d2f3a442e814", "", "", "Dancing Plate (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "f49a34f1fdd7dc147cbf96ce2ce71b76", "", "", "Qb (Special Edition) (PAL) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "f4a09f906cc37be31224433f576d77d3", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Atari Trak-Ball Hack v1.2 (PAL) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f4ab6bd5f80d8988141edde4c84b23b5", "Atari, Alan Miller", "CX2624, CX2624P", "Basketball (1978) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f4b8a47a95b61895e671c3ec86ffd461", "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart", "PB5540", "Star Wars - The Arcade Game (01-03-1984) (Parker Bros) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "f4c2e50b01dff99bddbe037b3489511c", "", "", "Hypnotic (V0.04) (2001) (Inkling) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f4c6621f1a0b4d27081123c08d7d1497", "CCE", "C-838", "Immies & Aggies (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f4cf6881b65c424095dc25dc987f151f", "", "", "128 in 1 Game Select ROM (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f4dabd5bcc603e8464a478208037d423", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (08-21-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f526d0c519f5001adb1fc7948bfbb3ce", "Mythicon, Bill Bryner, Bruce de Graaf", "MA1003", "Star Fox (1983) (Mythicon)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f52f40299fd238c6ffd9e6107050dc76", "Activision, Bob Whitehead - Ariola", "EAG-011, PAG-011 - 711 011-715", "Stampede (1981) (Activision) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f539e32bf6ce39c8ca47cb0cdd2c5cb8", "Control Video Corporation", "", "GameLine Master Module ROM (1983) (Control Video)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f542b5d0193a3959b54f3c4c803ba242", "Atari, Tom Rudadahl - Sears", "CX2634 - 49-75121", "Golf (1980) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f5445b52999e229e3789c39e7ee99947", "Atari, Jim Huether", "CX26163P", "Flag Capture (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f5a2f6efa33a3e5541bc680e9dc31d5b", "Suntek", "SS-022", "Motocross (1983) (Suntek) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f5a3e051730d45fea518f2e8b926565b", "Robby", "", "Keystone Kapers (Robby)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f5aa6bd10f662199c42e43863a30106c", "", "", "Music Kit (V1.0) - Song Player (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "f5d103a9ae36d1d4ee7eef657b75d2b3", "Starpath Corporation, Stephen H. Landrum", "9 AR-4105", "Official Frogger, The (Preview) (1983) (Starpath)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f613aad84d2163d6b197b220bfec1b7e", "", "", "X-Doom V.27 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f661f129644f338b13d9f4510d816c03", "Atari, David Crane", "CX26163P", "Outlaw (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f6676e3fe901eb8515fc7ae310302c3c", "Activision, David Crane", "AG-008", "Laser Blast (1981) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f67181b3a01b9c9159840b15449b87b0", "Atari, Nick 'Sandy Maiwald' Turner", "CX2665", "Frog Pond (08-27-1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f687ec4b69611a7f78bd69b8a567937a", "Activision, Alan Miller - Ariola", "EAZ-028 - 711 028-725", "Robot Tank (1983) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f69a39b215852a0c2764d2a923c1e463", "", "", "Move a Blue Blob Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f69bb58b815a6bdca548fa4d5e0d5a75", "Atari, Larry Kaplan", "CX26163P", "Bowling (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f69d4fcf76942fcd9bdf3fd8fde790fb", "CCE", "", "Aquaventure (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f6a282374441012b01714e19699fc62a", "ZiMAG - Emag - Vidco", "710-111 - GN-010", "I Want My Mommy (1983) (ZiMAG)", "AKA Open, Sesame!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "f6a9ea814d15b85bffe980c927df606b", "", "", "Missile Command (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "f6b5ebb65cbb2981af4d546c470629d7", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (09-13-1984) (Coleco) (Prototype) [a]", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f6c13e816e58c8c62f82b2c8b91a2d67", "", "", "Scrolling Playfield 2 (Junkosoft) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f6d512bef1bf253dc935d0e13c3d1462", "", "", "Slot Racers (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f6daebc0424fa0f8d9aaf26c86df50f4", "Brian Watson", "", "Color Tweaker (V1.0) (2001) (B. Watson)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f6efa00ae99aaf33e427b674bcfd834d", "", "", "2600 Digital Clock (Demo 3) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f6f1b27efc247a0e8d473ddb4269ff9e", "Rainbow Vision - Suntek", "SS-015", "Catch Time (1983) (Rainbow Vision) (PAL)", "AKA Plaque Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f70e3f3bb2d19ec2aaec8f78dc43744f", "Jone Yuan Telephonic Enterprise Co", "", "Pooyan (Jone Yuan) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f714a223954c28eccf459295517dcae6", "", "", "Big - Move This Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f7154add27b95cd90464dbed8cfd7557", "Fabrizio Zavagli", "", "Space Treat Deluxe (2003) (PAL)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f724d3dd2471ed4cf5f191dbb724b69f", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX2659", "Raiders of the Lost Ark (1982) (Atari)", "Console ports are swapped", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "" }, - { "f736864442164b29235e8872013180cd", "Telegames - VSS", "6057 A227", "Quest for Quintana Roo (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f73d2d0eff548e8fc66996f27acf2b4b", "CCE", "C-813", "Pitfall (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f7424985bac41067502b4a05b64cb75a", "Activision, Steve Cartwright", "AX-027", "Plaque Attack (1983) (Activision)", "Genesis controller (B is fire up, C is fire down)", "Hack of Plaque Attack", "", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "" }, - { "f74ad642552385c3daa203a2a6fc2291", "Eckhard Stolberg", "", "Cubis (1997) (Eckhard Stolberg)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f750b5d613796963acecab1690f554ae", "Manuel Polik", "", "Gunfight 2600 (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f75872946e82ad74d48eae5bc28f5f0e", "Sears Tele-Games, Jim Huether", "CX2614 - 49-75126", "Steeplechase (04-15-1980) (Sears) (Prototype)", "Uses the Paddle Controllers", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f777444fc21a5925e066b68b1d350575", "", "", "Marble Craze (Kernel Works) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f77f5fc3893da5d00198e4cd96544aad", "Canal 3 - Intellivision", "", "Stampede (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f7856e324bc56f45b9c8e6ff062ec033", "Atari, Jerome Domurat, Michael Sierchio", "CX2667", "RealSports Soccer (1983) (Atari) [no opening tune]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "f78c125b5da483c41e51522947d6c4ce", "", "", "Sound Paddle V1 (Dennis Caswell & Jim Nitchals) (PD)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "YES", "", "", "", "01", "", "", "", "" }, - { "f7a138eed69665b5cd1bfa796a550b01", "Tigervision - Teldec", "7-012 - 3.60016 VC", "Espial (1984) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f7a651972d78f9ba485b14690452d4be", "Paul Slocum", "", "Homestar Runner Demo #2 (2004-03-29)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f80cf77164079d774b9b0fae33dffca9", "", "", "Fu Kung! (V0.15) (Negative Version) (05-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f8240e62d8c0a64a61e19388414e3104", "Activision, Steve Cartwright", "AX-013", "Barnstorming (1982) (Activision)", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f825c538481f9a7a46d1e9bc06200aaf", "Atari, Richard Maurer - Sears", "CX2635 - 49-75157", "Maze Craze (1980) (Atari)", "AKA A Game of Cops 'n Robbers", "", "", "", "", "", "", "", "", "", "", "", "", "NTSC", "", "", "" }, - { "f844f4c6f3baaaf5322657442d6f29eb", "Atari, Sam Comstock, Richard Dobbis, Nick 'Sandy Maiwald' Turner", "CX26111", "Snoopy and the Red Baron (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f847fb8dba6c6d66d13724dbe5d95c4d", "Absolute Entertainment, David Crane", "AG-042-02, AG-042-04", "Skate Boardin' (1987) (Absolute)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f8582bc6ca7046adb8e18164e8cecdbc", "", "", "Panda Chase (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f8648d0c6ad1266434f6c485ff69ec40", "CCE", "", "Oink! (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f8811d45a9935cca90c62f924712f8e6", "Jone Yuan Telephonic Enterprise Co", "", "Chopper Command (Jone Yuan) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f8b2a6a4d73ebff10d805a9b59041986", "Activision, Larry Kaplan - Ariola", "EAX-006, PAX-006 - 771 006-720", "Bridge (1980) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f8bfd99163d2c4ec688357786e6fba28", "", "", "Eckhard Stolberg's Scrolling Text Demo 2 (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f8c1c4a41303bd40b0d6c81bfaf8573b", "HES", "773-891", "2 Pak Special - Dungeon Master, Creature Strike (1992) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f8fbe2b07345086fc867bceeaf38dc48", "Atari, Eric Manghise, Mimi Nyden, Joseph Tung", "CX2640", "RealSports Baseball (1982) (Atari) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f8ff34b53d86f55bd52d7a520af6d1dc", "", "", "Big Dig (04-04-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f90b5da189f24d7e1a2117d8c8abc952", "Atari, David Crane - Sears", "CX2653 - 6-99823, 49-75111", "Slot Machine (1979) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f91fb8da3223b79f1c9a07b77ebfa0b2", "Atari, Alan J. Murphy, Nick 'Sandy Maiwald' Turner - Sears", "CX2615 - 49-75140", "Demons to Diamonds (1982) (Atari)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "YES", "10 57", "", "", "", "" }, - { "f93d7fee92717e161e6763a88a293ffa", "20th Century Fox Video Games - Lazer Micro Systems - Dunhill Electronics, B. Winston Hendrickson, Randall Hyde, Mark V. Rhoads, John Simonds", "11013", "Porky's (1983) (20th Century Fox)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f9420173efcb4b9f2b01c2a7b595cca7", "CCE", "", "Laser Blast (CCE) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f954381f9e0f2009d1ac40dedd777b1a", "Thomas Jentzsch", "", "Robot City (V0.18) (01-09-2002) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f9655ed51462ecfc690c7b97cec649f9", "Andrew Wallace", "", "Laseresal 2002 (PAL) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f965cc981cbb0822f955641f8d84e774", "Answer Software Corporation - TY Associates, Kim Ellis", "ASC2001", "Confrontation (1983) (Answer) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "f9660ebed66fee8bdfdf07b4faa22941", "VGS", "", "Vanguard (VGS)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f9677b2ec8728a703eb710274474613d", "Atari, Ian Shepard", "CX2604, CX2604P", "Space War (1978) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f97dee1aa2629911f30f225ca31789d4", "Avalon Hill, Jean Baer, Bill 'Rebecca Ann' Heineman, Jim Jacob", "5005002", "Out of Control (1983) (Avalon Hill)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f98d2276d4a25b286135566255aea9d0", "Digitel", "", "Name This Game (1983) (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f98d869f287d2ce4f8fb36e0686929d9", "", "", "Skeleton+ (17-04-2003) (Eric Ball) (NTSC)", "", "", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f991e0670b5f67faa6b6211e9bd81b91", "Nukey Shay, Omegamatrix", "", "Double Dragon (Genesis) (PAL) V2", "Genesis controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f992a39b46aa48188fab12ad3809ae4a", "", "", "Sky Jinks (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f9967369943209b4788d4e92cefc0795", "Atari", "CX26163P", "Fishing (32 in 1) (1988) (Atari) (PAL) (4K)", "AKA Fishing Derby", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f9cef637ea8e905a10e324e582dd39c2", "CCE", "", "Private Eye (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f9d51a4e5f8b48f68770c89ffd495ed1", "Atari, Tod Frye, Mimi Nyden", "CX2657", "SwordQuest - FireWorld (1982) (Atari)", "AKA Adventure II, SwordQuest II - FireWorld", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f9da42f91a1c5cfa344d2ff440c6f8d4", "ZUT", "", "Pac Invaders (ZUT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f9de91d868d6ebfb0076af9063d7195e", "", "", "Maze Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "f9e99596345a84358bc5d1fbe877134b", "Activision, Larry Kaplan, David Crane - Ariola", "EAG-010, PAG-010 - 711 010-720", "Kaboom! (1981) (Activision) (PAL)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, - { "fa0570561aa80896f0ead05c46351389", "Tigervision", "7-008", "Miner 2049er (1983) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fa1b060fd8e0bca0c2a097dcffce93d3", "Atari - CCW, Christopher H. Omarzu, Preston Stuart, Bruce Williams", "CX26101", "Oscar's Trash Race (1984) (Atari)", "Uses the Keypad Controllers", "", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "" }, - { "fa2be8125c3c60ab83e1c0fe56922fcb", "Camelot - DSD, Michael Doherty, Clyde Hager - Johnson & Johnson", "", "Tooth Protectors (1983) (Camelot)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "fa3de71841c0841db6a741884a6b6b2f", "", "", "Warring Worms (17-02-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fa4404fabc094e3a31fcd7b559cdd029", "Atari, Alan J. Murphy, Robert C. Polaro", "CX26100", "Bugs Bunny (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fa529ec88eca679f6d5fd0ccb2120e46", "", "", "20 Sprites at Once Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fa6fe97a10efb9e74c0b5a816e6e1958", "ZiMAG - Emag - Vidco", "707-111 - GN-030", "Tanks But No Tanks (1983) (ZiMAG)", "AKA Phantom Tank", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fa7ce62e7fd77e02b3e2198d70742f80", "Atari, Peter C. Niday", "CX26108", "Donald Duck's Speedboat (04-18-1983) (Atari) (Prototype) (PAL)", "AKA Donald Duck's Regatta", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fa7e11a3dbea4365975cd2f094e61d25", "Tim Snider", "", "Mystery Science Theater 2600 (1999) (Tim Snider) (Hack)", "Hack of Megamania", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fa98d48cd609c9babc819e0a1bd8d598", "AtariAge (Chris Walton)", "", "Juno First (2009) (PAL60)", "AtariVox supported", "Homebrew", "", "", "", "", "", "", "", "", "ATARIVOX", "", "", "", "", "YES", "" }, - { "fab7b04b9f42df761eb6f2bc445eaa99", "20th Century Fox Video Games - Sirius Software, David Lubar", "11008", "Fantastic Voyage (11-04-1982) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fabca526d57de46768b392f758f1a008", "", "", "Laseresal 2600 (16-12-2001) (Andrew Wallace) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fac28963307b6e85082ccd77c88325e7", "CCE", "", "Berzerk (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fadb89f9b23beb4d43a7895c532757e2", "Galaga Games", "", "River Raid (1984) (Galaga Games) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fae0b86934a7c5a362281dffebdb43a0", "Retroactive", "", "Qb (2.07) (Retroactive) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "faebcb2ef1f3831b2fc1dbd39d36517c", "Atari, Jerome Domurat, Steve Woita", "CX2696", "Asterix (1984) (Atari) (PAL)", "AKA Taz", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "faed2ef6b44894f8c83f2b50891c35c6", "CCE", "", "Super Baseball (CCE)", "AKA RealSports Baseball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "faffd84f3a8eceee2fa5ea5b0a3e6678", "Suntek", "SS-025", "Spectracube Invasion (1983) (Suntek) (PAL)", "AKA Immies & Aggies", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fb09ee4ccd47ae74a3c314f0d8a40344", "", "", "Titans (SnailSoft)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fb0c32ef7af5b45486db663510094be8", "", "", "Demo Image Series #15 - Three Marios (NTSC) (Non-Interleave) (06-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fb0e84cee4c108d24253bcb7e382cffd", "", "", "Interleaved ChronoColour Demo (SECAM) (05-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fb27afe896e7c928089307b32e5642ee", "M Network - INTV - APh Technological Consulting, Jeff Ronne, Brett Stutz", "MT5662", "TRON - Deadly Discs (1983) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fb4ca865abc02d66e39651bd9ade140a", "Arcadia Corporation, Brian McGhie", "AR-4104", "Rabbit Transit (1983) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fb531febf8e155328ec0cd39ef77a122", "", "", "Worm War I (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "fb5c8af97bd8ffe88323656f462645a7", "", "", "Interlace Demo (Glenn Saunders)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "fb833ed50c865a9a505a125fc9d79a7e", "ITT Family Games", "", "Pumuckl I (1983) (ITT Family Games) (PAL)", "AKA Panda Chase", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fb884ffd89013331a6f01ae3f6abd214", "Activision, David Crane", "", "Venetian Blinds Demo (1982) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fb88baa01afd34e0e4b601e1d29bc806", "Manuel Polik", "", "Star Fire (2003) (XYPE)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fb88c400d602fe759ae74ef1716ee84e", "20th Century Fox Video Games, Bill Aspromonte", "11031", "Crash Dive (1983) (20th Century Fox)", "AKA Voyage to the Bottom of the Sea", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fb91da78455d9b1606913fbf8c859772", "", "", "Split Screen (Ballblazer) Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fb91dfc36cddaa54b09924ae8fd96199", "Parker Brothers, Mark Lesser", "PB5590", "Frogger II (1984) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "fb978f1c053e8061cc37a726639f43f7", "Atari - Axlon, Tod Frye - Heuristica, Agustin Ortiz", "CX26169", "Shooting Arcade (03-07-1989) (Atari) (Prototype)", "Uses the Light Gun Controller (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fbac6476e7b2b20d246202af81662c88", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (Preview) (1982) (Starpath) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fbb0151ea2108e33b2dbaae14a1831dd", "Thomas Jentzsch", "", "Robot Tank TV (Thomas Jentzsch) (Hack)", "Uses two simultaneous Joystick Controllers, Hack of Robot Tank", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fbb4f3debf48dc961b559384467f2057", "Digitel", "", "River Raid III (1985) (Digitel)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fbe554aa8f759226d251ba6b64a9cce4", "Atari - GCC, Mike Feinstein, Brad Rice", "CX2681, CX2681P", "Battlezone (1983) (Atari) (PAL)", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fbfebee9c14694719e3eda4854dc42ee", "Jake Patterson", "", "Baubles 3 (Jake Patterson) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fc2104dd2dadf9a6176c1c1c8f87ced9", "Coleco - Woodside Design Associates, Harley H. Puthuff Jr.", "2663", "Time Pilot (1983) (Coleco)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fc2233fc116faef0d3c31541717ca2db", "Atari, Tod Frye", "CX2646", "Pac-Man (1982) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fc24a94d4371c69bc58f5245ada43c44", "Atari - Axlon, Steve DeFrisco", "CX26170", "Secret Quest (1989) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fc6052438f339aea373bbc999433388a", "Atari, David Crane", "CX2653P", "Slot Machine (1979) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fc668a2251dd79cbd903d4fa0e558f96", "Thomas Jentzsch", "", "Thrust (V1.1) (2000) (TJ) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fc92d74f073a44bc6e46a3b3fa8256a2", "", "", "Megademo (19xx) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fc9c1652fe3a2cade6188f4d3692481f", "Andrew Davies", "", "Andrew Davies early notBoulderDash demo (NTSC)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "fca4a5be1251927027f2c24774a02160", "Activision, John Van Ryzin", "AZ-036-04", "H.E.R.O. (1984) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fcbbd0a407d3ff7bf857b8a399280ea1", "ZiMAG - Emag - Vidco", "GN-070", "Mysterious Thief, A (1983) (ZiMAG) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "fcbdf405f0fc2027b0ea45bb5af94c1a", "Amiga - Video Soft, Michael K. Glass, Jerry Lawson", "", "3-D Ghost Attack (1983) (Amiga) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "fcea12625c071ddc49f4e409f4038c60", "Fabrizio Zavagli", "", "Balls! (16-09-2002) (Fabrizio Zavagli)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, - { "fcf8e306f6615f74feba5cb25550038c", "", "", "Blue Dot Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fd0e5148162e8ec6719445d559f018a9", "Activision, Steve Cartwright - Ariola", "EAX-022, EAX-022-04I - 711 022-720", "Seaquest (1983) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fd10915633aea4f9cd8b518a25d62b55", "Atari, John Dunn", "CX2631, CX2631P", "Superman (1979) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fd16949913aaab5beaefed73bf2ca67c", "Atari - GCC, John Allred, Mike Feinstein", "CX2688", "Jungle Hunt (02-03-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fd4f5536fd80f35c64d365df85873418", "Atari - Bobco, Robert C. Polaro", "CX26140", "Desert Falcon (1987) (Atari)", "AKA Nile Flyer, Sphinx", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fd6e507b5df68beeeddeaf696b6828fa", "", "", "Boxing (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fd7464edaa8cc264b97ba0d13e7f0678", "HES", "771-333", "2 Pak Special - Challenge, Surfing (1990) (HES) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fd78f186bdff83fbad7f97cb583812fe", "Amiga - Video Soft", "3125", "Surf's Up (1983) (Amiga) (Prototype) [a2]", "Uses the Joyboard controller", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fd8b4ee0d57605b35e236e814f706ff1", "Atari - GCC, Mike Feinstein, John Mracek", "CX2673, CX2673P", "Phoenix (1982) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fd9b321cee5fbb32c39ba3ca5d9ec7cf", "Jeffry Johnston", "", "Radial Pong - Version 5 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fdd4995a50395db14f518f63c2d63438", "", "", "Oh No! (Version 3) (18-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fde42e39710e75e9e4d4d75440f8e4e5", "Thomas Jentzsch", "", "Coke Zero (v1.0) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fdf0de38517e0cf7f0885f98ccc95836", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (2 of 4) (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fdf6680b2b1e8054293a39700a765692", "", "", "Alpha Demo - The Beta Demo 2 (2000) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fe0b7f27e3ad50bbf9ff468ee56d553d", "", "", "Lines Demo (Eckhard Stolberg) (PAL) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fe0bc4bb92c1c4de7d5706aaa8d8c10d", "", "", "Sprite Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fe3b461d4c8b179fe68bc77760294c25", "Atari, Joe Decuir", "CX2621, CX2621P", "Video Olympics (1977) (Atari) (PAL) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "YES", "", "", "", "", "" }, - { "fe641247a4ab9bee970e19ab55f23b25", "20th Century Fox Video Games, Beck-Tech, Steve Beck", "11035", "Save the Whales (02-07-1983) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fe67087f9c22655ce519616fc6c6ef4d", "Atari - Zip Technology, Randy Bowker, Bruce Williams", "CX26142", "Crack'ed (11-28-1988) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fe6abc0f63e31e2646c9c600926b5b7f", "Atari", "CX26137", "4 in 1 (02-19-1987) (Atari) (Prototype)", "Home Run, Canyon Bomber, Sky Diver, Night Driver", "Prototype", "", "", "4IN1", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fe870018332a0221eb59fb18b0c6bccc", "", "", "Incoming (08-11-2002) (Ben Larson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fe9ae625d924b54c9f8a14ac9a0f6c6d", "BG Dodson", "", "High Bid! (BG Dodson) (Hack)", "Hack of Pepsi Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "feba8686fd0376015258d1152923958a", "", "", "Super Circus (Unknown) (PAL)", "AKA Circus Atari", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fec0c2e2ab0588ed20c750b58cf3baa3", "Activision - Cheshire Engineering, David Rolfe, Larry Zwick", "EAZ-037-04, EAZ-037-04I", "Beamrider (1984) (Activision) (PAL)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "fece458a8023a809a5006867feca40e8", "", "", "SCSIcide (24-02-2001) (Joe Grand) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "feec54aac911887940b47fe8c9f80b11", "Atari, Rob Fulop", "CX2633, CX2633P", "Night Driver (1980) (Atari) (PAL)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "AUTO 65", "", "", "YES", "" }, - { "feedcc20bc3ca34851cd5d9e38aa2ca6", "Atari, David Crane - Sears", "CX2607 - 6-99828, 49-75115", "Canyon Bomber (1979) (Atari)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "YES", "10", "", "", "", "" }, - { "ff1523783e0e76a3b0d1f7f0d1cb3050", "Thomas Jentzsch", "", "Marble Craze - Atari Trak-Ball Hack v1.0 (PAL) (TJ)", "Uses Atari Trak-Ball Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ff3bd0c684f7144aeaa18758d8281a78", "Atari, Bob Whitehead", "CX2651", "Blackjack (1977) (Atari) (PAL)", "Uses the Paddle Controllers", "Rare", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "", "", "" }, - { "ff5a9e340d96df6f5a5b6eb038e923bd", "", "", "Space Shuttle (1983) (Activision) [t1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ff7627207e8aa03730c35c735a82c26c", "Atari, Bob Whitehead", "CX26163P", "Blackjack (32 in 1) (1988) (Atari) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "", "", "" }, - { "ff86fc8ffa717bb095e8471638c1c31c", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix - Bop a Buggy (1 of 3) (1983) (Arcadia) (PAL)", "Uses Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "01 56", "", "", "", "" }, - { "ff87d58125ae517eb7b09a0475a1ccdc", "", "", "SCSIcide (Score Hack 1) (24-02-2001) (Joe Grand) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ffb1cd548563158ce33f9d10268187e7", "Erik Eid", "", "Euchre (Beta) (NTSC) (12-09-2002) (Erik Eid)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ffc0ff4305dd46b4b459885bd1818e2e", "Barry Laws Jr.", "", "Star Wars - The Battle of Alderaan (Star Strike Hack)", "Hack of Star Strike (Mattel)", "New Release (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ffdc0eb3543404eb4c353fbdddfa33b6", "CCE", "C-827", "Chopper Command (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ffe51989ba6da2c6ae5a12d277862e16", "Atari - Sears", "CX2627 - 6-99841", "Human Cannonball (1979) (Atari) (4K)", "AKA Cannon Man", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "ffebb0070689b9d322687edd9c0a2bae", "", "", "Spitfire Attack (1983) (Milton Bradley) [h1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" } +static const BSPF::array2D DefProps = {{ + { "000509d1ed2b8d30a9d94be1b3b5febb", "Greg Zumwalt", "", "Jungle Jane (2003) (Greg Zumwalt) (Hack)", "Hack of Pitfall!", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0060a89b4c956b9c703a59b181cb3018", "CommaVid, Irwin Gaines - Ariola", "CM-008 - 712 008-720", "Cakewalk (1983) (CommaVid) (PAL)", "AKA Alarm in der Backstube", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "007d18dedc1f0565f09c42aa61a6f585", "CCE", "C-843", "Worm War I (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "008543ae43497af015e9428a5e3e874e", "Retroactive", "", "Qb (V2.09) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "00b7b4cbec81570642283e7fc1ef17af", "SEGA - Beck-Tech, Steve Beck, Phat Ho", "006-01", "Congo Bongo (1983) (SEGA)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "00ce0bdd43aed84a983bef38fe7f5ee3", "20th Century Fox, Bill Aspromonte", "11012", "Bank Heist (1983) (20th Century Fox)", "AKA Bonnie and Clyde, Cops 'n' Robbers, Holdup, Rooring 20's", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "00ce76ad69cdc2fa36ada01ae092d5a6", "Bit Corporation", "PGP214", "Cosmic Avenger (4 Game in One) (1983) (BitCorp) (PAL)", "AKA StarMaster", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "00dc28b881989c39a6cf87a892bd3c6b", "CCE", "", "Krull (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "00e19ebf9d0817ccfb057e262be1e5af", "Atari, Ed Logg, Carol Shaw", "CX2639, CX2639P", "Othello (1981) (Atari) (PAL) [no grid markers]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "00e55b27fe2e96354cd21b8b698d1e31", "", "", "Phoenix (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "00eaee22034aff602f899b684c107d77", "Rainbow Vision - Suntek - Sunteck Corp", "SS-001", "Time Race (1983) (Rainbow Vision) (PAL)", "AKA Space Jockey", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "00f7985c20b8bdf3c557fac4d3f26775", "Aaron Curtis", "", "AStar (NTSC)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "012020625a3227815e47b37fd025e480", "Rob Kudla", "", "Better Space Invaders (1999) (Rob Kudla) (Hack) [a]", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "01293bd90a4579abb7aed2f7d440681f", "Century", "", "Snoopy (1983) (Century) (PAL)", "AKA Snoopy and the Red Baron", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "01297d9b450455dd716db9658efb2fae", "TechnoVision - Video Technology", "TVS1002", "Save Our Ship (1983) (TechnoVision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "012b8e6ef3b5fd5aabc94075c527709d", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix (1983) (Arcadia)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "01 56", "", "", "", "" }, + { "0164f26f6b38a34208cd4a2d0212afc3", "Coleco, Ed English", "2656", "Mr. Do! (1983) (Coleco)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "0173675d40a8d975763ee493377ca87d", "CBS Electronics, Ed English", "4L1751", "Roc 'n Rope (1984) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "01abcc1d2d3cba87a3aa0eb97a9d7b9c", "Jone Yuan Telephonic Enterprise Co", "", "Topy (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "01b09872dcd9556427761f0ed64aa42a", "Galaga Games", "", "River Raid (1984) (Galaga Games)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "01cb3e8dfab7203a9c62ba3b94b4e59f", "Atari, Mimi Nyden, Scott Smith, Robert Vieira", "CX26127", "Gremlins (1984) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "01e5c81258860dd82f77339d58bc5f5c", "CCE", "", "Corrida da Matematica (CCE)", "AKA Math Gran Prix", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "01e60a109a6a67c70d3c0528381d0187", "ITT Family Games, Perry Rhodan-Serie", "554-33 383", "Fire Birds (1983) (ITT Family Games) (PAL)", "AKA Sky Alien", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "01f584bf67b0e464014a8c8b5ea470e3", "Arcadia Corporation, Dennis Caswell", "5 AR-4200", "Labyrinth (Escape from the Mindmaster Beta) (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "02066b17f29082412c6754c1a2d6302e", "", "", "Demo Image Series #3 - Baboon (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "024365007a87f213cbe8ef5f2e8e1333", "Atari, Frank Hausman, Mimi Nyden, Steve Woita", "CX2686", "Quadrun (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "025668e36a788e8af8ac4f1be7e72043", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX2659", "Raiders of the Lost Ark (06-14-82) (Atari) (Prototype)", "Console ports are swapped", "Prototype", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "", "" }, + { "026180bf641ff17d8577c33facf0edea", "Activision, Steve Cartwright", "AX-022", "Seaquest (1983) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0277c449fae63f6f1c8f94dedfcf0058", "", "", "Laser Demo (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "027a59a575b78860aed780b2ae7d001d", "CCE", "", "Pressure Cooker (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "028024fb8e5e5f18ea586652f9799c96", "Coleco - Woodside Design Associates, Steve 'Jessica Stevens' Kitchen", "2468", "Carnival (1982) (Coleco)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "02811151906e477d47c135db5b1699c6", "", "", "FlickerSort Demo (Updated) (20-04-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "02a5fc90a0d183f870e8eebac1f16591", "HES", "771-422", "2 Pak Special - Star Warrior, Frogger (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "02ab2c47bc21e7feafa015f90d7df776", "Atari", "MA017600", "Diagnostic Test Cartridge 2.6 (1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "02ced7ea2b7cb509748db6bfa227ebec", "Parker Brothers, Ed English, David Lamkins", "931502", "Frogger (1982) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "02cee0b140d2f1a1efcfb1d482a5c392", "Atari, Ed Logg, Carol Shaw - Sears", "CX2639 - 49-75162", "Othello (1981) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "02dcba28c614fec7ca25955327128abb", "Andrew Wallace", "", "Laseresal 2002 (PAL) (PD) [a]", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "02e3f4ba156fb578bef7d7a0bf3400c1", "", "", "Booster (Junkosoft) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "033e21521e0bf4e54e8816873943406d", "20th Century Fox Video Games - Sirius Software, Dan Thompson", "11020", "Earth Dies Screaming, The (1983) (20th Century Fox)", "The Day the Earth Stood Still", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "034c1434280b0f2c9f229777d790d1e1", "Telegames", "5665 A016", "Baseball (1988) (Telegames) (PAL)", "AKA Super Challenge Baseball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0375f589f7da06d2d2be532e0d4d4b94", "", "", "Push (V0.04) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0383dc02cb82302da3d155fd108bfe3a", "AtariAge, Chris Spry", "CX26200", "Princess Rescue (2013) (Sprybug) (PAL60)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "JOYSTICK", "", "", "", "", "", "", "", "YES", "" }, + { "038e1e79c3d4410defde4bfe0b99cc32", "Atari, Tod Frye, Gary Shannon", "", "Aquaventure (08-12-1983) (Atari) (Prototype)", "AKA Sea Sentinel", "Unbelievably Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "039cf18b459d33b8a8fca31d06c4c244", "", "", "Demo Image Series #0 (12-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "03b1051c9374678363c899914412cfc5", "", "", "Incoming (30-10-2002) (Ben Larson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "03c3f7ba4585e349dd12bfa7b34b7729", "SEGA, Jeff Lorenz", "004-01", "Star Trek - Strategic Operations Simulator (1983) (SEGA)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "03fbcee0bc80e31f27254aea3d920510", "Bit Corporation", "R320", "Trick Shot (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "03ff9e8a7af437f16447fe88cea3226c", "Bomb - Onbase", "CA285", "Wall-Defender (1983) (Bomb)", "AKA Wall Break", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "04014d563b094e79ac8974366f616308", "Atari, Andrew Fuchs, Courtney Granner, Jeffrey Gusman, Mark R. Hahn", "CX2690", "Pengo (1984) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "041b5e56bbc650db574bd8db3fae2696", "Thomas Jentzsch", "", "Thrust (V1.0) (2000) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "043f165f384fbea3ea89393597951512", "Spectravision - Spectravideo", "SA-202", "Planet Patrol (1982) (Spectravision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0443cfa9872cdb49069186413275fa21", "M Network - INTV, Patricia Lewis Du Long, Ron Surratt", "MT4518", "BurgerTime (1983) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "045035f995272eb2deb8820111745a07", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (1983) (Arcadia)", "AKA Jungle Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "047ac3b9faea64522b7a23c4465a7aa8", "", "", "Defender (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "04856e3006a4f5f7b4638da71dad3d88", "Atari, Douglas Neubauer", "CX26176", "Radar Lock (1989) (Atari) (PAL)", "AKA Dog Fight", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "049626cbfb1a5f7a5dc885a0c4bb758e", "", "", "MegaMania (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "04b488d4eef622d022a0021375e7e339", "Home Vision - Gem International Corp. - VDI", "VCS83107", "Tennis (1983) (Home Vision) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "04cf9e6898007024622ed6a0b295961f", "Bit Corporation", "R320", "Tennis (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "04dfb4acac1d0909e4c360fd2ac04480", "Thomas Jentzsch", "", "Jammed (2001) (XYPE) (NTSC)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "04e737c9d53cd84bfd5ee679954e4706", "Jone Yuan Telephonic Enterprise Co", "", "Checkers (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "04fccc7735155a6c1373d453b110c640", "HES - Imagineering, David Lubar", "535", "My Golf (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0519f395d5f7d76be813b834aa51c0be", "Atari, Ian Shepard", "CX2604", "Space War (1978) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0546f4e6b946f38956799dd00caab3b1", "Thomas Jentzsch", "", "My Golf (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "056f5d886a4e7e6fdd83650554997d0d", "Parker Brothers, Ed Temple", "931504", "Amidar (1982) (Parker Bros) (PAL)", "", "Uncommon", "", "", "", "A", "A", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "056ff67dd9715fafa91fb8b0ddcc4a46", "", "", "Frisco (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "05824fcbe615dbca836d061a140a50e0", "Jeffry Johnston", "", "Radial Pong - Version 9 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "05aedf04803c43eb5e09dfd098d3fd01", "", "", "Keystone Kapers (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "05aff8f626ef870432ae3b3d9d5aa301", "Activision, Bob Whitehead", "AG-019", "Sky Jinks (1982) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "05b45ba09c05befa75ac70476829eda0", "Parker Brothers, Rex Bradford", "931507", "Star Wars - Jedi Arena (1983) (Parker Bros) (PAL)", "Uses the Paddle Controllers (swapped)", "", "", "", "", "", "", "", "", "", "", "YES", "", "", "10 50", "", "", "", "" }, + { "05c60458ec69e7fe8b1be973852d84f1", "", "", "Test (1996) (J.V. Matthews) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "05c765a63e61882abd1c2d627b652225", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Amiga Mouse Hack v1.1 (NTSC) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "05ccf96247af12eef59698f1a060a54f", "Otto Versand", "600273", "King Arthur (1983) (Otto Versand) (PAL)", "AKA Dragonfire (Double-Game Package)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "05d61b925d3d2474bab83f0a79bb5df1", "Eckhard Stolberg", "", "Cosmic Ark Stars (1997) (Eckhard Stolberg)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "05eb4347f0ec8f4783983ca35ffd8d1b", "", "", "Qb (2.06) (Retroactive) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "05ebd183ea854c0a1b56c218246fbbae", "Atari, Dan Hitchens", "CX2656", "SwordQuest - EarthWorld (1982) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "05f11fb2e45c4e47424d3cb25414d278", "", "", "Boring (NTSC) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "060c865c782debb047e6fd101c8923fc", "Atari", "CX26163P", "Freeway Rabbit (32 in 1) (1988) (Atari) (PAL) (4K)", "AKA Freeway", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0614ed51acd027d531e7c85c4f435292", "", "", "Narnia (Glenn Saunders) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0619e1c3286bbfbace040b8c3ec5add2", "Omegamatrix", "", "Millipede (Atari Trak-Ball) v6.5 (Omegamatrix)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "0651216c4a4a9c9ac5ada3013a317c72", "Jone Yuan Telephonic Enterprise Co", "", "Fishing Derby (Jone Yuan) (4K) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "06742cf522f23797157f215a1dc8a1a9", "", "", "Healthbars (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0685bd0bcb975ceef7041749a5454a48", "Piero Cavina", "", "11 Sprite Demo (Piero Cavina) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "069c17beb1e8e0557adb8539fdcf6cba", "", "", "Phantom II & Pirate (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "06b0194ce992584c365278e0d7323279", "Activision", "", "Unknown Activision Game #2 (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "06b6c5031b8353f3a424a5b86b8fe409", "Activision, Mike Lorenzen - Ariola", "EAX-023 - 711 023-720", "Oink! (1983) (Activision) (PAL)", "AKA Das Schweinchen und der Wolf", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "06cfd57f0559f38b9293adae9128ff88", "Telegames", "4317 A009", "Adventures on GX-12 (1988) (Telegames) (PAL)", "AKA Adventures of Tron", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "06d2f7674cea977607f74c464ce600a2", "CBS Electronics, Alex Nevelson", "4L 2737 0000", "Omega Race (1983) (CBS Electronics) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "BOOSTERGRIP", "", "", "", "", "", "", "", "", "" }, + { "06db908011065e5ebb37f4e253c2a0b0", "", "", "Gopher (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "06e5dc181a8eda1c31cc7c581c68b6ef", "", "", "Tac-Scan (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "071f84d10b343c7c05ce3e32af631687", "Rainbow Vision - Suntek", "SS-019", "Curtiss (1983) (Rainbow Vision) (PAL)", "AKA Atlantis", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "072a6ea2181ca0df88ac0dedc67b239d", "", "", "Multiple Missiles Demo (19-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "073cb76b006af034fd150be3f5e0e7e6", "", "", "Mobile 48 Sprite Kernel (Bug Fixed) (10-01-2003) (Eric Ball)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "073d7aff37b7601431e4f742c36c0dc1", "", "", "Bermuda (Unknown) (PAL)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "074ec425ec20579e64a7ded592155d48", "Atari - Sculptured Software, Steve Aguirre", "CX26162", "Fatal Run (Ultimate Driving) (1991) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "075069ad80cde15eca69e3c98bd66714", "CCE", "C-803", "Bobby Is Going Home (1983) (CCE)", "AKA Bobby Vai Para Casa", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0751f342ee4cf28f2c9a6e8467c901be", "Atari, Mimi Nyden, Joseph Tung", "CX26152", "Super Baseball (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "07973be3ecfd55235bf59aa56bdef28c", "Suntek", "SS-036", "Criminal Pursuit (1983) (Suntek) (PAL)", "AKA A Mysterious Thief", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "079fe9103515d15bc108577e234a484d", "", "", "Multi-Color Demo 0 (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "07a3af1e18b63765b6807876366f5e8a", "Joe Grand", "", "SCSIcide Pre-release 2 (Joe Grand)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "07c76f2d88552d20ad2c0ed7aef406c6", "Cody Pittman", "", "Blob (Cody Pittman) (Hack)", "Hack of Halloween", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "07f42847a79e4f5ae55cc03304b18c25", "Zellers", "", "Sea Hawk (Zellers)", "AKA Seahawk", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "07f84db31e97ef8d08dc9fa8a5250755", "Supergame", "", "Enduro (1984) (Supergame)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "07f91e33e76f53bb9d2731fd5d8a35a5", "Atari", "CX2632", "Space Invaders (1978) (Atari) [t1]", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0805366f1b165a64b6d4df20d2c39d25", "Atari, Dan Hitchens", "CX2650", "Berzerk (1982) (Atari) (PAL)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "08188785e2b8300983529946dbeff4d2", "Atari, Carla Meninsky, Ed Riddle - Sears", "CX2611 - 99821, 49-75149", "Indy 500 (1977) (Atari) (4K)", "Uses the Driving Controllers", "", "", "", "", "", "", "", "", "DRIVING", "DRIVING", "", "", "", "45", "", "", "", "" }, + { "081e2c114c9c20b61acf25fc95c71bf4", "Parker Brothers, Ed English, David Lamkins", "PB5300", "Frogger (1982) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "082fdc8bd47fef01482ce5883c4ffdb8", "Charles Morgan", "", "Tanks DX (Charles Morgan) (Hack)", "Hack of Tanks But No Tanks", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0832fb2ee654bf9382bc57d2b16d2ffc", "Apollo - Games by Apollo, Ed Salvo", "AP-1001", "Skeet Shoot (1981) (Apollo) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "083e7cae41a874b2f9b61736c37d2ffe", "Imagic, Rob Fulop, Bob Smith", "720106-2A, IA3600P, EIX-009-04I", "Riddle of the Sphinx (1982) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "085322bae40d904f53bdcc56df0593fc", "Parker Brothers, Dave Engman, Dawn Stockbridge", "PB5340", "Tutankham (1983) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0856f202b18cd46e44fd1dc3b42e9bfb", "", "", "Frame Counter 1 (2001) (Jake Patterson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0866e22f6f56f92ea1a14c8d8d01d29c", "Androbot - Western Technologies, Michael Case, Lenny Carlson", "", "AndroMan on the Moon (1984) (Western Tech) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0891252ee4e307689febccf3cfd8a8ab", "Thomas Jentzsch", "", "Centipede - Atari Trak-Ball Hack v1.4 (PAL60) (Half-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0894aa7be77521f9df562be8d9555fe6", "CBS Electronics, Dan Kitchen, Garry Kitchen", "4L1700, 4L1701, 4L1702, 4L1802, 4L2274", "Donkey Kong (1982) (CBS Electronics) (PAL) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "08989fa4ff537f5dbd611aff4019521a", "Atari, Gary Palmer", "CX26163P", "Fun with Numbers (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "08bd4c1dcc843f6a0b563d9fd80b3b11", "Quelle", "343.273 9", "Phantompanzer II (1983) (Quelle) (PAL)", "AKA Thunderground", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "08bf437d012db07b05ff57a0c745c49e", "Arcadia Corporation, Steve Hales, Stephen H. Landrum", "4 AR-4102", "Meteoroids (1982) (Arcadia) (Prototype)", "Suicide Mission Beta", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "08d1b6d75206edb999252caf542a2c7f", "Larry Petit", "", "Super Home Run (2003) (Larry Petit) (Hack)", "Hack of Home Run", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "08d60a58a691c7f690162850302dc0e1", "", "", "Poker Squares (V0.27) (PAL) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "08e5960bb52d9a3e2c9954677b5e4472", "Atari - CCW, Christopher H. Omarzu, Preston Stuart, Bruce Williams", "CX26101", "Oscar's Trash Race (10-20-1982) (Atari) (Prototype)", "Uses the Keypad Controllers", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "08ea2fdaa22e5802c839ee7dfb0483dc", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Atari Trak-Ball Hack v1.2 (PAL60) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "08f4dc6f118f7c98e2406c180c08e78e", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix - Tug of War (2 of 3) (1983) (Arcadia) (PAL)", "Uses Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "02", "", "", "", "" }, + { "08f853e8e01e711919e734d85349220d", "Atari, Jerome Domurat, Michael Sierchio", "CX2667", "RealSports Soccer (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0906c6e0e4bda9c10cfa4c5fc64d2f4b", "Retroactive", "", "Qb (V0.12) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "090f0a7ef8a3f885048d213faa59b2f8", "Carrere Video - Western Technologies, John Hall - Teldec - Prism", "USC1012", "M.A.D. (1983) (Carrere Video) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "09274c3fc1c43bf1e362fda436651fd8", "Thomas Jentzsch", "", "Acid Drop (TJ)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "09388bf390cd9a86dc0849697b96c7dc", "Absolute Entertainment, Alex DeMeo", "AG-045-04, AK-045-04", "Pete Rose Baseball (1988) (Absolute)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0945081a6bd00345ff3d58eb7a07330a", "", "", "Stampede (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0956285e24a18efa10c68a33846ca84d", "Dismac", "", "Viagem Espacial (Dismac)", "AKA Star Voyager", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0963aa9f7f6cf5a36ff700001583624e", "Franklin Cruz", "", "Space Invaders 2 (Hack) [o1]", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "096649575e451508006b17e0353259a5", "Justin J. Scott", "", "Yar Vs. Yar (2002) (Justin J. Scott) (Hack)", "Hack of Yars' Revenge", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "097074f24cde141fe6a0f26a10333265", "", "", "Marble Craze (V0.90) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "097936b07e0e0117b9026ae6835eb168", "Imagic, Dennis Koble", "720100-2B, IA3000P", "Trick Shot (1982) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "09abfe9a312ce7c9f661582fdf12eab6", "Atari, Douglas Neubauer", "CX26154", "Super Football (1988) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "09e1ecf9bd2a3030d5670dba7a65e78d", "Atari, James Andreasen", "CX2654", "Haunted House (1982) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "09e9ba0762fd0c3cf3c2e072cff79cac", "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart", "PB5540", "Star Wars - The Arcade Game (1984) (Parker Bros) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "09f89bbfa2ab00f1964d200e12d7ced0", "Atari", "MA017600", "Diagnostic Test Cartridge 2.6 (1982) (Atari) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0a1b98937911d621b004b1617446d124", "", "", "Hangman Pac-Man Biglist1 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0a981c03204ac2b278ba392674682560", "Atari, Bob Whitehead - Sears", "CX2651 - 99805, 49-75602", "Blackjack (1977) (Atari)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "", "", "", "", "" }, + { "0aa208060d7c140f20571e3341f5a3f8", "U.S. Games Corporation - Western Technologies, Jeff Corsiglia, Paul Allen Newell, Tom Sloper", "VC1009", "Towering Inferno (1982) (U.S. Games)", "Uses the Joystick Controllers (swapped)", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "YES", "" }, + { "0abf64ca504a116adca80f77f85e00fb", "", "", "Cube Conquest (Billy Eno) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0ac0d491763153fac75f5337ce32a9d6", "", "", "SPAM Image Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0acaf71e60b89f6b6eab63db6ab84510", "", "", "This Planet Sucks (Greg Troutman) [a2]", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0aceb7c3bd13fe048b77a1928ed4267d", "Imagic, Bob Smith", "720102-2B, IA3201P, EIX-011-04I", "Star Voyager (1982) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0ad9a358e361256b94f3fb4f2fa5a3b1", "Atari, Carol Shaw, Nick 'Sandy Maiwald' Turner - Sears", "CX2608 - 49-75165", "Super Breakout (1982 - 1981) (Atari) [a]", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "", "", "01 45", "", "", "", "" }, + { "0adb21206de92e8aec5ef295805ebb90", "", "", "Solaris (Genesis)", "Genesis controller (C switches to map mode)", "Hack of Solaris", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0ae3497e731ca0bf6a77b23441d9d9f9", "", "", "Analog Clock (V0.0) (20-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0af51ceb4aecc7a8fc89781ac44a1973", "Barry Laws Jr.", "", "Face Invaders Deluxe (Barry Laws Jr.) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0afe6ae18966795b89314c3797dd2b1e", "Atari - GCC, Mark Ackerman, Noellie Alito", "CX2692, CX2692P", "Moon Patrol (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0b01909ba84512fdaf224d3c3fd0cf8d", "", "", "Revenge of the Apes (Hack)", "Hack of Planet of the Apes", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0b1056f1091cfdc5eb0e2301f47ac6c3", "Tigervision - Software Electronics Corp., Karl T. Olinger - Teldec", "7-001 - 3.60001 VE", "King Kong (1982) (Tigervision) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0b17ed42984000da8b727ca46143f87a", "Atari - CCW, Christopher H. Omarzu", "CX26104", "Big Bird's Egg Catch (05-17-1983) (Atari) (Prototype)", "Uses the Keypad Controller", "Prototype", "", "", "", "", "", "", "", "KEYBOARD", "", "", "", "", "", "", "", "", "" }, + { "0b24658714f8dff110a693a2052cc207", "CCE", "C-815", "Seaquest (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0b33252b680b65001e91a411e56e72e9", "CCE", "C-832", "Atlantis (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0b4e793c9425175498f5a65a3e960086", "CCE", "", "Kung Fu Master (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0b55399cf640a2a00ba72dd155a0c140", "Imagic, Wilfredo Aguilar, Michael Becker, Rob Fulop", "720111-1A, 03205", "Fathom (1983) (Imagic)", "AKA Scuba", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "0b577e63b0c64f9779f315dca8967587", "Videospielkassette - Ariola", "PGP236", "Raketen-Angriff (Ariola) (PAL)", "AKA Missile Control", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0b8d3002d8f744a753ba434a4d39249a", "Sears Tele-Games, Robert Zdybel", "CX2619 - 49-75159", "Stellar Track (1981) (Sears)", "AKA Stella Trak", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "0bf19e40d5cd8aa5afb33b16569313e6", "Atari, Jerome Domurat, Andrew Fuchs, Dave Staugas, Robert Vieira", "CX26118", "Millipede (01-04-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0bf1e354304f46c0caf8fc0f6f5e9525", "Arcadia Corporation, Stephen Harland Landrum", "AR-4105", "Official Frogger (1983) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0bfabf1e98bdb180643f35f2165995d0", "Atari, Bob Whitehead - Sears", "CX2623 - 6-99819, 49-75108, 49-75125", "Home Run (1978) (Atari)", "", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "", "" }, + { "0c0392db94a20e4d006d885abbe60d8e", "", "", "Dodge Demo 3 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0c336f83b0e6e3bc86c77f368448e77b", "Bit Corporation", "R320", "Circus Atari (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0c35806ff0019a270a7acae68de89d28", "Froggo", "FG1003", "Task Force (1987) (Froggo)", "AKA Gangster Alley", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0c48e820301251fbb6bcdc89bd3555d9", "Atari, Bill Aspromonte, Andrew Fuchs", "CX26120", "Stargate (1984) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0c54811cf3b1f1573c9164d5f19eca65", "Activision, David Crane - Ariola", "EAG-001, PAG-001, EAG-001-04B, EAG-001-04I - 711 001-715", "Dragster (1980) (Activision) (PAL)", "AKA Dragster Rennen, Drag Strip", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0c72cc3a6658c1abd4b735ef55fa72e4", "Dion Olsthoorn", "v1.3", "Amoeba Jump (2018) (Dionoid) (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0c7926d660f903a2d6910c254660c32c", "Atari, Larry Kaplan", "CX2602, CX2602P", "Air-Sea Battle (1977) (Atari) (PAL)", "AKA Anti-Aircraft", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0c7bd935d9a7f2522155e48315f44fa0", "Carrere Video - Western Technologies, Jeff Corsiglia, Paul Allen Newell, Tom Sloper - Teldec - Prism", "USC1009", "Infernal Tower (1983) (Carrere Video) (PAL)", "AKA Towering Inferno", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "YES", "" }, + { "0c80751f6f7a3b370cc9e9f39ad533a7", "Atari, Carla Meninsky", "CX2610", "Warlords (1981) (Atari) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, + { "0cb7af80fd0ddef84844481d85e5d29b", "", "", "Mr. Pac-Man (El Destructo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0cc8224ff1edfe458e8629e9e5fe3f5b", "Thomas Jentzsch", "", "Trick 12 (2001) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0cdd9cc692e8b04ba8eb31fc31d72e5e", "Thomas Jentzsch", "", "Wing War (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0cebb0bb45a856b23f56d21ce7d1bc34", "20th Century Fox Video Games, Bill Aspromonte", "11131", "Crash Dive (1983) (20th Century Fox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0cec9e46a25d338bf595a29aa2606516", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Atari Mouse Hack v1.1 (PAL60) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0cfdd2f3b243cac21f38a0f09f54bead", "", "", "Overhead Adventure Demo 4 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0d07d2c1be1a5eaaea235a533bcda781", "", "", "Scrolling Playfield 1 (Junkosoft) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0d08558f34a47e4eaa39d01c8efb81f0", "Thomas Jentzsch", "", "Missile Control - Atari Mouse Hack v1.15 (NTSC) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0d09cff0d28033c02c3290edfc3a5cea", "Atari, Jerome Domurat, Steve Woita", "CX2699", "Taz (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0d1b3abf681a2fc9a6aa31a9b0e8b445", "Atari", "CX26163P", "Laser Blast (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0d27c7f5db349b592f70f68daf5e8f3b", "", "", "Space Instigators (21-10-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0d35618b6d76ddd46d2626e9e3e40db5", "", "", "X-Doom V.26 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0d5af65ad3f19558e6f8e29bf2a9d0f8", "Atari - Sculptured Software, Adam Clayton", "CX26151, CX26151P", "Dark Chambers (1989) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "0d6b974fe58a1bdd453600401c407856", "Atari", "", "128-in-1 Junior Console (Chip 3 or 4) (1991) (Atari) (PAL)", "Actually contains only 16 games, not 32", "", "", "", "16IN1", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0d786a41695e5fc8cffd05a6dbb3f659", "", "", "Scrolling Playfield With Score (10-02-2003) (Aaron Bergstrom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0d7e630a14856f4d52c9666040961d4d", "", "", "Wavy Line Test (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0d90a0ee73d55539b7def24c88caa651", "Activision, Bob Whitehead", "AG-005, CAG-005, AG-005-04", "Skiing (1980) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0db4f4150fecf77e4ce72ca4d04c052f", "Atari, Carol Shaw - Sears", "CX2618 - 49-75123", "3-D Tic-Tac-Toe (1980) (Atari)", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0dd4c69b5f9a7ae96a7a08329496779a", "Tigervision - Software Electronics Corp., Karl T. Olinger - Teldec", "7-001 - 3.60001 VE", "King Kong (1982) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0de53160a8b54c3aa5aed8d68c970b62", "Quelle", "806.174 9", "Fuchs & Schweinchen Schlau (1983) (Quelle) (PAL)", "AKA Oink!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0dfbdadf8f1bc718e7e1bb3ccd5fef3d", "", "", "Mr. Pac-Man (New start tune) (El Destructo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0e0808227ef41f6825c06f25082c2e56", "", "", "Candi (Hack) [a]", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0e08cd2c5bcf11c6a7e5a009a7715b6a", "", "", "Boing! (PD) [a1]", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0e224ea74310da4e7e2103400eb1b4bf", "Atari, Peter C. Niday, Gary Shannon, Howard Scott Warshaw", "", "Mind Maze (10-10-1984) (Atari) (Prototype)", "Uses the MindLink controller", "Prototype", "", "", "", "", "", "", "", "", "MINDLINK", "", "", "", "", "", "", "", "" }, + { "0e23d0ed4c33b2011ab4cc93a7619683", "Thomas Jentzsch", "", "Centipede - Amiga Mouse Hack v1.4 (PAL60) (Half-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0e4b2b6e014a93ef8be896823da0d4ec", "", "", "Skiing (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0e713d4e272ea7322c5b27d645f56dd0", "Home Vision - Gem International Corp. - VDI", "VCS83105", "Panda Chase (1983) (Home Vision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0e7e73421606873b544e858c59dc283e", "Digivision", "", "Super Soccer (Digivision)", "AKA RealSports Soccer", "", "", "", "F8", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "0e86470791b26292abe1c64545c47985", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix - Down on the Line (3 of 3) (1983) (Arcadia) (PAL)", "Uses Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "01 70", "", "", "", "" }, + { "0ec93f519bb769e0d9f80e61f6cc8023", "Atari - GCC, John Allred, Mike Feinstein", "CX2688", "Jungle Hunt (02-25-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0ecdb07bf9b36ef18f3780ef48e6c709", "Bit Corporation", "PG209", "Mr. Postman (1983) (BitCorp)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0eebfb60d437796d536039701ec43845", "Fabrizio Zavagli", "", "Cakewalk (Fabrizio Zavagli)", "NTSC Conversion", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0eecb5f58f55de9db4eedb3a0f6b74a8", "Xonox - Beck-Tech", "6210, 06002, 06004, 99002", "Ghost Manor (1983) (Xonox) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0ef64cdbecccb7049752a3de0b7ade14", "Atari, Joe Decuir, Larry Caplan, Steve Mayer, Larry Wagner", "CX26163P", "Combat (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0efc91e45f61023cda9d086a7d3c402f", "B.J. Best (aka bjbest60)", "", "Space Cactus Canyon (2017)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "0effef4a341f8eebab65621c60c48787", "Thomas Jentzsch", "", "Reactor - Atari Trak-Ball Hack v1.3 (PAL) (Full-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0f14c03050b35d6b1d8850b07578722d", "Jeffry Johnston", "", "Radial Pong - Version 10 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0f24ca5668b4ab5dfaf217933c505926", "", "", "Fantastic Voyage (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0f2e09c71cc216f79d22a804152ba24b", "Bob Colbert", "", "Scroller Demo (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "0f341d1f4e144e3163d9a5fc5a662b79", "", "", "RUN Platform Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "0f39fc03d579d0d93a6b729a3746843e", "Atari, Sam Comstock, Richard Dobbis, Nick 'Sandy Maiwald' Turner", "CX26111", "Snoopy and the Red Baron (05-27-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0f604cd4c9d2795cf5746e8af7948064", "Champ Games", "CG-02-N", "Conquest Of Mars (2010) (NTSC)", "Rev 2 release", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0f643c34e40e3f1daafd9c524d3ffe64", "Atari, Robert C. Polaro, Alan J. Murphy - Sears", "CX2609 - 49-75186", "Defender (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0f6676b05621f80c670966e2995b227a", "", "", "Globe Trotter Demo 1 (24-03-2003) (Weston)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0f738dc44437557624eb277ed7ad91c9", "", "", "Grand Prix (Unknown) (PAL)", "AKA Grand Prix", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0f8043715d66a4bbed394ef801d99862", "Quelle", "684.733 9", "Robin Hood (1983) (Quelle) (PAL)", "AKA Save Our Ship", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0f95264089c99fc2a839a19872552004", "Activision, David Crane", "AG-009, AG-009-04", "Freeway (1981) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0fba7d8c3520bdb681f75494e498ec36", "", "", "Gunfight 2600 - Final Run (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0fbf618be43d4396856d4244126fe7dc", "Quelle", "805.784 6", "Labyrinth (1983) (Quelle) (PAL)", "AKA Maze Craze", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0fc161704c46e16f7483f92b06c1558d", "CCE", "C-853", "Spider Fighter (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0fcff6fe3b0769ad5d0cf82814d2a6d9", "Suntek", "SS-027", "Zoo Fun (1983) (Suntek) (PAL)", "AKA Panda Chase", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0fd72a13b3b6103fc825a692c71963b4", "Imagic, Rob Fulop", "720104-2A, IA3204P, EIX-008-04I", "Cosmic Ark (1982) (Imagic) (PAL) [selectable starfield]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "0fee596b974c9d3e70b367a3671599b6", "Bit Corporation", "R320", "Name This Game (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "101ab60f4000a5d13792ef0abad5f74b", "Atari, Jerome Domurat, Peter C. Niday, Robert Vieira", "CX26109", "Sorcerer's Apprentice (1983) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "102672bbd7e25cd79f4384dd7214c32b", "Atari, Alan Miller - Sears", "CX2642 - 6-99814", "Hunt & Score - Memory Match (1978) (Atari)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "103e9d616328969f5d7b4e0a381b25d5", "", "", "Playfield Illustration and Logo Demo (2001) (Jake Patterson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "103f1756d9dc0dd2b16b53ad0f0f1859", "Home Vision, Gem International Corp.", "", "Go Go Home Monster (1983) (Home Vision) (PAL)", "AKA Go Go Home", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "104468e44898b8e9fa4a1500fde8d4cb", "AtariAge, Chris Spry", "CX26200", "Princess Rescue (2013) (Sprybug)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "JOYSTICK", "", "", "", "", "", "", "", "YES", "" }, + { "106326c262dfd3e8eaeabd961d2a0519", "", "", "PAL-NTSC Detector (15-11-2002) (CT)[a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "106855474c69d08c8ffa308d47337269", "Atari - Sculptured Software, Adam Clayton", "CX26151", "Dark Chambers (1989) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "107cc025334211e6d29da0b6be46aec7", "Atari, Bob Smith - Sears", "CX2648 - 49-75161", "Video Pinball (1981) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1086ff69f82b68d6776634f336fb4857", "Activision, David Crane", "AG-009", "Bloody Human Freeway (1981) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "10958cd0a1a81d599005f1797ab0e51d", "", "", "Centipede 2k (2000) (PD) (Hack)", "Hack of Centipede", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "10a3cd14e5dcfdde6ff216a14ce7b7dd", "Atari", "CX262, CX2627P", "Human Cannonball (1979) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "10af8728f975aa35a99d0965de8f714c", "Dinatronic", "", "Seaquest (Dinatronic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "10c47acca2ecd212b900ad3cf6942dbb", "Atari - Axlon, Tod Frye - Heuristica, Agustin Ortiz", "CX26169", "Shooting Arcade (03-07-1989) (Atari) (Prototype) [a4]", "Uses the Light Gun Controller (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "10c8cfd8c37522f11d47540ff024e5f9", "Canal 3 - Intellivision", "C 3016", "Demon Attack (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "10eae73a07b3da044b72473d8d366267", "Funvision - Fund. Int'l Co.", "", "Karate (1982) (Funvision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "10f0ecaf962aef1fc28abed870b01b65", "Atari, Paul Donaldson", "", "Bionic Breakthrough (06-22-1984) (Atari) (Prototype)", "Uses the Mindlink Controller", "Prototype", "", "", "", "", "", "", "", "MINDLINK", "", "", "", "", "", "", "", "", "" }, + { "10f62443f1ae087dc588a77f9e8f43e9", "Atari, Carla Meninsky", "CX2637, CX2637P", "Dodge 'Em (1980) (Atari) (PAL) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "110ac8ecaf1b69f41bc94c59dfcb8b2d", "", "", "Demon Attack (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "111029770226b319524134193886a10e", "Hozer Video Games", "", "Gunfight 2600 - One Limit Reached! (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "11330eaa5dd2629052fac37cfe1a0b7d", "128-in-1 Junior Console", "", "Human Cannonball (128-in-1 Junior Console) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "113cd09c9771ac278544b7e90efe7df2", "Atari, Ed Logg, Carol Shaw - Sears", "CX2639 - 49-75162", "Othello (1981) (Atari) [no grid markers]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "114c599454d32f74c728a6e1f71012ba", "Activision, Bob Whitehead - Ariola", "EAX-015, EAX-015-04I - 711 015-725", "Chopper Command (1982) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "11bcf5c752088b5aaf86d6c7a6a11e8d", "Atari, Jerome Domurat, Andrew Fuchs, Dave Staugas, Robert Vieira", "CX26118", "Millipede (1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "11e7e0d9437ec98fa085284cf16d0eb4", "", "", "Bowling (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "11f9532557e4c9569f4b242164006161", "Chris Walton, Justin Hairgrove, Tony Morse", "", "Hunchy II (2005) (PAL)", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1201c18cf00d2c236f42e4d7d8c86aa1", "", "", "Nick Bensema Demo (Nick Bensema)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "12080205f669b8e7783b976f8cf3d8bb", "Omegamatrix", "", "Star Wars Arcade (Amiga Mouse) v4 (Omegamatrix)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "12123b534bdee79ed7563b9ad74f1cbd", "Absolute Entertainment, Alex DeMeo", "AG-041-04", "Title Match Pro Wrestling (1987) (Absolute)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1228c01cd3c4b9c477540c5adb306d2a", "Atari, Alan Miller", "CX26163P", "Basketball (32 in 1) (1988) (Atari) (PAL)", "Console ports are swapped", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "", "" }, + { "1266b3fd632c981f3ef9bdbf9f86ce9a", "Activision, Bob Whitehead", "EAZ-034-04, EAZ-034-04I", "Private Eye (1984) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1267e3c6ca951ff1df6f222c8f813d97", "", "", "Dragonfire (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "126f7f64b7b00e25dcf5e3710b4cf8b8", "Atari - GCC", "CX2676", "Centipede (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1278f74ca1dfaa9122df3eca3c5bcaad", "Rainbow Vision - Suntek", "SS-013", "Bi! Bi! (Rainbow Vision) (PAL)", "AKA Skindiver", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1287535256bf5dff404839ac9e25c3e7", "PacManPlus", "Rev 2", "Alien Pac-Man (PacManPlus) (Hack)", "Hack of Alien", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "12937db3d4a80da5c4452b752891252d", "Digitel", "", "Megamania (1983) (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "12bca8305d5ab8ea51fe1cfd95d7ab0e", "Epyx, Steven A. Baker, Tod Frye, Peter Engelbrite", "80561-00250", "Summer Games (1987) (Epyx) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "12d7e0d6b187889f8d150bf7034d1db2", "", "", "Poker Squares (V0.0e) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "130c5742cd6cbe4877704d733d5b08ca", "Home Vision - Gem International Corp. - VDI", "VCS83109", "World End (1983) (Home Vision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1323c45d660f5a5b6d5ea45c6c4cbe4a", "Canal 3 - Intellivision", "", "Enduro (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "133456269a03e3fdae6cddd65754c50d", "Tigervision - Software Electronics Corporation - Teldec", "7-006 - 3.60008 VG", "Springer (1983) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "133a4234512e8c4e9e8c5651469d4a09", "Atari, Andrew Fuchs, Jeffrey Gusman, Dave Jolly, Suki Lee", "CX26117", "Obelix (1984) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "133b56de011d562cbab665968bde352b", "Activision, John Van Ryzin", "AG-038-04", "Cosmic Commuter (1984) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1343de49c2a50d99176255f99f0d0234", "Gray Games & AtariAge", "", "E.T. Book Cart (PAL)", "Charles F. Gray & Michael Rideout", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "55" }, + { "13448eb5ba575e8d7b8d5b280ea6788f", "Digivision", "", "Crackpots (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1345e972dbe08ea3e70850902e20e1a5", "Greg Troutman", "", "Dark Mage (rough beta) (Greg Troutman) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "1351c67b42770c1bd758c3e42f553fea", "Digivision", "", "Keystone Kapers (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "135708b9a7dd20576c1b66ab2a41860d", "", "", "Hangman Man Biglist1 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "13584411da0a8d431991035423fdc0dc", "Jone Yuan Telephonic Enterprise Co", "", "Skiing (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1367e41858be525710eb04d0dab53505", "Kyle Pittman", "", "Zelda (2003) (Kyle Pittman) (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "136f75c4dd02c29283752b7e5799f978", "Atari, Dan Hitchens - Sears", "CX2650 - 49-75168", "Berzerk (1982) (Atari)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "13895ef15610af0d0f89d588f376b3fe", "Tigervision, Rorke Weigandt", "7-005", "Marauder (1982) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "13a37cf8170a3a34ce311b89bde82032", "Atari - GCC, Mark Ackerman, Tom Calderwood, Glenn Parker", "CX2684, CX2684P", "Galaxian (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "13a991bc9c2ff03753aeb322d3e3e2e5", "Funvision - Fund. International Co.", "", "Galactic (Funvision) (PAL)", "AKA Condor Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "13aa1f9ac4249947e4af61319d9a08f2", "Atari - GCC", "CX2680, CX2680P", "RealSports Tennis (1983) (Atari) (PAL) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "13abc32f803165c458bb086fa57195fb", "Christian Samuel", "", "E.T. The Extra-Testical (Christian Samuel) (Hack)", "Hack of E.T. The Extra-Terrestrial", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "13ccc692f111d52fec75d83df16192e2", "Canal 3 - Intellivision", "", "Fishing Derby (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "13d8326bf5648db4dafce45d25e62ddd", "", "", "Atari Logo Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "13dfb095e519a555a5b60b7d9d7169f9", "", "", "Red Line Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "140909d204abd6841c64cdad4d7765b4", "", "", "Moving Blue Ladder Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "14163eb2a3ddd35576bd8527eae3b45e", "", "", "Multi-Color Demo 6 (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1423f560062c4f3c669d55891a2bcbe7", "CCE", "C-859", "MASH (1983) (CCE) [a]", "AKA M.A.S.H", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1428029e762797069ad795ce7c6a1a93", "", "", "Thunderground (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "143918368f4f4dfff90999188c0197c9", "", "", "Unknown Title (bin00016 (200110)) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1442d1b35a6478fba22ae7dd1fcb5634", "Thomas Jentzsch", "", "Thrust (V0.2) (2000) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "148471144ccebd7f6aa9aa9215896533", "Parker Brothers - JWDA, Todd Marshall", "PB5550", "Q-bert's Qubes (1984) (Parker Bros) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "149b543c917c180a1b02d33c12415206", "CCE", "C-857", "Superman (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "14a56b493a8d9d10e94a3e100362e3a2", "Hozer Video Games", "", "Gunfight 2600 - Early Play-kernel (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "14b1e30982962c72f426e2e763eb4274", "Atari, Carol Shaw - Ralph Lauren", "", "Polo (1978) (Atari) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "14c2548712099c220964d7f044c59fd9", "First Star Software, Alex Leavens, Shirley Ann Russell", "", "Boing! (1983) (First Star Software)", "AKA Bubbles, Soap Suds, The Emphysema Game", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "14d365bbfaac3d20c6119591f57acca4", "", "", "Video Life (Unknown) (4K) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "14dbb3686dd31964332dc2ef0c55cad0", "", "", "Demo Image Series #15 - Three Marios (PAL) (Non-Interleave) (06-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "151c33a71b99e6bcffb34b43c6f0ec23", "Parker Brothers, Laura Nikolich", "", "Care Bears (1983) (Parker Bros) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "151fa3218d8d7600114eb5bcd79c85cb", "Atari - CCW, Christopher H. Omarzu", "CX26104", "Big Bird's Egg Catch (05-02-1983) (Atari) (Prototype)", "Uses the Keypad Controller", "Prototype", "", "", "", "", "", "", "", "KEYBOARD", "", "", "", "", "", "", "", "", "" }, + { "152c253478b009c275e18cd731b48561", "", "", "Quest (11-10-2002) (Chris Larkin)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "153f40e335e5cb90f5ce02e54934ab62", "Absolute Entertainment, Alex DeMeo", "EAZ-041-04I", "Title Match Pro Wrestling (1987) (Absolute) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1542662f665d2ffaa77b4b897dd2e2af", "", "", "Starfield (V1.0) (2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "155fa7f479dcba3b10b1494e236d6010", "Skyworks", "", "Tomcat (2002) (Skyworks) (PAL)", "AKA The F-14 Flight Simulator", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "157356f80c709ab675961d8b8b207e20", "", "", "Multi-Sprite Game V2.5 (Piero Cavina) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "157bddb7192754a45372be196797f284", "Atari, Warren Robinett - Sears", "CX2613, 49-75154", "Adventure (1980) (Atari)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "159e5cd6ccb968015f49aed5adbc91eb", "Justin J. Scott", "", "Yar's Defeat (2002) (Justin J. Scott) (Hack)", "Hack of Yars' Revenge", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "15a0d59304dece2c7d0580f3ea3527f0", "Atari, Jerome Domurat, Peter C. Niday", "CX26115", "Dumbo's Flying Circus (04-04-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "15b498199ed0ed28057bf0dbdce9b8d8", "Thomas Jentzsch", "", "Jammed (V0.2) (Demo) (2001) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "15b9f5e2439bfaa08874b5184261c777", "Bit Corporation", "R320", "Space Invaders (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "15bcd74f2f1f2a63e1aa93e90d2c0555", "", "", "Incoming (22-08-2002) (Ben Larson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "15bf2ef7583bfcbbba630847a1dc5539", "Erik Eid", "", "Euchre (Jul 15) (2002) (Eric Eid) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "15c11ab6e4502b2010b18366133fc322", "Atari - Axlon, Tod Frye - Heuristica, Augustin Ortiz", "CX26169", "Shooting Arcade (09-19-1989) (Atari) (Prototype)", "Uses the Light Gun Controller (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "15dd21c2608e0d7d9f54c0d3f08cca1f", "Data Age, J. Ray Dettling", "112-008", "Frankenstein's Monster (1983) (Data Age)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "15fe28d0c8893be9223e8cb2d032e557", "", "", "Towering Inferno (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "1619bc27632f9148d8480cd813aa74c3", "Thomas Jentzsch", "", "Steeple Chase (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "A", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "161ded4a85d3c78e44fffd40426f537f", "Thomas Jentzsch", "", "JtzBall (Alpha) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "163e7e757e2dc44469123ff0e5daec5e", "", "", "Many Blue Bars and Text Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "169d4c7bd3a4d09e184a3b993823d048", "", "", "Superman (Unknown) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "16cb43492987d2f32b423817cdaaf7c4", "Atari, Larry Kaplan - Sears", "CX2602 - 99802, 6-99802, 49-75102", "Air-Sea Battle (1977) (Atari)", "AKA Target Fun (Anti-Aircraft)", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "16cc6d1b4ddce51c767a1ba8e5ff196c", "", "", "Big - Move This Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "16d69f71bf5846639be5ff16483f0498", "Bit Corporation", "R320", "Golf (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "16e04823887c547dc24bc70dff693df4", "Atari", "CX26163P", "Tennis (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "16ee443c990215f61f7dd1e55a0d2256", "Spectravideo, David Lubar", "SA-218, SA-218C", "Bumper Bash (1983) (Spectravideo) (PAL)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "PADDLES", "", "", "", "", "", "", "", "", "" }, + { "16f494f20af5dc803bc35939ef924020", "Mark De Smet", "", "Video Simon (Mark De Smet)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "170e7589a48739cfb9cc782cbb0fe25a", "M Network - INTV - APh Technological Consulting, Hal Finney", "MT5666", "Astroblast (1982) (M Network) [fixed]", "Can also use left joystick", "Uncommon", "", "", "", "", "", "", "", "PADDLES", "", "YES", "", "", "AUTO 55", "", "", "", "" }, + { "171cd6b55267573e6a9c2921fb720794", "Kurt Howe", "", "Adventure 34 (Kurt Howe) (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "171ebf135b13ba907f462c10d88a2c25", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Amiga Mouse Hack v1.1 (PAL60) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1733772165d7b886a94e2b4ed0f74ccd", "", "", "Boring Journey Escape (Hack)", "Hack of Journey - Escape", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1738b2e3f25ab3eef3cecb95e1d0d957", "", "", "Hangman Monkey Biglist1 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "17512d0c38f448712f49f36f9d185c4e", "Retroactive", "", "Qb (Release Candidate #1) (Retroactive)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "17515a4d0b7ea5029ffff7dfa8456671", "Piero Cavina", "", "Multi-Sprite Demo V1.1 (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "176d3fba7d687f2b23158098e103c34a", "Zach Matley", "", "Combat AI (16-02-2003) (Zach Matley)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "177504abd4260c4265e1338955e9fa47", "HCC Software", "", "Pitfall! (Steroids Hack)", "Hack of Pitfall! (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1782929e1c214b70fb6884f77c207a55", "Activision, David Crane", "AX-018, AX-018-04", "Pitfall! (1982) (Activision) (Prototype)", "Pitfall Harry's Jungle Adventure (Jungle Runner)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "17ba72433dd41383065d4aa6dedb3d91", "", "", "SCSIcide (09-06-2001) (Joe Grand)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "17badbb3f54d1fc01ee68726882f26a6", "M Network - INTV - APh Technological Consulting, Hal Finney, Bruce Pedersen", "MT5659", "Space Attack (1982) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "17bbe288c3855c235950fea91c9504e9", "Dismac", "", "Pega Ladrao (Dismac)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "17c0a63f9a680e7a61beba81692d9297", "U.S. Games Corporation - Western Technologies, Jeff Corsiglia, David Johnson, Tom Sloper", "VC2004", "Picnic (1983) (U.S. Games)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "AUTO 45", "", "", "", "" }, + { "17d000a2882f9fdaa8b4a391ad367f00", "Atari - GCC", "CX2676", "Centipede (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "17ee158d15e4a34f57a837bc1ce2b0ce", "Atari - GCC, Mike Feinstein, Kevin Osborn", "CX2691, CX2691P", "Joust (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "17ee23e5da931be82f733917adcb6386", "Salu, Dennis M. Kiss", "460758", "Acid Drop (1992) (Salu) (PAL)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1802cc46b879b229272501998c5de04f", "Atari - CCW, Christopher H. Omarzu", "CX26104", "Big Bird's Egg Catch (1983) (Atari)", "Uses Kids/Keypad Controllers", "Rare", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "", "" }, + { "183020a80848e06a1238a1ab74079d52", "Thomas Jentzsch", "", "Missile Command (Amiga Mouse) (2002) (TJ) (PAL)", "Uses Amiga Mouse Controller", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "1862fca4f98e66f363308b859b5863af", "Atari", "", "128-in-1 Junior Console (Chip 1 of 4) (1991) (Atari) (PAL)", "Actually contains only 16 games, not 32", "", "", "", "16IN1", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "18a970bea7ac4d29707c8d5cd559d03a", "", "", "Bridge (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "18b28b386abdadb3a700ac8fb68e639a", "Manuel Polik", "", "Gunfight 2600 (MP) (PAL)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "18b476a34ce5e6db2c032029873ac39b", "Bit Corporation", "R320", "Atlantis (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "18be8981b8201638f3ed8ae92bb4c215", "Thomas Jentzsch", "", "Missile Control - Amiga Mouse Hack v1.15 (PAL60) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "18bebbbd41c234f82b1717b1905e6027", "", "", "Space Instigators (Public Release) (02-01-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "18d26111cef66dff0c8af8cf0e117843", "", "", "Tunnel Demo (Cycling Colours 2) (29-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "18dc28bc22402f21e1c9b81344b3b8c5", "Atari - GCC, Mark Ackerman, Glenn Parker", "CX2684, CX2684P", "Galaxian (1983) (Atari) (PAL) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "18ed63e3ce5bc3dd2d8bd188b807f1a2", "", "", "Stell-A-Sketch (Bob Colbert) (PD) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "18f299edb5ba709a64c80c8c9cec24f2", "Home Vision - Gem International Corp. - VDI", "VCS83111", "Asteroid Fire (1983) (Home Vision) (PAL)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "19098c46da0640f2b5763167dea6c716", "Andrew Wallace", "", "Laseresal 2002 (NTSC) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "191449e40b0c56411c70772706f79224", "", "", "Multi-Color Demo 2 (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "19162393786098d50587827588198a86", "Jone Yuan Telephonic Enterprise Co", "", "Flag Capture (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "191ac4eec767358ee3ec3756c120423a", "", "", "Checkers (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "192aa2e8c795c9e10a7913e5d41feb81", "Atari - GCC, Jaques Hugon, Seth Lipkin", "CX26125", "Los Angeles 1984 Games (1984) (Atari) (Prototype) (PAL)", "AKA Track and Field (Uses Track & Field Controller)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "193f060553ba0a2a2676f91d9ec0c555", "Atari, Carol Shaw", "CX2636, CX2636P", "Video Checkers (1980) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1942bdb7abc75e412068330a9082b0ff", "Atari, Omegamatrix", "", "Super Breakout Menu (2020) (PAL) (Hack)", "Hack of Super Breakout", "", "", "", "", "", "", "", "", "", "", "", "", "", "AUTO 55", "", "", "", "" }, + { "1986f864e32e3e8d198b5becf3022257", "Thomas Jentzsch", "", "Reactor - Atari Trak-Ball Hack v1.3 (PAL) (Half-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "199985cae1c0123ab1aef921daace8be", "", "", "Euchre (Release Candidate 2) (PAL) (01-10-2002) (Erik Eid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "199eb0b8dce1408f3f7d46411b715ca9", "Parker Brothers, David Lamkins, Laura Nikolich", "PB5900", "Spider-Man (1982) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "19a9d3f9fa1b1358fb53009444247aaf", "", "", "Blackjack (Unknown) (PAL) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "", "", "", "", "" }, + { "19abaf2144b6a7b281c4112cff154904", "Atari, Brad Stewart", "CX2649, CX2649P", "Asteroids (1981) (Atari) (PAL) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "19b3b807507653516985ba95da92499d", "Joe Gaucher", "", "VCS Draw Demo (Joe Gaucher)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "19d6956ff17a959c48fcd8f4706a848d", "PlayAround - J.H.M.", "202", "Burning Desire (1982) (PlayAround)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "19d9b5f8428947eae6f8e97c7f33bf44", "", "", "Fortress (Dual Version) (20-04-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "19e739c2764a5ab9ed08f9095aa2af0b", "Atari, Andrew Fuchs, Jeffrey Gusman, Dave Jolly, Suki Lee", "CX26117", "Obelix (1984) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "19e761e53e5ec8e9f2fceea62715ca06", "Panda", "104", "Scuba Diver (1983) (Panda)", "AKA Skindiver", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1a23540d91f87584a04f184304a00648", "", "", "Race Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1a613ce60fc834d4970e1e674b9196b3", "Home Vision - Gem International Corp. - VDI", "VCS83135", "Tanks War (1983) (Home Vision) (PAL)", "AKA Phantom Tank", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1a624e236526c4c8f31175e9c89b2a22", "Rainbow Vision - Suntek", "SS-007", "Space Raid (1983) (Rainbow Vision) (PAL) [a]", "AKA MegaMania", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1a8204a2bcd793f539168773d9ad6230", "Atari, Rob Fulop - Sears", "CX2638 - 49-75166", "Missile Command (1981) (Atari) [no initials]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1aa7344b563c597eecfbfcf8e7093c27", "David Marli", "", "Slot Invaders (David Marli) (Hack)", "Hack of Slot Machine", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1b0f3d7af668eeea38ddd6182d8f48fb", "Jone Yuan Telephonic Enterprise Co", "", "Cosmic Swarm (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "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]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1bc2427ac9b032a52fe527c7b26ce22c", "Intellivision Productions - M Network - APh Technological Consulting, Bruce Pedersen, Larry Zwick", "MT5860", "Sea Battle (1983) (M Network)", "High Seas", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1bef389e3dd2d4ca4f2f60d42c932509", "Dimax - Sinmax", "SM8001", "Space Robot (1983) (Dimax - Sinmax) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "1bf503c724001b09be79c515ecfcbd03", "", "", "Bumper Bash (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1bfae770e089fa81412d04eb299f4c3f", "Thomas Jentzsch", "", "Marble Craze - Atari Mouse Hack v1.0 (NTSC) (TJ)", "Uses Atari Mouse Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1c3f3133a3e5b023c77ecba94fd65995", "CCE", "C-830", "Planet Patrol (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1c5796d277d9e4df3f6648f7012884c4", "Rainbow Vision - Suntek", "SS-012", "Hey! Stop! (1983) (Rainbow Vision) (PAL)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1c666ba5aac19b81671357e76062989b", "Nukey Shay, Omegamatrix", "", "Double Dragon (Genesis) (PAL60) V2", "Genesis controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1c6eb740d3c485766cade566abab8208", "Atari, Michael Kosaka, Peter C. Niday, Robert Vieira", "CX26110", "Crystal Castles (1984) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1c85c0fc480bbd69dc301591b6ecb422", "CCE", "", "Super Box (CCE)", "AKA RealSports Boxing", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1c8c42d1aee5010b30e7f1992d69216e", "PlayAround - J.H.M.", "205", "Gigolo (1982) (PlayAround)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "1cad3b56cc0e6e858554e46d08952861", "Jone Yuan Telephonic Enterprise Co", "", "Chopper Command (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1cafa9f3f9a2fce4af6e4b85a2bbd254", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX2659", "Raiders of the Lost Ark (1982) (Atari) (PAL)", "Console ports are swapped", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "", "" }, + { "1cca2197d95c5a41f2add49a13738055", "Atari, Larry Kaplan - Sears", "CX2664 - 6-99818", "Brain Games (1978) (Atari)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "", "" }, + { "1cf59fc7b11cdbcefe931e41641772f6", "SEGA", "005-01", "Buck Rogers - Planet of Zoom (1983) (SEGA)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "1d1d2603ec139867c1d1f5ddf83093f1", "Atari, Larry Kaplan - Sears", "CX2602 - 99802, 6-99802, 49-75102", "Air-Sea Battle (1977) (Atari) (4K)", "AKA Target Fun (Anti-Aircraft)", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1d284d6a3f850bafb25635a12b316f3d", "CCE", "", "H.E.R.O. (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1d2a28eb8c95da0d6d6b18294211839f", "", "", "Fishing Derby (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1d4e0a034ad1275bc4d75165ae236105", "20th Century Fox Video Games, Mark Klein", "11034", "Pick Up (1983) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1d5eac85e67b8cff1377c8dba1136929", "", "", "Chronocolor Donkey Kong Sideways (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1d6ed6fe9dfbde32708e8353548cbb80", "Jone Yuan Telephonic Enterprise Co", "", "Super Challenge Baseball (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1d72cc6ee466a4af1b27587b900ed430", "Atari, Omegamatrix", "", "Space Invaders Menu (2020) (Hack)", "Hack of Space Invaders", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1da2da7974d2ca73a823523f82f517b3", "Spectravision - Spectravideo - Sirius Software, David Lubar", "SA-206", "Challenge of.... Nexar, The (1982) (Spectravision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1db3bc4601f22cf43be7ce015d74f59a", "", "", "Ship Demo (V 10) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1e060a8025512ad2127e3da11e212ccc", "Arcadia Corporation, Scott Nelson", "13", "Sweat! - The Decathlon Game (3 of 3) (1983) (Arcadia) (Prototype)", "Uses the Paddle Controllers (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1e0ef01e330e5b91387f75f700ccaf8f", "Quelle - Otto Versand", "686.561 2 - 781627", "Mein Weg (1983) (Quelle) (PAL)", "AKA Challenge", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "1e1290ea102e12d7ac52820961457e2b", "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart", "PB5540", "Star Wars - The Arcade Game (12-15-1983) (Parker Bros) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "1e272d09c0e55f5ef14fcb76a735f6d7", "Atari, David Crane", "CX26163P", "Slot Machine (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1e31b3a48865ba98d4d1aa5205115983", "Atari - Roklan, Bob Curtiss", "", "Firefox (1983) (Atari) (Prototype)", "AKA Combat II, Fighter Command", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1e587ca91518a47753a28217cd4fd586", "Telesys, Jim Rupp, Jack Woodman", "1001", "Coco Nuts (1982) (Telesys)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1e750000af77cc76232f4d040f4ab060", "Jone Yuan Telephonic Enterprise Co", "", "Raft Rider (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1e85f8bccb4b866d4daa9fcf89306474", "Atari, Lou Harp", "CX26122", "Sinistar (02-13-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1e89f722494608d6ea15a00d99f81337", "", "", "River Raid (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "NTSC50", "", "", "" }, + { "1ea1abcd2d3d3d628f59a99a9d41b13b", "Jone Yuan Telephonic Enterprise Co", "", "Stampede (Jone Yuan) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1ea980574416bfd504f62575ba524005", "Atari - GCC, Mark Ackerman, Glenn Parker", "CX2675", "Ms. Pac-Man (1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1ec57bbd27bdbd08b60c391c4895c1cf", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX26119", "Saboteur (09-02-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1ec5bef77b91e59313cba205f15b06d7", "", "", "Overhead Adventure Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1ede4f365ce1386d58f121b15a775e24", "Parker Brothers, Dave Hampton, Tom Sloper", "931517", "Q-bert (1983) (Parker Bros) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1ee2cfc7d0333b96bd11f7f3ec8ce8bc", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (4 of 4) (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1ee9c1ba95cef2cf987d63f176c54ac3", "Atari - GCC, Mark Ackerman, Glenn Parker", "CX2675, CX2675P", "Ms. Pac-Man (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1ef04e7e508296a8d9eb61cc7dae2e5d", "SOLID Corp. (D. Scott Williamson)", "CX2655-069", "Star Castle 2600 (SolidCorp) [069]", "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "1f21666b8f78b65051b7a609f1d48608", "K-Tel Vision", "", "Vulture Attack (1982) (K-Tel Vision)", "AKA Condor Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1f2ae0c70a04c980c838c2cdc412cf45", "Atari - GCC", "CX2698", "Rubik's Cube (1984) (Atari)", "AKA Atari Video Cube", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1f349dd41c3f93c4214e5e308dccb056", "", "", "Virtual Pet Demo 2 (CRACKERS) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1f40eefc7447336ae6cd8ffa5eb325be", "Atari, Chris Crawford", "", "Wizard (1980) (Atari) (Prototype) (4K) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1f562b89d081e36d58e6fc943512ec05", "", "", "Hangman Man Biglist2 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1f5a2927a0b2faf87540b01d9d7d7fd1", "Pet Boat", "", "Tennis (Pet Boat) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1f60e48ad98b659a05ce0c1a8e999ad9", "", "", "Mondo Pong V2 (Piero Cavina) (PD)", "Uses the Paddle Controllers", "New Release", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "", "", "01", "", "", "", "" }, + { "1f773a94d919b2a3c647172bbb97f6b4", "Atari, Jerome Domurat, Peter C. Niday", "CX26115", "Dumbo's Flying Circus (07-11-1983) (Atari) (Prototype) (PAL)", "AKA Dumbo Flies Home", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1fa58679d4a39052bd9db059e8cda4ad", "Imagic, Dan Oliver", "720118-1A, 03208", "Laser Gates (1983) (Imagic)", "AKA Innerspace", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1fa7a42c2c7d6b7a0c6a05d38c7508f4", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (09-04-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "1fa86282403fa35d103ab88a9d603c31", "SpiceWare - Darrell Spice Jr.", "", "Stay Frosty (SpiceWare) (PAL60)", "Part of Stella's Stocking 2007 Xmas compilation", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "1fab68fd67fe5a86b2c0a9227a59bb95", "20th Century Fox Video Games - Videa, Lee Actor", "", "Lasercade (1983) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "200309c8fba0f248c13751ed4fc69bab", "Jeffry Johnston", "", "Radial Pong - Version 1 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2008c76deba5953201ef75a09b2ff7dc", "", "", "Fortress (21-04-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "200a9d2a7cb4441ce4f002df6aa47e38", "", "", "Doomzerk (PD) (Hack)", "Hack of Berzerk", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2016726db38ad6a68b4c48ba6fe51557", "Piero Cavina, Erik Mooney", "", "INV 2 (Piero Cavina, Erik Mooney)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "203049f4d8290bb4521cc4402415e737", "Tigervision, Robert H. O'Neil - Teldec", "7-007 - 3.60005 VG", "Polaris (1983) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "203abb713c00b0884206dcc656caa48f", "Imagic, Bob Smith", "720114-1A, 03207, IZ-001-04", "Moonsweeper (1983) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "203b1efc6101d4b9d83bb6cc1c71f67f", "Quelle", "685.996 1", "Teller-Jonglieren! (1983) (Quelle) (PAL)", "AKA Dancing Plate", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "205070b6a0d454961dd9196a8e81d877", "", "", "Hangman Monkey Biglist2 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2058cf3fefad4d2bc03ed817cedddcd4", "Thomas Jentzsch", "", "Reactor - Amiga Mouse Hack v1.3 (PAL60) (Full-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2091af29b4e7b86914d79d9aaa4cbd20", "CBS Electronics - Woodside Design Associates, Harley H. Puthuff Jr.", "4L1802", "Donkey Kong Junior (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "20ae62fb69c6cc6e8098cca8cd080487", "Zirok", "", "Tennis (Zirok)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "20d4457ba22517253fcb62967af11b37", "Atari, Eric Manghise, Mimi Nyden, Joseph Tung", "CX2640", "RealSports Baseball (1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "20dca534b997bf607d658e77fbb3c0ee", "Mythicon, Bill Bryner, Bruce de Graaf", "MA1002", "Fire Fly (1983) (Mythicon)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "20edcc3aa6c189259fa7e2f044a99c49", "Spectravision - Spectravideo", "SA-201", "Gangster Alley (1982) (Spectravision) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "211774f4c5739042618be8ff67351177", "Atari - GCC, Mark Ackerman, Tom Calderwood, Glenn Parker", "CX2684", "Galaxian (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "211f76dff0b7dad3f6fcac9d938ee61a", "JSK", "", "Custer's Viagra (JSK) (Hack) [a]", "Hack of Custer's Revenge", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "211fbbdbbca1102dc5b43dc8157c09b3", "Apollo", "AP-2009", "Final Approach (1982) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2124cf92978c46684b6c39ccc2e33713", "", "", "Sea Monster (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "21299c8c3ac1d54f8289d88702a738fd", "K-Tel Vision", "", "Spider Maze (1982) (K-Tel Vision)", "AKA Spider Kong", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "212d0b200ed8b45d8795ad899734d7d7", "Atari, Richard Maurer, Christopher H. Omarzu - Coca Cola", "", "Pepsi Invaders (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "213e5e82ecb42af237cfed8612c128ac", "Sancho - Tang's Electronic Co.", "TEC006", "Forest (1983) (Sancho) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "2162266b906c939b35c84ff9a0f50ad1", "Atari, Larry Kaplan", "CX2664, CX2664P", "Brain Games (1978) (Atari) (PAL) (4K)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "", "" }, + { "2179dfd7edee76efafe698c1bc763735", "", "", "Yellow Submarine (Cody Pittman) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "217b1452881264ac75126bf77b8d0db8", "Thomas Jentzsch", "", "Centipede - Atari Trak-Ball Hack v1.4 (NTSC) (Full-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "218b76f5a4142dc2ea9051a768583d70", "Atari - GCC, Mark Ackerman, Glenn Parker", "CX2684, CX2684P", "Galaxian (1983) (Atari) (PAL) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "218c0fe53dfaaa37f3c823f66eafd3fc", "Atari, Alan Miller", "CX2624, CX2624P", "Basketball (1978) (Atari) (PAL)", "Console ports are swapped", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "", "" }, + { "21a96301bb0df27fde2e7eefa49e0397", "Data Age", "DA1003", "Sssnake (1982) (Data Age)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "21b09c40295c2d7074a83ae040f22edf", "", "", "Marble Craze (V0.90) (Easy Version) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "21d2c435bcccde7792d82844b3cf60f4", "Atari - GCC, Doug Macrae", "CX2677, CX2677P", "Dig Dug (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "21d7334e406c2407e69dbddd7cec3583", "Activision, Bob Whitehead", "AG-011", "Stampede (1981) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2228c67d25e507603d4873d3934f0757", "", "", "Fu Kung! (V0.10) (28-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "22319be7a640af5314ec3c482cceb676", "", "", "Joustpong (05-07-2002) (Kirk Israel) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2240655247d6de1c585564004a853ab7", "", "", "Fu Kung! (V0.17) (07-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "225522777dc7155627808bde0c1d0ef0", "", "", "This Planet Sucks Demo 1 (Greg Troutman) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "22675cacd9b71dea21800cbf8597f000", "Atari, David Crane", "CX2605, CX2605P", "Outlaw (1978) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "227532d82505c3c185a878273c285d5f", "", "", "Hangman Man Original Words (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "22abbdcb094d014388d529352abe9b4b", "Apollo", "AP-2012", "Squoosh (1983) (Apollo) (Prototype) [a]", "AKA Vat's Incredible!, The Grape Escape", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "22b22c4ce240303012e8a9596ae8d189", "", "", "Skeleton+ (03-05-2003) (Eric Ball) (PAL)", "", "", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "22f6b40fc82110d68e50a1208ae0bb97", "", "", "Purple Bar Demo (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2319922df4d0c820b3e5f15faa870cc3", "Atari - GCC, Mike Feinstein", "CX2681, CX2681P", "Battlezone (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2327456f86d7e0deda94758c518d05b3", "Digitel", "", "Mr. Postman (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2351d26d0bfdee3095bec9c05cbcf7b0", "", "", "Warring Worms (19-01-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2353725ec98e0f0073462109e886efd7", "Champ Games", "CG-03-P", "Scramble (PAL60)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "JOYSTICK", "", "", "", "", "", "", "", "YES", "" }, + { "235436ab0832370e73677c9c6f0c8b06", "", "", "Beast Invaders (Double Shot) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2365e1534d67f94d8670394ab99150ce", "Thomas Jentzsch", "", "Missile Command (Atari Mouse) (2002) (TJ)", "Uses Atari ST Mouse Controller", "Homebrew", "", "", "", "", "", "", "", "ATARIMOUSE", "ATARIMOUSE", "", "", "", "", "", "", "YES", "" }, + { "23d445ea19a18fb78d5035878d9fb649", "CBS Electronics - JWDA, Sylvia Day, Todd Marshall, Henry Will IV", "4L1818, 4L1819, 4L1820, 4L1821", "Mouse Trap (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "23e4ca038aba11982e1694559f3be10f", "", "", "Big Dig (V3) (20-10-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "23fad5a125bcd4463701c8ad8a0043a9", "CCE", "C-840", "Stone Age (1983) (CCE)", "Uses the Joystick Controllers (swapped)", "", "", "", "", "A", "A", "", "YES", "", "", "", "", "", "", "", "", "YES", "" }, + { "240bfbac5163af4df5ae713985386f92", "Activision, Steve Cartwright", "AX-022", "Seaquest (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2432f33fd278dea5fe6ae94073627fcc", "CBS Electronics, Tom DiDomenico", "4L2477, 4L2482, 4L2485, 4L4171", "Blueprint (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "2434102f30eeb47792cf0825e368229b", "Sparrow - Enter-Tech, Paul Walters, Rick Harris, George Hefner, Barbara Ultis", "", "Arkyology (1983) (Sparrow) (Prototype)", "ROM must be started in bank 0", "Prototype", "", "0", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "24385ba7f5109fbe76aadc0a375de573", "CCE", "", "Xevious (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "2447e17a4e18e6b609de498fe4ab52ba", "CCE", "", "Super Futebol (CCE)", "AKA RealSports Soccer", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "244c6de27faff527886fc7699a41c3be", "", "", "Matt Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2450dfa1df70d12b60683185775efed8", "Jeffry Johnston", "", "Radial Pong - Version 7 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "24544ee5d76f579992d9522e9b238955", "Carrere Video - Western Technologies, Jeff Corsiglia, David Johnson, Tom Sloper - Teldec - Prism", "USC2004", "Picnic (1983) (Carrere Video) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "AUTO 45", "", "", "", "" }, + { "245f07c8603077a0caf5f83ee6cf8b43", "Home Vision - Thomas Jentzsch", "", "Parachute (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "24759be31e8fe55d2829fd86bdf3181f", "Hozer Video Games", "", "Gunfight 2600 - Worst Nightmare... (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "247fa1a29ad90e64069ee13d96fea6d6", "CCE", "C-867", "Radar (1983) (CCE)", "AKA Exocet", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "248668b364514de590382a7eda2c9834", "CBS Electronics, Richard K. Balaska Jr., Bob Curtiss, Alex Leavens, Alex Nevelson", "", "Kick-Man (01-08-82) (CBS Electronics) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2496d404bfc561a40a80bea6a69695c3", "CCE", "C-1007", "Jungle Hunt (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "24ad538291eb5f5cac4b9998f3b851c3", "", "", "Gunfight 2600 - This time it's your decission! (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "24aff972d58990f9b88a6d787c796f1e", "CBS Electronics", "4L1767, 4L1768, 4L1769, 4L1770", "Smurf (1982) (CBS Electronics) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "24b5f4bbdb853eca38ea0cae2dfe73a1", "", "", "Home Run (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "", "" }, + { "24b9adac1b4f85b0bac9bf9b9e180906", "Angelino", "", "Space 2002 (Angelino) (Hack)", "Hack of Space Jockey", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "24d018c4a6de7e5bd19a36f2b879b335", "Activision, Larry Miller", "AX-021", "Spider Fighter (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "24d9a55d8f0633e886a1b33ee1e0e797", "Thomas Jentzsch", "", "Dragon Defender (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "24df052902aa9de21c2b2525eb84a255", "Imagic, Dennis Koble", "720000-100, 720100-1B, IA3000, IA3000C", "Trick Shot (1982) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "24fbf8250a71611e40ef18552e61b009", "", "", "Movable Grid Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2516f4f4b811ede4ecf6fbeb5d54a299", "Quelle", "701.134 9", "Schiessbude (1983) (Quelle) (PAL)", "AKA Carnival", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2517827950fee41a3b9de60275c8aa6a", "Atari", "CX26163P", "Fishing (32 in 1) (1988) (Atari) (PAL)", "AKA Fishing Derby", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "25265d0e7f88b3026003809f25ee025e", "Atari - GCC, Ava-Robin Cohen", "CX26123", "Jr. Pac-Man (1984) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "25472dfdeef6a42581a231d631d6b04d", "", "", "Gunfight 2600 - Design thoughts (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "25710bde8fa181b0c5cf0846b983bec1", "", "", "Demo Image Series #15 - Three Marios (NTSC) (06-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "257bc3b72a6b5db3fd0d47619125b387", "CBS Electronics", "4L 2737 0000", "Omega Race (1983) (CBS Electronics) [a]", "Set right difficulty to 'A' for BoosterGrip in both ports", "", "", "", "", "", "", "", "", "BOOSTERGRIP", "BOOSTERGRIP", "", "", "", "", "", "", "", "" }, + { "25a21c47afe925a3ca0806876a2b4f3f", "Quelle", "685.640 5", "Der kleine Baer (1983) (Quelle) (PAL)", "AKA Frostbite", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "25b52bf8dd215bcbd59c9abdb55c44f8", "Atari - GCC, Betty Ryan Tylko, Doug Macrae", "CX2694, CX2694P", "Pole Position (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "25b6dc012cdba63704ea9535c6987beb", "Avalon Hill, Jean Baer, Bill Hood", "5004002", "Shuttle Orbiter (1983) (Avalon Hill)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "25bb080457351be724aac8a02021aa92", "CBS Electronics", "4L1784, 4L1786, 4L1787, 4L2277", "Zaxxon (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "25d4be3309b89583c6b39d9f93bf654f", "Activision, Bob Whitehead", "AX-015, AX-015-04", "Chopper Command (1982) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "25e73efb9a6edf119114718bd2f646ba", "Atari, Suki Lee", "CX26113", "Miss Piggy's Wedding (1983) (Atari) (Prototype) (4K) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "25f2e760cd7f56b88aac88d63757d41b", "Activision, Bob Whitehead - Ariola", "EAG-002, EAG-002-04I, PAG-002 - 711 002-715", "Boxing (1980) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "25f879ff678130fea615ac418e7943f1", "Activision, Garry Kitchen", "EAX-025", "Keystone Kapers (1983) (Activision) (SECAM)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "25f9cf703575c5d63048c222f5463758", "", "", "Multi-Sprite Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "260c787e8925bf3649c8aeae5b97dcc0", "Thomas Jentzsch", "", "Hell Driver (Thomas Jentzsch)", "NTSC Conversion, joystick ports swapped", "Homebrew", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "", "" }, + { "262ccb882ff617d9b4b51f24aee02cbe", "Atari, Douglas Neubauer", "CX26154, CX26154P", "Super Football (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "265a85f66544eaf95fda06c3d9e48abf", "", "", "Tunnel Demo (Cycling Colours) (29-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "265c74a956500bd31efd24adc6d5ccf6", "Activision, Larry Miller", "AX-026, AX-026-04", "Enduro (1983) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2683d29a282dd059535ac3bb250f540d", "", "", "Space Treat (12-01-2003) (Fabrizio Zavagli)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "268f46038e29301568fa9e443e16e960", "Atarius Maximum", "", "Pitfall Unlimited (Atarius Maximus) (Hack)", "Hack of Pitfall", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "26bc2bdf447a17376aea7ef187ff6e44", "", "", "Amanda Invaders (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "26f4f8b098609164effef7809e0121e1", "", "", "Oystron (V2.7) (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "270229c6d5578446e6a588492e4e5910", "", "", "Space Invaders 2 (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2712e91f6f1dc55e90e2b14b27c042ac", "Omegamatrix", "", "SpaceMaster X-7 (Amiga Mouse) (PAL60) (Omegamatrix)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "271bfd5dc2673d382019f1fb6cab9332", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (Preview) (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "273ce50db5a0d6da7ea827a54f44dee9", "", "", "Island Flyer Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "274d17ccd825ef9c728d68394b4569d2", "Playaround - J.H.M.", "202", "Bachelorette Party (1982) (Playaround)", "AKA Bachelor Party, Uses the paddle controllers", "Extremely Rare", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "AUTO 65", "", "", "YES", "" }, + { "277c7281ac945b8331e2e6fcad560c11", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (2 of 3) (1983) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "277cca62014fceebb46c549bac25a2e3", "Activision, Bob Whitehead", "AG-002, CAG-002, AG-002-04", "Boxing (1980) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "277fa4b9a6bb7a8dcea2c5f38a4c25f0", "Atari, Alan J. Murphy, Robert Zdybel", "CX2668", "RealSports Football (1982) (Atari) (Prototype)", "AKA Football II", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "278155fc9956e9b6ef2359eb238f7c7f", "", "", "Donkey Kong Junior (Unknown) (Hack)", "Hack of Donkey Kong Junior", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2783006ee6519f15cbc96adae031c9a9", "Telegames", "", "Night Stalker (1989) (Telegames) (PAL) [a]", "AKA Dark Cavern", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "278531cc31915747018d22145823d2c9", "", "", "Defender MegaDrive (PAL) (Genesis)", "Genesis controller (C is smartbomb)", "Hack of Defender", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "278f14887d601b5e5b620f1870bc09f6", "Thomas Jentzsch", "", "SWOOPS! (v0.96) (TJ)", "Uses the Joystick (L) and Paddle (R) Controllers", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "27a5d2d0c74c8e4b2c05b94c9f098eea", "Atari, Omegamatrix", "", "Video Olympics Menu (2020) (PAL60) (Hack)", "Hack of Video Olympics", "", "", "", "", "", "", "", "", "", "", "YES", "", "", "AUTO 60", "", "", "", "" }, + { "27baecd618e7e53dc11f2a9c559f529d", "Omegamatrix", "", "Star Wars Arcade (Atari Trak-Ball) v4 (Omegamatrix)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "27c4c2af4b46394bb98638af8e0f6e9d", "Atari, Jerome Domurat, Peter C. Niday, Robert Vieira", "CX26109", "Sorcerer's Apprentice (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "27c6a2ca16ad7d814626ceea62fa8fb4", "Parker Brothers, Mark Lesser", "PB5590", "Frogger II (1984) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "27f9e2e1b92af9dc17c6155605c38e49", "CCE", "", "Nightmare (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2808dc745ff4321dc5c8122abef6711f", "Retroactive", "", "Qb (2.11) (Retroactive) (Stella)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "28148a52b1955ce12c7a74d3a3e620a4", "CCE", "", "Freeway (CCE) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "281ff9bd0470643853de5cbd6d9e17f5", "Eckhard Stolberg", "", "Cubis (EM) (1997) (Eckhard Stolberg)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2823364702595feea24a3fbee138a243", "Bit Corporation", "PG206", "Bobby Is Going Home (1983) (BitCorp) (PAL)", "AKA Bobby geht Heim", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2825f4d068feba6973e61c84649489fe", "", "", "Boom Bang (Unknown) (PAL)", "AKA Crackpots", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "282a77841cb3d33af5b56151acba770e", "Otto Versand", "311388", "Black Hole (1983) (Otto Versand) (PAL)", "AKA Cosmic Ark (Double-Game Package)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "283cb03ee031c842beabdad1aa4e7dbc", "Bit Corporation", "R320", "Demon Attack (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "283dee88f295834c4c077d788f151125", "Retroactive", "", "Qb (2.11) (Retroactive) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "284ca61b2407bdba3938048b0a559015", "Atari, Tod Frye", "CX2695", "Xevious (05-25-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "2854e5dfb84173fafc5bf485c3e69d5a", "Canal 3 - Intellivision", "C 3004", "Moon Patrol (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2880c6b59bd54b153174676e465167c7", "Tron", "", "Donkey Kong Jr. (Tron)", "AKA Donkey Kong Junior", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "28a2bea8f84936cb2e063f857414cda0", "Thiago Paiva", "", "Mega Mania Raid (1999) (Thiago Paiva) (Hack)", "Hack of Megamania", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "28a4cd87fb9de4ee91693a38611cb53c", "", "", "Skeleton (V1.1) (NTSC) (24-10-2002) (Eric Ball)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "28d5df3ed036ed63d33a31d0d8b85c47", "Bit Corporation", "PG204", "Open, Sesame! (1983) (BitCorp) (PAL)", "AKA Sesam, Offne Dich", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "2903896d88a341511586d69fcfc20f7d", "Activision, David Crane", "AX-014, AX-014-04", "Grand Prix (1982) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "291bcdb05f2b37cdf9452d2bf08e0321", "Atari", "CX26163P", "32 in 1 Game Cartridge (1988) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "32IN1", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "291cc37604bc899e8e065c30153fc4b9", "Activision, Carol Shaw", "AX-020, AX-020-04", "River Raid (1982) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "291dd47588b9158beebe4accc3a093a6", "Atari", "", "32 in 1 Console ROM (02-10-1989) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "32IN1", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "292a0bb975b2587f9ac784c960e1b453", "", "", "Qb (05-02-2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "292f2446a0325b7b423e88a2ebfeb5a0", "", "", "Cube Conquest (Non Interlaced) (Billy Eno) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "29396db58406084e416032c372734a3e", "", "", "Gunfight 2600 - Fixed Beta Release! (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2942680c47beb9bf713a910706ffabfe", "", "", "Blue Line Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "294762000e853b4319f9991c1ced5dfc", "", "", "T.F. Space Invaders (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "295f3679bdf91ca5e37da3f787b29997", "", "", "Exorcise (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "29630a20d356fb58685b150bfa8f00c3", "M Network, Kevin Miller", "MT5687", "International Soccer (1982) (Mattel) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "297236cb9156be35679f83c4e38ee169", "Exus Corporation", "", "Video Reflex (1983) (Exus) [no roman numbers]", "AKA Foot Craz (no roman numbers)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "297c405afd01f3ac48cdb67b00d273fe", "Atari - GCC, Ava-Robin Cohen", "CX26123, CX26123P", "Jr. Pac-Man (1986) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2982e655dffc89d218a0a3072cfc6811", "", "", "Mini Golf 812631 (Hack)", "Hack of Miniature Golf", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "298387b0637173d2002770a649b4fbca", "", "", "S.I.PLIX 2 (Hack) [a]", "Hack of Kaboom!", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, + { "29843f43b81f3736bf35c00b1bb88fb2", "Gray Games & AtariAge", "", "E.T. Book Cart (NTSC)", "Charles F. Gray & Michael Rideout", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "55" }, + { "29949f893ef6cb9e8ecb368b9e99eee4", "Erik Eid", "", "Euchre (Alpha) (NTSC) (31-08-2002) (Erik Eid)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "29dfa26b7988af9984d617708e4fc6e2", "", "", "Boulderdash Demo (05-04-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2a0ba55e56e7a596146fa729acf0e109", "Activision, Bob Whitehead", "AG-019", "Sky Jinks (1982) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2a10053fd08664c7cfbbb104386ed77f", "", "", "Alpha Demo - The Beta Demo (2000) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2a1b454a5c3832b0240111e7fd73de8a", "Tigervision, Bill Hogue", "7-011", "Miner 2049er Volume II (1983) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "2a2f46b3f4000495239cbdad70f17c59", "CommaVid, John Bronstein - Ariola", "CM-003 - 712 003-720", "Cosmic Swarm (1982) (CommaVid) (PAL)", "AKA Angriff der Termiten", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "2a33e21447bf9e13dcfed85077ff6b40", "", "", "Backwards Cannonball v2 (Hack)", "Hack of Human Cannonball", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2a360bc85bf22de438651cf92ffda1de", "Bit Corporation", "PGP213", "Spy Vs. Spy (4 Game in One) (1983) (BitCorp) (PAL)", "AKA Chopper Command", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2a9f9001540c55a302befd8e9d54b47b", "Atari, Dan Hitchens", "CX2697, CX2697P", "Mario Bros. (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2aa5e56d36c2e58b6f2856109f2099a9", "Atari, Larry Kaplan - Sears", "CX2628 - 6-99842, 49-75117", "Bowling (1979) (Atari) (4K) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2aba6a1b01a5859e96d6a66d2286772f", "Activision, Steve Cartwright", "AX-027", "Plaque Attack (1983) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2abc3d46b3f2140160759e2e10bc86d9", "", "", "Gunfight 2600 - Beta Release! (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2ac3a08cfbf1942ba169c3e9e6c47e09", "Activision, Dan Kitchen", "EAK-046-04B", "Fighter Pilot (1988) (Activision) (PAL)", "AKA Tomcat - The F-14 Fighter Simulator", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2ae700c9dba843a68dfdca40d7d86bd6", "TechnoVision - Thomas Jentzsch", "", "Pharaoh's Curse (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "2aeedcc6eb1602efb77161b0cef832ab", "SOLID Corp. (D. Scott Williamson)", "CX2655-025", "Star Castle 2600 (SolidCorp) [025]", "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "2b1589c7e1f394ae6a1c046944f06688", "Carrere Video - JWDA, Todd Marshall, Robin McDaniel, Wes Trager, Henry Will IV - Teldec - Prism", "USC2003", "Eggomania (1983) (Carrere Video) (PAL)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "", "", "AUTO 60", "", "", "", "" }, + { "2b27eb194e13f3b38d23c879cc1e3abf", "Quelle", "402.272 9", "Super-Ferrari (1983) (Quelle) (PAL)", "AKA Enduro", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2b42da79a682ed6e2d735facbf70107e", "", "", "DKjr Improved (Hack)", "Hack of Donkey Kong Jr.", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2b430c00dc79e495762ac59b2f9b4fcd", "Activision, David Crane", "AX-018, AX-018-04", "Pitfall! (1982) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2b71a59a53be5883399917bf582b7772", "Greg Troutman", "", "Dark Mage (final beta) (Greg Troutman) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "2ba02f509a4991aa176ba8d9e540df3d", "Atari, Mark R. Hahn", "CX2678", "Dukes of Hazzard (1983) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2bb0a1f1dee5226de648eb5f1c97f067", "Robby", "", "Enduro (Robby)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2bb9f4686f7e08c5fcc69ec1a1c66fe7", "Atari - GCC, John Allred, Mike Feinstein", "CX2688", "Jungle Hunt (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2bc26619e31710a9884c110d8430c1da", "Atari, Bob Whitehead", "CX2652, CX2652P", "Casino (1979) (Atari) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "", "", "", "", "" }, + { "2bc6c53b19e0097a242f22375a6a60ff", "", "", "Droid Demo 2 (David Conrad Schweinsberg) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2bee7f226d506c217163bad4ab1768c0", "Xonox - K-Tel Software - Beck-Tech, Steve Beck", "6210, 06002, 06004, 99002", "Ghost Manor (1983) (Xonox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2bf34b6ad7d2317a2d0808b3fb93571b", "", "", "Easy Playfield Graphics (1997) (Chris Cracknell)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2c0dc885d5ede94aa664bf3081add34e", "", "", "Earth Dies Screaming, The (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2c29182edf0965a7f56fe0897d2f84ba", "Atari - Axlon, Steve DeFrisco", "CX26192", "Klax (08-18-1990) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2c2aea31b01c6126c1a43e10cacbfd58", "Paul Slocum", "", "Synthcart (2002) (Paul Slocum)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "2c3b2843295c9d6b16996971180a3fe9", "HES - Activision", "", "Sports Action Pak - Enduro, Ice Hockey, Fishing Derby, Dragster (1988) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2c3b9c171e214e9e46bbaa12bdf8977e", "Bit Corporation", "R320", "Othello (32 in 1) (BitCorp)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2c45c3eb819a797237820a1816c532eb", "Atari", "CX26163P", "Boxing (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2c8835aed7f52a0da9ade5226ee5aa75", "Arcadia Corporation, Stephen H. Landrum", "AR-4101", "Communist Mutants from Space (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2c8c11295d8613f875b7bcf5253ab9bb", "Fabrizio Zavagli", "", "Kool Aid Man (PAL Conversion) (16-11-2002) (Fabrizio Zavagli) (PAL60)", "PAL60 Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2c9fadd510509cc7f28f1ccba931855f", "", "", "Hangman Invader Biglist1 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2ca6445204ffb7686ddee3e33ba64d5b", "Alex Herbert", "", "AtariVox Test ROM", "Uses the AtariVox controller", "", "", "", "", "", "", "", "", "", "ATARIVOX", "", "", "", "", "", "", "", "" }, + { "2cb42cf62b2f25f59f909b5447821b14", "Atari, Christopher H. Omarzu - Children's Computer Workshop", "CX26104", "Big Bird's Egg Catch (1983) (Atari) (PAL) [a]", "Uses Kids/Keypad Controllers", "", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "", "" }, + { "2cc3049b7feb8e92f1870f1972629757", "Video Soft", "", "Atom Smasher (1984) (Video Soft) (Prototype) [stack pointer fix]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2cccc079c15e9af94246f867ffc7e9bf", "PlayAround - J.H.M.", "203", "Jungle Fever (1982) (PlayAround)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "2cefa695df2ed020899a7df7bb1e3a95", "Manuel Polik, Fabrizio Zavagli", "", "A-Team (2002) (Manuel Polik) (Hack)", "Hack of A-Team", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2cf20f82abcae2decff88db99331e071", "Activision, Mike Lorenzen", "AX-023", "Oink! (1983) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2cfb188c1091cc7ec2a7e60064d2a758", "", "", "Space Invaders Hack Demo (2003) (SnailSoft)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2d15b092e8350912ec4b2e5e750fa1c6", "Wizard Video Games, Bob Davis, Robert H. O'Neil", "", "Texas Chainsaw Massacre, The (1982) (Wizard Video Games) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2d16a8b59a225ea551667be45f554652", "Quelle", "802.744 3", "Der Geheimkurier (1983) (Quelle) (PAL)", "AKA Mr. Postman", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2d1cf85fbc732856bf76470cd4060f4a", "", "", "Daredevil (V1) (Stunt_Cycle_Rules!) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2d2c5f0761e609e3c5228766f446f7f8", "Atari - Axlon, Steve DeFrisco", "CX26170, CX26170P", "Secret Quest (1989) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2d33a44e82f88d05f6c50577218c0cae", "AtariAge - Michael Haas", "RC2", "Flappy (2014) (AtariAge)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2d38a96f92952b301eefdf25a5e6976b", "Omegamatrix", "", "Star Wars Arcade (Atari Mouse) (Y_Inverted) v4 (Omegamatrix)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2d405da70af82b20a6b3ecc3d1d2c4ec", "Genus", "", "Pitfall (Genus)", "AKA Pitfall!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2d6388a8389f1d59108fd169c3356d79", "Thomas Jentzsch", "", "Reactor - Atari Mouse Hack v1.3 (NTSC) (Half-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2d63b452f897818c52b3fceeb080a4d0", "HES - Absolute Entertainment", "", "Pete Rose Baseball (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2d6741cda3000230f6bbdd5e31941c01", "CBS Electronics - VSS", "80110", "Targ (1983) (CBS Electronics) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2d69a5f23784f1c2230143292a073b53", "", "", "Qb (Fixed background animation) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "2d6da0eb85eabc93270e5bb8a466ca51", "", "", "Sprite Demo 7 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2d76c5d1aad506442b9e9fb67765e051", "Apollo - Games by Apollo, Larry Minor, Ernie Runyon, Ed Salvo", "AP-2004", "Lost Luggage (1982) (Apollo) [no opening scene]", "AKA Airport Mayhem", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2d9e5d8d083b6367eda880e80dfdfaeb", "QDI, Mike Montana, Rich Montana - Selchow & Righter", "87", "Glib (1983) (QDI)", "AKA Video Word Game", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2d9e65959808a6098c16c82a59c9d9dc", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (1 of 3) (1982) (Starpath) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2dbc92688f9ba92a7e086d62be9df79d", "", "", "How to Draw a Playfield (1997) (Jim Crawford) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2dbdca3058035d2b40c734dcf06a86d9", "Thomas Jentzsch", "", "Asteroids DC+ (Thomas Jentzsch) (Hack)", "Uses the Joystick (left) or Driving (right) Controller", "Hack", "", "", "", "", "", "", "", "", "DRIVING", "", "", "", "58", "", "", "YES", "" }, + { "2dcf9ce486393cd36ca0928cd53b96cb", "Atari - GCC, Mike Feinstein, John Allred", "CX2688, CX2688P", "Jungle Hunt (1983) (Atari) (PAL) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2de41a11c6767e54a5ee9ebaffec72af", "Gray Games & AtariAge", "", "E.T. Book Cart (PAL60)", "Charles F. Gray & Michael Rideout", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "55" }, + { "2dfec1615c49501fefc02165c81955e6", "", "", "Song (05-11-2002) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "2e0aed5bb619edcefa3fafb4fbe7c551", "", "", "Qb (2.06) (Retroactive) (NTSC)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "2e2acef8513edcca991e7e5149412e11", "Parker Brothers, Larry Gelberg, Gary Goltz", "PB5065", "Star Wars - Ewok Adventure (1983) (Parker Bros) (Prototype) (16K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2e3728f3086dc3e71047ffd6b2d9f015", "Atari, David Crane", "CX26163P", "Outlaw (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2e5b184da8a27c4d362b5a81f0b4a68f", "Atari", "", "Rabbit Transit (08-29-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2e663eaa0d6b723b645e643750b942fd", "Atari, Tom Rudadahl - Sears", "CX2634 - 49-75121", "Golf (1980) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2e7e9c6dcfcceaffc6fa73f0d08a402a", "CCE", "C-818", "Star Voyager (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2e82a1628ef6c735c0ab8fa92927e9b0", "Atari, Jerome Domurat, Peter C. Niday, Robert Vieira", "CX26109", "Sorcerer's Apprentice (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2e842c2ee22e9dad9df16eed091315c4", "HES", "701-157", "2 Pak Special - Moto-cross, Boom Bang (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2eaf8fa9e9fdf1fcfc896926a4bdbf85", "Arcadia Corporation, Stephen H. Landrum", "AR-4400", "Excalibur Version 39 (Dragonstomper Beta) (1982) (Arcadia) (Prototype)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2ec6b045cfd7bc52d9cdfd1b1447d1e5", "Activision, David Crane - Ariola", "EAG-009, PAG-009 - 711 009-720", "Freeway (1981) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2eda6a49a49fcb2b674ea9e160b6a617", "Kyle Pittman", "", "Rambo in Afghanistan (Kyle Pittman) (Hack)", "Hack of Riddle of the Sphinx", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2ef36341d1bf42e02c7ea2f71e024982", "", "", "Space Invaders (Explosion Hack)", "Hack of Space Invaders (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2f0546c4d238551c7d64d884b618100c", "SEGA, Jeff Lorenz", "", "Ixion (1984) (SEGA) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2f0a8bb4e18839f9b1dcaa2f5d02fd1d", "CCE", "", "Super Futebol (CCE) [a]", "AKA RealSports Football", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "2f11ba54609777e2c6a5da9b302c98e8", "Atari - GCC", "CX2676", "Centipede (1982) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2f16663b01591539624d0ef52934a17d", "M Network", "", "Rocky and Bullwinkle", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2f2f9061398a74c80420b99ddecf6448", "Rentacom - Brazil", "", "Bobby Is Going Home (Rentacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2f66ebf037321ed0442ac4b89ce22633", "Baroque Gaming (Brian Eno)", "", "Warring Worms (Beta 2) (2002) (Baroque Gaming)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2f7772879a1ed04f660aa9d77a86a4bd", "", "", "Yars' Revenge (Genesis)", "Genesis controller (C is zorlon cannon)", "Hack of Yars' Revenge", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "2f77f015fc880b05f28e84156f989a0c", "", "", "Plane Demo (Gonzalo) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2f7949f71076db42480d3f5036b4a332", "", "", "Name This Game (208 in 1) (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "2facd460a6828e0e476d3ac4b8c5f4f7", "Sancho - Tang's Electronic Co.", "", "Words-Attack (1983) (Sancho) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "3025bdc30b5aec9fb40668787f67d24c", "", "", "Demo Image Series #14 - Two Marios (4K Interleaved Chronocolour Vertical Movement) (05-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "303242c239474f2d7763b843de58c1c3", "CCE", "", "Laser Blast (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "304512528a5530a9361e8a231ed9a6de", "Thomas Jentzsch", "", "River Raid Plus (Thomas Jentzsch) (Hack)", "Hack of River Raid", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "30512e0e83903fc05541d2f6a6a62654", "Atari, Jim Huether - Sears", "CX2644 - 6-99824", "Flag Capture (1978) (Atari)", "AKA Capture the Flag", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "30516cfbaa1bc3b5335ee53ad811f17a", "Wizard Video Games - MicroGraphic Image, Robert Barber, Tim Martin", "007", "Halloween (1983) (Wizard Video Games)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3051b6071cb26377cd428af155e1bfc4", "Atari, David Crane - Sears", "CX2607 - 6-99828, 49-75115", "Canyon Bomber (1979) (Atari) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "YES", "", "", "10", "", "", "", "" }, + { "30685b9b6ebd9ba71536dd7632a1e3b6", "Dactari - Milmar", "", "Tennis (Dactari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3091af0ef1a61e801f4867783c21d45c", "CCE", "C-862", "Crackpots (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "30997031b668e37168d4d0e299ccc46f", "", "", "John K Harvey's Equalizer (PAL) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "30c92c685224dc7a72b9bbe5eb62d004", "", "", "Hangman Monkey Original Words (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "30e012e8d50330c8972f126b8e913bc4", "", "", "Indy 500 (Hack) [a2]", "Hack of Indy 500", "Hack", "", "", "", "", "", "", "", "DRIVING", "DRIVING", "", "", "", "", "", "", "", "" }, + { "30e0ab8be713208ae9a978b34e9e8e8c", "Atari, Mike Lorenzen", "CX2630, CX2630P", "Circus Atari (1980) (Atari) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "01 55", "", "", "", "" }, + { "30f0b49661cfcfd4ec63395fab837dc3", "SEGA, Jeff Lorenz - Teldec", "004-01", "Star Trek - Strategic Operations Simulator (1983) (SEGA) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "3105967f7222cc36a5ac6e5f6e89a0b4", "SEGA, Jeff Lorenz", "011-01, 011-02", "Spy Hunter (1984) (SEGA)", "Uses Joystick Coupler (Dual Control Module)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "310ba30e25ea8957e58180b663503c0c", "Ed Federmeyer", "", "Sound X6 (1994) (Ed Federmeyer)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "31235a27b065c2863048fa84db330dc6", "Thomas Jentzsch", "", "Missile Control - Amiga Mouse Hack v1.15 (PAL) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "313243fc41e49ef6bd3aa9ebc0d372dd", "", "", "Fast Food (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "31512cdfadfd82bfb6f196e3b0fd83cd", "Tigervision", "7-004", "River Patrol (1984) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3177cc5c04c1a4080a927dfa4099482b", "Atari - Imagineering, Alex DeMeo", "CX26135", "RealSports Boxing (1987) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "317a4cdbab090dcc996833d07cb40165", "Goliath - Hot Shot", "83-312", "Missile War (1983) (Goliath) (PAL)", "AKA Astrowar", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "318046ae3711c05fd16e479b298e5fcc", "Retroactive", "", "Qb (V2.08) (Stella) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "318a9d6dda791268df92d72679914ac3", "Activision, Steve Cartwright", "AX-017, AX-017-04", "MegaMania (1982) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "319a142aab6260842ab616382848c204", "", "", "Marble Craze (05-02-2002) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "31bb9b8ceed46cb3e506777a9e65f3ce", "Bit Corporation", "", "4 Game in One Light Green (1983) (BitCorp) (PAL)", "Phantom UFO, Ice Hockey, Cosmic Avenger, Spy Vs. Spy", "", "", "", "4IN1", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "31c5fd55a39db5ff30a0da065f86c140", "Dactari - Milmar", "", "Enduro (Dactari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "31d08cb465965f80d3541a57ec82c625", "Atari, Alan Miller - Sears", "CX2641 - 99807, 49-75105", "Surround (1977) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "31df1c50c4351e144c9a378adb8c10ba", "Quelle", "687.463 0", "Die Ratte und die Karotten (1983) (Quelle) (PAL)", "AKA Gopher", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "31e518debba46df6226b535fa8bd2543", "Atari, Douglas 'Solaris' Neubauer, Mimi Nyden", "CX26134", "Last Starfighter (1984) (Atari) (Prototype)", "Solaris Beta", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "31f4692ee2ca07a7ce1f7a6a1dab4ac9", "Atari, Alan Miller", "CX2642", "Game of Concentration (1980) (Atari) (4K)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "31fcbce1cfa6ec9f5b6de318e1f57647", "Atari, Jerome Domurat, Peter C. Niday", "CX26115", "Dumbo's Flying Circus (1983) (Atari) (Prototype) (PAL)", "AKA Dumbo Flies Home", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "32199271dc980eb31a2cc96e10a9e244", "", "", "Radial Pong - Version 12 (Jeffry Johnston) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "321c3451129357af42a375d12afd4450", "Atari - Imagineering, Dan Kitchen", "CX26177", "Ikari Warriors (1991) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "32244e55ce6ec6bfbd763f33384bdc2e", "Activision, Steve Cartwright", "AX-027", "Plaque Attack (1983) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3225676f5c0c577aeccfaa7e6bedd765", "CCE", "C-1002", "Pole Position (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "322b29e84455aa41e7cc9af463bffa89", "Atari - Bobco, Robert C. Polaro", "CX2663", "Road Runner (06-25-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "324cb4a749bcac4f3db9da842b85d2f7", "Dennis Debro", "", "Climber 5 (01-05-2003) (Dennis Debro)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "327468d6c19697e65ab702f06502c7ed", "Charles Morgan", "", "Aster-Hawk (2002) (Charles Morgan) (Hack)", "Hack of Asteroids", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "3276c777cbe97cdd2b4a63ffc16b7151", "Atari - GCC, Mike Feinstein, Kevin Osborn", "CX2691", "Joust (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "3278158e5c1f7eb5c5d28ccfd7285250", "Dactari - Milmar", "", "Megamania (Dactari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "327fe8cf94f3a45c35a840a453df1235", "", "", "Spice Girls Rule Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "328949872e454181223a80389d03c122", "", "", "Home Run (Unknown) (PAL)", "", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "", "" }, + { "32ae78abbb5e677e2aabae5cc86cec29", "Atari, Christopher H. Omarzu, Courtney Granner", "CX26112", "Good Luck, Charlie Brown (04-18-1984) (Atari) (Prototype)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "32d1260ea682e1bb10850fa94c04ec5f", "Atari, Alan Miller", "CX26163P", "Basketball (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "32dcd1b535f564ee38143a70a8146efe", "Xonox - K-Tel Software - Product Guild, Anthony R. Henderson", "99007, 6240", "Tomarc the Barbarian (1983) (Xonox)", "AKA Thundarr the Barbarian", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "32e65d1e4dfcbcd9b57fee72cafe074c", "", "", "Eckhard Stolberg's Scrolling Text Demo 3 (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "32ecb5a652eb73d287e883eea751d99c", "Dactar - Milmar", "", "Bowling (Dactar - Milmar)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "32f4e47a71601ab06cfb59e1c6a0b846", "Ed Federmeyer", "", "Sound X (1994) (Ed Federmeyer)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3316ee2f887e9cb9b54dd23c5b98c3e2", "", "", "Texas Golf (miniature Gold Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "331938989f0f33ca39c10af4c09ff640", "Zach Matley", "", "Combat - Tank AI (19-04-2003) (Zach Matley)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "332f01fd18e99c6584f61aa45ee7791e", "", "", "X'Mission (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "3347a6dd59049b15a38394aa2dafa585", "Parker Brothers - JWDA, Henry Will IV", "PB5760", "Montezuma's Revenge (1984) (Parker Bros)", "Featuring Panama Joe", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "335793736cbf6fc99c9359ed2a32a49d", "", "", "Analog Clock (V0.0) (20-01-2003) (AD) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "335a7c5cfa6fee0f35f5824d1fa09aed", "SEGA - Beck-Tech, Steve Beck, Phat Ho - Teldec", "006-01 - 3.60105 VG", "Congo Bongo (1983) (SEGA) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3367eeba3269aa04720abe6169767502", "", "", "Space Treat (30-12-2002) (Fabrizio Zavagli)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "336ea20d38f98926919d4b4651d1a03f", "Omegamatrix", "", "Omega Race (Genesis) V2", "Genesis controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3391f7c4c656793f92299f4187e139f7", "Commavid, Ben Burch", "CM-010", "Rush Hour (1983) (Commavid) (Prototype) [a4]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "33cac5e767a534c95d292b04f439dc37", "Jone Yuan Telephonic Enterprise Co", "", "Tapeworm (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "33d68c3cd74e5bc4cf0df3716c5848bc", "CBS Electronics, Tom DiDomenico", "4L 2486 5000", "Blueprint (1983) (CBS Electronics)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "33ed6dfac4b9ea2f81f778ceddbb4a75", "Activision", "", "River Raid (1982) (SpkSoft) [t1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "340f546d59e72fb358c49ac2ca8482bb", "Sancho - Tang's Electronic Co.", "TEC003", "Skindiver (1983) (Sancho) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "34340c8eecd1e557314789cc6477e650", "Joe Grand", "", "SCSIcide Pre-release 4 (Joe Grand)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "345488d3b014b684a181108f0ef823cb", "CBS Electronics, Tom DiDomenico", "4L 2486 5000", "Blueprint (1983) (CBS Electronics) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "345758747b893e4c9bdde8877de47788", "CBS Electronics, Joseph Biel", "4L1802, 4L1803, 4L1804, 4L2278", "Venture (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "345769d085113d57937198262af52298", "Rainbow Vision - Suntek", "SS-007", "Space Raid (1983) (Rainbow Vision) (PAL)", "AKA MegaMania", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "346555779a2d51b48833463b5433472f", "Thomas Jentzsch", "", "Thrust (V0.1) (2000) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "348615ffa30fab3cec1441b5a76e9460", "Activision, Alan Miller - Ariola", "EAX-016, PAX-016 - 711 016-725", "StarMaster (1982) (Activision) (PAL) [fixed]", "Use Color/BW switch to change between galactic chart and front views", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "34b269387fa1aa5a396636f5ecdd63dd", "", "", "Marble Craze (mc7_23) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "34c808ad6577dbfa46169b73171585a3", "Apollo", "AP-2012", "Squoosh (1983) (Apollo) (Prototype)", "AKA Vat's Incredible!, The Grape Escape", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "34ca2fcbc8ba4a0b544acd94991cfb50", "Atari, Robert C. Polaro", "", "Dukes of Hazzard (1980) (Atari) (Prototype) (4K)", "AKA Stunt Cycle", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "34e37eaffc0d34e05e40ed883f848b40", "Retroactive", "", "Qb (2.15) (Retroactive) (Stella)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "34f4b1d809aa705ace6e46b13253fd3b", "Aaron Bergstrom", "", "Nothern Alliance (Aaron Bergstrom) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "34fd4fcb40ff5babce67f8b806d5969c", "", "", "Boxing (Dactari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "350e0f7b562ec5e457b3f5af013648db", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX26119", "Saboteur (06-09-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "35156407e54f67eb1f625450d5c093e1", "", "", "Mouse Trap (Genesis)", "Genesis controller (C changes to dog)", "Hack of Mouse Trap", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "35163b56f4a692a232ae96ad3e23310f", "Retroactive", "", "Qb (2.12) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "3545eb3b8b1e7dc19f87d231ab0b1d4c", "CBS Electronics - Roklan, Joe Hellesen, Joe Wagner", "M8774, M8794", "Wizard of Wor (1982) (CBS Electronics) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3556e125681aea864e17b09f3f3b2a75", "", "", "Incoming (2 Player Demo) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3576037c9281656655fa114a835be553", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (1 of 4) (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3577e19714921912685bb0e32ddf943c", "TechnoVision - Video Technology", "TVS1003", "Pharaoh's Curse (1983) (TechnoVision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "35ae903dff7389755ad4a07f2fb7400c", "", "", "Colored Wall Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "35b10a248a7e67493ec43aeb9743538c", "Dor-x", "", "Defender (Dor-x) (Hack)", "Hack of Defender", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "35b43b54e83403bb3d71f519739a9549", "Parker Brothers, Dave Engman, Isabel Garret", "", "McDonald's (06-06-1983) (Parker Bros) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "35be55426c1fec32dfb503b4f0651572", "Men-A-Vision", "", "Air Raid (Men-A-Vision) (PAL)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "35fa32256982774a4f134c3347882dff", "Retroactive", "", "Qb (V0.05) (Macintosh) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "360ba640f6810ec902b01a09cc8ab556", "Atari, Jerome Domurat, Steve Woita", "CX2699", "Taz (06-15-1983) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "360c0dcb11506e73bd0b77207c81bc62", "Digitel", "", "Enduro (1983) (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3619786f6a32efc1e4a262d5aca8a070", "Atari, John Dunn - Sears", "CX2631 - 49-75152", "Superman (1979) (Atari) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3624e5568368929fabb55d7f9df1022e", "Activision - Imagineering, Donald Hahn, Dan Kitchen", "EAK-050-04", "Double Dragon (1989) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "36306070f0c90a72461551a7a4f3a209", "U.S. Games Corporation - JWDA, Roger Booth, Sylvia Day, Ron Dubren, Todd Marshall, Robin McDaniel, Wes Trager, Henry Will IV", "VC1007", "Name This Game (1983) (U.S. Games)", "AKA Octopussy", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "36547bc6faa5132b87504e18d088e1d7", "", "", "Cosmic Swarm (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "367411b78119299234772c08df10e134", "Atari", "CX26163P", "Skiing (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3685060707df27d4091ba0ea2dc4b059", "", "", "PezZerk - PezMan in Ghost Manor (Hack)", "Hack of Berzerk", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "368d88a6c071caba60b4f778615aae94", "Atari, Matthew L. Hubbard", "CX26159", "Double Dunk (1989) (Atari)", "AKA Super Basketball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "36a701c60a9f9768d057bc2a83526a80", "", "", "Cube Conquest (Interlaced) (Billy Eno) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "36b20c427975760cb9cf4a47e41369e4", "Coleco - Woodside Design Associates - Imaginative Systems Software, Garry Kitchen", "2451", "Donkey Kong (1982) (Coleco)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "36c29ceee2c151b23a1ad7aa04bd529d", "Atari - GCC, Ava-Robin Cohen", "CX26123", "Jr. Pac-Man (1986) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "36c31bb5daeb103f488c66de67ac5075", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix - Bop a Buggy (1 of 3) (1983) (Arcadia)", "Uses Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "01 56", "", "", "", "" }, + { "36c993dc328933e4dd6374a8ffe224f4", "Gameworld, J. Ray Dettling", "133-007", "Bermuda Triangle (1983) (Gameworld) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "36e47ed74968c365121eab60f48c6517", "Quelle", "343.373 7", "Master Builder (1983) (Quelle) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "36edef446ab4c2395666efc672b92ed0", "Atari - Axlon, John Vifian", "CX26168", "Off the Wall (1989) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "36f9a953ebdd9a8be97ccf27a2041903", "", "", "Chinese Character Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "37252757a79dc5b174e3c03d6ea0bdcb", "", "", "Sky Diver (Unknown) (PAL) (4K) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "372bddf113d088bc572f94e98d8249f5", "Bomb - Onbase", "CA285", "Wall-Defender (1983) (Bomb) (PAL)", "AKA Wall Break", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "373b8a081acd98a895db0cb02df35673", "", "", "Demo Image Series #5 - Boofly (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3750f2375252b6a20e4628692e94e8b1", "Dismac", "", "Ases do Ar (Dismac)", "AKA Sky Jinks", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "37527966823ee9243d34c7da8302774f", "", "", "Word Zapper (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "376944889dcfa96c73d3079f308e3d32", "Retroactive", "", "Qb (0.11) (Retroactive) (Stella)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "3783f12821b88b08814da8adb1a9f220", "", "", "Mission Survive (PAL) (Genesis)", "Genesis controller (C is vertical fire)", "Hack of Mission Survive)", "", "", "", "", "A", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "378a62af6e9c12a760795ff4fc939656", "Atari - Axlon, Steve DeFrisco", "CX26171", "MotoRodeo (1991) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "378c118b3bda502c73e76190ca089eef", "Atari, Alan Miller", "CX2662P", "Hangman (1978) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "37ab3affc7987995784b59fcd3fcbd31", "", "", "Sprite Test (29-11-2002) (Eric Ball)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "37b98344c8e0746c486caf5aaeec892a", "K-Tel Vision", "6", "Spider Maze (1982) (K-Tel Vision) (PAL)", "AKA Spider Kong", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "37e828675d556775ae8285c0caf7d11c", "AtariAge - Fred Quimby", "", "Gingerbread Man (Fred Quimby) (Genesis)", "Genesis controller (C throws cookie)", "New Release", "", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "", "" }, + { "37f42ab50018497114f6b0f4f01aa9a1", "", "", "Droid Demo 2-M (David Conrad Schweinsberg) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "37fd7fa52d358f66984948999f1213c5", "Rainbow Vision - Suntek", "SS-004", "Pyramid War (1983) (Rainbow Vision) (PAL) [a2]", "AKA Chopper Command", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "384db97670817103dd8c0bbdef132445", "Atari - Sears", "CX2626 - 6-99829, 49-75116", "Miniature Golf (1979) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "384f5fbf57b5e92ed708935ebf8a8610", "20th Century Fox Video Games, John W.S. Marvin", "11009", "Crypts of Chaos (1983) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3856b9425cc0185ed770376a62af0282", "Kyle Pittman", "", "Yellow Submarine (Kyle Pittman) (Hack)", "Hack of Bermuda Triangle", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "386ff28ac5e254ba1b1bac6916bcc93a", "Arcadia Corporation, Scott Nelson", "AR-4300", "Fireball (1982) (Arcadia)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "01", "", "", "", "" }, + { "3882224adbd0ca7c748b2a1c9b87263e", "Atari, Tod Frye", "CX2657", "SwordQuest - FireWorld (1982) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3889351c6c2100b9f3aef817a7e17a7a", "CCE", "", "Dolphin (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3897744dd3c756ea4b1542e5e181e02a", "Atari, Jerome Domurat, Peter C. Niday", "CX26115", "Dumbo's Flying Circus (05-05-1983) (Atari) (Prototype)", "AKA Dumbo Flies Home", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "38bd172da8b2a3a176e517c213fcd5a6", "Atari", "MA017600", "Diagnostic Test Cartridge 2.6 (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "38c362dcd5cad5a62e73ae52631bd9d8", "Jake Patterson", "", "Baubles (14-11-2001) (Jake Patterson) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "38cf93eacfb2fa9a2c5e39059ff35a74", "Greg Zumwalt", "", "WacMan (2003) (Greg Zumwalt) (Hack)", "Hack of Ms. Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "38de7b68379770b9bd3f7bf000136eb0", "Imagic, Mark Klein", "EIZ-003-04I", "Subterranea (1983) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "391764720140c432aec454a468f77a40", "Video Game Program", "", "Miss Pack Man (Video Game Program) (PAL)", "AKA Ms. Pac-Man", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "392d34c0498075dd58df0ce7cd491ea2", "Atari, Frank Hausman, Mimi Nyden, Steve Woita", "CX2686", "Quadrun (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "392f00fd1a074a3c15bc96b0a57d52a1", "Atari, Rob Fulop - Sears", "CX2633 - 49-75119", "Night Driver (1980) (Atari)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "", "", "AUTO 65", "", "", "YES", "" }, + { "393948436d1f4cc3192410bb918f9724", "Activision, Carol Shaw", "AX-020, AX-020-04", "River Raid (1982) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "393e41ca8bdd35b52bf6256a968a9b89", "U.S. Games Corporation - Western Technologies, John Hall", "VC1012", "M.A.D. (1983) (U.S. Games)", "AKA Missile Intercept, Mutually Assured Destruction", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3947eb7305b0c904256cdbc5c5956c0f", "Jone Yuan Telephonic Enterprise Co", "", "Lilly Adventure (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "396f7bc90ab4fa4975f8c74abe4e81f0", "Atari, Larry Kaplan - Sears", "CX2612 - 99804, 49-75103", "Street Racer (1977) (Atari)", "Uses the Paddle Controllers (swapped)", "", "", "", "", "", "", "", "", "", "", "YES", "", "", "AUTO 60", "", "", "", "" }, + { "3974e2d1f614fbd3a092533ecae2e84d", "Alessandro Ciceri", "", "MagiCard+ (alex_79) WIP_20150118", "MagiCard hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "39790a2e9030751d7db414e13f1b6960", "", "", "Robotfindskitten2600 (26-04-2003) (Jeremy Penner) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "39a6a5a2e1f6297cceaa48bb03af02e9", "", "", "Pitfall 2 Plus (Hack)", "Hack of Pitfall 2", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "39b94d41bd3b01c12b4054c1a8733783", "SOLID Corp. (D. Scott Williamson)", "CX2655-016", "Star Castle 2600 (SolidCorp) [016]", "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "39c78d682516d79130b379fa9deb8d1c", "Apollo - Games by Apollo, Ed Salvo", "AP-1001", "Skeet Shoot (1981) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "39d36366ae7e6dfd53393fb9ebab02a0", "CCE", "C-811", "River Raid (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "39da69ff9833f8c143f03b6e0e7a996b", "Charles Morgan", "", "Ventrra Invaders 2002 (Charles Morgan) (Hack)", "Hack of Megamania", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "39fe316952134b1277b6a81af8e05776", "Robby", "18", "River Raid (Robby)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3a10562937a766cbbb77203d029b00e1", "Carrere Video - JWDA, Garry Kitchen, Paul Willson - Teldec - Prism", "USC1002", "Sneak 'n Peek (1983) (Carrere Video) (PAL)", "AKA Der Unsichtbare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3a2e2d0c6892aa14544083dfb7762782", "Atari, Rob Fulop - Sears", "CX2638 - 49-75166", "Missile Command (1981) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "3a35d7f1dc2a33565c8dca52baa86bc4", "", "", "Rubik's Cube Demo 2 (23-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3a51a6860848e36e6d06ffe01b71fb13", "Retroactive", "", "Qb (2.07) (Retroactive) (NTSC)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "3a521b7e29123b2d38e34e3ff8dc255c", "Thomas Jentzsch", "", "Centipede - Atari Mouse Hack v1.4 (NTSC) (Full-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3a526e6a1f9fe918af0f2ce997dfea73", "CBS Electronics, Dan Kitchen, Garry Kitchen", "4L1700, 4L1701, 4L1702, 4L1802, 4L2274", "Donkey Kong (1982) (CBS Electronics) (PAL) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3a53963f053b22599db6ac9686f7722f", "", "", "Word Zapper (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3a771876e4b61d42e3a3892ad885d889", "Atari, Bill Aspromonte, Andrew Fuchs", "CX26120", "Defender II (1987) (Atari)", "AKA Stargate", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3aad0ef62885736a5b8c6ccac0dbe00c", "Dynacom", "", "Atlantis (1983) (Dynacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3ab5d138e26d88c8190e7cc629a89493", "", "", "Phased Color Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "3ac6c50a8e62d4ce71595134cbd8035e", "Absolute Entertainment, Dan Kitchen", "AK-046-04", "Tomcat (1988) (Absolute)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3ad3dc799211ccd424d7c6d454401436", "Probe 2000 - NAP", "", "Power Lords (1983) (Probe) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3ad58b53a1e972396890bd86c735e78d", "Arcadia Corporation, Stephen H. Landrum", "AR-4400", "Excalibur Version 36 (Dragonstomper Beta) (1982) (Arcadia) (Prototype)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3b040ed7d1ef8acb4efdeebebdaa2052", "Tigervision", "7-008", "Miner 2049er (1983) (Tigervision) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3b097a7ed5bd2a84dc3d3ed361e9c31c", "", "", "Interleaved ChronoColour Demo (PAL) (05-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3b10106836565e5db28c7823c0898fbb", "Xonox - Beck-Tech", "6210, 06002, 06004, 99002", "Ghost Manor (1983) (Xonox) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3b2c32fcd331664d037952bcaa62df94", "Xonox", "6230, 6250", "Super Kung-Fu (1983) (Xonox) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3b5751a8d20f7de41eb069f76fecd5d7", "", "", "Eckhard Stolberg's Scrolling Text Demo 4 (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3b64a00ce147c3c29f7f8f8e531d08d8", "", "", "This Planet Sucks (16K) (Greg Troutman)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3b69f8929373598e1752f43f8da61aa4", "Apollo - Games by Apollo - RCA Video Jeux", "AP-2006", "Infiltrate (1921) (Apollo) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "3b6dba1a24bb2893bd3bd0593f92016b", "CBS Electronics / Thomas Jentzsch", "", "Omega Race JS (TJ)", "Hack of Omega Race (CBS Electronics)", "New Release (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3b76242691730b2dd22ec0ceab351bc6", "M Network - INTV, Connie Goldman, Joe King, Patricia Lewis Du Long, Gerald Moore, Mike Sanders, Jossef Wagner", "MT4319", "Masters of the Universe (1983) (M Network)", "", "", "", "", "", "", "A", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "3b80b8f52a0939e16b5059f93a3fc19a", "V007", "", "Virtual Pet (V007) (after Demo 2) (CRACKERS) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3b86a27132fb74d9b35d4783605a1bcb", "Atari, Chris Crawford", "", "Wizard (1980) (Atari) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3b8aacf5f5638492b926b5124de19f18", "Atari, Tod Frye - Sears", "CX2646 - 49-75185", "Pac-Man (1981) (Atari) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3b91c347d8e6427edbe942a7a405290d", "Parker Brothers", "PB5350", "Sky Skipper (1983) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3b9480bb6fb1e358c9c0a64e86945aee", "", "", "Title Match Pro Wrestling (2002) (Skyworks)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3b966bf3c2ca34ac6ca1de4cf6383582", "", "", "Double-Height 6-Digit Score Display (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3bb9793c60c92911895cf44530846136", "Jone Yuan Telephonic Enterprise Co", "", "Dragster (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3c21a89bc38d8cd0b010a2916bcff5c2", "", "", "Colony 7 - CX-22 Hack v0.4 (NTSC)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "50" }, + { "3c3a2bb776dec245c7d6678b5a56ac10", "", "", "Unknown Title (bin00003) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3c4223316c835ceaad619651e25df0f9", "", "", "Defender (Genesis)", "Genesis controller (C is smartbomb)", "Hack of Defender", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3c4a6f613ca8ba27ce9e43c6c92a3128", "", "", "Qb (V0.04) (Non-Lax Version) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "3c57748c8286cf9e821ecd064f21aaa9", "Atari, Jerome Domurat, Andrew Fuchs, Dave Staugas, Robert Vieira", "CX26118", "Millipede (1984) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3c72ddaf41158fdd66e4f1cb90d4fd29", "Dismac", "", "Comando Suicida (Dismac)", "AKA Chopper Command", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3c7a7b3a0a7e6319b2fa0f923ef6c9af", "Atari - Roklan, Joe Gaucher", "", "Racer (1982) (Atari) (Prototype)", "ROM must be started in bank 0", "Prototype", "", "0", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3c7a96978f52b2b15426cdd50f2c4048", "", "", "Overhead Adventure Demo 3 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3c82e808fe0e6a006dc0c4e714d36209", "Activision, David Crane", "AG-004", "Fishing Derby (1980) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3c853d864a1d5534ed0d4b325347f131", "Telesys, Don 'Donyo' Ruffcorn", "1002", "Cosmic Creeps (1982) (Telesys)", "AKA Space Maze, Spaze Maze", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "3c8e57a246742fa5d59e517134c0b4e6", "Parker Brothers, Rex Bradford, Sam Kjellman", "PB5050", "Star Wars - The Empire Strikes Back (1982) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3ca51b5c08f5a0ecfb17d0c1ec6d0942", "Atari, James Andreasen - Sears", "CX2654 - 49-75141", "Haunted House (09-28-81) (Atari) (Prototype)", "AKA Mystery Mansion, Graves' Manor, Nightmare Manor", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3caa902ac0ce4509308990645876426a", "Atari - GCC, Dave Payne", "CX2669, CX2669P", "Vanguard (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3cbdf71bb9fd261fbc433717f547d738", "CCE", "C-803", "Bobby Is Going Home (1983) (CCE) (PAL)", "AKA Bobby Vai Para Casa", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3cdd91e1c28d28e856c0063d602da166", "", "", "Stell-A-Sketch (03-11-1997) (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "3d1e83afdb4265fa2fb84819c9cfd39c", "Coleco - JWDA, Todd Marshall, Robin McDaniel, Henry Will IV", "2465", "Smurf - Rescue in Gargamel's Castle (1983) (Coleco)", "AKA Smurf, Smurf Action", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3d2367b2b09c28f1659c082bb46a7334", "Imagic, Dennis Koble", "720103-2A, IA3203P, EIX-010-04I", "Atlantis (1982) (Imagic) (PAL)", "AKA Lost City of Atlantis", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3d2652cbea462a886a41791dd7c8d073", "", "", "Ritorno dei frattelli di Mario (Mario Bros Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3d48b8b586a09bdbf49f1a016bf4d29a", "Video Game Cartridge - Ariola", "TP-606", "Hole Hunter (Video Game Cartridge)", "AKA Topy", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3d6fc7a19be76d808aa233415cb583fc", "CCE", "C-833", "Target Practice (1983) (CCE)", "AKA Carnival", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3d7749fb9c2f91a276dfe494495234c5", "Jone Yuan Telephonic Enterprise Co", "", "Checkers (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3d7aad37c55692814211c8b590a0334c", "Atari, Dan Oliver", "", "Telepathy (1983) (Atari) (Prototype)", "Uses both left joystick and right Mindlink controllers (press Fire on respective controller to begin)", "Prototype", "", "", "", "", "", "", "", "", "MINDLINK", "", "", "", "78", "", "", "", "" }, + { "3d8a2d6493123a53ade45e3e2c5cafa0", "Atari, Jim Huether - Sears", "CX2629 - 6-99843, 49-75118", "Sky Diver (1979) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3d934bb980e2e63e1ead3e7756928ccd", "Activision, Steve Cartwright - Ariola", "EAX-017, EAX-017-04I - 711 017-720", "MegaMania (1982) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3d9c2fccf8b11630762ff00811c19277", "", "", "Challenge of.... Nexar, The (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3da7cc7049d73d34920bb73817bd05a9", "Activision, Mike Lorenzen", "AX-023", "Oink! (1983) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3dfb7c1803f937fadc652a3e95ff7dc6", "Dimax - Sinmax", "SM8001", "Space Robot (Dimax - Sinmax)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "3e03086da53ecc29d855d8edf10962cb", "CBS Electronics - Roklan, Joe Gaucher, Alex Leavens", "4L1751, 4L1752, 4L1753, 4L2275", "Gorf (1982) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "3e1682ddaec486d8b6b90b527aaa0fc4", "Thomas Jentzsch", "", "Robot City (V0.12) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3e22c7eaf6459b67388602e4bebbb3a8", "CommaVid, John Bronstein - Ariola", "CM-003 - 712 003-720", "Cosmic Swarm (1982) (CommaVid) (PAL) (4K)", "AKA Angriff der Termiten", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3e33ac10dcf2dff014bc1decf8a9aea4", "Spectravideo - Video Games Industries Corporation, Michael Schwartz - Ralston Purina", "", "Chase the Chuckwagon (1983) (Spectravideo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "3e49da621193d2611a4ea152d5d5ca3a", "", "", "Atari Logo Demo 3 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3e4b1137433cc1e617b5508619e13063", "", "", "Asteroids (Genesis)", "Genesis controller (C is hyperspace)", "Hack of Asteroids", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "3e5ca1afaa27c5da3c54c9942fec528b", "", "", "2600 Digital Clock (Demo 2) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3e6dab92009d6034618cb6b7844c5216", "", "", "Ed Invaders (Hack)", "Hack of Pepsi Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3e7d10d0a911afc4b492d06c99863e65", "VGS", "", "Super Tenis (VGS)", "AKA RealSports Tennis", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3e88cca5b860d0bd8947479e74c44284", "Atari, Lou Harp", "CX26122", "Sinistar (01-23-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3e899eba0ca8cd2972da1ae5479b4f0d", "Coleco, Joseph Biel", "2457", "Venture (1982) (Coleco)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "3e90cf23106f2e08b2781e41299de556", "Activision, David Crane", "AX-018, AX-018-04", "Pitfall! (1982) (Activision)", "Pitfall Harry's Jungle Adventure (Jungle Runner)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3eae062a9b722bda1255d474a87eca5c", "Atari, David Crane", "CX2605, CX2605P", "Outlaw (1978) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3eb1e34a4f0eec36f12e7336badcecf2", "Jake Patterson", "", "Baubles (V0.001) (2001) (Jake Patterson) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3eb21313ea5d5764c5ed9160a5a55a83", "Activision, Alan Miller", "AX-012, CAX-012, AX-012-04", "Ice Hockey (1981) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3ec12372ca3e870b11ca70edc7ec26a4", "CommaVid, John Bronstein", "CM-002", "Video Life (1981) (CommaVid) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "3eccf9f363f5c5de0c8b174a535dc83b", "", "", "Plaque Attack (Unknown) (PAL)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3ef9573536730dcd6d9c20b6822dbdc4", "Atari, Larry Wagner, Bob Whitehead", "CX2645, CX2645P", "Video Chess (1979) (Atari) (PAL)", "AKA Computer Chess", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3f01bd6d059396f495a4cde7de0ab180", "", "", "Qb (Special Edition) (NTSC) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "3f039981255691d3859d04ef813a1264", "Xonox, John Perkins", "6230, 7210, 06004, 99004", "Artillery Duel (1983) (Xonox) [a]", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3f251c50aa7237e61a38ab42315ebed4", "Thomas Jentzsch", "", "Ikari Warriors (1990) (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3f3ad2765c874ca13c015ca6a44a40a1", "CCE", "C-862", "Crackpots (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3f540a30fdee0b20aed7288e4a5ea528", "Atari - GCC", "CX2670", "Atari Video Cube (1983) (Atari)", "AKA Atari Cube, Video Cube", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3f58f972276d1e4e0e09582521ed7a5b", "Telegames", "6082 A145", "Kung Fu Superkicks (1988) (Telegames)", "AKA Chuck Norris Superkicks", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3f5a43602f960ede330cd2f43a25139e", "Activision, Alan Miller", "AG-003", "Checkers (1980) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3f6938aa6ce66e6f42e582c1eb19b18c", "Jone Yuan Telephonic Enterprise Co", "", "Laser Blast (Jone Yuan) (4K) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3f6dbf448f25e2bd06dea44248eb122d", "", "5687 A279", "Soccer (1988) (Telegames)", "AKA International Soccer", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3f75a5da3e40d486b21dfc1c8517adc0", "Atari, Jim Huether", "CX26163P", "Sky Diver (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3f9431cc8c5e2f220b2ac14bbc8231f4", "", "", "Colors Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3f96eb711928a6fac667c04ecd41f59f", "Bit Corporation", "PGP218", "Rodeo Champ (4 Game in One Dark Green) (1983) (BitCorp) (PAL)", "AKA Stampede", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3f9cb1aba8ec20e2c243ae642f9942bf", "", "", "New Questions (1998) (John K. Harvey) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3fd1f9d66a418c9f787fc5799174ddb7", "Aaron Curtis", "", "AStar (PAL)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3fd53bfeee39064c945a769f17815a7f", "CCE", "", "Sea Hawk (CCE)", "AKA Seahawk", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3fe43915e5655cf69485364e9f464097", "CCE", "C-863", "Fisher Price (1983) (CCE)", "AKA Skindiver", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "3ff5165378213dab531ffa4f1a41ae45", "Otto Versand", "311377", "Pygmy (1983) (Otto Versand) (PAL)", "AKA Lock 'n' Chase (Double-Game Package)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4026ad38ba5ce486e88383dc27d7a46f", "Nukey Shay, Omegamatrix", "", "Double Dragon (Genesis) V2", "Genesis controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "402b1ca3c230a60fb279d4a2a10fa677", "", "", "3-D Tic-Tac-Toe (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "402d876ec4a73f9e3133f8f7f7992a1e", "Alex Herbert", "", "Man Goes Down (2006) (A. Herbert) (Prototype)", "Uses AtariVox controller", "Homebrew", "", "", "", "", "", "", "", "", "ATARIVOX", "", "", "", "", "", "", "", "" }, + { "405f8591b6941cff56c9b392c2d5e4e5", "Telegames", "", "Star Strike (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4066309eb3fa3e7a725585b9814bc375", "", "", "Multi Ball Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4066d7d88ec4a2c656127a67fa52dcf1", "", "", "Overhead Adventure Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "407a0c6cc0ff777f67b669440d68a242", "Erik Eid", "", "Euchre (Alpha) (PAL) (31-08-2002) (Erik Eid)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4093382187f8387e6d011883e8ea519b", "", "", "Go Go Home (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "40aa851e8d0f1c555176a5e209a5fabb", "", "", "Euchre (More for less) (NTSC) (22-08-2002) (Erik Eid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "40b1832177c63ebf81e6c5b61aaffd3a", "Atari, Peter C. Niday", "", "Rubik's Cube 3-D (1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "40b59249e05135bca33861e383735e9e", "Atari", "CX26163P", "Skiing (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "40d8ed6a5106245aa79f05642a961485", "Xonox - K-Tel Software - Beck-Tech, Steve Beck", "6210, 06002, 06004, 99002", "Ghost Manor (1983) (Xonox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "40d9f5709877ecf3dd1184f9791dd35e", "Dactari - Milmar", "", "Skiing (Dactari - Milmar)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "40e12c008037a323a1290c8fa4d2fe7f", "", "", "Skeleton (NTSC) (06-09-2002) (Eric Ball)", "", "", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "40eb4e263581b3dfec6dd8920b68e00f", "Sears Tele-Games, Marilyn Churchill, Matthew L. Hubbard", "CX2647 - 49-75142", "Seawolf 3 (03-23-1981) (Sears) (Prototype) (PAL)", "Submarine Commander Beta", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "413c925c5fdcea62842a63a4c671a5f2", "Activision, Larry Kaplan", "AX-006", "Bridge (1980) (Activision) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4153dd2beed648e9dc082140ebe8e836", "Thomas Jentzsch", "", "Coke Zero (v1.0) (NTSC)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "415c11fcac66bbd2ace2096687774b5a", "", "", "Fu Kung! (V0.00) (07-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4181087389a79c7f59611fb51c263137", "Atari, Suki Lee", "CX26113", "Miss Piggy's Wedding (06-24-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "41810dd94bd0de1110bedc5092bef5b0", "Funvision - Fund. International Co.", "", "Dragon Treasure (Funvision)", "AKA Dragonfire", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "41818738ab1745e879024a17784d71f5", "CCE", "C-832", "Atlantis (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4189adfc1b30c121248876e3a1a3ac7e", "Eric Ball", "", "Skeleton (Complete) (06-09-2002) (Eric Ball)", "", "New Release", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4191b671bcd8237fc8e297b4947f2990", "Exus Corporation", "", "Video Jogger (1983) (Exus)", "AKA Foot Craz", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "41b554c6970b18670acc7b6baef8ed2e", "Thomas Jentzsch", "", "Reactor - Amiga Mouse Hack v1.3 (PAL) (Half-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "41c4e3d45a06df9d21b7aae6ae7e9912", "CCE", "C-826", "Grand Prix (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "41f252a66c6301f1e8ab3612c19bc5d4", "Atari - GCC, Mike Feinstein, Brad Rice", "CX2681", "Battlezone (1983) (Atari)", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4209e9dcdf05614e290167a1c033cfd2", "CommaVid, John Bronstein", "CM-002", "Video Life (1984) (CommaVid) [higher sounds]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "42249ec8043a9a0203dde0b5bb46d8c4", "CCE", "", "Resgate Espacial (CCE)", "AKA Moonsweeper", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "4233eb824c2b4811abef9b6d00355ae9", "Retroactive", "", "Qb (V0.10) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "4251b4557ea6953e88afb22a3a868724", "Thomas Jentzsch", "", "Robot City (V1.1) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "425ee444a41d218598893d6b6e03431a", "Thomas Jentzsch", "", "Invaders Demo (2001) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4279485e922b34f127a88904b31ce9fa", "", "", "Enduro (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "428b2d36f5d716765460701f7016ac91", "Andrew Wallace", "", "Brooni (2001) (Andrew Wallace) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "42ae81ae8ac51e5c238639f9f77d91ae", "", "", "Multi-Sprite Demo 2 (Piero Cavina) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "42b2c3b4545f1499a083cfbc4a3b7640", "U.S. Games Corporation - JWDA, Todd Marshall, Robin McDaniel, Wes Trager, Henry Will IV", "VC2003", "Eggomania (1982) (U.S. Games)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "AUTO 60", "", "", "", "" }, + { "42b3ab3cf661929bdc77b621a8c37574", "Robby", "", "Volleyball (Robby)", "AKA RealSports Volleyball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "42b5e3a35b032f033809afb0ea28802d", "Atari, Mimi Nyden, Scott Smith, Robert Vieira", "CX26127", "Gremlins (03-12-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "42cdd6a9e42a3639e190722b8ea3fc51", "Activision, Alan Miller", "AG-007, CAG-007", "Tennis (1981) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "42dcc02777b0bcfacd85aeb61d33558a", "", "", "Human Cannonball (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "42e0ec5ab8f5deba53e4169ff2a5efbe", "", "", "Atari Logo Demo 5 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4311a4115fb7bc68477c96cf44cebacf", "", "", "Challenge (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4326edb70ff20d0ee5ba58fa5cb09d60", "Atari - GCC, Kevin Osborn", "CX2689", "Kangaroo (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "435fd469f088468c4d66be6b5204d887", "Atari - GCC", "CX2680, CX2680P", "RealSports Tennis (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "438968a26b7cfe14a499f5bbbbf844db", "", "", "Raft Rider (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "43adf60ebdd6b5a0fae21594ecf17154", "Jone Yuan Telephonic Enterprise Co", "", "Stampede (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "43c6cfffeddab6b3787357fed9d44529", "20th Century Fox Video Games, Frank Cohen, Douglas 'Dallas North' Neubauer", "11111", "M.A.S.H (1983) (20th Century Fox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "43f33c6dfdeaf5138ce6e6968ad7c5ce", "Jeffry Johnston", "", "Radial Pong - Version 11 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "43f8459d39fb4eddf9186d62722ff795", "", "", "Skeleton+ (17-04-2003) (Eric Ball) (PAL)", "", "", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "442602713cb45b9321ee93c6ea28a5d0", "", "", "Demon Attack (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4427f06085bb4c22ff047027f7acecc2", "Parker Brothers, Rex Bradford", "PB5000", "Star Wars - Jedi Arena (1983) (Parker Bros) (Prototype)", "Uses the Paddle Controllers (swapped)", "Prototype", "", "", "", "", "", "", "", "", "", "YES", "", "", "10 50", "", "", "", "" }, + { "442b7863683e5f084716fda050474feb", "Eckhard Stolberg", "", "Frame Timed Sound Effects-EM (Eckhard Stolberg)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4431428a7500c96fc0e2798a5dbd36d6", "", "", "Kangaroo (Genesis)", "Genesis controller (B is punch, C is jump)", "Hack of Kangaroo", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4474b3ad3bf6aabe719a2d7f1d1fb4cc", "Activision - Imagineering, Dan Kitchen, Garry Kitchen", "EAX-039-04B, EAX-039-04I", "Kung-Fu Master (1987) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4476c39736090dabac09f6caf835fc49", "", "", "Text Screen (25-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "448c2a175afc8df174d6ff4cce12c794", "Activision, David Crane", "AB-035-04", "Pitfall II (1983) (Activision) [a2]", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "44e9c4a047c348dbeb7ace60f45484b4", "", "", "Moon Patrol Arcade (Genesis)", "Genesis controller (C is jump)", "Hack of Moon Patrol", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "44f71e70b89dcc7cf39dfd622cfb9a27", "Tigervision, Robert H. O'Neil", "7-007", "Polaris (1983) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "45027dde2be5bdd0cab522b80632717d", "Epyx, Steven A. Baker, Tod Frye, Peter Engelbrite", "80561-00250", "Summer Games (1987) (Epyx)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "45040679d72b101189c298a864a5b5ba", "20th Century Fox Video Games - Sirius Software, David Lubar", "11022", "SpaceMaster X-7 (1983) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4543b7691914dfd69c3755a5287a95e1", "CommaVid, Irwin Gaines", "CM-005", "Mines of Minos (1982) (CommaVid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "456453a54ca65191781aef316343ae00", "", "", "Full Screen Bitmap (3-D Green) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4565c1a7abce773e53c75b35414adefd", "Arcadia Corporation", "", "Supercharger BIOS (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "457b03cd48ff6d895795ef043c6b0f1e", "AtariAge, Chris Spry", "CX26201", "Zippy the Porcupine (2014) (Sprybug)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "457e7d4fcd56ebc47f5925dbea3ee427", "Carrere Video - JWDA, Garry Kitchen - Teldec - Prism", "USC1001", "Space Jockey (1983) (Carrere Video) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "457f4ad2cda5f4803f122508bfbde3f5", "", "", "Canyon Bomber (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "458883f1d952cd772cf0057abca57497", "", "", "Fishing Derby (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "45a095645696a217e416e4bd2baea723", "Digivision", "", "Snoopy (Digivision)", "AKA Snoopy and the Red Baron", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "45a4f55bb9a5083d470ad479afd8bca2", "CommaVid, Joseph Biel", "", "Frog Demo (1983) (CommaVid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "45beef9da1a7e45f37f3f445f769a0b3", "Atari, Suki Lee", "CX2658", "Math Gran Prix (1982) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "45c4413dd703b9cfea49a13709d560eb", "Jone Yuan Telephonic Enterprise Co", "", "Challenge of.... Nexar, The (Jone Yuan) (Hack)", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "45cb0f41774b78def53331e4c3bf3362", "Carrere Video - JWDA, Roger Booth, Sylvia Day, Todd Marshall, Robin McDaniel, Wes Trager, Henry Will IV - Teldec - Prism", "USC1007", "Octopus (1983) (Carrere Video) (PAL)", "AKA Name This Game", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4605a00f5b44a9cbd5803a7a55de150e", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (07-03-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "461029ab23800833e9645be3e472d470", "", "", "Combat TC (v0.1)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "46258bd92b1f66f4cb47864d7654f542", "Zellers", "", "Turmoil (Zellers)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "463dd4770506e6c0ef993a40c52c47be", "Arcadia Corporation, Steve Hales, Stephen H. Landrum", "4 AR-4102", "Suicide Mission (Preview) (1982) (Arcadia)", "AKA Meteoroids", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "463e66ad98806a49106cffa49c08e2ed", "", "", "Interlace Game Demo (01-09-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "467340a18158649aa5e02a4372dcfccd", "Activision, John Van Ryzin - Ariola", "EAZ-036-04, EAZ-036-04B, EAZ-036-04I - 711 036-720", "H.E.R.O. (1984) (Activision) (PAL) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4689081b7363721858756fe781cc7713", "", "", "Oystron (V2.6) (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "468f2dec984f3d4114ea84f05edf82b6", "Tigervision - Teldec", "7-011 - 3.60015 VG", "Miner 2049er Volume II (1983) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "4690fdb70c86604bb35da26696818667", "", "", "Euchre (Release Candidate) (NTSC) (28-09-2002) (Erik Eid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "469473ff6fed8cc8d65f3c334f963aab", "Atari, Bruce Poehlman, Gary Stark", "", "Dune (07-10-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "46c021a3e9e2fd00919ca3dd1a6b76d8", "Atari, Jim Huether - Sears", "CX2629 - 6-99843, 49-75118", "Sky Diver (1979) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "46c43fdcbce8fde3a91ebeafc05b7cbd", "", "", "Invaders Demo (PAL) (2001) (Eckhard Stolberg)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "46dc526773808c8b9bb2111f24e5704c", "Omegamatrix", "", "SpaceMaster X-7 (Atari Mouse) (Omegamatrix)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "46e9428848c9ea71a4d8f91ff81ac9cc", "Telegames", "", "Astroblast (1988) (Telegames) (PAL)", "Can also use left joystick", "", "", "", "", "", "", "", "", "PADDLES", "", "YES", "", "", "AUTO 55", "", "", "", "" }, + { "4702d8d9b48a332724af198aeac9e469", "Atari, Jerome Domurat, Steve Woita", "CX2699", "Taz (1983) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "470878b9917ea0348d64b5750af149aa", "Atari, Suki Lee - Sears", "CX2658 - 49-75128", "Math Gran Prix (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "471f7bdc933e8db0e44aa3dde2dd92af", "Omegamatrix", "", "Millipede (Atari Mouse) v6.5 (Omegamatrix)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "47464694e9cce07fdbfd096605bf39d4", "Activision, Dan Kitchen", "EAK-050-04", "Double Dragon (1989) (Activision) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "47585c047802dd9af888b998fb921f32", "Omegamatrix", "", "Star Wars Arcade (Atari Trak-Ball) v4 (PAL60) (Omegamatrix)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4767356fa0ed3ebe21437b4473d4ee28", "Atari, Dan Hitchens, Mimi Nyden", "CX2685", "Gravitar (04-12-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "47711c44723da5d67047990157dcb5dd", "CCE", "", "Ice Hockey (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "47911752bf113a2496dbb66c70c9e70c", "Atari - CCW, Christopher H. Omarzu, Preston Stuart, Bruce Williams", "CX26101", "Oscar's Trash Race (1984) (Atari) (PAL)", "Uses the Keypad Controllers", "", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "", "" }, + { "4799a40b6e889370b7ee55c17ba65141", "Konami", "RC 100-X 02", "Pooyan (1983) (Konami)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "47aad247cce2534fd70c412cb483c7e0", "Rainbow Vision - Suntek", "SS-010", "Mafia (1983) (Rainbow Vision) (PAL)", "AKA Gangster Alley", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "47abfb993ff14f502f88cf988092e055", "Zellers", "", "Inca Gold (Zellers)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "47aef18509051bab493589cb2619170b", "", "", "Stell-A-Sketch (Bob Colbert) (PD)", "Uses Driving, Joystick, or Amiga/Atari ST Mouse Controllers", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "47b82d47e491ac7fdb5053a88fccc832", "Atari Freak 1, Franklin Cruz", "", "Asteroid 2 (Atari Freak 1) (Hack)", "Hack of Asteroids", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "47cd61f83457a0890de381e478f5cf5f", "Imagic, Wilfredo Aguilar, Michael Becker, Rob Fulop", "720111-2A, 13205", "Fathom (1983) (Imagic) (PAL)", "AKA Scuba", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "481d20ec22e7a63e818d5ef9679d548b", "Atari", "CX26163P", "Freeway Rabbit (32 in 1) (1988) (Atari) (PAL)", "AKA Freeway", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "481f9a742052801cc5f3defb41cb638e", "Jeffry Johnston", "", "Radial Pong - Version 4 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "48287a9323a0ae6ab15e671ac2a87598", "Zellers", "", "Laser Volley (Zellers)", "AKA Innerspace", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4834b7b28ea862227ac7e40053fb52a5", "Nukey Shay", "", "Montezuma's Revenge (Genesis) (F6_Conversion)", "Genesis controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "48411c9ef7e2cef1d6b2bee0e6055c27", "Telesys, Don Ruffcorn, Jack Woodman", "1003", "Fast Food (1982) (Telesys) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "484b0076816a104875e00467d431c2d2", "Atari", "CX26150", "Q-bert (1987) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4857f8bb88bb63c640d3ea5aac7f5d6d", "Atari, James Andreasen - Sears", "CX2654 - 49-75141", "Haunted House (08-12-81) (Atari) (Prototype)", "AKA Mystery Mansion, Graves' Manor, Nightmare Manor", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4868a81e1b6031ed66ecd60547e6ec85", "Eric Mooney", "", "Invaders by Erik Mooney (V2.1) (1-3-98) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "487193a7b7fe57a1bbc2f431f628bd5f", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Atari Trak-Ball Hack v1.1 (NTSC) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4884b1297500bd1243659e43c7e7579e", "Atari - Axlon, Tod Frye", "CX26178", "Save Mary! (10-24-1991) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4892b85c248131d6a42c66a4163a40d0", "Canal 3 - Intellivision", "", "Tac-Scan (Canal 3)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "YES", "", "", "YES", "", "", "AUTO 60", "", "", "", "" }, + { "48bcf2c5a8c80f18b24c55db96845472", "Activision, John Van Ryzin - Ariola", "EAZ-036-04, EAZ-036-04B, EAZ-036-04I - 711 036-720", "H.E.R.O. (1984) (Activision) (PAL) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "48e5c4ae4f2d3b62b35a87bca18dc9f5", "Quelle", "476.774 5", "Bobby geht nach Hause (1983) (Quelle) (PAL)", "AKA Bobby Is Going Home", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "48f18d69799a5f5451a5f0d17876acef", "ZiMAG - Emag - Vidco", "GN-070", "Mysterious Thief, A (1983) (ZiMAG) (Prototype) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "4901c05068512828367fde3fb22199fe", "Imagic, Rob Fulop", "720101-2B, IA3200P, EIX-006-04I", "Demon Attack (1982) (Imagic) (PAL)", "AKA Death from Above", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4904a2550759b9b4570e886374f9d092", "Parker Brothers, Charlie Heath", "931506", "Reactor (1983) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "490e3cc59d82f85fae817cdf767ea7a0", "", "", "Berzerk (Unknown) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "490eed07d4691b27f473953fbea6541a", "Activision, Steve Cartwright, David Crane", "AB-035-04", "Pitfall II (1983) (Activision) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "493daaf9fb1ba450eba6b8ed53ffb37d", "", "", "3-D Corridor Demo (27-03-2003) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "493de059b32f84ab29cde6213964aeee", "Atari, Bill Aspromonte, Andrew Fuchs", "CX26120", "Stargate (1984) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "493e90602a4434b117c91c95e73828d1", "Telegames", "", "Lock 'n' Chase (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4947c9de2e28b2f5f3b0c40ce7e56d93", "", "", "3-D Corridor Demo 2 (29-03-2003) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "494cda91cc640551b4898c82be058dd9", "Andreas Dietrich", "", "Donkey Kong VCS (2017) (1.0) (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "49571b26f46620a85f93448359324c28", "", "", "Save Our Ship (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "497c811026367c08fd838c9c59e5041d", "Omegamatrix", "", "SpaceMaster X-7 (Atari Trak-Ball) (Omegamatrix)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "497f3d2970c43e5224be99f75e97cbbb", "CommaVid, John Bronstein", "CM-002", "Video Life (1984) (CommaVid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "4981cefe5493ea512284e7f9f27d1e54", "Home Vision - Gem International Corp. - VDI", "VCS83136", "Cosmic War (1983) (Home Vision) (PAL)", "AKA Space Tunnel", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4999b45be0ab5a85bac1b7c0e551542b", "CCE", "", "Double Dragon (CCE) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "499b612f6544ae71d4915aa63e403e10", "Atari, Carol Shaw", "CX26163P", "Checkers (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "49f2cef5269fd06218be9f9474c74f8d", "Rentacom", "", "Time Pilot (Rentacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4a196713a21ef07a3f74cf51784c6b12", "Jone Yuan Telephonic Enterprise Co", "", "Frogs and Flies (Jone Yuan) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4a2fe6f0f6317f006fd6d4b34515448b", "", "", "Warring Worms (Midwest Classic Edition) (08-06-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4a45c6d75b1ba131f94a9c13194d8e46", "", "", "How to Draw a Playfield II (Joystick Hack) (1997) (Eric Bacher) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4a5fddf89801336637ac8e57a7c9a881", "Amiga", "1125", "Power Play Arcade Video Game Album IV (1984) (Amiga) (Prototype)", "Atlantis, Cosmic Ark, Dragonfire", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4a6be79310f86f0bebc7dfcba4d74161", "", "", "Demolition Herby (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "4a7eee19c2dfb6aeb4d9d0a01d37e127", "Hozer Video Games", "", "Crazy Valet (Hozer Video Games)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4a8c743396b8ad69d97e6fd3dd3e3132", "Arcadia Corporation", "", "Supercharger BIOS (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4a9009620038f7f30aaeb2a00ae58fde", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (3 of 3) (1983) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4ab2ebd95a8f861ea451abebdad914a5", "Nukey Shay, Thomas Jentzsch", "PAL conversion (F6)", "Montezuma's Revenge (PAL) (Genesis)", "Genesis controller (B jumps left, C jumps right)", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4ab4af3adcdae8cdacc3d06084fc8d6a", "Nick Bensema", "", "Sucky Zepplin (Nick Bensema) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4abb4c87a4c5f5d0c14ead2bb36251be", "Atari - Imagineering, Alex DeMeo", "CX26135, CX26135P", "RealSports Boxing (1987) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4ac9f40ddfcf194bd8732a75b3f2f214", "Atari - CCW, Stephan R. Keith, Laura Scholl, Preston Stuart", "CX26106", "Grover's Music Maker (12-29-1982) (Atari) (Prototype)", "Uses Keypad Controller", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4ae8c76cd6f24a2e181ae874d4d2aa3d", "", "", "Flash Gordon (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4af4103759d603c82b1c9c5acd2d8faf", "Imagic, Bob Smith", "720114-2A, 13207, EIZ-001-04I", "Moonsweeper (1983) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "4afa7f377eae1cafb4265c68f73f2718", "Ed Fries", "", "Halo 2600 (2010) (Ed Fries)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4afe528a082f0d008e7319ebd481248d", "", "", "Multi-Color Demo 1 (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4b143d7dcf6c96796c37090cba045f4f", "Atari, Jim Huether - Sears", "CX2644 - 6-99824", "Flag Capture (1978) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4b205ef73a5779acc5759bde3f6d33ed", "", "", "Berzerk (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4b27f5397c442d25f0c418ccdacf1926", "Atari, Warren Robinett", "CX2613, 49-75154", "Adventure (1980) (Atari) (PAL)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4b379b885e2694f992c6cc932f18327f", "Omegamatrix", "", "SpaceMaster X-7 (Atari Mouse) (PAL60) (Omegamatrix)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4b71197153d651480830638cb6a03249", "Atari, Larry Kaplan", "CX26163P", "Bowling (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4b753a97aee91e4b3e4e02f5e9758c72", "Glenn Saunders, Roger Williams", "", "Asymmetric Reflected Playfield (Glenn Saunders)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4b94fd272785d7ec6c95fb7279d0f522", "Atari - CCW, Christopher H. Omarzu, Preston Stuart, Bruce Williams", "CX26101", "Oscar's Trash Race (12-03-1982) (Atari) (Prototype)", "Uses the Keypad Controllers", "Prototype", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "", "" }, + { "4b9581c3100a1ef05eac1535d25385aa", "", "", "IQ 180 (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4baada22435320d185c95b7dd2bcdb24", "Atari, Jerome Domurat, Dave Staugas", "CX2682", "Krull (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4bcc7f6ba501a26ee785b7efbfb0fdc8", "Atari, Andrew Fuchs, Courtney Granner, Jeffrey Gusman, Mark R. Hahn", "CX2690", "Pengo (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4bdae9246d6ee258c26665512c1c8de3", "Atari", "CX26163P", "Human Cannonball (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4bdf54a454470ba015a217a8f5e61320", "Omegamatrix", "", "Millipede (Amiga Mouse) v6.5 (Omegamatrix)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "4c030667d07d1438f0e5c458a90978d8", "Retroactive", "", "Qb (V2.03) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "4c0fb2544ae0f8b5f7ae8bce7bd7f134", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix (Preview) (1983) (Arcadia)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4c205f166157154df2f1ef60d87e552f", "", "", "Single-Scanline Positioning Demo 2 (2001) (Roger Williams)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4c39a2c97917d3d71739b3e21f60bba5", "", "", "Whale (Sub Scan Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4c462b2b6fb0a19a1437eb2c3dc20783", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (1 of 3) (1983) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4c4ce802cbfd160f7b3ec0f13f2a29df", "", "", "Beta Demo (V1.1) (26-09-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4c606235f4ec5d2a4b89139093a69437", "Andrew Davies", "", "Andrew Davies early notBoulderDash demo (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "4c6afb8a44adf8e28f49164c84144bfe", "CCE", "C-806", "Mission 3,000 A.D. (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4c8832ed387bbafc055320c05205bc08", "Atari, Joe Decuir, Steve Mayer, Larry Wagner - Sears", "CX2601 - 99801, 6-99801, 49-75124", "Combat (1977) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4c8970f6c294a0a54c9c45e5e8445f93", "Xonox - K-Tel Software - Product Guild, Anthony R. Henderson", "99006, 6220", "Sir Lancelot (1983) (Xonox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4c9307de724c36fd487af6c99ca078f2", "Imagic, Brad Stewart", "720106-1A, IA3409", "Sky Patrol (1982) (Imagic) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4ca0959f846d2beada18ecf29efe137e", "Atari, Jim Huether, Alan J. Murphy, Robert C. Polaro", "CX2666, CX2666P", "RealSports Volleyball (1982) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4ca73eb959299471788f0b685c3ba0b5", "Activision, Steve Cartwright", "AX-031", "Frostbite (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4ca90ba45eced6f5ad560ea8938641b2", "", "", "Hangman Man Wordlist (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4cabc895ea546022c2ecaa5129036634", "Funvision - Fund. International Co.", "", "Ocean City (Funvision)", "AKA Atlantis", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4cd796b5911ed3f1062e805a3df33d98", "Tigervision - Software Electronics Corporation - Teldec", "7-006", "Springer (1983) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4d06f72cc3d8934579c11ff8f375c260", "Bit Corporation", "R320", "Bowling (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4d0a28443f7df5f883cf669894164cfa", "", "", "Beast Invaders (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4d2cef8f19cafeec72d142e34a1bbc03", "HES", "771-422", "2 Pak Special - Star Warrior, Frogger (1990) (HES) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4d38e1105c3a5f0b3119a805f261fcb5", "Bit Corporation", "PGP212", "Phantom UFO (4 Game in One Light Green) (1983) (BitCorp) (PAL)", "AKA Spider Fighter", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4d502d6fb5b992ee0591569144128f99", "Atari - Axlon, Tod Frye", "CX26178", "Save Mary! (11-21-1989) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4d5f6db55f7f44fd0253258e810bde21", "Fabrizio Zavagli", "", "Betterblast (Fabrizio Zavagli) (Hack)", "Hack of Astroblast", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4d7517ae69f95cfbc053be01312b7dba", "Atari, Alan Miller - Sears", "CX2641 - 99807, 49-75105", "Surround (1977) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4d77f291dca1518d7d8e47838695f54b", "Data Age", "DA1004", "Airlock (1982) (Data Age)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4d8396deeabb40b5e8578276eb5a8b6d", "Otto Versand", "781698", "Volleyball (1983) (Otto Versand) (PAL)", "AKA RealSports Volleyball (Double-Game Package)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4dbd7e8b30e715efc8d71d215aec7fe7", "Bit Corporation", "R320", "Air Raiders (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4dbf47c7f5ac767a3b07843a530d29a5", "Ric Pryor", "", "Breaking News (2002) (Ric Pryor) (Hack)", "Hack of Bump 'n' Jump", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4dcc7e7c2ec0738e26c817b9383091af", "", "", "Unknown Title (bin00026 (200110)) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4dd6c7ab9ef77f2b4950d8fc7cd42ee1", "Retroactive", "", "Qb (V2.04) (Stella) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "4df6124093ccb4f0b6c26a719f4b7706", "Atari, Brad Stewart - Sears", "CX2622 - 6-99813, 49-75107", "Breakout (1978) (Atari) [a]", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "01 60", "", "", "", "" }, + { "4df9d7352a56a458abb7961bf10aba4e", "", "", "Racing Car (Unknown)", "", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "", "" }, + { "4e01d9072c500331e65bb87c24020d3f", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX26119", "Saboteur (06-15-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4e02880beeb8dbd4da724a3f33f0971f", "Imagic, Michael Greene", "EIZ-002-04I", "Wing War (1983) (Imagic) (PAL)", "AKA Flap!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4e15ddfd48bca4f0bf999240c47b49f5", "Avalon Hill, Jean Baer, Jim Jacob", "5001002", "Death Trap (1983) (Avalon Hill)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "4e2c884d04b57b43f23a5a2f4e9d9750", "", "", "Baby Center Animation (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "4e37992a37ea36489283f7eb90913bbc", "Kris", "", "Hangman Ghost Halloween (Kris) (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4e4895c3381aa4220f8c2795d6338237", "", "", "Backwards Cannonball v1 (Hack)", "Hack of Human Cannonball", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4e66c8e7c670532569c70d205f615dad", "Atari - GCC", "CX2680, CX2680P", "RealSports Tennis (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4e86866d9cde738d1630e2e35d7288ce", "Supergame", "", "River Raid III (Supergame)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4e99ebd65a967cabf350db54405d577c", "Coleco", "2663", "Time Pilot (1983) (Coleco) [b1]", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4eb4fd544805babafc375dcdb8c2a597", "Inspirational Video Concepts, Steve Shustack", "321430", "Red Sea Crossing (1983) (Inspirational Video Concepts)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4edb251f5f287c22efc64b3a2d095504", "Atari", "", "Atari VCS Point-of-Purchase ROM (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4f0071946e80ca68edfdccbac86dcce0", "", "", "Virtual Pet Demo 1 (CRACKERS) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4f2d47792a06da224ba996c489a87939", "HES - Activision", "223", "Super Action Pak - Pitfall, Barnstorming, Grand Prix, Laser Blast (1988) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4f32b24869d8c1310fecf039c6424db6", "U.S. Games Corporation - JWDA, Todd Marshall", "", "3-D Zapper (12-15-82) (U.S. Games) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "4f618c2429138e0280969193ed6c107e", "Activision, Alan Miller", "AZ-028, AG-028-04", "Robot Tank (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4f634893d54e9cabe106e0ec0b7bdcdf", "Retroactive", "", "Qb (2.14) (Retroactive) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "4f64d6d0694d9b7a1ed7b0cb0b83e759", "20th Century Fox Video Games, John Russell", "11016", "Revenge of the Beefsteak Tomatoes (1983) (20th Century Fox)", "AKA Revenge of the Cherry Tomatoes", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4f6702c3ba6e0ee2e2868d054b00c064", "Activision - Woodside Design Associates, Steve 'Jessica Stevens' Kitchen - Ariola", "EAZ-033 - 711 033-725", "Space Shuttle (1983) (Activision) (PAL)", "A Journey Into Space, Eine Reise ins All", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4f781f0476493c50dc578336f1132a67", "", "", "Indy 500 (Unknown) (PAL) (4K)", "Uses Driving Controllers", "", "", "", "", "", "", "", "", "DRIVING", "DRIVING", "", "", "", "45", "", "", "", "" }, + { "4f7b07ec2bef5ccffe06403a142f80db", "Apollo - Games by Apollo, Ed Salvo, Byron Parks", "AP-2003", "Racquetball (1982) (Apollo) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "4f82d8d78099dd71e8e169646e799d05", "", "", "Miniature Golf (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4f89b897444e7c3b36aed469b8836839", "Atari", "CX26190", "BMX Air Master (1989) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4fae08027365d31c558e400b687adf21", "", "", "Qb (V2.17) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "4faeb04b1b7fb0fa25db05753182a898", "", "", "2600 Digital Clock (V x.xx) (PD) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4fbe0f10a6327a76f83f83958c3cbeff", "CCE", "C-816", "Keystone Kappers (1983) (CCE)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "4fc1b85b8074b4b9436d097900e34f29", "John K. Harvey", "", "John K. Harvey's Equalizer (John K. Harvey)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "50200f697aeef38a3ce31c4f49739551", "Mystique - American Multiple Industries, Joel H. Martin", "", "Custer's Revenge (1982) (Mystique) (PAL60)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "502044b1ac111b394e6fbb0d821fca41", "", "", "Hangman Invader 4letter (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "502168660bfd9c1d2649d415dc89c69d", "Activision, Bob Whitehead - Ariola", "EAG-019, EAG-019-04I - 711 019-715", "Sky Jinks (1982) (Activision) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "504688d49a41bf03d8a955512609f3f2", "Thomas Jentzsch", "", "SWOOPS! (v0.94) (TJ)", "Uses the Joystick (L) and Paddle (R) Controllers", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "50568c80ac61cab789d9923c9b05b68e", "Ebivision", "", "Merlin's Walls - Standard Edition (1999) (Ebivision)", "Image rotated 90 degrees CW", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5069fecbe4706371f17737b0357cfa68", "Apollo - Games by Apollo, Steve Stringfellow", "AP-2005", "Shark Attack (1982) (Apollo) (PAL)", "AKA Lochjaw", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5079bfbc7b8f5770f84215ed2e3bdd1b", "Omegamatrix (2012)", "", "Genesis Button Tester", "", "Homebrew", "", "", "", "", "", "", "", "GENESIS", "GENESIS", "", "", "", "", "", "", "", "" }, + { "50a410a5ded0fc9aa6576be45a04f215", "Activision, Bob Whitehead - Ariola", "EAG-019, EAG-019-04I - 711 019-715", "Sky Jinks (1982) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "50c7edc9f9dc0369abcdab3b4efeb5e9", "U.S. Games Corporation - JWDA, Todd Marshall", "", "3-D Zapper (U.S. Games) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "50ef88f9a5e0e1e6b86e175362a27fdb", "", "", "Multi-Sprite Game V2.4 (Piero Cavina) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "512e874a240731d7378586a05f28aec6", "Tigervision, Rorke Weigandt - Teldec", "7-005", "Marauder (1982) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5131ab3797fe8c127e3e135b18b4d2c8", "Activision, David Crane", "AG-004", "Fishing Derby (1980) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "514f911ecff2be5eeff2f39c49a9725c", "Parker Brothers", "931510", "Sky Skipper (1983) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "515046e3061b7b18aa3a551c3ae12673", "Atari - GCC, Mark Ackerman, Noellie Alito", "CX2692", "Moon Patrol (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "516ffd008057a1d78d007c851e6eff37", "Parker Brothers, Dawn Stockbridge", "PB5910", "Strawberry Shortcake - Musical Match-Ups (1983) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "517592e6e0c71731019c0cebc2ce044f", "Parker Brothers - JWDA, Todd Marshall", "PB5550", "Q-bert's Qubes (1984) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "517923e655755086a3b72c0b17b430e6", "Tron", "", "Super Tennis (Tron)", "AKA RealSports Tennis", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5188fee071d3c5ef0d66fb45c123e4a5", "Gameworld", "133-001", "Encounter at L-5 (1983) (Gameworld) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "AUTO 50", "", "", "", "" }, + { "519f007c0e14fb90208dbb5199dfb604", "Amiga - Video Soft", "", "Depth Charge (1983) (Amiga) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "51c1ddc9d6d597f71fb7efb56012abec", "Bit Corporation", "R320", "Lock 'n' Chase (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "51de328e79d919d7234cf19c1cd77fbc", "Atari, Mark R. Hahn", "CX2678", "Dukes of Hazzard (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "51e390424f20e468d2b480030ce95d7b", "Video Game Program", "", "Fire Bird (Video Game Program) (PAL)", "AKA Phoenix", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "51f15b39d9f502c2361b6ba6a73464d4", "", "", "Amanda Invaders (PD) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "51f211c8fc879391fee26edfa7d3f11c", "Activision, Bob Whitehead", "AX-015, AX-015-04", "Chopper Command (1982) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "521f4dd1eb84a09b2b19959a41839aad", "Bit Corporation", "PG206", "Bobby Is Going Home (1983) (BitCorp)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "522b27a8afeb951b5a5a667f8d1a46a1", "Omegamatrix", "", "Millipede (Amiga Mouse) v6.5 (Omegamatrix)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "522c9cf684ecd72db2f85053e6f6f720", "Rainbow Vision - Suntek", "SS-008", "Year 1999, The (1983) (Rainbow Vision) (PAL)", "AKA Condor Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "52385334ac9e9b713e13ffa4cc5cb940", "CCE", "C-804", "Open, Sesame! (1983) (CCE)", "AKA Abre-te, Sesamo!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "523f5cbb992f121e2d100f0f9965e33f", "Joe Grand", "", "SCSIcide (1.30) (CGE 2001 Release) (Joe Grand)", "Uses the Paddle Controllers", "New Release", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "", "", "AUTO 65", "", "", "", "" }, + { "524693b337f7ecc9e8b9126e04a232af", "", "", "Euchre (19-08-2001) (Eric Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5256f68d1491986aae5cfdff539bfeb5", "Atari - GCC, Mark Ackerman, Noellie Alito", "CX2692", "Moon Patrol (07-26-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "525ea747d746f3e80e3027720e1fa7ac", "Activision, Garry Kitchen - Ariola", "EAZ-032 - 771 032-712", "Pressure Cooker (1983) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "525f2dfc8b21b0186cff2568e0509bfc", "Activision, David Crane", "AG-930-04, AZ-030", "Decathlon (1983) (Activision) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "52615ae358a68de6e76467e95eb404c7", "", "", "DJdsl-wopd (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "528400fad9a77fd5ad7fc5fdc2b7d69d", "Starpath Corporation, Stephen H. Landrum, Jon Leupp", "11 AR-4201", "Sword of Saros (1983) (Starpath)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "52a0003efb3b1c49fcde4dbc2c685d8f", "Atari, Alan Miller - Sears", "CX2641 - 99807, 49-75105", "Surround (1977) (Atari) (4K) [a]", "", "", "", "", "2K", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "52b448757081fd9fabf859f4e2f91f6b", "", "", "Worm War I (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "52bae1726d2d7a531c9ca81e25377fc3", "", "", "Space Instigators (V1.8 Fixed) (20-10-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "52e1954dc01454c03a336b30c390fb8d", "Retroactive", "", "Qb (2.14) (Retroactive) (Stella)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "52e9db3fe8b5d336843acac234aaea79", "", "", "Fu Kung! (V0.11) (28-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5305f69fbf772fac4760cdcf87f1ab1f", "Jone Yuan Telephonic Enterprise Co", "", "Ski Run (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5324cf5b6dc17af4c64bf8696c39c2c1", "Imagic, Dennis Koble", "IA3203, IX-010-04", "Atlantis (1982) (Imagic) (8K)", "AKA Lost City of Atlantis", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "533661e9bccd8a9f80ce3765f282c92f", "Omegamatrix", "", "Star Wars Arcade (Atari Trak-Ball) (Y Inverted) v4 (Omegamatrix)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5336f86f6b982cc925532f2e80aa1e17", "Parker Brothers - JWDA, Todd Marshall, Robin McDaniel, Ray Miller", "PB5060", "Star Wars - Death Star Battle (1983) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "534e23210dd1993c828d944c6ac4d9fb", "M Network, Stephen Tatsumi, Jane Terjung - Kool Aid", "MT4648", "Kool-Aid Man (1983) (M Network)", "AKA Kool Aid Pitcher Man", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5355f80cacf0e63a49cbf4ade4e27034", "Christian Samuel", "", "Cute Dead Things House (Christian Samuel) (Hack)", "Hack of Haunted House", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5360693f1eb90856176bd1c0a7b17432", "", "", "Oystron (V2.85) (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "536bf56baa70acb17113884ac41f2820", "Atari, Omegamatrix", "", "Video Olympics Menu (2020) (PAL) (Hack)", "Hack of Video Olympics", "", "", "", "", "", "", "", "", "", "", "YES", "", "", "AUTO 60", "", "", "", "" }, + { "537ed1e0d80e6c9f752b33ea7acbe079", "", "", "A-VCS-tec Challenge (beta 5) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5385cf2a04de1d36ab55c73174b84db0", "Paul Slocum", "", "Combat Rock (PD) (Hack)", "Hack of Combat", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "539d26b6e9df0da8e7465f0f5ad863b7", "Atari, Carol Shaw - Sears", "CX2636 - 49-75156", "Video Checkers (1980) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "539f3c42c4e15f450ed93cb96ce93af5", "Dion Olsthoorn", "v1.3", "Amoeba Jump (2018) (Dionoid)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "53b66f11f67c3b53b2995e0e02017bd7", "CCE", "C-1005", "Super Tennis (1983) (CCE)", "AKA RealSports Tennis", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "53bd1c7c972ae634c912331a9276c6e3", "Atari, Nick 'Sandy Maiwald' Turner", "CX2665", "Frog Pond (1982) (Atari) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "53d181cde2e0219b5754caad246fcb66", "", "", "Missile Demo (1998) (Ruffin Bailey) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "53e03df47e76329b701641f8bdc206f5", "Thomas Jentzsch", "", "Centipede - Atari Trak-Ball Hack v1.4 (PAL) (Half-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "53f147b9746fdc997c62f3dd67888ee5", "Activision, Bob Whitehead", "AG-011", "Stampede (1981) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "540075f657d4b244a1f74da1b9e4bf92", "Bit Corporation", "PGP230", "Festival (4 Game in One Dark Green) (1983) (BitCorp) (PAL)", "AKA Carnival", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5409d20c1aea0b89c56993aec5dc5740", "", "", "Carnival Shooter (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "541cac55ebcf7891d9d51c415922303f", "SpiceWare - Darrell Spice Jr.", "SW-05", "Stay Frosty 2", "AtariAge Holiday Greetings 2014", "Homebrew", "", "", "", "", "", "", "", "JOYSTICK", "", "", "", "", "", "", "", "YES", "" }, + { "5428cdfada281c569c74c7308c7f2c26", "Activision, Larry Kaplan, David Crane", "AG-010, AG-010-04", "Kaboom! (1981) (Activision)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, + { "542c6dd5f7280179b51917a4cba4faff", "ZiMAG - Emag - Vidco", "GN-080", "Spinning Fireball (1983) (ZiMAG) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5438e84b90e50a5362f01cc843b358d4", "Arcadia Corporation, Scott Nelson", "3 AR-4300", "Fireball (1982) (Arcadia) (Prototype)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "543b4b8ff1d616fa250c648be428a75c", "Warren Robinett", "", "Adventure (1978) (Warren Robinett) (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "545048ccb045f9efc6cf2b125cd0dfa8", "Arcadia Corporation, Stephen Harland Landrum, Jon Leupp", "AR-4201", "Sword of Saros (1983) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "54785fa29e28aae6038929ba29d33d38", "", "", "Poker Squares (V0.19) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "54836a8f23913e9a77c7f2665baf36ac", "Bit Corporation", "PG204", "Open, Sesame! (1982) (BitCorp)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5494b9ee403d9757f0fd1f749e80214a", "Larry Petit", "", "Xenophobe Arcade (2003) (Larry Petit) (Hack)", "Hack of Xenophobe", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "54a1c1255ed45eb8f71414dadb1cf669", "Spectravideo", "SA-212", "Mangia' (1983) (Spectravideo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "54bafc299423f5a50b8bc3a797914706", "SOLID Corp. (D. Scott Williamson)", "CX2655*", "Star Castle 2600 (SolidCorp) (PAL)", "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "54da3b0b3f43f5b37911c135b9432b49", "", "", "Halloween III Revision (Hack)", "Hack of Kaboom!", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, + { "54f7efa6428f14b9f610ad0ca757e26c", "Apollo - Games by Apollo, Steve Stringfellow", "AP-2005", "Shark Attack (1982) (Apollo)", "AKA Lochjaw", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "551a64a945d7d6ece81e9c1047acedbc", "Matthias Jaap", "", "Coffee Cup Soccer (Matthias Jaap) (Hack)", "Hack of Pele's Soccer", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5524718a19107a04ec3265c93136a7b5", "Thomas Jentzsch", "", "RealSports Basketball (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "553dbf9358cfd2195e2fa0e08b01fb6a", "Atari - GCC, Mike Feinstein, Kevin Osborn", "CX2691", "Joust (07-05-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "554fd5775ca6d544818c96825032cf0d", "Atari - Roklan, Bob Curtiss", "", "Firefox (06-01-83) (Atari) (Prototype)", "AKA Combat II, Fighter Command", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "557e893616648c37a27aab5a47acbf10", "Atari - Axlon, Tod Frye - Heuristica, Augustin Ortiz", "CX26169", "Shooting Arcade (01-16-1990) (Atari) (Prototype) (PAL)", "Uses the Light Gun Controller (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "559317712f989f097ea464517f1a8318", "Panda", "100", "Space Canyon (1983) (Panda)", "AKA Space Cavern", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "55949cb7884f9db0f8dfcf8707c7e5cb", "Atari, Ed Logg, Carol Shaw - Sears", "CX2639 - 49-75162", "Othello (1981) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "55ace3c775f42eb46f08bb1dca9114e7", "", "", "Shadow Keep (04-03-2003) (Andrew Towers)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "55ef6ab2321ca0c3d369e63d59c059c8", "", "", "Pitfall! (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "55ef7b65066428367844342ed59f956c", "Atari - Roklan, Joe Gaucher, Alex Leavens", "CX2683", "Crazy Climber (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "56210a3b9ea6d5dd8f417a357ed8ca92", "Probe 2000 - NAP, Roger Booth, Todd Marshall, Robin McDaniel, Jim Wickstead", "3152VC", "Pursuit of the Pink Panther (Probe) (Prototype) [bad dump]", "AKA Adventures of the Pink Panther", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "56300ed31fef018bd96768ccc982f7b4", "HES - Activision", "559", "Rad Action Pak - Kung-Fu Master, Freeway, Frostbite (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5641c0ff707630d2dd829b26a9f2e98f", "Joystik", "", "Motocross (Joystik)", "AKA Motocross Racer", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5643ee916f7dc760148fca4db3aa7d10", "", "", "Moon Patrol (Genesis)", "Genesis controller (C is jump)", "Hack of Moon Patrol", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5678ebaa09ca3b699516dba4671643ed", "Coleco, Sylvia Day, Henry Will IV", "2459", "Mouse Trap (1982) (Coleco)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "568371fbae6f5e5b936af80031cd8888", "", "", "Robotfindskitten2600 (26-04-2003) (Jeremy Penner)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "56f72247eb9ebfd33bfd0cca23ab7ef4", "Omegamatrix", "", "Star Wars Arcade (Amiga Mouse) v4 (PAL60) (Omegamatrix)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "571c6d9bc71cb97617422851f787f8fe", "Activision, David Crane - Ariola", "EAG-004, PAG-004 - 711 004-715", "Fishing Derby (1980) (Activision) (PAL)", "AKA Schneller als der Hai", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "572d0a4633d6a9407d3ba83083536e0f", "Funvision - Fund. International Co.", "", "Busy Police (Funvision)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "575c0fb61e66a31d982c95c9dea6865c", "", "", "Blackjack (Unknown) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "", "", "", "", "" }, + { "57939b326df86b74ca6404f64f89fce9", "Atari, Sam Comstock, Richard Dobbis, Nick 'Sandy Maiwald' Turner", "CX26111", "Snoopy and the Red Baron (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "579baa6a4aa44f035d245908ea7a044d", "Jess Ragan", "", "Galaxian Enhanced Graphics (Jess Ragan) (Hack)", "Hack of Galaxian", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "57a66b6db7efc5df17b0b0f2f2c2f078", "Retroactive", "", "Qb (V2.08) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "57c5b351d4de021785cf8ed8191a195c", "Atari - CCW, Gary Stark", "CX26102", "Cookie Monster Munch (1983) (Atari)", "Uses Kids/Keypad Controllers", "", "", "", "", "", "", "", "", "", "KEYBOARD", "", "", "", "", "", "", "", "" }, + { "5835a78a88f97acea38c964980b7dbc6", "", "", "Cosmic Creeps (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "5846b1d34c296bf7afc2fa05bbc16e98", "Atari - Sears", "CX2643 - 6-99815", "Codebreaker (1978) (Atari)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "58513bae774360b96866a07ca0e8fd8e", "Mystique - American Multiple Industries, Joel H. Martin", "1001", "Custer's Revenge (1982) (Mystique)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "585600522b1f22f617652c962e358a5d", "", "", "Multi-Sprite Game V2.2 (Piero Cavina) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "585f73010e205ae5b04ee5c1a67e632d", "", "", "Daredevil (V3) (Stunt_Cycle_Rules!) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5864cab0bc21a60be3853b6bcd50c59f", "", "", "Commando Raid (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "58746219d8094edff869f0f5c2aeaad5", "Jone Yuan Telephonic Enterprise Co", "", "Bowling (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5894c9c0c1e7e29f3ab86c6d3f673361", "Activision - Woodside Design Associates, Steve 'Jessica Stevens' Kitchen", "AZ-033, AZ-033-04", "Space Shuttle (1983) (Activision)", "A Journey Into Space", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "589c73bbcd77db798cb92a992b4c06c3", "Xonox - K-Tel Software - Action Graphics, Michael Schwartz, David Thiel", "6230, 7210, 06004, 99004", "Artillery Duel (1983) (Xonox) (PAL60)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "58a82e1da64a692fd727c25faef2ecc9", "CCE", "C-824", "Jaw Breaker (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "58c396323ea3e85671e34c98eb54e2a4", "Brian Watson", "", "Color Tweaker (B. Watson)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "58d331c23297ed98663d11b869636f16", "", "", "Fu Kung! (V0.09) (26-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "58e313e2b5613b2439b5f12bb41e3eef", "", "", "Cube Conquest (Demo Interlace) (Billy Eno) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "590ac71fa5f71d3eb29c41023b09ade9", "Atari - GCC, Mark Ackerman, Tom Calderwood, Glenn Parker", "CX2684", "Galaxian (01-05-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "59135f13985b84c4f13cc9e55eec869a", "", "", "Multi-Sprite Game V2.0 (Piero Cavina) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "594437a35603c3e857b5af75b9718b61", "HES - Activision", "", "Robot Tank (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "594dbc80b93fa5804e0f1368c037331d", "Telesys, Alex Leavens", "", "Bouncin' Baby Bunnies (1983) (Telesys) (Prototype)", "AKA Baby Boom Boom, Bouncing Baby Monkeys", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5961d259115e99c30b64fe7058256bcf", "Universal Gamex Corporation, Miguel Castillo, H.K. Poon", "GX-001", "X-Man (1983) (Universal)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "59734e1cc41822373845a09c51e6ba21", "Activision, John Van Ryzin", "AG-038-04", "Cosmic Commuter (1984) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "598a4e6e12f8238b7e7555f5a7777b46", "Tigervision", "7-008", "Miner 2049er (1983) (Tigervision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "599cbf919d47a05af975ad447df29497", "Jake Patterson", "", "Baubles (V0.002) (2001) (Jake Patterson) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "59b70658f9dd0e2075770b07be1a35cf", "Thomas Jentzsch", "", "Surfer's Paradise (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "59d33e00c07665395209c1e55da0b139", "", "", "Imagic Selector ROM (1982) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "59e53894b3899ee164c91cfa7842da66", "Data Age", "", "Survival Run (1983) (Data Age) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "59e96de9628e8373d1c685f5e57dcf10", "PlayAround - J.H.M.", "204", "Beat 'Em & Eat 'Em (1982) (PlayAround)", "Uses the Paddle Controllers", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "AUTO 45", "", "", "", "" }, + { "59f596285d174233c84597dee6f34f1f", "CCE", "C-811", "River Raid (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5a0ff99ba10bd26d542e1d6f59f56850", "Champ Games", "CG-04-P", "Super Cobra Arcade (PAL60)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "JOYSTICK", "", "", "", "", "", "", "", "YES", "" }, + { "5a17e30e6e911e74ccd7b716d02b16c6", "Activision, Dan Kitchen", "AX-029", "Crackpots (1983) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5a272012a62becabcd52920348c7c60b", "Star Game", "", "Pitfall (Star Game)", "AKA Pitfall!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5a2f2dcd775207536d9299e768bcd2df", "Otto Versand", "781698", "Flippern (Double-Game Package) (1983) (Otto Versand) (PAL)", "AKA Video Pinball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5a4205aeedd3b0588f973f38bbd9dfd4", "Thomas Jentzsch", "", "Centipede - Amiga Mouse Hack v1.4 (PAL) (Full-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5a5390f91437af9951a5f8455b61cd43", "Retroactive", "", "Qb (0.11) (Retroactive) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "5a6febb9554483d8c71c86a84a0aa74e", "CCE", "C-1003", "Donkey Kong Jr (1983) (CCE)", "AKA Donkey Kong Junior", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5a734779d797ccef25dc8acfa47244c7", "", "", "Oh No! (Version 2) (18-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5a80b857eb8b908ab477ec4ef902edc8", "Activision, Bob Whitehead", "AG-002, CAG-002, AG-002-04", "Boxing (1980) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5a81ad4e184050851e63c8e16e3dac77", "Jone Yuan Telephonic Enterprise Co", "Hack", "Sky Diver (Jone Yuan) (Hack)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5a8afe5422abbfb0a342fb15afd7415f", "Atari - Bobco, Robert C. Polaro", "CX26155", "Sprint Master (1988) (Atari)", "AKA Sprint 88, Sprint 2000", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5a93265095146458df2baf2162014889", "Activision, Steve Cartwright - Ariola", "EAX-031, EAX-031-04B - 711 031-717", "Frostbite (1983) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5a9685c4d51a6c1d6a9544946d9e8dc3", "AtariAge", "", "Grandma's Revenge (AtariAge)", "Can use Driving Controller in right port", "", "", "", "", "", "", "", "", "", "DRIVING", "", "", "", "", "", "", "", "" }, + { "5a9d188245aff829efde816fcade0b16", "CCE", "C-808", "Phantom Tank (1983) (CCE) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5acf9865a72c0ce944979f76ff9610f0", "", "", "Dodge Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5ae73916fa1da8d38ceff674fa25a78a", "CCE", "", "Barnstorming (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5aea9974b975a6a844e6df10d2b861c4", "Atari, Dan Hitchens. Mimi Nyden", "CX2656", "SwordQuest - EarthWorld (1982) (Atari)", "AKA Adventure I, SwordQuest I - EarthWorld", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5af9cd346266a1f2515e1fbc86f5186a", "SEGA", "002-01", "Sub-Scan (1983) (SEGA)", "AKA Subterfuge", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5b124850de9eea66781a50b2e9837000", "PlayAround - J.H.M.", "205", "Bachelor Party (1982) (PlayAround)", "Uses the paddle controllers", "Extremely Rare", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "AUTO 65", "", "", "YES", "" }, + { "5b574faa56836da0866ba32ae32547f2", "", "", "Tomb Raider 2600 [REV 03] (Montezuma's Revenge Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5b5d04887922b430de0b7b2a21f9cd25", "", "", "Omega Race (Genesis)", "Genesis controller (B is thrust, C is fire)", "Hack of Omega Race", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5b6f5bcbbde42fc77d0bdb3146693565", "", "", "Seaquest (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5b7ea6aa6b35dc947c65ce665fde624b", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (2 of 3) (1982) (Starpath)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5b85e987e2b1618769d97ba9182333d0", "Atari - GCC, Mike Feinstein, Brad Rice", "CX2681", "Battlezone (05-12-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5b92a93b23523ff16e2789b820e2a4c5", "Activision - Imagineering, Dan Kitchen, Garry Kitchen", "AG-039-04", "Kung-Fu Master (1987) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5b98e0536c3f60547dd708ae22adb04b", "Ben Hudman", "", "Donkey Kong Gingerbread Man (Ben Hudman) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5b9c2e0012fbfd29efd3306359bbfc4a", "HES", "", "2 Pak Special - Hoppy, Alien Force (1992) (HES) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5babe0cad3ec99d76b0aa1d36a695d2f", "Coleco - Individeo, Ed Temple", "2654", "Looping (1983) (Coleco) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5bba254e18257e578c245ed96f6b003b", "", "", "Music Effects Demo (21-01-2003) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "5bbab3f3e4b47e3e23f9820765dbb45c", "", "", "Pitfall! (says 1985) [h1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5bbb75b49b2bccef9c91ff84bb249c80", "Thomas Jentzsch", "", "Missile Control - Atari Trak-Ball Hack v1.15 (NTSC) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5bc9998b7e9a970e31d2cb60e8696cc4", "Jack Kortkamp", "", "Borgwars Asteroids (2003) (Jack Kortkamp) (Hack)", "Hack of Asteroids", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "5bcc83677d68f7ef74c1b4a0697ba2a8", "Activision, Alan Miller", "AX-012, CAX-012, AX-012-04", "Ice Hockey (1981) (Activision) (16K)", "", "", "", "", "4K", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5bd79139a0c03b63f6f2cf00a7d385d2", "Marc de Smet", "", "An Exercise In Minimalism (V1) (1999) (Marc de Smet) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5be03a1fe7b2c114725150be04b38704", "Atari, Alan Miller", "CX2642", "Hunt & Score (1978) (Atari) (PAL)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5c0227ad63300670a647fcebf595ea37", "Josh", "", "Battle for Naboo (Josh) (Hack)", "Hack of Atlantis", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5c0520c00163915a4336e481ca4e7ef4", "Rainbow Vision - Suntek", "SS-004", "Pyramid War (1983) (Rainbow Vision) (PAL) [a1]", "AKA Chopper Command", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5c19f6da638c4c7c1f98d09e63df43e4", "Canal 3 - Intellivision", "", "Cosmic Ark (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5c1b1aa78b7609d43c5144c3b3b60adf", "", "", "Demo Image Series #8 - Two Marios (Different Interlacing) (27-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5c3a6d27c026f59a96b7af91e8b1bf26", "PlayAround - J.H.M.", "", "PlayAround Demo (PlayAround) (1982)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5c618a50dfa23daac97ba459b9ff5206", "Steve Engelhardt", "", "Berzerk Renegade (2002) (Steve Engelhardt) (Hack)", "Hack of Room of Doom", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "5c73693a89b06e5a09f1721a13176f95", "", "", "Wavy Line Test 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5c86e938e0845b9d61f458539e9a552b", "Atari, Alan Miller", "CX26163P", "Surround (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5cbd7c31443fb9c308e9f0b54d94a395", "Spectravideo, Mark Turmell", "SA-217", "Gas Hog (1983) (Spectravideo) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5ce98f22ade915108860424d8dde0d35", "", "", "Hangman Man Biglist3 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5ced13931c21ef4fc77d3fe801a1cbfa", "CCE", "C-828", "Missile Command (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5d0e8a25cbd23e76f843c75a86b7e15b", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (09-07-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5d132d121aabc5235dd039dfc46aa024", "", "", "Basketball (208 in 1) (Unknown) (PAL) (Hack)", "Console ports are swapped", "Hack", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "", "" }, + { "5d25df9dc2cde746ceac48e834cf84a7", "Activision - Woodside Design Associates, Steve 'Jessica Stevens' Kitchen", "EAZ-033", "Space Shuttle (1983) (Activision) (SECAM)", "A Journey Into Space", "", "", "", "FE", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5d2cc33ca798783dee435eb29debf6d6", "Activision - Imagineering, Mike Reidel", "AK-043-04", "Commando (1988) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5d7293f1892b66c014e8d222e06f6165", "Atari - Axlon, Tod Frye - Heuristica, Agustin Ortiz", "CX26169", "Shooting Arcade (03-07-1989) (Atari) (Prototype) [a1]", "Uses the Light Gun Controller (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5d799bfa9e1e7b6224877162accada0d", "Spectravision - Spectravideo - Sirius Software, David Lubar", "SA-206", "Challenge of.... Nexar, The (1982) (Spectravision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5d8f1ab95362acdf3426d572a6301bf2", "Thomas Jentzsch", "", "SWOOPS! (v0.96) (TJ) (PAL)", "Uses the Joystick (L) and Paddle (R) Controllers", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5d8fb14860c2f198472b233874f6b0c9", "", "", "Boing! (PD) [a2]", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5d9592756425192ec621d2613d0e683d", "CCE", "C-839", "Misterious Thief, A (1983) (CCE) [a]", "AKA A Mysterious Thief", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5da8fd0b5ed33a360bff37f8b5d0cd58", "Tron", "", "Pole Position (Tron)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5dae540347cf0a559962d62604ecf750", "Canal 3 - Intellivision", "", "Freeway (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5db9e5bf663cad6bf159bc395f6ead53", "Goliath - Hot Shot", "83-212", "Time Race (1983) (Goliath) (PAL)", "AKA Space Jockey", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5dccf215fdb9bbf5d4a6d0139e5e8bcb", "Froggo", "FG1009", "Sea Hunt (1987) (Froggo)", "AKA Skindiver", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5de8803a59c36725888346fdc6e7429d", "Atari, John Dunn - Sears", "CX2631 - 49-75152", "Superman (1979) (Atari) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5df32450b9fbcaf43f9d83bd66bd5a81", "Eric Ball", "", "Atari Logo Playfield Demo (2001) (Eric Ball) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5df559a36347d8572f9a6e8075a31322", "Digivision", "", "Enduro (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5e0c37f534ab5ccc4661768e2ddf0162", "Telegames - VSS, Ed Salvo", "5667 A106", "Glacier Patrol (1988) (Telegames)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5e1b4629426f4992cf3b2905a696e1a7", "Activision - Bobco, Robert C. Polaro", "AK-049-04", "Rampage! (1989) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5e1b7a6078af428ef056fe85a37a95ca", "Activision, David Crane", "AX-014, AX-014-04", "Grand Prix (1982) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5e1cd11a6d41fc15cf4792257400a31e", "Philip R. Frey", "", "Return of Mario Bros (Philip R. Frey) (Hack)", "Hack of Mario Bros.", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5e201d6bfc520424a28f129ee5e56835", "Universal Gamex Corporation, Miguel Castillo, H.K. Poon", "GX-001", "X-Man (1983) (Universal) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5e2495d43b981010304af55efed1e798", "Jone Yuan Telephonic Enterprise Co", "", "Math Gran Prix (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5e43c0391f7412ae64fae6f3742d6ee9", "Thomas Jentzsch, Paul Slocum", "", "Thrust+ Platinum (v1.27)", "", "New Release, supports BoosterGrip", "", "", "", "", "", "", "", "BOOSTERGRIP", "DRIVING", "", "", "", "", "", "", "", "" }, + { "5e99aa93d0acc741dcda8752c4e813ce", "", "", "2600 Digital Clock (V b2) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5ec73ac7d2ac95ac9530c6d33e713d14", "Arcadia Corporation, Scott Nelson", "13", "Sweat! - The Decathlon Game (2 of 3) (1983) (Arcadia) (Prototype)", "Uses the Paddle Controllers (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5eeb81292992e057b290a5cd196f155d", "Wizard Video Games - VSS, Ed Salvo", "008", "Texas Chainsaw Massacre, The (1983) (Wizard Video)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5ef303b9f0aa8cf20720c560e5f9baa1", "Atari, Jim Huether", "CX2629, CX2629P", "Sky Diver (1979) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5f1b7d5fa73aa071ba0a3c2819511505", "CCE", "", "Cosmic Commuter (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5f2b4c155949f01c06507fb32369d42a", "Apollo, Ed Salvo", "AP-1001", "Skeet Shoot (1981) (Apollo) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5f316973ffd107f7ab9117e93f50e4bd", "", "", "Commando Raid (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5f39353f7c6925779b0169a87ff86f1e", "Atari - GCC, John Allred, Douglas B. Macrae, Betty Ryan Tylko", "CX2694", "Pole Position (1983) (Atari) [a]", "AKA RealSports Driving", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5f46d1ff6d7cdeb4b09c39d04dfd50a1", "Atari, Gary Palmer", "CX2661P", "Fun with Numbers (1980) (Atari) (PAL)", "AKA Basic Math", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5f4ebf8a1e5f5f7b9ff3e3c6affff3e6", "Bit Corporation", "R320", "Donkey Kong (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5f560837396387455c9dcb05cdd4b053", "Canal 3 - Intellivision", "", "Eggomania (Canal 3)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "AUTO 60", "", "", "", "" }, + { "5f681403b1051a0822344f467b05a94d", "Atari, Howard Scott Warshaw - Sears", "CX2655 - 49-75167", "Yars' Revenge (1982) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "5f708ca39627697e859d1c53f8d8d7d2", "Atari, Warren Robinett - Sears", "CX2606 - 6-99825, 49-75112", "Slot Racers (1978) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5f73e7175474c1c22fb8030c3158e9b3", "Atari, Nick 'Sandy Maiwald' Turner", "CX2665", "Frog Pond (1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5f786b67e05fb9985b77d4beb35e06ee", "Atari, Bill Aspromonte, Andrew Fuchs", "CX26120", "Defender II (1987) (Atari) (PAL)", "AKA Stargate", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5f7ae9a7f8d79a3b37e8fc841f65643a", "Atari, Jerome Domurat, Peter C. Niday, Robert Vieira", "CX26109", "Sorcerer's Apprentice (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5f7de62a408b9de3a1168898298fd31d", "", "", "Super Cobra (Genesis)", "Genesis controller (B is bomb, C is laser)", "Hack of Super Cobra", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5f950a2d1eb331a1276819520705df94", "20th Century Fox Video Games - Micro Computer Technologies, Jim Collas", "", "Heart Like a Wheel (1983) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "5f9b62350b31be8bd270d9a241cbd50e", "Telegames", "5658 A088", "Football (1988) (Telegames) (PAL)", "AKA Super Challenge Football", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5faffe1c4c57430978dec5ced32b9f4a", "Dactari - Milmar", "", "Volleyball (Dactari - Milmar)", "AKA RealSports Volleyball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "5fb71cc60e293fe10a5023f11c734e55", "", "", "This Planet Sucks (Fix) (27-12-2002) (Greg Troutman)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "600d48eef5c0ec27db554b7328b3251c", "", "", "Bars and Text Demo 3 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6015a9cef783e97e98a2aa2cf070ae06", "Thomas Jentzsch", "", "Battlezone TC (Thomas Jentzsch) (Hack)", "Uses two simultaneous Joystick Controllers, Hack of Battlezone", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "60358edf0c2cc76b1e549e031e50e130", "Manuel Polik", "", "Cyber Goth Galaxian (Manuel Polik) (Hack)", "Hack of Galaxian", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "603c7a0d12c935df5810f400f3971b67", "Bit Corporation", "PG209", "Mr. Postman (1983) (BitCorp) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6041f400b45511aa3a69fab4b8fc8f41", "Apollo, Ban Tran", "AP-2010", "Wabbit (1982) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "604e09724555807c28108049efe34a13", "", "", "Sokoban (01-01-2003) (Adam Wozniak)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6058e40ce79d7434c7f7477b29abd4a5", "", "", "Rubik's Cube Demo (23-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "605dcb73d22f4efdb90ef9da2f290f7c", "Atari, Larry Kaplan", "CX26163P", "Air-Sea Battle (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "605fd59bfef88901c8c4794193a4cbad", "Data Age", "", "Secret Agent (1983) (Data Age) (Prototype)", "Uses the Paddle Controllers", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "01 45", "", "", "", "" }, + { "606c2c1753051e03c1f1ac096c9d2832", "Jone Yuan Telephonic Enterprise Co", "", "Crackpots (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6076b187a5d8ea7a2a05111c19b5d5cd", "", "", "Fu Kung! (V0.14) (01-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "60a61da9b2f43dd7e13a5093ec41a53d", "VentureVision, Dan Oliver", "VV2001", "Rescue Terra I (1982) (VentureVision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "60bbd425cb7214ddb9f9a31948e91ecb", "Activision, Bob Whitehead", "AG-005, CAG-005, AG-005-04", "Skiing (1980) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "60cd61a2dfccb0e2736434f9792c1672", "Amiga - Video Soft, Frank Ellis, Jerry Lawson", "2110", "3-D Havoc (1983) (Amiga) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "60d304582d33e2957b73eb300a7495bb", "", "", "Jam Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "60e0ea3cbe0913d39803477945e9e5ec", "Atari, Joe Decuir - Sears", "CX2621 - 99806, 6-99806, 49-75104", "Video Olympics (1977) (Atari)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXDR", "PADDLES_IAXDR", "YES", "", "", "AUTO 60", "", "", "", "" }, + { "613abf596c304ef6dbd8f3351920c37a", "", "", "Boring Pac-Man (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6141c095d0aee4e734bebfaac939030a", "Rainbow Vision - Suntek", "SS-017", "Mariana (1983) (Rainbow Vision) (PAL)", "AKA Seaquest", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "61426cee013306e7f7367534ab124747", "", "", "One Blue Bar Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "615a3bf251a38eb6638cdc7ffbde5480", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX2674", "E.T. - The Extra-Terrestrial (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "61621a556ad3228f0234f5feb3ab135c", "", "", "Fu Kung! (V0.05 Cuttle Card Compattle Revision) (14-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "61631c2f96221527e7da9802b4704f93", "Activision - Imagineering, Mike Reidel", "AK-043-04", "Commando (1988) (Activision) [different logo]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "61719a8bdafbd8dab3ca9ce7b171b9e2", "", "", "Enduro (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "61728c6cfb052e62a9ed088c5bf407ba", "", "", "Sprite Demo 4 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "619de46281eb2e0adbb98255732483b4", "", "", "Time Warp (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "61dbe94f110f30ca4ec524ae5ce2d026", "CCE", "C-820", "Space Invaders (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "61e0f5e1cc207e98704d0758c68df317", "Star Game", "007", "Tennis (Star Game)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "61ef8c2fc43be9a04fe13fdb79ff2bd9", "", "", "Gas Gauge Demo - Revisited (2001) (Joe Grand) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6205855cc848d1f6c4551391b9bfa279", "", "", "Euchre (Release Candidate 2) (NTSC) (01-10-2002) (Erik Eid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6238ac888871fec301d1b9fc4fc613c9", "Thomas Jentzsch", "", "Marble Craze - Atari Mouse Hack v1.0 (PAL) (TJ)", "Uses Atari Mouse Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "624e0a77f9ec67d628211aaf24d8aea6", "Panda", "108", "Sea Hawk (1983) (Panda)", "AKA Seahawk", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "626d67918f4b5e3f961e4b2af2f41f1d", "Atari", "50008", "Diagnostic Test Cartridge 2.0 (1980) (Atari) (Prototype)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6272f348a9a7f2d500a4006aa93e0d08", "Atari, Jerome Domurat, Michael Sierchio", "CX2667, CX2667P", "RealSports Soccer (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "62899430338e0538ee93397867d85957", "Gameworld", "133-004", "Airlock (1983) (Gameworld) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "62921652f6634eb1a0940ed5489c7e18", "", "", "SCSIcide (V1.09) (2001) (Joe Grand)", "", "", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "", "", "AUTO 65", "", "", "", "" }, + { "62992392ea651a16aa724a92e4596ed6", "Eric Mooney", "", "Invaders by Erik Mooney (Beta) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "62d1f50219edf9a429a9f004c19f31b3", "JWDA, Todd Marshall", "", "Euro Gen (02-01-83) (JWDA) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "62ee2b8f59e9cd6285bbdb674a952e8b", "Probe 2000 - NAP, Roger Booth, Todd Marshall, Robin McDaniel, Jim Wickstead", "3152VC", "Pursuit of the Pink Panther (Probe) (Prototype)", "AKA Adventures of the Pink Panther", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "62f74a2736841191135514422b20382d", "", "", "Pharaoh's Curse (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "YES", "" }, + { "62ffd175cac3f781ef6e4870136a2520", "", "", "2600 Digital Clock (V x.xx) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "63166867f75869a3592b7a94ea62d147", "", "", "Indy 500 (Hack) [a1]", "Hack of Indy 500", "Hack", "", "", "", "", "", "", "", "DRIVING", "DRIVING", "", "", "", "", "", "", "", "" }, + { "6333ef5b5cbb77acd47f558c8b7a95d3", "Greg Troutman", "", "Dark Mage (Greg Troutman) (PD) (8K)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "6337927ad909aa739d6d0044699a916d", "Jeffry Johnston", "", "Radial Pong - Version 2 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6339d28c9a7f92054e70029eb0375837", "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart", "PB5540", "Star Wars - The Arcade Game (1984) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "6342afe9c9ad1b6120b8f6fb040d0926", "", "", "Move a Blue Blob Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6354f9c7588a27109c66905b0405825b", "Thomas Jentzsch", "", "Amidar DS (2003) (TJ) (Hack)", "Hack of Amidar", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6358f7f8bf0483402a080efccf250d61", "CommaVid, John Bronstein", "CM-003", "Cosmic Swarm (1982) (CommaVid) (Prototype)", "AKA Termite", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "635cc7a0db33773959d739d04eff96c2", "", "", "Minesweeper (V.90) (Soren Gust) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6362396c8344eec3e86731a700b13abf", "Panda", "109", "Exocet (1983) (Panda)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "637efac676ff063f2fbb0abff77c4fa5", "", "", "Noize Maker Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "63811ed69bdbc35c69d8aa7806c3d6e9", "Atari", "CX26163P", "Homerun (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "638cc82ea96f67674595ba9ae05da6c6", "Rainbow Vision - Suntek", "SS-011", "Super Ferrari (1983) (Rainbow Vision) (PAL)", "AKA Enduro", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "63a6eda1da30446569ac76211d0f861c", "Activision, David Crane", "AG-001", "Dragster (1980) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "63a7445b1d3046d3cdcdbd488dca38d9", "Rob Kudla", "", "Better Space Invaders (1999) (Rob Kudla) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "63c5fef3208bb1424d26cf1ab984b40c", "", "", "Analog Clock (V0.1) (20-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "63c7395d412a3cd095ccdd9b5711f387", "Eric Ball", "ELB005", "Skeleton+ (PAL)", "Stereo sound", "Homebrew", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "63d6247f35902ba32aa49e7660b0ecaa", "", "", "Space War (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "63e42d576800086488679490a833e097", "Telesys, Jim Rupp", "1004", "Ram It (1983) (Telesys) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "63e783994df824caf289b69a084cbf3e", "David Marli", "", "Fat Albert (David Marli) (Hack)", "Hack of Fast Food", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "63e9e612bbee31045f8d184a4e53f8ec", "ATARITALIA", "", "Moby Blues (2002) (ATARITALIA) (Hack)", "Hack of Mario Bros", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "640a08e9ca019172d612df22a9190afb", "Atari - GCC, Mike Feinstein, Kevin Osborn", "CX2691, CX2691P", "Joust (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "64198bb6470c78ac24fcf13fe76ab28c", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (1982) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "643e6451eb6b8ab793eb60ba9c02e000", "Salu - Avantgarde Software, Michael Buetepage", "460741", "Ghostbusters II (1992) (Salu) (PAL) [different tune]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "645bf7f9146f0e4811ff9c7898f5cd93", "Xonox - K-Tel Software - VSS, Robert Weatherby", "6230, 6250", "Super Kung-Fu (1983) (Xonox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6468d744be9984f2a39ca9285443a2b2", "Atari, Ed Logg, Carol Shaw", "CX26163P", "Reversi (32 in 1) (1988) (Atari) (PAL)", "AKA Othello", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "647162cceb550fd49820e2206d9ee7e8", "", "", "Skeleton (NTSC) (2002) (Eric Ball)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "64b8e19c767191ccdc97acc6904c397b", "Jeffry Johnston", "", "Radial Pong - Version 6 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "64ca518905311d2d9aeb56273f6caa04", "CCE", "", "Cubo Magico (CCE)", "AKA Cubicolor", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "64d43859258dc8ca54949e9ff4174202", "Thomas Jentzsch", "", "Lilly Adventure (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "64fab9d15df937915b1c392fc119b83b", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX26119", "Saboteur (05-20-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "650df778c6ce22d3fd1a7c33c565bcc3", "Atari - GCC, Betty Ryan Tylko, Douglas B. Macrae", "CX2694", "Pole Position (1983) (Atari)", "Genesis controller (B is high gear, C is low gear, left difficulty switch swaps gear buttons)", "Hack of Pole Position", "", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "", "" }, + { "651d2b6743a3a18b426bce2c881af212", "CCE", "C-812", "Pac Man (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6522717cfd75d1dba252cbde76992090", "Home Vision - Gem International Corp. - VDI", "VCS83102", "War 2000 (1983) (Home Vision) (PAL)", "AKA Astrowar", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6538e454b0498ad2befe1ef0f87815c0", "Joe Grand", "", "SCSIcide (v1.2) (2001) (Joe Grand)", "", "New Release", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "", "", "AUTO 65", "", "", "", "" }, + { "65490d61922f3e3883ee1d583ce10855", "Atari - GCC, Mark Ackerman, Noellie Alito", "CX2692, CX2692P", "Moon Patrol (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "65562f686b267b21b81c4dddc129d724", "", "", "Euchre (28-07-2001) (Eric Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "655c84e5b951258c9d20f0bf2b9d496d", "", "", "2600_2003 Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "656dc247db2871766dffd978c71da80c", "Sears Tele-Games, Jim Huether", "CX2614 - 49-75126", "Steeplechase (1981) (Sears)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "AUTO 60", "", "", "", "" }, + { "6588d192d9a8afce27b44271a2072325", "Bit Corporation", "R320", "Basketball (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "65917ae29a8c9785bb1f2acb0d6aafd0", "", "", "Junkosoft One Year Demo (1999) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6596b3737ae4b976e4aadb68d836c5c7", "Digivision", "", "Defender (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "659a20019de4a23c748ec2292ea5f221", "Retroactive", "", "Qb (V2.05) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "65c6406f5af934590097c8c032ebb482", "", "", "Three Hugger (Pave Demo) (20-12-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6604f72a966ca6b2df6a94ee4a68eb82", "", "", "MegaMania (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "662eca7e3d89175ba0802e8e3425dedb", "", "", "Hangman Pac-Man Biglist3 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "66362890eb78d6ea65301592cce65f5b", "", "", "Euchre (13-07-2001) (Eric Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "663ef22eb399504d5204c543b8a86bcd", "CBS Electronics - Roklan, Joe Hellesen, Joe Wagner", "4L1720, 4L1721, 4L1722, 4L2276", "Wizard of Wor (1982) (CBS Electronics) (PAL)", "Uses the Joystick Controllers (swapped)", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "YES", "" }, + { "664d9bfda6f32511f6b4aa0159fd87f5", "Atari - Roklan, Joe Gaucher", "", "Racer (1982) (Atari) (Prototype) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6651e2791d38edc02c5a5fd7b47a1627", "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart", "PB5540", "Star Wars - The Arcade Game (04-05-1984) (Parker Bros) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "665b8f8ead0eef220ed53886fbd61ec9", "Telesys, Don Ruffcorn, Jack Woodman", "1003", "Fast Food (1982) (Telesys)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "66706459e62514d0c39c3797cbf73ff1", "Video Gems", "VG-05", "Treasure Below (1983) (Video Gems) (PAL)", "", "", "", "", "", "", "A", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6672de8f82c4f7b8f7f1ef8b6b4f614d", "Videospielkassette - Ariola", "PGP237", "Angeln I (Ariola) (PAL)", "AKA Fishing Derby", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "667a70b028f581d87648693b873bc962", "Parker Brothers - Roklan, Joe Gaucher", "PB5370", "Popeye (1983) (Parker Bros) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "668dc528b7ea9345140f4fcfbecf7066", "Gakken", "001", "Pooyan (1983) (Gakken) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6697f177847c70505824422e76aad586", "", "", "Tennis (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "669840b0411bfbab5c05b786947d55d4", "Atari, Andrew Fuchs, Jeffrey Gusman, Dave Jolly, Suki Lee", "CX26117", "Obelix (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "66b89ba44e7ae0b51f9ef000ebba1eb7", "Atari - CCW, Stephan R. Keith, Laura Scholl, Preston Stuart", "CX26106", "Grover's Music Maker (01-18-1983) (Atari) (Prototype)", "Uses Keypad Controller", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "66b92ede655b73b402ecd1f4d8cd9c50", "Activision, John Van Ryzin - Ariola", "EAZ-036-04, EAZ-036-04B, EAZ-036-04I - 711 036-720", "H.E.R.O. (1984) (Activision) (PAL) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "66bc1bef269ea59033928bac2d1d81e6", "Arcadia Corporation, Scott Nelson", "AR-4300", "Fireball (Preview) (1982) (Arcadia)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "01", "", "", "", "" }, + { "66c2380c71709efa7b166621e5bb4558", "Parker Brothers, Dave Engman, Dawn Stockbridge", "931509", "Tutankham (1983) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "66c4e0298d4120df333bc2f3e163657e", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (2 of 3) (1982) (Starpath) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "66f49b3248791b9803fa3e2f4165d072", "Bit Corporation", "R320", "Football (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "66fcf7643d554f5e15d4d06bab59fe70", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (09-13-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6706a00f9635508cfeda20639156e66e", "Atari, Jerome Domurat, Michael Sierchio", "CX2667", "RealSports Soccer (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "672012d40336b403edea4a98ce70c76d", "", "", "Spider Kong (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "675ae9c23fa1aae376cea86cad96f9a5", "", "", "Poker Squares (V0.25) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "67631ea5cfe44066a1e76ddcb6bcb512", "", "", "Termool (Unknown) (PAL)", "AKA Turmoil", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "67684a1d18c85ffa5d82dab48fd1cb51", "Tigervision, Warren Schwader - Teldec", "7-003", "Threshold (1982) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "678c1d71a1616d9d022f03d8545b64bb", "", "", "Demo Image Series #11 - Donald And Mario (28-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "67931b0d37dc99af250dd06f1c095e8d", "CommaVid, Irwin Gaines", "CM-004", "Room of Doom (1982) (CommaVid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "679d30c7886b283cbe1db4e7dbe5f2a6", "Colin Hughes", "", "Puzzle (Colin Hughes) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "679e910b27406c6a2072f9569ae35fc8", "Data Age", "DA1002", "Warplock (1982) (Data Age)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "01 40", "", "", "YES", "" }, + { "67bd3d4dc5ac6a42a99950b4245bdc81", "Retroactive", "", "Qb (2.11) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "67c05ae94bf8b83a666c3ae2c4bc14de", "Atari", "CX26163P", "NFL Football (32 in 1) (1988) (Atari) (PAL) (4K)", "AKA Football", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "67cdde4176e0447fc45a71e0a1cdd288", "Telegames - VSS, Ed Salvo", "5665 A016", "Glacier Patrol (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "67ce6cdf788d324935fd317d064ed842", "Retroactive", "", "Qb (V2.09) (Stella) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "67cf913d1df0bf2d7ae668060d0b6694", "", "", "Hangman Monkey 4letter (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "67f90d74fd0b72fdc6d9b92436780ea9", "Omegamatrix", "", "SpaceMaster X-7 (Atari Trak-Ball) (PAL60) (Omegamatrix)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6803fa7c2c094b428b859a58dc1dd06a", "Retroactive", "", "Qb (0.11) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "6805734a0b7bcc8925d9305b071bf147", "Bit Corporation", "PGP229", "Kung Fu (4 Game in One Dark Green) (1983) (BitCorp) (PAL)", "AKA Karate", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "681206a6bde73e71c19743607e96c4bb", "", "", "Casino (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6833c26f385e866f3a0fa0dff311216e", "Thomas Jentzsch", "", "Centipede - Atari Mouse Hack v1.4 (PAL60) (Full-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "683bb0d0f0c5df58557fba9dffc32c40", "Arcadia Corporation, Scott Nelson", "AR-4300", "Fireball (1982) (Arcadia) [a]", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "01", "", "", "", "" }, + { "683dc64ef7316c13ba04ee4398e2b93a", "Ed Federmeyer", "", "Edtris (1995) (Ed Federmeyer)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "68449e4aaba677abcd7cde4264e02168", "", "", "Horizonal Color Bars Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6847ce70819b74febcfd03e99610243b", "", "", "Ruby Runner 4A50", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "68489e60268a5e6e052bad9c62681635", "Bit Corporation", "PG201", "Sea Monster (1982) (BitCorp) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "68597264c8e57ada93be3a5be4565096", "Data Age", "DA1005", "Bugs (1982) (Data Age)", "Uses the Paddle Controllers", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "AUTO 50", "", "", "", "" }, + { "685e9668dc270b6deeb9cfbfd4d633c3", "CommaVid, Irwin Gaines - Ariola", "CM-004 - 712 004-720", "Room of Doom (1982) (CommaVid) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "68760b82fc5dcf3fedf84376a4944bf9", "CCE", "C-860", "Laser Gate (1983) (CCE)", "AKA Innerspace", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "687c23224e26f81c56e431c24faea36d", "", "", "Qb (Simple Background Animation) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "68878250e106eb6c7754bc2519d780a0", "CCE", "C-809", "Squirrel (1983) (CCE)", "AKA Snail Against Squirrel", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "68ac69b8e1ba83af8792f693f5ae7783", "Digivision", "", "Fathon (Digivision)", "AKA Fathom", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "68c80e7e1d30df98a0cf67ecbf39cc67", "Hozer Video Games", "", "Gunfight 2600 - One Step Forward & Two Steps Back (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "68c938a2a2b45c37db50509f1037fe6e", "Omegamatrix", "", "Star Wars Arcade (Atari Mouse) v4 (Omegamatrix)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "68cd2adc6b1fc9a1f263ab4561112f30", "Thomas Jentzsch", "", "Boulderdash Demo (09-12-2002) (TJ)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "68feb6d6ff63e80df1302d8547979aec", "", "", "Starfield Demo 2 (20-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "690a6049db78b9400c13521646708e9c", "King Tripod Enterprise Co.", "SS - 007", "Space Raid (King Tripod) (PAL)", "AKA Challenge of.... Nexar, The", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6913c90002636c1487538d4004f7cac2", "Atari - CCW", "CX26131", "Monster Cise (1984) (Atari) (Prototype)", "Uses the Keypad Controllers (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "691d67910b08b63de8631901d1887c1f", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (1983) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "692202772d8b38ccf85a90c8003a1324", "", "", "Zi - The Flie Buster (2002) (Fernando Mora) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "693137592a7f5ccc9baae2d1041b7a85", "", "", "Qb (V2.02) (Stella) (2001) (Retroactive) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "6936aa6763835f62ac13d1aaa79b9f91", "Thomas Jentzsch", "", "Centipede - Atari Trak-Ball Hack v1.4 (NTSC) (Half-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6979f30204149be3e227558cffe21c1d", "Atari", "CX26163P", "Miniaturer Golf (32 in 1) (1988) (Atari) (PAL) (4K)", "AKA Miniature Golf", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6982854657a2cc87d712f718e402bf85", "Zellers", "", "Earth Attack (Zellers)", "AKA Defender", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "69877da5caded48315e3e45882a303d5", "Atari - Roklan, Joe Gaucher, Alex Leavens", "CX2683", "Crazy Climber (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "698f569eab5a9906eec3bc7c6b3e0980", "SpkLeader", "", "Demons! (2003) (SpkLeader) (Hack)", "Hack of Phoenix", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "69974dd5d6420b90898cde50aec5ef39", "Activision, David Crane", "AG-009, AG-009-04", "Freeway (1981) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "69df0411d4d176e558017f961f5c5849", "CCE", "C-831", "Cosmic Ark (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "69e79b1352b9ee1754bbe63b4a7062c3", "Barry Laws Jr.", "", "Pink Floyd - The Wall (2003) (Barry Laws Jr.) (Hack)", "Hack of Berzerk", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "69ebf910ab9b63e5b8345f016095003b", "", "", "Maze Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "69edfb4e1810a523311b3e250fc1e275", "Thomas Jentzsch", "", "Missile Command Atari Trak-Ball Hack v1.3 (PAL) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "69fac82cd2312dd9ce5d90e22e2f070a", "Spectravision - Spectravideo - Quelle", "SA-202 - 412.851 8", "Planet Patrol (1982) (Spectravision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6a03c28d505bab710bf20b954e14d521", "", "", "Pressure Gauge 2 Beta (Hozer Video Games)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6a07836c382195dd5305ce61d992aaa6", "Apollo, Larry Martin", "AP-2008", "Guardian (1982) (Apollo) (Prototype)", "Uses the Paddle Controller (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "01", "", "", "", "" }, + { "6a091b8ffeacd0939850da2094b51564", "", "", "Vertically Scrolling Playfield (02-02-2003) (Aaron Bergstrom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6a222c26bcece3a510ddda21398f72c6", "Bit Corporation", "PG203", "Phantom Tank (1982) (BitCorp)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6a2c68f7a77736ba02c0f21a6ba0985b", "Atari, Larry Wagner, Bob Whitehead", "", "Computer Chess (07-07-1978) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6a3b0c33cf74b1e213a629e3c142b73c", "Cody Pittman", "", "Cory The Interviewer (Cody Pittman) (Hack)", "Hack of Ghostbusters", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6a76d5f0ed721639474aa9bbde69ebf0", "", "", "Play Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "6a82b8ecc663f371b19076d99f46c598", "Activision, Larry Miller - Ariola", "EAX-026, EAX-026-04B, EAX-026-04I - 711 026-725", "Enduro (1983) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6a882fb1413912d2ce5cf5fa62cf3875", "Video Game Cartridge - Ariola", "TP-605", "Dragon Defender (Ariola) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "6a8c6940d3be6fd01274363c4d4b298e", "", "", "Spy Hunter (Genesis)", "Genesis controller (C is oil/smoke)", "Hack of Spy Hunter", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6a9b30ca46b0dba9e719f4cbd340e01c", "", "", "Frostbite (Unknown) (PAL) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6a9e0c72fab92df70084eccd9061fdbd", "CCE", "C-835", "Beany Bopper (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6aa66e9c3eea76a0c40ef05513497c40", "", "", "Hangman Ghost Biglist2 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6ac3fd31a51730358708c7fdc62487f8", "Matthias Jaap", "", "PC Invaders (Matthias Jaap) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6aca52e11b597ab84b33d5252e1cd9d1", "Bit Corporation", "R320", "Tac-Scan (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "AUTO 60", "", "", "", "" }, + { "6ae4dc6d7351dacd1012749ca82f9a56", "Atari - GCC, Jaques Hugon, Seth Lipkin", "CX26125, CX26127", "Track and Field (1984) (Atari)", "Uses the Track & Field Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6b01a519b413f8cfa2f399f4d2841b42", "", "", "Aphex Invaders (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6b1fc959e28bd71aed7b89014574bdc2", "Bit Corporation", "PG203", "Phantom Tank (1982) (BitCorp) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6b4eb5b3df80995b8d9117cb7e9aeb3c", "Gameworld, J. Ray Dettling", "133-006", "Journey Escape (1983) (Gameworld) (PAL)", "AKA Rock 'n' Roll Escape", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "6b683be69f92958abe0e2a9945157ad5", "U.S. Games Corporation - Western Technologies, Jeff Corsiglia, Paul Allen Newell, Steven B. Sidley, Tom Sloper", "VC2007", "Entombed (1983) (U.S. Games)", "Released as Name That Game for a contest (winning name was Entombed)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "6b6ca32228ae352b4267e4bd2cddf10c", "", "", "Pac-Man 4 (Pac-Man Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6b71f20c857574b732e7a8e840bd3cb2", "", "", "Frostbite (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6b72b691ea86f61438ed0d84c4d711de", "", "", "Fishing Derby (Unknown) (PAL) (4K) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6b75f8fa4fd011a6698c58315f83d2ac", "Thomas Jentzsch", "", "Sprintmaster DC (TJ)", "Uses the Driving Controllers, Hack of Sprintmaster (Atari)", "New Release (Hack)", "", "", "", "", "", "", "", "DRIVING", "DRIVING", "", "", "", "45", "", "", "", "" }, + { "6b7a56b6ac2ca4bf9254474bf6ed7d80", "", "", "Horizonal Color Bars Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6b7e1c11448c4d3f28160d2de884ebc8", "Zirok", "", "Fast Food (Zirok)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6b8fb021bb2e1f1e9bd7ee57f2a8e709", "Paul Slocum", "", "3-D Corridor (29-03-2003) (Paul Slocum) (PD) [a]", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6bb09bc915a7411fe160d0b2e4d66047", "Atari", "CX26163P", "UFO (32 in 1) (1988) (Atari) (PAL)", "AKA Space Jockey", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6bb22efa892b89b69b9bf5ea547e62b8", "Dynacom", "", "Megamania (1982) (Dynacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6bde3f6ac31aceef447ce57d4d2c2ec0", "Piero Cavina", "", "Mondo Pong V1 (Piero Cavina) (PD)", "Uses the Paddle Controllers", "New Release", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "", "", "01", "", "", "", "" }, + { "6c128bc950fcbdbcaf0d99935da70156", "Digitel", "", "Volleyball (1983) (Digitel)", "AKA RealSports Volleyball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6c1553ca90b413bf762dfc65f2b881c7", "Quelle", "343.073 3", "Winterjagd (1983) (Quelle) (PAL)", "AKA Ski Hunt", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6c1f3f2e359dbf55df462ccbcdd2f6bf", "Activision, Garry Kitchen - Ariola", "EAX-025, EAX-025-04I - 711 025-725", "Keystone Kapers (1983) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6c25f58fd184632ca76020f589bb3767", "Dynacom", "", "Beat 'Em & Eat 'Em (1983) (Dynacom)", "Uses the Paddle Controller (left only)", "", "", "", "", "", "", "", "", "", "", "", "", "", "AUTO 45", "", "", "", "" }, + { "6c449db9bbbd90972ad1932d6af87330", "", "", "20 Sprites at Once Demo 3 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6c658b52d03e01828b9d2d4718a998ac", "", "", "Hangman Invader Biglist2 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6c76fe09aa8b39ee52035e0da6d0808b", "Atari, Brad Stewart", "CX2622, CX2622P", "Breakout (1978) (Atari) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "01 60", "", "", "", "" }, + { "6c85098518d3f94f7622c42fd1d819ac", "Suntek", "SS-028", "Firebug (1983) (Suntek) (PAL)", "AKA Spinning Fireball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6c91ac51421cb9fc72c9833c4f440d65", "ITT Family Games", "554-33 375", "Cosmic Town (1983) (ITT Family Games) (PAL)", "AKA Base Attack (Perry Rhodan-Serie)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6c9a32ad83bcfde3774536e52be1cce7", "", "", "Space Treat (NTSC) (13-08-2002) (Fabrizio Zavagli)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6cab04277e7cd552a3e40b3c0e6e1e3d", "Telegames - VSS", "7062 A305", "Universal Chaos (1988) (Telegames) (Prototype)", "AKA Targ", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6cbe945e16d9f827d0d295546ac11b22", "", "", "Gunfight 2600 - AI (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6ccd8ca17a0e4429b446cdcb66327bf1", "", "", "RPG Engine (12-05-2003) (Paul Slocum) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "6cd1dc960e3e8d5c5e0fbe67ab49087a", "", "", "Vertical Playfield Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6cd506509e8fd5627f55603780e862a8", "Greg Troutman", "", "Dark Mage (SuperCharger) (Greg Troutman) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "6ce2110ac5dd89ab398d9452891752ab", "Funvision - Fund. International Co.", "", "Persian Gulf War (Funvision)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6cea35ded079863a846159c3a1101cc7", "", "", "Atlantis (208 in 1) (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6ceb7d6a54e9a5e62d26874d1cc88dbc", "Video Soft", "", "Atom Smasher (1984) (Video Soft) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6cf054cd23a02e09298d2c6f787eb21d", "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart", "PB5540", "Star Wars - The Arcade Game (1984) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "6d218dafbf5a691045cdc1f67ceb6a8f", "Robin Harbron", "", "6 Digit Score Display (1998) (Robin Harbron) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6d475019ea30d0b29f695e9dcfd8f730", "Eric Mooney", "", "Invaders by Erik Mooney (Alpha 2) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6d74ebaba914a5cfc868de9dd1a5c434", "", "", "Fortress (Smooth Version) (20-04-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6d842c96d5a01967be9680080dd5be54", "Activision, Steve Cartwright, David Crane", "AB-035-04", "Pitfall II (1984) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6d8a04ee15951480cb7c466e5951eee0", "Zirok", "", "Kanguru (1983) (Zirok)", "AKA Kangaroo", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6d9afd70e9369c2a6bff96c4964413b7", "", "", "Time Warp (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6dda84fb8e442ecf34241ac0d1d91d69", "Atari - GCC, Douglas B. Macrae", "CX2677", "Dig Dug (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6de924c2297c8733524952448d54a33c", "CCE", "C-1006", "Moon Patrol (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6dfad2dd2c7c16ac0fa257b6ce0be2f0", "Parker Brothers, Larry Gelberg", "PB5065", "Star Wars - Ewok Adventure (1983) (Parker Bros) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6e179eee3d4631a7434d40cf7aeea6e8", "Wizard Video Games - MicroGraphic Image, Robert Barber, Tim Martin", "007", "Halloween (1983) (Wizard Video Games) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6e19428387686a77d8c8d2f731cb09e0", "", "", "Purple Cross Demo (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6e372f076fb9586aff416144f5cfe1cb", "Atari, Tod Frye - Sears", "CX2646 - 49-75185", "Pac-Man (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6e59dd52f88c00d5060eac56c1a0b0d3", "Atari, Bob Smith", "CX2648", "Video Pinball (1981) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6e5d5ba193d2540aec2e847aafb2a5fb", "Retroactive", "", "Qb (2.14) (Retroactive) (NTSC)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "6e7ed74082f39ad4166c823765a59909", "", "", "Poker Squares (V0.14) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6e7efb0ed13ec28a00d19572de9c9f03", "Apollo - Games by Apollo", "AP-2006", "Infiltrate (1982) (Apollo) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6eb10fd23c7161751d18b9e8484c0004", "Coleco - JWDA, Todd Marshall, Robin McDaniel, Henry Will IV", "2465", "Smurf - Rescue in Gargamel's Castle (1983) (Coleco) (Prototype)", "AKA Smurf, Smurf Action", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6ed5012793f5ddf4353a48c11ea9b8d3", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix - Down on the Line (3 of 3) (1983) (Arcadia)", "Uses Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "01 70", "", "", "", "" }, + { "6ed6bda5c42b2eb7a21c54e5b3ace3e3", "Canal 3 - Intellivision", "", "Ice Hockey (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6efe876168e2d45d4719b6a61355e5fe", "Bit Corporation", "PG207", "Mission 3,000 A.D. (1983) (BitCorp) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "6f084daf265599f65422ef4173b69bc7", "", "", "Music Kit (V2.0) - Song Player (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "6f2aaffaaf53d23a28bf6677b86ac0e3", "U.S. Games Corporation - Vidtec - JWDA, Garry Kitchen", "VC1001", "Space Jockey (1982) (U.S. Games)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6f3e3306da2aa6e74a5e046ff43bf028", "", "", "Defender Arcade (Genesis)", "Genesis controller (C is smartbomb)", "Hack of Defender 2", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6f744f14aac04f7e1ea0d3f4bafcb3e4", "Atari - Roklan, Joe Gaucher, Alex Leavens", "CX2683", "Crazy Climber (1983) (Atari) (Prototype) [a3]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6f74ed915ffe73b524ef0f63819e2a1d", "Eckhard Stolberg", "", "An Exercise In Minimalism (V2) (1999) (Eckhard Stolberg)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6fa0ac6943e33637d8e77df14962fbfc", "Imagic, Rob Fulop", "", "Cubicolor (1982) (Imagic) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6fac680fc9a72e0e54255567c72afe34", "", "", "Superman (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6fbd05b0ad65b2a261fa154b34328a7f", "", "", "Boardgame Demo (20-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6fc0176ccf53d7bce249aeb56d59d414", "Rainbow Vision - Suntek", "SS-004", "Pyramid War (1983) (Rainbow Vision) (PAL)", "AKA Chopper Command", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6fc27a9233fc69d28d3f190b4ff80f03", "", "", "UFO #6 (Charles Morgan) (Hack)", "Hack of Pepsi Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6fc394dbf21cf541a60e3b3631b817f1", "Imagic, Bob Smith", "720020-2A, IA3611P", "Dragonfire (1982) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "6fd7c7057eeab273b29c7aafc7429a96", "Activision, David Crane", "AX-018, AX-018-04", "Pitfall! (1982) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6fe67f525c39200a798985e419431805", "Atari - GCC, Kevin Osborn", "CX2689, CX2689P", "Kangaroo (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "6ff4156d10b357f61f09820d03c0f852", "Atari, Larry Kaplan - Sears", "CX2612 - 99804, 49-75103", "Street Racer (1977) (Atari) (4K)", "Uses the Paddle Controllers (swapped)", "", "", "", "", "", "", "", "", "", "", "YES", "", "", "10 60", "", "", "", "" }, + { "6ffc95108e5add6f9b8abcaf330be835", "Charles Morgan", "", "TP Bug (Charles Morgan) (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "700a786471c8a91ec09e2f8e47f14a04", "Activision", "", "Hard-Head (1983) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "703d32062436e4c20c48313dff30e257", "", "", "Moving Maze Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "703f0f7af350b0fa29dfe5fbf45d0d75", "Bit Corporation", "P460", "4 Game in One Dark Green (1983) (BitCorp) (PAL)", "Rodeo Champ, Bobby is Going Home, Open Sesame, Festival", "", "", "", "4IN1", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "705fe719179e65b0af328644f3a04900", "Atari, David Crane - Sears", "CX2653 - 6-99823, 49-75111", "Slot Machine (1979) (Atari) (4K) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "706e3cc4931f984447213b92d1417aff", "", "", "Joustpong (06-07-2002) (Kirk Israel) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "707ecd80030e85751ef311ced66220bc", "", "", "Double-Height 6-Digit Score Display (Background Color Change) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7096a198531d3f16a99d518ac0d7519a", "Telesys, Jim Rupp", "1004", "Ram It (1983) (Telesys)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "709910c2e83361bc4bf8cd0c20c34fbf", "Rainbow Vision - Suntek", "SS-006", "Netmaker (1983) (Rainbow Vision) (PAL)", "AKA Amidar", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "70a43fbdb1c039283ee5048d99842469", "Thomas Jentzsch", "", "Reactor - Atari Mouse Hack v1.3 (PAL) (Half-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "70a8480cfaf08776e5420365732159d2", "Rob Kudla", "", "Horizontally Scrolling Playfield Thing (Rob Kudla) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "70ce036e59be92821c4c7fd735ec6f68", "Activision, Steve Cartwright - Ariola", "EAX-031, EAX-031-04B - 711 031-717", "Frostbite (1983) (Activision) (PAL) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "70d14c66c319683b4c19abbe0e3db57c", "", "", "Oystron (V2.82) (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "710497df2caab69cdcc45e919c69e13f", "Arcadia Corporation, Dennis Caswell", "5 AR-4200", "Labyrinth (Escape from the Mindmaster Beta) (1982) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "713fde2af865b6ec464dfd72e2ebb83e", "", "", "Challenge (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "71464c54da46adae9447926fdbfc1abe", "M Network - INTV - APh Technological Consulting, Bruce Pedersen", "MT5663", "Lock 'n' Chase (1982) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "714e13c08508ee9a7785ceac908ae831", "Home Vision - Gem International Corp. - VDI", "VCS83123", "Parachute (1983) (Home Vision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "715dbf2e39ba8a52c5fe5cdd927b37e0", "Amiga - Video Soft", "3135", "S.A.C. Alert (1983) (Amiga) (Prototype)", "Uses Joyboard", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "715dd9e0240638d441a3add49316c018", "Atari", "", "128-in-1 Junior Console (Chip 2 of 4) (1991) (Atari) (PAL)", "Actually contains only 16 games, not 32", "", "", "", "16IN1", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7187118674ff3c0bb932e049d9dbb379", "Zirok", "", "Keystone Keypers (1983) (Zirok)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "718ae62c70af4e5fd8e932fee216948a", "Data Age, J. Ray Dettling", "112-006", "Journey Escape (1983) (Data Age)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "718ee85ea7ec27d5bea60d11f6d40030", "Thomas Jentzsch", "", "Ghostbusters II (1992) (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "7197b6cbde6ecd10376155e6b848e80d", "Piero Cavina", "", "Multi-Sprite Game V2.1 (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "71b193f46c88fb234329855452dfac5b", "Digitel", "", "Atlantis (1983) (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "71d005b60cf6e608d04efb99a37362c3", "Atari, Larry Kaplan", "CX2643", "Codebreaker (1978) (Atari) (PAL) (4K) [a]", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "71f09f128e76eb14e244be8f44848759", "Funvision - Fund. International Co.", "", "Time Race (Funvision) (PAL)", "AKA Time Warp", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "71f8bacfbdca019113f3f0801849057e", "Atari, Dan Hitchens", "CX26126", "Elevator Action (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "72097e9dc366900ba2da73a47e3e80f5", "", "", "Euchre (15-06-2001) (Eric Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "721a5567f76856f6b50a6707aa8f8316", "Activision, David Crane, Dan Kitchen", "EAG-108-04, EAZ-108-04B", "Ghostbusters (1985) (Activision) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "72305c997f2cec414fe6f8c946172f83", "Arcadia Corporation, Dennis Caswell", "AR-4000, AR-4100", "Phaser Patrol (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "724613effaf7743cbcd695fab469c2a8", "", "", "Super-Ferrari (Unknown)", "AKA Enduro", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "728152f5ae6fdd0d3a9b88709bee6c7a", "Spectravideo, Mark Turmell", "SA-217", "Gas Hog (1983) (Spectravideo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "72876fd7c7435f41d571f1101fc456ea", "Quelle", "688.383 9", "Die Ente und der Wolf (1983) (Quelle) (PAL)", "AKA Pooyan", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "72a46e0c21f825518b7261c267ab886e", "Xonox - K-Tel Software - Computer Magic", "99005, 6220, 6250", "Robin Hood (1983) (Xonox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "72a5b5052272ac785fa076709d16cef4", "", "", "KC Munckin (29-01-2003) (J. Parlee)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "72a63bcb5eb31bd0fd5e98ed05125ec1", "Thomas Jentzsch", "", "Missile Control - Atari Trak-Ball Hack v1.15 (PAL60) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "72bda70c75dfa2365b3f8894bace9e6a", "Thomas Jentzsch", "", "Atlantis (TJ) (Hack)", "Hack of Atlantis", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "72d0acb5de0db662de0360a6fc59334d", "", "", "Cosmic Ark (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "72db1194b1cc7d45b242f25eb1c148d3", "", "", "Pac-Man (1981) (Atari) (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "72fd08deed1d6195942e0c6f392e9848", "HES", "0701-406", "2 Pak Special - Wall Defender, Planet Patrol (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "72ffbef6504b75e69ee1045af9075f66", "Atari, Richard Maurer - Sears", "CX2632 - 49-75153", "Space Invaders (1980) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "73158ea51d77bf521e1369311d26c27b", "Zellers", "", "Challenge (Zellers)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "73521c6b9fed6a243d9b7b161a0fb793", "Atari, Tom Reuterdahl", "CX26163P", "Miniaturer Golf (32 in 1) (1988) (Atari) (PAL)", "AKA Miniature Golf", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "736388d73198552d77d423962000006f", "Dactari", "", "Tennis (Dactari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "73a710e621d44e97039d640071908aef", "", "", "Barber Pole Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "73aa02458b413091ac940c0489301710", "Rainbow Vision - Suntek", "SS-016", "Boom Bang (1983) (Rainbow Vision) (PAL)", "AKA Crackpots", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "73b4e8f8b04515d91937510e680214bc", "", "", "Rubik's Cube Demo 3 (24-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "73c545db2afd5783d37c46004e4024c2", "CBS Electronics - JWDA, Todd Marshall, Robin McDaniel, Henry Will IV", "4L1767, 4L1768, 4L1769, 4L1770", "Smurf - Schtroumpfs (1983) (CBS Electronics) (PAL)", "Pitufo", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "73c839aff6a055643044d2ce16b3aaf7", "Activision, Alan Miller - Ariola", "EAX-016, PAX-016 - 711 016-725", "StarMaster (1982) (Activision) (PAL)", "Use Color/BW switch to change between galactic chart and front views", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "73cb1f1666f3fd30b52b4f3d760c928f", "", "", "Mines of Minos (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "73e66e82ac22b305eb4d9578e866236e", "Jone Yuan Telephonic Enterprise Co", "", "Unknown Datatech Game (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "73efa9f3cbe197f26e0fb87132829232", "CCE", "C-858", "Tennis (1983) (CCE) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "74023e0f2e739fc5a9ba7caaeeee8b6b", "Jone Yuan Telephonic Enterprise Co", "", "Fishing Derby (Jone Yuan) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "740a7fa80f52cc7287ba37677afb6b21", "", "", "Double Dragon (PAL) (Genesis)", "Genesis controller (C is jumpkick)", "Hack of Double Dragon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "740b47df422372fbef700b42cea4e0bf", "", "", "Dizzy Wiz (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "740f39e71104e90416c29a73560b9c6b", "Atari", "TE016643", "Diagnostic Test Cartridge 2.6P (1982) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7412f6788087d7e912c33ba03b36dd1b", "AtariAge, Omegamatrix", "", "Venture Reloaded (2019) (AtariAge) (Hack)", "Transformative hack of Venture", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "742de93b8d849220f266b627fbabba82", "", "", "SCSIcide (25-02-2001) (Chris Wilkson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7450ae4e10ba8380c55b259d7c2b13e8", "", "", "Register Twiddler Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7454786af7126ccc7a0c31fcf5af40f1", "", "", "Phantom Tank (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7465b06b6e25a4a6c6d77d02242af6d6", "Atari", "CX26193", "8 in 1 (01-16-92) (Atari) (Prototype)", "Game 2 is Centipede, but doesn't work", "Prototype", "", "", "8IN1", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7481f0771bff13885b2ff2570cf90d7b", "Arcadia Corporation, Brian McGhie", "AR-4104", "Rabbit Transit (1983) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "749fec9918160921576f850b2375b516", "Spectravision - Spectravideo", "SA-205", "China Syndrome (1982) (Spectravision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "74d072e8a34560c36cacbc57b2462360", "Sancho - Tang's Electronic Co.", "TEC002", "Seahawk (1982) (Sancho) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "74ebaca101cc428cf219f15dda84b6f8", "Activision, Alan Miller", "AG-007, CAG-007", "Tennis (1981) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "74f623833429d35341b7a84bc09793c0", "Zellers", "", "Radar (Zellers)", "AKA Exocet", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "75028162bfc4cc8e74b04e320f9e6a3f", "Atari, Greg Easter, Mimi Nyden", "CX26107", "Snow White (02-09-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7511c34518a9a124ea773f5b0b5c9a48", "", "", "Donkey Kong (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "75169c08b56e4e6c36681e599c4d8cc5", "M Network - INTV - APh Technological Consulting, Hal Finney", "MT5666", "Astroblast (1982) (M Network)", "Can also use left joystick", "Uncommon", "", "", "", "", "", "", "", "PADDLES", "", "YES", "", "", "AUTO 55", "", "", "", "" }, + { "752da1c0acd7d132ccfb0b1067f53cf6", "Thomas Jentzsch", "", "Reactor - Atari Mouse Hack v1.3 (PAL) (Full-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "753375d183c713cfa0aa7298d1f3067b", "Arcadia Corporation, Steve Hales, Stephen Harland Landrum", "AR-4102", "Suicide Mission (1982) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "7550b821ee56fb5833dca2be88622d5a", "", "", "Multiple Moving Objects Demo (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "75511bb694662301c9e71df645f4b5a7", "Activision, Bob Whitehead - Ariola", "EAG-011, PAG-011 - 711 011-715", "Stampede (1981) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "755fed16b48e81de05130708a905d00d", "SnailSoft", "", "Comitoid beta 3 (SnailSoft)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "756ca07a65a4fbbedeb5f0ddfc04d0be", "Atari, Jim Huether", "CX2629, CX2629P", "Sky Diver (1979) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7574480ae2ab0d282c887e9015fdb54c", "Atari, Jerome Domurat, Steve Woita", "CX2699", "Taz (1984) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7576dd46c2f8d8ab159d97e3a3f2052f", "Goliath - Hot Shot", "83-112", "Time Machine (1983) (Goliath) (PAL)", "AKA Asteroid Fire", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "757f529026696e13838364dea382a4ed", "Activision, David Crane - Ariola", "EAX-014, PAX-014, EAX-014-04B, EAX-014-04I - 711 014-720", "Grand Prix (1982) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "75893a9dc5de4b91cc426959b82a1da0", "Champ Games", "CG-02-P", "Conquest Of Mars (2010) (PAL60)", "Rev 2 release", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "75a303fd46ad12457ed8e853016815a0", "ZiMAG - Emag - Vidco", "715-111 - GN-060", "Immies & Aggies (1983) (ZiMAG) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "75b22fdf632d76e246433db1ebccd3c4", "", "", "Skeleton+ (05-05-2003) (Eric Ball) (PAL)", "", "", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "75b557be7f08db84ec5b242207b9f241", "", "", "Space Treat (30-12-2002) (Fabrizio Zavagli) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "75e276ba12dc4504659481c31345703a", "Arcadia Corporation, Kevin Norman", "AR-4103", "Killer Satellites (1983) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "75e8d8b9e9c5c67c2226dbfd77dcfa7d", "", "", "2600 Digital Clock (V b1) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "75ea128ba96ac6db8edf54b071027c4e", "Atari, David Crane", "CX26163P", "Slot Machine (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "75ea60884c05ba496473c23a58edf12f", "Atari, Howard Scott Warshaw - Sears", "CX2655 - 49-75167", "Yars' Revenge (1982) (Atari) (PAL) [a]", "ROM must be started in bank 0", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "75ee371ccfc4f43e7d9b8f24e1266b55", "Atari, Greg Easter, Mimi Nyden", "CX26107", "Snow White (11-09-1982) (Atari) (Prototype)", "ROM must be started in bank 0", "Prototype", "", "0", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7608abdfd9b26f4a0ecec18b232bea54", "Atari, Bob Whitehead", "CX26163P", "NFL Football (32 in 1) (1988) (Atari) (PAL)", "AKA Football", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7623a639a6fffdb246775fe2eabc8d01", "Activision, Bob Whitehead", "AG-005, CAG-005, AG-005-04", "Skiing (1980) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7628d3cadeee0fd2e41e68b3b8fbe229", "Atari", "CX26163P", "Fishing Derby (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7648e72a5b5899076688df18a1ddcf72", "CBS Electronics, Richard K. Balaska Jr., Andy Frank, Stuart Ross", "4L 2520 5000", "Tunnel Runner (1983) (CBS Electronics) (Prototype)", "Black Box", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "764ce6801f28a9ad36f11de3e57c053b", "Atari, Jim Huether, Alan J. Murphy, Robert C. Polaro", "CX2666", "RealSports Volleyball (1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "76809eb1ee0db8a318308a5cdda0f4e2", "Atari, Jerome Domurat, Steve Woita", "CX2699", "Taz (1983) (Atari) (Prototype) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "769ddc995dbb9edb8167efcea9f34a7c", "", "", "H.E.R.O. (Genesis)", "Genesis controller (B is laser, C is dynamite)", "Hack of H.E.R.0.", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "76a9bf05a6de8418a3ebc7fc254b71b4", "VideoSoft, Jerry Lawson, Dan McElroy", "VS1008", "Color Bar Generator (1984) (VideoSoft)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "76c685d1a60c0107aa54a772113a2972", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (3 of 3) (1983) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "76c88341017eae660efc6e49c4b6ab40", "", "", "Indiana Pitfall (Hack)", "Hack of Pitfall!", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "76ee917d817ef9a654bc4783e0273ac4", "Otto Versand", "311377", "Fox & Goat (Double-Game Package) (1983) (Otto Versand) (PAL)", "AKA Nuts", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "76f53abbbf39a0063f24036d6ee0968a", "M Network, David Akers, Joe 'Ferreira' King, Patricia Lewis Du Long, Jeff Ratcliff - INTV", "MT7045", "Bump 'n' Jump (1983) (M Network)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "76f66ce3b83d7a104a899b4b3354a2f2", "UA Limited", "", "Cat Trax (1983) (UA Limited) (1)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "77057d9d14b99e465ea9e29783af0ae3", "Activision, David Crane", "AG-001", "Dragster (1980) (Activision)", "AKA Drag Strip", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7732e4e4cc2644f163d6650ddcc9d9df", "HES", "771-333", "2 Pak Special - Challenge, Surfing (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7761418d46af069b8cd80c29fe6cd814", "Dion Olsthoorn", "RetroN 77 edition", "Amoeba Jump (R77) (DionoiD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7778ac65d775a079f537e97cbdad541c", "", "", "Spider Fighter (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "777aece98d7373998ffb8bc0b5eff1a2", "", "", "2600 Collison Demo 2 (Piero Cavina) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "77887e4192a6b0a781530e6cf9be7199", "Atari", "CX2604", "Space War (1978) (Atari) [b1]", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "77be57d872e3f5b7ecf8d19d97f73281", "", "", "Basketball (208 in 1) (Unknown) (PAL)", "Console ports are swapped", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "", "" }, + { "77cd9a9dd810ce8042bdb9d40e256dfe", "Kyle Pittman", "", "Evil Dead (2003) (Kyle Pittman) (Hack)", "Hack of Haunted House", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "77d0a577636e1c9212aeccde9d0baa4b", "Atari, Joe Decuir", "CX2621, CX2621P", "Video Olympics (1977) (Atari) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXDR", "PADDLES_IAXDR", "YES", "", "", "AUTO 60", "", "", "", "" }, + { "78297db7f416af3052dd793b53ff014e", "", "", "Poker Squares (V0.17) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7836794b79e8060c2b8326a2db74eef0", "", "", "RIOT RAM Test (26-11-2002) (Dennis Debro)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "784176346e9422733d55c427230e5bad", "Activision, Alex DeMeo", "", "Title Match Pro Wrestling (1989) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "784abfdb31d5341e5bd404d8d2a71c3b", "Alessandro Ciceri", "", "MagiCard (TV format conversion) (alex_79) (PAL)", "MagiCard PAL conversion hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7860716fa5dbc0fffab93fb9a4cb4132", "", "", "Hangman Monkey Wordlist (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7867ee819b53d69cfcfe740f7ddca574", "Arcadia Corporation, Dennis Caswell", "1 AR-4000, AR-4100", "Phaser Patrol (1982) (Arcadia) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "787ebc2609a31eb5c57c4a18837d1aee", "Prescott", "", "Vault Assault (19xx) (Prescott)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "78821ef76ebc3934850d1bc1b9e4f4b0", "HES - Activision", "542", "Hot Action Pak - Ghostbusters, Tennis, Plaque Attack (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "78963290052fd17c6c7998305ab3a6a0", "", "", "Push (V0.08) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "78b84cfb1c57b0488d674d2374e656e6", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (1 of 3) (1982) (Starpath)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "78c2de58e42cd1faac2ea7df783eaeb3", "", "", "Fu Kung! (V0.07) (25-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "79004f84bdeee78d142e445057883169", "CCE", "C-830", "Planet Patrol (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "791bc8aceb6b0f4d9990d6062b30adfa", "Activision, David Crane - Ariola", "EAX-018, EAX-018-04B, EAX-018-04I - 711 018-725", "Pitfall! (1982) (Activision) (PAL)", "Abenteuer im Urwald (Jungle Runner)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "791c88eca9836af8c34bf32b07cb58a7", "SpiceWare - Darrell Spice Jr.", "SW-05", "Stay Frosty 2 (PAL60)", "AtariAge Holiday Greetings 2014", "Homebrew", "", "", "", "", "", "", "", "JOYSTICK", "", "", "", "", "", "", "", "YES", "" }, + { "7926083ad423ed685de3b3a04a914315", "Barry Laws Jr.", "", "Face Invaders 2 (Barry Laws Jr.) (Hack)", "Hack of Astroblast", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "792b1d93eb1d8045260c840b0688ec8f", "Kroko", "", "3E Bankswitch Test (TIA @ $00)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7972e5101fa548b952d852db24ad6060", "Atari - Sears", "CX2627 - 6-99841", "Human Cannonball (1979) (Atari)", "AKA Cannon Man", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "798b8921276eec9e332dfcb47a2dbb17", "Atari - CCW, Gary Stark", "CX26102", "Cookie Monster Munch (1983) (Atari) (PAL) [a]", "Uses Kids/Keypad Controllers", "", "", "", "", "", "", "", "", "", "KEYBOARD", "", "", "", "", "", "", "", "" }, + { "798cc114f1623c14085868cd3494fe8e", "", "", "Pins Revenge (Atari Freak 1)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7991e1797e5e9f311fd957e62d889dff", "Joe Grand", "", "SCSIcide (v1.1) (2001) (Joe Grand)", "", "New Release", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "", "", "AUTO 65", "", "", "", "" }, + { "7996b8d07462a19259baa4c811c2b4b4", "", "", "Math Gran Prix (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "79ab4123a83dc11d468fb2108ea09e2e", "Activision - Cheshire Engineering, David Rolfe, Larry Zwick", "AZ-037-04", "Beamrider (1984) (Activision)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "79b649fb812c50b4347d12e7ddbb8400", "", "", "Red Pong Number 2 Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "79c27f90591e3fdc7d2ed020ecbedeb3", "CCE", "C-815", "Seaquest (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "79d4af56036ec28f298cad964a2e2494", "", "", "Hangman Pac-Man Wordlist (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "79d6f61da3c64688ac8e075667f8a39f", "", "", "Tie-Fighters (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "79e5338dbfa6b64008bb0d72a3179d3c", "M Network - INTV, David Akers, Patricia Lewis Du Long", "MT4313", "Star Strike (1983) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "79fcdee6d71f23f6cf3d01258236c3b9", "Atari - GCC, Mike Feinstein, John Mracek", "CX2673, CX2673P", "Phoenix (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7a09299f473105ae1ef3ad6f9f2cd807", "Atari, Steve Wright", "CX2616P", "Pele's Soccer (1981) (Atari) (PAL)", "AKA Pele's Championship Soccer", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7a2af383014f5d810ad26d322823549d", "", "", "FlickerSort Demo (20-04-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7a5463545dfb2dcfdafa6074b2f2c15e", "20th Century Fox Video Games - Sirius Software, Mark Turmell", "11007", "Turmoil (1982) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7a63d7ea3f2851bcf04f0bb4ba1a3929", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (3 of 4) (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7a64a8b727c8215d945e37d565ca95a5", "Atari, Warren Robinett", "CX2606", "Slot Racers (1978) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7a64b5a6e90619c6aacf244cdd7502f8", "Baroque Gaming (Brian Eno)", "", "Warring Worms (Beta 1) (2002) (Baroque Gaming)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7a7f6ab9215a3a6b5940b8737f116359", "Arcadia Corporation, Kevin Norman", "AR-4103", "Killer Satellites (1983) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7a93d0c029eaa72236523eedc3f19645", "", "", "20 Sprites at Once Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7ab0917107b6ec768a5ebaadf28c497a", "", "", "Santa's Helper (Hack)", "Hack of Kaboom!", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, + { "7ab210f448de518fa61a5924120ba872", "", "", "Fortress (20-04-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7ab2f190d4e59e8742e76a6e870b567e", "Apollo, Larry Martin", "AP-2008", "Guardian (1982) (Apollo)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "01 65", "", "", "", "" }, + { "7ac4f4fb425db38288fa07fb8ff4b21d", "Goliath", "83-213", "Space Eagle (1983) (Goliath) (PAL)", "AKA Exocet", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7ad257833190bc60277c1ca475057051", "Atari, Alan J. Murphy, Robert Zdybel", "CX2668", "RealSports Football (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "7ad782952e5147b88b65a25cadcdf9e0", "Imagic, Dave Johnson", "720119-1A, 03211", "Kwibble (1983) (Imagic) (Prototype)", "AKA Quick Step! Beta", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7adbcf78399b19596671edbffc3d34aa", "Atari, Mimi Nyden, Joseph Tung", "CX26152", "Super Baseball (1988) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7af40c1485ce9f29b1a7b069a2eb04a7", "Amiga - Video Soft", "3120", "Mogul Maniac (1983) (Amiga)", "Uses the Amiga Joyboard", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7b24bfe1b61864e758ada1fe9adaa098", "Atari, Chris Crawford", "", "Wizard (1980) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7b33407b2b198af74906b936ce1eecbb", "King Atari", "", "Ghostbuster 2 (King Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "7b3cf0256e1fa0fdc538caf3d5d86337", "CommaVid, Joseph Biel", "CM-009", "Stronghold (1983) (CommaVid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7b43c32e3d4ff5932f39afcb4c551627", "Syncro, Daniel Wolf", "", "Kamikaze Saucers (1983) (Syncro) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7b4be337ac4d73eda75c848355f6f480", "Omegamatrix", "", "Star Wars Arcade (Atari Trak-Ball) (Y Inverted) (PAL60) v4 (Omegamatrix)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7b5207e68ee85b16998bea861987c690", "Atari, Carol Shaw", "CX26163P", "3-D Tic-Tac-Toe (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7b57318c489ff178f7ff500da1ec9e8c", "Thomas Jentzsch", "", "Reactor - Amiga Mouse Hack v1.3 (PAL) (Full-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7b6f3348dbf71ada88db0fdaf7feefe0", "", "", "3-D Corridor (Pink Spiral) (31-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7b79beb378d1b4471def90ceccf413de", "", "", "Pitfall Cupcake (Hack)", "Hack of Pitfall", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7b7b4ac05232490c28f9b680c72998f9", "Zellers", "", "Freeway (Zellers)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7b8a481e0c5aa78150b5555dff01f64e", "Atari - GCC, Mark Ackerman, Noellie Alito", "CX2692", "Moon Patrol (05-12-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7b938c7ddf18e8362949b62c7eaa660a", "Atari, Bob Whitehead - Sears", "CX2603 - 99803, 49-75601", "Star Ship (1977) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7ba07d4ea18bf3b3245c374d8720ad30", "Starpath Corporation, Stephen H. Landrum", "AR-4101", "Communist Mutants from Space (Preview) (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7bb286cb659d146af3966d699b51f509", "Atari - Axlon, Tod Frye", "CX26178", "Save Mary! (04-03-1989) (Atari) (Prototype)", "AKA Saving Mary", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7bc4fd254ec8c0a25a13f02fd3f762ff", "Retroactive", "", "Qb (V1.00) (Stella) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "7c00e7a205d3fda98eb20da7c9c50a55", "Apollo - Games by Apollo, Larry Minor, Ernie Runyon, Ed Salvo", "AP-2004", "Lost Luggage (1982) (Apollo)", "AKA Airport Mayhem", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7c4a499d343fca0cef2d59dd16af621a", "", "", "Poker Card Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7c757bb151269b2a626c907a22f5dae7", "TNT Games - Sculptured Software, Adam Clayton", "26192", "BMX Air Master (1989) (TNT Games) (PAL)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7c7a4a2d505c2d0c75337c44711d8d54", "Atari, Warren Robinett", "", "Elf Adventure (04-22-83) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7c9b3b8b25acf2fe3b8da834f69629c6", "", "", "I Robot (1984) (Atari) (Prototype) [!]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7ca7a471d70305c673fedd08174a81e8", "Tim Snider", "", "Venture II (2001) (Tim Snider)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "7cc77f6745e1f2b20df4a4327d350545", "Atari, Richard Maurer", "CX2632, CX2632P", "Space Invaders (1980) (Atari) (PAL) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7ccf350354ee15cd9b85564a2014b08c", "", "", "Big Dig (13-04-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7cd379da92c93679f3b6d2548617746a", "", "", "Demo Image Series #5 - Clown (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7cd900e9eccbb240fe9c37fa28f917b5", "Jone Yuan Telephonic Enterprise Co", "", "Bi! Bi! (Jone Yuan) (PAL)", "AKA Skindiver", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7ced6709f091e79a2ab9575d3516a4ac", "Activision, Steve Cartwright - Ariola", "EAX-027 - 711 027-722", "Plaque Attack (1983) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7cedffa0db65d610568b90aeca705ac6", "Atari, Rob Fulop - Sears", "CX2638 - 49-75166", "Missile Command (1981) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7cf3a9267cdb95aba91abc5838d61cc5", "Thomas Jentzsch", "", "Centipede - Atari Mouse Hack v1.4 (PAL60) (Half-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7d0b49ea4fe3a5f1e119a6d14843db17", "Gameworld, J. Ray Dettling", "133-008", "Frankenstein's Monster (1983) (Gameworld) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7d1034bcb38c9b746ea2c0ae37d9dff2", "Atari, Brad Stewart", "", "Morse Code Tutor (1979) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7d3cdde63b16fa637c4484e716839c94", "CCE", "", "Road Runner (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7d483b702c44ee65cd2df22cbcc8b7ed", "Atari, Warren Robinett", "", "Elf Adventure (05-25-83) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7d5c3b7b908752b98e30690e2a3322c2", "Dactari - Milmar", "", "Freeway (Dactari - Milmar)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7d726fa494f706784bafeb1b50d87f23", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (07-27-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7d8287e8423a56d4f8cef10435d97179", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Atari Trak-Ball Hack v1.2 (NTSC) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7d903411807704e725cf3fafbeb97255", "Imagic, Rob Fulop", "720104-1A, 720104-1B, IA3204", "Cosmic Ark (Reaction) (1982) (Imagic) [selectable starfield]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7d93071b3e3616093a6b5a98b0315751", "", "", "Gunfight 2600 - Music & Bugfixes 2 (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7d940d749e55b96b7b746519fa06f2de", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix (Preview) (1983) (Arcadia) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7d9c96b215d1941e87b6fb412eb9204f", "", "", "Othello (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7da9de8d62fcdd3a2c545b2e720c2a61", "CommaVid, John Bronstein", "CM-001", "MagiCard (1981) (CommaVid) (4K)", "Uses the Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7dbc8fa2e488e3f6b87fbe0f76c5b89f", "Ed Federmeyer", "", "Sound X (1996) (Ed Federmeyer)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7dc03a1f56d0e6a8aae3e3e50d654a08", "", "", "Hozer Video Demo (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7dcbfd2acc013e817f011309c7504daa", "Arcadia Corporation, Dennis Caswell", "AR-4000, AR-4100", "Phaser Patrol (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "7dd9c5284422f729066ab22a284c8283", "CCE", "C-833", "Target Practice (1983) (CCE) [a]", "AKA Carnival", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7ded20e88b17c8149b4de0d55c795d37", "Thomas Jentzsch, Paul Slocum", "", "Thrust+ Platinum (v1.26)", "", "New Release, supports BoosterGrip", "", "", "", "", "", "", "", "BOOSTERGRIP", "DRIVING", "", "", "", "", "", "", "", "" }, + { "7dfd100bda9abb0f3744361bc7112681", "Telesys, Don Ruffcorn", "1006", "Demolition Herby (1983) (Telesys) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "7e2fe40a788e56765fe56a3576019968", "Activision - Imagineering, Donald Hahn, Dan Kitchen", "AK-050-04", "Double Dragon (1989) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7e464186ba384069582d9f0c141f7491", "PlayAround - J.H.M.", "206", "General Re-Treat (1982) (PlayAround) (PAL)", "AKA Custer's Revenge", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7e4783a59972ae2cd8384f231757ea0b", "Atari - Imagineering, Dan Kichen", "CX26139P", "Crossbow (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7e51a58de2c0db7d33715f518893b0db", "CBS Electronics, E.F. Dreyer, Ed Salvo", "4L 2738 0000", "Mountain King (1983) (CBS Electronics) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "7e52a95074a66640fcfde124fffd491a", "Atari - GCC, Mike Feinstein, John Mracek", "CX2673", "Phoenix (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7e7c4c59d55494e66eef5e04ec1c6157", "Baroque Gaming (Brian Eno)", "", "Warring Worms (2002) (Baroque Gaming)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7e8aa18bc9502eb57daaf5e7c1e94da7", "CBS Electronics - Roklan, Joe Hellesen, Joe Wagner", "M8774, M8794", "Wizard of Wor (1982) (CBS Electronics)", "Uses the Joystick Controllers (swapped)", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "YES", "" }, + { "7e9da5cb84d5bc869854938fe3e85ffa", "Atari, Ian Shepard - Sears", "CX2604 - 6-99812, 49-75106", "Space War (1978) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7e9f088e15b2af9ff3411991393e6b1f", "Atari - Roklan, Joe Gaucher", "CX2679", "RealSports Basketball (12-28-1982) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7eab0284a0cd1043461d446a08d08cec", "Jone Yuan Telephonic Enterprise Co", "", "Basic Math (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7ead257e8b5a44cac538f5f54c7a0023", "Xonox, Anthony R. Henderson", "99006, 6220", "Sir Lancelot (1983) (Xonox) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7eaf009a892f03d90682dc1e67e85f07", "Fabrizio Zavagli", "", "Bounce! (18-03-2003) (Fabrizio Zavagli)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "7eafc9827e8d5b1336905939e097aae7", "Atari, Mark R. Hahn", "", "Elk Attack (1987) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7eba20c2291a982214cc7cbe8d0b47cd", "Imagic, Dave Johnson", "720119-1A, 03211", "Quick Step! (1983) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7ed61a18cebdeca0a93be1f5461731e5", "Dactari", "", "Skiing (Dactari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7ed7130a6e4020161836414332b11983", "", "", "Fu Kung! (V0.05 Cuttle Card Compatible) (13-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7edc8fcb319b3fb61cac87614afd4ffa", "Activision, Alan Miller", "AG-003", "Checkers (1980) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7ef3ca08abde439c6ccca84693839c57", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix (1983) (Arcadia) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "01", "", "", "", "" }, + { "7ef74879d7cb9fa0ef161b91ad55b3bb", "CCE", "", "Vanguard (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7f0209cfcc3d181715463f4d6451cecf", "Atari - GCC, John Allred, Douglas B. Macrae, Betty Ryan Tylko", "CX2694", "Pole Position (05-15-1983) (Atari) (Prototype)", "AKA RealSports Driving", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7f07cd2e89dda5a3a90d3ab064bfd1f6", "Videospielkassette - Ariola", "PGP234", "Boxen (Ariola) (PAL)", "AKA Boxing", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7f430c33044e0354815392b53a9a772d", "HES", "773-891", "2 Pak Special - Cavern Blaster, City War (1992) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7f525b07bc98080cc8950f7284e52ede", "Atari", "", "128-in-1 Junior Console (Chip 4 of 4) (1991) (Atari) (PAL)", "Actually contains only 16 games, not 32", "", "", "", "16IN1", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7f54fa6aa824001af415503c313262f2", "HES", "", "Boom Bang (HES) (PAL)", "AKA Crackpots", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7f6533386644c7d6358f871666c86e79", "CommaVid, Irwin Gaines", "CM-008", "Cakewalk (1983) (CommaVid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7f790939f7eaa8c47a246c4283981f84", "", "", "This Planet Sucks Demo 3 (Greg Troutman) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "7f819454734ddf93f83fefcffcd3e212", "Jone Yuan Telephonic Enterprise Co", "", "Outlaw (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7f9fbe3e00a21ea06e6ae5e0e5db2143", "", "", "Skate Boardin' (2002) (Skyworks)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7fcd1766de75c614a3ccc31b25dd5b7a", "PlayAround - J.H.M.", "203", "Knight on the Town (1982) (PlayAround)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "7fcd5fb59e88fc7b8473c641f44226c3", "CCE", "C-807", "Space Tunnel (1983) (CCE)", "AKA O Tunel Espacial", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7ff53f6922708119e7bf478d7d618c86", "Suntek", "SS-032", "Walker (1983) (Suntek) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "7ffc2d80fd49a124808315306d19868e", "Ishido", "", "Domino (Ishido) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "801ba40f3290fc413e8c816c467c765c", "Hozer Video Games", "", "Gunfight 2600 - Westward Ho! (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "803393ed29a9e9346569dd1bf209907b", "Atari - GCC, Mark Ackerman, Tom Calderwood, Glenn Parker", "CX2684", "Galaxian (02-04-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "804ed85eadf1ce3e93721547cbea7592", "CCE", "", "Fishing Derby (CCE) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8055b9c2622136fd91edfea6df642daf", "Activision", "", "Unknown Activision Game #1 (1983) (Activision) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "805f9a32ef97ac25f999a25014dc5c23", "SnailSoft", "", "Balthazar (SnailSoft)", "AKA Babylon 5", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "8068e07b484dfd661158b3771d6621ca", "Epyx, Steven A. Baker, Peter Engelbrite", "80561-00286", "California Games (1987) (Epyx) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "807841df228ee8aab0a06ee639ce5a8a", "Coleco - Project Guild - GMA, Michael Green, Anthony R. Henderson, Gary Littleton", "2455", "Turbo (1982) (Coleco) (Prototype)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "807a8ff6216b00d52aba2dfea5d8d860", "John Payson", "", "Strat-O-Gems Deluxe (2005) (J. Payson)", "Uses the AtariVox controller", "Homebrew", "", "", "", "", "", "", "", "", "ATARIVOX", "", "", "", "", "", "", "", "" }, + { "808c3b1e60ee0e7c65205fa4bd772221", "CCE", "", "Defender (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "80cd42881e670e4b74a9ccd10d0d7b2e", "20th Century Fox Video Games - Sirius, Ed Hodapp", "11004", "Deadly Duck (1982) (20th Century Fox) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "80cec82239913cb8c4016eb13749de44", "David Marli", "", "Invaders from Space by David Marli (Space Invaders Hack)", "Hack of Space Invaders (Atari)", "New Release (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "80dcbe1b55f12be731a224a53ee4ad5f", "Bit Corporation", "R320", "Amidar (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "80e1410ec98089e0733cc09e584dba4b", "Dynamics", "DY-293005", "Jumping Jack (1983) (Dynamics) (PAL)", "AKA Bobby Is Going Home", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "80e52315919bd8a8b82a407ccd9bb13f", "", "", "Euchre (Jul 28) (2002) (Eric Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "80e5400470ac788143e6db9bc8dd88cf", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (06-XX-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "80f7bf7418a462e8687ecefeaf6eb9c2", "Thomas Jentzsch", "", "Reactor - Atari Trak-Ball Hack v1.3 (NTSC) (Half-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8101efafcf0af32fedda4579c941e6f4", "", "", "Okie Dokie (4K) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "81073d0377a2badef8d5e74fc44fc323", "Thomas Jentzsch", "", "Sadoom (TJ) (PAL60) (Hack)", "Hack of Kaboom!", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, + { "8108162bc88b5a14adc3e031cf4175ad", "Suntek", "SS-030", "Skydiver (1983) (Suntek) (PAL)", "AKA Parachute", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8108ad2679bd055afec0a35a1dca46a4", "", "", "Maze Craze (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "NTSC", "", "", "" }, + { "810d8952af5a6036fca8d0c4e1b23db6", "Tiger Vision - Eram", "", "Keystone (Tiger Vision)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "81254ebce88fa46c4ff5a2f4d2bad538", "Atari, David Crane - Sears", "CX2653 - 6-99823, 49-75111", "Slot Machine (1979) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "81341f00b61ab37d19d1529f483d496d", "", "", "Fu Kung! (V0.04) (10-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "813985a940aa739cc28df19e0edd4722", "Imagic, Bob Smith", "720000-201, 720102-1B, IA3201", "Star Voyager (1982) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "81414174f1816d5c1e583af427ac89fc", "Thomas Jentzsch", "", "Treasure Below (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "A", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "814210c0e121f7dbc25661b93c06311c", "", "", "Joustpong (16-09-2002) (Kirk Israel) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "81591a221419024060b890665beb0fb8", "Atari, Carla Meninsky, Ed Riddle", "CX2611, CX2611P", "Indy 500 (1977) (Atari) (PAL)", "Uses the Driving Controllers", "", "", "", "", "", "", "", "", "DRIVING", "DRIVING", "", "", "", "45", "", "", "", "" }, + { "8190b403d67bf9792fe22fa5d22f3556", "", "", "Sky Diver (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "819aeeb9a2e11deb54e6de334f843894", "Atari, Gary Palmer", "CX2661", "Fun with Numbers (1980) (Atari)", "AKA Basic Math", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "81a010abdba1a640f7adf7f84e13d307", "Telegames - VSS", "7062 A305", "Universal Chaos (1988) (Telegames)", "AKA Targ", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "81b3bf17cf01039d311b4cd738ae608e", "CBS Electronics - Roklan, Joe Gaucher, Alex Leavens", "M8776, M8793", "Gorf (1982) (CBS Electronics)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "81f4f0285f651399a12ff2e2f35bab77", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "822a950f27ff0122870558a89a49cad3", "", "", "Space Jockey (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "82337e5fe0f418ca9484ca851dfc226a", "Thomas Jentzsch", "", "Robot City (V1.0) (Alpha) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "826481f6fc53ea47c9f272f7050eedf7", "Imagic, Dennis Koble", "720103-1A, IA3203", "Atlantis II (1982) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "827a22b9dffee24e93ed0df09ff8414a", "CBS Electronics, Stuart Ross", "", "Wings (10-10-1983) (CBS Electronics) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "8290daea8391f96d7c8e1482e184d19c", "Eckhard Stolberg", "", "Frame Timed Sound Effects (Eckhard Stolberg)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "82bf0dff20cee6a1ed4bb834b00074e6", "Suntek", "SS-035", "Panda (1983) (Quest) (Suntek) (PAL)", "AKA Panda Chase", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "82c25d1c35e6ac6f893d1d7c2fc2f9c8", "Atari, Larry Kaplan", "CX2628, CX2628P", "Bowling (1979) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "82de957d155fc041fc6afb8315a28550", "Coleco, Joseph Biel", "2457", "Venture (1982) (Coleco) (Prototype)", "2K", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "82e7aab602c378cffdd8186a099e807e", "", "", "Space Robot (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "82efe7984783e23a7c55266a5125c68e", "CCE", "C-837", "Pizza Chef (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "834a2273e97aec3181ee127917b4b269", "Quelle", "043.151 0, 874.382 5", "Die hungrigen Froesche (1983) (Quelle) (PAL)", "AKA Frogs and Flies", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "835759ff95c2cdc2324d7c1e7c5fa237", "20th Century Fox Video Games, Frank Cohen, Douglas 'Dallas North' Neubauer", "11011", "M.A.S.H (1983) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8372eec01a08c60dbed063c5524cdfb1", "", "", "Cross Force (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8388d6fe59c38c0b3a6ab2c58420036a", "Atari, Frank Hausman, Mimi Nyden, Steve Woita", "CX2686", "Quadrun (12-06-1982) (Atari) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "83b8c01c72306d60dd9b753332ebd276", "", "", "Bank Heist (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "83bdc819980db99bf89a7f2ed6a2de59", "Atari, Carla Meninsky - Sears", "CX2637 - 49-75158", "Dodge 'Em (1980) (Atari) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "83d15fb9843d9f84aa3710538403f434", "", "", "Gunfight 2600 - Release Candidate (2001) (MP) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "83e1b9f22f29259679e1018bc04cc018", "Bit Corporation", "R320", "Fast Eddie (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "83f05ececae8be59ba1e51135f4bdcbf", "", "", "Demo Image Series #13 - Mario (4K Interleaved Chronocolour) (05-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "83f50fa0fbae545e4b88bb53b788c341", "Atari, Larry Kaplan - Sears", "CX2643 - 6-99815", "Codebreaker (1978) (Atari) (4K)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "83fafd7bd12e3335166c6314b3bde528", "Epyx, Steven A. Baker, Tod Frye, Peter Engelbrite", "80561-00251", "Winter Games (1987) (Epyx)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "840a5a2eaea24d95d289f514fd12f9bb", "", "", "GBImprov (Hack)", "Hack of Ghostbusters", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "841057f83ce3731e6bbfda1707cbca58", "Champ Games", "CG-04-N", "Super Cobra Arcade (NTSC)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "JOYSTICK", "", "", "", "", "", "", "", "YES", "" }, + { "841b7bc1cad05f5408302308777d49dc", "Activision", "", "Unknown Activision Game (10-22-1982) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "84290e333ff7567c2380f179430083b8", "Imagic, Dave Johnson", "13211, EIX-004-04I", "Quick Step! (1983) (Imagic) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "843435eb360ed72085f7ab9374f9749a", "Joe Grand", "", "SCSIcide (1.31) (Joe Grand)", "Uses the Paddle Controllers", "New Release", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "", "", "AUTO 65", "", "", "", "" }, + { "84535afb9a69712ec0af4947329e08b8", "CCE", "C-868", "Bingo (1983) (CCE) (PAL)", "AKA Dice Puzzle", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "8454ed9787c9d8211748ccddb673e920", "Froggo", "FG1002", "Spiderdroid (1987) (Froggo)", "AKA Amidar", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8490e1014c2baa0d3a3a08854e5d68b3", "Xonox, Anthony R. Henderson", "99006, 6220", "Sir Lancelot (1983) (Xonox) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "84db818cd4111542a15c2a795369a256", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (1983) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "850ffd5849c911946b24544ea1e60496", "", "", "Invasion (07-10-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "851cc1f3c64eaedd10361ea26345acea", "Activision, David Crane", "AG-009, AG-009-04", "Freeway (1981) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "85227160f37aaa29f5e3a6c7a3219f54", "Activision, David Crane", "AG-004", "Fishing Derby (1980) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8530caaaf40acbdcd118c282b5f8a37a", "", "", "This Planet Sucks Demo 2 (Greg Troutman) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8538c5e3ee83267774480649f83fa8d6", "", "", "Escape Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "853c11c4d07050c22ef3e0721533e0c5", "", "", "Oink! (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "85470dcb7989e5e856f36b962d815537", "Atari - Sculptured Software, Inc., Steve Aguirre", "CX26162", "Fatal Run (1989) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "85478bb289dfa5c63726b9153992a920", "", "", "Candi (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "854b68b93e7123a3be42b5a2a41f75d7", "Atari, Carol Shaw", "CX2618, CX2618P", "3-D Tic-Tac-Toe (1980) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "85502d69fe46b7f54ef2598225678b47", "Jone Yuan Telephonic Enterprise Co", "", "Super-Ferrari (Jone Yuan)", "AKA Enduro", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "85564dd0665aa0a1359037aef1a48d58", "ITT Family Games", "554-33 367", "Laser Base (1983) (ITT Family Games) (PAL) [a]", "AKA The End of the World (Perry Rhodan-Serie)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "8556b42aa05f94bc29ff39c39b11bff4", "Atari, Craig Nelson - Sears", "CX2617 - 49-75183", "Backgammon (1979) (Atari)", "Uses the Paddle Controllers", "Extremely Rare", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "", "", "AUTO 80", "", "", "", "" }, + { "855a42078b14714bcfd490d2cf57e68d", "Atari, Suki Lee", "CX26113", "Miss Piggy's Wedding (1983) (Atari) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8597f66dd37d9c855663804669d69d7a", "Tigervision, Warren Schwader", "7-003", "Threshold (1982) (Tigervision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "85a4133f6dcf4180e36e70ad0fca0921", "CCE", "C-827", "Chopper Command (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "85b1bca93e69f13905107cc802a02470", "Atari, Craig Nelson", "CX2617, CX2617P", "Backgammon (1979) (Atari) (PAL)", "Uses the Paddle Controllers", "Extremely Rare", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "", "", "AUTO 80", "", "", "", "" }, + { "85bbefb90e16bf386b304c1e9a1f6084", "Champ Games", "CG-02-P", "Conquest Of Mars (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "85e48d68c8d802e3ba9d494a47d6e016", "", "", "Ship Demo (V 15) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "85e564dae5687e431955056fbda10978", "Milton Bradley Company - Renaissance Technology, Ty Roberts", "4362", "Survival Run (1983) (Milton Bradley)", "AKA Cosmic Commander", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "86128001e69ab049937f265911ce7e8a", "Apollo - Games by Apollo, Steve Stringfellow", "AP-2005", "Lochjaw (1982) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8619da7f6796cedff59e5aa20712fb4e", "Thomas Jentzsch", "", "Sadistroids (v1.2) (2003) (Thomas Jentzsch)", "Supports Driving Controller in right port", "", "", "", "", "", "", "", "", "", "DRIVING", "", "", "", "", "", "", "YES", "30" }, + { "862cf669cbced78f9ed31a5d375b2ebe", "", "", "Gunfight 2600 - Flicker acceptance (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8644352b806985efde499ae6fc7b0fec", "CCE", "C-801", "Mr. Postman (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8654d7f0fb351960016e06646f639b02", "Home Vision, R.J.P.G. - Gem International Corp. - VDI", "VCS83106", "Ski Hunt (1983) (Home Vision) (PAL)", "AKA Skiiing Hunt", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "866e5150c995c4ae5172e5207ba948c7", "Canal 3 - Intellivision", "", "Stampede (Canal 3) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "869abe0426e6e9fcb6d75a3c2d6e05d1", "", "", "Stampede (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "86b4aa76bbeb70e1a4f9211a9880ba8e", "", "", "Incoming (1 Player Version) (05-11-2002) (Ben Larson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8712cceec5644aacc2c21203d9ebe2ec", "Retroactive", "", "Qb (V0.10) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "8726c17ee7b559cb7bf2330d20972ad0", "", "", "Cave Demo (21-04-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "873fb75a7788ba0f4ae715229a05545e", "", "", "Euchre (Improved Colors) (PAL) (26-09-2002) (Erik Eid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8747ba79cd39fa83a529bb26010db21b", "Atari, Richard Maurer", "CX2632, CX2632P", "Space Invaders (1980) (Atari) (PAL) [different speed and colors]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8749a0d088df25218c149dc325abc7ca", "Commavid, Ben Burch", "CM-010", "Rush Hour (1983) (Commavid) (Prototype) [a5]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "874c76726f68c166fcfac48ce78eef95", "", "", "Red Pong Number 2 Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "8764462d7d19a33b0717af22b99fc88f", "CCE", "", "Sky Jinks (CCE) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "87662815bc4f3c3c86071dc994e3f30e", "Intellivision Productions - M Network, Patricia Lewis Du Long, Stephen Tatsumi", "", "Swordfight (1983) (Intellivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "876a953daae0e946620cf05ed41989f4", "Retroactive", "", "Qb (V2.08) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "877a5397f3f205bf6750398c98f33de1", "Erik Eid", "", "Euchre (Beta) (PAL) (12-09-2002) (Erik Eid)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8786c1e56ef221d946c64f6b65b697e9", "20th Century Fox Video Games, David Lubar", "11015", "AKA Space Adventure", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8786f229b974c393222874f73a9f3206", "Activision, Larry Miller - Ariola", "EAX-021, EAX-021-04I - 711 021-720", "Spider Fighter (1983) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8786f4609a66fbea2cd9aa48ca7aa11c", "Goliath", "5", "Open Sesame (1983) (Goliath) (PAL)", "AKA Open, Sesame!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "87b460df21b7bbcfc57b1c082c6794b0", "Dennis Debro", "", "Climber 5 (20-03-2003) (Dennis Debro)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "87b6a17132fc32f576bc49ea18729506", "Atari, Andrew Fuchs, Courtney Granner, Jeffrey Gusman, Mark R. Hahn", "CX2690", "Pengo (1984) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "87bea777a34278d29b3b6029833c5422", "Thomas Jentzsch", "", "Polaris (1983) (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "87e79cd41ce136fd4f72cc6e2c161bee", "Atari - GCC, Mark Ackerman, Glenn Parker", "CX2675", "Ms. Pac-Man (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "87f020daa98d0132e98e43db7d8fea7e", "20th Century Fox Video Games - Sirius, David Lubar", "11001", "Worm War I (1982) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "883258dcd68cefc6cd4d40b1185116dc", "Activision, David Crane - Ariola", "EAZ-030, EAZ-030-04B, EAZ-030-04I - 711 030-725", "Decathlon (1983) (Activision) (PAL)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8874b68751fd2ba6d3306a263ae57a7d", "Eric Mooney", "", "Invaders by Erik Mooney (Alpha 1) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8885d0ce11c5b40c3a8a8d9ed28cefef", "Atari, Carol Shaw, Nick 'Sandy Maiwald' Turner - Sears", "CX2608 - 49-75165", "Super Breakout (1982 - 1981) (Atari)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "", "", "01 45", "", "", "", "" }, + { "888debb162d7d1ae71025b4ab794257f", "", "", "Interleaved ChronoColour - Nude Art (17-04-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "88a6c9c88cb329ee5fa7d168bd6c7c63", "CCE", "C-1007", "Jungle Hunt (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "88d300a38bdd7cab9edad271c18cd02b", "Funvision - Fund. Int'l Co.", "", "Pac Kong (Funvision) (PAL)", "AKA Inca Gold", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "88d7b6b3967de0db24cdae1c7f7181bd", "Atari - GCC, Dave Payne", "CX2669", "Vanguard (1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "88d8a1accab58cf1abb043613cf185e9", "Ultravison", "", "Sabotage (Ultravison)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "88dce4037471424bb38ab6841aaa8cab", "", "", "Double-Height 6-Digit Score Display (Two Background Color Change) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "88ed87c011f699dd27321dbe404db6c8", "Activision, Dan Kitchen", "AX-029", "Crackpots (1983) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "88f74ec75ef696e7294b7b6ac5ca465f", "Activision, Bob Whitehead", "AG-002, CAG-002, AG-002-04", "Boxing (1980) (Activision) (16K)", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8905d54f48b8024fc718ed643e9033f7", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (05-24-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "890c13590e0d8d5d6149737d930e4d95", "Atari, David Crane - Sears", "CX2605 - 6-99822, 49-75109", "Outlaw (1978) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8917f7c1ac5eb05b82331cf01c495af2", "Bit Corporation", "PG202", "Space Tunnel (1982) (BitCorp) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8933976f2029c0d8492ebd8f4eb21492", "", "", "Synthcart Plus (09-02-2003) (Paul Slocum)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8953bc11352d794431d3303e31d3b892", "Tigervision, Robert H. O'Neil", "7-007", "Polaris (02-17-1983) (Tigervision) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "896ec58f26e930e02f5e4f046602c3a1", "", "", "Synthcart (Beta) (2002) (Paul Slocum)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "898143773824663efe88d0a3a0bb1ba4", "Activision - Woodside Design Associates, Steve 'Jessica Stevens' Kitchen", "AZ-033, AZ-033-04", "Space Shuttle (1983) (Activision) [FE]", "A Journey Into Space", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "898748d5eaac3164b0391a64ae1e0e32", "", "", "Hangman Man 4letter (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "898b5467551d32af48a604802407b6e8", "Bit Corporation", "PG208", "Snail Against Squirrel (1983) (BitCorp) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "89a65b83203980d5d4d60f52a584a5b8", "", "", "Marble Craze (PAL) (02-02-2003) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "89a68746eff7f266bbf08de2483abe55", "Atari, Jerome Domurat, Steve Woita", "CX2696", "Asterix (1984) (Atari)", "AKA Taz", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "89afff4a10807093c105740c73e9b544", "", "", "Pooyan (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "89eaba47a59cbfd26e74aad32f553cd7", "Apollo - Games by Apollo, Ed Salvo, Byron Parks", "AP-2001", "Spacechase (1982) (Apollo) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8a159ee58b2f0a54805162984b0f07e5", "Atari - Sculptured Software, Inc., Steve Aguirre", "CX26162", "Fatal Run (1989) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8a183b6357987db5170c5cf9f4a113e5", "Atari - Roklan, Joe Gaucher", "CX2679", "RealSports Basketball (01-11-1983) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8a42e2c7266439d8997a55d0124c912c", "", "", "Hangman Invader Wordlist (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8a49cf1785e3dea2012d331a3ad476e1", "", "", "Boulderdash (10 Blocks Wide) (02-04-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8a6c84f481acf42abcb78ba5064ad755", "128-in-1 Junior Console", "", "Street Racer (128-in-1 Junior Console) (PAL) (4K)", "Uses the Paddle Controllers (swapped)", "", "", "", "", "", "", "", "", "", "", "YES", "", "", "10 75", "", "", "", "" }, + { "8a8e401369e2b63a13e18a4d685387c6", "Activision, David Crane - Ariola", "EAG-008, PAG-008, EAG-008-04I - 711 008-720", "Laser Blast (1981) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8a9d874a38608964f33ec0c35cab618d", "Chris Cracknell", "", "Rescue Bira Bira (Chris Cracknell)", "Hack of Jungle Fever", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "8a9d953ac3db52a313a90d6a9b139c76", "", "", "Hangman Invader Biglist3 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8aad33da907bed78b76b87fceaa838c1", "Atari, Larry Kaplan", "CX26163P", "Air-Sea Battle (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8ac18076d01a6b63acf6e2cab4968940", "Atari, Dan Hitchens, Mimi Nyden", "CX2685", "Gravitar (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8af58a9b90b25907da0251ec0facf3b8", "Jone Yuan Telephonic Enterprise Co", "", "Cosmic Swarm (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "8b04e9d132b8e30d447acaa6bd049c32", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (1982) (Starpath) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8b40a9ca1cfcd14822e2547eaa9df5c1", "Parker Brothers - Western Technologies, Dave Hampton, Tom Sloper", "931517", "Q-bert (1983) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8b504b417c8626167a7e02f44229f0e7", "Retroactive", "", "Qb (V1.00) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "8b556c3d9ca8e5e6e665bd759b93ffae", "", "", "Synthcart (2002) (Paul Slocum) (PAL) [!]", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "8b5b1e3a434ebbdc2c2a49dc68f46360", "CBS Electronics - Woodside Design Associates - Imaginative Systems Software, Garry Kitchen", "4L1700, 4L1701, 4L1702, 4L1802, 4L2274", "Donkey Kong (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8b7ca29a55432f886cee3d452fb00481", "Starpath Corporation, Stephen H. Landrum, Jon Leupp", "11 AR-4201", "Sword of Saros (1983) (Starpath) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8b8152d6081f31365406cb716bd95567", "Atari", "CX2626, CX2626P", "Miniature Golf (1979) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8b8789c6669a4cee86c579a65332f852", "Digivision", "", "Plaque Attack (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8bbfd951c89cc09c148bfabdefa08bec", "UA Limited", "", "Pleiades (1983) (UA Limited) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "8bc0d2052b4f259e7a50a7c771b45241", "Xonox - K-Tel Software, Anthony R. Henderson", "99007, 6240", "Tomarc the Barbarian (1983) (Xonox) [a]", "AKA Thundarr the Barbarian", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8bd8f65377023bdb7c5fcf46ddda5d31", "Activision, Bob Whitehead", "AG-019", "Sky Jinks (1982) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8bebac614571135933116045204f0f00", "Thomas Jentzsch", "", "Missile Command (Trakball) (2002) (TJ) (PAL)", "Uses the Trakball Controller", "Homebrew", "", "", "", "", "", "", "", "TRAKBALL", "TRAKBALL", "", "", "", "", "", "", "YES", "" }, + { "8c103a79b007a2fd5af602334937b4e1", "Thomas Jentzsch", "", "Laser Base (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8c136e97c0a4af66da4a249561ed17db", "", "", "Poker Squares (V0.27) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8c146c61817edd376bc1354c7f1ddc63", "Omegamatrix", "", "Star Wars Arcade (Amiga Mouse) (Y Inverted) (PAL60) v4 (Omegamatrix)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8c1cc284edba691139d6626d062c606f", "Atari, Omegamatrix", "", "Super Breakout Menu (2020) (PAL60) (Hack)", "Hack of Super Breakout", "", "", "", "", "", "", "", "", "", "", "", "", "", "AUTO 45", "", "", "", "" }, + { "8c2fa33048f055f38358d51eefe417db", "Home Vision - Gem International Corp. - VDI", "VCS83137", "Teddy Apple (1983) (Home Vision) (PAL)", "AKA Open, Sesame!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "8c36ed2352801031516695d1eeefe617", "Epyx, Steven A. Baker, Tod Frye, Peter Engelbrite", "80561-00251", "Winter Games (1987) (Epyx) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8c7e5e2329f4f4e06cbcc994a30fd352", "Data Age", "DA1004", "Airlock (1982) (Data Age) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8c8a26ed57870daba8e13162d497bad1", "HES", "", "2 Pak Special - Dolphin, Oink (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8c8b15b3259e60757987ed13cdd74d41", "Supergame", "71", "River Raid (1984) (Supergame)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8c941fa32c7718a10061d8c328909577", "Digivision", "", "River Raid (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8ccaa442d26b09139685f5b22bf189c4", "Retroactive", "", "Qb (V1.01) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "8ccf63141a029603572d1056e772990e", "Thomas Jentzsch", "", "Centipede - Amiga Mouse Hack v1.4 (NTSC) (Full-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8cd26dcf249456fe4aeb8db42d49df74", "Atari - Imagineering, Dan Kichen", "CX26139", "Crossbow (1988) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8ce9126066f2ddd5173e9f1f9ce1494e", "Thomas Jentzsch", "", "Missile Command (Trakball) (2002) (TJ)", "Uses the Trakball Controller", "Homebrew", "", "", "", "", "", "", "", "TRAKBALL", "TRAKBALL", "", "", "", "", "", "", "YES", "" }, + { "8cf0d333bbe85b9549b1e6b1e2390b8d", "Atari, Brad Stewart", "CX2649, CX2649P", "Asteroids (1981) (Atari) (PAL)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "8d00a38f4c8f8800f1c237215ac243fc", "", "", "3-D Corridor (Green) (30-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8d1e2a6d2885966e6d86717180938f87", "Thomas Jentzsch", "", "Missile Command (Amiga Mouse) (2002) (TJ)", "Uses Amiga Mouse Controller", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "8d8b7d7b983f75debbdaac651e814768", "", "", "Demo Image Series #15 - Three Marios (PAL) (06-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8d9a06101ebb0f147936356e645309b8", "", "", "Grid Pattern Demo 2 (20-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8da51e0c4b6b46f7619425119c7d018e", "Atari - Imagineering, David Lubar", "CX26183", "Sentinel (1991) (Atari)", "Uses the Light Gun Controller (left only)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8db152458abaef3cfa7a4e420ddbda59", "", "", "Keystone Kapers (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8df4be9ddc54ac363b13dc57ceaf161a", "Scott Stilphen", "", "Asteroids SS (Scott Stilphen) (Hack)", "Hack of Asteroids", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "8e0ab801b1705a740b476b7f588c6d16", "Activision, David Crane", "AG-009, AG-009-04", "Freeway (1981) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8e42674972d6805068fc653e014370fd", "", "", "Skeleton (PAL) (15-10-2002) (Eric Ball)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8e48ea6ea53709b98e6f4bd8aa018908", "CBS Electronics, Stuart Ross", "", "Wings (06-03-1983) (CBS Electronics) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "8e4cd60d93fcde8065c1a2b972a26377", "Imagic, Dan Oliver", "720118-2A, 13208, EIX-007-04I", "Laser Gates (1983) (Imagic) (PAL)", "AKA Innerspace", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8e4fa8c6ad8d8dce0db8c991c166cdaa", "Atari, Bill Aspromonte, John Russell, Michael Sierchio, Robert Zdybel", "CX26114", "Pigs in Space (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8e512ad4506800458f99dec084fc2c64", "Bob Montgomery, Nathan Strum", "", "Reindeer Rescue (2005)", "2005 AtariAge Holiday Cart", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8e7241bfc8380aac3c0ef1b6881cdded", "Atari, Howard Scott Warshaw - Sears", "CX2655 - 49-75167", "Yars' Revenge (09-01-81) (Atari) (Prototype)", "Time Freeze", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "8e737a88a566cc94bd50174c2d019593", "Quelle", "343.173 1", "Feuerwehr im Einsatz (1983) (Quelle) (PAL)", "AKA Fire Fighter", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8e822b39a71c84ac875f0107fb61d6f0", "", "", "Hangman Ghost Original Words (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8e879aa58db41edb67cbf318b77766c4", "Thomas Jentzsch", "", "Cosmic Commuter (Thomas Jentzsch) (PAL60)", "NTSC Conversion", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8e887d1ba5f3a71ae8a0ea16a4af9fc9", "", "", "Skeleton (V1.1) (PAL) (24-10-2002) (Eric Ball)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8ed5a746c59571feb255eaa7d6d0cf98", "", "", "Carnival (208 in 1) (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8ed73106e2f42f91447fb90b6f0ea4a4", "Spectravision - Spectravideo", "SA-204", "Tapeworm (1982) (Spectravision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "8ee3f64dc0f349adc893fe93df5245d8", "", "", "Euchre (20-07-2001) (Eric Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8ef96ace4a1d6dfb65926c1e868b0188", "Thomas Jentzsch", "", "Reactor - Amiga Mouse Hack v1.3 (PAL60) (Half-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8f33bce5ba1053dcf4cea9c1c69981e4", "", "", "Jawbreaker (Unknown) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8f53a3b925f0fd961d9b8c4d46ee6755", "", "", "Astrowar (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8f5ac5139419c5d49bacc296e342a247", "Atari - CCW, Michael Callahan, Preston Stuart", "CX26103", "Alpha Beam with Ernie (12-22-1982) (Atari) (Prototype)", "Uses Keypad Controllers", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8f60551db6d1535ef0030f155018c738", "", "", "Space War (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8f613ea7c32a587d6741790e32872ddd", "", "", "Troll Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8f88309afad108936ca70f8b2b084718", "Spectravision - Spectravideo - Quelle", "SA-203 - 413.223 9", "Cross Force (1982) (Spectravision) (PAL)", "AKA Kreuzfeuer (Cross Fire)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8f90590dba143d783df5a6cff2000e4d", "", "", "Gopher (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8f98519a91dbbf4864f135a10050d9ed", "Silvio Mogno", "", "Rainbow Invaders (non-playable demo) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8fa47e5242776e841df7e708b12eb998", "", "", "Sea Hawk (Genesis)", "Genesis controller (C drops bomb)", "Hack of Sea Hawk", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8fbabaa87941cdf3a377c15e95bdb0f3", "", "", "Meteor Smasher (SnailSoft)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8fe00172e7fff4c1878dabcf11bb8dce", "Quelle", "689.302 8", "Hili Ball (1983) (Quelle) (PAL)", "AKA Racquetball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "8febdd9142960d084ab6eeb1d3e88969", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX2674", "E.T. - The Extra-Terrestrial (1982) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "8fffc8f15bb2e6d24e211884a5479aa5", "Retroactive", "", "Qb (V1.00) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "9007c3cbb55ce05ad7d1c34d4906750a", "Activision, David Crane", "AX-018, AX-018-04", "Pitfall! (03-18-1983) (Activision) (Prototype)", "Pitfall Harry's Jungle Adventure (Jungle Runner)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9048ccb7e0802cd8fa5bfc2609f292d8", "Tigervision, Robert H. O'Neil", "7-007", "Polaris (1983) (Tigervision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9057694dce8449521e6164d263702185", "Activision, Bob Whitehead", "AG-011", "Stampede (1981) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "90578a63441de4520be5324e8f015352", "Bit Corporation", "PGP204", "Open Sesame (4 Game in One) (1983) (BitCorp) (PAL)", "AKA Open, Sesame!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "9072c142728a3a3d994956d03bfacba2", "Fabrizio Zavagli", "", "Crash Dive (Fabrizio Zavagli) (PAL60)", "NTSC Conversion", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "90a3c3255f2a54225cdcb50831f8793a", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Atari Trak-Ball Hack v1.1 (PAL) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "90b1799dddb8bf748ee286d22e609480", "", "", "Ship Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "90b647bfb6b18af35fcf613573ad2eec", "AtariAge (Chris Walton)", "", "Juno First (2009)", "AtariVox supported", "Homebrew", "", "", "", "", "", "", "", "", "ATARIVOX", "", "", "", "", "", "", "YES", "" }, + { "90ccf4f30a5ad8c801090b388ddd5613", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (1982) (Starpath)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "90d77e966793754ab4312c47b42900b1", "Imagic, Brad Stewart", "720105-2A, IA3400P, EIX-005-04I", "Fire Fighter (1982) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "90f502cbf4438a95f69f848cef36eb64", "Digitel", "", "River Raid II (1985) (Digitel)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "910dd9bf98cc5bc080943e5128b15bf5", "", "", "Gunfight 2600 - Improved AI (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "911d385ee0805ff5b8f96c5a63da7de5", "Thomas Jentzsch", "", "Jammed (V0.1) (Demo) (2001) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "913d5d959b5021f879033c89797bab5e", "", "", "Robot Player Graphic (1996) (J.V. Matthews) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "914a8feaf6d0a1bbed9eb61d33817679", "Atari", "CX26163P", "Freeway Chicken (32 in 1) (1988) (Atari) (PAL)", "AKA Freeway", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "91925abce3a29e33b6a8b81482f4f5af", "Activision, Garry Kitchen - Ariola", "EAX-025, EAX-025-04I - 711 025-725", "Keystone Kapers (1983) (Activision) (PAL) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9193b6fff6897d43274741d4f9855b6d", "", "", "M.A.S.H (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "91a3749ff7b7e72b7fa09e05396a0e7b", "", "", "Gunfight 2600 - Final Run Part 2 (2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "91b007f33f9b790be64f57220ec52e80", "Jone Yuan Telephonic Enterprise", "", "Laser Blast (Jone Yuan) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "91c2098e88a6b13f977af8c003e0bca5", "Atari - GCC", "CX2676", "Centipede (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "91d1c82ceaf8af2add3973a3c34bc0cb", "", "", "Starfield Demo 1 (20-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "91f0a708eeb93c133e9672ad2c8e0429", "", "", "Oystron (V2.9) (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "91fdb6541f70c40b16aabf8308123be8", "", "", "Interlacing Game (19-08-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9222b25a0875022b412e8da37e7f6887", "Panda", "106", "Dice Puzzle (1983) (Panda)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "9245a84e9851565d565cb6c9fac5802b", "Bomb - Onbase", "CA282", "Great Escape (1983) (Bomb)", "AKA Asteroid Fire", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "927d422d6335018da469a9a07cd80390", "Activision, Carol Shaw - Ariola", "EAX-020, EAX-020-04B, EAX-020-04I - 711 020-720", "River Raid (1982) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9281eccd7f6ef4b3ebdcfd2204c9763a", "Retroactive", "", "Qb (2.15) (Retroactive) (PAL)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "9295570a141cdec18074c55dc7229d08", "Telegames", "7045 A015", "Bump 'n' Jump (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "929e8a84ed50601d9af8c49b0425c7ea", "Bit Corporation", "PG205", "Dancing Plate (1982) (BitCorp) (PAL)", "AKA Dishaster, Dancing Plates, Tanzende Teller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "92a1a605b7ad56d863a56373a866761b", "U.S. Games Corporation - Western Technologies, Dave Hampton", "VC2006", "Raft Rider (1983) (U.S. Games)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "92d1b6cb8a1b615266c4088a58464779", "Bit Corporation", "R320", "Fishing Derby (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "92d1f6ac179ebe5963868d6bc1bdda8d", "HES", "498", "Smash Hit Pak - Frogger, Boxing, Seaquest, Skiing, Stampede (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "92e72f7cc569584c44c9530d645ae04e", "Canal 3 - Intellivision", "", "Spider Fighter (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "931b91a8ea2d39fe4dca1a23832b591a", "Activision, David Crane", "AG-008", "Laser Blast (1981) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9333172e3c4992ecf548d3ac1f2553eb", "Konami", "RC 101-X 02", "Strategy X (1983) (Konami)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "93420cc4cb1af1f2175c63e52ec18332", "Tim Snider", "", "Blair Witch Project (Tim Snider) (Hack)", "Hack of Haunted House", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9364ad51c321e0f15c96a8c0aff47ceb", "Atari, Rob Fulop", "CX2638", "Missile Command (1981) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "936ef1d6f8a57b9ff575dc195ee36b80", "", "", "Pac Kong (Unknown)", "AKA Inca Gold", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "936f555b4b1a2cd061b659ff63f4f5f2", "HES, David Lubar", "535", "My Golf (1990) (HES) (PAL) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "937736d899337036de818391a87271e0", "Atari, Peter C. Niday", "CX26108", "Donald Duck's Speedboat (04-12-1983) (Atari) (Prototype)", "AKA Donald Duck's Regatta", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "939ce554f5c0e74cc6e4e62810ec2111", "ZiMAG - Emag - Vidco", "711-111 - GN-020", "Dishaster (1983) (ZiMAG)", "AKA Dancing Plate", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "93acd5020ae8eb5673601e2edecbc158", "Chris Cracknell", "", "Video Time Machine (Chris Cracknell)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "93b9229fc0ea4fb959d604f83f8f603c", "Thomas Jentzsch", "", "Amidar DS (Fast Enemies) (2003) (TJ) (Hack)", "Hack of Amidar", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "93c4b910f7649b3e998bb6d8527c6f4a", "Sparrow - Enter-Tech, Paul Walters, Rick Harris, George Hefner, Barbara Ultis", "", "Arkyology (1983) (Sparrow) (Prototype) [fixed]", "Fix for un-initialized 'X' register", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "93c52141d3c4e1b5574d072f1afde6cd", "Imagic, Mark Klein", "720112-1A, 03213", "Subterranea (1983) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "93c8d9d24f9c5f1f570694848d087df7", "Digivision", "", "Galaxian (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "93c9f9239a4e5c956663dd7affa70da2", "Quelle", "626.610 0", "Billard (1983) (Quelle) (PAL)", "AKA Trick Shot", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "93db185c3b3dc382f3aecd6a2fea7fd9", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Atari Trak-Ball Hack v1.1 (PAL60) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "93dc15d15e77a7b23162467f95a5f22d", "CCE", "", "Sky Jinks (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "93e276172b521c4491097f8b1393eea7", "Atari", "", "Diagnostic Test Cartridge 4.2 (06-01-1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "93eb1795c8b1065b1b3d62bb9ec0ccdc", "JSK", "", "Custer's Viagra (JSK) (Hack)", "Hack of Custer's Revenge", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "94102febc53b4a78342d11b645342ed4", "", "", "Joustpong (14-07-2002) (Kirk Israel) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9433770890f087bfcf3e50122694d8c0", "Omegamatrix", "", "Star Wars Arcade (Amiga Mouse) (Y Inverted) v4 (Omegamatrix)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9436b7ad131b5a1f7753ce4309ba3dee", "Kyle Pittman", "", "War of The Worlds (Kyle Pittman) (Hack)", "Hack of Defender", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "943798452ceba9357e2c56303cadb4f7", "Thomas Jentzsch, Paul Slocum", "", "Thrust+ Platinum (v1.28)", "", "New Release, supports BoosterGrip and Genesis (switched by Color/B+W)", "", "", "", "", "", "", "", "JOYSTICK", "DRIVING", "", "", "", "", "", "", "", "" }, + { "9446940866c9417f210f8552cf6c3078", "Thomas Jentzsch", "", "Marble Craze - Amiga Mouse Hack v1.0 (PAL60) (TJ)", "Uses Amiga Mouse Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "94507dee401b0a072a481c00d7699ffe", "Thomas Jentzsch", "", "Missile Control - Atari Trak-Ball Hack v1.15 (PAL) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9469d18238345d87768e8965f9f4a6b2", "CCE", "", "Ms. Pac-Man (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "947317a89af38a49c4864d6bdd6a91fb", "CBS Electronics, Bob Curtiss", "4L 2487 5000", "Solar Fox (1983) (CBS Electronics)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "94b92a882f6dbaa6993a46e2dcc58402", "Activision, Larry Miller", "AX-026, AX-026-04", "Enduro (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "94d90f63678e086f6b6d5e1bc6c4c8c2", "Digivision", "", "Seaquest (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "94e3fbc19107a169909e274187247a9d", "", "2402-044-01", "2-in-1 Freeway and Tennis (Unknown)", "", "", "", "", "2IN1", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "94e4c9b924286038527f49cdc20fda69", "Retroactive", "", "Qb (V2.12) (Stella) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "94e7cc6342d11e508e7e8b2ddf53c255", "", "", "Missile Command (208 in 1) (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "94ff6b7489ed401dcaaf952fece10f67", "Atari - GCC, Mark Ackerman, Noellie Alito", "CX2692", "Moon Patrol (07-31-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "951e8cec7a1a1d6c01fd649e7ff7743a", "Atari - Sculptured Software, Adam Clayton", "CX26151, CX26151P", "Dark Chambers (1988) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9526e3db3bdfbc27989a9cbfd0ee34bf", "", "", "Atari Logo Demo 6 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "95351b46fa9c45471d852d28b9b4e00b", "Atari, Tom Rudadahl", "CX26163P", "Golf (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "955c408265ad6994f61f9b66657bbae9", "", "", "Quadrun (Video Conversion) (Fabrizio Zavagli)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "956496f81775de0b69a116a0d1ad41cc", "CCE", "", "Alien (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "956b99511c0f47b3a11d18e8b7ac8d47", "", "", "Bones (Arcade Golf Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "95956108289a917f80667eccd3ce98a9", "Atari, Ed Logg, Carol Shaw", "CX2639, CX2639P", "Othello (1981) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "95a69cf8c08ef1522b050529464f0bca", "", "", "Grid Pattern Demo 1 (20-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "95a89d1bf767d7cc9d0d5093d579ba61", "PlayAround - J.H.M.", "204", "Lady in Wading (1982) (PlayAround)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "95e1d834c57cdd525dd0bd6048a57f7b", "Atari, Bill Aspromonte, John Russell, Michael Sierchio, Robert Zdybel", "CX26114", "Pigs in Space (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "95e542a7467c94b1e4ab24a3ebe907f1", "Suntek", "SS-021", "Dragon Defender (1983) (Suntek) (PAL)", "", "", "", "", "", "", "", "", "", "MINDLINK", "", "", "", "", "", "", "", "YES", "" }, + { "95fd6097dc27c20666f039cfe34f7c69", "", "", "Oh No! (Version 1) (17-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "961112b74a920a5242e233480326c356", "Activision, Alan Miller", "AG-007, CAG-007", "Tennis (1981) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "962ffd3eaf865230a7a312b80e6c5cfd", "Imagic, Wilfredo 'Willy' Aguilar, Michael Becker, Rob Fulop", "13205", "Fathom (1983) (Imagic) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "96662271ae50b6859017bffbdda75525", "Andrew Davie & Thomas Jentzsch", "", "Boulder Dash - Demo (2011)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "96670d0bf3610da2afcabd8e21d8eabf", "", "", "Boring Pitfall (Hack)", "Hack of Pitfall!", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "966b11d3c147d894dd9e4ebb971ea309", "", "", "Marble Craze Song (Paul Slocum) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "966c955e4aaca7082d9ffb9a68e3f3ed", "Thomas Jentzsch", "", "Centipede - Atari Mouse Hack v1.4 (PAL) (Full-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9671b658286e276cc4a3d02aa25931d2", "", "", "Hangman Ghost Wordlist (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "968efc79d500dce52a906870a97358ab", "TNT Games - Sculptured Software, Adam Clayton", "26192", "BMX Air Master (1989) (TNT Games)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "969b968383d9f0e9d8ffd1056bcaef49", "Atari, Larry Kaplan", "CX2628, CX2628P", "Bowling (1979) (Atari) (PAL)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "96bcb3d97ce4ff7586326d183ac338a2", "", "", "Revenge of the Apes (Hack) [h2]", "Hack of Planet of the Apes", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "96e798995af6ed9d8601166d4350f276", "20th Century Fox Video Games - Videa, David Ross", "11029", "Meltdown (1983) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "96eccc2277043508a6c481ea432d7dd9", "Thomas Jentzsch", "", "Missile Command (Atari Mouse) (2002) (TJ) (PAL)", "Uses Atari ST Mouse Controller", "Homebrew", "", "", "", "", "", "", "", "ATARIMOUSE", "ATARIMOUSE", "", "", "", "", "", "", "YES", "" }, + { "96f806fc62005205d851e758d050dfca", "", "", "Push (V0.05) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "97184b263722748757cfdc41107ca5c0", "Parker Brothers", "PB5820", "Mr. Do!'s Castle (1984) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "9718b85ac5a55cbc7348963c63ffa35a", "Robby", "", "Demon Attack (Robby)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "972486110933623039a3581db308fda6", "", "", "Xeno Plus (Hack)", "Hack of Xenophobe", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "97327d6962f8c64e6f926f79cd01c6b9", "", "", "Jawbreaker (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "977294ae6526c31c7f9a166ee00964ad", "Atari - GCC, Douglas B. Macrae", "CX2677, CX2677P", "Dig Dug (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9784290f422e7aeeab4d542318bd9a1f", "AtariAge, Chris Walton", "1.0 (Release)", "Chetiry (2011) (AtariAge) (60k)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "50" }, + { "97842fe847e8eb71263d6f92f7e122bd", "Imagic, Wilfredo Aguilar, Michael Becker, Dennis Koble", "720113-1A, 03206", "Solar Storm (1983) (Imagic)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "01 45", "", "", "", "" }, + { "97933c9f20873446e4c1f8a4da21575f", "", "", "Racquetball (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "97a9bb5c3679d67f5c2cd17f30b85d95", "Atari", "", "Colors (1980) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "97cd63c483fe3c68b7ce939ab8f7a318", "Thomas Jentzsch", "", "Robot City (V0.21) (15-09-2002) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "97d0151beb84acbe82aa6db18cd91b98", "Steve Engelhardt", "", "Lunar Attack (2002) (Steve Engelhardt) (Hack)", "Hack of Z-Tack", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "97d079315c09796ff6d95a06e4b70171", "Activision, Garry Kitchen", "AZ-032", "Pressure Cooker (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "97e47512f89e79818d988d078dc90410", "Thomas Jentzsch", "", "Missile Control - Amiga Mouse Hack v1.15 (NTSC) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "97f4da9f1031486f4e588f1e53572e53", "SpiceWare - Darrell Spice Jr.", "", "Draconian", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "9813b9e4b8a6fd919c86a40c6bda8c93", "Atari", "CX26177", "Ikari Warriors (1989) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9831efc7f4cb8ffb4df0082bab2f07a3", "Activision, Steve Cartwright - Ariola", "EAX-031, EAX-031-04B - 711 031-717", "Frostbite (1983) (Activision) (PAL) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9848b5ef7a0c02fe808b920a2ac566d2", "Skyworks Technology Inc.", "", "Baseball (2002) (Skyworks)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9853089672116117258097dbbdb939b7", "Hozer Video Games", "", "Gunfight 2600 - Cowboy Hair (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "98555b95cb38e0e0b22b482b2b60a5b6", "", "", "Spinning Fireball (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "98ba601a60172cb46c5bf9a962fd5b1f", "", "", "Gorilla Kong (Hack)", "Hack of Donkey Kong", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "98ccd15345b1aee6caf51e05955f0261", "Retroactive", "", "Qb (V2.03) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "98e5e4d5c4dd9a986d30fd62bd2f75ae", "", "", "Air-Sea Battle (Unknown) (Hack) (4K)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "98e6e34af45a0664597972c3bb31180f", "", "", "Space Instigators (V1.7) (17-10-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "98e7caaab8ec237558378d2776c66616", "Bradford W. Mott", "", "HMOVE Test (Bradford W. Mott) (1998) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "98ea10c47c13f1b3306c7b13db304865", "", "", "Jam Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "98ec0fa4199b9c01f7b8fa3732e43372", "Activision, David Crane", "AX-018, AX-018-04", "Pitfall! (1982) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "98ef1593624b409b9fb83a1c272a0aa7", "CCE", "C-831", "Cosmic Ark (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "98f63949e656ff309cefa672146dc1b8", "Atari - Axlon, John Vifian", "CX26168", "Off the Wall (1989) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "98fa3ad778a668a79449350de4b3b95b", "Thomas Jentzsch", "", "Thrust (V1.1) (2000) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9905f9f4706223dadee84f6867ede8e3", "HES", "", "Challenge (HES) (PAL)", "Surfer's Paradise if right difficulty = 'A'", "", "", "0", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9912d06eea42200a198dd3e2be18c601", "Imagic, Michael Greene", "IA3312", "No Escape! (1982) (Imagic) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "991d57bbcd529ad62925098e0aec1241", "", "", "Gunfight 2600 - The Final Kernel (MP) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9945a22f60bbaf6d04a8d73b3cf3db75", "Activision, Dan Kitchen", "EAX-039-04B, EAX-039-04I", "Kung-Fu Master (1987) (Activision) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9947f1ebabb56fd075a96c6d37351efa", "CBS Electronics", "4L 2737 0000", "Omega Race (1983) (CBS Electronics)", "Set right difficulty to 'A' for BoosterGrip in both ports", "", "", "", "", "", "A", "", "", "BOOSTERGRIP", "BOOSTERGRIP", "", "", "", "", "", "", "", "" }, + { "9962034ea7b3d4a905d0991804670087", "", "", "Grid Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9989f974c3cf9c641db6c8a70a2a2267", "Eckhard Stolberg", "", "Colours Selector (Eckhard Stolberg)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "99a24d7bb31d49b720b422550b32c35f", "", "", "Hangman Ghost Biglist1 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "99ac89241365b692255ba95d745edd91", "Atari, Frank Hausman, Mimi Nyden, Steve Woita", "CX2686", "Quadrun (18-03-1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "99f7c6c26046bbe95f1c604b25da8360", "SnailSoft", "", "Comitoid beta 2 (SnailSoft)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9a01115206f32eb0b539c7e5a47ccafa", "Atari, Jerome Domurat, Steve Woita", "CX2699", "Taz (07-15-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9a165c39af3f050fdee6583fdfcdc9be", "Zirok", "", "Mario Bros. (Zirok)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9a21fba9ee9794e0fadd7c7eb6be4e12", "Atari - Imagineering, Dan Kitchen", "CX26177", "Ikari Warriors (1991) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9a25b3cfe2bbb847b66a97282200cca2", "Atari, Brad Stewart - Sears", "CX2622 - 6-99813, 49-75107", "Breakout (1978) (Atari) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "01 60", "", "", "", "" }, + { "9a4274409216ff09ecde799f2a56ac73", "CCE", "C-801", "Mr. Postman (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9ab72d3fd2cc1a0c9adb504502579037", "Epyx, Steven A. Baker, Peter Engelbrite", "80561-00286", "California Games (1987) (Epyx)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9ad362179c2eea4ea115c7640b4b003e", "", "", "Barnstorming (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "NTSC50", "", "", "" }, + { "9ad36e699ef6f45d9eb6c4cf90475c9f", "Imagic, Dennis Koble", "720103-1A, 720103-1B, IA3203, IX-010-04", "Atlantis (1982) (Imagic)", "AKA Lost City of Atlantis", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9aeb5206c5bf974892a9cc59f1478db3", "Activision, Steve Cartwright", "AX-013", "Barnstorming (1982) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9af615951e9719df2244bc77fc50cb95", "Dactari - Milmar", "", "Defender (Dactari - Milmar)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9afdfe1cff7f37f1c971fe3f0c900606", "Funvision - Fund. International Co.", "", "Plug Attack (Funvision)", "AKA Plaque Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9b150a42fc788960fbb4cbe250259ee2", "Kroko", "", "3E Bankswitch Test (TIA @ $40)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9b21d8fc78cc4308990d99a4d906ec52", "CCE", "C-838", "Immies & Aggies (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9b246683f44c963a50e41d6b485bee77", "", "", "Boring (PAL) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9bb136b62521c67ac893213e01dd338f", "Xonox - Beck-Tech", "6210, 7210, 06003. 99001", "Spike's Peak (1983) (Xonox) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9bd4e0d5f28ba6da417c26649171f8e4", "", "", "Hangman Pac-Man Original Words (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9be58a14e055b0e7581fc4d6c2f6b31d", "", "", "Adventure (Color Scrolling) (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9c27ef3bd01c611cdb80182a59463a82", "Arcadia Corporation, Kevin Norman", "AR-4103", "Killer Satellites (1983) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9c40bf810f761ffc9c1b69c4647a8b84", "", "", "2 in 1 - Frostbite, River Raid (Unknown)", "", "", "", "", "2IN1", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9c6d65bd3b477aace0376f705b354d68", "", "", "RPG Kernal (18-04-2003) (Paul Slocum) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "9c6faa4ff7f2ae549bbcb14f582b70e4", "U.S. Games Corporation, Garry Kitchen, Paul Willson - Vidtec", "VC1002", "Sneak 'n Peek (1982) (U.S. Games)", "AKA Hide 'n Seek", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9c6fd6ed3599978ab7b6f900484b9be6", "Andrew Wallace", "", "Laseresal 2002 (PAL60) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9c729017dd2f9ccbadcb511187f80e6b", "", "", "J-Pac (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9c7fa3cfcaaafb4e6daf1e2517d43d88", "", "", "PIEROXM Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9ca2deb61318eba4fb784d4bf7441d8b", "", "", "Purple Bar Demo 2 (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9cbb07f1993a027bc2f87d5205457ec9", "", "", "Eckhard Stolberg's Scrolling Text Demo 1 (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9d0befa555f003069a21d2f6847ad962", "Atari - GCC, Dave Payne", "CX2669", "Vanguard (1982) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9d1556ae5890398be7e3d57449774b40", "Activision, David Crane", "AG-001", "Dragster (1980) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9d2938eb2b17bb73e9a79bbc06053506", "Imagic, Michael Greene", "EIZ-002-04I", "Wing War (1983) (Imagic) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9d2f05d0fe8b2dfcf770b02eda066fc1", "", "", "Push (V0.06) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9d33d31fb1de58c5460d8a67b57b36da", "", "", "Star Voyager (Genesis)", "Genesis controller (C is secondary lasers)", "Hack of Star Voyager", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9d37a1be4a6e898026414b8fee2fc826", "M Network - INTV - APh Technological Consulting, David Rolfe", "MT5665", "Super Challenge Baseball (1982) (M Network)", "AKA Big League Baseball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9d4bc7c6fe9a7c8c4aa24a237c340adb", "Dennis Debro", "", "Climber 5 (16-04-2003) (Dennis Debro)", "For Philly Classic 4", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9d522a3759aa855668e75962c84546f7", "Atari, Tom Rudadahl", "CX2634, CX2634P", "Golf (1980) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9d7f04618bb4043f531d087e3aaa7ac8", "Parker Brothers, Larry Gelberg, Gary Goltz", "PB5065", "Star Wars - Ewok Adventure (1983) (Parker Bros) (Prototype) (PAL) (16K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9de0d45731f90a0a922ab09228510393", "20th Century Fox Video Games - Sirius, Mark Turmell", "11003", "Fast Eddie (1982) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9dec0be14d899e1aac4337acef5ab94a", "CommaVid, John Bronstein", "CM-003", "Cosmic Swarm (1982) (CommaVid) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "9e01f7f95cb8596765e03b9a36e8e33c", "Atari - CCW, Michael Callahan, Preston Stuart", "CX26103", "Alpha Beam with Ernie (1983) (Atari)", "Uses Keypad Controllers", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9e135f5dce61e3435314f5cddb33752f", "Fabrizio Zavagli", "", "Space Treat Deluxe (2003)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9e192601829f5f5c2d3b51f8ae25dbe5", "PlayAround - J.H.M.", "201", "Cathouse Blues (1982) (PlayAround)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "9e2c7299c69b602443d327c7dad51cbf", "Charles Morgan", "", "Xaxyrax Road (Charles Morgan) (Hack)", "Hack of Freeway", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9e437229136f1c5e6ef4c5f36178ed18", "Funvision - Fund. International Co.", "", "Grand Prize (Funvision)", "AKA Enduro", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9e5007131695621d06902ab3c960622a", "Sega", "", "Tac Scan (1983) (Sega) [h1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "AUTO 60", "", "", "YES", "" }, + { "9e792a59f8795664cbaaff1ba152d731", "", "", "Bullet Demo (20-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9e904e2eaa471c050c491289b8b80f60", "", "", "How to Draw a Playfield II (1997) (Erik Mooney) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9ea8ed9dec03082973244a080941e58a", "Eric Mooney, Piero Cavina", "", "INV+", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9ec1b259a1bcffa63042a3c2b3b90f0a", "Activision, David Crane", "AG-008", "Laser Blast (1981) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9eca521db1959156a115dee85a405194", "", "", "Fu Kung! (V0.08) (2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9ed0f2aa226c34d4f55f661442e8f22a", "", "", "Nuts (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9eeb40f04a27efb1c68ba1d25e606607", "Kyle Pittman", "", "Rambo II (2003) (Kyle Pittman) (Hack)", "Hack of Double Dragon", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9efa877a98dd5a075e058214da428abb", "Hozer Video Games", "", "SCSIcide (1.32) (Hozer Video Games)", "Uses the Paddle Controllers", "New Release", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "", "", "AUTO 65", "", "", "", "" }, + { "9efb4e1a15a6cdd286e4bcd7cd94b7b8", "20th Century Fox Video Games, John W.S. Marvin", "", "Planet of the Apes (1983) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9f2d58dce1b81c6ba201ed103507c025", "", "", "Fu Kung! (V0.02) (2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9f48eeb47836cf145a15771775f0767a", "Atari, Warren Robinett", "CX2620", "Basic Programming (1979) (Atari)", "Uses Keypad Controllers", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "9f5096a6f1a5049df87798eb59707583", "20th Century Fox Video Games, Mark Klein", "11036", "Entity, The (1983) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9f52271759f8a2004d207b2247ae0bb3", "Parker Brothers", "PB5820", "Mr. Do!'s Castle (03-12-84) (Parker Bros) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "9f59eddf9ba91a7d93bce7ee4b7693bc", "Thomas Jentzsch", "", "Montezuma's Revenge (Thomas Jentzsch) (PAL60)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9f8fad4badcd7be61bbd2bcaeef3c58f", "Parker Brothers, Charlie Heath", "PB5330", "Reactor (1983) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "9f901509f0474bf9760e6ebd80e629cd", "Atari, Bob Whitehead - Sears", "CX2623 - 6-99819, 49-75108, 49-75125", "Home Run (1978) (Atari) (4K)", "", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "", "" }, + { "9f93734c68f6479eb022cab40814142e", "", "", "Push (V0.07) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9f982421b9b4320ede00fe4aa2e812f4", "Atari, Omegamatrix", "", "Super Breakout Menu (2020) (Hack)", "Hack of Super Breakout", "", "", "", "", "", "", "", "", "", "", "", "", "", "AUTO 45", "", "", "", "" }, + { "9f9ee0f60c119c831e80694b6678ca1a", "Jeffry Johnston", "", "Radial Pong - Version 8 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9fa0c664b157a0c27d10319dbbca812c", "Chris Walton, Justin Hairgrove, Tony Morse", "", "Hunchy II (2005)", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "9fc2d1627dcdd8925f4c042e38eb0bc9", "Atari - GCC, John Allred, Mike Feinstein", "CX2688, CX2688P", "Jungle Hunt (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "E68E28752D3C54EDD3CCDA42C27E320C", "Xonox - K-Tel Software, Anthony R. Henderson", "99007, 6240", "Tomarc the Barbarian (1983) (Xonox)", "Genesis controller (B is jump and throw, C switches between players)", "Hack of Tomarc the Barbarian", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a0028f057d496f22b549fd8deecc6f78", "Joe Grand", "", "SCSIcide Pre-release 6 (Joe Grand)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a00ec89d22fcc0c1a85bb542ddcb1178", "CCE", "C-1012", "Phoenix (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a00ee0aed5c8979add4c170f5322c706", "Barry Laws Jr.", "", "Egghead (Barry Laws Jr.) (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a0185c06297b2818f786d11a3f9e42c3", "", "", "International Soccer (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a025a8f83a42a4d6d46c4887e799bfac", "Hozer Video Games", "", "Gunfight 2600 - Descissions had to be made (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a0297c4788f9e91d43e522f4c561b4ad", "Atari - CCW, Gary Stark", "CX26102", "Cookie Monster Munch (1983) (Atari) (PAL)", "Uses Kids/Keypad Controllers", "", "", "", "", "", "", "", "", "", "KEYBOARD", "", "", "", "", "", "", "", "" }, + { "a0563dd6d8215c38c488fbbd61435626", "", "", "Ship Demo (V 1501) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a0675883f9b09a3595ddd66a6f5d3498", "Telegames - VSS", "6057 A227", "Quest for Quintana Roo (1988) (Telegames)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a075ad332942740c386f4c3814925ece", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (2 of 4) (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a0d502dc8b90b1d7daa5f6effb10d349", "", "", "Demo Image Series #5 - Sam (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a0e2d310e3e98646268200c8f0f08f46", "Atari, Ed Logg, Carol Shaw", "CX2639, CX2639P", "Othello (1981) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a100eff2d7ae61ca2b8e65baf7e2aae8", "David Marli", "", "Muncher (David Marli) (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a11099b6ec24e4b00b8795744fb12005", "Activision - Bobco, Robert C. Polaro", "EAK-049-04B", "Rampage! (1989) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a1403fef01641dcd3980cac9f24d63f9", "Dactari - Milmar", "", "Atlantis (Dactari - Milmar)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a14d8a388083c60283e00592b18d4c6c", "", "", "Tunnel Demo (28-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a15b5831a1fab52e4c416068c85ec011", "Hozer Video Games", "", "Gunfight 2600 - The Good, The Bad, The Ugly (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a174cece06b3abc0aec3516913cdf9cc", "Sears Tele-Games, Jim Huether", "CX2614 - 49-75126", "Steeplechase (1980) (Sears) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "", "", "", "", "" }, + { "a1770ef47146ab7b12e2c4beccd68806", "Digitel", "", "Kaystone Kapers (1983) (Digitel)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a184846d8904396830951217b47d13d9", "Activision, Dan Kitchen", "AX-029", "Crackpots (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a189f280521f4e5224d345efb4e75506", "Atari - Thomas Jentzsch", "", "Obelix (1983) (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a1bcbe0bfe6570da2661fc4de2f74e8a", "Imagic - Advanced Program Technology, Rob Fulop", "", "Actionauts (Microbots) (1984-2008) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a1ca372388b6465a693e4626cc98b865", "Quelle", "176.543 7", "Der Vielfrass (1983) (Quelle) (PAL)", "AKA Fast Food", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a1ead9c181d67859aa93c44e40f1709c", "American Videogame - Dunhill Electronics, Darrell Wagner, Todd Clark Holm, John Simonds", "", "Tax Avoiders (1986) (American Videogame)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a1f9159121142d42e63e6fb807d337aa", "Quelle - Otto Versand", "700.223 1 - 781627", "Der moderne Ritter (1983) (Quelle) (PAL)", "AKA Fast Eddie", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a204cd4fb1944c86e800120706512a64", "Coleco, Rob Harris", "2511", "Smurfs Save the Day (1983) (Coleco)", "Uses the Kid Vid Controller", "", "", "", "", "", "", "", "", "", "KIDVID", "", "", "", "", "", "", "", "" }, + { "a20b7abbcdf90fbc29ac0fafa195bd12", "Quelle - Otto Versand", "719.383 2 - 649635, 781393, 781784, 986404", "Motocross (1983) (Quelle) (PAL)", "AKA Motorcross", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a20d931a8fddcd6f6116ed21ff5c4832", "Apollo - Games by Apollo, Ed Salvo, Byron Parks", "AP-2003", "Racquetball (1982) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "a2170318a8ef4b50a1b1d38567c220d6", "Amiga - Video Soft", "3125", "Surf's Up (1983) (Amiga) (Prototype) [a1]", "Uses the Joyboard controller", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a2276822c772f72073a8a40a72a1ca52", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Atari Mouse Hack v1.1 (NTSC) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a2424c1a0c783d7585d701b1c71b5fdc", "", "", "Video Pinball (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a25bb76e9e773117e567fd4300b1bb23", "", "", "Interleaved ChronoColour Demo (NTSC) (05-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a28d872fc50fa6b64eb35981d0f4bb8d", "Atari, Larry Kaplan - Sears", "CX2628 - 6-99842, 49-75117", "Bowling (1979) (Atari) (4K)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a29df35557f31dfea2e2ae4609c6ebb7", "Atari", "", "Circus Atari (1980) (Atari) (Joystick)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a29fc854838e08c247553a7d883dd65b", "Activision, Steve Cartwright", "AX-013", "Barnstorming (1982) (Activision) (16K)", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a2a384d3a16d5be50afd12906f146827", "Bit Corporation", "R320", "Flash Gordon (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a2aae759e4e76f85c8afec3b86529317", "", "", "Boom Bang (Unknown)", "AKA Crackpots", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a2d7cc2e5419a9e4ab91fdb26339b726", "Omegamatrix", "", "Star Wars Arcade (Atari Mouse) (Y Inverted) (PAL60) v4 (Omegamatrix)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a2de0fc85548871279ed2a3c1325c13e", "George Veeder", "", "Cat and Mouse (George Veeder) (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a2eb84cfeed55acd7fece7fefdc83fbb", "", "", "Kool Aid Man (Fixed) (15-11-2002) (CT)", "HMOVE handling fixed in this version", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a2f296ea2d6d4b59979bac5dfbf4edf0", "", "", "Warring Worms (28-01-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a2f9e3b6aaa23b6dc06099cdd5b51b31", "Nukey Shay", "", "Montezuma's Revenge (Genesis) (PAL60) (F6_Conversion)", "Genesis controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a302b922a8dbec47743f28b7f91d4cd8", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (Preview) (1982) (Starpath)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a30ece6dc4787e474fbc4090512838dc", "Zellers", "", "Circus (Zellers)", "AKA Circus Atari", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a310494ad5ba2b5b221a30d7180a0336", "", "", "Demo Image Series #6 - Mario (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a336beac1f0a835614200ecd9c41fd70", "Atari, Christopher H. Omarzu, Robert Vieira", "CX26121", "Zoo Keeper Sounds (1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a34560841e0878c7b14cc65f79f6967d", "Multivision, Michael Case", "", "Harem (1982) (Multivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a3486c0b8110d9d4b1db5d8a280723c6", "Atari, Alan J. Murphy, Robert C. Polaro", "CX26100", "Bugs Bunny (08-04-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a35d47898b2b16ec641d1dfa8a45c2b7", "Activision, Steve Cartwright", "AX-017, AX-017-04", "MegaMania (1982) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a3873d7c544af459f40d58dfcfb78887", "", "", "Tennis (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a3b9d2be822eab07e7f4b10593fb5eaa", "", "", "GREGXM Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a3c1c70024d7aabb41381adbfb6d3b25", "Telesys, Alex Leavens", "1005", "Stargunner (1983) (Telesys)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a3d7c299fbcd7b637898ee0fdcfc47fc", "Arcadia Corporation, Scott Nelson", "AR-4300", "Fireball (Preview) (1982) (Arcadia) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "01", "", "", "", "" }, + { "a3f2a0fcf74bbc5fa763b0ee979b05b1", "Quelle", "873.790 0", "Eishockey-Fieber (1983) (Quelle) (PAL)", "AKA Ice Hockey", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a3f8aebb38182749cb8da85cfbc63d7c", "", "", "Tennis (208 in 1) (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a3fee8ce15525ea00d45a06f04c215d1", "Aaron Curtis", "", "AStar (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a406d2f6d84e61d842f4cb13b2b1cfa7", "Tigervision, John Harris - Teldec", "7-002", "Jawbreaker (1982) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a412c8577b2d57b09185ae51739ac54f", "Arcadia Corporation, Dennis Caswell", "AR-4000", "Phaser Patrol (1982) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "a41450333f8dd0e96e5e9f0af3770ae9", "", "", "Basic Math (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a422194290c64ef9d444da9d6a207807", "M Network - APh Technological Consulting, Hal Finney", "MT5667", "Dark Cavern (1982) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a428068d3e51498907d97cec40000515", "Bit Corporation", "R320", "Sky Alien (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a47878a760f5fa3aa99f95c3fdc70a0b", "", "", "Demo Image Series #5 - Baboon (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a4790224bd5afabd53cbe93e46a7f241", "Activision, Bob Whitehead", "AG-019", "Sky Jinks (1982) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a47e26096de6f6487bf5dd2d1cced294", "Atari", "CX2643", "Codebreaker (1978) (Atari) (PAL)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a484638990de7b12c62947c79dafa4c6", "Thomas Jentzsch", "", "Marble Craze - Atari Mouse Hack v1.0 (PAL60) (TJ)", "Uses Atari Mouse Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a499d720e7ee35c62424de882a3351b6", "SEGA - Beck-Tech, Steve Beck, Phat Ho", "009-01", "Up 'n Down (1984) (SEGA)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a4aa7630e4c0ad7ebb9837d2d81de801", "", "", "Atari 2600 Invaders (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a4ab331e8768eafdc20ce8b0411ff77a", "", "", "Demo Image Series #1 - Sam (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a4b9423877a0b86ca35b52ca3c994ac5", "CCE", "C-805", "Sea Monster (1983) (CCE)", "O Monstro Marinho", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a4b99aa5ed85cfdb7d101923147de035", "Jim Goebel", "", "Pac-Law (Jim Goebel) (Hack)", "Hack of Outlaw", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a4c08c4994eb9d24fb78be1793e82e26", "Activision, Alan Miller", "AX-012, CAX-012, AX-012-04", "Ice Hockey (1981) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a4d026a5c200ef98518ebb77719fe8dc", "Kyle Pittman", "", "SpongeBob SquarePants (2003) (Kyle Pittman) (Hack)", "Hack of Revenge of the Beefsteak Tomatoes", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a4e885726af9d97b12bb5a36792eab63", "Xonox - K-Tel Software - Beck-Tech, Steve Beck", "6210, 7210, 06003. 99001", "Spike's Peak (1983) (Xonox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a4ecb54f877cd94515527b11e698608c", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX26119", "Saboteur (12-20-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a4f1cea2c8479284e2a2292f8d51b5fa", "", "", "Gunfight 2600 - The Final Kernel Part 2 (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a4ff39d513b993159911efe01ac12eba", "Atari - GCC, John Allred, Douglas B. Macrae, Betty Ryan Tylko", "CX2694", "Pole Position (1983) (Atari)", "AKA RealSports Driving", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a511f7ee13e4b35512f9217a677b4028", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX2674", "E.T. - The Extra-Terrestrial (1982) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a5262fe6d01d6a1253692682a47f79dd", "", "", "JKH Text Scrolling Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a537879d8e82e1061d3ad800479d3b84", "Andrew Wallace", "", "Brooni (2001) (Andrew Wallace) (PD) (PAL)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a539b9fd1ba57e46442b3e9351e6383b", "", "", "River Raid (208 in 1) (Unknown) (PAL) (Hack) [a]", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a56b642a3d3ab9bbeee63cd44eb73216", "Carrere Video - JWDA, Sylvia Day, Todd Marshall, Robin McDaniel, Henry Will IV - Teldec - Prism", "USC2001", "Gopher (1983) (Carrere Video) (PAL)", "AKA Vossicht Whlmaus!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a5855d73d304d83ef07dde03e379619f", "Atari, David Crane", "", "Boggle (08-07-1978) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "a58b11148c18d85e4c2aef4ff46ade67", "", "", "Video Chess (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a591b5e8587aae0d984a0f6fe2cc7d1c", "", "", "Globe Trotter Demo (24-03-2003) (Weston)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a5b7f420ca6cc1384da0fed523920d8e", "", "", "Adventure (New Graphics) (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a5c96b046d5f8b7c96daaa12f925bef8", "Activision, Alan Miller - Ariola", "EAG-007, EAG-007-04I, PAG-007 - 711 007-720", "Tennis (1981) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a5e9ed3033fb2836e80aa7a420376788", "Atari, Carla Meninsky", "CX2637, CX2637P", "Dodge 'Em (1980) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a60598ad7ee9c5ccad42d5b0df1570a1", "Atari, Alan Miller", "CX26163P", "Surround (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a6127f470306eed359d85eb4a9cf3c96", "Atari, Michael Kosaka, Peter C. Niday, Robert Vieira", "CX26110", "Crystal Castles (1984) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a6239810564638de7e4c54e66b3014e4", "Personal Games Company, Robert Anthony Tokar", "", "Birthday Mania (1984) (Personal Games)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a62e3e19280ff958407e05ca0a2d5ec7", "", "", "Hangman Ghost Biglist3 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a6737c81542a99ee71cb5f5ff14703d9", "", "", "Scrolling Playfield 3 (Junkosoft) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a69f5b1761a8a11c98e706ec7204937f", "", "", "Pharaoh's Curse (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "a6ed8d72ed691fd3aad5b6974fa17978", "Bit Corporation", "R320", "Bank Heist (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a74689a08746a667a299b0507e1e6dd9", "Starpath Corporation, Stephen H. Landrum", "9 AR-4105", "Official Frogger, The (1983) (Starpath) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a7523db9a33e9417637be0e71fa4377c", "Videospielkassette - Ariola", "PGP238", "Gangster (Ariola) (PAL)", "AKA Outlaw", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a7673809068062106db8e9d10b56a5b3", "Atari, Jerome Domurat, Andrew Fuchs, Dave Staugas, Robert Vieira", "CX26118, CX26118P", "Millipede (1984) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a779b9fa02c62d00d7c31ed51268f18a", "Arcadia Corporation, Brian McGhie", "AR-4104", "Rabbit Transit (1983) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a7a58e9291aefa1064e933071f60d4ef", "Arcadia Corporation, Dennis Caswell", "1 AR-4000, AR-4100", "Phaser Patrol (1982) (Arcadia) (Prototype) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "a7b584937911d60c120677fe0d47f36f", "M Network - INTV - APh Technological Consulting, Hal Finney", "MT5661", "Armor Ambush (1982) (M Network)", "AKA Tank Battle", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a7b96a8150600b3e800a4689c3ec60a2", "Atari, Mike Lorenzen - Sears", "CX2630 - 49-75122", "Circus Atari (1980) (Atari)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "01 55", "", "", "", "" }, + { "a7bf8353f77caca407ef85c2698fdff2", "Atari, Suki Lee - Sears", "CX2658 - 49-75128", "Math Gran Prix (1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a7cf2b9afdbb3a161bf418dbcf0321dc", "Barry Laws Jr.", "", "Attack Of The Mutant Space Urchins (2002) (Barry Laws Jr.) (Hack)", "Hack of Alien", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "a7d2e9408bb7cd70139ecced407ff238", "Atari - Roklan, Joe Gaucher, Alex Leavens", "CX2683", "Crazy Climber (1983) (Atari) (Prototype) [a1]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a7ed7dc5cbc901388afa59030fb11d26", "Atari, Warren Robinett", "CX2606, CX2606P", "Slot Racers (1978) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a7ef44ccb5b9000caf02df3e6da71a92", "Atari, Ian Shepard - Sears", "CX2604 - 6-99812, 49-75106", "Space War (1978) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a8101cb667e50a46165c6fb48c608b6b", "", "", "Kung Fu Sprite Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "a81697b0c8bbc338ae4d0046ede0646b", "CCE", "", "Gravitar (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a81b29177f258494b499fbac69789cef", "Greg Thompson", "", "Console Wars (Greg Thompson) (Hack)", "Hack of Space Jockey", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a83b070b485cf1fb4d5a48da153fdf1a", "Apollo", "AP-2011", "Pompeii (1983) (Apollo) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a8435ec570141de5d833c4abec499e55", "", "", "Happy Birthday Demo (2001) (Dennis Debro) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a8633050a686270fcf6c0cc4dcbad630", "Zirok", "", "Phoenix (Zirok)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a867b76098786c4091dba2fcee5084c3", "", "", "Dragrace (Hack)", "Hack of Dragster", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a875f0a919129b4f1b5103ddd200d2fe", "Atari, Dan Hitchens. Mimi Nyden", "CX2656", "SwordQuest - EarthWorld (1982) (Atari) (PAL)", "AKA Adventure I, SwordQuest I - EarthWorld", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a8916734ff8c64ec3342f4c73fd5b57d", "Atari", "", "Stand Alone Test Cart (1982) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a89a3e0547d6887279c34aba4b17a560", "M Network, Steve Crandall, Patricia Lewis Du Long", "MT4646", "Rocky & Bullwinkle (1983) (Mattel) (Prototype)", "", "Prototype", "", "", "4K", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a8a703e073183a89c94d4d99b9661b7f", "Franklin Cruz", "", "Spice Invaders (Franklin Cruz) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a8b3ea6836b99bea77c8f603cf1ea187", "CCE", "C-861", "Boxing (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a8c48b4e0bf35fe97cc84fdd2c507f78", "Puzzy - Bit Corporation", "PG201", "Seamonster (1982) (Puzzy)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a8d0a4a77cd71ac601bd71df5a060e4c", "", "", "Space Shuttle (1983) (Activision) [t2] (Fuel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a8d4a9500b18b0a067a1f272f869e094", "", "", "Red And White Checkerboard Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a8e49d7e24ce293629ca29614862821b", "", "", "Enduro (Genesis)", "Genesis controller (B is acceleration, C is brakes)", "Hack of Enduro", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a91d0858a52de3a2e6468437212d93e8", "", "", "Q-bert (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a936d80083e99d48752ad15c2b5f7c96", "", "", "Room of Doom (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "a93e8ea1f565c3c1e86b708cf0dc2fa9", "Jess Ragan", "", "Kabul! (Jess Ragan) (Hack)", "Hack of Kaboom!", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, + { "a94528ae05dd051894e945d4d2349b3b", "Genus", "", "River Raid (Genus)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a94b8ca630f467b574b614808d813919", "HES", "773-883", "2 Pak Special - Space Voyage, Fire Alert (1992) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a9531c763077464307086ec9a1fd057d", "Atari, John Dunn - Sears", "CX2631 - 49-75152", "Superman (1979) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a957dbe7d85ea89133346ad56fbda03f", "Atari, Brad Stewart", "CX2649, CX2649P", "Asteroids (1981) (Atari) (PAL) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "a97733b0852ee3096300102cb0689175", "CCE", "C-834", "Fast Eddie (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a9784c24cddb33bd0d14442b97784f3d", "Thomas Jentzsch", "", "Omega Race DC (2003) (TJ) (Omega Race Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a98b649912b6ca19eaf5c2d2faf38562", "", "", "This Planet Sucks (Greg Troutman) (PAL) [!]", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a995b6cbdb1f0433abc74050808590e6", "Imagic, Rob Fulop, Bob Smith", "720106-1A, IA3600", "Riddle of the Sphinx (1982) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a9cb638cd2cb2e8e0643d7a67db4281c", "M Network - INTV - APh Technological Consulting, Larry Zwick", "MT5861", "Air Raiders (1983) (M Network)", "AKA Air Battle", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a9d9e19d0c89fb31780b5d63e1f8c6a4", "AtariAge, Chris Spry", "CX26201", "Zippy the Porcupine (2014) (Sprybug) (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a9e3c23599c0d77151602f8e31daf879", "", "", "Kung Fu Master (Genesis)", "Genesis controller (C is extra kick modes)", "Hack of Kung Fu Master", "", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "", "" }, + { "aa1c41f86ec44c0a44eb64c332ce08af", "Spectravideo, David Lubar", "SA-218", "Bumper Bash (1983) (Spectravideo)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "PADDLES", "", "", "", "", "", "", "", "", "" }, + { "aa2c4b32656bde9a75042a4d158583e1", "", "", "Oystron X (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "aa5cfe3b20395aba1d479135943ad85c", "", "", "Defender (Hack) (Unknown)", "", "Hack of Defender", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "aa7bb54d2c189a31bb1fa20099e42859", "CBS Electronics, Ed English", "4L4478", "Mr. Do! (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "aa8c75d6f99548309949916ad6cf33bc", "Bob Montgomery (aka vdub_bobby)", "", "Squish 'Em (2007)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "aa8e4b2cb8a78ffe6b20580033f4dec9", "", "", "Bitmap Demo (13-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "aaac0d277eda054861e613c59c2e4ff2", "JWDA, Todd Marshall", "", "Music Demo (JWDA)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "aab840db22075aa0f6a6b83a597f8890", "Home Vision, R.J.P.G. - Gem International Corp. - VDI", "VCS83124", "Racing Car (1983) (Home Vision) (PAL)", "", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "", "" }, + { "aad61898633f470ce528e3d7ef3d0adb", "Commavid, Ben Burch", "CM-010", "Rush Hour (1983) (Commavid) (Prototype) [a1]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "aad91be0bf78d33d29758876d999848a", "Activision, David Crane", "AX-018, AX-018-04", "Pitfall! (1981) (Activision) (Prototype)", "Pitfall Harry's Jungle Adventure (Jungle Runner)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "aaea37b65db9e492798f0105a6915e96", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix - Tug of War (2 of 3) (1983) (Arcadia)", "Uses Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "02", "", "", "", "" }, + { "aafc79ffc32c4c9b2d73c8ada7602cfe", "", "", "Planet Patrol (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ab10f2974dee73dab4579f0cab35fca6", "ITT Family Games", "", "Wilma Wanderer (1983) (ITT Family Games) (PAL)", "AKA Lilly Adventure", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ab2cfcaad3daaf673b2b14fdbb8dac33", "M Network - INTV, David Akers, Joe King, Patricia Lewis Du Long, Jeff Ratcliff", "MT7045", "Bump 'n' Jump (1983) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ab2ea35dcc1098c87455bb8210b018cf", "", "", "Fu Kung! (V0.04 Single Line Resolution) (10-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ab301d3d7f2f4fe3fdd8a3540b7a74f5", "Jone Yuan Telephonic Enterprise Co", "", "IQ 180 (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ab434f4c942d6472e75d5490cc4dd128", "HES", "773-875", "2 Pak Special - Hoppy, Alien Force (1992) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ab48c4af46c8b34c3613d210e1206132", "Andrew Davie & Thomas Jentzsch", "", "Boulder Dash - Demo V2 (2014)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ab4ac994865fb16ebb85738316309457", "Atari, Alan Miller - Sears", "CX2624 - 6-99826, 49-75113", "Basketball (1978) (Atari)", "Console ports are swapped", "Common", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "", "" }, + { "ab56f1b2542a05bebc4fbccfc4803a38", "Activision - Imagineering, Dan Kitchen, David Lubar", "AK-048-04", "River Raid II (1988) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ab5bf1ef5e463ad1cbb11b6a33797228", "Imagic, Rob Fulop", "720104-1A, 720104-1B, IA3204", "Cosmic Ark (1982) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ab60ea7b707c58d356cad858eb18db43", "", "", "Tazer (John K. Harvey)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ab8d318da4addd39c65b7f9c408df2a6", "", "", "Star Trek (Genesis)", "Genesis controller (B is phaser, C is warp)", "Hack of Star Trek", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "abb740bea0a6842831b4f53112fb8145", "", "", "Qb (V1.01) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "abb741c83f665d73c86d90a7d9292a9b", "Telegames", "", "Space Attack (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "abc64037ca5d5b04ae8a7eedbca3ed74", "", "", "Green and Yellow Number 1 Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "abe40542e4ff2d1c51aa2bb033f09984", "Absolute Entertainment, David Crane", "EAZ-042-04B, EAZ-042-04I", "Skate Boardin' (1987) (Absolute) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ac05c0e53a5e7009ddd75ed4b99949fc", "Atari, Joe Decuir, Steve Mayer, Larry Wagner - Sears", "CX2601 - 99801, 6-99801, 49-75124", "Combat (1977) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ac0ddbcff34d064009591607746e33b8", "Thomas Jentzsch", "", "Atlantis FH (2003) (TJ) (Hack)", "Hack of Atlantis", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ac26d7d37248d1d8eac5eccacdbef8db", "", "", "Snail Against Squirrel (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ac3dd22dd945724be705ddd2785487c2", "Atari - GCC, Mark Ackerman, Noellie Alito", "CX2692", "Moon Patrol (06-15-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ac53b83e1b57a601eeae9d3ce1b4a458", "Retroactive", "", "Qb (2.15) (Retroactive) (NTSC)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "ac5f78bae0638cf3f2a0c8d07eb4df69", "", "", "Minesweeper (V.99) (Soren Gust) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ac7c2260378975614192ca2bc3d20e0b", "Activision, David Crane", "AG-930-04, AZ-030", "Decathlon (1983) (Activision)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ac9adbd6de786a242e19d4bec527982b", "Activision, Alan Miller - Ariola", "EAG-012-04I, EAX-012, EAX-012-04B - 711 012-720", "Ice Hockey (1981) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "aca09ffea77174b148b96b205109db4d", "Activision, Alan Miller", "AG-007, CAG-007", "Tennis (1981) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "acaa27d214039d89d7031609aafa55c3", "", "", "Sprite Demo 6 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "acb6787b938079f4e74313a905ec3ceb", "", "", "Chronocolor Donkey Kong (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "acb7750b4d0c4bd34969802a7deb2990", "Parker Brothers, Ed Temple", "PB5310", "Amidar (1982) (Parker Bros)", "", "Uncommon", "", "", "", "A", "A", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "acb962473185d7a652f90ed6591ae13b", "Imagic, Dennis Koble", "IA3203, IX-010-04", "Atlantis (1982) (Imagic) (16K)", "AKA Lost City of Atlantis", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ace319dc4f76548659876741a6690d57", "Atari, Steve Wright", "CX2616", "Pele's Soccer (1981) (Atari)", "AKA Pele's Championship Soccer", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ad2e6bfb3b9b9b36ba8bf493ce764c49", "", "", "2600 Collison Demo 1 (Piero Cavina) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ad42e3ca3144e2159e26be123471bffc", "Atari", "CX26163P", "Human Cannonball (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ad72d616030a17634ff29ce8680d3c4c", "Thomas Jentzsch", "", "Reactor - Atari Trak-Ball Hack v1.3 (PAL60) (Full-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ad7e97c19bd25d5aa3999430845c755b", "", "", "Sprite Demo 5 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ad8072675109d13fdd31a2e0403d5cff", "Funvision - Fund. International Co.", "", "Tank City (Funvision)", "AKA Thunderground", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "adb770ff70e9adf08bbb907a7eccd240", "", "", "Inv Demo 3 (2001) (Erik Mooney) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "adb79f9ac1a633cdd44954e2eac14774", "Digivision", "", "Frostbite (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "adf1afac3bdd7b36d2eda5949f1a0fa3", "Quelle - Otto Versand", "495.463 2 - 746381", "Angriff der Luftflotten (1983) (Quelle) (PAL)", "AKA Paris Attack, M.A.D.", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "adfbd2e8a38f96e03751717f7422851d", "Champ Games", "CG-01-N", "Lady Bug (NTSC)", "", "Homebrew", "", "", "", "", "A", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "ae047e9468bda961d8e9e9d8ff52980f", "", "", "Tunnel Demo (Red Spiral) (30-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ae0d4f3396cb49de0fabdff03cb2756f", "Retroactive", "", "Qb (V2.02) (PAL) (2001) (Retroactive)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "ae10527840a1ac24de43730645ed508d", "Charles Morgan", "", "Planet Invaders (Charles Morgan) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ae18c11e4d7ed2437f0bf5d167c0e96c", "", "", "Multi-Color Demo 3 (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ae2f1f69bb38355395c1c75c81acc644", "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart", "PB5540", "Star Wars - The Arcade Game (12-23-1983) (Parker Bros) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "ae465044dfba287d344ba468820995d7", "", "", "Inca Gold (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ae4be3a36b285c1a1dff202157e2155d", "Spectravideo", "SA-210", "Master Builder (1983) (Spectravideo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ae682886058cd6981c4b8e93e7b019cf", "Retroactive", "", "Qb (V0.12) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "ae6cb335470788b94beb5787976e8818", "", "", "Mortal Kurling (02-01-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ae83541cf4a4c0bce0adccd2c1bf6288", "", "", "Maze 003 Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ae97cf8ed21f4154b4360a3cf6c95c5e", "", "", "Teleterm 2600 (John K. Harvey) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "aeb104f1e7b166bc0cbaca0a968fde51", "", "", "Ms. Pac-Man (1999) (Hack)", "Hack of Ms. Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "aec9b885d0e8b24e871925630884095c", "Amiga - Video Soft", "3125", "Surf's Up (1983) (Amiga) (Prototype)", "Uses the Joyboard controller", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "aed0b7bd64cc384f85fdea33e28daf3b", "Atari, Jim Huether, Alan J. Murphy, Robert C. Polaro", "CX2666", "RealSports Volleyball (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "aed82052f7589df05a3f417bb4e45f0c", "Atari, Warren Robinett - Sears", "CX2606 - 6-99825, 49-75112", "Slot Racers (1978) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "af6ab88d3d7c7417db2b3b3c70b0da0a", "Activision, Larry Kaplan, David Crane", "AG-010, AG-010-04", "Kaboom! (1981) (Activision) (4K)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, + { "af6f3e9718bccfcd8afb421f96561a34", "Atari, Tod Frye", "CX2695", "Xevious (01-18-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "afb3bc45c6a82739cc82582127cd96e6", "Atari - Sculptured Software, Adam Clayton", "CX26151, CX26151P", "Dungeon (11-22-1985) (Atari) (Prototype)", "Dark Chambers Beta", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "afc194534c1b346609ef05eff6d3cef6", "Jone Yuan Telephonic Enterprise Co", "", "Boxing (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "afd2cf258d51ae4965ee21abba3627ab", "Atari - CCW, Christopher H. Omarzu", "CX26104", "Big Bird's Egg Catch (12-08-1982) (Atari) (Prototype)", "Uses the Keypad Controller", "Prototype", "", "", "", "", "", "", "", "KEYBOARD", "", "", "", "", "", "", "", "", "" }, + { "afe4eefc7d885c277fc0649507fbcd84", "Atari", "CX26163P", "Ant Party (32 in 1) (1988) (Atari) (PAL)", "AKA Cosmic Swarm", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "afe776db50e3378cd6f29c7cdd79104a", "Thomas Jentzsch", "", "Bobby is Going Home (TJ)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "afe88aae81d99e0947c0cfb687b16251", "Apollo - Games by Apollo", "AP-2006", "Infiltrate (1982) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "aff8cba0f2d2eb239953dd7116894a08", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (3 of 3) (1982) (Starpath) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b00088418fc891f3faa3d4ddde6ace94", "", "", "Unknown Title (bin00007 (200102)) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b00a8bc9d7fe7080980a514005cbad13", "K-Tel Vision", "", "Vulture Attack (1982) (K-Tel Vision) (PAL)", "AKA Condor Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b00e8217633e870bf39d948662a52aac", "Konami", "RC 102-X 02", "Marine Wars (1983) (Konami)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b011d8fdc450597c0762c2c0010a9b17", "Thomas Jentzsch", "", "Reactor - Amiga Mouse Hack v1.3 (NTSC) (Half-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b049fc8ac50be7c2f28418817979c637", "Activision - Imagineering, Dan Kitchen, David Lubar", "EAK-048-04, EAK-048-04B", "River Raid II (1988) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b06050f686c6b857d0df1b79fea47bb4", "Activision", "AIZ-001", "Moonsweeper (1988) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "b061e98a4c854a672aadefa233236e51", "Atari, Warren Robinett", "CX2620, CX2620P", "Basic Programming (1979) (Atari) (PAL)", "Uses Keypad Controllers", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "b095009004df341386d22b2a3fae3c81", "", "", "Sub-Scan (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b09b79c9628878be051e89f7f1e77378", "Activision, Larry Kaplan, David Crane - Ariola", "EAG-010, PAG-010 - 711 010-720", "Kaboom! (1981) (Activision) (PAL) (4K)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, + { "b0a9c6f6c8014c4023e0341ba11ca35e", "The Atari 2600 Connection - John K. Harvey, Tim Duarte", "v75", "Mean Santa (2009) (PAL)", "Released in 2019", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b0ba51723b9330797985808db598fc31", "Atari, Michael Callahan, Preston Stuart", "CX26103", "Alpha Beam with Ernie (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b0c47e426c7f799aee2c40422df8f56a", "", "", "Space Treat (PAL) (Fabrizio Zavagli)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b0c9cf89a6d4e612524f4fd48b5bb562", "Atari - GCC", "CX2663", "Combat Two (1982) (Atari) (Prototype)", "AKA Super Combat", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b0e1ee07fbc73493eac5651a52f90f00", "Colin Hughes", "", "Tetris 2600 (Colin Hughes)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "b1276417fb0f79bc52e741bb8f4d8360", "Thomas Jentzsch", "", "Marble Craze - Amiga Mouse Hack v1.0 (NTSC) (TJ)", "Uses Amiga Mouse Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b129d7541cff79ebe33852a83057c524", "Thomas Jentzsch", "", "Marble Craze - Atari Trak-Ball Hack v1.0 (NTSC) (TJ)", "Uses Atari Trak-Ball Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b12a7f63787a6bb08e683837a8ed3f18", "Imagic, Rob Fulop", "720000-200, 720101-1B, 720101-1C, IA3200, IA3200C, IX-006-04", "Demon Attack (1982) (Imagic) [fixed]", "AKA Death from Above", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b1339c56a9ea63122232fe4328373ac5", "Goliath - Hot Shot", "83-215", "Dream Flight (1983) (Goliath) (PAL)", "AKA Nightmare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b1486e12de717013376447ac6f7f3a80", "Spectravideo, Mark Turmell, Quelle", "SA-217, SA-217C - 413.723 8", "Gas Hog - Piraten Schiff (1983) (Spectravideo) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b15026b43c6758609667468434766dd8", "Retroactive", "", "Qb (0.06) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "b16cd9784589219391c839cb68c47b9c", "Video Soft, Jerry Lawson, Dan McElroy", "", "Golf Diagnostic (1983) (Video Soft) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b17b9cc4103844dcda54f77f44acc93a", "Quelle", "377.943 6", "Stopp die Gangster (1983) (Quelle) (PAL)", "AKA Gangster Alley", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b182d9708e00709830caab9cf8205ca0", "Thomas Jentzsch", "", "Reactor - Atari Mouse Hack v1.3 (PAL60) (Half-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b1a6c96e9093352106bc335e96caa154", "Joe Grand", "", "SCSIcide Pre-release 1 (Joe Grand)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b1b20536aef4eed9c79dc5804f077862", "", "", "Euchre (NTSC) (09-11-2001) (Erik Eid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b1c14b5ac896400cc91c8e5dd67acb59", "", "", "River Raid (208 in 1) (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b1d1e083dc9e7d9a5dc1627869d2ade7", "CCE", "C-1004", "Mario's Bros. (1983) (CCE)", "AKA Mario Bros.", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b1e2d5dc1353af6d56cd2fe7cfe75254", "Atari - Axlon, Steve DeFrisco", "CX26171", "MotoRodeo (1991) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "b1fd0b71de9f6eeb5143a97963674cb6", "", "", "Multi-Color Demo 7 (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b227175699e372b8fe10ce243ad6dda5", "Atari, Brad Stewart - Sears", "CX2649, 49-75163", "Asteroids (1981) (Atari) [a1]", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "b23ebf427713dd0198b7ef47dbd07ef4", "Jone Yuan Telephonic Enterprise Co", "", "Sky Diver (Jone Yuan) (4K) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b24f6a5820a4b7763a3d547e3e07441d", "CCE", "C-823", "Demon Attack (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b25841173f058380b1771aacd5e7cdf3", "Bit Corporation", "PG205", "Dancing Plate (1982) (BitCorp)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b26506fbf411009e5e3f7365f442960e", "Atari, Alan Miller", "CX2642", "Hunt & Score (1978) (Atari) (PAL) (4K)", "Uses the Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b2737034f974535f5c0c6431ab8caf73", "CBS Electronics, Richard K. Balaska Jr., Andy Frank, Stuart Ross", "4L 2520 5000", "Tunnel Runner (1983) (CBS Electronics)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b2761efb8a11fc59b00a3b9d78022ad6", "Atari, Bob Whitehead - Sears", "CX2651 - 99805, 49-75602", "Blackjack (1977) (Atari) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "", "", "", "", "" }, + { "b290c2b139344fcff5b312c71b9ac3b2", "Atari", "CX26163P", "UFO (32 in 1) (1988) (Atari) (PAL) (4K)", "AKA Space Jockey", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b29359f7de62fed6e6ad4c948f699df8", "Goliath", "3", "Phantom Tank (1983) (Goliath) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b2a6f31636b699aeda900f07152bab6e", "", "", "Space Instigators (Public Release 2) (06-01-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b2ab209976354ad4a0e1676fc1fe5a82", "Atari - Axlon, Tod Frye - Heuristica, Agustin Ortiz", "CX26169", "Shooting Arcade (03-07-1989) (Atari) (Prototype) [a3]", "Uses the Light Gun Controller (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b2d1e63f7f22864096b7b6c154151d55", "Fabrizio Zavagli", "", "Bounce! (17-03-2003) (Fabrizio Zavagli)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "b2d3bcee001cff2bd2d8a21b2cb55109", "Atari - GCC, Mike Feinstein, Kevin Osborn", "CX2691", "Joust (08-09-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "b2d5d200f0af8485413fad957828582a", "Atari - Bobco, Robert C. Polaro", "CX26155P", "Sprint Master (1988) (Atari) (PAL)", "AKA Sprint 88, Sprint 2000", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b2f0d7217147160b2f481954cedf814b", "", "", "Marquee Drawer (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "b3017e397f74efd53caf8fae0a38e3fe", "Retroactive", "", "Qb (2.12) (Retroactive) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "b311ab95e85bc0162308390728a7361d", "Parker Brothers - Roklan, Joe Gaucher", "PB5080", "Gyruss (1984) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "b31dc989f594764eacfa7931cead0050", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (2 of 3) (1983) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b31e9487efc06f18dfc3d7ebadf54416", "Omegamatrix", "", "Star Wars Arcade (Atari Mouse) v4 (PAL60) (Omegamatrix)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b31f178aa0d569cccac7959f84e0a724", "Atari, Jerome Domurat, Steve Woita", "CX2699", "Taz (07-13-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b3203e383b435f7e43f9492893c7469f", "Gameworld", "133-003", "Sssnake (1983) (Gameworld) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b36040a2f9ecafa73d835d804a572dbf", "Digitel", "", "Pac Man (1983) (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b37f0fe822b92ca8f5e330bf62d56ea9", "Xonox - K-Tel Software - Beck-Tech, Steve Beck", "6210, 7210, 06003. 99001", "Spike's Peak (1983) (Xonox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b392964e8b1c9c2bed12246f228011b2", "", "", "Name This Game (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b4030c38a720dd84b84178b6ce1fc749", "M Network - APh Technological Consulting, Kevin Miller", "MT5687", "International Soccer (1982) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b40dea357d41c5408546e4e4d5f27779", "Digivision", "", "Spider Fighter (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b41fdd4a522e1d5a2721840028684ac2", "", "", "Green and Yellow Number 1 Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "b42df8d92e3118dc594cecd575f515d7", "Mystique - American Multiple Industries", "1003", "Burning Desire (1982) (Mystique) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "b438a6aa9d4b9b8f0b2ddb51323b21e4", "Telegames", "5861 A030", "Bogey Blaster (1988) (Telegames) (PAL)", "AKA Air Raiders", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b451307b8b5e29f1c5f2cf064f6c7227", "", "", "Demo Image Series #6 - Mario (Fixed) (26-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b49331b237c8f11d5f36fe2054a7b92b", "", "", "Condor Attack (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b4a4c87840613f102acb5b3a647d0a67", "", "", "Mobile 48 Sprite Kernel (04-01-2003) (Eric Ball)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b4daedb43511521db9036d503b3c1b69", "", "", "Sokoban (01-01-2003) (Adam Wozniak) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b4e2fd27d3180f0f4eb1065afc0d7fc9", "Avalon Hill, Jean Baer, Bill 'Rebecca Ann' Heineman, William O. Sheppard", "5002002", "London Blitz (1983) (Avalon Hill)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b4f05e544834d0238a0c263491775edf", "Starpath Corporation, Steve Hales, Stephen H. Landrum", "4 AR-4102", "Suicide Mission (Preview) (1982) (Starpath) (PAL)", "AKA Meteoroids", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "b4f31ea8a6cc9f1fd4d5585a87c3b487", "Mystique - American Multiple Industries, Joel H. Martin", "", "Beat 'Em & Eat 'Em (1982) (Mystique) (PAL)", "Uses the Paddle Controller (left only)", "", "", "", "", "", "", "", "", "", "", "", "", "", "AUTO 45", "", "", "", "" }, + { "b4f87ce75f7329c18301a2505fe59cd3", "Videospielkassett - Ariola", "PGP232", "Autorennen (Ariola) (PAL)", "AKA Grand Prix", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b50ae55aac93fbed258bc5a873edd2cb", "Recompile", "", "E.T. The Extra-Terrestrial (Recompile) (Hack)", "www.neocomputer.org/projects/et", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b5110f55ed99d5279f18266d001a8cd5", "Eckhard Stolberg", "", "Auto-mobile Demo (2001) (Eckhard Stolberg)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b56264f738b2eb2c8f7cf5a2a75e5fdc", "Atari - GCC, John Allred, Douglas B. Macrae, Betty Ryan Tylko", "CX2694, CX2694P", "Pole Position (1983) (Atari) (PAL)", "AKA RealSports Driving", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b5657d4c1c732fbb6af150668464247f", "Arcadia Corporation, Stephen H. Landrum", "AR-4400", "Excalibur (Dragonstomper Beta) (1982) (Arcadia) (Prototype)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b59417d083b0be2d49a7d93769880a4b", "Pet Boat", "", "Donkey Kong (1983) (Pet Boat) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b59fd465abf76f64c85652ff29d5952d", "VentureVision, Dan Oliver", "", "Innerspace (1983) (VentureVision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b5a1a189601a785bdb2f02a424080412", "Imagic, Dennis Koble", "720021-1A, IA3410", "Shootin' Gallery (1983) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b5cb9cf6e668ea3f4cc2be00ea70ec3c", "CommaVid, Irwin Gaines - Ariola", "CM-005 - 712 005-720", "Mines of Minos (1982) (CommaVid) (PAL)", "AKA Im Labyrinth des Roboters", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "b5cdbab514ea726a14383cff6db40e26", "Video Gems", "VG-04", "Mission Survive (1983) (Video Gems) (PAL) [a]", "", "", "", "", "", "", "A", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "b5efe0271d2214e4d5dc798881486884", "Atari - Axlon, Steve DeFrisco", "CX26192", "Klax (06-14-1990) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b6166f15720fdf192932f1f76df5b65d", "Amiga - Video Soft", "3130", "Off Your Rocker (1983) (Amiga) (Prototype)", "Uses the Amiga Joyboard", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b64426e787f04ff23ee629182c168603", "Dynacom", "", "Plaque Attack (1983) (Dynacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b65d4a38d6047735824ee99684f3515e", "Dynacom", "", "MegaBoy (Dynacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b676a9b7094e0345a76ef027091d916b", "Thomas Jentzsch", "", "Mission Survive (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "A", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "b6812eaf87127f043e78f91f2028f9f4", "Simage", "", "Eli's Ladder (1984) (Simage)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b6821ac51c4c1dcb283f01be2f047dc1", "Thomas Jentzsch", "", "Rubik's Cube 3D Demo (25-11-2002) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b6960be26bee87d53ba4e2e71cfe772f", "", "", "3-D Corridor (Spiral Words) (31-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b6d52a0cf53ad4216feb04147301f87d", "Imagic, Michael Greene", "720055-1A, IA3312", "No Escape! (1983) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b6e40bce550672e5495a8cdde7075b8b", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (1 of 3) (1983) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b702641d698c60bcdc922dbd8c9dd49c", "Atari, Ian Shepard", "CX26163P", "Space War (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b719ada17771a8d206c7976553825139", "Ron Corcoran", "", "DUP Space Invaders (Ron Corcoran) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b731d35e4ac6b3b47eba5dd0991f452f", "Thomas Jentzsch", "", "Rubik's Cube 3D Demo (Final) (08-01-2003) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b7345220a0c587f3b0c47af33ebe533c", "Quelle", "176.433 1", "Landungskommando (1983) (Quelle) (PAL)", "AKA Strategy X", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b76fbadc8ffb1f83e2ca08b6fb4d6c9f", "Activision, Bob Whitehead", "AG-005, CAG-005, AG-005-04", "Skiing (1980) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b77468d586957d1b7fb4cccda2684f47", "Atari", "CX26163P", "Boxing (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b7903268e235310dc346a164af4c7022", "Thomas Jentzsch", "", "Cat Trax (Thomas Jentzsch) (PAL60)", "NTSC Conversion", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "b79fe32320388a197ac3a0b932cc2189", "Imagic, Bob Smith", "13207, EIZ-001-04I", "Moonsweeper (1983) (Imagic) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "b7a7e34e304e4b7bc565ec01ba33ea27", "Parker Brothers", "PB5820", "Mr. Do!'s Castle (1984) (Parker Bros) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "b7b1d3ce07e75976c43a2dca3866237e", "Atari", "CX26163P", "Freeway Chicken (32 in 1) (1988) (Atari) (PAL) (4K)", "AKA Freeway", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b7d0aae399781b3c18679debda6d32b1", "Thomas Jentzsch", "", "Three.s (v1.02)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b7d7c76e37f372f4e4979b380ed95a58", "AtariAge - Michael Haas", "RC2", "Flappy (2014) (AtariAge) (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b7e459d5416eeb196aaa8e092db14463", "", "", "Push (V0.02) (1998) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b7f184013991823fc02a6557341d2a7a", "", "", "Blue Rod Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b80d50ecee73919a507498d0a4d922ae", "20th Century Fox Video Games - Sirius Software, David Lubar", "11008", "Fantastic Voyage (1982) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b816296311019ab69a21cb9e9e235d12", "Atari, Bob Whitehead - Sears", "CX2652 - 6-99816, 49-75151", "Casino (1979) (Atari)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "", "", "", "", "" }, + { "b822fba8b7c8a97ea4e92aeb2c455ef9", "Dactari", "", "Freeway (Dactari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b83579c4450fcbdf2b108903731fa734", "", "", "Mission 3,000 A.D. (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "b83df1f32b4539c324bdf94851b4db55", "Angelino", "", "One On One by Angelino (Basketball Hack)", "Hack of Basketball (1978) (Atari)", "New Release (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b86552198f52cfce721bafb496363099", "Apollo, Tim Martin", "AP-2007", "Kyphus (1982) (Apollo) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b86a12e53ab107b6caedd4e0272aa034", "Funvision - Fund. International Co.", "", "Treasure Hunting (Funvision)", "AKA Pitfall!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b879e13fd99382e09bcaf1d87ad84add", "Zellers", "", "Time Warp (Zellers)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b8865f05676e64f3bec72b9defdacfa7", "Activision, David Crane", "AG-004", "Fishing Derby (1980) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b897f9e3f939b9f21566d56db812a84e", "Atari, Jim Huether", "CX26163P", "Flag Capture (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b8e715223ba65cf716b3620a90ca3ec1", "Parker Brothers", "PB5820", "Mr. Do!'s Castle (1984) (Parker Bros) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "b8ed78afdb1e6cfe44ef6e3428789d5f", "Data Age, J. Ray Dettling", "112-007", "Bermuda Triangle (1983) (Data Age)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b9232c1de494875efe1858fc8390616d", "Panda", "110", "Harbor Escape (1983) (Panda)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b9336ed6d94a5cc81a16483b0a946a73", "Atari, Jerome Domurat, Michael Sierchio", "CX2667, CX2667P", "RealSports Soccer (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "b955eb0e2baf7a437c186bddd4c49958", "Atari, Omegamatrix", "", "Space Invaders Menu (2020) (PAL60) (Hack)", "Hack of Space Invaders", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b958d5fd9574c5cf9ece4b9421c28ecd", "Piero Cavina", "", "Multi-Sprite Game V1.0 (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b95a6274ca0e0c773bfdc06b4c3daa42", "Paul Slocum", "", "3-D Corridor (29-03-2003) (Paul Slocum)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b98cc2c6f7a0f05176f74f0f62c45488", "Spectravideo", "SV-010", "CompuMate (1983) (Spectravideo)", "", "", "", "", "CM", "", "", "", "", "COMPUMATE", "COMPUMATE", "", "", "", "", "", "", "YES", "" }, + { "b9b4612358a0b2c1b4d66bb146767306", "Commavid, Ben Burch", "CM-010", "Rush Hour (1983) (Commavid) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b9d1e3be30b131324482345959aed5e5", "Activision - Boston Design Center, Rex Bradford", "", "Kabobber (07-25-1983) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "b9f6fa399b8cd386c235983ec45e4355", "Parker Brothers, John Emerson", "931511", "Action Force (1983) (Parker Bros) (PAL)", "AKA G.I. Joe - Cobra Strike", "", "", "", "", "", "", "", "", "", "", "", "", "", "01 55", "", "", "", "" }, + { "b9f9c0fed0db08c34346317f3957a945", "SuperVision", "405, 427, 806, 808, 813, 816", "Chopper Command (SuperVision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ba257438f8a78862a9e014d831143690", "U.S. Games Corporation - JWDA, Todd Marshall, Robin McDaniel, Henry Will IV", "VC2002", "Squeeze Box (1983) (U.S. Games)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ba317f83cdfcd58cbc65aac1ccb87bc5", "Thomas Jentzsch", "", "Jammed (2001) (XYPE) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ba3a17efd26db8b4f09c0cf7afdf84d1", "Activision, Larry Miller", "AX-021", "Spider Fighter (1983) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ba3b0eebccc7b791107de5b4abb671b4", "Thomas Jentzsch", "", "Thrust (V0.9) (2000) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ba657d940a11e807ff314bba2c8b389b", "Activision, John Van Ryzin", "AG-038-04", "Cosmic Commuter (1984) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bac28d06dfc03d3d2f4a7c13383e84ee", "Supergame", "", "Demon Attack (Supergame)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bae1a23f9b6acdadf465cfb330ba0acb", "Atari - GCC, Doug Macrae", "CX2677", "Dig Dug (1983) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bae66907c3200bc63592efe5a9a69dbb", "Spectravision - Spectravideo - Quelle", "SA-201 - 412.783 3", "Gangster Alley (1982) (Spectravision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "baf4ce885aa281fd31711da9b9795485", "Atari, Douglas Neubauer", "CX26176", "Radar Lock (1989) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bb18189021d58362d9e4d317cd2e28b7", "Activision, David Crane - Ariola", "EAG-001, PAG-001, EAG-001-04B, EAG-001-04I - 711 001-715", "Dragster (1980) (Activision) (PAL) (4K)", "AKA Dragster Rennen", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bb2b83fff97604f74ada565e0b5bae94", "Thomas Jentzsch", "", "Missile Control - Atari Mouse Hack v1.15 (PAL60) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bb5049e4558daade0f87fed69a244c59", "Atari, Brad Stewart", "CX2649, CX2649P", "Asteroids (1981) (Atari) (PAL) [no copyright]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "bb579404924c40ca378b4aff6ccf302d", "", "", "Lightbulb Lightens, The (PD) (Non Functional)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bb6a5a2f7b67bee5d1f237f62f1e643f", "", "", "Demo Image Series #5 - Animegirl (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bb745c893999b0efc96ea9029e3c62ca", "Play Video", "", "Planet Patrol (1982) (Play Video) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bb756aa98b847dddc8fc170bc79f92b2", "", "", "Golf (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bb9112d478a1a922d2c289a752bba695", "Omegamatrix", "", "SpaceMaster X-7 (Amiga Mouse) (Omegamatrix)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bbf8c7c9ed280151934aabe138e41ba7", "Amiga", "1130", "Power Play Arcade Video Game Album V (1984) (Amiga) (Prototype)", "Mogul Maniac, Surf's Up, Off Your Rocker, S.A.C. Alert", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bc24440b59092559a1ec26055fd1270e", "", "", "Private Eye (1984) (Activision) [a]", "", "", "", "0", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bc3057a35319aae3a5cd87a203736abe", "CCE", "C-845", "Time Warp (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bc33c685e6ffced83abe7a43f30df7f9", "Dynacom", "", "Seaquest (1983) (Dynacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bc4cf38a4bee45752dc466c98ed7ad09", "Atari, Douglas Neubauer, Mimi Nyden", "CX26136", "Solaris (1986) (Atari) (PAL)", "AKA Universe, Star Raiders II, The Last Starfighter", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bc526185ad324241782dc68ba5d0540b", "", "", "Dodge Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bc5389839857612cfabeb810ba7effdc", "Atari, Tod Frye", "CX2671", "SwordQuest - WaterWorld (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bc703ea6afb20bc089f04d8c9d79a2bd", "", "", "Gunfight 2600 - Not mergeable with Colbert wizardry... (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bc97d544f1d4834cc72bcc92a37b8c1b", "", "", "Sky Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bcb31f22856b0028c00d12f0e4c0a952", "Canal 3 - Intellivision", "", "Thunderground (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bcb73b534ed7c613ac379ecd726effb5", "Bob Montgomery (aka vdub_bobby)", "", "Squish 'Em (2007) (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bccb4e2cfad5efc93f6d55dc992118ce", "Activision, Carol Shaw", "AX-020, AX-020-04", "River Raid (1982) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bce4c291d0007f16997faa5c4db0a6b8", "Quelle", "292.651 7", "Weltraumtunnel (1983) (Quelle) (PAL)", "AKA Innerspace", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bce93984b920e9b56cf24064f740fe78", "Atari", "CX26163P", "Checkers (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bcef7880828a391cf6b50d5a6dcef719", "Rainbow Vision - Suntek", "SS-009", "Bermuda, The (1983) (Rainbow Vision) (PAL)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bd1bd6f6b928df17a702def0302f46f4", "", "", "Binary To Decimal Routine (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bd39598f067a1193ae81bd6182e756d1", "Telegames", "", "Night Stalker (1988) (Telegames) (PAL)", "AKA Dark Cavern", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bd430c2193045c68d1a20a018a976248", "", "", "Pac Ghost Sprite Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bd551ff1264f5c367a3ad7cf0d2f266c", "Bit Corporation", "R320", "SpaceMaster X-7 (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bda1463e02ae3a6e1107ffe1b572efd2", "Atari, Nick 'Sandy Maiwald' Turner", "CX26111", "Snoopy and the Red Baron (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bdb4b584ddc90c9d2ec7e21632a236b6", "Atari Freak 1", "", "Nitemare at Sunshine Bowl-a-Rama (Atari Freak 1) (Hack)", "Hack of Pac-Man Jr.", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bdbaeff1f7132358ea64c7be9e46c1ac", "20th Century Fox Video Games, Douglas 'Dallas North' Neubauer", "11105", "Mega Force (1982) (20th Century Fox) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bdc381baf7c252c63739c5e9ed087a5c", "", "", "Vertical Ship Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bdecc81f740200780db04a107c3a1eba", "Quelle", "874.254 6", "Super-Cowboy beim Rodeo (1983) (Quelle) (PAL)", "AKA Stampede", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bdf1996e2dd64baf8eff5511811ca6ca", "Tron", "", "H.E.R.O. (Tron)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "be060a704803446c02e6f039ab12eb91", "Parker Brothers, Rex Bradford, Sam Kjellman", "931501", "Star Wars - The Empire Strikes Back (1982) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "be1922bd8e09d74da471287e1e968653", "Cropsy", "", "Hangman Pacman Demo (Cropsy) (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "be2870a0120fd28d25284e9ccdcbdc99", "", "", "Tomb Raider 2600 [REV 01] (Montezuma's Revenge Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "be35d8b37bbc03848a5f020662a99909", "Atari, Joe Decuir, Steve Mayer, Larry Wagner - Sears", "CX2601 - 99801, 6-99801, 49-75124", "Combat (1977) (Atari) (4K) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "be3f0e827e2f748819dac2a22d6ac823", "Puzzy - Bit Corporation", "PG202", "Space Tunnel (1982) (Puzzy)", "AKA Le Tunnel de L'Estace", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "be41463cd918daef107d249f8cde3409", "", "", "Berzerk (Voice Enhanced) (Hack)", "Hack of Berzerk", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "be561b286b6432cac71bccbae68002f7", "", "", "Counter Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "be929419902e21bd7830a7a7d746195d", "Activision, Garry Kitchen", "AX-025, AX-025-04", "Keystone Kapers (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "becd908f9d7bb361982c3dc02d6475c6", "Kyle Pittman", "", "THX-1138 (Kyle Pittman) (Hack)", "Hack of Berserk", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bedfbde71fb606601f936b5b057f26f7", "Activision, Garry Kitchen - Ariola", "EAX-025, EAX-025-04I - 711 025-725", "Keystone Kapers (1983) (Activision) (PAL) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "befce0de2012b24fd6cb8b53c17c8271", "", "", "Push (V0.03) (No Illegal Opcodes) (1998) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bf1970b692275b42c4ec0683588eb062", "Thomas Jentzsch", "", "Reactor - Amiga Mouse Hack v1.3 (NTSC) (Full-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bf52327c2197d9d2c4544be053caded1", "HES - Activision", "AG-930-04, AZ-030", "Decathlon (HES) (PAL) (16K)", "AKA Activision Decathlon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bf84f528de44225dd733c0e6a8e400a0", "CCE", "", "Demons to Diamonds (CCE)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "YES", "", "", "10 57", "", "", "", "" }, + { "bf976cf80bcf52c5f164c1d45f2b316b", "Atari, Tod Frye, Mimi Nyden", "CX2657", "SwordQuest - FireWorld (1982) (Atari) (PAL)", "AKA Adventure II, SwordQuest II - FireWorld", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bfa58198c6b9cd8062ee76a2b38e9b33", "", "", "20 Sprites at Once Demo 4 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bfb73aabb2489316cd5882c3cd11d9f9", "AtariAge, Chris Walton & Thomas Jentzsch", "165", "Star Castle Arcade (2014) (AtariAge)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "bff8f8f53a8aeb1ee804004ccbb08313", "", "", "Droid Demo 22 (David Conrad Schweinsberg) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "bffe34516aaa3cbf5d307eab382a7e95", "", "", "Euchre (Release Candidate) (PAL) (28-09-2002) (Erik Eid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c00734a2233ef683d9b6e622ac97a5c8", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX26133", "A-Team, The (03-30-1984) (Atari) (Prototype)", "AKA Saboteur", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c00b65d1bae0aef6a1b5652c9c2156a1", "Atari, Joe Decuir - Sears", "CX2621 - 99806, 6-99806, 49-75104", "Video Olympics (1977) (Atari) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "YES", "", "", "AUTO 60", "", "", "", "" }, + { "c02e1afa0671e438fd526055c556d231", "Atari", "", "A-Team (Atari) (Prototype) (PAL60)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c032c2bd7017fdfbba9a105ec50f800e", "Activision, Charlie Heath", "", "Thwocker (04-09-1984) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c033dc1d7b6fde41b9cadce9638909bb", "", "", "Skeleton (V1.1) (06-09-2002) (Eric Ball)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c0589bb73858924389077fa3c2e9441a", "SOLID Corp. (D. Scott Williamson)", "CX2655-014", "Star Castle 2600 (SolidCorp) [014]", "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "c05f367fa4767ceb27abadf0066df7f4", "Thomas Jentzsch", "", "TomInv (31-07-2001) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c08d0cee43077d3055febb00e5745c1d", "HES - Activision", "", "Super Hit Pak - River Raid, Sky Jinks, Grand Prix, Fishing Derby, Checkers (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c0a68837c60e15d1fc5a40c9a62894bc", "Arcadia Corporation, Kevin Norman", "7 AR-4103", "Killer Satellites (1983) (Arcadia) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c0c7eddefce9015346db88ade3e1e096", "CBS Electronics, Bob Curtiss", "4L 2487 5000", "Solar Fox (1983) (CBS Electronics) (Prototype) (4K)", "RAM must be zero'ed to start correctly", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "c0d2434348de72fa6edcc6d8e40f28d7", "SEGA - Beck-Tech, Steve Beck", "010-01", "Tapper (1984) (SEGA)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c1034a5bfb0bb13cc5bdf86cc58989a7", "Atari, Nick 'Sandy Maiwald' Turner", "CX2665", "Frog Pond (1982) (Atari) (Prototype) (4K) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c118854d670289a8b5d5156aa74b0c49", "Jone Yuan Telephonic Enterprise Co", "", "Skiing (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c11e8473c652619ac6166900150ce215", "AtariAge, Chris Walton", "1.0 (Release)", "Chetiry (2011) (AtariAge) (60k) (PAL)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "50" }, + { "c126656df6badfa519cc63e681fb3596", "Ron Corcoran", "", "Space Invaders (2002) (Ron Corcoran) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c15042e54c7408498f051d782aaa8945", "Omegamatrix", "", "Millipede (Atari Trak-Ball) v6.5 (Omegamatrix)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c150c76cbde2c9b5a97eb5399d46c64f", "", "", "Unknown Title (xxx00000 (200203)) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c16c79aad6272baffb8aae9a7fff0864", "U.S. Games Corporation - JWDA, Sylvia Day, Todd Marshall, Robin McDaniel, Henry Will IV", "VC2001", "Gopher (1982) (U.S. Games)", "AKA Gopher Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c16fbfdbfdf5590cc8179e4b0f5f5aeb", "", "", "Wall Break (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c17bdc7d14a36e10837d039f43ee5fa3", "Spectravision - Spectravideo", "SA-203", "Cross Force (1982) (Spectravision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c1a83f44137ea914b495fc6ac036c493", "Atari, Carla Meninsky", "CX2660", "Star Raiders (1982) (Atari) (PAL)", "Uses Joystick (left) and Keypad (right) Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c1b038ce5cb6d85e956c5509b0e0d0d8", "", "", "Rotating Colors Demo 2 (Junkosoft) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c1b1049b88bcd98437d8872d1d62ba31", "", "", "Demo Image Series #4 - Donald (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c1b7aeabc3ec41556d924c8372a9ba5b", "Atari, Robert C. Polaro", "", "Dukes of Hazard (1980) (Atari) (Prototype)", "AKA Stunt Cycle", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c1cb228470a87beb5f36e90ac745da26", "Activision, Bob Whitehead", "AX-015, AX-015-04", "Chopper Command (1982) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c1e6e4e7ef5f146388a090f1c469a2fa", "Bomb - Onbase", "CA283", "Z-Tack (1983) (Bomb)", "AKA Base Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c1f209d80f0624dada5866ce05dd3399", "Telegames", "", "Deadly Discs (1988) (Telegames) (PAL)", "AKA TRON - Deadly Discs", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c1fdd44efda916414be3527a47752c75", "Parker Brothers, John Emerson", "PB5920", "G.I. Joe - Cobra Strike (1983) (Parker Bros)", "Uses the Paddle (left) and Joystick (right) Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c20f15282a1aa8724d70c117e5c9709e", "Video Gems", "VG-02", "Surfer's Paradise (1983) (Video Gems) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c21450c21efb7715746e9fa87ad6f145", "Hozer Video Games", "", "Gunfight 2600 - It could've been soooo cool, but... (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c216b91f5db21a093ded6a5aaec85709", "Jone Yuan Telephonic Enterprise Co", "", "Dragster (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c221607529cabc93450ef25dbac6e8d2", "Eckhard Stolberg", "", "Color Test (26-09-2002) (Eckhard Stolberg)", "", "Homebrew", "", "", "", "", "A", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c225379e7c4fb6f886ef9c8c522275b4", "Video Mania", "", "Frostbite (1983) (Video Mania)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c225abfb584960efe1f359fc94b73379", "", "", "Joustpong (21-09-2002) (Kirk Israel) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c2410d03820e0ff0a449fa6170f51211", "", "", "Pac-Man (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c246e05b52f68ab2e9aee40f278cd158", "Thomas Jentzsch", "", "Star Wars - Ewok Adventure (Thomas Jentzsch) (Prototype)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c2778507b83d9540e9be5713758ff945", "", "", "Island Flyer Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c28b29764c2338b0cf95537cc9aad8c9", "", "", "Multi-Color Demo 4 (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c29d17eef6b0784db4586c12cb5fd454", "Jone Yuan Telephonic Enterprise Co", "", "River Raid (Jone Yuan) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c29f8db680990cb45ef7fef6ab57a2c2", "Parker Brothers - Roklan, Paul Crowley, Bob Curtiss", "931505", "Super Cobra (1983) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c2a37f1c7603c5fd97df47d6c562abfa", "Roger Williams", "", "Bar-Score Demo (2001) (Roger Williams)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c2b5c50ccb59816867036d7cf730bf75", "Salu - Avantgarde Software, Michael Buetepage", "460741", "Ghostbusters II (1992) (Salu) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "c2bcd8f2378c3779067f3a551f662bb7", "Activision, Bob Whitehead - Ariola", "EAG-002, EAG-002-04I, PAG-002 - 711 002-715", "Boxing (1980) (Activision) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c2c7a11717e255593e54d0acaf653ee5", "", "", "Chopper Command (208 in 1) (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c2c8eb642765137bb82b83a65232961f", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Atari Mouse Hack v1.1 (PAL) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c2dea467f4a02fa1f06d66f52bc12e6e", "Thomas Jentzsch", "", "Missile Command Atari Trak-Ball Hack v1.3 (NTSC) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c2fbef02b6eea37d8df3e91107f89950", "Champ Games", "CG-02-N", "Conquest Of Mars (NTSC)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c31a17942d162b80962cb1f7571cd1d5", "Home Vision - Gem International Corp. - VDI", "VCS83112", "Sky Alien (1983) (Home Vision) (PAL)", "AKA Sky Aliem", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c3205e3707f646e1a106e09c5c49c1bf", "", "", "Unknown Title (bin00003 (200206)) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c3472fa98c3b452fa2fd37d1c219fb6f", "Atari, Carla Meninsky - Sears", "CX2637 - 49-75158", "Dodge 'Em (1980) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c370c3268ad95b3266d6e36ff23d1f0c", "Atari, Alan Miller", "CX2641, CX2641P", "Surround (1977) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c3a9550f6345f4c25b372c42dc865703", "Atari - Bobco, Robert C. Polaro", "CX2663", "Road Runner (1989) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c3aeb796fdaf9429e8cd6af6346f337e", "", "", "If It's Not One Thing It's Another (1997) (Chris Cracknell)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c3bbc673acf2701b5275e85d9372facf", "Atari, Robert C. Polaro", "CX26157", "Stunt Cycle (07-21-1980) (Atari) (Prototype)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c3e4aa718f46291311f1cce53e6ccd79", "", "", "Hangman Ghost 4letter (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c3ef5c4653212088eda54dc91d787870", "Activision, Bob Whitehead", "AG-002, CAG-002, AG-002-04", "Boxing (1980) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c3f53993ade534b0982ca3a286c85bb5", "", "", "Full Screen Bitmap Drawing System (12-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c4060a31d61ba857e756430a0a15ed2e", "Thomas Jentzsch", "", "Pick 'n Pile (2003) (TJ)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "c41e7735f6701dd50e84ee71d3ed1d8f", "Dynacom", "", "Spider Fighter (1983) (Dynacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c43bd363e1f128e73ba5f0380b6fd7e3", "Atari, Chris Crawford", "", "Wizard (1980) (Atari) (Prototype) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c446288fe62c0c2737639fd788ae4a21", "", "", "Mark's Sound Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "c450a285daa7a3b65188c2c3cf04fb3e", "Wizard Video Games", "007", "Halloween (1983) (Wizard Video Games) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c469151655e333793472777052013f4f", "", "", "Base Attack (Unknown) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c471b97446a85304bbac021c57c2cb49", "First Star Software, Alex Leavens, Shirley Ann Russell", "", "Boing! (1983) (First Star Software) (PAL)", "AKA Bubbles, Soap Suds, The Emphysema Game", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "c47244f5557ae12c61e8e01c140e2173", "Atari - GCC, Mike Feinstein, John Allred", "CX2688, CX2688P", "Jungle Hunt (1983) (Atari) (PAL) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c47b7389e76974fd0de3f088fea35576", "Funvision - Fund. International Co.", "", "Mighty Mouse (Funvision)", "AKA Gopher", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c482f8eebd45e0b8d479d9b71dd72bb8", "Retroactive", "", "Push (V0.03) (1998) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "c49fe437800ad7fd9302f3a90a38fb7d", "Atari, Dan Hitchens, Mimi Nyden", "CX2697, CX2697P", "Mario Bros. (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c4b73c35bc2f54b66cd786f55b668a82", "Arcadia Corporation, Stephen Harland Landrum", "AR-4101", "Communist Mutants from Space (1982) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c4bbbb0c8fe203cbd3be2e318e55bcc0", "", "", "Atlantis (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c4bc8c2e130d76346ebf8eb544991b46", "Imagic", "", "Imagic Selector ROM (1982) (Imagic) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c4d888bcf532e7c9c5fdeafbb145266a", "", "", "Space Robot (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "c504a71c411a601d1fc3173369cfdca4", "Retroactive", "", "Qb (V2.02) (Stella) (2001) (Retroactive)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "c5124e7d7a8c768e5a18bde8b54aeb1d", "Imagic, Rob Fulop", "720104-2A, IA3204P, EIX-008-04I", "Cosmic Ark (1982) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c517144e3d3ac5c06f2f682ebf212dd7", "Tigervision - Teldec", "7-008 - 3.60006 VG", "Miner 2049er (1983) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c529e63013698064149b9e0468afd941", "", "", "S.I.PLIX 2 (Hack)", "Hack of Kaboom!", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, + { "c52d9bbdc5530e1ef8e8ba7be692b01e", "Atari, Robert C. Polaro", "CX26130", "Holey Moley (02-29-1984) (Atari) (Prototype)", "Uses Keypad Controllers", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c5301f549d0722049bb0add6b10d1e09", "Atari, Carla Meninsky, Ed Riddle - Sears", "CX2611 - 99821, 49-75149", "Indy 500 (1977) (Atari)", "Uses the Driving Controllers", "", "", "", "", "", "", "", "", "DRIVING", "DRIVING", "", "", "", "45", "", "", "", "" }, + { "c5387fc1aa71f11d2fa82459e189a5f0", "Bit Corporation", "PG202", "Space Tunnel (1982) (BitCorp) (PAL)", "AKA Weltraum-Tunnel", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c53c0d10c74325deae9ba84074281983", "The Atari 2600 Connection - John K. Harvey, Tim Duarte", "v75", "Mean Santa (2009)", "Released in 2019", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c541a5f6fc23b40a211196dd78233780", "Atari, Carla Meninsky - Sears", "CX2660 - 49-75187", "Star Raiders (1981) (Atari) (Prototype) (4K)", "Uses Joystick (left) and Keypad (right) Controllers", "Prototype", "", "", "", "", "", "", "", "", "KEYBOARD", "", "", "", "", "", "", "", "" }, + { "c54b4207ce1d4bf72fadbb1a805d4a39", "Billy Eno", "", "Sniper (Feb 30) (2001) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c560a3ecb7b751021953819efcfe5b41", "Omegamatrix", "", "Ghostbusters (Genesis)", "Genesis controller", "", "", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "", "" }, + { "c569e57dca93d3bee115a49923057fd7", "", "", "Pac-Space (Pac-Man Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c58708c09ccb61625cda9d15ddcd8be6", "SPIKE the Percussionist", "", "NOIZ Invaders (SPIKE) (2002) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c5930d0e8cdae3e037349bfa08e871be", "Atari, Howard Scott Warshaw - Sears", "CX2655 - 49-75167", "Yars' Revenge (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "c59633dbebd926c150fb6d30b0576405", "Telegames", "5861 A030", "Bogey Blaster (1988) (Telegames)", "AKA Air Raiders", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c5a76bafc4676edb76e0126fb9f0fb2d", "Charles Morgan", "", "Zero Patrol (Charles Morgan) (Hack)", "Hack of Moon Patrol", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c5bab953ac13dbb2cba03cd0684fb125", "SpiceWare - Darrell Spice Jr.", "", "Stay Frosty (SpiceWare)", "Part of Stella's Stocking 2007 Xmas compilation", "Homebrew", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "c5bf03028b2e8f4950ec8835c6811d47", "Atari - Axlon, Tod Frye - Heuristica, Agustin Ortiz", "CX26169", "Shooting Arcade (03-07-1989) (Atari) (Prototype) [a2]", "Uses the Light Gun Controller (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c5c7cc66febf2d4e743b4459de7ed868", "Atari, Jerome Domurat, Steve Woita", "CX2696", "Asterix (1983) (Atari) (PAL) [a]", "AKA Taz", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c5d2834bf98e90245e545573eb7e6bbc", "CCE", "", "Snoopy and the Red Baron (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c5dd8399257d8862f3952be75c23e0eb", "Atari - GCC", "CX2680", "RealSports Tennis (1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c5f71dfbdca9cc96b28643ff4d06aa6f", "Thomas Jentzsch", "", "Centipede - Atari Trak-Ball Hack v1.4 (PAL) (Full-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c5fe45f2734afd47e27ca3b04a90213c", "Atari, Brad Stewart", "CX2622, CX2622P", "Breakout (1978) (Atari) (PAL) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "01", "", "", "", "" }, + { "c63a98ca404aa5ee9fcff1de488c3f43", "Atari", "CX26145", "Venture (1987) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "c6556e082aac04260596b4045bc122de", "Atari - GCC, Dave Payne", "CX2669", "Vanguard (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c6688781f4ab844852f4e3352772289b", "Atari, Tod Frye", "CX2695", "Xevious (08-02-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "c67ff409f28f44883bd5251cea79727d", "", "", "Gunfight 2600 - Music & Bugfixes 1 (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c689148ad9275667924ab334107b517e", "Jone Yuan Telephonic Enterprise Co", "", "Space Raid (Jone Yuan)", "AKA MegaMania", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c68a6bafb667bad2f6d020f879be1d11", "Atari, Michael Kosaka, Peter C. Niday, Robert Vieira", "CX26110", "Crystal Castles (1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c6ae21caceaad734987cb24243793bd5", "CCE", "", "Frostbite (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c6c63da3bc2e47291f63280e057061d0", "128-in-1 Junior Console", "", "Human Cannonball (128-in-1 Junior Console) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c6d48c6ae6461e0e82753540a985ac9e", "Ed Federmeyer", "", "Edtris (1994) (Ed Federmeyer)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c6d7fe7a46dc46f962fe8413c6f53fc9", "Parker Brothers, Mark Lesser", "PB5950", "Lord of the Rings (1983) (Parker Bros) (Prototype) [a]", "Journey to Rivendell (The Lord of the Rings I)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c6db733e0b108c2580a1d65211f06dbf", "Atari, Eric Manghise, Mimi Nyden, Joseph Tung", "CX2640", "RealSports Baseball (07-09-1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c738fc3f5aae1e8f86f7249f6c82ac81", "Atari, Brad Stewart - Sears", "CX2622 - 6-99813, 49-75107", "Breakout (1978) (Atari) (16K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "01 60", "", "", "", "" }, + { "c73ae5ba5a0a3f3ac77f0a9e14770e73", "Starpath Corporation, Stephen H. Landrum", "9 AR-4105", "Official Frogger, The (1983) (Starpath)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c745487828a1a6a743488ecebc55ad44", "Rainbow Vision - Suntek", "SS-002", "Galactic (1983) (Rainbow Vision) (PAL)", "AKA The Challenge of.... Nexar", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c74bfd02c7f1877bbe712c1da5c4c194", "Thomas Jentzsch", "", "River Raid Tanks (Thomas Jentzsch) (Hack)", "Hack of River Raid", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c7600d72247c5dfa1ec1a88d23e6c85e", "Arcadia Corporation, Scott Nelson", "13", "Sweat! - The Decathlon Game (1 of 3) (1983) (Arcadia) (Prototype)", "Uses the Paddle Controllers (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c77c35a6fc3c0f12bf9e8bae48cba54b", "Xonox - K-Tel Software - Action Graphics, Michael Schwartz, David Thiel", "6230, 7210, 06004, 99004", "Artillery Duel (1983) (Xonox)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c77d3b47f2293e69419b92522c6f6647", "Panda", "101", "Tank Brigade (1983) (Panda)", "AKA Phantom Tank", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c7900a7fe95a47eef3b325072ad2c232", "Larry Petit", "", "Super Congo Bongo (2003) (Larry Petit) (Hack)", "Hack of Bongo", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c7d5819b26b480a49eb26aeb63cc831e", "Bit Corporation", "PGP210", "Ice Hockey (4 Game in One Light Green) (1983) (BitCorp) (PAL)", "AKA Hockey, Hockey", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c7e43ad79c5e5c029d9f5ffde23e32cf", "", "", "PAL-NTSC Detector (15-11-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c7eab66576696e11e3c11ffff92e13cc", "Atari - GCC", "CX2680, CX2680P", "RealSports Tennis (1983) (Atari) (PAL) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c7f13ef38f61ee2367ada94fdcc6d206", "Parker Brothers - Roklan, Joe Gaucher", "PB5370", "Popeye (1983) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "c82ec00335cbb4b74494aecf31608fa1", "CCE", "", "E.T. - The Extra-Terrestrial (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c830f6ae7ee58bcc2a6712fb33e92d55", "Atari, Michael Kosaka", "CX2687", "Tempest (01-05-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c866c995c0d2ca7d017fef0fc0c2e268", "Retroactive", "", "Qb (2.00) (Retroactive) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "c880c659cdc0f84c4a66bc818f89618e", "Thomas Jentzsch", "", "Open Sesame (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "c89c3138a99fd1fd54367d65f75b0244", "Atari, Omegamatrix", "", "Space Invaders Menu (2020) (PAL) (Hack)", "Hack of Space Invaders", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c8c7da12f087e8d16d3e6a21b371a5d3", "", "", "Demo Image Series #9 - Genius (28-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c8e90fc944596718c84c82b55139b065", "Atari - Roklan, Bob Curtiss", "", "Firefox (1983) (Atari) (Prototype) [a]", "AKA Combat II, Fighter Command", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c8fa5d69d9e555eb16068ef87b1c9c45", "Atari", "CX26144", "Donkey Kong Junior (1987) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c90788d9aa71a78bcc78c015edb22c54", "Thomas Jentzsch", "", "Marble Craze - Atari Trak-Ball Hack v1.0 (PAL60) (TJ)", "Uses Atari Trak-Ball Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c9196e28367e46f8a55e04c27743148f", "Atari", "CX26163P", "Stampede (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c92cfa54b5d022637fdcbdc1ef640d82", "Retroactive", "", "Qb (V2.05) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "c98e8c918a40b4d3a243dd6c49196330", "AtariAge, Omegamatrix", "", "Venture Reloaded (2019) (AtariAge) (PAL60) (Hack)", "Transformative hack of Venture", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "c9b7afad3bfd922e006a6bfc1d4f3fe7", "Atari, Larry Kaplan - Sears", "CX2628 - 6-99842, 49-75117", "Bowling (1979) (Atari)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c9c25fc536de9a7cdc5b9a916c459110", "Activision, Mike Lorenzen", "AX-023", "Oink! (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c9d02d3cfeef8b48fb71cb4520a4aa84", "", "", "Euchre (More for less) (PAL) (22-08-2002) (Erik Eid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c9e721eb29c940c2e743485b044c0a3f", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "c9f6e521a49a2d15dac56b6ddb3fb4c7", "Parker Brothers, Rex Bradford", "PB5000", "Star Wars - Jedi Arena (1983) (Parker Bros)", "Uses the Paddle Controllers (swapped)", "", "", "", "", "", "", "", "", "", "", "YES", "", "", "10 50", "", "", "", "" }, + { "ca09fa7406b7d2aea10d969b6fc90195", "Activision, Matthew L. Hubbard, Bob Whitehead", "AX-024", "Dolphin (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ca4f8c5b4d6fb9d608bb96bc7ebd26c7", "M Network - INTV - APh Technological Consulting, Hal Finney, Glenn Hightower, Peter Kaminski", "MT4317", "Adventures of TRON (1983) (M Network)", "AKA Tron Joystick", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ca50cc4b21b0155255e066fcd6396331", "Suntek", "SS-031", "UFO Patrol (1983) (Suntek) (PAL)", "AKA X'Mission", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "ca53fc8fd8b3c4a7df89ac86b222eba0", "CCE", "C-812", "Pac Man (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ca54de69f7cdf4d7996e86f347129892", "PlayAround - J.H.M.", "201", "Philly Flasher (1982) (PlayAround)", "Uses the Paddle Controllers, AKA Beat 'Em & Eat 'Em", "", "", "", "", "", "", "", "", "", "", "", "", "", "AUTO 45", "", "", "", "" }, + { "ca7aaebd861a9ef47967d31c5a6c4555", "Atari, Bob Whitehead", "CX26163P", "Homerun (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "", "" }, + { "ca7abc774a2fa95014688bc0849eee47", "Atari, Michael Kosaka, Peter C. Niday, Robert Vieira", "CX26110", "Crystal Castles (1984) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ca7f166a94eed1a349dec6d6a358bcad", "Activision, Alan Miller - Ariola", "EAG-007, EAG-007-04I, PAG-007 - 711 007-720", "Tennis (1981) (Activision) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cac9928a84e1001817b223f0cecaa3f2", "Amiga - Video Soft, Jerry Lawson, Dan McElroy", "", "3-D Genesis (1983) (Amiga) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "cad982c9b45bc5eff34e4ea982d5f1ca", "", "", "Song (17-02-2003) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "cade123747426df69570a2bc871d3baf", "Gakken", "011", "Marine Wars (1983) (Gakken) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cae8f83c06831ec7bb6a3c07e98e9342", "Colin Hughes", "", "Tetris 2600 (Colin Hughes) [o1]", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "cb18d8d5fbdcb1cd7bd36c5423348859", "", "", "RAM-Pong (NTSC) v1.0", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cb24210dc86d92df97b38cf2a51782da", "Video Gems", "VG-01", "Missile Control (1983) (Video Gems) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cb4a7b507372c24f8b9390d22d54a918", "ITT Family Games", "554-37 338", "Peter Penguin (1983) (ITT Family Games) (PAL)", "AKA Frisco (Pumuckl-Serie)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cb8399dc0d409ff1f531ef86b3b34953", "", "", "Demo Image Series #12 - Luigi And Mario (01-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cb9626517b440f099c0b6b27ca65142c", "Atari, Larry Kaplan - Sears", "CX2664 - 6-99818", "Brain Games (1978) (Atari) (4K)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "", "" }, + { "cb96b0cf90ab7777a2f6f05e8ad3f694", "Silvio Mogno", "", "Rainbow Invaders", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cb9b2e9806a7fbab3d819cfe15f0f05a", "Parker Brothers - JWDA, Todd Marshall, Robin McDaniel, Ray Miller", "931513", "Star Wars - Death Star Battle (1983) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cba56e939252b05df7b7de87307d12ca", "", "", "Playfield Text Demo (2001) (Roger Williams)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cbad928e10aeee848786cc55394fb692", "", "", "Fu Kung! (V0.06a Cuttle Cart Compatible) (15-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cbb0ee17c1308148823cc6da85bff25c", "", "", "Rotating Colors Demo 1 (Junkosoft) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cbc373fbcb1653b4c56bfabba33ea50d", "CCE", "", "Super Voleyball (CCE)", "AKA RealSports Volleyball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cbced209dd0575a27212d3eee6aee3bc", "Apollo - Games by Apollo, Ed Salvo, Byron Parks", "AP-2003", "Racquetball (1982) (Apollo) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "cbd981a23c592fb9ab979223bb368cd5", "Atari, Carla Meninsky - Sears", "CX2660 - 49-75187", "Star Raiders (1982) (Atari)", "Uses Joystick (left) and Keypad (right) Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cbe5a166550a8129a5e6d374901dffad", "Atari, Carla Meninsky - Sears", "CX2610 - 49-75127", "Warlords (1981) (Atari)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "AUTO 50", "", "", "", "" }, + { "cbeafd37f15e0dddb0540dbe15c545a4", "", "", "Black and White Fast Scolling Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cc03c68b8348b62331964d7a3dbec381", "Jone Yuan Telephonic Enterprise Co", "", "Marauder (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cc12581e079cd18330a89902625b8347", "Dave Neuman", "", "Space Battle (PAL)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cc1939e4769d0c157ace326efcfdcf80", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (3 of 4) (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cc2973680c150886cce1ed8693c3aca2", "Quelle", "874.254 6", "Super-Cowboy beim Rodeo (1983) (Quelle) (PAL) (4K)", "AKA Stampede", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cc3d942c6958bd16b1c602623f59e6e1", "Atari, Bill Aspromonte, John Russell, Michael Sierchio, Robert Zdybel", "CX26114", "Pigs in Space (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cc7138202cd8f6776212ebfc3a820ecc", "Atari - CCW, Christopher H. Omarzu, Preston Stuart, Bruce Williams", "CX26101", "Oscar's Trash Race (03-30-1983) (Atari) (Prototype)", "Uses the Keypad Controllers", "Prototype", "", "", "", "", "", "", "", "", "KEYBOARD", "", "", "", "", "", "", "", "" }, + { "cc724ebe74a109e39c0b2784ddc980ca", "Atari, Jerome Domurat, Dave Staugas", "CX2682", "Krull (05-27-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cc74ddb45d7bc4d04c2e6f1907416699", "", "", "Colour Display Programme (1997) (Chris Cracknell)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cca33ae30a58f39e3fc5d80f94dc0362", "", "", "Okie Dokie (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ccb56107ff0492232065b85493daa635", "Bit Corporation", "PG206 [demonstration cartridge]", "Bobby Is Going Home (1983) (BitCorp) (PAL) [demo cart]", "AKA Bobby geht Heim", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ccb5fa954fb76f09caae9a8c66462190", "Answer Software Corporation - TY Associates, Mike Wentz", "ASC1001", "Malagai (1983) (Answer Software)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "ccb807eb79b0ed0f5fdc460445ef703a", "", "", "Superman (Stunt_Cycle_Rules!) (Hack)", "Hack of Superman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ccbd36746ed4525821a8083b0d6d2c2c", "Atari, Brad Stewart - Sears", "CX2649, 49-75163", "Asteroids (1981) (Atari) [no copyright]", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "cccfe9e9a11b1dad04beba46eefb7351", "", "", "Poker Squares (V0.25) (PAL) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ccd6ce508eee4b3fca67212833edcd85", "Otto Versand", "746422", "Hot Wave (Double-Game Package) (1983) (Otto Versand) (PAL)", "AKA Ram It", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ccd92a269a4c2bd64d58cf2c0114423c", "Atari - GCC, Mark Ackerman, Glenn Parker", "CX2675", "Ms. Pac-Man (09-20-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cd032ab6764b55438a7b0bfb5e78595a", "", "", "Hangman Pac-Man 4letter (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cd139ae6d09f3665ad09eb79da3f9e49", "Eric Mooney", "", "Invaders by Erik Mooney (4-24-97) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cd34b3b3ef9e485201e841ba71beb253", "Bradford W. Mott", "", "Hit HMOVE At Various Cycles After WSYNC Test (Bradford W. Mott) (1998) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cd38ad19f51b1048d8e5e99c86a2a655", "", "", "Demo Image Series #5 - Flag (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cd399bc422992a361ba932cc50f48b65", "Arcadia Corporation, Brian McGhie", "AR-4104", "Rabbit Transit (Preview) (1983) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cd3e26786136a4692fd2cb2dfbc1927e", "", "", "Multiple Moving Objects Demo 2 (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cd4423bd9f0763409bae9111f888f7c2", "Jone Yuan Telephonic Enterprise Co", "", "River Raid (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cd4ded1ede63c4dd09f3dd01bda7458c", "Future Video Games", "", "Laser Gate (Future Video Games) (PAL)", "AKA Innerspace", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cd568d6acb2f14477ebf7e59fb382292", "Videospielkassette - Ariola", "PGP235", "Fussball (Ariola) (PAL)", "AKA International Soccer", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cd5af682685cfecbc25a983e16b9d833", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX26133", "A-Team, The (05-08-1984) (Atari) (Prototype)", "AKA Saboteur", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cd88ef1736497288c4533bcca339f881", "SEGA - Teldec", "005-10", "Buck Rogers - Planet of Zoom (1983) (SEGA) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "cd8fa2e9f6255ef3d3b9b5a4f24a54f7", "", "", "Daredevil (V2) (Stunt_Cycle_Rules!) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cd98be8a48ebf610c9609a688b9c57f2", "Arcadia Corporation, Steve Hales, Stephen H. Landrum", "4 AR-4102", "Suicide Mission (1982) (Arcadia) (Prototype)", "AKA Meteoroids", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "cd9fea12051e414a6dfe17052067da8e", "Paul Slocum", "", "Marble Craze Demo (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cda38714267978b9a8b0b24bee3529ae", "", "", "Space Instigators (V1.6) (17-10-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cdadb57b34438805ee322ff05bd3d43e", "Thomas Jentzsch", "", "Centipede - Amiga Mouse Hack v1.4 (PAL60) (Full-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cdb81bf33d830ee4ee0606ee99e84dba", "Arcadia Corporation, Scott Nelson", "AR-4300", "Fireball (1982) (Arcadia) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "01", "", "", "", "" }, + { "cdc1a5c61d7488eadc9aba36166b253d", "Retroactive", "", "Qb (V0.12) (Stella) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "cddabfd68363a76cd30bee4e8094c646", "Computer Magic - CommaVid, John Bronstein", "CM-001", "MagiCard (1981) (CommaVid)", "Uses the Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ce17325834bf8b0a0d0d8de08478d436", "", "", "Boring Freeway (Hack)", "Hack of Freeway", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ce1cbe159b9ae5992dacf09371de5e13", "Atari - GCC, Kevin Osborn", "CX2689", "Kangaroo (01-19-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ce243747bf34a2de366f846b3f4ca772", "Home Vision - Gem International Corp. - VDI", "", "Jacky Jump (1983) (Home Vision) (PAL)", "AKA Bobby Is Going Home", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ce4bbe11d682c15a490ae15a4a8716cf", "", "", "Okie Dokie (Older) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ce5524bb18e3bd8e092273ef22d36cb9", "Carrere Video - JWDA, Todd Marshall, Wes Trager, Henry Will IV - Teldec - Prism", "USC1004", "Commando Raid (1983) (Carrere Video) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ce5cc62608be2cd3ed8abd844efb8919", "Atari - Bobco, Robert C. Polaro", "CX2663", "Road Runner (1989) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ce64812eb83c95723b04fb56d816910b", "Retroactive", "", "Qb (V2.04) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "ce6c4270f605ad3ce5e82678b0fc71f8", "", "", "Vertical Rainbow Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ce82a675c773ff21e0ffc0a4d1c90a71", "", "", "Defender 2 (Genesis)", "Genesis controller (C is smartbomb)", "Hack of Defender 2", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ce8467ae2a3a5bc88ca72a2ce44ce28c", "SOLID Corp. (D. Scott Williamson)", "CX2655-015", "Star Castle 2600 (SolidCorp) (PAL) [015]", "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "ce89529d6e98a13ddf3d84827bbdfe68", "", "", "Kung Fu Sprite Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "ce904c0ae58d36d085cd506989116b0b", "Telegames", "5687 A279", "International Soccer (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cea9f72036dc6f7af5eff52459066290", "Retroactive", "", "Qb (2.07) (Retroactive) (Stella)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "ceba7965a93c689bdecdb46a5b2ac0c1", "Thomas Jentzsch", "", "Reactor - Atari Trak-Ball Hack v1.3 (PAL60) (Half-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cedbd67d1ff321c996051eec843f8716", "Ultravision", "1044", "Karate (1982) (Ultravision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cef01595000627ee50863d4290372c27", "", "", "Many Blue Bars and Text Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cef2287d5fd80216b2200fb2ef1adfa8", "Milton Bradley Company", "4363", "Spitfire Attack (1983) (Milton Bradley)", "AKA Flight Commander)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cf0c593c563c84fdaf0f741adb367445", "Retroactive", "", "Qb (V0.05) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "cf3a9ada2692bb42f81192897752b912", "", "", "Air Raiders (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cf3c2725f736d4bcb84ad6f42de62a41", "Rainbow Vision - Suntek", "SS-009", "Bermuda, The (1983) (Rainbow Vision) (PAL) [a]", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cf507910d6e74568a68ac949537bccf9", "SEGA, Jeff Lorenz", "003-01", "Thunderground (1983) (SEGA)", "AKA Underground", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "cf63ffac9da89ef09c6c973083061a47", "CCE", "C-859", "MASH (1983) (CCE)", "AKA M.A.S.H", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cf9069f92a43f719974ee712c50cd932", "Video Gems", "VG-04", "Mission Survive (1983) (Video Gems) (PAL)", "", "", "", "", "", "", "A", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "cfad2b9ca8b8fec7fb1611d656cc765b", "Bit Corporation", "PG207", "Mission 3,000 A.D. (1983) (BitCorp) (PAL) [demo cart]", "demonstration cartridge", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "cfb3260c603b0341d49ddfc94051ec10", "Dactari - Milmar", "", "Boxing (Dactari - Milmar)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cfb83a3b0513acaf8be4cae1512281dc", "Starpath Corporation", "", "Going-Up (1983) (Starpath) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cfc226d04d7490b69e155abd7741e98c", "Atari, Matthew L. Hubbard", "CX26159", "Double Dunk (1989) (Atari) (PAL)", "AKA Super Basketball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cfce5596a7e8ca13529e9804cad693ef", "Canal 3 - Intellivision", "", "Tennis (Canal 3) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cfd5518c71552b8bb853b0e461e328d7", "Bit Corporation", "R320", "Spider Fighter (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cfd6a8b23d12b0462baf6a05ef347cd8", "Activision, Larry Kaplan", "AX-006", "Bridge (1980) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cfdb4d0427a1ea8085c6bc6eb90259d8", "", "", "Gunfight 2600 - Release Candidate (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cfe2185f84ce8501933beb5c5e1fd053", "", "", "Football (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cfe62ed7125ff9fae99b4c8a367c0399", "Activision, Larry Miller", "AX-026, AX-026-04", "Enduro (1983) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cfee10bd7119f10b136921ced2ee8972", "", "", "Space Instigators (V1.8) (19-10-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cfef1a2d1f6a5ee7a5e1f43f3056f112", "", "", "Skeleton+ (05-05-2003) (Eric Ball) (NTSC)", "", "", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cff1e9170bdbc29859b815203edf18fa", "Retroactive", "", "Push (V0.01) (1998) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "cff578e5c60de8caecbee7f2c9bbb57b", "George Veeder", "", "Suicide Adventure (George Veeder) (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "cff9950d4e650094f65f40d179a9882d", "Paul Slocum", "", "Mr. Roboto (Paul Slocum) (Hack)", "Hack of Berzerk", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "cfffc4b97d01cc3e7b9f47575f7b11ec", "Xonox - K-Tel Software, Anthony R. Henderson", "99007, 6240", "Tomarc the Barbarian (1983) (Xonox) (PAL60)", "Genesis controller (B is jump and throw, C switches between players)", "Hack of Tomarc the Barbarian", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d00f6f8ba89559e4b20972a478fc0370", "Spiceware", "SW-01", "Medieval Mayhem (PAL)", "", "Homebrew", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "AUTO 55", "", "", "", "" }, + { "d010e3dfe7366e47561c088079a59439", "Retroactive", "", "Qb (V0.10) (Stella) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "d026716b3c5be2c951cc4c064317c524", "", "", "Fu Kung! (V0.06) (14-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d0498baca989e792db4b8270a02b9624", "", "", "Pac Ghost Sprite Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d071d2ec86b9d52b585cc0382480b351", "UA Limited", "", "Cat Trax (1983) (UA Limited) (1) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "d078674afdf24a4547b4b32890fdc614", "Jone Yuan Telephonic Enterprise Co", "", "Laser Blast (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d078d25873c5b99f78fa267245a2af02", "SEGA - Beck-Tech, Steve Beck, Phat Ho", "006-01", "Congo Bongo (1983) (SEGA) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d0796a0317abf9018d6745086bef411f", "Edward Smith", "", "Alien Attack (2018)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d08fccfbebaa531c4a4fa7359393a0a9", "Activision, David Crane, Bob Whitehead", "", "Venetian Blinds Demo (1981) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d090836f0a4ea8db9ac7abb7d6adf61e", "Hozer Video Games", "", "Yahtzee (Hozer Video Games)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "d09935802d6760ae58253685ff649268", "Telesys, Don Ruffcorn", "1006", "Demolition Herby (1983) (Telesys)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "d09a7504ee8c8717ac3e24d263e7814d", "Activision, Matthew L. Hubbard, Bob Whitehead", "AX-024", "Dolphin (1983) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d09f1830fb316515b90694c45728d702", "Imagic, Brad Stewart", "720105-1A, IA3400", "Fire Fighter (1982) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d0a379946ed77b1b126230ca68461333", "Ataripoll", "", "Atari Invaders (Ataripoll) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d0af33865512e9b6900714c26db5fa23", "Telegames", "", "Armor Ambush (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d0b26e908370683ad99bc6b52137a784", "Apollo - Games by Apollo, Larry Minor, Ernie Runyon, Ed Salvo - RCA Video Jeux", "AP-2004", "Lost Luggage (1982) (Apollo) (PAL)", "AKA La valise piegee", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d0b9df57bfea66378c0418ec68cfe37f", "20th Century Fox Video Games - Sirius, Grady Ward", "11002", "Beany Bopper (1982) (20th Century Fox)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d0b9f705aa5f61f47a748a66009ae2d2", "", "", "Synthcart (14-01-2002) (Paul Slocum)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "d0cb28e1b7bd6c7f683a0917b59f707e", "Atari, Gary Palmer", "CX2661P", "Fun with Numbers (1980) (Atari) (PAL) (4K)", "AKA Basic Math", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d0cdafcb000b9ae04ac465f17788ad11", "Quelle - Otto Versand", "732.273 8 - 600273, 781644", "Lilly Adventure (1983) (Quelle) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d0e05ba5f10e3df3023c5ee787f760ef", "Thomas Jentzsch", "", "Centipede - Atari Mouse Hack v1.4 (PAL) (Half-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d0e15a3ce322c5af60f07343594392af", "Amiga - Video Soft", "3125", "Surf's Up (1983) (Amiga) (Prototype) (4K)", "Uses the Joyboard controller", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d0e9beb2347595c6c7d158e9d83d2da8", "Retroactive", "", "Qb (2.00) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "d100b11be34a1e5b7832b1b53f711497", "", "", "Robotfindskitten2600 (26-04-2003) (Jeremy Penner) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d15655fe355fa57dd541487dc5725145", "Rentacom", "", "Vanguard (Rentacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d170317ae4c7d997a989c7d6567c2840", "Jone Yuan Telephonic Enterprise Co", "", "Stampede (Jone Yuan) (4K) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d175258b2973b917a05b46df4e1cf15d", "Suntek", "SS-032", "Walker (1983) (Suntek) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d17a671029b1532b197defca5f3649a7", "Hozer Video Games", "", "Gunfight 2600 - Limit broken again! (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d17a8c440d6be79fae393a4b46661164", "", "", "Warring Worms (Beta 3) (2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d1a1841b7f2007a24439ac248374630a", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (1 of 4) (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d1a9478b99d6a55e13a9fd4262da7cd4", "U.S. Games Corporation, Garry Kitchen - Vidtec", "VC1001", "Space Jockey (1982) (U.S. Games) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d1b4075925e8d3031a7616d2f02fdd1f", "", "", "Demo Image Series #7 - Two Marios (27-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d1c3520b57c348bc21d543699bc88e7e", "Gameworld", "133-002", "Warplock (1983) (Gameworld) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "01", "", "", "YES", "" }, + { "d1ca47b262f952413c1234117c4e4e21", "Bit Corporation", "R320", "Missile Command (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d1d704a7146e95709b57b6d4cac3f788", "Atari, Warren Robinett", "CX26163P", "Slot Racers (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d20e61c86ed729780feca162166912ca", "Supergame", "32", "Pitfall (1984) (Supergame)", "AKA Pitfall!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d214c7a734e133a5c18e93229435b57a", "Digivision", "", "Mickey (Digivision)", "AKA Sorcerer's Apprentice", "", "", "", "UASW", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d223bc6f13358642f02ddacfaf4a90c9", "Rainbow Vision - Suntek", "SS-003", "Pac-Kong (1983) (Rainbow Vision) (PAL)", "AKA Inca Gold", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d245e2f27c84016041e9496b66b722fe", "", "", "Gunfight 2600 - The Final Kernel (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d25018349c544320bf3fd5092ee072bc", "Activision, Larry Miller", "AX-021", "Spider Fighter (1983) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d28afe0517a046265c418181fa9dd9a1", "", "", "Dodge 'Em (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d2901c34bb6496bb96c7bc78a9e6142a", "Greg Zumwalt", "", "Fish Revenge (2003) (Greg Zumwalt) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d2c4f8a4a98a905a9deef3ba7380ed64", "Mythicon, Bill Bryner, Bruce de Graaf", "MA1001", "Sorcerer (1983) (Mythicon)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d2c8e6aa8172b16c8aa9aae739ac9c5e", "Activision, David Crane", "08-08-1980", "Laser Blast (08-08-1980) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d2c957dd7746521b51bb09fde25c5774", "Eckhard Stolberg", "", "Cubis (6K) (1997) (Eckhard Stolberg)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d2d8c4f1ea7f347c8bcc7d24f45aa338", "", "", "20 Sprites at Once Demo 5 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d2deddb77c8b823e4be9c57cb3c69adc", "Canal 3 - Intellivision", "C 3007", "Snoopy and the Red Baron (Canal 3)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d2f713c78a9ebba9da6d10aeefc6f20f", "Digivision", "", "Enduro (Digivision) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d3171407c3a8bb401a3a62eb578f48fb", "ZiMAG - Emag - Vidco", "GN-080", "Spinning Fireball (1983) (ZiMAG) (Prototype) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "d326db524d93fa2897ab69c42d6fb698", "Parker Brothers - Roklan, Paul Crowley, Bob Curtiss", "931505", "Super Cobra (1983) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d339b95f273f8c3550dc4daa67a4aa94", "", "", "Laser Blast (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d341d39774277cee6a1d378a013f92ac", "Xonox, John Perkins", "6230, 7210, 06004, 99004", "Artillery Duel (1983) (Xonox) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d3423d7600879174c038f53e5ebbf9d3", "U.S. Games Corporation - Western Technologies", "VC2005", "Piece o' Cake (1983) (U.S. Games)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "AUTO 60", "", "", "", "" }, + { "d3456b4cf1bd1a7b8fb907af1a80ee15", "Avalon Hill, Duncan Scott", "5003002", "Wall Ball (1983) (Avalon Hill)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "d34b933660e29c0a0a04004f15d7e160", "", "", "Multi-Color Demo 5 (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d36308387241e98f813646f346e7f9f7", "King Atari", "", "Ghostbuster 2 (King Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "d39e29b03af3c28641084dd1528aae05", "Funvision - Fund. Int'l Co.", "", "Spider Monster (1982) (Funvision) (PAL)", "AKA Spider Kong", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d3bb42228a6cd452c111c1932503cc03", "UA Limited", "", "Funky Fish (1983) (UA Limited) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "d44d90e7c389165f5034b5844077777f", "Parker Brothers, Larry Gelberg", "PB5065", "Star Wars - Ewok Adventure (1983) (Parker Bros) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d45bf71871b196022829aa3b96bfcfd4", "Activision, Steve Cartwright", "AX-017, AX-017-04", "MegaMania (1982) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d45ebf130ed9070ea8ebd56176e48a38", "SEGA, Jeff Lorenz", "001-01", "Tac-Scan (1983) (SEGA)", "Uses the Paddle Controllers (right only)", "", "", "", "", "", "", "", "YES", "", "", "YES", "", "", "AUTO 60", "", "", "YES", "" }, + { "d47387658ed450db77c3f189b969cc00", "PlayAround - J.H.M.", "206", "Westward Ho (1982) (PlayAround) (PAL)", "AKA Custer's Revenge", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d4806775693fcaaa24cf00fc00edcdf3", "Atari - Bobco, Robert C. Polaro", "CX26140, CX26140P", "Desert Falcon (1987) (Atari) (PAL)", "AKA Nile Flyer, Sphinx", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d483f65468d9a265661917bae1a54f3e", "Joe Grand", "", "SCSIcide Pre-release 3 (Joe Grand)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d4942f4b55313ff269488527d84ce35c", "Atari - GCC, Mark Ackerman, Glenn Parker", "CX2675, CX2675P", "Ms. Pac-Man (1982) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d49aff83f77a1b9041ad7185df3c2277", "", "", "Space Treat (60% complete) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d4aa89e96d2902692f5c45f36903d336", "", "", "Euchre (NTSC) (Erik Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d4c590ccfb611a73b3331359700c01a3", "", "", "Sprite Movement Demo 2 (2001) (Roger Williams)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d541b20eae221a8ee321375e5971e766", "Arcadia Corporation, Stephen H. Landrum", "AR-4101", "Communist Mutants from Space (Preview) (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d54cd41ecfd59e4b72d2c086152b9a75", "Amiga - Video Soft - Michael K. Glass, Jerry Lawson", "1110", "Power Play Arcade Video Game Album (1983) (Amiga) (Prototype)", "3-D Ghost Attack only (3-D Genesis & 3-D Havoc missing in ROM)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "d5618464dbdc2981f6aa8b955828eeb4", "CCE", "C-829", "Megamania (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d563ba38151b8204c9f5c9f58e781455", "Atari, Brad Stewart - Sears", "CX2649, 49-75163", "Asteroids (1981) (Atari) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "d573089534ca596e64efef474be7b6bc", "Parker Brothers, John Emerson", "931511", "Action Force (1983) (Parker Bros) (PAL) [a]", "AKA G.I. Joe - Cobra Strike", "", "", "", "", "", "", "", "", "", "", "", "", "", "01 55", "", "", "", "" }, + { "d57913088e0c49ac3a716bf9837b284f", "Activision, Garry Kitchen", "EAZ-032", "Pressure Cooker (1983) (Activision) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d57eb282d7540051bc9b5427cf966f03", "Atari Troll", "", "Custer's Viagra (Atari Troll) (Hack)", "Hack of Custer's Revenge", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d597d35c6022c590d6e75e865738558a", "", "", "Sprite Color Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d5aa7472e7f2cc17e893a1a36f8dadf0", "", "", "Overhead Adventure Demo 5 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d5c6b81212ad86fd9542a1fedaf57cae", "", "", "Sprite Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d5d2d44fb73785996ccc24ae3a0f5cef", "Robby", "", "Grand Prix (Robby)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d5e17022d1ecc20fd9b53dc464c302f1", "Activision, Carol Shaw", "EAX-020", "River Raid (1982) (Activision) (SECAM)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d5e27051512c1e7445a9bf91501bda09", "Activision, David Crane", "AG-008", "Laser Blast (1981) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d5e5b3ec074fff8976017ef121d26129", "Star Game", "003", "River Raid (Star Game)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d5f965c159e26a1fb49a22a47fbd1dd0", "Supergame", "", "River Raid II (Supergame)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d605ed12f4eaaaec3dcd5aa909a4bad7", "", "", "Chronocolor Frame Demo (10-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d61629bbbe035f45552e31cef7d591b2", "", "", "Atari Logo Demo (PD) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d62283aed0f4199adb2333de4c263e9c", "Atari, Alan J. Murphy, Nick 'Sandy Maiwald' Turner", "CX2615", "Demons to Diamonds (1982) (Atari) (PAL)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "YES", "", "", "10 57", "", "", "", "" }, + { "d62d7d1a974c31c5803f96a8c1552510", "", "", "StarMaster (Unknown) (PAL)", "Use Color/BW switch to change between galactic chart and front views", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d632b74fea533d593af82cf16e7c5e4a", "", "", "Fu Kung! (V0.13) (01-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "d65028524761ef52fbbdebab46f79d0f", "CCE", "", "Galaxian (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d65900fefa7dc18ac3ad99c213e2fa4e", "", "", "Guntest (2000) (Eckhard Stolberg)", "Light Gun Test (based on Sentinel code)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d69559f9c9dc6ef528d841bf9d91b275", "Activision, Alan Miller", "AX-016", "StarMaster (1982) (Activision)", "Use Color/BW switch to change between galactic chart and front views", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d6a44277c3eb4f9d039185e0ecf7bfa6", "", "", "Trick (1997) (Eckhard Stolberg)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d6acff6aed0f04690fe4024d58ff4ce3", "Spectravision - Spectravideo - Quelle", "SA-202 - 412.851 8", "Planet Patrol (1982) (Spectravision) (PAL) [different spaceship]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d6b8beeb05e5b730084d4b8f381bbf8d", "", "", "208 in 1 Game Select ROM (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d6d1ddd21e9d17ea5f325fa09305069c", "Funvision - Fund. International Co.", "", "Time Warp (1982) (Funvision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d6d5dd8fd322d3cf874e651e7b6c1657", "", "", "How to Draw a Playfield (1997) (Nick Bensema) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d6dc9b4508da407e2437bfa4de53d1b2", "Bomb - Onbase", "CA283", "Z-Tack (1983) (Bomb) (PAL)", "AKA Base Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d726621c676552afa503b7942af5afa2", "Atari, Bob Whitehead", "CX26163P", "Blackjack (32 in 1) (1988) (Atari) (PAL) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d73ad614f1c2357997c88f37e75b18fe", "Goliath", "7", "Space Tunnel (1983) (Goliath) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d74a81fcd89c5cf0bd4c88eb207ebd62", "", "", "Poker Squares (V0.00a) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d763e3a9cdcdd56c715ec826106fab6a", "Activision, David Crane", "AG-001", "Dragster (1980) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d7759fa91902edd93f1568a37dc70cdb", "Atari, Robert C. Polaro", "CX26157", "Stunt Cycle (1980) (Atari) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d782543818b6320e4f60d77da2b596de", "Atari", "CX26163P", "Fishing Derby (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d787ec6785b0ccfbd844c7866db9667d", "Retroactive", "", "Qb (V0.04) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "d7891b0faa4c7f764482762d0ed427a5", "", "", "Bars and Text Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d7b2259f6bb57bf37eac82365c1f8ad6", "Parker Brothers, Mike Brodie", "PB5320", "Super Cobra (1983) (Parker Bros) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d7b58303ec8d8c4dbcbf54d3b9734c7e", "", "", "Paddle Demo (Joe Grand) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d7dd56677e4ec1e6627419478a4a9668", "", "", "Shadow Keep (Fixed) (04-03-2003) (Andrew Towers)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d7f5bf138cfc7feab7b8ef1534c8b477", "", "", "Eric Bergstrom's KC-135 (Radar Map) (Aaron Bergstrom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d816fea559b47f9a672604df06f9d2e3", "Atari, Gary Palmer", "CX26163P", "Fun with Numbers (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d81bb6965e6c99b3be99ffd8978740e4", "", "", "Gunfight 2600 - The Final Kernel Part 3 (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d82675ce67caf16afe5ed6b6fac8aa37", "Thomas Jentzsch", "", "Robot City (V0.23) (13-11-2002) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d8295eff5dcc43360afa87221ea6021f", "Spectravideo", "SA-212", "Mangia' (1983) (Spectravideo) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d82c8a58098a6b46c5b81c16180354d1", "Dennis Debro", "", "Climber 5 (30-10-2002) (Dennis Debro) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d85f1e35c5445ac898746719a3d93f09", "Suntek", "SS-034", "Farmyard Fun (1983) (Suntek) (PAL)", "AKA Play Farm", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d86deb100c6abed1588aa84b2f7b3a98", "Atari, Bob Whitehead - Sears", "CX2625 - 6-99827, 49-75114", "Football (1979) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d88691c995008b9ab61a44bb686b32e4", "", "", "Warring Worms (07-02-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d89262907e70c13dff23356c4a9055d0", "Bit Corporation", "R320", "Video Pinball (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d89fedded0436fdeda7c3c37e2fb7cf1", "", "", "Surround (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d8acaa980cda94b65066568dd04d9eb0", "CCE", "", "Sea Hunt (CCE)", "AKA Skindiver", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d8b2c81cea5af04f795eb3dc6573d72b", "", "", "Tunnel Demo 2 (27-03-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d8df256c0d89e494a9fb3e9abb8e44ac", "Imagic, Michael Greene", "IA3312P", "No Escape! (1982) (Imagic) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d8e4c8e2d210270cd1e0f6d1b4582b91", "Imagic, Mark Klein", "EIZ-003-04I", "Subterranea (1983) (Imagic) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d90205e29bb73a4cdf28ea7662ba0c3c", "Thomas Jentzsch", "", "Boulderdash Demo (Brighter Version) (09-12-2002) (TJ)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "d912312349d90e9d41a9db0d5cd3db70", "CCE", "C-818", "Star Voyager (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d9548ad44e67edec202d1b8b325e5adf", "Apollo - Games by Apollo, Dan Oliver - RCA Video Jeux", "AP-2002", "Space Cavern (1982) (Apollo) (PAL)", "AKA Les guerriers de l'espace", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d968de2b4ff18bfe4a95066cde310578", "Thomas Jentzsch", "", "Centipede - Amiga Mouse Hack v1.4 (PAL) (Half-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d97e3d0b4575ce0b9a6132e19cfeac6e", "Fabrizio Zavagli", "", "Space Treat (061002) (PD)", "Won't work with Stella < V1.2", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d97fd5e6e1daacd909559a71f189f14b", "M Network, Steve Crandall, Patricia Lewis Du Long", "MT4646", "Rocky & Bullwinkle (04-20-1983) (M Network) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d9ab6b67a17da51e5ad13717e93fa2e2", "Thomas Jentzsch", "", "Turbo (Coleco) Prototype Fake v0.1 (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d9b49f0678776e04916fa5478685a819", "Activision, John Van Ryzin - Ariola", "EAZ-036-04, EAZ-036-04B, EAZ-036-04I - 711 036-720", "H.E.R.O. (1984) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d9bd343533b61389b270c0787210943b", "Atari, Douglas 'Solaris' Neubauer", "CX26134", "Last Starfighter (1984) (Atari) (Prototype)", "Genesis controller (C switches to map mode)", "Hack of Last Starfighter (Solaris prototype)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "d9c9cece2e769c7985494b1403a25721", "SOLID Corp. (D. Scott Williamson)", "CX2655*", "Star Castle 2600 (SolidCorp)", "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "d9da2ae7c7894a29b43b3c6b79f3b7a2", "Atari, Rob Fulop", "CX2633, CX2633P", "Night Driver (1980) (Atari) (PAL) (4K)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "", "", "AUTO 65", "", "", "YES", "" }, + { "d9fbf1113114fb3a3c97550a0689f10f", "ZiMAG - Emag - Vidco", "713-111 - GN-050", "Pizza Chef (1983) (ZiMAG) (Prototype)", "AKA Pizza Time", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "da0fb2a484d0d2d8f79d6e063c94063d", "", "", "Air Raiders (1982) (Unknown) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "da4e3396aa2db3bd667f83a1cb9e4a36", "Activision, Steve Cartwright", "AX-027", "Plaque Attack (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "da5096000db5fdaa8d02db57d9367998", "Digitel", "", "River Raid (1983) (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "da6465a34d2e44d26aa9a2a0cd1bce4d", "Absolute Entertainment, Alex DeMeo", "AG-041-04", "Title Match Pro Wrestling (1987) (Absolute) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "da66d75e4b47fab99733529743f86f4f", "Digitel", "", "Chopper Command (1983) (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "da732c57697ad7d7af414998fa527e75", "Atari - Glenn Axworthy", "CX26129", "Midnight Magic (1986) (Atari) (PAL)", "AKA Pinball Wizard", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "da79aad11572c80a96e261e4ac6392d0", "Salu - Ubi Soft, Dennis M. Kiss", "460673", "Pick 'n' Pile (1990) (Salu) (PAL)", "", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "YES", "" }, + { "da7a17dcdaa62d6971393c0a6faf202a", "", "", "Flag Capture (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dab844deed4c752632b5e786b0f47999", "", "", "Super Challenge Baseball (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dac38b4dd3da73bb7b2e9d70c61d2b7c", "", "", "Hangman Monkey Biglist3 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dac5c0fe74531f077c105b396874a9f1", "Atari - GCC", "CX2680", "RealSports Tennis (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dac762e4d01d445bdef20b7771f6570e", "Atari, Carla Meninsky, Ed Riddle - Sears", "CX2611 - 99821, 49-75149", "Indy 500 (1977) (Atari) (4K) [a]", "Uses the Driving Controllers", "", "", "", "", "", "", "", "", "DRIVING", "DRIVING", "", "", "", "45", "", "", "", "" }, + { "dad2ab5f66f98674f12c92abcfbf3a20", "", "", "Blue and White Sprite Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "daeb54957875c50198a7e616f9cc8144", "20th Century Fox Video Games, Douglas 'Dallas North' Neubauer", "11005", "Mega Force (1982) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "daef7d8e5a09981c4aa81573d4dbb380", "Adam Thornton", "", "Lord of the Rings (Adam Thornton) (Hack)", "Hack of Dark Mage", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "dafc3945677ccc322ce323d1e9930beb", "Atari", "", "A-Team (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "db1753cc702c18d3917ec7f3b0e8659f", "", "", "Frame Counter 2 (2001) (Jake Patterson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "db339aea2b65b84c7cfe0eeab11e110a", "", "", "Chronocolor Frame Demo 2 (10-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "db4eb44bc5d652d9192451383d3249fc", "CBS Electronics - E.F. Dreyer - VSS, Ed Salvo", "4L 2738 0000", "Mountain King (1983) (CBS Electronics)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "db5073bd75eb05f7d62a7268396d1e77", "Atari", "CX26163P", "Golf (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "db76f7a0819659d9e585f2cdde9175c7", "Xonox", "99005, 6220, 6250", "Robin Hood (1983) (Xonox) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "db80d8ef9087af4764236f7b5649fa12", "M Network, Steve Crandall, Patricia Lewis Du Long", "MT4646", "Rocky & Bullwinkle (1983) (Mattel) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "db971b6afc9d243f614ebf380af0ac60", "Gammation, Robert L. Esken Jr.", "", "Gamma-Attack (1983) (Gammation)", "Uses right joystick controller", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "", "" }, + { "dba270850ae997969a18ee0001675821", "Greg Troutman", "", "Dark Mage (Greg Troutman) (PD) (4K)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "dbabb80e92ff18d8eecf615c0539151e", "", "", "Sprite Demo 3 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dbb10b904242fcfb8428f372e00c01af", "Atari, John Dunn", "CX2631, CX2631P", "Superman (1979) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dbba14a0f69f0e13fdccb3fde3baedca", "Thomas Jentzsch", "", "Reactor - Atari Trak-Ball Hack v1.3 (NTSC) (Full-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dbc7485ad5814d466de780a3e7ed3b46", "Kyle Pittman", "", "Pink Floyd (Kyle Pittman) (PD)", "Hack of Adventures of Tron (Mattel)", "New Release (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dbc8829ef6f12db8f463e30f60af209f", "Data Age", "DA1001", "Encounter at L-5 (1982) (Data Age)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "AUTO 50", "", "", "", "" }, + { "dbdaf82f4f0c415a94d1030271a9ef44", "CCE", "", "Kaboom! (CCE)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, + { "dbdd21e1ee3d72119e8cd14d943c585b", "", "", "Slot Machine (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dc13df8420ec69841a7c51e41b9fbba5", "Atari, Mimi Nyden, Steve Woita", "CX26132", "Garfield (06-21-1984) (Atari) (Prototype)", "AKA Garfield on the Run", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dc33479d66615a3b09670775de4c2a38", "Suntek", "SS-033", "I.Q. Memory Teaser (1983) (Suntek) (PAL)", "AKA IQ 180", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dc81c4805bf23959fcf2c649700b82bf", "Imagic, Michael Greene", "720055-2A, IA3312P", "No Escape! (1983) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dc905b22de0f191a029df13eddfcabc4", "Atari, Warren Robinett", "", "Elf Adventure (05-02-83) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dc97cbcf091a5ef4ca7fe95dc0848036", "Atari - Roklan, Joe Gaucher, Alex Leavens", "CX2683", "Crazy Climber (1983) (Atari) (Prototype) [a2]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dca90ea1084a2fdbe300d7178ca1a138", "Imagic, Dennis Koble", "IA3000P", "Trick Shot (1982) (Imagic) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "dca941dab5c6f859b71883b13ade9744", "", "", "Hangman Pac-Man Biglist2 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dcba0e33aa4aed67630a4b292386f405", "Retroactive", "", "Qb (V2.08) (Half Speed Version) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "dcc2956c7a39fdbf1e861fc5c595da0d", "M Network - INTV - APh Technological Consulting, David Rolfe", "MT5664", "Frogs and Flies (1982) (M Network)", "AKA Frogs 'n' Flies", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dcec46a98f45b193f07239611eb878c2", "", "", "Bars and Text Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dd08e18cfee87a0e7fc19a684b36e124", "Atari - GCC, Kevin Osborn", "CX2689, CX2689P", "Kangaroo (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dd0cbe5351551a538414fb9e37fc56e8", "Xonox - K-Tel Software - Product Guild, Anthony R. Henderson", "99006, 6220", "Sir Lancelot (1983) (Xonox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dd0de0f61af2a2a4878e377b880a3933", "SOLID Corp. (D. Scott Williamson)", "CX2655-013", "Star Castle 2600 (SolidCorp) [013]", "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "dd10b5ee37fdbf909423f2998a1f3179", "", "", "Space Instigators (V1.9) (21-10-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dd13a16d14100819f79b1ce3a5bf499c", "Thomas Jentzsch", "", "Missile Control - Atari Mouse Hack v1.15 (PAL) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dd1422ffd538e2e33b339ebeef4f259d", "Atari, Michael Sierchio", "", "Football Demo (1982) (Atari)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dd17711a30ad60109c8beace0d4a76e8", "", "", "Karate (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dd1842ba0f3f9d94dccb21eaa0f069b7", "Bit Corporation", "R320", "Defender (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dd45e370aceff765f1e72c619efd4399", "Bit Corporation", "PG201", "Sea Monster (1982) (BitCorp)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dd4f4e0fbd81762533e39e6f5b55bb3a", "Thomas Jentzsch", "", "Turbo WIP (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dd7598b8bcb81590428900f71b720efb", "Xonox - K-Tel Software - Computer Magic", "99005, 6220, 6250", "Robin Hood (1983) (Xonox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dd7884b4f93cab423ac471aa1935e3df", "Atari, Brad Stewart - Sears", "CX2649, 49-75163", "Asteroids (1981) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "dd8a2124d4eda200df715c698a6ea887", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (3 of 3) (1982) (Starpath)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dd92d6ad50976f881d86b52d38616118", "SpkSoft", "", "River Raid (SpkSoft) [h1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dda23757407c4e217f64962c87ad0c82", "Atari Freak 1", "", "Nitemare at Sunshine Bowl-a-Rama (Atari Freak 1) (Hack) [a]", "Hack of Pac-Man Jr.", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ddd1efc1862cd3eb3baf4cba81ff5050", "", "", "Max3 (2001) (Maxime Beauvais) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "de0173ed6be9de6fd049803811e5f1a8", "Xonox - K-Tel Software - Product Guild, Anthony R. Henderson", "99008, 6240", "Motocross Racer (1983) (Xonox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "de07e9cb43ad8d06a35f6506e22c62e9", "", "", "Oh No! (Version 4) (22-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "de1a636d098349be11bbc2d090f4e9cf", "", "", "Pressure Gauge (Hozer Video Games)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "de1e9fb700baf8d2e5ae242bffe2dbda", "Activision - Imagineering, Mike Reidel", "EAK-043-04I", "Commando (1988) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "de24f700fd28d5b8381de13abd091db9", "CCE", "", "Plaque Attack (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "de29e46dbea003c3c09c892d668b9413", "Coleco - Woodside Design Associates, Steve 'Jessica Stevens' Kitchen", "4L1717, 4L1718, 4L1719, 4L2277", "Carnival (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "de3d0e37729d85afcb25a8d052a6e236", "Spectravision - Spectravideo", "SA-204", "Tapeworm (1982) (Spectravision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "de4436eaa41e5d7b7609512632b90078", "Activision, David Crane", "AX-014, AX-014-04", "Grand Prix (1982) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "de5aab22e5aba5edcb29a3e7491ff319", "Star Game", "001", "Donkey Kong (Star Game)", "AKA Inca Gold", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "de61a0b171e909a5a4cfcf81d146dbcb", "Rainbow Vision - Suntek", "SS-005", "Tom Boy (1983) (Rainbow Vision) (PAL)", "AKA Pitfall!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "de62f8a30298e2325249fe112ecb5c10", "CCE", "C-810", "Enduro (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "de78b3a064d374390ac0710f95edde92", "Bomb - Onbase", "CA281", "Assault (1983) (Bomb)", "AKA Sky Alien", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "de7a64108074098ba333cc0c70eef18a", "", "", "Nuts (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "de7bca4e569ad9d3fd08ff1395e53d2d", "Thomas Jentzsch", "", "Thrust (V1.22) (2000) (TJ)", "Supports BoosterGrip", "New Release", "", "", "", "", "", "", "", "BOOSTERGRIP", "", "", "", "", "", "", "", "", "" }, + { "de8443ff47283e7b274a7838cb071fb6", "Atari, Lou Harp", "CX26122", "Sinistar (01-04-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dea0ade296f7093e71185e802b500db8", "CCE", "", "Fishing Derby (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "deb39482e77f984d4ce73be9fd8adabd", "Activision, David Lubar", "AK-048-04", "River Raid II (1988) (Activision) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ded26e1cb17f875a9c17515c900f9933", "", "", "Space Treat (29-12-2002) (Fabrizio Zavagli)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "df12953b919844dad2070ed2e70c9fa2", "Amiga - Video Soft", "3135", "S.A.C. Alert (1983) (Amiga) (Prototype) (PAL)", "Uses Joyboard", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "df2745d585238780101df812d00b49f4", "Bit Corporation", "PG202", "Space Tunnel (1982) (BitCorp)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "df3e6a9b6927cf59b7afb626f6fd7eea", "", "", "Tuby Bird (208 in 1) (Unknown) (PAL)", "AKA Dolphin", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "df40af244a8d68b492bfba9e97dea4d6", "Franklin Cruz", "", "Asteroids 2 (Franlin Cruz) (Hack)", "Hack of Asteroids", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "df5cc5cccdc140eb7107f5b8adfacda1", "Cracker Jack Productions", "", "Lumberman (Cracker Jack) (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "df62a658496ac98a3aa4a6ee5719c251", "Atari, Tom Reuterdahl - Sears", "CX2626 - 6-99829, 49-75116", "Miniature Golf (1979) (Atari)", "AKA Arcade Golf", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "df6a28a89600affe36d94394ef597214", "Apollo - Games by Apollo, Dan Oliver", "AP-2002", "Space Cavern (1982) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "df6a46714960a3e39b57b3c3983801b5", "Puzzy - Bit Corporation", "PG201", "Sea Monster (1982) (Puzzy) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "df753cb87d3af4d03f694ab848638108", "CBS Electronics, Bob Curtiss", "4L1845, 4L1852, 4L1853, 4L1854", "Solar Fox (1983) (CBS Electronics) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "df91277a3569344b89e6e8bd5bebc8d1", "Thomas Jentzsch", "", "Marble Craze - Amiga Mouse Hack v1.0 (PAL) (TJ)", "Uses Amiga Mouse Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "df95e4af466c809619299f49ece92365", "Atari - CCW, Michael Callahan, Preston Stuart", "CX26103", "Alpha Beam with Ernie (06-03-1983) (Atari) (Prototype) (PAL)", "Uses Keypad Controllers", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dfad86dd85a11c80259f3ddb6151f48f", "HES - Imagineering, David Lubar", "535", "My Golf (1990) (HES) (PAL) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dfafa3fa58f5cc3f0342cca475df6095", "", "", "Space Treat (V1.1 Beta) (24-12-2002) (Fabrizio Zavagli)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dfc03ef371cf5163f54c50d8ee73c8cf", "Atari, Gary Palmer", "CX2661", "Fun with Numbers (1980) (Atari) (4K)", "AKA Basic Math", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dfc3dbbb39f05d7dd8ee3ac987478970", "", "", "Imagic Selector ROM (1982) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dfcdd6f593bb7b05dbc2e8e1fc6ee0de", "", "", "Gunfight 2600 - Scenarios complete (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dfe034297200dff672df9533ed1449a9", "", "", "Sprite Movement Demo 1 (2001) (Roger Williams)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dfe6aa7443bb813cefa35a4cf4887422", "", "", "This Planet Sucks (Greg Troutman) [a1]", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "dff33523ccd2fdc8912e84cab8e0d982", "", "", "Fu Kung! (V0.03) (10-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e01e00504e6d4b88fa743c0bbe8a96e5", "", "", "Qb (Special Edition, some bugfixes) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "e020f612255e266a8a6a9795a4df0c0f", "Telegames - VSS", "7062 A305", "Universal Chaos (1988) (Telegames) (PAL)", "AKA Targ", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e02156294393818ff872d4314fc2f38e", "Sancho - Tang's Electronic Co.", "TEC005", "Dice Puzzle (1983) (Sancho) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "e0221c95aa657f5764eeeb64c8429258", "", "", "Tomb Raider 2600 [REV 02] (Montezuma's Revenge Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e03b0b091bea5bc9d3f14ee0221e714d", "CBS Electronics, Bob Curtiss", "4L1852, 4L1853, 4L1854, 4L1855", "Solar Fox (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e040df95a055b18ebdb094e904cb71b2", "", "", "Score Demo (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e04f1c1e4401d584d3f4343410a5bcc4", "Wizard Video Games - MicroGraphic Image, Robert Barber, Tim Martin", "007", "Halloween (1983) (Wizard Video Games) (Prototype) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e0b24c3f40a46cda52e29835ab7ad660", "Quelle - Otto Versand", "626.502 9 - 746381", "Top Gun (1983) (Quelle) (PAL)", "AKA Air Raiders", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e0cf2dcc4c1348c468f5bb1e421c9164", "", "", "Invader Sprites in a Line Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e0de3773f5b867795db557be7b8a703e", "", "", "Boulderdash (13 Blocks Wide) (02-04-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e0eff071f578ecf19edc2ab276644e46", "", "", "Gas Gauge Demo (2001) (Joe Grand) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e1029676edb3d35b76ca943da7434da8", "Atari, Robert C. Polaro, Alan J. Murphy - Sears", "CX2609 - 49-75186", "Defender (10-30-1981) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e10bf1af6bf3b4a253c5bef6577fe923", "Rob Kudla", "", "Space Invaders (1978) (Atari) [h1]", "Hack of Space Invaders (Atari)", "New Release (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e10d2c785aadb42c06390fae0d92f282", "Parker Brothers, Dawn Stockbridge", "PB5910", "Strawberry Shortcake - Musical Match-Ups (1983) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e1143b72a30d4d3fee385eec38b4aa4d", "", "", "Word Zapper (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e12e32dee68201b6765fcd0ed54d6646", "Atari, Larry Kaplan", "CX2612, CX2612P", "Street Racer (1977) (Atari) (PAL)", "Uses the Paddle Controllers (swapped)", "", "", "", "", "", "", "", "", "", "", "YES", "", "", "AUTO 75", "", "", "", "" }, + { "e13818a5c0cb2f84dd84368070e9f099", "CCE", "C-839", "Misterious Thief, A (1983) (CCE)", "AKA A Mysterious Thief", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "e13c7627b2e136b9c449d9e8925b4547", "Atari, Alan Miller - Sears", "CX2624 - 6-99826, 49-75113", "Basketball (1978) (Atari) (4K)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e1486c7822c07117b4f94a32e5ed68c1", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (06-14-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e14dc36b24fe22c04fa076e298f2e15f", "Activision, Larry Kaplan, David Crane", "AG-010, AG-010-04", "Kaboom! (1981) (Activision) (16K)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, + { "e14feddeb82f5160ed5cf9ca4078e58d", "", "", "SpaceMaster X-7 (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e150f0d14f013a104b032305c0ce23ef", "Spectravision - Spectravideo", "SA-205", "China Syndrome (1982) (Spectravision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "e15b5525cf8f77297b322838df8d999c", "", "", "Sprite Demo 0 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e171558c51bb3bac97bfa79fa2c1a19c", "", "", "Warring Worms (Tim Strauss Edition) (20-12-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e17699a54c90f3a56ae4820f779f72c4", "Rainbow Vision - Suntek", "SS-020", "Tuby Bird (1983) (Rainbow Vision) (PAL)", "AKA Dolphin", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e18abe87035379c56b435bfe8175077b", "Grimlock", "", "Rumble 2600 (Grimlock) (Hack)", "Hack of Mario Bros.", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e1a51690792838c5c687da80cd764d78", "20th Century Fox, John Russell", "", "Alligator People (1983) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e1b90f1e01b1a316d7bbf141525cc00e", "", "", "Sky Jinks (Unknown) (PAL) (4K) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e1d5c8213e82820128fa9c4775f1e166", "Jess Ragan", "", "Jungle King (2003) (Jess Ragan) (Hack)", "Hack of Jungle Hunt", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e1d79e4e7c150f3861256c541ec715a1", "", "", "Space Jockey (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e1e09e2f280e8e142121a377d0dc1b46", "Thomas Jentzsch", "", "Thrust (V1.21) (2000) (TJ)", "Bugfixed", "New Release", "", "", "", "", "", "", "", "BOOSTERGRIP", "", "", "", "", "", "", "", "", "" }, + { "e1efe2ef7664bb6758b1a22ff8ea16a1", "Dynacom", "", "Enduro (1983) (Dynacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e1f88da6da8a7d521ca1dcbf2bc6978b", "Activision, Bob Whitehead - Ariola", "EAG-005, PAG-005, EAG-005-04B - 711 005-715", "Skiing (1980) (Activision) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e21ee3541ebd2c23e817ffb449939c37", "Tigervision - Software Electronics Corp., Karl T. Olinger - Teldec", "7-001", "King Kong (1982) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e227be19f572f6900e314213ae9a4deb", "Atari, Dan Hitchens, Mimi Nyden", "CX2656", "SwordQuest - EarthWorld (1982) (Atari) (Prototype)", "AKA Adventure I, SwordQuest I - EarthWorld", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e237ee91514d5ed535c95a14fc608c11", "Activision, Matthew L. Hubbard, Bob Whitehead", "AX-024", "Dolphin (1983) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e2389c0be5b5b84e0d3ca36ec7e67514", "Retroactive", "", "Qb (V2.09) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "e24d7d879281ffec0641e9c3f52e505a", "Parker Brothers, Mark Lesser", "PB5950", "Lord of the Rings (1983) (Parker Bros) (Prototype)", "Journey to Rivendell (The Lord of the Rings I)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e25e173740f7ecc0e23025445c4591f3", "Greg Zumwalt", "", "Comitoid (Greg Zumwalt)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e275cbe7d4e11e62c3bfcfb38fca3d49", "M Network - INTV - APh Technological Consulting, Ken Smith", "MT5658", "Super Challenge Football (1982) (M Network)", "AKA Pro Football", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e27d518993b0a010f16e92b971ecdcdd", "Manuel Polik", "", "Star Fire (2003) (XYPE) (PAL)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e28113d10c0c14cc3b5f430b0d142fcb", "CCE", "C-816", "Keystone Kappers (1983) (CCE) [a]", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e2846af3e4d172b251ab77cbdd01761e", "Steve Engelhardt", "", "Adventure Plus (2003) (Steve Engelhardt) (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e2904748da63dfefc8816652b924b642", "Jone Yuan Telephonic Enterprise Co", "", "Catch Time (Jone Yuan)", "AKA Plaque Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e2b682f6e6d76b35c180c7d847e93b4f", "", "", "Dodge Demo 4 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e2c1b60eaa8eda131632d73e4e0c146b", "Atari - GCC, Mark Ackerman, Noellie Alito", "CX2692", "Moon Patrol (07-04-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e2c89f270f72cd256ed667507fa038a2", "Starpath Corporation, Stephen H. Landrum", "AR-4101", "Communist Mutants from Space (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e2ca84a2bb63d1a210ebb659929747a9", "Telesys, Don 'Donyo' Ruffcorn", "1002", "Cosmic Creeps (1982) (Telesys) (PAL)", "AKA Space Maze, Spaze Maze", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "e2eccbbe963f80f291cb1f18803bf557", "Atari, Joe Decuir, Steve Mayer, Larry Wagner", "CX26163P", "Combat (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e30f3a37032da52d7815b5a409f6d4b4", "SEGA, Fred Mack", "", "Bear Game Demo (1983) (SEGA)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e314b42761cd13c03def744b4afc7b1b", "Activision, David Crane, Dan Kitchen", "AZ-108-04", "Ghostbusters (1985) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e34c236630c945089fcdef088c4b6e06", "Activision, Steve Cartwright, David Crane - Ariola", "EAB-035-04 - 711 035-721", "Pitfall II (1984) (Activision) (PAL)", "Lost Caverns", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e3533684a7ef930a7fbd0c4dd8ec4847", "CCE", "C-856", "Pimball (1983) (CCE)", "AKA Video Pinball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e3600be9eb98146adafdc12d91323d0f", "Atari, Carol Shaw", "CX2618, CX2618P", "3-D Tic-Tac-Toe (1980) (Atari) (PAL)", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e363e467f605537f3777ad33e74e113a", "Atari, Bob Whitehead - Sears", "CX2603 - 99803, 49-75601", "Star Ship (1977) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e377c3af4f54a51b85efe37d4b7029e6", "20th Century Fox Video Games, Beck-Tech, Steve Beck", "11035", "Save the Whales (1983) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e37c8055d70979af354251ebe9f1b7dd", "HES", "", "Mega Funpak - Gorf, P. Patrol, Pacman, Skeet Shoot (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e38dc1f81a02e325562cd285123f579b", "Atari - GCC, Mike Feinstein", "CX2681, CX2681P", "Battlezone (1983) (Atari) (PAL) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e39843c56b7a4a08b18fa7949ec3ee6b", "", "", "Joshua Invaders (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e39a13b13dc82c5fdbfbbfd55ba1230e", "", "", "Analog Clock (Additional Frame Info) (V0.0) (20-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e3c0451d29dad724231bc5818ec4bae0", "", "", "Single-Scanline Positioning Demo 1 (2001) (Roger Williams)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e3c35eac234537396a865d23bafb1c84", "TechnoVision - Video Technology", "TVS1001", "Nuts (1983) (TechnoVision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e3ed4ba3361756970f076e46e9cad1d2", "", "", "Tennis (Unknown) (PAL) (4K) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e40a818dac4dd851f3b4aafbe2f1e0c1", "Atari, Bill Aspromonte, Dr. Lee Salk", "CX26135", "Peek-A-Boo (1984) (Atari) (Prototype)", "Uses the Keypad Controllers", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e42b937c30c617241ca9e01e4510c3f6", "", "", "Pitfall! (No Walls Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e434c0e161dd3c3fb435eb6bad2e182c", "Atari - GCC, Mike Feinstein, Brad Rice", "CX2681", "Battlezone (05-02-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e48d3a4056ede9393586421996db1ae8", "Thomas Jentzsch", "", "Centipede - Atari Trak-Ball Hack v1.4 (PAL60) (Full-Speed) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e49ac0ec879a0d7820bc2598fc2cfcd4", "CCE", "", "Kaboom! (CCE) (4K)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, + { "e4a0b28befaaa2915df1fa01238b1e29", "", "", "Gunfight 2600 - Red River (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e4afe157c09962cf39cdb25845d83d47", "Activision, David Crane - Ariola", "EAG-009, PAG-009 - 711 009-720", "Freeway (1981) (Activision) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e4b12deaafd1dbf5ac31afe4b8e9c233", "Adam Thornton", "", "Lord of the Rings (Adam Thornton) (Hack) [a]", "Hack of Dark Mage", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "e4bff1d5df70163c0428a1ead309c22d", "Atari, Robert C. Polaro, Alan J. Murphy", "CX2609, CX2609P", "Defender (1982) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e4c00beb17fdc5881757855f2838c816", "20th Century Fox Video Games - Sirius, Ed Hodapp", "11004", "Deadly Duck (1982) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e4c2077a18e3c27f4819aa7757903aa0", "", "", "Many Blue Bars Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e5359cbbbff9c6d7fe8aeff5fb471b46", "CCE", "C-849", "Boom Bang (1983) (CCE)", "AKA Crackpots", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e549f1178e038fa88dc6d657dc441146", "Atari, Bob Whitehead - Sears", "CX2625 - 6-99827, 49-75114", "Football (1979) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e556e07cc06c803f2955986f53ef63ed", "Coleco - Individeo, Ed Temple", "2665", "Front Line (1984) (Coleco)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e558be88eef569f33716e8e330d2f5bc", "Shock Vision", "", "Keystone Kapers (Shock Vision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e56da674188ba2f02c7a0a343a01236f", "", "", "This Planet Sucks Demo 4 (Greg Troutman) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e59d022d524d05acc19515598c831e4d", "Alessandro Ciceri", "", "MagiCard+ (alex_79) WIP_20150118 (PAL)", "MagiCard hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e5a6e0bb7d56e2f08b237e15076e5699", "", "", "Color Table Display Helper (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e5bacf526036d3c8c99db5b030cf00e7", "", "", "Starmaster (Genesis)", "Genesis controller (C switches to map mode)", "Hack of Starmaster", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e5d5085123a98c1e61818caa2971e999", "", "", "Euchre (PAL) (Erik Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e5d72ff8bab4450be57785cc9e83f3c0", "Telegames", "6082 A145", "Kung Fu Superkicks (1988) (Telegames) (PAL)", "AKA Chuck Norris Superkicks", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e5ecd78edd24326a968809decbc7b916", "Imagic, Bob Smith", "720020-1A, IA3611", "Cheese (Dragonfire Beta) (05-21-1982) (Imagic) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "e5f17b3e62a21d0df1ca9aee1aa8c7c5", "CommaVid, John Bronstein", "CM-003", "Cosmic Swarm (1982) (CommaVid)", "AKA Termite", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "e5f360226dc552aba3e7e9b202330f48", "Supercat", "", "Mega Bitmap Demo (2007) (Supercat)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "e5f84930aa468db33c0d0f7b26dd8293", "CCE", "C-826", "Grand Prix (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e5fcc62e1d73706be7b895e887e90f84", "", "", "Air-Sea Battle (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e600f5e98a20fafa47676198efe6834d", "Parker Brothers - Roklan, Joe Gaucher", "PB5080", "Gyruss (1984) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "e609e8a007127b8fcff79ffc380da6b1", "", "", "Multi-Sprite Game V2.3 (Piero Cavina) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e61210293b14c9c4ecc91705072c6a7e", "Gameworld", "133-005", "Bugs (1983) (Gameworld) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "AUTO 50", "", "", "", "" }, + { "e62e60a3e6cb5563f72982fcd83de25a", "Jone Yuan Telephonic Enterprise Co", "", "End of the World (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e63a87c231ee9a506f9599aa4ef7dfb9", "Tigervision, Warren Schwader", "7-003", "Threshold (1982) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e63efdfda9a4003dcd77a854a781a06a", "Paul Slocum", "", "Combat Rock (PD) (Hack) [a]", "Hack of Combat", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e643aaec9a9e1c8ab7fe1eae90bc77d7", "Roger Williams", "", "Asymmetric Playfield (Roger Williams)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e64a8008812327853877a37befeb6465", "Answer Software Corporation - TY Associates, Mike Wentz", "ASC1002", "Gauntlet (1983) (Answer Software)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e6508b878145187b87b9cded097293e7", "", "", "Oystron (V2.8) (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e66e5af5dea661d58420088368e4ef0d", "Activision, Bob Whitehead", "AG-011", "Stampede (1981) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e67b0ed32fd9d28d12ab3775d52e8c3a", "Atari, Omegamatrix", "", "Video Olympics Menu (2020) (Hack)", "Hack of Video Olympics", "", "", "", "", "", "", "", "", "", "", "YES", "", "", "AUTO 60", "", "", "", "" }, + { "e6d5948f451a24994dfaaca51dfdb4e1", "Jone Yuan Telephonic Enterprise Co", "", "Football (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e6de4ef9ab62e2196962aa6b0dedac59", "Imagic, Wilfredo Aguilar, Michael Becker, Dennis Koble", "720113-2A, 13206", "Solar Storm (1983) (Imagic) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "01 45", "", "", "", "" }, + { "e6e5bb0e4f4350da573023256268313d", "Thomas Jentzsch", "", "Missile Control (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e6f49a1053c79211f82be4d90dc9fe3d", "", "", "Gunfight 2600 - Little progress... (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e723ad8f406cb258b89681ef4cef0eff", "Thomas Jentzsch", "", "Sadoom (TJ) (PAL) (Hack)", "Hack of Kaboom!", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, + { "e72eb8d4410152bdcb69e7fba327b420", "Atari, Douglas Neubauer, Mimi Nyden", "CX26136", "Solaris (1986) (Atari)", "AKA Universe, Star Raiders II, The Last Starfighter", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e72ee2d6e501f07ec5e8a0efbe520bee", "Imagic, Dave Johnson", "720119-2A, 13211, EIX-004-04I", "Quick Step! (1983) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e73838c43040bcbc83e4204a3e72eef4", "CCE", "", "Apples and Dolls (CCE)", "AKA Open, Sesame!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "e74022cfe31ec8908844718dfbdedf7a", "", "", "Space Treat (30-12-2002) (Fabrizio Zavagli) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e77ec259e1387bc308b0534647a89198", "Parker Brothers, David Lamkins, Laura Nikolich", "931503", "Spider-Man (1982) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e77f332b71f13884c84771e7a121182d", "Jone Yuan Telephonic Enterprise Co", "", "Hey! Stop! (Jone Yuan)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e784a9d26707cfcd170a4c1c60422a72", "Quelle", "147.443 6", "Gefecht im All (1983) (Quelle) (PAL)", "AKA Space Jockey", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e7864caaf9ec49ed67b1904ce8602690", "", "", "Donkey Kong 2K3 Pic (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e7a758bb0b43d0f7004e92b9abf4bc83", "", "", "Troll's Adventure (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e7dd8c2e6c100044002c1086d02b366e", "Activision, Steve Cartwright - Ariola", "EAX-013, PAX-013, 711 013-720", "Barnstorming (1982) (Activision) (PAL)", "AKA Die tollkeuhnen Flieger", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e7f005ddb6902c648de098511f6ae2e5", "Spectravideo - Universum", "SV-010", "CompuMate (1983) (Spectravideo) (PAL)", "", "", "", "", "CM", "", "", "", "", "COMPUMATE", "COMPUMATE", "", "", "", "", "", "", "YES", "80" }, + { "e800e4aec7c6c54c9cf3db0d1d030058", "", "", "Qb (2.06) (Retroactive) (Stella)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "e80a4026d29777c3c7993fbfaee8920f", "", "", "Frisco (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e823b13751e4388f1f2a375d3560a8d7", "Arcadia Corporation, Stephen Harland Landrum", "AR-4105", "Official Frogger (Preview) (1983) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e879b7093ac4cfad74c88d636ca97d00", "", "", "Poker Squares (V0.0f) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e88340f5bd2f03e2e9ce5ecfa9c644f5", "", "", "Lock 'n' Chase (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e8a3473bf786cf796d1336d2d03a0008", "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart", "PB5540", "Star Wars - The Arcade Game (12-05-1983) (Parker Bros) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "e8aa36e3d49e9bfa654c25dcc19c74e6", "Atari, Joe Decuir, Larry Caplan, Steve Mayer, Larry Wagner", "CX2601, CX2601P", "Combat (1977) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e8e7b9bdf4bf04930c2bcaa0278ee637", "", "", "Boring Taz (Hack)", "Hack of Taz", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e8f7679359c4f532f5d5e93af7d8a985", "", "", "Hangman Invader Original Words (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e9034b41741dcee64ab6605aba9de455", "Digivision", "", "Phanton Tank (Digivision)", "AKA Phantom Tank", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e908611d99890733be31733a979c62d8", "Atari, Dan Hitchens, Mimi Nyden", "CX2697", "Mario Bros. (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e91d2ecf8803ae52b55bbf105af04d4b", "Atari, Howard Scott Warshaw", "CX2655, CX2655P", "Yars' Revenge (1982) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "e923001015bedd7901569f035d9c592c", "", "", "Adventure II (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e927ecf80f3784d745abd8368d78f2f3", "", "", "Space Instigators (V1.8) (19-10-2002) (CT) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e932f44fad2a66b6d5faec9addec208e", "", "", "Atari Logo Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e94632b0d863dd76459d689a9865bb33", "Jone Yuan Telephonic Enterprise Co", "", "Combat (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e957eb4612d6bd5940d3492dfa749668", "", "", "Tunnel Demo (27-03-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e959b5a2c882ccaacb43c32790957c2d", "", "", "Phantom II & Pirate (NTSC)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e97eafd0635651d3999cece953c06bd5", "", "", "M.A.S.H (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e9be3e8e4a7e73dd63ed4235a3a1a25f", "", "", "MMetall (Hack)", "Hack of Miniature Golf", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e9c5d04643855949a23ff29349af74ea", "", "", "SCSIcide (Score Hack 2) (24-02-2001) (Joe Grand) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e9c71f8cdba6037521c9a3c70819d171", "Action Hi Tech - Hi-Score", "", "Bank Heist (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e9cb18770a41a16de63b124c1e8bd493", "Parker Brothers - Roklan, Joe Gaucher", "931519", "Popeye (1983) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "e9db2f91efe6ff7ea3546e2c2578fb09", "Omegamatrix", "", "Millipede (Atari Mouse) v6.5 (Omegamatrix)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "" }, + { "e9e646f730b8400cd5da08c849ef3e3b", "Tron", "", "Enduro (Tron)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e9e6ad30549a6e2cd89fe93b7691d447", "Atari - Bobco, Robert C. Polaro", "CX26140, CX26140P", "Desert Falcon (05-27-1987) (Atari) (Prototype) (PAL)", "AKA Nile Flyer, Sphinx", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "e9f25c7af4f27c9e1b5b8f6fe6141e8c", "Champ Games", "CG-03-N", "Scramble (NTSC)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "JOYSTICK", "", "", "", "", "", "", "", "YES", "" }, + { "ea38fcfc06ad87a0aed1a3d1588744e4", "Atari, Lou Harp", "CX26122", "Sinistar (01-XX-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ea6d40db5498d6386571a76df448aa4c", "", "", "Vertical Playfield Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ea7e25ade3fe68f5b786ee0aa82b1fe5", "", "", "Galatic (208 in 1) (Unknown) (PAL)", "AKA Challenge of.... Nexar, The", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ea832e2cb6aae6f525f07452c381fa48", "", "", "Polar to Cartesian and VV (2001) (Roger Williams)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ea86176b27ab0da8cce8f0179884bfaa", "", "", "Demo Image Series #10 - It's Art (28-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "eaacfcdc1d4ee1258429b7ae7f084125", "Telegames", "6057 A227", "Quest for Quintana Roo (1989) (Telegames)", "Genesis controller (B is action button, C chooses tool or weapon)", "Hack of Quest for Quintana Roo", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ead60451c28635b55ca8fea198444e16", "Sancho - Tang's Electronic Co.", "TEC004", "Nightmare (1983) (Sancho) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "eada0dd61ce13f8317de774dc1e68604", "", "", "2600 Digital Clock (Demo 1) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "eae0c06ee61c63b81cd016096fc901b0", "Joe Grand", "", "SCSIcide (v1.0) (2001) (Joe Grand)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "eae6a5510055341d3abeb45667bb3e9b", "HES", "", "Wall Defender (HES) (PAL)", "AKA Wall Break (Planet Patrol if right difficulty = 'A')", "", "", "0", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "eaf744185d5e8def899950ba7c6e7bb5", "Atari", "CX26172", "Xenophobe (1991) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "eafe8b40313a65792e88ff9f2fe2655c", "Eric Ball", "ELB004", "Skeleton+ (NTSC)", "Stereo sound", "Homebrew", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "eb3d680699f8762f71f38e28e321234d", "", "", "Fu Kung! (V0.01) (08-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "eb4252faff7a4f2ba5284a98b8f78d1a", "", "", "John K Harvey's Equalizer (NTSC) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "eb46e99ec15858f8cd8c91cef384ce09", "Goliath - Hot Shot", "83-113", "Ground Zero (1983) (Goliath) (PAL)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "eb503cc64c3560cd78b7051188b7ba56", "Star Game", "043", "Moto Laser (Star Game)", "AKA Mega Force", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "eb634650c3912132092b7aee540bbce3", "Atari, Eric Manghise, Mimi Nyden, Joseph Tung", "CX2640", "RealSports Baseball (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "eb6d6e22a16f30687ade526d7a6f05c5", "Atari", "CX26150P", "Q-bert (1987) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "eb71743c6c7ccce5b108fad70a326ad9", "", "", "Euchre (25-11-2001) (Erik Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "eb7934360658a29c50aeaff20bfda23b", "Activision, John Van Ryzin", "EAZ-036-04", "H.E.R.O. (1984) (Activision) (SECAM)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "eb92193f06b645df0b2a15d077ce435f", "Starpath Corporation, Steve Hales, Stephen H. Landrum", "4 AR-4102", "Suicide Mission (1982) (Starpath) (PAL)", "AKA Meteoroids", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "eb9712e423b57f0b07ccd315bb9abf61", "Retroactive", "", "Qb (V2.04) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "eb9f8b84c193d9d93a58fca112aa39ed", "", "", "Register Twiddler Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ebcb084a91d41865b2c1915779001ca7", "JVP", "", "Bob Is Going Home (JVP)", "AKA Bobby Is Going Home", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ebcbc8a181a738e13df6216e5c329230", "Activision, Steve Cartwright", "AX-022", "Seaquest (1983) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ebd2488dcace40474c1a78fa53ebfadf", "Skill Screen Games, Herman Quast", "SSG001", "Extra Terrestrials (1984) (SSG)", "The only Canadian-designed and manufactured Atari 2600 game from the 1980's", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ebdc5716b85c4ff44fa357cb697d6cef", "Thomas Jentzsch", "", "Centipede - Amiga Mouse Hack v1.4 (NTSC) (Half-Speed) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ebf2dff78a08733251bf3838f02f7938", "Commavid, Ben Burch", "CM-010", "Rush Hour (1983) (Commavid) (Prototype) [a2]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ebf9038e927e6a0db3e0d170c59911e6", "", "", "Pac-2600 (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ec3beb6d8b5689e867bafb5d5f507491", "U.S. Games Corporation - Vidtec - JWDA, Todd Marshall, Henry Will IV", "VC1003", "Word Zapper (1982) (U.S. Games)", "AKA Word Grabber", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ec407a206b718a0a9f69b03e920a0185", "Quelle", "876.482 1", "Landung in der Normandie (1983) (Quelle) (PAL)", "AKA Commando Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ec5c861b487a5075876ab01155e74c6c", "Apollo - Games by Apollo, Ed Salvo, Byron Parks", "AP-2001", "Spacechase (1982) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ece463abde92e8b89bcd867ec71751b8", "Puzzy - Bit Corporation", "PG205", "Dancing Plate (1982) (Puzzy) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "ece908d77ab944f7bac84322b9973549", "", "", "Tom Boy (Unknown) (PAL60)", "AKA Pitfall!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ecf51385384b468834611d44a8429c03", "20th Century Fox Video Games, Douglas 'Dallas North' Neubauer", "11105", "Mega Force (1982) (20th Century Fox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ecfa04523dde82fe42cdc7315a8f61b6", "Activision, David Crane - Ariola", "EAG-004, PAG-004 - 711 004-715", "Fishing Derby (1980) (Activision) (PAL) (4K)", "AKA Schneller als der Hai", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ed014beeeb77dbb2bbcf9b5f6850b2f4", "", "", "Green Bar Text Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ed0451010d022b96a464febcba70b9c4", "PlayAround - J.H.M.", "203", "Knight on the Town (1982) (PlayAround) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "ed0ab909cf7b30aff6fc28c3a4660b8e", "Panda", "105", "Stunt Man (1983) (Panda)", "AKA Nightmare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ed1306436ce237afc5a7ed3f77134202", "HES", "771-341", "2 Pak Special - Dolphin, Pigs n' Wolf (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ed1492d4cafd7ebf064f0c933249f5b0", "CCE", "", "Video Cube (CCE)", "AKA Atari Video Cube", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ed1a784875538c7871d035b7a98c2433", "Bit Corporation", "R320", "Save Our Ship (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ed2218b3075d15eaa34e3356025ccca3", "Atari, Richard Maurer", "CX2635, CX2635P", "Maze Craze (1980) (Atari) (PAL)", "AKA A Game of Cops 'n Robbers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ed5ccfc93ad4561075436ee42a15438a", "Atari, Tom Reuterdahl", "CX2626, CX2626P", "Miniature Golf (1979) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ed8f319e82d355832195eb7715644795", "Activision, Larry Kaplan, David Crane", "AG-010, AG-010-04", "Kaboom! (1981) (Activision) (8K)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, + { "eddef10fdc0029301064115ae0cd41d4", "CCE", "", "Freeway (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ede4ab11ca346bd023b2c21d941e0c50", "Activision, David Crane", "EAZ-030", "Decathlon (1983) (Activision) (SECAM)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ede7e8bf865b0afb4744f86d13624f9a", "", "", "Demo Image Series #2 - Clown (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "edf69b123e06eaf8663cc78d8aeba06e", "SpkSoft 98", "", "River Raid (SpkSoft 98) [h1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ee28424af389a7f3672182009472500c", "Atari, Carol Shaw - Ralph Lauren", "", "Polo (1978) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ee456542b93fa8d7e6a8c689b5a0413c", "", "", "Chronocolor Donkey Kong Clean (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ee4c186123d31a279ed7a84d3578df23", "Atari, Carol Shaw, Nick 'Sandy Maiwald' Turner", "CX2608", "Super Breakout (1982 - 1981) (Atari) (PAL)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "", "", "01 45", "", "", "", "" }, + { "ee659ae50e9df886ac4f8d7ad10d046a", "Exus Corporation", "", "Video Reflex (1983) (Exus)", "AKA Foot Craz", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ee6665683ebdb539e89ba620981cb0f6", "Coleco", "2658", "Berenstain Bears (1983) (Coleco)", "Uses the KidVid Controller", "Unbelievably Rare", "", "", "", "A", "", "", "", "", "KIDVID", "", "", "", "", "", "", "", "" }, + { "ee67dc0b01746372d2b983d88f48e24f", "", "", "Scroller Demo (02-01-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ee681f566aad6c07c61bbbfc66d74a27", "Activision", "", "Unknown Activision Game (10-29-1982) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ee6cbedf6c0aac90faa0a8dbc093ffbe", "CCE", "", "My Golf (CCE) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ee8027d554d14c8d0b86f94737d2fdcc", "Canal 3 - Intellivision", "", "Yars' Revenge (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "ee84bdc5dae268e227e407c7b5e6b6b7", "", "", "Marilyn Monroe Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ee9caee4eb958284fb10c277b14537f1", "Carrere Video, Garry Kitchen - Teldec", "USC1001", "Space Jockey (1983) (Carrere Video) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "eea0da9b987d661264cce69a7c13c3bd", "Coleco", "2454", "Zaxxon (1983) (Coleco)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "eeb92f3f46df841487d1504f2896d61a", "Cody Pittman", "", "Corys Adventure (Cody Pittman) (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "eec61cc4250df70939d48fe02d7122ac", "Activision, Bob Whitehead - Ariola", "EAG-005, PAG-005, EAG-005-04B - 711 005-715", "Skiing (1980) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "eed9eaf1a0b6a2b9bc4c8032cb43e3fb", "Atari - Axlon, Steve DeFrisco", "CX26192", "Klax (1991) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "eee7695ae3eea7818321df0b790b31f3", "", "", "Sound Paddle V2 (Dennis Caswell & Jim Nitchals) (PD)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "01", "", "", "", "" }, + { "ef263d40a23483ab339cac44d9515a56", "Thomas Jentzsch", "", "Fatal Run (TJ)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ef3a4f64b6494ba770862768caf04b86", "Activision, Bob Whitehead", "AG-034-04", "Private Eye (1984) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ef60b06fddb675b0d783afbfa5fc5232", "", "", "Many Blue Bars and Text Demo 4 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ef66af190840871409fe1702d2483554", "Andrew Davie, Paul Slocum, Christopher Tumber", "", "DiscoTech (12-02-2003) (Andrew Davie)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ef71e9fb0d8d477226d8d42261fbf0a7", "Piero Cavina", "", "Multi-Sprite Demo V2.0 (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ef76ea05655a0b62cb1018c92b9b4b7d", "Gakken", "010", "Strategy X (1983) (Gakken) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "efa1098c7d091b940c2543abe372f036", "Scott Stilphen", "", "E.T. The Extra-Terrestrial (Scott Stilphen) (Hack)", "Hack of E.T. The Extra-Terrestrial", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "efb47d70b2965ce689e2c5757616b286", "", "", "Time Test Demo (Eckhard Stolberg) (PAL) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "efd387430a35a659ff569a9a0ec22209", "Atari - GCC", "CX26118", "Millipede (1984) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "efefc02bbc5258815457f7a5b8d8750a", "CBS Electronics, Richard K. Balaska Jr.", "4L 2520 5000", "Tunnel Runner (1983) (CBS Electronics) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "effa3a7ce078c6d83bf43174a7bfdb1f", "Thomas Jentzsch", "", "Centipede - Atari Mouse Hack v1.4 (NTSC) (Half-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "efffafc17b7cb01b9ca35324aa767364", "", "", "Circus Atari (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f02ba8b5292bf3017d10553c9b7b2861", "Atari", "CX26172", "Xenophobe (1991) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f032b2f2d8323404a6b4541f92dd1825", "", "", "Many Blue Bars and Text Demo 3 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f047df70d3d08e331122cd2de61d6af8", "Dave Neuman", "", "Space Battle (NTSC)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f04ee80011d95798006378643650aaa7", "Atari, Bill Aspromonte, John Russell, Michael Sierchio, Robert Zdybel", "CX26114", "Pigs in Space (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f0510abbfbe24ead552e92e3841f63f3", "Thomas Jentzsch", "", "Reactor - Atari Mouse Hack v1.3 (NTSC) (Full-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f0536303f49006806bac3aec15738336", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (4 of 4) (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f0541d2f7cda5ec7bab6d62b6128b823", "Atari, Paul Donaldson", "", "Bionic Breakthrough (1984) (Atari) (Prototype)", "Uses Mindlink Controller (left only)", "Prototype", "", "", "", "", "", "", "", "MINDLINK", "", "", "", "", "", "", "", "", "" }, + { "f060826626aac9e0d8cda0282f4b7fc3", "Atari, David Crane - Sears", "CX2605 - 6-99822, 49-75109", "Outlaw (1978) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f0631c6675033428238408885d7e4fde", "Paul Slocum", "", "Test Cart (2002) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "f066bea7ab0a37b83c83c924a87c5b67", "", "", "Air Raiders (1982) (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f0a6e99f5875891246c3dbecbf2d2cea", "Atari, James Andreasen - Sears", "CX2654 - 49-75141", "Haunted House (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f0b7db930ca0e548c41a97160b9f6275", "Atari, Larry Wagner, Bob Whitehead - Sears", "CX2645 - 49-75181", "Video Chess (1979) (Atari)", "AKA Computer Chess", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f0cacae1d1b79ee92f0dc035f42e0560", "", "", "Boring Donkey Kong (Hack)", "Hack of Donkey Kong", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f0d393dbf4164a688b2346770c9bbd12", "", "", "Racquetball (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "f0daaa966199ef2b49403e9a29d12c50", "", "", "Mr. Postman (Unknown)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f0de4f49e95d529569e8788d5a7b4d30", "Thomas Jentzsch", "", "Reactor - Atari Mouse Hack v1.3 (PAL60) (Full-Speed) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f0e0addc07971561ab80d9abe1b8d333", "Imagic, Rob Fulop", "720000-200, 720101-1B, 720101-1C, IA3200, IA3200C, IX-006-04", "Demon Attack (1982) (Imagic)", "AKA Death from Above", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f0ef9a1e5d4027a157636d7f19952bb5", "Atari - Axlon, Tod Frye - Heuristica, Agustin Ortiz", "CX26169", "Shooting Arcade (03-07-1989) (Atari) (Prototype) [a5]", "Uses the Light Gun Controller (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f10e3f45fb01416c87e5835ab270b53a", "Suntek", "SS-024", "Ski Run (1983) (Suntek) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f1127ade54037236e75a133b1dfc389d", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (Preview) (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f11cfab087fcbd930ab8b0becc5b2e5a", "Canal 3 - Intellivision", "", "River Raid (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f12afbffa080dd3b2801dd14d4837cf6", "Atari, Michael Kosaka, Peter C. Niday, Robert Vieira", "CX26110", "Crystal Castles (01-04-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "f137211537438b1fce3d811baef25457", "", "", "Incoming (02-10-2002) (Ben Larson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f1489e27a4539a0c6c8529262f9f7e18", "Champ Games", "CG-01-P", "Lady Bug (PAL60)", "", "Homebrew", "", "", "", "", "A", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "f14d5e96ec3380aef57a4b70132c6677", "Goliath - Hot Shot", "83-414", "Pac Kong (1983) (Goliath) (PAL)", "AKA Inca Gold", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f1554569321dc933c87981cf5c239c43", "Atari - Glenn Axworthy", "CX26129", "Midnight Magic (1986) (Atari)", "AKA Pinball Wizard", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "f16c709df0a6c52f47ff52b9d95b7d8d", "Atari, Alan Miller - Sears", "CX2662 - 6-99811", "Hangman (1978) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f16ef574d2042ed8fe877d6541f4dba4", "Spectravision - Spectravideo", "SA-201", "Gangster Alley (1982) (Spectravision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f1929bb9b5db22d98dd992aa3fe72920", "", "", "Cube Conquest (Improved Interlace) (Billy Eno) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "f19aba18f86e415812480ad2be221425", "Chris Larkin", "", "Solaris Trainer (2002) (Chris Larkin) (Hack)", "Hack of Solaris", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f1a0a23e6464d954e3a9579c4ccd01c8", "20th Century Fox, Douglas 'Dallas North' Neubauer", "11006", "Alien (1982) (20th Century Fox)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "f1ae6305fa33a948e36deb0ef12af852", "Andreas Dietrich", "", "Donkey Kong VCS (2017) (1.0)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "f1b2ea568b3e156e3f2849dac83591f6", "", "", "Sprite Demo (1997) (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f1b7edff81ceef5af7ae1fa76c8590fc", "Atari, Richard Maurer", "CX2632, CX2632P", "Space Invaders (1980) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f1beca5a198cf08190487e5c27b8e540", "", "", "Fu Kung! (V0.16) (2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f1e375d921858467166e53bcec05803f", "Jeffry Johnston", "", "Radial Pong - Version 3 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f1eeeccc4bba6999345a2575ae96508e", "Video Gems", "VG-03", "Steeplechase (1983) (Video Gems) (PAL)", "", "", "", "", "", "", "A", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "f1fe06ebe2900eac4cdd17799389a102", "Atari, Jim Huether", "CX26163P", "Sky Diver (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f20675c8b98518367b9f5b8ee6f7c8ea", "Atari", "CX26163P", "Stampede (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f20bd756f3990e06c492f53cd0168e68", "", "", "Skeleton+ (03-05-2003) (Eric Ball) (NTSC)", "", "", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f21813aa050437f0dbc8479864acec6d", "", "", "Sneak 'n Peek (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f23d19b73dac50cc6149316912b8ee53", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Amiga Mouse Hack v1.1 (PAL) (TJ)", "Uses Amiga Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f240ba9f8092d2e8a4c7d82c554bf509", "Quelle", "463.860 7", "Strahlen der Teufelsvoegel (1983) (Quelle) (PAL)", "AKA Atlantis", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f280976d69d6e27a48506bd6bad11dcd", "Atari, Larry Kaplan", "CX2664, CX2664P", "Brain Games (1978) (Atari) (PAL)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "", "" }, + { "f283cc294ece520c2badf9da20cfc025", "Atari - CCW, Christopher H. Omarzu", "CX26104", "Big Bird's Egg Catch (1983) (Atari) (PAL)", "Uses Kids/Keypad Controllers", "Rare", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "", "" }, + { "f28c07767b3e90a2689ade5b5e305874", "Canal 3 - Intellivision", "C 3014", "Keystone Kapers (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f2d40c70cf3e1d03bc112796315888d9", "Atari - CCW, Michael Callahan, Preston Stuart", "CX26103", "Alpha Beam with Ernie (1983) (Atari) (PAL)", "Uses Keypad Controllers", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f2d4d6187903cac2d5ea8ed90dad120d", "Digimax", "", "River Raid II (Digimax)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f2e4fb2d3600c0f76d05864e658cc57b", "", "", "Marble Craze (Kernel) (17-02-2002) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f2f2cb35fdef063c966c1f5481050ea2", "", "", "Ram It (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f2f59629d7341c97644405daeac08845", "Jone Yuan Telephonic Enterprise Co", "", "Bobby Is Going Home (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f303630a2d7316787aecd67fff6b2e33", "AtariAge - Fred Quimby", "", "Gingerbread Man (Fred Quimby)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f3213a8a702b0646d2eaf9ee0722b51c", "Atari, Carol Shaw - Sears", "CX2618 - 49-75123", "3-D Tic-Tac-Toe (1980) (Atari) (4K)", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f33f1d0f7819c74148dacb48cbf1c597", "Retroactive", "", "Qb (2.00) (Retroactive) (Stella)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "f344ac1279152157d63e64aa39479599", "Tigervision", "7-012", "Espial (1984) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f34dd3b8156aaf113cb621b2e51d90b8", "Joe Grand", "", "SCSIcide Pre-release 5 (Joe Grand)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f34f08e5eb96e500e851a80be3277a56", "Atari, Brad Stewart - Sears", "CX2622 - 6-99813, 49-75107", "Breakout (1978) (Atari)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "01 60", "", "", "", "" }, + { "f367e58667a30e7482175809e3cec4d4", "ZiMAG - Emag - Vidco", "708-111 - GN-040", "Cosmic Corridor (1983) (ZiMAG)", "AKA Space Tunnel", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f38358cd8f5ecfedffd5aca1aa939f18", "Universal Gamex Corporation, Alan Roberts", "1005", "X-Man (1983) (Universal) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f4204fc92d17ed4cb567c40361ad58f1", "Inky", "", "Beanie Baby Bash (Inky) (Hack)", "Hack of Beany Bopper", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f4469178cd8998cb437fa110a228eaca", "Digitel", "", "Frostbite (1983) (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f45644ff82b533a781a1ee50f2e95f3c", "", "", "Overhead Adventure Demo 6 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f457674cef449cfd85f21db2b4f631a7", "U.S. Games Corporation - JWDA, Todd Marshall, Wes Trager, Henry Will IV", "VC1004", "Commando Raid (1982) (U.S. Games)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f473f99e47d4026a7a571184922ebf04", "Philip R. Frey", "", "Donkey Claus (Philip R. Frey) (Hack)", "Hack of Donkey Kong", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f48022230bb774a7f22184b48a3385af", "Atari, Rob Fulop - Sears", "CX2633 - 49-75119", "Night Driver (1980) (Atari) (4K)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "", "", "AUTO 65", "", "", "YES", "" }, + { "f48735115ec302ba8bb2d2f3a442e814", "", "", "Dancing Plate (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "f49a34f1fdd7dc147cbf96ce2ce71b76", "", "", "Qb (Special Edition) (PAL) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "f4a09f906cc37be31224433f576d77d3", "Thomas Jentzsch", "", "Challenge of... Nexar, The - Atari Trak-Ball Hack v1.2 (PAL) (TJ)", "Uses Atari Trak-Ball Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f4ab6bd5f80d8988141edde4c84b23b5", "Atari, Alan Miller", "CX2624, CX2624P", "Basketball (1978) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f4b8a47a95b61895e671c3ec86ffd461", "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart", "PB5540", "Star Wars - The Arcade Game (01-03-1984) (Parker Bros) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "f4c2e50b01dff99bddbe037b3489511c", "", "", "Hypnotic (V0.04) (2001) (Inkling) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f4c6621f1a0b4d27081123c08d7d1497", "CCE", "C-838", "Immies & Aggies (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f4cf6881b65c424095dc25dc987f151f", "", "", "128 in 1 Game Select ROM (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f4dabd5bcc603e8464a478208037d423", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (08-21-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f526d0c519f5001adb1fc7948bfbb3ce", "Mythicon, Bill Bryner, Bruce de Graaf", "MA1003", "Star Fox (1983) (Mythicon)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f52f40299fd238c6ffd9e6107050dc76", "Activision, Bob Whitehead - Ariola", "EAG-011, PAG-011 - 711 011-715", "Stampede (1981) (Activision) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f539e32bf6ce39c8ca47cb0cdd2c5cb8", "Control Video Corporation", "", "GameLine Master Module ROM (1983) (Control Video)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f542b5d0193a3959b54f3c4c803ba242", "Atari, Tom Rudadahl - Sears", "CX2634 - 49-75121", "Golf (1980) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f5445b52999e229e3789c39e7ee99947", "Atari, Jim Huether", "CX26163P", "Flag Capture (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f5a2f6efa33a3e5541bc680e9dc31d5b", "Suntek", "SS-022", "Motocross (1983) (Suntek) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f5a3e051730d45fea518f2e8b926565b", "Robby", "", "Keystone Kapers (Robby)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f5aa6bd10f662199c42e43863a30106c", "", "", "Music Kit (V1.0) - Song Player (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "f5d103a9ae36d1d4ee7eef657b75d2b3", "Starpath Corporation, Stephen H. Landrum", "9 AR-4105", "Official Frogger, The (Preview) (1983) (Starpath)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f613aad84d2163d6b197b220bfec1b7e", "", "", "X-Doom V.27 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f661f129644f338b13d9f4510d816c03", "Atari, David Crane", "CX26163P", "Outlaw (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f6676e3fe901eb8515fc7ae310302c3c", "Activision, David Crane", "AG-008", "Laser Blast (1981) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f67181b3a01b9c9159840b15449b87b0", "Atari, Nick 'Sandy Maiwald' Turner", "CX2665", "Frog Pond (08-27-1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f687ec4b69611a7f78bd69b8a567937a", "Activision, Alan Miller - Ariola", "EAZ-028 - 711 028-725", "Robot Tank (1983) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f69a39b215852a0c2764d2a923c1e463", "", "", "Move a Blue Blob Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f69bb58b815a6bdca548fa4d5e0d5a75", "Atari, Larry Kaplan", "CX26163P", "Bowling (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f69d4fcf76942fcd9bdf3fd8fde790fb", "CCE", "", "Aquaventure (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f6a282374441012b01714e19699fc62a", "ZiMAG - Emag - Vidco", "710-111 - GN-010", "I Want My Mommy (1983) (ZiMAG)", "AKA Open, Sesame!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "f6a9ea814d15b85bffe980c927df606b", "", "", "Missile Command (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "f6b5ebb65cbb2981af4d546c470629d7", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (09-13-1984) (Coleco) (Prototype) [a]", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f6c13e816e58c8c62f82b2c8b91a2d67", "", "", "Scrolling Playfield 2 (Junkosoft) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f6d512bef1bf253dc935d0e13c3d1462", "", "", "Slot Racers (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f6daebc0424fa0f8d9aaf26c86df50f4", "Brian Watson", "", "Color Tweaker (V1.0) (2001) (B. Watson)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f6efa00ae99aaf33e427b674bcfd834d", "", "", "2600 Digital Clock (Demo 3) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f6f1b27efc247a0e8d473ddb4269ff9e", "Rainbow Vision - Suntek", "SS-015", "Catch Time (1983) (Rainbow Vision) (PAL)", "AKA Plaque Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f70e3f3bb2d19ec2aaec8f78dc43744f", "Jone Yuan Telephonic Enterprise Co", "", "Pooyan (Jone Yuan) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f714a223954c28eccf459295517dcae6", "", "", "Big - Move This Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f7154add27b95cd90464dbed8cfd7557", "Fabrizio Zavagli", "", "Space Treat Deluxe (2003) (PAL)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f724d3dd2471ed4cf5f191dbb724b69f", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX2659", "Raiders of the Lost Ark (1982) (Atari)", "Console ports are swapped", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "", "" }, + { "f736864442164b29235e8872013180cd", "Telegames - VSS", "6057 A227", "Quest for Quintana Roo (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f73d2d0eff548e8fc66996f27acf2b4b", "CCE", "C-813", "Pitfall (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f7424985bac41067502b4a05b64cb75a", "Activision, Steve Cartwright", "AX-027", "Plaque Attack (1983) (Activision)", "Genesis controller (B is fire up, C is fire down)", "Hack of Plaque Attack", "", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "", "" }, + { "f74ad642552385c3daa203a2a6fc2291", "Eckhard Stolberg", "", "Cubis (1997) (Eckhard Stolberg)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f750b5d613796963acecab1690f554ae", "Manuel Polik", "", "Gunfight 2600 (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f75872946e82ad74d48eae5bc28f5f0e", "Sears Tele-Games, Jim Huether", "CX2614 - 49-75126", "Steeplechase (04-15-1980) (Sears) (Prototype)", "Uses the Paddle Controllers", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f777444fc21a5925e066b68b1d350575", "", "", "Marble Craze (Kernel Works) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f77f5fc3893da5d00198e4cd96544aad", "Canal 3 - Intellivision", "", "Stampede (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f7856e324bc56f45b9c8e6ff062ec033", "Atari, Jerome Domurat, Michael Sierchio", "CX2667", "RealSports Soccer (1983) (Atari) [no opening tune]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "f78c125b5da483c41e51522947d6c4ce", "", "", "Sound Paddle V1 (Dennis Caswell & Jim Nitchals) (PD)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "01", "", "", "", "" }, + { "f7a138eed69665b5cd1bfa796a550b01", "Tigervision - Teldec", "7-012 - 3.60016 VC", "Espial (1984) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f7a651972d78f9ba485b14690452d4be", "Paul Slocum", "", "Homestar Runner Demo #2 (2004-03-29)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f80cf77164079d774b9b0fae33dffca9", "", "", "Fu Kung! (V0.15) (Negative Version) (05-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f8240e62d8c0a64a61e19388414e3104", "Activision, Steve Cartwright", "AX-013", "Barnstorming (1982) (Activision)", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f825c538481f9a7a46d1e9bc06200aaf", "Atari, Richard Maurer - Sears", "CX2635 - 49-75157", "Maze Craze (1980) (Atari)", "AKA A Game of Cops 'n Robbers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "NTSC", "", "", "" }, + { "f844f4c6f3baaaf5322657442d6f29eb", "Atari, Sam Comstock, Richard Dobbis, Nick 'Sandy Maiwald' Turner", "CX26111", "Snoopy and the Red Baron (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f847fb8dba6c6d66d13724dbe5d95c4d", "Absolute Entertainment, David Crane", "AG-042-02, AG-042-04", "Skate Boardin' (1987) (Absolute)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f8582bc6ca7046adb8e18164e8cecdbc", "", "", "Panda Chase (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f8648d0c6ad1266434f6c485ff69ec40", "CCE", "", "Oink! (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f8811d45a9935cca90c62f924712f8e6", "Jone Yuan Telephonic Enterprise Co", "", "Chopper Command (Jone Yuan) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f8b2a6a4d73ebff10d805a9b59041986", "Activision, Larry Kaplan - Ariola", "EAX-006, PAX-006 - 771 006-720", "Bridge (1980) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f8bfd99163d2c4ec688357786e6fba28", "", "", "Eckhard Stolberg's Scrolling Text Demo 2 (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f8c1c4a41303bd40b0d6c81bfaf8573b", "HES", "773-891", "2 Pak Special - Dungeon Master, Creature Strike (1992) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f8fbe2b07345086fc867bceeaf38dc48", "Atari, Eric Manghise, Mimi Nyden, Joseph Tung", "CX2640", "RealSports Baseball (1982) (Atari) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f8ff34b53d86f55bd52d7a520af6d1dc", "", "", "Big Dig (04-04-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f90b5da189f24d7e1a2117d8c8abc952", "Atari, David Crane - Sears", "CX2653 - 6-99823, 49-75111", "Slot Machine (1979) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f91fb8da3223b79f1c9a07b77ebfa0b2", "Atari, Alan J. Murphy, Nick 'Sandy Maiwald' Turner - Sears", "CX2615 - 49-75140", "Demons to Diamonds (1982) (Atari)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "YES", "", "", "10 57", "", "", "", "" }, + { "f93d7fee92717e161e6763a88a293ffa", "20th Century Fox Video Games - Lazer Micro Systems - Dunhill Electronics, B. Winston Hendrickson, Randall Hyde, Mark V. Rhoads, John Simonds", "11013", "Porky's (1983) (20th Century Fox)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f9420173efcb4b9f2b01c2a7b595cca7", "CCE", "", "Laser Blast (CCE) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f954381f9e0f2009d1ac40dedd777b1a", "Thomas Jentzsch", "", "Robot City (V0.18) (01-09-2002) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f9655ed51462ecfc690c7b97cec649f9", "Andrew Wallace", "", "Laseresal 2002 (PAL) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f965cc981cbb0822f955641f8d84e774", "Answer Software Corporation - TY Associates, Kim Ellis", "ASC2001", "Confrontation (1983) (Answer) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "f9660ebed66fee8bdfdf07b4faa22941", "VGS", "", "Vanguard (VGS)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f9677b2ec8728a703eb710274474613d", "Atari, Ian Shepard", "CX2604, CX2604P", "Space War (1978) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f97dee1aa2629911f30f225ca31789d4", "Avalon Hill, Jean Baer, Bill 'Rebecca Ann' Heineman, Jim Jacob", "5005002", "Out of Control (1983) (Avalon Hill)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f98d2276d4a25b286135566255aea9d0", "Digitel", "", "Name This Game (1983) (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f98d869f287d2ce4f8fb36e0686929d9", "", "", "Skeleton+ (17-04-2003) (Eric Ball) (NTSC)", "", "", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f991e0670b5f67faa6b6211e9bd81b91", "Nukey Shay, Omegamatrix", "", "Double Dragon (Genesis) (PAL) V2", "Genesis controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f992a39b46aa48188fab12ad3809ae4a", "", "", "Sky Jinks (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f9967369943209b4788d4e92cefc0795", "Atari", "CX26163P", "Fishing (32 in 1) (1988) (Atari) (PAL) (4K)", "AKA Fishing Derby", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f9cef637ea8e905a10e324e582dd39c2", "CCE", "", "Private Eye (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f9d51a4e5f8b48f68770c89ffd495ed1", "Atari, Tod Frye, Mimi Nyden", "CX2657", "SwordQuest - FireWorld (1982) (Atari)", "AKA Adventure II, SwordQuest II - FireWorld", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f9da42f91a1c5cfa344d2ff440c6f8d4", "ZUT", "", "Pac Invaders (ZUT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f9de91d868d6ebfb0076af9063d7195e", "", "", "Maze Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "f9e99596345a84358bc5d1fbe877134b", "Activision, Larry Kaplan, David Crane - Ariola", "EAG-010, PAG-010 - 711 010-720", "Kaboom! (1981) (Activision) (PAL)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "", "", "01 50", "", "", "", "" }, + { "fa0570561aa80896f0ead05c46351389", "Tigervision", "7-008", "Miner 2049er (1983) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fa1b060fd8e0bca0c2a097dcffce93d3", "Atari - CCW, Christopher H. Omarzu, Preston Stuart, Bruce Williams", "CX26101", "Oscar's Trash Race (1984) (Atari)", "Uses the Keypad Controllers", "", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "", "" }, + { "fa2be8125c3c60ab83e1c0fe56922fcb", "Camelot - DSD, Michael Doherty, Clyde Hager - Johnson & Johnson", "", "Tooth Protectors (1983) (Camelot)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "fa3de71841c0841db6a741884a6b6b2f", "", "", "Warring Worms (17-02-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fa4404fabc094e3a31fcd7b559cdd029", "Atari, Alan J. Murphy, Robert C. Polaro", "CX26100", "Bugs Bunny (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fa529ec88eca679f6d5fd0ccb2120e46", "", "", "20 Sprites at Once Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fa6fe97a10efb9e74c0b5a816e6e1958", "ZiMAG - Emag - Vidco", "707-111 - GN-030", "Tanks But No Tanks (1983) (ZiMAG)", "AKA Phantom Tank", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fa7ce62e7fd77e02b3e2198d70742f80", "Atari, Peter C. Niday", "CX26108", "Donald Duck's Speedboat (04-18-1983) (Atari) (Prototype) (PAL)", "AKA Donald Duck's Regatta", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fa7e11a3dbea4365975cd2f094e61d25", "Tim Snider", "", "Mystery Science Theater 2600 (1999) (Tim Snider) (Hack)", "Hack of Megamania", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fa98d48cd609c9babc819e0a1bd8d598", "AtariAge (Chris Walton)", "", "Juno First (2009) (PAL60)", "AtariVox supported", "Homebrew", "", "", "", "", "", "", "", "", "ATARIVOX", "", "", "", "", "", "", "YES", "" }, + { "fab7b04b9f42df761eb6f2bc445eaa99", "20th Century Fox Video Games - Sirius Software, David Lubar", "11008", "Fantastic Voyage (11-04-1982) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fabca526d57de46768b392f758f1a008", "", "", "Laseresal 2600 (16-12-2001) (Andrew Wallace) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fac28963307b6e85082ccd77c88325e7", "CCE", "", "Berzerk (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fadb89f9b23beb4d43a7895c532757e2", "Galaga Games", "", "River Raid (1984) (Galaga Games) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fae0b86934a7c5a362281dffebdb43a0", "Retroactive", "", "Qb (2.07) (Retroactive) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "faebcb2ef1f3831b2fc1dbd39d36517c", "Atari, Jerome Domurat, Steve Woita", "CX2696", "Asterix (1984) (Atari) (PAL)", "AKA Taz", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "faed2ef6b44894f8c83f2b50891c35c6", "CCE", "", "Super Baseball (CCE)", "AKA RealSports Baseball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "faffd84f3a8eceee2fa5ea5b0a3e6678", "Suntek", "SS-025", "Spectracube Invasion (1983) (Suntek) (PAL)", "AKA Immies & Aggies", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fb09ee4ccd47ae74a3c314f0d8a40344", "", "", "Titans (SnailSoft)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fb0c32ef7af5b45486db663510094be8", "", "", "Demo Image Series #15 - Three Marios (NTSC) (Non-Interleave) (06-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fb0e84cee4c108d24253bcb7e382cffd", "", "", "Interleaved ChronoColour Demo (SECAM) (05-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fb27afe896e7c928089307b32e5642ee", "M Network - INTV - APh Technological Consulting, Jeff Ronne, Brett Stutz", "MT5662", "TRON - Deadly Discs (1983) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fb4ca865abc02d66e39651bd9ade140a", "Arcadia Corporation, Brian McGhie", "AR-4104", "Rabbit Transit (1983) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fb531febf8e155328ec0cd39ef77a122", "", "", "Worm War I (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "fb5c8af97bd8ffe88323656f462645a7", "", "", "Interlace Demo (Glenn Saunders)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "fb833ed50c865a9a505a125fc9d79a7e", "ITT Family Games", "", "Pumuckl I (1983) (ITT Family Games) (PAL)", "AKA Panda Chase", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fb884ffd89013331a6f01ae3f6abd214", "Activision, David Crane", "", "Venetian Blinds Demo (1982) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fb88baa01afd34e0e4b601e1d29bc806", "Manuel Polik", "", "Star Fire (2003) (XYPE)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fb88c400d602fe759ae74ef1716ee84e", "20th Century Fox Video Games, Bill Aspromonte", "11031", "Crash Dive (1983) (20th Century Fox)", "AKA Voyage to the Bottom of the Sea", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fb91da78455d9b1606913fbf8c859772", "", "", "Split Screen (Ballblazer) Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fb91dfc36cddaa54b09924ae8fd96199", "Parker Brothers, Mark Lesser", "PB5590", "Frogger II (1984) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "fb978f1c053e8061cc37a726639f43f7", "Atari - Axlon, Tod Frye - Heuristica, Agustin Ortiz", "CX26169", "Shooting Arcade (03-07-1989) (Atari) (Prototype)", "Uses the Light Gun Controller (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fbac6476e7b2b20d246202af81662c88", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (Preview) (1982) (Starpath) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fbb0151ea2108e33b2dbaae14a1831dd", "Thomas Jentzsch", "", "Robot Tank TV (Thomas Jentzsch) (Hack)", "Uses two simultaneous Joystick Controllers, Hack of Robot Tank", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fbb4f3debf48dc961b559384467f2057", "Digitel", "", "River Raid III (1985) (Digitel)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fbe554aa8f759226d251ba6b64a9cce4", "Atari - GCC, Mike Feinstein, Brad Rice", "CX2681, CX2681P", "Battlezone (1983) (Atari) (PAL)", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fbfebee9c14694719e3eda4854dc42ee", "Jake Patterson", "", "Baubles 3 (Jake Patterson) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fc2104dd2dadf9a6176c1c1c8f87ced9", "Coleco - Woodside Design Associates, Harley H. Puthuff Jr.", "2663", "Time Pilot (1983) (Coleco)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fc2233fc116faef0d3c31541717ca2db", "Atari, Tod Frye", "CX2646", "Pac-Man (1982) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fc24a94d4371c69bc58f5245ada43c44", "Atari - Axlon, Steve DeFrisco", "CX26170", "Secret Quest (1989) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fc6052438f339aea373bbc999433388a", "Atari, David Crane", "CX2653P", "Slot Machine (1979) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fc668a2251dd79cbd903d4fa0e558f96", "Thomas Jentzsch", "", "Thrust (V1.1) (2000) (TJ) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fc92d74f073a44bc6e46a3b3fa8256a2", "", "", "Megademo (19xx) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fc9c1652fe3a2cade6188f4d3692481f", "Andrew Davies", "", "Andrew Davies early notBoulderDash demo (NTSC)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "fca4a5be1251927027f2c24774a02160", "Activision, John Van Ryzin", "AZ-036-04", "H.E.R.O. (1984) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fcbbd0a407d3ff7bf857b8a399280ea1", "ZiMAG - Emag - Vidco", "GN-070", "Mysterious Thief, A (1983) (ZiMAG) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "fcbdf405f0fc2027b0ea45bb5af94c1a", "Amiga - Video Soft, Michael K. Glass, Jerry Lawson", "", "3-D Ghost Attack (1983) (Amiga) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "fcea12625c071ddc49f4e409f4038c60", "Fabrizio Zavagli", "", "Balls! (16-09-2002) (Fabrizio Zavagli)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, + { "fcf8e306f6615f74feba5cb25550038c", "", "", "Blue Dot Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fd0e5148162e8ec6719445d559f018a9", "Activision, Steve Cartwright - Ariola", "EAX-022, EAX-022-04I - 711 022-720", "Seaquest (1983) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fd10915633aea4f9cd8b518a25d62b55", "Atari, John Dunn", "CX2631, CX2631P", "Superman (1979) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fd16949913aaab5beaefed73bf2ca67c", "Atari - GCC, John Allred, Mike Feinstein", "CX2688", "Jungle Hunt (02-03-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fd4f5536fd80f35c64d365df85873418", "Atari - Bobco, Robert C. Polaro", "CX26140", "Desert Falcon (1987) (Atari)", "AKA Nile Flyer, Sphinx", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fd6e507b5df68beeeddeaf696b6828fa", "", "", "Boxing (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fd7464edaa8cc264b97ba0d13e7f0678", "HES", "771-333", "2 Pak Special - Challenge, Surfing (1990) (HES) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fd78f186bdff83fbad7f97cb583812fe", "Amiga - Video Soft", "3125", "Surf's Up (1983) (Amiga) (Prototype) [a2]", "Uses the Joyboard controller", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fd8b4ee0d57605b35e236e814f706ff1", "Atari - GCC, Mike Feinstein, John Mracek", "CX2673, CX2673P", "Phoenix (1982) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fd9b321cee5fbb32c39ba3ca5d9ec7cf", "Jeffry Johnston", "", "Radial Pong - Version 5 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fdd4995a50395db14f518f63c2d63438", "", "", "Oh No! (Version 3) (18-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fde42e39710e75e9e4d4d75440f8e4e5", "Thomas Jentzsch", "", "Coke Zero (v1.0) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fdf0de38517e0cf7f0885f98ccc95836", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (2 of 4) (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fdf6680b2b1e8054293a39700a765692", "", "", "Alpha Demo - The Beta Demo 2 (2000) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fe0b7f27e3ad50bbf9ff468ee56d553d", "", "", "Lines Demo (Eckhard Stolberg) (PAL) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fe0bc4bb92c1c4de7d5706aaa8d8c10d", "", "", "Sprite Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fe3b461d4c8b179fe68bc77760294c25", "Atari, Joe Decuir", "CX2621, CX2621P", "Video Olympics (1977) (Atari) (PAL) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "YES", "", "", "", "", "", "", "" }, + { "fe641247a4ab9bee970e19ab55f23b25", "20th Century Fox Video Games, Beck-Tech, Steve Beck", "11035", "Save the Whales (02-07-1983) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fe67087f9c22655ce519616fc6c6ef4d", "Atari - Zip Technology, Randy Bowker, Bruce Williams", "CX26142", "Crack'ed (11-28-1988) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fe6abc0f63e31e2646c9c600926b5b7f", "Atari", "CX26137", "4 in 1 (02-19-1987) (Atari) (Prototype)", "Home Run, Canyon Bomber, Sky Diver, Night Driver", "Prototype", "", "", "4IN1", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fe870018332a0221eb59fb18b0c6bccc", "", "", "Incoming (08-11-2002) (Ben Larson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fe9ae625d924b54c9f8a14ac9a0f6c6d", "BG Dodson", "", "High Bid! (BG Dodson) (Hack)", "Hack of Pepsi Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "feba8686fd0376015258d1152923958a", "", "", "Super Circus (Unknown) (PAL)", "AKA Circus Atari", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fec0c2e2ab0588ed20c750b58cf3baa3", "Activision - Cheshire Engineering, David Rolfe, Larry Zwick", "EAZ-037-04, EAZ-037-04I", "Beamrider (1984) (Activision) (PAL)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "fece458a8023a809a5006867feca40e8", "", "", "SCSIcide (24-02-2001) (Joe Grand) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "feec54aac911887940b47fe8c9f80b11", "Atari, Rob Fulop", "CX2633, CX2633P", "Night Driver (1980) (Atari) (PAL)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "", "", "", "", "", "", "AUTO 65", "", "", "YES", "" }, + { "feedcc20bc3ca34851cd5d9e38aa2ca6", "Atari, David Crane - Sears", "CX2607 - 6-99828, 49-75115", "Canyon Bomber (1979) (Atari)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "YES", "", "", "10", "", "", "", "" }, + { "ff1523783e0e76a3b0d1f7f0d1cb3050", "Thomas Jentzsch", "", "Marble Craze - Atari Trak-Ball Hack v1.0 (PAL) (TJ)", "Uses Atari Trak-Ball Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ff3bd0c684f7144aeaa18758d8281a78", "Atari, Bob Whitehead", "CX2651", "Blackjack (1977) (Atari) (PAL)", "Uses the Paddle Controllers", "Rare", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "", "", "", "", "" }, + { "ff5a9e340d96df6f5a5b6eb038e923bd", "", "", "Space Shuttle (1983) (Activision) [t1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ff7627207e8aa03730c35c735a82c26c", "Atari, Bob Whitehead", "CX26163P", "Blackjack (32 in 1) (1988) (Atari) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "", "", "", "", "" }, + { "ff86fc8ffa717bb095e8471638c1c31c", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix - Bop a Buggy (1 of 3) (1983) (Arcadia) (PAL)", "Uses Paddle Controllers", "", "", "", "", "", "", "", "", "", "", "", "", "", "01 56", "", "", "", "" }, + { "ff87d58125ae517eb7b09a0475a1ccdc", "", "", "SCSIcide (Score Hack 1) (24-02-2001) (Joe Grand) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ffb1cd548563158ce33f9d10268187e7", "Erik Eid", "", "Euchre (Beta) (NTSC) (12-09-2002) (Erik Eid)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ffc0ff4305dd46b4b459885bd1818e2e", "Barry Laws Jr.", "", "Star Wars - The Battle of Alderaan (Star Strike Hack)", "Hack of Star Strike (Mattel)", "New Release (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ffdc0eb3543404eb4c353fbdddfa33b6", "CCE", "C-827", "Chopper Command (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ffe51989ba6da2c6ae5a12d277862e16", "Atari - Sears", "CX2627 - 6-99841", "Human Cannonball (1979) (Atari) (4K)", "AKA Cannon Man", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "ffebb0070689b9d322687edd9c0a2bae", "", "", "Spitfire Attack (1983) (Milton Bradley) [h1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" } }}; #endif diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index 638265910..29359d6ba 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -600,6 +600,8 @@ unique_ptr OSystem::openConsole(const FilesystemNode& romfile, string& CMDLINE_PROPS_UPDATE("vcenter", PropType::Display_VCenter); CMDLINE_PROPS_UPDATE("pp", PropType::Display_Phosphor); CMDLINE_PROPS_UPDATE("ppblend", PropType::Display_PPBlend); + CMDLINE_PROPS_UPDATE("pxcenter", PropType::Controller_PaddlesXCenter); + CMDLINE_PROPS_UPDATE("pycenter", PropType::Controller_PaddlesYCenter); // Finally, create the cart with the correct properties if(cart) diff --git a/src/emucore/Paddles.cxx b/src/emucore/Paddles.cxx index b4782cfb8..eb6171411 100644 --- a/src/emucore/Paddles.cxx +++ b/src/emucore/Paddles.cxx @@ -238,7 +238,7 @@ void Paddles::update() sa_xaxis = new_val; setPin(AnalogPin::Nine, Int32(MAX_RESISTANCE * - (BSPF::clamp(32768 - Int32(Int32(sa_xaxis) * SENSITIVITY + CENTER), 0, 65536) / 65536.0))); + (BSPF::clamp(32768 - Int32(Int32(sa_xaxis) * SENSITIVITY + XCENTER), 0, 65536) / 65536.0))); sa_changed = true; } @@ -253,7 +253,7 @@ void Paddles::update() sa_yaxis = new_val; setPin(AnalogPin::Five, Int32(MAX_RESISTANCE * - (BSPF::clamp(32768 - Int32(Int32(sa_yaxis) * SENSITIVITY + CENTER), 0, 65536) / 65536.0))); + (BSPF::clamp(32768 - Int32(Int32(sa_yaxis) * SENSITIVITY + YCENTER), 0, 65536) / 65536.0))); sa_changed = true; } myLastAxisX = sa_xaxis; @@ -383,10 +383,17 @@ bool Paddles::setMouseControl( } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Paddles::setAnalogCenter(int center) +void Paddles::setAnalogXCenter(int xcenter) { - // TODO: convert into ~5 pixel (also in Input Dialog!) - CENTER = BSPF::clamp(center, MIN_ANALOG_CENTER, MAX_ANALOG_CENTER) * 860; + // convert into ~5 pixel steps + XCENTER = BSPF::clamp(xcenter, MIN_ANALOG_CENTER, MAX_ANALOG_CENTER) * 860; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Paddles::setAnalogYCenter(int ycenter) +{ + // convert into ~5 pixel steps + YCENTER = BSPF::clamp(ycenter, MIN_ANALOG_CENTER, MAX_ANALOG_CENTER) * 860; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -431,7 +438,8 @@ void Paddles::setDigitalPaddleRange(int range) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int Paddles::CENTER = 0; +int Paddles::XCENTER = 0; +int Paddles::YCENTER = 0; float Paddles::SENSITIVITY = 1.0; int Paddles::TRIGRANGE = Paddles::TRIGMAX; diff --git a/src/emucore/Paddles.hxx b/src/emucore/Paddles.hxx index 0a8adc9c9..7628e840c 100644 --- a/src/emucore/Paddles.hxx +++ b/src/emucore/Paddles.hxx @@ -50,8 +50,8 @@ class Paddles : public Controller public: static constexpr float BASE_ANALOG_SENSE = 0.148643628f; static constexpr int MAX_ANALOG_SENSE = 30; - static constexpr int MIN_ANALOG_CENTER = -20; - static constexpr int MAX_ANALOG_CENTER = 20; + static constexpr int MIN_ANALOG_CENTER = -10; + static constexpr int MAX_ANALOG_CENTER = 30; static constexpr int MAX_DIGITAL_SENSE = 20; static constexpr int MAX_MOUSE_SENSE = 20; static constexpr int MIN_DEJITTER = 0; @@ -93,11 +93,18 @@ class Paddles : public Controller Controller::Type ytype, int yid) override; /** - Sets the center for analog paddles. + Sets the x-center for analog paddles. - @param center Value from -20 to 20, representing the center offset/860 + @param center Value from -10 to 30, representing the center offset/860 */ - static void setAnalogCenter(int center); + static void setAnalogXCenter(int xcenter); + + /** + Sets the y-center for analog paddles. + + @param center Value from -10 to 30, representing the center offset/860 + */ + static void setAnalogYCenter(int ycenter); /** Sets the sensitivity for analog paddles. @@ -175,7 +182,8 @@ class Paddles : public Controller int myLastAxisX{0}, myLastAxisY{0}; int myAxisDigitalZero{0}, myAxisDigitalOne{0}; - static int CENTER; + static int XCENTER; + static int YCENTER; static float SENSITIVITY; static int DIGITAL_SENSITIVITY, DIGITAL_DISTANCE; diff --git a/src/emucore/Props.cxx b/src/emucore/Props.cxx index fad325d85..144955c9c 100644 --- a/src/emucore/Props.cxx +++ b/src/emucore/Props.cxx @@ -251,6 +251,8 @@ void Properties::print() const << get(PropType::Controller_Left) << "|" << get(PropType::Controller_Right) << "|" << get(PropType::Controller_SwapPaddles) << "|" + << get(PropType::Controller_PaddlesXCenter) << "|" + << get(PropType::Controller_PaddlesYCenter) << "|" << get(PropType::Controller_MouseAxis) << "|" << get(PropType::Display_Format) << "|" << get(PropType::Display_VCenter) << "|" @@ -296,6 +298,8 @@ void Properties::printHeader() << "Controller_Left|" << "Controller_Right|" << "Controller_SwapPaddles|" + << "Controller_PaddlesXCenter|" + << "Controller_PaddlesYCenter|" << "Controller_MouseAxis|" << "Display_Format|" << "Display_VCenter|" @@ -323,6 +327,8 @@ std::array Properties::ourDefaultProperties = "AUTO", // Controller.Left "AUTO", // Controller.Right "NO", // Controller.SwapPaddles + "0", // Controller.PaddlesXCenter + "0", // Controller.PaddlesYCenter "AUTO", // Controller.MouseAxis "AUTO", // Display.Format "0", // Display.VCenter @@ -349,6 +355,8 @@ std::array Properties::ourPropertyNames = "Controller.Left", "Controller.Right", "Controller.SwapPaddles", + "Controller.PaddlesXCenter", + "Controller.PaddlesYCenter", "Controller.MouseAxis", "Display.Format", "Display.VCenter", diff --git a/src/emucore/Props.hxx b/src/emucore/Props.hxx index af3f67568..70e9fa727 100644 --- a/src/emucore/Props.hxx +++ b/src/emucore/Props.hxx @@ -37,6 +37,8 @@ enum class PropType : uInt8 { Controller_Left, Controller_Right, Controller_SwapPaddles, + Controller_PaddlesXCenter, + Controller_PaddlesYCenter, Controller_MouseAxis, Display_Format, Display_VCenter, diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index 0e3de3de8..68747896a 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -103,7 +103,6 @@ Settings::Settings() setPermanent("dejitter.base", "0"); setPermanent("dejitter.diff", "0"); setPermanent("dsense", "10"); - setPermanent("pcenter", "0"); setPermanent("psense", "20"); setPermanent("msense", "10"); setPermanent("tsense", "10"); @@ -324,10 +323,6 @@ void Settings::validate() if(i < 0 || i > 3) setValue("cursor", "2"); - i = getInt("pcenter"); - if(i < Paddles::MIN_ANALOG_CENTER || i > Paddles::MAX_ANALOG_CENTER) - setValue("pcenter", "0"); - i = getInt("psense"); if(i < 0|| i > Paddles::MAX_ANALOG_SENSE) setValue("psense", "20"); @@ -458,7 +453,6 @@ void Settings::usage() const << " -cursor <0,1,2,3> Set cursor state in UI/emulation modes\n" << " -dejitter.base <0-10> Strength of analog paddle value averaging\n" << " -dejitter.diff <0-10> Strength of analog paddle reaction to fast movements\n" - << " -pcenter <-20-20> Center of analog paddle\n" << " -psense <0-30> Sensitivity of analog paddle movement\n" << " -dsense <1-20> Sensitivity of digital emulated paddle movement\n" << " -msense <1-20> Sensitivity of mouse emulated paddle movement\n" @@ -568,6 +562,8 @@ void Settings::usage() const << " -rc Sets the 'Controller.Right' property\n" << " -bc Same as using both -lc and -rc\n" << " -cp Sets the 'Controller.SwapPaddles' property\n" + << " -pxcenter Sets the 'Controller.PaddlesXCenter' property\n" + << " -pycenter Sets the 'Controller.PaddlesYCenter' property\n" << " -format Sets the 'Display.Format' property\n" << " -vcenter Sets the 'Display.vcenter' property\n" << " -pp Sets the 'Display.Phosphor' property\n" diff --git a/src/gui/GameInfoDialog.cxx b/src/gui/GameInfoDialog.cxx index 2cfb80912..49ec158b0 100644 --- a/src/gui/GameInfoDialog.cxx +++ b/src/gui/GameInfoDialog.cxx @@ -27,6 +27,7 @@ #include "OSystem.hxx" #include "CartDetector.hxx" #include "ControllerDetector.hxx" +#include "Paddles.hxx" #include "PopUpWidget.hxx" #include "Props.hxx" #include "PropsSet.hxx" @@ -66,7 +67,7 @@ GameInfoDialog::GameInfoDialog( StaticTextWidget* t; // Set real dimensions - setSize(53 * fontWidth + 8, + setSize(55 * fontWidth + 8, 8 * (lineHeight + VGAP) + 1 * (infoLineHeight + VGAP) + VBORDER * 2 + _th + buttonHeight + fontHeight + ifont.getLineHeight() + 20, max_w, max_h); @@ -118,12 +119,13 @@ GameInfoDialog::GameInfoDialog( pwidth, lineHeight, items, "", 0, 0); wid.push_back(myFormat); - myFormatDetected = new StaticTextWidget(myTab, ifont, myFormat->getRight() + 8, ypos + 4, "SECAM60 detected"); - + myFormatDetected = new StaticTextWidget(myTab, ifont, myFormat->getRight() + 8, ypos + 4, + "SECAM60 detected"); // Phosphor ypos += lineHeight + VGAP; - myPhosphor = new CheckboxWidget(myTab, font, HBORDER, ypos + 1, "Phosphor (enabled for all ROMs)", kPhosphorChanged); + myPhosphor = new CheckboxWidget(myTab, font, HBORDER, ypos + 1, + "Phosphor (enabled for all ROMs)", kPhosphorChanged); wid.push_back(myPhosphor); ypos += lineHeight + VGAP * 0; @@ -261,10 +263,35 @@ GameInfoDialog::GameInfoDialog( pwidth, buttonHeight, "Erase EEPROM", kEEButtonPressed); wid.push_back(myEraseEEPROMButton); myEraseEEPROMInfo = new StaticTextWidget(myTab, ifont, myEraseEEPROMButton->getRight() + 4, - myEraseEEPROMLabel->getTop() + 3, "(for this game only)"); - + myEraseEEPROMLabel->getTop() + 3, + "(for this game only)"); ypos += lineHeight + VGAP * 4; - myMouseControl = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Specific mouse axes", kMCtrlChanged); + + // Paddles + myPaddlesCenter = new StaticTextWidget(myTab, font, xpos, ypos, "Paddles center:"); + ypos += lineHeight + VGAP; + + xpos += 20; + myPaddleXCenter = new SliderWidget(myTab, font, xpos, ypos - 1, "X ", 0, kPXCenterChanged, + fontWidth * 6, "px", 0 ,true); + myPaddleXCenter->setMinValue(Paddles::MIN_ANALOG_CENTER); + myPaddleXCenter->setMaxValue(Paddles::MAX_ANALOG_CENTER); + myPaddleXCenter->setTickmarkIntervals(4); + wid.push_back(myPaddleXCenter); + ypos += lineHeight + VGAP; + + myPaddleYCenter = new SliderWidget(myTab, font, xpos, ypos - 1, "Y ", 0, kPYCenterChanged, + fontWidth * 6, "px", 0 ,true); + myPaddleYCenter->setMinValue(Paddles::MIN_ANALOG_CENTER); + myPaddleYCenter->setMaxValue(Paddles::MAX_ANALOG_CENTER); + myPaddleYCenter->setTickmarkIntervals(4); + wid.push_back(myPaddleYCenter); + + // Mouse + xpos = HBORDER + fontWidth * 24 - 20; + ypos = myPaddlesCenter->getTop(); + myMouseControl = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Specific mouse axes", + kMCtrlChanged); wid.push_back(myMouseControl); // Mouse controller specific axis @@ -291,8 +318,8 @@ GameInfoDialog::GameInfoDialog( "Y-Axis is "); wid.push_back(myMouseY); - xpos = HBORDER; ypos += lineHeight + VGAP; - myMouseRange = new SliderWidget(myTab, font, HBORDER, ypos, + xpos -= 20; ypos += lineHeight + VGAP; + myMouseRange = new SliderWidget(myTab, font, xpos, ypos, "Mouse axes range ", 0, 0, fontWidth * 4, "%"); myMouseRange->setMinValue(1); myMouseRange->setMaxValue(100); myMouseRange->setTickmarkIntervals(4); @@ -492,6 +519,10 @@ void GameInfoDialog::loadControllerProperties(const Properties& props) mySwapPorts->setState(props.get(PropType::Console_SwapPorts) == "YES"); mySwapPaddles->setState(props.get(PropType::Controller_SwapPaddles) == "YES"); + // Paddle centers + myPaddleXCenter->setValue(BSPF::stringToInt(props.get(PropType::Controller_PaddlesXCenter))); + myPaddleYCenter->setValue(BSPF::stringToInt(props.get(PropType::Controller_PaddlesYCenter))); + // MouseAxis property (potentially contains 'range' information) istringstream m_axis(props.get(PropType::Controller_MouseAxis)); string m_control, m_range; @@ -557,7 +588,11 @@ void GameInfoDialog::saveConfig() myGameProperties.set(PropType::Controller_Left, myLeftPort->getSelectedTag().toString()); myGameProperties.set(PropType::Controller_Right, myRightPort->getSelectedTag().toString()); myGameProperties.set(PropType::Console_SwapPorts, (mySwapPorts->isEnabled() && mySwapPorts->getState()) ? "YES" : "NO"); - myGameProperties.set(PropType::Controller_SwapPaddles, (/*mySwapPaddles->isEnabled() &&*/ mySwapPaddles->getState()) ? "YES" : "NO"); + myGameProperties.set(PropType::Controller_SwapPaddles, mySwapPaddles->getState() ? "YES" : "NO"); + + // Paddle center + myGameProperties.set(PropType::Controller_PaddlesXCenter, std::to_string(myPaddleXCenter->getValue())); + myGameProperties.set(PropType::Controller_PaddlesYCenter, std::to_string(myPaddleYCenter->getValue())); // MouseAxis property (potentially contains 'range' information) string mcontrol = "AUTO"; @@ -598,6 +633,9 @@ void GameInfoDialog::saveConfig() // update 'Controllers' tab settings immediately instance().console().setControllers(myGameProperties.get(PropType::Cart_MD5)); + + Paddles::setAnalogXCenter(myPaddleXCenter->getValue()); + Paddles::setAnalogYCenter(myPaddleYCenter->getValue()); } } @@ -686,7 +724,7 @@ void GameInfoDialog::updateControllerStates() // Compumate bankswitching scheme doesn't allow to select controllers bool enableSelectControl = myBSType->getSelectedTag() != "CM"; // Enable Swap Paddles checkbox only for paddle games - bool enableSwapPaddles = BSPF::startsWithIgnoreCase(contrLeft, "PADDLES") || + bool enablePaddles = BSPF::startsWithIgnoreCase(contrLeft, "PADDLES") || BSPF::startsWithIgnoreCase(contrRight, "PADDLES") || BSPF::startsWithIgnoreCase(myLeftPortDetected->getLabel(), "Paddles") || BSPF::startsWithIgnoreCase(myRightPortDetected->getLabel(), "Paddles"); @@ -712,11 +750,27 @@ void GameInfoDialog::updateControllerStates() myRightPort->setEnabled(enableSelectControl); mySwapPorts->setEnabled(enableSelectControl); - mySwapPaddles->setEnabled(enableSwapPaddles); + mySwapPaddles->setEnabled(enablePaddles); myEraseEEPROMLabel->setEnabled(enableEEEraseButton); myEraseEEPROMButton->setEnabled(enableEEEraseButton); myEraseEEPROMInfo->setEnabled(enableEEEraseButton); + + myPaddlesCenter->setEnabled(enablePaddles); + myPaddleXCenter->setEnabled(enablePaddles); + myPaddleYCenter->setEnabled(enablePaddles); + + + bool enableMouse = enablePaddles || + BSPF::startsWithIgnoreCase(contrLeft, "Driving") || + BSPF::startsWithIgnoreCase(contrRight, "Driving") || + BSPF::startsWithIgnoreCase(contrLeft, "MindLink") || + BSPF::startsWithIgnoreCase(contrRight, "MindLink"); + + myMouseControl->setEnabled(enableMouse); + myMouseX->setEnabled(enableMouse); + myMouseY->setEnabled(enableMouse); + myMouseRange->setEnabled(enableMouse); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -797,6 +851,14 @@ void GameInfoDialog::handleCommand(CommandSender* sender, int cmd, myVCenter->setValueUnit("px"); break; + case kPXCenterChanged: + myPaddleXCenter->setValueLabel(myPaddleXCenter->getValue() * 5); + break; + + case kPYCenterChanged: + myPaddleYCenter->setValueLabel(myPaddleYCenter->getValue() * 5); + break; + case kMCtrlChanged: { bool state = myMouseControl->getState(); diff --git a/src/gui/GameInfoDialog.hxx b/src/gui/GameInfoDialog.hxx index 8704a13d3..2e2dc4f8a 100644 --- a/src/gui/GameInfoDialog.hxx +++ b/src/gui/GameInfoDialog.hxx @@ -89,6 +89,9 @@ class GameInfoDialog : public Dialog, public CommandSender StaticTextWidget* myEraseEEPROMLabel{nullptr}; ButtonWidget* myEraseEEPROMButton{nullptr}; StaticTextWidget* myEraseEEPROMInfo{nullptr}; + StaticTextWidget* myPaddlesCenter{nullptr}; + SliderWidget* myPaddleXCenter{nullptr}; + SliderWidget* myPaddleYCenter{nullptr}; CheckboxWidget* myMouseControl{nullptr}; PopUpWidget* myMouseX{nullptr}; PopUpWidget* myMouseY{nullptr}; @@ -110,6 +113,8 @@ class GameInfoDialog : public Dialog, public CommandSender kRightCChanged = 'RCch', kMCtrlChanged = 'MCch', kEEButtonPressed = 'EEgb', + kPXCenterChanged = 'Pxch', + kPYCenterChanged = 'Pych', }; // Game properties for currently loaded ROM diff --git a/src/gui/InputDialog.cxx b/src/gui/InputDialog.cxx index 60d7ab14b..5b34d1800 100644 --- a/src/gui/InputDialog.cxx +++ b/src/gui/InputDialog.cxx @@ -123,20 +123,9 @@ void InputDialog::addDevicePortTab() xpos = HBORDER; ypos += lineHeight + VGAP * 2; new StaticTextWidget(myTab, _font, xpos, ypos+1, "Analog paddle:"); - - // Add paddle center xpos += fontWidth * 2; - ypos += lineHeight + VGAP; - myPaddleCenter = new SliderWidget(myTab, _font, xpos, ypos - 1, 13 * fontWidth, lineHeight, - "Center", - lwidth - fontWidth * 2, kPCenterChanged, 6 * fontWidth, "px", 0, true); - myPaddleCenter->setMinValue(Paddles::MIN_ANALOG_CENTER); - myPaddleCenter->setMaxValue(Paddles::MAX_ANALOG_CENTER); - myPaddleCenter->setTickmarkIntervals(4); - wid.push_back(myPaddleCenter); - - // Add paddle sensitivity + // Add analog paddle sensitivity ypos += lineHeight + VGAP; myPaddleSpeed = new SliderWidget(myTab, _font, xpos, ypos - 1, 13 * fontWidth, lineHeight, "Sensitivity", @@ -146,26 +135,26 @@ void InputDialog::addDevicePortTab() wid.push_back(myPaddleSpeed); - // Add dejitter (Stelladaptor emulation for now only) + // Add dejitter (analog paddles) ypos += lineHeight + VGAP; - myDejitterBase = new SliderWidget(myTab, _font, xpos, ypos - 1, 6 * fontWidth, lineHeight, - "Dejitter strength", lwidth - fontWidth * 2, kDejitterChanged); + myDejitterBase = new SliderWidget(myTab, _font, xpos, ypos - 1, 13 * fontWidth, lineHeight, + "Dejitter averaging", lwidth - fontWidth * 2, + kDejitterAvChanged, 3 * fontWidth); myDejitterBase->setMinValue(Paddles::MIN_DEJITTER); myDejitterBase->setMaxValue(Paddles::MAX_DEJITTER); - myDejitterBase->setTickmarkIntervals(2); - xpos += myDejitterBase->getWidth() + fontWidth - 4; + myDejitterBase->setTickmarkIntervals(5); + //xpos += myDejitterBase->getWidth() + fontWidth - 4; wid.push_back(myDejitterBase); - myDejitterDiff = new SliderWidget(myTab, _font, xpos, ypos - 1, 6 * fontWidth, lineHeight, - "", 0, kDejitterChanged); + ypos += lineHeight + VGAP; + myDejitterDiff = new SliderWidget(myTab, _font, xpos, ypos - 1, 13 * fontWidth, lineHeight, + "Dejitter reaction", lwidth - fontWidth * 2, + kDejitterReChanged, 3 * fontWidth); myDejitterDiff->setMinValue(Paddles::MIN_DEJITTER); myDejitterDiff->setMaxValue(Paddles::MAX_DEJITTER); - myDejitterDiff->setTickmarkIntervals(2); - xpos += myDejitterDiff->getWidth(); + myDejitterDiff->setTickmarkIntervals(5); wid.push_back(myDejitterDiff); - myDejitterLabel = new StaticTextWidget(myTab, _font, xpos, ypos + 1, 7 * fontWidth, lineHeight, ""); - // Add paddle speed (digital emulation) ypos += lineHeight + VGAP * 4; myDPaddleSpeed = new SliderWidget(myTab, _font, HBORDER, ypos - 1, 13 * fontWidth, lineHeight, @@ -319,14 +308,13 @@ void InputDialog::loadConfig() // Joystick deadzone myDeadzone->setValue(instance().settings().getInt("joydeadzone")); - // Paddle center & speed (analog) - myPaddleCenter->setValue(instance().settings().getInt("pcenter")); + // Paddle speed (analog) myPaddleSpeed->setValue(instance().settings().getInt("psense")); - - // Paddle speed (digital and mouse) + // Paddle dejitter (analog) myDejitterBase->setValue(instance().settings().getInt("dejitter.base")); myDejitterDiff->setValue(instance().settings().getInt("dejitter.diff")); - updateDejitter(); + + // Paddle speed (digital and mouse) myDPaddleSpeed->setValue(instance().settings().getInt("dsense")); myMPaddleSpeed->setValue(instance().settings().getInt("msense")); @@ -376,11 +364,6 @@ void InputDialog::saveConfig() instance().settings().setValue("joydeadzone", deadzone); Joystick::setDeadZone(deadzone); - // Paddle center (analog) - int center = myPaddleCenter->getValue(); - instance().settings().setValue("pcenter", center); - Paddles::setAnalogCenter(center); - // Paddle speed (analog) int sensitivity = myPaddleSpeed->getValue(); instance().settings().setValue("psense", sensitivity); @@ -453,8 +436,7 @@ void InputDialog::setDefaults() // Joystick deadzone myDeadzone->setValue(0); - // Paddle center & speed (analog) - myPaddleCenter->setValue(0); + // Paddle speed (analog) myPaddleSpeed->setValue(20); // Paddle speed (digital) @@ -466,7 +448,6 @@ void InputDialog::setDefaults() myDejitterBase->setValue(0); myDejitterDiff->setValue(0); #endif - updateDejitter(); myTrackBallSpeed->setValue(10); // AtariVox serial port @@ -625,16 +606,16 @@ void InputDialog::handleCommand(CommandSender* sender, int cmd, myDeadzone->setValueLabel(3200 + 1000 * myDeadzone->getValue()); break; - case kPCenterChanged: - myPaddleCenter->setValueLabel(myPaddleCenter->getValue() * 5); - break; - case kPSpeedChanged: myPaddleSpeed->setValueLabel(Paddles::setAnalogSensitivity(myPaddleSpeed->getValue()) * 100.0 + 0.5); break; - case kDejitterChanged: - updateDejitter(); + case kDejitterAvChanged: + updateDejitterAveraging(); + break; + + case kDejitterReChanged: + updateDejitterReaction(); break; case kDPSpeedChanged: @@ -696,25 +677,19 @@ void InputDialog::handleCommand(CommandSender* sender, int cmd, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void InputDialog::updateDejitter() +void InputDialog::updateDejitterAveraging() { int strength = myDejitterBase->getValue(); - stringstream label; - if (strength) - label << myDejitterBase->getValue(); - else - label << "Off"; + myDejitterBase->setValueLabel(strength ? std::to_string(strength) : "Off"); +} - label << " "; - strength = myDejitterDiff->getValue(); +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void InputDialog::updateDejitterReaction() +{ + int strength = myDejitterDiff->getValue(); - if (strength) - label << myDejitterDiff->getValue(); - else - label << "Off"; - - myDejitterLabel->setLabel(label.str()); + myDejitterDiff->setValueLabel(strength ? std::to_string(strength) : "Off"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/gui/InputDialog.hxx b/src/gui/InputDialog.hxx index b86155fca..0924f514b 100644 --- a/src/gui/InputDialog.hxx +++ b/src/gui/InputDialog.hxx @@ -65,15 +65,16 @@ class InputDialog : public Dialog void handleMouseControlState(); void handleCursorState(); - void updateDejitter(); + void updateDejitterAveraging(); + void updateDejitterReaction(); void eraseEEPROM(); private: enum { kDeadzoneChanged = 'DZch', - kPCenterChanged = 'Pcch', kPSpeedChanged = 'Ppch', - kDejitterChanged = 'Pjch', + kDejitterAvChanged = 'JAch', + kDejitterReChanged = 'JRch', kDPSpeedChanged = 'PDch', kTBSpeedChanged = 'TBch', kDBButtonPressed = 'DBbp', @@ -96,14 +97,12 @@ class InputDialog : public Dialog EditTextWidget* myAVoxPort{nullptr}; SliderWidget* myDeadzone{nullptr}; - SliderWidget* myPaddleCenter{nullptr}; SliderWidget* myPaddleSpeed{nullptr}; SliderWidget* myDejitterBase{nullptr}; SliderWidget* myDejitterDiff{nullptr}; SliderWidget* myDPaddleSpeed{nullptr}; SliderWidget* myMPaddleSpeed{nullptr}; SliderWidget* myTrackBallSpeed{nullptr}; - StaticTextWidget* myDejitterLabel{nullptr}; CheckboxWidget* myAllowAll4{nullptr}; CheckboxWidget* myGrabMouse{nullptr}; CheckboxWidget* myModCombo{nullptr}; diff --git a/src/tools/PropSet.pm b/src/tools/PropSet.pm index 26e57a09e..7cba557f9 100755 --- a/src/tools/PropSet.pm +++ b/src/tools/PropSet.pm @@ -19,11 +19,13 @@ my %prop_type = ( "Controller.Left" => 13, "Controller.Right" => 14, "Controller.SwapPaddles" => 15, - "Controller.MouseAxis" => 16, - "Display.Format" => 17, - "Display.VCenter" => 18, - "Display.Phosphor" => 19, - "Display.PPBlend" => 20 + "Controller.PaddlesXCenter" => 16, + "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", @@ -42,6 +44,8 @@ my @prop_type_as_string = ( "Controller.Left", "Controller.Right", "Controller.SwapPaddles", + "Controller.PaddlesXCenter", + "Controller.PaddlesYCenter", "Controller.MouseAxis", "Display.Format", "Display.VCenter", From a374a5b9c65de3db2b5de68618fc8be4e6540edf Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 26 Mar 2020 13:48:46 +0100 Subject: [PATCH 045/377] display write destination address in debugger (implements #74) --- src/debugger/CartDebug.cxx | 12 ++++++++++++ src/debugger/CartDebug.hxx | 6 ++++++ src/debugger/CpuDebug.cxx | 2 ++ src/debugger/CpuDebug.hxx | 2 +- src/debugger/Debugger.cxx | 6 ++++-- src/debugger/DebuggerParser.cxx | 8 ++++---- src/debugger/gui/CpuWidget.cxx | 13 +++++++++---- src/debugger/gui/CpuWidget.hxx | 1 + src/emucore/M6502.cxx | 4 ++-- src/emucore/M6502.hxx | 16 +++++++++++++++- src/yacc/YaccParser.cxx | 9 +++++++-- 11 files changed, 63 insertions(+), 16 deletions(-) diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index 5b54563f5..5d2654764 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -156,6 +156,18 @@ void CartDebug::saveOldState() } } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int CartDebug::lastReadAddress() +{ + return mySystem.m6502().lastReadAddress(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int CartDebug::lastWriteAddress() +{ + return mySystem.m6502().lastWriteAddress(); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int CartDebug::lastReadBaseAddress() { diff --git a/src/debugger/CartDebug.hxx b/src/debugger/CartDebug.hxx index 57a9e1319..3561b3d3e 100644 --- a/src/debugger/CartDebug.hxx +++ b/src/debugger/CartDebug.hxx @@ -104,6 +104,12 @@ class CartDebug : public DebuggerSystem CartDebugWidget* getDebugWidget() const { return myDebugWidget; } void setDebugWidget(CartDebugWidget* w) { myDebugWidget = w; } + + // Return the address of the last CPU read + int lastReadAddress(); + // Return the address of the last CPU write + int lastWriteAddress(); + // Return the base (= non-mirrored) address of the last CPU read int lastReadBaseAddress(); // Return the base (= non-mirrored) address of the last CPU write diff --git a/src/debugger/CpuDebug.cxx b/src/debugger/CpuDebug.cxx index 549d512e3..b7d26c3b5 100644 --- a/src/debugger/CpuDebug.cxx +++ b/src/debugger/CpuDebug.cxx @@ -46,6 +46,7 @@ const DebuggerState& CpuDebug::getState() myState.srcA = my6502.lastSrcAddressA(); myState.srcX = my6502.lastSrcAddressX(); myState.srcY = my6502.lastSrcAddressY(); + myState.dest = my6502.lastWriteAddress(); Debugger::set_bits(myState.PS, myState.PSbits); @@ -66,6 +67,7 @@ void CpuDebug::saveOldState() myOldState.srcA = my6502.lastSrcAddressA(); myOldState.srcX = my6502.lastSrcAddressX(); myOldState.srcY = my6502.lastSrcAddressY(); + myOldState.dest = my6502.lastWriteAddress(); Debugger::set_bits(myOldState.PS, myOldState.PSbits); } diff --git a/src/debugger/CpuDebug.hxx b/src/debugger/CpuDebug.hxx index a9d9bc99c..dd016fe88 100644 --- a/src/debugger/CpuDebug.hxx +++ b/src/debugger/CpuDebug.hxx @@ -31,7 +31,7 @@ class CpuState : public DebuggerState { public: int PC{0}, SP{0}, PS{0}, A{0}, X{0}, Y{0}; - int srcS{0}, srcA{0}, srcX{0}, srcY{0}; + int srcS{0}, srcA{0}, srcX{0}, srcY{0}, dest{0}; BoolArray PSbits; }; diff --git a/src/debugger/Debugger.cxx b/src/debugger/Debugger.cxx index 1ccf5e3f1..8cdd525de 100644 --- a/src/debugger/Debugger.cxx +++ b/src/debugger/Debugger.cxx @@ -887,6 +887,8 @@ std::array Debugger::ourPseudoRegisters = { { { "_vblank", "Whether vertical blank is enabled (1 or 0)" }, { "_vsync", "Whether vertical sync is enabled (1 or 0)" } // CPU address access functions: - /*{ "__lastread", "last CPU read address" }, - { "__lastwrite", "last CPU write address" },*/ + /*{ "_lastread", "last CPU read address" }, + { "_lastwrite", "last CPU write address" }, + { "__lastbaseread", "last CPU read base address" }, + { "__lastbasewrite", "last CPU write base address" }*/ } }; diff --git a/src/debugger/DebuggerParser.cxx b/src/debugger/DebuggerParser.cxx index 50ff2daae..f3dfde946 100644 --- a/src/debugger/DebuggerParser.cxx +++ b/src/debugger/DebuggerParser.cxx @@ -2054,18 +2054,18 @@ void DebuggerParser::executeTraps(bool read, bool write, const string& command, if(read) { if(beginRead != endRead) - conditionBuf << "__lastread>=" << Base::toString(beginRead) << "&&__lastread<=" << Base::toString(endRead); + conditionBuf << "__lastbaseread>=" << Base::toString(beginRead) << "&&__lastbaseread<=" << Base::toString(endRead); else - conditionBuf << "__lastread==" << Base::toString(beginRead); + conditionBuf << "__lastbaseread==" << Base::toString(beginRead); } if(read && write) conditionBuf << "||"; if(write) { if(beginWrite != endWrite) - conditionBuf << "__lastwrite>=" << Base::toString(beginWrite) << "&&__lastwrite<=" << Base::toString(endWrite); + conditionBuf << "__lastbasewrite>=" << Base::toString(beginWrite) << "&&__lastbasewrite<=" << Base::toString(endWrite); else - conditionBuf << "__lastwrite==" << Base::toString(beginWrite); + conditionBuf << "__lastbasewrite==" << Base::toString(beginWrite); } // parenthesize provided condition (end) if(hasCond) diff --git a/src/debugger/gui/CpuWidget.cxx b/src/debugger/gui/CpuWidget.cxx index cd6b87640..87aba7d34 100644 --- a/src/debugger/gui/CpuWidget.cxx +++ b/src/debugger/gui/CpuWidget.cxx @@ -93,10 +93,11 @@ CpuWidget::CpuWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& n myCpuDataSrc[i]->setEditable(false, true); src_y += fontHeight+2; } - int swidth = lfont.getStringWidth("Source Address"); - new StaticTextWidget(boss, lfont, xpos, src_y + 4, src_w, - fontHeight, swidth <= src_w ? "Source Address" : "Source Addr", - TextAlign::Center); + + // Last write destination address + new StaticTextWidget(boss, lfont, xpos - fontWidth * 4.5, src_y + 4, "Dest"); + myCpuDataDest = new EditTextWidget(boss, nfont, xpos, src_y + 2, src_w, fontHeight+1); + myCpuDataDest->setEditable(false, true); // Add labels for other CPU registers xpos = x; @@ -325,6 +326,10 @@ void CpuWidget::loadConfig() myCpuDataSrc[3]->setText((srcY != EmptyString ? srcY : Common::Base::toString(state.srcY)), state.srcY != oldstate.srcY); + const string& dest = state.dest < 0 ? "" : cart.getLabel(state.dest, false); + myCpuDataDest->setText((srcY != EmptyString ? dest : Common::Base::toString(state.dest)), + state.dest != oldstate.dest); + // Update the PS register booleans changed.clear(); for(uInt32 i = 0; i < state.PSbits.size(); ++i) diff --git a/src/debugger/gui/CpuWidget.hxx b/src/debugger/gui/CpuWidget.hxx index 5008002f5..5992970f3 100644 --- a/src/debugger/gui/CpuWidget.hxx +++ b/src/debugger/gui/CpuWidget.hxx @@ -76,6 +76,7 @@ class CpuWidget : public Widget, public CommandSender ToggleBitWidget* myPSRegister{nullptr}; EditTextWidget* myPCLabel{nullptr}; std::array myCpuDataSrc{nullptr}; + EditTextWidget* myCpuDataDest{nullptr}; private: // Following constructors and assignment operators not supported diff --git a/src/emucore/M6502.cxx b/src/emucore/M6502.cxx index a69213b69..29863c306 100644 --- a/src/emucore/M6502.cxx +++ b/src/emucore/M6502.cxx @@ -300,8 +300,8 @@ inline void M6502::_execute(uInt64 cycles, DispatchResult& result) mySystem->cart().clearAllRAMAccesses(); #endif // DEBUGGER_SUPPORT - // Reset the peek/poke address pointers - myLastPeekAddress = myLastPokeAddress = myDataAddressForPoke = 0; + // Reset the data poke address pointer + myDataAddressForPoke = 0; try { uInt16 operandAddress = 0, intermediateAddress = 0; diff --git a/src/emucore/M6502.hxx b/src/emucore/M6502.hxx index d4769e0e7..c05fbc522 100644 --- a/src/emucore/M6502.hxx +++ b/src/emucore/M6502.hxx @@ -156,13 +156,27 @@ class M6502 : public Serializable @return The address of the last read */ - uInt16 lastReadBaseAddress() const { return myLastPeekBaseAddress; } + uInt16 lastReadAddress() const { return myLastPeekAddress; } /** Return the last address that was part of a write/poke. @return The address of the last write */ + uInt16 lastWriteAddress() const { return myLastPokeAddress; } + + /** + Return the last (non-mirrored) address that was part of a read/peek. + + @return The address of the last read + */ + uInt16 lastReadBaseAddress() const { return myLastPeekBaseAddress; } + + /** + Return the last (non-mirrored) address that was part of a write/poke. + + @return The address of the last write + */ uInt16 lastWriteBaseAddress() const { return myLastPokeBaseAddress; } /** diff --git a/src/yacc/YaccParser.cxx b/src/yacc/YaccParser.cxx index 696987b38..82163c433 100644 --- a/src/yacc/YaccParser.cxx +++ b/src/yacc/YaccParser.cxx @@ -181,10 +181,15 @@ CartMethod getCartSpecial(char* ch) { if(BSPF::equalsIgnoreCase(ch, "_bank")) return &CartDebug::getPCBank; - else if(BSPF::equalsIgnoreCase(ch, "__lastread")) + + else if(BSPF::equalsIgnoreCase(ch, "__lastbaseread")) return &CartDebug::lastReadBaseAddress; - else if(BSPF::equalsIgnoreCase(ch, "__lastwrite")) + else if(BSPF::equalsIgnoreCase(ch, "__lastbasewrite")) return &CartDebug::lastWriteBaseAddress; + else if(BSPF::equalsIgnoreCase(ch, "__lastread")) + return &CartDebug::lastReadAddress; + else if(BSPF::equalsIgnoreCase(ch, "__lastwrite")) + return &CartDebug::lastWriteAddress; else return nullptr; } From ca0fad75d84f733a2b8369db722c5696b403f212 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Thu, 26 Mar 2020 12:30:33 -0230 Subject: [PATCH 046/377] Fix some minor warnings from Clang. --- src/emucore/Paddles.cxx | 3 ++- src/emucore/Paddles.hxx | 6 +++--- src/gui/InputDialog.cxx | 5 ++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/emucore/Paddles.cxx b/src/emucore/Paddles.cxx index eb6171411..31ba8875d 100644 --- a/src/emucore/Paddles.cxx +++ b/src/emucore/Paddles.cxx @@ -400,7 +400,8 @@ void Paddles::setAnalogYCenter(int ycenter) float Paddles::setAnalogSensitivity(int sensitivity) { // BASE_ANALOG_SENSE * (1.1 ^ 20) = 1.0 - SENSITIVITY = BASE_ANALOG_SENSE * std::pow(1.1, BSPF::clamp(sensitivity, 0, MAX_ANALOG_SENSE)); + SENSITIVITY = BASE_ANALOG_SENSE * std::pow(1.1F, + static_cast(BSPF::clamp(sensitivity, 0, MAX_ANALOG_SENSE))); return SENSITIVITY; } diff --git a/src/emucore/Paddles.hxx b/src/emucore/Paddles.hxx index 7628e840c..57acda958 100644 --- a/src/emucore/Paddles.hxx +++ b/src/emucore/Paddles.hxx @@ -48,7 +48,7 @@ class Paddles : public Controller virtual ~Paddles() = default; public: - static constexpr float BASE_ANALOG_SENSE = 0.148643628f; + static constexpr float BASE_ANALOG_SENSE = 0.148643628F; static constexpr int MAX_ANALOG_SENSE = 30; static constexpr int MIN_ANALOG_CENTER = -10; static constexpr int MAX_ANALOG_CENTER = 30; @@ -95,14 +95,14 @@ class Paddles : public Controller /** Sets the x-center for analog paddles. - @param center Value from -10 to 30, representing the center offset/860 + @param xcenter Value from -10 to 30, representing the center offset/860 */ static void setAnalogXCenter(int xcenter); /** Sets the y-center for analog paddles. - @param center Value from -10 to 30, representing the center offset/860 + @param ycenter Value from -10 to 30, representing the center offset/860 */ static void setAnalogYCenter(int ycenter); diff --git a/src/gui/InputDialog.cxx b/src/gui/InputDialog.cxx index 5b34d1800..5931ed44a 100644 --- a/src/gui/InputDialog.cxx +++ b/src/gui/InputDialog.cxx @@ -229,8 +229,7 @@ void InputDialog::addDevicePortTab() void InputDialog::addMouseTab() { const int lineHeight = _font.getLineHeight(), - fontWidth = _font.getMaxCharWidth(), - fontHeight = _font.getFontHeight(); + fontWidth = _font.getMaxCharWidth(); int ypos, lwidth, pwidth, tabID; WidgetArray wid; VariantList items; @@ -607,7 +606,7 @@ void InputDialog::handleCommand(CommandSender* sender, int cmd, break; case kPSpeedChanged: - myPaddleSpeed->setValueLabel(Paddles::setAnalogSensitivity(myPaddleSpeed->getValue()) * 100.0 + 0.5); + myPaddleSpeed->setValueLabel(Paddles::setAnalogSensitivity(myPaddleSpeed->getValue()) * 100.F + 0.5F); break; case kDejitterAvChanged: From 0a4acb18c5c9358dbcda3eff796a6f6042ce6a8c Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 26 Mar 2020 22:22:52 +0100 Subject: [PATCH 047/377] add detection of color data in DiStella (see #596) --- .gitignore | 2 + Changes.txt | 13 ++- src/common/bspf.hxx | 1 + src/debugger/CartDebug.cxx | 87 +++++++++++++++++- src/debugger/CartDebug.hxx | 23 ++--- src/debugger/Debugger.cxx | 12 +-- src/debugger/Debugger.hxx | 12 +-- src/debugger/DiStella.cxx | 139 +++++++++++++++++++++++++---- src/debugger/DiStella.hxx | 9 +- src/debugger/gui/RomListWidget.cxx | 3 +- src/emucore/Cart.cxx | 2 +- src/emucore/Cart.hxx | 2 +- src/emucore/Cart4A50.cxx | 4 +- src/emucore/Cart4A50.hxx | 4 +- src/emucore/CartAR.cxx | 4 +- src/emucore/CartAR.hxx | 4 +- src/emucore/Device.hxx | 4 +- src/emucore/M6502.cxx | 4 +- src/emucore/M6502.hxx | 6 +- src/emucore/M6532.cxx | 4 +- src/emucore/M6532.hxx | 10 +-- src/emucore/System.cxx | 8 +- src/emucore/System.hxx | 10 +-- src/emucore/tia/TIA.cxx | 34 ++++++- src/emucore/tia/TIA.hxx | 6 +- 25 files changed, 318 insertions(+), 89 deletions(-) diff --git a/.gitignore b/.gitignore index 5524d520a..8e6d3e86a 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,5 @@ src/**/*.psess src/**/*.vspx src/**/**.pdb Stella.xcscheme +src/tools/fonts/* + diff --git a/Changes.txt b/Changes.txt index 5d8291b4f..5dbc6047e 100644 --- a/Changes.txt +++ b/Changes.txt @@ -13,11 +13,16 @@ =========================================================================== 6.1 to 6.2: (??? ??, 2020) - * Paddle centering and sensitivity can be adjusted now - * 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. + * Added that paddle centering and sensitivity can be adjusted now (TOOD: Doc) + + * 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. (TOOD: Doc) + + * Added displaying last write address in debugger. (TOOD: Doc) + + * Added detection of color data in DiStella. (TOOD: Doc) 6.0.2 to 6.1: (March 22, 2020) diff --git a/src/common/bspf.hxx b/src/common/bspf.hxx index e7cc60024..06333b13c 100644 --- a/src/common/bspf.hxx +++ b/src/common/bspf.hxx @@ -84,6 +84,7 @@ using ByteArray = std::vector; using ShortArray = std::vector; using StringList = std::vector; using ByteBuffer = std::unique_ptr; // NOLINT +using WordBuffer = std::unique_ptr; // NOLINT // We use KB a lot; let's make a literal for it constexpr uInt32 operator "" _KB(unsigned long long size) diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index 5d2654764..6199bb306 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -900,6 +900,21 @@ string CartDebug::loadConfigFile() buf >> hex >> start >> hex >> end; addDirective(CartDebug::PGFX, start, end, currentbank); } + else if(BSPF::startsWithIgnoreCase(directive, "COL")) + { + buf >> hex >> start >> hex >> end; + addDirective(CartDebug::COL, start, end, currentbank); + } + else if(BSPF::startsWithIgnoreCase(directive, "PCOL")) + { + buf >> hex >> start >> hex >> end; + addDirective(CartDebug::PCOL, start, end, currentbank); + } + else if(BSPF::startsWithIgnoreCase(directive, "BCOL")) + { + buf >> hex >> start >> hex >> end; + addDirective(CartDebug::BCOL, start, end, currentbank); + } else if(BSPF::startsWithIgnoreCase(directive, "DATA")) { buf >> hex >> start >> hex >> end; @@ -966,6 +981,25 @@ string CartDebug::saveConfigFile() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartDebug::saveDisassembly() { + string NTSC_COLOR[16] = { + "BLACK", "YELLOW", "BROWN", "ORANGE", + "RED", "MAUVE", "VIOLET", "PURPLE", + "BLUE", "BLUE_CYAN", "CYAN", "CYAN_GREEN", + "GREEN", "GREEN_YELLOW", "GREEN_BEIGE", "BEIGE" + }; + string PAL_COLOR[16] = { + "BLACK0", "BLACK1", "YELLOW", "GREEN_YELLOW", + "ORANGE", "GREEN", "RED", "CYAN_GREEN", + "MAUVE", "CYAN", "VIOLET", "BLUE_CYAN", + "PURPLE", "BLUE", "BLACKE", "BLACKF" + }; + string SECAM_COLOR[8] = { + "BLACK", "BLUE", "RED", "PURPLE", + "GREEN", "CYAN", "YELLOW", "WHITE" + }; + bool isNTSC = myConsole.timing() == ConsoleTiming::ntsc; + bool isPAL = myConsole.timing() == ConsoleTiming::pal; + if(myDisasmFile == "") { const string& propsname = @@ -1064,6 +1098,18 @@ string CartDebug::saveDisassembly() buf << ALIGN(13) << "|" << "$" << Base::HEX4 << tag.address << " (P)"; break; } + case CartDebug::COL: + buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 12) << "; $" << Base::HEX4 << tag.address << " (Px)"; + break; + + case CartDebug::PCOL: + buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 12) << "; $" << Base::HEX4 << tag.address << " (PF)"; + break; + + case CartDebug::BCOL: + buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 12) << "; $" << Base::HEX4 << tag.address << " (BK)"; + break; + case CartDebug::DATA: { buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 8 * 4 - 1) << "; $" << Base::HEX4 << tag.address << " (D)"; @@ -1097,6 +1143,27 @@ string CartDebug::saveDisassembly() << "; ! = page crossed, 1 cycle penalty\n" << "\n processor 6502\n\n"; + out << "\n;-----------------------------------------------------------\n" + << "; Color constants\n" + << ";-----------------------------------------------------------\n\n"; + + if(isNTSC) + { + for(int i = 0; i < 16; ++i) + out << ALIGN(16) << NTSC_COLOR[i] << " = $" << Base::HEX2 << (i << 4) << "\n"; + } + else if(isPAL) + { + for(int i = 0; i < 16; ++i) + out << ALIGN(16) << PAL_COLOR[i] << " = $" << Base::HEX2 << (i << 4) << "\n"; + } + else + { + for(int i = 0; i < 8; ++i) + out << ALIGN(16) << SECAM_COLOR[i] << " = $" << Base::HEX1 << (i << 1) << "\n"; + } + out << "\n"; + bool addrUsed = false; for(uInt16 addr = 0x00; addr <= 0x0F; ++addr) addrUsed = addrUsed || myReserved.TIARead[addr] || (mySystem.getAccessFlags(addr) & WRITE); @@ -1104,6 +1171,7 @@ string CartDebug::saveDisassembly() addrUsed = addrUsed || myReserved.TIAWrite[addr] || (mySystem.getAccessFlags(addr) & DATA); for(uInt16 addr = 0x00; addr <= 0x17; ++addr) addrUsed = addrUsed || myReserved.IOReadWrite[addr]; + if(addrUsed) { out << "\n;-----------------------------------------------------------\n" @@ -1393,7 +1461,7 @@ void CartDebug::addressTypeAsString(ostream& buf, uInt16 addr) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -CartDebug::DisasmType CartDebug::disasmTypeAbsolute(uInt8 flags) const +CartDebug::DisasmType CartDebug::disasmTypeAbsolute(uInt16 flags) const { if(flags & CartDebug::CODE) return CartDebug::CODE; @@ -1403,6 +1471,12 @@ CartDebug::DisasmType CartDebug::disasmTypeAbsolute(uInt8 flags) const return CartDebug::GFX; else if(flags & CartDebug::PGFX) return CartDebug::PGFX; + else if(flags & CartDebug::COL) + return CartDebug::COL; + else if(flags & CartDebug::PCOL) + return CartDebug::PCOL; + else if(flags & CartDebug::BCOL) + return CartDebug::BCOL; else if(flags & CartDebug::DATA) return CartDebug::DATA; else if(flags & CartDebug::ROW) @@ -1420,6 +1494,9 @@ void CartDebug::disasmTypeAsString(ostream& buf, DisasmType type) const case CartDebug::TCODE: buf << "TCODE"; break; case CartDebug::GFX: buf << "GFX"; break; case CartDebug::PGFX: buf << "PGFX"; break; + case CartDebug::COL: buf << "COL"; break; + case CartDebug::PCOL: buf << "PCOL"; break; + case CartDebug::BCOL: buf << "BCOL"; break; case CartDebug::DATA: buf << "DATA"; break; case CartDebug::ROW: buf << "ROW"; break; case CartDebug::REFERENCED: @@ -1429,7 +1506,7 @@ void CartDebug::disasmTypeAsString(ostream& buf, DisasmType type) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartDebug::disasmTypeAsString(ostream& buf, uInt8 flags) const +void CartDebug::disasmTypeAsString(ostream& buf, uInt16 flags) const { if(flags) { @@ -1441,6 +1518,12 @@ void CartDebug::disasmTypeAsString(ostream& buf, uInt8 flags) const buf << "GFX "; if(flags & CartDebug::PGFX) buf << "PGFX "; + if(flags & CartDebug::COL) + buf << "COL "; + if(flags & CartDebug::PCOL) + buf << "PCOL "; + if(flags & CartDebug::BCOL) + buf << "BCOL "; if(flags & CartDebug::DATA) buf << "DATA "; if(flags & CartDebug::ROW) diff --git a/src/debugger/CartDebug.hxx b/src/debugger/CartDebug.hxx index 3561b3d3e..e331cc585 100644 --- a/src/debugger/CartDebug.hxx +++ b/src/debugger/CartDebug.hxx @@ -60,14 +60,17 @@ class CartDebug : public DebuggerSystem // debugger, or specified in a Distella cfg file, and are listed in order // of decreasing hierarchy // - CODE = 1 << 7, // 0x80, disassemble-able code segments - TCODE = 1 << 6, // 0x40, (tentative) disassemble-able code segments - GFX = 1 << 5, // 0x20, addresses loaded into GRPx registers - PGFX = 1 << 4, // 0x10, addresses loaded into PFx registers - DATA = 1 << 3, // 0x08, addresses loaded into registers other than GRPx / PFx - ROW = 1 << 2, // 0x04, all other addresses + CODE = 1 << 10, // 0x400, disassemble-able code segments + TCODE = 1 << 9, // 0x200, (tentative) disassemble-able code segments + GFX = 1 << 8, // 0x100, addresses loaded into GRPx registers + PGFX = 1 << 7, // 0x080, addresses loaded into PFx registers + COL = 1 << 6, // 0x040, addresses loaded into COLUPx registers + PCOL = 1 << 5, // 0x010, addresses loaded into COLUPF register + BCOL = 1 << 4, // 0x010, addresses loaded into COLUBK register + DATA = 1 << 3, // 0x008, addresses loaded into registers other than GRPx / PFx + ROW = 1 << 2, // 0x004, all other addresses // special type for poke() - WRITE = TCODE // 0x40, address written to + WRITE = TCODE // 0x200, address written to }; struct DisassemblyTag { DisasmType type{NONE}; @@ -263,7 +266,7 @@ class CartDebug : public DebuggerSystem using LabelToAddr = std::map>; - using AddrTypeArray = std::array; + using AddrTypeArray = std::array; struct DirectiveTag { DisasmType type{NONE}; @@ -305,14 +308,14 @@ class CartDebug : public DebuggerSystem void getBankDirectives(ostream& buf, BankInfo& info) const; // Get disassembly enum type from 'flags', taking precendence into account - DisasmType disasmTypeAbsolute(uInt8 flags) const; + DisasmType disasmTypeAbsolute(uInt16 flags) const; // Convert disassembly enum type to corresponding string and append to buf void disasmTypeAsString(ostream& buf, DisasmType type) const; // Convert all disassembly types in 'flags' to corresponding string and // append to buf - void disasmTypeAsString(ostream& buf, uInt8 flags) const; + void disasmTypeAsString(ostream& buf, uInt16 flags) const; private: const OSystem& myOSystem; diff --git a/src/debugger/Debugger.cxx b/src/debugger/Debugger.cxx index 8cdd525de..ce712bf1f 100644 --- a/src/debugger/Debugger.cxx +++ b/src/debugger/Debugger.cxx @@ -440,19 +440,19 @@ bool Debugger::writeTrap(uInt16 t) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 Debugger::peek(uInt16 addr, uInt8 flags) +uInt8 Debugger::peek(uInt16 addr, uInt16 flags) { return mySystem.peek(addr, flags); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 Debugger::dpeek(uInt16 addr, uInt8 flags) +uInt16 Debugger::dpeek(uInt16 addr, uInt16 flags) { return uInt16(mySystem.peek(addr, flags) | (mySystem.peek(addr+1, flags) << 8)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Debugger::poke(uInt16 addr, uInt8 value, uInt8 flags) +void Debugger::poke(uInt16 addr, uInt8 value, uInt16 flags) { mySystem.poke(addr, value, flags); } @@ -464,13 +464,13 @@ M6502& Debugger::m6502() const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int Debugger::peekAsInt(int addr, uInt8 flags) +int Debugger::peekAsInt(int addr, uInt16 flags) { return mySystem.peek(uInt16(addr), flags); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int Debugger::dpeekAsInt(int addr, uInt8 flags) +int Debugger::dpeekAsInt(int addr, uInt16 flags) { return mySystem.peek(uInt16(addr), flags) | (mySystem.peek(uInt16(addr+1), flags) << 8); @@ -483,7 +483,7 @@ int Debugger::getAccessFlags(uInt16 addr) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Debugger::setAccessFlags(uInt16 addr, uInt8 flags) +void Debugger::setAccessFlags(uInt16 addr, uInt16 flags) { mySystem.setAccessFlags(addr, flags); } diff --git a/src/debugger/Debugger.hxx b/src/debugger/Debugger.hxx index 7e9ad0bc1..738404552 100644 --- a/src/debugger/Debugger.hxx +++ b/src/debugger/Debugger.hxx @@ -243,18 +243,18 @@ class Debugger : public DialogContainer static Debugger& debugger() { return *myStaticDebugger; } /** Convenience methods to access peek/poke from System */ - uInt8 peek(uInt16 addr, uInt8 flags = 0); - uInt16 dpeek(uInt16 addr, uInt8 flags = 0); - void poke(uInt16 addr, uInt8 value, uInt8 flags = 0); + uInt8 peek(uInt16 addr, uInt16 flags = 0); + uInt16 dpeek(uInt16 addr, uInt16 flags = 0); + void poke(uInt16 addr, uInt8 value, uInt16 flags = 0); /** Convenience method to access the 6502 from System */ M6502& m6502() const; /** These are now exposed so Expressions can use them. */ - int peekAsInt(int addr, uInt8 flags = 0); - int dpeekAsInt(int addr, uInt8 flags = 0); + int peekAsInt(int addr, uInt16 flags = 0); + int dpeekAsInt(int addr, uInt16 flags = 0); int getAccessFlags(uInt16 addr) const; - void setAccessFlags(uInt16 addr, uInt8 flags); + void setAccessFlags(uInt16 addr, uInt16 flags); uInt32 getBaseAddress(uInt32 addr, bool read); diff --git a/src/debugger/DiStella.cxx b/src/debugger/DiStella.cxx index 9ee79c61e..235b2d9da 100644 --- a/src/debugger/DiStella.cxx +++ b/src/debugger/DiStella.cxx @@ -125,14 +125,25 @@ void DiStella::disasm(uInt32 distart, int pass) goto FIX_LAST; if (checkBits(myPC, CartDebug::GFX | CartDebug::PGFX, - CartDebug::CODE)) { + CartDebug::CODE)) + { if (pass == 2) mark(myPC + myOffset, CartDebug::VALID_ENTRY); if (pass == 3) outputGraphics(); ++myPC; + } else if (checkBits(myPC, CartDebug::COL | CartDebug::PCOL | CartDebug::BCOL, + CartDebug::CODE | CartDebug::GFX | CartDebug::PGFX)) + { + if (pass == 2) + mark(myPC + myOffset, CartDebug::VALID_ENTRY); + if (pass == 3) + outputColors(); + ++myPC; } else if (checkBits(myPC, CartDebug::DATA, - CartDebug::CODE | CartDebug::GFX | CartDebug::PGFX)) { + CartDebug::CODE | CartDebug::GFX | CartDebug::PGFX | + CartDebug::COL | CartDebug::PCOL | CartDebug::BCOL)) + { if (pass == 2) mark(myPC + myOffset, CartDebug::VALID_ENTRY); if (pass == 3) @@ -140,7 +151,9 @@ void DiStella::disasm(uInt32 distart, int pass) else ++myPC; } else if (checkBits(myPC, CartDebug::ROW, - CartDebug::CODE | CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX)) { + CartDebug::CODE | + CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX | + CartDebug::COL | CartDebug::PCOL | CartDebug::BCOL)) { FIX_LAST: if (pass == 2) mark(myPC + myOffset, CartDebug::VALID_ENTRY); @@ -606,12 +619,13 @@ void DiStella::disasmPass1(CartDebug::AddressList& debuggerAddresses) // in the emulation core indicate that the CODE range has finished // Therefore, we stop at the first such address encountered for (uInt32 k = pcBeg; k <= myPCEnd; ++k) { - if (checkBits(k, CartDebug::CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX, - CartDebug::CODE)) { + if (checkBits(k, CartDebug::CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX | + CartDebug::COL | CartDebug::PCOL | CartDebug::BCOL, + CartDebug::CODE)) { //if (Debugger::debugger().getAccessFlags(k) & // (CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX)) { // TODO: this should never happen, remove when we are sure - // TODO: NOT USED: uInt8 flags = Debugger::debugger().getAccessFlags(k); + // TODO: NOT USED: uInt16 flags = Debugger::debugger().getAccessFlags(k); myPCEnd = k - 1; break; } @@ -667,8 +681,9 @@ void DiStella::disasmPass1(CartDebug::AddressList& debuggerAddresses) } // Must be ROW / unused bytes - if (!checkBit(k, CartDebug::CODE | CartDebug::GFX | - CartDebug::PGFX | CartDebug::DATA)) + if (!checkBit(k, CartDebug::CODE | CartDebug::GFX | CartDebug::PGFX | + CartDebug::COL | CartDebug::PCOL | CartDebug::BCOL | + CartDebug::DATA)) mark(k + myOffset, CartDebug::ROW); } } @@ -685,7 +700,9 @@ void DiStella::disasmFromAddress(uInt32 distart) while (myPC <= myAppData.end) { // abort when we reach non-code areas - if (checkBits(myPC, CartDebug::CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX, CartDebug::CODE)) { + if (checkBits(myPC, CartDebug::CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX | + CartDebug::COL | CartDebug::PCOL | CartDebug::BCOL, + CartDebug::CODE)) { myPCEnd = (myPC - 1) + myOffset; return; } @@ -823,7 +840,7 @@ void DiStella::disasmFromAddress(uInt32 distart) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int DiStella::mark(uInt32 address, uInt8 mask, bool directive) +int DiStella::mark(uInt32 address, uInt16 mask, bool directive) { /*----------------------------------------------------------------------- For any given offset and code range... @@ -896,16 +913,16 @@ int DiStella::mark(uInt32 address, uInt8 mask, bool directive) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool DiStella::checkBit(uInt16 address, uInt8 mask, bool useDebugger) const +bool DiStella::checkBit(uInt16 address, uInt16 mask, bool useDebugger) const { // The REFERENCED and VALID_ENTRY flags are needed for any inspection of // an address // Since they're set only in the labels array (as the lower two bits), // they must be included in the other bitfields - uInt8 label = myLabels[address & myAppData.end], + uInt16 label = myLabels[address & myAppData.end], lastbits = label & 0x03, - directive = myDirectives[address & myAppData.end] & 0xFC, - debugger = Debugger::debugger().getAccessFlags(address | myOffset) & 0xFC; + directive = myDirectives[address & myAppData.end] & ~0x03, + debugger = Debugger::debugger().getAccessFlags(address | myOffset) & ~0x03; // Any address marked by a manual directive always takes priority if (directive) @@ -918,11 +935,18 @@ bool DiStella::checkBit(uInt16 address, uInt8 mask, bool useDebugger) const return label & mask; } -bool DiStella::checkBits(uInt16 address, uInt8 mask, uInt8 notMask, bool useDebugger) const +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool DiStella::checkBits(uInt16 address, uInt16 mask, uInt16 notMask, bool useDebugger) const { return checkBit(address, mask, useDebugger) && !checkBit(address, notMask, useDebugger); } +/*bool DiStella::isType(uInt16 address) const +{ + return checkBits(address, CartDebug::GFX | CartDebug::PGFX | + CartDebug::COL | CartDebug::PCOL | CartDebug::BCOL); +}*/ + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool DiStella::check_range(uInt16 beg, uInt16 end) const { @@ -999,18 +1023,29 @@ void DiStella::addEntry(CartDebug::DisasmType type) Debugger::debugger().setAccessFlags(tag.address, CartDebug::TCODE); } break; + case CartDebug::GFX: case CartDebug::PGFX: getline(myDisasmBuf, tag.disasm, '\''); getline(myDisasmBuf, tag.bytes); break; + + case CartDebug::COL: + case CartDebug::PCOL: + case CartDebug::BCOL: + getline(myDisasmBuf, tag.disasm, '\''); + getline(myDisasmBuf, tag.bytes); + break; + case CartDebug::DATA: getline(myDisasmBuf, tag.disasm, '\''); getline(myDisasmBuf, tag.bytes); break; + case CartDebug::ROW: getline(myDisasmBuf, tag.disasm); break; + case CartDebug::NONE: default: // should never happen tag.disasm = " "; @@ -1044,7 +1079,7 @@ void DiStella::outputGraphics() myDisasmBuf << ".byte $" << Base::HEX2 << int(byte) << " |"; for (uInt8 i = 0, c = byte; i < 8; ++i, c <<= 1) myDisasmBuf << ((c > 127) ? bitString : " "); - myDisasmBuf << "| $" << Base::HEX4 << myPC + myOffset << "'"; + myDisasmBuf << "| $" << Base::HEX4 << myPC + myOffset << "'"; if (mySettings.gfxFormat == Base::Fmt::_2) myDisasmBuf << Base::toString(byte, Base::Fmt::_2_8); else @@ -1053,6 +1088,74 @@ void DiStella::outputGraphics() addEntry(isPGfx ? CartDebug::PGFX : CartDebug::GFX); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void DiStella::outputColors() +{ + string NTSC_COLOR[16] = { + "BLACK", "YELLOW", "BROWN", "ORANGE", + "RED", "MAUVE", "VIOLET", "PURPLE", + "BLUE", "BLUE_CYAN", "CYAN", "CYAN_GREEN", + "GREEN", "GREEN_YELLOW", "GREEN_BEIGE", "BEIGE" + }; + string PAL_COLOR[16] = { + "BLACK0", "BLACK1", "YELLOW", "GREEN_YELLOW", + "ORANGE", "GREEN", "RED", "CYAN_GREEN", + "MAUVE", "CYAN", "VIOLET", "BLUE_CYAN", + "PURPLE", "BLUE", "BLACKE", "BLACKF" + }; + string SECAM_COLOR[8] = { + "BLACK", "BLUE", "RED", "PURPLE", + "GREEN", "CYAN", "YELLOW", "WHITE" + }; + + uInt8 byte = Debugger::debugger().peek(myPC + myOffset); + + // add extra spacing line when switching from non-colors to colors + if(mySegType != CartDebug::COL && mySegType != CartDebug::NONE) + { + myDisasmBuf << " ' ' "; + addEntry(CartDebug::NONE); + } + mySegType = CartDebug::COL; + + // output label/address + if(checkBit(myPC, CartDebug::REFERENCED)) + myDisasmBuf << Base::HEX4 << myPC + myOffset << "'L" << Base::HEX4 << myPC + myOffset << "'"; + else + myDisasmBuf << Base::HEX4 << myPC + myOffset << "' '"; + + // output color + string color; + + myDisasmBuf << ".byte "; + if(myDbg.myConsole.timing() == ConsoleTiming::ntsc) + { + color = NTSC_COLOR[byte >> 4]; + myDisasmBuf << color << "|$" << Base::HEX1 << (byte & 0xf); + } + else if(myDbg.myConsole.timing() == ConsoleTiming::pal) + { + color = PAL_COLOR[byte >> 4]; + myDisasmBuf << color << "|$" << Base::HEX1 << (byte & 0xf); + } + else + { + color = SECAM_COLOR[(byte >> 1) & 0x7]; + myDisasmBuf << "$" << Base::HEX1 << (byte >> 4) << "|" << color; + } + myDisasmBuf << std::setw(16 - color.length()) << std::setfill(' '); + + // output address + myDisasmBuf << "; $" << Base::HEX4 << myPC + myOffset << " " + << (checkBit(myPC, CartDebug::COL) ? "(Px)" : checkBit(myPC, CartDebug::PCOL) ? "(PF)" : "(BK)"); + + // output color value + myDisasmBuf << "'" << Base::HEX2 << int(byte); + + addEntry(checkBit(myPC, CartDebug::COL) ? CartDebug::COL : + checkBit(myPC, CartDebug::PCOL) ? CartDebug::PCOL : CartDebug::BCOL); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DiStella::outputBytes(CartDebug::DisasmType type) { @@ -1097,7 +1200,9 @@ void DiStella::outputBytes(CartDebug::DisasmType type) ++myPC; } isType = checkBits(myPC, type, - CartDebug::CODE | (type != CartDebug::DATA ? CartDebug::DATA : 0) | CartDebug::GFX | CartDebug::PGFX); + CartDebug::CODE | (type != CartDebug::DATA ? CartDebug::DATA : 0) | + CartDebug::GFX | CartDebug::PGFX | + CartDebug::COL | CartDebug::PCOL | CartDebug::BCOL); referenced = checkBit(myPC, CartDebug::REFERENCED); } if (!lineEmpty) diff --git a/src/debugger/DiStella.hxx b/src/debugger/DiStella.hxx index 16da2b6ba..830835a02 100644 --- a/src/debugger/DiStella.hxx +++ b/src/debugger/DiStella.hxx @@ -87,11 +87,12 @@ class DiStella void disasmFromAddress(uInt32 distart); bool check_range(uInt16 start, uInt16 end) const; - int mark(uInt32 address, uInt8 mask, bool directive = false); - bool checkBit(uInt16 address, uInt8 mask, bool useDebugger = true) const; - - bool checkBits(uInt16 address, uInt8 mask, uInt8 notMask, bool useDebugger = true) const; + int mark(uInt32 address, uInt16 mask, bool directive = false); + bool checkBit(uInt16 address, uInt16 mask, bool useDebugger = true) const; + bool checkBits(uInt16 address, uInt16 mask, uInt16 notMask, bool useDebugger = true) const; + //bool isType(uInt16 address) const; void outputGraphics(); + void outputColors(); void outputBytes(CartDebug::DisasmType type); // Convenience methods to generate appropriate labels diff --git a/src/debugger/gui/RomListWidget.cxx b/src/debugger/gui/RomListWidget.cxx index 8a705f3b1..fdc24fb71 100644 --- a/src/debugger/gui/RomListWidget.cxx +++ b/src/debugger/gui/RomListWidget.cxx @@ -511,7 +511,8 @@ void RomListWidget::drawWidget(bool hilite) // Bytes are only editable if they represent code, graphics, or accessible data // Otherwise, the disassembly should get all remaining space - if(dlist[pos].type & (CartDebug::CODE|CartDebug::GFX|CartDebug::PGFX|CartDebug::DATA)) + if(dlist[pos].type & (CartDebug::CODE|CartDebug::GFX|CartDebug::PGFX| + CartDebug::COL|CartDebug::PCOL|CartDebug::BCOL|CartDebug::DATA)) { if(dlist[pos].type == CartDebug::CODE) { diff --git a/src/emucore/Cart.cxx b/src/emucore/Cart.cxx index 3f1f53690..cd40f886b 100644 --- a/src/emucore/Cart.cxx +++ b/src/emucore/Cart.cxx @@ -117,7 +117,7 @@ void Cartridge::pokeRAM(uInt8& dest, uInt16 address, uInt8 value) void Cartridge::createCodeAccessBase(size_t size) { #ifdef DEBUGGER_SUPPORT - myCodeAccessBase = make_unique(size); + myCodeAccessBase = make_unique(size); std::fill_n(myCodeAccessBase.get(), size, CartDebug::ROW); #else myCodeAccessBase = nullptr; diff --git a/src/emucore/Cart.hxx b/src/emucore/Cart.hxx index 9e8d40a4b..a7bd1da6b 100644 --- a/src/emucore/Cart.hxx +++ b/src/emucore/Cart.hxx @@ -322,7 +322,7 @@ class Cartridge : public Device // The array containing information about every byte of ROM indicating // whether it is used as code. - ByteBuffer myCodeAccessBase; + WordBuffer myCodeAccessBase; // Contains address of illegal RAM write access or 0 uInt16 myRamWriteAccess{0}; diff --git a/src/emucore/Cart4A50.cxx b/src/emucore/Cart4A50.cxx index ead5d9285..ca634ed09 100644 --- a/src/emucore/Cart4A50.cxx +++ b/src/emucore/Cart4A50.cxx @@ -182,7 +182,7 @@ bool Cartridge4A50::poke(uInt16 address, uInt8 value) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 Cartridge4A50::getAccessFlags(uInt16 address) const +uInt16 Cartridge4A50::getAccessFlags(uInt16 address) const { if((address & 0x1800) == 0x1000) // 2K region from 0x1000 - 0x17ff { @@ -214,7 +214,7 @@ uInt8 Cartridge4A50::getAccessFlags(uInt16 address) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge4A50::setAccessFlags(uInt16 address, uInt8 flags) +void Cartridge4A50::setAccessFlags(uInt16 address, uInt16 flags) { if((address & 0x1800) == 0x1000) // 2K region from 0x1000 - 0x17ff { diff --git a/src/emucore/Cart4A50.hxx b/src/emucore/Cart4A50.hxx index 863b1a020..210a2604b 100644 --- a/src/emucore/Cart4A50.hxx +++ b/src/emucore/Cart4A50.hxx @@ -158,14 +158,14 @@ class Cartridge4A50 : public Cartridge @param address The address to query */ - uInt8 getAccessFlags(uInt16 address) const override; + uInt16 getAccessFlags(uInt16 address) const override; /** Change the given address to use the given disassembly flags. @param address The address to modify @param flags A bitfield of DisasmType directives for the given address */ - void setAccessFlags(uInt16 address, uInt8 flags) override; + void setAccessFlags(uInt16 address, uInt16 flags) override; /** Check all possible hotspots diff --git a/src/emucore/CartAR.cxx b/src/emucore/CartAR.cxx index b095d446a..59ad6f03f 100644 --- a/src/emucore/CartAR.cxx +++ b/src/emucore/CartAR.cxx @@ -191,14 +191,14 @@ bool CartridgeAR::poke(uInt16 addr, uInt8) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeAR::getAccessFlags(uInt16 address) const +uInt16 CartridgeAR::getAccessFlags(uInt16 address) const { return myCodeAccessBase[(address & 0x07FF) + myImageOffset[(address & 0x0800) ? 1 : 0]]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeAR::setAccessFlags(uInt16 address, uInt8 flags) +void CartridgeAR::setAccessFlags(uInt16 address, uInt16 flags) { myCodeAccessBase[(address & 0x07FF) + myImageOffset[(address & 0x0800) ? 1 : 0]] |= flags; diff --git a/src/emucore/CartAR.hxx b/src/emucore/CartAR.hxx index 039d19bb8..09dc11b3a 100644 --- a/src/emucore/CartAR.hxx +++ b/src/emucore/CartAR.hxx @@ -164,14 +164,14 @@ class CartridgeAR : public Cartridge @param address The address to query */ - uInt8 getAccessFlags(uInt16 address) const override; + uInt16 getAccessFlags(uInt16 address) const override; /** Change the given address to use the given disassembly flags. @param address The address to modify @param flags A bitfield of DisasmType directives for the given address */ - void setAccessFlags(uInt16 address, uInt8 flags) override; + void setAccessFlags(uInt16 address, uInt16 flags) override; // Handle a change to the bank configuration bool bankConfiguration(uInt8 configuration); diff --git a/src/emucore/Device.hxx b/src/emucore/Device.hxx index 444a599af..f405a8739 100644 --- a/src/emucore/Device.hxx +++ b/src/emucore/Device.hxx @@ -102,7 +102,7 @@ class Device : public Serializable @param address The address to modify */ - virtual uInt8 getAccessFlags(uInt16 address) const { return 0; } + virtual uInt16 getAccessFlags(uInt16 address) const { return 0; } /** Change the given address type to use the given disassembly flags @@ -110,7 +110,7 @@ class Device : public Serializable @param address The address to modify @param flags A bitfield of DisasmType directives for the given address */ - virtual void setAccessFlags(uInt16 address, uInt8 flags) { } + virtual void setAccessFlags(uInt16 address, uInt16 flags) { } protected: /// Pointer to the system the device is installed in or the null pointer diff --git a/src/emucore/M6502.cxx b/src/emucore/M6502.cxx index 29863c306..fda514705 100644 --- a/src/emucore/M6502.cxx +++ b/src/emucore/M6502.cxx @@ -104,7 +104,7 @@ void M6502::reset() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -inline uInt8 M6502::peek(uInt16 address, uInt8 flags) +inline uInt8 M6502::peek(uInt16 address, uInt16 flags) { handleHalt(); @@ -144,7 +144,7 @@ inline uInt8 M6502::peek(uInt16 address, uInt8 flags) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -inline void M6502::poke(uInt16 address, uInt8 value, uInt8 flags) +inline void M6502::poke(uInt16 address, uInt8 value, uInt16 flags) { //////////////////////////////////////////////// // TODO - move this logic directly into CartAR diff --git a/src/emucore/M6502.hxx b/src/emucore/M6502.hxx index c05fbc522..dd48315a6 100644 --- a/src/emucore/M6502.hxx +++ b/src/emucore/M6502.hxx @@ -269,7 +269,7 @@ class M6502 : public Serializable @return The byte at the specified address */ - uInt8 peek(uInt16 address, uInt8 flags); + uInt8 peek(uInt16 address, uInt16 flags); /** Change the byte at the specified address to the given value and @@ -278,7 +278,7 @@ class M6502 : public Serializable @param address The address where the value should be stored @param value The value to be stored at the address */ - void poke(uInt16 address, uInt8 value, uInt8 flags = 0); + void poke(uInt16 address, uInt8 value, uInt16 flags = 0); /** Get the 8-bit value of the Processor Status register. @@ -391,7 +391,7 @@ class M6502 : public Serializable /// accessed specifically by a peek or poke command uInt16 myLastPeekBaseAddress{0}, myLastPokeBaseAddress{0}; // Indicates the type of the last access - uInt8 myFlags{0}; + uInt16 myFlags{0}; /// Indicates the last address used to access data by a peek command /// for the CPU registers (S/A/X/Y) diff --git a/src/emucore/M6532.cxx b/src/emucore/M6532.cxx index dec6d9981..80f828f83 100644 --- a/src/emucore/M6532.cxx +++ b/src/emucore/M6532.cxx @@ -467,7 +467,7 @@ void M6532::createAccessBases() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 M6532::getAccessFlags(uInt16 address) const +uInt16 M6532::getAccessFlags(uInt16 address) const { if (address & IO_BIT) return myIOAccessBase[address & IO_MASK]; @@ -478,7 +478,7 @@ uInt8 M6532::getAccessFlags(uInt16 address) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void M6532::setAccessFlags(uInt16 address, uInt8 flags) +void M6532::setAccessFlags(uInt16 address, uInt16 flags) { // ignore none flag if (flags != CartDebug::NONE) { diff --git a/src/emucore/M6532.hxx b/src/emucore/M6532.hxx index bbda58e31..db93414a3 100644 --- a/src/emucore/M6532.hxx +++ b/src/emucore/M6532.hxx @@ -151,14 +151,14 @@ class M6532 : public Device @param address The address to query */ - uInt8 getAccessFlags(uInt16 address) const override; + uInt16 getAccessFlags(uInt16 address) const override; /** Change the given address to use the given disassembly flags. @param address The address to modify @param flags A bitfield of DisasmType directives for the given address */ - void setAccessFlags(uInt16 address, uInt8 flags) override; + void setAccessFlags(uInt16 address, uInt16 flags) override; #endif // DEBUGGER_SUPPORT private: @@ -225,9 +225,9 @@ class M6532 : public Device // The arrays containing information about every byte of RIOT // indicating whether and how (RW) it is used. - std::array myRAMAccessBase; - std::array myStackAccessBase; - std::array myIOAccessBase; + std::array myRAMAccessBase; + std::array myStackAccessBase; + std::array myIOAccessBase; // The array used to skip the first ZP access tracking std::array myZPAccessDelay; #endif // DEBUGGER_SUPPORT diff --git a/src/emucore/System.cxx b/src/emucore/System.cxx index ee9392b03..e40124c2a 100644 --- a/src/emucore/System.cxx +++ b/src/emucore/System.cxx @@ -99,7 +99,7 @@ void System::clearDirtyPages() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 System::peek(uInt16 addr, uInt8 flags) +uInt8 System::peek(uInt16 addr, uInt16 flags) { const PageAccess& access = getPageAccess(addr); @@ -127,7 +127,7 @@ uInt8 System::peek(uInt16 addr, uInt8 flags) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void System::poke(uInt16 addr, uInt8 value, uInt8 flags) +void System::poke(uInt16 addr, uInt8 value, uInt16 flags) { uInt16 page = (addr & ADDRESS_MASK) >> PAGE_SHIFT; const PageAccess& access = myPageAccessTable[page]; @@ -160,7 +160,7 @@ void System::poke(uInt16 addr, uInt8 value, uInt8 flags) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 System::getAccessFlags(uInt16 addr) const +uInt16 System::getAccessFlags(uInt16 addr) const { #ifdef DEBUGGER_SUPPORT const PageAccess& access = getPageAccess(addr); @@ -175,7 +175,7 @@ uInt8 System::getAccessFlags(uInt16 addr) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void System::setAccessFlags(uInt16 addr, uInt8 flags) +void System::setAccessFlags(uInt16 addr, uInt16 flags) { #ifdef DEBUGGER_SUPPORT const PageAccess& access = getPageAccess(addr); diff --git a/src/emucore/System.hxx b/src/emucore/System.hxx index a9cf75cc2..f4423c491 100644 --- a/src/emucore/System.hxx +++ b/src/emucore/System.hxx @@ -202,7 +202,7 @@ class System : public Serializable @return The byte at the specified address */ - uInt8 peek(uInt16 address, uInt8 flags = 0); + uInt8 peek(uInt16 address, uInt16 flags = 0); /** Change the byte at the specified address to the given value. @@ -217,7 +217,7 @@ class System : public Serializable @param address The address where the value should be stored @param value The value to be stored at the address */ - void poke(uInt16 address, uInt8 value, uInt8 flags = 0); + void poke(uInt16 address, uInt8 value, uInt16 flags = 0); /** Lock/unlock the data bus. When the bus is locked, peek() and @@ -236,8 +236,8 @@ class System : public Serializable address. Note that while any flag can be used, the disassembly only really acts on CODE/GFX/PGFX/DATA/ROW. */ - uInt8 getAccessFlags(uInt16 address) const; - void setAccessFlags(uInt16 address, uInt8 flags); + uInt16 getAccessFlags(uInt16 address) const; + void setAccessFlags(uInt16 address, uInt16 flags); public: /** @@ -277,7 +277,7 @@ class System : public Serializable conclusively determine if a section of address space is CODE, even if the disassembler failed to mark it as such. */ - uInt8* codeAccessBase{nullptr}; + uInt16* codeAccessBase{nullptr}; /** Pointer to the device associated with this page or to the system's diff --git a/src/emucore/tia/TIA.cxx b/src/emucore/tia/TIA.cxx index 38beebbcf..145eea6e5 100644 --- a/src/emucore/tia/TIA.cxx +++ b/src/emucore/tia/TIA.cxx @@ -568,26 +568,47 @@ bool TIA::poke(uInt16 address, uInt8 value) break; case COLUBK: + { value &= 0xFE; myBackground.setColor(value); myShadowRegisters[address] = value; + #ifdef DEBUGGER_SUPPORT + uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); + if(dataAddr) + mySystem->setAccessFlags(dataAddr, CartDebug::BCOL); + #endif break; + } case COLUP0: + { value &= 0xFE; myPlayfield.setColorP0(value); myMissile0.setColor(value); myPlayer0.setColor(value); myShadowRegisters[address] = value; + #ifdef DEBUGGER_SUPPORT + uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); + if(dataAddr) + mySystem->setAccessFlags(dataAddr, CartDebug::COL); + #endif break; + } case COLUP1: + { value &= 0xFE; myPlayfield.setColorP1(value); myMissile1.setColor(value); myPlayer1.setColor(value); myShadowRegisters[address] = value; + #ifdef DEBUGGER_SUPPORT + uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); + if(dataAddr) + mySystem->setAccessFlags(dataAddr, CartDebug::COL); + #endif break; + } case CTRLPF: flushLineCache(); @@ -599,9 +620,10 @@ bool TIA::poke(uInt16 address, uInt8 value) break; case COLUPF: + { flushLineCache(); value &= 0xFE; - if (myPFColorDelay) + if(myPFColorDelay) myDelayQueue.push(COLUPF, value, 1); else { @@ -609,7 +631,13 @@ bool TIA::poke(uInt16 address, uInt8 value) myBall.setColor(value); myShadowRegisters[address] = value; } + #ifdef DEBUGGER_SUPPORT + uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); + if(dataAddr) + mySystem->setAccessFlags(dataAddr, CartDebug::PCOL); + #endif break; + } case PF0: { @@ -1891,13 +1919,13 @@ void TIA::createAccessBase() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 TIA::getAccessFlags(uInt16 address) const +uInt16 TIA::getAccessFlags(uInt16 address) const { return myAccessBase[address & TIA_MASK]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::setAccessFlags(uInt16 address, uInt8 flags) +void TIA::setAccessFlags(uInt16 address, uInt16 flags) { // ignore none flag if (flags != CartDebug::NONE) { diff --git a/src/emucore/tia/TIA.hxx b/src/emucore/tia/TIA.hxx index 0b3cb4eaf..acb7ee40e 100644 --- a/src/emucore/tia/TIA.hxx +++ b/src/emucore/tia/TIA.hxx @@ -685,14 +685,14 @@ class TIA : public Device * * @param address The address to query */ - uInt8 getAccessFlags(uInt16 address) const override; + uInt16 getAccessFlags(uInt16 address) const override; /** * Change the given address to use the given disassembly flags. * * @param address The address to modify * @param flags A bitfield of DisasmType directives for the given address */ - void setAccessFlags(uInt16 address, uInt8 flags) override; + void setAccessFlags(uInt16 address, uInt16 flags) override; #endif // DEBUGGER_SUPPORT private: @@ -901,7 +901,7 @@ class TIA : public Device #ifdef DEBUGGER_SUPPORT // The arrays containing information about every byte of TIA // indicating whether and how (RW) it is used. - std::array myAccessBase; + std::array myAccessBase; // The array used to skip the first two TIA access trackings std::array myAccessDelay; From 5fd53520e713cf63bcec5ad5e94fab0b0eb05faa Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 26 Mar 2020 23:26:18 +0100 Subject: [PATCH 048/377] use defined type for disassembly flags --- src/common/bspf.hxx | 1 - src/debugger/CartDebug.cxx | 4 ++-- src/debugger/CartDebug.hxx | 6 ++++-- src/debugger/Debugger.cxx | 14 +++++++------- src/debugger/Debugger.hxx | 15 ++++++++------- src/emucore/Cart.hxx | 3 ++- src/emucore/Cart4A50.cxx | 4 ++-- src/emucore/Cart4A50.hxx | 4 ++-- src/emucore/CartAR.cxx | 4 ++-- src/emucore/CartAR.hxx | 4 ++-- src/emucore/Device.hxx | 5 +++-- src/emucore/M6502.cxx | 4 ++-- src/emucore/M6502.hxx | 5 +++-- src/emucore/M6532.cxx | 4 ++-- src/emucore/M6532.hxx | 4 ++-- src/emucore/System.cxx | 8 ++++---- src/emucore/System.hxx | 11 ++++++----- src/emucore/tia/TIA.cxx | 4 ++-- src/emucore/tia/TIA.hxx | 4 ++-- 19 files changed, 57 insertions(+), 51 deletions(-) diff --git a/src/common/bspf.hxx b/src/common/bspf.hxx index 06333b13c..e7cc60024 100644 --- a/src/common/bspf.hxx +++ b/src/common/bspf.hxx @@ -84,7 +84,6 @@ using ByteArray = std::vector; using ShortArray = std::vector; using StringList = std::vector; using ByteBuffer = std::unique_ptr; // NOLINT -using WordBuffer = std::unique_ptr; // NOLINT // We use KB a lot; let's make a literal for it constexpr uInt32 operator "" _KB(unsigned long long size) diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index 6199bb306..0f9a75a27 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -1461,7 +1461,7 @@ void CartDebug::addressTypeAsString(ostream& buf, uInt16 addr) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -CartDebug::DisasmType CartDebug::disasmTypeAbsolute(uInt16 flags) const +CartDebug::DisasmType CartDebug::disasmTypeAbsolute(CartDebug::DisasmFlags flags) const { if(flags & CartDebug::CODE) return CartDebug::CODE; @@ -1506,7 +1506,7 @@ void CartDebug::disasmTypeAsString(ostream& buf, DisasmType type) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartDebug::disasmTypeAsString(ostream& buf, uInt16 flags) const +void CartDebug::disasmTypeAsString(ostream& buf, CartDebug::DisasmFlags flags) const { if(flags) { diff --git a/src/debugger/CartDebug.hxx b/src/debugger/CartDebug.hxx index e331cc585..17f67aa7a 100644 --- a/src/debugger/CartDebug.hxx +++ b/src/debugger/CartDebug.hxx @@ -72,6 +72,8 @@ class CartDebug : public DebuggerSystem // special type for poke() WRITE = TCODE // 0x200, address written to }; + using DisasmFlags = uInt16; + struct DisassemblyTag { DisasmType type{NONE}; uInt16 address{0}; @@ -308,14 +310,14 @@ class CartDebug : public DebuggerSystem void getBankDirectives(ostream& buf, BankInfo& info) const; // Get disassembly enum type from 'flags', taking precendence into account - DisasmType disasmTypeAbsolute(uInt16 flags) const; + DisasmType disasmTypeAbsolute(CartDebug::DisasmFlags flags) const; // Convert disassembly enum type to corresponding string and append to buf void disasmTypeAsString(ostream& buf, DisasmType type) const; // Convert all disassembly types in 'flags' to corresponding string and // append to buf - void disasmTypeAsString(ostream& buf, uInt16 flags) const; + void disasmTypeAsString(ostream& buf, CartDebug::DisasmFlags flags) const; private: const OSystem& myOSystem; diff --git a/src/debugger/Debugger.cxx b/src/debugger/Debugger.cxx index ce712bf1f..e332d2586 100644 --- a/src/debugger/Debugger.cxx +++ b/src/debugger/Debugger.cxx @@ -440,19 +440,19 @@ bool Debugger::writeTrap(uInt16 t) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 Debugger::peek(uInt16 addr, uInt16 flags) +uInt8 Debugger::peek(uInt16 addr, CartDebug::DisasmFlags flags) { return mySystem.peek(addr, flags); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 Debugger::dpeek(uInt16 addr, uInt16 flags) +uInt16 Debugger::dpeek(uInt16 addr, CartDebug::DisasmFlags flags) { return uInt16(mySystem.peek(addr, flags) | (mySystem.peek(addr+1, flags) << 8)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Debugger::poke(uInt16 addr, uInt8 value, uInt16 flags) +void Debugger::poke(uInt16 addr, uInt8 value, CartDebug::DisasmFlags flags) { mySystem.poke(addr, value, flags); } @@ -464,26 +464,26 @@ M6502& Debugger::m6502() const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int Debugger::peekAsInt(int addr, uInt16 flags) +int Debugger::peekAsInt(int addr, CartDebug::DisasmFlags flags) { return mySystem.peek(uInt16(addr), flags); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int Debugger::dpeekAsInt(int addr, uInt16 flags) +int Debugger::dpeekAsInt(int addr, CartDebug::DisasmFlags flags) { return mySystem.peek(uInt16(addr), flags) | (mySystem.peek(uInt16(addr+1), flags) << 8); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int Debugger::getAccessFlags(uInt16 addr) const +CartDebug::DisasmFlags Debugger::getAccessFlags(uInt16 addr) const { return mySystem.getAccessFlags(addr); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Debugger::setAccessFlags(uInt16 addr, uInt16 flags) +void Debugger::setAccessFlags(uInt16 addr, CartDebug::DisasmFlags flags) { mySystem.setAccessFlags(addr, flags); } diff --git a/src/debugger/Debugger.hxx b/src/debugger/Debugger.hxx index 738404552..0cfbaf458 100644 --- a/src/debugger/Debugger.hxx +++ b/src/debugger/Debugger.hxx @@ -47,6 +47,7 @@ class RewindManager; #include "DialogContainer.hxx" #include "DebuggerDialog.hxx" #include "FrameBufferConstants.hxx" +#include "CartDebug.hxx" #include "bspf.hxx" /** @@ -243,18 +244,18 @@ class Debugger : public DialogContainer static Debugger& debugger() { return *myStaticDebugger; } /** Convenience methods to access peek/poke from System */ - uInt8 peek(uInt16 addr, uInt16 flags = 0); - uInt16 dpeek(uInt16 addr, uInt16 flags = 0); - void poke(uInt16 addr, uInt8 value, uInt16 flags = 0); + uInt8 peek(uInt16 addr, CartDebug::DisasmFlags flags = CartDebug::NONE); + uInt16 dpeek(uInt16 addr, CartDebug::DisasmFlags flags = CartDebug::NONE); + void poke(uInt16 addr, uInt8 value, CartDebug::DisasmFlags flags = CartDebug::NONE); /** Convenience method to access the 6502 from System */ M6502& m6502() const; /** These are now exposed so Expressions can use them. */ - int peekAsInt(int addr, uInt16 flags = 0); - int dpeekAsInt(int addr, uInt16 flags = 0); - int getAccessFlags(uInt16 addr) const; - void setAccessFlags(uInt16 addr, uInt16 flags); + int peekAsInt(int addr, CartDebug::DisasmFlags flags = CartDebug::NONE); + int dpeekAsInt(int addr, CartDebug::DisasmFlags flags = CartDebug::NONE); + CartDebug::DisasmFlags getAccessFlags(uInt16 addr) const; + void setAccessFlags(uInt16 addr, CartDebug::DisasmFlags flags); uInt32 getBaseAddress(uInt32 addr, bool read); diff --git a/src/emucore/Cart.hxx b/src/emucore/Cart.hxx index a7bd1da6b..5a34f1fc3 100644 --- a/src/emucore/Cart.hxx +++ b/src/emucore/Cart.hxx @@ -30,6 +30,7 @@ class GuiObject; #ifdef DEBUGGER_SUPPORT #include "Font.hxx" #endif +#include "CartDebug.hxx" /** A cartridge is a device which contains the machine code for a @@ -322,7 +323,7 @@ class Cartridge : public Device // The array containing information about every byte of ROM indicating // whether it is used as code. - WordBuffer myCodeAccessBase; + std::unique_ptr myCodeAccessBase; // Contains address of illegal RAM write access or 0 uInt16 myRamWriteAccess{0}; diff --git a/src/emucore/Cart4A50.cxx b/src/emucore/Cart4A50.cxx index ca634ed09..9ac05b2b3 100644 --- a/src/emucore/Cart4A50.cxx +++ b/src/emucore/Cart4A50.cxx @@ -182,7 +182,7 @@ bool Cartridge4A50::poke(uInt16 address, uInt8 value) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 Cartridge4A50::getAccessFlags(uInt16 address) const +CartDebug::DisasmFlags Cartridge4A50::getAccessFlags(uInt16 address) const { if((address & 0x1800) == 0x1000) // 2K region from 0x1000 - 0x17ff { @@ -214,7 +214,7 @@ uInt16 Cartridge4A50::getAccessFlags(uInt16 address) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge4A50::setAccessFlags(uInt16 address, uInt16 flags) +void Cartridge4A50::setAccessFlags(uInt16 address, CartDebug::DisasmFlags flags) { if((address & 0x1800) == 0x1000) // 2K region from 0x1000 - 0x17ff { diff --git a/src/emucore/Cart4A50.hxx b/src/emucore/Cart4A50.hxx index 210a2604b..e1299431c 100644 --- a/src/emucore/Cart4A50.hxx +++ b/src/emucore/Cart4A50.hxx @@ -158,14 +158,14 @@ class Cartridge4A50 : public Cartridge @param address The address to query */ - uInt16 getAccessFlags(uInt16 address) const override; + CartDebug::DisasmFlags getAccessFlags(uInt16 address) const override; /** Change the given address to use the given disassembly flags. @param address The address to modify @param flags A bitfield of DisasmType directives for the given address */ - void setAccessFlags(uInt16 address, uInt16 flags) override; + void setAccessFlags(uInt16 address, CartDebug::DisasmFlags flags) override; /** Check all possible hotspots diff --git a/src/emucore/CartAR.cxx b/src/emucore/CartAR.cxx index 59ad6f03f..fc63d7954 100644 --- a/src/emucore/CartAR.cxx +++ b/src/emucore/CartAR.cxx @@ -191,14 +191,14 @@ bool CartridgeAR::poke(uInt16 addr, uInt8) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeAR::getAccessFlags(uInt16 address) const +CartDebug::DisasmFlags CartridgeAR::getAccessFlags(uInt16 address) const { return myCodeAccessBase[(address & 0x07FF) + myImageOffset[(address & 0x0800) ? 1 : 0]]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeAR::setAccessFlags(uInt16 address, uInt16 flags) +void CartridgeAR::setAccessFlags(uInt16 address, CartDebug::DisasmFlags flags) { myCodeAccessBase[(address & 0x07FF) + myImageOffset[(address & 0x0800) ? 1 : 0]] |= flags; diff --git a/src/emucore/CartAR.hxx b/src/emucore/CartAR.hxx index 09dc11b3a..888e5e6f9 100644 --- a/src/emucore/CartAR.hxx +++ b/src/emucore/CartAR.hxx @@ -164,14 +164,14 @@ class CartridgeAR : public Cartridge @param address The address to query */ - uInt16 getAccessFlags(uInt16 address) const override; + CartDebug::DisasmFlags getAccessFlags(uInt16 address) const override; /** Change the given address to use the given disassembly flags. @param address The address to modify @param flags A bitfield of DisasmType directives for the given address */ - void setAccessFlags(uInt16 address, uInt16 flags) override; + void setAccessFlags(uInt16 address, CartDebug::DisasmFlags flags) override; // Handle a change to the bank configuration bool bankConfiguration(uInt8 configuration); diff --git a/src/emucore/Device.hxx b/src/emucore/Device.hxx index f405a8739..f55312869 100644 --- a/src/emucore/Device.hxx +++ b/src/emucore/Device.hxx @@ -22,6 +22,7 @@ class System; #include "Console.hxx" #include "Serializable.hxx" +#include "CartDebug.hxx" #include "bspf.hxx" /** @@ -102,7 +103,7 @@ class Device : public Serializable @param address The address to modify */ - virtual uInt16 getAccessFlags(uInt16 address) const { return 0; } + virtual CartDebug::DisasmFlags getAccessFlags(uInt16 address) const { return CartDebug::NONE; } /** Change the given address type to use the given disassembly flags @@ -110,7 +111,7 @@ class Device : public Serializable @param address The address to modify @param flags A bitfield of DisasmType directives for the given address */ - virtual void setAccessFlags(uInt16 address, uInt16 flags) { } + virtual void setAccessFlags(uInt16 address, CartDebug::DisasmFlags flags) { } protected: /// Pointer to the system the device is installed in or the null pointer diff --git a/src/emucore/M6502.cxx b/src/emucore/M6502.cxx index fda514705..49f8ff7e2 100644 --- a/src/emucore/M6502.cxx +++ b/src/emucore/M6502.cxx @@ -104,7 +104,7 @@ void M6502::reset() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -inline uInt8 M6502::peek(uInt16 address, uInt16 flags) +inline uInt8 M6502::peek(uInt16 address, CartDebug::DisasmFlags flags) { handleHalt(); @@ -144,7 +144,7 @@ inline uInt8 M6502::peek(uInt16 address, uInt16 flags) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -inline void M6502::poke(uInt16 address, uInt8 value, uInt16 flags) +inline void M6502::poke(uInt16 address, uInt8 value, CartDebug::DisasmFlags flags) { //////////////////////////////////////////////// // TODO - move this logic directly into CartAR diff --git a/src/emucore/M6502.hxx b/src/emucore/M6502.hxx index dd48315a6..5c7bbbc01 100644 --- a/src/emucore/M6502.hxx +++ b/src/emucore/M6502.hxx @@ -35,6 +35,7 @@ class DispatchResult; #include "bspf.hxx" #include "Serializable.hxx" +#include "CartDebug.hxx" /** The 6502 is an 8-bit microprocessor that has a 64K addressing space. @@ -269,7 +270,7 @@ class M6502 : public Serializable @return The byte at the specified address */ - uInt8 peek(uInt16 address, uInt16 flags); + uInt8 peek(uInt16 address, CartDebug::DisasmFlags flags); /** Change the byte at the specified address to the given value and @@ -278,7 +279,7 @@ class M6502 : public Serializable @param address The address where the value should be stored @param value The value to be stored at the address */ - void poke(uInt16 address, uInt8 value, uInt16 flags = 0); + void poke(uInt16 address, uInt8 value, CartDebug::DisasmFlags flags = CartDebug::NONE); /** Get the 8-bit value of the Processor Status register. diff --git a/src/emucore/M6532.cxx b/src/emucore/M6532.cxx index 80f828f83..b5276567b 100644 --- a/src/emucore/M6532.cxx +++ b/src/emucore/M6532.cxx @@ -467,7 +467,7 @@ void M6532::createAccessBases() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 M6532::getAccessFlags(uInt16 address) const +CartDebug::DisasmFlags M6532::getAccessFlags(uInt16 address) const { if (address & IO_BIT) return myIOAccessBase[address & IO_MASK]; @@ -478,7 +478,7 @@ uInt16 M6532::getAccessFlags(uInt16 address) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void M6532::setAccessFlags(uInt16 address, uInt16 flags) +void M6532::setAccessFlags(uInt16 address, CartDebug::DisasmFlags flags) { // ignore none flag if (flags != CartDebug::NONE) { diff --git a/src/emucore/M6532.hxx b/src/emucore/M6532.hxx index db93414a3..42fca9640 100644 --- a/src/emucore/M6532.hxx +++ b/src/emucore/M6532.hxx @@ -151,14 +151,14 @@ class M6532 : public Device @param address The address to query */ - uInt16 getAccessFlags(uInt16 address) const override; + CartDebug::DisasmFlags getAccessFlags(uInt16 address) const override; /** Change the given address to use the given disassembly flags. @param address The address to modify @param flags A bitfield of DisasmType directives for the given address */ - void setAccessFlags(uInt16 address, uInt16 flags) override; + void setAccessFlags(uInt16 address, CartDebug::DisasmFlags flags) override; #endif // DEBUGGER_SUPPORT private: diff --git a/src/emucore/System.cxx b/src/emucore/System.cxx index e40124c2a..e2050ee1b 100644 --- a/src/emucore/System.cxx +++ b/src/emucore/System.cxx @@ -99,7 +99,7 @@ void System::clearDirtyPages() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 System::peek(uInt16 addr, uInt16 flags) +uInt8 System::peek(uInt16 addr, CartDebug::DisasmFlags flags) { const PageAccess& access = getPageAccess(addr); @@ -127,7 +127,7 @@ uInt8 System::peek(uInt16 addr, uInt16 flags) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void System::poke(uInt16 addr, uInt8 value, uInt16 flags) +void System::poke(uInt16 addr, uInt8 value, CartDebug::DisasmFlags flags) { uInt16 page = (addr & ADDRESS_MASK) >> PAGE_SHIFT; const PageAccess& access = myPageAccessTable[page]; @@ -160,7 +160,7 @@ void System::poke(uInt16 addr, uInt8 value, uInt16 flags) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 System::getAccessFlags(uInt16 addr) const +CartDebug::DisasmFlags System::getAccessFlags(uInt16 addr) const { #ifdef DEBUGGER_SUPPORT const PageAccess& access = getPageAccess(addr); @@ -175,7 +175,7 @@ uInt16 System::getAccessFlags(uInt16 addr) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void System::setAccessFlags(uInt16 addr, uInt16 flags) +void System::setAccessFlags(uInt16 addr, CartDebug::DisasmFlags flags) { #ifdef DEBUGGER_SUPPORT const PageAccess& access = getPageAccess(addr); diff --git a/src/emucore/System.hxx b/src/emucore/System.hxx index f4423c491..306f269e1 100644 --- a/src/emucore/System.hxx +++ b/src/emucore/System.hxx @@ -29,6 +29,7 @@ class NullDevice; #include "NullDev.hxx" #include "Random.hxx" #include "Serializable.hxx" +#include "CartDebug.hxx" /** This class represents a system consisting of a 6502 microprocessor @@ -202,7 +203,7 @@ class System : public Serializable @return The byte at the specified address */ - uInt8 peek(uInt16 address, uInt16 flags = 0); + uInt8 peek(uInt16 address, CartDebug::DisasmFlags flags = CartDebug::NONE); /** Change the byte at the specified address to the given value. @@ -217,7 +218,7 @@ class System : public Serializable @param address The address where the value should be stored @param value The value to be stored at the address */ - void poke(uInt16 address, uInt8 value, uInt16 flags = 0); + void poke(uInt16 address, uInt8 value, CartDebug::DisasmFlags flags = CartDebug::NONE); /** Lock/unlock the data bus. When the bus is locked, peek() and @@ -236,8 +237,8 @@ class System : public Serializable address. Note that while any flag can be used, the disassembly only really acts on CODE/GFX/PGFX/DATA/ROW. */ - uInt16 getAccessFlags(uInt16 address) const; - void setAccessFlags(uInt16 address, uInt16 flags); + CartDebug::DisasmFlags getAccessFlags(uInt16 address) const; + void setAccessFlags(uInt16 address, CartDebug::DisasmFlags flags); public: /** @@ -277,7 +278,7 @@ class System : public Serializable conclusively determine if a section of address space is CODE, even if the disassembler failed to mark it as such. */ - uInt16* codeAccessBase{nullptr}; + CartDebug::DisasmFlags* codeAccessBase{nullptr}; /** Pointer to the device associated with this page or to the system's diff --git a/src/emucore/tia/TIA.cxx b/src/emucore/tia/TIA.cxx index 145eea6e5..10f71ec80 100644 --- a/src/emucore/tia/TIA.cxx +++ b/src/emucore/tia/TIA.cxx @@ -1919,13 +1919,13 @@ void TIA::createAccessBase() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 TIA::getAccessFlags(uInt16 address) const +CartDebug::DisasmFlags TIA::getAccessFlags(uInt16 address) const { return myAccessBase[address & TIA_MASK]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::setAccessFlags(uInt16 address, uInt16 flags) +void TIA::setAccessFlags(uInt16 address, CartDebug::DisasmFlags flags) { // ignore none flag if (flags != CartDebug::NONE) { diff --git a/src/emucore/tia/TIA.hxx b/src/emucore/tia/TIA.hxx index acb7ee40e..842bc395f 100644 --- a/src/emucore/tia/TIA.hxx +++ b/src/emucore/tia/TIA.hxx @@ -685,14 +685,14 @@ class TIA : public Device * * @param address The address to query */ - uInt16 getAccessFlags(uInt16 address) const override; + CartDebug::DisasmFlags getAccessFlags(uInt16 address) const override; /** * Change the given address to use the given disassembly flags. * * @param address The address to modify * @param flags A bitfield of DisasmType directives for the given address */ - void setAccessFlags(uInt16 address, uInt16 flags) override; + void setAccessFlags(uInt16 address, CartDebug::DisasmFlags flags) override; #endif // DEBUGGER_SUPPORT private: From fca12051baa029faea34c44da2f7fa28e3178735 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Fri, 27 Mar 2020 09:03:06 +0100 Subject: [PATCH 049/377] refactored access flags used for disassembly --- src/debugger/CartDebug.cxx | 223 +++++++++++++------------- src/debugger/CartDebug.hxx | 50 ++---- src/debugger/CpuDebug.cxx | 1 - src/debugger/Debugger.cxx | 14 +- src/debugger/Debugger.hxx | 16 +- src/debugger/DebuggerParser.cxx | 14 +- src/debugger/DiStella.cxx | 241 +++++++++++++++-------------- src/debugger/DiStella.hxx | 5 +- src/debugger/gui/RomListWidget.cxx | 10 +- src/emucore/Cart.cxx | 5 +- src/emucore/Cart.hxx | 4 +- src/emucore/Cart4A50.cxx | 4 +- src/emucore/Cart4A50.hxx | 10 +- src/emucore/CartAR.cxx | 4 +- src/emucore/CartAR.hxx | 10 +- src/emucore/Device.hxx | 39 ++++- src/emucore/M6502.cxx | 22 +-- src/emucore/M6502.hxx | 6 +- src/emucore/M6532.cxx | 15 +- src/emucore/M6532.hxx | 16 +- src/emucore/System.cxx | 8 +- src/emucore/System.hxx | 15 +- src/emucore/tia/TIA.cxx | 32 ++-- src/emucore/tia/TIA.hxx | 12 +- src/gui/DeveloperDialog.cxx | 1 - 25 files changed, 385 insertions(+), 392 deletions(-) diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index 0f9a75a27..7446efad4 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -32,6 +32,7 @@ #include "CartRamWidget.hxx" #include "RomWidget.hxx" #include "Base.hxx" +#include "Device.hxx" #include "exception/EmulationWarning.hxx" using Common::Base; @@ -85,7 +86,7 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem) // We know the address for the startup bank right now myBankInfo[myConsole.cartridge().startBank()].addressList.push_front( myDebugger.dpeek(0xfffc)); - addLabel("Start", myDebugger.dpeek(0xfffc, DATA)); + addLabel("Start", myDebugger.dpeek(0xfffc, Device::DATA)); // Add system equates for(uInt16 addr = 0x00; addr <= 0x0F; ++addr) @@ -316,8 +317,8 @@ bool CartDebug::fillDisassemblyList(BankInfo& info, uInt16 search) const DisassemblyTag& tag = myDisassembly.list[i]; const uInt16 address = tag.address & 0xFFF; - // Exclude 'ROW'; they don't have a valid address - if(tag.type != CartDebug::ROW) + // Exclude 'Device::ROW'; they don't have a valid address + if(tag.type != Device::ROW) { // Create a mapping from addresses to line numbers myAddrToLineList.emplace(address, i); @@ -358,7 +359,7 @@ string CartDebug::disassemble(uInt16 start, uInt16 lines) const if((tag.address & 0xfff) >= start) { if(begin == list_size) begin = end; - if(tag.type != CartDebug::ROW) + if(tag.type != Device::ROW) length = std::max(length, uInt32(tag.disasm.length())); --lines; @@ -369,7 +370,7 @@ string CartDebug::disassemble(uInt16 start, uInt16 lines) const for(uInt32 i = begin; i < end; ++i) { const CartDebug::DisassemblyTag& tag = myDisassembly.list[i]; - if(tag.type == CartDebug::NONE) + if(tag.type == Device::NONE) continue; else if(tag.address) buffer << std::uppercase << std::hex << std::setw(4) @@ -386,7 +387,7 @@ string CartDebug::disassemble(uInt16 start, uInt16 lines) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartDebug::addDirective(CartDebug::DisasmType type, +bool CartDebug::addDirective(Device::AccessType type, uInt16 start, uInt16 end, int bank) { if(end < start || start == 0 || end == 0) @@ -885,46 +886,46 @@ string CartDebug::loadConfigFile() // TODO - figure out what to do with this buf >> hex >> start; } - else if(BSPF::startsWithIgnoreCase(directive, "CODE")) + else if(BSPF::startsWithIgnoreCase(directive, "Device::CODE")) { buf >> hex >> start >> hex >> end; - addDirective(CartDebug::CODE, start, end, currentbank); + addDirective(Device::CODE, start, end, currentbank); } - else if(BSPF::startsWithIgnoreCase(directive, "GFX")) + else if(BSPF::startsWithIgnoreCase(directive, "Device::GFX")) { buf >> hex >> start >> hex >> end; - addDirective(CartDebug::GFX, start, end, currentbank); + addDirective(Device::GFX, start, end, currentbank); } - else if(BSPF::startsWithIgnoreCase(directive, "PGFX")) + else if(BSPF::startsWithIgnoreCase(directive, "Device::PGFX")) { buf >> hex >> start >> hex >> end; - addDirective(CartDebug::PGFX, start, end, currentbank); + addDirective(Device::PGFX, start, end, currentbank); } - else if(BSPF::startsWithIgnoreCase(directive, "COL")) + else if(BSPF::startsWithIgnoreCase(directive, "Device::COL")) { buf >> hex >> start >> hex >> end; - addDirective(CartDebug::COL, start, end, currentbank); + addDirective(Device::COL, start, end, currentbank); } - else if(BSPF::startsWithIgnoreCase(directive, "PCOL")) + else if(BSPF::startsWithIgnoreCase(directive, "Device::PCOL")) { buf >> hex >> start >> hex >> end; - addDirective(CartDebug::PCOL, start, end, currentbank); + addDirective(Device::PCOL, start, end, currentbank); } - else if(BSPF::startsWithIgnoreCase(directive, "BCOL")) + else if(BSPF::startsWithIgnoreCase(directive, "Device::BCOL")) { buf >> hex >> start >> hex >> end; - addDirective(CartDebug::BCOL, start, end, currentbank); + addDirective(Device::BCOL, start, end, currentbank); } - else if(BSPF::startsWithIgnoreCase(directive, "DATA")) + else if(BSPF::startsWithIgnoreCase(directive, "Device::DATA")) { buf >> hex >> start >> hex >> end; - addDirective(CartDebug::DATA, start, end, currentbank); + addDirective(Device::DATA, start, end, currentbank); } - else if(BSPF::startsWithIgnoreCase(directive, "ROW")) + else if(BSPF::startsWithIgnoreCase(directive, "Device::ROW")) { buf >> hex >> start; buf >> hex >> end; - addDirective(CartDebug::ROW, start, end, currentbank); + addDirective(Device::ROW, start, end, currentbank); } } } @@ -1053,7 +1054,7 @@ string CartDebug::saveDisassembly() if (myReserved.breakFound) addLabel("Break", myDebugger.dpeek(0xfffe)); - buf << " SEG CODE\n" + buf << " SEG Device::CODE\n" << " ORG $" << Base::HEX4 << info.offset << "\n\n"; // Format in 'distella' style @@ -1068,19 +1069,19 @@ string CartDebug::saveDisassembly() switch(tag.type) { - case CartDebug::CODE: + case Device::CODE: { buf << ALIGN(32) << tag.disasm << tag.ccount.substr(0, 5) << tag.ctotal << tag.ccount.substr(5, 2); if (tag.disasm.find("WSYNC") != std::string::npos) buf << "\n;---------------------------------------"; break; } - case CartDebug::ROW: + case Device::ROW: { buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 8*4-1) << "; $" << Base::HEX4 << tag.address << " (*)"; break; } - case CartDebug::GFX: + case Device::GFX: { buf << ".byte " << (settings.gfxFormat == Base::Fmt::_2 ? "%" : "$") << tag.bytes << " ; |"; @@ -1089,7 +1090,7 @@ string CartDebug::saveDisassembly() buf << ALIGN(13) << "|" << "$" << Base::HEX4 << tag.address << " (G)"; break; } - case CartDebug::PGFX: + case Device::PGFX: { buf << ".byte " << (settings.gfxFormat == Base::Fmt::_2 ? "%" : "$") << tag.bytes << " ; |"; @@ -1098,24 +1099,24 @@ string CartDebug::saveDisassembly() buf << ALIGN(13) << "|" << "$" << Base::HEX4 << tag.address << " (P)"; break; } - case CartDebug::COL: + case Device::COL: buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 12) << "; $" << Base::HEX4 << tag.address << " (Px)"; break; - case CartDebug::PCOL: + case Device::PCOL: buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 12) << "; $" << Base::HEX4 << tag.address << " (PF)"; break; - case CartDebug::BCOL: + case Device::BCOL: buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 12) << "; $" << Base::HEX4 << tag.address << " (BK)"; break; - case CartDebug::DATA: + case Device::DATA: { buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 8 * 4 - 1) << "; $" << Base::HEX4 << tag.address << " (D)"; break; } - case CartDebug::NONE: + case Device::NONE: default: { break; @@ -1133,10 +1134,10 @@ string CartDebug::saveDisassembly() << "; ROM properties name : " << myConsole.properties().get(PropType::Cart_Name) << "\n" << "; ROM properties MD5 : " << myConsole.properties().get(PropType::Cart_MD5) << "\n" << "; Bankswitch type : " << myConsole.cartridge().about() << "\n;\n" - << "; Legend: * = CODE not yet run (tentative code)\n" - << "; D = DATA directive (referenced in some way)\n" - << "; G = GFX directive, shown as '#' (stored in player, missile, ball)\n" - << "; P = PGFX directive, shown as '*' (stored in playfield)\n" + << "; Legend: * = Device::CODE not yet run (tentative code)\n" + << "; D = Device::DATA directive (referenced in some way)\n" + << "; G = Device::GFX directive, shown as '#' (stored in player, missile, ball)\n" + << "; P = Device::PGFX directive, shown as '*' (stored in playfield)\n" << "; i = indexed accessed only\n" << "; c = used by code executed in RAM\n" << "; s = used by stack\n" @@ -1166,9 +1167,9 @@ string CartDebug::saveDisassembly() bool addrUsed = false; for(uInt16 addr = 0x00; addr <= 0x0F; ++addr) - addrUsed = addrUsed || myReserved.TIARead[addr] || (mySystem.getAccessFlags(addr) & WRITE); + addrUsed = addrUsed || myReserved.TIARead[addr] || (mySystem.getAccessFlags(addr) & Device::WRITE); for(uInt16 addr = 0x00; addr <= 0x3F; ++addr) - addrUsed = addrUsed || myReserved.TIAWrite[addr] || (mySystem.getAccessFlags(addr) & DATA); + addrUsed = addrUsed || myReserved.TIAWrite[addr] || (mySystem.getAccessFlags(addr) & Device::DATA); for(uInt16 addr = 0x00; addr <= 0x17; ++addr) addrUsed = addrUsed || myReserved.IOReadWrite[addr]; @@ -1183,7 +1184,7 @@ string CartDebug::saveDisassembly() if(myReserved.TIARead[addr] && ourTIAMnemonicR[addr]) out << ALIGN(16) << ourTIAMnemonicR[addr] << "= $" << Base::HEX2 << right << addr << " ; (R)\n"; - else if (mySystem.getAccessFlags(addr) & DATA) + else if (mySystem.getAccessFlags(addr) & Device::DATA) out << ";" << ALIGN(16-1) << ourTIAMnemonicR[addr] << "= $" << Base::HEX2 << right << addr << " ; (Ri)\n"; out << "\n"; @@ -1193,7 +1194,7 @@ string CartDebug::saveDisassembly() if(myReserved.TIAWrite[addr] && ourTIAMnemonicW[addr]) out << ALIGN(16) << ourTIAMnemonicW[addr] << "= $" << Base::HEX2 << right << addr << " ; (W)\n"; - else if (mySystem.getAccessFlags(addr) & WRITE) + else if (mySystem.getAccessFlags(addr) & Device::WRITE) out << ";" << ALIGN(16-1) << ourTIAMnemonicW[addr] << "= $" << Base::HEX2 << right << addr << " ; (Wi)\n"; out << "\n"; @@ -1208,8 +1209,8 @@ string CartDebug::saveDisassembly() addrUsed = false; for(uInt16 addr = 0x80; addr <= 0xFF; ++addr) addrUsed = addrUsed || myReserved.ZPRAM[addr-0x80] - || (mySystem.getAccessFlags(addr) & (DATA | WRITE)) - || (mySystem.getAccessFlags(addr|0x100) & (DATA | WRITE)); + || (mySystem.getAccessFlags(addr) & (Device::DATA | Device::WRITE)) + || (mySystem.getAccessFlags(addr|0x100) & (Device::DATA | Device::WRITE)); if(addrUsed) { bool addLine = false; @@ -1218,9 +1219,9 @@ string CartDebug::saveDisassembly() << ";-----------------------------------------------------------\n\n"; for (uInt16 addr = 0x80; addr <= 0xFF; ++addr) { - bool ramUsed = (mySystem.getAccessFlags(addr) & (DATA | WRITE)); - bool codeUsed = (mySystem.getAccessFlags(addr) & CODE); - bool stackUsed = (mySystem.getAccessFlags(addr|0x100) & (DATA | WRITE)); + bool ramUsed = (mySystem.getAccessFlags(addr) & (Device::DATA | Device::WRITE)); + bool codeUsed = (mySystem.getAccessFlags(addr) & Device::CODE); + bool stackUsed = (mySystem.getAccessFlags(addr|0x100) & (Device::DATA | Device::WRITE)); if (myReserved.ZPRAM[addr - 0x80] && myUserLabels.find(addr) == myUserLabels.end()) { @@ -1315,10 +1316,10 @@ string CartDebug::listConfig(int bank) buf << "[" << b << "]" << endl; for(const auto& i: info.directiveList) { - if(i.type != CartDebug::NONE) + if(i.type != Device::NONE) { buf << "(*) "; - disasmTypeAsString(buf, i.type); + AccessTypeAsString(buf, i.type); buf << " " << Base::HEX4 << i.start << " " << Base::HEX4 << i.end << endl; } } @@ -1414,15 +1415,15 @@ void CartDebug::getBankDirectives(ostream& buf, BankInfo& info) const // Now consider each byte uInt32 prev = info.offset, addr = prev + 1; - DisasmType prevType = disasmTypeAbsolute(mySystem.getAccessFlags(prev)); + Device::AccessType prevType = accessTypeAbsolute(mySystem.getAccessFlags(prev)); for( ; addr < info.offset + info.size; ++addr) { - DisasmType currType = disasmTypeAbsolute(mySystem.getAccessFlags(addr)); + Device::AccessType currType = accessTypeAbsolute(mySystem.getAccessFlags(addr)); // Have we changed to a new type? if(currType != prevType) { - disasmTypeAsString(buf, prevType); + AccessTypeAsString(buf, prevType); buf << " " << Base::HEX4 << prev << " " << Base::HEX4 << (addr-1) << endl; prev = addr; @@ -1433,13 +1434,13 @@ void CartDebug::getBankDirectives(ostream& buf, BankInfo& info) const // Grab the last directive, making sure it accounts for all remaining space if(prev != addr) { - disasmTypeAsString(buf, prevType); + AccessTypeAsString(buf, prevType); buf << " " << Base::HEX4 << prev << " " << Base::HEX4 << (addr-1) << endl; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartDebug::addressTypeAsString(ostream& buf, uInt16 addr) const +void CartDebug::accessTypeAsString(ostream& buf, uInt16 addr) const { if(!(addr & 0x1000)) { @@ -1452,86 +1453,86 @@ void CartDebug::addressTypeAsString(ostream& buf, uInt16 addr) const label = myDisLabels[addr & 0xFFF]; buf << endl << "directive: " << Base::toString(directive, Base::Fmt::_2_8) << " "; - disasmTypeAsString(buf, directive); + AccessTypeAsString(buf, directive); buf << endl << "emulation: " << Base::toString(debugger, Base::Fmt::_2_8) << " "; - disasmTypeAsString(buf, debugger); + AccessTypeAsString(buf, debugger); buf << endl << "tentative: " << Base::toString(label, Base::Fmt::_2_8) << " "; - disasmTypeAsString(buf, label); + AccessTypeAsString(buf, label); buf << endl; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -CartDebug::DisasmType CartDebug::disasmTypeAbsolute(CartDebug::DisasmFlags flags) const +Device::AccessType CartDebug::accessTypeAbsolute(Device::AccessFlags flags) const { - if(flags & CartDebug::CODE) - return CartDebug::CODE; - else if(flags & CartDebug::TCODE) - return CartDebug::CODE; // TODO - should this be separate?? - else if(flags & CartDebug::GFX) - return CartDebug::GFX; - else if(flags & CartDebug::PGFX) - return CartDebug::PGFX; - else if(flags & CartDebug::COL) - return CartDebug::COL; - else if(flags & CartDebug::PCOL) - return CartDebug::PCOL; - else if(flags & CartDebug::BCOL) - return CartDebug::BCOL; - else if(flags & CartDebug::DATA) - return CartDebug::DATA; - else if(flags & CartDebug::ROW) - return CartDebug::ROW; + if(flags & Device::CODE) + return Device::CODE; + else if(flags & Device::TCODE) + return Device::CODE; // TODO - should this be separate?? + else if(flags & Device::GFX) + return Device::GFX; + else if(flags & Device::PGFX) + return Device::PGFX; + else if(flags & Device::COL) + return Device::COL; + else if(flags & Device::PCOL) + return Device::PCOL; + else if(flags & Device::BCOL) + return Device::BCOL; + else if(flags & Device::DATA) + return Device::DATA; + else if(flags & Device::ROW) + return Device::ROW; else - return CartDebug::NONE; + return Device::NONE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartDebug::disasmTypeAsString(ostream& buf, DisasmType type) const +void CartDebug::AccessTypeAsString(ostream& buf, Device::AccessType type) const { switch(type) { - case CartDebug::CODE: buf << "CODE"; break; - case CartDebug::TCODE: buf << "TCODE"; break; - case CartDebug::GFX: buf << "GFX"; break; - case CartDebug::PGFX: buf << "PGFX"; break; - case CartDebug::COL: buf << "COL"; break; - case CartDebug::PCOL: buf << "PCOL"; break; - case CartDebug::BCOL: buf << "BCOL"; break; - case CartDebug::DATA: buf << "DATA"; break; - case CartDebug::ROW: buf << "ROW"; break; - case CartDebug::REFERENCED: - case CartDebug::VALID_ENTRY: - case CartDebug::NONE: break; + case Device::CODE: buf << "Device::CODE"; break; + case Device::TCODE: buf << "Device::TCODE"; break; + case Device::GFX: buf << "Device::GFX"; break; + case Device::PGFX: buf << "Device::PGFX"; break; + case Device::COL: buf << "Device::COL"; break; + case Device::PCOL: buf << "Device::PCOL"; break; + case Device::BCOL: buf << "Device::BCOL"; break; + case Device::DATA: buf << "Device::DATA"; break; + case Device::ROW: buf << "Device::ROW"; break; + case Device::REFERENCED: + case Device::VALID_ENTRY: + case Device::NONE: break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartDebug::disasmTypeAsString(ostream& buf, CartDebug::DisasmFlags flags) const +void CartDebug::AccessTypeAsString(ostream& buf, Device::AccessFlags flags) const { if(flags) { - if(flags & CartDebug::CODE) - buf << "CODE "; - if(flags & CartDebug::TCODE) - buf << "TCODE "; - if(flags & CartDebug::GFX) - buf << "GFX "; - if(flags & CartDebug::PGFX) - buf << "PGFX "; - if(flags & CartDebug::COL) - buf << "COL "; - if(flags & CartDebug::PCOL) - buf << "PCOL "; - if(flags & CartDebug::BCOL) - buf << "BCOL "; - if(flags & CartDebug::DATA) - buf << "DATA "; - if(flags & CartDebug::ROW) - buf << "ROW "; - if(flags & CartDebug::REFERENCED) - buf << "*REFERENCED "; - if(flags & CartDebug::VALID_ENTRY) - buf << "*VALID_ENTRY "; + if(flags & Device::CODE) + buf << "Device::CODE "; + if(flags & Device::TCODE) + buf << "Device::TCODE "; + if(flags & Device::GFX) + buf << "Device::GFX "; + if(flags & Device::PGFX) + buf << "Device::PGFX "; + if(flags & Device::COL) + buf << "Device::COL "; + if(flags & Device::PCOL) + buf << "Device::PCOL "; + if(flags & Device::BCOL) + buf << "Device::BCOL "; + if(flags & Device::DATA) + buf << "Device::DATA "; + if(flags & Device::ROW) + buf << "Device::ROW "; + if(flags & Device::REFERENCED) + buf << "*Device::REFERENCED "; + if(flags & Device::VALID_ENTRY) + buf << "*Device::VALID_ENTRY "; } else buf << "no flags set"; diff --git a/src/debugger/CartDebug.hxx b/src/debugger/CartDebug.hxx index 17f67aa7a..e52389974 100644 --- a/src/debugger/CartDebug.hxx +++ b/src/debugger/CartDebug.hxx @@ -31,6 +31,7 @@ using CartMethod = int (CartDebug::*)(); #include "bspf.hxx" #include "DebuggerSystem.hxx" +#include "Device.hxx" class CartState : public DebuggerState { @@ -47,35 +48,8 @@ class CartDebug : public DebuggerSystem friend class DiStella; public: - enum DisasmType { - NONE = 0, - REFERENCED = 1 << 0, /* 0x01, code somewhere in the program references it, - i.e. LDA $F372 referenced $F372 */ - VALID_ENTRY = 1 << 1, /* 0x02, addresses that can have a label placed in front of it. - A good counterexample would be "FF00: LDA $FE00"; $FF01 - would be in the middle of a multi-byte instruction, and - therefore cannot be labelled. */ - - // The following correspond to specific types that can be set within the - // debugger, or specified in a Distella cfg file, and are listed in order - // of decreasing hierarchy - // - CODE = 1 << 10, // 0x400, disassemble-able code segments - TCODE = 1 << 9, // 0x200, (tentative) disassemble-able code segments - GFX = 1 << 8, // 0x100, addresses loaded into GRPx registers - PGFX = 1 << 7, // 0x080, addresses loaded into PFx registers - COL = 1 << 6, // 0x040, addresses loaded into COLUPx registers - PCOL = 1 << 5, // 0x010, addresses loaded into COLUPF register - BCOL = 1 << 4, // 0x010, addresses loaded into COLUBK register - DATA = 1 << 3, // 0x008, addresses loaded into registers other than GRPx / PFx - ROW = 1 << 2, // 0x004, all other addresses - // special type for poke() - WRITE = TCODE // 0x200, address written to - }; - using DisasmFlags = uInt16; - struct DisassemblyTag { - DisasmType type{NONE}; + Device::AccessType type{Device::NONE}; uInt16 address{0}; string label; string disasm; @@ -175,7 +149,7 @@ class CartDebug : public DebuggerSystem @return True if directive was added, else false if it was removed */ - bool addDirective(CartDebug::DisasmType type, uInt16 start, uInt16 end, + bool addDirective(Device::AccessType type, uInt16 start, uInt16 end, int bank = -1); // The following are convenience methods that query the cartridge object @@ -260,8 +234,8 @@ class CartDebug : public DebuggerSystem */ void getCompletions(const char* in, StringList& list) const; - // Convert given address to corresponding disassembly type and append to buf - void addressTypeAsString(ostream& buf, uInt16 addr) const; + // Convert given address to corresponding access type and append to buf + void accessTypeAsString(ostream& buf, uInt16 addr) const; private: using AddrToLabel = std::map; @@ -271,7 +245,7 @@ class CartDebug : public DebuggerSystem using AddrTypeArray = std::array; struct DirectiveTag { - DisasmType type{NONE}; + Device::AccessType type{Device::NONE}; uInt16 start{0}; uInt16 end{0}; }; @@ -309,15 +283,15 @@ class CartDebug : public DebuggerSystem // based on its disassembly void getBankDirectives(ostream& buf, BankInfo& info) const; - // Get disassembly enum type from 'flags', taking precendence into account - DisasmType disasmTypeAbsolute(CartDebug::DisasmFlags flags) const; + // Get access enum type from 'flags', taking precendence into account + Device::AccessType accessTypeAbsolute(Device::AccessFlags flags) const; - // Convert disassembly enum type to corresponding string and append to buf - void disasmTypeAsString(ostream& buf, DisasmType type) const; + // Convert access enum type to corresponding string and append to buf + void AccessTypeAsString(ostream& buf, Device::AccessType type) const; - // Convert all disassembly types in 'flags' to corresponding string and + // Convert all access types in 'flags' to corresponding string and // append to buf - void disasmTypeAsString(ostream& buf, CartDebug::DisasmFlags flags) const; + void AccessTypeAsString(ostream& buf, Device::AccessFlags flags) const; private: const OSystem& myOSystem; diff --git a/src/debugger/CpuDebug.cxx b/src/debugger/CpuDebug.cxx index b7d26c3b5..f0bf9be12 100644 --- a/src/debugger/CpuDebug.cxx +++ b/src/debugger/CpuDebug.cxx @@ -20,7 +20,6 @@ #include "M6502.hxx" #include "System.hxx" #include "Debugger.hxx" -#include "CartDebug.hxx" #include "TIADebug.hxx" #include "CpuDebug.hxx" diff --git a/src/debugger/Debugger.cxx b/src/debugger/Debugger.cxx index e332d2586..cfb16a1e5 100644 --- a/src/debugger/Debugger.cxx +++ b/src/debugger/Debugger.cxx @@ -440,19 +440,19 @@ bool Debugger::writeTrap(uInt16 t) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 Debugger::peek(uInt16 addr, CartDebug::DisasmFlags flags) +uInt8 Debugger::peek(uInt16 addr, Device::AccessFlags flags) { return mySystem.peek(addr, flags); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 Debugger::dpeek(uInt16 addr, CartDebug::DisasmFlags flags) +uInt16 Debugger::dpeek(uInt16 addr, Device::AccessFlags flags) { return uInt16(mySystem.peek(addr, flags) | (mySystem.peek(addr+1, flags) << 8)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Debugger::poke(uInt16 addr, uInt8 value, CartDebug::DisasmFlags flags) +void Debugger::poke(uInt16 addr, uInt8 value, Device::AccessFlags flags) { mySystem.poke(addr, value, flags); } @@ -464,26 +464,26 @@ M6502& Debugger::m6502() const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int Debugger::peekAsInt(int addr, CartDebug::DisasmFlags flags) +int Debugger::peekAsInt(int addr, Device::AccessFlags flags) { return mySystem.peek(uInt16(addr), flags); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int Debugger::dpeekAsInt(int addr, CartDebug::DisasmFlags flags) +int Debugger::dpeekAsInt(int addr, Device::AccessFlags flags) { return mySystem.peek(uInt16(addr), flags) | (mySystem.peek(uInt16(addr+1), flags) << 8); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -CartDebug::DisasmFlags Debugger::getAccessFlags(uInt16 addr) const +Device::AccessFlags Debugger::getAccessFlags(uInt16 addr) const { return mySystem.getAccessFlags(addr); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Debugger::setAccessFlags(uInt16 addr, CartDebug::DisasmFlags flags) +void Debugger::setAccessFlags(uInt16 addr, Device::AccessFlags flags) { mySystem.setAccessFlags(addr, flags); } diff --git a/src/debugger/Debugger.hxx b/src/debugger/Debugger.hxx index 0cfbaf458..2b0ce6c1c 100644 --- a/src/debugger/Debugger.hxx +++ b/src/debugger/Debugger.hxx @@ -47,7 +47,7 @@ class RewindManager; #include "DialogContainer.hxx" #include "DebuggerDialog.hxx" #include "FrameBufferConstants.hxx" -#include "CartDebug.hxx" +#include "Cart.hxx" #include "bspf.hxx" /** @@ -244,18 +244,18 @@ class Debugger : public DialogContainer static Debugger& debugger() { return *myStaticDebugger; } /** Convenience methods to access peek/poke from System */ - uInt8 peek(uInt16 addr, CartDebug::DisasmFlags flags = CartDebug::NONE); - uInt16 dpeek(uInt16 addr, CartDebug::DisasmFlags flags = CartDebug::NONE); - void poke(uInt16 addr, uInt8 value, CartDebug::DisasmFlags flags = CartDebug::NONE); + uInt8 peek(uInt16 addr, Device::AccessFlags flags = Device::NONE); + uInt16 dpeek(uInt16 addr, Device::AccessFlags flags = Device::NONE); + void poke(uInt16 addr, uInt8 value, Device::AccessFlags flags = Device::NONE); /** Convenience method to access the 6502 from System */ M6502& m6502() const; /** These are now exposed so Expressions can use them. */ - int peekAsInt(int addr, CartDebug::DisasmFlags flags = CartDebug::NONE); - int dpeekAsInt(int addr, CartDebug::DisasmFlags flags = CartDebug::NONE); - CartDebug::DisasmFlags getAccessFlags(uInt16 addr) const; - void setAccessFlags(uInt16 addr, CartDebug::DisasmFlags flags); + int peekAsInt(int addr, Device::AccessFlags flags = Device::NONE); + int dpeekAsInt(int addr, Device::AccessFlags flags = Device::NONE); + Device::AccessFlags getAccessFlags(uInt16 addr) const; + void setAccessFlags(uInt16 addr, Device::AccessFlags flags); uInt32 getBaseAddress(uInt32 addr, bool read); diff --git a/src/debugger/DebuggerParser.cxx b/src/debugger/DebuggerParser.cxx index f3dfde946..176083b1f 100644 --- a/src/debugger/DebuggerParser.cxx +++ b/src/debugger/DebuggerParser.cxx @@ -924,7 +924,7 @@ void DebuggerParser::executeCode() } bool result = debugger.cartDebug().addDirective( - CartDebug::CODE, args[0], args[1]); + Device::CODE, args[0], args[1]); commandResult << (result ? "added" : "removed") << " CODE directive on range $" << hex << args[0] << " $" << hex << args[1]; debugger.rom().invalidate(); @@ -965,7 +965,7 @@ void DebuggerParser::executeData() } bool result = debugger.cartDebug().addDirective( - CartDebug::DATA, args[0], args[1]); + Device::DATA, args[0], args[1]); commandResult << (result ? "added" : "removed") << " DATA directive on range $" << hex << args[0] << " $" << hex << args[1]; debugger.rom().invalidate(); @@ -1282,7 +1282,7 @@ void DebuggerParser::executeGfx() } bool result = debugger.cartDebug().addDirective( - CartDebug::GFX, args[0], args[1]); + Device::GFX, args[0], args[1]); commandResult << (result ? "added" : "removed") << " GFX directive on range $" << hex << args[0] << " $" << hex << args[1]; debugger.rom().invalidate(); @@ -1642,7 +1642,7 @@ void DebuggerParser::executePGfx() } bool result = debugger.cartDebug().addDirective( - CartDebug::PGFX, args[0], args[1]); + Device::PGFX, args[0], args[1]); commandResult << (result ? "added" : "removed") << " PGFX directive on range $" << hex << args[0] << " $" << hex << args[1]; debugger.rom().invalidate(); @@ -1734,7 +1734,7 @@ void DebuggerParser::executeRow() } bool result = debugger.cartDebug().addDirective( - CartDebug::ROW, args[0], args[1]); + Device::ROW, args[0], args[1]); commandResult << (result ? "added" : "removed") << " ROW directive on range $" << hex << args[0] << " $" << hex << args[1]; debugger.rom().invalidate(); @@ -2194,7 +2194,7 @@ void DebuggerParser::executeType() for(uInt32 i = beg; i <= end; ++i) { commandResult << Base::HEX4 << i << ": "; - debugger.cartDebug().addressTypeAsString(commandResult, i); + debugger.cartDebug().accessTypeAsString(commandResult, i); commandResult << endl; } } @@ -3182,7 +3182,7 @@ std::array DebuggerParser::commands = { { { "type", - "Show disassembly type for address xx [yy]", + "Show access type for address xx [yy]", "Example: type f000, type f000 f010", true, false, diff --git a/src/debugger/DiStella.cxx b/src/debugger/DiStella.cxx index 235b2d9da..43d67749e 100644 --- a/src/debugger/DiStella.cxx +++ b/src/debugger/DiStella.cxx @@ -17,6 +17,7 @@ #include "bspf.hxx" #include "Debugger.hxx" +#include "Device.hxx" #include "DiStella.hxx" using Common::Base; @@ -73,7 +74,7 @@ DiStella::DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list, // Add reserved line equates ostringstream reservedLabel; for (int k = 0; k <= myAppData.end; k++) { - if ((myLabels[k] & (CartDebug::REFERENCED | CartDebug::VALID_ENTRY)) == CartDebug::REFERENCED) { + if ((myLabels[k] & (Device::REFERENCED | Device::VALID_ENTRY)) == Device::REFERENCED) { // If we have a piece of code referenced somewhere else, but cannot // locate the label in code (i.e because the address is inside of a // multi-byte instruction, then we make note of that address for reference @@ -110,7 +111,7 @@ void DiStella::disasm(uInt32 distart, int pass) int labelFound = 0; stringstream nextLine, nextLineBytes; - mySegType = CartDebug::NONE; // create extra lines between code and data + mySegType = Device::NONE; // create extra lines between code and data myDisasmBuf.str(""); @@ -124,58 +125,58 @@ void DiStella::disasm(uInt32 distart, int pass) if(myPC == myAppData.end) goto FIX_LAST; - if (checkBits(myPC, CartDebug::GFX | CartDebug::PGFX, - CartDebug::CODE)) + if (checkBits(myPC, Device::GFX | Device::PGFX, + Device::CODE)) { if (pass == 2) - mark(myPC + myOffset, CartDebug::VALID_ENTRY); + mark(myPC + myOffset, Device::VALID_ENTRY); if (pass == 3) outputGraphics(); ++myPC; - } else if (checkBits(myPC, CartDebug::COL | CartDebug::PCOL | CartDebug::BCOL, - CartDebug::CODE | CartDebug::GFX | CartDebug::PGFX)) + } else if (checkBits(myPC, Device::COL | Device::PCOL | Device::BCOL, + Device::CODE | Device::GFX | Device::PGFX)) { if (pass == 2) - mark(myPC + myOffset, CartDebug::VALID_ENTRY); + mark(myPC + myOffset, Device::VALID_ENTRY); if (pass == 3) outputColors(); ++myPC; - } else if (checkBits(myPC, CartDebug::DATA, - CartDebug::CODE | CartDebug::GFX | CartDebug::PGFX | - CartDebug::COL | CartDebug::PCOL | CartDebug::BCOL)) + } else if (checkBits(myPC, Device::DATA, + Device::CODE | Device::GFX | Device::PGFX | + Device::COL | Device::PCOL | Device::BCOL)) { if (pass == 2) - mark(myPC + myOffset, CartDebug::VALID_ENTRY); + mark(myPC + myOffset, Device::VALID_ENTRY); if (pass == 3) - outputBytes(CartDebug::DATA); + outputBytes(Device::DATA); else ++myPC; - } else if (checkBits(myPC, CartDebug::ROW, - CartDebug::CODE | - CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX | - CartDebug::COL | CartDebug::PCOL | CartDebug::BCOL)) { + } else if (checkBits(myPC, Device::ROW, + Device::CODE | + Device::DATA | Device::GFX | Device::PGFX | + Device::COL | Device::PCOL | Device::BCOL)) { FIX_LAST: if (pass == 2) - mark(myPC + myOffset, CartDebug::VALID_ENTRY); + mark(myPC + myOffset, Device::VALID_ENTRY); if (pass == 3) - outputBytes(CartDebug::ROW); + outputBytes(Device::ROW); else ++myPC; } else { // The following sections must be CODE // add extra spacing line when switching from non-code to code - if (pass == 3 && mySegType != CartDebug::CODE && mySegType != CartDebug::NONE) { + if (pass == 3 && mySegType != Device::CODE && mySegType != Device::NONE) { myDisasmBuf << " ' ' "; - addEntry(CartDebug::NONE); - mark(myPC + myOffset, CartDebug::REFERENCED); // add label when switching + addEntry(Device::NONE); + mark(myPC + myOffset, Device::REFERENCED); // add label when switching } - mySegType = CartDebug::CODE; + mySegType = Device::CODE; /* version 2.1 bug fix */ if (pass == 2) - mark(myPC + myOffset, CartDebug::VALID_ENTRY); + mark(myPC + myOffset, Device::VALID_ENTRY); // get opcode opcode = Debugger::debugger().peek(myPC + myOffset); @@ -183,7 +184,7 @@ FIX_LAST: addrMode = ourLookup[opcode].addr_mode; if (pass == 3) { - if (checkBit(myPC, CartDebug::REFERENCED)) + if (checkBit(myPC, Device::REFERENCED)) myDisasmBuf << Base::HEX4 << myPC + myOffset << "'L" << Base::HEX4 << myPC + myOffset << "'"; else myDisasmBuf << Base::HEX4 << myPC + myOffset << "' '"; @@ -193,7 +194,7 @@ FIX_LAST: // detect labels inside instructions (e.g. BIT masks) labelFound = false; for (Uint8 i = 0; i < ourLookup[opcode].bytes - 1; i++) { - if (checkBit(myPC + i, CartDebug::REFERENCED)) { + if (checkBit(myPC + i, Device::REFERENCED)) { labelFound = true; break; } @@ -216,7 +217,7 @@ FIX_LAST: nextLine.str(""); cycles = 0; - addEntry(CartDebug::CODE); // add the new found CODE entry + addEntry(Device::CODE); // add the new found CODE entry } // continue with the label's opcode continue; @@ -255,10 +256,10 @@ FIX_LAST: myDisasmBuf << ".byte $" << Base::HEX2 << int(opcode) << " $" << Base::HEX4 << myPC + myOffset << "'" << Base::HEX2 << int(opcode); - addEntry(CartDebug::DATA); + addEntry(Device::DATA); if (myPC == myAppData.end) { - if (checkBit(myPC, CartDebug::REFERENCED)) + if (checkBit(myPC, Device::REFERENCED)) myDisasmBuf << Base::HEX4 << myPC + myOffset << "'L" << Base::HEX4 << myPC + myOffset << "'"; else myDisasmBuf << Base::HEX4 << myPC + myOffset << "' '"; @@ -267,7 +268,7 @@ FIX_LAST: myDisasmBuf << ".byte $" << Base::HEX2 << int(opcode) << " $" << Base::HEX4 << myPC + myOffset << "'" << Base::HEX2 << int(opcode); - addEntry(CartDebug::DATA); + addEntry(Device::DATA); } } myPCEnd = myAppData.end + myOffset; @@ -284,7 +285,7 @@ FIX_LAST: /* Line information is already printed, but we can remove the Instruction (i.e. BMI) by simply clearing the buffer to print */ myDisasmBuf << ".byte $" << Base::HEX2 << int(opcode); - addEntry(CartDebug::ROW); + addEntry(Device::ROW); nextLine.str(""); nextLineBytes.str(""); } @@ -312,7 +313,7 @@ FIX_LAST: case AddressingMode::ABSOLUTE: { ad = Debugger::debugger().dpeek(myPC + myOffset); myPC += 2; - labelFound = mark(ad, CartDebug::REFERENCED); + labelFound = mark(ad, Device::REFERENCED); if (pass == 3) { if (ad < 0x100 && mySettings.fFlag) nextLine << ".w "; @@ -342,7 +343,7 @@ FIX_LAST: case AddressingMode::ZERO_PAGE: { d1 = Debugger::debugger().peek(myPC + myOffset); ++myPC; - labelFound = mark(d1, CartDebug::REFERENCED); + labelFound = mark(d1, Device::REFERENCED); if (pass == 3) { nextLine << " "; LABEL_A12_LOW(int(d1)); @@ -364,13 +365,13 @@ FIX_LAST: case AddressingMode::ABSOLUTE_X: { ad = Debugger::debugger().dpeek(myPC + myOffset); myPC += 2; - labelFound = mark(ad, CartDebug::REFERENCED); - if (pass == 2 && !checkBit(ad & myAppData.end, CartDebug::CODE)) { + labelFound = mark(ad, Device::REFERENCED); + if (pass == 2 && !checkBit(ad & myAppData.end, Device::CODE)) { // Since we can't know what address is being accessed unless we also // know the current X value, this is marked as ROW instead of DATA // The processing is left here, however, in case future versions of // the code can somehow track access to CPU registers - mark(ad, CartDebug::ROW); + mark(ad, Device::ROW); } else if (pass == 3) { if (ad < 0x100 && mySettings.fFlag) nextLine << ".wx "; @@ -403,13 +404,13 @@ FIX_LAST: case AddressingMode::ABSOLUTE_Y: { ad = Debugger::debugger().dpeek(myPC + myOffset); myPC += 2; - labelFound = mark(ad, CartDebug::REFERENCED); - if (pass == 2 && !checkBit(ad & myAppData.end, CartDebug::CODE)) { + labelFound = mark(ad, Device::REFERENCED); + if (pass == 2 && !checkBit(ad & myAppData.end, Device::CODE)) { // Since we can't know what address is being accessed unless we also // know the current Y value, this is marked as ROW instead of DATA // The processing is left here, however, in case future versions of // the code can somehow track access to CPU registers - mark(ad, CartDebug::ROW); + mark(ad, Device::ROW); } else if (pass == 3) { if (ad < 0x100 && mySettings.fFlag) nextLine << ".wy "; @@ -468,7 +469,7 @@ FIX_LAST: case AddressingMode::ZERO_PAGE_X: { d1 = Debugger::debugger().peek(myPC + myOffset); ++myPC; - labelFound = mark(d1, CartDebug::REFERENCED); + labelFound = mark(d1, Device::REFERENCED); if (pass == 3) { nextLine << " "; LABEL_A12_LOW(d1); @@ -481,7 +482,7 @@ FIX_LAST: case AddressingMode::ZERO_PAGE_Y: { d1 = Debugger::debugger().peek(myPC + myOffset); ++myPC; - labelFound = mark(d1, CartDebug::REFERENCED); + labelFound = mark(d1, Device::REFERENCED); if (pass == 3) { nextLine << " "; LABEL_A12_LOW(d1); @@ -499,7 +500,7 @@ FIX_LAST: d1 = Debugger::debugger().peek(myPC + myOffset); ++myPC; ad = ((myPC + Int8(d1)) & 0xfff) + myOffset; - labelFound = mark(ad, CartDebug::REFERENCED); + labelFound = mark(ad, Device::REFERENCED); if (pass == 3) { if (labelFound == 1) { nextLine << " "; @@ -515,13 +516,13 @@ FIX_LAST: case AddressingMode::ABS_INDIRECT: { ad = Debugger::debugger().dpeek(myPC + myOffset); myPC += 2; - labelFound = mark(ad, CartDebug::REFERENCED); - if (pass == 2 && !checkBit(ad & myAppData.end, CartDebug::CODE)) { + labelFound = mark(ad, Device::REFERENCED); + if (pass == 2 && !checkBit(ad & myAppData.end, Device::CODE)) { // Since we can't know what address is being accessed unless we also // know the current X value, this is marked as ROW instead of DATA // The processing is left here, however, in case future versions of // the code can somehow track access to CPU registers - mark(ad, CartDebug::ROW); + mark(ad, Device::ROW); } else if (pass == 3) { if (ad < 0x100 && mySettings.fFlag) nextLine << ".ind "; @@ -555,7 +556,7 @@ FIX_LAST: << ";" << std::dec << int(ourLookup[opcode].cycles) << (addrMode == AddressingMode::RELATIVE ? (ad & 0xf00) != ((myPC + myOffset) & 0xf00) ? "/3!" : "/3 " : " "); if ((opcode == 0x40 || opcode == 0x60 || opcode == 0x4c || opcode == 0x00 // code block end - || checkBit(myPC, CartDebug::REFERENCED) // referenced address + || checkBit(myPC, Device::REFERENCED) // referenced address || (ourLookup[opcode].rw_mode == RWMode::WRITE && d1 == WSYNC)) // strobe WSYNC && cycles > 0) { // output cycles for previous code block @@ -566,11 +567,11 @@ FIX_LAST: } myDisasmBuf << "'" << nextLineBytes.str(); - addEntry(CartDebug::CODE); + addEntry(Device::CODE); if (opcode == 0x40 || opcode == 0x60 || opcode == 0x4c || opcode == 0x00) { myDisasmBuf << " ' ' "; - addEntry(CartDebug::NONE); - mySegType = CartDebug::NONE; // prevent extra lines if data follows + addEntry(Device::NONE); + mySegType = Device::NONE; // prevent extra lines if data follows } nextLine.str(""); @@ -619,17 +620,17 @@ void DiStella::disasmPass1(CartDebug::AddressList& debuggerAddresses) // in the emulation core indicate that the CODE range has finished // Therefore, we stop at the first such address encountered for (uInt32 k = pcBeg; k <= myPCEnd; ++k) { - if (checkBits(k, CartDebug::CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX | - CartDebug::COL | CartDebug::PCOL | CartDebug::BCOL, - CartDebug::CODE)) { + if (checkBits(k, Device::Device::DATA | Device::GFX | Device::PGFX | + Device::COL | Device::PCOL | Device::BCOL, + Device::CODE)) { //if (Debugger::debugger().getAccessFlags(k) & - // (CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX)) { + // (Device::DATA | Device::GFX | Device::PGFX)) { // TODO: this should never happen, remove when we are sure // TODO: NOT USED: uInt16 flags = Debugger::debugger().getAccessFlags(k); myPCEnd = k - 1; break; } - mark(k, CartDebug::CODE); + mark(k, Device::CODE); } } @@ -651,7 +652,7 @@ void DiStella::disasmPass1(CartDebug::AddressList& debuggerAddresses) while (myAddressQueue.empty() && it != debuggerAddresses.end()) { uInt16 addr = *it; - if (!checkBit(addr - myOffset, CartDebug::CODE)) { + if (!checkBit(addr - myOffset, Device::CODE)) { myAddressQueue.push(addr); ++it; } else // remove this address, it is redundant @@ -661,8 +662,8 @@ void DiStella::disasmPass1(CartDebug::AddressList& debuggerAddresses) // Stella itself can provide hints on whether an address has ever // been referenced as CODE while (myAddressQueue.empty() && codeAccessPoint <= myAppData.end) { - if ((Debugger::debugger().getAccessFlags(codeAccessPoint + myOffset) & CartDebug::CODE) - && !(myLabels[codeAccessPoint & myAppData.end] & CartDebug::CODE)) { + if ((Debugger::debugger().getAccessFlags(codeAccessPoint + myOffset) & Device::CODE) + && !(myLabels[codeAccessPoint & myAppData.end] & Device::CODE)) { myAddressQueue.push(codeAccessPoint + myOffset); ++codeAccessPoint; break; @@ -674,17 +675,17 @@ void DiStella::disasmPass1(CartDebug::AddressList& debuggerAddresses) for (int k = 0; k <= myAppData.end; k++) { // Let the emulation core know about tentative code - if (checkBit(k, CartDebug::CODE) && - !(Debugger::debugger().getAccessFlags(k + myOffset) & CartDebug::CODE) + if (checkBit(k, Device::CODE) && + !(Debugger::debugger().getAccessFlags(k + myOffset) & Device::CODE) && myOffset != 0) { - Debugger::debugger().setAccessFlags(k + myOffset, CartDebug::TCODE); + Debugger::debugger().setAccessFlags(k + myOffset, Device::TCODE); } // Must be ROW / unused bytes - if (!checkBit(k, CartDebug::CODE | CartDebug::GFX | CartDebug::PGFX | - CartDebug::COL | CartDebug::PCOL | CartDebug::BCOL | - CartDebug::DATA)) - mark(k + myOffset, CartDebug::ROW); + if (!checkBit(k, Device::CODE | Device::GFX | Device::PGFX | + Device::COL | Device::PCOL | Device::BCOL | + Device::DATA)) + mark(k + myOffset, Device::ROW); } } @@ -700,9 +701,9 @@ void DiStella::disasmFromAddress(uInt32 distart) while (myPC <= myAppData.end) { // abort when we reach non-code areas - if (checkBits(myPC, CartDebug::CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX | - CartDebug::COL | CartDebug::PCOL | CartDebug::BCOL, - CartDebug::CODE)) { + if (checkBits(myPC, Device::Device::DATA | Device::GFX | Device::PGFX | + Device::COL | Device::PCOL | Device::BCOL, + Device::CODE)) { myPCEnd = (myPC - 1) + myOffset; return; } @@ -746,22 +747,22 @@ void DiStella::disasmFromAddress(uInt32 distart) switch (addrMode) { case AddressingMode::ABSOLUTE: ad = Debugger::debugger().dpeek(myPC + myOffset); myPC += 2; - mark(ad, CartDebug::REFERENCED); + mark(ad, Device::REFERENCED); // handle JMP/JSR if (ourLookup[opcode].source == AccessMode::ADDR) { // do NOT use flags set by debugger, else known CODE will not analyzed statically. - if (!checkBit(ad & myAppData.end, CartDebug::CODE, false)) { + if (!checkBit(ad & myAppData.end, Device::CODE, false)) { if (ad > 0xfff) myAddressQueue.push((ad & myAppData.end) + myOffset); - mark(ad, CartDebug::CODE); + mark(ad, Device::CODE); } } else - mark(ad, CartDebug::DATA); + mark(ad, Device::DATA); break; case AddressingMode::ZERO_PAGE: d1 = Debugger::debugger().peek(myPC + myOffset); ++myPC; - mark(d1, CartDebug::REFERENCED); + mark(d1, Device::REFERENCED); break; case AddressingMode::IMMEDIATE: @@ -770,12 +771,12 @@ void DiStella::disasmFromAddress(uInt32 distart) case AddressingMode::ABSOLUTE_X: ad = Debugger::debugger().dpeek(myPC + myOffset); myPC += 2; - mark(ad, CartDebug::REFERENCED); + mark(ad, Device::REFERENCED); break; case AddressingMode::ABSOLUTE_Y: ad = Debugger::debugger().dpeek(myPC + myOffset); myPC += 2; - mark(ad, CartDebug::REFERENCED); + mark(ad, Device::REFERENCED); break; case AddressingMode::INDIRECT_X: @@ -788,12 +789,12 @@ void DiStella::disasmFromAddress(uInt32 distart) case AddressingMode::ZERO_PAGE_X: d1 = Debugger::debugger().peek(myPC + myOffset); ++myPC; - mark(d1, CartDebug::REFERENCED); + mark(d1, Device::REFERENCED); break; case AddressingMode::ZERO_PAGE_Y: d1 = Debugger::debugger().peek(myPC + myOffset); ++myPC; - mark(d1, CartDebug::REFERENCED); + mark(d1, Device::REFERENCED); break; case AddressingMode::RELATIVE: @@ -802,17 +803,17 @@ void DiStella::disasmFromAddress(uInt32 distart) // indexing into the labels array caused a crash d1 = Debugger::debugger().peek(myPC + myOffset); ++myPC; ad = ((myPC + Int8(d1)) & 0xfff) + myOffset; - mark(ad, CartDebug::REFERENCED); + mark(ad, Device::REFERENCED); // do NOT use flags set by debugger, else known CODE will not analyzed statically. - if (!checkBit(ad - myOffset, CartDebug::CODE, false)) { + if (!checkBit(ad - myOffset, Device::CODE, false)) { myAddressQueue.push(ad); - mark(ad, CartDebug::CODE); + mark(ad, Device::CODE); } break; case AddressingMode::ABS_INDIRECT: ad = Debugger::debugger().dpeek(myPC + myOffset); myPC += 2; - mark(ad, CartDebug::REFERENCED); + mark(ad, Device::REFERENCED); break; default: @@ -821,10 +822,10 @@ void DiStella::disasmFromAddress(uInt32 distart) // mark BRK vector if (opcode == 0x00) { - ad = Debugger::debugger().dpeek(0xfffe, CartDebug::DATA); + ad = Debugger::debugger().dpeek(0xfffe, Device::DATA); if (!myReserved.breakFound) { myAddressQueue.push(ad); - mark(ad, CartDebug::CODE); + mark(ad, Device::CODE); myReserved.breakFound = true; } } @@ -943,8 +944,8 @@ bool DiStella::checkBits(uInt16 address, uInt16 mask, uInt16 notMask, bool useDe /*bool DiStella::isType(uInt16 address) const { - return checkBits(address, CartDebug::GFX | CartDebug::PGFX | - CartDebug::COL | CartDebug::PCOL | CartDebug::BCOL); + return checkBits(address, Device::GFX | Device::PGFX | + Device::COL | Device::PCOL | Device::BCOL); }*/ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -967,7 +968,7 @@ bool DiStella::check_range(uInt16 beg, uInt16 end) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void DiStella::addEntry(CartDebug::DisasmType type) +void DiStella::addEntry(Device::AccessType type) { CartDebug::DisassemblyTag tag; @@ -993,7 +994,7 @@ void DiStella::addEntry(CartDebug::DisasmType type) if (tag.label == EmptyString) { if (myDisasmBuf.peek() != ' ') getline(myDisasmBuf, tag.label, '\''); - else if (mySettings.showAddresses && tag.type == CartDebug::CODE) { + else if (mySettings.showAddresses && tag.type == Device::CODE) { // Have addresses indented, to differentiate from actual labels tag.label = " " + Base::toString(tag.address, Base::Fmt::_16_4); tag.hllabel = false; @@ -1006,7 +1007,7 @@ void DiStella::addEntry(CartDebug::DisasmType type) // variable length labels, cycle counts, etc myDisasmBuf.seekg(11, std::ios::beg); switch (tag.type) { - case CartDebug::CODE: + case Device::CODE: getline(myDisasmBuf, tag.disasm, '\''); getline(myDisasmBuf, tag.ccount, '\''); getline(myDisasmBuf, tag.ctotal, '\''); @@ -1017,36 +1018,36 @@ void DiStella::addEntry(CartDebug::DisasmType type) // but it could also indicate that code will *never* be accessed // Since it is impossible to tell the difference, marking the address // in the disassembly at least tells the user about it - if (!(Debugger::debugger().getAccessFlags(tag.address) & CartDebug::CODE) + if (!(Debugger::debugger().getAccessFlags(tag.address) & Device::CODE) && myOffset != 0) { tag.ccount += " *"; - Debugger::debugger().setAccessFlags(tag.address, CartDebug::TCODE); + Debugger::debugger().setAccessFlags(tag.address, Device::TCODE); } break; - case CartDebug::GFX: - case CartDebug::PGFX: + case Device::GFX: + case Device::PGFX: getline(myDisasmBuf, tag.disasm, '\''); getline(myDisasmBuf, tag.bytes); break; - case CartDebug::COL: - case CartDebug::PCOL: - case CartDebug::BCOL: + case Device::COL: + case Device::PCOL: + case Device::BCOL: getline(myDisasmBuf, tag.disasm, '\''); getline(myDisasmBuf, tag.bytes); break; - case CartDebug::DATA: + case Device::DATA: getline(myDisasmBuf, tag.disasm, '\''); getline(myDisasmBuf, tag.bytes); break; - case CartDebug::ROW: + case Device::ROW: getline(myDisasmBuf, tag.disasm); break; - case CartDebug::NONE: + case Device::NONE: default: // should never happen tag.disasm = " "; break; @@ -1061,18 +1062,18 @@ DONE_WITH_ADD: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DiStella::outputGraphics() { - bool isPGfx = checkBit(myPC, CartDebug::PGFX); + bool isPGfx = checkBit(myPC, Device::PGFX); const string& bitString = isPGfx ? "\x1f" : "\x1e"; uInt8 byte = Debugger::debugger().peek(myPC + myOffset); // add extra spacing line when switching from non-graphics to graphics - if (mySegType != CartDebug::GFX && mySegType != CartDebug::NONE) { + if (mySegType != Device::GFX && mySegType != Device::NONE) { myDisasmBuf << " ' ' "; - addEntry(CartDebug::NONE); + addEntry(Device::NONE); } - mySegType = CartDebug::GFX; + mySegType = Device::GFX; - if (checkBit(myPC, CartDebug::REFERENCED)) + if (checkBit(myPC, Device::REFERENCED)) myDisasmBuf << Base::HEX4 << myPC + myOffset << "'L" << Base::HEX4 << myPC + myOffset << "'"; else myDisasmBuf << Base::HEX4 << myPC + myOffset << "' '"; @@ -1085,7 +1086,7 @@ void DiStella::outputGraphics() else myDisasmBuf << Base::HEX2 << int(byte); - addEntry(isPGfx ? CartDebug::PGFX : CartDebug::GFX); + addEntry(isPGfx ? Device::PGFX : Device::GFX); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1111,15 +1112,15 @@ void DiStella::outputColors() uInt8 byte = Debugger::debugger().peek(myPC + myOffset); // add extra spacing line when switching from non-colors to colors - if(mySegType != CartDebug::COL && mySegType != CartDebug::NONE) + if(mySegType != Device::COL && mySegType != Device::NONE) { myDisasmBuf << " ' ' "; - addEntry(CartDebug::NONE); + addEntry(Device::NONE); } - mySegType = CartDebug::COL; + mySegType = Device::COL; // output label/address - if(checkBit(myPC, CartDebug::REFERENCED)) + if(checkBit(myPC, Device::REFERENCED)) myDisasmBuf << Base::HEX4 << myPC + myOffset << "'L" << Base::HEX4 << myPC + myOffset << "'"; else myDisasmBuf << Base::HEX4 << myPC + myOffset << "' '"; @@ -1147,29 +1148,29 @@ void DiStella::outputColors() // output address myDisasmBuf << "; $" << Base::HEX4 << myPC + myOffset << " " - << (checkBit(myPC, CartDebug::COL) ? "(Px)" : checkBit(myPC, CartDebug::PCOL) ? "(PF)" : "(BK)"); + << (checkBit(myPC, Device::COL) ? "(Px)" : checkBit(myPC, Device::PCOL) ? "(PF)" : "(BK)"); // output color value myDisasmBuf << "'" << Base::HEX2 << int(byte); - addEntry(checkBit(myPC, CartDebug::COL) ? CartDebug::COL : - checkBit(myPC, CartDebug::PCOL) ? CartDebug::PCOL : CartDebug::BCOL); + addEntry(checkBit(myPC, Device::COL) ? Device::COL : + checkBit(myPC, Device::PCOL) ? Device::PCOL : Device::BCOL); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void DiStella::outputBytes(CartDebug::DisasmType type) +void DiStella::outputBytes(Device::AccessType type) { bool isType = true; - bool referenced = checkBit(myPC, CartDebug::REFERENCED); + bool referenced = checkBit(myPC, Device::REFERENCED); bool lineEmpty = true; int numBytes = 0; // add extra spacing line when switching from non-data to data - if (mySegType != CartDebug::DATA && mySegType != CartDebug::NONE) { + if (mySegType != Device::DATA && mySegType != Device::NONE) { myDisasmBuf << " ' ' "; - addEntry(CartDebug::NONE); + addEntry(Device::NONE); } - mySegType = CartDebug::DATA; + mySegType = Device::DATA; while (isType && myPC <= myAppData.end) { if (referenced) { @@ -1200,15 +1201,15 @@ void DiStella::outputBytes(CartDebug::DisasmType type) ++myPC; } isType = checkBits(myPC, type, - CartDebug::CODE | (type != CartDebug::DATA ? CartDebug::DATA : 0) | - CartDebug::GFX | CartDebug::PGFX | - CartDebug::COL | CartDebug::PCOL | CartDebug::BCOL); - referenced = checkBit(myPC, CartDebug::REFERENCED); + Device::CODE | (type != Device::DATA ? Device::DATA : 0) | + Device::GFX | Device::PGFX | + Device::COL | Device::PCOL | Device::BCOL); + referenced = checkBit(myPC, Device::REFERENCED); } if (!lineEmpty) addEntry(type); /*myDisasmBuf << " ' ' "; - addEntry(CartDebug::NONE);*/ + addEntry(Device::NONE);*/ } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/debugger/DiStella.hxx b/src/debugger/DiStella.hxx index 830835a02..bb1b54f5e 100644 --- a/src/debugger/DiStella.hxx +++ b/src/debugger/DiStella.hxx @@ -22,6 +22,7 @@ #include "Base.hxx" #include "CartDebug.hxx" +#include "Device.hxx" #include "bspf.hxx" /** @@ -75,7 +76,7 @@ class DiStella // Indicate that a new line of disassembly has been completed // In the original Distella code, this indicated a new line to be printed // Here, we add a new entry to the DisassemblyList - void addEntry(CartDebug::DisasmType type); + void addEntry(Device::AccessType type); // Process directives given in the list // Directives are basically the contents of a distella configuration file @@ -93,7 +94,7 @@ class DiStella //bool isType(uInt16 address) const; void outputGraphics(); void outputColors(); - void outputBytes(CartDebug::DisasmType type); + void outputBytes(Device::AccessType type); // Convenience methods to generate appropriate labels inline void labelA12High(stringstream& buf, uInt8 op, uInt16 addr, int labfound) diff --git a/src/debugger/gui/RomListWidget.cxx b/src/debugger/gui/RomListWidget.cxx index fdc24fb71..b4af0daf7 100644 --- a/src/debugger/gui/RomListWidget.cxx +++ b/src/debugger/gui/RomListWidget.cxx @@ -511,10 +511,10 @@ void RomListWidget::drawWidget(bool hilite) // Bytes are only editable if they represent code, graphics, or accessible data // Otherwise, the disassembly should get all remaining space - if(dlist[pos].type & (CartDebug::CODE|CartDebug::GFX|CartDebug::PGFX| - CartDebug::COL|CartDebug::PCOL|CartDebug::BCOL|CartDebug::DATA)) + if(dlist[pos].type & (Device::CODE|Device::GFX|Device::PGFX| + Device::COL|Device::PCOL|Device::BCOL|Device::DATA)) { - if(dlist[pos].type == CartDebug::CODE) + if(dlist[pos].type == Device::CODE) { // Draw mnemonic s.drawString(_font, dlist[pos].disasm.substr(0, 7), xpos + _labelWidth, ypos, @@ -593,8 +593,8 @@ void RomListWidget::startEditMode() _editMode = true; switch(myDisasm->list[_selectedItem].type) { - case CartDebug::GFX: - case CartDebug::PGFX: + case Device::GFX: + case Device::PGFX: _base = DiStella::settings.gfxFormat; break; default: diff --git a/src/emucore/Cart.cxx b/src/emucore/Cart.cxx index cd40f886b..ec7cea379 100644 --- a/src/emucore/Cart.cxx +++ b/src/emucore/Cart.cxx @@ -20,7 +20,6 @@ #include "MD5.hxx" #ifdef DEBUGGER_SUPPORT #include "Debugger.hxx" - #include "CartDebug.hxx" #endif #include "Cart.hxx" @@ -117,8 +116,8 @@ void Cartridge::pokeRAM(uInt8& dest, uInt16 address, uInt8 value) void Cartridge::createCodeAccessBase(size_t size) { #ifdef DEBUGGER_SUPPORT - myCodeAccessBase = make_unique(size); - std::fill_n(myCodeAccessBase.get(), size, CartDebug::ROW); + myCodeAccessBase = make_unique(size); + std::fill_n(myCodeAccessBase.get(), size, Device::ROW); #else myCodeAccessBase = nullptr; #endif diff --git a/src/emucore/Cart.hxx b/src/emucore/Cart.hxx index 5a34f1fc3..4b9cda533 100644 --- a/src/emucore/Cart.hxx +++ b/src/emucore/Cart.hxx @@ -30,7 +30,7 @@ class GuiObject; #ifdef DEBUGGER_SUPPORT #include "Font.hxx" #endif -#include "CartDebug.hxx" + /** A cartridge is a device which contains the machine code for a @@ -323,7 +323,7 @@ class Cartridge : public Device // The array containing information about every byte of ROM indicating // whether it is used as code. - std::unique_ptr myCodeAccessBase; + std::unique_ptr myCodeAccessBase; // Contains address of illegal RAM write access or 0 uInt16 myRamWriteAccess{0}; diff --git a/src/emucore/Cart4A50.cxx b/src/emucore/Cart4A50.cxx index 9ac05b2b3..fd05804d4 100644 --- a/src/emucore/Cart4A50.cxx +++ b/src/emucore/Cart4A50.cxx @@ -182,7 +182,7 @@ bool Cartridge4A50::poke(uInt16 address, uInt8 value) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -CartDebug::DisasmFlags Cartridge4A50::getAccessFlags(uInt16 address) const +Device::AccessFlags Cartridge4A50::getAccessFlags(uInt16 address) const { if((address & 0x1800) == 0x1000) // 2K region from 0x1000 - 0x17ff { @@ -214,7 +214,7 @@ CartDebug::DisasmFlags Cartridge4A50::getAccessFlags(uInt16 address) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge4A50::setAccessFlags(uInt16 address, CartDebug::DisasmFlags flags) +void Cartridge4A50::setAccessFlags(uInt16 address, Device::AccessFlags flags) { if((address & 0x1800) == 0x1000) // 2K region from 0x1000 - 0x17ff { diff --git a/src/emucore/Cart4A50.hxx b/src/emucore/Cart4A50.hxx index e1299431c..d55ec8d2f 100644 --- a/src/emucore/Cart4A50.hxx +++ b/src/emucore/Cart4A50.hxx @@ -154,18 +154,18 @@ class Cartridge4A50 : public Cartridge private: /** - Query the given address type for the associated disassembly flags. + Query the given address type for the associated access flags. @param address The address to query */ - CartDebug::DisasmFlags getAccessFlags(uInt16 address) const override; + Device::AccessFlags getAccessFlags(uInt16 address) const override; /** - Change the given address to use the given disassembly flags. + Change the given address to use the given access flags. @param address The address to modify - @param flags A bitfield of DisasmType directives for the given address + @param flags A bitfield of AccessType directives for the given address */ - void setAccessFlags(uInt16 address, CartDebug::DisasmFlags flags) override; + void setAccessFlags(uInt16 address, Device::AccessFlags flags) override; /** Check all possible hotspots diff --git a/src/emucore/CartAR.cxx b/src/emucore/CartAR.cxx index fc63d7954..42d12c0fd 100644 --- a/src/emucore/CartAR.cxx +++ b/src/emucore/CartAR.cxx @@ -191,14 +191,14 @@ bool CartridgeAR::poke(uInt16 addr, uInt8) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -CartDebug::DisasmFlags CartridgeAR::getAccessFlags(uInt16 address) const +Device::AccessFlags CartridgeAR::getAccessFlags(uInt16 address) const { return myCodeAccessBase[(address & 0x07FF) + myImageOffset[(address & 0x0800) ? 1 : 0]]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeAR::setAccessFlags(uInt16 address, CartDebug::DisasmFlags flags) +void CartridgeAR::setAccessFlags(uInt16 address, Device::AccessFlags flags) { myCodeAccessBase[(address & 0x07FF) + myImageOffset[(address & 0x0800) ? 1 : 0]] |= flags; diff --git a/src/emucore/CartAR.hxx b/src/emucore/CartAR.hxx index 888e5e6f9..877817c1b 100644 --- a/src/emucore/CartAR.hxx +++ b/src/emucore/CartAR.hxx @@ -160,18 +160,18 @@ class CartridgeAR : public Cartridge private: /** - Query the given address type for the associated disassembly flags. + Query the given address type for the associated access flags. @param address The address to query */ - CartDebug::DisasmFlags getAccessFlags(uInt16 address) const override; + Device::AccessFlags getAccessFlags(uInt16 address) const override; /** - Change the given address to use the given disassembly flags. + Change the given address to use the given access flags. @param address The address to modify - @param flags A bitfield of DisasmType directives for the given address + @param flags A bitfield of AccessType directives for the given address */ - void setAccessFlags(uInt16 address, CartDebug::DisasmFlags flags) override; + void setAccessFlags(uInt16 address, Device::AccessFlags flags) override; // Handle a change to the bank configuration bool bankConfiguration(uInt8 configuration); diff --git a/src/emucore/Device.hxx b/src/emucore/Device.hxx index f55312869..205de10ac 100644 --- a/src/emucore/Device.hxx +++ b/src/emucore/Device.hxx @@ -22,7 +22,6 @@ class System; #include "Console.hxx" #include "Serializable.hxx" -#include "CartDebug.hxx" #include "bspf.hxx" /** @@ -33,6 +32,34 @@ class System; */ class Device : public Serializable { + public: + enum AccessType { + NONE = 0, + REFERENCED = 1 << 0, /* 0x01, code somewhere in the program references it, + i.e. LDA $F372 referenced $F372 */ + VALID_ENTRY = 1 << 1, /* 0x02, addresses that can have a label placed in front of it. + A good counterexample would be "FF00: LDA $FE00"; $FF01 + would be in the middle of a multi-byte instruction, and + therefore cannot be labelled. */ + + // The following correspond to specific types that can be set within the + // debugger, or specified in a Distella cfg file, and are listed in order + // of decreasing hierarchy + // + CODE = 1 << 10, // 0x400, disassemble-able code segments + TCODE = 1 << 9, // 0x200, (tentative) disassemble-able code segments + GFX = 1 << 8, // 0x100, addresses loaded into GRPx registers + PGFX = 1 << 7, // 0x080, addresses loaded into PFx registers + COL = 1 << 6, // 0x040, addresses loaded into COLUPx registers + PCOL = 1 << 5, // 0x010, addresses loaded into COLUPF register + BCOL = 1 << 4, // 0x010, addresses loaded into COLUBK register + DATA = 1 << 3, // 0x008, addresses loaded into registers other than GRPx / PFx + ROW = 1 << 2, // 0x004, all other addresses + // special type for poke() + WRITE = TCODE // 0x200, address written to + }; + using AccessFlags = uInt16; + public: Device() = default; virtual ~Device() = default; @@ -99,19 +126,19 @@ class Device : public Serializable virtual bool poke(uInt16 address, uInt8 value) { return false; } /** - Query the given address for its disassembly flags + Query the given address for its access flags @param address The address to modify */ - virtual CartDebug::DisasmFlags getAccessFlags(uInt16 address) const { return CartDebug::NONE; } + virtual AccessFlags getAccessFlags(uInt16 address) const { return AccessType::NONE; } /** - Change the given address type to use the given disassembly flags + Change the given address type to use the given access flags @param address The address to modify - @param flags A bitfield of DisasmType directives for the given address + @param flags A bitfield of AccessType directives for the given address */ - virtual void setAccessFlags(uInt16 address, CartDebug::DisasmFlags flags) { } + virtual void setAccessFlags(uInt16 address, AccessFlags flags) { } protected: /// Pointer to the system the device is installed in or the null pointer diff --git a/src/emucore/M6502.cxx b/src/emucore/M6502.cxx index 49f8ff7e2..6f7392326 100644 --- a/src/emucore/M6502.cxx +++ b/src/emucore/M6502.cxx @@ -18,19 +18,19 @@ #ifdef DEBUGGER_SUPPORT #include "Debugger.hxx" #include "Expression.hxx" - #include "CartDebug.hxx" + #include "Device.hxx" #include "Base.hxx" - // Flags for disassembly types - #define DISASM_CODE CartDebug::CODE -// #define DISASM_GFX CartDebug::GFX -// #define DISASM_PGFX CartDebug::PGFX - #define DISASM_DATA CartDebug::DATA -// #define DISASM_ROW CartDebug::ROW - #define DISASM_WRITE CartDebug::WRITE + // Flags for access types + #define DISASM_CODE Device::CODE +// #define DISASM_GFX Device::GFX +// #define DISASM_PGFX Device::PGFX + #define DISASM_DATA Device::DATA +// #define DISASM_ROW Device::ROW + #define DISASM_WRITE Device::WRITE #define DISASM_NONE 0 #else - // Flags for disassembly types + // Flags for access types #define DISASM_CODE 0 // #define DISASM_GFX 0 // #define DISASM_PGFX 0 @@ -104,7 +104,7 @@ void M6502::reset() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -inline uInt8 M6502::peek(uInt16 address, CartDebug::DisasmFlags flags) +inline uInt8 M6502::peek(uInt16 address, Device::AccessFlags flags) { handleHalt(); @@ -144,7 +144,7 @@ inline uInt8 M6502::peek(uInt16 address, CartDebug::DisasmFlags flags) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -inline void M6502::poke(uInt16 address, uInt8 value, CartDebug::DisasmFlags flags) +inline void M6502::poke(uInt16 address, uInt8 value, Device::AccessFlags flags) { //////////////////////////////////////////////// // TODO - move this logic directly into CartAR diff --git a/src/emucore/M6502.hxx b/src/emucore/M6502.hxx index 5c7bbbc01..6cb3ccc65 100644 --- a/src/emucore/M6502.hxx +++ b/src/emucore/M6502.hxx @@ -34,8 +34,8 @@ class DispatchResult; #endif #include "bspf.hxx" +#include "Device.hxx" #include "Serializable.hxx" -#include "CartDebug.hxx" /** The 6502 is an 8-bit microprocessor that has a 64K addressing space. @@ -270,7 +270,7 @@ class M6502 : public Serializable @return The byte at the specified address */ - uInt8 peek(uInt16 address, CartDebug::DisasmFlags flags); + uInt8 peek(uInt16 address, Device::AccessFlags flags); /** Change the byte at the specified address to the given value and @@ -279,7 +279,7 @@ class M6502 : public Serializable @param address The address where the value should be stored @param value The value to be stored at the address */ - void poke(uInt16 address, uInt8 value, CartDebug::DisasmFlags flags = CartDebug::NONE); + void poke(uInt16 address, uInt8 value, Device::AccessFlags flags = Device::NONE); /** Get the 8-bit value of the Processor Status register. diff --git a/src/emucore/M6532.cxx b/src/emucore/M6532.cxx index b5276567b..645a4a332 100644 --- a/src/emucore/M6532.cxx +++ b/src/emucore/M6532.cxx @@ -21,9 +21,6 @@ #include "Settings.hxx" #include "Switches.hxx" #include "System.hxx" -#ifdef DEBUGGER_SUPPORT - #include "CartDebug.hxx" -#endif #include "M6532.hxx" @@ -460,14 +457,14 @@ uInt32 M6532::timerClocks() const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6532::createAccessBases() { - myRAMAccessBase.fill(CartDebug::NONE); - myStackAccessBase.fill(CartDebug::NONE); - myIOAccessBase.fill(CartDebug::NONE); + myRAMAccessBase.fill(Device::NONE); + myStackAccessBase.fill(Device::NONE); + myIOAccessBase.fill(Device::NONE); myZPAccessDelay.fill(ZP_DELAY); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -CartDebug::DisasmFlags M6532::getAccessFlags(uInt16 address) const +Device::AccessFlags M6532::getAccessFlags(uInt16 address) const { if (address & IO_BIT) return myIOAccessBase[address & IO_MASK]; @@ -478,10 +475,10 @@ CartDebug::DisasmFlags M6532::getAccessFlags(uInt16 address) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void M6532::setAccessFlags(uInt16 address, CartDebug::DisasmFlags flags) +void M6532::setAccessFlags(uInt16 address, Device::AccessFlags flags) { // ignore none flag - if (flags != CartDebug::NONE) { + if (flags != Device::NONE) { if (address & IO_BIT) myIOAccessBase[address & IO_MASK] |= flags; else { diff --git a/src/emucore/M6532.hxx b/src/emucore/M6532.hxx index 42fca9640..4f543b8a8 100644 --- a/src/emucore/M6532.hxx +++ b/src/emucore/M6532.hxx @@ -147,18 +147,18 @@ class M6532 : public Device void createAccessBases(); /** - Query the given address type for the associated disassembly flags. + Query the given address type for the associated access flags. @param address The address to query */ - CartDebug::DisasmFlags getAccessFlags(uInt16 address) const override; + Device::AccessFlags getAccessFlags(uInt16 address) const override; /** - Change the given address to use the given disassembly flags. + Change the given address to use the given access flags. @param address The address to modify - @param flags A bitfield of DisasmType directives for the given address + @param flags A bitfield of AccessType directives for the given address */ - void setAccessFlags(uInt16 address, CartDebug::DisasmFlags flags) override; + void setAccessFlags(uInt16 address, Device::AccessFlags flags) override; #endif // DEBUGGER_SUPPORT private: @@ -225,9 +225,9 @@ class M6532 : public Device // The arrays containing information about every byte of RIOT // indicating whether and how (RW) it is used. - std::array myRAMAccessBase; - std::array myStackAccessBase; - std::array myIOAccessBase; + std::array myRAMAccessBase; + std::array myStackAccessBase; + std::array myIOAccessBase; // The array used to skip the first ZP access tracking std::array myZPAccessDelay; #endif // DEBUGGER_SUPPORT diff --git a/src/emucore/System.cxx b/src/emucore/System.cxx index e2050ee1b..7bf3551ef 100644 --- a/src/emucore/System.cxx +++ b/src/emucore/System.cxx @@ -99,7 +99,7 @@ void System::clearDirtyPages() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 System::peek(uInt16 addr, CartDebug::DisasmFlags flags) +uInt8 System::peek(uInt16 addr, Device::AccessFlags flags) { const PageAccess& access = getPageAccess(addr); @@ -127,7 +127,7 @@ uInt8 System::peek(uInt16 addr, CartDebug::DisasmFlags flags) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void System::poke(uInt16 addr, uInt8 value, CartDebug::DisasmFlags flags) +void System::poke(uInt16 addr, uInt8 value, Device::AccessFlags flags) { uInt16 page = (addr & ADDRESS_MASK) >> PAGE_SHIFT; const PageAccess& access = myPageAccessTable[page]; @@ -160,7 +160,7 @@ void System::poke(uInt16 addr, uInt8 value, CartDebug::DisasmFlags flags) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -CartDebug::DisasmFlags System::getAccessFlags(uInt16 addr) const +Device::AccessFlags System::getAccessFlags(uInt16 addr) const { #ifdef DEBUGGER_SUPPORT const PageAccess& access = getPageAccess(addr); @@ -175,7 +175,7 @@ CartDebug::DisasmFlags System::getAccessFlags(uInt16 addr) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void System::setAccessFlags(uInt16 addr, CartDebug::DisasmFlags flags) +void System::setAccessFlags(uInt16 addr, Device::AccessFlags flags) { #ifdef DEBUGGER_SUPPORT const PageAccess& access = getPageAccess(addr); diff --git a/src/emucore/System.hxx b/src/emucore/System.hxx index 306f269e1..1a6dcff68 100644 --- a/src/emucore/System.hxx +++ b/src/emucore/System.hxx @@ -29,7 +29,6 @@ class NullDevice; #include "NullDev.hxx" #include "Random.hxx" #include "Serializable.hxx" -#include "CartDebug.hxx" /** This class represents a system consisting of a 6502 microprocessor @@ -203,7 +202,7 @@ class System : public Serializable @return The byte at the specified address */ - uInt8 peek(uInt16 address, CartDebug::DisasmFlags flags = CartDebug::NONE); + uInt8 peek(uInt16 address, Device::AccessFlags flags = Device::NONE); /** Change the byte at the specified address to the given value. @@ -218,7 +217,7 @@ class System : public Serializable @param address The address where the value should be stored @param value The value to be stored at the address */ - void poke(uInt16 address, uInt8 value, CartDebug::DisasmFlags flags = CartDebug::NONE); + void poke(uInt16 address, uInt8 value, Device::AccessFlags flags = Device::NONE); /** Lock/unlock the data bus. When the bus is locked, peek() and @@ -233,12 +232,12 @@ class System : public Serializable void unlockDataBus() { myDataBusLocked = false; } /** - Access and modify the disassembly type flags for the given + Access and modify the access type flags for the given address. Note that while any flag can be used, the disassembly - only really acts on CODE/GFX/PGFX/DATA/ROW. + only really acts on CODE/GFX/PGFX/COL/PCOL/BCOL/DATA/ROW. */ - CartDebug::DisasmFlags getAccessFlags(uInt16 address) const; - void setAccessFlags(uInt16 address, CartDebug::DisasmFlags flags); + Device::AccessFlags getAccessFlags(uInt16 address) const; + void setAccessFlags(uInt16 address, Device::AccessFlags flags); public: /** @@ -278,7 +277,7 @@ class System : public Serializable conclusively determine if a section of address space is CODE, even if the disassembler failed to mark it as such. */ - CartDebug::DisasmFlags* codeAccessBase{nullptr}; + Device::AccessFlags* codeAccessBase{nullptr}; /** Pointer to the device associated with this page or to the system's diff --git a/src/emucore/tia/TIA.cxx b/src/emucore/tia/TIA.cxx index 10f71ec80..58eb8c8ea 100644 --- a/src/emucore/tia/TIA.cxx +++ b/src/emucore/tia/TIA.cxx @@ -25,10 +25,6 @@ #include "AudioQueue.hxx" #include "DispatchResult.hxx" -#ifdef DEBUGGER_SUPPORT - #include "CartDebug.hxx" -#endif - enum CollisionMask: uInt32 { player0 = 0b0111110000000000, player1 = 0b0100001111000000, @@ -575,7 +571,7 @@ bool TIA::poke(uInt16 address, uInt8 value) #ifdef DEBUGGER_SUPPORT uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); if(dataAddr) - mySystem->setAccessFlags(dataAddr, CartDebug::BCOL); + mySystem->setAccessFlags(dataAddr, Device::BCOL); #endif break; } @@ -590,7 +586,7 @@ bool TIA::poke(uInt16 address, uInt8 value) #ifdef DEBUGGER_SUPPORT uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); if(dataAddr) - mySystem->setAccessFlags(dataAddr, CartDebug::COL); + mySystem->setAccessFlags(dataAddr, Device::COL); #endif break; } @@ -605,7 +601,7 @@ bool TIA::poke(uInt16 address, uInt8 value) #ifdef DEBUGGER_SUPPORT uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); if(dataAddr) - mySystem->setAccessFlags(dataAddr, CartDebug::COL); + mySystem->setAccessFlags(dataAddr, Device::COL); #endif break; } @@ -634,7 +630,7 @@ bool TIA::poke(uInt16 address, uInt8 value) #ifdef DEBUGGER_SUPPORT uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); if(dataAddr) - mySystem->setAccessFlags(dataAddr, CartDebug::PCOL); + mySystem->setAccessFlags(dataAddr, Device::PCOL); #endif break; } @@ -645,7 +641,7 @@ bool TIA::poke(uInt16 address, uInt8 value) #ifdef DEBUGGER_SUPPORT uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); if(dataAddr) - mySystem->setAccessFlags(dataAddr, CartDebug::PGFX); + mySystem->setAccessFlags(dataAddr, Device::PGFX); #endif break; } @@ -656,7 +652,7 @@ bool TIA::poke(uInt16 address, uInt8 value) #ifdef DEBUGGER_SUPPORT uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); if(dataAddr) - mySystem->setAccessFlags(dataAddr, CartDebug::PGFX); + mySystem->setAccessFlags(dataAddr, Device::PGFX); #endif break; } @@ -667,7 +663,7 @@ bool TIA::poke(uInt16 address, uInt8 value) #ifdef DEBUGGER_SUPPORT uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); if(dataAddr) - mySystem->setAccessFlags(dataAddr, CartDebug::PGFX); + mySystem->setAccessFlags(dataAddr, Device::PGFX); #endif break; } @@ -735,7 +731,7 @@ bool TIA::poke(uInt16 address, uInt8 value) #ifdef DEBUGGER_SUPPORT uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); if(dataAddr) - mySystem->setAccessFlags(dataAddr, CartDebug::GFX); + mySystem->setAccessFlags(dataAddr, Device::GFX); #endif break; } @@ -748,7 +744,7 @@ bool TIA::poke(uInt16 address, uInt8 value) #ifdef DEBUGGER_SUPPORT uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); if(dataAddr) - mySystem->setAccessFlags(dataAddr, CartDebug::GFX); + mySystem->setAccessFlags(dataAddr, Device::GFX); #endif break; } @@ -1914,22 +1910,22 @@ void TIA::toggleCollBLPF() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::createAccessBase() { - myAccessBase.fill(CartDebug::NONE); + myAccessBase.fill(Device::NONE); myAccessDelay.fill(TIA_DELAY); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -CartDebug::DisasmFlags TIA::getAccessFlags(uInt16 address) const +Device::AccessFlags TIA::getAccessFlags(uInt16 address) const { return myAccessBase[address & TIA_MASK]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::setAccessFlags(uInt16 address, CartDebug::DisasmFlags flags) +void TIA::setAccessFlags(uInt16 address, Device::AccessFlags flags) { // ignore none flag - if (flags != CartDebug::NONE) { - if (flags == CartDebug::WRITE) { + if (flags != Device::NONE) { + if (flags == Device::WRITE) { // the first two write accesses are assumed as initialization if (myAccessDelay[address & TIA_MASK]) myAccessDelay[address & TIA_MASK]--; diff --git a/src/emucore/tia/TIA.hxx b/src/emucore/tia/TIA.hxx index 842bc395f..30c3d04f5 100644 --- a/src/emucore/tia/TIA.hxx +++ b/src/emucore/tia/TIA.hxx @@ -681,18 +681,18 @@ class TIA : public Device void createAccessBase(); /** - * Query the given address type for the associated disassembly flags. + * Query the given address type for the associated access flags. * * @param address The address to query */ - CartDebug::DisasmFlags getAccessFlags(uInt16 address) const override; + Device::AccessFlags getAccessFlags(uInt16 address) const override; /** - * Change the given address to use the given disassembly flags. + * Change the given address to use the given access flags. * * @param address The address to modify - * @param flags A bitfield of DisasmType directives for the given address + * @param flags A bitfield of AccessType directives for the given address */ - void setAccessFlags(uInt16 address, CartDebug::DisasmFlags flags) override; + void setAccessFlags(uInt16 address, Device::AccessFlags flags) override; #endif // DEBUGGER_SUPPORT private: @@ -901,7 +901,7 @@ class TIA : public Device #ifdef DEBUGGER_SUPPORT // The arrays containing information about every byte of TIA // indicating whether and how (RW) it is used. - std::array myAccessBase; + std::array myAccessBase; // The array used to skip the first two TIA access trackings std::array myAccessDelay; diff --git a/src/gui/DeveloperDialog.cxx b/src/gui/DeveloperDialog.cxx index 4d6924f11..1d3d59aa5 100644 --- a/src/gui/DeveloperDialog.cxx +++ b/src/gui/DeveloperDialog.cxx @@ -39,7 +39,6 @@ #include "M6502.hxx" #ifdef DEBUGGER_SUPPORT #include "Debugger.hxx" - #include "CartDebug.hxx" #include "DebuggerDialog.hxx" #endif #include "DeveloperDialog.hxx" From a3a79749f6663e20c6501313da4ea9e3791a9826 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Fri, 27 Mar 2020 20:52:15 -0230 Subject: [PATCH 050/377] And we start again ... --- src/common/Version.hxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/Version.hxx b/src/common/Version.hxx index 51da31362..09c706540 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.1" -#define STELLA_BUILD "5729" +#define STELLA_VERSION "6.2_pre" +#define STELLA_BUILD "5741" #endif From 0047c7bd5fdf42bd82ce30a6b7a320559cf6f616 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 28 Mar 2020 09:35:27 +0100 Subject: [PATCH 051/377] replace some magic numbers in Distella --- docs/debugger.html | 3 +- src/debugger/CartDebug.cxx | 2 +- src/debugger/DiStella.cxx | 112 ++++++++++++++++++++----------------- src/debugger/DiStella.hxx | 28 +++++++--- 4 files changed, 85 insertions(+), 60 deletions(-) diff --git a/docs/debugger.html b/docs/debugger.html index 80246c1c4..15a80bcb1 100644 --- a/docs/debugger.html +++ b/docs/debugger.html @@ -1447,7 +1447,8 @@ isn't already a defined label). in either binary or hexidecimal.
  • Use address relocation: Corresponds to the Distella '-r' option -(Relocate calls out of address range).
  • +(Relocate calls out of address range).
    +Note: The code will continue to run fine, but the ROM image will be altered. diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index 7446efad4..0552b2d65 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -1054,7 +1054,7 @@ string CartDebug::saveDisassembly() if (myReserved.breakFound) addLabel("Break", myDebugger.dpeek(0xfffe)); - buf << " SEG Device::CODE\n" + buf << " SEG CODE\n" << " ORG $" << Base::HEX4 << info.offset << "\n\n"; // Format in 'distella' style diff --git a/src/debugger/DiStella.cxx b/src/debugger/DiStella.cxx index 43d67749e..a53143668 100644 --- a/src/debugger/DiStella.cxx +++ b/src/debugger/DiStella.cxx @@ -108,7 +108,7 @@ void DiStella::disasm(uInt32 distart, int pass) uInt16 ad; Int32 cycles = 0; AddressingMode addrMode; - int labelFound = 0; + AddressType labelFound = AddressType::INVALID; stringstream nextLine, nextLineBytes; mySegType = Device::NONE; // create extra lines between code and data @@ -192,14 +192,14 @@ FIX_LAST: ++myPC; // detect labels inside instructions (e.g. BIT masks) - labelFound = false; + labelFound = AddressType::INVALID; for (Uint8 i = 0; i < ourLookup[opcode].bytes - 1; i++) { if (checkBit(myPC + i, Device::REFERENCED)) { - labelFound = true; + labelFound = AddressType::ROM; break; } } - if (labelFound) { + if (labelFound != AddressType::INVALID) { if (myOffset >= 0x1000) { // the opcode's operand address matches a label address if (pass == 3) { @@ -320,10 +320,10 @@ FIX_LAST: else nextLine << " "; - if (labelFound == 1) { + if (labelFound == AddressType::ROM) { LABEL_A12_HIGH(ad); nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8); - } else if (labelFound == 4) { + } else if (labelFound == AddressType::ROM_MIRROR) { if (mySettings.rFlag) { int tmp = (ad & myAppData.end) + myOffset; LABEL_A12_HIGH(tmp); @@ -378,11 +378,11 @@ FIX_LAST: else nextLine << " "; - if (labelFound == 1) { + if (labelFound == AddressType::ROM) { LABEL_A12_HIGH(ad); nextLine << ",x"; nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8); - } else if (labelFound == 4) { + } else if (labelFound == AddressType::ROM_MIRROR) { if (mySettings.rFlag) { int tmp = (ad & myAppData.end) + myOffset; LABEL_A12_HIGH(tmp); @@ -417,11 +417,11 @@ FIX_LAST: else nextLine << " "; - if (labelFound == 1) { + if (labelFound == AddressType::ROM) { LABEL_A12_HIGH(ad); nextLine << ",y"; nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8); - } else if (labelFound == 4) { + } else if (labelFound == AddressType::ROM_MIRROR) { if (mySettings.rFlag) { int tmp = (ad & myAppData.end) + myOffset; LABEL_A12_HIGH(tmp); @@ -502,7 +502,7 @@ FIX_LAST: labelFound = mark(ad, Device::REFERENCED); if (pass == 3) { - if (labelFound == 1) { + if (labelFound == AddressType::ROM) { nextLine << " "; LABEL_A12_HIGH(ad); } else @@ -529,12 +529,21 @@ FIX_LAST: else nextLine << " "; } - if (labelFound == 1) { + if (labelFound == AddressType::ROM) { nextLine << "("; LABEL_A12_HIGH(ad); nextLine << ")"; } - // TODO - should we consider case 4?? + else if (labelFound == AddressType::ROM_MIRROR) { + nextLine << "("; + if (mySettings.rFlag) { + int tmp = (ad & myAppData.end) + myOffset; + LABEL_A12_HIGH(tmp); + } else { + LABEL_A12_LOW(ad); + } + nextLine << ")"; + } else { nextLine << "("; LABEL_A12_LOW(ad); @@ -841,7 +850,7 @@ void DiStella::disasmFromAddress(uInt32 distart) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int DiStella::mark(uInt32 address, uInt16 mask, bool directive) +DiStella::AddressType DiStella::mark(uInt32 address, uInt16 mask, bool directive) { /*----------------------------------------------------------------------- For any given offset and code range... @@ -849,68 +858,75 @@ int DiStella::mark(uInt32 address, uInt16 mask, bool directive) If we're between the offset and the end of the code range, we mark the bit in the labels array for that data. The labels array is an array of label info for each code address. If this is the case, - return "1", else... + return "ROM", else... We sweep for hardware/system equates, which are valid addresses, outside the scope of the code/data range. For these, we mark its - corresponding hardware/system array element, and return "2" or "3" + corresponding hardware/system array element, and return "TIA" or "RIOT" (depending on which system/hardware element was accessed). If this was not the case... Next we check if it is a code "mirror". For the 2600, address ranges are limited with 13 bits, so other addresses can exist outside of the standard code/data range. For these, we mark the element in the "labels" - array that corresponds to the mirrored address, and return "4" + array that corresponds to the mirrored address, and return "ROM_MIRROR" - If all else fails, it's not a valid address, so return 0. + If all else fails, it's not a valid address, so return INVALID. A quick example breakdown for a 2600 4K cart: =========================================================== - $00-$3d = system equates (WSYNC, etc...); return 2. - $80-$ff = zero-page RAM (ram_80, etc...); return 5. + $00-$3d = system equates (WSYNC, etc...); return TIA. + $80-$ff = zero-page RAM (ram_80, etc...); return ZP_RAM. $0280-$0297 = system equates (INPT0, etc...); mark the array's element - with the appropriate bit; return 3. + with the appropriate bit; return RIOT. $1000-$1FFF = mark the code/data array for the mirrored address - with the appropriate bit; return 4. + with the appropriate bit; return ROM_MIRROR. $3000-$3FFF = mark the code/data array for the mirrored address - with the appropriate bit; return 4. + with the appropriate bit; return ROM_MIRROR. $5000-$5FFF = mark the code/data array for the mirrored address - with the appropriate bit; return 4. + with the appropriate bit; return ROM_MIRROR. $7000-$7FFF = mark the code/data array for the mirrored address - with the appropriate bit; return 4. + with the appropriate bit; return ROM_MIRROR. $9000-$9FFF = mark the code/data array for the mirrored address - with the appropriate bit; return 4. + with the appropriate bit; return ROM_MIRROR. $B000-$BFFF = mark the code/data array for the mirrored address - with the appropriate bit; return 4. + with the appropriate bit; return ROM_MIRROR. $D000-$DFFF = mark the code/data array for the mirrored address - with the appropriate bit; return 4. + with the appropriate bit; return ROM_MIRROR. $F000-$FFFF = mark the code/data array for the address - with the appropriate bit; return 1. - Anything else = invalid, return 0. + with the appropriate bit; return ROM. + Anything else = invalid, return INVALID. =========================================================== -----------------------------------------------------------------------*/ // Check for equates before ROM/ZP-RAM accesses, because the original logic // of Distella assumed either equates or ROM; it didn't take ZP-RAM into account CartDebug::AddrType type = myDbg.addressType(address); - if (type == CartDebug::AddrType::TIA) { - return 2; - } else if (type == CartDebug::AddrType::IO) { - return 3; - } else if (type == CartDebug::AddrType::ZPRAM && myOffset != 0) { - return 5; - } else if (address >= uInt32(myOffset) && address <= uInt32(myAppData.end + myOffset)) { + if(type == CartDebug::AddrType::TIA) { + return AddressType::TIA; + } + else if(type == CartDebug::AddrType::IO) { + return AddressType::RIOT; + } + else if(type == CartDebug::AddrType::ZPRAM && myOffset != 0) { + return AddressType::ZP_RAM; + } + else if(address >= uInt32(myOffset) && address <= uInt32(myAppData.end + myOffset)) { myLabels[address - myOffset] = myLabels[address - myOffset] | mask; - if (directive) myDirectives[address - myOffset] = mask; - return 1; - } else if (address > 0x1000 && myOffset != 0) // Exclude zero-page accesses + if(directive) + myDirectives[address - myOffset] = mask; + return AddressType::ROM; + } + else if(address > 0x1000 && myOffset != 0) // Exclude zero-page accesses { /* 2K & 4K case */ myLabels[address & myAppData.end] = myLabels[address & myAppData.end] | mask; - if (directive) myDirectives[address & myAppData.end] = mask; - return 4; - } else - return 0; + if(directive) + myDirectives[address & myAppData.end] = mask; + return AddressType::ROM_MIRROR; + } + else + return AddressType::INVALID; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -942,12 +958,6 @@ bool DiStella::checkBits(uInt16 address, uInt16 mask, uInt16 notMask, bool useDe return checkBit(address, mask, useDebugger) && !checkBit(address, notMask, useDebugger); } -/*bool DiStella::isType(uInt16 address) const -{ - return checkBits(address, Device::GFX | Device::PGFX | - Device::COL | Device::PCOL | Device::BCOL); -}*/ - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool DiStella::check_range(uInt16 beg, uInt16 end) const { @@ -1201,7 +1211,7 @@ void DiStella::outputBytes(Device::AccessType type) ++myPC; } isType = checkBits(myPC, type, - Device::CODE | (type != Device::DATA ? Device::DATA : 0) | + Device::CODE | (type != Device::DATA ? Device::DATA : 0) | Device::GFX | Device::PGFX | Device::COL | Device::PCOL | Device::BCOL); referenced = checkBit(myPC, Device::REFERENCED); diff --git a/src/debugger/DiStella.hxx b/src/debugger/DiStella.hxx index bb1b54f5e..18a7bf25c 100644 --- a/src/debugger/DiStella.hxx +++ b/src/debugger/DiStella.hxx @@ -72,6 +72,21 @@ class DiStella CartDebug::AddrTypeArray& directives, CartDebug::ReservedEquates& reserved); + private: + /** + Enumeration of the addressing type (RAM, ROM, RIOT, TIA...) + */ + enum class AddressType : int + { + INVALID, + ROM, + TIA, + RIOT, + ROM_MIRROR, + ZP_RAM + }; + + private: // Indicate that a new line of disassembly has been completed // In the original Distella code, this indicated a new line to be printed @@ -88,33 +103,32 @@ class DiStella void disasmFromAddress(uInt32 distart); bool check_range(uInt16 start, uInt16 end) const; - int mark(uInt32 address, uInt16 mask, bool directive = false); + AddressType mark(uInt32 address, uInt16 mask, bool directive = false); bool checkBit(uInt16 address, uInt16 mask, bool useDebugger = true) const; bool checkBits(uInt16 address, uInt16 mask, uInt16 notMask, bool useDebugger = true) const; - //bool isType(uInt16 address) const; void outputGraphics(); void outputColors(); void outputBytes(Device::AccessType type); // Convenience methods to generate appropriate labels - inline void labelA12High(stringstream& buf, uInt8 op, uInt16 addr, int labfound) + inline void labelA12High(stringstream& buf, uInt8 op, uInt16 addr, AddressType labfound) { if(!myDbg.getLabel(buf, addr, true)) buf << "L" << Common::Base::HEX4 << addr; } - inline void labelA12Low(stringstream& buf, uInt8 op, uInt16 addr, int labfound) + inline void labelA12Low(stringstream& buf, uInt8 op, uInt16 addr, AddressType labfound) { myDbg.getLabel(buf, addr, ourLookup[op].rw_mode == RWMode::READ, 2); - if (labfound == 2) + if (labfound == AddressType::TIA) { if(ourLookup[op].rw_mode == RWMode::READ) myReserved.TIARead[addr & 0x0F] = true; else myReserved.TIAWrite[addr & 0x3F] = true; } - else if (labfound == 3) + else if (labfound == AddressType::RIOT) myReserved.IOReadWrite[(addr & 0xFF) - 0x80] = true; - else if (labfound == 5) + else if (labfound == AddressType::ZP_RAM) myReserved.ZPRAM[(addr & 0xFF) - 0x80] = true; } From f17794231c37882b78c947313f9afeb38bff2469 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sat, 28 Mar 2020 12:03:23 -0230 Subject: [PATCH 052/377] libretro: Fix core on Debian Buster (fixes #598) --- src/libretro/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libretro/Makefile b/src/libretro/Makefile index a1bc5025a..8d17db9db 100644 --- a/src/libretro/Makefile +++ b/src/libretro/Makefile @@ -57,7 +57,7 @@ endif # Unix ifneq (,$(findstring unix,$(platform))) CXXFLAGS += $(LTO) - LDFLAGS += $(LTO) $(PTHREAD_FLAGS) + LDFLAGS += $(LTO) $(PTHREAD_FLAGS) -static-libgcc -static-libstdc++ TARGET := $(TARGET_NAME)_libretro.so fpic := -fPIC ifneq ($(findstring SunOS,$(shell uname -a)),) From e85738978c5a18aa4351684c921139988c3759ee Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 29 Mar 2020 10:51:16 +0200 Subject: [PATCH 053/377] add detection of audio data in DiStella (see #596) --- Changes.txt | 2 +- src/debugger/CartDebug.cxx | 57 +++++---- src/debugger/CartDebug.hxx | 2 +- src/debugger/DiStella.cxx | 239 ++++++++++++++++++++----------------- src/emucore/Device.hxx | 15 +-- src/emucore/M6502.cxx | 10 +- src/emucore/Settings.cxx | 4 +- src/emucore/System.hxx | 2 +- src/emucore/tia/TIA.cxx | 42 +++++++ 9 files changed, 223 insertions(+), 150 deletions(-) diff --git a/Changes.txt b/Changes.txt index 5dbc6047e..9daaf6f42 100644 --- a/Changes.txt +++ b/Changes.txt @@ -22,7 +22,7 @@ * Added displaying last write address in debugger. (TOOD: Doc) - * Added detection of color data in DiStella. (TOOD: Doc) + * Added detection of color and audio data in DiStella. (TOOD: Doc) 6.0.2 to 6.1: (March 22, 2020) diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index 0552b2d65..d9750629e 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -916,6 +916,11 @@ string CartDebug::loadConfigFile() buf >> hex >> start >> hex >> end; addDirective(Device::BCOL, start, end, currentbank); } + else if(BSPF::startsWithIgnoreCase(directive, "Device::AUD")) + { + buf >> hex >> start >> hex >> end; + addDirective(Device::AUD, start, end, currentbank); + } else if(BSPF::startsWithIgnoreCase(directive, "Device::DATA")) { buf >> hex >> start >> hex >> end; @@ -1070,57 +1075,54 @@ string CartDebug::saveDisassembly() switch(tag.type) { case Device::CODE: - { buf << ALIGN(32) << tag.disasm << tag.ccount.substr(0, 5) << tag.ctotal << tag.ccount.substr(5, 2); if (tag.disasm.find("WSYNC") != std::string::npos) buf << "\n;---------------------------------------"; break; - } + case Device::ROW: - { buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 8*4-1) << "; $" << Base::HEX4 << tag.address << " (*)"; break; - } + case Device::GFX: - { buf << ".byte " << (settings.gfxFormat == Base::Fmt::_2 ? "%" : "$") << tag.bytes << " ; |"; for(int c = 12; c < 20; ++c) buf << ((tag.disasm[c] == '\x1e') ? "#" : " "); buf << ALIGN(13) << "|" << "$" << Base::HEX4 << tag.address << " (G)"; break; - } + case Device::PGFX: - { buf << ".byte " << (settings.gfxFormat == Base::Fmt::_2 ? "%" : "$") << tag.bytes << " ; |"; for(int c = 12; c < 20; ++c) buf << ((tag.disasm[c] == '\x1f') ? "*" : " "); buf << ALIGN(13) << "|" << "$" << Base::HEX4 << tag.address << " (P)"; break; - } + case Device::COL: - buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 12) << "; $" << Base::HEX4 << tag.address << " (Px)"; + buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 12) << "; $" << Base::HEX4 << tag.address << " (C)"; break; case Device::PCOL: - buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 12) << "; $" << Base::HEX4 << tag.address << " (PF)"; + buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 12) << "; $" << Base::HEX4 << tag.address << " (CP)"; break; case Device::BCOL: - buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 12) << "; $" << Base::HEX4 << tag.address << " (BK)"; + buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 12) << "; $" << Base::HEX4 << tag.address << " (CB)"; + break; + + case Device::AUD: + buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 8 * 4 - 1) << "; $" << Base::HEX4 << tag.address << " (A)"; break; case Device::DATA: - { buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 8 * 4 - 1) << "; $" << Base::HEX4 << tag.address << " (D)"; break; - } + case Device::NONE: default: - { break; - } } // switch buf << "\n"; } @@ -1134,14 +1136,18 @@ string CartDebug::saveDisassembly() << "; ROM properties name : " << myConsole.properties().get(PropType::Cart_Name) << "\n" << "; ROM properties MD5 : " << myConsole.properties().get(PropType::Cart_MD5) << "\n" << "; Bankswitch type : " << myConsole.cartridge().about() << "\n;\n" - << "; Legend: * = Device::CODE not yet run (tentative code)\n" - << "; D = Device::DATA directive (referenced in some way)\n" - << "; G = Device::GFX directive, shown as '#' (stored in player, missile, ball)\n" - << "; P = Device::PGFX directive, shown as '*' (stored in playfield)\n" - << "; i = indexed accessed only\n" - << "; c = used by code executed in RAM\n" - << "; s = used by stack\n" - << "; ! = page crossed, 1 cycle penalty\n" + << "; Legend: * = Device::CODE not yet run (tentative code)\n" + << "; D = Device::DATA directive (referenced in some way)\n" + << "; G = Device::GFX directive, shown as '#' (stored in player, missile, ball)\n" + << "; P = Device::PGFX directive, shown as '*' (stored in playfield)\n" + << "; C = Device::COL directive, shown as '*' (stored in player color)\n" + << "; CP = Device::PCOL directive, shown as '*' (stored in playfield color)\n" + << "; CB = Device::BCOL directive, shown as '*' (stored in background color)\n" + << "; A = Device::AUD directive, shown as '*' (stored in audio registers)\n" + << "; i = indexed accessed only\n" + << "; c = used by code executed in RAM\n" + << "; s = used by stack\n" + << "; ! = page crossed, 1 cycle penalty\n" << "\n processor 6502\n\n"; out << "\n;-----------------------------------------------------------\n" @@ -1478,6 +1484,8 @@ Device::AccessType CartDebug::accessTypeAbsolute(Device::AccessFlags flags) cons return Device::PCOL; else if(flags & Device::BCOL) return Device::BCOL; + else if(flags & Device::AUD) + return Device::AUD; else if(flags & Device::DATA) return Device::DATA; else if(flags & Device::ROW) @@ -1498,6 +1506,7 @@ void CartDebug::AccessTypeAsString(ostream& buf, Device::AccessType type) const case Device::COL: buf << "Device::COL"; break; case Device::PCOL: buf << "Device::PCOL"; break; case Device::BCOL: buf << "Device::BCOL"; break; + case Device::AUD: buf << "Device::AUD"; break; case Device::DATA: buf << "Device::DATA"; break; case Device::ROW: buf << "Device::ROW"; break; case Device::REFERENCED: @@ -1525,6 +1534,8 @@ void CartDebug::AccessTypeAsString(ostream& buf, Device::AccessFlags flags) cons buf << "Device::PCOL "; if(flags & Device::BCOL) buf << "Device::BCOL "; + if(flags & Device::AUD) + buf << "Device::AUD "; if(flags & Device::DATA) buf << "Device::DATA "; if(flags & Device::ROW) diff --git a/src/debugger/CartDebug.hxx b/src/debugger/CartDebug.hxx index e52389974..dda0906cb 100644 --- a/src/debugger/CartDebug.hxx +++ b/src/debugger/CartDebug.hxx @@ -142,7 +142,7 @@ class CartDebug : public DebuggerSystem things can't be automatically determined. For now, these directives have exactly the same syntax as in a distella configuration file. - @param type Currently, CODE/DATA/GFX are supported + @param type Currently, CODE/DATA/GFX/PGFX/COL/PCOL/BCOL/AUD/ROW are supported @param start The start address (inclusive) to mark with the given type @param end The end address (inclusive) to mark with the given type @param bank Bank to which these directive apply (0 indicated current bank) diff --git a/src/debugger/DiStella.cxx b/src/debugger/DiStella.cxx index a53143668..547a75933 100644 --- a/src/debugger/DiStella.cxx +++ b/src/debugger/DiStella.cxx @@ -117,57 +117,73 @@ void DiStella::disasm(uInt32 distart, int pass) /* pc=myAppData.start; */ myPC = distart - myOffset; - while (myPC <= myAppData.end) { - + while(myPC <= myAppData.end) + { // since -1 is used in m6502.m4 for clearing the last peek // and this results into an access at e.g. 0xffff, // we have to fix the consequences here (ugly!). if(myPC == myAppData.end) goto FIX_LAST; - if (checkBits(myPC, Device::GFX | Device::PGFX, - Device::CODE)) + if(checkBits(myPC, Device::GFX | Device::PGFX, + Device::CODE)) { - if (pass == 2) + if(pass == 2) mark(myPC + myOffset, Device::VALID_ENTRY); - if (pass == 3) + if(pass == 3) outputGraphics(); ++myPC; - } else if (checkBits(myPC, Device::COL | Device::PCOL | Device::BCOL, - Device::CODE | Device::GFX | Device::PGFX)) + } + else if(checkBits(myPC, Device::COL | Device::PCOL | Device::BCOL, + Device::CODE | Device::GFX | Device::PGFX)) { - if (pass == 2) + if(pass == 2) mark(myPC + myOffset, Device::VALID_ENTRY); - if (pass == 3) + if(pass == 3) outputColors(); ++myPC; - } else if (checkBits(myPC, Device::DATA, - Device::CODE | Device::GFX | Device::PGFX | - Device::COL | Device::PCOL | Device::BCOL)) + } + else if(checkBits(myPC, Device::AUD, + Device::CODE | Device::GFX | Device::PGFX | + Device::COL | Device::PCOL | Device::BCOL)) { - if (pass == 2) + if(pass == 2) mark(myPC + myOffset, Device::VALID_ENTRY); - if (pass == 3) + if(pass == 3) + outputBytes(Device::AUD); + else + ++myPC; + } + else if(checkBits(myPC, Device::DATA, + Device::CODE | Device::GFX | Device::PGFX | + Device::COL | Device::PCOL | Device::BCOL | + Device::AUD)) + { + if(pass == 2) + mark(myPC + myOffset, Device::VALID_ENTRY); + if(pass == 3) outputBytes(Device::DATA); else ++myPC; - } else if (checkBits(myPC, Device::ROW, - Device::CODE | - Device::DATA | Device::GFX | Device::PGFX | - Device::COL | Device::PCOL | Device::BCOL)) { -FIX_LAST: - if (pass == 2) + } + else if(checkBits(myPC, Device::ROW, + Device::CODE | Device::GFX | Device::PGFX | + Device::COL | Device::PCOL | Device::BCOL | + Device::AUD | Device::DATA)) { + FIX_LAST: + if(pass == 2) mark(myPC + myOffset, Device::VALID_ENTRY); - if (pass == 3) + if(pass == 3) outputBytes(Device::ROW); else ++myPC; - } else { - // The following sections must be CODE + } + else { + // The following sections must be CODE - // add extra spacing line when switching from non-code to code - if (pass == 3 && mySegType != Device::CODE && mySegType != Device::NONE) { + // add extra spacing line when switching from non-code to code + if(pass == 3 && mySegType != Device::CODE && mySegType != Device::NONE) { myDisasmBuf << " ' ' "; addEntry(Device::NONE); mark(myPC + myOffset, Device::REFERENCED); // add label when switching @@ -175,7 +191,7 @@ FIX_LAST: mySegType = Device::CODE; /* version 2.1 bug fix */ - if (pass == 2) + if(pass == 2) mark(myPC + myOffset, Device::VALID_ENTRY); // get opcode @@ -183,8 +199,8 @@ FIX_LAST: // get address mode for opcode addrMode = ourLookup[opcode].addr_mode; - if (pass == 3) { - if (checkBit(myPC, Device::REFERENCED)) + if(pass == 3) { + if(checkBit(myPC, Device::REFERENCED)) myDisasmBuf << Base::HEX4 << myPC + myOffset << "'L" << Base::HEX4 << myPC + myOffset << "'"; else myDisasmBuf << Base::HEX4 << myPC + myOffset << "' '"; @@ -193,16 +209,16 @@ FIX_LAST: // detect labels inside instructions (e.g. BIT masks) labelFound = AddressType::INVALID; - for (Uint8 i = 0; i < ourLookup[opcode].bytes - 1; i++) { - if (checkBit(myPC + i, Device::REFERENCED)) { + for(Uint8 i = 0; i < ourLookup[opcode].bytes - 1; i++) { + if(checkBit(myPC + i, Device::REFERENCED)) { labelFound = AddressType::ROM; break; } } - if (labelFound != AddressType::INVALID) { - if (myOffset >= 0x1000) { + if(labelFound != AddressType::INVALID) { + if(myOffset >= 0x1000) { // the opcode's operand address matches a label address - if (pass == 3) { + if(pass == 3) { // output the byte of the opcode incl. cycles Uint8 nextOpcode = Debugger::debugger().peek(myPC + myOffset); @@ -221,8 +237,9 @@ FIX_LAST: } // continue with the label's opcode continue; - } else { - if (pass == 3) { + } + else { + if(pass == 3) { // TODO } } @@ -230,18 +247,18 @@ FIX_LAST: // Undefined opcodes start with a '.' // These are undefined wrt DASM - if (ourLookup[opcode].mnemonic[0] == '.' && pass == 3) { + if(ourLookup[opcode].mnemonic[0] == '.' && pass == 3) { nextLine << ".byte $" << Base::HEX2 << int(opcode) << " ;"; } - if (pass == 3) { + if(pass == 3) { nextLine << ourLookup[opcode].mnemonic; nextLineBytes << Base::HEX2 << int(opcode) << " "; } // Add operand(s) for PC values outside the app data range - if (myPC >= myAppData.end) { - switch (addrMode) { + if(myPC >= myAppData.end) { + switch(addrMode) { case AddressingMode::ABSOLUTE: case AddressingMode::ABSOLUTE_X: case AddressingMode::ABSOLUTE_Y: @@ -249,7 +266,7 @@ FIX_LAST: case AddressingMode::INDIRECT_Y: case AddressingMode::ABS_INDIRECT: { - if (pass == 3) { + if(pass == 3) { /* Line information is already printed; append .byte since last instruction will put recompilable object larger that original binary file */ @@ -258,8 +275,8 @@ FIX_LAST: << Base::HEX2 << int(opcode); addEntry(Device::DATA); - if (myPC == myAppData.end) { - if (checkBit(myPC, Device::REFERENCED)) + if(myPC == myAppData.end) { + if(checkBit(myPC, Device::REFERENCED)) myDisasmBuf << Base::HEX4 << myPC + myOffset << "'L" << Base::HEX4 << myPC + myOffset << "'"; else myDisasmBuf << Base::HEX4 << myPC + myOffset << "' '"; @@ -281,7 +298,7 @@ FIX_LAST: case AddressingMode::ZERO_PAGE_Y: case AddressingMode::RELATIVE: { - if (pass == 3) { + if(pass == 3) { /* Line information is already printed, but we can remove the Instruction (i.e. BMI) by simply clearing the buffer to print */ myDisasmBuf << ".byte $" << Base::HEX2 << int(opcode); @@ -302,10 +319,10 @@ FIX_LAST: // Add operand(s) ad = d1 = 0; // not WSYNC by default! /* Version 2.1 added the extensions to mnemonics */ - switch (addrMode) { + switch(addrMode) { case AddressingMode::ACCUMULATOR: { - if (pass == 3 && mySettings.aFlag) + if(pass == 3 && mySettings.aFlag) nextLine << " A"; break; } @@ -314,25 +331,28 @@ FIX_LAST: { ad = Debugger::debugger().dpeek(myPC + myOffset); myPC += 2; labelFound = mark(ad, Device::REFERENCED); - if (pass == 3) { - if (ad < 0x100 && mySettings.fFlag) + if(pass == 3) { + if(ad < 0x100 && mySettings.fFlag) nextLine << ".w "; else nextLine << " "; - if (labelFound == AddressType::ROM) { + if(labelFound == AddressType::ROM) { LABEL_A12_HIGH(ad); nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8); - } else if (labelFound == AddressType::ROM_MIRROR) { - if (mySettings.rFlag) { + } + else if(labelFound == AddressType::ROM_MIRROR) { + if(mySettings.rFlag) { int tmp = (ad & myAppData.end) + myOffset; LABEL_A12_HIGH(tmp); nextLineBytes << Base::HEX2 << int(tmp & 0xff) << " " << Base::HEX2 << int(tmp >> 8); - } else { + } + else { nextLine << "$" << Base::HEX4 << ad; nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8); } - } else { + } + else { LABEL_A12_LOW(ad); nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8); } @@ -344,7 +364,7 @@ FIX_LAST: { d1 = Debugger::debugger().peek(myPC + myOffset); ++myPC; labelFound = mark(d1, Device::REFERENCED); - if (pass == 3) { + if(pass == 3) { nextLine << " "; LABEL_A12_LOW(int(d1)); nextLineBytes << Base::HEX2 << int(d1); @@ -355,7 +375,7 @@ FIX_LAST: case AddressingMode::IMMEDIATE: { d1 = Debugger::debugger().peek(myPC + myOffset); ++myPC; - if (pass == 3) { + if(pass == 3) { nextLine << " #$" << Base::HEX2 << int(d1) << " "; nextLineBytes << Base::HEX2 << int(d1); } @@ -366,33 +386,37 @@ FIX_LAST: { ad = Debugger::debugger().dpeek(myPC + myOffset); myPC += 2; labelFound = mark(ad, Device::REFERENCED); - if (pass == 2 && !checkBit(ad & myAppData.end, Device::CODE)) { + if(pass == 2 && !checkBit(ad & myAppData.end, Device::CODE)) { // Since we can't know what address is being accessed unless we also // know the current X value, this is marked as ROW instead of DATA // The processing is left here, however, in case future versions of // the code can somehow track access to CPU registers mark(ad, Device::ROW); - } else if (pass == 3) { - if (ad < 0x100 && mySettings.fFlag) + } + else if(pass == 3) { + if(ad < 0x100 && mySettings.fFlag) nextLine << ".wx "; else nextLine << " "; - if (labelFound == AddressType::ROM) { + if(labelFound == AddressType::ROM) { LABEL_A12_HIGH(ad); nextLine << ",x"; nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8); - } else if (labelFound == AddressType::ROM_MIRROR) { - if (mySettings.rFlag) { + } + else if(labelFound == AddressType::ROM_MIRROR) { + if(mySettings.rFlag) { int tmp = (ad & myAppData.end) + myOffset; LABEL_A12_HIGH(tmp); nextLine << ",x"; nextLineBytes << Base::HEX2 << int(tmp & 0xff) << " " << Base::HEX2 << int(tmp >> 8); - } else { + } + else { nextLine << "$" << Base::HEX4 << ad << ",x"; nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8); } - } else { + } + else { LABEL_A12_LOW(ad); nextLine << ",x"; nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8); @@ -405,33 +429,37 @@ FIX_LAST: { ad = Debugger::debugger().dpeek(myPC + myOffset); myPC += 2; labelFound = mark(ad, Device::REFERENCED); - if (pass == 2 && !checkBit(ad & myAppData.end, Device::CODE)) { + if(pass == 2 && !checkBit(ad & myAppData.end, Device::CODE)) { // Since we can't know what address is being accessed unless we also // know the current Y value, this is marked as ROW instead of DATA // The processing is left here, however, in case future versions of // the code can somehow track access to CPU registers mark(ad, Device::ROW); - } else if (pass == 3) { - if (ad < 0x100 && mySettings.fFlag) + } + else if(pass == 3) { + if(ad < 0x100 && mySettings.fFlag) nextLine << ".wy "; else nextLine << " "; - if (labelFound == AddressType::ROM) { + if(labelFound == AddressType::ROM) { LABEL_A12_HIGH(ad); nextLine << ",y"; nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8); - } else if (labelFound == AddressType::ROM_MIRROR) { - if (mySettings.rFlag) { + } + else if(labelFound == AddressType::ROM_MIRROR) { + if(mySettings.rFlag) { int tmp = (ad & myAppData.end) + myOffset; LABEL_A12_HIGH(tmp); nextLine << ",y"; nextLineBytes << Base::HEX2 << int(tmp & 0xff) << " " << Base::HEX2 << int(tmp >> 8); - } else { + } + else { nextLine << "$" << Base::HEX4 << ad << ",y"; nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8); } - } else { + } + else { LABEL_A12_LOW(ad); nextLine << ",y"; nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8); @@ -443,7 +471,7 @@ FIX_LAST: case AddressingMode::INDIRECT_X: { d1 = Debugger::debugger().peek(myPC + myOffset); ++myPC; - if (pass == 3) { + if(pass == 3) { labelFound = mark(d1, 0); // dummy call to get address type nextLine << " ("; LABEL_A12_LOW(d1); @@ -456,7 +484,7 @@ FIX_LAST: case AddressingMode::INDIRECT_Y: { d1 = Debugger::debugger().peek(myPC + myOffset); ++myPC; - if (pass == 3) { + if(pass == 3) { labelFound = mark(d1, 0); // dummy call to get address type nextLine << " ("; LABEL_A12_LOW(d1); @@ -470,7 +498,7 @@ FIX_LAST: { d1 = Debugger::debugger().peek(myPC + myOffset); ++myPC; labelFound = mark(d1, Device::REFERENCED); - if (pass == 3) { + if(pass == 3) { nextLine << " "; LABEL_A12_LOW(d1); nextLine << ",x"; @@ -483,7 +511,7 @@ FIX_LAST: { d1 = Debugger::debugger().peek(myPC + myOffset); ++myPC; labelFound = mark(d1, Device::REFERENCED); - if (pass == 3) { + if(pass == 3) { nextLine << " "; LABEL_A12_LOW(d1); nextLine << ",y"; @@ -501,11 +529,12 @@ FIX_LAST: ad = ((myPC + Int8(d1)) & 0xfff) + myOffset; labelFound = mark(ad, Device::REFERENCED); - if (pass == 3) { - if (labelFound == AddressType::ROM) { + if(pass == 3) { + if(labelFound == AddressType::ROM) { nextLine << " "; LABEL_A12_HIGH(ad); - } else + } + else nextLine << " $" << Base::HEX4 << ad; nextLineBytes << Base::HEX2 << int(d1); @@ -517,29 +546,31 @@ FIX_LAST: { ad = Debugger::debugger().dpeek(myPC + myOffset); myPC += 2; labelFound = mark(ad, Device::REFERENCED); - if (pass == 2 && !checkBit(ad & myAppData.end, Device::CODE)) { + if(pass == 2 && !checkBit(ad & myAppData.end, Device::CODE)) { // Since we can't know what address is being accessed unless we also // know the current X value, this is marked as ROW instead of DATA // The processing is left here, however, in case future versions of // the code can somehow track access to CPU registers mark(ad, Device::ROW); - } else if (pass == 3) { - if (ad < 0x100 && mySettings.fFlag) + } + else if(pass == 3) { + if(ad < 0x100 && mySettings.fFlag) nextLine << ".ind "; else nextLine << " "; } - if (labelFound == AddressType::ROM) { + if(labelFound == AddressType::ROM) { nextLine << "("; LABEL_A12_HIGH(ad); nextLine << ")"; } - else if (labelFound == AddressType::ROM_MIRROR) { + else if(labelFound == AddressType::ROM_MIRROR) { nextLine << "("; - if (mySettings.rFlag) { + if(mySettings.rFlag) { int tmp = (ad & myAppData.end) + myOffset; LABEL_A12_HIGH(tmp); - } else { + } + else { LABEL_A12_LOW(ad); } nextLine << ")"; @@ -558,26 +589,27 @@ FIX_LAST: break; } // end switch - if (pass == 3) { + if(pass == 3) { cycles += int(ourLookup[opcode].cycles); // A complete line of disassembly (text, cycle count, and bytes) myDisasmBuf << nextLine.str() << "'" << ";" << std::dec << int(ourLookup[opcode].cycles) << (addrMode == AddressingMode::RELATIVE ? (ad & 0xf00) != ((myPC + myOffset) & 0xf00) ? "/3!" : "/3 " : " "); - if ((opcode == 0x40 || opcode == 0x60 || opcode == 0x4c || opcode == 0x00 // code block end - || checkBit(myPC, Device::REFERENCED) // referenced address - || (ourLookup[opcode].rw_mode == RWMode::WRITE && d1 == WSYNC)) // strobe WSYNC - && cycles > 0) { - // output cycles for previous code block + if((opcode == 0x40 || opcode == 0x60 || opcode == 0x4c || opcode == 0x00 // code block end + || checkBit(myPC, Device::REFERENCED) // referenced address + || (ourLookup[opcode].rw_mode == RWMode::WRITE && d1 == WSYNC)) // strobe WSYNC + && cycles > 0) { + // output cycles for previous code block myDisasmBuf << "'= " << std::setw(3) << std::setfill(' ') << std::dec << cycles; cycles = 0; - } else { + } + else { myDisasmBuf << "' "; } myDisasmBuf << "'" << nextLineBytes.str(); addEntry(Device::CODE); - if (opcode == 0x40 || opcode == 0x60 || opcode == 0x4c || opcode == 0x00) { + if(opcode == 0x40 || opcode == 0x60 || opcode == 0x4c || opcode == 0x00) { myDisasmBuf << " ' ' "; addEntry(Device::NONE); mySegType = Device::NONE; // prevent extra lines if data follows @@ -586,8 +618,8 @@ FIX_LAST: nextLine.str(""); nextLineBytes.str(""); } - } - } /* while loop */ + } // CODE + } /* while loop */ /* Just in case we are disassembling outside of the address range, force the myPCEnd to EOF */ myPCEnd = myAppData.end + myOffset; @@ -630,7 +662,7 @@ void DiStella::disasmPass1(CartDebug::AddressList& debuggerAddresses) // Therefore, we stop at the first such address encountered for (uInt32 k = pcBeg; k <= myPCEnd; ++k) { if (checkBits(k, Device::Device::DATA | Device::GFX | Device::PGFX | - Device::COL | Device::PCOL | Device::BCOL, + Device::COL | Device::PCOL | Device::BCOL | Device::AUD, Device::CODE)) { //if (Debugger::debugger().getAccessFlags(k) & // (Device::DATA | Device::GFX | Device::PGFX)) { @@ -692,7 +724,7 @@ void DiStella::disasmPass1(CartDebug::AddressList& debuggerAddresses) // Must be ROW / unused bytes if (!checkBit(k, Device::CODE | Device::GFX | Device::PGFX | - Device::COL | Device::PCOL | Device::BCOL | + Device::COL | Device::PCOL | Device::BCOL | Device::AUD | Device::DATA)) mark(k + myOffset, Device::ROW); } @@ -711,7 +743,7 @@ void DiStella::disasmFromAddress(uInt32 distart) // abort when we reach non-code areas if (checkBits(myPC, Device::Device::DATA | Device::GFX | Device::PGFX | - Device::COL | Device::PCOL | Device::BCOL, + Device::COL | Device::PCOL | Device::BCOL | Device::AUD, Device::CODE)) { myPCEnd = (myPC - 1) + myOffset; return; @@ -1037,18 +1069,11 @@ void DiStella::addEntry(Device::AccessType type) case Device::GFX: case Device::PGFX: - getline(myDisasmBuf, tag.disasm, '\''); - getline(myDisasmBuf, tag.bytes); - break; - case Device::COL: case Device::PCOL: case Device::BCOL: - getline(myDisasmBuf, tag.disasm, '\''); - getline(myDisasmBuf, tag.bytes); - break; - case Device::DATA: + case Device::AUD: getline(myDisasmBuf, tag.disasm, '\''); getline(myDisasmBuf, tag.bytes); break; @@ -1213,7 +1238,7 @@ void DiStella::outputBytes(Device::AccessType type) isType = checkBits(myPC, type, Device::CODE | (type != Device::DATA ? Device::DATA : 0) | Device::GFX | Device::PGFX | - Device::COL | Device::PCOL | Device::BCOL); + Device::COL | Device::PCOL | Device::BCOL | Device::AUD); referenced = checkBit(myPC, Device::REFERENCED); } if (!lineEmpty) diff --git a/src/emucore/Device.hxx b/src/emucore/Device.hxx index 205de10ac..d60ec7054 100644 --- a/src/emucore/Device.hxx +++ b/src/emucore/Device.hxx @@ -46,13 +46,14 @@ class Device : public Serializable // debugger, or specified in a Distella cfg file, and are listed in order // of decreasing hierarchy // - CODE = 1 << 10, // 0x400, disassemble-able code segments - TCODE = 1 << 9, // 0x200, (tentative) disassemble-able code segments - GFX = 1 << 8, // 0x100, addresses loaded into GRPx registers - PGFX = 1 << 7, // 0x080, addresses loaded into PFx registers - COL = 1 << 6, // 0x040, addresses loaded into COLUPx registers - PCOL = 1 << 5, // 0x010, addresses loaded into COLUPF register - BCOL = 1 << 4, // 0x010, addresses loaded into COLUBK register + CODE = 1 << 11, // 0x800, disassemble-able code segments + TCODE = 1 << 10, // 0x400, (tentative) disassemble-able code segments + GFX = 1 << 9, // 0x200, addresses loaded into GRPx registers + PGFX = 1 << 8, // 0x100, addresses loaded into PFx registers + COL = 1 << 7, // 0x080, addresses loaded into COLUPx registers + PCOL = 1 << 6, // 0x040, addresses loaded into COLUPF register + BCOL = 1 << 5, // 0x020, addresses loaded into COLUBK register + AUD = 1 << 4, // 0x010, addresses loaded into audio registers DATA = 1 << 3, // 0x008, addresses loaded into registers other than GRPx / PFx ROW = 1 << 2, // 0x004, all other addresses // special type for poke() diff --git a/src/emucore/M6502.cxx b/src/emucore/M6502.cxx index 6f7392326..86b050dfb 100644 --- a/src/emucore/M6502.cxx +++ b/src/emucore/M6502.cxx @@ -23,21 +23,15 @@ // Flags for access types #define DISASM_CODE Device::CODE -// #define DISASM_GFX Device::GFX -// #define DISASM_PGFX Device::PGFX #define DISASM_DATA Device::DATA -// #define DISASM_ROW Device::ROW #define DISASM_WRITE Device::WRITE - #define DISASM_NONE 0 + #define DISASM_NONE Device::NONE #else // Flags for access types #define DISASM_CODE 0 -// #define DISASM_GFX 0 -// #define DISASM_PGFX 0 #define DISASM_DATA 0 -// #define DISASM_ROW 0 - #define DISASM_NONE 0 #define DISASM_WRITE 0 + #define DISASM_NONE 0 #endif #include "Settings.hxx" #include "Vec.hxx" diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index 68747896a..d4cdb81e8 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -534,8 +534,8 @@ void Settings::usage() const << " Arguments are more fully explained in the manual\n" << endl << " -dis.resolve <1|0> Attempt to resolve code sections in disassembler\n" - << " -dis.gfxformat <2|16> Set base to use for displaying GFX sections in\n" - << " disassembler\n" + << " -dis.gfxformat <2|16> Set base to use for displaying (P)GFX sections\n" + << " in disassembler\n" << " -dis.showaddr <1|0> Show opcode addresses in disassembler\n" << " -dis.relocate <1|0> Relocate calls out of address range in\n" << " disassembler\n" diff --git a/src/emucore/System.hxx b/src/emucore/System.hxx index 1a6dcff68..2e7c158a9 100644 --- a/src/emucore/System.hxx +++ b/src/emucore/System.hxx @@ -234,7 +234,7 @@ class System : public Serializable /** Access and modify the access type flags for the given address. Note that while any flag can be used, the disassembly - only really acts on CODE/GFX/PGFX/COL/PCOL/BCOL/DATA/ROW. + only really acts on CODE/GFX/PGFX/COL/PCOL/BCOL/AUD/DATA/ROW. */ Device::AccessFlags getAccessFlags(uInt16 address) const; void setAccessFlags(uInt16 address, Device::AccessFlags flags); diff --git a/src/emucore/tia/TIA.cxx b/src/emucore/tia/TIA.cxx index 58eb8c8ea..c5896c3aa 100644 --- a/src/emucore/tia/TIA.cxx +++ b/src/emucore/tia/TIA.cxx @@ -530,34 +530,76 @@ bool TIA::poke(uInt16 address, uInt8 value) break; case AUDV0: + { myAudio.channel0().audv(value); myShadowRegisters[address] = value; + #ifdef DEBUGGER_SUPPORT + uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); + if(dataAddr) + mySystem->setAccessFlags(dataAddr, Device::AUD); + #endif break; + } case AUDV1: + { myAudio.channel1().audv(value); myShadowRegisters[address] = value; + #ifdef DEBUGGER_SUPPORT + uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); + if(dataAddr) + mySystem->setAccessFlags(dataAddr, Device::AUD); + #endif break; + } case AUDF0: + { myAudio.channel0().audf(value); myShadowRegisters[address] = value; + #ifdef DEBUGGER_SUPPORT + uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); + if(dataAddr) + mySystem->setAccessFlags(dataAddr, Device::AUD); + #endif break; + } case AUDF1: + { myAudio.channel1().audf(value); myShadowRegisters[address] = value; + #ifdef DEBUGGER_SUPPORT + uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); + if(dataAddr) + mySystem->setAccessFlags(dataAddr, Device::AUD); + #endif break; + } case AUDC0: + { myAudio.channel0().audc(value); myShadowRegisters[address] = value; + #ifdef DEBUGGER_SUPPORT + uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); + if(dataAddr) + mySystem->setAccessFlags(dataAddr, Device::AUD); + #endif break; + } case AUDC1: + { myAudio.channel1().audc(value); myShadowRegisters[address] = value; + #ifdef DEBUGGER_SUPPORT + uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); + if(dataAddr) + mySystem->setAccessFlags(dataAddr, Device::AUD); + #endif break; + } case HMOVE: myDelayQueue.push(HMOVE, value, Delay::hmove); From d9a207786d8c210fbe141bb7b59c62a317971a8c Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 29 Mar 2020 12:30:26 +0200 Subject: [PATCH 054/377] update debugger docs add missing debugger commands for enhanced DiStella data detection --- Changes.txt | 4 +- docs/debugger.html | 100 +++++++++-- docs/graphics/debugger_cpuregs.png | Bin 2045 -> 1795 bytes docs/graphics/debugger_main.png | Bin 63559 -> 63592 bytes docs/graphics/resources/debugger_main.pdn | Bin 204692 -> 204733 bytes src/debugger/DebuggerParser.cxx | 192 +++++++++++++--------- src/debugger/DebuggerParser.hxx | 9 +- 7 files changed, 204 insertions(+), 101 deletions(-) diff --git a/Changes.txt b/Changes.txt index 9daaf6f42..0b2e20aa0 100644 --- a/Changes.txt +++ b/Changes.txt @@ -20,9 +20,9 @@ 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. (TOOD: Doc) - * Added displaying last write address in debugger. (TOOD: Doc) + * Added displaying last write address in debugger. - * Added detection of color and audio data in DiStella. (TOOD: Doc) + * Added detection of color and audio data in DiStella. 6.0.2 to 6.1: (March 22, 2020) diff --git a/docs/debugger.html b/docs/debugger.html index 15a80bcb1..46e38d079 100644 --- a/docs/debugger.html +++ b/docs/debugger.html @@ -121,13 +121,14 @@ feature that no other 2600 debugger has; it's completely cross-platform.<
  • Supports Distella 'configuration directives', which may be used to override automatic code/data determination in the disassembly. For now, - the following directives are supported: CODE, GFX, PGFX, DATA, ROW. - These directives can be entered at the debugger prompt, or (automatically) + the following directives are supported: CODE, GFX, PGFX, COL, PCOL, BCOL, AUD, DATA, ROW. + These directives can be entered at the debugger prompt, or be (automatically) loaded and saved in configuration files.
  • Extensive disassembly support, both from the emulation core and with help from Distella. Where possible, the disassembly differentiates between code, - player graphics and playfield graphics (ie, addresses stored in GRPx and PFx) + player and playfield graphics, colors and audio (ie, addresses stored in + GRPx, PFx, COLUxx, AUDxx) and data (addresses used as an operand of a command). Code sections are also differentiated between actual code, and 'tentative' code (ie, areas that may represent code sections, but haven't actually been executed yet). Such @@ -906,7 +907,9 @@ Type "help 'cmd'" to see extended information about the given command.

                     a - Set Accumulator to <value>
    +              aud - Mark 'AUD' range in disassembly
                  base - Set default number base to <base> (bin, dec, hex)
    +             bcol - Mark 'BCOL' range in disassembly
                 break - Set/clear breakpoint at <address> and <bank>
               breakif - Set/clear breakpoint on <condition>
            breaklabel - Set/clear breakpoint on <address> (no mirrors, all banks)
    @@ -919,6 +922,7 @@ clearsavestateifs - Clear all savestate points
          clearwatches - Clear all watches
                   cls - Clear prompt area of text
                  code - Mark 'CODE' range in disassembly
    +              col - Mark 'COL' range in disassembly
             colortest - Show value xx as TIA color
                     d - Decimal Mode Flag: set (0 or 1), or toggle (no arg)
                  data - Mark 'DATA' range in disassembly
    @@ -959,6 +963,7 @@ clearsavestateifs - Clear all savestate points
                     n - Negative Flag: set (0 or 1), or toggle (no arg)
               palette - Show current TIA palette
                    pc - Set Program Counter to address xx
    +             pcol - Mark 'PCOL' range in disassembly
                  pgfx - Mark 'PGFX' range in disassembly
                 print - Evaluate/print expression xx in hex/dec/binary
                   ram - Show ZP RAM, or set address xx to yy1 [yy2 ...]
    @@ -1217,6 +1222,8 @@ registers. For example, consider the command 'LDA ($80),Y'. The operand of
     the command resolves to some address, which isn't always easy to determine at
     first glance. The 'Src Addr' area shows the actual resulting operand/address
     being used with the given opcode.

    +

    The destination address of the last write is shown besides 'Dest'.

    +

    There's not much else to say about the CPU Registers widget: if you know 6502 assembly, it's pretty self-explanatory. If you don't, well, you should learn :)

    @@ -1371,21 +1378,78 @@ can use. These are known as 'directives', and partly correspond to configuration options from the standalone Distella program. They are listed in order of decreasing hierarchy:

  • -launcherfont <small|medium|large>
    -launcherfont <small|small medium|medium|large>
    Set the size of the font in the ROM launcher.
    -romviewer <0|1|2>
    Hide ROM Info Viewer in ROM launcher mode (0), or use the - given zoom level (1 or 2).
    -romviewer <float>
    Hide ROM Info Viewer in ROM launcher mode (0) or use the + given zoom level.
    + Note: The zoom level is converted into a percentage in the UI.
    -launcherfont <small|small medium|medium|large>
    -launcherfont <small|small_medium|medium|large>
    Set the size of the font in the ROM launcher.
    -launcherfont <small|small_medium|medium|large>
    -launcherfont <small|low_medium|medium|large|large12|large14|large16>
    Set the size of the font in the ROM launcher.
    - - - - - + + + + + + + + + + + + + + + + + + +
    CODEAddresses which have appeared in the program counter, or -which tentatively can appear in the program counter. These can be edited in hex.
    GFXAddresses which contain data stored in the player graphics registers -(GRP0/GRP1). These addresses are shown with a bitmap of the graphics, which -can be edited in either hex or binary. The bitmap is shown as large blocks.
    PGFXAddresses which contain data stored in the playfield graphics registers -(PF0/PF1/PF2). These addresses are shown with a bitmap of the graphics, which -can be edited in either hex or binary. The bitmap is shown as small dashes.
    DATAAddresses used as an operand for some opcode. These can be edited -in hex.
    ROWAddresses not used as any of the above. These are shown up -to 8 per line, and cannot be edited.
    + CODE + + Addresses which have appeared in the program counter, or + which tentatively can appear in the program counter. These can be edited in hex. +
    + GFX + + Addresses which contain data stored in the player graphics registers + (GRP0/GRP1). These addresses are shown with a bitmap of the graphics, which + can be edited in either hex or binary. The bitmap is shown as large blocks. +
    + PGFX + + Addresses which contain data stored in the playfield graphics registers + (PF0/PF1/PF2). These addresses are shown with a bitmap of the graphics, which + can be edited in either hex or binary. The bitmap is shown as small dashes. +
    + COL + + Addresses which contain data stored in the player color registers + (COLUP0/COLUP1). These addresses are shown as color constants, which + can be edited in hex. The color constant names are depending on the ROM's TV type. +
    + PCOL + + Addresses which contain data stored in the playfield color register + (COLUPF). These addresses are shown as color constants, which + can be edited in hex. The color constant names are depending on the ROM's TV type. +
    + BCOL + + Addresses which contain data stored in the background color register + (COLUBK). These addresses are shown as color constants, which + can be edited in hex. The color constant names are depending on the ROM's TV type. +
    + AUD + + Addresses which contain data stored in the audio registers + (AUDC0/AUDC1/AUDF0/AUDF1/AUDV0/AUDV1). These can be edited + in hex. +
    + DATA + + Addresses used as an operand for some opcode. These can be edited + in hex. +
    + ROW + + Addresses not used as any of the above. These are shown up + to 8 per line and cannot be edited. +
    -

    For code sections, the 6502 mnemonic will be UPPERCASE for all standard instructions, or lowercase for "illegal" 6502 instructions (like "dcp"). If automatic resolving of code sections has been disabled for any reason, you'll likely see a lot @@ -1523,12 +1587,12 @@ the RAM in the DPC scheme is not viewable by the 6507, so its addresses start fr

    Distella Configuration Files

    As mentioned in ROM Disassembly, Stella supports the following directives: -CODE/GFX/PGFX/DATA/ROW. While the debugger will try to automatically mark address +CODE, GFX, PGFX, COL, PCOL, BCOL, AUD, DATA, ROW. While the debugger will try to automatically mark address space with the appropriate directive, there are times when it will fail. There are several options in this case:

    1. Manually set the directives: Directives can be set in the debugger -prompt with the code/gfx/pgfx/data/row commands. These accept an address range +prompt with the aud/code/col/bcol/gfx/pcol/pgfx/data/row commands. These accept an address range for the given directive type. Setting a range with the same type a second time will remove that directive from the range.
    2. Use configuration files: Configuration files can be used to automatically diff --git a/docs/graphics/debugger_cpuregs.png b/docs/graphics/debugger_cpuregs.png index f8cd3cb552bcd67be02544425136e5599d608668..feb238c1b698502214f98abc61790c71f023076f 100644 GIT binary patch literal 1795 zcmV+e2mJVnP)Px#1ZP1_K>z@;j|==^1poj5Fi=cXMF0Q*XlQ82005(mVacz2|NnsS@Xr7M00000 z00000000000000000000000000928BQvd(}32;bRa{vGi!vFvd!vV){sAK>D23$!* zK~#9!?VQ1m;~)$`eTaIWZngKFRli`RJ!hqSL8aUyjnx1Dgar)5217GbXiEl<+GZe4 zc(rlBIDu)eGIq2ErK7bd9j!(AerRu^oOIQ{w-zLgc6^rv(WVAOH?pI3w3iW&HiCW! zLb)HbVI1(yi9wsq>wGcWmsZgxn3!ccw6jG!U*^4`%@z$mS~bWJZ8liyH7jFmS8LjX z1ZYZ2v-vX{E%&t>Xf5}(1e!8N%h+sRo2JnDqa8Y}wT%{BvN>9_1{sU>kOobA$Y$M0 zEPZ(VveMCZh9(Cbb`cxdgKW{-iB-i~JEgSzCheL$Oi@Xr{k#$h(5|7Jg8ef>(59M_ z>1!RWqdgN1U@$K)yFs(D5u!lV)CE*i;2@%@;spS%>UD5vi{4d#C$quO)R*0v$#kkb z+Qd(wnhL5x%K;=bUA#8eqG?F~b0jvn)I`PI=n+7@{N+OS)+ zNOwn_4THHb5}ICAJe!q8yP|k>|J$#a3Y&34ssgn0<*XMdXOq4$KMoB~C8A+d&m^7X zX#bx*l}*T4cNNjrUt`9EsYjsMGl^(=DVVR``-}yv?b&GLLU&D|t;s}l6*LHk-WCnl zu|qVY5(y1;b+%|;t-gw*;lUkVEv-c%rK3JEOU+_Gw?k76W?J)o&3w_>+gioYX1gb` z+!|<-)@FHCp@IT#-8~l+f>XZO-NPf4ZkaH#2(W84mI6~gtkf_9&eG3cDH;_v>nGr zda$meb+m%Q*VmZr8x0r54oS2Ht~_sq=TltC5qwF2HV!5OVVb7W%TQ$LFg&u$1Cf&} zjDT4>T(!m%4m>9-iO?o@>qIrQsK>cwdbglUzh#x?)$ODOMSWsEs@YHQ#G_G z4vBdnIW%KpDKxJuUc%8v6SmMd1?uI|vS~3{G`nC8d9-!Gmut=UHD1COe2uEmYKFMG z7eW&Z(mH_*8qXVfRW!+s;1YetAc53>8O?MzWsJ4Z(#}7F#_I1vgNj|&(5~D4wKDcE2bP--6ct~%M)jVX3Mx+mqI~qB8J?VKPJvP#c);d~8 zdmi5O;4lNx<)W`Ykw+cp)=#YTL| zRYn_eZm-_mBp)X>CFX5g&>-tZQd--FW_bu2d9RMPk3oyX#zr6=hg>5cso01w;kz<4G|1_(XyWLIpz->< z2U<{M5W>qeLg3r?1`U#C)97(N&ec;kL?9F z(59NQ;bBu9t)qn}uP1A4L=SRC>AA=4qv4`t_}t?Jni=e30fYrI+9-?4QKv;G39`2O+W*uSHU3Hu0+vXR9@!~J`F80$QaFp zQj%!?Ib<^0R1XajXc*Mkga+5F){GE?^bytCXruJp<4>Vs{7dX>t8WLJ5%$kK8O(RS zTFyTfinfH#-(8`7=L5LmA^m6vQy|epj_QxNkvf-b39S#0JDPm*dh$KdN`xm~G&Zsa l>1ZuVM{7|!T7xo;{{fmwkp@@vs1X1F002ovPDHLkV1jxqD*ONd literal 2045 zcmaJ?3se(l7EYiDq(uY~j;P>@hQ=y{M*yKftsss~VwwPA+#CWZ7!Z_4fF%fsD=t{c zafeqzA`6ZPs9+@xD;RlZ5dpygv4BAoK|^>Hn8Yz5MuUp-05l#4 z>M*HTz4H}7@anlY)=Vmjm=Xo6YG^4@M0I^+q4zI#Z4Ij{w+jI@(TR1EU0&qOY<(>` zk#%j}5tl(Ds&6TNtxH1h19gHD5*z76O9OwNSyPz@S(j+Z_@bL`d#$PfK>tuAGj?G$ zyR-Tsw4RgpJIf&3EuhZNU63yMAi`>Ojv+;MJ^ zl6tvBrk2)Tv_oRdla?)xynXo!x|p1(sK#M0aD#LiOxR8VF(Ooob|^_#5ea`&rnuKo zUZhl6B-LtEc6in$i6)7YI24Q7XLI=T;d^0l)>s{Rs0SJV99~0xU%lNQ3X5GrkgkDN z5pWwFCubm)xy_mNcVJ0djgi8p+@wi@Tmow$@7SEVH?r}{+*4uJFWX4%cKAo0MAKO~ zQs3E;im&9TVy+_8u5*GAjPPKlW$7uzq_PG5vGmGZ(6neM`zK#16iRi#wf#4Tzxm%O z7QK;Dv=Gv4Y;^u#ML;%`_i>A&SQL^5``Q^iH7_xcwU9idt;23eDH0AXevCI@&U zt^gOw6X#MLy%iOkLB~%VtSch(|2d$x1AYCmreF>dW0O`jjyPm;*7Tx9$9z36{!+W0 z3CPUZClgkppI?XGbtR?yr@^I*z-j#T=2JAVyrO{HAB#W*N|ql?I^Y5aV=ezYdjsH! zLhLHe2QGEO$$FQk*Kw`4fmxj+vV3;^(yl0>vsx39*aH#kc|f1d)1zR)U(6E)h+`5# zKEChq9V998!OF2Vi0de4-pNZYd4sacz--z%DQs~m%J!SYCf`D&f88>NU7iabf7dxEdDZpv2$UWFUe3D_U#L^u20h<1>KhOPt@UVzxFNxT315XP6gIvNAYQrWiROtjdHR5 zW#tpm3hqm+w3ICSYrU@93?D`;JW<&+XL?(Qw%x4-wLJTDu{N(xe+k zjUNAC#e@R}08hsW6KmrPz_SHHfpObGoi!~9Vqp8Eg4z^>bTsywf7|Ej9y`6|W*Q&x zwomY$aY=vUQS~tQaSqpS@^%G-=`gq7?Dpkh6@%--dP%*>;fcbTa;{JO{ei~i^Yh-= z?iU{h=)j_D22h6_v4@^PMz609UN{8C?4UWxdj~JPWW)BfXUeUyvv~1T0M)cAkS}5$ z%mDoO%8y}xH?924s%v_$lU%b(e_m~M>2>JbyMRVzA4}*g^Rgk)ZSJBSaA38Vtd{P} zj?yVf4|tpFJGbjlvw`2nv_dI(Tw<-6cDvOcizDpEz_Z6AWA6j4*&lcbsehy6Zt`)7 zGw)S)lT)q>ZF;SYf{g_(teM^JGAJxug@E7R*#z}Cv6_AUNh9(-TCViW=${P~|8y*r zGLHw#%`m6no1w7!lD>`pYKH7yOOZ&GyBTyb#tSp~ahR%bp(uZ0z*&w{K(#Sf2hLg> zxgE&kgg-t@5Ho}CjN%)?#W3=O#q1A-(=qv^=~j-PoTKvG(5RXkk#M+_-A#~H2sHyZ wkc+fIEBT@X0YG32P*^>!;c>s&_AdLjtRJh+_^Y9-ab~#hHS1n+o#%C4=L&zSu7HR000#sD;VCJ~YJotvD?uRi zNUU4HH@%<4BEhQQs8=!tX%+ht}m( zYykotUn9{jr1sEigYTD~h!|sq6=CMr3s}kD;$8(b#zIf9qOGotP zK|-sNszP|rZM+24@3HpW&`nupd}s4}=AAL6Iic1HxVCgT?0GD#{NsUvo7V@IS(9DE z$3Ml~H-5e<$?89M_bP5MnEv=a>uhHDkiDc&bU%<0=o#>WX!kooRMJgYa4@L z7M5V}r@g>%AD}&b=p0zxzY6#pqH5Ndh?M$p2A*}AkW@$z@OwbdsG*YhI3dMkzlg&4 z)i_MAJDBZ_*H9X~`GV!_+A*=eL~)l7BX1LH5w*RnAAwvUE!c=#9Jhg0qc6U-d_%unV; zM~o~JN0x0)wnB{TkWU0xs9xV-i!JbZJ`sHZLOYqcG99!x(sSIY=ELFe-6!c(AP79jXD zc6WA{Vz06TPMXIyzQvhK_ux9w7H#meU!0t#P@fc~Wc$7`aCd4FT|A{}`Y~-FviqaF zd9fDG`JSekcKD!xuO4y46pW}SA@E1L@3;HoylzUiSAfIBfBEYqywSzyWnoDYyx>lZ zx6==%va{Vnz2?R4salu!KO4S}HRR{+q<>u6axn4P&miK1JAIv`uN^wjEMwZ55NCdd zv2A;vxS#Jo(sFGbxjzLnxQ!Zzz`eC^6^W^F+F`JySpgZd(@DP*^f2mIYiCPOEf^Pn z$KEe%I^K__F~)x`?m1O>A^u%}vsqH%VNaoxo6|@WvRL4BM_g<@jzTv*;I}Q6FO#rE zc8N*N)Rv2?=U(EIgA7fNYspE2^du4YZwDIBz4*3zXFj_P`CK-i+_gO~qR>4$Mptp! z;Yrs2oV4Xr;4q7%kZ8IP`p)>VqN%B0$;qXC@u<(n{yejr$LfsqW{6FF?~%W{N0bmz z5og{CZ{Bin^4l;l`ib+r@O#6zmrHnQy|fB1>9^Ztj^;$dQrKs)r>qPsq`e8062qj4S| z%$2`nU^lm`Km{65pj2tdoxw#`DZ5b*un?2zR`sy8l#6u|y-eR{!^0zjOxItDF*vPn zmpZn=HoA_`deJS()1mYZah?4XC}&r4iqVd|_2vled8Zkoa~ z-~O@wPIysCp>*-nRGMMEh{rEHJ%?5YmRTJc2Lj(=uFo^ zcyR%&p#5HdV$W}See3~2D?>`#Do=G?ZqWpEy-%L0zEES{5k0wc?MVAr;##TqlFMUe zo-ZiH=%g~qBo#s~f2h}|J$Y5svt)9VNWiGOJz^>F$;gZClWc7Dplhr-vn{8 zi>WJ)rkKWMBHYSUbu_@JzimZB-MO!T>1E&Sc=x8u!bJXEs?70o_!3qDb3Gd4y^{(; z_=_|(t-G6WSB#z&oI?o*f;D{K13L-NUD(WVm-dUBaNAb#;@b7dAHw20@WVWCtR zpX>fIBb!7N?Fm>jvi71h*KT%iMZ~{f&64Tnmn6e3DhNYsE}oJ1dt^ty9k1afy7@lm zJ{I^-U?F_~gN;f&{qq3?zV)vtF7v+&_70~Risk+ngN}GN&4Ea}C)l3USL|+9^}q50 zaX)6x_T9%;*xAy(`E!E9RCN+Ux+$Fa=A&sYE&ENB070z(-3@UAEN-t8ds<-q83Naj za&SaV=&PNZ&pVj46YvJq5<+R)7H@7$WlOItZ#@x(SAw3V1YV0joX)vSUg_%`&8|Fw z6HDE%%ZpL6S?K;b8>85dZf_=S{k@#}oB(MuY6LCvG)3#tJjcnyG5%8Ne}Lg=^L6=9 zp{|g$u3x>u)@BF_rO{BMVeOFittA90%LZk~8v^hhh(W(c!Q8DR^>~;~=2?w~+FTdS zpP6ivPE@?pz*{d9Q9)=*`$=RQ$z9LO(qY=KK6{A{YGXNh@s=T_QF_I*uxZ`WHmNYd z{H-o22a_Kq!W@G0yw|==?eGslUe8Y`k=Hv}#Yvliubogwz__TVrU1>@x zzmgbM`1ztt@%nS=cp(UM8K0po95>)mhUDGT6`R7=!=fkZiC@-YRYT-?CB94gaw>}t zgR9m(uySc}R5Uw%hgxh;+f#qI#@}tKiM`Drn3+A1|DHUlkVRBC`pICZ{RCOYr&rd~ zmre_dKlK!g)XUh_nv|(5%PHw(Tm$gknD+MpscxSkM3+1R|Y~) z69lsrvojeK25djEXsl2z$Mf(fjM=_$TTQ*iLkn_K*-piK8EZ$4yu0xFNz+|~G}Z4K z{X2n0o}H8#{H`sUQ0_3%{bhK|W^dA(gv9xCy$=Gv6awjsH}ktDlS;ehc|JUB8a)!; zsbF?{BUpbJU+p_n^>rIZw=?AJhs0i^_7ZXdGPE2E%J8qZqP|c(o65ACpt6-;(IV#j zE_v2M_Sjr5^OxNh$d?R7^LFE5U(jmi_ofW>mV@Wv_i4P1*y|ruD4xjTEI|9h-@QmG z6=twH+2w&o-QUNKp%ohZs4b(4#VvI2qteB17|v&3ItR-%J)tgx7fEXNL$cl~_JZy; zBAg@^`lM01pD+66s$d{O#%IQ90q+xa$sL&0q%n+_F|0fAn*}9AM_!ev@77OmFo_xq z-p4_g0HxC45V*P2Pk!Ckhp++*wf$Ansj>RfM~0M=k1+5-TO)n<5^IuN0y$|s#D66M z3mhxFe(-iGVu+sxgdmrGC^WXf3ZvF_h~j z0{V5|tNNHxw`-fZaOGbPL+`#j~roMyl^I5#m03oOPFi;a*5vVen-3U2Lly;r7%(aZ(`B6MN|72(*qJU-C5 zT_9UPenkE3)DWV$xnO{2O_beD1uR2@HgV~UkiK#V-=z;WUqV-clgL?%PF9*sqbK9cKtE7|Ba`-c5F1q_OYu5s@ zkV0^LRQSK7IK^Z&lbV2>x*iUuP#dNh?rnNDKI$fsX@50+>aXrdg}UlYU^PQgCGrdD z3SQyoH>;@xM%&5DmV-wg>P~c9J)QgF4BW9R#bfBbVb+0as*1E$0Fl7)tw&Q;vEll> z&z0n+y2~_#Ke$JERt1AXz6Je)oJOKUY5ySS@DT59+m9u2YiAjH!wW40&53%Aqh1g} z-%T-LzuWRyU~)_wsOb}3@wO2lQl*ykS+V*VvV~@!4ifZ!%{=4m#%?jN8$Tf_P6!MOZ1vⅅH-N4}86!B5`gW+nB~DGV(8+!vf2= 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 z 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 diff --git a/docs/graphics/resources/debugger_main.pdn b/docs/graphics/resources/debugger_main.pdn index e486c0048c65d99e54379f4145b90056497dc0a8..de1d1e3578ed75594e3e8072526d29f1f25ac7e6 100644 GIT binary patch delta 52807 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 delta 52599 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 DebuggerParser::commands = { { +std::array DebuggerParser::commands = { { { "a", "Set Accumulator to ", @@ -2311,6 +2302,16 @@ std::array DebuggerParser::commands = { { std::mem_fn(&DebuggerParser::executeA) }, + { + "aud", + "Mark 'AUD' range in disassembly", + "Start and end of range required\nExample: aud f000 f010", + true, + false, + { Parameters::ARG_WORD, Parameters::ARG_MULTI_BYTE }, + std::mem_fn(&DebuggerParser::executeAud) + }, + { "base", "Set default number base to ", @@ -2321,6 +2322,17 @@ std::array DebuggerParser::commands = { { std::mem_fn(&DebuggerParser::executeBase) }, + { + "bcol", + "Mark 'BCOL' range in disassembly", + "Start and end of range required\nExample: bcol f000 f010", + true, + false, + { Parameters::ARG_WORD, Parameters::ARG_MULTI_BYTE }, + std::mem_fn(&DebuggerParser::executeBCol) + }, + + { "break", "Break at
      and ", @@ -2442,6 +2454,16 @@ std::array DebuggerParser::commands = { { std::mem_fn(&DebuggerParser::executeCode) }, + { + "col", + "Mark 'COL' range in disassembly", + "Start and end of range required\nExample: col f000 f010", + true, + false, + { Parameters::ARG_WORD, Parameters::ARG_MULTI_BYTE }, + std::mem_fn(&DebuggerParser::executeCol) + }, + { "colortest", "Show value xx as TIA color", @@ -2847,6 +2869,16 @@ std::array DebuggerParser::commands = { { std::mem_fn(&DebuggerParser::executePc) }, + { + "pcol", + "Mark 'PCOL' range in disassembly", + "Start and end of range required\nExample: col f000 f010", + true, + false, + { Parameters::ARG_WORD, Parameters::ARG_MULTI_BYTE }, + std::mem_fn(&DebuggerParser::executePCol) + }, + { "pgfx", "Mark 'PGFX' range in disassembly", diff --git a/src/debugger/DebuggerParser.hxx b/src/debugger/DebuggerParser.hxx index dced64dfb..9de21b3e9 100644 --- a/src/debugger/DebuggerParser.hxx +++ b/src/debugger/DebuggerParser.hxx @@ -27,6 +27,7 @@ class FilesystemNode; struct Command; #include "bspf.hxx" +#include "Device.hxx" class DebuggerParser { @@ -97,7 +98,7 @@ class DebuggerParser std::array parms; std::function executor; }; - static std::array commands; + static std::array commands; struct Trap { @@ -140,9 +141,13 @@ class DebuggerParser // output the error with the example provided for the command void outputCommandError(const string& errorMsg, int command); + void executeDirective(Device::AccessType type); + // List of available command methods void executeA(); + void executeAud(); void executeBase(); + void executeBCol(); void executeBreak(); void executeBreakif(); void executeBreaklabel(); @@ -155,6 +160,7 @@ class DebuggerParser void executeClearwatches(); void executeCls(); void executeCode(); + void executeCol(); void executeColortest(); void executeD(); void executeData(); @@ -195,6 +201,7 @@ class DebuggerParser void executeN(); void executePalette(); void executePc(); + void executePCol(); void executePGfx(); void executePrint(); void executeRam(); From 49a9f07452456d19d6aea7e3aa5926e58ea2bfc3 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 29 Mar 2020 13:02:58 +0200 Subject: [PATCH 055/377] fix DiStella configuration output --- src/debugger/CartDebug.cxx | 70 ++++++++++++++++----------------- src/debugger/CartDebug.hxx | 6 +-- src/debugger/DebuggerParser.cxx | 20 ++-------- 3 files changed, 41 insertions(+), 55 deletions(-) diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index d9750629e..5fd9a10cf 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -886,47 +886,47 @@ string CartDebug::loadConfigFile() // TODO - figure out what to do with this buf >> hex >> start; } - else if(BSPF::startsWithIgnoreCase(directive, "Device::CODE")) + else if(BSPF::startsWithIgnoreCase(directive, "CODE")) { buf >> hex >> start >> hex >> end; addDirective(Device::CODE, start, end, currentbank); } - else if(BSPF::startsWithIgnoreCase(directive, "Device::GFX")) + else if(BSPF::startsWithIgnoreCase(directive, "GFX")) { buf >> hex >> start >> hex >> end; addDirective(Device::GFX, start, end, currentbank); } - else if(BSPF::startsWithIgnoreCase(directive, "Device::PGFX")) + else if(BSPF::startsWithIgnoreCase(directive, "PGFX")) { buf >> hex >> start >> hex >> end; addDirective(Device::PGFX, start, end, currentbank); } - else if(BSPF::startsWithIgnoreCase(directive, "Device::COL")) + else if(BSPF::startsWithIgnoreCase(directive, "COL")) { buf >> hex >> start >> hex >> end; addDirective(Device::COL, start, end, currentbank); } - else if(BSPF::startsWithIgnoreCase(directive, "Device::PCOL")) + else if(BSPF::startsWithIgnoreCase(directive, "PCOL")) { buf >> hex >> start >> hex >> end; addDirective(Device::PCOL, start, end, currentbank); } - else if(BSPF::startsWithIgnoreCase(directive, "Device::BCOL")) + else if(BSPF::startsWithIgnoreCase(directive, "BCOL")) { buf >> hex >> start >> hex >> end; addDirective(Device::BCOL, start, end, currentbank); } - else if(BSPF::startsWithIgnoreCase(directive, "Device::AUD")) + else if(BSPF::startsWithIgnoreCase(directive, "AUD")) { buf >> hex >> start >> hex >> end; addDirective(Device::AUD, start, end, currentbank); } - else if(BSPF::startsWithIgnoreCase(directive, "Device::DATA")) + else if(BSPF::startsWithIgnoreCase(directive, "DATA")) { buf >> hex >> start >> hex >> end; addDirective(Device::DATA, start, end, currentbank); } - else if(BSPF::startsWithIgnoreCase(directive, "Device::ROW")) + else if(BSPF::startsWithIgnoreCase(directive, "ROW")) { buf >> hex >> start; buf >> hex >> end; @@ -1304,9 +1304,6 @@ string CartDebug::saveRom() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartDebug::listConfig(int bank) { - if(myConsole.cartridge().bankCount() > 1) - return DebuggerParser::red("config file for multi-bank ROM not yet supported"); - uInt32 startbank = 0, endbank = bankCount(); if(bank >= 0 && bank < bankCount()) { @@ -1319,7 +1316,7 @@ string CartDebug::listConfig(int bank) for(uInt32 b = startbank; b < endbank; ++b) { BankInfo& info = myBankInfo[b]; - buf << "[" << b << "]" << endl; + buf << "Bank [" << b << "]" << endl; for(const auto& i: info.directiveList) { if(i.type != Device::NONE) @@ -1332,6 +1329,9 @@ string CartDebug::listConfig(int bank) getBankDirectives(buf, info); } + if(myConsole.cartridge().bankCount() > 1) + buf << DebuggerParser::red("config file for multi-bank ROM not fully supported") << endl; + return buf.str(); } @@ -1499,16 +1499,16 @@ void CartDebug::AccessTypeAsString(ostream& buf, Device::AccessType type) const { switch(type) { - case Device::CODE: buf << "Device::CODE"; break; - case Device::TCODE: buf << "Device::TCODE"; break; - case Device::GFX: buf << "Device::GFX"; break; - case Device::PGFX: buf << "Device::PGFX"; break; - case Device::COL: buf << "Device::COL"; break; - case Device::PCOL: buf << "Device::PCOL"; break; - case Device::BCOL: buf << "Device::BCOL"; break; - case Device::AUD: buf << "Device::AUD"; break; - case Device::DATA: buf << "Device::DATA"; break; - case Device::ROW: buf << "Device::ROW"; break; + case Device::CODE: buf << "CODE"; break; + case Device::TCODE: buf << "TCODE"; break; + case Device::GFX: buf << "GFX"; break; + case Device::PGFX: buf << "PGFX"; break; + case Device::COL: buf << "COL"; break; + case Device::PCOL: buf << "PCOL"; break; + case Device::BCOL: buf << "BCOL"; break; + case Device::AUD: buf << "AUD"; break; + case Device::DATA: buf << "DATA"; break; + case Device::ROW: buf << "ROW"; break; case Device::REFERENCED: case Device::VALID_ENTRY: case Device::NONE: break; @@ -1521,29 +1521,29 @@ void CartDebug::AccessTypeAsString(ostream& buf, Device::AccessFlags flags) cons if(flags) { if(flags & Device::CODE) - buf << "Device::CODE "; + buf << "CODE "; if(flags & Device::TCODE) - buf << "Device::TCODE "; + buf << "TCODE "; if(flags & Device::GFX) - buf << "Device::GFX "; + buf << "GFX "; if(flags & Device::PGFX) - buf << "Device::PGFX "; + buf << "PGFX "; if(flags & Device::COL) - buf << "Device::COL "; + buf << "COL "; if(flags & Device::PCOL) - buf << "Device::PCOL "; + buf << "PCOL "; if(flags & Device::BCOL) - buf << "Device::BCOL "; + buf << "BCOL "; if(flags & Device::AUD) - buf << "Device::AUD "; + buf << "AUD "; if(flags & Device::DATA) - buf << "Device::DATA "; + buf << "DATA "; if(flags & Device::ROW) - buf << "Device::ROW "; + buf << "ROW "; if(flags & Device::REFERENCED) - buf << "*Device::REFERENCED "; + buf << "*REFERENCED "; if(flags & Device::VALID_ENTRY) - buf << "*Device::VALID_ENTRY "; + buf << "*VALID_ENTRY "; } else buf << "no flags set"; diff --git a/src/debugger/CartDebug.hxx b/src/debugger/CartDebug.hxx index dda0906cb..c6ba615b5 100644 --- a/src/debugger/CartDebug.hxx +++ b/src/debugger/CartDebug.hxx @@ -237,6 +237,9 @@ class CartDebug : public DebuggerSystem // Convert given address to corresponding access type and append to buf void accessTypeAsString(ostream& buf, uInt16 addr) const; + // Convert access enum type to corresponding string and append to buf + void AccessTypeAsString(ostream& buf, Device::AccessType type) const; + private: using AddrToLabel = std::map; using LabelToAddr = std::map Date: Sun, 29 Mar 2020 17:24:16 +0200 Subject: [PATCH 056/377] fix savedis output --- src/debugger/CartDebug.cxx | 16 ++++++++-------- src/emucore/Device.hxx | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index 5fd9a10cf..89fad0d1b 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -1136,14 +1136,14 @@ string CartDebug::saveDisassembly() << "; ROM properties name : " << myConsole.properties().get(PropType::Cart_Name) << "\n" << "; ROM properties MD5 : " << myConsole.properties().get(PropType::Cart_MD5) << "\n" << "; Bankswitch type : " << myConsole.cartridge().about() << "\n;\n" - << "; Legend: * = Device::CODE not yet run (tentative code)\n" - << "; D = Device::DATA directive (referenced in some way)\n" - << "; G = Device::GFX directive, shown as '#' (stored in player, missile, ball)\n" - << "; P = Device::PGFX directive, shown as '*' (stored in playfield)\n" - << "; C = Device::COL directive, shown as '*' (stored in player color)\n" - << "; CP = Device::PCOL directive, shown as '*' (stored in playfield color)\n" - << "; CB = Device::BCOL directive, shown as '*' (stored in background color)\n" - << "; A = Device::AUD directive, shown as '*' (stored in audio registers)\n" + << "; Legend: * = CODE not yet run (tentative code)\n" + << "; D = DATA directive (referenced in some way)\n" + << "; G = GFX directive, shown as '#' (stored in player, missile, ball)\n" + << "; P = PGFX directive, shown as '*' (stored in playfield)\n" + << "; C = COL directive, shown as color constants (stored in player color)\n" + << "; CP = PCOL directive, shown as color constants (stored in playfield color)\n" + << "; CB = BCOL directive, shown as color constants (stored in background color)\n" + << "; A = AUD directive (stored in audio registers)\n" << "; i = indexed accessed only\n" << "; c = used by code executed in RAM\n" << "; s = used by stack\n" diff --git a/src/emucore/Device.hxx b/src/emucore/Device.hxx index d60ec7054..d8b9cbaa9 100644 --- a/src/emucore/Device.hxx +++ b/src/emucore/Device.hxx @@ -54,7 +54,7 @@ class Device : public Serializable PCOL = 1 << 6, // 0x040, addresses loaded into COLUPF register BCOL = 1 << 5, // 0x020, addresses loaded into COLUBK register AUD = 1 << 4, // 0x010, addresses loaded into audio registers - DATA = 1 << 3, // 0x008, addresses loaded into registers other than GRPx / PFx + DATA = 1 << 3, // 0x008, addresses loaded into registers other than GRPx / PFx / COLUxx, AUDxx ROW = 1 << 2, // 0x004, all other addresses // special type for poke() WRITE = TCODE // 0x200, address written to From 302d1fb51cbe0ba4298fe49db619a21694a1ea41 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 29 Mar 2020 18:05:07 +0200 Subject: [PATCH 057/377] fix CPU destination display --- src/debugger/gui/CpuWidget.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/debugger/gui/CpuWidget.cxx b/src/debugger/gui/CpuWidget.cxx index 87aba7d34..babdb8e08 100644 --- a/src/debugger/gui/CpuWidget.cxx +++ b/src/debugger/gui/CpuWidget.cxx @@ -327,7 +327,7 @@ void CpuWidget::loadConfig() state.srcY != oldstate.srcY); const string& dest = state.dest < 0 ? "" : cart.getLabel(state.dest, false); - myCpuDataDest->setText((srcY != EmptyString ? dest : Common::Base::toString(state.dest)), + myCpuDataDest->setText((dest != EmptyString ? dest : Common::Base::toString(state.dest)), state.dest != oldstate.dest); // Update the PS register booleans From 30fec1ee896a3924ece7019c0d73fa434ce9152b Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 29 Mar 2020 18:36:26 +0200 Subject: [PATCH 058/377] add some more DEBUGGER_SUPPORT defines --- src/emucore/Cart4A50.cxx | 2 ++ src/emucore/Cart4A50.hxx | 3 ++- src/emucore/CartAR.cxx | 2 ++ src/emucore/CartAR.hxx | 2 ++ src/emucore/System.hxx | 2 ++ 5 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/emucore/Cart4A50.cxx b/src/emucore/Cart4A50.cxx index fd05804d4..f8f144667 100644 --- a/src/emucore/Cart4A50.cxx +++ b/src/emucore/Cart4A50.cxx @@ -181,6 +181,7 @@ bool Cartridge4A50::poke(uInt16 address, uInt8 value) return myBankChanged; } +#ifdef DEBUGGER_SUPPORT // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Device::AccessFlags Cartridge4A50::getAccessFlags(uInt16 address) const { @@ -243,6 +244,7 @@ void Cartridge4A50::setAccessFlags(uInt16 address, Device::AccessFlags flags) myCodeAccessBase[(address & 0xff) + 0x1ff00] |= flags; } } +#endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge4A50::checkBankSwitch(uInt16 address, uInt8 value) diff --git a/src/emucore/Cart4A50.hxx b/src/emucore/Cart4A50.hxx index d55ec8d2f..e68bb8f4a 100644 --- a/src/emucore/Cart4A50.hxx +++ b/src/emucore/Cart4A50.hxx @@ -153,6 +153,7 @@ class Cartridge4A50 : public Cartridge bool poke(uInt16 address, uInt8 value) override; private: + #ifdef DEBUGGER_SUPPORT /** Query the given address type for the associated access flags. @@ -166,7 +167,7 @@ class Cartridge4A50 : public Cartridge @param flags A bitfield of AccessType directives for the given address */ void setAccessFlags(uInt16 address, Device::AccessFlags flags) override; - + #endif /** Check all possible hotspots */ diff --git a/src/emucore/CartAR.cxx b/src/emucore/CartAR.cxx index 42d12c0fd..e5755d6dd 100644 --- a/src/emucore/CartAR.cxx +++ b/src/emucore/CartAR.cxx @@ -190,6 +190,7 @@ bool CartridgeAR::poke(uInt16 addr, uInt8) return modified; } +#ifdef DEBUGGER_SUPPORT // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Device::AccessFlags CartridgeAR::getAccessFlags(uInt16 address) const { @@ -203,6 +204,7 @@ void CartridgeAR::setAccessFlags(uInt16 address, Device::AccessFlags flags) myCodeAccessBase[(address & 0x07FF) + myImageOffset[(address & 0x0800) ? 1 : 0]] |= flags; } +#endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeAR::bankConfiguration(uInt8 configuration) diff --git a/src/emucore/CartAR.hxx b/src/emucore/CartAR.hxx index 877817c1b..6fda35f38 100644 --- a/src/emucore/CartAR.hxx +++ b/src/emucore/CartAR.hxx @@ -159,6 +159,7 @@ class CartridgeAR : public Cartridge bool poke(uInt16 address, uInt8 value) override; private: + #ifdef DEBUGGER_SUPPORT /** Query the given address type for the associated access flags. @@ -172,6 +173,7 @@ class CartridgeAR : public Cartridge @param flags A bitfield of AccessType directives for the given address */ void setAccessFlags(uInt16 address, Device::AccessFlags flags) override; + #endif // Handle a change to the bank configuration bool bankConfiguration(uInt8 configuration); diff --git a/src/emucore/System.hxx b/src/emucore/System.hxx index 2e7c158a9..1262b6ad3 100644 --- a/src/emucore/System.hxx +++ b/src/emucore/System.hxx @@ -231,6 +231,7 @@ class System : public Serializable void lockDataBus() { myDataBusLocked = true; } void unlockDataBus() { myDataBusLocked = false; } + #ifdef DEBUGGER_SUPPORT /** Access and modify the access type flags for the given address. Note that while any flag can be used, the disassembly @@ -238,6 +239,7 @@ class System : public Serializable */ Device::AccessFlags getAccessFlags(uInt16 address) const; void setAccessFlags(uInt16 address, Device::AccessFlags flags); + #endif public: /** From b7e1d7dd1780625c7aa989efa7eb973f46778a33 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 29 Mar 2020 19:30:09 +0200 Subject: [PATCH 059/377] fix compiler error without debugger support create VS configuration (without debugger support) --- src/emucore/System.cxx | 8 +- src/windows/Stella.sln | 16 +- src/windows/Stella.vcxproj | 968 ++++++++++++++++++++++++++++++------- 3 files changed, 798 insertions(+), 194 deletions(-) diff --git a/src/emucore/System.cxx b/src/emucore/System.cxx index 7bf3551ef..2fa33a201 100644 --- a/src/emucore/System.cxx +++ b/src/emucore/System.cxx @@ -159,33 +159,29 @@ void System::poke(uInt16 addr, uInt8 value, Device::AccessFlags flags) myDataBusState = value; } +#ifdef DEBUGGER_SUPPORT // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Device::AccessFlags System::getAccessFlags(uInt16 addr) const { -#ifdef DEBUGGER_SUPPORT const PageAccess& access = getPageAccess(addr); if(access.codeAccessBase) return *(access.codeAccessBase + (addr & PAGE_MASK)); else return access.device->getAccessFlags(addr); -#else - return 0; -#endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void System::setAccessFlags(uInt16 addr, Device::AccessFlags flags) { -#ifdef DEBUGGER_SUPPORT const PageAccess& access = getPageAccess(addr); if(access.codeAccessBase) *(access.codeAccessBase + (addr & PAGE_MASK)) |= flags; else access.device->setAccessFlags(addr, flags); -#endif } +#endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool System::save(Serializer& out) const diff --git a/src/windows/Stella.sln b/src/windows/Stella.sln index fb70ffeaf..3aae8e551 100755 --- a/src/windows/Stella.sln +++ b/src/windows/Stella.sln @@ -1,16 +1,15 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.168 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29613.14 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Stella", "Stella.vcxproj", "{D7FCEC7F-33E1-49DD-A4B0-D5FC222250AD}" EndProject Global - GlobalSection(Performance) = preSolution - HasPerformanceSessions = true - EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 + Debug-NoDebugger|Win32 = Debug-NoDebugger|Win32 + Debug-NoDebugger|x64 = Debug-NoDebugger|x64 Profile|Win32 = Profile|Win32 Profile|x64 = Profile|x64 Release|Win32 = Release|Win32 @@ -21,6 +20,10 @@ Global {D7FCEC7F-33E1-49DD-A4B0-D5FC222250AD}.Debug|Win32.Build.0 = Debug|Win32 {D7FCEC7F-33E1-49DD-A4B0-D5FC222250AD}.Debug|x64.ActiveCfg = Debug|x64 {D7FCEC7F-33E1-49DD-A4B0-D5FC222250AD}.Debug|x64.Build.0 = Debug|x64 + {D7FCEC7F-33E1-49DD-A4B0-D5FC222250AD}.Debug-NoDebugger|Win32.ActiveCfg = Debug-NoDebugger|Win32 + {D7FCEC7F-33E1-49DD-A4B0-D5FC222250AD}.Debug-NoDebugger|Win32.Build.0 = Debug-NoDebugger|Win32 + {D7FCEC7F-33E1-49DD-A4B0-D5FC222250AD}.Debug-NoDebugger|x64.ActiveCfg = Debug-NoDebugger|x64 + {D7FCEC7F-33E1-49DD-A4B0-D5FC222250AD}.Debug-NoDebugger|x64.Build.0 = Debug-NoDebugger|x64 {D7FCEC7F-33E1-49DD-A4B0-D5FC222250AD}.Profile|Win32.ActiveCfg = Profile|Win32 {D7FCEC7F-33E1-49DD-A4B0-D5FC222250AD}.Profile|Win32.Build.0 = Profile|Win32 {D7FCEC7F-33E1-49DD-A4B0-D5FC222250AD}.Profile|x64.ActiveCfg = Profile|x64 @@ -42,4 +45,7 @@ Global GlobalSection(Performance) = preSolution HasPerformanceSessions = true EndGlobalSection + GlobalSection(Performance) = preSolution + HasPerformanceSessions = true + EndGlobalSection EndGlobal diff --git a/src/windows/Stella.vcxproj b/src/windows/Stella.vcxproj index e15336141..9aa49cb84 100644 --- a/src/windows/Stella.vcxproj +++ b/src/windows/Stella.vcxproj @@ -1,6 +1,14 @@  + + Debug-NoDebugger + Win32 + + + Debug-NoDebugger + x64 + Debug Win32 @@ -48,6 +56,11 @@ MultiByte v141_xp + + Application + MultiByte + v141_xp + Application MultiByte @@ -63,6 +76,11 @@ MultiByte v141_xp + + Application + MultiByte + v141_xp + false @@ -81,6 +99,10 @@ + + + + @@ -93,15 +115,25 @@ + + + + <_ProjectFileVersion>10.0.30319.1 $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ true + true $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ true + true $(Platform)\$(Configuration)\ Release\ $(Platform)\$(Configuration)\ @@ -111,11 +143,17 @@ $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ AllRules.ruleset + AllRules.ruleset + + AllRules.ruleset + AllRules.ruleset + + AllRules.ruleset AllRules.ruleset @@ -133,6 +171,10 @@ $(ProjectDir)\SDL\lib\x86;$(LibraryPath) $(ProjectDir)\SDL\include;$(IncludePath) + + $(ProjectDir)\SDL\lib\x86;$(LibraryPath) + $(ProjectDir)\SDL\include;$(IncludePath) + $(ProjectDir)\SDL\lib\x86;$(LibraryPath) $(ProjectDir)\SDL\include;$(IncludePath) @@ -145,6 +187,10 @@ $(ProjectDir)\SDL\lib\x64;$(LibraryPath) $(ProjectDir)\SDL\include;$(IncludePath) + + $(ProjectDir)\SDL\lib\x64;$(LibraryPath) + $(ProjectDir)\SDL\include;$(IncludePath) + $(ProjectDir)\SDL\lib\x64;$(LibraryPath) $(ProjectDir)\SDL\include;$(IncludePath) @@ -187,6 +233,40 @@ Default + + + Disabled + ..\yacc;..\emucore;..\emucore\tia;..\emucore\tia\frame-manager;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\windows;..\cheat;..\zlib;..\libpng;%(AdditionalIncludeDirectories) + BSPF_WINDOWS;WIN32;NOMINMAX;DEBUG_BUILD;SDL_SUPPORT;GUI_SUPPORT;PNG_SUPPORT;ZIP_SUPPORT;JOYSTICK_SUPPORT;DEBUGGER_SUPPORT;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDLL + + + Level4 + EditAndContinue + $(IntDir)obj\\windows\%(RelativeDir) + StreamingSIMDExtensions + stdcpp17 + true + 4100;4127;4146;4244;%(DisableSpecificWarnings) + CompileAsCpp + NoListing + $(IntDir)asm\windows\%(RelativeDir) + + + SDL2.lib;SDL2main.lib;SDL2main.lib;%(AdditionalDependencies) + $(OutDir)Stella.exe + true + $(OutDir)Stella.pdb + Console + false + + + MachineX86 + Default + + X64 @@ -223,6 +303,42 @@ Default + + + X64 + + + Disabled + ..\yacc;..\emucore;..\emucore\tia;..\emucore\tia\frame-manager;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\windows;..\cheat;..\zlib;..\libpng;%(AdditionalIncludeDirectories) + BSPF_WINDOWS;WIN32;NOMINMAX;DEBUG_BUILD;SDL_SUPPORT;GUI_SUPPORT;PNG_SUPPORT;ZIP_SUPPORT;JOYSTICK_SUPPORT;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDLL + + + Level4 + ProgramDatabase + $(IntDir)obj\\windows\%(RelativeDir) + stdcpp17 + true + 4100;4127;4146;4244;%(DisableSpecificWarnings) + CompileAsCpp + NoListing + $(IntDir)asm\windows\%(RelativeDir) + + + SDL2.lib;SDL2main.lib;SDL2main.lib;%(AdditionalDependencies) + $(OutDir)Stella.exe + true + $(OutDir)Stella.pdb + Console + false + + + MachineX64 + Default + + true @@ -403,70 +519,201 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + @@ -591,31 +838,78 @@ - - - - - - - - - - - - - - - - - - - - - - - - - + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + @@ -653,421 +947,541 @@ CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC Level2 + Level2 Level2 Level2 Level2 + Level2 Level2 Level2 CompileAsC + CompileAsC CompileAsC CompileAsC CompileAsC + CompileAsC CompileAsC CompileAsC @@ -1118,73 +1532,207 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + @@ -1339,33 +1887,87 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + From 8c635a6f91859c7859a71e714cd239bee9e3f41f Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 30 Mar 2020 09:22:45 +0200 Subject: [PATCH 060/377] rename code access into ROM access to better reflect the usage --- src/debugger/DiStella.cxx | 2 +- src/emucore/Cart.cxx | 16 ++++++++-------- src/emucore/Cart.hxx | 16 +++++++++------- src/emucore/Cart0840.cxx | 4 ++-- src/emucore/Cart2K.cxx | 4 ++-- src/emucore/Cart3E.cxx | 10 +++++----- src/emucore/Cart3EPlus.cxx | 6 +++--- src/emucore/Cart3F.cxx | 6 +++--- src/emucore/Cart4A50.cxx | 32 ++++++++++++++++---------------- src/emucore/Cart4K.cxx | 4 ++-- src/emucore/Cart4KSC.cxx | 8 ++++---- src/emucore/CartAR.cxx | 8 ++++---- src/emucore/CartBF.cxx | 6 +++--- src/emucore/CartBFSC.cxx | 10 +++++----- src/emucore/CartBUS.cxx | 4 ++-- src/emucore/CartCDF.cxx | 4 ++-- src/emucore/CartCM.cxx | 8 ++++---- src/emucore/CartCTY.cxx | 4 ++-- src/emucore/CartCV.cxx | 8 ++++---- src/emucore/CartCVPlus.cxx | 10 +++++----- src/emucore/CartDASH.cxx | 6 +++--- src/emucore/CartDF.cxx | 6 +++--- src/emucore/CartDFSC.cxx | 10 +++++----- src/emucore/CartDPC.cxx | 6 +++--- src/emucore/CartDPCPlus.cxx | 4 ++-- src/emucore/CartE0.cxx | 12 ++++++------ src/emucore/CartEF.cxx | 6 +++--- src/emucore/CartEFSC.cxx | 10 +++++----- src/emucore/CartF0.cxx | 6 +++--- src/emucore/CartF4.cxx | 6 +++--- src/emucore/CartF4SC.cxx | 10 +++++----- src/emucore/CartF6.cxx | 6 +++--- src/emucore/CartF6SC.cxx | 10 +++++----- src/emucore/CartF8.cxx | 6 +++--- src/emucore/CartF8SC.cxx | 10 +++++----- src/emucore/CartFA.cxx | 10 +++++----- src/emucore/CartFA2.cxx | 10 +++++----- src/emucore/CartFC.cxx | 6 +++--- src/emucore/CartFE.cxx | 2 +- src/emucore/CartMDM.cxx | 4 ++-- src/emucore/CartMNetwork.cxx | 6 +++--- src/emucore/CartSB.cxx | 4 ++-- src/emucore/CartUA.cxx | 4 ++-- src/emucore/CartWD.cxx | 14 +++++++------- src/emucore/CartX07.cxx | 4 ++-- src/emucore/System.cxx | 16 ++++++++-------- src/emucore/System.hxx | 10 +++++++--- 47 files changed, 190 insertions(+), 184 deletions(-) diff --git a/src/debugger/DiStella.cxx b/src/debugger/DiStella.cxx index 547a75933..2aa304ac6 100644 --- a/src/debugger/DiStella.cxx +++ b/src/debugger/DiStella.cxx @@ -657,7 +657,7 @@ void DiStella::disasmPass1(CartDebug::AddressList& debuggerAddresses) // Note that this is a 'best-effort' approach, since // Distella will normally keep going until the end of the // range or branch is encountered - // However, addresses *specifically* marked as DATA/GFX/PGFX + // However, addresses *specifically* marked as DATA/GFX/PGFX/COL/PCOL/BCOL/AUD // in the emulation core indicate that the CODE range has finished // Therefore, we stop at the first such address encountered for (uInt32 k = pcBeg; k <= myPCEnd; ++k) { diff --git a/src/emucore/Cart.cxx b/src/emucore/Cart.cxx index ec7cea379..c5c13e34c 100644 --- a/src/emucore/Cart.cxx +++ b/src/emucore/Cart.cxx @@ -38,7 +38,7 @@ Cartridge::Cartridge(const Settings& settings, const string& md5) for(uInt32 i = 0; i < 256; ++i) myRWPRandomValues[i] = rand.next(); - myRAMAccesses.reserve(5); + myRamReadAccesses.reserve(5); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -86,7 +86,7 @@ uInt8 Cartridge::peekRAM(uInt8& dest, uInt16 address) if(!bankLocked() && !mySystem->autodetectMode()) { // Record access here; final determination will happen in ::pokeRAM() - myRAMAccesses.push_back(address); + myRamReadAccesses.push_back(address); dest = value; } #else @@ -100,11 +100,11 @@ uInt8 Cartridge::peekRAM(uInt8& dest, uInt16 address) void Cartridge::pokeRAM(uInt8& dest, uInt16 address, uInt8 value) { #ifdef DEBUGGER_SUPPORT - for(auto i = myRAMAccesses.begin(); i != myRAMAccesses.end(); ++i) + for(auto i = myRamReadAccesses.begin(); i != myRamReadAccesses.end(); ++i) { if(*i == address) { - myRAMAccesses.erase(i); + myRamReadAccesses.erase(i); break; } } @@ -113,13 +113,13 @@ void Cartridge::pokeRAM(uInt8& dest, uInt16 address, uInt8 value) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge::createCodeAccessBase(size_t size) +void Cartridge::createRomAccessBase(size_t size) { #ifdef DEBUGGER_SUPPORT - myCodeAccessBase = make_unique(size); - std::fill_n(myCodeAccessBase.get(), size, Device::ROW); + myRomAccessBase = make_unique(size); + std::fill_n(myRomAccessBase.get(), size, Device::ROW); #else - myCodeAccessBase = nullptr; + myRomAccessBase = nullptr; #endif } diff --git a/src/emucore/Cart.hxx b/src/emucore/Cart.hxx index 4b9cda533..8a5124219 100644 --- a/src/emucore/Cart.hxx +++ b/src/emucore/Cart.hxx @@ -113,7 +113,7 @@ class Cartridge : public Device Clears information about all accesses to cart RAM. */ void clearAllRAMAccesses() { - myRAMAccesses.clear(); + myRamReadAccesses.clear(); myRamWriteAccess = 0; } @@ -125,7 +125,7 @@ class Cartridge : public Device @return Address of illegal access if one occurred, else 0 */ uInt16 getIllegalRAMReadAccess() const { - return myRAMAccesses.size() > 0 ? myRAMAccesses[0] : 0; + return myRamReadAccesses.size() > 0 ? myRamReadAccesses[0] : 0; } /** @@ -274,7 +274,7 @@ class Cartridge : public Device @param size The size of the code-access array to create */ - void createCodeAccessBase(size_t size); + void createRomAccessBase(size_t size); /** Fill the given RAM array with (possibly random) data. @@ -322,8 +322,8 @@ class Cartridge : public Device bool myBankChanged{true}; // The array containing information about every byte of ROM indicating - // whether it is used as code. - std::unique_ptr myCodeAccessBase; + // whether it is used as code, data, graphics etc. + std::unique_ptr myRomAccessBase; // Contains address of illegal RAM write access or 0 uInt16 myRamWriteAccess{0}; @@ -348,8 +348,10 @@ class Cartridge : public Device // Used when we want the 'Cartridge.StartBank' ROM property StartBankFromPropsFunc myStartBankFromPropsFunc; - // Contains - ShortArray myRAMAccesses; + // Used to answer whether an access in the last instruction cycle + // generated an illegal read RAM access. Contains address of illegal + // access. + ShortArray myRamReadAccesses; // Following constructors and assignment operators not supported Cartridge() = delete; diff --git a/src/emucore/Cart0840.cxx b/src/emucore/Cart0840.cxx index 22e6a1cff..21e0f35fd 100644 --- a/src/emucore/Cart0840.cxx +++ b/src/emucore/Cart0840.cxx @@ -25,7 +25,7 @@ Cartridge0840::Cartridge0840(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createCodeAccessBase(myImage.size()); + createRomAccessBase(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -137,7 +137,7 @@ bool Cartridge0840::bank(uInt16 bank) for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/Cart2K.cxx b/src/emucore/Cart2K.cxx index bbad871af..5a6ffec5d 100644 --- a/src/emucore/Cart2K.cxx +++ b/src/emucore/Cart2K.cxx @@ -51,7 +51,7 @@ Cartridge2K::Cartridge2K(const ByteBuffer& image, size_t size, mySize = System::PAGE_SIZE; } - createCodeAccessBase(mySize); + createRomAccessBase(mySize); // Set mask for accessing the image buffer // This is guaranteed to work, as mySize is a power of two @@ -76,7 +76,7 @@ void Cartridge2K::install(System& system) for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[addr & myMask]; - access.codeAccessBase = &myCodeAccessBase[addr & myMask]; + access.romAccessBase = &myRomAccessBase[addr & myMask]; mySystem->setPageAccess(addr, access); } } diff --git a/src/emucore/Cart3E.cxx b/src/emucore/Cart3E.cxx index 7844fc7e3..7df89d58c 100644 --- a/src/emucore/Cart3E.cxx +++ b/src/emucore/Cart3E.cxx @@ -30,7 +30,7 @@ Cartridge3E::Cartridge3E(const ByteBuffer& image, size_t size, // Copy the ROM image into my buffer std::copy_n(image.get(), mySize, myImage.get()); - createCodeAccessBase(mySize + myRAM.size()); + createRomAccessBase(mySize + myRAM.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -59,7 +59,7 @@ void Cartridge3E::install(System& system) for(uInt16 addr = 0x1800; addr < 0x2000; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[(mySize - 2048) + (addr & 0x07FF)]; - access.codeAccessBase = &myCodeAccessBase[(mySize - 2048) + (addr & 0x07FF)]; + access.romAccessBase = &myRomAccessBase[(mySize - 2048) + (addr & 0x07FF)]; mySystem->setPageAccess(addr, access); } @@ -158,7 +158,7 @@ bool Cartridge3E::bank(uInt16 bank) for(uInt16 addr = 0x1000; addr < 0x1800; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[offset + (addr & 0x07FF)]; - access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x07FF)]; + access.romAccessBase = &myRomAccessBase[offset + (addr & 0x07FF)]; mySystem->setPageAccess(addr, access); } } @@ -177,7 +177,7 @@ bool Cartridge3E::bank(uInt16 bank) for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE) { access.directPeekBase = &myRAM[offset + (addr & 0x03FF)]; - access.codeAccessBase = &myCodeAccessBase[mySize + offset + (addr & 0x03FF)]; + access.romAccessBase = &myRomAccessBase[mySize + offset + (addr & 0x03FF)]; mySystem->setPageAccess(addr, access); } @@ -189,7 +189,7 @@ bool Cartridge3E::bank(uInt16 bank) // check if RWP happens for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[mySize + offset + (addr & 0x03FF)]; + access.romAccessBase = &myRomAccessBase[mySize + offset + (addr & 0x03FF)]; mySystem->setPageAccess(addr, access); } } diff --git a/src/emucore/Cart3EPlus.cxx b/src/emucore/Cart3EPlus.cxx index 139cda4b7..1ca18f7d9 100644 --- a/src/emucore/Cart3EPlus.cxx +++ b/src/emucore/Cart3EPlus.cxx @@ -30,7 +30,7 @@ Cartridge3EPlus::Cartridge3EPlus(const ByteBuffer& image, size_t size, // Copy the ROM image into my buffer std::copy_n(image.get(), mySize, myImage.get()); - createCodeAccessBase(mySize + myRAM.size()); + createRomAccessBase(mySize + myRAM.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -214,7 +214,7 @@ void Cartridge3EPlus::bankRAMSlot(uInt16 bank) if(!upper) access.directPeekBase = &myRAM[startCurrentBank + (addr & (RAM_BANK_SIZE - 1))]; - access.codeAccessBase = &myCodeAccessBase[mySize + startCurrentBank + (addr & (RAM_BANK_SIZE - 1))]; + access.romAccessBase = &myRomAccessBase[mySize + startCurrentBank + (addr & (RAM_BANK_SIZE - 1))]; mySystem->setPageAccess(addr, access); } } @@ -254,7 +254,7 @@ void Cartridge3EPlus::bankROMSlot(uInt16 bank) for(uInt16 addr = start; addr <= end; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[startCurrentBank + (addr & (ROM_BANK_SIZE - 1))]; - access.codeAccessBase = &myCodeAccessBase[startCurrentBank + (addr & (ROM_BANK_SIZE - 1))]; + access.romAccessBase = &myRomAccessBase[startCurrentBank + (addr & (ROM_BANK_SIZE - 1))]; mySystem->setPageAccess(addr, access); } } diff --git a/src/emucore/Cart3F.cxx b/src/emucore/Cart3F.cxx index 8b59d77ba..8be902554 100644 --- a/src/emucore/Cart3F.cxx +++ b/src/emucore/Cart3F.cxx @@ -30,7 +30,7 @@ Cartridge3F::Cartridge3F(const ByteBuffer& image, size_t size, // Copy the ROM image into my buffer std::copy_n(image.get(), mySize, myImage.get()); - createCodeAccessBase(mySize); + createRomAccessBase(mySize); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -57,7 +57,7 @@ void Cartridge3F::install(System& system) for(uInt16 addr = 0x1800; addr < 0x2000; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[(mySize - 2048) + (addr & 0x07FF)]; - access.codeAccessBase = &myCodeAccessBase[(mySize - 2048) + (addr & 0x07FF)]; + access.romAccessBase = &myRomAccessBase[(mySize - 2048) + (addr & 0x07FF)]; mySystem->setPageAccess(addr, access); } @@ -117,7 +117,7 @@ bool Cartridge3F::bank(uInt16 bank) for(uInt16 addr = 0x1000; addr < 0x1800; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[offset + (addr & 0x07FF)]; - access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x07FF)]; + access.romAccessBase = &myRomAccessBase[offset + (addr & 0x07FF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/Cart4A50.cxx b/src/emucore/Cart4A50.cxx index f8f144667..373684481 100644 --- a/src/emucore/Cart4A50.cxx +++ b/src/emucore/Cart4A50.cxx @@ -34,14 +34,14 @@ Cartridge4A50::Cartridge4A50(const ByteBuffer& image, size_t size, for(uInt32 slice = 0; slice < 128_KB / size; ++slice) std::copy_n(image.get(), size, myImage.begin() + (slice*size)); - // We use System::PageAccess.codeAccessBase, but don't allow its use + // We use System::PageAccess.romAccessBase, but don't allow its use // through a pointer, since the address space of 4A50 carts can change // at the instruction level, and PageAccess is normally defined at an // interval of 64 bytes // // Instead, access will be through the getAccessFlags and setAccessFlags // methods below - createCodeAccessBase(myImage.size() + myRAM.size()); + createRomAccessBase(myImage.size() + myRAM.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -188,28 +188,28 @@ Device::AccessFlags Cartridge4A50::getAccessFlags(uInt16 address) const if((address & 0x1800) == 0x1000) // 2K region from 0x1000 - 0x17ff { if(myIsRomLow) - return myCodeAccessBase[(address & 0x7ff) + mySliceLow]; + return myRomAccessBase[(address & 0x7ff) + mySliceLow]; else - return myCodeAccessBase[131072 + (address & 0x7ff) + mySliceLow]; + return myRomAccessBase[131072 + (address & 0x7ff) + mySliceLow]; } else if(((address & 0x1fff) >= 0x1800) && // 1.5K region from 0x1800 - 0x1dff ((address & 0x1fff) <= 0x1dff)) { if(myIsRomMiddle) - return myCodeAccessBase[(address & 0x7ff) + mySliceMiddle + 0x10000]; + return myRomAccessBase[(address & 0x7ff) + mySliceMiddle + 0x10000]; else - return myCodeAccessBase[131072 + (address & 0x7ff) + mySliceMiddle]; + return myRomAccessBase[131072 + (address & 0x7ff) + mySliceMiddle]; } else if((address & 0x1f00) == 0x1e00) // 256B region from 0x1e00 - 0x1eff { if(myIsRomHigh) - return myCodeAccessBase[(address & 0xff) + mySliceHigh + 0x10000]; + return myRomAccessBase[(address & 0xff) + mySliceHigh + 0x10000]; else - return myCodeAccessBase[131072 + (address & 0xff) + mySliceHigh]; + return myRomAccessBase[131072 + (address & 0xff) + mySliceHigh]; } else if((address & 0x1f00) == 0x1f00) // 256B region from 0x1f00 - 0x1fff { - return myCodeAccessBase[(address & 0xff) + 0x1ff00]; + return myRomAccessBase[(address & 0xff) + 0x1ff00]; } return 0; } @@ -220,28 +220,28 @@ void Cartridge4A50::setAccessFlags(uInt16 address, Device::AccessFlags flags) if((address & 0x1800) == 0x1000) // 2K region from 0x1000 - 0x17ff { if(myIsRomLow) - myCodeAccessBase[(address & 0x7ff) + mySliceLow] |= flags; + myRomAccessBase[(address & 0x7ff) + mySliceLow] |= flags; else - myCodeAccessBase[131072 + (address & 0x7ff) + mySliceLow] |= flags; + myRomAccessBase[131072 + (address & 0x7ff) + mySliceLow] |= flags; } else if(((address & 0x1fff) >= 0x1800) && // 1.5K region from 0x1800 - 0x1dff ((address & 0x1fff) <= 0x1dff)) { if(myIsRomMiddle) - myCodeAccessBase[(address & 0x7ff) + mySliceMiddle + 0x10000] |= flags; + myRomAccessBase[(address & 0x7ff) + mySliceMiddle + 0x10000] |= flags; else - myCodeAccessBase[131072 + (address & 0x7ff) + mySliceMiddle] |= flags; + myRomAccessBase[131072 + (address & 0x7ff) + mySliceMiddle] |= flags; } else if((address & 0x1f00) == 0x1e00) // 256B region from 0x1e00 - 0x1eff { if(myIsRomHigh) - myCodeAccessBase[(address & 0xff) + mySliceHigh + 0x10000] |= flags; + myRomAccessBase[(address & 0xff) + mySliceHigh + 0x10000] |= flags; else - myCodeAccessBase[131072 + (address & 0xff) + mySliceHigh] |= flags; + myRomAccessBase[131072 + (address & 0xff) + mySliceHigh] |= flags; } else if((address & 0x1f00) == 0x1f00) // 256B region from 0x1f00 - 0x1fff { - myCodeAccessBase[(address & 0xff) + 0x1ff00] |= flags; + myRomAccessBase[(address & 0xff) + 0x1ff00] |= flags; } } #endif diff --git a/src/emucore/Cart4K.cxx b/src/emucore/Cart4K.cxx index 8c924f720..763bc35f0 100644 --- a/src/emucore/Cart4K.cxx +++ b/src/emucore/Cart4K.cxx @@ -25,7 +25,7 @@ Cartridge4K::Cartridge4K(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createCodeAccessBase(myImage.size()); + createRomAccessBase(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -46,7 +46,7 @@ void Cartridge4K::install(System& system) for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[addr & 0x0FFF]; - access.codeAccessBase = &myCodeAccessBase[addr & 0x0FFF]; + access.romAccessBase = &myRomAccessBase[addr & 0x0FFF]; mySystem->setPageAccess(addr, access); } } diff --git a/src/emucore/Cart4KSC.cxx b/src/emucore/Cart4KSC.cxx index fa36e7b0f..e65955735 100644 --- a/src/emucore/Cart4KSC.cxx +++ b/src/emucore/Cart4KSC.cxx @@ -25,7 +25,7 @@ Cartridge4KSC::Cartridge4KSC(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createCodeAccessBase(myImage.size()); + createRomAccessBase(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -49,7 +49,7 @@ void Cartridge4KSC::install(System& system) access.type = System::PageAccessType::WRITE; for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[addr & 0x007F]; + access.romAccessBase = &myRomAccessBase[addr & 0x007F]; mySystem->setPageAccess(addr, access); } @@ -58,7 +58,7 @@ void Cartridge4KSC::install(System& system) for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE) { access.directPeekBase = &myRAM[addr & 0x007F]; - access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)]; + access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)]; mySystem->setPageAccess(addr, access); } @@ -66,7 +66,7 @@ void Cartridge4KSC::install(System& system) for(uInt16 addr = 0x1100; addr < 0x2000; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[addr & 0x0FFF]; - access.codeAccessBase = &myCodeAccessBase[addr & 0x0FFF]; + access.romAccessBase = &myRomAccessBase[addr & 0x0FFF]; mySystem->setPageAccess(addr, access); } } diff --git a/src/emucore/CartAR.cxx b/src/emucore/CartAR.cxx index e5755d6dd..f4edb41ba 100644 --- a/src/emucore/CartAR.cxx +++ b/src/emucore/CartAR.cxx @@ -35,13 +35,13 @@ CartridgeAR::CartridgeAR(const ByteBuffer& image, size_t size, std::copy_n(ourDefaultHeader.data(), ourDefaultHeader.size(), myLoadImages.get()+myImage.size()); - // We use System::PageAccess.codeAccessBase, but don't allow its use + // We use System::PageAccess.romAccessBase, but don't allow its use // through a pointer, since the AR scheme doesn't support bankswitching // in the normal sense // // Instead, access will be through the getAccessFlags and setAccessFlags // methods below - createCodeAccessBase(mySize); + createRomAccessBase(mySize); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -194,14 +194,14 @@ bool CartridgeAR::poke(uInt16 addr, uInt8) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Device::AccessFlags CartridgeAR::getAccessFlags(uInt16 address) const { - return myCodeAccessBase[(address & 0x07FF) + + return myRomAccessBase[(address & 0x07FF) + myImageOffset[(address & 0x0800) ? 1 : 0]]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeAR::setAccessFlags(uInt16 address, Device::AccessFlags flags) { - myCodeAccessBase[(address & 0x07FF) + + myRomAccessBase[(address & 0x07FF) + myImageOffset[(address & 0x0800) ? 1 : 0]] |= flags; } #endif diff --git a/src/emucore/CartBF.cxx b/src/emucore/CartBF.cxx index b1f780699..df773d805 100644 --- a/src/emucore/CartBF.cxx +++ b/src/emucore/CartBF.cxx @@ -25,7 +25,7 @@ CartridgeBF::CartridgeBF(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createCodeAccessBase(myImage.size()); + createRomAccessBase(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -88,7 +88,7 @@ bool CartridgeBF::bank(uInt16 bank) for(uInt16 addr = (0x1F80 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } @@ -97,7 +97,7 @@ bool CartridgeBF::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartBFSC.cxx b/src/emucore/CartBFSC.cxx index 00b5efc32..fdfac6f95 100644 --- a/src/emucore/CartBFSC.cxx +++ b/src/emucore/CartBFSC.cxx @@ -25,7 +25,7 @@ CartridgeBFSC::CartridgeBFSC(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createCodeAccessBase(myImage.size()); + createRomAccessBase(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -51,7 +51,7 @@ void CartridgeBFSC::install(System& system) access.type = System::PageAccessType::WRITE; for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[addr & 0x007F]; + access.romAccessBase = &myRomAccessBase[addr & 0x007F]; mySystem->setPageAccess(addr, access); } @@ -60,7 +60,7 @@ void CartridgeBFSC::install(System& system) for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE) { access.directPeekBase = &myRAM[addr & 0x007F]; - access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)]; + access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)]; mySystem->setPageAccess(addr, access); } @@ -127,7 +127,7 @@ bool CartridgeBFSC::bank(uInt16 bank) for(uInt16 addr = (0x1F80 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } @@ -136,7 +136,7 @@ bool CartridgeBFSC::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartBUS.cxx b/src/emucore/CartBUS.cxx index c34593e73..1dc991563 100644 --- a/src/emucore/CartBUS.cxx +++ b/src/emucore/CartBUS.cxx @@ -49,7 +49,7 @@ CartridgeBUS::CartridgeBUS(const ByteBuffer& image, size_t size, std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); // Even though the ROM is 32K, only 28K is accessible to the 6507 - createCodeAccessBase(28_KB); + createRomAccessBase(28_KB); // Pointer to the program ROM (28K @ 0 byte offset) // which starts after the 2K BUS Driver and 2K C Code @@ -442,7 +442,7 @@ bool CartridgeBUS::bank(uInt16 bank) // Map Program ROM image into the system for(uInt16 addr = 0x1040; addr < 0x2000; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartCDF.cxx b/src/emucore/CartCDF.cxx index 052a1b523..48f3d3d0f 100644 --- a/src/emucore/CartCDF.cxx +++ b/src/emucore/CartCDF.cxx @@ -65,7 +65,7 @@ CartridgeCDF::CartridgeCDF(const ByteBuffer& image, size_t size, std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); // even though the ROM is 32K, only 28K is accessible to the 6507 - createCodeAccessBase(28_KB); + createRomAccessBase(28_KB); // Pointer to the program ROM (28K @ 0 byte offset) // which starts after the 2K CDF Driver and 2K C Code @@ -415,7 +415,7 @@ bool CartridgeCDF::bank(uInt16 bank) // Map Program ROM image into the system for(uInt16 addr = 0x1040; addr < 0x2000; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartCM.cxx b/src/emucore/CartCM.cxx index c460e72ff..6bead1b33 100644 --- a/src/emucore/CartCM.cxx +++ b/src/emucore/CartCM.cxx @@ -27,7 +27,7 @@ CartridgeCM::CartridgeCM(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createCodeAccessBase(myImage.size()); + createRomAccessBase(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -119,7 +119,7 @@ bool CartridgeCM::bank(uInt16 bank) for(uInt16 addr = 0x1000; addr < 0x1800; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } @@ -131,12 +131,12 @@ bool CartridgeCM::bank(uInt16 bank) if(mySWCHA & 0x10) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; } else { access.directPeekBase = &myRAM[addr & 0x7FF]; - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x07FF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x07FF)]; } if((mySWCHA & 0x30) == 0x20) diff --git a/src/emucore/CartCTY.cxx b/src/emucore/CartCTY.cxx index 22472dc0f..40cae5597 100644 --- a/src/emucore/CartCTY.cxx +++ b/src/emucore/CartCTY.cxx @@ -28,7 +28,7 @@ CartridgeCTY::CartridgeCTY(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createCodeAccessBase(myImage.size()); + createRomAccessBase(myImage.size()); // Default to no tune data in case user is utilizing an old ROM myTuneData.fill(0); @@ -240,7 +240,7 @@ bool CartridgeCTY::bank(uInt16 bank) System::PageAccess access(this, System::PageAccessType::READ); for(uInt16 addr = 0x1080; addr < 0x2000; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartCV.cxx b/src/emucore/CartCV.cxx index e5ca47788..bea42e759 100644 --- a/src/emucore/CartCV.cxx +++ b/src/emucore/CartCV.cxx @@ -40,7 +40,7 @@ CartridgeCV::CartridgeCV(const ByteBuffer& image, size_t size, // Copy the RAM image into a buffer for use in reset() std::copy_n(image.get(), myInitialRAM.size(), myInitialRAM.begin()); } - createCodeAccessBase(myImage.size() + myRAM.size()); + createRomAccessBase(myImage.size() + myRAM.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -68,7 +68,7 @@ void CartridgeCV::install(System& system) for(uInt16 addr = 0x1800; addr < 0x2000; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[addr & 0x07FF]; - access.codeAccessBase = &myCodeAccessBase[addr & 0x07FF]; + access.romAccessBase = &myRomAccessBase[addr & 0x07FF]; mySystem->setPageAccess(addr, access); } @@ -76,7 +76,7 @@ void CartridgeCV::install(System& system) // Map access to this class, since we need to inspect all accesses to // check if RWP happens access.directPeekBase = nullptr; - access.codeAccessBase = nullptr; + access.romAccessBase = nullptr; access.type = System::PageAccessType::WRITE; for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); @@ -87,7 +87,7 @@ void CartridgeCV::install(System& system) for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE) { access.directPeekBase = &myRAM[addr & 0x03FF]; - access.codeAccessBase = &myCodeAccessBase[2048 + (addr & 0x03FF)]; + access.romAccessBase = &myRomAccessBase[2048 + (addr & 0x03FF)]; mySystem->setPageAccess(addr, access); } } diff --git a/src/emucore/CartCVPlus.cxx b/src/emucore/CartCVPlus.cxx index c70c53b0d..c0d9b01d2 100644 --- a/src/emucore/CartCVPlus.cxx +++ b/src/emucore/CartCVPlus.cxx @@ -30,7 +30,7 @@ CartridgeCVPlus::CartridgeCVPlus(const ByteBuffer& image, size_t size, // Copy the ROM image into my buffer std::copy_n(image.get(), mySize, myImage.get()); - createCodeAccessBase(mySize + myRAM.size()); + createRomAccessBase(mySize + myRAM.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -58,11 +58,11 @@ void CartridgeCVPlus::install(System& system) // Map access to this class, since we need to inspect all accesses to // check if RWP happens access.directPeekBase = access.directPokeBase = nullptr; - access.codeAccessBase = nullptr; + access.romAccessBase = nullptr; access.type = System::PageAccessType::WRITE; for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[mySize + (addr & 0x03FF)]; + access.romAccessBase = &myRomAccessBase[mySize + (addr & 0x03FF)]; mySystem->setPageAccess(addr, access); } @@ -71,7 +71,7 @@ void CartridgeCVPlus::install(System& system) for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE) { access.directPeekBase = &myRAM[addr & 0x03FF]; - access.codeAccessBase = &myCodeAccessBase[mySize + (addr & 0x03FF)]; + access.romAccessBase = &myRomAccessBase[mySize + (addr & 0x03FF)]; mySystem->setPageAccess(addr, access); } @@ -148,7 +148,7 @@ bool CartridgeCVPlus::bank(uInt16 bank) for(uInt16 addr = 0x1800; addr < 0x2000; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[offset + (addr & 0x07FF)]; - access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x07FF)]; + access.romAccessBase = &myRomAccessBase[offset + (addr & 0x07FF)]; mySystem->setPageAccess(addr, access); } diff --git a/src/emucore/CartDASH.cxx b/src/emucore/CartDASH.cxx index 2c85ada47..e893b6f07 100644 --- a/src/emucore/CartDASH.cxx +++ b/src/emucore/CartDASH.cxx @@ -30,7 +30,7 @@ CartridgeDASH::CartridgeDASH(const ByteBuffer& image, size_t size, // Copy the ROM image into my buffer std::copy_n(image.get(), mySize, myImage.get()); - createCodeAccessBase(mySize + myRAM.size()); + createRomAccessBase(mySize + myRAM.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -204,7 +204,7 @@ void CartridgeDASH::bankRAMSlot(uInt16 bank) if(!upper) access.directPeekBase = &myRAM[startCurrentBank + (addr & (RAM_BANK_SIZE - 1))]; - access.codeAccessBase = &myCodeAccessBase[mySize + startCurrentBank + (addr & (RAM_BANK_SIZE - 1))]; + access.romAccessBase = &myRomAccessBase[mySize + startCurrentBank + (addr & (RAM_BANK_SIZE - 1))]; mySystem->setPageAccess(addr, access); } } @@ -247,7 +247,7 @@ void CartridgeDASH::bankROMSlot(uInt16 bank) for (uInt16 addr = start; addr <= end; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[startCurrentBank + (addr & (ROM_BANK_SIZE - 1))]; - access.codeAccessBase = &myCodeAccessBase[startCurrentBank + (addr & (ROM_BANK_SIZE - 1))]; + access.romAccessBase = &myRomAccessBase[startCurrentBank + (addr & (ROM_BANK_SIZE - 1))]; mySystem->setPageAccess(addr, access); } } diff --git a/src/emucore/CartDF.cxx b/src/emucore/CartDF.cxx index d837f9631..7e4ed9c2c 100644 --- a/src/emucore/CartDF.cxx +++ b/src/emucore/CartDF.cxx @@ -25,7 +25,7 @@ CartridgeDF::CartridgeDF(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createCodeAccessBase(myImage.size()); + createRomAccessBase(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -84,7 +84,7 @@ bool CartridgeDF::bank(uInt16 bank) for(uInt16 addr = (0x1FC0 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } @@ -93,7 +93,7 @@ bool CartridgeDF::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartDFSC.cxx b/src/emucore/CartDFSC.cxx index 1df44e638..530ef811c 100644 --- a/src/emucore/CartDFSC.cxx +++ b/src/emucore/CartDFSC.cxx @@ -25,7 +25,7 @@ CartridgeDFSC::CartridgeDFSC(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createCodeAccessBase(myImage.size()); + createRomAccessBase(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -51,7 +51,7 @@ void CartridgeDFSC::install(System& system) access.type = System::PageAccessType::WRITE; for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[addr & 0x007F]; + access.romAccessBase = &myRomAccessBase[addr & 0x007F]; mySystem->setPageAccess(addr, access); } @@ -60,7 +60,7 @@ void CartridgeDFSC::install(System& system) for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE) { access.directPeekBase = &myRAM[addr & 0x007F]; - access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)]; + access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)]; mySystem->setPageAccess(addr, access); } @@ -127,7 +127,7 @@ bool CartridgeDFSC::bank(uInt16 bank) for(uInt16 addr = (0x1FC0 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } @@ -136,7 +136,7 @@ bool CartridgeDFSC::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartDPC.cxx b/src/emucore/CartDPC.cxx index e382c8707..2ac559a57 100644 --- a/src/emucore/CartDPC.cxx +++ b/src/emucore/CartDPC.cxx @@ -27,7 +27,7 @@ CartridgeDPC::CartridgeDPC(const ByteBuffer& image, size_t size, { // Make a copy of the entire image std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createCodeAccessBase(8_KB); + createRomAccessBase(8_KB); // Pointer to the program ROM (8K @ 0 byte offset) myProgramImage = myImage.data(); @@ -373,7 +373,7 @@ bool CartridgeDPC::bank(uInt16 bank) for(uInt16 addr = (0x1FF8 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } @@ -382,7 +382,7 @@ bool CartridgeDPC::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.directPeekBase = &myProgramImage[myBankOffset + (addr & 0x0FFF)]; - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartDPCPlus.cxx b/src/emucore/CartDPCPlus.cxx index ab7230f78..5e92ec2a1 100644 --- a/src/emucore/CartDPCPlus.cxx +++ b/src/emucore/CartDPCPlus.cxx @@ -36,7 +36,7 @@ CartridgeDPCPlus::CartridgeDPCPlus(const ByteBuffer& image, size_t size, if(mySize < myImage.size()) myImage.fill(0); std::copy_n(image.get(), size, myImage.begin() + (myImage.size() - mySize)); - createCodeAccessBase(24_KB); + createRomAccessBase(24_KB); // Pointer to the program ROM (24K @ 3K offset; ignore first 3K) myProgramImage = myImage.data() + 3_KB; @@ -604,7 +604,7 @@ bool CartridgeDPCPlus::bank(uInt16 bank) // Map Program ROM image into the system for(uInt16 addr = 0x1080; addr < 0x2000; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartE0.cxx b/src/emucore/CartE0.cxx index 0c1921464..96029f903 100644 --- a/src/emucore/CartE0.cxx +++ b/src/emucore/CartE0.cxx @@ -25,7 +25,7 @@ CartridgeE0::CartridgeE0(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createCodeAccessBase(myImage.size()); + createRomAccessBase(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -61,13 +61,13 @@ void CartridgeE0::install(System& system) addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[0x1C00 + (addr & 0x03FF)]; - access.codeAccessBase = &myCodeAccessBase[0x1C00 + (addr & 0x03FF)]; + access.romAccessBase = &myRomAccessBase[0x1C00 + (addr & 0x03FF)]; mySystem->setPageAccess(addr, access); } // Set the page accessing methods for the hot spots in the last segment access.directPeekBase = nullptr; - access.codeAccessBase = &myCodeAccessBase[0x1FC0]; // TJ: is this the correct address (or 0x1FE0)? + access.romAccessBase = &myRomAccessBase[0x1FC0]; // TJ: is this the correct address (or 0x1FE0)? access.type = System::PageAccessType::READ; for(uInt16 addr = (0x1FE0 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) @@ -144,7 +144,7 @@ void CartridgeE0::segmentZero(uInt16 slice) for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[offset + (addr & 0x03FF)]; - access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)]; + access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; mySystem->setPageAccess(addr, access); } myBankChanged = true; @@ -165,7 +165,7 @@ void CartridgeE0::segmentOne(uInt16 slice) for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[offset + (addr & 0x03FF)]; - access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)]; + access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; mySystem->setPageAccess(addr, access); } myBankChanged = true; @@ -186,7 +186,7 @@ void CartridgeE0::segmentTwo(uInt16 slice) for(uInt16 addr = 0x1800; addr < 0x1C00; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[offset + (addr & 0x03FF)]; - access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)]; + access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; mySystem->setPageAccess(addr, access); } myBankChanged = true; diff --git a/src/emucore/CartEF.cxx b/src/emucore/CartEF.cxx index f89e3b441..96c5cf0da 100644 --- a/src/emucore/CartEF.cxx +++ b/src/emucore/CartEF.cxx @@ -25,7 +25,7 @@ CartridgeEF::CartridgeEF(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createCodeAccessBase(myImage.size()); + createRomAccessBase(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -84,7 +84,7 @@ bool CartridgeEF::bank(uInt16 bank) for(uInt16 addr = (0x1FE0 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } @@ -93,7 +93,7 @@ bool CartridgeEF::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartEFSC.cxx b/src/emucore/CartEFSC.cxx index 15f8470c0..8c9cdbb3c 100644 --- a/src/emucore/CartEFSC.cxx +++ b/src/emucore/CartEFSC.cxx @@ -25,7 +25,7 @@ CartridgeEFSC::CartridgeEFSC(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createCodeAccessBase(myImage.size()); + createRomAccessBase(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -51,7 +51,7 @@ void CartridgeEFSC::install(System& system) access.type = System::PageAccessType::WRITE; for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[addr & 0x007F]; + access.romAccessBase = &myRomAccessBase[addr & 0x007F]; mySystem->setPageAccess(addr, access); } @@ -60,7 +60,7 @@ void CartridgeEFSC::install(System& system) for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE) { access.directPeekBase = &myRAM[addr & 0x007F]; - access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)]; + access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)]; mySystem->setPageAccess(addr, access); } @@ -127,7 +127,7 @@ bool CartridgeEFSC::bank(uInt16 bank) for(uInt16 addr = (0x1FE0 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } @@ -136,7 +136,7 @@ bool CartridgeEFSC::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartF0.cxx b/src/emucore/CartF0.cxx index 14ace4375..bb10ccd43 100644 --- a/src/emucore/CartF0.cxx +++ b/src/emucore/CartF0.cxx @@ -25,7 +25,7 @@ CartridgeF0::CartridgeF0(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createCodeAccessBase(myImage.size()); + createRomAccessBase(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -91,7 +91,7 @@ bool CartridgeF0::bank(uInt16 bank) for(uInt16 addr = (0x1FF0 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } @@ -100,7 +100,7 @@ bool CartridgeF0::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } diff --git a/src/emucore/CartF4.cxx b/src/emucore/CartF4.cxx index 82d3f61bb..81e53a238 100644 --- a/src/emucore/CartF4.cxx +++ b/src/emucore/CartF4.cxx @@ -26,7 +26,7 @@ CartridgeF4::CartridgeF4(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createCodeAccessBase(myImage.size()); + createRomAccessBase(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -88,7 +88,7 @@ bool CartridgeF4::bank(uInt16 bank) for(uInt16 addr = (0x1FF4 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } @@ -97,7 +97,7 @@ bool CartridgeF4::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartF4SC.cxx b/src/emucore/CartF4SC.cxx index 45ec2ec88..79e34e854 100644 --- a/src/emucore/CartF4SC.cxx +++ b/src/emucore/CartF4SC.cxx @@ -25,7 +25,7 @@ CartridgeF4SC::CartridgeF4SC(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createCodeAccessBase(myImage.size()); + createRomAccessBase(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -51,7 +51,7 @@ void CartridgeF4SC::install(System& system) access.type = System::PageAccessType::WRITE; for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[addr & 0x007F]; + access.romAccessBase = &myRomAccessBase[addr & 0x007F]; mySystem->setPageAccess(addr, access); } @@ -60,7 +60,7 @@ void CartridgeF4SC::install(System& system) for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE) { access.directPeekBase = &myRAM[addr & 0x007F]; - access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)]; + access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)]; mySystem->setPageAccess(addr, access); } @@ -127,7 +127,7 @@ bool CartridgeF4SC::bank(uInt16 bank) for(uInt16 addr = (0x1FF4 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } @@ -136,7 +136,7 @@ bool CartridgeF4SC::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartF6.cxx b/src/emucore/CartF6.cxx index a5ed70ce3..8bf672695 100644 --- a/src/emucore/CartF6.cxx +++ b/src/emucore/CartF6.cxx @@ -25,7 +25,7 @@ CartridgeF6::CartridgeF6(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createCodeAccessBase(myImage.size()); + createRomAccessBase(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -128,7 +128,7 @@ bool CartridgeF6::bank(uInt16 bank) for(uInt16 addr = (0x1FF6 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } @@ -137,7 +137,7 @@ bool CartridgeF6::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartF6SC.cxx b/src/emucore/CartF6SC.cxx index 513560824..dbcd4c340 100644 --- a/src/emucore/CartF6SC.cxx +++ b/src/emucore/CartF6SC.cxx @@ -25,7 +25,7 @@ CartridgeF6SC::CartridgeF6SC(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createCodeAccessBase(myImage.size()); + createRomAccessBase(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -51,7 +51,7 @@ void CartridgeF6SC::install(System& system) access.type = System::PageAccessType::WRITE; for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[addr & 0x007F]; + access.romAccessBase = &myRomAccessBase[addr & 0x007F]; mySystem->setPageAccess(addr, access); } @@ -60,7 +60,7 @@ void CartridgeF6SC::install(System& system) for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE) { access.directPeekBase = &myRAM[addr & 0x007F]; - access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)]; + access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)]; mySystem->setPageAccess(addr, access); } @@ -167,7 +167,7 @@ bool CartridgeF6SC::bank(uInt16 bank) for(uInt16 addr = (0x1FF6 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } @@ -176,7 +176,7 @@ bool CartridgeF6SC::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartF8.cxx b/src/emucore/CartF8.cxx index 34e8ae7d7..cde6d47f0 100644 --- a/src/emucore/CartF8.cxx +++ b/src/emucore/CartF8.cxx @@ -25,7 +25,7 @@ CartridgeF8::CartridgeF8(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createCodeAccessBase(myImage.size()); + createRomAccessBase(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -109,7 +109,7 @@ bool CartridgeF8::bank(uInt16 bank) for(uInt16 addr = (0x1FF8 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } @@ -118,7 +118,7 @@ bool CartridgeF8::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartF8SC.cxx b/src/emucore/CartF8SC.cxx index d07cf9cb7..549fbea35 100644 --- a/src/emucore/CartF8SC.cxx +++ b/src/emucore/CartF8SC.cxx @@ -25,7 +25,7 @@ CartridgeF8SC::CartridgeF8SC(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createCodeAccessBase(myImage.size()); + createRomAccessBase(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -51,7 +51,7 @@ void CartridgeF8SC::install(System& system) access.type = System::PageAccessType::WRITE; for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[addr & 0x007F]; + access.romAccessBase = &myRomAccessBase[addr & 0x007F]; mySystem->setPageAccess(addr, access); } @@ -60,7 +60,7 @@ void CartridgeF8SC::install(System& system) for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE) { access.directPeekBase = &myRAM[addr & 0x007F]; - access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)]; + access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)]; mySystem->setPageAccess(addr, access); } @@ -147,7 +147,7 @@ bool CartridgeF8SC::bank(uInt16 bank) for(uInt16 addr = (0x1FF8 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } @@ -156,7 +156,7 @@ bool CartridgeF8SC::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartFA.cxx b/src/emucore/CartFA.cxx index eeef63016..e06b869b6 100644 --- a/src/emucore/CartFA.cxx +++ b/src/emucore/CartFA.cxx @@ -25,7 +25,7 @@ CartridgeFA::CartridgeFA(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createCodeAccessBase(myImage.size()); + createRomAccessBase(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -51,7 +51,7 @@ void CartridgeFA::install(System& system) access.type = System::PageAccessType::WRITE; for(uInt16 addr = 0x1000; addr < 0x1100; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[addr & 0x00FF]; + access.romAccessBase = &myRomAccessBase[addr & 0x00FF]; mySystem->setPageAccess(addr, access); } @@ -60,7 +60,7 @@ void CartridgeFA::install(System& system) for(uInt16 addr = 0x1100; addr < 0x1200; addr += System::PAGE_SIZE) { access.directPeekBase = &myRAM[addr & 0x00FF]; - access.codeAccessBase = &myCodeAccessBase[0x100 + (addr & 0x00FF)]; + access.romAccessBase = &myRomAccessBase[0x100 + (addr & 0x00FF)]; mySystem->setPageAccess(addr, access); } @@ -157,7 +157,7 @@ bool CartridgeFA::bank(uInt16 bank) for(uInt16 addr = (0x1FF8 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } @@ -166,7 +166,7 @@ bool CartridgeFA::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartFA2.cxx b/src/emucore/CartFA2.cxx index ce83f4c78..e6325e9ac 100644 --- a/src/emucore/CartFA2.cxx +++ b/src/emucore/CartFA2.cxx @@ -35,7 +35,7 @@ CartridgeFA2::CartridgeFA2(const ByteBuffer& image, size_t size, // Copy the ROM image into my buffer std::copy_n(img_ptr, mySize, myImage.begin()); - createCodeAccessBase(mySize); + createRomAccessBase(mySize); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -61,7 +61,7 @@ void CartridgeFA2::install(System& system) access.type = System::PageAccessType::WRITE; for(uInt16 addr = 0x1000; addr < 0x1100; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[addr & 0x00FF]; + access.romAccessBase = &myRomAccessBase[addr & 0x00FF]; mySystem->setPageAccess(addr, access); } @@ -71,7 +71,7 @@ void CartridgeFA2::install(System& system) for(uInt16 addr = 0x1100; addr < 0x1200; addr += System::PAGE_SIZE) { access.directPeekBase = &myRAM[addr & 0x00FF]; - access.codeAccessBase = &myCodeAccessBase[0x100 + (addr & 0x00FF)]; + access.romAccessBase = &myRomAccessBase[0x100 + (addr & 0x00FF)]; mySystem->setPageAccess(addr, access); } @@ -222,7 +222,7 @@ bool CartridgeFA2::bank(uInt16 bank) for(uInt16 addr = (0x1FF4 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } @@ -231,7 +231,7 @@ bool CartridgeFA2::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartFC.cxx b/src/emucore/CartFC.cxx index 251ea5a30..5195e499e 100644 --- a/src/emucore/CartFC.cxx +++ b/src/emucore/CartFC.cxx @@ -26,7 +26,7 @@ CartridgeFC::CartridgeFC(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createCodeAccessBase(myImage.size()); + createRomAccessBase(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -113,7 +113,7 @@ bool CartridgeFC::bank(uInt16 bank) for (uInt16 addr = (0x1FF8 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } @@ -122,7 +122,7 @@ bool CartridgeFC::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } myCurrentBank = myTargetBank; diff --git a/src/emucore/CartFE.cxx b/src/emucore/CartFE.cxx index 454cf4427..de5c088e9 100644 --- a/src/emucore/CartFE.cxx +++ b/src/emucore/CartFE.cxx @@ -26,7 +26,7 @@ CartridgeFE::CartridgeFE(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createCodeAccessBase(myImage.size()); + createRomAccessBase(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartMDM.cxx b/src/emucore/CartMDM.cxx index da6ddbf3a..6eaacee0b 100644 --- a/src/emucore/CartMDM.cxx +++ b/src/emucore/CartMDM.cxx @@ -29,7 +29,7 @@ CartridgeMDM::CartridgeMDM(const ByteBuffer& image, size_t size, // Copy the ROM image into my buffer std::copy_n(image.get(), mySize, myImage.get()); - createCodeAccessBase(mySize); + createRomAccessBase(mySize); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -111,7 +111,7 @@ bool CartridgeMDM::bank(uInt16 bank) for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } diff --git a/src/emucore/CartMNetwork.cxx b/src/emucore/CartMNetwork.cxx index b433c4d72..9c3213292 100644 --- a/src/emucore/CartMNetwork.cxx +++ b/src/emucore/CartMNetwork.cxx @@ -34,7 +34,7 @@ void CartridgeMNetwork::initialize(const ByteBuffer& image, size_t size) // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(romSize(), size), myImage.get()); - createCodeAccessBase(romSize() + myRAM.size()); + createRomAccessBase(romSize() + myRAM.size()); myRAMSlice = bankCount() - 1; } @@ -70,7 +70,7 @@ void CartridgeMNetwork::setAccess(uInt16 addrFrom, uInt16 size, access.directPeekBase = &directData[directOffset + (addr & addrMask)]; else if(type == System::PageAccessType::WRITE) // all RAM writes mapped to ::poke() access.directPokeBase = nullptr; - access.codeAccessBase = &myCodeAccessBase[codeOffset + (addr & addrMask)]; + access.romAccessBase = &myRomAccessBase[codeOffset + (addr & addrMask)]; mySystem->setPageAccess(addr, access); } } @@ -86,7 +86,7 @@ void CartridgeMNetwork::install(System& system) for(uInt16 addr = (0x1FE0 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[0x1fc0]; + access.romAccessBase = &myRomAccessBase[0x1fc0]; mySystem->setPageAccess(addr, access); } /*setAccess(0x1FE0 & ~System::PAGE_MASK, System::PAGE_SIZE, diff --git a/src/emucore/CartSB.cxx b/src/emucore/CartSB.cxx index 796ecfcdf..db8d4a051 100644 --- a/src/emucore/CartSB.cxx +++ b/src/emucore/CartSB.cxx @@ -29,7 +29,7 @@ CartridgeSB::CartridgeSB(const ByteBuffer& image, size_t size, // Copy the ROM image into my buffer std::copy_n(image.get(), mySize, myImage.get()); - createCodeAccessBase(mySize); + createRomAccessBase(mySize); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -121,7 +121,7 @@ bool CartridgeSB::bank(uInt16 bank) for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartUA.cxx b/src/emucore/CartUA.cxx index b9de6bf4b..b0643cf97 100644 --- a/src/emucore/CartUA.cxx +++ b/src/emucore/CartUA.cxx @@ -27,7 +27,7 @@ CartridgeUA::CartridgeUA(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createCodeAccessBase(myImage.size()); + createRomAccessBase(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -135,7 +135,7 @@ bool CartridgeUA::bank(uInt16 bank) for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartWD.cxx b/src/emucore/CartWD.cxx index d6b2bc239..2a6ea653a 100644 --- a/src/emucore/CartWD.cxx +++ b/src/emucore/CartWD.cxx @@ -37,7 +37,7 @@ CartridgeWD::CartridgeWD(const ByteBuffer& image, size_t size, } else std::copy_n(image.get(), mySize, myImage.begin()); - createCodeAccessBase(8_KB); + createRomAccessBase(8_KB); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -63,7 +63,7 @@ void CartridgeWD::install(System& system) for(uInt16 addr = 0x1000; addr < 0x1040; addr += System::PAGE_SIZE) { read.directPeekBase = &myRAM[addr & 0x003F]; - read.codeAccessBase = &myCodeAccessBase[addr & 0x003F]; + read.romAccessBase = &myRomAccessBase[addr & 0x003F]; mySystem->setPageAccess(addr, read); } @@ -73,7 +73,7 @@ void CartridgeWD::install(System& system) System::PageAccess write(this, System::PageAccessType::WRITE); for(uInt16 addr = 0x1040; addr < 0x1080; addr += System::PAGE_SIZE) { - write.codeAccessBase = &myCodeAccessBase[addr & 0x003F]; + write.romAccessBase = &myRomAccessBase[addr & 0x003F]; mySystem->setPageAccess(addr, write); } @@ -177,7 +177,7 @@ void CartridgeWD::segmentZero(uInt8 slice) // Skip first 128 bytes; it is always RAM for(uInt16 addr = 0x1080; addr < 0x1400; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)]; + access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; mySystem->setPageAccess(addr, access); } myOffset[0] = offset; @@ -191,7 +191,7 @@ void CartridgeWD::segmentOne(uInt8 slice) for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)]; + access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; mySystem->setPageAccess(addr, access); } myOffset[1] = offset; @@ -205,7 +205,7 @@ void CartridgeWD::segmentTwo(uInt8 slice) for(uInt16 addr = 0x1800; addr < 0x1C00; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)]; + access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; mySystem->setPageAccess(addr, access); } myOffset[2] = offset; @@ -225,7 +225,7 @@ void CartridgeWD::segmentThree(uInt8 slice) for(uInt16 addr = 0x1C00; addr < 0x2000; addr += System::PAGE_SIZE) { - access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)]; + access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; mySystem->setPageAccess(addr, access); } myOffset[3] = offset; diff --git a/src/emucore/CartX07.cxx b/src/emucore/CartX07.cxx index 0e0bb2869..a58b97abb 100644 --- a/src/emucore/CartX07.cxx +++ b/src/emucore/CartX07.cxx @@ -27,7 +27,7 @@ CartridgeX07::CartridgeX07(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createCodeAccessBase(myImage.size()); + createRomAccessBase(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -115,7 +115,7 @@ bool CartridgeX07::bank(uInt16 bank) for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[offset + (addr & 0x0FFF)]; - access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x0FFF)]; + access.romAccessBase = &myRomAccessBase[offset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/System.cxx b/src/emucore/System.cxx index 2fa33a201..f11a05fe4 100644 --- a/src/emucore/System.cxx +++ b/src/emucore/System.cxx @@ -105,8 +105,8 @@ uInt8 System::peek(uInt16 addr, Device::AccessFlags flags) #ifdef DEBUGGER_SUPPORT // Set access type - if(access.codeAccessBase) - *(access.codeAccessBase + (addr & PAGE_MASK)) |= flags; + if(access.romAccessBase) + *(access.romAccessBase + (addr & PAGE_MASK)) |= flags; else access.device->setAccessFlags(addr, flags); #endif @@ -134,8 +134,8 @@ void System::poke(uInt16 addr, uInt8 value, Device::AccessFlags flags) #ifdef DEBUGGER_SUPPORT // Set access type - if (access.codeAccessBase) - *(access.codeAccessBase + (addr & PAGE_MASK)) |= flags; + if (access.romAccessBase) + *(access.romAccessBase + (addr & PAGE_MASK)) |= flags; else access.device->setAccessFlags(addr, flags); #endif @@ -165,8 +165,8 @@ Device::AccessFlags System::getAccessFlags(uInt16 addr) const { const PageAccess& access = getPageAccess(addr); - if(access.codeAccessBase) - return *(access.codeAccessBase + (addr & PAGE_MASK)); + if(access.romAccessBase) + return *(access.romAccessBase + (addr & PAGE_MASK)); else return access.device->getAccessFlags(addr); } @@ -176,8 +176,8 @@ void System::setAccessFlags(uInt16 addr, Device::AccessFlags flags) { const PageAccess& access = getPageAccess(addr); - if(access.codeAccessBase) - *(access.codeAccessBase + (addr & PAGE_MASK)) |= flags; + if(access.romAccessBase) + *(access.romAccessBase + (addr & PAGE_MASK)) |= flags; else access.device->setAccessFlags(addr, flags); } diff --git a/src/emucore/System.hxx b/src/emucore/System.hxx index 1262b6ad3..b400b1cdb 100644 --- a/src/emucore/System.hxx +++ b/src/emucore/System.hxx @@ -273,13 +273,17 @@ class System : public Serializable uInt8* directPokeBase{nullptr}; /** - Pointer to a lookup table for marking an address as CODE. A CODE - section is defined as any address that appears in the program + Pointer to a lookup table for marking an address as CODE, DATA, GFX, + COL etc. + A CODE section is defined as any address that appears in the program counter. Currently, this is used by the debugger/disassembler to conclusively determine if a section of address space is CODE, even if the disassembler failed to mark it as such. + A DATA, GFX, COL etc. section is defined as any ROM address from which + data is read. This is used by the debugger/disassembler to format + address sections accordingly. */ - Device::AccessFlags* codeAccessBase{nullptr}; + Device::AccessFlags* romAccessBase{nullptr}; /** Pointer to the device associated with this page or to the system's From 2d754a9aea17f982c43f980868123f6af6cbbb8a Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 30 Mar 2020 09:52:56 +0200 Subject: [PATCH 061/377] fix color value disassembly add ORG/RORG for multi-bank ROM disassembly --- src/debugger/CartDebug.cxx | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index 89fad0d1b..aa0a3136b 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -1024,11 +1024,6 @@ string CartDebug::saveDisassembly() // We can't print the header to the disassembly until it's actually // been processed; therefore buffer output to a string first ostringstream buf; - buf << "\n\n;***********************************************************\n" - << "; Bank " << myConsole.cartridge().getBank(); - if (myConsole.cartridge().bankCount() > 1) - buf << " / 0.." << myConsole.cartridge().bankCount() - 1; - buf << "\n;***********************************************************\n\n"; // Use specific settings for disassembly output // This will most likely differ from what you see in the debugger @@ -1044,13 +1039,23 @@ string CartDebug::saveDisassembly() Disassembly disasm; disasm.list.reserve(2048); - for(int bank = 0; bank < myConsole.cartridge().bankCount(); ++bank) + uInt16 bankCount = myConsole.cartridge().bankCount(); + + for(int bank = 0; bank < bankCount; ++bank) { BankInfo& info = myBankInfo[bank]; + // An empty address list means that DiStella can't do a disassembly if(info.addressList.size() == 0) continue; + buf << "\n\n;***********************************************************\n" + << "; Bank " << bank; + if (bankCount > 1) + buf << " / 0.." << bankCount - 1; + buf << "\n;***********************************************************\n\n"; + + // Disassemble bank disasm.list.clear(); DiStella distella(*this, disasm.list, info, settings, @@ -1059,8 +1064,13 @@ string CartDebug::saveDisassembly() if (myReserved.breakFound) addLabel("Break", myDebugger.dpeek(0xfffe)); - buf << " SEG CODE\n" - << " ORG $" << Base::HEX4 << info.offset << "\n\n"; + buf << " SEG CODE\n"; + + if(bankCount == 1) + buf << " ORG $" << Base::HEX4 << info.offset << "\n\n"; + else + buf << " ORG $" << Base::HEX4 << ((0x0000 + bank * 0x1000) & 0xffff) << "\n" + << " RORG $" << Base::HEX4 << info.offset << "\n\n"; // Format in 'distella' style for(uInt32 i = 0; i < disasm.list.size(); ++i) @@ -1101,15 +1111,15 @@ string CartDebug::saveDisassembly() break; case Device::COL: - buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 12) << "; $" << Base::HEX4 << tag.address << " (C)"; + buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 15) << "; $" << Base::HEX4 << tag.address << " (C)"; break; case Device::PCOL: - buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 12) << "; $" << Base::HEX4 << tag.address << " (CP)"; + buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 15) << "; $" << Base::HEX4 << tag.address << " (CP)"; break; case Device::BCOL: - buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 12) << "; $" << Base::HEX4 << tag.address << " (CB)"; + buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 15) << "; $" << Base::HEX4 << tag.address << " (CB)"; break; case Device::AUD: From e619895d94985afd24da4cc5fcb487b2d5d9a934 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 30 Mar 2020 12:20:59 +0200 Subject: [PATCH 062/377] some progress with multi-bank games disassembly (it now works, but still requires a bit of manual action before) --- src/debugger/CartDebug.cxx | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index aa0a3136b..d3676e048 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -86,7 +86,7 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem) // We know the address for the startup bank right now myBankInfo[myConsole.cartridge().startBank()].addressList.push_front( myDebugger.dpeek(0xfffc)); - addLabel("Start", myDebugger.dpeek(0xfffc, Device::DATA)); + addLabel("Start", myDebugger.dpeek(0xfffc, Device::DATA)); // TOOD: ::CODE??? // Add system equates for(uInt16 addr = 0x00; addr <= 0x0F; ++addr) @@ -1040,11 +1040,26 @@ string CartDebug::saveDisassembly() Disassembly disasm; disasm.list.reserve(2048); uInt16 bankCount = myConsole.cartridge().bankCount(); + uInt16 oldBank = myConsole.cartridge().getBank(); + + // prepare for switching banks + myConsole.cartridge().unlockBank(); // TODO: make sure every CartWidget does it like that, + // maybe define a commonly used method. for(int bank = 0; bank < bankCount; ++bank) { + myConsole.cartridge().bank(bank); + BankInfo& info = myBankInfo[bank]; + // TODO: we have to get the bank disassembled if it had not been debugged before. + // If the debugger is stopped at least once in each bank, the disassembly is mostly* correct. + // So we have to replicate that. + // (* Beamrider is 100% identical, Asteroids has some bytes after the hotspot wrong) + // One problem seems to be, that we do not know where to start. There is no valid addressList + // list for a non-debugged bank. + //disassemble(); // DOES NOT WORK YET!!! (makes it even worse!) + // An empty address list means that DiStella can't do a disassembly if(info.addressList.size() == 0) continue; @@ -1137,6 +1152,8 @@ string CartDebug::saveDisassembly() buf << "\n"; } } + myConsole.cartridge().bank(oldBank); + myConsole.cartridge().lockBank(); // Some boilerplate, similar to what DiStella adds auto timeinfo = BSPF::localTime(); From 83eda87d7992e7bd54051658ad678b8235074472 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 30 Mar 2020 23:01:15 +0200 Subject: [PATCH 063/377] enhance debugger disassemblies, 'savedis' now allows multi-bank ROMs --- src/debugger/CartDebug.cxx | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index d3676e048..9e8fc88b6 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -1043,22 +1043,19 @@ string CartDebug::saveDisassembly() uInt16 oldBank = myConsole.cartridge().getBank(); // prepare for switching banks - myConsole.cartridge().unlockBank(); // TODO: make sure every CartWidget does it like that, - // maybe define a commonly used method. + myConsole.cartridge().unlockBank(); for(int bank = 0; bank < bankCount; ++bank) { + // TODO: not every CartDebugWidget does it like that, we need a method + myConsole.cartridge().unlockBank(); myConsole.cartridge().bank(bank); + myConsole.cartridge().lockBank(); BankInfo& info = myBankInfo[bank]; - // TODO: we have to get the bank disassembled if it had not been debugged before. - // If the debugger is stopped at least once in each bank, the disassembly is mostly* correct. - // So we have to replicate that. - // (* Beamrider is 100% identical, Asteroids has some bytes after the hotspot wrong) - // One problem seems to be, that we do not know where to start. There is no valid addressList - // list for a non-debugged bank. - //disassemble(); // DOES NOT WORK YET!!! (makes it even worse!) + // TODO: make PageAccess ready for multi-bank ROMs + disassemble(); // An empty address list means that DiStella can't do a disassembly if(info.addressList.size() == 0) @@ -1152,6 +1149,7 @@ string CartDebug::saveDisassembly() buf << "\n"; } } + myConsole.cartridge().unlockBank(); myConsole.cartridge().bank(oldBank); myConsole.cartridge().lockBank(); @@ -1310,7 +1308,7 @@ string CartDebug::saveDisassembly() stringstream retVal; if(myConsole.cartridge().bankCount() > 1) - retVal << DebuggerParser::red("disassembly for multi-bank ROM not fully supported, only currently enabled banks disassembled\n"); + retVal << DebuggerParser::red("disassembly for multi-bank ROM not fully supported\n"); retVal << "saved " << node.getShortPath() << " OK"; return retVal.str(); } From 9fbf337cc85777494edc68c9e9f63b9774aeefc3 Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Tue, 31 Mar 2020 00:46:20 +0200 Subject: [PATCH 064/377] Fix snapshots on retina displays. --- src/common/FrameBufferSDL2.hxx | 4 ++-- src/common/PNGLibrary.cxx | 9 ++++++++- src/emucore/FrameBuffer.hxx | 10 ++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/common/FrameBufferSDL2.hxx b/src/common/FrameBufferSDL2.hxx index 64803e6bb..857891685 100644 --- a/src/common/FrameBufferSDL2.hxx +++ b/src/common/FrameBufferSDL2.hxx @@ -137,12 +137,12 @@ class FrameBufferSDL2 : public FrameBuffer /** Transform from window to renderer coordinates, x direction */ - int scaleX(int x) const { return (x * myRenderW) / myWindowW; } + int scaleX(int x) const override { return (x * myRenderW) / myWindowW; } /** Transform from window to renderer coordinates, y direction */ - int scaleY(int y) const { return (y * myRenderH) / myWindowH; } + int scaleY(int y) const override { return (y * myRenderH) / myWindowH; } protected: ////////////////////////////////////////////////////////////////////// diff --git a/src/common/PNGLibrary.cxx b/src/common/PNGLibrary.cxx index 779f6b0f6..e1980a975 100644 --- a/src/common/PNGLibrary.cxx +++ b/src/common/PNGLibrary.cxx @@ -29,6 +29,7 @@ #include "TIASurface.hxx" #include "Version.hxx" #include "PNGLibrary.hxx" +#include "Rect.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PNGLibrary::PNGLibrary(OSystem& osystem) @@ -129,7 +130,13 @@ void PNGLibrary::saveImage(const string& filename, const VariantList& comments) throw runtime_error("ERROR: Couldn't create snapshot file"); const FrameBuffer& fb = myOSystem.frameBuffer(); - const Common::Rect& rect = fb.imageRect(); + + const Common::Rect& rectUnscaled = fb.imageRect(); + const Common::Rect rect( + Common::Point(fb.scaleX(rectUnscaled.x()), fb.scaleY(rectUnscaled.y())), + fb.scaleX(rectUnscaled.w()), fb.scaleY(rectUnscaled.h()) + ); + png_uint_32 width = rect.w(), height = rect.h(); // Get framebuffer pixel data (we get ABGR format) diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index ce215345a..67628ee84 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -381,6 +381,16 @@ class FrameBuffer */ virtual void clear() = 0; + /** + Transform from window to renderer coordinates, x direction + */ + virtual int scaleX(int x) const { return x; } + + /** + Transform from window to renderer coordinates, y direction + */ + virtual int scaleY(int y) const { return y; } + protected: /** This method is called to query and initialize the video hardware From 6b847438ef5ea4c99e84d0f12a6d99f3564bac0d Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Mon, 30 Mar 2020 21:20:19 -0230 Subject: [PATCH 065/377] Updated changelog, before we forget about the details. --- Changes.txt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Changes.txt b/Changes.txt index 0b2e20aa0..8228ec3a2 100644 --- a/Changes.txt +++ b/Changes.txt @@ -20,10 +20,18 @@ 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. (TOOD: Doc) - * Added displaying last write address in debugger. + * Added displaying last write address in the debugger. * Added detection of color and audio data in DiStella. + * Fix snapshots on Retina HiDPI displays capturing only the top-left corner. + + * Fixed wrong color for BK (background) swatch in the debugger. + + * Fixed compilation of libretro port on Debian Buster. + +-Have fun! + 6.0.2 to 6.1: (March 22, 2020) @@ -214,8 +222,6 @@ * Updated UNIX configure script to work with the gcc version 10 and above. --Have fun! - 6.0.1 to 6.0.2: (October 11, 2019) From 7cbec465e9a66ce7efcc29d86c64abc3903acb0e Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 31 Mar 2020 18:12:38 +0200 Subject: [PATCH 066/377] Enhance disassembly (determine correct bank offset, preliminary solution for simple 4K bankswitching, e.g. standard Atari) --- src/debugger/CartDebug.cxx | 54 ++++++++++++++++++++++++++++++++++---- src/debugger/CartDebug.hxx | 36 ++++++++++++++----------- src/debugger/DiStella.cxx | 6 ++--- src/emucore/Device.hxx | 22 +++++++++------- src/emucore/System.cxx | 8 +++--- 5 files changed, 89 insertions(+), 37 deletions(-) diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index 9e8fc88b6..89c3d94d0 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -238,11 +238,51 @@ string CartDebug::toString() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDebug::disassemble(bool force) +{ + uInt16 PC = myDebugger.cpuDebug().pc(); + int bank = (PC & 0x1000) ? getBank(PC) : int(myBankInfo.size()) - 1; + + return disassemble(bank, PC, force); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CartDebug::disassembleBank(int bank) +{ + // isolate the high 3 address bits, count them and + // select the most frequent to define the bank offset + BankInfo& info = myBankInfo[bank]; + uInt16 count[8]; + + for(int i = 0; i < 8; ++i) + count[i] = 0; + + for(uInt32 addr = 0x1000; addr < 0x1000 + info.size; ++addr) + { + Device::AccessFlags flags = mySystem.getAccessFlags(addr); + // only count really accessed addresses + if (flags & ~Device::ROW) + count[(flags & Device::HADDR) >> 13]++; + } + uInt16 max = 0, maxIdx = 0; + for(int idx = 0; idx < 8; ++idx) + { + if(count[idx] > max) + { + max = count[idx]; + maxIdx = idx; + } + } + info.offset = maxIdx << 13 | 0x1000; + + return disassemble(bank, info.offset, true); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CartDebug::disassemble(int bank, uInt16 PC, bool force) { // Test current disassembly; don't re-disassemble if it hasn't changed // Also check if the current PC is in the current list bool bankChanged = myConsole.cartridge().bankChanged(); - uInt16 PC = myDebugger.cpuDebug().pc(); int pcline = addressToLine(PC); bool pcfound = (pcline != -1) && (uInt32(pcline) < myDisassembly.list.size()) && (myDisassembly.list[pcline].disasm[0] != '.'); @@ -254,8 +294,9 @@ bool CartDebug::disassemble(bool force) if(changed) { // Are we disassembling from ROM or ZP RAM? - BankInfo& info = (PC & 0x1000) ? myBankInfo[getBank(PC)] : - myBankInfo[myBankInfo.size()-1]; + BankInfo& info = myBankInfo[bank]; + //(PC & 0x1000) ? myBankInfo[getBank(PC)] : + //myBankInfo[myBankInfo.size()-1]; // If the offset has changed, all old addresses must be 'converted' // For example, if the list contains any $fxxx and the address space is now @@ -1044,6 +1085,7 @@ string CartDebug::saveDisassembly() // prepare for switching banks myConsole.cartridge().unlockBank(); + uInt32 origin = 0; for(int bank = 0; bank < bankCount; ++bank) { @@ -1055,7 +1097,8 @@ string CartDebug::saveDisassembly() BankInfo& info = myBankInfo[bank]; // TODO: make PageAccess ready for multi-bank ROMs - disassemble(); + // TODO: define offset if still undefined + disassembleBank(bank); // An empty address list means that DiStella can't do a disassembly if(info.addressList.size() == 0) @@ -1081,8 +1124,9 @@ string CartDebug::saveDisassembly() if(bankCount == 1) buf << " ORG $" << Base::HEX4 << info.offset << "\n\n"; else - buf << " ORG $" << Base::HEX4 << ((0x0000 + bank * 0x1000) & 0xffff) << "\n" + buf << " ORG $" << Base::HEX4 << origin << "\n" << " RORG $" << Base::HEX4 << info.offset << "\n\n"; + origin += info.size; // Format in 'distella' style for(uInt32 i = 0; i < disasm.list.size(); ++i) diff --git a/src/debugger/CartDebug.hxx b/src/debugger/CartDebug.hxx index c6ba615b5..327450560 100644 --- a/src/debugger/CartDebug.hxx +++ b/src/debugger/CartDebug.hxx @@ -94,23 +94,16 @@ class CartDebug : public DebuggerSystem // Return the base (= non-mirrored) address of the last CPU write int lastWriteBaseAddress(); - // The following two methods are meant to be used together - // First, a call is made to disassemble(), which updates the disassembly - // list; it will figure out when an actual complete disassembly is - // required, and when the previous results can be used - // - // Later, successive calls to disassemblyList() simply return the - // previous results; no disassembly is done in this case - /** - Disassemble from the given address using the Distella disassembler - Address-to-label mappings (and vice-versa) are also determined here - - @param force Force a re-disassembly, even if the state hasn't changed - - @return True if disassembly changed from previous call, else false - */ + // TODO bool disassemble(bool force = false); + bool disassembleBank(int bank); + // First, a call is made to disassemble(), which updates the disassembly + // list, is required; it will figure out when an actual complete + // disassembly is required, and when the previous results can be used + // + // Later, successive calls to disassembly() simply return the + // previous results; no disassembly is done in this case /** Get the results from the most recent call to disassemble() */ @@ -278,6 +271,19 @@ class CartDebug : public DebuggerSystem }; ReservedEquates myReserved; + /** + Disassemble from the given address using the Distella disassembler + Address-to-label mappings (and vice-versa) are also determined here + + @param bank The current bank to disassemble + @param PC A program counter to start with + @param force Force a re-disassembly, even if the state hasn't changed + + @return True if disassembly changed from previous call, else false + */ + bool disassemble(int bank, uInt16 PC, bool force = false); + + // Actually call DiStella to fill the DisassemblyList structure // Return whether the search address was actually in the list bool fillDisassemblyList(BankInfo& bankinfo, uInt16 search); diff --git a/src/debugger/DiStella.cxx b/src/debugger/DiStella.cxx index 2aa304ac6..8aff0b568 100644 --- a/src/debugger/DiStella.cxx +++ b/src/debugger/DiStella.cxx @@ -969,9 +969,9 @@ bool DiStella::checkBit(uInt16 address, uInt16 mask, bool useDebugger) const // Since they're set only in the labels array (as the lower two bits), // they must be included in the other bitfields uInt16 label = myLabels[address & myAppData.end], - lastbits = label & 0x03, - directive = myDirectives[address & myAppData.end] & ~0x03, - debugger = Debugger::debugger().getAccessFlags(address | myOffset) & ~0x03; + lastbits = label & (Device::REFERENCED | Device::VALID_ENTRY), + directive = myDirectives[address & myAppData.end] & ~(Device::REFERENCED | Device::VALID_ENTRY), + debugger = Debugger::debugger().getAccessFlags(address | myOffset) & ~(Device::REFERENCED | Device::VALID_ENTRY); // Any address marked by a manual directive always takes priority if (directive) diff --git a/src/emucore/Device.hxx b/src/emucore/Device.hxx index d8b9cbaa9..ecb857e21 100644 --- a/src/emucore/Device.hxx +++ b/src/emucore/Device.hxx @@ -44,18 +44,20 @@ class Device : public Serializable // The following correspond to specific types that can be set within the // debugger, or specified in a Distella cfg file, and are listed in order - // of decreasing hierarchy + // of increasing hierarchy // - CODE = 1 << 11, // 0x800, disassemble-able code segments - TCODE = 1 << 10, // 0x400, (tentative) disassemble-able code segments - GFX = 1 << 9, // 0x200, addresses loaded into GRPx registers - PGFX = 1 << 8, // 0x100, addresses loaded into PFx registers - COL = 1 << 7, // 0x080, addresses loaded into COLUPx registers - PCOL = 1 << 6, // 0x040, addresses loaded into COLUPF register - BCOL = 1 << 5, // 0x020, addresses loaded into COLUBK register - AUD = 1 << 4, // 0x010, addresses loaded into audio registers - DATA = 1 << 3, // 0x008, addresses loaded into registers other than GRPx / PFx / COLUxx, AUDxx ROW = 1 << 2, // 0x004, all other addresses + DATA = 1 << 3, // 0x008, addresses loaded into registers other than GRPx / PFx / COLUxx, AUDxx + AUD = 1 << 4, // 0x010, addresses loaded into audio registers + BCOL = 1 << 5, // 0x020, addresses loaded into COLUBK register + PCOL = 1 << 6, // 0x040, addresses loaded into COLUPF register + COL = 1 << 7, // 0x080, addresses loaded into COLUPx registers + PGFX = 1 << 8, // 0x100, addresses loaded into PFx registers + GFX = 1 << 9, // 0x200, addresses loaded into GRPx registers + TCODE = 1 << 10, // 0x400, (tentative) disassemble-able code segments + CODE = 1 << 11, // 0x800, disassemble-able code segments + // special bits for address + HADDR = 1 << 13 | 1 << 14 | 1 << 15, // 0xe000, // highest 3 address bits // special type for poke() WRITE = TCODE // 0x200, address written to }; diff --git a/src/emucore/System.cxx b/src/emucore/System.cxx index f11a05fe4..c94f465fd 100644 --- a/src/emucore/System.cxx +++ b/src/emucore/System.cxx @@ -106,7 +106,7 @@ uInt8 System::peek(uInt16 addr, Device::AccessFlags flags) #ifdef DEBUGGER_SUPPORT // Set access type if(access.romAccessBase) - *(access.romAccessBase + (addr & PAGE_MASK)) |= flags; + *(access.romAccessBase + (addr & PAGE_MASK)) |= (flags | (addr & Device::HADDR)); else access.device->setAccessFlags(addr, flags); #endif @@ -134,8 +134,8 @@ void System::poke(uInt16 addr, uInt8 value, Device::AccessFlags flags) #ifdef DEBUGGER_SUPPORT // Set access type - if (access.romAccessBase) - *(access.romAccessBase + (addr & PAGE_MASK)) |= flags; + if(access.romAccessBase) + *(access.romAccessBase + (addr & PAGE_MASK)) |= (flags | (addr & Device::HADDR)); else access.device->setAccessFlags(addr, flags); #endif @@ -177,7 +177,7 @@ void System::setAccessFlags(uInt16 addr, Device::AccessFlags flags) const PageAccess& access = getPageAccess(addr); if(access.romAccessBase) - *(access.romAccessBase + (addr & PAGE_MASK)) |= flags; + *(access.romAccessBase + (addr & PAGE_MASK)) |= (flags | (addr & Device::HADDR)); else access.device->setAccessFlags(addr, flags); } From 5ce434cc59730dd502a9a9bf86754350bd1b751b Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 31 Mar 2020 18:35:51 +0200 Subject: [PATCH 067/377] fix last commit --- src/debugger/CartDebug.cxx | 6 ++---- src/debugger/CartDebug.hxx | 2 +- src/debugger/DebuggerParser.cxx | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index 89c3d94d0..daeee9f72 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -385,7 +385,7 @@ int CartDebug::addressToLine(uInt16 address) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartDebug::disassemble(uInt16 start, uInt16 lines) const +string CartDebug::disassembleLines(uInt16 start, uInt16 lines) const { // Fill the string with disassembled data start &= 0xFFF; @@ -1096,8 +1096,6 @@ string CartDebug::saveDisassembly() BankInfo& info = myBankInfo[bank]; - // TODO: make PageAccess ready for multi-bank ROMs - // TODO: define offset if still undefined disassembleBank(bank); // An empty address list means that DiStella can't do a disassembly @@ -1126,7 +1124,7 @@ string CartDebug::saveDisassembly() else buf << " ORG $" << Base::HEX4 << origin << "\n" << " RORG $" << Base::HEX4 << info.offset << "\n\n"; - origin += info.size; + origin += uInt32(info.size); // Format in 'distella' style for(uInt32 i = 0; i < disasm.list.size(); ++i) diff --git a/src/debugger/CartDebug.hxx b/src/debugger/CartDebug.hxx index 327450560..f0b4b49fe 100644 --- a/src/debugger/CartDebug.hxx +++ b/src/debugger/CartDebug.hxx @@ -127,7 +127,7 @@ class CartDebug : public DebuggerSystem @return The disassembly represented as a string */ - string disassemble(uInt16 start, uInt16 lines) const; + string disassembleLines(uInt16 start, uInt16 lines) const; /** Add a directive to the disassembler. Directives are basically overrides diff --git a/src/debugger/DebuggerParser.cxx b/src/debugger/DebuggerParser.cxx index 77032fd5f..fb905e8a5 100644 --- a/src/debugger/DebuggerParser.cxx +++ b/src/debugger/DebuggerParser.cxx @@ -1082,7 +1082,7 @@ void DebuggerParser::executeDisasm() return; } - commandResult << debugger.cartDebug().disassemble(start, lines); + commandResult << debugger.cartDebug().disassembleLines(start, lines); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 5f008f60ce148746ed4bd8de9e02c535e47a034b Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 31 Mar 2020 18:40:48 +0200 Subject: [PATCH 068/377] fix non-VS warning --- src/debugger/CartDebug.cxx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index daeee9f72..7e76d2dc1 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -1576,9 +1576,7 @@ void CartDebug::AccessTypeAsString(ostream& buf, Device::AccessType type) const case Device::AUD: buf << "AUD"; break; case Device::DATA: buf << "DATA"; break; case Device::ROW: buf << "ROW"; break; - case Device::REFERENCED: - case Device::VALID_ENTRY: - case Device::NONE: break; + default: break; } } From b97c9f0899615fe5623305b2112b9ac5532efe82 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Tue, 31 Mar 2020 18:25:25 -0230 Subject: [PATCH 069/377] Synchronize wil upcoming 6.1.1 release. --- Changes.txt | 10 +++++++--- debian/changelog | 7 +++++++ src/unix/stella.spec | 3 +++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/Changes.txt b/Changes.txt index 8228ec3a2..8babda153 100644 --- a/Changes.txt +++ b/Changes.txt @@ -24,14 +24,18 @@ * Added detection of color and audio data in DiStella. - * Fix snapshots on Retina HiDPI displays capturing only the top-left corner. +-Have fun! + + +6.1 to 6.1.1: (April 4, 2020) + + * Fix snapshots on Retina HiDPI displays capturing only the top-left + corner. * Fixed wrong color for BK (background) swatch in the debugger. * Fixed compilation of libretro port on Debian Buster. --Have fun! - 6.0.2 to 6.1: (March 22, 2020) diff --git a/debian/changelog b/debian/changelog index 553ddda1b..af319a670 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +stella (6.1.1-1) stable; urgency=high + + * Version 6.1.1 release + + -- Stephen Anthony Sat, 04 Apr 2020 17:09:59 -0230 + + stella (6.1-1) stable; urgency=high * Version 6.1 release diff --git a/src/unix/stella.spec b/src/unix/stella.spec index 09d4d2827..a4236c38f 100644 --- a/src/unix/stella.spec +++ b/src/unix/stella.spec @@ -100,6 +100,9 @@ rm -rf $RPM_BUILD_DIR/%{name}-%{version} %_datadir/icons/large/%{name}.png %changelog +* Sat Apr 04 2020 Stephen Anthony 6.1.1-1 +- Version 6.1.1 release + * Sun Mar 22 2020 Stephen Anthony 6.1-1 - Version 6.1 release From bf69225db691b85c28062a4f4b9596e181831eed Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 1 Apr 2020 11:06:03 +0200 Subject: [PATCH 070/377] first shot at #586 (Heat Map) (TODO: differentiate cartridge read/write access) add Cartridge::bankSize method (TODO: varying bank sizes) add Cartridge::bankOrigin detection method (TODO: banks smaller 4K) --- src/debugger/CartDebug.cxx | 54 +++++++++++------------- src/debugger/CartDebug.hxx | 5 +++ src/debugger/DebuggerParser.cxx | 20 ++++++++- src/debugger/DebuggerParser.hxx | 3 +- src/emucore/Cart.cxx | 69 +++++++++++++++++++++++++++++- src/emucore/Cart.hxx | 31 +++++++++++++- src/emucore/Cart0840.cxx | 2 +- src/emucore/Cart2K.cxx | 2 +- src/emucore/Cart3E.cxx | 2 +- src/emucore/Cart3EPlus.cxx | 2 +- src/emucore/Cart3F.cxx | 2 +- src/emucore/Cart4A50.cxx | 2 +- src/emucore/Cart4K.cxx | 3 +- src/emucore/Cart4KSC.cxx | 2 +- src/emucore/CartAR.cxx | 2 +- src/emucore/CartBF.cxx | 2 +- src/emucore/CartBFSC.cxx | 2 +- src/emucore/CartBUS.cxx | 2 +- src/emucore/CartCDF.cxx | 2 +- src/emucore/CartCM.cxx | 2 +- src/emucore/CartCTY.cxx | 2 +- src/emucore/CartCV.cxx | 2 +- src/emucore/CartCVPlus.cxx | 2 +- src/emucore/CartDASH.cxx | 2 +- src/emucore/CartDF.cxx | 2 +- src/emucore/CartDFSC.cxx | 2 +- src/emucore/CartDPC.cxx | 2 +- src/emucore/CartDPCPlus.cxx | 2 +- src/emucore/CartE0.cxx | 2 +- src/emucore/CartEF.cxx | 2 +- src/emucore/CartEFSC.cxx | 2 +- src/emucore/CartF0.cxx | 2 +- src/emucore/CartF4.cxx | 2 +- src/emucore/CartF4SC.cxx | 2 +- src/emucore/CartF6.cxx | 2 +- src/emucore/CartF6SC.cxx | 2 +- src/emucore/CartF8.cxx | 2 +- src/emucore/CartF8SC.cxx | 2 +- src/emucore/CartFA.cxx | 2 +- src/emucore/CartFA2.cxx | 2 +- src/emucore/CartFC.cxx | 2 +- src/emucore/CartFE.cxx | 2 +- src/emucore/CartMDM.cxx | 2 +- src/emucore/CartMNetwork.cxx | 2 +- src/emucore/CartSB.cxx | 2 +- src/emucore/CartUA.cxx | 2 +- src/emucore/CartWD.cxx | 2 +- src/emucore/CartX07.cxx | 2 +- src/emucore/Device.hxx | 25 +++++++++++ src/emucore/M6532.cxx | 74 +++++++++++++++++++++++++++++++++ src/emucore/M6532.hxx | 34 +++++++++++++-- src/emucore/System.cxx | 33 +++++++++++++++ src/emucore/System.hxx | 19 +++++++++ src/emucore/tia/TIA.cxx | 46 +++++++++++++++++++- src/emucore/tia/TIA.hxx | 32 +++++++++++++- 55 files changed, 446 insertions(+), 84 deletions(-) diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index 7e76d2dc1..e6dd39c0e 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -34,6 +34,8 @@ #include "Base.hxx" #include "Device.hxx" #include "exception/EmulationWarning.hxx" +#include "TIA.hxx" +#include "M6532.hxx" using Common::Base; using std::hex; @@ -69,16 +71,12 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem) } // Create bank information for each potential bank, and an extra one for ZP RAM - // Banksizes greater than 4096 indicate multi-bank ROMs, but we handle only - // 4K pieces at a time - // Banksizes less than 4K use the actual value - size_t banksize = 0; - myConsole.cartridge().getImage(banksize); - BankInfo info; - info.size = std::min(banksize, 4_KB); for(uInt32 i = 0; i < myConsole.cartridge().bankCount(); ++i) + { + info.size = myConsole.cartridge().bankSize(i); myBankInfo.push_back(info); + } info.size = 128; // ZP RAM myBankInfo.push_back(info); @@ -248,31 +246,9 @@ bool CartDebug::disassemble(bool force) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDebug::disassembleBank(int bank) { - // isolate the high 3 address bits, count them and - // select the most frequent to define the bank offset BankInfo& info = myBankInfo[bank]; - uInt16 count[8]; - for(int i = 0; i < 8; ++i) - count[i] = 0; - - for(uInt32 addr = 0x1000; addr < 0x1000 + info.size; ++addr) - { - Device::AccessFlags flags = mySystem.getAccessFlags(addr); - // only count really accessed addresses - if (flags & ~Device::ROW) - count[(flags & Device::HADDR) >> 13]++; - } - uInt16 max = 0, maxIdx = 0; - for(int idx = 0; idx < 8; ++idx) - { - if(count[idx] > max) - { - max = count[idx]; - maxIdx = idx; - } - } - info.offset = maxIdx << 13 | 0x1000; + info.offset = myConsole.cartridge().bankOrigin(bank); return disassemble(bank, info.offset, true); } @@ -1368,6 +1344,24 @@ string CartDebug::saveRom() return DebuggerParser::red("failed to save ROM"); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartDebug::saveAccessFile() +{ + const string& rom = myConsole.properties().get(PropType::Cart_Name) + ".cvs"; + FilesystemNode node(myOSystem.defaultSaveDir() + rom); + ofstream out(node.getPath()); + + if(out) + { + out << myConsole.tia().getAccessCounters(); + out << myConsole.riot().getAccessCounters(); + out << myConsole.cartridge().getAccessCounters(); + return "saved access counters as " + node.getShortPath(); + } + else + return DebuggerParser::red("failed to save access counters file"); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartDebug::listConfig(int bank) { diff --git a/src/debugger/CartDebug.hxx b/src/debugger/CartDebug.hxx index f0b4b49fe..7fff9c8a6 100644 --- a/src/debugger/CartDebug.hxx +++ b/src/debugger/CartDebug.hxx @@ -209,6 +209,11 @@ class CartDebug : public DebuggerSystem string saveDisassembly(); string saveRom(); + /** + Save access counters file + */ + string saveAccessFile(); + /** Show Distella directives (both set by the user and determined by Distella) for the given bank (or all banks, if no bank is specified). diff --git a/src/debugger/DebuggerParser.cxx b/src/debugger/DebuggerParser.cxx index fb905e8a5..4f50be800 100644 --- a/src/debugger/DebuggerParser.cxx +++ b/src/debugger/DebuggerParser.cxx @@ -678,7 +678,6 @@ string DebuggerParser::saveScriptFile(string file) return "saved " + node.getShortPath() + " OK"; } - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerParser::executeDirective(Device::AccessType type) { @@ -1810,6 +1809,13 @@ void DebuggerParser::executeSave() commandResult << saveScriptFile(argStrings[0]); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// "saveaccess" +void DebuggerParser::executeSaveAccess() +{ + commandResult << debugger.cartDebug().saveAccessFile(); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "saveconfig" void DebuggerParser::executeSaveconfig() @@ -2277,7 +2283,7 @@ void DebuggerParser::executeZ() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // List of all commands available to the parser -std::array DebuggerParser::commands = { { +std::array DebuggerParser::commands = { { { "a", "Set Accumulator to ", @@ -2998,6 +3004,16 @@ std::array DebuggerParser::commands = { { std::mem_fn(&DebuggerParser::executeSave) }, + { + "saveaccess", + "Save the access counters to CSV file", + "Example: saveaccess (no parameters)", + false, + false, + { Parameters::ARG_END_ARGS }, + std::mem_fn(&DebuggerParser::executeSaveAccess) + }, + { "saveconfig", "Save Distella config file (with default name)", diff --git a/src/debugger/DebuggerParser.hxx b/src/debugger/DebuggerParser.hxx index 9de21b3e9..44445b307 100644 --- a/src/debugger/DebuggerParser.hxx +++ b/src/debugger/DebuggerParser.hxx @@ -98,7 +98,7 @@ class DebuggerParser std::array parms; std::function executor; }; - static std::array commands; + static std::array commands; struct Trap { @@ -215,6 +215,7 @@ class DebuggerParser void executeRunToPc(); void executeS(); void executeSave(); + void executeSaveAccess(); void executeSaveallstates(); void executeSaveconfig(); void executeSavedisassembly(); diff --git a/src/emucore/Cart.cxx b/src/emucore/Cart.cxx index c5c13e34c..f6a787f48 100644 --- a/src/emucore/Cart.cxx +++ b/src/emucore/Cart.cxx @@ -20,6 +20,7 @@ #include "MD5.hxx" #ifdef DEBUGGER_SUPPORT #include "Debugger.hxx" + #include "Base.hxx" #endif #include "Cart.hxx" @@ -75,6 +76,16 @@ bool Cartridge::bankChanged() return changed; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt16 Cartridge::bankSize(uInt16 bank) const +{ + size_t size; + + getImage(size); + + return std::min(uInt32(size) / bankCount(), 4_KB); // assuming that each bank has the same size +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 Cartridge::peekRAM(uInt8& dest, uInt16 address) { @@ -113,16 +124,72 @@ void Cartridge::pokeRAM(uInt8& dest, uInt16 address, uInt8 value) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge::createRomAccessBase(size_t size) +void Cartridge::createRomAccessArrays(size_t size) { #ifdef DEBUGGER_SUPPORT myRomAccessBase = make_unique(size); std::fill_n(myRomAccessBase.get(), size, Device::ROW); + myRomAccessCounter = make_unique(size * 2); + std::fill_n(myRomAccessCounter.get(), size * 2, 0); #else myRomAccessBase = nullptr; + myRomAccessCounter = nullptr; #endif } +#ifdef DEBUGGER_SUPPORT +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string Cartridge::getAccessCounters() const +{ + ostringstream out; + + for(uInt16 bank = 0; bank < bankCount(); ++bank) + { + uInt32 offset = bank * bankSize(); + uInt16 origin = bankOrigin(bank); + + out << "Bank " << bank << " / 0.." << bankCount() - 1 << ":\n"; + for(uInt16 addr = 0; addr < bankSize(); ++addr) + { + out << Common::Base::HEX4 << (addr | origin) << "," + << Common::Base::toString(myRomAccessBase[offset + addr], Common::Base::Fmt::_10_8) << ", "; + } + out << "\n"; + } + + return out.str(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt16 Cartridge::bankOrigin(uInt16 bank) const +{ + // isolate the high 3 address bits, count them and + // select the most frequent to define the bank origin + std::array count; + uInt32 offset = bank * bankSize(); + + count.fill(0); + + for(uInt16 addr = 0x0000; addr < bankSize(bank); ++addr) + { + Device::AccessFlags flags = myRomAccessBase[offset + addr]; + // only count really accessed addresses + if (flags & ~Device::ROW) + count[(flags & Device::HADDR) >> 13]++; + } + uInt16 max = 0, maxIdx = 0; + for(int idx = 0; idx < 8; ++idx) + { + if(count[idx] > max) + { + max = count[idx]; + maxIdx = idx; + } + } + return maxIdx << 13 | 0x1000; +} +#endif + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge::initializeRAM(uInt8* arr, size_t size, uInt8 val) const { diff --git a/src/emucore/Cart.hxx b/src/emucore/Cart.hxx index 8a5124219..34e575a6c 100644 --- a/src/emucore/Cart.hxx +++ b/src/emucore/Cart.hxx @@ -136,6 +136,22 @@ class Cartridge : public Device @return Address of illegal access if one occurred, else 0 */ uInt16 getIllegalRAMWriteAccess() const { return myRamWriteAccess; } + + + /** + Query the access counters + + @return The access counters as comma separated string + */ + string getAccessCounters() const override; + + /** + Determine the bank's origin + + @param The bank to query + @return The origin of the bank + */ + uInt16 bankOrigin(uInt16 bank) const; #endif public: @@ -178,6 +194,14 @@ class Cartridge : public Device */ virtual uInt16 bankCount() const { return 1; } + /** + Get the size of a bank. + + @param bank The bank to get the size for + @return The bank's size + */ + virtual uInt16 bankSize(uInt16 bank = 0) const; + /** Patch the cartridge ROM. @@ -274,7 +298,7 @@ class Cartridge : public Device @param size The size of the code-access array to create */ - void createRomAccessBase(size_t size); + void createRomAccessArrays(size_t size); /** Fill the given RAM array with (possibly random) data. @@ -325,6 +349,11 @@ class Cartridge : public Device // whether it is used as code, data, graphics etc. std::unique_ptr myRomAccessBase; + // The array containing information about every byte of ROM indicating + // how often it is accessed. + std::unique_ptr myRomAccessCounter; + + // Contains address of illegal RAM write access or 0 uInt16 myRamWriteAccess{0}; diff --git a/src/emucore/Cart0840.cxx b/src/emucore/Cart0840.cxx index 21e0f35fd..f10dbb7b2 100644 --- a/src/emucore/Cart0840.cxx +++ b/src/emucore/Cart0840.cxx @@ -25,7 +25,7 @@ Cartridge0840::Cartridge0840(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Cart2K.cxx b/src/emucore/Cart2K.cxx index 5a6ffec5d..ed7820b1b 100644 --- a/src/emucore/Cart2K.cxx +++ b/src/emucore/Cart2K.cxx @@ -51,7 +51,7 @@ Cartridge2K::Cartridge2K(const ByteBuffer& image, size_t size, mySize = System::PAGE_SIZE; } - createRomAccessBase(mySize); + createRomAccessArrays(mySize); // Set mask for accessing the image buffer // This is guaranteed to work, as mySize is a power of two diff --git a/src/emucore/Cart3E.cxx b/src/emucore/Cart3E.cxx index 7df89d58c..a4683762b 100644 --- a/src/emucore/Cart3E.cxx +++ b/src/emucore/Cart3E.cxx @@ -30,7 +30,7 @@ Cartridge3E::Cartridge3E(const ByteBuffer& image, size_t size, // Copy the ROM image into my buffer std::copy_n(image.get(), mySize, myImage.get()); - createRomAccessBase(mySize + myRAM.size()); + createRomAccessArrays(mySize + myRAM.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Cart3EPlus.cxx b/src/emucore/Cart3EPlus.cxx index 1ca18f7d9..27eb94986 100644 --- a/src/emucore/Cart3EPlus.cxx +++ b/src/emucore/Cart3EPlus.cxx @@ -30,7 +30,7 @@ Cartridge3EPlus::Cartridge3EPlus(const ByteBuffer& image, size_t size, // Copy the ROM image into my buffer std::copy_n(image.get(), mySize, myImage.get()); - createRomAccessBase(mySize + myRAM.size()); + createRomAccessArrays(mySize + myRAM.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Cart3F.cxx b/src/emucore/Cart3F.cxx index 8be902554..47b5c4dcd 100644 --- a/src/emucore/Cart3F.cxx +++ b/src/emucore/Cart3F.cxx @@ -30,7 +30,7 @@ Cartridge3F::Cartridge3F(const ByteBuffer& image, size_t size, // Copy the ROM image into my buffer std::copy_n(image.get(), mySize, myImage.get()); - createRomAccessBase(mySize); + createRomAccessArrays(mySize); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Cart4A50.cxx b/src/emucore/Cart4A50.cxx index 373684481..845229bc4 100644 --- a/src/emucore/Cart4A50.cxx +++ b/src/emucore/Cart4A50.cxx @@ -41,7 +41,7 @@ Cartridge4A50::Cartridge4A50(const ByteBuffer& image, size_t size, // // Instead, access will be through the getAccessFlags and setAccessFlags // methods below - createRomAccessBase(myImage.size() + myRAM.size()); + createRomAccessArrays(myImage.size() + myRAM.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Cart4K.cxx b/src/emucore/Cart4K.cxx index 763bc35f0..417afccc8 100644 --- a/src/emucore/Cart4K.cxx +++ b/src/emucore/Cart4K.cxx @@ -25,7 +25,7 @@ Cartridge4K::Cartridge4K(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -47,6 +47,7 @@ void Cartridge4K::install(System& system) { access.directPeekBase = &myImage[addr & 0x0FFF]; access.romAccessBase = &myRomAccessBase[addr & 0x0FFF]; + access.romAccessCounter = &myRomAccessCounter[addr & 0x0FFF]; mySystem->setPageAccess(addr, access); } } diff --git a/src/emucore/Cart4KSC.cxx b/src/emucore/Cart4KSC.cxx index e65955735..09e043c94 100644 --- a/src/emucore/Cart4KSC.cxx +++ b/src/emucore/Cart4KSC.cxx @@ -25,7 +25,7 @@ Cartridge4KSC::Cartridge4KSC(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartAR.cxx b/src/emucore/CartAR.cxx index f4edb41ba..5201a14df 100644 --- a/src/emucore/CartAR.cxx +++ b/src/emucore/CartAR.cxx @@ -41,7 +41,7 @@ CartridgeAR::CartridgeAR(const ByteBuffer& image, size_t size, // // Instead, access will be through the getAccessFlags and setAccessFlags // methods below - createRomAccessBase(mySize); + createRomAccessArrays(mySize); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartBF.cxx b/src/emucore/CartBF.cxx index df773d805..91d13cbb7 100644 --- a/src/emucore/CartBF.cxx +++ b/src/emucore/CartBF.cxx @@ -25,7 +25,7 @@ CartridgeBF::CartridgeBF(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartBFSC.cxx b/src/emucore/CartBFSC.cxx index fdfac6f95..d0d33c79f 100644 --- a/src/emucore/CartBFSC.cxx +++ b/src/emucore/CartBFSC.cxx @@ -25,7 +25,7 @@ CartridgeBFSC::CartridgeBFSC(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartBUS.cxx b/src/emucore/CartBUS.cxx index 1dc991563..cb0be831f 100644 --- a/src/emucore/CartBUS.cxx +++ b/src/emucore/CartBUS.cxx @@ -49,7 +49,7 @@ CartridgeBUS::CartridgeBUS(const ByteBuffer& image, size_t size, std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); // Even though the ROM is 32K, only 28K is accessible to the 6507 - createRomAccessBase(28_KB); + createRomAccessArrays(28_KB); // Pointer to the program ROM (28K @ 0 byte offset) // which starts after the 2K BUS Driver and 2K C Code diff --git a/src/emucore/CartCDF.cxx b/src/emucore/CartCDF.cxx index 48f3d3d0f..3289b2e04 100644 --- a/src/emucore/CartCDF.cxx +++ b/src/emucore/CartCDF.cxx @@ -65,7 +65,7 @@ CartridgeCDF::CartridgeCDF(const ByteBuffer& image, size_t size, std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); // even though the ROM is 32K, only 28K is accessible to the 6507 - createRomAccessBase(28_KB); + createRomAccessArrays(28_KB); // Pointer to the program ROM (28K @ 0 byte offset) // which starts after the 2K CDF Driver and 2K C Code diff --git a/src/emucore/CartCM.cxx b/src/emucore/CartCM.cxx index 6bead1b33..7ce27bea4 100644 --- a/src/emucore/CartCM.cxx +++ b/src/emucore/CartCM.cxx @@ -27,7 +27,7 @@ CartridgeCM::CartridgeCM(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartCTY.cxx b/src/emucore/CartCTY.cxx index 40cae5597..9133ca891 100644 --- a/src/emucore/CartCTY.cxx +++ b/src/emucore/CartCTY.cxx @@ -28,7 +28,7 @@ CartridgeCTY::CartridgeCTY(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); // Default to no tune data in case user is utilizing an old ROM myTuneData.fill(0); diff --git a/src/emucore/CartCV.cxx b/src/emucore/CartCV.cxx index bea42e759..cb77d7790 100644 --- a/src/emucore/CartCV.cxx +++ b/src/emucore/CartCV.cxx @@ -40,7 +40,7 @@ CartridgeCV::CartridgeCV(const ByteBuffer& image, size_t size, // Copy the RAM image into a buffer for use in reset() std::copy_n(image.get(), myInitialRAM.size(), myInitialRAM.begin()); } - createRomAccessBase(myImage.size() + myRAM.size()); + createRomAccessArrays(myImage.size() + myRAM.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartCVPlus.cxx b/src/emucore/CartCVPlus.cxx index c0d9b01d2..86fb25d8b 100644 --- a/src/emucore/CartCVPlus.cxx +++ b/src/emucore/CartCVPlus.cxx @@ -30,7 +30,7 @@ CartridgeCVPlus::CartridgeCVPlus(const ByteBuffer& image, size_t size, // Copy the ROM image into my buffer std::copy_n(image.get(), mySize, myImage.get()); - createRomAccessBase(mySize + myRAM.size()); + createRomAccessArrays(mySize + myRAM.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartDASH.cxx b/src/emucore/CartDASH.cxx index e893b6f07..6e187d76a 100644 --- a/src/emucore/CartDASH.cxx +++ b/src/emucore/CartDASH.cxx @@ -30,7 +30,7 @@ CartridgeDASH::CartridgeDASH(const ByteBuffer& image, size_t size, // Copy the ROM image into my buffer std::copy_n(image.get(), mySize, myImage.get()); - createRomAccessBase(mySize + myRAM.size()); + createRomAccessArrays(mySize + myRAM.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartDF.cxx b/src/emucore/CartDF.cxx index 7e4ed9c2c..556d51bf6 100644 --- a/src/emucore/CartDF.cxx +++ b/src/emucore/CartDF.cxx @@ -25,7 +25,7 @@ CartridgeDF::CartridgeDF(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartDFSC.cxx b/src/emucore/CartDFSC.cxx index 530ef811c..993bbf226 100644 --- a/src/emucore/CartDFSC.cxx +++ b/src/emucore/CartDFSC.cxx @@ -25,7 +25,7 @@ CartridgeDFSC::CartridgeDFSC(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartDPC.cxx b/src/emucore/CartDPC.cxx index 2ac559a57..43d15dc7e 100644 --- a/src/emucore/CartDPC.cxx +++ b/src/emucore/CartDPC.cxx @@ -27,7 +27,7 @@ CartridgeDPC::CartridgeDPC(const ByteBuffer& image, size_t size, { // Make a copy of the entire image std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(8_KB); + createRomAccessArrays(8_KB); // Pointer to the program ROM (8K @ 0 byte offset) myProgramImage = myImage.data(); diff --git a/src/emucore/CartDPCPlus.cxx b/src/emucore/CartDPCPlus.cxx index 5e92ec2a1..c9392fdc8 100644 --- a/src/emucore/CartDPCPlus.cxx +++ b/src/emucore/CartDPCPlus.cxx @@ -36,7 +36,7 @@ CartridgeDPCPlus::CartridgeDPCPlus(const ByteBuffer& image, size_t size, if(mySize < myImage.size()) myImage.fill(0); std::copy_n(image.get(), size, myImage.begin() + (myImage.size() - mySize)); - createRomAccessBase(24_KB); + createRomAccessArrays(24_KB); // Pointer to the program ROM (24K @ 3K offset; ignore first 3K) myProgramImage = myImage.data() + 3_KB; diff --git a/src/emucore/CartE0.cxx b/src/emucore/CartE0.cxx index 96029f903..9102788f2 100644 --- a/src/emucore/CartE0.cxx +++ b/src/emucore/CartE0.cxx @@ -25,7 +25,7 @@ CartridgeE0::CartridgeE0(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartEF.cxx b/src/emucore/CartEF.cxx index 96c5cf0da..1de837bf7 100644 --- a/src/emucore/CartEF.cxx +++ b/src/emucore/CartEF.cxx @@ -25,7 +25,7 @@ CartridgeEF::CartridgeEF(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartEFSC.cxx b/src/emucore/CartEFSC.cxx index 8c9cdbb3c..4cb481547 100644 --- a/src/emucore/CartEFSC.cxx +++ b/src/emucore/CartEFSC.cxx @@ -25,7 +25,7 @@ CartridgeEFSC::CartridgeEFSC(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartF0.cxx b/src/emucore/CartF0.cxx index bb10ccd43..44f967327 100644 --- a/src/emucore/CartF0.cxx +++ b/src/emucore/CartF0.cxx @@ -25,7 +25,7 @@ CartridgeF0::CartridgeF0(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartF4.cxx b/src/emucore/CartF4.cxx index 81e53a238..5576f5fd3 100644 --- a/src/emucore/CartF4.cxx +++ b/src/emucore/CartF4.cxx @@ -26,7 +26,7 @@ CartridgeF4::CartridgeF4(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartF4SC.cxx b/src/emucore/CartF4SC.cxx index 79e34e854..98d9f675c 100644 --- a/src/emucore/CartF4SC.cxx +++ b/src/emucore/CartF4SC.cxx @@ -25,7 +25,7 @@ CartridgeF4SC::CartridgeF4SC(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartF6.cxx b/src/emucore/CartF6.cxx index 8bf672695..43ae4abe7 100644 --- a/src/emucore/CartF6.cxx +++ b/src/emucore/CartF6.cxx @@ -25,7 +25,7 @@ CartridgeF6::CartridgeF6(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartF6SC.cxx b/src/emucore/CartF6SC.cxx index dbcd4c340..5ee84ee8a 100644 --- a/src/emucore/CartF6SC.cxx +++ b/src/emucore/CartF6SC.cxx @@ -25,7 +25,7 @@ CartridgeF6SC::CartridgeF6SC(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartF8.cxx b/src/emucore/CartF8.cxx index cde6d47f0..bb06d9414 100644 --- a/src/emucore/CartF8.cxx +++ b/src/emucore/CartF8.cxx @@ -25,7 +25,7 @@ CartridgeF8::CartridgeF8(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartF8SC.cxx b/src/emucore/CartF8SC.cxx index 549fbea35..e45298779 100644 --- a/src/emucore/CartF8SC.cxx +++ b/src/emucore/CartF8SC.cxx @@ -25,7 +25,7 @@ CartridgeF8SC::CartridgeF8SC(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartFA.cxx b/src/emucore/CartFA.cxx index e06b869b6..c91ea3b8e 100644 --- a/src/emucore/CartFA.cxx +++ b/src/emucore/CartFA.cxx @@ -25,7 +25,7 @@ CartridgeFA::CartridgeFA(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartFA2.cxx b/src/emucore/CartFA2.cxx index e6325e9ac..57fb118bb 100644 --- a/src/emucore/CartFA2.cxx +++ b/src/emucore/CartFA2.cxx @@ -35,7 +35,7 @@ CartridgeFA2::CartridgeFA2(const ByteBuffer& image, size_t size, // Copy the ROM image into my buffer std::copy_n(img_ptr, mySize, myImage.begin()); - createRomAccessBase(mySize); + createRomAccessArrays(mySize); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartFC.cxx b/src/emucore/CartFC.cxx index 5195e499e..a35b531ca 100644 --- a/src/emucore/CartFC.cxx +++ b/src/emucore/CartFC.cxx @@ -26,7 +26,7 @@ CartridgeFC::CartridgeFC(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartFE.cxx b/src/emucore/CartFE.cxx index de5c088e9..c827906f9 100644 --- a/src/emucore/CartFE.cxx +++ b/src/emucore/CartFE.cxx @@ -26,7 +26,7 @@ CartridgeFE::CartridgeFE(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartMDM.cxx b/src/emucore/CartMDM.cxx index 6eaacee0b..a3b0a0a6c 100644 --- a/src/emucore/CartMDM.cxx +++ b/src/emucore/CartMDM.cxx @@ -29,7 +29,7 @@ CartridgeMDM::CartridgeMDM(const ByteBuffer& image, size_t size, // Copy the ROM image into my buffer std::copy_n(image.get(), mySize, myImage.get()); - createRomAccessBase(mySize); + createRomAccessArrays(mySize); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartMNetwork.cxx b/src/emucore/CartMNetwork.cxx index 9c3213292..e9a3a5e45 100644 --- a/src/emucore/CartMNetwork.cxx +++ b/src/emucore/CartMNetwork.cxx @@ -34,7 +34,7 @@ void CartridgeMNetwork::initialize(const ByteBuffer& image, size_t size) // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(romSize(), size), myImage.get()); - createRomAccessBase(romSize() + myRAM.size()); + createRomAccessArrays(romSize() + myRAM.size()); myRAMSlice = bankCount() - 1; } diff --git a/src/emucore/CartSB.cxx b/src/emucore/CartSB.cxx index db8d4a051..34db0cca1 100644 --- a/src/emucore/CartSB.cxx +++ b/src/emucore/CartSB.cxx @@ -29,7 +29,7 @@ CartridgeSB::CartridgeSB(const ByteBuffer& image, size_t size, // Copy the ROM image into my buffer std::copy_n(image.get(), mySize, myImage.get()); - createRomAccessBase(mySize); + createRomAccessArrays(mySize); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartUA.cxx b/src/emucore/CartUA.cxx index b0643cf97..b4729c38e 100644 --- a/src/emucore/CartUA.cxx +++ b/src/emucore/CartUA.cxx @@ -27,7 +27,7 @@ CartridgeUA::CartridgeUA(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartWD.cxx b/src/emucore/CartWD.cxx index 2a6ea653a..254c78aa4 100644 --- a/src/emucore/CartWD.cxx +++ b/src/emucore/CartWD.cxx @@ -37,7 +37,7 @@ CartridgeWD::CartridgeWD(const ByteBuffer& image, size_t size, } else std::copy_n(image.get(), mySize, myImage.begin()); - createRomAccessBase(8_KB); + createRomAccessArrays(8_KB); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartX07.cxx b/src/emucore/CartX07.cxx index a58b97abb..fc58b0df5 100644 --- a/src/emucore/CartX07.cxx +++ b/src/emucore/CartX07.cxx @@ -27,7 +27,7 @@ CartridgeX07::CartridgeX07(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Device.hxx b/src/emucore/Device.hxx index ecb857e21..496306ae2 100644 --- a/src/emucore/Device.hxx +++ b/src/emucore/Device.hxx @@ -63,6 +63,8 @@ class Device : public Serializable }; using AccessFlags = uInt16; + using AccessCounter = uInt32; + public: Device() = default; virtual ~Device() = default; @@ -128,6 +130,7 @@ class Device : public Serializable */ virtual bool poke(uInt16 address, uInt8 value) { return false; } + #ifdef DEBUGGER_SUPPORT /** Query the given address for its access flags @@ -143,6 +146,28 @@ class Device : public Serializable */ virtual void setAccessFlags(uInt16 address, AccessFlags flags) { } + /** + Query the given address for its access counter + + @param address The address to query for + */ + virtual AccessCounter getAccessCounter(uInt16 address) const { return 0; } + + /** + Increase the given address's access counter + + @param address The address to modify + */ + virtual void increaseAccessCounter(uInt16 address, bool isWrite = false) { } + + /** + Query the access counters + + @return The access counters as comma separated string + */ + virtual string getAccessCounters() const { return ""; }; + #endif + protected: /// Pointer to the system the device is installed in or the null pointer System* mySystem{nullptr}; diff --git a/src/emucore/M6532.cxx b/src/emucore/M6532.cxx index 645a4a332..8165b5294 100644 --- a/src/emucore/M6532.cxx +++ b/src/emucore/M6532.cxx @@ -21,6 +21,7 @@ #include "Settings.hxx" #include "Switches.hxx" #include "System.hxx" +#include "Base.hxx" #include "M6532.hxx" @@ -460,6 +461,9 @@ void M6532::createAccessBases() myRAMAccessBase.fill(Device::NONE); myStackAccessBase.fill(Device::NONE); myIOAccessBase.fill(Device::NONE); + myRAMAccessCounter.fill(0); + myStackAccessCounter.fill(0); + myIOAccessCounter.fill(0); myZPAccessDelay.fill(ZP_DELAY); } @@ -492,4 +496,74 @@ void M6532::setAccessFlags(uInt16 address, Device::AccessFlags flags) } } } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Device::AccessCounter M6532::getAccessCounter(uInt16 address) const +{ + if (address & IO_BIT) + return myIOAccessCounter[address & IO_MASK]; + else if (address & STACK_BIT) + return myStackAccessCounter[address & STACK_MASK]; + else + return myRAMAccessCounter[address & RAM_MASK]; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void M6532::increaseAccessCounter(uInt16 address, bool isWrite) +{ + if (address & IO_BIT) + myIOAccessCounter[isWrite ? 0 : IO_SIZE + (address & IO_MASK)]++; + else { + // the first access, either by direct RAM or stack access is assumed as initialization + if (myZPAccessDelay[address & RAM_MASK]) + myZPAccessDelay[address & RAM_MASK]--; + else if (address & STACK_BIT) + myStackAccessCounter[isWrite ? 0 : STACK_SIZE + (address & STACK_MASK)]++; + else + myRAMAccessCounter[isWrite ? 0 : RAM_SIZE + (address & RAM_MASK)]++; + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string M6532::getAccessCounters() const +{ + ostringstream out; + + out << "RAM reads:\n"; + for(uInt16 addr = 0x00; addr < RAM_SIZE; ++addr) + out << Common::Base::HEX4 << (addr | 0x80) << "," + << Common::Base::toString(myRAMAccessCounter[addr], Common::Base::Fmt::_10_8) << ", "; + out << "\n"; + out << "RAM writes:\n"; + for(uInt16 addr = 0x00; addr < RAM_SIZE; ++addr) + out << Common::Base::HEX4 << (addr | 0x80) << "," + << Common::Base::toString(myRAMAccessCounter[RAM_SIZE + addr], Common::Base::Fmt::_10_8) << ", "; + out << "\n"; + + + out << "Stack reads:\n"; + for(uInt16 addr = 0x00; addr < STACK_SIZE; ++addr) + out << Common::Base::HEX4 << (addr | 0x180) << "," + << Common::Base::toString(myStackAccessCounter[addr], Common::Base::Fmt::_10_8) << ", "; + out << "\n"; + out << "Stack writes:\n"; + for(uInt16 addr = 0x00; addr < STACK_SIZE; ++addr) + out << Common::Base::HEX4 << (addr | 0x180) << "," + << Common::Base::toString(myStackAccessCounter[STACK_SIZE + addr], Common::Base::Fmt::_10_8) << ", "; + out << "\n"; + + out << "IO reads:\n"; + for(uInt16 addr = 0x00; addr < IO_SIZE; ++addr) + out << Common::Base::HEX4 << (addr | 0x280) << "," + << Common::Base::toString(myIOAccessCounter[addr], Common::Base::Fmt::_10_8) << ", "; + out << "\n"; + out << "IO writes:\n"; + for(uInt16 addr = 0x00; addr < IO_SIZE; ++addr) + out << Common::Base::HEX4 << (addr | 0x280) << "," + << Common::Base::toString(myIOAccessCounter[IO_SIZE + addr], Common::Base::Fmt::_10_8) << ", "; + out << "\n"; + + return out.str(); +} + #endif // DEBUGGER_SUPPORT diff --git a/src/emucore/M6532.hxx b/src/emucore/M6532.hxx index 4f543b8a8..d4cb695c9 100644 --- a/src/emucore/M6532.hxx +++ b/src/emucore/M6532.hxx @@ -130,12 +130,21 @@ class M6532 : public Device */ const uInt8* getRAM() const { return myRAM.data(); } + #ifdef DEBUGGER_SUPPORT + /** + Query the access counters + + @return The access counters as comma separated string + */ + string getAccessCounters() const override; + #endif + private: void setTimerRegister(uInt8 data, uInt8 interval); void setPinState(bool shcha); -#ifdef DEBUGGER_SUPPORT + #ifdef DEBUGGER_SUPPORT // The following are used by the debugger to read INTIM/TIMINT // We need separate methods to do this, so the state of the system // isn't changed @@ -159,7 +168,21 @@ class M6532 : public Device @param flags A bitfield of AccessType directives for the given address */ void setAccessFlags(uInt16 address, Device::AccessFlags flags) override; -#endif // DEBUGGER_SUPPORT + + /** + Query the given address for its access counter + + @param address The address to query for + */ + Device::AccessCounter getAccessCounter(uInt16 address) const override; + + /** + Increase the given address's access counter + + @param address The address to modify + */ + void increaseAccessCounter(uInt16 address, bool isWrite) override; + #endif // DEBUGGER_SUPPORT private: // Reference to the console @@ -221,13 +244,18 @@ class M6532 : public Device RAM_SIZE = 0x80, RAM_MASK = RAM_SIZE - 1, STACK_SIZE = RAM_SIZE, STACK_MASK = RAM_MASK, STACK_BIT = 0x100, IO_SIZE = 0x20, IO_MASK = IO_SIZE - 1, IO_BIT = 0x200, - ZP_DELAY = 1; + ZP_DELAY = 1 * 2; // The arrays containing information about every byte of RIOT // indicating whether and how (RW) it is used. std::array myRAMAccessBase; std::array myStackAccessBase; std::array myIOAccessBase; + // The arrays containing information about every byte of RIOT + // indicating how often it is accessed. + std::array myRAMAccessCounter; + std::array myStackAccessCounter; + std::array myIOAccessCounter; // The array used to skip the first ZP access tracking std::array myZPAccessDelay; #endif // DEBUGGER_SUPPORT diff --git a/src/emucore/System.cxx b/src/emucore/System.cxx index c94f465fd..b1f0c538a 100644 --- a/src/emucore/System.cxx +++ b/src/emucore/System.cxx @@ -109,6 +109,11 @@ uInt8 System::peek(uInt16 addr, Device::AccessFlags flags) *(access.romAccessBase + (addr & PAGE_MASK)) |= (flags | (addr & Device::HADDR)); else access.device->setAccessFlags(addr, flags); + // Increase access counter + if(access.romAccessCounter) + *(access.romAccessCounter + (addr & PAGE_MASK)) += 1; + else + access.device->increaseAccessCounter(addr); #endif // See if this page uses direct accessing or not @@ -138,6 +143,11 @@ void System::poke(uInt16 addr, uInt8 value, Device::AccessFlags flags) *(access.romAccessBase + (addr & PAGE_MASK)) |= (flags | (addr & Device::HADDR)); else access.device->setAccessFlags(addr, flags); + // Increase access counter + if(access.romAccessCounter) + *(access.romAccessCounter + (addr & PAGE_MASK)) += 1; + else + access.device->increaseAccessCounter(addr, true); #endif // See if this page uses direct accessing or not @@ -181,6 +191,29 @@ void System::setAccessFlags(uInt16 addr, Device::AccessFlags flags) else access.device->setAccessFlags(addr, flags); } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Device::AccessCounter System::getAccessCounter(uInt16 addr) const +{ + const PageAccess& access = getPageAccess(addr); + + if(access.romAccessCounter) + return *(access.romAccessCounter + (addr & PAGE_MASK)); + else + return access.device->getAccessCounter(addr); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void System::increaseAccessCounter(uInt16 addr, bool isWrite) +{ + const PageAccess& access = getPageAccess(addr); + + if(access.romAccessCounter) + *(access.romAccessCounter + (addr & PAGE_MASK)) += 1; + else + access.device->increaseAccessCounter(addr, isWrite); +} + #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/System.hxx b/src/emucore/System.hxx index b400b1cdb..6c5547d7f 100644 --- a/src/emucore/System.hxx +++ b/src/emucore/System.hxx @@ -239,6 +239,20 @@ class System : public Serializable */ Device::AccessFlags getAccessFlags(uInt16 address) const; void setAccessFlags(uInt16 address, Device::AccessFlags flags); + + /** + Query the given address for its access counter + + @param address The address to query for + */ + Device::AccessCounter getAccessCounter(uInt16 address) const; + + /** + Increase the given address's access counter + + @param address The address to modify + */ + void increaseAccessCounter(uInt16 address, bool isWrite); #endif public: @@ -285,6 +299,11 @@ class System : public Serializable */ Device::AccessFlags* romAccessBase{nullptr}; + /** + TODO + */ + Device::AccessCounter* romAccessCounter{nullptr}; + /** Pointer to the device associated with this page or to the system's null device if the page hasn't been mapped to a device. diff --git a/src/emucore/tia/TIA.cxx b/src/emucore/tia/TIA.cxx index c5896c3aa..57192b436 100644 --- a/src/emucore/tia/TIA.cxx +++ b/src/emucore/tia/TIA.cxx @@ -24,6 +24,7 @@ #include "frame-manager/FrameManager.hxx" #include "AudioQueue.hxx" #include "DispatchResult.hxx" +#include "Base.hxx" enum CollisionMask: uInt32 { player0 = 0b0111110000000000, @@ -183,7 +184,7 @@ void TIA::initialize() enableFixedColors(mySettings.getBool(devSettings ? "dev.debugcolors" : "plr.debugcolors")); #ifdef DEBUGGER_SUPPORT - createAccessBase(); + createAccessArrays(); #endif // DEBUGGER_SUPPORT } @@ -1950,9 +1951,10 @@ void TIA::toggleCollBLPF() #ifdef DEBUGGER_SUPPORT // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::createAccessBase() +void TIA::createAccessArrays() { myAccessBase.fill(Device::NONE); + myAccessCounter.fill(0); myAccessDelay.fill(TIA_DELAY); } @@ -1977,4 +1979,44 @@ void TIA::setAccessFlags(uInt16 address, Device::AccessFlags flags) myAccessBase[address & TIA_READ_MASK] |= flags; } } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Device::AccessCounter TIA::getAccessCounter(uInt16 address) const +{ + return myAccessCounter[address & TIA_MASK]; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIA::increaseAccessCounter(uInt16 address, bool isWrite) +{ + if(isWrite) + { + // the first two write accesses are assumed as initialization + if(myAccessDelay[address & TIA_MASK]) + myAccessDelay[address & TIA_MASK]--; + else + myAccessCounter[address & TIA_MASK]++; + } + else + myAccessCounter[TIA_SIZE + (address & TIA_READ_MASK)]++; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string TIA::getAccessCounters() const +{ + ostringstream out; + + out << "TIA reads:\n"; + for(uInt16 addr = 0x00; addr < TIA_READ_SIZE; ++addr) + out << Common::Base::HEX4 << addr << "," + << Common::Base::toString(myAccessCounter[TIA_SIZE + addr], Common::Base::Fmt::_10_8) << ", "; + out << "\n"; + out << "TIA writes:\n"; + for(uInt16 addr = 0x00; addr < TIA_SIZE; ++addr) + out << Common::Base::HEX4 << addr << "," + << Common::Base::toString(myAccessCounter[addr], Common::Base::Fmt::_10_8) << ", "; + out << "\n"; + + return out.str(); +} #endif // DEBUGGER_SUPPORT diff --git a/src/emucore/tia/TIA.hxx b/src/emucore/tia/TIA.hxx index 30c3d04f5..28481dfc6 100644 --- a/src/emucore/tia/TIA.hxx +++ b/src/emucore/tia/TIA.hxx @@ -530,6 +530,15 @@ class TIA : public Device */ void updateEmulation(); + #ifdef DEBUGGER_SUPPORT + /** + Query the access counters + + @return The access counters as comma separated string + */ + string getAccessCounters() const; + #endif + private: /** * During each line, the TIA cycles through these two states. @@ -678,7 +687,7 @@ class TIA : public Device void applyDeveloperSettings(); #ifdef DEBUGGER_SUPPORT - void createAccessBase(); + void createAccessArrays(); /** * Query the given address type for the associated access flags. @@ -693,6 +702,20 @@ class TIA : public Device * @param flags A bitfield of AccessType directives for the given address */ void setAccessFlags(uInt16 address, Device::AccessFlags flags) override; + + /** + Query the given address for its access counter + + @param address The address to query for + */ + Device::AccessCounter getAccessCounter(uInt16 address) const override; + + /** + Increase the given address's access counter + + @param address The address to modify + */ + void increaseAccessCounter(uInt16 address, bool isWrite) override; #endif // DEBUGGER_SUPPORT private: @@ -896,12 +919,17 @@ class TIA : public Device uInt8 myJitterFactor{0}; static constexpr uInt16 - TIA_SIZE = 0x40, TIA_MASK = TIA_SIZE - 1, TIA_READ_MASK = 0x0f, TIA_BIT = 0x080, TIA_DELAY = 2; + TIA_SIZE = 0x40, TIA_MASK = TIA_SIZE - 1, + TIA_READ_SIZE = 0x10, TIA_READ_MASK = TIA_READ_SIZE - 1, + TIA_BIT = 0x080, TIA_DELAY = 2 * 2; #ifdef DEBUGGER_SUPPORT // The arrays containing information about every byte of TIA // indicating whether and how (RW) it is used. std::array myAccessBase; + // The arrays containing information about every byte of TIA + // indicating how often it is accessed (read and write). + std::array myAccessCounter; // The array used to skip the first two TIA access trackings std::array myAccessDelay; From 7b16436a84d3f869ca860a16abe0faeab3662ffb Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Wed, 1 Apr 2020 09:45:19 -0230 Subject: [PATCH 071/377] Fix warnings from clang. --- src/emucore/Cart.hxx | 2 +- src/emucore/Device.hxx | 2 +- src/emucore/tia/TIA.hxx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/emucore/Cart.hxx b/src/emucore/Cart.hxx index 34e575a6c..dda0684fd 100644 --- a/src/emucore/Cart.hxx +++ b/src/emucore/Cart.hxx @@ -148,7 +148,7 @@ class Cartridge : public Device /** Determine the bank's origin - @param The bank to query + @param bank The bank to query @return The origin of the bank */ uInt16 bankOrigin(uInt16 bank) const; diff --git a/src/emucore/Device.hxx b/src/emucore/Device.hxx index 496306ae2..54f7b6264 100644 --- a/src/emucore/Device.hxx +++ b/src/emucore/Device.hxx @@ -165,7 +165,7 @@ class Device : public Serializable @return The access counters as comma separated string */ - virtual string getAccessCounters() const { return ""; }; + virtual string getAccessCounters() const { return ""; } #endif protected: diff --git a/src/emucore/tia/TIA.hxx b/src/emucore/tia/TIA.hxx index 28481dfc6..02c35ed24 100644 --- a/src/emucore/tia/TIA.hxx +++ b/src/emucore/tia/TIA.hxx @@ -536,7 +536,7 @@ class TIA : public Device @return The access counters as comma separated string */ - string getAccessCounters() const; + string getAccessCounters() const override; #endif private: From 3687180144e04499471692d0a398c13d88d38f5b Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 1 Apr 2020 22:14:22 +0200 Subject: [PATCH 072/377] differentiate ROM read/write access (done for Atari standard and 3E bankswitching) --- src/debugger/CartDebug.cxx | 2 +- src/emucore/Cart.cxx | 41 +++++++++++++++++++++++------- src/emucore/Cart2K.cxx | 2 ++ src/emucore/Cart3E.cxx | 8 ++++++ src/emucore/Cart4K.cxx | 3 ++- src/emucore/CartF4.cxx | 4 +++ src/emucore/CartF4SC.cxx | 8 ++++++ src/emucore/CartF6.cxx | 4 +++ src/emucore/CartF6SC.cxx | 8 ++++++ src/emucore/CartF8.cxx | 4 +++ src/emucore/CartF8SC.cxx | 8 ++++++ src/emucore/Device.hxx | 7 ----- src/emucore/M6532.cxx | 11 -------- src/emucore/M6532.hxx | 7 ----- src/emucore/System.cxx | 52 ++++++++++++++++++++------------------ src/emucore/System.hxx | 14 +++++----- src/emucore/tia/TIA.cxx | 6 ----- src/emucore/tia/TIA.hxx | 7 ----- 18 files changed, 115 insertions(+), 81 deletions(-) diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index e6dd39c0e..612f51542 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -1347,7 +1347,7 @@ string CartDebug::saveRom() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartDebug::saveAccessFile() { - const string& rom = myConsole.properties().get(PropType::Cart_Name) + ".cvs"; + const string& rom = myConsole.properties().get(PropType::Cart_Name) + ".csv"; FilesystemNode node(myOSystem.defaultSaveDir() + rom); ofstream out(node.getPath()); diff --git a/src/emucore/Cart.cxx b/src/emucore/Cart.cxx index f6a787f48..a4fe19857 100644 --- a/src/emucore/Cart.cxx +++ b/src/emucore/Cart.cxx @@ -142,19 +142,32 @@ void Cartridge::createRomAccessArrays(size_t size) string Cartridge::getAccessCounters() const { ostringstream out; + size_t romSize; + uInt32 offset = 0; + + getImage(romSize); for(uInt16 bank = 0; bank < bankCount(); ++bank) { - uInt32 offset = bank * bankSize(); uInt16 origin = bankOrigin(bank); + uInt16 bankSize = this->bankSize(bank); - out << "Bank " << bank << " / 0.." << bankCount() - 1 << ":\n"; - for(uInt16 addr = 0; addr < bankSize(); ++addr) + out << "Bank " << bank << " / 0.." << bankCount() - 1 << " reads:\n"; + for(uInt16 addr = 0; addr < bankSize; ++addr) { out << Common::Base::HEX4 << (addr | origin) << "," - << Common::Base::toString(myRomAccessBase[offset + addr], Common::Base::Fmt::_10_8) << ", "; + << Common::Base::toString(myRomAccessCounter[offset + addr], Common::Base::Fmt::_10_8) << ", "; } out << "\n"; + out << "Bank " << bank << " / 0.." << bankCount() - 1 << " writes:\n"; + for(uInt16 addr = 0; addr < bankSize; ++addr) + { + out << Common::Base::HEX4 << (addr | origin) << "," + << Common::Base::toString(myRomAccessCounter[offset + addr + romSize], Common::Base::Fmt::_10_8) << ", "; + } + out << "\n"; + + offset += bankSize; } return out.str(); @@ -165,20 +178,30 @@ uInt16 Cartridge::bankOrigin(uInt16 bank) const { // isolate the high 3 address bits, count them and // select the most frequent to define the bank origin - std::array count; + const int intervals = 0x8000 / 0x100; uInt32 offset = bank * bankSize(); + //uInt16 addrMask = (4_KB - 1) & ~(bankSize(bank) - 1); + //int addrShift = 0; + std::array count; // up to 128 256 byte interval origins + + + //if(addrMask) + // addrShift = log(addrMask) / log(2); + //addrMask; count.fill(0); - for(uInt16 addr = 0x0000; addr < bankSize(bank); ++addr) { Device::AccessFlags flags = myRomAccessBase[offset + addr]; // only count really accessed addresses - if (flags & ~Device::ROW) + if(flags & ~Device::ROW) + { + //uInt16 addrBit = addr >> addrShift; count[(flags & Device::HADDR) >> 13]++; + } } uInt16 max = 0, maxIdx = 0; - for(int idx = 0; idx < 8; ++idx) + for(int idx = 0; idx < intervals; ++idx) { if(count[idx] > max) { @@ -186,7 +209,7 @@ uInt16 Cartridge::bankOrigin(uInt16 bank) const maxIdx = idx; } } - return maxIdx << 13 | 0x1000; + return maxIdx << 13 | 0x1000 | (offset & 0xfff); } #endif diff --git a/src/emucore/Cart2K.cxx b/src/emucore/Cart2K.cxx index ed7820b1b..c5a5717c6 100644 --- a/src/emucore/Cart2K.cxx +++ b/src/emucore/Cart2K.cxx @@ -77,6 +77,8 @@ void Cartridge2K::install(System& system) { access.directPeekBase = &myImage[addr & myMask]; access.romAccessBase = &myRomAccessBase[addr & myMask]; + access.romPeekCounter = &myRomAccessCounter[addr & 0x0FFF]; + access.romPokeCounter = &myRomAccessCounter[(addr & 0x0FFF) + mySize]; mySystem->setPageAccess(addr, access); } } diff --git a/src/emucore/Cart3E.cxx b/src/emucore/Cart3E.cxx index a4683762b..f9fb495e0 100644 --- a/src/emucore/Cart3E.cxx +++ b/src/emucore/Cart3E.cxx @@ -60,6 +60,8 @@ void Cartridge3E::install(System& system) { access.directPeekBase = &myImage[(mySize - 2048) + (addr & 0x07FF)]; access.romAccessBase = &myRomAccessBase[(mySize - 2048) + (addr & 0x07FF)]; + access.romPeekCounter = &myRomAccessCounter[(mySize - 2048) + (addr & 0x07FF)]; + access.romPokeCounter = &myRomAccessCounter[(mySize - 2048) + (addr & 0x07FF) + mySize]; mySystem->setPageAccess(addr, access); } @@ -159,6 +161,8 @@ bool Cartridge3E::bank(uInt16 bank) { access.directPeekBase = &myImage[offset + (addr & 0x07FF)]; access.romAccessBase = &myRomAccessBase[offset + (addr & 0x07FF)]; + access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x07FF)]; + access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x07FF) + mySize]; mySystem->setPageAccess(addr, access); } } @@ -178,6 +182,8 @@ bool Cartridge3E::bank(uInt16 bank) { access.directPeekBase = &myRAM[offset + (addr & 0x03FF)]; access.romAccessBase = &myRomAccessBase[mySize + offset + (addr & 0x03FF)]; + access.romPeekCounter = &myRomAccessCounter[mySize + offset + (addr & 0x03FF)]; + access.romPokeCounter = &myRomAccessCounter[mySize + offset + (addr & 0x03FF) + mySize]; mySystem->setPageAccess(addr, access); } @@ -190,6 +196,8 @@ bool Cartridge3E::bank(uInt16 bank) for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[mySize + offset + (addr & 0x03FF)]; + access.romPeekCounter = &myRomAccessCounter[mySize + offset + (addr & 0x03FF)]; + access.romPokeCounter = &myRomAccessCounter[mySize + offset + (addr & 0x03FF) + mySize]; mySystem->setPageAccess(addr, access); } } diff --git a/src/emucore/Cart4K.cxx b/src/emucore/Cart4K.cxx index 417afccc8..af88dd1f9 100644 --- a/src/emucore/Cart4K.cxx +++ b/src/emucore/Cart4K.cxx @@ -47,7 +47,8 @@ void Cartridge4K::install(System& system) { access.directPeekBase = &myImage[addr & 0x0FFF]; access.romAccessBase = &myRomAccessBase[addr & 0x0FFF]; - access.romAccessCounter = &myRomAccessCounter[addr & 0x0FFF]; + access.romPeekCounter = &myRomAccessCounter[addr & 0x0FFF]; + access.romPokeCounter = &myRomAccessCounter[(addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } } diff --git a/src/emucore/CartF4.cxx b/src/emucore/CartF4.cxx index 5576f5fd3..d377ecedc 100644 --- a/src/emucore/CartF4.cxx +++ b/src/emucore/CartF4.cxx @@ -89,6 +89,8 @@ bool CartridgeF4::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } @@ -98,6 +100,8 @@ bool CartridgeF4::bank(uInt16 bank) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartF4SC.cxx b/src/emucore/CartF4SC.cxx index 98d9f675c..580dded30 100644 --- a/src/emucore/CartF4SC.cxx +++ b/src/emucore/CartF4SC.cxx @@ -52,6 +52,8 @@ void CartridgeF4SC::install(System& system) for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[addr & 0x007F]; + access.romPeekCounter = &myRomAccessCounter[addr & 0x007F]; + access.romPokeCounter = &myRomAccessCounter[(addr & 0x07F) + myImage.size()]; mySystem->setPageAccess(addr, access); } @@ -61,6 +63,8 @@ void CartridgeF4SC::install(System& system) { access.directPeekBase = &myRAM[addr & 0x007F]; access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)]; + access.romPeekCounter = &myRomAccessCounter[0x80 + (addr & 0x007F)]; + access.romPokeCounter = &myRomAccessCounter[0x80 + (addr & 0x007F) + myImage.size()]; mySystem->setPageAccess(addr, access); } @@ -128,6 +132,8 @@ bool CartridgeF4SC::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } @@ -137,6 +143,8 @@ bool CartridgeF4SC::bank(uInt16 bank) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartF6.cxx b/src/emucore/CartF6.cxx index 43ae4abe7..5a263498e 100644 --- a/src/emucore/CartF6.cxx +++ b/src/emucore/CartF6.cxx @@ -129,6 +129,8 @@ bool CartridgeF6::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } @@ -138,6 +140,8 @@ bool CartridgeF6::bank(uInt16 bank) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartF6SC.cxx b/src/emucore/CartF6SC.cxx index 5ee84ee8a..b6b0e3659 100644 --- a/src/emucore/CartF6SC.cxx +++ b/src/emucore/CartF6SC.cxx @@ -52,6 +52,8 @@ void CartridgeF6SC::install(System& system) for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[addr & 0x007F]; + access.romPeekCounter = &myRomAccessCounter[addr & 0x007F]; + access.romPokeCounter = &myRomAccessCounter[(addr & 0x07F) + myImage.size()]; mySystem->setPageAccess(addr, access); } @@ -61,6 +63,8 @@ void CartridgeF6SC::install(System& system) { access.directPeekBase = &myRAM[addr & 0x007F]; access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)]; + access.romPeekCounter = &myRomAccessCounter[0x80 + (addr & 0x007F)]; + access.romPokeCounter = &myRomAccessCounter[0x80 + (addr & 0x007F) + myImage.size()]; mySystem->setPageAccess(addr, access); } @@ -168,6 +172,8 @@ bool CartridgeF6SC::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } @@ -177,6 +183,8 @@ bool CartridgeF6SC::bank(uInt16 bank) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartF8.cxx b/src/emucore/CartF8.cxx index bb06d9414..68485eb3b 100644 --- a/src/emucore/CartF8.cxx +++ b/src/emucore/CartF8.cxx @@ -110,6 +110,8 @@ bool CartridgeF8::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + addr & 0x0FFF]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + addr & 0x0FFF + myImage.size()]; mySystem->setPageAccess(addr, access); } @@ -119,6 +121,8 @@ bool CartridgeF8::bank(uInt16 bank) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[addr & 0x0FFF]; + access.romPokeCounter = &myRomAccessCounter[addr & 0x0FFF + myImage.size()]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartF8SC.cxx b/src/emucore/CartF8SC.cxx index e45298779..4b367a4bc 100644 --- a/src/emucore/CartF8SC.cxx +++ b/src/emucore/CartF8SC.cxx @@ -52,6 +52,8 @@ void CartridgeF8SC::install(System& system) for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[addr & 0x007F]; + access.romPeekCounter = &myRomAccessCounter[addr & 0x007F]; + access.romPokeCounter = &myRomAccessCounter[(addr & 0x07F) + myImage.size()]; mySystem->setPageAccess(addr, access); } @@ -61,6 +63,8 @@ void CartridgeF8SC::install(System& system) { access.directPeekBase = &myRAM[addr & 0x007F]; access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)]; + access.romPeekCounter = &myRomAccessCounter[0x80 + (addr & 0x007F)]; + access.romPokeCounter = &myRomAccessCounter[0x80 + (addr & 0x007F) + myImage.size()]; mySystem->setPageAccess(addr, access); } @@ -148,6 +152,8 @@ bool CartridgeF8SC::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } @@ -157,6 +163,8 @@ bool CartridgeF8SC::bank(uInt16 bank) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/Device.hxx b/src/emucore/Device.hxx index 496306ae2..5aafda234 100644 --- a/src/emucore/Device.hxx +++ b/src/emucore/Device.hxx @@ -146,13 +146,6 @@ class Device : public Serializable */ virtual void setAccessFlags(uInt16 address, AccessFlags flags) { } - /** - Query the given address for its access counter - - @param address The address to query for - */ - virtual AccessCounter getAccessCounter(uInt16 address) const { return 0; } - /** Increase the given address's access counter diff --git a/src/emucore/M6532.cxx b/src/emucore/M6532.cxx index 8165b5294..3453596cd 100644 --- a/src/emucore/M6532.cxx +++ b/src/emucore/M6532.cxx @@ -497,17 +497,6 @@ void M6532::setAccessFlags(uInt16 address, Device::AccessFlags flags) } } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Device::AccessCounter M6532::getAccessCounter(uInt16 address) const -{ - if (address & IO_BIT) - return myIOAccessCounter[address & IO_MASK]; - else if (address & STACK_BIT) - return myStackAccessCounter[address & STACK_MASK]; - else - return myRAMAccessCounter[address & RAM_MASK]; -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6532::increaseAccessCounter(uInt16 address, bool isWrite) { diff --git a/src/emucore/M6532.hxx b/src/emucore/M6532.hxx index d4cb695c9..9aa4368b9 100644 --- a/src/emucore/M6532.hxx +++ b/src/emucore/M6532.hxx @@ -169,13 +169,6 @@ class M6532 : public Device */ void setAccessFlags(uInt16 address, Device::AccessFlags flags) override; - /** - Query the given address for its access counter - - @param address The address to query for - */ - Device::AccessCounter getAccessCounter(uInt16 address) const override; - /** Increase the given address's access counter diff --git a/src/emucore/System.cxx b/src/emucore/System.cxx index b1f0c538a..d0bf4814e 100644 --- a/src/emucore/System.cxx +++ b/src/emucore/System.cxx @@ -110,10 +110,11 @@ uInt8 System::peek(uInt16 addr, Device::AccessFlags flags) else access.device->setAccessFlags(addr, flags); // Increase access counter - if(access.romAccessCounter) - *(access.romAccessCounter + (addr & PAGE_MASK)) += 1; - else - access.device->increaseAccessCounter(addr); + if (flags != Device::NONE) + if(access.romPeekCounter) + *(access.romPeekCounter + (addr & PAGE_MASK)) += 1; + else + access.device->increaseAccessCounter(addr); #endif // See if this page uses direct accessing or not @@ -144,10 +145,11 @@ void System::poke(uInt16 addr, uInt8 value, Device::AccessFlags flags) else access.device->setAccessFlags(addr, flags); // Increase access counter - if(access.romAccessCounter) - *(access.romAccessCounter + (addr & PAGE_MASK)) += 1; - else - access.device->increaseAccessCounter(addr, true); + if (flags != Device::NONE) + if(access.romPokeCounter) + *(access.romPokeCounter + (addr & PAGE_MASK)) += 1; + else + access.device->increaseAccessCounter(addr, true); #endif // See if this page uses direct accessing or not @@ -192,28 +194,30 @@ void System::setAccessFlags(uInt16 addr, Device::AccessFlags flags) access.device->setAccessFlags(addr, flags); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Device::AccessCounter System::getAccessCounter(uInt16 addr) const -{ - const PageAccess& access = getPageAccess(addr); - - if(access.romAccessCounter) - return *(access.romAccessCounter + (addr & PAGE_MASK)); - else - return access.device->getAccessCounter(addr); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void System::increaseAccessCounter(uInt16 addr, bool isWrite) { const PageAccess& access = getPageAccess(addr); - if(access.romAccessCounter) - *(access.romAccessCounter + (addr & PAGE_MASK)) += 1; - else - access.device->increaseAccessCounter(addr, isWrite); -} + if(isWrite) + { + if(access.romPokeCounter) + { + *(access.romPokeCounter + (addr & PAGE_MASK)) += 1; + return; + } + } + else + { + if(access.romPeekCounter) + { + *(access.romPeekCounter + (addr & PAGE_MASK)) += 1; + return; + } + } + access.device->increaseAccessCounter(addr, isWrite); +} #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/System.hxx b/src/emucore/System.hxx index 6c5547d7f..1c36acf53 100644 --- a/src/emucore/System.hxx +++ b/src/emucore/System.hxx @@ -240,13 +240,6 @@ class System : public Serializable Device::AccessFlags getAccessFlags(uInt16 address) const; void setAccessFlags(uInt16 address, Device::AccessFlags flags); - /** - Query the given address for its access counter - - @param address The address to query for - */ - Device::AccessCounter getAccessCounter(uInt16 address) const; - /** Increase the given address's access counter @@ -302,7 +295,12 @@ class System : public Serializable /** TODO */ - Device::AccessCounter* romAccessCounter{nullptr}; + Device::AccessCounter* romPeekCounter{nullptr}; + + /** + TODO + */ + Device::AccessCounter* romPokeCounter{nullptr}; /** Pointer to the device associated with this page or to the system's diff --git a/src/emucore/tia/TIA.cxx b/src/emucore/tia/TIA.cxx index 57192b436..656524eae 100644 --- a/src/emucore/tia/TIA.cxx +++ b/src/emucore/tia/TIA.cxx @@ -1980,12 +1980,6 @@ void TIA::setAccessFlags(uInt16 address, Device::AccessFlags flags) } } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Device::AccessCounter TIA::getAccessCounter(uInt16 address) const -{ - return myAccessCounter[address & TIA_MASK]; -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::increaseAccessCounter(uInt16 address, bool isWrite) { diff --git a/src/emucore/tia/TIA.hxx b/src/emucore/tia/TIA.hxx index 28481dfc6..ef8dc7af0 100644 --- a/src/emucore/tia/TIA.hxx +++ b/src/emucore/tia/TIA.hxx @@ -703,13 +703,6 @@ class TIA : public Device */ void setAccessFlags(uInt16 address, Device::AccessFlags flags) override; - /** - Query the given address for its access counter - - @param address The address to query for - */ - Device::AccessCounter getAccessCounter(uInt16 address) const override; - /** Increase the given address's access counter From 62e192ac12514b719ebbc85aad8aef72b82ec29f Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Wed, 1 Apr 2020 20:36:43 -0230 Subject: [PATCH 073/377] Fix minor warning with clang (possible dangling else). --- src/emucore/System.cxx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/emucore/System.cxx b/src/emucore/System.cxx index d0bf4814e..28587d0ee 100644 --- a/src/emucore/System.cxx +++ b/src/emucore/System.cxx @@ -110,11 +110,13 @@ uInt8 System::peek(uInt16 addr, Device::AccessFlags flags) else access.device->setAccessFlags(addr, flags); // Increase access counter - if (flags != Device::NONE) + if(flags != Device::NONE) + { if(access.romPeekCounter) *(access.romPeekCounter + (addr & PAGE_MASK)) += 1; else access.device->increaseAccessCounter(addr); + } #endif // See if this page uses direct accessing or not @@ -145,11 +147,13 @@ void System::poke(uInt16 addr, uInt8 value, Device::AccessFlags flags) else access.device->setAccessFlags(addr, flags); // Increase access counter - if (flags != Device::NONE) + if(flags != Device::NONE) + { if(access.romPokeCounter) *(access.romPokeCounter + (addr & PAGE_MASK)) += 1; else access.device->increaseAccessCounter(addr, true); + } #endif // See if this page uses direct accessing or not From 017cbe9a017bd2b3cd58186ae4c38aa4698f251a Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 2 Apr 2020 10:38:15 +0200 Subject: [PATCH 074/377] add access counting to many more bankswitching types --- src/emucore/Cart.cxx | 6 ++++-- src/emucore/Cart2K.cxx | 4 ++-- src/emucore/Cart3F.cxx | 4 ++++ src/emucore/CartBUS.cxx | 2 ++ src/emucore/CartCDF.cxx | 2 ++ src/emucore/CartCM.cxx | 6 ++++++ src/emucore/CartCTY.cxx | 2 ++ src/emucore/CartDPC.cxx | 4 ++++ src/emucore/CartDPCPlus.cxx | 2 ++ src/emucore/CartE0.cxx | 10 ++++++++++ src/emucore/CartEF.cxx | 4 ++++ src/emucore/CartEFSC.cxx | 8 ++++++++ src/emucore/CartF0.cxx | 2 ++ src/emucore/CartF8.cxx | 4 ++-- src/emucore/CartFA.cxx | 8 ++++++++ src/emucore/CartFA2.cxx | 8 ++++++++ src/emucore/CartFC.cxx | 4 ++++ src/emucore/CartUA.cxx | 2 ++ src/emucore/CartWD.cxx | 12 ++++++++++++ src/emucore/CartX07.cxx | 2 ++ 20 files changed, 90 insertions(+), 6 deletions(-) diff --git a/src/emucore/Cart.cxx b/src/emucore/Cart.cxx index a4fe19857..2c2700c31 100644 --- a/src/emucore/Cart.cxx +++ b/src/emucore/Cart.cxx @@ -152,14 +152,16 @@ string Cartridge::getAccessCounters() const uInt16 origin = bankOrigin(bank); uInt16 bankSize = this->bankSize(bank); - out << "Bank " << bank << " / 0.." << bankCount() - 1 << " reads:\n"; + out << "Bank " << Common::Base::toString(bank, Common::Base::Fmt::_10_8) << " / 0.." + << Common::Base::toString(bankCount() - 1, Common::Base::Fmt::_10_8) << " reads:\n"; for(uInt16 addr = 0; addr < bankSize; ++addr) { out << Common::Base::HEX4 << (addr | origin) << "," << Common::Base::toString(myRomAccessCounter[offset + addr], Common::Base::Fmt::_10_8) << ", "; } out << "\n"; - out << "Bank " << bank << " / 0.." << bankCount() - 1 << " writes:\n"; + out << "Bank " << Common::Base::toString(bank, Common::Base::Fmt::_10_8) << " / 0.." + << Common::Base::toString(bankCount() - 1, Common::Base::Fmt::_10_8) << " writes:\n"; for(uInt16 addr = 0; addr < bankSize; ++addr) { out << Common::Base::HEX4 << (addr | origin) << "," diff --git a/src/emucore/Cart2K.cxx b/src/emucore/Cart2K.cxx index c5a5717c6..2a66a15ce 100644 --- a/src/emucore/Cart2K.cxx +++ b/src/emucore/Cart2K.cxx @@ -77,8 +77,8 @@ void Cartridge2K::install(System& system) { access.directPeekBase = &myImage[addr & myMask]; access.romAccessBase = &myRomAccessBase[addr & myMask]; - access.romPeekCounter = &myRomAccessCounter[addr & 0x0FFF]; - access.romPokeCounter = &myRomAccessCounter[(addr & 0x0FFF) + mySize]; + access.romPeekCounter = &myRomAccessCounter[addr & myMask]; + access.romPokeCounter = &myRomAccessCounter[(addr & myMask) + mySize]; mySystem->setPageAccess(addr, access); } } diff --git a/src/emucore/Cart3F.cxx b/src/emucore/Cart3F.cxx index 47b5c4dcd..796a1cd88 100644 --- a/src/emucore/Cart3F.cxx +++ b/src/emucore/Cart3F.cxx @@ -58,6 +58,8 @@ void Cartridge3F::install(System& system) { access.directPeekBase = &myImage[(mySize - 2048) + (addr & 0x07FF)]; access.romAccessBase = &myRomAccessBase[(mySize - 2048) + (addr & 0x07FF)]; + access.romPeekCounter = &myRomAccessCounter[(mySize - 2048) + (addr & 0x07FF)]; + access.romPokeCounter = &myRomAccessCounter[(mySize - 2048) + (addr & 0x07FF) + mySize]; mySystem->setPageAccess(addr, access); } @@ -118,6 +120,8 @@ bool Cartridge3F::bank(uInt16 bank) { access.directPeekBase = &myImage[offset + (addr & 0x07FF)]; access.romAccessBase = &myRomAccessBase[offset + (addr & 0x07FF)]; + access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x07FF)]; + access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x07FF) + mySize]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartBUS.cxx b/src/emucore/CartBUS.cxx index cb0be831f..c88db05fe 100644 --- a/src/emucore/CartBUS.cxx +++ b/src/emucore/CartBUS.cxx @@ -443,6 +443,8 @@ bool CartridgeBUS::bank(uInt16 bank) for(uInt16 addr = 0x1040; addr < 0x2000; addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartCDF.cxx b/src/emucore/CartCDF.cxx index 3289b2e04..6bd8d3578 100644 --- a/src/emucore/CartCDF.cxx +++ b/src/emucore/CartCDF.cxx @@ -416,6 +416,8 @@ bool CartridgeCDF::bank(uInt16 bank) for(uInt16 addr = 0x1040; addr < 0x2000; addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartCM.cxx b/src/emucore/CartCM.cxx index 7ce27bea4..3b3d35fa9 100644 --- a/src/emucore/CartCM.cxx +++ b/src/emucore/CartCM.cxx @@ -120,6 +120,8 @@ bool CartridgeCM::bank(uInt16 bank) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } @@ -132,11 +134,15 @@ bool CartridgeCM::bank(uInt16 bank) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; } else { access.directPeekBase = &myRAM[addr & 0x7FF]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x07FF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x07FF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x07FF) + myImage.size()]; } if((mySWCHA & 0x30) == 0x20) diff --git a/src/emucore/CartCTY.cxx b/src/emucore/CartCTY.cxx index 9133ca891..2c72e9030 100644 --- a/src/emucore/CartCTY.cxx +++ b/src/emucore/CartCTY.cxx @@ -241,6 +241,8 @@ bool CartridgeCTY::bank(uInt16 bank) for(uInt16 addr = 0x1080; addr < 0x2000; addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartDPC.cxx b/src/emucore/CartDPC.cxx index 43d15dc7e..1fbec9791 100644 --- a/src/emucore/CartDPC.cxx +++ b/src/emucore/CartDPC.cxx @@ -374,6 +374,8 @@ bool CartridgeDPC::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } @@ -383,6 +385,8 @@ bool CartridgeDPC::bank(uInt16 bank) { access.directPeekBase = &myProgramImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartDPCPlus.cxx b/src/emucore/CartDPCPlus.cxx index c9392fdc8..50cdeab39 100644 --- a/src/emucore/CartDPCPlus.cxx +++ b/src/emucore/CartDPCPlus.cxx @@ -605,6 +605,8 @@ bool CartridgeDPCPlus::bank(uInt16 bank) for(uInt16 addr = 0x1080; addr < 0x2000; addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartE0.cxx b/src/emucore/CartE0.cxx index 9102788f2..051ff8870 100644 --- a/src/emucore/CartE0.cxx +++ b/src/emucore/CartE0.cxx @@ -62,12 +62,16 @@ void CartridgeE0::install(System& system) { access.directPeekBase = &myImage[0x1C00 + (addr & 0x03FF)]; access.romAccessBase = &myRomAccessBase[0x1C00 + (addr & 0x03FF)]; + access.romPeekCounter = &myRomAccessCounter[0x1C00 + (addr & 0x03FF)]; + access.romPokeCounter = &myRomAccessCounter[0x1C00 + (addr & 0x03FF) + myImage.size()]; mySystem->setPageAccess(addr, access); } // Set the page accessing methods for the hot spots in the last segment access.directPeekBase = nullptr; access.romAccessBase = &myRomAccessBase[0x1FC0]; // TJ: is this the correct address (or 0x1FE0)? + access.romPeekCounter = &myRomAccessCounter[0x1FC0]; + access.romPokeCounter = &myRomAccessCounter[0x1FC0 + myImage.size()]; access.type = System::PageAccessType::READ; for(uInt16 addr = (0x1FE0 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) @@ -145,6 +149,8 @@ void CartridgeE0::segmentZero(uInt16 slice) { access.directPeekBase = &myImage[offset + (addr & 0x03FF)]; access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; + access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)]; + access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + myImage.size()]; mySystem->setPageAccess(addr, access); } myBankChanged = true; @@ -166,6 +172,8 @@ void CartridgeE0::segmentOne(uInt16 slice) { access.directPeekBase = &myImage[offset + (addr & 0x03FF)]; access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; + access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)]; + access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + myImage.size()]; mySystem->setPageAccess(addr, access); } myBankChanged = true; @@ -187,6 +195,8 @@ void CartridgeE0::segmentTwo(uInt16 slice) { access.directPeekBase = &myImage[offset + (addr & 0x03FF)]; access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; + access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)]; + access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + myImage.size()]; mySystem->setPageAccess(addr, access); } myBankChanged = true; diff --git a/src/emucore/CartEF.cxx b/src/emucore/CartEF.cxx index 1de837bf7..43901c916 100644 --- a/src/emucore/CartEF.cxx +++ b/src/emucore/CartEF.cxx @@ -85,6 +85,8 @@ bool CartridgeEF::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } @@ -94,6 +96,8 @@ bool CartridgeEF::bank(uInt16 bank) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartEFSC.cxx b/src/emucore/CartEFSC.cxx index 4cb481547..b2fd87032 100644 --- a/src/emucore/CartEFSC.cxx +++ b/src/emucore/CartEFSC.cxx @@ -52,6 +52,8 @@ void CartridgeEFSC::install(System& system) for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[addr & 0x007F]; + access.romPeekCounter = &myRomAccessCounter[addr & 0x007F]; + access.romPokeCounter = &myRomAccessCounter[(addr & 0x007F) + myImage.size()]; mySystem->setPageAccess(addr, access); } @@ -61,6 +63,8 @@ void CartridgeEFSC::install(System& system) { access.directPeekBase = &myRAM[addr & 0x007F]; access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)]; + access.romPeekCounter = &myRomAccessCounter[0x80 + (addr & 0x007F)]; + access.romPokeCounter = &myRomAccessCounter[0x80 + (addr & 0x007F) + myImage.size()]; mySystem->setPageAccess(addr, access); } @@ -128,6 +132,8 @@ bool CartridgeEFSC::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } @@ -137,6 +143,8 @@ bool CartridgeEFSC::bank(uInt16 bank) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartF0.cxx b/src/emucore/CartF0.cxx index 44f967327..fc6061d22 100644 --- a/src/emucore/CartF0.cxx +++ b/src/emucore/CartF0.cxx @@ -101,6 +101,8 @@ bool CartridgeF0::bank(uInt16 bank) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } diff --git a/src/emucore/CartF8.cxx b/src/emucore/CartF8.cxx index 68485eb3b..66b42af70 100644 --- a/src/emucore/CartF8.cxx +++ b/src/emucore/CartF8.cxx @@ -110,8 +110,8 @@ bool CartridgeF8::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + addr & 0x0FFF]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + addr & 0x0FFF + myImage.size()]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } diff --git a/src/emucore/CartFA.cxx b/src/emucore/CartFA.cxx index c91ea3b8e..eb9f1809b 100644 --- a/src/emucore/CartFA.cxx +++ b/src/emucore/CartFA.cxx @@ -52,6 +52,8 @@ void CartridgeFA::install(System& system) for(uInt16 addr = 0x1000; addr < 0x1100; addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[addr & 0x00FF]; + access.romPeekCounter = &myRomAccessCounter[addr & 0x00FF]; + access.romPokeCounter = &myRomAccessCounter[(addr & 0x00FF) + myImage.size()]; mySystem->setPageAccess(addr, access); } @@ -61,6 +63,8 @@ void CartridgeFA::install(System& system) { access.directPeekBase = &myRAM[addr & 0x00FF]; access.romAccessBase = &myRomAccessBase[0x100 + (addr & 0x00FF)]; + access.romPeekCounter = &myRomAccessCounter[0x100 + (addr & 0x00FF)]; + access.romPokeCounter = &myRomAccessCounter[0x100 + (addr & 0x00FF) + myImage.size()]; mySystem->setPageAccess(addr, access); } @@ -158,6 +162,8 @@ bool CartridgeFA::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } @@ -167,6 +173,8 @@ bool CartridgeFA::bank(uInt16 bank) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartFA2.cxx b/src/emucore/CartFA2.cxx index 57fb118bb..134c9d86b 100644 --- a/src/emucore/CartFA2.cxx +++ b/src/emucore/CartFA2.cxx @@ -62,6 +62,8 @@ void CartridgeFA2::install(System& system) for(uInt16 addr = 0x1000; addr < 0x1100; addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[addr & 0x00FF]; + access.romPeekCounter = &myRomAccessCounter[addr & 0x00FF]; + access.romPokeCounter = &myRomAccessCounter[(addr & 0x00FF) + myImage.size()]; mySystem->setPageAccess(addr, access); } @@ -72,6 +74,8 @@ void CartridgeFA2::install(System& system) { access.directPeekBase = &myRAM[addr & 0x00FF]; access.romAccessBase = &myRomAccessBase[0x100 + (addr & 0x00FF)]; + access.romPeekCounter = &myRomAccessCounter[0x100 + (addr & 0x00FF)]; + access.romPokeCounter = &myRomAccessCounter[0x100 + (addr & 0x00FF) + myImage.size()]; mySystem->setPageAccess(addr, access); } @@ -223,6 +227,8 @@ bool CartridgeFA2::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } @@ -232,6 +238,8 @@ bool CartridgeFA2::bank(uInt16 bank) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartFC.cxx b/src/emucore/CartFC.cxx index a35b531ca..113d259c3 100644 --- a/src/emucore/CartFC.cxx +++ b/src/emucore/CartFC.cxx @@ -114,6 +114,8 @@ bool CartridgeFC::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } @@ -123,6 +125,8 @@ bool CartridgeFC::bank(uInt16 bank) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } myCurrentBank = myTargetBank; diff --git a/src/emucore/CartUA.cxx b/src/emucore/CartUA.cxx index b4729c38e..ed2bd80bf 100644 --- a/src/emucore/CartUA.cxx +++ b/src/emucore/CartUA.cxx @@ -136,6 +136,8 @@ bool CartridgeUA::bank(uInt16 bank) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartWD.cxx b/src/emucore/CartWD.cxx index 254c78aa4..62b5a6c17 100644 --- a/src/emucore/CartWD.cxx +++ b/src/emucore/CartWD.cxx @@ -64,6 +64,8 @@ void CartridgeWD::install(System& system) { read.directPeekBase = &myRAM[addr & 0x003F]; read.romAccessBase = &myRomAccessBase[addr & 0x003F]; + read.romPeekCounter = &myRomAccessCounter[addr & 0x003F]; + read.romPokeCounter = &myRomAccessCounter[(addr & 0x003F) + myImage.size()]; mySystem->setPageAccess(addr, read); } @@ -74,6 +76,8 @@ void CartridgeWD::install(System& system) for(uInt16 addr = 0x1040; addr < 0x1080; addr += System::PAGE_SIZE) { write.romAccessBase = &myRomAccessBase[addr & 0x003F]; + write.romPeekCounter = &myRomAccessCounter[addr & 0x003F]; + write.romPokeCounter = &myRomAccessCounter[(addr & 0x003F) + myImage.size()]; mySystem->setPageAccess(addr, write); } @@ -178,6 +182,8 @@ void CartridgeWD::segmentZero(uInt8 slice) for(uInt16 addr = 0x1080; addr < 0x1400; addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; + access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)]; + access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + myImage.size()]; mySystem->setPageAccess(addr, access); } myOffset[0] = offset; @@ -192,6 +198,8 @@ void CartridgeWD::segmentOne(uInt8 slice) for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; + access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)]; + access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + myImage.size()]; mySystem->setPageAccess(addr, access); } myOffset[1] = offset; @@ -206,6 +214,8 @@ void CartridgeWD::segmentTwo(uInt8 slice) for(uInt16 addr = 0x1800; addr < 0x1C00; addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; + access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)]; + access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + myImage.size()]; mySystem->setPageAccess(addr, access); } myOffset[2] = offset; @@ -226,6 +236,8 @@ void CartridgeWD::segmentThree(uInt8 slice) for(uInt16 addr = 0x1C00; addr < 0x2000; addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; + access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)]; + access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + myImage.size()]; mySystem->setPageAccess(addr, access); } myOffset[3] = offset; diff --git a/src/emucore/CartX07.cxx b/src/emucore/CartX07.cxx index fc58b0df5..49fc30e0f 100644 --- a/src/emucore/CartX07.cxx +++ b/src/emucore/CartX07.cxx @@ -116,6 +116,8 @@ bool CartridgeX07::bank(uInt16 bank) { access.directPeekBase = &myImage[offset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[offset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x0FFF) + myImage.size()]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; From 04073548bdb30a108e69881465b0ceab326bfd8e Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 2 Apr 2020 11:07:04 +0200 Subject: [PATCH 075/377] fix CartFE to update access flags and counters --- src/emucore/Cart.cxx | 3 ++- src/emucore/CartFE.cxx | 20 ++++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/emucore/Cart.cxx b/src/emucore/Cart.cxx index 2c2700c31..beb76855d 100644 --- a/src/emucore/Cart.cxx +++ b/src/emucore/Cart.cxx @@ -180,6 +180,7 @@ uInt16 Cartridge::bankOrigin(uInt16 bank) const { // isolate the high 3 address bits, count them and // select the most frequent to define the bank origin + // TODO: origin for banks smaller than 4K const int intervals = 0x8000 / 0x100; uInt32 offset = bank * bankSize(); //uInt16 addrMask = (4_KB - 1) & ~(bankSize(bank) - 1); @@ -211,7 +212,7 @@ uInt16 Cartridge::bankOrigin(uInt16 bank) const maxIdx = idx; } } - return maxIdx << 13 | 0x1000 | (offset & 0xfff); + return maxIdx << 13 | 0x1000; //| (offset & 0xfff); } #endif diff --git a/src/emucore/CartFE.cxx b/src/emucore/CartFE.cxx index c827906f9..eaa17bc4d 100644 --- a/src/emucore/CartFE.cxx +++ b/src/emucore/CartFE.cxx @@ -49,11 +49,6 @@ void CartridgeFE::install(System& system) System::PageAccess access(this, System::PageAccessType::READWRITE); for(uInt16 addr = 0x180; addr < 0x200; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); - - // Map all of the cart accesses to call peek and poke - access.type = System::PageAccessType::READ; - for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE) - mySystem->setPageAccess(addr, access); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -104,6 +99,19 @@ bool CartridgeFE::bank(uInt16 bank) return false; myBankOffset = bank << 12; + + System::PageAccess access(this, System::PageAccessType::READ); + + // Setup the page access methods for the current bank + // Map all of the cart accesses to call peek and poke + for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE) + { + access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[addr & 0x0FFF]; + access.romPokeCounter = &myRomAccessCounter[addr & 0x0FFF + myImage.size()]; + mySystem->setPageAccess(addr, access); + } + return myBankChanged = true; } @@ -160,7 +168,7 @@ bool CartridgeFE::load(Serializer& in) } catch(...) { - cerr << "ERROR: CartridgeF8SC::load" << endl; + cerr << "ERROR: CartridgeFE::load" << endl; return false; } From f00b70a883922cf6b05ead1316264cafe1f35fa5 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 2 Apr 2020 12:03:35 +0200 Subject: [PATCH 076/377] fix poke access counter offset add a few more bank switching types --- src/emucore/Cart.cxx | 6 ++---- src/emucore/Cart.hxx | 3 +++ src/emucore/Cart2K.cxx | 2 +- src/emucore/Cart3E.cxx | 8 ++++---- src/emucore/Cart3F.cxx | 4 ++-- src/emucore/Cart4K.cxx | 2 +- src/emucore/CartBUS.cxx | 2 +- src/emucore/CartCDF.cxx | 2 +- src/emucore/CartCM.cxx | 6 +++--- src/emucore/CartCTY.cxx | 2 +- src/emucore/CartCV.cxx | 4 ++++ src/emucore/CartCVPlus.cxx | 4 ++++ src/emucore/CartDF.cxx | 4 ++++ src/emucore/CartDFSC.cxx | 8 ++++++++ src/emucore/CartDPC.cxx | 4 ++-- src/emucore/CartDPCPlus.cxx | 2 +- src/emucore/CartE0.cxx | 10 +++++----- src/emucore/CartEF.cxx | 4 ++-- src/emucore/CartEFSC.cxx | 8 ++++---- src/emucore/CartF0.cxx | 4 +++- src/emucore/CartF4.cxx | 4 ++-- src/emucore/CartF4SC.cxx | 8 ++++---- src/emucore/CartF6.cxx | 4 ++-- src/emucore/CartF6SC.cxx | 8 ++++---- src/emucore/CartF8.cxx | 6 +++--- src/emucore/CartF8SC.cxx | 8 ++++---- src/emucore/CartFA.cxx | 8 ++++---- src/emucore/CartFA2.cxx | 8 ++++---- src/emucore/CartFC.cxx | 4 ++-- src/emucore/CartFE.cxx | 4 ++-- src/emucore/CartMDM.cxx | 2 ++ src/emucore/CartMNetwork.cxx | 4 ++++ src/emucore/CartSB.cxx | 2 ++ src/emucore/CartUA.cxx | 2 +- src/emucore/CartWD.cxx | 12 ++++++------ src/emucore/CartX07.cxx | 2 +- 36 files changed, 103 insertions(+), 72 deletions(-) diff --git a/src/emucore/Cart.cxx b/src/emucore/Cart.cxx index beb76855d..f85850ba2 100644 --- a/src/emucore/Cart.cxx +++ b/src/emucore/Cart.cxx @@ -126,6 +126,7 @@ void Cartridge::pokeRAM(uInt8& dest, uInt16 address, uInt8 value) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge::createRomAccessArrays(size_t size) { + myAccessSize = uInt32(size); #ifdef DEBUGGER_SUPPORT myRomAccessBase = make_unique(size); std::fill_n(myRomAccessBase.get(), size, Device::ROW); @@ -142,11 +143,8 @@ void Cartridge::createRomAccessArrays(size_t size) string Cartridge::getAccessCounters() const { ostringstream out; - size_t romSize; uInt32 offset = 0; - getImage(romSize); - for(uInt16 bank = 0; bank < bankCount(); ++bank) { uInt16 origin = bankOrigin(bank); @@ -165,7 +163,7 @@ string Cartridge::getAccessCounters() const for(uInt16 addr = 0; addr < bankSize; ++addr) { out << Common::Base::HEX4 << (addr | origin) << "," - << Common::Base::toString(myRomAccessCounter[offset + addr + romSize], Common::Base::Fmt::_10_8) << ", "; + << Common::Base::toString(myRomAccessCounter[offset + addr + myAccessSize], Common::Base::Fmt::_10_8) << ", "; } out << "\n"; diff --git a/src/emucore/Cart.hxx b/src/emucore/Cart.hxx index dda0684fd..ce7d66a8b 100644 --- a/src/emucore/Cart.hxx +++ b/src/emucore/Cart.hxx @@ -357,6 +357,9 @@ class Cartridge : public Device // Contains address of illegal RAM write access or 0 uInt16 myRamWriteAccess{0}; + // Total size of ROM access area (might include RAM too) + uInt32 myAccessSize; + private: // The startup bank to use (where to look for the reset vector address) uInt16 myStartBank{0}; diff --git a/src/emucore/Cart2K.cxx b/src/emucore/Cart2K.cxx index 2a66a15ce..ee9f2b334 100644 --- a/src/emucore/Cart2K.cxx +++ b/src/emucore/Cart2K.cxx @@ -78,7 +78,7 @@ void Cartridge2K::install(System& system) access.directPeekBase = &myImage[addr & myMask]; access.romAccessBase = &myRomAccessBase[addr & myMask]; access.romPeekCounter = &myRomAccessCounter[addr & myMask]; - access.romPokeCounter = &myRomAccessCounter[(addr & myMask) + mySize]; + access.romPokeCounter = &myRomAccessCounter[(addr & myMask) + myAccessSize]; mySystem->setPageAccess(addr, access); } } diff --git a/src/emucore/Cart3E.cxx b/src/emucore/Cart3E.cxx index f9fb495e0..15084b53e 100644 --- a/src/emucore/Cart3E.cxx +++ b/src/emucore/Cart3E.cxx @@ -61,7 +61,7 @@ void Cartridge3E::install(System& system) access.directPeekBase = &myImage[(mySize - 2048) + (addr & 0x07FF)]; access.romAccessBase = &myRomAccessBase[(mySize - 2048) + (addr & 0x07FF)]; access.romPeekCounter = &myRomAccessCounter[(mySize - 2048) + (addr & 0x07FF)]; - access.romPokeCounter = &myRomAccessCounter[(mySize - 2048) + (addr & 0x07FF) + mySize]; + access.romPokeCounter = &myRomAccessCounter[(mySize - 2048) + (addr & 0x07FF) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -162,7 +162,7 @@ bool Cartridge3E::bank(uInt16 bank) access.directPeekBase = &myImage[offset + (addr & 0x07FF)]; access.romAccessBase = &myRomAccessBase[offset + (addr & 0x07FF)]; access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x07FF)]; - access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x07FF) + mySize]; + access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x07FF) + myAccessSize]; mySystem->setPageAccess(addr, access); } } @@ -183,7 +183,7 @@ bool Cartridge3E::bank(uInt16 bank) access.directPeekBase = &myRAM[offset + (addr & 0x03FF)]; access.romAccessBase = &myRomAccessBase[mySize + offset + (addr & 0x03FF)]; access.romPeekCounter = &myRomAccessCounter[mySize + offset + (addr & 0x03FF)]; - access.romPokeCounter = &myRomAccessCounter[mySize + offset + (addr & 0x03FF) + mySize]; + access.romPokeCounter = &myRomAccessCounter[mySize + offset + (addr & 0x03FF) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -197,7 +197,7 @@ bool Cartridge3E::bank(uInt16 bank) { access.romAccessBase = &myRomAccessBase[mySize + offset + (addr & 0x03FF)]; access.romPeekCounter = &myRomAccessCounter[mySize + offset + (addr & 0x03FF)]; - access.romPokeCounter = &myRomAccessCounter[mySize + offset + (addr & 0x03FF) + mySize]; + access.romPokeCounter = &myRomAccessCounter[mySize + offset + (addr & 0x03FF) + myAccessSize]; mySystem->setPageAccess(addr, access); } } diff --git a/src/emucore/Cart3F.cxx b/src/emucore/Cart3F.cxx index 796a1cd88..2989e88ff 100644 --- a/src/emucore/Cart3F.cxx +++ b/src/emucore/Cart3F.cxx @@ -59,7 +59,7 @@ void Cartridge3F::install(System& system) access.directPeekBase = &myImage[(mySize - 2048) + (addr & 0x07FF)]; access.romAccessBase = &myRomAccessBase[(mySize - 2048) + (addr & 0x07FF)]; access.romPeekCounter = &myRomAccessCounter[(mySize - 2048) + (addr & 0x07FF)]; - access.romPokeCounter = &myRomAccessCounter[(mySize - 2048) + (addr & 0x07FF) + mySize]; + access.romPokeCounter = &myRomAccessCounter[(mySize - 2048) + (addr & 0x07FF) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -121,7 +121,7 @@ bool Cartridge3F::bank(uInt16 bank) access.directPeekBase = &myImage[offset + (addr & 0x07FF)]; access.romAccessBase = &myRomAccessBase[offset + (addr & 0x07FF)]; access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x07FF)]; - access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x07FF) + mySize]; + access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x07FF) + myAccessSize]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/Cart4K.cxx b/src/emucore/Cart4K.cxx index af88dd1f9..4f4aab979 100644 --- a/src/emucore/Cart4K.cxx +++ b/src/emucore/Cart4K.cxx @@ -48,7 +48,7 @@ void Cartridge4K::install(System& system) access.directPeekBase = &myImage[addr & 0x0FFF]; access.romAccessBase = &myRomAccessBase[addr & 0x0FFF]; access.romPeekCounter = &myRomAccessCounter[addr & 0x0FFF]; - access.romPokeCounter = &myRomAccessCounter[(addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[(addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } } diff --git a/src/emucore/CartBUS.cxx b/src/emucore/CartBUS.cxx index c88db05fe..2c2cd803a 100644 --- a/src/emucore/CartBUS.cxx +++ b/src/emucore/CartBUS.cxx @@ -444,7 +444,7 @@ bool CartridgeBUS::bank(uInt16 bank) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + 28_KB]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartCDF.cxx b/src/emucore/CartCDF.cxx index 6bd8d3578..b182634a3 100644 --- a/src/emucore/CartCDF.cxx +++ b/src/emucore/CartCDF.cxx @@ -417,7 +417,7 @@ bool CartridgeCDF::bank(uInt16 bank) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + 28_KB]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartCM.cxx b/src/emucore/CartCM.cxx index 3b3d35fa9..5fa6dff3d 100644 --- a/src/emucore/CartCM.cxx +++ b/src/emucore/CartCM.cxx @@ -121,7 +121,7 @@ bool CartridgeCM::bank(uInt16 bank) access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -135,14 +135,14 @@ bool CartridgeCM::bank(uInt16 bank) access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; } else { access.directPeekBase = &myRAM[addr & 0x7FF]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x07FF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x07FF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x07FF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x07FF) + myAccessSize]; } if((mySWCHA & 0x30) == 0x20) diff --git a/src/emucore/CartCTY.cxx b/src/emucore/CartCTY.cxx index 2c72e9030..1536b64e0 100644 --- a/src/emucore/CartCTY.cxx +++ b/src/emucore/CartCTY.cxx @@ -242,7 +242,7 @@ bool CartridgeCTY::bank(uInt16 bank) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartCV.cxx b/src/emucore/CartCV.cxx index cb77d7790..42c74a808 100644 --- a/src/emucore/CartCV.cxx +++ b/src/emucore/CartCV.cxx @@ -69,6 +69,8 @@ void CartridgeCV::install(System& system) { access.directPeekBase = &myImage[addr & 0x07FF]; access.romAccessBase = &myRomAccessBase[addr & 0x07FF]; + access.romPeekCounter = &myRomAccessCounter[addr & 0x07FF]; + access.romPokeCounter = &myRomAccessCounter[(addr & 0x07FF) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -88,6 +90,8 @@ void CartridgeCV::install(System& system) { access.directPeekBase = &myRAM[addr & 0x03FF]; access.romAccessBase = &myRomAccessBase[2048 + (addr & 0x03FF)]; + access.romPeekCounter = &myRomAccessCounter[2048 + (addr & 0x03FF)]; + access.romPokeCounter = &myRomAccessCounter[2048 + (addr & 0x03FF) + myAccessSize]; mySystem->setPageAccess(addr, access); } } diff --git a/src/emucore/CartCVPlus.cxx b/src/emucore/CartCVPlus.cxx index 86fb25d8b..a3258e53c 100644 --- a/src/emucore/CartCVPlus.cxx +++ b/src/emucore/CartCVPlus.cxx @@ -63,6 +63,8 @@ void CartridgeCVPlus::install(System& system) for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[mySize + (addr & 0x03FF)]; + access.romPeekCounter = &myRomAccessCounter[mySize + (addr & 0x03FF)]; + access.romPokeCounter = &myRomAccessCounter[mySize + (addr & 0x03FF) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -72,6 +74,8 @@ void CartridgeCVPlus::install(System& system) { access.directPeekBase = &myRAM[addr & 0x03FF]; access.romAccessBase = &myRomAccessBase[mySize + (addr & 0x03FF)]; + access.romPeekCounter = &myRomAccessCounter[mySize + (addr & 0x03FF)]; + access.romPokeCounter = &myRomAccessCounter[mySize + (addr & 0x03FF) + myAccessSize]; mySystem->setPageAccess(addr, access); } diff --git a/src/emucore/CartDF.cxx b/src/emucore/CartDF.cxx index 556d51bf6..b43bc0837 100644 --- a/src/emucore/CartDF.cxx +++ b/src/emucore/CartDF.cxx @@ -85,6 +85,8 @@ bool CartridgeDF::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -94,6 +96,8 @@ bool CartridgeDF::bank(uInt16 bank) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartDFSC.cxx b/src/emucore/CartDFSC.cxx index 993bbf226..3661459fa 100644 --- a/src/emucore/CartDFSC.cxx +++ b/src/emucore/CartDFSC.cxx @@ -52,6 +52,8 @@ void CartridgeDFSC::install(System& system) for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[addr & 0x007F]; + access.romPeekCounter = &myRomAccessCounter[addr & 0x007F]; + access.romPokeCounter = &myRomAccessCounter[(addr & 0x007F) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -61,6 +63,8 @@ void CartridgeDFSC::install(System& system) { access.directPeekBase = &myRAM[addr & 0x007F]; access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)]; + access.romPeekCounter = &myRomAccessCounter[0x80 + (addr & 0x007F)]; + access.romPokeCounter = &myRomAccessCounter[0x80 + (addr & 0x007F) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -128,6 +132,8 @@ bool CartridgeDFSC::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -137,6 +143,8 @@ bool CartridgeDFSC::bank(uInt16 bank) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartDPC.cxx b/src/emucore/CartDPC.cxx index 1fbec9791..808e658d4 100644 --- a/src/emucore/CartDPC.cxx +++ b/src/emucore/CartDPC.cxx @@ -375,7 +375,7 @@ bool CartridgeDPC::bank(uInt16 bank) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -386,7 +386,7 @@ bool CartridgeDPC::bank(uInt16 bank) access.directPeekBase = &myProgramImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartDPCPlus.cxx b/src/emucore/CartDPCPlus.cxx index 50cdeab39..0761eeb19 100644 --- a/src/emucore/CartDPCPlus.cxx +++ b/src/emucore/CartDPCPlus.cxx @@ -606,7 +606,7 @@ bool CartridgeDPCPlus::bank(uInt16 bank) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + 24_KB]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartE0.cxx b/src/emucore/CartE0.cxx index 051ff8870..ff3a9b52c 100644 --- a/src/emucore/CartE0.cxx +++ b/src/emucore/CartE0.cxx @@ -63,7 +63,7 @@ void CartridgeE0::install(System& system) access.directPeekBase = &myImage[0x1C00 + (addr & 0x03FF)]; access.romAccessBase = &myRomAccessBase[0x1C00 + (addr & 0x03FF)]; access.romPeekCounter = &myRomAccessCounter[0x1C00 + (addr & 0x03FF)]; - access.romPokeCounter = &myRomAccessCounter[0x1C00 + (addr & 0x03FF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[0x1C00 + (addr & 0x03FF) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -71,7 +71,7 @@ void CartridgeE0::install(System& system) access.directPeekBase = nullptr; access.romAccessBase = &myRomAccessBase[0x1FC0]; // TJ: is this the correct address (or 0x1FE0)? access.romPeekCounter = &myRomAccessCounter[0x1FC0]; - access.romPokeCounter = &myRomAccessCounter[0x1FC0 + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[0x1FC0 + myAccessSize]; access.type = System::PageAccessType::READ; for(uInt16 addr = (0x1FE0 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) @@ -150,7 +150,7 @@ void CartridgeE0::segmentZero(uInt16 slice) access.directPeekBase = &myImage[offset + (addr & 0x03FF)]; access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)]; - access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + myAccessSize]; mySystem->setPageAccess(addr, access); } myBankChanged = true; @@ -173,7 +173,7 @@ void CartridgeE0::segmentOne(uInt16 slice) access.directPeekBase = &myImage[offset + (addr & 0x03FF)]; access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)]; - access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + myAccessSize]; mySystem->setPageAccess(addr, access); } myBankChanged = true; @@ -196,7 +196,7 @@ void CartridgeE0::segmentTwo(uInt16 slice) access.directPeekBase = &myImage[offset + (addr & 0x03FF)]; access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)]; - access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + myAccessSize]; mySystem->setPageAccess(addr, access); } myBankChanged = true; diff --git a/src/emucore/CartEF.cxx b/src/emucore/CartEF.cxx index 43901c916..16635200b 100644 --- a/src/emucore/CartEF.cxx +++ b/src/emucore/CartEF.cxx @@ -86,7 +86,7 @@ bool CartridgeEF::bank(uInt16 bank) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -97,7 +97,7 @@ bool CartridgeEF::bank(uInt16 bank) access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartEFSC.cxx b/src/emucore/CartEFSC.cxx index b2fd87032..3502be7a0 100644 --- a/src/emucore/CartEFSC.cxx +++ b/src/emucore/CartEFSC.cxx @@ -53,7 +53,7 @@ void CartridgeEFSC::install(System& system) { access.romAccessBase = &myRomAccessBase[addr & 0x007F]; access.romPeekCounter = &myRomAccessCounter[addr & 0x007F]; - access.romPokeCounter = &myRomAccessCounter[(addr & 0x007F) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[(addr & 0x007F) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -64,7 +64,7 @@ void CartridgeEFSC::install(System& system) access.directPeekBase = &myRAM[addr & 0x007F]; access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)]; access.romPeekCounter = &myRomAccessCounter[0x80 + (addr & 0x007F)]; - access.romPokeCounter = &myRomAccessCounter[0x80 + (addr & 0x007F) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[0x80 + (addr & 0x007F) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -133,7 +133,7 @@ bool CartridgeEFSC::bank(uInt16 bank) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -144,7 +144,7 @@ bool CartridgeEFSC::bank(uInt16 bank) access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartF0.cxx b/src/emucore/CartF0.cxx index fc6061d22..a69c3c8ed 100644 --- a/src/emucore/CartF0.cxx +++ b/src/emucore/CartF0.cxx @@ -92,6 +92,8 @@ bool CartridgeF0::bank(uInt16 bank) addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -102,7 +104,7 @@ bool CartridgeF0::bank(uInt16 bank) access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } diff --git a/src/emucore/CartF4.cxx b/src/emucore/CartF4.cxx index d377ecedc..8111bb1a0 100644 --- a/src/emucore/CartF4.cxx +++ b/src/emucore/CartF4.cxx @@ -90,7 +90,7 @@ bool CartridgeF4::bank(uInt16 bank) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -101,7 +101,7 @@ bool CartridgeF4::bank(uInt16 bank) access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartF4SC.cxx b/src/emucore/CartF4SC.cxx index 580dded30..24496b161 100644 --- a/src/emucore/CartF4SC.cxx +++ b/src/emucore/CartF4SC.cxx @@ -53,7 +53,7 @@ void CartridgeF4SC::install(System& system) { access.romAccessBase = &myRomAccessBase[addr & 0x007F]; access.romPeekCounter = &myRomAccessCounter[addr & 0x007F]; - access.romPokeCounter = &myRomAccessCounter[(addr & 0x07F) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[(addr & 0x07F) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -64,7 +64,7 @@ void CartridgeF4SC::install(System& system) access.directPeekBase = &myRAM[addr & 0x007F]; access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)]; access.romPeekCounter = &myRomAccessCounter[0x80 + (addr & 0x007F)]; - access.romPokeCounter = &myRomAccessCounter[0x80 + (addr & 0x007F) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[0x80 + (addr & 0x007F) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -133,7 +133,7 @@ bool CartridgeF4SC::bank(uInt16 bank) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -144,7 +144,7 @@ bool CartridgeF4SC::bank(uInt16 bank) access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartF6.cxx b/src/emucore/CartF6.cxx index 5a263498e..a7a8dec2b 100644 --- a/src/emucore/CartF6.cxx +++ b/src/emucore/CartF6.cxx @@ -130,7 +130,7 @@ bool CartridgeF6::bank(uInt16 bank) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -141,7 +141,7 @@ bool CartridgeF6::bank(uInt16 bank) access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartF6SC.cxx b/src/emucore/CartF6SC.cxx index b6b0e3659..60b998182 100644 --- a/src/emucore/CartF6SC.cxx +++ b/src/emucore/CartF6SC.cxx @@ -53,7 +53,7 @@ void CartridgeF6SC::install(System& system) { access.romAccessBase = &myRomAccessBase[addr & 0x007F]; access.romPeekCounter = &myRomAccessCounter[addr & 0x007F]; - access.romPokeCounter = &myRomAccessCounter[(addr & 0x07F) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[(addr & 0x07F) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -64,7 +64,7 @@ void CartridgeF6SC::install(System& system) access.directPeekBase = &myRAM[addr & 0x007F]; access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)]; access.romPeekCounter = &myRomAccessCounter[0x80 + (addr & 0x007F)]; - access.romPokeCounter = &myRomAccessCounter[0x80 + (addr & 0x007F) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[0x80 + (addr & 0x007F) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -173,7 +173,7 @@ bool CartridgeF6SC::bank(uInt16 bank) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -184,7 +184,7 @@ bool CartridgeF6SC::bank(uInt16 bank) access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartF8.cxx b/src/emucore/CartF8.cxx index 66b42af70..b23ed802e 100644 --- a/src/emucore/CartF8.cxx +++ b/src/emucore/CartF8.cxx @@ -111,7 +111,7 @@ bool CartridgeF8::bank(uInt16 bank) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -121,8 +121,8 @@ bool CartridgeF8::bank(uInt16 bank) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[addr & 0x0FFF]; - access.romPokeCounter = &myRomAccessCounter[addr & 0x0FFF + myImage.size()]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartF8SC.cxx b/src/emucore/CartF8SC.cxx index 4b367a4bc..c885a9c83 100644 --- a/src/emucore/CartF8SC.cxx +++ b/src/emucore/CartF8SC.cxx @@ -53,7 +53,7 @@ void CartridgeF8SC::install(System& system) { access.romAccessBase = &myRomAccessBase[addr & 0x007F]; access.romPeekCounter = &myRomAccessCounter[addr & 0x007F]; - access.romPokeCounter = &myRomAccessCounter[(addr & 0x07F) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[(addr & 0x07F) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -64,7 +64,7 @@ void CartridgeF8SC::install(System& system) access.directPeekBase = &myRAM[addr & 0x007F]; access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)]; access.romPeekCounter = &myRomAccessCounter[0x80 + (addr & 0x007F)]; - access.romPokeCounter = &myRomAccessCounter[0x80 + (addr & 0x007F) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[0x80 + (addr & 0x007F) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -153,7 +153,7 @@ bool CartridgeF8SC::bank(uInt16 bank) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -164,7 +164,7 @@ bool CartridgeF8SC::bank(uInt16 bank) access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartFA.cxx b/src/emucore/CartFA.cxx index eb9f1809b..5a4ecb6bd 100644 --- a/src/emucore/CartFA.cxx +++ b/src/emucore/CartFA.cxx @@ -53,7 +53,7 @@ void CartridgeFA::install(System& system) { access.romAccessBase = &myRomAccessBase[addr & 0x00FF]; access.romPeekCounter = &myRomAccessCounter[addr & 0x00FF]; - access.romPokeCounter = &myRomAccessCounter[(addr & 0x00FF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[(addr & 0x00FF) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -64,7 +64,7 @@ void CartridgeFA::install(System& system) access.directPeekBase = &myRAM[addr & 0x00FF]; access.romAccessBase = &myRomAccessBase[0x100 + (addr & 0x00FF)]; access.romPeekCounter = &myRomAccessCounter[0x100 + (addr & 0x00FF)]; - access.romPokeCounter = &myRomAccessCounter[0x100 + (addr & 0x00FF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[0x100 + (addr & 0x00FF) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -163,7 +163,7 @@ bool CartridgeFA::bank(uInt16 bank) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -174,7 +174,7 @@ bool CartridgeFA::bank(uInt16 bank) access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartFA2.cxx b/src/emucore/CartFA2.cxx index 134c9d86b..1630f216e 100644 --- a/src/emucore/CartFA2.cxx +++ b/src/emucore/CartFA2.cxx @@ -63,7 +63,7 @@ void CartridgeFA2::install(System& system) { access.romAccessBase = &myRomAccessBase[addr & 0x00FF]; access.romPeekCounter = &myRomAccessCounter[addr & 0x00FF]; - access.romPokeCounter = &myRomAccessCounter[(addr & 0x00FF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[(addr & 0x00FF) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -75,7 +75,7 @@ void CartridgeFA2::install(System& system) access.directPeekBase = &myRAM[addr & 0x00FF]; access.romAccessBase = &myRomAccessBase[0x100 + (addr & 0x00FF)]; access.romPeekCounter = &myRomAccessCounter[0x100 + (addr & 0x00FF)]; - access.romPokeCounter = &myRomAccessCounter[0x100 + (addr & 0x00FF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[0x100 + (addr & 0x00FF) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -228,7 +228,7 @@ bool CartridgeFA2::bank(uInt16 bank) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -239,7 +239,7 @@ bool CartridgeFA2::bank(uInt16 bank) access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartFC.cxx b/src/emucore/CartFC.cxx index 113d259c3..565e577cf 100644 --- a/src/emucore/CartFC.cxx +++ b/src/emucore/CartFC.cxx @@ -115,7 +115,7 @@ bool CartridgeFC::bank(uInt16 bank) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -126,7 +126,7 @@ bool CartridgeFC::bank(uInt16 bank) access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } myCurrentBank = myTargetBank; diff --git a/src/emucore/CartFE.cxx b/src/emucore/CartFE.cxx index eaa17bc4d..36cfa7c84 100644 --- a/src/emucore/CartFE.cxx +++ b/src/emucore/CartFE.cxx @@ -107,8 +107,8 @@ bool CartridgeFE::bank(uInt16 bank) for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[addr & 0x0FFF]; - access.romPokeCounter = &myRomAccessCounter[addr & 0x0FFF + myImage.size()]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } diff --git a/src/emucore/CartMDM.cxx b/src/emucore/CartMDM.cxx index a3b0a0a6c..4c69f7c7c 100644 --- a/src/emucore/CartMDM.cxx +++ b/src/emucore/CartMDM.cxx @@ -112,6 +112,8 @@ bool CartridgeMDM::bank(uInt16 bank) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } diff --git a/src/emucore/CartMNetwork.cxx b/src/emucore/CartMNetwork.cxx index e9a3a5e45..c5ff0cfab 100644 --- a/src/emucore/CartMNetwork.cxx +++ b/src/emucore/CartMNetwork.cxx @@ -71,6 +71,8 @@ void CartridgeMNetwork::setAccess(uInt16 addrFrom, uInt16 size, else if(type == System::PageAccessType::WRITE) // all RAM writes mapped to ::poke() access.directPokeBase = nullptr; access.romAccessBase = &myRomAccessBase[codeOffset + (addr & addrMask)]; + access.romPeekCounter = &myRomAccessCounter[codeOffset + (addr & addrMask)]; + access.romPokeCounter = &myRomAccessCounter[codeOffset + (addr & addrMask) + myAccessSize]; mySystem->setPageAccess(addr, access); } } @@ -87,6 +89,8 @@ void CartridgeMNetwork::install(System& system) addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[0x1fc0]; + access.romPeekCounter = &myRomAccessCounter[0x1fc0]; + access.romPokeCounter = &myRomAccessCounter[0x1fc0 + myAccessSize]; mySystem->setPageAccess(addr, access); } /*setAccess(0x1FE0 & ~System::PAGE_MASK, System::PAGE_SIZE, diff --git a/src/emucore/CartSB.cxx b/src/emucore/CartSB.cxx index 34db0cca1..44ff9381f 100644 --- a/src/emucore/CartSB.cxx +++ b/src/emucore/CartSB.cxx @@ -122,6 +122,8 @@ bool CartridgeSB::bank(uInt16 bank) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; + access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartUA.cxx b/src/emucore/CartUA.cxx index ed2bd80bf..bfa1321bb 100644 --- a/src/emucore/CartUA.cxx +++ b/src/emucore/CartUA.cxx @@ -137,7 +137,7 @@ bool CartridgeUA::bank(uInt16 bank) access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; diff --git a/src/emucore/CartWD.cxx b/src/emucore/CartWD.cxx index 62b5a6c17..c6373fa05 100644 --- a/src/emucore/CartWD.cxx +++ b/src/emucore/CartWD.cxx @@ -65,7 +65,7 @@ void CartridgeWD::install(System& system) read.directPeekBase = &myRAM[addr & 0x003F]; read.romAccessBase = &myRomAccessBase[addr & 0x003F]; read.romPeekCounter = &myRomAccessCounter[addr & 0x003F]; - read.romPokeCounter = &myRomAccessCounter[(addr & 0x003F) + myImage.size()]; + read.romPokeCounter = &myRomAccessCounter[(addr & 0x003F) + 8_KB]; mySystem->setPageAccess(addr, read); } @@ -77,7 +77,7 @@ void CartridgeWD::install(System& system) { write.romAccessBase = &myRomAccessBase[addr & 0x003F]; write.romPeekCounter = &myRomAccessCounter[addr & 0x003F]; - write.romPokeCounter = &myRomAccessCounter[(addr & 0x003F) + myImage.size()]; + write.romPokeCounter = &myRomAccessCounter[(addr & 0x003F) + 8_KB]; mySystem->setPageAccess(addr, write); } @@ -183,7 +183,7 @@ void CartridgeWD::segmentZero(uInt8 slice) { access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)]; - access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + 8_KB]; mySystem->setPageAccess(addr, access); } myOffset[0] = offset; @@ -199,7 +199,7 @@ void CartridgeWD::segmentOne(uInt8 slice) { access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)]; - access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + 8_KB]; mySystem->setPageAccess(addr, access); } myOffset[1] = offset; @@ -215,7 +215,7 @@ void CartridgeWD::segmentTwo(uInt8 slice) { access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)]; - access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + 8_KB]; mySystem->setPageAccess(addr, access); } myOffset[2] = offset; @@ -237,7 +237,7 @@ void CartridgeWD::segmentThree(uInt8 slice) { access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)]; - access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + 8_KB]; mySystem->setPageAccess(addr, access); } myOffset[3] = offset; diff --git a/src/emucore/CartX07.cxx b/src/emucore/CartX07.cxx index 49fc30e0f..96bf5e4ed 100644 --- a/src/emucore/CartX07.cxx +++ b/src/emucore/CartX07.cxx @@ -117,7 +117,7 @@ bool CartridgeX07::bank(uInt16 bank) access.directPeekBase = &myImage[offset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[offset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x0FFF) + myImage.size()]; + access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x0FFF) + myAccessSize]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; From 40bbd019fc544ef1c22438697797b943a4b5571b Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 2 Apr 2020 16:26:56 +0200 Subject: [PATCH 077/377] fix right diff action on Command menus --- src/gui/CommandDialog.cxx | 2 +- src/gui/MinUICommandDialog.cxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/CommandDialog.cxx b/src/gui/CommandDialog.cxx index d33fe3c57..6eaf714b7 100644 --- a/src/gui/CommandDialog.cxx +++ b/src/gui/CommandDialog.cxx @@ -65,7 +65,7 @@ CommandDialog::CommandDialog(OSystem& osystem, DialogContainer& parent) wid.push_back(myColorButton); myLeftDiffButton = ADD_CD_BUTTON("", kLeftDiffCmd); wid.push_back(myLeftDiffButton); - myRightDiffButton = ADD_CD_BUTTON("", kLeftDiffCmd); + myRightDiffButton = ADD_CD_BUTTON("", kRightDiffCmd); wid.push_back(myRightDiffButton); // Column 2 diff --git a/src/gui/MinUICommandDialog.cxx b/src/gui/MinUICommandDialog.cxx index dbb17870a..b93b95890 100644 --- a/src/gui/MinUICommandDialog.cxx +++ b/src/gui/MinUICommandDialog.cxx @@ -67,7 +67,7 @@ MinUICommandDialog::MinUICommandDialog(OSystem& osystem, DialogContainer& parent wid.push_back(myColorButton); myLeftDiffButton = ADD_CD_BUTTON("", kLeftDiffCmd); wid.push_back(myLeftDiffButton); - myRightDiffButton = ADD_CD_BUTTON("", kLeftDiffCmd); + myRightDiffButton = ADD_CD_BUTTON("", kRightDiffCmd); wid.push_back(myRightDiffButton); // Column 2 From c2e4b5d67c74a5aeec97d42d44f37320d0ae4e31 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 2 Apr 2020 17:59:04 +0200 Subject: [PATCH 078/377] fix M6532 access counters make stack pops result into DATA access --- src/emucore/M6502.ins | 10 +++++----- src/emucore/M6502.m4 | 10 +++++----- src/emucore/M6532.cxx | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/emucore/M6502.ins b/src/emucore/M6502.ins index f48e689eb..e04ac9cb2 100644 --- a/src/emucore/M6502.ins +++ b/src/emucore/M6502.ins @@ -3770,9 +3770,9 @@ case 0x40: } { peek(0x0100 + SP++, DISASM_NONE); - PS(peek(0x0100 + SP++, DISASM_NONE)); - PC = peek(0x0100 + SP++, DISASM_NONE); - PC |= (uInt16(peek(0x0100 + SP, DISASM_NONE)) << 8); + PS(peek(0x0100 + SP++, DISASM_DATA)); + PC = peek(0x0100 + SP++, DISASM_DATA); + PC |= (uInt16(peek(0x0100 + SP, DISASM_DATA)) << 8); } break; @@ -3784,8 +3784,8 @@ case 0x60: } { peek(0x0100 + SP++, DISASM_NONE); - PC = peek(0x0100 + SP++, DISASM_NONE); - PC |= (uInt16(peek(0x0100 + SP, DISASM_NONE)) << 8); + PC = peek(0x0100 + SP++, DISASM_DATA); + PC |= (uInt16(peek(0x0100 + SP, DISASM_DATA)) << 8); peek(PC++, DISASM_NONE); } break; diff --git a/src/emucore/M6502.m4 b/src/emucore/M6502.m4 index 0c9046018..da097512f 100644 --- a/src/emucore/M6502.m4 +++ b/src/emucore/M6502.m4 @@ -885,15 +885,15 @@ define(M6502_RRA, `{ define(M6502_RTI, `{ peek(0x0100 + SP++, DISASM_NONE); - PS(peek(0x0100 + SP++, DISASM_NONE)); - PC = peek(0x0100 + SP++, DISASM_NONE); - PC |= (uInt16(peek(0x0100 + SP, DISASM_NONE)) << 8); + PS(peek(0x0100 + SP++, DISASM_DATA)); + PC = peek(0x0100 + SP++, DISASM_DATA); + PC |= (uInt16(peek(0x0100 + SP, DISASM_DATA)) << 8); }') define(M6502_RTS, `{ peek(0x0100 + SP++, DISASM_NONE); - PC = peek(0x0100 + SP++, DISASM_NONE); - PC |= (uInt16(peek(0x0100 + SP, DISASM_NONE)) << 8); + PC = peek(0x0100 + SP++, DISASM_DATA); + PC |= (uInt16(peek(0x0100 + SP, DISASM_DATA)) << 8); peek(PC++, DISASM_NONE); }') diff --git a/src/emucore/M6532.cxx b/src/emucore/M6532.cxx index 3453596cd..f9eb8025c 100644 --- a/src/emucore/M6532.cxx +++ b/src/emucore/M6532.cxx @@ -501,15 +501,15 @@ void M6532::setAccessFlags(uInt16 address, Device::AccessFlags flags) void M6532::increaseAccessCounter(uInt16 address, bool isWrite) { if (address & IO_BIT) - myIOAccessCounter[isWrite ? 0 : IO_SIZE + (address & IO_MASK)]++; + myIOAccessCounter[(isWrite ? IO_SIZE : 0) + (address & IO_MASK)]++; else { // the first access, either by direct RAM or stack access is assumed as initialization if (myZPAccessDelay[address & RAM_MASK]) myZPAccessDelay[address & RAM_MASK]--; else if (address & STACK_BIT) - myStackAccessCounter[isWrite ? 0 : STACK_SIZE + (address & STACK_MASK)]++; + myStackAccessCounter[(isWrite ? STACK_SIZE : 0) + (address & STACK_MASK)]++; else - myRAMAccessCounter[isWrite ? 0 : RAM_SIZE + (address & RAM_MASK)]++; + myRAMAccessCounter[(isWrite ? RAM_SIZE : 0) + (address & RAM_MASK)]++; } } From ba09797bb300313f839bdd9fd22516e5d620cbda Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Thu, 2 Apr 2020 21:14:49 +0200 Subject: [PATCH 079/377] 3E: fix invalid access on write to ROM. --- src/emucore/Cart3E.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/emucore/Cart3E.cxx b/src/emucore/Cart3E.cxx index 15084b53e..3f2b1263f 100644 --- a/src/emucore/Cart3E.cxx +++ b/src/emucore/Cart3E.cxx @@ -115,6 +115,9 @@ bool Cartridge3E::poke(uInt16 address, uInt8 value) } else { + if (myCurrentBank < 256) + return false; + if(address & 0x0400) { pokeRAM(myRAM[(address & 0x03FF) + ((myCurrentBank - 256) << 10)], pokeAddress, value); From bf7a8be99f065c0fbbad2aad03eec41bc4eb174e Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Thu, 2 Apr 2020 21:18:56 +0200 Subject: [PATCH 080/377] 3E: improve debugger handling for writes to ROM space. --- src/emucore/Cart3E.cxx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/emucore/Cart3E.cxx b/src/emucore/Cart3E.cxx index 3f2b1263f..f908cd65a 100644 --- a/src/emucore/Cart3E.cxx +++ b/src/emucore/Cart3E.cxx @@ -115,17 +115,14 @@ bool Cartridge3E::poke(uInt16 address, uInt8 value) } else { - if (myCurrentBank < 256) - return false; - - if(address & 0x0400) + if(address & 0x0400 && myCurrentBank >= 256) { pokeRAM(myRAM[(address & 0x03FF) + ((myCurrentBank - 256) << 10)], pokeAddress, value); return true; } else { - // Writing to the read port should be ignored, but trigger a break if option enabled + // Writing to the read port or to ROM should be ignored, but trigger a break if option enabled uInt8 dummy; pokeRAM(dummy, pokeAddress, value); From 8ae062b8175babb00ade8770c6aef661d2572f83 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Thu, 2 Apr 2020 20:44:13 -0230 Subject: [PATCH 081/377] A little more optimization to 3E scheme. --- src/emucore/Cart3E.cxx | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/src/emucore/Cart3E.cxx b/src/emucore/Cart3E.cxx index f908cd65a..0947d783e 100644 --- a/src/emucore/Cart3E.cxx +++ b/src/emucore/Cart3E.cxx @@ -75,25 +75,19 @@ uInt8 Cartridge3E::peek(uInt16 address) uInt16 peekAddress = address; address &= 0x0FFF; - if(address < 0x0800) + // Due to the way paging is set up, the only way to get here is a TIA read or + // attempting to read from the RAM write port + + if(address < 0x0040) // TIA access + return mySystem->tia().peek(address); + else if(myCurrentBank >= 256) { - if(myCurrentBank < 256) - return myImage[(address & 0x07FF) + (myCurrentBank << 11)]; - else - { - if(address < 0x0400) - return myRAM[(address & 0x03FF) + ((myCurrentBank - 256) << 10)]; - else - { - // Reading from the write port triggers an unwanted write - return peekRAM(myRAM[(address & 0x03FF) + ((myCurrentBank - 256) << 10)], peekAddress); - } - } - } - else - { - return myImage[(address & 0x07FF) + mySize - 2048]; + // Reading from the write port triggers an unwanted write + return peekRAM(myRAM[(address & 0x03FF) + ((myCurrentBank - 256) << 10)], peekAddress); } + + // Make compiler happy; should never get here + return myImage[(address & 0x07FF) + mySize - 2048]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -113,16 +107,17 @@ bool Cartridge3E::poke(uInt16 address, uInt8 value) return mySystem->tia().poke(address, value); } - else + else if(myCurrentBank >= 256) { - if(address & 0x0400 && myCurrentBank >= 256) + if(address & 0x0400) { - pokeRAM(myRAM[(address & 0x03FF) + ((myCurrentBank - 256) << 10)], pokeAddress, value); + pokeRAM(myRAM[(address & 0x03FF) + ((myCurrentBank - 256) << 10)], + pokeAddress, value); return true; } else { - // Writing to the read port or to ROM should be ignored, but trigger a break if option enabled + // Writing to the read port should be ignored, but trigger a break if option enabled uInt8 dummy; pokeRAM(dummy, pokeAddress, value); @@ -130,6 +125,7 @@ bool Cartridge3E::poke(uInt16 address, uInt8 value) return false; } } + return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -178,6 +174,7 @@ bool Cartridge3E::bank(uInt16 bank) System::PageAccess access(this, System::PageAccessType::READ); // Map read-port RAM image into the system + // Writes are mapped to poke(), to check for write to the read port for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE) { access.directPeekBase = &myRAM[offset + (addr & 0x03FF)]; @@ -191,8 +188,7 @@ bool Cartridge3E::bank(uInt16 bank) access.type = System::PageAccessType::WRITE; // Map write-port RAM image into the system - // Map access to this class, since we need to inspect all accesses to - // check if RWP happens + // Reads are mapped to peek(), to check for read from write port for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE) { access.romAccessBase = &myRomAccessBase[mySize + offset + (addr & 0x03FF)]; From 74bdc9d6afcc05ed1c876c683b9c6c579b964349 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Thu, 2 Apr 2020 20:58:02 -0230 Subject: [PATCH 082/377] Synchronize changelog from 6.1.1. --- Changes.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Changes.txt b/Changes.txt index 8babda153..3ae1dba63 100644 --- a/Changes.txt +++ b/Changes.txt @@ -29,11 +29,16 @@ 6.1 to 6.1.1: (April 4, 2020) + * Fixed crash in 3E bankswitching scheme when writing to ROM addresses. + * Fix snapshots on Retina HiDPI displays capturing only the top-left corner. * Fixed wrong color for BK (background) swatch in the debugger. + * Fixed 'Right Diff' button in Command menu changing left difficulty + instead. + * Fixed compilation of libretro port on Debian Buster. From 2db1ea172b693f0f9d39de6f54b7067234596239 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Fri, 3 Apr 2020 17:08:42 +0200 Subject: [PATCH 083/377] initial commit --- src/common/bspf.hxx | 1 + src/debugger/gui/CartE0Widget.cxx | 18 +- src/emucore/CartE0.cxx | 101 ++----- src/emucore/CartE0.hxx | 20 +- src/emucore/CartEnhanced.cxx | 259 ++++++++++++++++++ src/emucore/CartEnhanced.hxx | 204 ++++++++++++++ src/emucore/CartF0.cxx | 152 +--------- src/emucore/CartF0.hxx | 104 +------ src/emucore/CartF4.cxx | 139 +--------- src/emucore/CartF4.hxx | 101 +------ src/emucore/CartF4SC.cxx | 204 +------------- src/emucore/CartF4SC.hxx | 102 +------ src/emucore/CartF6.cxx | 182 +----------- src/emucore/CartF6.hxx | 99 +------ src/emucore/CartF6SC.cxx | 244 +---------------- src/emucore/CartF6SC.hxx | 102 +------ src/emucore/CartF8.cxx | 151 +--------- src/emucore/CartF8.hxx | 98 +------ src/emucore/CartF8SC.cxx | 224 +-------------- src/emucore/CartF8SC.hxx | 102 +------ src/emucore/CartFC.cxx | 133 +-------- src/emucore/CartFC.hxx | 90 +----- src/emucore/CartFE.cxx | 100 ++----- src/emucore/CartFE.hxx | 50 +--- src/emucore/CartMNetwork.hxx | 2 +- src/emucore/CartUA.cxx | 133 +-------- src/emucore/CartUA.hxx | 72 +---- src/windows/Stella.vcxproj | 2 + src/windows/Stella.vcxproj.filters | 6 + {profile => test/roms/profile}/128.bin | Bin {profile => test/roms/profile}/README.md | 0 .../roms/profile}/catharsis_theory.bin | Bin 32 files changed, 656 insertions(+), 2539 deletions(-) create mode 100644 src/emucore/CartEnhanced.cxx create mode 100644 src/emucore/CartEnhanced.hxx rename {profile => test/roms/profile}/128.bin (100%) rename {profile => test/roms/profile}/README.md (100%) rename {profile => test/roms/profile}/catharsis_theory.bin (100%) diff --git a/src/common/bspf.hxx b/src/common/bspf.hxx index e7cc60024..06333b13c 100644 --- a/src/common/bspf.hxx +++ b/src/common/bspf.hxx @@ -84,6 +84,7 @@ using ByteArray = std::vector; using ShortArray = std::vector; using StringList = std::vector; using ByteBuffer = std::unique_ptr; // NOLINT +using WordBuffer = std::unique_ptr; // NOLINT // We use KB a lot; let's make a literal for it constexpr uInt32 operator "" _KB(unsigned long long size) diff --git a/src/debugger/gui/CartE0Widget.cxx b/src/debugger/gui/CartE0Widget.cxx index 9413ce5c0..de845b197 100644 --- a/src/debugger/gui/CartE0Widget.cxx +++ b/src/debugger/gui/CartE0Widget.cxx @@ -98,9 +98,9 @@ CartridgeE0Widget::CartridgeE0Widget( // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeE0Widget::loadConfig() { - mySlice0->setSelectedIndex(myCart.myCurrentSlice[0]); - mySlice1->setSelectedIndex(myCart.myCurrentSlice[1]); - mySlice2->setSelectedIndex(myCart.myCurrentSlice[2]); + mySlice0->setSelectedIndex(myCart.myCurrentBank[0]); + mySlice1->setSelectedIndex(myCart.myCurrentBank[1]); + mySlice2->setSelectedIndex(myCart.myCurrentBank[2]); CartDebugWidget::loadConfig(); } @@ -114,13 +114,13 @@ void CartridgeE0Widget::handleCommand(CommandSender* sender, switch(cmd) { case kSlice0Changed: - myCart.segmentZero(mySlice0->getSelected()); + myCart.bank(mySlice0->getSelected(), 0); break; case kSlice1Changed: - myCart.segmentOne(mySlice1->getSelected()); + myCart.bank(mySlice1->getSelected(), 1); break; case kSlice2Changed: - myCart.segmentTwo(mySlice2->getSelected()); + myCart.bank(mySlice2->getSelected(), 2); break; default: break; @@ -136,9 +136,9 @@ string CartridgeE0Widget::bankState() ostringstream& buf = buffer(); buf << "Slices: " << std::dec - << seg0[myCart.myCurrentSlice[0]] << " / " - << seg1[myCart.myCurrentSlice[1]] << " / " - << seg2[myCart.myCurrentSlice[2]]; + << seg0[myCart.myCurrentBank[0]] << " / " + << seg1[myCart.myCurrentBank[1]] << " / " + << seg2[myCart.myCurrentBank[2]]; return buf.str(); } diff --git a/src/emucore/CartE0.cxx b/src/emucore/CartE0.cxx index ff3a9b52c..3788a95bc 100644 --- a/src/emucore/CartE0.cxx +++ b/src/emucore/CartE0.cxx @@ -34,17 +34,17 @@ void CartridgeE0::reset() // Setup segments to some default slices if(randomStartBank()) { - segmentZero(mySystem->randGenerator().next() % 8); - segmentOne(mySystem->randGenerator().next() % 8); - segmentTwo(mySystem->randGenerator().next() % 8); + bank(mySystem->randGenerator().next() % 8, 0); + bank(mySystem->randGenerator().next() % 8, 1); + bank(mySystem->randGenerator().next() % 8, 2); } else { - segmentZero(4); - segmentOne(5); - segmentTwo(6); + bank(4, 0); + bank(5, 1); + bank(6, 2); } - myCurrentSlice[3] = 7; // fixed + myCurrentBank[3] = bankCount() - 1; // fixed myBankChanged = true; } @@ -69,7 +69,7 @@ void CartridgeE0::install(System& system) // Set the page accessing methods for the hot spots in the last segment access.directPeekBase = nullptr; - access.romAccessBase = &myRomAccessBase[0x1FC0]; // TJ: is this the correct address (or 0x1FE0)? + access.romAccessBase = &myRomAccessBase[0x1FC0]; access.romPeekCounter = &myRomAccessCounter[0x1FC0]; access.romPokeCounter = &myRomAccessCounter[0x1FC0 + myAccessSize]; access.type = System::PageAccessType::READ; @@ -81,7 +81,7 @@ void CartridgeE0::install(System& system) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeE0::getBank(uInt16 address) const { - return myCurrentSlice[(address & 0xFFF) >> 10]; // 1K slices + return myCurrentBank[(address & 0xFFF) >> 10]; // 1K slices } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -98,18 +98,18 @@ uInt8 CartridgeE0::peek(uInt16 address) // Switch banks if necessary if((address >= 0x0FE0) && (address <= 0x0FE7)) { - segmentZero(address & 0x0007); + bank(address & 0x0007, 0); } else if((address >= 0x0FE8) && (address <= 0x0FEF)) { - segmentOne(address & 0x0007); + bank(address & 0x0007, 1); } else if((address >= 0x0FF0) && (address <= 0x0FF7)) { - segmentTwo(address & 0x0007); + bank(address & 0x0007, 2); } - return myImage[(myCurrentSlice[address >> 10] << 10) + (address & 0x03FF)]; + return myImage[(myCurrentBank[address >> 10] << 10) + (address & 0x03FF)]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -120,83 +120,38 @@ bool CartridgeE0::poke(uInt16 address, uInt8) // Switch banks if necessary if((address >= 0x0FE0) && (address <= 0x0FE7)) { - segmentZero(address & 0x0007); + bank(address & 0x0007, 0); } else if((address >= 0x0FE8) && (address <= 0x0FEF)) { - segmentOne(address & 0x0007); + bank(address & 0x0007, 1); } else if((address >= 0x0FF0) && (address <= 0x0FF7)) { - segmentTwo(address & 0x0007); + bank(address & 0x0007, 2); } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeE0::segmentZero(uInt16 slice) +void CartridgeE0::bank(uInt16 bank, uInt16 slice) { if(bankLocked()) return; // Remember the new slice - myCurrentSlice[0] = slice; - uInt16 offset = slice << 10; + myCurrentBank[slice] = bank; + uInt16 sliceOffset = slice * (1 << 10); + uInt16 bankOffset = bank << 10; // Setup the page access methods for the current bank System::PageAccess access(this, System::PageAccessType::READ); - for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE) + for(uInt16 addr = 0x1000 + sliceOffset; addr < 0x1000 + sliceOffset + 0x400; addr += System::PAGE_SIZE) { - access.directPeekBase = &myImage[offset + (addr & 0x03FF)]; - access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; - access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)]; - access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeE0::segmentOne(uInt16 slice) -{ - if(bankLocked()) return; - - // Remember the new slice - myCurrentSlice[1] = slice; - uInt16 offset = slice << 10; - - // Setup the page access methods for the current bank - System::PageAccess access(this, System::PageAccessType::READ); - - for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[offset + (addr & 0x03FF)]; - access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; - access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)]; - access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeE0::segmentTwo(uInt16 slice) -{ - if(bankLocked()) return; - - // Remember the new slice - myCurrentSlice[2] = slice; - uInt16 offset = slice << 10; - - // Setup the page access methods for the current bank - System::PageAccess access(this, System::PageAccessType::READ); - - for(uInt16 addr = 0x1800; addr < 0x1C00; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[offset + (addr & 0x03FF)]; - access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; - access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)]; - access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + myAccessSize]; + access.directPeekBase = &myImage[bankOffset + (addr & 0x03FF)]; + access.romAccessBase = &myRomAccessBase[bankOffset + (addr & 0x03FF)]; + access.romPeekCounter = &myRomAccessCounter[bankOffset + (addr & 0x03FF)]; + access.romPokeCounter = &myRomAccessCounter[bankOffset + (addr & 0x03FF) + myAccessSize]; mySystem->setPageAccess(addr, access); } myBankChanged = true; @@ -206,7 +161,7 @@ void CartridgeE0::segmentTwo(uInt16 slice) bool CartridgeE0::patch(uInt16 address, uInt8 value) { address &= 0x0FFF; - myImage[(myCurrentSlice[address >> 10] << 10) + (address & 0x03FF)] = value; + myImage[(myCurrentBank[address >> 10] << 10) + (address & 0x03FF)] = value; return true; } @@ -222,7 +177,7 @@ bool CartridgeE0::save(Serializer& out) const { try { - out.putShortArray(myCurrentSlice.data(), myCurrentSlice.size()); + out.putShortArray(myCurrentBank.data(), myCurrentBank.size()); } catch(...) { @@ -238,7 +193,7 @@ bool CartridgeE0::load(Serializer& in) { try { - in.getShortArray(myCurrentSlice.data(), myCurrentSlice.size()); + in.getShortArray(myCurrentBank.data(), myCurrentBank.size()); } catch(...) { diff --git a/src/emucore/CartE0.hxx b/src/emucore/CartE0.hxx index 0a9453ab2..35513be85 100644 --- a/src/emucore/CartE0.hxx +++ b/src/emucore/CartE0.hxx @@ -156,32 +156,18 @@ class CartridgeE0 : public Cartridge private: /** - Install the specified slice for segment zero + Install the specified slice for segment (bank) 0..2 @param slice The slice to map into the segment */ - void segmentZero(uInt16 slice); - - /** - Install the specified slice for segment one - - @param slice The slice to map into the segment - */ - void segmentOne(uInt16 slice); - - /** - Install the specified slice for segment two - - @param slice The slice to map into the segment - */ - void segmentTwo(uInt16 slice); + void bank(uInt16 bank, uInt16 slice); private: // The 8K ROM image of the cartridge std::array myImage; // Indicates the slice mapped into each of the four segments - std::array myCurrentSlice; + std::array myCurrentBank; private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx new file mode 100644 index 000000000..ff4113ad4 --- /dev/null +++ b/src/emucore/CartEnhanced.cxx @@ -0,0 +1,259 @@ +//============================================================================ +// +// 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 "CartEnhanced.hxx" + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +CartridgeEnhanced::CartridgeEnhanced(const ByteBuffer& image, size_t size, + const string& md5, const Settings& settings) + : Cartridge(settings, md5), + mySize(size) +{ + // Allocate array for the ROM image + myImage = make_unique(mySize); + + // Copy the ROM image into my buffer + std::copy_n(image.get(), mySize, myImage.get()); + + // Copy the ROM image into my buffer + createRomAccessArrays(mySize); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void CartridgeEnhanced::install(System& system) +{ + // Allocate array for the current bank segments slices + myCurrentBankOffset = make_unique(BANK_SEGS); + std::fill_n(myCurrentBankOffset.get(), BANK_SEGS, 0); + + // Allocate array for the RAM area + myRAM = make_unique(myRamSize); + + // Setup page access + mySystem = &system; + + System::PageAccess access(this, System::PageAccessType::READ); + + // Set the page accessing method for the RAM writing pages + // Map access to this class, since we need to inspect all accesses to + // check if RWP happens + access.type = System::PageAccessType::WRITE; + for(uInt16 addr = 0x1000; addr < 0x1000 + myRamSize; addr += System::PAGE_SIZE) + { + uInt16 offset = addr & myRamMask; + access.romAccessBase = &myRomAccessBase[offset]; + access.romPeekCounter = &myRomAccessCounter[offset]; + access.romPokeCounter = &myRomAccessCounter[offset + myAccessSize]; + mySystem->setPageAccess(addr, access); + } + + // Set the page accessing method for the RAM reading pages + access.type = System::PageAccessType::READ; + for(uInt16 addr = 0x1000 + myRamSize; addr < 0x1000 + myRamSize * 2; addr += System::PAGE_SIZE) + { + uInt16 offset = addr & myRamMask; + access.directPeekBase = &myRAM[offset]; + access.romAccessBase = &myRomAccessBase[myRamSize + offset]; + access.romPeekCounter = &myRomAccessCounter[myRamSize + offset]; + access.romPokeCounter = &myRomAccessCounter[myRamSize + offset + myAccessSize]; + mySystem->setPageAccess(addr, access); + } + + // Install pages for the startup bank + bank(startBank()); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void CartridgeEnhanced::reset() +{ + initializeRAM(myRAM.get(), myRamSize); + + initializeStartBank(getStartBank()); + + // Upon reset we switch to the reset bank + bank(startBank()); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt8 CartridgeEnhanced::peek(uInt16 address) +{ + uInt16 peekAddress = address; + address &= myBankMask; + + checkSwitchBank(address); + + if(address < myRamSize) // Write port is at 0xF000 - 0xF07F (128 bytes) + return peekRAM(myRAM[address], peekAddress); + else + return myImage[myBankOffset + address]; + return myImage[myCurrentBankOffset[address >> BANK_SHIFT] + (address & BANK_MASK)]; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CartridgeEnhanced::poke(uInt16 address, uInt8 value) +{ + address &= myBankMask; + + // Switch banks if necessary + if (checkSwitchBank(address & myBankMask)) + return false; + + if(myRamSize) + { + if(!(address & myRamSize)) + { + pokeRAM(myRAM[address & myRamMask], address, value); + return true; + } + else + { + // Writing to the read port should be ignored, but trigger a break if option enabled + uInt8 dummy; + + pokeRAM(dummy, address, value); + myRamWriteAccess = address; + } + } + return false; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CartridgeEnhanced::bank(uInt16 bank, uInt16 slice) +{ + if(bankLocked()) return false; + + // Remember what bank we're in + myBankOffset = bank << myBankShift; + + uInt16 romHotspot = this->romHotspot(); + uInt16 fromAddr = 0x1000 + myRamSize * 2; + uInt16 toAddr; + + if(romHotspot) + { + System::PageAccess access(this, System::PageAccessType::READ); + + // Set the page accessing methods for the hot spots + for(uInt16 addr = (romHotspot & ~System::PAGE_MASK); addr < 0x1000 + myBankSize; + addr += System::PAGE_SIZE) + { + uInt16 offset = myBankOffset + (addr & myBankMask); + access.romAccessBase = &myRomAccessBase[offset]; + access.romPeekCounter = &myRomAccessCounter[offset]; + access.romPokeCounter = &myRomAccessCounter[offset + myAccessSize]; + mySystem->setPageAccess(addr, access); + } + toAddr = romHotspot; + } + else + toAddr = 0x1000 + myBankSize; + + System::PageAccess access(this, System::PageAccessType::READ); + + // Setup the page access methods for the current bank + for(uInt16 addr = (fromAddr & ~System::PAGE_MASK); addr < (toAddr & ~System::PAGE_MASK); + addr += System::PAGE_SIZE) + { + uInt16 offset = myBankOffset + (addr & myBankMask); + if(myDirectPeek) + access.directPeekBase = &myImage[offset]; + access.romAccessBase = &myRomAccessBase[offset]; + access.romPeekCounter = &myRomAccessCounter[offset]; + access.romPokeCounter = &myRomAccessCounter[offset + myAccessSize]; + mySystem->setPageAccess(addr, access); + } + + return myBankChanged = true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt16 CartridgeEnhanced::getBank(uInt16) const +{ + return myBankOffset >> myBankShift; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt16 CartridgeEnhanced::bankCount() const +{ + return uInt16(mySize >> myBankShift); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CartridgeEnhanced::patch(uInt16 address, uInt8 value) +{ + address &= myBankMask; + + if(address < myRamSize * 2) + { + // Normally, a write to the read port won't do anything + // However, the patch command is special in that ignores such + // cart restrictions + myRAM[address & myRamMask] = value; + } + else + myImage[myBankOffset + address] = value; + + return myBankChanged = true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const uInt8* CartridgeEnhanced::getImage(size_t& size) const +{ + size = mySize; + return myImage.get(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CartridgeEnhanced::save(Serializer& out) const +{ + try + { + out.putShort(myBankOffset); + if(myRamSize) + out.putByteArray(myRAM.get(), myRamSize); + + } + catch(...) + { + cerr << "ERROR: << " << name() << "::save" << endl; + return false; + } + + return true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CartridgeEnhanced::load(Serializer& in) +{ + try + { + myBankOffset = in.getShort(); + if(myRamSize) + in.getByteArray(myRAM.get(), myRamSize); + } + catch(...) + { + cerr << "ERROR: " << name() << "::load" << endl; + return false; + } + + // Remember what bank we were in + bank(myBankOffset >> myBankShift); + + return true; +} diff --git a/src/emucore/CartEnhanced.hxx b/src/emucore/CartEnhanced.hxx new file mode 100644 index 000000000..22d253b6a --- /dev/null +++ b/src/emucore/CartEnhanced.hxx @@ -0,0 +1,204 @@ +//============================================================================ +// +// 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 CARTRIDGEENHANCED_HXX +#define CARTRIDGEENHANCED_HXX + +class System; + +#include "bspf.hxx" +#include "Cart.hxx" + +/** + Enhanced cartridge base class used for multiple cart types. + + @author Thomas Jentzsch +*/ +class CartridgeEnhanced : public Cartridge +{ + 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) + */ + CartridgeEnhanced(const ByteBuffer& image, size_t size, const string& md5, + const Settings& settings); + virtual ~CartridgeEnhanced() = default; + + public: + /** + Install cartridge in the specified system. Invoked by the system + when the cartridge is attached to it. + + @param system The system the device should install itself in + */ + void install(System& system) override; + + /** + Reset device to its power-on state + */ + void reset() override; + + + /** + Install pages for the specified bank in the system. + + @param bank The bank that should be installed in the system + */ + bool bank(uInt16 bank, uInt16 slice); + + /** + Install pages for the specified bank in the system. + + @param bank The bank that should be installed in the system + */ + bool bank(uInt16 bank) override { return this->bank(bank, 0); } + + /** + Get the current bank. + + @param address The address to use when querying the bank + */ + uInt16 getBank(uInt16 address = 0) const override; + + /** + Query the number of banks supported by the cartridge. + */ + uInt16 bankCount() const override; + + /** + Patch the cartridge ROM. + + @param address The ROM address to patch + @param value The value to place into the address + @return Success or failure of the patch operation + */ + bool patch(uInt16 address, uInt8 value) override; + + /** + 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 + */ + const uInt8* getImage(size_t& size) const 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; + + public: + /** + Get the byte at the specified address. + + @return The byte at the specified address + */ + uInt8 peek(uInt16 address) override; + + /** + Change the byte at the specified address to the given value + + @param address The address where the value should be stored + @param value The value to be stored at the address + @return True if the poke changed the device address space, else false + */ + bool poke(uInt16 address, uInt8 value) override; + + protected: + // Pointer to a dynamically allocated ROM image of the cartridge + ByteBuffer myImage{nullptr}; + + // Pointer to a dynamically allocated RAM area of the cartridge + ByteBuffer myRAM{nullptr}; + + uInt16 myBankShift{BANK_SHIFT}; + + uInt16 myBankSize{BANK_SIZE}; + + uInt16 myBankMask{BANK_MASK}; + + uInt16 myRamSize{RAM_SIZE}; + + uInt16 myRamMask{RAM_MASK}; + + bool myDirectPeek{true}; + + // Indicates the offset into the ROM image (aligns to current bank) + uInt16 myBankOffset{0}; + + // Indicates the slice mapped into each of the bank segments + WordBuffer myCurrentBankOffset{nullptr}; + + private: + // log(ROM bank size) / log(2) + static constexpr uInt16 BANK_SHIFT = 12; + + // bank size + static constexpr uInt16 BANK_SIZE = 1 << BANK_SHIFT; // 2 ^ 12 = 4K + + // bank mask + static constexpr uInt16 BANK_MASK = BANK_SIZE - 1; + + // bank segments + static constexpr uInt16 BANK_SEGS = 1; + + // RAM size + static constexpr uInt16 RAM_SIZE = 0; + + // RAM mask + static constexpr uInt16 RAM_MASK = 0; + + // Size of the ROM image + size_t mySize{0}; + + protected: + /** + Check hotspots and switch bank if triggered. + */ + virtual bool checkSwitchBank(uInt16 address, uInt8 value = 0) = 0; + + private: + virtual uInt16 getStartBank() const { return 0; } + + virtual uInt16 romHotspot() const { return 0; } + + private: + // Following constructors and assignment operators not supported + CartridgeEnhanced() = delete; + CartridgeEnhanced(const CartridgeEnhanced&) = delete; + CartridgeEnhanced(CartridgeEnhanced&&) = delete; + CartridgeEnhanced& operator=(const CartridgeEnhanced&) = delete; + CartridgeEnhanced& operator=(CartridgeEnhanced&&) = delete; +}; + +#endif diff --git a/src/emucore/CartF0.cxx b/src/emucore/CartF0.cxx index a69c3c8ed..9f021a685 100644 --- a/src/emucore/CartF0.cxx +++ b/src/emucore/CartF0.cxx @@ -15,159 +15,25 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#include "System.hxx" #include "CartF0.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF0::CartridgeF0(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5) + : CartridgeEnhanced(image, size, md5, settings) { - // Copy the ROM image into my buffer - std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF0::reset() +bool CartridgeF0::checkSwitchBank(uInt16 address, uInt8) { - // Upon reset we switch to the startup bank - initializeStartBank(15); - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF0::install(System& system) -{ - mySystem = &system; - - // Install pages for the startup bank - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeF0::peek(uInt16 address) -{ - address &= 0x0FFF; - - // Switch to next bank + // Switch banks if necessary if(address == 0x0FF0) - incbank(); - - return myImage[myBankOffset + address]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF0::poke(uInt16 address, uInt8) -{ - address &= 0x0FFF; - - // Switch to next bank - if(address == 0x0FF0) - incbank(); - + { + // Switch to next bank + uInt8 nextBank = ((getBank()) + 1) & 0x0F; + bank(nextBank); + return true; + } return false; } - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF0::incbank() -{ - // Determine current bank, and increment to the next one - uInt8 nextBank = ((myBankOffset >> 12) + 1) & 0x0F; - bank(nextBank); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF0::bank(uInt16 bank) -{ - if(bankLocked()) return false; - - // Remember what bank we're in - myBankOffset = bank << 12; - - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page accessing methods for the hot spots - for(uInt16 addr = (0x1FF0 & ~System::PAGE_MASK); addr < 0x2000; - addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Setup the page access methods for the current bank - for(uInt16 addr = 0x1000; addr < static_cast(0x1FF0U & ~System::PAGE_MASK); - addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeF0::getBank(uInt16) const -{ - return myBankOffset >> 12; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeF0::bankCount() const -{ - return 16; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF0::patch(uInt16 address, uInt8 value) -{ - myImage[myBankOffset + (address & 0x0FFF)] = value; - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeF0::getImage(size_t& size) const -{ - size = myImage.size(); - return myImage.data(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF0::save(Serializer& out) const -{ - try - { - out.putShort(myBankOffset); - } - catch(...) - { - cerr << "ERROR: CartridgeF0::save" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF0::load(Serializer& in) -{ - try - { - myBankOffset = in.getShort(); - } - catch(...) - { - cerr << "ERROR: CartridgeF0::load" << endl; - return false; - } - - // Remember what bank we were in - bank(myBankOffset >> 12); - - return true; -} diff --git a/src/emucore/CartF0.hxx b/src/emucore/CartF0.hxx index d4733a784..07123bf34 100644 --- a/src/emucore/CartF0.hxx +++ b/src/emucore/CartF0.hxx @@ -18,10 +18,7 @@ #ifndef CARTRIDGEF0_HXX #define CARTRIDGEF0_HXX -class System; - -#include "bspf.hxx" -#include "Cart.hxx" +#include "CartEnhanced.hxx" #ifdef DEBUGGER_SUPPORT #include "CartF0Widget.hxx" #endif @@ -31,9 +28,9 @@ class System; There are 16 4K banks. Accessing $1FF0 switches to next bank. - @author Eckhard Stolberg + @author Eckhard Stolberg, Thomas Jentzsch */ -class CartridgeF0 : public Cartridge +class CartridgeF0 : public CartridgeEnhanced { friend class CartridgeF0Widget; @@ -51,71 +48,6 @@ class CartridgeF0 : public Cartridge virtual ~CartridgeF0() = default; public: - /** - Reset device to its power-on state - */ - void reset() override; - - /** - Install cartridge in the specified system. Invoked by the system - when the cartridge is attached to it. - - @param system The system the device should install itself in - */ - void install(System& system) override; - - /** - Install pages for the specified bank in the system. - - @param bank The bank that should be installed in the system - */ - bool bank(uInt16 bank) override; - - /** - Get the current bank. - - @param address The address to use when querying the bank - */ - uInt16 getBank(uInt16 address = 0) const override; - - /** - Query the number of banks supported by the cartridge. - */ - uInt16 bankCount() const override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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). @@ -135,35 +67,13 @@ class CartridgeF0 : public Cartridge } #endif - public: - /** - Get the byte at the specified address. + protected: + bool checkSwitchBank(uInt16 address, uInt8 value = 0); - @return The byte at the specified address - */ - uInt8 peek(uInt16 address) override; - - /** - Change the byte at the specified address to the given value - - @param address The address where the value should be stored - @param value The value to be stored at the address - @return True if the poke changed the device address space, else false - */ - bool poke(uInt16 address, uInt8 value) override; + uInt16 romHotspot() const override { return 0x1FF0; } private: - /** - Install pages for the next bank in the system - */ - void incbank(); - - private: - // The 64K ROM image of the cartridge - std::array myImage; - - // Indicates the offset into the ROM image (aligns to current bank) - uInt16 myBankOffset{0}; + uInt16 getStartBank() const override { return 15; } private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartF4.cxx b/src/emucore/CartF4.cxx index 8111bb1a0..0cb689228 100644 --- a/src/emucore/CartF4.cxx +++ b/src/emucore/CartF4.cxx @@ -15,155 +15,24 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#include "Random.hxx" -#include "System.hxx" #include "CartF4.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF4::CartridgeF4(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5) + : CartridgeEnhanced(image, size, md5, settings) { - // Copy the ROM image into my buffer - std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF4::reset() +bool CartridgeF4::checkSwitchBank(uInt16 address, uInt8) { - // Upon reset we switch to the startup bank - initializeStartBank(0); - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF4::install(System& system) -{ - mySystem = &system; - - // Install pages for the startup bank - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeF4::peek(uInt16 address) -{ - address &= 0x0FFF; - // Switch banks if necessary + // Note: addresses could be calculated from hotspot and bank count if((address >= 0x0FF4) && (address <= 0x0FFB)) { bank(address - 0x0FF4); + return true; } - - return myImage[myBankOffset + address]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF4::poke(uInt16 address, uInt8) -{ - address &= 0x0FFF; - - // Switch banks if necessary - if((address >= 0x0FF4) && (address <= 0x0FFB)) - { - bank(address - 0x0FF4); - } - return false; } - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF4::bank(uInt16 bank) -{ - if(bankLocked()) return false; - - // Remember what bank we're in - myBankOffset = bank << 12; - - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page accessing methods for the hot spots - for(uInt16 addr = (0x1FF4 & ~System::PAGE_MASK); addr < 0x2000; - addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Setup the page access methods for the current bank - for(uInt16 addr = 0x1000; addr < static_cast(0x1FF4U & ~System::PAGE_MASK); - addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeF4::getBank(uInt16) const -{ - return myBankOffset >> 12; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeF4::bankCount() const -{ - return 8; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF4::patch(uInt16 address, uInt8 value) -{ - myImage[myBankOffset + (address & 0x0FFF)] = value; - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeF4::getImage(size_t& size) const -{ - size = myImage.size(); - return myImage.data(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF4::save(Serializer& out) const -{ - try - { - out.putShort(myBankOffset); - } - catch(...) - { - cerr << "ERROR: CartridgeF4::save" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF4::load(Serializer& in) -{ - try - { - myBankOffset = in.getShort(); - } - catch(...) - { - cerr << "ERROR: CartridgeF4::load" << endl; - return false; - } - - // Remember what bank we were in - bank(myBankOffset >> 12); - - return true; -} diff --git a/src/emucore/CartF4.hxx b/src/emucore/CartF4.hxx index d9c8fd346..3b4f0f141 100644 --- a/src/emucore/CartF4.hxx +++ b/src/emucore/CartF4.hxx @@ -18,10 +18,7 @@ #ifndef CARTRIDGEF4_HXX #define CARTRIDGEF4_HXX -class System; - -#include "bspf.hxx" -#include "Cart.hxx" +#include "CartEnhanced.hxx" #ifdef DEBUGGER_SUPPORT #include "CartF4Widget.hxx" #endif @@ -30,9 +27,9 @@ class System; Cartridge class used for Atari's 32K bankswitched games. There are eight 4K banks, accessible by read/write to $1FF4 - $1FFB. - @author Bradford W. Mott + @author Bradford W. Mott, Thomas Jentzsch */ -class CartridgeF4 : public Cartridge +class CartridgeF4 : public CartridgeEnhanced { friend class CartridgeF4Widget; @@ -50,71 +47,6 @@ class CartridgeF4 : public Cartridge virtual ~CartridgeF4() = default; public: - /** - Reset device to its power-on state - */ - void reset() override; - - /** - Install cartridge in the specified system. Invoked by the system - when the cartridge is attached to it. - - @param system The system the device should install itself in - */ - void install(System& system) override; - - /** - Install pages for the specified bank in the system. - - @param bank The bank that should be installed in the system - */ - bool bank(uInt16 bank) override; - - /** - Get the current bank. - - @param address The address to use when querying the bank - */ - uInt16 getBank(uInt16 address = 0) const override; - - /** - Query the number of banks supported by the cartridge. - */ - uInt16 bankCount() const override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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). @@ -134,31 +66,12 @@ class CartridgeF4 : public Cartridge } #endif - public: - /** - Get the byte at the specified address. + protected: + bool checkSwitchBank(uInt16 address, uInt8 value = 0); - @return The byte at the specified address - */ - uInt8 peek(uInt16 address) override; + uInt16 romHotspot() const override { return 0x1FF4; } - /** - Change the byte at the specified address to the given value - - @param address The address where the value should be stored - @param value The value to be stored at the address - @return True if the poke changed the device address space, else false - */ - bool poke(uInt16 address, uInt8 value) override; - - private: - // The 32K ROM image of the cartridge - std::array myImage; - - // Indicates the offset into the ROM image (aligns to current bank) - uInt16 myBankOffset{0}; - - private: +private: // Following constructors and assignment operators not supported CartridgeF4() = delete; CartridgeF4(const CartridgeF4&) = delete; diff --git a/src/emucore/CartF4SC.cxx b/src/emucore/CartF4SC.cxx index 24496b161..5364f2eb4 100644 --- a/src/emucore/CartF4SC.cxx +++ b/src/emucore/CartF4SC.cxx @@ -15,211 +15,13 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#include "System.hxx" #include "CartF4SC.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF4SC::CartridgeF4SC(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5) + : CartridgeF4(image, size, md5, settings) { - // Copy the ROM image into my buffer - std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessArrays(myImage.size()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF4SC::reset() -{ - initializeRAM(myRAM.data(), myRAM.size()); - initializeStartBank(0); - - // Upon reset we switch to the startup bank - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF4SC::install(System& system) -{ - mySystem = &system; - - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page accessing method for the RAM writing pages - // Map access to this class, since we need to inspect all accesses to - // check if RWP happens - access.type = System::PageAccessType::WRITE; - for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[addr & 0x007F]; - access.romPeekCounter = &myRomAccessCounter[addr & 0x007F]; - access.romPokeCounter = &myRomAccessCounter[(addr & 0x07F) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Set the page accessing method for the RAM reading pages - access.type = System::PageAccessType::READ; - for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myRAM[addr & 0x007F]; - access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)]; - access.romPeekCounter = &myRomAccessCounter[0x80 + (addr & 0x007F)]; - access.romPokeCounter = &myRomAccessCounter[0x80 + (addr & 0x007F) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Install pages for the startup bank - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeF4SC::peek(uInt16 address) -{ - uInt16 peekAddress = address; - address &= 0x0FFF; - - // Switch banks if necessary - if((address >= 0x0FF4) && (address <= 0x0FFB)) - bank(address - 0x0FF4); - - if(address < 0x0080) // Write port is at 0xF000 - 0xF07F (128 bytes) - return peekRAM(myRAM[address], peekAddress); - else - return myImage[myBankOffset + address]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF4SC::poke(uInt16 address, uInt8 value) -{ - uInt16 pokeAddress = address; - address &= 0x0FFF; - - // Switch banks if necessary - if((address >= 0x0FF4) && (address <= 0x0FFB)) - { - bank(address - 0x0FF4); - return false; - } - - if(!(address & 0x080)) - { - pokeRAM(myRAM[address & 0x007F], pokeAddress, value); - return true; - } - else - { - // Writing to the read port should be ignored, but trigger a break if option enabled - uInt8 dummy; - - pokeRAM(dummy, pokeAddress, value); - myRamWriteAccess = pokeAddress; - return false; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF4SC::bank(uInt16 bank) -{ - if(bankLocked()) return false; - - // Remember what bank we're in - myBankOffset = bank << 12; - - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page accessing methods for the hot spots - for(uInt16 addr = (0x1FF4 & ~System::PAGE_MASK); addr < 0x2000; - addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Setup the page access methods for the current bank - for(uInt16 addr = 0x1100; addr < static_cast(0x1FF4U & ~System::PAGE_MASK); - addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeF4SC::getBank(uInt16) const -{ - return myBankOffset >> 12; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeF4SC::bankCount() const -{ - return 8; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF4SC::patch(uInt16 address, uInt8 value) -{ - address &= 0x0FFF; - - if(address < 0x0100) - { - // Normally, a write to the read port won't do anything - // However, the patch command is special in that ignores such - // cart restrictions - myRAM[address & 0x007F] = value; - } - else - myImage[myBankOffset + address] = value; - - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeF4SC::getImage(size_t& size) const -{ - size = myImage.size(); - return myImage.data(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF4SC::save(Serializer& out) const -{ - try - { - out.putShort(myBankOffset); - out.putByteArray(myRAM.data(), myRAM.size()); - } - catch(...) - { - cerr << "ERROR: CartridgeF4SC::save" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF4SC::load(Serializer& in) -{ - try - { - myBankOffset = in.getShort(); - in.getByteArray(myRAM.data(), myRAM.size()); - } - catch(...) - { - cerr << "ERROR: CartridgeF4SC::load" << endl; - return false; - } - - // Remember what bank we were in - bank(myBankOffset >> 12); - - return true; + myRamSize = RAM_SIZE; + myRamMask = RAM_MASK; } diff --git a/src/emucore/CartF4SC.hxx b/src/emucore/CartF4SC.hxx index 20c003970..5f49a33a6 100644 --- a/src/emucore/CartF4SC.hxx +++ b/src/emucore/CartF4SC.hxx @@ -18,10 +18,7 @@ #ifndef CARTRIDGEF4SC_HXX #define CARTRIDGEF4SC_HXX -class System; - -#include "bspf.hxx" -#include "Cart.hxx" +#include "CartF4.hxx" #ifdef DEBUGGER_SUPPORT #include "CartF4SCWidget.hxx" #endif @@ -31,9 +28,9 @@ class System; RAM. There are eight 4K banks, accessible by read/write to $1FF4 - $1FFB. RAM read port is $1080 - $10FF, write port is $1000 - $107F. - @author Bradford W. Mott + @author Bradford W. Mott, Thomas Jentzsch */ -class CartridgeF4SC : public Cartridge +class CartridgeF4SC : public CartridgeF4 { friend class CartridgeF4SCWidget; @@ -51,71 +48,6 @@ class CartridgeF4SC : public Cartridge virtual ~CartridgeF4SC() = default; public: - /** - Reset device to its power-on state - */ - void reset() override; - - /** - Install cartridge in the specified system. Invoked by the system - when the cartridge is attached to it. - - @param system The system the device should install itself in - */ - void install(System& system) override; - - /** - Install pages for the specified bank in the system. - - @param bank The bank that should be installed in the system - */ - bool bank(uInt16 bank) override; - - /** - Get the current bank. - - @param address The address to use when querying the bank - */ - uInt16 getBank(uInt16 address = 0) const override; - - /** - Query the number of banks supported by the cartridge. - */ - uInt16 bankCount() const override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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). @@ -135,32 +67,12 @@ class CartridgeF4SC : public Cartridge } #endif - public: - /** - Get the byte at the specified address. - - @return The byte at the specified address - */ - uInt8 peek(uInt16 address) override; - - /** - Change the byte at the specified address to the given value - - @param address The address where the value should be stored - @param value The value to be stored at the address - @return True if the poke changed the device address space, else false - */ - bool poke(uInt16 address, uInt8 value) override; - private: - // The 32K ROM image of the cartridge - std::array myImage; + // RAM size + static constexpr uInt16 RAM_SIZE = 0x80; - // The 128 bytes of RAM - std::array myRAM; - - // Indicates the offset into the ROM image (aligns to current bank) - uInt16 myBankOffset{0}; + // RAM mask + static constexpr uInt16 RAM_MASK = RAM_SIZE - 1; private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartF6.cxx b/src/emucore/CartF6.cxx index a7a8dec2b..567424d7a 100644 --- a/src/emucore/CartF6.cxx +++ b/src/emucore/CartF6.cxx @@ -15,195 +15,25 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#include "System.hxx" #include "CartF6.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF6::CartridgeF6(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5) + : CartridgeEnhanced(image, size, md5, settings) { - // Copy the ROM image into my buffer - std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF6::reset() +bool CartridgeF6::checkSwitchBank(uInt16 address, uInt8) { - // Upon reset we switch to the startup bank - initializeStartBank(0); - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF6::install(System& system) -{ - mySystem = &system; - - // Upon install we'll setup the startup bank - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeF6::peek(uInt16 address) -{ - address &= 0x0FFF; - // Switch banks if necessary - switch(address) + // Note: addresses could be calculated from hotspot and bank count + if((address >= 0x0FF6) && (address <= 0x0FF9)) { - case 0x0FF6: - // Set the current bank to the first 4k bank - bank(0); - break; - - case 0x0FF7: - // Set the current bank to the second 4k bank - bank(1); - break; - - case 0x0FF8: - // Set the current bank to the third 4k bank - bank(2); - break; - - case 0x0FF9: - // Set the current bank to the forth 4k bank - bank(3); - break; - - default: - break; - } - - return myImage[myBankOffset + address]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF6::poke(uInt16 address, uInt8) -{ - address &= 0x0FFF; - - // Switch banks if necessary - switch(address) - { - case 0x0FF6: - // Set the current bank to the first 4k bank - bank(0); - break; - - case 0x0FF7: - // Set the current bank to the second 4k bank - bank(1); - break; - - case 0x0FF8: - // Set the current bank to the third 4k bank - bank(2); - break; - - case 0x0FF9: - // Set the current bank to the forth 4k bank - bank(3); - break; - - default: - break; + bank(address - 0x0FF6); + return true; } return false; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF6::bank(uInt16 bank) -{ - if(bankLocked()) return false; - - // Remember what bank we're in - myBankOffset = bank << 12; - - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page accessing methods for the hot spots - for(uInt16 addr = (0x1FF6 & ~System::PAGE_MASK); addr < 0x2000; - addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Setup the page access methods for the current bank - for(uInt16 addr = 0x1000; addr < static_cast(0x1FF6U & ~System::PAGE_MASK); - addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeF6::getBank(uInt16) const -{ - return myBankOffset >> 12; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeF6::bankCount() const -{ - return 4; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF6::patch(uInt16 address, uInt8 value) -{ - myImage[myBankOffset + (address & 0x0FFF)] = value; - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeF6::getImage(size_t& size) const -{ - size = myImage.size(); - return myImage.data(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF6::save(Serializer& out) const -{ - try - { - out.putShort(myBankOffset); - } - catch(...) - { - cerr << "ERROR: CartridgeF6::save" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF6::load(Serializer& in) -{ - try - { - myBankOffset = in.getShort(); - } - catch(...) - { - cerr << "ERROR: CartridgeF6::load" << endl; - return false; - } - - // Remember what bank we were in - bank(myBankOffset >> 12); - - return true; -} diff --git a/src/emucore/CartF6.hxx b/src/emucore/CartF6.hxx index 4dc2c62b5..275727786 100644 --- a/src/emucore/CartF6.hxx +++ b/src/emucore/CartF6.hxx @@ -18,10 +18,7 @@ #ifndef CARTRIDGEF6_HXX #define CARTRIDGEF6_HXX -class System; - -#include "bspf.hxx" -#include "Cart.hxx" +#include "CartEnhanced.hxx" #ifdef DEBUGGER_SUPPORT #include "CartF6Widget.hxx" #endif @@ -30,9 +27,9 @@ class System; Cartridge class used for Atari's 16K bankswitched games. There are four 4K banks, accessible by read/write to $1FF6 - $1FF9. - @author Bradford W. Mott + @author Bradford W. Mott, Thomas Jentzsch */ -class CartridgeF6 : public Cartridge +class CartridgeF6 : public CartridgeEnhanced { friend class CartridgeF6Widget; @@ -50,71 +47,6 @@ class CartridgeF6 : public Cartridge virtual ~CartridgeF6() = default; public: - /** - Reset device to its power-on state - */ - void reset() override; - - /** - Install cartridge in the specified system. Invoked by the system - when the cartridge is attached to it. - - @param system The system the device should install itself in - */ - void install(System& system) override; - - /** - Install pages for the specified bank in the system. - - @param bank The bank that should be installed in the system - */ - bool bank(uInt16 bank) override; - - /** - Get the current bank. - - @param address The address to use when querying the bank - */ - uInt16 getBank(uInt16 address = 0) const override; - - /** - Query the number of banks supported by the cartridge. - */ - uInt16 bankCount() const override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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). @@ -134,29 +66,10 @@ class CartridgeF6 : public Cartridge } #endif - public: - /** - Get the byte at the specified address. + protected: + bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; - @return The byte at the specified address - */ - uInt8 peek(uInt16 address) override; - - /** - Change the byte at the specified address to the given value - - @param address The address where the value should be stored - @param value The value to be stored at the address - @return True if the poke changed the device address space, else false - */ - bool poke(uInt16 address, uInt8 value) override; - - private: - // The 16K ROM image of the cartridge - std::array myImage; - - // Indicates the offset into the ROM image (aligns to current bank) - uInt16 myBankOffset{0}; + uInt16 romHotspot() const override { return 0x1FF6; } private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartF6SC.cxx b/src/emucore/CartF6SC.cxx index 60b998182..034f02bce 100644 --- a/src/emucore/CartF6SC.cxx +++ b/src/emucore/CartF6SC.cxx @@ -15,251 +15,13 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#include "System.hxx" #include "CartF6SC.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF6SC::CartridgeF6SC(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5) + : CartridgeF6(image, size, md5, settings) { - // Copy the ROM image into my buffer - std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessArrays(myImage.size()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF6SC::reset() -{ - initializeRAM(myRAM.data(), myRAM.size()); - initializeStartBank(0); - - // Upon reset we switch to the startup bank - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF6SC::install(System& system) -{ - mySystem = &system; - - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page accessing method for the RAM writing pages - // Map access to this class, since we need to inspect all accesses to - // check if RWP happens - access.type = System::PageAccessType::WRITE; - for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[addr & 0x007F]; - access.romPeekCounter = &myRomAccessCounter[addr & 0x007F]; - access.romPokeCounter = &myRomAccessCounter[(addr & 0x07F) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Set the page accessing method for the RAM reading pages - access.type = System::PageAccessType::READ; - for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myRAM[addr & 0x007F]; - access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)]; - access.romPeekCounter = &myRomAccessCounter[0x80 + (addr & 0x007F)]; - access.romPokeCounter = &myRomAccessCounter[0x80 + (addr & 0x007F) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Install pages for the startup bank - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeF6SC::peek(uInt16 address) -{ - uInt16 peekAddress = address; - address &= 0x0FFF; - - // Switch banks if necessary - switch(address) - { - case 0x0FF6: - // Set the current bank to the first 4k bank - bank(0); - break; - - case 0x0FF7: - // Set the current bank to the second 4k bank - bank(1); - break; - - case 0x0FF8: - // Set the current bank to the third 4k bank - bank(2); - break; - - case 0x0FF9: - // Set the current bank to the forth 4k bank - bank(3); - break; - - default: - break; - } - - if(address < 0x0080) // Write port is at 0xF000 - 0xF07F (128 bytes) - return peekRAM(myRAM[address], peekAddress); - else - return myImage[myBankOffset + address]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF6SC::poke(uInt16 address, uInt8 value) -{ - // Switch banks if necessary - switch(address & 0x0FFF) - { - case 0x0FF6: - // Set the current bank to the first 4k bank - bank(0); - return false; - - case 0x0FF7: - // Set the current bank to the second 4k bank - bank(1); - return false; - - case 0x0FF8: - // Set the current bank to the third 4k bank - bank(2); - return false; - - case 0x0FF9: - // Set the current bank to the forth 4k bank - bank(3); - return false; - - default: - break; - } - - if(!(address & 0x080)) - { - pokeRAM(myRAM[address & 0x007F], address, value); - return true; - } - else - { - // Writing to the read port should be ignored, but trigger a break if option enabled - uInt8 dummy; - - pokeRAM(dummy, address, value); - myRamWriteAccess = address; - return false; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF6SC::bank(uInt16 bank) -{ - if(bankLocked()) return false; - - // Remember what bank we're in - myBankOffset = bank << 12; - - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page accessing methods for the hot spots - for(uInt16 addr = (0x1FF6 & ~System::PAGE_MASK); addr < 0x2000; - addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Setup the page access methods for the current bank - for(uInt16 addr = 0x1100; addr < static_cast(0x1FF6U & ~System::PAGE_MASK); - addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeF6SC::getBank(uInt16) const -{ - return myBankOffset >> 12; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeF6SC::bankCount() const -{ - return 4; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF6SC::patch(uInt16 address, uInt8 value) -{ - address &= 0x0FFF; - - if(address < 0x0100) - { - // Normally, a write to the read port won't do anything - // However, the patch command is special in that ignores such - // cart restrictions - myRAM[address & 0x007F] = value; - } - else - myImage[myBankOffset + address] = value; - - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeF6SC::getImage(size_t& size) const -{ - size = myImage.size(); - return myImage.data(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF6SC::save(Serializer& out) const -{ - try - { - out.putShort(myBankOffset); - out.putByteArray(myRAM.data(), myRAM.size()); - } - catch(...) - { - cerr << "ERROR: CartridgeF6SC::save" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF6SC::load(Serializer& in) -{ - try - { - myBankOffset = in.getShort(); - in.getByteArray(myRAM.data(), myRAM.size()); - } - catch(...) - { - cerr << "ERROR: CartridgeF6SC::load" << endl; - return false; - } - - // Remember what bank we were in - bank(myBankOffset >> 12); - - return true; + myRamSize = RAM_SIZE; + myRamMask = RAM_MASK; } diff --git a/src/emucore/CartF6SC.hxx b/src/emucore/CartF6SC.hxx index 45a7c5ac3..a791a538d 100644 --- a/src/emucore/CartF6SC.hxx +++ b/src/emucore/CartF6SC.hxx @@ -18,10 +18,7 @@ #ifndef CARTRIDGEF6SC_HXX #define CARTRIDGEF6SC_HXX -class System; - -#include "bspf.hxx" -#include "Cart.hxx" +#include "CartF6.hxx" #ifdef DEBUGGER_SUPPORT #include "CartF6SCWidget.hxx" #endif @@ -31,9 +28,9 @@ class System; RAM. There are four 4K banks, accessible by read/write to $1FF6 - $1FF9. RAM read port is $1080 - $10FF, write port is $1000 - $107F. - @author Bradford W. Mott + @author Bradford W. Mott, Thomas Jentzsch */ -class CartridgeF6SC : public Cartridge +class CartridgeF6SC : public CartridgeF6 { friend class CartridgeF6SCWidget; @@ -51,71 +48,6 @@ class CartridgeF6SC : public Cartridge virtual ~CartridgeF6SC() = default; public: - /** - Reset device to its power-on state - */ - void reset() override; - - /** - Install cartridge in the specified system. Invoked by the system - when the cartridge is attached to it. - - @param system The system the device should install itself in - */ - void install(System& system) override; - - /** - Install pages for the specified bank in the system. - - @param bank The bank that should be installed in the system - */ - bool bank(uInt16 bank) override; - - /** - Get the current bank. - - @param address The address to use when querying the bank - */ - uInt16 getBank(uInt16 address = 0) const override; - - /** - Query the number of banks supported by the cartridge. - */ - uInt16 bankCount() const override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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). @@ -135,32 +67,12 @@ class CartridgeF6SC : public Cartridge } #endif - public: - /** - Get the byte at the specified address. - - @return The byte at the specified address - */ - uInt8 peek(uInt16 address) override; - - /** - Change the byte at the specified address to the given value - - @param address The address where the value should be stored - @param value The value to be stored at the address - @return True if the poke changed the device address space, else false - */ - bool poke(uInt16 address, uInt8 value) override; - private: - // The 16K ROM image of the cartridge - std::array myImage; + // RAM size + static constexpr uInt16 RAM_SIZE = 0x80; - // The 128 bytes of RAM - std::array myRAM; - - // Indicates the offset into the ROM image (aligns to current bank) - uInt16 myBankOffset{0}; + // RAM mask + static constexpr uInt16 RAM_MASK = RAM_SIZE - 1; private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartF8.cxx b/src/emucore/CartF8.cxx index b23ed802e..79b4708c4 100644 --- a/src/emucore/CartF8.cxx +++ b/src/emucore/CartF8.cxx @@ -15,176 +15,33 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#include "System.hxx" #include "CartF8.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF8::CartridgeF8(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5) + : CartridgeEnhanced(image, size, md5, settings) { - // Copy the ROM image into my buffer - std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF8::reset() +bool CartridgeF8::checkSwitchBank(uInt16 address, uInt8) { - initializeStartBank(1); - - // Upon reset we switch to the reset bank - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF8::install(System& system) -{ - mySystem = &system; - - // Install pages for the startup bank - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeF8::peek(uInt16 address) -{ - address &= 0x0FFF; - // Switch banks if necessary switch(address) { case 0x0FF8: // Set the current bank to the lower 4k bank bank(0); - break; + return true; case 0x0FF9: // Set the current bank to the upper 4k bank bank(1); - break; - - default: - break; - } - - return myImage[myBankOffset + address]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF8::poke(uInt16 address, uInt8) -{ - address &= 0x0FFF; - - // Switch banks if necessary - switch(address) - { - case 0x0FF8: - // Set the current bank to the lower 4k bank - bank(0); - break; - - case 0x0FF9: - // Set the current bank to the upper 4k bank - bank(1); - break; + return true; default: break; } return false; } - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF8::bank(uInt16 bank) -{ - if(bankLocked()) return false; - - // Remember what bank we're in - myBankOffset = bank << 12; - - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page accessing methods for the hot spots - for(uInt16 addr = (0x1FF8 & ~System::PAGE_MASK); addr < 0x2000; - addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Setup the page access methods for the current bank - for(uInt16 addr = 0x1000; addr < static_cast(0x1FF8U & ~System::PAGE_MASK); - addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeF8::getBank(uInt16) const -{ - return myBankOffset >> 12; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeF8::bankCount() const -{ - return 2; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF8::patch(uInt16 address, uInt8 value) -{ - myImage[myBankOffset + (address & 0x0FFF)] = value; - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeF8::getImage(size_t& size) const -{ - size = myImage.size(); - return myImage.data(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF8::save(Serializer& out) const -{ - try - { - out.putShort(myBankOffset); - } - catch(...) - { - cerr << "ERROR: CartridgeF8::save" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF8::load(Serializer& in) -{ - try - { - myBankOffset = in.getShort(); - } - catch(...) - { - cerr << "ERROR: CartridgeF8::load" << endl; - return false; - } - - // Remember what bank we were in - bank(myBankOffset >> 12); - - return true; -} diff --git a/src/emucore/CartF8.hxx b/src/emucore/CartF8.hxx index b586d70ff..71e4d6e72 100644 --- a/src/emucore/CartF8.hxx +++ b/src/emucore/CartF8.hxx @@ -18,10 +18,7 @@ #ifndef CARTRIDGEF8_HXX #define CARTRIDGEF8_HXX -class System; - -#include "bspf.hxx" -#include "Cart.hxx" +#include "CartEnhanced.hxx" #ifdef DEBUGGER_SUPPORT #include "CartF8Widget.hxx" #endif @@ -30,9 +27,9 @@ class System; Cartridge class used for Atari's 8K bankswitched games. There are two 4K banks, accessible by read/write to $1FF8 - $1FF9. - @author Bradford W. Mott + @author Bradford W. Mott, Thomas Jentzsch */ -class CartridgeF8 : public Cartridge +class CartridgeF8 : public CartridgeEnhanced { friend class CartridgeF8Widget; @@ -50,71 +47,6 @@ class CartridgeF8 : public Cartridge virtual ~CartridgeF8() = default; public: - /** - Reset device to its power-on state - */ - void reset() override; - - /** - Install cartridge in the specified system. Invoked by the system - when the cartridge is attached to it. - - @param system The system the device should install itself in - */ - void install(System& system) override; - - /** - Install pages for the specified bank in the system. - - @param bank The bank that should be installed in the system - */ - bool bank(uInt16 bank) override; - - /** - Get the current bank. - - @param address The address to use when querying the bank - */ - uInt16 getBank(uInt16 address = 0) const override; - - /** - Query the number of banks supported by the cartridge. - */ - uInt16 bankCount() const override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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). @@ -134,29 +66,13 @@ class CartridgeF8 : public Cartridge } #endif - public: - /** - Get the byte at the specified address. + protected: + bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; - @return The byte at the specified address - */ - uInt8 peek(uInt16 address) override; - - /** - Change the byte at the specified address to the given value - - @param address The address where the value should be stored - @param value The value to be stored at the address - @return True if the poke changed the device address space, else false - */ - bool poke(uInt16 address, uInt8 value) override; + uInt16 romHotspot() const override { return 0x1FF8; } private: - // The 8K ROM image of the cartridge - std::array myImage; - - // Indicates the offset into the ROM image (aligns to current bank) - uInt16 myBankOffset{0}; + uInt16 getStartBank() const override { return 1; } private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartF8SC.cxx b/src/emucore/CartF8SC.cxx index c885a9c83..e9dd5bd5c 100644 --- a/src/emucore/CartF8SC.cxx +++ b/src/emucore/CartF8SC.cxx @@ -15,231 +15,13 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#include "System.hxx" #include "CartF8SC.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF8SC::CartridgeF8SC(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5) + : CartridgeF8(image, size, md5, settings) { - // Copy the ROM image into my buffer - std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessArrays(myImage.size()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF8SC::reset() -{ - initializeRAM(myRAM.data(), myRAM.size()); - initializeStartBank(1); - - // Upon reset we switch to the startup bank - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF8SC::install(System& system) -{ - mySystem = &system; - - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page accessing method for the RAM writing pages - // Map access to this class, since we need to inspect all accesses to - // check if RWP happens - access.type = System::PageAccessType::WRITE; - for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[addr & 0x007F]; - access.romPeekCounter = &myRomAccessCounter[addr & 0x007F]; - access.romPokeCounter = &myRomAccessCounter[(addr & 0x07F) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Set the page accessing method for the RAM reading pages - access.type = System::PageAccessType::READ; - for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myRAM[addr & 0x007F]; - access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)]; - access.romPeekCounter = &myRomAccessCounter[0x80 + (addr & 0x007F)]; - access.romPokeCounter = &myRomAccessCounter[0x80 + (addr & 0x007F) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Install pages for the startup bank - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeF8SC::peek(uInt16 address) -{ - uInt16 peekAddress = address; - address &= 0x0FFF; - - // Switch banks if necessary - switch(address) - { - case 0x0FF8: - // Set the current bank to the lower 4k bank - bank(0); - break; - - case 0x0FF9: - // Set the current bank to the upper 4k bank - bank(1); - break; - - default: - break; - } - - if(address < 0x0080) // Write port is at 0xF000 - 0xF07F (128 bytes) - return peekRAM(myRAM[address], peekAddress); - else - return myImage[myBankOffset + address]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF8SC::poke(uInt16 address, uInt8 value) -{ - // Switch banks if necessary - switch(address & 0x0FFF) - { - case 0x0FF8: - // Set the current bank to the lower 4k bank - bank(0); - return false; - - case 0x0FF9: - // Set the current bank to the upper 4k bank - bank(1); - return false; - - default: - break; - } - - if (!(address & 0x080)) - { - pokeRAM(myRAM[address & 0x007F], address, value); - return true; - } - else - { - // Writing to the read port should be ignored, but trigger a break if option enabled - uInt8 dummy; - - pokeRAM(dummy, address, value); - myRamWriteAccess = address; - return false; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF8SC::bank(uInt16 bank) -{ - if(bankLocked()) return false; - - // Remember what bank we're in - myBankOffset = bank << 12; - - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page accessing methods for the hot spots - for(uInt16 addr = (0x1FF8 & ~System::PAGE_MASK); addr < 0x2000; - addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Setup the page access methods for the current bank - for(uInt16 addr = 0x1100; addr < static_cast(0x1FF8U & ~System::PAGE_MASK); - addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeF8SC::getBank(uInt16) const -{ - return myBankOffset >> 12; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeF8SC::bankCount() const -{ - return 2; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF8SC::patch(uInt16 address, uInt8 value) -{ - address &= 0x0FFF; - - if(address < 0x0100) - { - // Normally, a write to the read port won't do anything - // However, the patch command is special in that ignores such - // cart restrictions - myRAM[address & 0x007F] = value; - } - else - myImage[myBankOffset + address] = value; - - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeF8SC::getImage(size_t& size) const -{ - size = myImage.size(); - return myImage.data(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF8SC::save(Serializer& out) const -{ - try - { - out.putShort(myBankOffset); - out.putByteArray(myRAM.data(), myRAM.size()); - } - catch(...) - { - cerr << "ERROR: CartridgeF8SC::save" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeF8SC::load(Serializer& in) -{ - try - { - myBankOffset = in.getShort(); - in.getByteArray(myRAM.data(), myRAM.size()); - } - catch(...) - { - cerr << "ERROR: CartridgeF8SC::load" << endl; - return false; - } - - // Remember what bank we were in - bank(myBankOffset >> 12); - - return true; + myRamSize = RAM_SIZE; + myRamMask = RAM_MASK; } diff --git a/src/emucore/CartF8SC.hxx b/src/emucore/CartF8SC.hxx index 592637d3d..9ec8209c4 100644 --- a/src/emucore/CartF8SC.hxx +++ b/src/emucore/CartF8SC.hxx @@ -18,10 +18,7 @@ #ifndef CARTRIDGEF8SC_HXX #define CARTRIDGEF8SC_HXX -class System; - -#include "bspf.hxx" -#include "Cart.hxx" +#include "CartF8.hxx" #ifdef DEBUGGER_SUPPORT #include "CartF8SCWidget.hxx" #endif @@ -31,9 +28,9 @@ class System; RAM. There are two 4K banks, accessible by read/write to $1FF8 - $1FF9. RAM read port is $1080 - $10FF, write port is $1000 - $107F. - @author Bradford W. Mott + @author Bradford W. Mott, Thomas Jentzsch */ -class CartridgeF8SC : public Cartridge +class CartridgeF8SC : public CartridgeF8 { friend class CartridgeF8SCWidget; @@ -51,71 +48,6 @@ class CartridgeF8SC : public Cartridge virtual ~CartridgeF8SC() = default; public: - /** - Reset device to its power-on state - */ - void reset() override; - - /** - Install cartridge in the specified system. Invoked by the system - when the cartridge is attached to it. - - @param system The system the device should install itself in - */ - void install(System& system) override; - - /** - Install pages for the specified bank in the system. - - @param bank The bank that should be installed in the system - */ - bool bank(uInt16 bank) override; - - /** - Get the current bank. - - @param address The address to use when querying the bank - */ - uInt16 getBank(uInt16 address = 0) const override; - - /** - Query the number of banks supported by the cartridge. - */ - uInt16 bankCount() const override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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). @@ -135,32 +67,12 @@ class CartridgeF8SC : public Cartridge } #endif - public: - /** - Get the byte at the specified address. - - @return The byte at the specified address - */ - uInt8 peek(uInt16 address) override; - - /** - Change the byte at the specified address to the given value - - @param address The address where the value should be stored - @param value The value to be stored at the address - @return True if the poke changed the device address space, else false - */ - bool poke(uInt16 address, uInt8 value) override; - private: - // The 8K ROM image of the cartridge - std::array myImage; + // RAM size + static constexpr uInt16 RAM_SIZE = 0x80; - // The 128 bytes of RAM - std::array myRAM; - - // Indicates the offset into the ROM image (aligns to current bank) - uInt16 myBankOffset{0}; + // RAM mask + static constexpr uInt16 RAM_MASK = RAM_SIZE - 1; private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartFC.cxx b/src/emucore/CartFC.cxx index 565e577cf..741935c06 100644 --- a/src/emucore/CartFC.cxx +++ b/src/emucore/CartFC.cxx @@ -21,52 +21,35 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeFC::CartridgeFC(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5), - mySize(size) + : CartridgeEnhanced(image, size, md5, settings) { - // Copy the ROM image into my buffer - std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFC::reset() { - initializeStartBank(0); + CartridgeEnhanced::reset(); + myTargetBank = 0; - - // Upon reset we switch to the reset bank - bank(startBank()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeFC::install(System& system) +bool CartridgeFC::checkSwitchBank(uInt16 address, uInt8) { - mySystem = &system; - - // Install pages for the startup bank - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeFC::peek(uInt16 address) -{ - address &= 0x0FFF; - // Switch banks if necessary if(address == 0x0FFC) { // Trigger the bank switch bank(myTargetBank); + return true; } - - return myImage[myBankOffset + address]; + return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeFC::poke(uInt16 address, uInt8 value) { - address &= 0x0FFF; + address &= myBankMask; // Switch banks if necessary switch (address) @@ -88,108 +71,8 @@ bool CartridgeFC::poke(uInt16 address, uInt8 value) myTargetBank = value % bankCount(); break; - case 0x0FFC: - // Trigger the bank switch - bank(myTargetBank); - break; - default: - break; + checkSwitchBank(address); } return false; } - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeFC::bank(uInt16 bank) -{ - if (bankLocked()) return false; - - // Remember what bank we're in - myBankOffset = bank << 12; - - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page accessing methods for the hot spots - for (uInt16 addr = (0x1FF8 & ~System::PAGE_MASK); addr < 0x2000; - addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Setup the page access methods for the current bank - for (uInt16 addr = 0x1000; addr < static_cast(0x1FF8U & ~System::PAGE_MASK); - addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - myCurrentBank = myTargetBank; - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeFC::getBank(uInt16) const -{ - return myBankOffset >> 12; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeFC::bankCount() const -{ - return uInt16(mySize >> 12); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeFC::patch(uInt16 address, uInt8 value) -{ - myImage[myBankOffset + (address & 0x0FFF)] = value; - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeFC::getImage(size_t& size) const -{ - size = mySize; - return myImage.data(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeFC::save(Serializer& out) const -{ - try - { - out.putShort(myBankOffset); - } - catch (...) - { - cerr << "ERROR: CartridgeFC::save" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeFC::load(Serializer& in) -{ - try - { - myBankOffset = in.getShort(); - } - catch (...) - { - cerr << "ERROR: CartridgeFC::load" << endl; - return false; - } - - // Remember what bank we were in - bank(myBankOffset >> 12); - - return true; -} diff --git a/src/emucore/CartFC.hxx b/src/emucore/CartFC.hxx index cc96d0131..c1987a189 100644 --- a/src/emucore/CartFC.hxx +++ b/src/emucore/CartFC.hxx @@ -21,7 +21,7 @@ class System; #include "bspf.hxx" -#include "Cart.hxx" +#include "CartEnhanced.hxx" #ifdef DEBUGGER_SUPPORT #include "CartFCWidget.hxx" @@ -30,12 +30,12 @@ class System; /** Cartridge class used for Amiga's 32K Power Play Arcade Video Game Album. There are eight 4K banks, writing to $1FF8 definies the two lowest bits - of the wanted bank, writeing to $1FF9 defines the high bits. Reading from + of the wanted bank, writeing to $1FF9 defines the high bits. Accessing $1FFC triggers the bank switching @author Thomas Jentzsch */ -class CartridgeFC : public Cartridge +class CartridgeFC : public CartridgeEnhanced { friend class CartridgeFCWidget; @@ -58,66 +58,6 @@ class CartridgeFC : public Cartridge */ void reset() override; - /** - Install cartridge in the specified system. Invoked by the system - when the cartridge is attached to it. - - @param system The system the device should install itself in - */ - void install(System& system) override; - - /** - Install pages for the specified bank in the system. - - @param bank The bank that should be installed in the system - */ - bool bank(uInt16 bank) override; - - /** - Get the current bank. - - @param address The address to use when querying the bank - */ - uInt16 getBank(uInt16 address = 0) const override; - - /** - Query the number of banks supported by the cartridge. - */ - uInt16 bankCount() const override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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). @@ -138,13 +78,6 @@ class CartridgeFC : public Cartridge #endif public: - /** - Get the byte at the specified address. - - @return The byte at the specified address - */ - uInt8 peek(uInt16 address) override; - /** Change the byte at the specified address to the given value @@ -154,19 +87,12 @@ class CartridgeFC : public Cartridge */ bool poke(uInt16 address, uInt8 value) override; + protected: + bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; + + uInt16 romHotspot() const override { return 0x1FF8; } + private: - // The 32K ROM image of the cartridge - std::array myImage; - - // Size of the ROM image - size_t mySize{0}; - - // Indicates the offset into the ROM image (aligns to current bank) - uInt16 myBankOffset{0}; - - // Indicates which bank is currently active for the first segment - uInt16 myCurrentBank{0}; - // Target bank defined by writing to $1FF8/9 uInt16 myTargetBank{0}; diff --git a/src/emucore/CartFE.cxx b/src/emucore/CartFE.cxx index 36cfa7c84..1837c7b88 100644 --- a/src/emucore/CartFE.cxx +++ b/src/emucore/CartFE.cxx @@ -22,20 +22,15 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeFE::CartridgeFE(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5) + : CartridgeEnhanced(image, size, md5, settings) { - // Copy the ROM image into my buffer - std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessArrays(myImage.size()); + myDirectPeek = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFE::reset() { - // Decathlon requires this, since there is no startup vector in bank 1 - initializeStartBank(0); - - bank(startBank()); + CartridgeEnhanced::reset(); myLastAccessWasFE = false; } @@ -51,14 +46,27 @@ void CartridgeFE::install(System& system) mySystem->setPageAccess(addr, access); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CartridgeFE::checkSwitchBank(uInt16 address, uInt8 value) +{ + if(myLastAccessWasFE) + { + bank((value & 0x20) ? 0 : 1); + myLastAccessWasFE = false; // was: address == 0x01FE; + return true; + } + myLastAccessWasFE = address == 0x01FE; + return false; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeFE::peek(uInt16 address) { uInt8 value = (address < 0x200) ? mySystem->m6532().peek(address) : - myImage[myBankOffset + (address & 0x0FFF)]; + myImage[myBankOffset + (address & myBankMask)]; // Check if we hit hotspot - checkBankSwitch(address, value); + checkSwitchBank(address, value); return value; } @@ -70,83 +78,17 @@ bool CartridgeFE::poke(uInt16 address, uInt8 value) mySystem->m6532().poke(address, value); // Check if we hit hotspot - checkBankSwitch(address, value); + checkSwitchBank(address, value); return false; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeFE::checkBankSwitch(uInt16 address, uInt8 value) -{ - if(bankLocked()) - return; - - // Did we detect $01FE on the last address bus access? - // If so, we bankswitch according to the upper 3 bits of the data bus - // NOTE: see the header file for the significance of 'value & 0x20' - if(myLastAccessWasFE) - bank((value & 0x20) ? 0 : 1); - - // On the next cycle, we use the (then) current data bus value to decode - // the bank to use - myLastAccessWasFE = address == 0x01FE; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeFE::bank(uInt16 bank) -{ - if(bankLocked()) - return false; - - myBankOffset = bank << 12; - - System::PageAccess access(this, System::PageAccessType::READ); - - // Setup the page access methods for the current bank - // Map all of the cart accesses to call peek and poke - for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeFE::getBank(uInt16) const -{ - return myBankOffset >> 12; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeFE::bankCount() const -{ - return 2; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeFE::patch(uInt16 address, uInt8 value) -{ - myImage[myBankOffset + (address & 0x0FFF)] = value; - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeFE::getImage(size_t& size) const -{ - size = myImage.size(); - return myImage.data(); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeFE::save(Serializer& out) const { + CartridgeEnhanced::save(out); try { - out.putShort(myBankOffset); out.putBool(myLastAccessWasFE); } catch(...) @@ -161,9 +103,9 @@ bool CartridgeFE::save(Serializer& out) const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeFE::load(Serializer& in) { + CartridgeEnhanced::load(in); try { - myBankOffset = in.getShort(); myLastAccessWasFE = in.getBool(); } catch(...) diff --git a/src/emucore/CartFE.hxx b/src/emucore/CartFE.hxx index dabfafdf4..18361faf0 100644 --- a/src/emucore/CartFE.hxx +++ b/src/emucore/CartFE.hxx @@ -21,7 +21,7 @@ class System; #include "bspf.hxx" -#include "Cart.hxx" +#include "CartEnhanced.hxx" #ifdef DEBUGGER_SUPPORT #include "CartFEWidget.hxx" #endif @@ -75,7 +75,7 @@ class System; @author Stephen Anthony; with ideas/research from Christian Speckner and alex_79 and TomSon (of AtariAge) */ -class CartridgeFE : public Cartridge +class CartridgeFE : public CartridgeEnhanced { friend class CartridgeFEWidget; @@ -106,42 +106,6 @@ class CartridgeFE : public Cartridge */ void install(System& system) override; - /** - Install pages for the specified bank in the system. - - @param bank The bank that should be installed in the system - */ - bool bank(uInt16 bank) override; - - /** - Get the current bank. - - @param address The address to use when querying the bank - */ - uInt16 getBank(uInt16 address = 0) const override; - - /** - Query the number of banks supported by the cartridge. - */ - uInt16 bankCount() const override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const override; - /** Save the current state of this cart to the given Serializer. @@ -194,20 +158,14 @@ class CartridgeFE : public Cartridge */ bool poke(uInt16 address, uInt8 value) override; - private: + protected: /** Perform bankswitch when necessary, by monitoring for $01FE on the address bus and getting the bank number from the data bus. */ - void checkBankSwitch(uInt16 address, uInt8 value); + bool checkSwitchBank(uInt16 address, uInt8 value) override; private: - // The 8K ROM image of the cartridge - std::array myImage; - - // Indicates the offset into the ROM image (aligns to current bank) - uInt16 myBankOffset{0}; - // Whether previous address by peek/poke equals $01FE (hotspot) bool myLastAccessWasFE{false}; diff --git a/src/emucore/CartMNetwork.hxx b/src/emucore/CartMNetwork.hxx index ad0decad9..ef06aae57 100644 --- a/src/emucore/CartMNetwork.hxx +++ b/src/emucore/CartMNetwork.hxx @@ -106,7 +106,7 @@ class CartridgeMNetwork : public Cartridge uInt16 getBank(uInt16 address = 0) const override; /** - Query the number of banks supported by the cartridge. + Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; diff --git a/src/emucore/CartUA.cxx b/src/emucore/CartUA.cxx index bfa1321bb..4fd5a5410 100644 --- a/src/emucore/CartUA.cxx +++ b/src/emucore/CartUA.cxx @@ -22,20 +22,9 @@ CartridgeUA::CartridgeUA(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings, bool swapHotspots) - : Cartridge(settings, md5), + : CartridgeEnhanced(image, size, md5, settings), mySwappedHotspots(swapHotspots) { - // Copy the ROM image into my buffer - std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessArrays(myImage.size()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeUA::reset() -{ - // Upon reset we switch to the startup bank - initializeStartBank(0); - bank(startBank()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -60,26 +49,33 @@ void CartridgeUA::install(System& system) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeUA::peek(uInt16 address) +bool CartridgeUA::checkSwitchBank(uInt16 address, uInt8) { - address &= 0x1FFF; - // Switch banks if necessary switch(address & 0x1260) { case 0x0220: // Set the current bank to the lower 4k bank bank(mySwappedHotspots ? 1 : 0); - break; + return true; case 0x0240: // Set the current bank to the upper 4k bank bank(mySwappedHotspots ? 0 : 1); - break; + return true; default: break; } + return false; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt8 CartridgeUA::peek(uInt16 address) +{ + address &= myBankMask; + + checkSwitchBank(address); // Because of the way accessing is set up, we will only get here // when doing a TIA read @@ -90,24 +86,9 @@ uInt8 CartridgeUA::peek(uInt16 address) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeUA::poke(uInt16 address, uInt8 value) { - address &= 0x1FFF; + address &= myBankMask; - // Switch banks if necessary - switch(address & 0x1260) - { - case 0x0220: - // Set the current bank to the lower 4k bank - bank(mySwappedHotspots ? 1 : 0); - break; - - case 0x0240: - // Set the current bank to the upper 4k bank - bank(mySwappedHotspots ? 0 : 1); - break; - - default: - break; - } + checkSwitchBank(address); // Because of the way accessing is set up, we will may get here by // doing a write to TIA or cart; we ignore the cart write @@ -119,87 +100,3 @@ bool CartridgeUA::poke(uInt16 address, uInt8 value) return false; } - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeUA::bank(uInt16 bank) -{ - if(bankLocked()) return false; - - // Remember what bank we're in - myBankOffset = bank << 12; - - // Setup the page access methods for the current bank - System::PageAccess access(this, System::PageAccessType::READ); - - // Map ROM image into the system - for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeUA::getBank(uInt16) const -{ - return myBankOffset >> 12; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeUA::bankCount() const -{ - return 2; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeUA::patch(uInt16 address, uInt8 value) -{ - myImage[myBankOffset + (address & 0x0FFF)] = value; - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeUA::getImage(size_t& size) const -{ - size = myImage.size(); - return myImage.data(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeUA::save(Serializer& out) const -{ - try - { - out.putShort(myBankOffset); - } - catch(...) - { - cerr << "ERROR: " << name() << "::save" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeUA::load(Serializer& in) -{ - try - { - myBankOffset = in.getShort(); - } - catch(...) - { - cerr << "ERROR: " << name() << "::load" << endl; - return false; - } - - // Remember what bank we were in - bank(myBankOffset >> 12); - - return true; -} diff --git a/src/emucore/CartUA.hxx b/src/emucore/CartUA.hxx index 38588e4a9..66fe82ec8 100644 --- a/src/emucore/CartUA.hxx +++ b/src/emucore/CartUA.hxx @@ -19,7 +19,7 @@ #define CARTRIDGEUA_HXX #include "bspf.hxx" -#include "Cart.hxx" +#include "CartEnhanced.hxx" #include "System.hxx" #ifdef DEBUGGER_SUPPORT #include "CartUAWidget.hxx" @@ -30,9 +30,9 @@ are two 4K banks, which are switched by accessing $0220 (bank 0) and $0240 (bank 1). - @author Bradford W. Mott + @author Bradford W. Mott, Thomas Jentzsch */ -class CartridgeUA : public Cartridge +class CartridgeUA : public CartridgeEnhanced { friend class CartridgeUAWidget; @@ -51,11 +51,6 @@ class CartridgeUA : public Cartridge virtual ~CartridgeUA() = default; public: - /** - Reset device to its power-on state - */ - void reset() override; - /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @@ -64,57 +59,6 @@ class CartridgeUA : public Cartridge */ void install(System& system) override; - /** - Install pages for the specified bank in the system. - - @param bank The bank that should be installed in the system - */ - bool bank(uInt16 bank) override; - - /** - Get the current bank. - - @param address The address to use when querying the bank - */ - uInt16 getBank(uInt16 address = 0) const override; - - /** - Query the number of banks supported by the cartridge. - */ - uInt16 bankCount() const override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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). @@ -152,16 +96,14 @@ class CartridgeUA : public Cartridge */ bool poke(uInt16 address, uInt8 value) override; - private: - // The 8K ROM image of the cartridge - std::array myImage; + protected: + bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; + + private: // Previous Device's page access std::array myHotSpotPageAccess; - // Indicates the offset into the ROM image (aligns to current bank) - uInt16 myBankOffset{0}; - // Indicates if banks are swapped ("Mickey" cart) bool mySwappedHotspots{false}; diff --git a/src/windows/Stella.vcxproj b/src/windows/Stella.vcxproj index 9aa49cb84..fcd2b85fb 100644 --- a/src/windows/Stella.vcxproj +++ b/src/windows/Stella.vcxproj @@ -717,6 +717,7 @@ + @@ -1739,6 +1740,7 @@ + diff --git a/src/windows/Stella.vcxproj.filters b/src/windows/Stella.vcxproj.filters index 4a2fe6691..ef41cf662 100644 --- a/src/windows/Stella.vcxproj.filters +++ b/src/windows/Stella.vcxproj.filters @@ -1005,6 +1005,9 @@ Source Files\gui + + Source Files\emucore + @@ -2063,6 +2066,9 @@ Header Files\gui + + Header Files\emucore + diff --git a/profile/128.bin b/test/roms/profile/128.bin similarity index 100% rename from profile/128.bin rename to test/roms/profile/128.bin diff --git a/profile/README.md b/test/roms/profile/README.md similarity index 100% rename from profile/README.md rename to test/roms/profile/README.md diff --git a/profile/catharsis_theory.bin b/test/roms/profile/catharsis_theory.bin similarity index 100% rename from profile/catharsis_theory.bin rename to test/roms/profile/catharsis_theory.bin From 8352a36401203af7473ab06db12936028ae4e39d Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 4 Apr 2020 10:53:14 +0200 Subject: [PATCH 084/377] add support for multi segment banking into CartEnhanced class refactor more cart classes --- src/common/bspf.hxx | 2 +- src/debugger/gui/CartE0Widget.cxx | 12 +- src/debugger/gui/DebuggerDialog.cxx | 2 +- src/emucore/CartBF.cxx | 133 +----------------- src/emucore/CartBF.hxx | 96 +------------ src/emucore/CartBFSC.cxx | 194 +------------------------- src/emucore/CartBFSC.hxx | 100 +------------- src/emucore/CartDF.cxx | 135 +------------------ src/emucore/CartDF.hxx | 96 +------------ src/emucore/CartDFSC.cxx | 202 +--------------------------- src/emucore/CartDFSC.hxx | 100 +------------- src/emucore/CartE0.cxx | 128 ++---------------- src/emucore/CartE0.hxx | 85 ++---------- src/emucore/CartEF.cxx | 135 +------------------ src/emucore/CartEF.hxx | 96 +------------ src/emucore/CartEFSC.cxx | 202 +--------------------------- src/emucore/CartEFSC.hxx | 99 +------------- src/emucore/CartEnhanced.cxx | 80 +++++------ src/emucore/CartEnhanced.hxx | 81 ++++++----- src/emucore/CartF0.hxx | 3 +- src/emucore/CartF4.hxx | 2 +- src/emucore/CartF4SC.cxx | 2 +- src/emucore/CartF6.hxx | 2 +- src/emucore/CartF6SC.cxx | 2 +- src/emucore/CartF8.hxx | 3 +- src/emucore/CartF8SC.cxx | 1 - src/emucore/CartF8SC.hxx | 3 - src/emucore/CartFC.hxx | 3 +- src/emucore/CartFE.cxx | 4 +- src/emucore/CartFE.hxx | 4 +- src/emucore/CartUA.cxx | 2 +- src/emucore/CartUA.hxx | 2 +- 32 files changed, 183 insertions(+), 1828 deletions(-) diff --git a/src/common/bspf.hxx b/src/common/bspf.hxx index 06333b13c..7312783b3 100644 --- a/src/common/bspf.hxx +++ b/src/common/bspf.hxx @@ -84,7 +84,7 @@ using ByteArray = std::vector; using ShortArray = std::vector; using StringList = std::vector; using ByteBuffer = std::unique_ptr; // NOLINT -using WordBuffer = std::unique_ptr; // NOLINT +using DWordBuffer = std::unique_ptr; // NOLINT // We use KB a lot; let's make a literal for it constexpr uInt32 operator "" _KB(unsigned long long size) diff --git a/src/debugger/gui/CartE0Widget.cxx b/src/debugger/gui/CartE0Widget.cxx index de845b197..bdce56fdb 100644 --- a/src/debugger/gui/CartE0Widget.cxx +++ b/src/debugger/gui/CartE0Widget.cxx @@ -98,9 +98,9 @@ CartridgeE0Widget::CartridgeE0Widget( // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeE0Widget::loadConfig() { - mySlice0->setSelectedIndex(myCart.myCurrentBank[0]); - mySlice1->setSelectedIndex(myCart.myCurrentBank[1]); - mySlice2->setSelectedIndex(myCart.myCurrentBank[2]); + mySlice0->setSelectedIndex(myCart.myCurrentSegOffset[0] >> myCart.myBankShift); + mySlice1->setSelectedIndex(myCart.myCurrentSegOffset[1] >> myCart.myBankShift); + mySlice2->setSelectedIndex(myCart.myCurrentSegOffset[2] >> myCart.myBankShift); CartDebugWidget::loadConfig(); } @@ -136,9 +136,9 @@ string CartridgeE0Widget::bankState() ostringstream& buf = buffer(); buf << "Slices: " << std::dec - << seg0[myCart.myCurrentBank[0]] << " / " - << seg1[myCart.myCurrentBank[1]] << " / " - << seg2[myCart.myCurrentBank[2]]; + << seg0[myCart.myCurrentSegOffset[0] >> myCart.myBankShift] << " / " + << seg1[myCart.myCurrentSegOffset[1] >> myCart.myBankShift] << " / " + << seg2[myCart.myCurrentSegOffset[2] >> myCart.myBankShift]; return buf.str(); } diff --git a/src/debugger/gui/DebuggerDialog.cxx b/src/debugger/gui/DebuggerDialog.cxx index 47e05da04..3143dbc10 100644 --- a/src/debugger/gui/DebuggerDialog.cxx +++ b/src/debugger/gui/DebuggerDialog.cxx @@ -617,7 +617,7 @@ void DebuggerDialog::addRomArea() // The 'cart-specific' information tab (optional) - tabID = myRomTab->addTab(" " + instance().console().cartridge().name() + " ", TabWidget::AUTO_WIDTH); + tabID = myRomTab->addTab(" " + instance().console().cartridge().name() + " ", TabWidget::AUTO_WIDTH); myCartInfo = instance().console().cartridge().infoWidget( myRomTab, *myLFont, *myNFont, 2, 2, tabWidth - 1, tabHeight - myRomTab->getTabHeight() - 2); diff --git a/src/emucore/CartBF.cxx b/src/emucore/CartBF.cxx index 91d13cbb7..0d1921c17 100644 --- a/src/emucore/CartBF.cxx +++ b/src/emucore/CartBF.cxx @@ -21,33 +21,12 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeBF::CartridgeBF(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5) + : CartridgeEnhanced(image, size, md5, settings) { - // Copy the ROM image into my buffer - std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeBF::reset() -{ - initializeStartBank(1); - - // Upon reset we switch to the startup bank - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeBF::install(System& system) -{ - mySystem = &system; - - // Install pages for the startup bank - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeBF::peek(uInt16 address) +bool CartridgeBF::checkSwitchBank(uInt16 address, uInt8) { // Due to the way addressing is set up, we will only get here if the // address is in the hotspot range ($1F80 - $1FFF) @@ -55,111 +34,9 @@ uInt8 CartridgeBF::peek(uInt16 address) // Switch banks if necessary if((address >= 0x0F80) && (address <= 0x0FBF)) + { bank(address - 0x0F80); - - return myImage[myBankOffset + address]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeBF::poke(uInt16 address, uInt8) -{ - // Due to the way addressing is set up, we will only get here if the - // address is in the hotspot range ($1F80 - $1FFF) - address &= 0x0FFF; - - // Switch banks if necessary - if((address >= 0x0F80) && (address <= 0x0FBF)) - bank(address - 0x0F80); - + return true; + } return false; } - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeBF::bank(uInt16 bank) -{ - if(bankLocked()) return false; - - // Remember what bank we're in - myBankOffset = bank << 12; - - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page accessing methods for the hot spots - for(uInt16 addr = (0x1F80 & ~System::PAGE_MASK); addr < 0x2000; - addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - mySystem->setPageAccess(addr, access); - } - - // Setup the page access methods for the current bank - for(uInt16 addr = 0x1000; addr < static_cast(0x1F80U & ~System::PAGE_MASK); - addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - mySystem->setPageAccess(addr, access); - } - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeBF::getBank(uInt16) const -{ - return myBankOffset >> 12; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeBF::bankCount() const -{ - return 64; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeBF::patch(uInt16 address, uInt8 value) -{ - myImage[myBankOffset + (address & 0x0FFF)] = value; - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeBF::getImage(size_t& size) const -{ - size = myImage.size(); - return myImage.data(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeBF::save(Serializer& out) const -{ - try - { - out.putInt(myBankOffset); - } - catch(...) - { - cerr << "ERROR: CartridgeBF::save" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeBF::load(Serializer& in) -{ - try - { - myBankOffset = in.getInt(); - } - catch(...) - { - cerr << "ERROR: CartridgeBF::load" << endl; - return false; - } - - // Remember what bank we were in - bank(myBankOffset >> 12); - - return true; -} diff --git a/src/emucore/CartBF.hxx b/src/emucore/CartBF.hxx index 158f43a45..08b54d731 100644 --- a/src/emucore/CartBF.hxx +++ b/src/emucore/CartBF.hxx @@ -21,7 +21,7 @@ class System; #include "bspf.hxx" -#include "Cart.hxx" +#include "CartEnhanced.hxx" #ifdef DEBUGGER_SUPPORT #include "CartBFWidget.hxx" #endif @@ -31,9 +31,9 @@ class System; There are 64 4K banks (total of 256K ROM). Accessing $1F80 - $1FBF switches to each bank. - @author Mike Saarna + @author Mike Saarna, Thomas Jentzsch */ -class CartridgeBF : public Cartridge +class CartridgeBF : public CartridgeEnhanced { friend class CartridgeBFWidget; @@ -51,71 +51,6 @@ class CartridgeBF : public Cartridge virtual ~CartridgeBF() = default; public: - /** - Reset device to its power-on state - */ - void reset() override; - - /** - Install cartridge in the specified system. Invoked by the system - when the cartridge is attached to it. - - @param system The system the device should install itself in - */ - void install(System& system) override; - - /** - Install pages for the specified bank in the system. - - @param bank The bank that should be installed in the system - */ - bool bank(uInt16 bank) override; - - /** - Get the current bank. - - @param address The address to use when querying the bank - */ - uInt16 getBank(uInt16 address = 0) const override; - - /** - Query the number of banks supported by the cartridge. - */ - uInt16 bankCount() const override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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). @@ -135,29 +70,12 @@ class CartridgeBF : public Cartridge } #endif - public: - /** - Get the byte at the specified address. - - @return The byte at the specified address - */ - uInt8 peek(uInt16 address) override; - - /** - Change the byte at the specified address to the given value - - @param address The address where the value should be stored - @param value The value to be stored at the address - @return True if the poke changed the device address space, else false - */ - bool poke(uInt16 address, uInt8 value) override; - private: - // The 256K ROM image of the cartridge - std::array myImage; + bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; - // Indicates the offset into the ROM image (aligns to current bank) - uInt32 myBankOffset{0}; + uInt16 romHotspot() const override { return 0x1F80; } + + uInt16 getStartBank() const override { return 1; } private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartBFSC.cxx b/src/emucore/CartBFSC.cxx index d0d33c79f..bd9793893 100644 --- a/src/emucore/CartBFSC.cxx +++ b/src/emucore/CartBFSC.cxx @@ -21,197 +21,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeBFSC::CartridgeBFSC(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5) + : CartridgeBF(image, size, md5, settings) { - // Copy the ROM image into my buffer - std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessArrays(myImage.size()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeBFSC::reset() -{ - initializeRAM(myRAM.data(), myRAM.size()); - initializeStartBank(15); - - // Upon reset we switch to the startup bank - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeBFSC::install(System& system) -{ - mySystem = &system; - - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page accessing method for the RAM writing pages - // Map access to this class, since we need to inspect all accesses to - // check if RWP happens - access.type = System::PageAccessType::WRITE; - for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[addr & 0x007F]; - mySystem->setPageAccess(addr, access); - } - - // Set the page accessing method for the RAM reading pages - access.type = System::PageAccessType::READ; - for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myRAM[addr & 0x007F]; - access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)]; - mySystem->setPageAccess(addr, access); - } - - // Install pages for the startup bank - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeBFSC::peek(uInt16 address) -{ - uInt16 peekAddress = address; - address &= 0x0FFF; - - // Switch banks if necessary - if((address >= 0x0F80) && (address <= 0x0FBF)) - bank(address - 0x0F80); - - if(address < 0x0080) // Write port is at 0xF000 - 0xF07F (128 bytes) - return peekRAM(myRAM[address], peekAddress); - else - return myImage[myBankOffset + address]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeBFSC::poke(uInt16 address, uInt8 value) -{ - uInt16 pokeAddress = address; - address &= 0x0FFF; - - // Switch banks if necessary - if((address >= 0x0F80) && (address <= 0x0FBF)) - { - bank(address - 0x0F80); - return false; - } - - if (!(address & 0x080)) - { - pokeRAM(myRAM[address & 0x007F], pokeAddress, value); - return true; - } - else - { - // Writing to the read port should be ignored, but trigger a break if option enabled - uInt8 dummy; - - pokeRAM(dummy, pokeAddress, value); - myRamWriteAccess = pokeAddress; - return false; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeBFSC::bank(uInt16 bank) -{ - if(bankLocked()) return false; - - // Remember what bank we're in - myBankOffset = bank << 12; - - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page accessing methods for the hot spots - for(uInt16 addr = (0x1F80 & ~System::PAGE_MASK); addr < 0x2000; - addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - mySystem->setPageAccess(addr, access); - } - - // Setup the page access methods for the current bank - for(uInt16 addr = 0x1100; addr < static_cast(0x1F80U & ~System::PAGE_MASK); - addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - mySystem->setPageAccess(addr, access); - } - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeBFSC::getBank(uInt16) const -{ - return myBankOffset >> 12; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeBFSC::bankCount() const -{ - return 64; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeBFSC::patch(uInt16 address, uInt8 value) -{ - address &= 0x0FFF; - - if(address < 0x0100) - { - // Normally, a write to the read port won't do anything - // However, the patch command is special in that ignores such - // cart restrictions - myRAM[address & 0x007F] = value; - } - else - myImage[myBankOffset + address] = value; - - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeBFSC::getImage(size_t& size) const -{ - size = myImage.size(); - return myImage.data(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeBFSC::save(Serializer& out) const -{ - try - { - out.putInt(myBankOffset); - out.putByteArray(myRAM.data(), myRAM.size()); - } - catch(...) - { - cerr << "ERROR: CartridgeBFSC::save" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeBFSC::load(Serializer& in) -{ - try - { - myBankOffset = in.getInt(); - in.getByteArray(myRAM.data(), myRAM.size()); - } - catch(...) - { - cerr << "ERROR: CartridgeBFSC::load" << endl; - return false; - } - - // Remember what bank we were in - bank(myBankOffset >> 12); - - return true; + myRamSize = RAM_SIZE; } diff --git a/src/emucore/CartBFSC.hxx b/src/emucore/CartBFSC.hxx index b4cb72aad..35c4b84ca 100644 --- a/src/emucore/CartBFSC.hxx +++ b/src/emucore/CartBFSC.hxx @@ -21,7 +21,7 @@ class System; #include "bspf.hxx" -#include "Cart.hxx" +#include "CartBF.hxx" #ifdef DEBUGGER_SUPPORT #include "CartBFSCWidget.hxx" #endif @@ -31,9 +31,9 @@ class System; Accessing $1F80 - $1FBF switches to each bank. RAM read port is $1080 - $10FF, write port is $1000 - $107F. - @author Stephen Anthony + @author Stephen Anthony, Thomas Jentzsch */ -class CartridgeBFSC : public Cartridge +class CartridgeBFSC : public CartridgeBF { friend class CartridgeBFSCWidget; @@ -50,72 +50,6 @@ class CartridgeBFSC : public Cartridge const Settings& settings); virtual ~CartridgeBFSC() = default; - public: - /** - Reset device to its power-on state - */ - void reset() override; - - /** - Install cartridge in the specified system. Invoked by the system - when the cartridge is attached to it. - - @param system The system the device should install itself in - */ - void install(System& system) override; - - /** - Install pages for the specified bank in the system. - - @param bank The bank that should be installed in the system - */ - bool bank(uInt16 bank) override; - - /** - Get the current bank. - - @param address The address to use when querying the bank - */ - uInt16 getBank(uInt16 address = 0) const override; - - /** - Query the number of banks supported by the cartridge. - */ - uInt16 bankCount() const override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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). @@ -135,32 +69,12 @@ class CartridgeBFSC : public Cartridge } #endif - public: - /** - Get the byte at the specified address. - - @return The byte at the specified address - */ - uInt8 peek(uInt16 address) override; - - /** - Change the byte at the specified address to the given value - - @param address The address where the value should be stored - @param value The value to be stored at the address - @return True if the poke changed the device address space, else false - */ - bool poke(uInt16 address, uInt8 value) override; + private: + uInt16 getStartBank() const override { return 15; } private: - // The 256K ROM image of the cartridge - std::array myImage; - - // The 128 bytes of RAM - std::array myRAM; - - // Indicates the offset into the ROM image (aligns to current bank) - uInt32 myBankOffset{0}; + // RAM size + static constexpr uInt16 RAM_SIZE = 0x80; private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartDF.cxx b/src/emucore/CartDF.cxx index b43bc0837..db9ab62d2 100644 --- a/src/emucore/CartDF.cxx +++ b/src/emucore/CartDF.cxx @@ -21,145 +21,20 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeDF::CartridgeDF(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5) + : CartridgeEnhanced(image, size, md5, settings) { - // Copy the ROM image into my buffer - std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeDF::reset() -{ - initializeStartBank(1); - - // Upon reset we switch to the startup bank - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeDF::install(System& system) -{ - mySystem = &system; - - // Install pages for the startup bank - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeDF::peek(uInt16 address) +bool CartridgeDF::checkSwitchBank(uInt16 address, uInt8) { address &= 0x0FFF; // Switch banks if necessary if((address >= 0x0FC0) && (address <= 0x0FDF)) + { bank(address - 0x0FC0); - - return myImage[myBankOffset + address]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeDF::poke(uInt16 address, uInt8) -{ - address &= 0x0FFF; - - // Switch banks if necessary - if((address >= 0x0FC0) && (address <= 0x0FDF)) - bank(address - 0x0FC0); - + return true; + } return false; } - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeDF::bank(uInt16 bank) -{ - if(bankLocked()) return false; - - // Remember what bank we're in - myBankOffset = bank << 12; - - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page accessing methods for the hot spots - for(uInt16 addr = (0x1FC0 & ~System::PAGE_MASK); addr < 0x2000; - addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Setup the page access methods for the current bank - for(uInt16 addr = 0x1000; addr < static_cast(0x1FC0U & ~System::PAGE_MASK); - addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeDF::getBank(uInt16) const -{ - return myBankOffset >> 12; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeDF::bankCount() const -{ - return 32; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeDF::patch(uInt16 address, uInt8 value) -{ - myImage[myBankOffset + (address & 0x0FFF)] = value; - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeDF::getImage(size_t& size) const -{ - size = myImage.size(); - return myImage.data(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeDF::save(Serializer& out) const -{ - try - { - out.putInt(myBankOffset); - } - catch(...) - { - cerr << "ERROR: CartridgeDF::save" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeDF::load(Serializer& in) -{ - try - { - myBankOffset = in.getInt(); - } - catch(...) - { - cerr << "ERROR: CartridgeDF::load" << endl; - return false; - } - - // Remember what bank we were in - bank(myBankOffset >> 12); - - return true; -} diff --git a/src/emucore/CartDF.hxx b/src/emucore/CartDF.hxx index 04804b957..5b2025285 100644 --- a/src/emucore/CartDF.hxx +++ b/src/emucore/CartDF.hxx @@ -21,7 +21,7 @@ class System; #include "bspf.hxx" -#include "Cart.hxx" +#include "CartEnhanced.hxx" #ifdef DEBUGGER_SUPPORT #include "CartDFWidget.hxx" #endif @@ -31,9 +31,9 @@ class System; There are 32 4K banks (total of 128K ROM). Accessing $1FC0 - $1FDF switches to each bank. - @author Mike Saarna + @author Mike Saarna, Thomas Jentzsch */ -class CartridgeDF : public Cartridge +class CartridgeDF : public CartridgeEnhanced { friend class CartridgeDFWidget; @@ -51,71 +51,6 @@ class CartridgeDF : public Cartridge virtual ~CartridgeDF() = default; public: - /** - Reset device to its power-on state - */ - void reset() override; - - /** - Install cartridge in the specified system. Invoked by the system - when the cartridge is attached to it. - - @param system The system the device should install itself in - */ - void install(System& system) override; - - /** - Install pages for the specified bank in the system. - - @param bank The bank that should be installed in the system - */ - bool bank(uInt16 bank) override; - - /** - Get the current bank. - - @param address The address to use when querying the bank - */ - uInt16 getBank(uInt16 address = 0) const override; - - /** - Query the number of banks supported by the cartridge. - */ - uInt16 bankCount() const override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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). @@ -135,29 +70,12 @@ class CartridgeDF : public Cartridge } #endif - public: - /** - Get the byte at the specified address. - - @return The byte at the specified address - */ - uInt8 peek(uInt16 address) override; - - /** - Change the byte at the specified address to the given value - - @param address The address where the value should be stored - @param value The value to be stored at the address - @return True if the poke changed the device address space, else false - */ - bool poke(uInt16 address, uInt8 value) override; - private: - // The 128K ROM image of the cartridge - std::array myImage; + bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; - // Indicates the offset into the ROM image (aligns to current bank) - uInt32 myBankOffset{0}; + uInt16 romHotspot() const override { return 0x1FC0; } + + uInt16 getStartBank() const override { return 15; } private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartDFSC.cxx b/src/emucore/CartDFSC.cxx index 3661459fa..f759136a7 100644 --- a/src/emucore/CartDFSC.cxx +++ b/src/emucore/CartDFSC.cxx @@ -21,205 +21,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeDFSC::CartridgeDFSC(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5) + : CartridgeDF(image, size, md5, settings) { - // Copy the ROM image into my buffer - std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessArrays(myImage.size()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeDFSC::reset() -{ - initializeRAM(myRAM.data(), myRAM.size()); - initializeStartBank(15); - - // Upon reset we switch to the startup bank - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeDFSC::install(System& system) -{ - mySystem = &system; - - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page accessing method for the RAM writing pages - // Map access to this class, since we need to inspect all accesses to - // check if RWP happens - access.type = System::PageAccessType::WRITE; - for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[addr & 0x007F]; - access.romPeekCounter = &myRomAccessCounter[addr & 0x007F]; - access.romPokeCounter = &myRomAccessCounter[(addr & 0x007F) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Set the page accessing method for the RAM reading pages - access.type = System::PageAccessType::READ; - for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myRAM[addr & 0x007F]; - access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)]; - access.romPeekCounter = &myRomAccessCounter[0x80 + (addr & 0x007F)]; - access.romPokeCounter = &myRomAccessCounter[0x80 + (addr & 0x007F) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Install pages for the startup bank - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeDFSC::peek(uInt16 address) -{ - uInt16 peekAddress = address; - address &= 0x0FFF; - - // Switch banks if necessary - if((address >= 0x0FC0) && (address <= 0x0FDF)) - bank(address - 0x0FC0); - - if(address < 0x0080) // Write port is at 0xF000 - 0xF07F (128 bytes) - return peekRAM(myRAM[address], peekAddress); - else - return myImage[myBankOffset + address]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeDFSC::poke(uInt16 address, uInt8 value) -{ - uInt16 pokeAddress = address; - address &= 0x0FFF; - - // Switch banks if necessary - if((address >= 0x0FC0) && (address <= 0x0FDF)) - { - bank(address - 0x0FC0); - return false; - } - - if(!(address & 0x080)) - { - pokeRAM(myRAM[address & 0x007F], pokeAddress, value); - return true; - } - else - { - // Writing to the read port should be ignored, but trigger a break if option enabled - uInt8 dummy; - - pokeRAM(dummy, pokeAddress, value); - myRamWriteAccess = pokeAddress; - return false; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeDFSC::bank(uInt16 bank) -{ - if(bankLocked()) return false; - - // Remember what bank we're in - myBankOffset = bank << 12; - - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page accessing methods for the hot spots - for(uInt16 addr = (0x1FC0 & ~System::PAGE_MASK); addr < 0x2000; - addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Setup the page access methods for the current bank - for(uInt16 addr = 0x1100; addr < static_cast(0x1FC0U & ~System::PAGE_MASK); - addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeDFSC::getBank(uInt16) const -{ - return myBankOffset >> 12; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeDFSC::bankCount() const -{ - return 32; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeDFSC::patch(uInt16 address, uInt8 value) -{ - address &= 0x0FFF; - - if(address < 0x0100) - { - // Normally, a write to the read port won't do anything - // However, the patch command is special in that ignores such - // cart restrictions - myRAM[address & 0x007F] = value; - } - else - myImage[myBankOffset + address] = value; - - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeDFSC::getImage(size_t& size) const -{ - size = myImage.size(); - return myImage.data(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeDFSC::save(Serializer& out) const -{ - try - { - out.putInt(myBankOffset); - out.putByteArray(myRAM.data(), myRAM.size()); - } - catch(...) - { - cerr << "ERROR: CartridgeDFSC::save" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeDFSC::load(Serializer& in) -{ - try - { - myBankOffset = in.getInt(); - in.getByteArray(myRAM.data(), myRAM.size()); - } - catch(...) - { - cerr << "ERROR: CartridgeDFSC::load" << endl; - return false; - } - - // Remember what bank we were in - bank(myBankOffset >> 12); - - return true; + myRamSize = RAM_SIZE; } diff --git a/src/emucore/CartDFSC.hxx b/src/emucore/CartDFSC.hxx index af35f476b..cf3661039 100644 --- a/src/emucore/CartDFSC.hxx +++ b/src/emucore/CartDFSC.hxx @@ -21,7 +21,7 @@ class System; #include "bspf.hxx" -#include "Cart.hxx" +#include "CartDF.hxx" #ifdef DEBUGGER_SUPPORT #include "CartDFSCWidget.hxx" #endif @@ -31,9 +31,9 @@ class System; Accessing $1FC0 - $1FDF switches to each bank. RAM read port is $1080 - $10FF, write port is $1000 - $107F. - @author Stephen Anthony + @author Stephen Anthony, Thomas Jentzsch */ -class CartridgeDFSC : public Cartridge +class CartridgeDFSC : public CartridgeDF { friend class CartridgeDFSCWidget; @@ -51,71 +51,6 @@ class CartridgeDFSC : public Cartridge virtual ~CartridgeDFSC() = default; public: - /** - Reset device to its power-on state - */ - void reset() override; - - /** - Install cartridge in the specified system. Invoked by the system - when the cartridge is attached to it. - - @param system The system the device should install itself in - */ - void install(System& system) override; - - /** - Install pages for the specified bank in the system. - - @param bank The bank that should be installed in the system - */ - bool bank(uInt16 bank) override; - - /** - Get the current bank. - - @param address The address to use when querying the bank - */ - uInt16 getBank(uInt16 address = 0) const override; - - /** - Query the number of banks supported by the cartridge. - */ - uInt16 bankCount() const override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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). @@ -135,34 +70,11 @@ class CartridgeDFSC : public Cartridge } #endif - public: - /** - Get the byte at the specified address. - - @return The byte at the specified address - */ - uInt8 peek(uInt16 address) override; - - /** - Change the byte at the specified address to the given value - - @param address The address where the value should be stored - @param value The value to be stored at the address - @return True if the poke changed the device address space, else false - */ - bool poke(uInt16 address, uInt8 value) override; - private: - // The 128K ROM image of the cartridge - std::array myImage; + // RAM size + static constexpr uInt16 RAM_SIZE = 0x80; - // The 128 bytes of RAM - std::array myRAM; - - // Indicates the offset into the ROM image (aligns to current bank) - uInt32 myBankOffset{0}; - - private: +private: // Following constructors and assignment operators not supported CartridgeDFSC() = delete; CartridgeDFSC(const CartridgeDFSC&) = delete; diff --git a/src/emucore/CartE0.cxx b/src/emucore/CartE0.cxx index 3788a95bc..e35917993 100644 --- a/src/emucore/CartE0.cxx +++ b/src/emucore/CartE0.cxx @@ -21,11 +21,9 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeE0::CartridgeE0(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5) + : CartridgeEnhanced(image, size, md5, settings) { - // Copy the ROM image into my buffer - std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessArrays(myImage.size()); + myBankShift = BANK_SHIFT; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -44,7 +42,7 @@ void CartridgeE0::reset() bank(5, 1); bank(6, 2); } - myCurrentBank[3] = bankCount() - 1; // fixed + myCurrentSegOffset[3] = (bankCount() - 1) << myBankShift; // fixed myBankChanged = true; } @@ -52,7 +50,13 @@ void CartridgeE0::reset() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeE0::install(System& system) { - mySystem = &system; + //// Allocate array for the current bank segments slices + //myCurrentSegOffset = make_unique(myBankSegs); + + //// Setup page access + //mySystem = &system; + + CartridgeEnhanced::install(system); System::PageAccess access(this, System::PageAccessType::READ); @@ -79,127 +83,23 @@ void CartridgeE0::install(System& system) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeE0::getBank(uInt16 address) const +bool CartridgeE0::checkSwitchBank(uInt16 address, uInt8) { - return myCurrentBank[(address & 0xFFF) >> 10]; // 1K slices -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeE0::bankCount() const -{ - return 8; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeE0::peek(uInt16 address) -{ - address &= 0x0FFF; - - // Switch banks if necessary - if((address >= 0x0FE0) && (address <= 0x0FE7)) - { - bank(address & 0x0007, 0); - } - else if((address >= 0x0FE8) && (address <= 0x0FEF)) - { - bank(address & 0x0007, 1); - } - else if((address >= 0x0FF0) && (address <= 0x0FF7)) - { - bank(address & 0x0007, 2); - } - - return myImage[(myCurrentBank[address >> 10] << 10) + (address & 0x03FF)]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeE0::poke(uInt16 address, uInt8) -{ - address &= 0x0FFF; - // Switch banks if necessary if((address >= 0x0FE0) && (address <= 0x0FE7)) { bank(address & 0x0007, 0); + return true; } else if((address >= 0x0FE8) && (address <= 0x0FEF)) { bank(address & 0x0007, 1); + return true; } else if((address >= 0x0FF0) && (address <= 0x0FF7)) { bank(address & 0x0007, 2); + return true; } return false; } - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeE0::bank(uInt16 bank, uInt16 slice) -{ - if(bankLocked()) return; - - // Remember the new slice - myCurrentBank[slice] = bank; - uInt16 sliceOffset = slice * (1 << 10); - uInt16 bankOffset = bank << 10; - - // Setup the page access methods for the current bank - System::PageAccess access(this, System::PageAccessType::READ); - - for(uInt16 addr = 0x1000 + sliceOffset; addr < 0x1000 + sliceOffset + 0x400; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[bankOffset + (addr & 0x03FF)]; - access.romAccessBase = &myRomAccessBase[bankOffset + (addr & 0x03FF)]; - access.romPeekCounter = &myRomAccessCounter[bankOffset + (addr & 0x03FF)]; - access.romPokeCounter = &myRomAccessCounter[bankOffset + (addr & 0x03FF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeE0::patch(uInt16 address, uInt8 value) -{ - address &= 0x0FFF; - myImage[(myCurrentBank[address >> 10] << 10) + (address & 0x03FF)] = value; - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeE0::getImage(size_t& size) const -{ - size = myImage.size(); - return myImage.data(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeE0::save(Serializer& out) const -{ - try - { - out.putShortArray(myCurrentBank.data(), myCurrentBank.size()); - } - catch(...) - { - cerr << "ERROR: CartridgeE0::save" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeE0::load(Serializer& in) -{ - try - { - in.getShortArray(myCurrentBank.data(), myCurrentBank.size()); - } - catch(...) - { - cerr << "ERROR: CartridgeE0::load" << endl; - return false; - } - - return true; -} diff --git a/src/emucore/CartE0.hxx b/src/emucore/CartE0.hxx index 35513be85..66dbbba6a 100644 --- a/src/emucore/CartE0.hxx +++ b/src/emucore/CartE0.hxx @@ -21,7 +21,7 @@ class System; #include "bspf.hxx" -#include "Cart.hxx" +#include "CartEnhanced.hxx" #ifdef DEBUGGER_SUPPORT #include "CartE0Widget.hxx" #endif @@ -39,9 +39,9 @@ class System; only one actual bank, in which pieces of it can be swapped out in many different ways. - @author Bradford W. Mott + @author Bradford W. Mott, Thomas Jentzsch */ -class CartridgeE0 : public Cartridge +class CartridgeE0 : public CartridgeEnhanced { friend class CartridgeE0Widget; @@ -72,52 +72,6 @@ class CartridgeE0 : public Cartridge */ void install(System& system) override; - - /** - Get the current bank. - - @param address The address to use when querying the bank - */ - uInt16 getBank(uInt16 address = 0) const override; - - /** - Query the number of banks supported by the cartridge. - */ - uInt16 bankCount() const override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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). @@ -137,37 +91,14 @@ class CartridgeE0 : public Cartridge } #endif - public: - /** - Get the byte at the specified address. + private: + bool checkSwitchBank(uInt16 address, uInt8 = 0) override; - @return The byte at the specified address - */ - uInt8 peek(uInt16 address) override; - - /** - Change the byte at the specified address to the given value - - @param address The address where the value should be stored - @param value The value to be stored at the address - @return True if the poke changed the device address space, else false - */ - bool poke(uInt16 address, uInt8 value) override; + uInt16 romHotspot() const override { return 0x1FE0; } private: - /** - Install the specified slice for segment (bank) 0..2 - - @param slice The slice to map into the segment - */ - void bank(uInt16 bank, uInt16 slice); - - private: - // The 8K ROM image of the cartridge - std::array myImage; - - // Indicates the slice mapped into each of the four segments - std::array myCurrentBank; + // log(ROM bank segment size) / log(2) + static constexpr uInt16 BANK_SHIFT = 10; // = 1K = 0x0400 private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartEF.cxx b/src/emucore/CartEF.cxx index 16635200b..70cd8236b 100644 --- a/src/emucore/CartEF.cxx +++ b/src/emucore/CartEF.cxx @@ -21,145 +21,20 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeEF::CartridgeEF(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5) + : CartridgeEnhanced(image, size, md5, settings) { - // Copy the ROM image into my buffer - std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeEF::reset() -{ - initializeStartBank(1); - - // Upon reset we switch to the startup bank - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeEF::install(System& system) -{ - mySystem = &system; - - // Install pages for the startup bank - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeEF::peek(uInt16 address) +bool CartridgeEF::checkSwitchBank(uInt16 address, uInt8) { address &= 0x0FFF; // Switch banks if necessary if((address >= 0x0FE0) && (address <= 0x0FEF)) + { bank(address - 0x0FE0); - - return myImage[myBankOffset + address]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeEF::poke(uInt16 address, uInt8) -{ - address &= 0x0FFF; - - // Switch banks if necessary - if((address >= 0x0FE0) && (address <= 0x0FEF)) - bank(address - 0x0FE0); - + return true; + } return false; } - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeEF::bank(uInt16 bank) -{ - if(bankLocked()) return false; - - // Remember what bank we're in - myBankOffset = bank << 12; - - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page accessing methods for the hot spots - for(uInt16 addr = (0x1FE0 & ~System::PAGE_MASK); addr < 0x2000; - addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Setup the page access methods for the current bank - for(uInt16 addr = 0x1000; addr < static_cast(0x1FE0U & ~System::PAGE_MASK); - addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeEF::getBank(uInt16) const -{ - return myBankOffset >> 12; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeEF::bankCount() const -{ - return 16; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeEF::patch(uInt16 address, uInt8 value) -{ - myImage[myBankOffset + (address & 0x0FFF)] = value; - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeEF::getImage(size_t& size) const -{ - size = myImage.size(); - return myImage.data(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeEF::save(Serializer& out) const -{ - try - { - out.putShort(myBankOffset); - } - catch(...) - { - cerr << "ERROR: CartridgeEF::save" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeEF::load(Serializer& in) -{ - try - { - myBankOffset = in.getShort(); - } - catch(...) - { - cerr << "ERROR: CartridgeEF::load" << endl; - return false; - } - - // Remember what bank we were in - bank(myBankOffset >> 12); - - return true; -} diff --git a/src/emucore/CartEF.hxx b/src/emucore/CartEF.hxx index 62a10975d..1461e954d 100644 --- a/src/emucore/CartEF.hxx +++ b/src/emucore/CartEF.hxx @@ -21,7 +21,7 @@ class System; #include "bspf.hxx" -#include "Cart.hxx" +#include "CartEnhanced.hxx" #ifdef DEBUGGER_SUPPORT #include "CartEFWidget.hxx" #endif @@ -31,9 +31,9 @@ class System; There are 16 4K banks (total of 64K ROM). Accessing $1FE0 - $1FEF switches to each bank. - @author Stephen Anthony + @author Stephen Anthony, Thomas Jentzsch */ -class CartridgeEF : public Cartridge +class CartridgeEF : public CartridgeEnhanced { friend class CartridgeEFWidget; @@ -51,71 +51,6 @@ class CartridgeEF : public Cartridge virtual ~CartridgeEF() = default; public: - /** - Reset device to its power-on state - */ - void reset() override; - - /** - Install cartridge in the specified system. Invoked by the system - when the cartridge is attached to it. - - @param system The system the device should install itself in - */ - void install(System& system) override; - - /** - Install pages for the specified bank in the system. - - @param bank The bank that should be installed in the system - */ - bool bank(uInt16 bank) override; - - /** - Get the current bank. - - @param address The address to use when querying the bank - */ - uInt16 getBank(uInt16 address = 0) const override; - - /** - Query the number of banks supported by the cartridge. - */ - uInt16 bankCount() const override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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). @@ -135,29 +70,12 @@ class CartridgeEF : public Cartridge } #endif - public: - /** - Get the byte at the specified address. - - @return The byte at the specified address - */ - uInt8 peek(uInt16 address) override; - - /** - Change the byte at the specified address to the given value - - @param address The address where the value should be stored - @param value The value to be stored at the address - @return True if the poke changed the device address space, else false - */ - bool poke(uInt16 address, uInt8 value) override; - private: - // The 64K ROM image of the cartridge - std::array myImage; + bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; - // Indicates the offset into the ROM image (aligns to current bank) - uInt16 myBankOffset{0}; + uInt16 romHotspot() const override { return 0x1FE0; } + + uInt16 getStartBank() const override { return 1; } private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartEFSC.cxx b/src/emucore/CartEFSC.cxx index 3502be7a0..c70cff194 100644 --- a/src/emucore/CartEFSC.cxx +++ b/src/emucore/CartEFSC.cxx @@ -21,205 +21,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeEFSC::CartridgeEFSC(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5) + : CartridgeEF(image, size, md5, settings) { - // Copy the ROM image into my buffer - std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessArrays(myImage.size()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeEFSC::reset() -{ - initializeRAM(myRAM.data(), myRAM.size()); - initializeStartBank(15); - - // Upon reset we switch to the startup bank - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeEFSC::install(System& system) -{ - mySystem = &system; - - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page accessing method for the RAM writing pages - // Map access to this class, since we need to inspect all accesses to - // check if RWP happens - access.type = System::PageAccessType::WRITE; - for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[addr & 0x007F]; - access.romPeekCounter = &myRomAccessCounter[addr & 0x007F]; - access.romPokeCounter = &myRomAccessCounter[(addr & 0x007F) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Set the page accessing method for the RAM reading pages - access.type = System::PageAccessType::READ; - for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myRAM[addr & 0x007F]; - access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)]; - access.romPeekCounter = &myRomAccessCounter[0x80 + (addr & 0x007F)]; - access.romPokeCounter = &myRomAccessCounter[0x80 + (addr & 0x007F) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Install pages for the startup bank - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeEFSC::peek(uInt16 address) -{ - uInt16 peekAddress = address; - address &= 0x0FFF; - - // Switch banks if necessary - if((address >= 0x0FE0) && (address <= 0x0FEF)) - bank(address - 0x0FE0); - - if(address < 0x0080) // Write port is at 0xF000 - 0xF07F (128 bytes) - return peekRAM(myRAM[address], peekAddress); - else - return myImage[myBankOffset + address]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeEFSC::poke(uInt16 address, uInt8 value) -{ - uInt16 pokeAddress = address; - address &= 0x0FFF; - - // Switch banks if necessary - if((address >= 0x0FE0) && (address <= 0x0FEF)) - { - bank(address - 0x0FE0); - return false; - } - - if (!(address & 0x080)) - { - pokeRAM(myRAM[address & 0x007F], pokeAddress, value); - return true; - } - else - { - // Writing to the read port should be ignored, but trigger a break if option enabled - uInt8 dummy; - - pokeRAM(dummy, pokeAddress, value); - myRamWriteAccess = pokeAddress; - return false; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeEFSC::bank(uInt16 bank) -{ - if(bankLocked()) return false; - - // Remember what bank we're in - myBankOffset = bank << 12; - - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page accessing methods for the hot spots - for(uInt16 addr = (0x1FE0 & ~System::PAGE_MASK); addr < 0x2000; - addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Setup the page access methods for the current bank - for(uInt16 addr = 0x1100; addr < static_cast(0x1FE0U & ~System::PAGE_MASK); - addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeEFSC::getBank(uInt16) const -{ - return myBankOffset >> 12; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeEFSC::bankCount() const -{ - return 16; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeEFSC::patch(uInt16 address, uInt8 value) -{ - address &= 0x0FFF; - - if(address < 0x0100) - { - // Normally, a write to the read port won't do anything - // However, the patch command is special in that ignores such - // cart restrictions - myRAM[address & 0x007F] = value; - } - else - myImage[myBankOffset + address] = value; - - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeEFSC::getImage(size_t& size) const -{ - size = myImage.size(); - return myImage.data(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeEFSC::save(Serializer& out) const -{ - try - { - out.putShort(myBankOffset); - out.putByteArray(myRAM.data(), myRAM.size()); - } - catch(...) - { - cerr << "ERROR: CartridgeEFSC::save" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeEFSC::load(Serializer& in) -{ - try - { - myBankOffset = in.getShort(); - in.getByteArray(myRAM.data(), myRAM.size()); - } - catch(...) - { - cerr << "ERROR: CartridgeEFSC::load" << endl; - return false; - } - - // Remember what bank we were in - bank(myBankOffset >> 12); - - return true; + myRamSize = RAM_SIZE; } diff --git a/src/emucore/CartEFSC.hxx b/src/emucore/CartEFSC.hxx index 810b27b22..d204d1ef5 100644 --- a/src/emucore/CartEFSC.hxx +++ b/src/emucore/CartEFSC.hxx @@ -21,7 +21,7 @@ class System; #include "bspf.hxx" -#include "Cart.hxx" +#include "CartEF.hxx" #ifdef DEBUGGER_SUPPORT #include "CartEFSCWidget.hxx" #endif @@ -32,9 +32,9 @@ class System; Accessing $1FE0 - $1FEF switches to each bank. RAM read port is $1080 - $10FF, write port is $1000 - $107F. - @author Stephen Anthony + @author Stephen Anthony, Thomas Jentzsch */ -class CartridgeEFSC : public Cartridge +class CartridgeEFSC : public CartridgeEF { friend class CartridgeEFSCWidget; @@ -52,71 +52,6 @@ class CartridgeEFSC : public Cartridge virtual ~CartridgeEFSC() = default; public: - /** - Reset device to its power-on state - */ - void reset() override; - - /** - Install cartridge in the specified system. Invoked by the system - when the cartridge is attached to it. - - @param system The system the device should install itself in - */ - void install(System& system) override; - - /** - Install pages for the specified bank in the system. - - @param bank The bank that should be installed in the system - */ - bool bank(uInt16 bank) override; - - /** - Get the current bank. - - @param address The address to use when querying the bank - */ - uInt16 getBank(uInt16 address = 0) const override; - - /** - Query the number of banks supported by the cartridge. - */ - uInt16 bankCount() const override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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). @@ -136,32 +71,12 @@ class CartridgeEFSC : public Cartridge } #endif - public: - /** - Get the byte at the specified address. - - @return The byte at the specified address - */ - uInt8 peek(uInt16 address) override; - - /** - Change the byte at the specified address to the given value - - @param address The address where the value should be stored - @param value The value to be stored at the address - @return True if the poke changed the device address space, else false - */ - bool poke(uInt16 address, uInt8 value) override; + private: + uInt16 getStartBank() const override { return 15; } private: - // The 64K ROM image of the cartridge - std::array myImage; - - // The 128 bytes of RAM - std::array myRAM; - - // Indicates the offset into the ROM image (aligns to current bank) - uInt16 myBankOffset{0}; + // RAM size + static constexpr uInt16 RAM_SIZE = 0x80; private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index ff4113ad4..0f0472392 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -37,9 +37,14 @@ CartridgeEnhanced::CartridgeEnhanced(const ByteBuffer& image, size_t size, // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeEnhanced::install(System& system) { + // calculate bank switching and RAM sizes and masks + myBankSize = 1 << myBankShift; // e.g. = 2 ^ 12 = 4K = 0x1000 + myBankMask = myBankSize - 1; // e.g. = 0x0FFF + myBankSegs = 1 << (12 - myBankShift); // e.g. = 1 + myRamMask = myRamSize - 1; // e.g. = 0xFFFF (doesn't matter for RAM size 0) + // Allocate array for the current bank segments slices - myCurrentBankOffset = make_unique(BANK_SEGS); - std::fill_n(myCurrentBankOffset.get(), BANK_SEGS, 0); + myCurrentSegOffset = make_unique(myBankSegs); // Allocate array for the RAM area myRAM = make_unique(myRamSize); @@ -93,24 +98,22 @@ void CartridgeEnhanced::reset() uInt8 CartridgeEnhanced::peek(uInt16 address) { uInt16 peekAddress = address; - address &= myBankMask; - checkSwitchBank(address); + checkSwitchBank(address & 0x0FFF); + address &= myBankMask; if(address < myRamSize) // Write port is at 0xF000 - 0xF07F (128 bytes) return peekRAM(myRAM[address], peekAddress); else - return myImage[myBankOffset + address]; - return myImage[myCurrentBankOffset[address >> BANK_SHIFT] + (address & BANK_MASK)]; + //return myImage[myBankOffset + address]; + return myImage[myCurrentSegOffset[(peekAddress & 0xFFF) >> myBankShift] + address]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeEnhanced::poke(uInt16 address, uInt8 value) { - address &= myBankMask; - // Switch banks if necessary - if (checkSwitchBank(address & myBankMask)) + if (checkSwitchBank(address & 0x0FFF)) return false; if(myRamSize) @@ -133,45 +136,34 @@ bool CartridgeEnhanced::poke(uInt16 address, uInt8 value) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeEnhanced::bank(uInt16 bank, uInt16 slice) +bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) { if(bankLocked()) return false; - // Remember what bank we're in - myBankOffset = bank << myBankShift; - + // Remember what bank is in which segment + uInt32 bankOffset = myCurrentSegOffset[segment] = bank << myBankShift; + uInt16 segmentOffset = segment << myBankShift; uInt16 romHotspot = this->romHotspot(); - uInt16 fromAddr = 0x1000 + myRamSize * 2; - uInt16 toAddr; + uInt16 hotSpotAddr; + uInt16 fromAddr = (segmentOffset + 0x1000 + myRamSize * 2) & ~System::PAGE_MASK; + uInt16 toAddr = (segmentOffset + 0x1000 + myBankSize) & ~System::PAGE_MASK; if(romHotspot) - { - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page accessing methods for the hot spots - for(uInt16 addr = (romHotspot & ~System::PAGE_MASK); addr < 0x1000 + myBankSize; - addr += System::PAGE_SIZE) - { - uInt16 offset = myBankOffset + (addr & myBankMask); - access.romAccessBase = &myRomAccessBase[offset]; - access.romPeekCounter = &myRomAccessCounter[offset]; - access.romPokeCounter = &myRomAccessCounter[offset + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - toAddr = romHotspot; - } + hotSpotAddr = segmentOffset + (romHotspot & ~System::PAGE_MASK); else - toAddr = 0x1000 + myBankSize; + hotSpotAddr = 0xFFFF; // none System::PageAccess access(this, System::PageAccessType::READ); // Setup the page access methods for the current bank - for(uInt16 addr = (fromAddr & ~System::PAGE_MASK); addr < (toAddr & ~System::PAGE_MASK); - addr += System::PAGE_SIZE) + for(uInt16 addr = fromAddr; addr < toAddr; addr += System::PAGE_SIZE) { - uInt16 offset = myBankOffset + (addr & myBankMask); - if(myDirectPeek) + uInt32 offset = bankOffset + (addr & myBankMask); + + if(myDirectPeek && addr != hotSpotAddr) access.directPeekBase = &myImage[offset]; + else + access.directPeekBase = nullptr; access.romAccessBase = &myRomAccessBase[offset]; access.romPeekCounter = &myRomAccessCounter[offset]; access.romPokeCounter = &myRomAccessCounter[offset + myAccessSize]; @@ -182,9 +174,9 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 slice) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeEnhanced::getBank(uInt16) const +uInt16 CartridgeEnhanced::getBank(uInt16 address) const { - return myBankOffset >> myBankShift; + return myCurrentSegOffset[(address & 0xFFF) >> myBankShift] >> myBankShift; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -196,9 +188,7 @@ uInt16 CartridgeEnhanced::bankCount() const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeEnhanced::patch(uInt16 address, uInt8 value) { - address &= myBankMask; - - if(address < myRamSize * 2) + if((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 @@ -206,7 +196,7 @@ bool CartridgeEnhanced::patch(uInt16 address, uInt8 value) myRAM[address & myRamMask] = value; } else - myImage[myBankOffset + address] = value; + myImage[myCurrentSegOffset[(address & 0xFFF) >> myBankShift] + (address & myBankMask)] = value; return myBankChanged = true; } @@ -223,7 +213,7 @@ bool CartridgeEnhanced::save(Serializer& out) const { try { - out.putShort(myBankOffset); + out.putIntArray(myCurrentSegOffset.get(), myBankSegs); if(myRamSize) out.putByteArray(myRAM.get(), myRamSize); @@ -242,7 +232,7 @@ bool CartridgeEnhanced::load(Serializer& in) { try { - myBankOffset = in.getShort(); + in.getIntArray(myCurrentSegOffset.get(), myBankSegs); if(myRamSize) in.getByteArray(myRAM.get(), myRamSize); } @@ -251,9 +241,5 @@ bool CartridgeEnhanced::load(Serializer& in) cerr << "ERROR: " << name() << "::load" << endl; return false; } - - // Remember what bank we were in - bank(myBankOffset >> myBankShift); - return true; } diff --git a/src/emucore/CartEnhanced.hxx b/src/emucore/CartEnhanced.hxx index 22d253b6a..b8511ac29 100644 --- a/src/emucore/CartEnhanced.hxx +++ b/src/emucore/CartEnhanced.hxx @@ -63,7 +63,7 @@ class CartridgeEnhanced : public Cartridge @param bank The bank that should be installed in the system */ - bool bank(uInt16 bank, uInt16 slice); + bool bank(uInt16 bank, uInt16 segment); /** Install pages for the specified bank in the system. @@ -135,62 +135,71 @@ class CartridgeEnhanced : public Cartridge bool poke(uInt16 address, uInt8 value) override; protected: + // The '2 ^ N = bank segment size' exponent + uInt16 myBankShift{BANK_SHIFT}; // default 12 (-> one 4K segment) + + // The size of a bank's segment + uInt16 myBankSize{0}; + + // The mask for a bank segment + uInt16 myBankMask{0}; + + // The number of segments a bank is split into + uInt16 myBankSegs{0}; + + // The extra RAM size + uInt16 myRamSize{RAM_SIZE}; // default 0 + + // The mask for the extra RAM + uInt16 myRamMask{0}; // RAM_SIZE - 1, but doesn't matter when RAM_SIZE is 0 + // Pointer to a dynamically allocated ROM image of the cartridge ByteBuffer myImage{nullptr}; + // Contains the offset into the ROM image for each of the bank segments + DWordBuffer myCurrentSegOffset{nullptr}; + + // Indicates whether to use direct ROM peeks or not + bool myDirectPeek{true}; + // Pointer to a dynamically allocated RAM area of the cartridge ByteBuffer myRAM{nullptr}; - uInt16 myBankShift{BANK_SHIFT}; - - uInt16 myBankSize{BANK_SIZE}; - - uInt16 myBankMask{BANK_MASK}; - - uInt16 myRamSize{RAM_SIZE}; - - uInt16 myRamMask{RAM_MASK}; - - bool myDirectPeek{true}; - - // Indicates the offset into the ROM image (aligns to current bank) - uInt16 myBankOffset{0}; - - // Indicates the slice mapped into each of the bank segments - WordBuffer myCurrentBankOffset{nullptr}; - private: - // log(ROM bank size) / log(2) - static constexpr uInt16 BANK_SHIFT = 12; + // Calculated as: log(ROM bank segment size) / log(2) + static constexpr uInt16 BANK_SHIFT = 12; // default = 4K - // bank size - static constexpr uInt16 BANK_SIZE = 1 << BANK_SHIFT; // 2 ^ 12 = 4K + // The size of extra RAM in ROM address space + static constexpr uInt16 RAM_SIZE = 0; // default = none - // bank mask - static constexpr uInt16 BANK_MASK = BANK_SIZE - 1; - - // bank segments - static constexpr uInt16 BANK_SEGS = 1; - - // RAM size - static constexpr uInt16 RAM_SIZE = 0; - - // RAM mask - static constexpr uInt16 RAM_MASK = 0; - - // Size of the ROM image + // The size of the ROM image size_t mySize{0}; protected: /** Check hotspots and switch bank if triggered. + + @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; private: + /** + Get the ROM's startup bank. + + @return The bank the ROM will start in + */ virtual uInt16 getStartBank() const { return 0; } + /** + Get the hotspot in ROM address space. + + @return The first hotspot address in ROM space or 0 + */ virtual uInt16 romHotspot() const { return 0; } + // TODO: handle cases where there the hotspots cover multiple pages private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartF0.hxx b/src/emucore/CartF0.hxx index 07123bf34..fc8d62939 100644 --- a/src/emucore/CartF0.hxx +++ b/src/emucore/CartF0.hxx @@ -67,12 +67,11 @@ class CartridgeF0 : public CartridgeEnhanced } #endif - protected: + private: bool checkSwitchBank(uInt16 address, uInt8 value = 0); uInt16 romHotspot() const override { return 0x1FF0; } - private: uInt16 getStartBank() const override { return 15; } private: diff --git a/src/emucore/CartF4.hxx b/src/emucore/CartF4.hxx index 3b4f0f141..afe81d0e0 100644 --- a/src/emucore/CartF4.hxx +++ b/src/emucore/CartF4.hxx @@ -66,7 +66,7 @@ class CartridgeF4 : public CartridgeEnhanced } #endif - protected: + private: bool checkSwitchBank(uInt16 address, uInt8 value = 0); uInt16 romHotspot() const override { return 0x1FF4; } diff --git a/src/emucore/CartF4SC.cxx b/src/emucore/CartF4SC.cxx index 5364f2eb4..4fe6e13eb 100644 --- a/src/emucore/CartF4SC.cxx +++ b/src/emucore/CartF4SC.cxx @@ -23,5 +23,5 @@ CartridgeF4SC::CartridgeF4SC(const ByteBuffer& image, size_t size, : CartridgeF4(image, size, md5, settings) { myRamSize = RAM_SIZE; - myRamMask = RAM_MASK; + myRamMask = RAM_SIZE - 1; } diff --git a/src/emucore/CartF6.hxx b/src/emucore/CartF6.hxx index 275727786..2f183ad7b 100644 --- a/src/emucore/CartF6.hxx +++ b/src/emucore/CartF6.hxx @@ -66,7 +66,7 @@ class CartridgeF6 : public CartridgeEnhanced } #endif - protected: + private: bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; uInt16 romHotspot() const override { return 0x1FF6; } diff --git a/src/emucore/CartF6SC.cxx b/src/emucore/CartF6SC.cxx index 034f02bce..15613a357 100644 --- a/src/emucore/CartF6SC.cxx +++ b/src/emucore/CartF6SC.cxx @@ -23,5 +23,5 @@ CartridgeF6SC::CartridgeF6SC(const ByteBuffer& image, size_t size, : CartridgeF6(image, size, md5, settings) { myRamSize = RAM_SIZE; - myRamMask = RAM_MASK; + myRamMask = RAM_SIZE - 1; } diff --git a/src/emucore/CartF8.hxx b/src/emucore/CartF8.hxx index 71e4d6e72..23863fa57 100644 --- a/src/emucore/CartF8.hxx +++ b/src/emucore/CartF8.hxx @@ -66,12 +66,11 @@ class CartridgeF8 : public CartridgeEnhanced } #endif - protected: + private: bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; uInt16 romHotspot() const override { return 0x1FF8; } - private: uInt16 getStartBank() const override { return 1; } private: diff --git a/src/emucore/CartF8SC.cxx b/src/emucore/CartF8SC.cxx index e9dd5bd5c..98ce4357f 100644 --- a/src/emucore/CartF8SC.cxx +++ b/src/emucore/CartF8SC.cxx @@ -23,5 +23,4 @@ CartridgeF8SC::CartridgeF8SC(const ByteBuffer& image, size_t size, : CartridgeF8(image, size, md5, settings) { myRamSize = RAM_SIZE; - myRamMask = RAM_MASK; } diff --git a/src/emucore/CartF8SC.hxx b/src/emucore/CartF8SC.hxx index 9ec8209c4..25fe0dfe3 100644 --- a/src/emucore/CartF8SC.hxx +++ b/src/emucore/CartF8SC.hxx @@ -71,9 +71,6 @@ class CartridgeF8SC : public CartridgeF8 // RAM size static constexpr uInt16 RAM_SIZE = 0x80; - // RAM mask - static constexpr uInt16 RAM_MASK = RAM_SIZE - 1; - private: // Following constructors and assignment operators not supported CartridgeF8SC() = delete; diff --git a/src/emucore/CartFC.hxx b/src/emucore/CartFC.hxx index c1987a189..b08f2085c 100644 --- a/src/emucore/CartFC.hxx +++ b/src/emucore/CartFC.hxx @@ -87,12 +87,11 @@ class CartridgeFC : public CartridgeEnhanced */ bool poke(uInt16 address, uInt8 value) override; - protected: + private: bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; uInt16 romHotspot() const override { return 0x1FF8; } - private: // Target bank defined by writing to $1FF8/9 uInt16 myTargetBank{0}; diff --git a/src/emucore/CartFE.cxx b/src/emucore/CartFE.cxx index 1837c7b88..3a07730e0 100644 --- a/src/emucore/CartFE.cxx +++ b/src/emucore/CartFE.cxx @@ -37,7 +37,7 @@ void CartridgeFE::reset() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFE::install(System& system) { - mySystem = &system; + CartridgeEnhanced::install(system); // The hotspot $01FE is in a mirror of zero-page RAM // We need to claim access to it here, and deal with it in peek/poke below @@ -63,7 +63,7 @@ bool CartridgeFE::checkSwitchBank(uInt16 address, uInt8 value) uInt8 CartridgeFE::peek(uInt16 address) { uInt8 value = (address < 0x200) ? mySystem->m6532().peek(address) : - myImage[myBankOffset + (address & myBankMask)]; + myImage[myCurrentSegOffset[(address & 0xFFF) >> myBankShift] + (address & myBankMask)]; // Check if we hit hotspot checkSwitchBank(address, value); diff --git a/src/emucore/CartFE.hxx b/src/emucore/CartFE.hxx index 18361faf0..3132704cd 100644 --- a/src/emucore/CartFE.hxx +++ b/src/emucore/CartFE.hxx @@ -72,8 +72,8 @@ class System; particular *why* the address $01FE will be placed on the address bus after both the JSR and RTS opcodes. - @author Stephen Anthony; with ideas/research from Christian Speckner and - alex_79 and TomSon (of AtariAge) + @author Stephen Anthony, Thomas Jentzsch; with ideas/research from Christian + Speckner and alex_79 and TomSon (of AtariAge) */ class CartridgeFE : public CartridgeEnhanced { diff --git a/src/emucore/CartUA.cxx b/src/emucore/CartUA.cxx index 4fd5a5410..74ccc3773 100644 --- a/src/emucore/CartUA.cxx +++ b/src/emucore/CartUA.cxx @@ -30,7 +30,7 @@ CartridgeUA::CartridgeUA(const ByteBuffer& image, size_t size, // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeUA::install(System& system) { - mySystem = &system; + CartridgeEnhanced::install(system); // Get the page accessing methods for the hot spots since they overlap // areas within the TIA we'll need to forward requests to the TIA diff --git a/src/emucore/CartUA.hxx b/src/emucore/CartUA.hxx index 66fe82ec8..94dcb4a98 100644 --- a/src/emucore/CartUA.hxx +++ b/src/emucore/CartUA.hxx @@ -97,7 +97,7 @@ class CartridgeUA : public CartridgeEnhanced bool poke(uInt16 address, uInt8 value) override; - protected: + private: bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; private: From 4c8549fc14134f2e816f48aa8bce0d935c484281 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 4 Apr 2020 11:25:02 +0200 Subject: [PATCH 085/377] allow changing default ROM path directly in launcher (resolves #610) --- src/gui/LauncherDialog.cxx | 69 ++++++++++++++++++++++++++------------ src/gui/LauncherDialog.hxx | 11 +++--- 2 files changed, 54 insertions(+), 26 deletions(-) diff --git a/src/gui/LauncherDialog.cxx b/src/gui/LauncherDialog.cxx index 2bad88ef0..2e79307a8 100644 --- a/src/gui/LauncherDialog.cxx +++ b/src/gui/LauncherDialog.cxx @@ -66,7 +66,7 @@ LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent, const int fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(), lineHeight = font.getLineHeight(), - bwidth = (_w - 2 * HBORDER - BUTTON_GAP * (4 - 1)), + bwidth = (_w - 2 * HBORDER - BUTTON_GAP * (5 - 1)), bheight = myUseMinimalUI ? lineHeight - 4 : lineHeight + 4, LBL_GAP = fontWidth; int xpos = 0, ypos = 0, lwidth = 0, lwidth2 = 0; @@ -176,35 +176,50 @@ LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent, // Add four buttons at the bottom xpos = HBORDER; ypos += myDir->getHeight() + 8; #ifndef BSPF_MACOS - myStartButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 0) / 4, bheight, + myStartButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 0) / 5, bheight, "Select", kLoadROMCmd); wid.push_back(myStartButton); - xpos += (bwidth + 0) / 4 + BUTTON_GAP; - myPrevDirButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 1) / 4, bheight, + + xpos += (bwidth + 0) / 5 + BUTTON_GAP; + myPrevDirButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 1) / 5, bheight, "Go Up", kPrevDirCmd); wid.push_back(myPrevDirButton); - xpos += (bwidth + 1) / 4 + BUTTON_GAP; - myOptionsButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 2) / 4, bheight, - "Options" + ELLIPSIS, kOptionsCmd); - wid.push_back(myOptionsButton); - xpos += (bwidth + 2) / 4 + BUTTON_GAP; - myQuitButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 3) / 4, bheight, - "Quit", kQuitCmd); - wid.push_back(myQuitButton); - #else - myQuitButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 0) / 4, bheight, - "Quit", kQuitCmd); - wid.push_back(myQuitButton); - xpos += (bwidth + 0) / 4 + BUTTON_GAP; - myOptionsButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 1) / 4, bheight, + + xpos += (bwidth + 1) / 5 + BUTTON_GAP; + mySetDefaultDirButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 2) / 5, bheight, + "Set Path", kDefaultDirCmd); + wid.push_back(mySetDefaultDirButton); + + xpos += (bwidth + 2) / 5 + BUTTON_GAP; + myOptionsButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 3) / 5, bheight, "Options" + ELLIPSIS, kOptionsCmd); wid.push_back(myOptionsButton); - xpos += (bwidth + 1) / 4 + BUTTON_GAP; - myPrevDirButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 2) / 4, bheight, + + xpos += (bwidth + 3) / 5 + BUTTON_GAP; + myQuitButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 4) / 5, bheight, + "Quit", kQuitCmd); + wid.push_back(myQuitButton); + #else + myQuitButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 0) / 5, bheight, + "Quit", kQuitCmd); + wid.push_back(myQuitButton); + + xpos += (bwidth + 0) / 5 + BUTTON_GAP; + myOptionsButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 1) / 5, bheight, + "Options" + ELLIPSIS, kOptionsCmd); + wid.push_back(myOptionsButton); + + xpos += (bwidth + 1) / 5 + BUTTON_GAP; + mySetDefaultDirButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 2) / 5, bheight, + "Set Path", kDefaultDirCmd); + + xpos += (bwidth + 2) / 5 + BUTTON_GAP; + myPrevDirButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 3) / 5, bheight, "Go Up", kPrevDirCmd); wid.push_back(myPrevDirButton); - xpos += (bwidth + 2) / 4 + BUTTON_GAP; - myStartButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 3) / 4, bheight, + + xpos += (bwidth + 3) / 5 + BUTTON_GAP; + myStartButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 4) / 5, bheight, "Select", kLoadROMCmd); wid.push_back(myStartButton); #endif @@ -582,6 +597,10 @@ void LauncherDialog::handleCommand(CommandSender* sender, int cmd, myList->selectParent(); break; + case kDefaultDirCmd: + setDefaultDir(); + break; + case FileListWidget::ItemChanged: updateUI(); break; @@ -637,6 +656,12 @@ void LauncherDialog::loadRom() instance().frameBuffer().showMessage(result, MessagePosition::MiddleCenter, true); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void LauncherDialog::setDefaultDir() +{ + instance().settings().setValue("romdir", myList->currentDir().getShortPath()); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LauncherDialog::openSettings() { diff --git a/src/gui/LauncherDialog.hxx b/src/gui/LauncherDialog.hxx index d734cdba5..6c03cd18d 100644 --- a/src/gui/LauncherDialog.hxx +++ b/src/gui/LauncherDialog.hxx @@ -117,6 +117,7 @@ class LauncherDialog : public Dialog void loadRomInfo(); void handleContextMenu(); void showOnlyROMs(bool state); + void setDefaultDir(); void openSettings(); private: @@ -131,6 +132,7 @@ class LauncherDialog : public Dialog ButtonWidget* myStartButton{nullptr}; ButtonWidget* myPrevDirButton{nullptr}; + ButtonWidget* mySetDefaultDirButton{nullptr}; ButtonWidget* myOptionsButton{nullptr}; ButtonWidget* myQuitButton{nullptr}; @@ -151,10 +153,11 @@ class LauncherDialog : public Dialog bool myEventHandled{false}; enum { - kAllfilesCmd = 'lalf', // show all files (or ROMs only) - kPrevDirCmd = 'PRVD', - kOptionsCmd = 'OPTI', - kQuitCmd = 'QUIT' + kAllfilesCmd = 'lalf', // show all files (or ROMs only) + kPrevDirCmd = 'PRVD', + kDefaultDirCmd = 'DEFD', + kOptionsCmd = 'OPTI', + kQuitCmd = 'QUIT' }; private: From 7e2ccf6d99223910c1dd16bb13871a1671fbc0d8 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 4 Apr 2020 17:28:30 +0200 Subject: [PATCH 086/377] refactor Cart3F improve CartEnhanced for segmented types --- src/debugger/gui/Cart3FWidget.cxx | 2 +- src/emucore/Cart3F.cxx | 163 ++---------------------------- src/emucore/Cart3F.hxx | 88 ++-------------- src/emucore/CartE0.cxx | 37 ------- src/emucore/CartE0.hxx | 8 -- src/emucore/CartEnhanced.cxx | 15 +-- src/emucore/CartEnhanced.hxx | 6 +- 7 files changed, 28 insertions(+), 291 deletions(-) diff --git a/src/debugger/gui/Cart3FWidget.cxx b/src/debugger/gui/Cart3FWidget.cxx index 223e56cc0..ab5a48761 100644 --- a/src/debugger/gui/Cart3FWidget.cxx +++ b/src/debugger/gui/Cart3FWidget.cxx @@ -88,7 +88,7 @@ string Cartridge3FWidget::bankState() { ostringstream& buf = buffer(); - buf << "Bank = #" << std::dec << myCart.myCurrentBank << ", hotspot = $3F"; + buf << "Bank = #" << std::dec << (myCart.myCurrentSegOffset[0] >> myCart.myBankShift) << ", hotspot = $3F"; return buf.str(); } diff --git a/src/emucore/Cart3F.cxx b/src/emucore/Cart3F.cxx index 2989e88ff..7c3701c16 100644 --- a/src/emucore/Cart3F.cxx +++ b/src/emucore/Cart3F.cxx @@ -22,177 +22,32 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge3F::Cartridge3F(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5), - mySize(size) + : CartridgeEnhanced(image, size, md5, settings) { - // Allocate array for the ROM image - myImage = make_unique(mySize); - - // Copy the ROM image into my buffer - std::copy_n(image.get(), mySize, myImage.get()); - createRomAccessArrays(mySize); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge3F::reset() -{ - initializeStartBank(bankCount() - 1); - - bank(startBank()); + myBankShift = BANK_SHIFT; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3F::install(System& system) { - mySystem = &system; + CartridgeEnhanced::install(system); System::PageAccess access(this, System::PageAccessType::READWRITE); // The hotspot ($3F) is in TIA address space, so we claim it here for(uInt16 addr = 0x00; addr < 0x40; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); - - // Setup the second segment to always point to the last ROM slice - access.type = System::PageAccessType::READ; - for(uInt16 addr = 0x1800; addr < 0x2000; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[(mySize - 2048) + (addr & 0x07FF)]; - access.romAccessBase = &myRomAccessBase[(mySize - 2048) + (addr & 0x07FF)]; - access.romPeekCounter = &myRomAccessCounter[(mySize - 2048) + (addr & 0x07FF)]; - access.romPokeCounter = &myRomAccessCounter[(mySize - 2048) + (addr & 0x07FF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - bank(startBank()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 Cartridge3F::peek(uInt16 address) +bool Cartridge3F::checkSwitchBank(uInt16 address, uInt8 value) { - address &= 0x0FFF; - - if(address < 0x0800) - return myImage[(address & 0x07FF) + (myCurrentBank << 11)]; - else - return myImage[(address & 0x07FF) + mySize - 2048]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Cartridge3F::poke(uInt16 address, uInt8 value) -{ - address &= 0x0FFF; - // Switch banks if necessary if(address <= 0x003F) - bank(value); - - // Handle TIA space that we claimed above - mySystem->tia().poke(address, value); - + { + // Make sure the bank they're asking for is reasonable + bank(value % bankCount(), 0); + return true; + } return false; } - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Cartridge3F::bank(uInt16 bank) -{ - if(bankLocked()) - return false; - - // Make sure the bank they're asking for is reasonable - if((uInt32(bank) << 11) < mySize) - { - myCurrentBank = bank; - } - else - { - // Oops, the bank they're asking for isn't valid so let's wrap it - // around to a valid bank number - myCurrentBank = bank % (mySize >> 11); - } - - uInt32 offset = myCurrentBank << 11; - - // Setup the page access methods for the current bank - System::PageAccess access(this, System::PageAccessType::READ); - - // Map ROM image into the system - for(uInt16 addr = 0x1000; addr < 0x1800; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[offset + (addr & 0x07FF)]; - access.romAccessBase = &myRomAccessBase[offset + (addr & 0x07FF)]; - access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x07FF)]; - access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x07FF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 Cartridge3F::getBank(uInt16 address) const -{ - if (address & 0x800) - return uInt16((mySize >> 11) - 1); // 2K slices, fixed bank - else - return myCurrentBank; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 Cartridge3F::bankCount() const -{ - return uInt16(mySize >> 11); // 2K slices -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Cartridge3F::patch(uInt16 address, uInt8 value) -{ - address &= 0x0FFF; - - if(address < 0x0800) - myImage[(address & 0x07FF) + (myCurrentBank << 11)] = value; - else - myImage[(address & 0x07FF) + mySize - 2048] = value; - - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* Cartridge3F::getImage(size_t& size) const -{ - size = mySize; - return myImage.get(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Cartridge3F::save(Serializer& out) const -{ - try - { - out.putShort(myCurrentBank); - } - catch(...) - { - cerr << "ERROR: Cartridge3F::save" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Cartridge3F::load(Serializer& in) -{ - try - { - myCurrentBank = in.getShort(); - } - catch(...) - { - cerr << "ERROR: Cartridge3F::load" << endl; - return false; - } - - // Now, go to the current bank - bank(myCurrentBank); - - return true; -} diff --git a/src/emucore/Cart3F.hxx b/src/emucore/Cart3F.hxx index cb75bcd88..53b71427a 100644 --- a/src/emucore/Cart3F.hxx +++ b/src/emucore/Cart3F.hxx @@ -21,7 +21,7 @@ class System; #include "bspf.hxx" -#include "Cart.hxx" +#include "CartEnhanced.hxx" #ifdef DEBUGGER_SUPPORT #include "Cart3FWidget.hxx" #endif @@ -38,7 +38,7 @@ class System; @author Bradford W. Mott */ -class Cartridge3F : public Cartridge +class Cartridge3F : public CartridgeEnhanced { friend class Cartridge3FWidget; @@ -56,11 +56,6 @@ class Cartridge3F : public Cartridge virtual ~Cartridge3F() = default; public: - /** - Reset device to its power-on state - */ - void reset() override; - /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @@ -69,57 +64,6 @@ class Cartridge3F : public Cartridge */ void install(System& system) override; - /** - Install pages for the specified bank in the system. - - @param bank The bank that should be installed in the system - */ - bool bank(uInt16 bank) override; - - /** - Get the current bank. - - @param address The address to use when querying the bank - */ - uInt16 getBank(uInt16 address = 0) const override; - - /** - Query the number of banks supported by the cartridge. - */ - uInt16 bankCount() const override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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). @@ -140,32 +84,12 @@ class Cartridge3F : public Cartridge } #endif - public: - /** - Get the byte at the specified address - - @return The byte at the specified address - */ - uInt8 peek(uInt16 address) override; - - /** - Change the byte at the specified address to the given value - - @param address The address where the value should be stored - @param value The value to be stored at the address - @return True if the poke changed the device address space, else false - */ - bool poke(uInt16 address, uInt8 value) override; + private: + bool checkSwitchBank(uInt16 address, uInt8 value) override; private: - // Pointer to a dynamically allocated ROM image of the cartridge - ByteBuffer myImage; - - // Size of the ROM image - size_t mySize{0}; - - // Indicates which bank is currently active for the first segment - uInt16 myCurrentBank{0}; + // log(ROM bank segment size) / log(2) + static constexpr uInt16 BANK_SHIFT = 11; // = 2K = 0x0800 private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartE0.cxx b/src/emucore/CartE0.cxx index e35917993..97752e447 100644 --- a/src/emucore/CartE0.cxx +++ b/src/emucore/CartE0.cxx @@ -42,46 +42,9 @@ void CartridgeE0::reset() bank(5, 1); bank(6, 2); } - myCurrentSegOffset[3] = (bankCount() - 1) << myBankShift; // fixed - myBankChanged = true; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeE0::install(System& system) -{ - //// Allocate array for the current bank segments slices - //myCurrentSegOffset = make_unique(myBankSegs); - - //// Setup page access - //mySystem = &system; - - CartridgeEnhanced::install(system); - - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page acessing methods for the first part of the last segment - for(uInt16 addr = 0x1C00; addr < static_cast(0x1FE0U & ~System::PAGE_MASK); - addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[0x1C00 + (addr & 0x03FF)]; - access.romAccessBase = &myRomAccessBase[0x1C00 + (addr & 0x03FF)]; - access.romPeekCounter = &myRomAccessCounter[0x1C00 + (addr & 0x03FF)]; - access.romPokeCounter = &myRomAccessCounter[0x1C00 + (addr & 0x03FF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Set the page accessing methods for the hot spots in the last segment - access.directPeekBase = nullptr; - access.romAccessBase = &myRomAccessBase[0x1FC0]; - access.romPeekCounter = &myRomAccessCounter[0x1FC0]; - access.romPokeCounter = &myRomAccessCounter[0x1FC0 + myAccessSize]; - access.type = System::PageAccessType::READ; - for(uInt16 addr = (0x1FE0 & ~System::PAGE_MASK); addr < 0x2000; - addr += System::PAGE_SIZE) - mySystem->setPageAccess(addr, access); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeE0::checkSwitchBank(uInt16 address, uInt8) { diff --git a/src/emucore/CartE0.hxx b/src/emucore/CartE0.hxx index 66dbbba6a..08fc82806 100644 --- a/src/emucore/CartE0.hxx +++ b/src/emucore/CartE0.hxx @@ -64,14 +64,6 @@ class CartridgeE0 : public CartridgeEnhanced */ void reset() override; - /** - Install cartridge in the specified system. Invoked by the system - when the cartridge is attached to it. - - @param system The system the device should install itself in - */ - void install(System& system) override; - /** Get a descriptor for the device name (used in error checking). diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index 0f0472392..0ac9ffadd 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -79,8 +79,11 @@ void CartridgeEnhanced::install(System& system) mySystem->setPageAccess(addr, access); } - // Install pages for the startup bank - bank(startBank()); + // Install pages for the startup bank (TODO: currently only in first bank segment) + bank(startBank(), 0); + if(myBankSegs > 1) + // Setup the last bank segment to always point to the last ROM segment + bank(bankCount() - 1, myBankSegs - 1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -99,13 +102,13 @@ uInt8 CartridgeEnhanced::peek(uInt16 address) { uInt16 peekAddress = address; - checkSwitchBank(address & 0x0FFF); + if (romHotspot()) + checkSwitchBank(address & 0x0FFF); address &= myBankMask; if(address < myRamSize) // Write port is at 0xF000 - 0xF07F (128 bytes) return peekRAM(myRAM[address], peekAddress); else - //return myImage[myBankOffset + address]; return myImage[myCurrentSegOffset[(peekAddress & 0xFFF) >> myBankShift] + address]; } @@ -113,7 +116,7 @@ uInt8 CartridgeEnhanced::peek(uInt16 address) bool CartridgeEnhanced::poke(uInt16 address, uInt8 value) { // Switch banks if necessary - if (checkSwitchBank(address & 0x0FFF)) + if (checkSwitchBank(address & 0x0FFF, value)) return false; if(myRamSize) @@ -149,7 +152,7 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) uInt16 toAddr = (segmentOffset + 0x1000 + myBankSize) & ~System::PAGE_MASK; if(romHotspot) - hotSpotAddr = segmentOffset + (romHotspot & ~System::PAGE_MASK); + hotSpotAddr = (romHotspot & ~System::PAGE_MASK); else hotSpotAddr = 0xFFFF; // none diff --git a/src/emucore/CartEnhanced.hxx b/src/emucore/CartEnhanced.hxx index b8511ac29..4bd45fadd 100644 --- a/src/emucore/CartEnhanced.hxx +++ b/src/emucore/CartEnhanced.hxx @@ -165,6 +165,9 @@ class CartridgeEnhanced : public Cartridge // Pointer to a dynamically allocated RAM area of the cartridge ByteBuffer myRAM{nullptr}; + // The size of the ROM image + size_t mySize{0}; + private: // Calculated as: log(ROM bank segment size) / log(2) static constexpr uInt16 BANK_SHIFT = 12; // default = 4K @@ -172,9 +175,6 @@ class CartridgeEnhanced : public Cartridge // The size of extra RAM in ROM address space static constexpr uInt16 RAM_SIZE = 0; // default = none - // The size of the ROM image - size_t mySize{0}; - protected: /** Check hotspots and switch bank if triggered. From ac5b46ee9746773bb0da3d3569a255bcce5cb704 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sat, 4 Apr 2020 13:39:38 -0230 Subject: [PATCH 087/377] Fixed compilation in Linux. --- src/emucore/CartF0.hxx | 2 +- src/emucore/CartF4.hxx | 2 +- src/emucore/module.mk | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/emucore/CartF0.hxx b/src/emucore/CartF0.hxx index fc8d62939..e885cd934 100644 --- a/src/emucore/CartF0.hxx +++ b/src/emucore/CartF0.hxx @@ -68,7 +68,7 @@ class CartridgeF0 : public CartridgeEnhanced #endif private: - bool checkSwitchBank(uInt16 address, uInt8 value = 0); + bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; uInt16 romHotspot() const override { return 0x1FF0; } diff --git a/src/emucore/CartF4.hxx b/src/emucore/CartF4.hxx index afe81d0e0..5b54af54d 100644 --- a/src/emucore/CartF4.hxx +++ b/src/emucore/CartF4.hxx @@ -67,7 +67,7 @@ class CartridgeF4 : public CartridgeEnhanced #endif private: - bool checkSwitchBank(uInt16 address, uInt8 value = 0); + bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; uInt16 romHotspot() const override { return 0x1FF4; } diff --git a/src/emucore/module.mk b/src/emucore/module.mk index e02fcdc2d..bbdd5eaab 100644 --- a/src/emucore/module.mk +++ b/src/emucore/module.mk @@ -6,6 +6,7 @@ MODULE_OBJS := \ src/emucore/Booster.o \ src/emucore/Cart.o \ src/emucore/CartDetector.o \ + src/emucore/CartEnhanced.o \ src/emucore/Cart0840.o \ src/emucore/Cart2K.o \ src/emucore/Cart3E.o \ From 6e06da11618bd4c7a02c7db25ed8fbe05fa10d5b Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 4 Apr 2020 18:29:05 +0200 Subject: [PATCH 088/377] add get current segment from cart for debug widgets --- src/debugger/gui/Cart3FWidget.cxx | 7 ++++--- src/debugger/gui/CartE0Widget.cxx | 12 ++++++------ src/emucore/Cart3F.hxx | 2 +- src/emucore/CartEnhanced.cxx | 6 ++++++ src/emucore/CartEnhanced.hxx | 13 ++++++++++--- 5 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/debugger/gui/Cart3FWidget.cxx b/src/debugger/gui/Cart3FWidget.cxx index ab5a48761..86d43177b 100644 --- a/src/debugger/gui/Cart3FWidget.cxx +++ b/src/debugger/gui/Cart3FWidget.cxx @@ -26,9 +26,10 @@ Cartridge3FWidget::Cartridge3FWidget( : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { - size_t size = cart.mySize; - ostringstream info; + size_t size; + + cart.getImage(size); info << "Tigervision 3F cartridge, 2-256 2K banks\n" << "Startup bank = " << cart.startBank() << " or undetermined\n" << "First 2K bank selected by writing to $3F\n" @@ -88,7 +89,7 @@ string Cartridge3FWidget::bankState() { ostringstream& buf = buffer(); - buf << "Bank = #" << std::dec << (myCart.myCurrentSegOffset[0] >> myCart.myBankShift) << ", hotspot = $3F"; + buf << "Bank = #" << std::dec << myCart.getSegmentBank() << ", hotspot = $3F"; return buf.str(); } diff --git a/src/debugger/gui/CartE0Widget.cxx b/src/debugger/gui/CartE0Widget.cxx index bdce56fdb..861c99228 100644 --- a/src/debugger/gui/CartE0Widget.cxx +++ b/src/debugger/gui/CartE0Widget.cxx @@ -98,9 +98,9 @@ CartridgeE0Widget::CartridgeE0Widget( // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeE0Widget::loadConfig() { - mySlice0->setSelectedIndex(myCart.myCurrentSegOffset[0] >> myCart.myBankShift); - mySlice1->setSelectedIndex(myCart.myCurrentSegOffset[1] >> myCart.myBankShift); - mySlice2->setSelectedIndex(myCart.myCurrentSegOffset[2] >> myCart.myBankShift); + mySlice0->setSelectedIndex(myCart.getSegmentBank(0)); + mySlice1->setSelectedIndex(myCart.getSegmentBank(1)); + mySlice2->setSelectedIndex(myCart.getSegmentBank(2)); CartDebugWidget::loadConfig(); } @@ -136,9 +136,9 @@ string CartridgeE0Widget::bankState() ostringstream& buf = buffer(); buf << "Slices: " << std::dec - << seg0[myCart.myCurrentSegOffset[0] >> myCart.myBankShift] << " / " - << seg1[myCart.myCurrentSegOffset[1] >> myCart.myBankShift] << " / " - << seg2[myCart.myCurrentSegOffset[2] >> myCart.myBankShift]; + << seg0[myCart.getSegmentBank(0)] << " / " + << seg1[myCart.getSegmentBank(1)] << " / " + << seg2[myCart.getSegmentBank(2)]; return buf.str(); } diff --git a/src/emucore/Cart3F.hxx b/src/emucore/Cart3F.hxx index 53b71427a..d9f3e9fa6 100644 --- a/src/emucore/Cart3F.hxx +++ b/src/emucore/Cart3F.hxx @@ -36,7 +36,7 @@ class System; $00 to $3F will change banks. Although, the Tigervision games only used 8K this bankswitching scheme supports up to 512K. - @author Bradford W. Mott + @author Bradford W. Mott, Thomas Jentzsch */ class Cartridge3F : public CartridgeEnhanced { diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index 0ac9ffadd..adcd8bc0e 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -182,6 +182,12 @@ uInt16 CartridgeEnhanced::getBank(uInt16 address) const return myCurrentSegOffset[(address & 0xFFF) >> myBankShift] >> myBankShift; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt16 CartridgeEnhanced::getSegmentBank(uInt16 segment) const +{ + return myCurrentSegOffset[segment % myBankSegs] >> myBankShift; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeEnhanced::bankCount() const { diff --git a/src/emucore/CartEnhanced.hxx b/src/emucore/CartEnhanced.hxx index 4bd45fadd..703cd320f 100644 --- a/src/emucore/CartEnhanced.hxx +++ b/src/emucore/CartEnhanced.hxx @@ -79,6 +79,13 @@ class CartridgeEnhanced : public Cartridge */ uInt16 getBank(uInt16 address = 0) const override; + /** + Get the current bank for a bank segment. + + @param segment The segment to get the bank for + */ + uInt16 getSegmentBank(uInt16 segment = 0) const; + /** Query the number of banks supported by the cartridge. */ @@ -165,9 +172,6 @@ class CartridgeEnhanced : public Cartridge // Pointer to a dynamically allocated RAM area of the cartridge ByteBuffer myRAM{nullptr}; - // The size of the ROM image - size_t mySize{0}; - private: // Calculated as: log(ROM bank segment size) / log(2) static constexpr uInt16 BANK_SHIFT = 12; // default = 4K @@ -175,6 +179,9 @@ class CartridgeEnhanced : public Cartridge // The size of extra RAM in ROM address space static constexpr uInt16 RAM_SIZE = 0; // default = none + // The size of the ROM image + size_t mySize{0}; + protected: /** Check hotspots and switch bank if triggered. From 706d82e75c4dd9334e863255e28874f326c6f982 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 4 Apr 2020 23:04:41 +0200 Subject: [PATCH 089/377] refactor Cart0840 --- src/emucore/Cart0840.cxx | 158 ++++++----------------------------- src/emucore/Cart0840.hxx | 70 ++-------------- src/emucore/CartBF.hxx | 2 +- src/emucore/CartDF.hxx | 2 +- src/emucore/CartE0.hxx | 2 +- src/emucore/CartEF.hxx | 2 +- src/emucore/CartEnhanced.cxx | 8 +- src/emucore/CartEnhanced.hxx | 4 +- src/emucore/CartF0.hxx | 2 +- src/emucore/CartF4.hxx | 2 +- src/emucore/CartF6.hxx | 2 +- src/emucore/CartF8.hxx | 2 +- 12 files changed, 45 insertions(+), 211 deletions(-) diff --git a/src/emucore/Cart0840.cxx b/src/emucore/Cart0840.cxx index f10dbb7b2..e071f61a2 100644 --- a/src/emucore/Cart0840.cxx +++ b/src/emucore/Cart0840.cxx @@ -21,25 +21,14 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge0840::Cartridge0840(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5) + : CartridgeEnhanced(image, size, md5, settings) { - // Copy the ROM image into my buffer - std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessArrays(myImage.size()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge0840::reset() -{ - // Upon reset we switch to the startup bank - initializeStartBank(0); - bank(startBank()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge0840::install(System& system) { - mySystem = &system; + CartridgeEnhanced::install(system); // Get the page accessing methods for the hot spots since they overlap // areas within the TIA we'll need to forward requests to the TIA @@ -56,32 +45,34 @@ void Cartridge0840::install(System& system) System::PageAccess access(this, System::PageAccessType::READ); for(uInt16 addr = 0x0800; addr < 0x0FFF; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); +} - // Install pages for bank 0 - bank(startBank()); +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool Cartridge0840::checkSwitchBank(uInt16 address, uInt8) +{ + // Switch banks if necessary + switch(address & 0x1840) + { + case 0x0800: + // Set the current bank to the lower 4k bank + bank(0); + return true; + + case 0x0840: + // Set the current bank to the upper 4k bank + bank(1); + return true; + + default: + break; + } + return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 Cartridge0840::peek(uInt16 address) { - address &= 0x1840; - - // Switch banks if necessary - switch(address) - { - case 0x0800: - // Set the current bank to the lower 4k bank - bank(0); - break; - - case 0x0840: - // Set the current bank to the upper 4k bank - bank(1); - break; - - default: - break; - } + checkSwitchBank(address); // Because of the way we've set up accessing above, we can only // get here when the addresses are from 0x800 - 0xFFF @@ -92,24 +83,7 @@ uInt8 Cartridge0840::peek(uInt16 address) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge0840::poke(uInt16 address, uInt8 value) { - address &= 0x1840; - - // Switch banks if necessary - switch(address) - { - case 0x0800: - // Set the current bank to the lower 4k bank - bank(0); - break; - - case 0x0840: - // Set the current bank to the upper 4k bank - bank(1); - break; - - default: - break; - } + checkSwitchBank(address); // Because of the way accessing is set up, we will may get here by // doing a write to 0x800 - 0xFFF or cart; we ignore the cart write @@ -121,85 +95,3 @@ bool Cartridge0840::poke(uInt16 address, uInt8 value) return false; } - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Cartridge0840::bank(uInt16 bank) -{ - if(bankLocked()) return false; - - // Remember what bank we're in - myBankOffset = bank << 12; - - // Setup the page access methods for the current bank - System::PageAccess access(this, System::PageAccessType::READ); - - // Map ROM image into the system - for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - mySystem->setPageAccess(addr, access); - } - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 Cartridge0840::getBank(uInt16) const -{ - return myBankOffset >> 12; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 Cartridge0840::bankCount() const -{ - return 2; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Cartridge0840::patch(uInt16 address, uInt8 value) -{ - myImage[myBankOffset + (address & 0x0fff)] = value; - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* Cartridge0840::getImage(size_t& size) const -{ - size = myImage.size(); - return myImage.data(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Cartridge0840::save(Serializer& out) const -{ - try - { - out.putShort(myBankOffset); - } - catch(...) - { - cerr << "ERROR: Cartridge0840::save" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Cartridge0840::load(Serializer& in) -{ - try - { - myBankOffset = in.getShort(); - } - catch(...) - { - cerr << "ERROR: Cartridge0840::load" << endl; - return false; - } - - // Remember what bank we were in - bank(myBankOffset); - - return true; -} diff --git a/src/emucore/Cart0840.hxx b/src/emucore/Cart0840.hxx index 87d372f59..af1977485 100644 --- a/src/emucore/Cart0840.hxx +++ b/src/emucore/Cart0840.hxx @@ -19,7 +19,7 @@ #define CARTRIDGE0840_HXX #include "bspf.hxx" -#include "Cart.hxx" +#include "CartEnhanced.hxx" #include "System.hxx" #ifdef DEBUGGER_SUPPORT #include "Cart0840Widget.hxx" @@ -30,9 +30,9 @@ are two 4K banks, which are switched by accessing $0800 (bank 0) and $0840 (bank 1). - @author Fred X. Quimby + @author Fred X. Quimby, Thomas Jentzsch */ -class Cartridge0840 : public Cartridge +class Cartridge0840 : public CartridgeEnhanced { friend class Cartridge0840Widget; @@ -50,11 +50,6 @@ class Cartridge0840 : public Cartridge virtual ~Cartridge0840() = default; public: - /** - Reset device to its power-on state - */ - void reset() override; - /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @@ -63,58 +58,6 @@ class Cartridge0840 : public Cartridge */ void install(System& system) override; - /** - Install pages for the specified bank in the system. - - @param bank The bank that should be installed in the system - */ - bool bank(uInt16 bank) override; - - /** - Get the current bank. - - @param address The address to use when querying the bank - */ - uInt16 getBank(uInt16 address = 0) const override; - - /** - Query the number of banks supported by the cartridge. - */ - uInt16 bankCount() const override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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). @@ -152,12 +95,11 @@ class Cartridge0840 : public Cartridge bool poke(uInt16 address, uInt8 value) override; private: - // The 8K ROM image of the cartridge - std::array myImage; + bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; - // Indicates the offset into the ROM image (aligns to current bank) - uInt16 myBankOffset{0}; + uInt16 hotspot() const override { return 0x0840; } + private: // Previous Device's page access std::array myHotSpotPageAccess; diff --git a/src/emucore/CartBF.hxx b/src/emucore/CartBF.hxx index 08b54d731..23c51f760 100644 --- a/src/emucore/CartBF.hxx +++ b/src/emucore/CartBF.hxx @@ -73,7 +73,7 @@ class CartridgeBF : public CartridgeEnhanced private: bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; - uInt16 romHotspot() const override { return 0x1F80; } + uInt16 hotspot() const override { return 0x1F80; } uInt16 getStartBank() const override { return 1; } diff --git a/src/emucore/CartDF.hxx b/src/emucore/CartDF.hxx index 5b2025285..3c33e8bff 100644 --- a/src/emucore/CartDF.hxx +++ b/src/emucore/CartDF.hxx @@ -73,7 +73,7 @@ class CartridgeDF : public CartridgeEnhanced private: bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; - uInt16 romHotspot() const override { return 0x1FC0; } + uInt16 hotspot() const override { return 0x1FC0; } uInt16 getStartBank() const override { return 15; } diff --git a/src/emucore/CartE0.hxx b/src/emucore/CartE0.hxx index 08fc82806..7c1fe18e3 100644 --- a/src/emucore/CartE0.hxx +++ b/src/emucore/CartE0.hxx @@ -86,7 +86,7 @@ class CartridgeE0 : public CartridgeEnhanced private: bool checkSwitchBank(uInt16 address, uInt8 = 0) override; - uInt16 romHotspot() const override { return 0x1FE0; } + uInt16 hotspot() const override { return 0x1FE0; } private: // log(ROM bank segment size) / log(2) diff --git a/src/emucore/CartEF.hxx b/src/emucore/CartEF.hxx index 1461e954d..ff71b9909 100644 --- a/src/emucore/CartEF.hxx +++ b/src/emucore/CartEF.hxx @@ -73,7 +73,7 @@ class CartridgeEF : public CartridgeEnhanced private: bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; - uInt16 romHotspot() const override { return 0x1FE0; } + uInt16 hotspot() const override { return 0x1FE0; } uInt16 getStartBank() const override { return 1; } diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index adcd8bc0e..a29cdcb6f 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -102,7 +102,7 @@ uInt8 CartridgeEnhanced::peek(uInt16 address) { uInt16 peekAddress = address; - if (romHotspot()) + if (hotspot()) checkSwitchBank(address & 0x0FFF); address &= myBankMask; @@ -146,13 +146,13 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) // Remember what bank is in which segment uInt32 bankOffset = myCurrentSegOffset[segment] = bank << myBankShift; uInt16 segmentOffset = segment << myBankShift; - uInt16 romHotspot = this->romHotspot(); + uInt16 hotspot = this->hotspot(); uInt16 hotSpotAddr; uInt16 fromAddr = (segmentOffset + 0x1000 + myRamSize * 2) & ~System::PAGE_MASK; uInt16 toAddr = (segmentOffset + 0x1000 + myBankSize) & ~System::PAGE_MASK; - if(romHotspot) - hotSpotAddr = (romHotspot & ~System::PAGE_MASK); + if(hotspot) + hotSpotAddr = (hotspot & ~System::PAGE_MASK); else hotSpotAddr = 0xFFFF; // none diff --git a/src/emucore/CartEnhanced.hxx b/src/emucore/CartEnhanced.hxx index 703cd320f..a78b725e7 100644 --- a/src/emucore/CartEnhanced.hxx +++ b/src/emucore/CartEnhanced.hxx @@ -203,9 +203,9 @@ class CartridgeEnhanced : public Cartridge /** Get the hotspot in ROM address space. - @return The first hotspot address in ROM space or 0 + @return The first hotspot address (ususally in ROM) space or 0 */ - virtual uInt16 romHotspot() const { return 0; } + virtual uInt16 hotspot() const { return 0; } // TODO: handle cases where there the hotspots cover multiple pages private: diff --git a/src/emucore/CartF0.hxx b/src/emucore/CartF0.hxx index e885cd934..0d5837066 100644 --- a/src/emucore/CartF0.hxx +++ b/src/emucore/CartF0.hxx @@ -70,7 +70,7 @@ class CartridgeF0 : public CartridgeEnhanced private: bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; - uInt16 romHotspot() const override { return 0x1FF0; } + uInt16 hotspot() const override { return 0x1FF0; } uInt16 getStartBank() const override { return 15; } diff --git a/src/emucore/CartF4.hxx b/src/emucore/CartF4.hxx index 5b54af54d..d44e96640 100644 --- a/src/emucore/CartF4.hxx +++ b/src/emucore/CartF4.hxx @@ -69,7 +69,7 @@ class CartridgeF4 : public CartridgeEnhanced private: bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; - uInt16 romHotspot() const override { return 0x1FF4; } + uInt16 hotspot() const override { return 0x1FF4; } private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartF6.hxx b/src/emucore/CartF6.hxx index 2f183ad7b..16faeebab 100644 --- a/src/emucore/CartF6.hxx +++ b/src/emucore/CartF6.hxx @@ -69,7 +69,7 @@ class CartridgeF6 : public CartridgeEnhanced private: bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; - uInt16 romHotspot() const override { return 0x1FF6; } + uInt16 hotspot() const override { return 0x1FF6; } private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartF8.hxx b/src/emucore/CartF8.hxx index 23863fa57..29b308808 100644 --- a/src/emucore/CartF8.hxx +++ b/src/emucore/CartF8.hxx @@ -69,7 +69,7 @@ class CartridgeF8 : public CartridgeEnhanced private: bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; - uInt16 romHotspot() const override { return 0x1FF8; } + uInt16 hotspot() const override { return 0x1FF8; } uInt16 getStartBank() const override { return 1; } From f2c464a71faca8bd48c8cf0facc9a2bc87b674aa Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 4 Apr 2020 23:05:09 +0200 Subject: [PATCH 090/377] one missing file --- src/emucore/CartFC.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/emucore/CartFC.hxx b/src/emucore/CartFC.hxx index b08f2085c..5858ae85a 100644 --- a/src/emucore/CartFC.hxx +++ b/src/emucore/CartFC.hxx @@ -90,7 +90,7 @@ class CartridgeFC : public CartridgeEnhanced private: bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; - uInt16 romHotspot() const override { return 0x1FF8; } + uInt16 hotspot() const override { return 0x1FF8; } // Target bank defined by writing to $1FF8/9 uInt16 myTargetBank{0}; From d9911ce6769f7486f77a38c3248cdf3ce7a80e73 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 5 Apr 2020 19:55:45 +0200 Subject: [PATCH 091/377] add configurable driving controller sensitivity --- Changes.txt | 4 +++- src/emucore/Driving.cxx | 21 +++++++++++++++------ src/emucore/Driving.hxx | 15 ++++++++++++++- src/emucore/EventHandler.cxx | 2 ++ src/emucore/Settings.cxx | 7 +++++++ src/gui/InputDialog.cxx | 32 +++++++++++++++++++++++++++----- src/gui/InputDialog.hxx | 2 ++ 7 files changed, 70 insertions(+), 13 deletions(-) diff --git a/Changes.txt b/Changes.txt index 3ae1dba63..dc28ed6e7 100644 --- a/Changes.txt +++ b/Changes.txt @@ -14,7 +14,9 @@ 6.1 to 6.2: (??? ??, 2020) - * Added that paddle centering and sensitivity can be adjusted now (TOOD: Doc) + * Added that paddle centering and sensitivity can be adjusted (TOOD: Doc) + + * Added that Driving controller sensitivity can be adjusted (TOOD: Doc) * 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 diff --git a/src/emucore/Driving.cxx b/src/emucore/Driving.cxx index 74fa30139..83f27e336 100644 --- a/src/emucore/Driving.cxx +++ b/src/emucore/Driving.cxx @@ -49,10 +49,6 @@ Driving::Driving(Jack jack, const Event& event, const System& system) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Driving::update() { - // Make sure direct gray codes from Stelladaptor stay in sync with - // simulated gray codes generated by PC keyboard or PC joystick - myCounter = (myGrayIndex << 2) | (myCounter & 3); - // Digital events (from keyboard or joystick hats & buttons) setPin(DigitalPin::Six, myEvent.get(myFireEvent) == 0); int d_axis = myEvent.get(myXAxisValue); @@ -92,8 +88,7 @@ void Driving::update() } // Only consider the lower-most bits (corresponding to pins 1 & 2) - myCounter &= 0x0f; - myGrayIndex = myCounter >> 2; + myGrayIndex = Int32(myCounter * SENSITIVITY / 4.0F) & 0b11; // Stelladaptor is the only controller that should set this int yaxis = myEvent.get(myYAxisValue); @@ -111,6 +106,10 @@ void Driving::update() myGrayIndex = 2; // up + down else /* if(yaxis < 16384-4096) */ myGrayIndex = 0; // no movement + + // Make sure direct gray codes from Stelladaptor stay in sync with + // simulated gray codes generated by PC keyboard or PC joystick + myCounter = myGrayIndex / SENSITIVITY * 4.0F; } // Gray codes for rotation @@ -154,3 +153,13 @@ bool Driving::setMouseControl( return true; } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Driving::setSensitivity(int sensitivity) +{ + BSPF::clamp(sensitivity, 1, 20, 10); + SENSITIVITY = sensitivity / 10.0F; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +float Driving::SENSITIVITY = 1.0; diff --git a/src/emucore/Driving.hxx b/src/emucore/Driving.hxx index 51c0226c3..6d0adaea8 100644 --- a/src/emucore/Driving.hxx +++ b/src/emucore/Driving.hxx @@ -76,9 +76,18 @@ class Driving : public Controller bool setMouseControl( Controller::Type xtype, int xid, Controller::Type ytype, int yid) override; + /** + Sets the sensitivity for digital emulation of driving controlle movement + using a keyboard. + + @param sensitivity Value from 1 to 20, with larger values causing + more movement (10 represents the baseline) + */ + static void setSensitivity(int sensitivity); + private: // Counter to iterate through the gray codes - uInt32 myCounter{0}; + Int32 myCounter{0}; // Index into the gray code table uInt32 myGrayIndex{0}; @@ -98,6 +107,10 @@ class Driving : public Controller // Controllers to emulate in 'specific' mouse axis mode int myControlIDX{-1}, myControlIDY{-1}; + // User-defined sensitivity; adjustable since end-users may prefer different + // speeds + static float SENSITIVITY; + private: // Following constructors and assignment operators not supported Driving() = delete; diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 4e6b3712d..4433ed244 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -29,6 +29,7 @@ #include "Paddles.hxx" #include "Lightgun.hxx" #include "PointingDevice.hxx" +#include "Driving.hxx" #include "PropsSet.hxx" #include "Settings.hxx" #include "Sound.hxx" @@ -97,6 +98,7 @@ void EventHandler::initialize() Paddles::setDigitalSensitivity(myOSystem.settings().getInt("dsense")); Paddles::setMouseSensitivity(myOSystem.settings().getInt("msense")); PointingDevice::setSensitivity(myOSystem.settings().getInt("tsense")); + Driving::setSensitivity(myOSystem.settings().getInt("dcsense")); #ifdef GUI_SUPPORT // Set quick select delay when typing characters in listwidgets diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index d4cdb81e8..a5bda6055 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -106,6 +106,7 @@ Settings::Settings() setPermanent("psense", "20"); setPermanent("msense", "10"); setPermanent("tsense", "10"); + setPermanent("dcsense", "10"); setPermanent("saport", "lr"); setPermanent("modcombo", "true"); @@ -339,6 +340,10 @@ void Settings::validate() if(i < 1 || i > 20) setValue("tsense", "10"); + i = getInt("dcsense"); + if(i < 1 || i > 20) + setValue("dcsense", "10"); + i = getInt("ssinterval"); if(i < 1) setValue("ssinterval", "2"); else if(i > 10) setValue("ssinterval", "10"); @@ -457,6 +462,8 @@ void Settings::usage() const << " -dsense <1-20> Sensitivity of digital emulated paddle movement\n" << " -msense <1-20> Sensitivity of mouse emulated paddle movement\n" << " -tsense <1-20> Sensitivity of mouse emulated trackball movement\n" + << " -dcsense <1-20> Sensitivity of digital emulated driving controller\n" + << " movement\n" << " -saport How to assign virtual ports to multiple\n" << " Stelladaptor/2600-daptors\n" << " -modcombo <1|0> Enable modifer key combos\n" diff --git a/src/gui/InputDialog.cxx b/src/gui/InputDialog.cxx index 5931ed44a..e5eaa9057 100644 --- a/src/gui/InputDialog.cxx +++ b/src/gui/InputDialog.cxx @@ -22,6 +22,7 @@ #include "Joystick.hxx" #include "Paddles.hxx" #include "PointingDevice.hxx" +#include "Driving.hxx" #include "SaveKey.hxx" #include "AtariVox.hxx" #include "Settings.hxx" @@ -156,7 +157,7 @@ void InputDialog::addDevicePortTab() wid.push_back(myDejitterDiff); // Add paddle speed (digital emulation) - ypos += lineHeight + VGAP * 4; + ypos += lineHeight + VGAP * 3; myDPaddleSpeed = new SliderWidget(myTab, _font, HBORDER, ypos - 1, 13 * fontWidth, lineHeight, "Digital paddle sensitivity", lwidth, kDPSpeedChanged, 4 * fontWidth, "%"); @@ -165,7 +166,7 @@ void InputDialog::addDevicePortTab() wid.push_back(myDPaddleSpeed); // Add trackball speed - ypos += lineHeight + VGAP * 2; + ypos += lineHeight + VGAP; myTrackBallSpeed = new SliderWidget(myTab, _font, HBORDER, ypos - 1, 13 * fontWidth, lineHeight, "Trackball sensitivity", lwidth, kTBSpeedChanged, 4 * fontWidth, "%"); @@ -173,8 +174,17 @@ void InputDialog::addDevicePortTab() myTrackBallSpeed->setTickmarkIntervals(4); wid.push_back(myTrackBallSpeed); + // Add driving controller speed + ypos += lineHeight + VGAP; + myDrivingSpeed = new SliderWidget(myTab, _font, HBORDER, ypos - 1, 13 * fontWidth, lineHeight, + "Driving contr. sensitivity", + lwidth, kDCSpeedChanged, 4 * fontWidth, "%"); + myDrivingSpeed->setMinValue(1); myDrivingSpeed->setMaxValue(20); + myDrivingSpeed->setTickmarkIntervals(4); + wid.push_back(myDrivingSpeed); + // Add 'allow all 4 directions' for joystick - ypos += lineHeight + VGAP * 4; + ypos += lineHeight + VGAP * 3; myAllowAll4 = new CheckboxWidget(myTab, _font, HBORDER, ypos, "Allow all 4 directions on joystick"); wid.push_back(myAllowAll4); @@ -194,7 +204,7 @@ void InputDialog::addDevicePortTab() int fwidth; // Add EEPROM erase (part 1/2) - ypos += VGAP*4; + ypos += VGAP * 3; fwidth = _font.getStringWidth("AtariVox/SaveKey"); lwidth = _font.getStringWidth("AtariVox/SaveKey"); new StaticTextWidget(myTab, _font, _w - HBORDER - 4 - (fwidth + lwidth) / 2, ypos, @@ -203,7 +213,7 @@ void InputDialog::addDevicePortTab() // Show joystick database ypos += lineHeight; myJoyDlgButton = new ButtonWidget(myTab, _font, HBORDER, ypos, 20, - "Joystick Database" + ELLIPSIS, kDBButtonPressed); + "Joystick Database" + ELLIPSIS, kDBButtonPressed); wid.push_back(myJoyDlgButton); // Add EEPROM erase (part 1/2) @@ -319,6 +329,8 @@ void InputDialog::loadConfig() // Trackball speed myTrackBallSpeed->setValue(instance().settings().getInt("tsense")); + // Driving controller speed + myDrivingSpeed->setValue(instance().settings().getInt("dcsense")); // AtariVox serial port myAVoxPort->setText(instance().settings().getString("avoxport")); @@ -389,6 +401,11 @@ void InputDialog::saveConfig() instance().settings().setValue("tsense", sensitivity); PointingDevice::setSensitivity(sensitivity); + // Driving controller speed + sensitivity = myDrivingSpeed->getValue(); + instance().settings().setValue("dcsense", sensitivity); + Driving::setSensitivity(sensitivity); + // AtariVox serial port instance().settings().setValue("avoxport", myAVoxPort->getText()); @@ -447,6 +464,7 @@ void InputDialog::setDefaults() myDejitterBase->setValue(0); myDejitterDiff->setValue(0); #endif + myDrivingSpeed->setValue(10); myTrackBallSpeed->setValue(10); // AtariVox serial port @@ -621,6 +639,10 @@ void InputDialog::handleCommand(CommandSender* sender, int cmd, myDPaddleSpeed->setValueLabel(myDPaddleSpeed->getValue() * 10); break; + case kDCSpeedChanged: + myDrivingSpeed->setValueLabel(myDrivingSpeed->getValue() * 10); + break; + case kTBSpeedChanged: myTrackBallSpeed->setValueLabel(myTrackBallSpeed->getValue() * 10); break; diff --git a/src/gui/InputDialog.hxx b/src/gui/InputDialog.hxx index 0924f514b..54fde4a91 100644 --- a/src/gui/InputDialog.hxx +++ b/src/gui/InputDialog.hxx @@ -77,6 +77,7 @@ class InputDialog : public Dialog kDejitterReChanged = 'JRch', kDPSpeedChanged = 'PDch', kTBSpeedChanged = 'TBch', + kDCSpeedChanged = 'DCch', kDBButtonPressed = 'DBbp', kEEButtonPressed = 'EEbp', kConfirmEEEraseCmd = 'EEcf', @@ -103,6 +104,7 @@ class InputDialog : public Dialog SliderWidget* myDPaddleSpeed{nullptr}; SliderWidget* myMPaddleSpeed{nullptr}; SliderWidget* myTrackBallSpeed{nullptr}; + SliderWidget* myDrivingSpeed{nullptr}; CheckboxWidget* myAllowAll4{nullptr}; CheckboxWidget* myGrabMouse{nullptr}; CheckboxWidget* myModCombo{nullptr}; From 93e81f180aecc4bdc8981ab92ccebe2e24ed1a3c Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 5 Apr 2020 21:30:38 +0200 Subject: [PATCH 092/377] remove new default path button replace with an UI option, which lets "romdir" automatically follow the launcher path --- src/emucore/Settings.cxx | 2 ++ src/gui/LauncherDialog.cxx | 52 ++++++++++++++++++-------------------- src/gui/LauncherDialog.hxx | 5 ++-- src/gui/UIDialog.cxx | 14 +++++++++- src/gui/UIDialog.hxx | 1 + 5 files changed, 42 insertions(+), 32 deletions(-) diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index a5bda6055..c3feece37 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -125,6 +125,7 @@ Settings::Settings() // ROM browser options setPermanent("exitlauncher", "false"); + setPermanent("followlauncher", "false"); setPermanent("launcherres", Common::Size(900, 600)); setPermanent("launcherfont", "medium"); setPermanent("launcherroms", "true"); @@ -500,6 +501,7 @@ void Settings::usage() const << " -launcherroms <1|0> Show only ROMs in the launcher (vs. all files)\n" << " -romviewer Show ROM info viewer at given zoom level in ROM\n" << " launcher (use 0 for off)\n" + << " -followlauncher <0|1> Default ROM path follows launcher navigation\n" << " -lastrom Last played ROM, automatically selected in\n" << " launcher\n" << " -romloadcount Number of ROM to load next from multicard\n" diff --git a/src/gui/LauncherDialog.cxx b/src/gui/LauncherDialog.cxx index 2e79307a8..fc47f9bbe 100644 --- a/src/gui/LauncherDialog.cxx +++ b/src/gui/LauncherDialog.cxx @@ -66,7 +66,7 @@ LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent, const int fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(), lineHeight = font.getLineHeight(), - bwidth = (_w - 2 * HBORDER - BUTTON_GAP * (5 - 1)), + bwidth = (_w - 2 * HBORDER - BUTTON_GAP * (4 - 1)), bheight = myUseMinimalUI ? lineHeight - 4 : lineHeight + 4, LBL_GAP = fontWidth; int xpos = 0, ypos = 0, lwidth = 0, lwidth2 = 0; @@ -176,50 +176,41 @@ LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent, // Add four buttons at the bottom xpos = HBORDER; ypos += myDir->getHeight() + 8; #ifndef BSPF_MACOS - myStartButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 0) / 5, bheight, + myStartButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 0) / 4, bheight, "Select", kLoadROMCmd); wid.push_back(myStartButton); - xpos += (bwidth + 0) / 5 + BUTTON_GAP; - myPrevDirButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 1) / 5, bheight, + xpos += (bwidth + 0) / 4 + BUTTON_GAP; + myPrevDirButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 1) / 4, bheight, "Go Up", kPrevDirCmd); wid.push_back(myPrevDirButton); - xpos += (bwidth + 1) / 5 + BUTTON_GAP; - mySetDefaultDirButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 2) / 5, bheight, - "Set Path", kDefaultDirCmd); - wid.push_back(mySetDefaultDirButton); - - xpos += (bwidth + 2) / 5 + BUTTON_GAP; - myOptionsButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 3) / 5, bheight, + xpos += (bwidth + 1) / 4 + BUTTON_GAP; + myOptionsButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 3) / 4, bheight, "Options" + ELLIPSIS, kOptionsCmd); wid.push_back(myOptionsButton); - xpos += (bwidth + 3) / 5 + BUTTON_GAP; - myQuitButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 4) / 5, bheight, + xpos += (bwidth + 2) / 4 + BUTTON_GAP; + myQuitButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 4) / 4, bheight, "Quit", kQuitCmd); wid.push_back(myQuitButton); #else - myQuitButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 0) / 5, bheight, + myQuitButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 0) / 4, bheight, "Quit", kQuitCmd); wid.push_back(myQuitButton); - xpos += (bwidth + 0) / 5 + BUTTON_GAP; - myOptionsButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 1) / 5, bheight, + xpos += (bwidth + 0) / 4 + BUTTON_GAP; + myOptionsButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 1) / 4, bheight, "Options" + ELLIPSIS, kOptionsCmd); wid.push_back(myOptionsButton); - xpos += (bwidth + 1) / 5 + BUTTON_GAP; - mySetDefaultDirButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 2) / 5, bheight, - "Set Path", kDefaultDirCmd); - - xpos += (bwidth + 2) / 5 + BUTTON_GAP; - myPrevDirButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 3) / 5, bheight, + xpos += (bwidth + 1) / 4 + BUTTON_GAP; + myPrevDirButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 2) / 4, bheight, "Go Up", kPrevDirCmd); wid.push_back(myPrevDirButton); - xpos += (bwidth + 3) / 5 + BUTTON_GAP; - myStartButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 4) / 5, bheight, + xpos += (bwidth + 2) / 4 + BUTTON_GAP; + myStartButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 3) / 4, bheight, "Select", kLoadROMCmd); wid.push_back(myStartButton); #endif @@ -317,6 +308,13 @@ void LauncherDialog::loadConfig() myList->clearFlags(Widget::FLAG_WANTS_RAWDATA); // always reset this } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void LauncherDialog::saveConfig() +{ + if(instance().settings().getBool("followlauncher")) + instance().settings().setValue("romdir", myList->currentDir().getShortPath()); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LauncherDialog::updateUI() { @@ -586,6 +584,7 @@ void LauncherDialog::handleCommand(CommandSender* sender, int cmd, case kLoadROMCmd: case FileListWidget::ItemActivated: + saveConfig(); loadRom(); break; @@ -597,10 +596,6 @@ void LauncherDialog::handleCommand(CommandSender* sender, int cmd, myList->selectParent(); break; - case kDefaultDirCmd: - setDefaultDir(); - break; - case FileListWidget::ItemChanged: updateUI(); break; @@ -617,6 +612,7 @@ void LauncherDialog::handleCommand(CommandSender* sender, int cmd, break; case kQuitCmd: + saveConfig(); close(); instance().eventHandler().quit(); break; diff --git a/src/gui/LauncherDialog.hxx b/src/gui/LauncherDialog.hxx index 6c03cd18d..dc1058356 100644 --- a/src/gui/LauncherDialog.hxx +++ b/src/gui/LauncherDialog.hxx @@ -107,6 +107,7 @@ class LauncherDialog : public Dialog Event::Type getJoyAxisEvent(int stick, JoyAxis axis, JoyDir adir, int button) override; void loadConfig() override; + void saveConfig() override; void updateUI(); void applyFiltering(); @@ -131,8 +132,7 @@ class LauncherDialog : public Dialog unique_ptr myROMInfoFont; ButtonWidget* myStartButton{nullptr}; - ButtonWidget* myPrevDirButton{nullptr}; - ButtonWidget* mySetDefaultDirButton{nullptr}; + ButtonWidget* myPrevDirButton{nullptr}; ButtonWidget* myOptionsButton{nullptr}; ButtonWidget* myQuitButton{nullptr}; @@ -155,7 +155,6 @@ class LauncherDialog : public Dialog enum { kAllfilesCmd = 'lalf', // show all files (or ROMs only) kPrevDirCmd = 'PRVD', - kDefaultDirCmd = 'DEFD', kOptionsCmd = 'OPTI', kQuitCmd = 'QUIT' }; diff --git a/src/gui/UIDialog.cxx b/src/gui/UIDialog.cxx index 175b8624b..fd52fa483 100644 --- a/src/gui/UIDialog.cxx +++ b/src/gui/UIDialog.cxx @@ -189,8 +189,14 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, myRomPath = new EditTextWidget(myTab, font, xpos, ypos + 1, _w - xpos - HBORDER - 2, lineHeight, ""); wid.push_back(myRomPath); + + xpos = _w - HBORDER - font.getStringWidth("Follow Launcher path") - 24; + ypos += lineHeight + V_GAP * 2; + myFollowLauncherWidget = new CheckboxWidget(myTab, font, xpos, ypos, "Follow Launcher path"); + wid.push_back(myFollowLauncherWidget); + xpos = HBORDER; - ypos += lineHeight + V_GAP * 4; + ypos += V_GAP * 2; // Launcher width and height myLauncherWidthSlider = new SliderWidget(myTab, font, xpos, ypos, "Launcher width ", @@ -309,6 +315,9 @@ void UIDialog::loadConfig() myLauncherWidthSlider->setValue(w); myLauncherHeightSlider->setValue(h); + // Follow Launcher path + myFollowLauncherWidget->setState(settings.getBool("followlauncher")); + // Launcher font const string& font = settings.getString("launcherfont"); myLauncherFontPopup->setSelected(font, "medium"); @@ -379,6 +388,9 @@ void UIDialog::saveConfig() // ROM path settings.setValue("romdir", myRomPath->getText()); + // Follow Launcher path + settings.setValue("followlauncher", myFollowLauncherWidget->getState()); + // Launcher size settings.setValue("launcherres", Common::Size(myLauncherWidthSlider->getValue(), diff --git a/src/gui/UIDialog.hxx b/src/gui/UIDialog.hxx index ff41c7702..4517396d0 100644 --- a/src/gui/UIDialog.hxx +++ b/src/gui/UIDialog.hxx @@ -54,6 +54,7 @@ class UIDialog : public Dialog, public CommandSender // Launcher options EditTextWidget* myRomPath{nullptr}; + CheckboxWidget* myFollowLauncherWidget{nullptr}; SliderWidget* myLauncherWidthSlider{nullptr}; SliderWidget* myLauncherHeightSlider{nullptr}; PopUpWidget* myLauncherFontPopup{nullptr}; From 6994556ef888c1b277146f806373b60375152878 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 5 Apr 2020 22:29:23 +0200 Subject: [PATCH 093/377] update changes.txt --- Changes.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Changes.txt b/Changes.txt index dc28ed6e7..2de2987ee 100644 --- a/Changes.txt +++ b/Changes.txt @@ -14,13 +14,15 @@ 6.1 to 6.2: (??? ??, 2020) - * Added that paddle centering and sensitivity can be adjusted (TOOD: Doc) + * Added that paddle centering and sensitivity can be adjusted (TODO: Doc) - * Added that Driving controller sensitivity can be adjusted (TOOD: Doc) + * Added that Driving controller sensitivity can be adjusted (TODO: Doc) * 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. (TOOD: Doc) + game and variation, the top 10 scores can be saved. (TODO: Doc) + + * Add option which lets default ROM path follow launcher navigation (TODO: Doc) * Added displaying last write address in the debugger. From db522623751f400227074e0399fb5504a99953ca Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 6 Apr 2020 09:21:32 +0200 Subject: [PATCH 094/377] refactor CartMDM make sure the banks are updated when stepping back --- src/debugger/gui/CartMDMWidget.cxx | 5 +- src/emucore/CartEnhanced.cxx | 4 ++ src/emucore/CartMDM.cxx | 90 +++++++----------------------- src/emucore/CartMDM.hxx | 50 ++--------------- 4 files changed, 31 insertions(+), 118 deletions(-) diff --git a/src/debugger/gui/CartMDMWidget.cxx b/src/debugger/gui/CartMDMWidget.cxx index 7b0f799e4..2ba603168 100644 --- a/src/debugger/gui/CartMDMWidget.cxx +++ b/src/debugger/gui/CartMDMWidget.cxx @@ -27,9 +27,10 @@ CartridgeMDMWidget::CartridgeMDMWidget( : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { - size_t size = myCart.mySize; - ostringstream info; + size_t size; + + myCart.getImage(size); info << "Menu Driven Megacart, containing up to 128 4K banks\n" << "Startup bank = " << cart.startBank() << "\n" << "\nBanks are selected by reading from $800 - $BFF, where the lower " diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index a29cdcb6f..4cbf61eca 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -250,5 +250,9 @@ bool CartridgeEnhanced::load(Serializer& in) cerr << "ERROR: " << name() << "::load" << endl; return false; } + // Restore bank sewgments + for(uInt16 i = 0; i < myBankSegs; ++i) + bank(getSegmentBank(i), i); + return true; } diff --git a/src/emucore/CartMDM.cxx b/src/emucore/CartMDM.cxx index 4c69f7c7c..decb634ec 100644 --- a/src/emucore/CartMDM.cxx +++ b/src/emucore/CartMDM.cxx @@ -21,30 +21,14 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeMDM::CartridgeMDM(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5), - mySize(size) + : CartridgeEnhanced(image, size, md5, settings) { - // Allocate array for the ROM image - myImage = make_unique(mySize); - - // Copy the ROM image into my buffer - std::copy_n(image.get(), mySize, myImage.get()); - createRomAccessArrays(mySize); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeMDM::reset() -{ - initializeStartBank(0); - - // Upon reset we switch to the startup bank - bank(startBank()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeMDM::install(System& system) { - mySystem = &system; + CartridgeEnhanced::install(system); // Get the page accessing methods for the hot spots since they overlap // areas within the TIA we'll need to forward requests to the TIA @@ -61,9 +45,18 @@ void CartridgeMDM::install(System& system) System::PageAccess access(this, System::PageAccessType::READWRITE); for(uInt16 addr = 0x0800; addr < 0x0BFF; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); +} - // Install pages for bank 0 - bank(startBank()); +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CartridgeMDM::checkSwitchBank(uInt16 address, uInt8) +{ + // Switch banks if necessary + if((address & 0x1C00) == 0x0800) + { + bank(address & 0x0FF); + return true; + } + return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -71,8 +64,8 @@ uInt8 CartridgeMDM::peek(uInt16 address) { // Because of the way we've set up accessing above, we can only // get here when the addresses are from 0x800 - 0xBFF - if((address & 0x1C00) == 0x0800) - bank(address & 0x0FF); + + checkSwitchBank(address); int hotspot = ((address & 0x0F00) >> 8) - 8; return myHotSpotPageAccess[hotspot].device->peek(address); @@ -85,8 +78,7 @@ bool CartridgeMDM::poke(uInt16 address, uInt8 value) // about those below $1000 if(!(address & 0x1000)) { - if((address & 0x1C00) == 0x0800) - bank(address & 0x0FF); + checkSwitchBank(address); int hotspot = ((address & 0x0F00) >> 8) - 8; myHotSpotPageAccess[hotspot].device->poke(address, value); @@ -100,22 +92,7 @@ bool CartridgeMDM::bank(uInt16 bank) { if(bankLocked() || myBankingDisabled) return false; - // Remember what bank we're in - // Wrap around to a valid bank number if necessary - myBankOffset = (bank % bankCount()) << 12; - - // Setup the page access methods for the current bank - System::PageAccess access(this, System::PageAccessType::READ); - - // Map ROM image into the system - for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } + CartridgeEnhanced::bank(bank); // Accesses above bank 127 disable further bankswitching; we're only // concerned with the lower byte @@ -123,38 +100,12 @@ bool CartridgeMDM::bank(uInt16 bank) return myBankChanged = true; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeMDM::getBank(uInt16) const -{ - return myBankOffset >> 12; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeMDM::bankCount() const -{ - return uInt16(mySize >> 12); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeMDM::patch(uInt16 address, uInt8 value) -{ - myImage[myBankOffset + (address & 0x0FFF)] = value; - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeMDM::getImage(size_t& size) const -{ - size = mySize; - return myImage.get(); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeMDM::save(Serializer& out) const { + CartridgeEnhanced::save(out); try { - out.putInt(myBankOffset); out.putBool(myBankingDisabled); } catch(...) @@ -169,9 +120,9 @@ bool CartridgeMDM::save(Serializer& out) const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeMDM::load(Serializer& in) { + CartridgeEnhanced::load(in); try { - myBankOffset = in.getInt(); myBankingDisabled = in.getBool(); } catch(...) @@ -180,8 +131,5 @@ bool CartridgeMDM::load(Serializer& in) return false; } - // Remember what bank we were in - bank(myBankOffset >> 12); - return true; } diff --git a/src/emucore/CartMDM.hxx b/src/emucore/CartMDM.hxx index 1c2a34cb6..6fd7435a3 100644 --- a/src/emucore/CartMDM.hxx +++ b/src/emucore/CartMDM.hxx @@ -19,7 +19,7 @@ #define CARTRIDGEMDM_HXX #include "bspf.hxx" -#include "Cart.hxx" +#include "CartEnhanced.hxx" #include "System.hxx" #ifdef DEBUGGER_SUPPORT #include "CartMDMWidget.hxx" @@ -42,9 +42,9 @@ Therefore, there are 128 banks / 512K possible in total. - @author Stephen Anthony, based on 0840 scheme by Fred X. Quimby + @author Stephen Anthony, Thomas Jentzsch, based on 0840 scheme by Fred X. Quimby */ -class CartridgeMDM : public Cartridge +class CartridgeMDM : public CartridgeEnhanced { friend class CartridgeMDMWidget; @@ -62,11 +62,6 @@ class CartridgeMDM : public Cartridge virtual ~CartridgeMDM() = default; public: - /** - Reset device to its power-on state - */ - void reset() override; - /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @@ -82,35 +77,6 @@ class CartridgeMDM : public Cartridge */ bool bank(uInt16 bank) override; - /** - Get the current bank. - - @param address The address to use when querying the bank - */ - uInt16 getBank(uInt16 address = 0) const override; - - /** - Query the number of banks supported by the cartridge. - */ - uInt16 bankCount() const override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const override; - /** Save the current state of this cart to the given Serializer. @@ -164,18 +130,12 @@ class CartridgeMDM : public Cartridge bool poke(uInt16 address, uInt8 value) override; private: - // Pointer to a dynamically allocated ROM image of the cartridge - ByteBuffer myImage; - - // Size of the ROM image - size_t mySize{0}; + bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; + private: // Previous Device's page access std::array myHotSpotPageAccess; - // Indicates the offset into the ROM image (aligns to current bank) - uInt32 myBankOffset{0}; - // Indicates whether banking has been disabled due to a bankswitch // above bank 127 bool myBankingDisabled{false}; From 4b89f335d0c924e6c54b9406f70c8e541b51e60f Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 6 Apr 2020 09:42:13 +0200 Subject: [PATCH 095/377] refactor CartSB --- src/debugger/gui/CartSBWidget.cxx | 5 +- src/emucore/CartSB.cxx | 132 +++++------------------------- src/emucore/CartSB.hxx | 73 ++--------------- 3 files changed, 30 insertions(+), 180 deletions(-) diff --git a/src/debugger/gui/CartSBWidget.cxx b/src/debugger/gui/CartSBWidget.cxx index a7bf7e5b2..78d352879 100644 --- a/src/debugger/gui/CartSBWidget.cxx +++ b/src/debugger/gui/CartSBWidget.cxx @@ -26,10 +26,11 @@ CartridgeSBWidget::CartridgeSBWidget( : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { - size_t size = myCart.mySize; - VariantList items; ostringstream info, bank; + size_t size; + + myCart.getImage(size); info << "SB SUPERbanking, 32 or 64 4K banks\n" << "Hotspots are from $800 to $" << Common::Base::HEX2 << (0x800 + myCart.bankCount() - 1) << ", including\n" diff --git a/src/emucore/CartSB.cxx b/src/emucore/CartSB.cxx index 44ff9381f..58dd94522 100644 --- a/src/emucore/CartSB.cxx +++ b/src/emucore/CartSB.cxx @@ -21,30 +21,14 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeSB::CartridgeSB(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5), - mySize(size) + : CartridgeEnhanced(image, size, md5, settings) { - // Allocate array for the ROM image - myImage = make_unique(mySize); - - // Copy the ROM image into my buffer - std::copy_n(image.get(), mySize, myImage.get()); - createRomAccessArrays(mySize); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeSB::reset() -{ - initializeStartBank(bankCount() - 1); - - // Upon reset we switch to the startup bank - bank(startBank()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeSB::install(System& system) { - mySystem = &system; + CartridgeEnhanced::install(system); // Get the page accessing methods for the hot spots since they overlap // areas within the TIA we'll need to forward requests to the TIA @@ -62,19 +46,27 @@ void CartridgeSB::install(System& system) // Set the page accessing methods for the hot spots for(uInt16 addr = 0x0800; addr < 0x0FFF; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); - - // Install pages for startup bank - bank(startBank()); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CartridgeSB::checkSwitchBank(uInt16 address, uInt8) +{ + // Switch banks if necessary + if((address & 0x1800) == 0x0800) + { + bank(address & startBank()); + return true; + } + return false; +} + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeSB::peek(uInt16 address) { - address &= (0x17FF + (mySize >> 12)); + address &= (0x17FF + bankCount()); - // Switch banks if necessary - if ((address & 0x1800) == 0x0800) - bank(address & startBank()); + checkSwitchBank(address); if(!(address & 0x1000)) { @@ -90,11 +82,9 @@ uInt8 CartridgeSB::peek(uInt16 address) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeSB::poke(uInt16 address, uInt8 value) { - address &= (0x17FF + (mySize >> 12)); + address &= (0x17FF + bankCount()); - // Switch banks if necessary - if((address & 0x1800) == 0x0800) - bank(address & startBank()); + checkSwitchBank(address); if(!(address & 0x1000)) { @@ -105,87 +95,3 @@ bool CartridgeSB::poke(uInt16 address, uInt8 value) } return false; } - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeSB::bank(uInt16 bank) -{ - if(bankLocked()) return false; - - // Remember what bank we're in - myBankOffset = bank << 12; - - // Setup the page access methods for the current bank - System::PageAccess access(this, System::PageAccessType::READ); - - // Map ROM image into the system - for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeSB::getBank(uInt16) const -{ - return myBankOffset >> 12; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeSB::bankCount() const -{ - return uInt16(mySize >> 12); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeSB::patch(uInt16 address, uInt8 value) -{ - myImage[myBankOffset + (address & 0x0FFF)] = value; - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeSB::getImage(size_t& size) const -{ - size = mySize; - return myImage.get(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeSB::save(Serializer& out) const -{ - try - { - out.putInt(myBankOffset); - } - catch(...) - { - cerr << "ERROR: CartridgeSB::save" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeSB::load(Serializer& in) -{ - try - { - myBankOffset = in.getInt(); - } - catch(...) - { - cerr << "ERROR: CartridgeSB::load" << endl; - return false; - } - - // Remember what bank we were in - bank(myBankOffset >> 12); - - return true; -} diff --git a/src/emucore/CartSB.hxx b/src/emucore/CartSB.hxx index fe8f8b75d..3682dbb04 100644 --- a/src/emucore/CartSB.hxx +++ b/src/emucore/CartSB.hxx @@ -19,7 +19,7 @@ #define CARTRIDGESB_HXX #include "bspf.hxx" -#include "Cart.hxx" +#include "CartEnhanced.hxx" #include "System.hxx" #ifdef DEBUGGER_SUPPORT #include "CartSBWidget.hxx" @@ -31,9 +31,9 @@ (32 banks) and $800 - $83F (64 banks). All mirrors up to $FFF are also used ($900, $A00, ...). - @author Fred X. Quimby + @author Fred X. Quimby, Thomas Jentzsch */ -class CartridgeSB : public Cartridge +class CartridgeSB : public CartridgeEnhanced { friend class CartridgeSBWidget; @@ -51,11 +51,6 @@ class CartridgeSB : public Cartridge virtual ~CartridgeSB() = default; public: - /** - Reset device to its power-on state - */ - void reset() override; - /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @@ -64,58 +59,6 @@ class CartridgeSB : public Cartridge */ void install(System& system) override; - /** - Install pages for the specified bank in the system. - - @param bank The bank that should be installed in the system - */ - bool bank(uInt16 bank) override; - - /** - Get the current bank. - - @param address The address to use when querying the bank - */ - uInt16 getBank(uInt16 address = 0) const override; - - /** - Query the number of banks supported by the cartridge. - */ - uInt16 bankCount() const override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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). @@ -153,13 +96,13 @@ class CartridgeSB : public Cartridge bool poke(uInt16 address, uInt8 value) override; private: - // The 128-256K ROM image and size of the cartridge - ByteBuffer myImage; - size_t mySize{0}; + bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; - // Indicates the offset into the ROM image (aligns to current bank) - uInt32 myBankOffset{0}; + uInt16 hotspot() const override { return 0x0840; } + uInt16 getStartBank() const override { return bankCount() - 1; } + + private: // Previous Device's page access std::array myHotSpotPageAccess; From fdabb6fe1cbb5bed1d9a6cf9da65d11e2c3ee0a9 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 7 Apr 2020 08:24:06 +0200 Subject: [PATCH 096/377] refactor Cart2K and Cart4K(SC) --- src/debugger/gui/Cart2KWidget.cxx | 5 +- src/emucore/Cart2K.cxx | 68 +++------------ src/emucore/Cart2K.hxx | 68 +-------------- src/emucore/Cart4K.cxx | 45 +--------- src/emucore/Cart4K.hxx | 62 +------------- src/emucore/Cart4KSC.cxx | 134 +----------------------------- src/emucore/Cart4KSC.hxx | 76 ++--------------- src/emucore/CartEnhanced.cxx | 15 ++-- src/emucore/CartEnhanced.hxx | 6 +- 9 files changed, 44 insertions(+), 435 deletions(-) diff --git a/src/debugger/gui/Cart2KWidget.cxx b/src/debugger/gui/Cart2KWidget.cxx index e90ed67f2..745c52316 100644 --- a/src/debugger/gui/Cart2KWidget.cxx +++ b/src/debugger/gui/Cart2KWidget.cxx @@ -25,7 +25,10 @@ Cartridge2KWidget::Cartridge2KWidget( : CartDebugWidget(boss, lfont, nfont, x, y, w, h) { // Eventually, we should query this from the debugger/disassembler - size_t size = cart.mySize; + size_t size; + + cart.getImage(size); + uInt16 start = (cart.myImage[size-3] << 8) | cart.myImage[size-4]; start -= start % size; diff --git a/src/emucore/Cart2K.cxx b/src/emucore/Cart2K.cxx index ee9f2b334..24a328736 100644 --- a/src/emucore/Cart2K.cxx +++ b/src/emucore/Cart2K.cxx @@ -21,15 +21,19 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge2K::Cartridge2K(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5) + : CartridgeEnhanced(image, size, md5, settings) { // Size can be a maximum of 2K - if(size > 2_KB) size = 2_KB; + if(size > 2_KB) + size = 2_KB; // Set image size to closest power-of-two for the given size - mySize = 1; + mySize = 1; myBankShift = 0; while(mySize < size) + { mySize <<= 1; + myBankShift++; + } // Initialize ROM with illegal 6502 opcode that causes a real 6502 to jam size_t bufSize = std::max(mySize, System::PAGE_SIZE); @@ -49,62 +53,12 @@ Cartridge2K::Cartridge2K(const ByteBuffer& image, size_t size, 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; } + // update access arrays, bank size and mask based on new size createRomAccessArrays(mySize); - // Set mask for accessing the image buffer - // This is guaranteed to work, as mySize is a power of two - myMask = static_cast(mySize) - 1; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge2K::reset() -{ - myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge2K::install(System& system) -{ - mySystem = &system; - - // Map ROM image into the system - // Note that we don't need our own peek/poke methods, since the mapping - // takes care of the entire address space - System::PageAccess access(this, System::PageAccessType::READ); - for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[addr & myMask]; - access.romAccessBase = &myRomAccessBase[addr & myMask]; - access.romPeekCounter = &myRomAccessCounter[addr & myMask]; - access.romPokeCounter = &myRomAccessCounter[(addr & myMask) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Cartridge2K::patch(uInt16 address, uInt8 value) -{ - myImage[address & myMask] = value; - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* Cartridge2K::getImage(size_t& size) const -{ - size = mySize; - return myImage.get(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Cartridge2K::save(Serializer&) const -{ - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Cartridge2K::load(Serializer&) -{ - return true; + myBankSize = 1 << myBankShift; // e.g. = 2 ^ 11 = 2048 = 0x0800 + myBankMask = myBankSize - 1; // e.g. = 0x07FF } diff --git a/src/emucore/Cart2K.hxx b/src/emucore/Cart2K.hxx index 22f08fbf5..1ef2ee250 100644 --- a/src/emucore/Cart2K.hxx +++ b/src/emucore/Cart2K.hxx @@ -21,7 +21,7 @@ class System; #include "bspf.hxx" -#include "Cart.hxx" +#include "CartEnhanced.hxx" #ifdef DEBUGGER_SUPPORT #include "Cart2KWidget.hxx" #endif @@ -33,9 +33,9 @@ class System; data repeats in intervals based on the size of the ROM (which will always be a power of 2). - @author Stephen Anthony + @author Stephen Anthony, Thomas Jentzsch */ -class Cartridge2K : public Cartridge +class Cartridge2K : public CartridgeEnhanced { friend class Cartridge2KWidget; @@ -53,52 +53,6 @@ class Cartridge2K : public Cartridge virtual ~Cartridge2K() = default; public: - /** - Reset cartridge to its power-on state - */ - void reset() override; - - /** - Install cartridge in the specified system. Invoked by the system - when the cartridge is attached to it. - - @param system The system the device should install itself in - */ - void install(System& system) override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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). @@ -118,22 +72,8 @@ class Cartridge2K : public Cartridge } #endif - /** - Get the byte at the specified address. - - @return The byte at the specified address - */ - uInt8 peek(uInt16 address) override { return myImage[address & myMask]; } - private: - // Pointer to a dynamically allocated ROM image of the cartridge - ByteBuffer myImage; - - // Size of the ROM image - size_t mySize{0}; - - // Mask to use for mirroring - uInt16 myMask{0}; + bool checkSwitchBank(uInt16 address, uInt8 value = 0) override { return false; }; private: // Following constructors and assignment operators not supported diff --git a/src/emucore/Cart4K.cxx b/src/emucore/Cart4K.cxx index 4f4aab979..d26ccfec0 100644 --- a/src/emucore/Cart4K.cxx +++ b/src/emucore/Cart4K.cxx @@ -21,48 +21,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge4K::Cartridge4K(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5) + : CartridgeEnhanced(image, size, md5, settings) { - // Copy the ROM image into my buffer - std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessArrays(myImage.size()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge4K::reset() -{ - myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge4K::install(System& system) -{ - mySystem = &system; - - // Map ROM image into the system - // Note that we don't need our own peek/poke methods, since the mapping - // takes care of the entire address space - System::PageAccess access(this, System::PageAccessType::READ); - for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[addr & 0x0FFF]; - access.romAccessBase = &myRomAccessBase[addr & 0x0FFF]; - access.romPeekCounter = &myRomAccessCounter[addr & 0x0FFF]; - access.romPokeCounter = &myRomAccessCounter[(addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Cartridge4K::patch(uInt16 address, uInt8 value) -{ - myImage[address & 0x0FFF] = value; - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* Cartridge4K::getImage(size_t& size) const -{ - size = myImage.size(); - return myImage.data(); + cerr << "Cartridge4K" << endl; } diff --git a/src/emucore/Cart4K.hxx b/src/emucore/Cart4K.hxx index 2b42516f5..70819c5b2 100644 --- a/src/emucore/Cart4K.hxx +++ b/src/emucore/Cart4K.hxx @@ -21,7 +21,7 @@ class System; #include "bspf.hxx" -#include "Cart.hxx" +#include "CartEnhanced.hxx" #ifdef DEBUGGER_SUPPORT #include "Cart4KWidget.hxx" #endif @@ -30,9 +30,9 @@ class System; This is the standard Atari 4K cartridge. These cartridges are not bankswitched. - @author Bradford W. Mott + @author Bradford W. Mott, Thomas Jentzsch */ -class Cartridge4K : public Cartridge +class Cartridge4K : public CartridgeEnhanced { friend class Cartridge4KWidget; @@ -50,52 +50,6 @@ class Cartridge4K : public Cartridge virtual ~Cartridge4K() = default; public: - /** - Reset cartridge to its power-on state - */ - void reset() override; - - /** - Install cartridge in the specified system. Invoked by the system - when the cartridge is attached to it. - - @param system The system the device should install itself in - */ - void install(System& system) override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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 { return true; } - - /** - 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 { return true; } - /** Get a descriptor for the device name (used in error checking). @@ -115,16 +69,8 @@ class Cartridge4K : public Cartridge } #endif - /** - Get the byte at the specified address. - - @return The byte at the specified address - */ - uInt8 peek(uInt16 address) override { return myImage[address & 0x0FFF]; } - private: - // The 4K ROM image for the cartridge - std::array myImage; + bool checkSwitchBank(uInt16 address, uInt8 value = 0) override { return false; }; private: // Following constructors and assignment operators not supported diff --git a/src/emucore/Cart4KSC.cxx b/src/emucore/Cart4KSC.cxx index 09e043c94..92d2e946e 100644 --- a/src/emucore/Cart4KSC.cxx +++ b/src/emucore/Cart4KSC.cxx @@ -21,137 +21,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge4KSC::Cartridge4KSC(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5) + : Cartridge4K(image, size, md5, settings) { - // Copy the ROM image into my buffer - std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessArrays(myImage.size()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge4KSC::reset() -{ - initializeRAM(myRAM.data(), myRAM.size()); - - myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge4KSC::install(System& system) -{ - mySystem = &system; - - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page accessing method for the RAM writing pages - // Map access to this class, since we need to inspect all accesses to - // check if RWP happens - access.type = System::PageAccessType::WRITE; - for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[addr & 0x007F]; - mySystem->setPageAccess(addr, access); - } - - // Set the page accessing method for the RAM reading pages - access.type = System::PageAccessType::READ; - for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myRAM[addr & 0x007F]; - access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)]; - mySystem->setPageAccess(addr, access); - } - - // Map ROM image into the system - for(uInt16 addr = 0x1100; addr < 0x2000; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[addr & 0x0FFF]; - access.romAccessBase = &myRomAccessBase[addr & 0x0FFF]; - mySystem->setPageAccess(addr, access); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 Cartridge4KSC::peek(uInt16 address) -{ - // The only way we can get to this method is if we attempt to read from - // the write port (0xF000 - 0xF07F, 128 bytes), in which case an - // unwanted write is potentially triggered - return peekRAM(myRAM[address & 0x007F], address); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Cartridge4KSC::poke(uInt16 address, uInt8 value) -{ - if (!(address & 0x080)) - { - pokeRAM(myRAM[address & 0x007F], address, value); - return true; - } - else - { - // Writing to the read port should be ignored, but trigger a break if option enabled - uInt8 dummy; - - pokeRAM(dummy, address, value); - myRamWriteAccess = address; - return false; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Cartridge4KSC::patch(uInt16 address, uInt8 value) -{ - address &= 0x0FFF; - - if(address < 0x0100) - { - // Normally, a write to the read port won't do anything - // However, the patch command is special in that ignores such - // cart restrictions - myRAM[address & 0x007F] = value; - } - else - myImage[address & 0xFFF] = value; - - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* Cartridge4KSC::getImage(size_t& size) const -{ - size = myImage.size(); - return myImage.data(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Cartridge4KSC::save(Serializer& out) const -{ - try - { - out.putByteArray(myRAM.data(), myRAM.size()); - } - catch(...) - { - cerr << "ERROR: Cartridge4KSC::save" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Cartridge4KSC::load(Serializer& in) -{ - try - { - in.getByteArray(myRAM.data(), myRAM.size()); - } - catch(...) - { - cerr << "ERROR: Cartridge4KSC::load" << endl; - return false; - } - - return true; + myRamSize = RAM_SIZE; } diff --git a/src/emucore/Cart4KSC.hxx b/src/emucore/Cart4KSC.hxx index 4d596f47a..64dde3c39 100644 --- a/src/emucore/Cart4KSC.hxx +++ b/src/emucore/Cart4KSC.hxx @@ -21,7 +21,7 @@ class System; #include "bspf.hxx" -#include "Cart.hxx" +#include "Cart4K.hxx" #ifdef DEBUGGER_SUPPORT #include "Cart4KSCWidget.hxx" #endif @@ -29,9 +29,11 @@ class System; /** Cartridge class used for 4K games with 128 bytes of RAM. RAM read port is $1080 - $10FF, write port is $1000 - $107F. + + @author Stephen Anthony, Thomas Jentzsch */ -class Cartridge4KSC : public Cartridge +class Cartridge4KSC : public Cartridge4K { friend class Cartridge4KSCWidget; @@ -49,52 +51,6 @@ class Cartridge4KSC : public Cartridge virtual ~Cartridge4KSC() = default; public: - /** - Reset device to its power-on state - */ - void reset() override; - - /** - Install cartridge in the specified system. Invoked by the system - when the cartridge is attached to it. - - @param system The system the device should install itself in - */ - void install(System& system) override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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). @@ -114,29 +70,9 @@ class Cartridge4KSC : public Cartridge } #endif - public: - /** - Get the byte at the specified address. - - @return The byte at the specified address - */ - uInt8 peek(uInt16 address) override; - - /** - Change the byte at the specified address to the given value - - @param address The address where the value should be stored - @param value The value to be stored at the address - @return True if the poke changed the device address space, else false - */ - bool poke(uInt16 address, uInt8 value) override; - private: - // The 4K ROM image of the cartridge - std::array myImage; - - // The 128 bytes of RAM - std::array myRAM; + // RAM size + static constexpr uInt16 RAM_SIZE = 0x80; private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index 4cbf61eca..8efab740a 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -24,19 +24,19 @@ CartridgeEnhanced::CartridgeEnhanced(const ByteBuffer& image, size_t size, : Cartridge(settings, md5), mySize(size) { - // Allocate array for the ROM image - myImage = make_unique(mySize); + // Allocate array for the ROM image (at least 64 bytzes) + myImage = make_unique(std::max(uInt16(mySize), System::PAGE_SIZE)); // Copy the ROM image into my buffer std::copy_n(image.get(), mySize, myImage.get()); - - // Copy the ROM image into my buffer - createRomAccessArrays(mySize); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeEnhanced::install(System& system) { + // Copy the ROM image into my buffer + createRomAccessArrays(mySize); + // calculate bank switching and RAM sizes and masks myBankSize = 1 << myBankShift; // e.g. = 2 ^ 12 = 4K = 0x1000 myBankMask = myBankSize - 1; // e.g. = 0x0FFF @@ -81,7 +81,7 @@ void CartridgeEnhanced::install(System& system) // Install pages for the startup bank (TODO: currently only in first bank segment) bank(startBank(), 0); - if(myBankSegs > 1) + if(mySize >= 4_KB && myBankSegs > 1) // Setup the last bank segment to always point to the last ROM segment bank(bankCount() - 1, myBankSegs - 1); } @@ -149,7 +149,8 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) uInt16 hotspot = this->hotspot(); uInt16 hotSpotAddr; uInt16 fromAddr = (segmentOffset + 0x1000 + myRamSize * 2) & ~System::PAGE_MASK; - uInt16 toAddr = (segmentOffset + 0x1000 + myBankSize) & ~System::PAGE_MASK; + // for ROMs < 4_KB, the whole address space will be mapped. + uInt16 toAddr = (segmentOffset + 0x1000 + (mySize < 4_KB ? 0x1000 : myBankSize)) & ~System::PAGE_MASK; if(hotspot) hotSpotAddr = (hotspot & ~System::PAGE_MASK); diff --git a/src/emucore/CartEnhanced.hxx b/src/emucore/CartEnhanced.hxx index a78b725e7..6437c362e 100644 --- a/src/emucore/CartEnhanced.hxx +++ b/src/emucore/CartEnhanced.hxx @@ -172,6 +172,9 @@ class CartridgeEnhanced : public Cartridge // Pointer to a dynamically allocated RAM area of the cartridge ByteBuffer myRAM{nullptr}; + // The size of the ROM image + size_t mySize{0}; + private: // Calculated as: log(ROM bank segment size) / log(2) static constexpr uInt16 BANK_SHIFT = 12; // default = 4K @@ -179,9 +182,6 @@ class CartridgeEnhanced : public Cartridge // The size of extra RAM in ROM address space static constexpr uInt16 RAM_SIZE = 0; // default = none - // The size of the ROM image - size_t mySize{0}; - protected: /** Check hotspots and switch bank if triggered. From 2efd94d099a0f8599eef07146c16f7795af969f6 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Wed, 8 Apr 2020 11:59:02 -0230 Subject: [PATCH 097/377] Fix 'saveconfig' not saving file correctly (fixes #602). --- Changes.txt | 2 ++ src/debugger/CartDebug.cxx | 22 ++++++++++++---------- src/debugger/CartDebug.hxx | 2 +- src/emucore/OSystem.cxx | 4 ++++ src/emucore/OSystem.hxx | 8 ++++++++ 5 files changed, 27 insertions(+), 11 deletions(-) diff --git a/Changes.txt b/Changes.txt index 2de2987ee..60fd29f4e 100644 --- a/Changes.txt +++ b/Changes.txt @@ -28,6 +28,8 @@ * Added detection of color and audio data in DiStella. + * Restored 'cfg' directory for Distella config files. + -Have fun! diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index 612f51542..a52732cfe 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -843,12 +843,13 @@ string CartDebug::loadSymbolFile() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartDebug::loadConfigFile() { - // The default naming/location for config files is the ROM dir based on the - // actual ROM filename + // The default naming/location for config files is the CFG dir and based + // on the actual ROM filename if(myCfgFile == "") { - FilesystemNode cfg(myOSystem.romFile().getPathWithExt("") + ".cfg"); + FilesystemNode romNode(myOSystem.romFile().getPathWithExt("") + ".cfg"); + FilesystemNode cfg(myOSystem.cfgDir() + romNode.getName()); if(cfg.isFile() && cfg.isReadable()) myCfgFile = cfg.getPath(); else @@ -964,14 +965,14 @@ string CartDebug::loadConfigFile() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartDebug::saveConfigFile() { - // The default naming/location for config files is the ROM dir based on the - // actual ROM filename + // The default naming/location for config files is the CFG dir and based + // on the actual ROM filename - FilesystemNode cfg; if(myCfgFile == "") { - cfg = FilesystemNode(myOSystem.romFile().getPathWithExt("") + ".cfg"); - if(cfg.isFile() && cfg.isWritable()) + FilesystemNode romNode(myOSystem.romFile().getPathWithExt("") + ".cfg"); + FilesystemNode cfg(myOSystem.cfgDir() + romNode.getName()); + if(cfg.getParent().isWritable()) myCfgFile = cfg.getPath(); else return DebuggerParser::red("config file \'" + cfg.getShortPath() + "\' not writable"); @@ -980,13 +981,14 @@ string CartDebug::saveConfigFile() const string& name = myConsole.properties().get(PropType::Cart_Name); const string& md5 = myConsole.properties().get(PropType::Cart_MD5); + FilesystemNode cfg(myCfgFile); ofstream out(cfg.getPath()); if(!out.is_open()) return "Unable to save directives to " + cfg.getShortPath(); // Store all bank information - out << "//Stella.pro: \"" << name << "\"" << endl - << "//MD5: " << md5 << endl + out << "// Stella.pro: \"" << name << "\"" << endl + << "// MD5: " << md5 << endl << endl; for(uInt32 b = 0; b < myConsole.cartridge().bankCount(); ++b) { diff --git a/src/debugger/CartDebug.hxx b/src/debugger/CartDebug.hxx index 7fff9c8a6..c2bd03cae 100644 --- a/src/debugger/CartDebug.hxx +++ b/src/debugger/CartDebug.hxx @@ -343,7 +343,7 @@ class CartDebug : public DebuggerSystem uInt16 myLabelLength{8}; // longest pre-defined label // Filenames to use for various I/O (currently these are hardcoded) - string myListFile, mySymbolFile, myCfgFile, myDisasmFile, myRomFile; + string myListFile, mySymbolFile, myCfgFile, myDisasmFile; /// Table of instruction mnemonics static std::array ourTIAMnemonicR; // read mode diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index 29359d6ba..832b1ce35 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -268,6 +268,9 @@ void OSystem::setConfigPaths() buildDirIfRequired(myStateDir, myBaseDir + "state"); buildDirIfRequired(myNVRamDir, myBaseDir + "nvram"); +#ifdef DEBUGGER_SUPPORT + buildDirIfRequired(myCfgDir, myBaseDir + "cfg"); +#endif #ifdef PNG_SUPPORT mySnapshotSaveDir = mySettings->getString("snapsavedir"); @@ -292,6 +295,7 @@ void OSystem::setConfigPaths() dbgPath("base dir ", myBaseDir); dbgPath("state dir ", myStateDir); dbgPath("nvram dir ", myNVRamDir); + dbgPath("cfg dir ", myCfgDir); dbgPath("ssave dir ", mySnapshotSaveDir); dbgPath("sload dir ", mySnapshotLoadDir); dbgPath("cheat file", myCheatFile); diff --git a/src/emucore/OSystem.hxx b/src/emucore/OSystem.hxx index 123bc92cb..b23cbdb83 100644 --- a/src/emucore/OSystem.hxx +++ b/src/emucore/OSystem.hxx @@ -270,6 +270,13 @@ class OSystem const string& cheatFile() const { return myCheatFile; } #endif + #ifdef DEBUGGER_SUPPORT + /** + Return the full/complete directory name for storing Distella cfg files. + */ + const string& cfgDir() const { return myCfgDir; } + #endif + #ifdef PNG_SUPPORT /** Return the full/complete directory name for saving and loading @@ -529,6 +536,7 @@ class OSystem string mySnapshotSaveDir; string mySnapshotLoadDir; string myNVRamDir; + string myCfgDir; string myDefaultSaveDir; string myDefaultLoadDir; From a1ded47af3cf842c2271d534394f4fb1e3bcf5aa Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 8 Apr 2020 22:02:01 +0200 Subject: [PATCH 098/377] fix carts >= 64K --- src/emucore/CartEnhanced.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index 8efab740a..6752d3153 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -25,7 +25,7 @@ CartridgeEnhanced::CartridgeEnhanced(const ByteBuffer& image, size_t size, mySize(size) { // Allocate array for the ROM image (at least 64 bytzes) - myImage = make_unique(std::max(uInt16(mySize), System::PAGE_SIZE)); + myImage = make_unique(std::max(uInt32(mySize), uInt32(System::PAGE_SIZE))); // Copy the ROM image into my buffer std::copy_n(image.get(), mySize, myImage.get()); @@ -251,7 +251,7 @@ bool CartridgeEnhanced::load(Serializer& in) cerr << "ERROR: " << name() << "::load" << endl; return false; } - // Restore bank sewgments + // Restore bank segments for(uInt16 i = 0; i < myBankSegs; ++i) bank(getSegmentBank(i), i); From 60cd8739b41f6c8d8e1e0bf14304b6bc11f5dfb6 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 9 Apr 2020 16:07:38 +0200 Subject: [PATCH 099/377] refactor CartX07 --- src/debugger/gui/CartX07Widget.cxx | 2 +- src/emucore/CartX07.cxx | 146 ++++++----------------------- src/emucore/CartX07.hxx | 69 +------------- 3 files changed, 33 insertions(+), 184 deletions(-) diff --git a/src/debugger/gui/CartX07Widget.cxx b/src/debugger/gui/CartX07Widget.cxx index 78fd70d3b..0c6bc5b95 100644 --- a/src/debugger/gui/CartX07Widget.cxx +++ b/src/debugger/gui/CartX07Widget.cxx @@ -103,7 +103,7 @@ string CartridgeX07Widget::bankState() { ostringstream& buf = buffer(); - buf << "Bank = " << std::dec << myCart.myCurrentBank; + buf << "Bank = " << std::dec << myCart.getBank(); return buf.str(); } diff --git a/src/emucore/CartX07.cxx b/src/emucore/CartX07.cxx index 96bf5e4ed..ac40b6ac6 100644 --- a/src/emucore/CartX07.cxx +++ b/src/emucore/CartX07.cxx @@ -23,25 +23,14 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeX07::CartridgeX07(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5) + : CartridgeEnhanced(image, size, md5, settings) { - // Copy the ROM image into my buffer - std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessArrays(myImage.size()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeX07::reset() -{ - // Upon reset we switch to the startup bank - initializeStartBank(0); - bank(startBank()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeX07::install(System& system) { - mySystem = &system; + CartridgeEnhanced::install(system); // Set the page accessing methods for the hot spots // The hotspots use almost all addresses below 0x1000, so we simply grab them @@ -49,31 +38,42 @@ void CartridgeX07::install(System& system) System::PageAccess access(this, System::PageAccessType::READWRITE); for(uInt16 addr = 0x00; addr < 0x1000; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); +} - // Install pages for the startup bank - bank(startBank()); +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CartridgeX07::checkSwitchBank(uInt16 address, uInt8) +{ + // Switch banks if necessary + if((address & 0x180f) == 0x080d) + { + bank((address & 0xf0) >> 4); + return true; + } + else if((address & 0x1880) == 0) + { + if((getBank() & 0xe) == 0xe) + { + bank(((address & 0x40) >> 6) | 0xe); + return true; + } + } + + return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeX07::peek(uInt16 address) { - uInt8 value = 0; - + uInt8 value = 0; // JTZ: is this correct? // Check for RAM or TIA mirroring uInt16 lowAddress = address & 0x3ff; + if(lowAddress & 0x80) value = mySystem->m6532().peek(address); else if(!(lowAddress & 0x200)) value = mySystem->tia().peek(address); - // Switch banks if necessary - if((address & 0x180f) == 0x080d) - bank((address & 0xf0) >> 4); - else if((address & 0x1880) == 0) - { - if((myCurrentBank & 0xe) == 0xe) - bank(((address & 0x40) >> 6) | (myCurrentBank & 0xe)); - } + checkSwitchBank(address); return value; } @@ -83,103 +83,13 @@ bool CartridgeX07::poke(uInt16 address, uInt8 value) { // Check for RAM or TIA mirroring uInt16 lowAddress = address & 0x3ff; + if(lowAddress & 0x80) mySystem->m6532().poke(address, value); else if(!(lowAddress & 0x200)) mySystem->tia().poke(address, value); - // Switch banks if necessary - if((address & 0x180f) == 0x080d) - bank((address & 0xf0) >> 4); - else if((address & 0x1880) == 0) - { - if((myCurrentBank & 0xe) == 0xe) - bank(((address & 0x40) >> 6) | (myCurrentBank & 0xe)); - } + checkSwitchBank(address); + return false; } - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeX07::bank(uInt16 bank) -{ - if(bankLocked()) return false; - - // Remember what bank we're in - myCurrentBank = (bank & 0x0f); - uInt32 offset = myCurrentBank << 12; - - // Setup the page access methods for the current bank - System::PageAccess access(this, System::PageAccessType::READ); - - // Map ROM image into the system - for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[offset + (addr & 0x0FFF)]; - access.romAccessBase = &myRomAccessBase[offset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeX07::getBank(uInt16) const -{ - return myCurrentBank; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeX07::bankCount() const -{ - return 16; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeX07::patch(uInt16 address, uInt8 value) -{ - myImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value; - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeX07::getImage(size_t& size) const -{ - size = myImage.size(); - return myImage.data(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeX07::save(Serializer& out) const -{ - try - { - out.putShort(myCurrentBank); - } - catch(...) - { - cerr << "ERROR: CartridgeX07::save" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeX07::load(Serializer& in) -{ - try - { - myCurrentBank = in.getShort(); - } - catch(...) - { - cerr << "ERROR: CartridgeX07::load" << endl; - return false; - } - - // Remember what bank we were in - bank(myCurrentBank); - - return true; -} diff --git a/src/emucore/CartX07.hxx b/src/emucore/CartX07.hxx index 0beff0e0b..3cde4efdf 100644 --- a/src/emucore/CartX07.hxx +++ b/src/emucore/CartX07.hxx @@ -21,7 +21,7 @@ class System; #include "bspf.hxx" -#include "Cart.hxx" +#include "CartEnhanced.hxx" #ifdef DEBUGGER_SUPPORT #include "CartX07Widget.hxx" #endif @@ -40,9 +40,9 @@ class System; Note that the latter will hit on almost any TIA access. - @author Eckhard Stolberg + @author Eckhard Stolberg, Thomas Jentzsch */ -class CartridgeX07 : public Cartridge +class CartridgeX07 : public CartridgeEnhanced { friend class CartridgeX07Widget; @@ -60,11 +60,6 @@ class CartridgeX07 : public Cartridge virtual ~CartridgeX07() = default; public: - /** - Reset device to its power-on state - */ - void reset() override; - /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @@ -73,58 +68,6 @@ class CartridgeX07 : public Cartridge */ void install(System& system) override; - /** - Install pages for the specified bank in the system. - - @param bank The bank that should be installed in the system - */ - bool bank(uInt16 bank) override; - - /** - Get the current bank. - - @param address The address to use when querying the bank - */ - uInt16 getBank(uInt16 address = 0) const override; - - /** - Query the number of banks supported by the cartridge. - */ - uInt16 bankCount() const override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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). @@ -162,11 +105,7 @@ class CartridgeX07 : public Cartridge bool poke(uInt16 address, uInt8 value) override; private: - // The 64K ROM image of the cartridge - std::array myImage; - - // Indicates which bank is currently active - uInt16 myCurrentBank{0}; + bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; private: // Following constructors and assignment operators not supported From ebc097a01618470dcaa86dca04c11c9fa3029bee Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 11 Apr 2020 14:12:27 +0200 Subject: [PATCH 100/377] refactor CartFA(2).cxx --- src/emucore/CartFA.cxx | 228 +---------------------------- src/emucore/CartFA.hxx | 99 ++----------- src/emucore/CartFA2.cxx | 309 +++++----------------------------------- src/emucore/CartFA2.hxx | 89 ++---------- 4 files changed, 58 insertions(+), 667 deletions(-) diff --git a/src/emucore/CartFA.cxx b/src/emucore/CartFA.cxx index 5a4ecb6bd..3f1062f41 100644 --- a/src/emucore/CartFA.cxx +++ b/src/emucore/CartFA.cxx @@ -21,235 +21,19 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeFA::CartridgeFA(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5) + : CartridgeEnhanced(image, size, md5, settings) { - // Copy the ROM image into my buffer - std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessArrays(myImage.size()); + myRamSize = RAM_SIZE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeFA::reset() -{ - initializeRAM(myRAM.data(), myRAM.size()); - initializeStartBank(2); - - // Upon reset we switch to the startup bank - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeFA::install(System& system) -{ - mySystem = &system; - - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page accessing method for the RAM writing pages - // Map access to this class, since we need to inspect all accesses to - // check if RWP happens - access.type = System::PageAccessType::WRITE; - for(uInt16 addr = 0x1000; addr < 0x1100; addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[addr & 0x00FF]; - access.romPeekCounter = &myRomAccessCounter[addr & 0x00FF]; - access.romPokeCounter = &myRomAccessCounter[(addr & 0x00FF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Set the page accessing method for the RAM reading pages - access.type = System::PageAccessType::READ; - for(uInt16 addr = 0x1100; addr < 0x1200; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myRAM[addr & 0x00FF]; - access.romAccessBase = &myRomAccessBase[0x100 + (addr & 0x00FF)]; - access.romPeekCounter = &myRomAccessCounter[0x100 + (addr & 0x00FF)]; - access.romPokeCounter = &myRomAccessCounter[0x100 + (addr & 0x00FF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Install pages for the startup bank - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeFA::peek(uInt16 address) -{ - uInt16 peekAddress = address; - address &= 0x0FFF; - - // Switch banks if necessary - switch(address) - { - case 0x0FF8: - // Set the current bank to the lower 4k bank - bank(0); - break; - - case 0x0FF9: - // Set the current bank to the middle 4k bank - bank(1); - break; - - case 0x0FFA: - // Set the current bank to the upper 4k bank - bank(2); - break; - - default: - break; - } - - if(address < 0x0100) // Write port is at 0xF000 - 0xF0FF (256 bytes) - return peekRAM(myRAM[address], peekAddress); - else - return myImage[myBankOffset + address]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeFA::poke(uInt16 address, uInt8 value) +bool CartridgeFA::checkSwitchBank(uInt16 address, uInt8) { // Switch banks if necessary - switch(address & 0x0FFF) + if((address >= 0x0FF8) && (address <= 0x0FFA)) { - case 0x0FF8: - // Set the current bank to the lower 4k bank - bank(0); - return false; - - case 0x0FF9: - // Set the current bank to the middle 4k bank - bank(1); - return false; - - case 0x0FFA: - // Set the current bank to the upper 4k bank - bank(2); - return false; - - default: - break; - } - - if (!(address & 0x100)) - { - pokeRAM(myRAM[address & 0x00FF], address, value); + bank(address - 0x0FF8); return true; } - else - { - // Writing to the read port should be ignored, but trigger a break if option enabled - uInt8 dummy; - - pokeRAM(dummy, address, value); - myRamWriteAccess = address; - return false; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeFA::bank(uInt16 bank) -{ - if(bankLocked()) return false; - - // Remember what bank we're in - myBankOffset = bank << 12; - - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page accessing methods for the hot spots - for(uInt16 addr = (0x1FF8 & ~System::PAGE_MASK); addr < 0x2000; - addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Setup the page access methods for the current bank - for(uInt16 addr = 0x1200; addr < static_cast(0x1FF8U & ~System::PAGE_MASK); - addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeFA::getBank(uInt16) const -{ - return myBankOffset >> 12; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeFA::bankCount() const -{ - return 3; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeFA::patch(uInt16 address, uInt8 value) -{ - address &= 0x0FFF; - - if(address < 0x0200) - { - // Normally, a write to the read port won't do anything - // However, the patch command is special in that ignores such - // cart restrictions - myRAM[address & 0x00FF] = value; - } - else - myImage[myBankOffset + address] = value; - - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeFA::getImage(size_t& size) const -{ - size = myImage.size(); - return myImage.data(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeFA::save(Serializer& out) const -{ - try - { - out.putShort(myBankOffset); - out.putByteArray(myRAM.data(), myRAM.size()); - } - catch(...) - { - cerr << "ERROR: CartridgeFA::save" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeFA::load(Serializer& in) -{ - try - { - myBankOffset = in.getShort(); - in.getByteArray(myRAM.data(), myRAM.size()); - } - catch(...) - { - cerr << "ERROR: CartridgeFA::load" << endl; - return false; - } - - // Remember what bank we were in - bank(myBankOffset >> 12); - - return true; + return false; } diff --git a/src/emucore/CartFA.hxx b/src/emucore/CartFA.hxx index 9729a366f..920f2bdec 100644 --- a/src/emucore/CartFA.hxx +++ b/src/emucore/CartFA.hxx @@ -21,7 +21,7 @@ class System; #include "bspf.hxx" -#include "Cart.hxx" +#include "CartEnhanced.hxx" #ifdef DEBUGGER_SUPPORT #include "CartFAWidget.hxx" #endif @@ -31,9 +31,9 @@ class System; banks, accessible by read/write at $1FF8 - $1FFA, and 256 bytes of RAM. RAM read port is $1100 - $11FF, write port is $1000 - $10FF. - @author Bradford W. Mott + @author Bradford W. Mott, Thomas Jentzsch */ -class CartridgeFA : public Cartridge +class CartridgeFA : public CartridgeEnhanced { friend class CartridgeFAWidget; @@ -51,71 +51,6 @@ class CartridgeFA : public Cartridge virtual ~CartridgeFA() = default; public: - /** - Reset device to its power-on state - */ - void reset() override; - - /** - Install cartridge in the specified system. Invoked by the system - when the cartridge is attached to it. - - @param system The system the device should install itself in - */ - void install(System& system) override; - - /** - Install pages for the specified bank in the system. - - @param bank The bank that should be installed in the system - */ - bool bank(uInt16 bank) override; - - /** - Get the current bank. - - @param address The address to use when querying the bank - */ - uInt16 getBank(uInt16 address = 0) const override; - - /** - Query the number of banks supported by the cartridge. - */ - uInt16 bankCount() const override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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). @@ -135,32 +70,16 @@ class CartridgeFA : public Cartridge } #endif - public: - /** - Get the byte at the specified address. + private: + bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; - @return The byte at the specified address - */ - uInt8 peek(uInt16 address) override; + uInt16 hotspot() const override { return 0x1FF8; } - /** - Change the byte at the specified address to the given value - - @param address The address where the value should be stored - @param value The value to be stored at the address - @return True if the poke changed the device address space, else false - */ - bool poke(uInt16 address, uInt8 value) override; + uInt16 getStartBank() const override { return 2; } private: - // The 12K ROM image of the cartridge - std::array myImage; - - // The 256 bytes of RAM on the cartridge - std::array myRAM; - - // Indicates the offset into the ROM image (aligns to current bank) - uInt16 myBankOffset{0}; + // RAM size + static constexpr uInt16 RAM_SIZE = 0x100; private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartFA2.cxx b/src/emucore/CartFA2.cxx index 1630f216e..0d892c9b3 100644 --- a/src/emucore/CartFA2.cxx +++ b/src/emucore/CartFA2.cxx @@ -15,308 +15,67 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#include "OSystem.hxx" -#include "Serializer.hxx" -#include "System.hxx" #include "TimerManager.hxx" #include "CartFA2.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeFA2::CartridgeFA2(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5) + : CartridgeFA(image, size, md5, settings) { // 29/32K version of FA2 has valid data @ 1K - 29K const uInt8* img_ptr = image.get(); if(size >= 29_KB) + { img_ptr += 1_KB; - else if(size < mySize) - mySize = size; + mySize = 28_KB; + } + + // Allocate array for the ROM image + myImage = make_unique(mySize); // Copy the ROM image into my buffer - std::copy_n(img_ptr, mySize, myImage.begin()); - createRomAccessArrays(mySize); + std::copy_n(image.get(), mySize, myImage.get()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeFA2::reset() +bool CartridgeFA2::checkSwitchBank(uInt16 address, uInt8) { - initializeRAM(myRAM.data(), myRAM.size()); - initializeStartBank(0); - - // Upon reset we switch to the startup bank - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeFA2::install(System& system) -{ - mySystem = &system; - - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page accessing method for the RAM writing pages - // Map access to this class, since we need to inspect all accesses to - // check if RWP happens - access.type = System::PageAccessType::WRITE; - for(uInt16 addr = 0x1000; addr < 0x1100; addr += System::PAGE_SIZE) + // Switch banks if necessary + if((address >= 0x0FF5) && (address <= 0x0FFB)) { - access.romAccessBase = &myRomAccessBase[addr & 0x00FF]; - access.romPeekCounter = &myRomAccessCounter[addr & 0x00FF]; - access.romPokeCounter = &myRomAccessCounter[(addr & 0x00FF) + myAccessSize]; - mySystem->setPageAccess(addr, access); + bank(address - 0x0FF5); + return true; } - - // Set the page accessing method for the RAM reading pages - access.directPokeBase = nullptr; - access.type = System::PageAccessType::READ; - for(uInt16 addr = 0x1100; addr < 0x1200; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myRAM[addr & 0x00FF]; - access.romAccessBase = &myRomAccessBase[0x100 + (addr & 0x00FF)]; - access.romPeekCounter = &myRomAccessCounter[0x100 + (addr & 0x00FF)]; - access.romPokeCounter = &myRomAccessCounter[0x100 + (addr & 0x00FF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Install pages for the startup bank - bank(startBank()); + return false; } - + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeFA2::peek(uInt16 address) { - uInt16 peekAddress = address; - address &= 0x0FFF; - // Switch banks if necessary - switch(address) + if((address & 0x0FFF) == 0x0FF4) { - case 0x0FF4: - // Load/save RAM to/from Harmony cart flash - if(mySize == 28_KB && !bankLocked()) - return ramReadWrite(); - break; - - case 0x0FF5: - // Set the current bank to the first 4k bank - bank(0); - break; - - case 0x0FF6: - // Set the current bank to the second 4k bank - bank(1); - break; - - case 0x0FF7: - // Set the current bank to the third 4k bank - bank(2); - break; - - case 0x0FF8: - // Set the current bank to the fourth 4k bank - bank(3); - break; - - case 0x0FF9: - // Set the current bank to the fifth 4k bank - bank(4); - break; - - case 0x0FFA: - // Set the current bank to the sixth 4k bank - bank(5); - break; - - case 0x0FFB: - // Set the current bank to the seventh 4k bank - // This is only available on 28K ROMs - if(mySize == 28_KB) bank(6); - break; - - default: - break; + // Load/save RAM to/from Harmony cart flash + if(mySize == 28_KB && !bankLocked()) + return ramReadWrite(); } - if(address < 0x0100) // Write port is at 0xF000 - 0xF0FF (256 bytes) - return peekRAM(myRAM[address], peekAddress); - else - return myImage[myBankOffset + address]; + return CartridgeEnhanced::peek(address); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeFA2::poke(uInt16 address, uInt8 value) { - // Switch banks if necessary - switch(address & 0x0FFF) + if((address & 0x0FFF) == 0x0FF4) { - case 0x0FF4: - // Load/save RAM to/from Harmony cart flash - if(mySize == 28_KB && !bankLocked()) - ramReadWrite(); - return false; - - case 0x0FF5: - // Set the current bank to the first 4k bank - bank(0); - return false; - - case 0x0FF6: - // Set the current bank to the second 4k bank - bank(1); - return false; - - case 0x0FF7: - // Set the current bank to the third 4k bank - bank(2); - return false; - - case 0x0FF8: - // Set the current bank to the fourth 4k bank - bank(3); - return false; - - case 0x0FF9: - // Set the current bank to the fifth 4k bank - bank(4); - return false; - - case 0x0FFA: - // Set the current bank to the sixth 4k bank - bank(5); - return false; - - case 0x0FFB: - // Set the current bank to the seventh 4k bank - // This is only available on 28K ROMs - if(mySize == 28_KB) bank(6); - return false; - - default: - break; - } - - if(!(address & 0x100)) - { - pokeRAM(myRAM[address & 0x00FF], address, value); - return true; - } - else - { - // Writing to the read port should be ignored, but trigger a break if option enabled - uInt8 dummy; - - pokeRAM(dummy, address, value); - myRamWriteAccess = address; - return false; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeFA2::bank(uInt16 bank) -{ - if(bankLocked()) return false; - - // Remember what bank we're in - myBankOffset = bank << 12; - - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page accessing methods for the hot spots - for(uInt16 addr = (0x1FF4 & ~System::PAGE_MASK); addr < 0x2000; - addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Setup the page access methods for the current bank - for(uInt16 addr = 0x1200; addr < static_cast(0x1FF4U & ~System::PAGE_MASK); - addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeFA2::getBank(uInt16) const -{ - return myBankOffset >> 12; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeFA2::bankCount() const -{ - return uInt16(mySize / 4_KB); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeFA2::patch(uInt16 address, uInt8 value) -{ - address &= 0x0FFF; - - if(address < 0x0200) - { - // Normally, a write to the read port won't do anything - // However, the patch command is special in that ignores such - // cart restrictions - myRAM[address & 0x00FF] = value; - } - else - myImage[myBankOffset + address] = value; - - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeFA2::getImage(size_t& size) const -{ - size = mySize; - return myImage.data(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeFA2::save(Serializer& out) const -{ - try - { - out.putShort(myBankOffset); - out.putByteArray(myRAM.data(), myRAM.size()); - } - catch(...) - { - cerr << "ERROR: CartridgeFA2::save" << endl; + // Load/save RAM to/from Harmony cart flash + if(mySize == 28_KB && !bankLocked()) + ramReadWrite(); return false; } - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeFA2::load(Serializer& in) -{ - try - { - myBankOffset = in.getShort(); - in.getByteArray(myRAM.data(), myRAM.size()); - } - catch(...) - { - cerr << "ERROR: CartridgeFA2::load" << endl; - return false; - } - - // Remember what bank we were in - bank(myBankOffset >> 12); - - return true; + return CartridgeEnhanced::poke(address, value); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -361,11 +120,11 @@ uInt8 CartridgeFA2::ramReadWrite() { try { - serializer.getByteArray(myRAM.data(), myRAM.size()); + serializer.getByteArray(myRAM.get(), myRamSize); } catch(...) { - myRAM.fill(0); + std::fill_n(myRAM.get(), myRamSize, 0); } myRamAccessTimeout += 500; // Add 0.5 ms delay for read } @@ -373,7 +132,7 @@ uInt8 CartridgeFA2::ramReadWrite() { try { - serializer.putByteArray(myRAM.data(), myRAM.size()); + serializer.putByteArray(myRAM.get(), myRamSize); } catch(...) { @@ -384,7 +143,7 @@ uInt8 CartridgeFA2::ramReadWrite() } } // Bit 6 is 1, busy - return myImage[myBankOffset + 0xFF4] | 0x40; + return myImage[myCurrentSegOffset[0] + 0xFF4] | 0x40; } else { @@ -395,11 +154,11 @@ uInt8 CartridgeFA2::ramReadWrite() myRAM[255] = 0; // Successful operation // Bit 6 is 0, ready/success - return myImage[myBankOffset + 0xFF4] & ~0x40; + return myImage[myCurrentSegOffset[0] + 0xFF4] & ~0x40; } else // Bit 6 is 1, busy - return myImage[myBankOffset + 0xFF4] | 0x40; + return myImage[myCurrentSegOffset[0] + 0xFF4] | 0x40; } } @@ -424,18 +183,18 @@ void CartridgeFA2::flash(uInt8 operation) { try { - serializer.getByteArray(myRAM.data(), myRAM.size()); + serializer.getByteArray(myRAM.get(), myRamSize); } catch(...) { - myRAM.fill(0); + std::fill_n(myRAM.get(), myRamSize, 0); } } else if(operation == 2) // write { try { - serializer.putByteArray(myRAM.data(), myRAM.size()); + serializer.putByteArray(myRAM.get(), myRamSize); } catch(...) { diff --git a/src/emucore/CartFA2.hxx b/src/emucore/CartFA2.hxx index ea19b0d43..8175f4cdc 100644 --- a/src/emucore/CartFA2.hxx +++ b/src/emucore/CartFA2.hxx @@ -21,7 +21,7 @@ class System; #include "bspf.hxx" -#include "Cart.hxx" +#include "CartFA.hxx" #ifdef DEBUGGER_SUPPORT #include "CartFA2Widget.hxx" #endif @@ -43,9 +43,9 @@ class System; by the emulator. Also supported is a 32K variant. In any event, only data at 1K - 29K of the ROM is used. - @author Chris D. Walton + @author Chris D. Walton, Thomas Jentzsch */ -class CartridgeFA2 : public Cartridge +class CartridgeFA2 : public CartridgeFA { friend class CartridgeFA2Widget; @@ -63,71 +63,6 @@ class CartridgeFA2 : public Cartridge virtual ~CartridgeFA2() = default; public: - /** - Reset device to its power-on state - */ - void reset() override; - - /** - Install cartridge in the specified system. Invoked by the system - when the cartridge is attached to it. - - @param system The system the device should install itself in - */ - void install(System& system) override; - - /** - Install pages for the specified bank in the system. - - @param bank The bank that should be installed in the system - */ - bool bank(uInt16 bank) override; - - /** - Get the current bank. - - @param address The address to use when querying the bank - */ - uInt16 getBank(uInt16 address = 0) const override; - - /** - Query the number of banks supported by the cartridge. - */ - uInt16 bankCount() const override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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). @@ -173,6 +108,12 @@ class CartridgeFA2 : public Cartridge bool poke(uInt16 address, uInt8 value) override; private: + bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; + + uInt16 hotspot() const override { return 0x1FF4; } + + uInt16 getStartBank() const override { return 0; } + /** Either load or save internal RAM to Harmony flash (represented by a file in emulation). @@ -192,15 +133,6 @@ class CartridgeFA2 : public Cartridge void flash(uInt8 operation); private: - // The 24K/28K ROM image of the cartridge - std::array myImage; - - // Actual usable size of the ROM image - size_t mySize{28_KB}; - - // The 256 bytes of RAM on the cartridge - std::array myRAM; - // The time after which the first request of a load/save operation // will actually be completed // Due to flash RAM constraints, a read/write isn't instantaneous, @@ -211,9 +143,6 @@ class CartridgeFA2 : public Cartridge // of internal RAM to Harmony cart flash string myFlashFile; - // Indicates the offset into the ROM image (aligns to current bank) - uInt16 myBankOffset{0}; - private: // Following constructors and assignment operators not supported CartridgeFA2() = delete; From 40f0c2f6a0e185bea687ba2a3fea0caf1aa5619a Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 12 Apr 2020 09:02:28 +0200 Subject: [PATCH 101/377] remove superfluous code in Cart2K --- src/emucore/Cart2K.cxx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/emucore/Cart2K.cxx b/src/emucore/Cart2K.cxx index 24a328736..f4d4ef7bd 100644 --- a/src/emucore/Cart2K.cxx +++ b/src/emucore/Cart2K.cxx @@ -55,10 +55,4 @@ Cartridge2K::Cartridge2K(const ByteBuffer& image, size_t size, mySize = System::PAGE_SIZE; myBankShift = 6; } - - // update access arrays, bank size and mask based on new size - createRomAccessArrays(mySize); - - myBankSize = 1 << myBankShift; // e.g. = 2 ^ 11 = 2048 = 0x0800 - myBankMask = myBankSize - 1; // e.g. = 0x07FF } From eae35042fa61a61465d706cb263d69f570c07cfd Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 12 Apr 2020 11:35:41 +0200 Subject: [PATCH 102/377] improve CartEnhanced to allow swapped RAM read/write ports refactor CartCV add more CV test ROMs --- src/emucore/CartCV.cxx | 160 +++++------------------------------ src/emucore/CartCV.hxx | 82 +++--------------- src/emucore/CartEnhanced.cxx | 33 +++++--- src/emucore/CartEnhanced.hxx | 20 ++++- 4 files changed, 72 insertions(+), 223 deletions(-) diff --git a/src/emucore/CartCV.cxx b/src/emucore/CartCV.cxx index 42c74a808..136e817c3 100644 --- a/src/emucore/CartCV.cxx +++ b/src/emucore/CartCV.cxx @@ -21,164 +21,42 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeCV::CartridgeCV(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5), - mySize(size) + : CartridgeEnhanced(image, size, md5, settings) { - if(mySize == myImage.size()) - { - // Copy the ROM data into my buffer - std::copy_n(image.get(), myImage.size(), myImage.begin()); - } - else if(mySize == 4_KB) + myBankShift = BANK_SHIFT; + myRamSize = RAM_SIZE; + myRamWpHigh = RAM_HIGH_WP; + + + if(mySize == 4_KB) { // The game has something saved in the RAM // Useful for MagiCard program listings - // Copy the ROM data into my buffer - std::copy_n(image.get() + myImage.size(), myImage.size(), myImage.begin()); + // 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()); + + + myInitialRAM = make_unique(1_KB); // Copy the RAM image into a buffer for use in reset() - std::copy_n(image.get(), myInitialRAM.size(), myInitialRAM.begin()); + std::copy_n(image.get(), 1_KB, myInitialRAM.get()); } - createRomAccessArrays(myImage.size() + myRAM.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCV::reset() { - if(mySize == 4_KB) + if(myInitialRAM != nullptr) { // Copy the RAM image into my buffer - myRAM = myInitialRAM; + std::copy_n(myInitialRAM.get(), 1_KB, myRAM.get()); } else - initializeRAM(myRAM.data(), myRAM.size()); + initializeRAM(myRAM.get(), myRamSize); myBankChanged = true; } - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeCV::install(System& system) -{ - mySystem = &system; - - System::PageAccess access(this, System::PageAccessType::READ); - - // Map ROM image into the system - for(uInt16 addr = 0x1800; addr < 0x2000; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[addr & 0x07FF]; - access.romAccessBase = &myRomAccessBase[addr & 0x07FF]; - access.romPeekCounter = &myRomAccessCounter[addr & 0x07FF]; - access.romPokeCounter = &myRomAccessCounter[(addr & 0x07FF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Set the page accessing method for the RAM writing pages - // Map access to this class, since we need to inspect all accesses to - // check if RWP happens - access.directPeekBase = nullptr; - access.romAccessBase = nullptr; - access.type = System::PageAccessType::WRITE; - for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE) - mySystem->setPageAccess(addr, access); - - // Set the page accessing method for the RAM reading pages - access.directPokeBase = nullptr; - access.type = System::PageAccessType::READ; - for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myRAM[addr & 0x03FF]; - access.romAccessBase = &myRomAccessBase[2048 + (addr & 0x03FF)]; - access.romPeekCounter = &myRomAccessCounter[2048 + (addr & 0x03FF)]; - access.romPokeCounter = &myRomAccessCounter[2048 + (addr & 0x03FF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeCV::peek(uInt16 address) -{ - // The only way we can get to this method is if we attempt to read from - // the write port (0xF400 - 0xF7FF, 1024 bytes), in which case an - // unwanted write is potentially triggered - return peekRAM(myRAM[address & 0x03FF], address); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeCV::poke(uInt16 address, uInt8 value) -{ - - if(address & 0x0400) - { - pokeRAM(myRAM[address & 0x03FF], address, value); - return true; - } - else - { - // Writing to the read port should be ignored, but trigger a break if option enabled - uInt8 dummy; - - pokeRAM(dummy, address, value); - myRamWriteAccess = address; - return false; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeCV::patch(uInt16 address, uInt8 value) -{ - address &= 0x0FFF; - - if(address < 0x0800) - { - // Normally, a write to the read port won't do anything - // However, the patch command is special in that ignores such - // cart restrictions - // The following will work for both reads and writes - myRAM[address & 0x03FF] = value; - } - else - myImage[address & 0x07FF] = value; - - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeCV::getImage(size_t& size) const -{ - size = myImage.size(); - return myImage.data(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeCV::save(Serializer& out) const -{ - try - { - out.putByteArray(myRAM.data(), myRAM.size()); - } - catch(...) - { - cerr << "ERROR: CartridgeCV::save" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeCV::load(Serializer& in) -{ - try - { - in.getByteArray(myRAM.data(), myRAM.size()); - } - catch(...) - { - cerr << "ERROR: CartridgeCV::load" << endl; - return false; - } - - return true; -} diff --git a/src/emucore/CartCV.hxx b/src/emucore/CartCV.hxx index 3b872ce9d..4e18040a6 100644 --- a/src/emucore/CartCV.hxx +++ b/src/emucore/CartCV.hxx @@ -21,7 +21,7 @@ class System; #include "bspf.hxx" -#include "Cart.hxx" +#include "CartEnhanced.hxx" #ifdef DEBUGGER_SUPPORT #include "CartCVWidget.hxx" #endif @@ -33,9 +33,9 @@ class System; $F400-$F7FF write to RAM $F800-$FFFF ROM - @author Eckhard Stolberg + @author Eckhard Stolberg, Thomas Jentzsch */ -class CartridgeCV : public Cartridge +class CartridgeCV : public CartridgeEnhanced { friend class CartridgeCVWidget; @@ -58,47 +58,6 @@ class CartridgeCV : public Cartridge */ void reset() override; - /** - Install cartridge in the specified system. Invoked by the system - when the cartridge is attached to it. - - @param system The system the device should install itself in - */ - void install(System& system) override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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). @@ -118,35 +77,22 @@ class CartridgeCV : public Cartridge } #endif - public: - /** - Get the byte at the specified address + private: + bool checkSwitchBank(uInt16, uInt8 = 0) override { return false; }; - @return The byte at the specified address - */ - uInt8 peek(uInt16 address) override; - - /** - Change the byte at the specified address to the given value - - @param address The address where the value should be stored - @param value The value to be stored at the address - @return True if the poke changed the device address space, else false - */ - bool poke(uInt16 address, uInt8 value) override; + protected: + // Initial RAM data from the cart (doesn't always exist) + ByteBuffer myInitialRAM{nullptr}; private: - // The 2k ROM image for the cartridge - std::array myImage; + // Calculated as: log(ROM bank segment size) / log(2) + static constexpr uInt16 BANK_SHIFT = 11; // 2K - // Initial size of the cart data - size_t mySize{0}; + // RAM size + static constexpr uInt16 RAM_SIZE = 0x400; // 1K - // The 1024 bytes of RAM - std::array myRAM; - - // Initial RAM data from the cart (doesn't always exist) - std::array myInitialRAM; + // Write port for extra RAM is at high address + static constexpr bool RAM_HIGH_WP = true; private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index 6752d3153..c479ddd92 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -42,6 +42,8 @@ void CartridgeEnhanced::install(System& system) myBankMask = myBankSize - 1; // e.g. = 0x0FFF myBankSegs = 1 << (12 - myBankShift); // e.g. = 1 myRamMask = myRamSize - 1; // e.g. = 0xFFFF (doesn't matter for RAM size 0) + myWriteOffset = myRamWpHigh ? myRamSize : 0; + myReadOffset = myRamWpHigh ? 0 : myRamSize; // Allocate array for the current bank segments slices myCurrentSegOffset = make_unique(myBankSegs); @@ -58,24 +60,24 @@ void CartridgeEnhanced::install(System& system) // Map access to this class, since we need to inspect all accesses to // check if RWP happens access.type = System::PageAccessType::WRITE; - for(uInt16 addr = 0x1000; addr < 0x1000 + myRamSize; addr += System::PAGE_SIZE) + for(uInt16 addr = 0x1000 + myWriteOffset; addr < 0x1000 + myWriteOffset + myRamSize; addr += System::PAGE_SIZE) { uInt16 offset = addr & myRamMask; - access.romAccessBase = &myRomAccessBase[offset]; - access.romPeekCounter = &myRomAccessCounter[offset]; - access.romPokeCounter = &myRomAccessCounter[offset + myAccessSize]; + access.romAccessBase = &myRomAccessBase[myWriteOffset + offset]; + access.romPeekCounter = &myRomAccessCounter[myWriteOffset + offset]; + access.romPokeCounter = &myRomAccessCounter[myWriteOffset + offset + myAccessSize]; mySystem->setPageAccess(addr, access); } // Set the page accessing method for the RAM reading pages access.type = System::PageAccessType::READ; - for(uInt16 addr = 0x1000 + myRamSize; addr < 0x1000 + myRamSize * 2; addr += System::PAGE_SIZE) + for(uInt16 addr = 0x1000 + myReadOffset; addr < 0x1000 + myReadOffset + myRamSize; addr += System::PAGE_SIZE) { uInt16 offset = addr & myRamMask; access.directPeekBase = &myRAM[offset]; - access.romAccessBase = &myRomAccessBase[myRamSize + offset]; - access.romPeekCounter = &myRomAccessCounter[myRamSize + offset]; - access.romPokeCounter = &myRomAccessCounter[myRamSize + offset + myAccessSize]; + access.romAccessBase = &myRomAccessBase[myReadOffset + offset]; + access.romPeekCounter = &myRomAccessCounter[myReadOffset + offset]; + access.romPokeCounter = &myRomAccessCounter[myReadOffset + offset + myAccessSize]; mySystem->setPageAccess(addr, access); } @@ -106,7 +108,9 @@ uInt8 CartridgeEnhanced::peek(uInt16 address) checkSwitchBank(address & 0x0FFF); address &= myBankMask; - if(address < myRamSize) // Write port is at 0xF000 - 0xF07F (128 bytes) + // Write port is e.g. at 0xF000 - 0xF07F (128 bytes) + if(address < myReadOffset + myRamSize && address >= myReadOffset) + // This is a read accees to a write port! return peekRAM(myRAM[address], peekAddress); else return myImage[myCurrentSegOffset[(peekAddress & 0xFFF) >> myBankShift] + address]; @@ -115,15 +119,18 @@ uInt8 CartridgeEnhanced::peek(uInt16 address) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeEnhanced::poke(uInt16 address, uInt8 value) { + uInt16 pokeAddress = address; + // Switch banks if necessary if (checkSwitchBank(address & 0x0FFF, value)) return false; + address &= myBankMask; if(myRamSize) { - if(!(address & myRamSize)) + if(bool(address & myRamSize) == myRamWpHigh) { - pokeRAM(myRAM[address & myRamMask], address, value); + pokeRAM(myRAM[address & myRamMask], pokeAddress, value); return true; } else @@ -131,8 +138,8 @@ bool CartridgeEnhanced::poke(uInt16 address, uInt8 value) // Writing to the read port should be ignored, but trigger a break if option enabled uInt8 dummy; - pokeRAM(dummy, address, value); - myRamWriteAccess = address; + pokeRAM(dummy, pokeAddress, value); + myRamWriteAccess = pokeAddress; } } return false; diff --git a/src/emucore/CartEnhanced.hxx b/src/emucore/CartEnhanced.hxx index 6437c362e..6c67b6eaf 100644 --- a/src/emucore/CartEnhanced.hxx +++ b/src/emucore/CartEnhanced.hxx @@ -40,7 +40,7 @@ class CartridgeEnhanced : public Cartridge @param settings A reference to the various settings (read-only) */ CartridgeEnhanced(const ByteBuffer& image, size_t size, const string& md5, - const Settings& settings); + const Settings& settings); virtual ~CartridgeEnhanced() = default; public: @@ -160,6 +160,21 @@ class CartridgeEnhanced : public Cartridge // The mask for the extra RAM uInt16 myRamMask{0}; // RAM_SIZE - 1, but doesn't matter when RAM_SIZE is 0 + // The offset into ROM space for writing to RAM + // - xxSC = 0x0000 + // - FA(2) = 0x0000 + // - CV = 0x0400 + uInt16 myWriteOffset{0}; + + // The offset into ROM space for reading from RAM + // - xxSC = 0x0080 + // - FA(2) = 0x0100 + // - CV = 0x0000 + uInt16 myReadOffset{0}; + + // Flag, true if write port is at high and read port is at low address + bool myRamWpHigh{RAM_HIGH_WP}; + // Pointer to a dynamically allocated ROM image of the cartridge ByteBuffer myImage{nullptr}; @@ -182,6 +197,9 @@ class CartridgeEnhanced : public Cartridge // The size of extra RAM in ROM address space static constexpr uInt16 RAM_SIZE = 0; // default = none + // Write port for extra RAM is at low address by default + static constexpr bool RAM_HIGH_WP = false; + protected: /** Check hotspots and switch bank if triggered. From 3e6780d6bb2084f33eb6589b5c622e335112c19e Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sun, 12 Apr 2020 19:15:07 -0230 Subject: [PATCH 103/377] Fixed some warnings from clang. Just checking on the progress; looking good so far. --- src/emucore/Cart2K.hxx | 2 +- src/emucore/Cart4K.hxx | 2 +- src/emucore/CartCV.cxx | 2 -- src/emucore/CartCV.hxx | 2 +- src/emucore/CartDetector.cxx | 6 ++---- src/emucore/CartEnhanced.cxx | 3 +-- src/emucore/CartEnhanced.hxx | 1 - src/emucore/CartFA2.cxx | 3 +-- src/emucore/CartUA.hxx | 6 +++--- 9 files changed, 10 insertions(+), 17 deletions(-) diff --git a/src/emucore/Cart2K.hxx b/src/emucore/Cart2K.hxx index 1ef2ee250..0ed6fedef 100644 --- a/src/emucore/Cart2K.hxx +++ b/src/emucore/Cart2K.hxx @@ -73,7 +73,7 @@ class Cartridge2K : public CartridgeEnhanced #endif private: - bool checkSwitchBank(uInt16 address, uInt8 value = 0) override { return false; }; + bool checkSwitchBank(uInt16 address, uInt8 value = 0) override { return false; } private: // Following constructors and assignment operators not supported diff --git a/src/emucore/Cart4K.hxx b/src/emucore/Cart4K.hxx index 70819c5b2..1a7c428f4 100644 --- a/src/emucore/Cart4K.hxx +++ b/src/emucore/Cart4K.hxx @@ -70,7 +70,7 @@ class Cartridge4K : public CartridgeEnhanced #endif private: - bool checkSwitchBank(uInt16 address, uInt8 value = 0) override { return false; }; + bool checkSwitchBank(uInt16 address, uInt8 value = 0) override { return false; } private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartCV.cxx b/src/emucore/CartCV.cxx index 136e817c3..8d7ac9d89 100644 --- a/src/emucore/CartCV.cxx +++ b/src/emucore/CartCV.cxx @@ -27,7 +27,6 @@ CartridgeCV::CartridgeCV(const ByteBuffer& image, size_t size, myRamSize = RAM_SIZE; myRamWpHigh = RAM_HIGH_WP; - if(mySize == 4_KB) { // The game has something saved in the RAM @@ -40,7 +39,6 @@ CartridgeCV::CartridgeCV(const ByteBuffer& image, size_t size, // Copy the ROM image into my buffer std::copy_n(image.get() + mySize, mySize, myImage.get()); - myInitialRAM = make_unique(1_KB); // Copy the RAM image into a buffer for use in reset() std::copy_n(image.get(), 1_KB, myInitialRAM.get()); diff --git a/src/emucore/CartCV.hxx b/src/emucore/CartCV.hxx index 4e18040a6..1b4773e5e 100644 --- a/src/emucore/CartCV.hxx +++ b/src/emucore/CartCV.hxx @@ -78,7 +78,7 @@ class CartridgeCV : public CartridgeEnhanced #endif private: - bool checkSwitchBank(uInt16, uInt8 = 0) override { return false; }; + bool checkSwitchBank(uInt16, uInt8 = 0) override { return false; } protected: // Initial RAM data from the cart (doesn't always exist) diff --git a/src/emucore/CartDetector.cxx b/src/emucore/CartDetector.cxx index b6e6f150a..9fe79314f 100644 --- a/src/emucore/CartDetector.cxx +++ b/src/emucore/CartDetector.cxx @@ -951,14 +951,13 @@ bool CartDetector::isProbablyFC(const ByteBuffer& image, size_t size) { 0x8d, 0xf8, 0xff, 0x8d, 0xfc, 0xff }, // STA $FFF8, STA $FFFC Surf's Up (4K) { 0x8c, 0xf9, 0xff, 0xad, 0xfc, 0xff } // STY $FFF9, LDA $FFFC 3-D Havoc }; - for (uInt32 i = 0; i < 3; ++i) - if (searchForBytes(image.get(), size, signature[i], 6, 1)) + for(uInt32 i = 0; i < 3; ++i) + if(searchForBytes(image.get(), size, signature[i], 6, 1)) return true; return false; } - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbablyFE(const ByteBuffer& image, size_t size) { @@ -1032,7 +1031,6 @@ bool CartDetector::isProbablyWD(const ByteBuffer& image, size_t size) return searchForBytes(image.get(), size, signature[0], 3, 1); } - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbablyX07(const ByteBuffer& image, size_t size) { diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index c479ddd92..db2768ed0 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -110,7 +110,7 @@ uInt8 CartridgeEnhanced::peek(uInt16 address) // Write port is e.g. at 0xF000 - 0xF07F (128 bytes) if(address < myReadOffset + myRamSize && address >= myReadOffset) - // This is a read accees to a write port! + // This is a read access to a write port! return peekRAM(myRAM[address], peekAddress); else return myImage[myCurrentSegOffset[(peekAddress & 0xFFF) >> myBankShift] + address]; @@ -233,7 +233,6 @@ bool CartridgeEnhanced::save(Serializer& out) const out.putIntArray(myCurrentSegOffset.get(), myBankSegs); if(myRamSize) out.putByteArray(myRAM.get(), myRamSize); - } catch(...) { diff --git a/src/emucore/CartEnhanced.hxx b/src/emucore/CartEnhanced.hxx index 6c67b6eaf..dd8bd4322 100644 --- a/src/emucore/CartEnhanced.hxx +++ b/src/emucore/CartEnhanced.hxx @@ -57,7 +57,6 @@ class CartridgeEnhanced : public Cartridge */ void reset() override; - /** Install pages for the specified bank in the system. diff --git a/src/emucore/CartFA2.cxx b/src/emucore/CartFA2.cxx index 0d892c9b3..1e4251988 100644 --- a/src/emucore/CartFA2.cxx +++ b/src/emucore/CartFA2.cxx @@ -49,11 +49,10 @@ bool CartridgeFA2::checkSwitchBank(uInt16 address, uInt8) } return false; } - + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeFA2::peek(uInt16 address) { - if((address & 0x0FFF) == 0x0FF4) { // Load/save RAM to/from Harmony cart flash diff --git a/src/emucore/CartUA.hxx b/src/emucore/CartUA.hxx index 94dcb4a98..97569dd76 100644 --- a/src/emucore/CartUA.hxx +++ b/src/emucore/CartUA.hxx @@ -59,13 +59,14 @@ class CartridgeUA : public CartridgeEnhanced */ void install(System& system) override; - /** Get a descriptor for the device name (used in error checking). @return The name of the object */ - string name() const override { return mySwappedHotspots ? "CartridgeUASW" : "CartridgeUA"; } + string name() const override { + return mySwappedHotspots ? "CartridgeUASW" : "CartridgeUA"; + } #ifdef DEBUGGER_SUPPORT /** @@ -96,7 +97,6 @@ class CartridgeUA : public CartridgeEnhanced */ bool poke(uInt16 address, uInt8 value) override; - private: bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; From ac3ce8cb595357beb9a90fee90b32fd5b1c50d0e Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 13 Apr 2020 18:05:44 +0200 Subject: [PATCH 104/377] intermediate commit for refactoring 3E (something got broken in disassembly before) --- src/emucore/Cart3E.cxx | 29 ++++++----- src/emucore/Cart3E.hxx | 6 +++ src/emucore/CartEnhanced.cxx | 99 +++++++++++++++++++++++++++--------- src/emucore/CartEnhanced.hxx | 16 ++++-- 4 files changed, 106 insertions(+), 44 deletions(-) diff --git a/src/emucore/Cart3E.cxx b/src/emucore/Cart3E.cxx index 0947d783e..f5f37febc 100644 --- a/src/emucore/Cart3E.cxx +++ b/src/emucore/Cart3E.cxx @@ -23,7 +23,8 @@ Cartridge3E::Cartridge3E(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) : Cartridge(settings, md5), - mySize(size) + mySize(size), + myRomBanks(256/*uInt16(size) >> 11*/) { // Allocate array for the ROM image myImage = make_unique(mySize); @@ -80,10 +81,10 @@ uInt8 Cartridge3E::peek(uInt16 address) if(address < 0x0040) // TIA access return mySystem->tia().peek(address); - else if(myCurrentBank >= 256) + else if(myCurrentBank >= myRomBanks) { // Reading from the write port triggers an unwanted write - return peekRAM(myRAM[(address & 0x03FF) + ((myCurrentBank - 256) << 10)], peekAddress); + return peekRAM(myRAM[(address & 0x03FF) + ((myCurrentBank - myRomBanks) << 10)], peekAddress); } // Make compiler happy; should never get here @@ -103,15 +104,15 @@ bool Cartridge3E::poke(uInt16 address, uInt8 value) if(address == 0x003F) bank(value); else if(address == 0x003E) - bank(value + 256); + bank(value + myRomBanks); return mySystem->tia().poke(address, value); } - else if(myCurrentBank >= 256) + else if(myCurrentBank >= myRomBanks) { if(address & 0x0400) { - pokeRAM(myRAM[(address & 0x03FF) + ((myCurrentBank - 256) << 10)], + pokeRAM(myRAM[(address & 0x03FF) + ((myCurrentBank - myRomBanks) << 10)], pokeAddress, value); return true; } @@ -133,7 +134,7 @@ bool Cartridge3E::bank(uInt16 bank) { if(bankLocked()) return false; - if(bank < 256) + if(bank < myRomBanks) { // Make sure the bank they're asking for is reasonable if((uInt32(bank) << 11) < mySize) @@ -164,9 +165,9 @@ bool Cartridge3E::bank(uInt16 bank) } else { - bank -= 256; - bank %= 32; - myCurrentBank = bank + 256; + bank -= myRomBanks; + bank %= myRamBanks; + myCurrentBank = bank + myRomBanks; uInt32 offset = bank << 10; @@ -204,7 +205,7 @@ bool Cartridge3E::bank(uInt16 bank) uInt16 Cartridge3E::getBank(uInt16 address) const { if (address & 0x800) - return 255; // 256 - 1 // 2K slices, fixed bank + return myRomBanks - 1; // 2K slices, fixed bank else return myCurrentBank; } @@ -217,7 +218,7 @@ uInt16 Cartridge3E::bankCount() const // If the RAM banks were simply appended to the number of actual // ROM banks, bank numbers would be ambiguous (ie, would bank 128 be // the last bank of ROM, or one of the banks of RAM?) - return 256 + 32; + return myRomBanks + myRamBanks; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -227,10 +228,10 @@ bool Cartridge3E::patch(uInt16 address, uInt8 value) if(address < 0x0800) { - if(myCurrentBank < 256) + if(myCurrentBank < myRomBanks) myImage[(address & 0x07FF) + (myCurrentBank << 11)] = value; else - myRAM[(address & 0x03FF) + ((myCurrentBank - 256) << 10)] = value; + myRAM[(address & 0x03FF) + ((myCurrentBank - myRomBanks) << 10)] = value; } else myImage[(address & 0x07FF) + mySize - 2048] = value; diff --git a/src/emucore/Cart3E.hxx b/src/emucore/Cart3E.hxx index 554560fd5..6b2ea0b88 100644 --- a/src/emucore/Cart3E.hxx +++ b/src/emucore/Cart3E.hxx @@ -190,6 +190,12 @@ class Cartridge3E : public Cartridge // Size of the ROM image size_t mySize{0}; + // Size of the ROM image + uInt16 myRomBanks{0}; + + // Size of the ROM image + uInt16 myRamBanks{32}; + // Indicates which bank is currently active for the first segment uInt16 myCurrentBank{0}; diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index db2768ed0..1a446a9a8 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -146,40 +146,89 @@ bool CartridgeEnhanced::poke(uInt16 address, uInt8 value) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) +bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment, bool isRAM) { if(bankLocked()) return false; - // Remember what bank is in which segment - uInt32 bankOffset = myCurrentSegOffset[segment] = bank << myBankShift; uInt16 segmentOffset = segment << myBankShift; - uInt16 hotspot = this->hotspot(); - uInt16 hotSpotAddr; - uInt16 fromAddr = (segmentOffset + 0x1000 + myRamSize * 2) & ~System::PAGE_MASK; - // for ROMs < 4_KB, the whole address space will be mapped. - uInt16 toAddr = (segmentOffset + 0x1000 + (mySize < 4_KB ? 0x1000 : myBankSize)) & ~System::PAGE_MASK; - if(hotspot) - hotSpotAddr = (hotspot & ~System::PAGE_MASK); - else - hotSpotAddr = 0xFFFF; // none - - System::PageAccess access(this, System::PageAccessType::READ); - - // Setup the page access methods for the current bank - for(uInt16 addr = fromAddr; addr < toAddr; addr += System::PAGE_SIZE) + if(!isRAM) { - uInt32 offset = bankOffset + (addr & myBankMask); + // Setup ROM bank + // Remember what bank is in which segment + uInt32 bankOffset = myCurrentSegOffset[segment] = bank << myBankShift; - if(myDirectPeek && addr != hotSpotAddr) - access.directPeekBase = &myImage[offset]; + uInt16 hotspot = this->hotspot(); + uInt16 hotSpotAddr; + uInt16 fromAddr = (segmentOffset + 0x1000 + myRamSize * 2) & ~System::PAGE_MASK; + // for ROMs < 4_KB, the whole address space will be mapped. + uInt16 toAddr = (segmentOffset + 0x1000 + (mySize < 4_KB ? 0x1000 : myBankSize)) & ~System::PAGE_MASK; + + if(hotspot) + hotSpotAddr = (hotspot & ~System::PAGE_MASK); else - access.directPeekBase = nullptr; - access.romAccessBase = &myRomAccessBase[offset]; - access.romPeekCounter = &myRomAccessCounter[offset]; - access.romPokeCounter = &myRomAccessCounter[offset + myAccessSize]; - mySystem->setPageAccess(addr, access); + hotSpotAddr = 0xFFFF; // none + + System::PageAccess access(this, System::PageAccessType::READ); + // Setup the page access methods for the current bank + for(uInt16 addr = fromAddr; addr < toAddr; addr += System::PAGE_SIZE) + { + uInt32 offset = bankOffset + (addr & myBankMask); + + if(myDirectPeek && addr != hotSpotAddr) + access.directPeekBase = &myImage[offset]; + else + access.directPeekBase = nullptr; + access.romAccessBase = &myRomAccessBase[offset]; + access.romPeekCounter = &myRomAccessCounter[offset]; + access.romPokeCounter = &myRomAccessCounter[offset + myAccessSize]; + mySystem->setPageAccess(addr, access); + } } + /*else + { + // Setup RAM bank + // TODO: define offsets on init + uInt16 myWriteBankOffset = myBankSize >> 1; + uInt16 myReadBankOffset = 0; + + // Remember what bank is in which segment + uInt32 bankOffset = myCurrentSegOffset[segment] = bank << myBankShift; + + // Set the page accessing method for the RAM writing pages + uInt16 fromAddr = (segmentOffset + myWriteBankOffset + 0x1000) & ~System::PAGE_MASK; + uInt16 toAddr = (segmentOffset + myWriteBankOffset + 0x1000 + myBankSize >> 1) & ~System::PAGE_MASK; + System::PageAccess access(this, System::PageAccessType::WRITE); + + for(uInt16 addr = fromAddr; addr < toAddr; addr += System::PAGE_SIZE) + { + uInt32 offset = bankOffset + (addr & myBankMask); + + access.romAccessBase = &myRomAccessBase[offset]; + access.romPeekCounter = &myRomAccessCounter[offset]; + access.romPokeCounter = &myRomAccessCounter[offset + myAccessSize]; + mySystem->setPageAccess(addr, access); + } + + // Set the page accessing method for the RAM reading pages + fromAddr = (segmentOffset + myReadBankOffset + 0x1000) & ~System::PAGE_MASK; + toAddr = (segmentOffset + myReadBankOffset + 0x1000 + myBankSize >> 1) & ~System::PAGE_MASK; + + access.type = System::PageAccessType::READ; + for(uInt16 addr = fromAddr; addr < toAddr; addr += System::PAGE_SIZE) + { + uInt32 offset = bankOffset + (addr & myBankMask); + + + + uInt16 offset = addr & myRamMask; + access.directPeekBase = &myBankRAM[offset]; + access.romAccessBase = &myRomAccessBase[offset]; + access.romPeekCounter = &myRomAccessCounter[offset]; + access.romPokeCounter = &myRomAccessCounter[offset + myAccessSize]; + mySystem->setPageAccess(addr, access); + } + }*/ return myBankChanged = true; } diff --git a/src/emucore/CartEnhanced.hxx b/src/emucore/CartEnhanced.hxx index dd8bd4322..29046f0ea 100644 --- a/src/emucore/CartEnhanced.hxx +++ b/src/emucore/CartEnhanced.hxx @@ -60,28 +60,34 @@ class CartridgeEnhanced : 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 + @param isRAM True if the bank is a RAM bank + + @return true, if bank has changed */ - bool bank(uInt16 bank, uInt16 segment); + bool bank(uInt16 bank, uInt16 segment, bool isRAM = false); /** 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 + + @return true, if bank has changed */ bool bank(uInt16 bank) override { return this->bank(bank, 0); } /** Get the current bank. - @param address The address to use when querying the bank + @param address The address to use when querying the bank */ uInt16 getBank(uInt16 address = 0) const override; /** Get the current bank for a bank segment. - @param segment The segment to get the bank for + @param segment The segment to get the bank for */ uInt16 getSegmentBank(uInt16 segment = 0) const; From 59e530fc78655a6c59941231f0cdbcd13ea93bd9 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 13 Apr 2020 19:34:34 +0200 Subject: [PATCH 105/377] fix 3E disassembly (bankSize() override) --- src/emucore/Cart3E.cxx | 6 ++++++ src/emucore/Cart3E.hxx | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/src/emucore/Cart3E.cxx b/src/emucore/Cart3E.cxx index 0947d783e..963fd14de 100644 --- a/src/emucore/Cart3E.cxx +++ b/src/emucore/Cart3E.cxx @@ -220,6 +220,12 @@ uInt16 Cartridge3E::bankCount() const return 256 + 32; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt16 Cartridge3E::bankSize(uInt16 bank) const +{ + return 2_KB; // we cannot use bankCount() here, because it delivers wrong numbers +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge3E::patch(uInt16 address, uInt8 value) { diff --git a/src/emucore/Cart3E.hxx b/src/emucore/Cart3E.hxx index 554560fd5..021497c82 100644 --- a/src/emucore/Cart3E.hxx +++ b/src/emucore/Cart3E.hxx @@ -111,6 +111,14 @@ class Cartridge3E : public Cartridge */ uInt16 bankCount() const override; + /** + Get the size of a bank. + + @param bank The bank to get the size for + @return The bank's size + */ + virtual uInt16 bankSize(uInt16 bank = 0) const; + /** Patch the cartridge ROM. From 7fb2d096b967272751effb0d02e6a648bb720d8a Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 13 Apr 2020 21:58:16 +0200 Subject: [PATCH 106/377] removed CV+ type (incl. doc update) --- Changes.txt | 4 +- docs/index.html | 23 ++- src/debugger/gui/CartCVPlusWidget.cxx | 157 ----------------- src/debugger/gui/CartCVPlusWidget.hxx | 73 -------- src/debugger/gui/module.mk | 3 +- src/emucore/Bankswitch.cxx | 3 - src/emucore/Bankswitch.hxx | 16 +- src/emucore/CartCVPlus.cxx | 235 -------------------------- src/emucore/CartCVPlus.hxx | 188 --------------------- src/emucore/CartDetector.cxx | 19 +-- src/emucore/CartDetector.hxx | 5 - src/emucore/module.mk | 3 +- src/windows/Stella.vcxproj | 8 - src/windows/Stella.vcxproj.filters | 12 -- 14 files changed, 31 insertions(+), 718 deletions(-) delete mode 100644 src/debugger/gui/CartCVPlusWidget.cxx delete mode 100644 src/debugger/gui/CartCVPlusWidget.hxx delete mode 100644 src/emucore/CartCVPlus.cxx delete mode 100644 src/emucore/CartCVPlus.hxx diff --git a/Changes.txt b/Changes.txt index 60fd29f4e..7a6b7bc3d 100644 --- a/Changes.txt +++ b/Changes.txt @@ -22,7 +22,7 @@ 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) - * Add option which lets default ROM path follow launcher navigation (TODO: Doc) + * Added option which lets default ROM path follow launcher navigation (TODO: Doc) * Added displaying last write address in the debugger. @@ -30,6 +30,8 @@ * Restored 'cfg' directory for Distella config files. + * Removed unused CV+ bank switching type. + -Have fun! diff --git a/docs/index.html b/docs/index.html index 68be48e0d..b0065878b 100644 --- a/docs/index.html +++ b/docs/index.html @@ -3756,7 +3756,9 @@ Ms Pac-Man (Stella extended codes):

      Each block in a property file consists of a set of properties for a single game. Stella supports the properties described below:

      - +

      + +

      @@ -3791,8 +3793,7 @@ Ms Pac-Man (Stella extended codes): - - + @@ -3875,11 +3876,15 @@ Ms Pac-Man (Stella extended codes):
      CDF Chris, Darrell, Fred (includes CDFJ).CDF
      CM ¹Spectravideo CompuMate .CM
      CTY ²CDW - Chetiry .CTY
      CV Commavid extra RAM .CV
      CV+ Extended Commavid extra RAM.CVP
      CV CommaVid extra RAM .CV
      DASH Boulder Dash 2 .DAS, .DASH
      DF CPUWIZ 128K .DF
      DFSC CPUWIZ 128K + RAM.DFS, .DFSC
      +
      - +

      + +

      + @@ -3899,8 +3904,11 @@ Ms Pac-Man (Stella extended codes): right player. The value must be A or B.
      Console.TelevisionType:
      +
      - +

      + +

      @@ -3975,8 +3983,11 @@ Ms Pac-Man (Stella extended codes): how to use the X/Y axis (ie, 02 is paddle0/paddle2). -->
      Controller.Left:
      Controller.Right:
      +
      - +

      + +

      diff --git a/src/debugger/gui/CartCVPlusWidget.cxx b/src/debugger/gui/CartCVPlusWidget.cxx deleted file mode 100644 index cab27d3e5..000000000 --- a/src/debugger/gui/CartCVPlusWidget.cxx +++ /dev/null @@ -1,157 +0,0 @@ -//============================================================================ -// -// 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 "Debugger.hxx" -#include "CartDebug.hxx" -#include "CartCVPlus.hxx" -#include "PopUpWidget.hxx" -#include "CartCVPlusWidget.hxx" - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -CartridgeCVPlusWidget::CartridgeCVPlusWidget( - GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, - int x, int y, int w, int h, CartridgeCVPlus& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) -{ - size_t size = cart.mySize; - - ostringstream info; - info << "LS_Dracon CV+ cartridge, 1K RAM, 2-256 2K ROM\n" - << "1024 bytes RAM @ $F000 - $F7FF\n" - << " $F000 - $F3FF (R), $F400 - $F7FF (W)\n" - << "2048 bytes ROM @ $F800 - $FFFF, by writing to $3D\n" - << "Startup bank = " << cart.startBank() << "\n"; - - int xpos = 2, - ypos = addBaseInformation(size, "LS_Dracon / Stephen Anthony", - info.str()) + myLineHeight; - - VariantList items; - for(uInt16 i = 0; i < cart.bankCount(); ++i) - VarList::push_back(items, Variant(i).toString() + " ($3D)"); - - ostringstream label; - label << "Set bank ($F800 - $FFFF) "; - myBank = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("xxx ($3D)"), - myLineHeight, items, label.str(), - _font.getStringWidth(label.str()), kBankChanged); - myBank->setTarget(this); - addFocusWidget(myBank); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeCVPlusWidget::loadConfig() -{ - myBank->setSelectedIndex(myCart.getBank(), myCart.getBank() != myOldState.bank); - - CartDebugWidget::loadConfig(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeCVPlusWidget::handleCommand(CommandSender* sender, - int cmd, int data, int id) -{ - if(cmd == kBankChanged) - { - myCart.unlockBank(); - myCart.bank(myBank->getSelected()); - myCart.lockBank(); - invalidate(); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeCVPlusWidget::bankState() -{ - ostringstream& buf = buffer(); - - buf << "Bank = " << std::dec << myCart.myCurrentBank << ", hotspot = $3D"; - - return buf.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeCVPlusWidget::saveOldState() -{ - myOldState.internalram.clear(); - - for(uInt32 i = 0; i < internalRamSize(); ++i) - myOldState.internalram.push_back(myCart.myRAM[i]); - - myOldState.bank = myCart.getBank(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 CartridgeCVPlusWidget::internalRamSize() -{ - return 1024; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 CartridgeCVPlusWidget::internalRamRPort(int start) -{ - return 0xF000 + start; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeCVPlusWidget::internalRamDescription() -{ - ostringstream desc; - desc << "$F000 - $F3FF used for Read Access\n" - << "$F400 - $F7FF used for Write Access"; - - return desc.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& CartridgeCVPlusWidget::internalRamOld(int start, int count) -{ - myRamOld.clear(); - for(int i = 0; i < count; i++) - myRamOld.push_back(myOldState.internalram[start + i]); - return myRamOld; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& CartridgeCVPlusWidget::internalRamCurrent(int start, int count) -{ - myRamCurrent.clear(); - for(int i = 0; i < count; i++) - myRamCurrent.push_back(myCart.myRAM[start + i]); - return myRamCurrent; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeCVPlusWidget::internalRamSetValue(int addr, uInt8 value) -{ - myCart.myRAM[addr] = value; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeCVPlusWidget::internalRamGetValue(int addr) -{ - return myCart.myRAM[addr]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeCVPlusWidget::internalRamLabel(int addr) -{ - CartDebug& dbg = instance().debugger().cartDebug(); - return dbg.getLabel(addr + 0xF000, false); -} diff --git a/src/debugger/gui/CartCVPlusWidget.hxx b/src/debugger/gui/CartCVPlusWidget.hxx deleted file mode 100644 index b1401b07c..000000000 --- a/src/debugger/gui/CartCVPlusWidget.hxx +++ /dev/null @@ -1,73 +0,0 @@ -//============================================================================ -// -// 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 CARTRIDGECVPlus_WIDGET_HXX -#define CARTRIDGECVPlus_WIDGET_HXX - -class CartridgeCVPlus; -class PopUpWidget; - -#include "CartDebugWidget.hxx" - -class CartridgeCVPlusWidget : public CartDebugWidget -{ - public: - CartridgeCVPlusWidget(GuiObject* boss, const GUI::Font& lfont, - const GUI::Font& nfont, - int x, int y, int w, int h, - CartridgeCVPlus& cart); - virtual ~CartridgeCVPlusWidget() = default; - - private: - CartridgeCVPlus& myCart; - PopUpWidget* myBank{nullptr}; - struct CartState { - ByteArray internalram; - uInt16 bank{0}; - }; - CartState myOldState; - - enum { kBankChanged = 'bkCH' }; - - private: - void loadConfig() override; - void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - - string bankState() override; - - void saveOldState() override; - - // start of functions for Cartridge RAM tab - uInt32 internalRamSize() override; - uInt32 internalRamRPort(int start) override; - string internalRamDescription() override; - const ByteArray& internalRamOld(int start, int count) override; - const ByteArray& internalRamCurrent(int start, int count) override; - void internalRamSetValue(int addr, uInt8 value) override; - uInt8 internalRamGetValue(int addr) override; - string internalRamLabel(int addr) override; - // end of functions for Cartridge RAM tab - - // Following constructors and assignment operators not supported - CartridgeCVPlusWidget() = delete; - CartridgeCVPlusWidget(const CartridgeCVPlusWidget&) = delete; - CartridgeCVPlusWidget(CartridgeCVPlusWidget&&) = delete; - CartridgeCVPlusWidget& operator=(const CartridgeCVPlusWidget&) = delete; - CartridgeCVPlusWidget& operator=(CartridgeCVPlusWidget&&) = delete; -}; - -#endif diff --git a/src/debugger/gui/module.mk b/src/debugger/gui/module.mk index d80408a60..522d31cf4 100644 --- a/src/debugger/gui/module.mk +++ b/src/debugger/gui/module.mk @@ -21,8 +21,7 @@ MODULE_OBJS := \ src/debugger/gui/CartCDFWidget.o \ src/debugger/gui/CartCDFInfoWidget.o \ src/debugger/gui/CartCMWidget.o \ - src/debugger/gui/CartCTYWidget.o \ - src/debugger/gui/CartCVPlusWidget.o \ + src/debugger/gui/CartCTYWidget.o \ src/debugger/gui/CartCVWidget.o \ src/debugger/gui/CartDASHWidget.o \ src/debugger/gui/CartDFSCWidget.o \ diff --git a/src/emucore/Bankswitch.cxx b/src/emucore/Bankswitch.cxx index 231d6f73f..9726dc6aa 100644 --- a/src/emucore/Bankswitch.cxx +++ b/src/emucore/Bankswitch.cxx @@ -118,7 +118,6 @@ Bankswitch::BSList = {{ { "CM" , "CM (SpectraVideo CompuMate)" }, { "CTY" , "CTY (CDW - Chetiry)" }, { "CV" , "CV (Commavid extra RAM)" }, - { "CV+" , "CV+ (Extended Commavid)" }, { "DASH" , "DASH (Experimental)" }, { "DF" , "DF (CPUWIZ 128K)" }, { "DFSC" , "DFSC (CPUWIZ 128K + RAM)" }, @@ -197,7 +196,6 @@ Bankswitch::ExtensionMap Bankswitch::ourExtensions = { { "CM" , Bankswitch::Type::_CM }, { "CTY" , Bankswitch::Type::_CTY }, { "CV" , Bankswitch::Type::_CV }, - { "CVP" , Bankswitch::Type::_CVP }, { "DAS" , Bankswitch::Type::_DASH }, { "DASH" , Bankswitch::Type::_DASH }, { "DF" , Bankswitch::Type::_DF }, @@ -262,7 +260,6 @@ Bankswitch::NameToTypeMap Bankswitch::ourNameToTypes = { { "CM" , Bankswitch::Type::_CM }, { "CTY" , Bankswitch::Type::_CTY }, { "CV" , Bankswitch::Type::_CV }, - { "CV+" , Bankswitch::Type::_CVP }, { "DASH" , Bankswitch::Type::_DASH }, { "DF" , Bankswitch::Type::_DF }, { "DFSC" , Bankswitch::Type::_DFSC }, diff --git a/src/emucore/Bankswitch.hxx b/src/emucore/Bankswitch.hxx index c57f81609..4ed7cc445 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, _3EP, _3F, _4A50, - _4K, _4KSC, _AR, _BF, _BFSC, _BUS, _CDF, - _CM, _CTY, _CV, _CVP, _DASH, _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, _3EP, _3F, _4A50, + _4K, _4KSC, _AR, _BF, _BFSC, _BUS, _CDF, + _CM, _CTY, _CV, _DASH, _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, #ifdef CUSTOM_ARM _CUSTOM, #endif diff --git a/src/emucore/CartCVPlus.cxx b/src/emucore/CartCVPlus.cxx deleted file mode 100644 index a3258e53c..000000000 --- a/src/emucore/CartCVPlus.cxx +++ /dev/null @@ -1,235 +0,0 @@ -//============================================================================ -// -// 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 "TIA.hxx" -#include "CartCVPlus.hxx" - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -CartridgeCVPlus::CartridgeCVPlus(const ByteBuffer& image, size_t size, - const string& md5, const Settings& settings) - : Cartridge(settings, md5), - mySize(size) -{ - // Allocate array for the ROM image - myImage = make_unique(mySize); - - // Copy the ROM image into my buffer - std::copy_n(image.get(), mySize, myImage.get()); - createRomAccessArrays(mySize + myRAM.size()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeCVPlus::reset() -{ - initializeRAM(myRAM.data(), myRAM.size()); - initializeStartBank(0); - - // We'll map the startup bank into the first segment upon reset - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeCVPlus::install(System& system) -{ - mySystem = &system; - - System::PageAccess access(this, System::PageAccessType::READWRITE); - - // The hotspot ($3D) is in TIA address space, so we claim it here - for(uInt16 addr = 0x00; addr < 0x40; addr += System::PAGE_SIZE) - mySystem->setPageAccess(addr, access); - - // Set the page accessing method for the RAM writing pages - // Map access to this class, since we need to inspect all accesses to - // check if RWP happens - access.directPeekBase = access.directPokeBase = nullptr; - access.romAccessBase = nullptr; - access.type = System::PageAccessType::WRITE; - for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[mySize + (addr & 0x03FF)]; - access.romPeekCounter = &myRomAccessCounter[mySize + (addr & 0x03FF)]; - access.romPokeCounter = &myRomAccessCounter[mySize + (addr & 0x03FF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Set the page accessing method for the RAM reading pages - access.type = System::PageAccessType::READ; - for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myRAM[addr & 0x03FF]; - access.romAccessBase = &myRomAccessBase[mySize + (addr & 0x03FF)]; - access.romPeekCounter = &myRomAccessCounter[mySize + (addr & 0x03FF)]; - access.romPokeCounter = &myRomAccessCounter[mySize + (addr & 0x03FF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Install pages for the startup bank into the first segment - bank(startBank()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeCVPlus::peek(uInt16 address) -{ - if((address & 0x0FFF) < 0x0800) // Write port is at 0xF400 - 0xF7FF (1024 bytes) - return peekRAM(myRAM[address & 0x03FF], address); - else - return myImage[(address & 0x07FF) + (myCurrentBank << 11)]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeCVPlus::poke(uInt16 address, uInt8 value) -{ - uInt16 pokeAddress = address; - address &= 0x0FFF; - - if(address < 0x0040) - { - // Switch banks if necessary - if(address == 0x003D) - bank(value); - - // Handle TIA space that we claimed above - return mySystem->tia().poke(address, value); - } - else - { - if(address & 0x0400) - { - pokeRAM(myRAM[address & 0x03FF], pokeAddress, value); - return true; - } - else - { - // Writing to the read port should be ignored, but trigger a break if option enabled - uInt8 dummy; - - pokeRAM(dummy, pokeAddress, value); - myRamWriteAccess = pokeAddress; - return false; - } - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeCVPlus::bank(uInt16 bank) -{ - if(bankLocked()) return false; - - // Make sure the bank they're asking for is reasonable - if((uInt32(bank) << 11) < mySize) - { - myCurrentBank = bank; - } - else - { - // Oops, the bank they're asking for isn't valid so let's wrap it - // around to a valid bank number - myCurrentBank = bank % (mySize >> 11); - } - - uInt32 offset = myCurrentBank << 11; - - // Setup the page access methods for the current bank - System::PageAccess access(this, System::PageAccessType::READ); - - // Map ROM image into the system - for(uInt16 addr = 0x1800; addr < 0x2000; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[offset + (addr & 0x07FF)]; - access.romAccessBase = &myRomAccessBase[offset + (addr & 0x07FF)]; - mySystem->setPageAccess(addr, access); - } - - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeCVPlus::getBank(uInt16) const -{ - return myCurrentBank; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeCVPlus::bankCount() const -{ - return uInt16(mySize >> 11); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeCVPlus::patch(uInt16 address, uInt8 value) -{ - address &= 0x0FFF; - - if(address < 0x0800) - { - // Normally, a write to the read port won't do anything - // However, the patch command is special in that ignores such - // cart restrictions - // The following will work for both reads and writes - myRAM[address & 0x03FF] = value; - } - else - myImage[(address & 0x07FF) + (myCurrentBank << 11)] = value; - - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeCVPlus::getImage(size_t& size) const -{ - size = mySize; - return myImage.get(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeCVPlus::save(Serializer& out) const -{ - try - { - out.putShort(myCurrentBank); - out.putByteArray(myRAM.data(), myRAM.size()); - } - catch(...) - { - cerr << "ERROR: CartridgeCVPlus::save" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeCVPlus::load(Serializer& in) -{ - try - { - myCurrentBank = in.getShort(); - in.getByteArray(myRAM.data(), myRAM.size()); - } - catch(...) - { - cerr << "ERROR: CartridgeCVPlus::load" << endl; - return false; - } - - // Now, go to the current bank - bank(myCurrentBank); - - return true; -} diff --git a/src/emucore/CartCVPlus.hxx b/src/emucore/CartCVPlus.hxx deleted file mode 100644 index 63fcb62da..000000000 --- a/src/emucore/CartCVPlus.hxx +++ /dev/null @@ -1,188 +0,0 @@ -//============================================================================ -// -// 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 CARTRIDGECVPlus_HXX -#define CARTRIDGECVPlus_HXX - -class System; - -#include "bspf.hxx" -#include "Cart.hxx" -#ifdef DEBUGGER_SUPPORT - #include "CartCVPlusWidget.hxx" -#endif - -/** - Cartridge class based on both Commavid and 3F/3E schemes: - - Commavid (RAM): - $F000-$F3FF read from RAM - $F400-$F7FF write to RAM - - 3F/3E (ROM): - $F800-$FFFF ROM - - In this bankswitching scheme the 2600's 4K cartridge - address space is broken into two 2K segments. The lower 2K - is RAM, as decribed above (same as CV/Commavid scheme). - To map ROM, the desired bank number of the upper 2K segment is - selected by storing its value into $3D. - - @author Stephen Anthony, LS_Dracon -*/ - -class CartridgeCVPlus : public Cartridge -{ - friend class CartridgeCVPlusWidget; - - public: - /** - 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 settings A reference to the various settings (read-only) - */ - CartridgeCVPlus(const ByteBuffer& image, size_t size, const string& md5, - const Settings& settings); - virtual ~CartridgeCVPlus() = default; - - public: - /** - Reset device to its power-on state - */ - void reset() override; - - /** - Install cartridge in the specified system. Invoked by the system - when the cartridge is attached to it. - - @param system The system the device should install itself in - */ - void install(System& system) override; - - /** - Install pages for the specified bank in the system. - - @param bank The bank that should be installed in the system - */ - bool bank(uInt16 bank) override; - - /** - Get the current bank. - - @param address The address to use when querying the bank - */ - uInt16 getBank(uInt16 address = 0) const override; - - /** - Query the number of banks supported by the cartridge. - */ - uInt16 bankCount() const override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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 "CartridgeCV+"; } - - #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 CartridgeCVPlusWidget(boss, lfont, nfont, x, y, w, h, *this); - } - #endif - - public: - /** - Get the byte at the specified address - - @return The byte at the specified address - */ - uInt8 peek(uInt16 address) override; - - /** - Change the byte at the specified address to the given value - - @param address The address where the value should be stored - @param value The value to be stored at the address - @return True if the poke changed the device address space, else false - */ - bool poke(uInt16 address, uInt8 value) override; - - private: - // Pointer to a dynamically allocated ROM image of the cartridge - ByteBuffer myImage; - - // The 1024 bytes of RAM - std::array myRAM; - - // Size of the ROM image - size_t mySize{0}; - - // Indicates which bank is currently active for the first segment - uInt16 myCurrentBank{0}; - - private: - // Following constructors and assignment operators not supported - CartridgeCVPlus() = delete; - CartridgeCVPlus(const CartridgeCVPlus&) = delete; - CartridgeCVPlus(CartridgeCVPlus&&) = delete; - CartridgeCVPlus& operator=(const CartridgeCVPlus&) = delete; - CartridgeCVPlus& operator=(CartridgeCVPlus&&) = delete; -}; - -#endif diff --git a/src/emucore/CartDetector.cxx b/src/emucore/CartDetector.cxx index 9fe79314f..09e0def71 100644 --- a/src/emucore/CartDetector.cxx +++ b/src/emucore/CartDetector.cxx @@ -33,7 +33,6 @@ #include "CartCM.hxx" #include "CartCTY.hxx" #include "CartCV.hxx" -#include "CartCVPlus.hxx" #include "CartDASH.hxx" #include "CartDF.hxx" #include "CartDFSC.hxx" @@ -278,8 +277,6 @@ CartDetector::createFromImage(const ByteBuffer& image, size_t size, Bankswitch:: return make_unique(image, size, md5, settings); case Bankswitch::Type::_CV: return make_unique(image, size, md5, settings); - case Bankswitch::Type::_CVP: - return make_unique(image, size, md5, settings); case Bankswitch::Type::_DASH: return make_unique(image, size, md5, settings); case Bankswitch::Type::_DF: @@ -346,11 +343,7 @@ Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t si // Guess type based on size Bankswitch::Type type = Bankswitch::Type::_AUTO; - if(isProbablyCVPlus(image, size)) - { - type = Bankswitch::Type::_CVP; - } - else if((size % 8448) == 0 || size == 6144) + if((size % 8448) == 0 || size == 6144) { type = Bankswitch::Type::_AR; } @@ -757,16 +750,6 @@ bool CartDetector::isProbablyCV(const ByteBuffer& image, size_t size) return searchForBytes(image.get(), size, signature[1], 3, 1); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartDetector::isProbablyCVPlus(const ByteBuffer& image, size_t) -{ - // CV+ cart is identified key 'commavidplus' @ $04 in the ROM - // We inspect only this area to speed up the search - uInt8 cvp[12] = { 'c', 'o', 'm', 'm', 'a', 'v', 'i', 'd', - 'p', 'l', 'u', 's' }; - return searchForBytes(image.get()+4, 24, cvp, 12, 1); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbablyDASH(const ByteBuffer& image, size_t size) { diff --git a/src/emucore/CartDetector.hxx b/src/emucore/CartDetector.hxx index 5f6a60674..8f9d04ac9 100644 --- a/src/emucore/CartDetector.hxx +++ b/src/emucore/CartDetector.hxx @@ -175,11 +175,6 @@ class CartDetector */ static bool isProbablyCV(const ByteBuffer& image, size_t size); - /** - Returns true if the image is probably a CV+ bankswitching cartridge - */ - static bool isProbablyCVPlus(const ByteBuffer& image, size_t size); - /** Returns true if the image is probably a DASH bankswitching cartridge */ diff --git a/src/emucore/module.mk b/src/emucore/module.mk index bbdd5eaab..4b72d3b22 100644 --- a/src/emucore/module.mk +++ b/src/emucore/module.mk @@ -20,8 +20,7 @@ MODULE_OBJS := \ src/emucore/CartCDF.o \ src/emucore/CartCM.o \ src/emucore/CartCTY.o \ - src/emucore/CartCV.o \ - src/emucore/CartCVPlus.o \ + src/emucore/CartCV.o \ src/emucore/CartDASH.o \ src/emucore/CartDPC.o \ src/emucore/CartDPCPlus.o \ diff --git a/src/windows/Stella.vcxproj b/src/windows/Stella.vcxproj index fcd2b85fb..46fd9a877 100644 --- a/src/windows/Stella.vcxproj +++ b/src/windows/Stella.vcxproj @@ -585,9 +585,6 @@ true - - true - true @@ -724,7 +721,6 @@ - @@ -1596,9 +1592,6 @@ true - - true - true @@ -1747,7 +1740,6 @@ - diff --git a/src/windows/Stella.vcxproj.filters b/src/windows/Stella.vcxproj.filters index ef41cf662..8f9d893f8 100644 --- a/src/windows/Stella.vcxproj.filters +++ b/src/windows/Stella.vcxproj.filters @@ -759,12 +759,6 @@ Source Files\debugger - - Source Files\emucore - - - Source Files\debugger - Source Files\debugger @@ -1748,12 +1742,6 @@ Header Files\debugger - - Header Files\debugger - - - Header Files\emucore - Header Files\debugger From fa199a09ddf63d889f044d7cb8cadf71a5bd0e24 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Mon, 13 Apr 2020 17:30:36 -0230 Subject: [PATCH 107/377] Fix 'ovveride' warning from clang. Convert 'template class' to the more modern 'template typename'. --- src/common/LinkedObjectPool.hxx | 2 +- src/common/Stack.hxx | 2 +- src/common/Vec.hxx | 6 +++--- src/common/bspf.hxx | 6 +++--- src/emucore/Cart3E.hxx | 2 +- src/emucore/DispatchResult.hxx | 2 +- src/emucore/tia/DelayQueue.hxx | 4 ++-- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/common/LinkedObjectPool.hxx b/src/common/LinkedObjectPool.hxx index ab4a2fcbd..7c35439e3 100644 --- a/src/common/LinkedObjectPool.hxx +++ b/src/common/LinkedObjectPool.hxx @@ -49,7 +49,7 @@ */ namespace Common { -template +template class LinkedObjectPool { public: diff --git a/src/common/Stack.hxx b/src/common/Stack.hxx index aac9c28b2..e3b2afd87 100644 --- a/src/common/Stack.hxx +++ b/src/common/Stack.hxx @@ -27,7 +27,7 @@ */ namespace Common { -template +template class FixedStack { private: diff --git a/src/common/Vec.hxx b/src/common/Vec.hxx index 10e0c492e..7d102a785 100644 --- a/src/common/Vec.hxx +++ b/src/common/Vec.hxx @@ -22,19 +22,19 @@ namespace Vec { -template +template void append(vector& dst, const vector& src) { dst.insert(dst.cend(), src.cbegin(), src.cend()); } -template +template void insertAt(vector& dst, uInt32 idx, const T& element) { dst.insert(dst.cbegin()+idx, element); } -template +template void removeAt(vector& dst, uInt32 idx) { dst.erase(dst.cbegin()+idx); diff --git a/src/common/bspf.hxx b/src/common/bspf.hxx index e7cc60024..18c60bd2a 100644 --- a/src/common/bspf.hxx +++ b/src/common/bspf.hxx @@ -119,16 +119,16 @@ namespace BSPF #endif // Make 2D-arrays using std::array less verbose - template + template using array2D = std::array, ROW>; // Combines 'max' and 'min', and clamps value to the upper/lower value // if it is outside the specified range - template inline T clamp(T val, T lower, T upper) + template inline T clamp(T val, T lower, T upper) { return (val < lower) ? lower : (val > upper) ? upper : val; } - template inline void clamp(T& val, T lower, T upper, T setVal) + template inline void clamp(T& val, T lower, T upper, T setVal) { if(val < lower || val > upper) val = setVal; } diff --git a/src/emucore/Cart3E.hxx b/src/emucore/Cart3E.hxx index 021497c82..e2382babb 100644 --- a/src/emucore/Cart3E.hxx +++ b/src/emucore/Cart3E.hxx @@ -117,7 +117,7 @@ class Cartridge3E : public Cartridge @param bank The bank to get the size for @return The bank's size */ - virtual uInt16 bankSize(uInt16 bank = 0) const; + virtual uInt16 bankSize(uInt16 bank = 0) const override; /** Patch the cartridge ROM. diff --git a/src/emucore/DispatchResult.hxx b/src/emucore/DispatchResult.hxx index 4ce172aeb..6d76cf5ce 100644 --- a/src/emucore/DispatchResult.hxx +++ b/src/emucore/DispatchResult.hxx @@ -55,7 +55,7 @@ class DispatchResult if (myStatus != status) throw runtime_error("invalid status for operation"); } - template void assertStatus(Status status, Ts... more) const + template void assertStatus(Status status, Ts... more) const { if (myStatus == status) return; diff --git a/src/emucore/tia/DelayQueue.hxx b/src/emucore/tia/DelayQueue.hxx index d3e7e544b..996bde72e 100644 --- a/src/emucore/tia/DelayQueue.hxx +++ b/src/emucore/tia/DelayQueue.hxx @@ -41,7 +41,7 @@ class DelayQueue : public Serializable void reset(); - template void execute(T executor); + template void execute(T executor); /** Serializable methods (see that class for more information). @@ -103,7 +103,7 @@ void DelayQueue::reset() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template -template +template void DelayQueue::execute(T executor) { DelayQueueMember& currentMember = myMembers[myIndex]; From db0d92eb2c948040fe37a8fbc132c7c1428252fa Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 15 Apr 2020 14:53:05 +0200 Subject: [PATCH 108/377] add RAM bank support to CartEnhanced refactor Cart3E differentiate between ROM and RAM banks (TODO: check debugger) --- src/debugger/CartDebug.cxx | 45 ++-- src/debugger/CartDebug.hxx | 4 +- src/debugger/DebuggerParser.cxx | 14 +- src/debugger/gui/Cart3EWidget.cxx | 24 +-- src/debugger/gui/Cart3FWidget.cxx | 2 +- src/debugger/gui/CartFA2Widget.cxx | 4 +- src/debugger/gui/CartFCWidget.cxx | 4 +- src/debugger/gui/CartMDMWidget.cxx | 2 +- src/debugger/gui/CartMNetworkWidget.cxx | 4 +- src/debugger/gui/CartSBWidget.cxx | 4 +- src/debugger/gui/RomWidget.cxx | 2 +- src/emucore/Cart.cxx | 14 +- src/emucore/Cart.hxx | 12 +- src/emucore/Cart3E.cxx | 263 +++--------------------- src/emucore/Cart3E.hxx | 108 ++-------- src/emucore/Cart3EPlus.cxx | 2 +- src/emucore/Cart3EPlus.hxx | 2 +- src/emucore/Cart3F.cxx | 2 +- src/emucore/CartAR.cxx | 2 +- src/emucore/CartAR.hxx | 2 +- src/emucore/CartBUS.cxx | 2 +- src/emucore/CartBUS.hxx | 2 +- src/emucore/CartCDF.cxx | 2 +- src/emucore/CartCDF.hxx | 2 +- src/emucore/CartCM.cxx | 2 +- src/emucore/CartCM.hxx | 2 +- src/emucore/CartCTY.cxx | 2 +- src/emucore/CartCTY.hxx | 2 +- src/emucore/CartDPC.cxx | 2 +- src/emucore/CartDPC.hxx | 2 +- src/emucore/CartDPCPlus.cxx | 2 +- src/emucore/CartDPCPlus.hxx | 2 +- src/emucore/CartEnhanced.cxx | 217 ++++++++++++------- src/emucore/CartEnhanced.hxx | 32 ++- src/emucore/CartFC.cxx | 6 +- src/emucore/CartMNetwork.cxx | 8 +- src/emucore/CartMNetwork.hxx | 2 +- src/emucore/CartSB.cxx | 4 +- src/emucore/CartSB.hxx | 2 +- src/emucore/CartWD.cxx | 2 +- src/emucore/CartWD.hxx | 2 +- src/gui/GameInfoDialog.cxx | 2 +- 42 files changed, 313 insertions(+), 504 deletions(-) diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index a52732cfe..ef6924187 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -72,12 +72,18 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem) // Create bank information for each potential bank, and an extra one for ZP RAM BankInfo info; - for(uInt32 i = 0; i < myConsole.cartridge().bankCount(); ++i) + for(uInt32 i = 0; i < myConsole.cartridge().romBankCount(); ++i) { info.size = myConsole.cartridge().bankSize(i); myBankInfo.push_back(info); } + for(uInt32 i = 0; i < myConsole.cartridge().ramBankCount(); ++i) + { + info.size = myConsole.cartridge().bankSize(i) >> 1; + myBankInfo.push_back(info); + } + info.size = 128; // ZP RAM myBankInfo.push_back(info); @@ -235,9 +241,10 @@ string CartDebug::toString() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartDebug::disassemble(bool force) +bool CartDebug::disassemblePC(bool force) { uInt16 PC = myDebugger.cpuDebug().pc(); + // ROM/RAM bank or ZP-RAM? int bank = (PC & 0x1000) ? getBank(PC) : int(myBankInfo.size()) - 1; return disassemble(bank, PC, force); @@ -414,7 +421,7 @@ bool CartDebug::addDirective(Device::AccessType type, bank = (myDebugger.cpuDebug().pc() & 0x1000) ? getBank(myDebugger.cpuDebug().pc()) : int(myBankInfo.size())-1; - bank = std::min(bank, bankCount()); + bank = std::min(bank, romBankCount()); BankInfo& info = myBankInfo[bank]; DirectiveList& list = info.directiveList; @@ -546,9 +553,9 @@ int CartDebug::getPCBank() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int CartDebug::bankCount() const +int CartDebug::romBankCount() const { - return myConsole.cartridge().bankCount(); + return myConsole.cartridge().romBankCount(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -955,7 +962,7 @@ string CartDebug::loadConfigFile() myDebugger.rom().invalidate(); stringstream retVal; - if(myConsole.cartridge().bankCount() > 1) + if(myConsole.cartridge().romBankCount() > 1) retVal << DebuggerParser::red("config file for multi-bank ROM not fully supported\n"); retVal << "config file '" << node.getShortPath() << "' loaded OK"; return retVal.str(); @@ -990,14 +997,14 @@ string CartDebug::saveConfigFile() out << "// Stella.pro: \"" << name << "\"" << endl << "// MD5: " << md5 << endl << endl; - for(uInt32 b = 0; b < myConsole.cartridge().bankCount(); ++b) + for(uInt32 b = 0; b < myConsole.cartridge().romBankCount(); ++b) { out << "[" << b << "]" << endl; getBankDirectives(out, myBankInfo[b]); } stringstream retVal; - if(myConsole.cartridge().bankCount() > 1) + if(myConsole.cartridge().romBankCount() > 1) retVal << DebuggerParser::red("config file for multi-bank ROM not fully supported\n"); retVal << "config file '" << cfg.getShortPath() << "' saved OK"; return retVal.str(); @@ -1058,14 +1065,14 @@ string CartDebug::saveDisassembly() Disassembly disasm; disasm.list.reserve(2048); - uInt16 bankCount = myConsole.cartridge().bankCount(); + uInt16 romBankCount = myConsole.cartridge().romBankCount(); uInt16 oldBank = myConsole.cartridge().getBank(); // prepare for switching banks myConsole.cartridge().unlockBank(); uInt32 origin = 0; - for(int bank = 0; bank < bankCount; ++bank) + for(int bank = 0; bank < romBankCount; ++bank) { // TODO: not every CartDebugWidget does it like that, we need a method myConsole.cartridge().unlockBank(); @@ -1082,8 +1089,8 @@ string CartDebug::saveDisassembly() buf << "\n\n;***********************************************************\n" << "; Bank " << bank; - if (bankCount > 1) - buf << " / 0.." << bankCount - 1; + if (romBankCount > 1) + buf << " / 0.." << romBankCount - 1; buf << "\n;***********************************************************\n\n"; @@ -1097,7 +1104,7 @@ string CartDebug::saveDisassembly() buf << " SEG CODE\n"; - if(bankCount == 1) + if(romBankCount == 1) buf << " ORG $" << Base::HEX4 << info.offset << "\n\n"; else buf << " ORG $" << Base::HEX4 << origin << "\n" @@ -1327,7 +1334,7 @@ string CartDebug::saveDisassembly() out << buf.str(); stringstream retVal; - if(myConsole.cartridge().bankCount() > 1) + if(myConsole.cartridge().romBankCount() > 1) retVal << DebuggerParser::red("disassembly for multi-bank ROM not fully supported\n"); retVal << "saved " << node.getShortPath() << " OK"; return retVal.str(); @@ -1367,8 +1374,8 @@ string CartDebug::saveAccessFile() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartDebug::listConfig(int bank) { - uInt32 startbank = 0, endbank = bankCount(); - if(bank >= 0 && bank < bankCount()) + uInt32 startbank = 0, endbank = romBankCount(); + if(bank >= 0 && bank < romBankCount()) { startbank = bank; endbank = startbank + 1; @@ -1392,7 +1399,7 @@ string CartDebug::listConfig(int bank) getBankDirectives(buf, info); } - if(myConsole.cartridge().bankCount() > 1) + if(myConsole.cartridge().romBankCount() > 1) buf << DebuggerParser::red("config file for multi-bank ROM not fully supported") << endl; return buf.str(); @@ -1401,8 +1408,8 @@ string CartDebug::listConfig(int bank) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartDebug::clearConfig(int bank) { - uInt32 startbank = 0, endbank = bankCount(); - if(bank >= 0 && bank < bankCount()) + uInt32 startbank = 0, endbank = romBankCount(); + if(bank >= 0 && bank < romBankCount()) { startbank = bank; endbank = startbank + 1; diff --git a/src/debugger/CartDebug.hxx b/src/debugger/CartDebug.hxx index c2bd03cae..486eedd79 100644 --- a/src/debugger/CartDebug.hxx +++ b/src/debugger/CartDebug.hxx @@ -95,7 +95,7 @@ class CartDebug : public DebuggerSystem int lastWriteBaseAddress(); // TODO - bool disassemble(bool force = false); + bool disassemblePC(bool force = false); bool disassembleBank(int bank); // First, a call is made to disassemble(), which updates the disassembly @@ -159,7 +159,7 @@ class CartDebug : public DebuggerSystem /** Get the total number of banks supported by the cartridge. */ - int bankCount() const; + int romBankCount() const; /** Add a label and associated address. diff --git a/src/debugger/DebuggerParser.cxx b/src/debugger/DebuggerParser.cxx index 4f50be800..da3b0bc5f 100644 --- a/src/debugger/DebuggerParser.cxx +++ b/src/debugger/DebuggerParser.cxx @@ -763,7 +763,7 @@ void DebuggerParser::executeBreak() { uInt16 addr; uInt8 bank; - uInt32 bankCount = debugger.cartDebug().bankCount(); + uInt32 romBankCount = debugger.cartDebug().romBankCount(); if(argCount == 0) addr = debugger.cpuDebug().pc(); @@ -775,7 +775,7 @@ void DebuggerParser::executeBreak() else { bank = args[1]; - if(bank >= bankCount && bank != 0xff) + if(bank >= romBankCount && bank != 0xff) { commandResult << red("invalid bank"); return; @@ -791,12 +791,12 @@ void DebuggerParser::executeBreak() commandResult << "cleared"; commandResult << " breakpoint at $" << Base::HEX4 << addr << " + mirrors"; - if(bankCount > 1) + if(romBankCount > 1) commandResult << " in bank #" << std::dec << int(bank); } else { - for(int i = 0; i < debugger.cartDebug().bankCount(); ++i) + for(int i = 0; i < debugger.cartDebug().romBankCount(); ++i) { bool set = debugger.toggleBreakPoint(addr, i); @@ -809,7 +809,7 @@ void DebuggerParser::executeBreak() commandResult << "cleared"; commandResult << " breakpoint at $" << Base::HEX4 << addr << " + mirrors"; - if(bankCount > 1) + if(romBankCount > 1) commandResult << " in bank #" << std::dec << int(bank); } } @@ -1459,11 +1459,11 @@ void DebuggerParser::executeListbreaks() { stringstream buf; int count = 0; - uInt32 bankCount = debugger.cartDebug().bankCount(); + uInt32 romBankCount = debugger.cartDebug().romBankCount(); for(const auto& bp : debugger.breakPoints().getBreakpoints()) { - if(bankCount == 1) + if(romBankCount == 1) { buf << debugger.cartDebug().getLabel(bp.addr, true, 4) << " "; if(!(++count % 8)) buf << endl; diff --git a/src/debugger/gui/Cart3EWidget.cxx b/src/debugger/gui/Cart3EWidget.cxx index 3880f2026..e91b268ab 100644 --- a/src/debugger/gui/Cart3EWidget.cxx +++ b/src/debugger/gui/Cart3EWidget.cxx @@ -25,8 +25,8 @@ Cartridge3EWidget::Cartridge3EWidget( int x, int y, int w, int h, Cartridge3E& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart), - myNumRomBanks(uInt32(cart.mySize >> 11)), - myNumRamBanks(32) + myNumRomBanks(myCart.romBankCount()), + myNumRamBanks(myCart.ramBankCount()) { size_t size = cart.mySize; @@ -93,21 +93,21 @@ void Cartridge3EWidget::saveOldState() for(uInt32 i = 0; i < internalRamSize(); ++i) myOldState.internalram.push_back(myCart.myRAM[i]); - myOldState.bank = myCart.myCurrentBank; + myOldState.bank = myCart.getBank(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3EWidget::loadConfig() { - if(myCart.myCurrentBank < 256) + if(myCart.getBank() < myCart.romBankCount()) { - myROMBank->setSelectedIndex(myCart.myCurrentBank % myNumRomBanks, myOldState.bank != myCart.myCurrentBank); - myRAMBank->setSelectedMax(myOldState.bank >= 256); + myROMBank->setSelectedIndex(myCart.getBank() % myNumRomBanks, myOldState.bank != myCart.getBank()); + myRAMBank->setSelectedMax(myOldState.bank >= myCart.romBankCount()); } else { - myROMBank->setSelectedMax(myOldState.bank < 256); - myRAMBank->setSelectedIndex(myCart.myCurrentBank - 256, myOldState.bank != myCart.myCurrentBank); + myROMBank->setSelectedMax(myOldState.bank < myCart.romBankCount()); + myRAMBank->setSelectedIndex(myCart.getBank() - myCart.romBankCount(), myOldState.bank != myCart.getBank()); } CartDebugWidget::loadConfig(); @@ -128,7 +128,7 @@ void Cartridge3EWidget::handleCommand(CommandSender* sender, } else { - bank = 256; // default to first RAM bank + bank = myCart.romBankCount(); // default to first RAM bank myRAMBank->setSelectedIndex(0); } } @@ -137,7 +137,7 @@ void Cartridge3EWidget::handleCommand(CommandSender* sender, if(myRAMBank->getSelected() < int(myNumRamBanks)) { myROMBank->setSelectedMax(); - bank = myRAMBank->getSelected() + 256; + bank = myRAMBank->getSelected() + myCart.romBankCount(); } else { @@ -157,8 +157,8 @@ string Cartridge3EWidget::bankState() { ostringstream& buf = buffer(); - uInt16& bank = myCart.myCurrentBank; - if(bank < 256) + uInt16 bank = myCart.getBank(); + if(bank < myCart.romBankCount()) buf << "ROM bank #" << std::dec << bank % myNumRomBanks << ", RAM inactive"; else buf << "ROM inactive, RAM bank #" << std::dec << bank % myNumRomBanks; diff --git a/src/debugger/gui/Cart3FWidget.cxx b/src/debugger/gui/Cart3FWidget.cxx index 86d43177b..13cd851bd 100644 --- a/src/debugger/gui/Cart3FWidget.cxx +++ b/src/debugger/gui/Cart3FWidget.cxx @@ -44,7 +44,7 @@ Cartridge3FWidget::Cartridge3FWidget( ypos = addBaseInformation(size, "TigerVision", info.str()) + myLineHeight; VariantList items; - for(uInt16 i = 0; i < cart.bankCount(); ++i) + for(uInt16 i = 0; i < cart.romBankCount(); ++i) VarList::push_back(items, Variant(i).toString() + " ($3F)"); ostringstream label; diff --git a/src/debugger/gui/CartFA2Widget.cxx b/src/debugger/gui/CartFA2Widget.cxx index eb2bf4d07..9a24eb5a7 100644 --- a/src/debugger/gui/CartFA2Widget.cxx +++ b/src/debugger/gui/CartFA2Widget.cxx @@ -38,7 +38,7 @@ CartridgeFA2Widget::CartridgeFA2Widget( << "Startup bank = " << cart.startBank() << " or undetermined\n"; // Eventually, we should query this from the debugger/disassembler - for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF5; i < cart.bankCount(); + for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF5; i < cart.romBankCount(); ++i, offset += 0x1000) { uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; @@ -58,7 +58,7 @@ CartridgeFA2Widget::CartridgeFA2Widget( VarList::push_back(items, "3 ($FFF8)"); VarList::push_back(items, "4 ($FFF9)"); VarList::push_back(items, "5 ($FFFA)"); - if(cart.bankCount() == 7) + if(cart.romBankCount() == 7) VarList::push_back(items, "6 ($FFFB)"); myBank = diff --git a/src/debugger/gui/CartFCWidget.cxx b/src/debugger/gui/CartFCWidget.cxx index ce1bf9403..a034b56e3 100644 --- a/src/debugger/gui/CartFCWidget.cxx +++ b/src/debugger/gui/CartFCWidget.cxx @@ -26,7 +26,7 @@ CartridgeFCWidget::CartridgeFCWidget( : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { - uInt16 size = cart.bankCount() * 4096; + uInt16 size = cart.romBankCount() * 4096; ostringstream info; info << "FC cartridge, up to eight 4K banks\n" @@ -42,7 +42,7 @@ CartridgeFCWidget::CartridgeFCWidget( ypos = addBaseInformation(size, "Amiga Corp.", info.str()) + myLineHeight; VariantList items; - for (uInt16 i = 0; i < cart.bankCount(); ++i) + for (uInt16 i = 0; i < cart.romBankCount(); ++i) VarList::push_back(items, Variant(i).toString() + " ($FFF8 = " + Variant(i & 0b11).toString() + "/$FFF9 = " + Variant(i >> 2).toString() +")"); diff --git a/src/debugger/gui/CartMDMWidget.cxx b/src/debugger/gui/CartMDMWidget.cxx index 2ba603168..48afbaf77 100644 --- a/src/debugger/gui/CartMDMWidget.cxx +++ b/src/debugger/gui/CartMDMWidget.cxx @@ -40,7 +40,7 @@ CartridgeMDMWidget::CartridgeMDMWidget( ypos = addBaseInformation(size, "Edwin Blink", info.str(), 15) + myLineHeight; VariantList items; - for(uInt32 i = 0x800; i < (0x800U + myCart.bankCount()); ++i) + for(uInt32 i = 0x800; i < (0x800U + myCart.romBankCount()); ++i) { info.str(""); info << std::dec << (i & 0xFF) << " ($" << Common::Base::HEX4 << i << ")"; diff --git a/src/debugger/gui/CartMNetworkWidget.cxx b/src/debugger/gui/CartMNetworkWidget.cxx index cdc1f9bce..37d382a7e 100644 --- a/src/debugger/gui/CartMNetworkWidget.cxx +++ b/src/debugger/gui/CartMNetworkWidget.cxx @@ -35,14 +35,14 @@ CartridgeMNetworkWidget::CartridgeMNetworkWidget( // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeMNetworkWidget::initialize(GuiObject* boss, CartridgeMNetwork& cart, ostringstream& info) { - uInt32 size = cart.bankCount() * cart.BANK_SIZE; + uInt32 size = cart.romBankCount() * cart.BANK_SIZE; int xpos = 2, ypos = addBaseInformation(size, "M-Network", info.str(), 15) + myLineHeight; VariantList items0, items1; - for(int i = 0; i < cart.bankCount(); ++i) + for(int i = 0; i < cart.romBankCount(); ++i) VarList::push_back(items0, getSpotLower(i)); for(int i = 0; i < 4; ++i) VarList::push_back(items1, getSpotUpper(i)); diff --git a/src/debugger/gui/CartSBWidget.cxx b/src/debugger/gui/CartSBWidget.cxx index 78d352879..7a82ba8e0 100644 --- a/src/debugger/gui/CartSBWidget.cxx +++ b/src/debugger/gui/CartSBWidget.cxx @@ -33,12 +33,12 @@ CartridgeSBWidget::CartridgeSBWidget( myCart.getImage(size); info << "SB SUPERbanking, 32 or 64 4K banks\n" << "Hotspots are from $800 to $" - << Common::Base::HEX2 << (0x800 + myCart.bankCount() - 1) << ", including\n" + << Common::Base::HEX2 << (0x800 + myCart.romBankCount() - 1) << ", including\n" << "mirrors ($900, $A00, $B00, ...)\n" << "Startup bank = " << std::dec << cart.startBank() << "\n"; // Eventually, we should query this from the debugger/disassembler - for(uInt32 i = 0, offset = 0xFFC, spot = 0x800; i < myCart.bankCount(); + for(uInt32 i = 0, offset = 0xFFC, spot = 0x800; i < myCart.romBankCount(); ++i, offset += 0x1000, ++spot) { uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; diff --git a/src/debugger/gui/RomWidget.cxx b/src/debugger/gui/RomWidget.cxx index 18c8b0b78..e62fe0a17 100644 --- a/src/debugger/gui/RomWidget.cxx +++ b/src/debugger/gui/RomWidget.cxx @@ -68,7 +68,7 @@ void RomWidget::loadConfig() const CartState& oldstate = static_cast(cart.getOldState()); // Fill romlist the current bank of source or disassembly - myListIsDirty |= cart.disassemble(myListIsDirty); + myListIsDirty |= cart.disassemblePC(myListIsDirty); if(myListIsDirty) { myRomList->setList(cart.disassembly()); diff --git a/src/emucore/Cart.cxx b/src/emucore/Cart.cxx index f85850ba2..7639101ff 100644 --- a/src/emucore/Cart.cxx +++ b/src/emucore/Cart.cxx @@ -83,7 +83,7 @@ uInt16 Cartridge::bankSize(uInt16 bank) const getImage(size); - return std::min(uInt32(size) / bankCount(), 4_KB); // assuming that each bank has the same size + return std::min(uInt32(size) / romBankCount(), 4_KB); // assuming that each bank has the same size } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -145,13 +145,13 @@ string Cartridge::getAccessCounters() const ostringstream out; uInt32 offset = 0; - for(uInt16 bank = 0; bank < bankCount(); ++bank) + for(uInt16 bank = 0; bank < romBankCount(); ++bank) { uInt16 origin = bankOrigin(bank); uInt16 bankSize = this->bankSize(bank); out << "Bank " << Common::Base::toString(bank, Common::Base::Fmt::_10_8) << " / 0.." - << Common::Base::toString(bankCount() - 1, Common::Base::Fmt::_10_8) << " reads:\n"; + << Common::Base::toString(romBankCount() - 1, Common::Base::Fmt::_10_8) << " reads:\n"; for(uInt16 addr = 0; addr < bankSize; ++addr) { out << Common::Base::HEX4 << (addr | origin) << "," @@ -159,7 +159,7 @@ string Cartridge::getAccessCounters() const } out << "\n"; out << "Bank " << Common::Base::toString(bank, Common::Base::Fmt::_10_8) << " / 0.." - << Common::Base::toString(bankCount() - 1, Common::Base::Fmt::_10_8) << " writes:\n"; + << Common::Base::toString(romBankCount() - 1, Common::Base::Fmt::_10_8) << " writes:\n"; for(uInt16 addr = 0; addr < bankSize; ++addr) { out << Common::Base::HEX4 << (addr | origin) << "," @@ -230,11 +230,11 @@ uInt16 Cartridge::initializeStartBank(uInt16 defaultBank) int propsBank = myStartBankFromPropsFunc(); if(randomStartBank()) - return myStartBank = mySystem->randGenerator().next() % bankCount(); + return myStartBank = mySystem->randGenerator().next() % romBankCount(); else if(propsBank >= 0) - return myStartBank = BSPF::clamp(propsBank, 0, bankCount() - 1); + return myStartBank = BSPF::clamp(propsBank, 0, romBankCount() - 1); else - return myStartBank = BSPF::clamp(int(defaultBank), 0, bankCount() - 1); + return myStartBank = BSPF::clamp(int(defaultBank), 0, romBankCount() - 1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Cart.hxx b/src/emucore/Cart.hxx index ce7d66a8b..a7488f551 100644 --- a/src/emucore/Cart.hxx +++ b/src/emucore/Cart.hxx @@ -180,7 +180,7 @@ class Cartridge : public Device virtual uInt16 getBank(uInt16 address = 0) const { return 0; } /** - Query the number of 'banks' supported by the cartridge. Note that + Query the number of ROM 'banks' supported by the cartridge. Note that this information is cart-specific, where each cart basically defines what a 'bank' is. @@ -192,7 +192,15 @@ class Cartridge : public Device RAM slices at multiple access points) is so complicated that the cart will report having only one 'virtual' bank. */ - virtual uInt16 bankCount() const { return 1; } + 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 + what a 'bank' is. + */ + virtual uInt16 ramBankCount() const { return 0; } /** Get the size of a bank. diff --git a/src/emucore/Cart3E.cxx b/src/emucore/Cart3E.cxx index f1ccd2957..a927ddd2d 100644 --- a/src/emucore/Cart3E.cxx +++ b/src/emucore/Cart3E.cxx @@ -22,52 +22,42 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge3E::Cartridge3E(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5), - mySize(size), - myRomBanks(256/*uInt16(size) >> 11*/) + : CartridgeEnhanced(image, size, md5, settings) { - // Allocate array for the ROM image - myImage = make_unique(mySize); - - // Copy the ROM image into my buffer - std::copy_n(image.get(), mySize, myImage.get()); - createRomAccessArrays(mySize + myRAM.size()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge3E::reset() -{ - initializeRAM(myRAM.data(), myRAM.size()); - initializeStartBank(0); - - // We'll map the startup bank into the first segment upon reset - bank(startBank()); + myBankShift = BANK_SHIFT; + myRamSize = RAM_SIZE; + myRamBankCount = RAM_BANKS; + myRamWpHigh = RAM_HIGH_WP; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3E::install(System& system) { - mySystem = &system; + CartridgeEnhanced::install(system); System::PageAccess access(this, System::PageAccessType::READWRITE); // The hotspots ($3E and $3F) are in TIA address space, so we claim it here for(uInt16 addr = 0x00; addr < 0x40; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); +} - // Setup the second segment to always point to the last ROM slice - access.type = System::PageAccessType::READ; - for(uInt16 addr = 0x1800; addr < 0x2000; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[(mySize - 2048) + (addr & 0x07FF)]; - access.romAccessBase = &myRomAccessBase[(mySize - 2048) + (addr & 0x07FF)]; - access.romPeekCounter = &myRomAccessCounter[(mySize - 2048) + (addr & 0x07FF)]; - access.romPokeCounter = &myRomAccessCounter[(mySize - 2048) + (addr & 0x07FF) + myAccessSize]; - mySystem->setPageAccess(addr, access); +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool Cartridge3E::checkSwitchBank(uInt16 address, uInt8 value) +{ + // Switch banks if necessary + if(address == 0x003F) { + // Switch ROM bank into segment 0 + bank(value); + return true; } - - // Install pages for the startup bank into the first segment - bank(startBank()); + else if(address == 0x003E) + { + // Switch RAM bank into segment 0 + bank(value + romBankCount()); + return true; + } + return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -76,215 +66,8 @@ uInt8 Cartridge3E::peek(uInt16 address) uInt16 peekAddress = address; address &= 0x0FFF; - // Due to the way paging is set up, the only way to get here is a TIA read or - // attempting to read from the RAM write port - if(address < 0x0040) // TIA access return mySystem->tia().peek(address); - else if(myCurrentBank >= myRomBanks) - { - // Reading from the write port triggers an unwanted write - return peekRAM(myRAM[(address & 0x03FF) + ((myCurrentBank - myRomBanks) << 10)], peekAddress); - } - // Make compiler happy; should never get here - return myImage[(address & 0x07FF) + mySize - 2048]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Cartridge3E::poke(uInt16 address, uInt8 value) -{ - uInt16 pokeAddress = address; - address &= 0x0FFF; - - // Switch banks if necessary. Armin (Kroko) says there are no mirrored - // hotspots. - if(address < 0x0040) - { - if(address == 0x003F) - bank(value); - else if(address == 0x003E) - bank(value + myRomBanks); - - return mySystem->tia().poke(address, value); - } - else if(myCurrentBank >= myRomBanks) - { - if(address & 0x0400) - { - pokeRAM(myRAM[(address & 0x03FF) + ((myCurrentBank - myRomBanks) << 10)], - pokeAddress, value); - return true; - } - else - { - // Writing to the read port should be ignored, but trigger a break if option enabled - uInt8 dummy; - - pokeRAM(dummy, pokeAddress, value); - myRamWriteAccess = pokeAddress; - return false; - } - } - return false; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Cartridge3E::bank(uInt16 bank) -{ - if(bankLocked()) return false; - - if(bank < myRomBanks) - { - // Make sure the bank they're asking for is reasonable - if((uInt32(bank) << 11) < mySize) - { - myCurrentBank = bank; - } - else - { - // Oops, the bank they're asking for isn't valid so let's wrap it - // around to a valid bank number - myCurrentBank = bank % (mySize >> 11); - } - - uInt32 offset = myCurrentBank << 11; - - // Setup the page access methods for the current bank - System::PageAccess access(this, System::PageAccessType::READ); - - // Map ROM image into the system - for(uInt16 addr = 0x1000; addr < 0x1800; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[offset + (addr & 0x07FF)]; - access.romAccessBase = &myRomAccessBase[offset + (addr & 0x07FF)]; - access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x07FF)]; - access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x07FF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - } - else - { - bank -= myRomBanks; - bank %= myRamBanks; - myCurrentBank = bank + myRomBanks; - - uInt32 offset = bank << 10; - - // Setup the page access methods for the current bank - System::PageAccess access(this, System::PageAccessType::READ); - - // Map read-port RAM image into the system - // Writes are mapped to poke(), to check for write to the read port - for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myRAM[offset + (addr & 0x03FF)]; - access.romAccessBase = &myRomAccessBase[mySize + offset + (addr & 0x03FF)]; - access.romPeekCounter = &myRomAccessCounter[mySize + offset + (addr & 0x03FF)]; - access.romPokeCounter = &myRomAccessCounter[mySize + offset + (addr & 0x03FF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - access.directPeekBase = nullptr; - access.type = System::PageAccessType::WRITE; - - // Map write-port RAM image into the system - // Reads are mapped to peek(), to check for read from write port - for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[mySize + offset + (addr & 0x03FF)]; - access.romPeekCounter = &myRomAccessCounter[mySize + offset + (addr & 0x03FF)]; - access.romPokeCounter = &myRomAccessCounter[mySize + offset + (addr & 0x03FF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - } - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 Cartridge3E::getBank(uInt16 address) const -{ - if (address & 0x800) - return myRomBanks - 1; // 2K slices, fixed bank - else - return myCurrentBank; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 Cartridge3E::bankCount() const -{ - // Because the RAM banks always start at 256 and above, we require the - // number of ROM banks to be 256 - // If the RAM banks were simply appended to the number of actual - // ROM banks, bank numbers would be ambiguous (ie, would bank 128 be - // the last bank of ROM, or one of the banks of RAM?) - return myRomBanks + myRamBanks; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 Cartridge3E::bankSize(uInt16 bank) const -{ - return 2_KB; // we cannot use bankCount() here, because it delivers wrong numbers -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Cartridge3E::patch(uInt16 address, uInt8 value) -{ - address &= 0x0FFF; - - if(address < 0x0800) - { - if(myCurrentBank < myRomBanks) - myImage[(address & 0x07FF) + (myCurrentBank << 11)] = value; - else - myRAM[(address & 0x03FF) + ((myCurrentBank - myRomBanks) << 10)] = value; - } - else - myImage[(address & 0x07FF) + mySize - 2048] = value; - - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* Cartridge3E::getImage(size_t& size) const -{ - size = mySize; - return myImage.get(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Cartridge3E::save(Serializer& out) const -{ - try - { - out.putShort(myCurrentBank); - out.putByteArray(myRAM.data(), myRAM.size()); - } - catch(...) - { - cerr << "ERROR: Cartridge3E::save" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Cartridge3E::load(Serializer& in) -{ - try - { - myCurrentBank = in.getShort(); - in.getByteArray(myRAM.data(), myRAM.size()); - } - catch(...) - { - cerr << "ERROR: Cartridge3E::load" << endl; - return false; - } - - // Now, go to the current bank - bank(myCurrentBank); - - return true; + return CartridgeEnhanced::peek(peekAddress); } diff --git a/src/emucore/Cart3E.hxx b/src/emucore/Cart3E.hxx index d78cb3bb0..4871c67a6 100644 --- a/src/emucore/Cart3E.hxx +++ b/src/emucore/Cart3E.hxx @@ -21,7 +21,7 @@ class System; #include "bspf.hxx" -#include "Cart.hxx" +#include "CartEnhanced.hxx" #ifdef DEBUGGER_SUPPORT #include "Cart3EWidget.hxx" #endif @@ -47,10 +47,8 @@ class System; by storing its value into $3F. To map RAM in the first 2K segment instead, store the RAM bank number into $3E. - This implementation of 3E bankswitching numbers the ROM banks 0 to - 255, and the RAM banks 256 to 287. This is done because the public - bankswitching interface requires us to use one bank number, not one - bank number plus the knowledge of whether it's RAM or ROM. + This implementation of 3E bankswitching numbers the RAM banks (up to 32) + after the ROM banks (up to 256). All 32K of potential RAM is available to a game using this class, even though real cartridges might not have the full 32K: We have no way to @@ -58,10 +56,10 @@ class System; may add a stella.pro property for this), but for now it shouldn't cause any problems. (Famous last words...) - @author B. Watson + @author B. Watson, Thomas Jentzsch */ -class Cartridge3E : public Cartridge +class Cartridge3E : public CartridgeEnhanced { friend class Cartridge3EWidget; @@ -79,10 +77,6 @@ class Cartridge3E : public Cartridge virtual ~Cartridge3E() = default; public: - /** - Reset device to its power-on state - */ - void reset() override; /** Install cartridge in the specified system. Invoked by the system @@ -92,66 +86,6 @@ class Cartridge3E : public Cartridge */ void install(System& system) override; - /** - Install pages for the specified bank in the system. - - @param bank The bank that should be installed in the system - */ - bool bank(uInt16 bank) override; - - /** - Get the current bank. - - @param address The address to use when querying the bank - */ - uInt16 getBank(uInt16 address = 0) const override; - - /** - Query the number of banks supported by the cartridge. - */ - uInt16 bankCount() const override; - - /** - Get the size of a bank. - - @param bank The bank to get the size for - @return The bank's size - */ - virtual uInt16 bankSize(uInt16 bank = 0) const; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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). @@ -179,33 +113,21 @@ class Cartridge3E : public Cartridge */ uInt8 peek(uInt16 address) override; - /** - Change the byte at the specified address to the given value - - @param address The address where the value should be stored - @param value The value to be stored at the address - @return True if the poke changed the device address space, else false - */ - bool poke(uInt16 address, uInt8 value) override; + private: + bool checkSwitchBank(uInt16 address, uInt8 value) override; private: - // Pointer to a dynamically allocated ROM image of the cartridge - ByteBuffer myImage; + // log(ROM bank segment size) / log(2) + static constexpr uInt16 BANK_SHIFT = 11; // = 2K = 0x0800 - // RAM contents. For now every ROM gets all 32K of potential RAM - std::array myRAM; + // The size of extra RAM in ROM address space + static constexpr uInt16 RAM_BANKS = 32; - // Size of the ROM image - size_t mySize{0}; + // RAM size + static constexpr uInt16 RAM_SIZE = RAM_BANKS << (BANK_SHIFT - 1); // = 32K = 0x4000; - // Size of the ROM image - uInt16 myRomBanks{0}; - - // Size of the ROM image - uInt16 myRamBanks{32}; - - // Indicates which bank is currently active for the first segment - uInt16 myCurrentBank{0}; + // Write port for extra RAM is at high address + static constexpr bool RAM_HIGH_WP = true; private: // Following constructors and assignment operators not supported diff --git a/src/emucore/Cart3EPlus.cxx b/src/emucore/Cart3EPlus.cxx index 27eb94986..1fe28a022 100644 --- a/src/emucore/Cart3EPlus.cxx +++ b/src/emucore/Cart3EPlus.cxx @@ -85,7 +85,7 @@ uInt16 Cartridge3EPlus::getBank(uInt16 address) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 Cartridge3EPlus::bankCount() const +uInt16 Cartridge3EPlus::romBankCount() const { return uInt16(mySize >> 10); // 1K slices } diff --git a/src/emucore/Cart3EPlus.hxx b/src/emucore/Cart3EPlus.hxx index 76919b9ae..70309d308 100644 --- a/src/emucore/Cart3EPlus.hxx +++ b/src/emucore/Cart3EPlus.hxx @@ -80,7 +80,7 @@ class Cartridge3EPlus: public Cartridge /** Query the number of banks supported by the cartridge. */ - uInt16 bankCount() const override; + uInt16 romBankCount() const override; /** Patch the cartridge ROM. diff --git a/src/emucore/Cart3F.cxx b/src/emucore/Cart3F.cxx index 7c3701c16..21b21b9c7 100644 --- a/src/emucore/Cart3F.cxx +++ b/src/emucore/Cart3F.cxx @@ -46,7 +46,7 @@ bool Cartridge3F::checkSwitchBank(uInt16 address, uInt8 value) if(address <= 0x003F) { // Make sure the bank they're asking for is reasonable - bank(value % bankCount(), 0); + bank(value % romBankCount(), 0); return true; } return false; diff --git a/src/emucore/CartAR.cxx b/src/emucore/CartAR.cxx index 5201a14df..2d8b204b6 100644 --- a/src/emucore/CartAR.cxx +++ b/src/emucore/CartAR.cxx @@ -406,7 +406,7 @@ uInt16 CartridgeAR::getBank(uInt16) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeAR::bankCount() const +uInt16 CartridgeAR::romBankCount() const { return 32; } diff --git a/src/emucore/CartAR.hxx b/src/emucore/CartAR.hxx index 6fda35f38..0bc74a291 100644 --- a/src/emucore/CartAR.hxx +++ b/src/emucore/CartAR.hxx @@ -87,7 +87,7 @@ class CartridgeAR : public Cartridge /** Query the number of banks supported by the cartridge. */ - uInt16 bankCount() const override; + uInt16 romBankCount() const override; /** Patch the cartridge ROM. diff --git a/src/emucore/CartBUS.cxx b/src/emucore/CartBUS.cxx index 2c2cd803a..bd6d227c2 100644 --- a/src/emucore/CartBUS.cxx +++ b/src/emucore/CartBUS.cxx @@ -457,7 +457,7 @@ uInt16 CartridgeBUS::getBank(uInt16) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeBUS::bankCount() const +uInt16 CartridgeBUS::romBankCount() const { return 7; } diff --git a/src/emucore/CartBUS.hxx b/src/emucore/CartBUS.hxx index d00e90133..5567f1196 100644 --- a/src/emucore/CartBUS.hxx +++ b/src/emucore/CartBUS.hxx @@ -98,7 +98,7 @@ class CartridgeBUS : public Cartridge /** Query the number of banks supported by the cartridge. */ - uInt16 bankCount() const override; + uInt16 romBankCount() const override; /** Patch the cartridge ROM. diff --git a/src/emucore/CartCDF.cxx b/src/emucore/CartCDF.cxx index b182634a3..2758a9825 100644 --- a/src/emucore/CartCDF.cxx +++ b/src/emucore/CartCDF.cxx @@ -430,7 +430,7 @@ uInt16 CartridgeCDF::getBank(uInt16) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeCDF::bankCount() const +uInt16 CartridgeCDF::romBankCount() const { return 7; } diff --git a/src/emucore/CartCDF.hxx b/src/emucore/CartCDF.hxx index 5e65bc4d4..7c5295f7a 100644 --- a/src/emucore/CartCDF.hxx +++ b/src/emucore/CartCDF.hxx @@ -104,7 +104,7 @@ class CartridgeCDF : public Cartridge /** Query the number of banks supported by the cartridge. */ - uInt16 bankCount() const override; + uInt16 romBankCount() const override; /** Patch the cartridge ROM. diff --git a/src/emucore/CartCM.cxx b/src/emucore/CartCM.cxx index 5fa6dff3d..40ec603e5 100644 --- a/src/emucore/CartCM.cxx +++ b/src/emucore/CartCM.cxx @@ -163,7 +163,7 @@ uInt16 CartridgeCM::getBank(uInt16) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeCM::bankCount() const +uInt16 CartridgeCM::romBankCount() const { // We report 4 banks (of ROM), even though RAM can overlap the upper 2K // of cart address space at some times diff --git a/src/emucore/CartCM.hxx b/src/emucore/CartCM.hxx index 2c0cf54d2..bf8b2586e 100644 --- a/src/emucore/CartCM.hxx +++ b/src/emucore/CartCM.hxx @@ -155,7 +155,7 @@ class CartridgeCM : public Cartridge /** Query the number of banks supported by the cartridge. */ - uInt16 bankCount() const override; + uInt16 romBankCount() const override; /** Patch the cartridge ROM. diff --git a/src/emucore/CartCTY.cxx b/src/emucore/CartCTY.cxx index 1536b64e0..822473081 100644 --- a/src/emucore/CartCTY.cxx +++ b/src/emucore/CartCTY.cxx @@ -255,7 +255,7 @@ uInt16 CartridgeCTY::getBank(uInt16) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeCTY::bankCount() const +uInt16 CartridgeCTY::romBankCount() const { return 8; } diff --git a/src/emucore/CartCTY.hxx b/src/emucore/CartCTY.hxx index 5626013a1..fdd6c1e19 100644 --- a/src/emucore/CartCTY.hxx +++ b/src/emucore/CartCTY.hxx @@ -153,7 +153,7 @@ class CartridgeCTY : public Cartridge /** Query the number of banks supported by the cartridge. */ - uInt16 bankCount() const override; + uInt16 romBankCount() const override; /** Patch the cartridge ROM. diff --git a/src/emucore/CartDPC.cxx b/src/emucore/CartDPC.cxx index 808e658d4..c8a038c25 100644 --- a/src/emucore/CartDPC.cxx +++ b/src/emucore/CartDPC.cxx @@ -399,7 +399,7 @@ uInt16 CartridgeDPC::getBank(uInt16) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeDPC::bankCount() const +uInt16 CartridgeDPC::romBankCount() const { return 2; } diff --git a/src/emucore/CartDPC.hxx b/src/emucore/CartDPC.hxx index 330a0086a..6c186bfdb 100644 --- a/src/emucore/CartDPC.hxx +++ b/src/emucore/CartDPC.hxx @@ -85,7 +85,7 @@ class CartridgeDPC : public Cartridge /** Query the number of banks supported by the cartridge. */ - uInt16 bankCount() const override; + uInt16 romBankCount() const override; /** Patch the cartridge ROM. diff --git a/src/emucore/CartDPCPlus.cxx b/src/emucore/CartDPCPlus.cxx index 0761eeb19..b71f5a8c0 100644 --- a/src/emucore/CartDPCPlus.cxx +++ b/src/emucore/CartDPCPlus.cxx @@ -619,7 +619,7 @@ uInt16 CartridgeDPCPlus::getBank(uInt16) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeDPCPlus::bankCount() const +uInt16 CartridgeDPCPlus::romBankCount() const { return 6; } diff --git a/src/emucore/CartDPCPlus.hxx b/src/emucore/CartDPCPlus.hxx index 46b18af99..9617d6545 100644 --- a/src/emucore/CartDPCPlus.hxx +++ b/src/emucore/CartDPCPlus.hxx @@ -100,7 +100,7 @@ class CartridgeDPCPlus : public Cartridge /** Query the number of banks supported by the cartridge. */ - uInt16 bankCount() const override; + uInt16 romBankCount() const override; /** Patch the cartridge ROM. diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index 1a446a9a8..b8c1cde13 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -34,16 +34,19 @@ CartridgeEnhanced::CartridgeEnhanced(const ByteBuffer& image, size_t size, // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeEnhanced::install(System& system) { - // Copy the ROM image into my buffer - createRomAccessArrays(mySize); + // limit banked RAM size to the size of one RAM bank + uInt16 ramSize = myRamBankCount ? 1 << (myBankShift - 1) : myRamSize; // calculate bank switching and RAM sizes and masks myBankSize = 1 << myBankShift; // e.g. = 2 ^ 12 = 4K = 0x1000 myBankMask = myBankSize - 1; // e.g. = 0x0FFF myBankSegs = 1 << (12 - myBankShift); // e.g. = 1 - myRamMask = myRamSize - 1; // e.g. = 0xFFFF (doesn't matter for RAM size 0) - myWriteOffset = myRamWpHigh ? myRamSize : 0; - myReadOffset = myRamWpHigh ? 0 : myRamSize; + myRomOffset = myRamBankCount ? 0 : myRamSize * 2; + myRamMask = ramSize - 1; // e.g. = 0xFFFF (doesn't matter for RAM size 0) + myWriteOffset = myRamWpHigh ? ramSize : 0; + myReadOffset = myRamWpHigh ? 0 : ramSize; + + createRomAccessArrays(mySize + (myRomOffset ? 0 : myRamSize)); // Allocate array for the current bank segments slices myCurrentSegOffset = make_unique(myBankSegs); @@ -51,41 +54,44 @@ void CartridgeEnhanced::install(System& system) // Allocate array for the RAM area myRAM = make_unique(myRamSize); - // Setup page access mySystem = &system; - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page accessing method for the RAM writing pages - // Map access to this class, since we need to inspect all accesses to - // check if RWP happens - access.type = System::PageAccessType::WRITE; - for(uInt16 addr = 0x1000 + myWriteOffset; addr < 0x1000 + myWriteOffset + myRamSize; addr += System::PAGE_SIZE) + if(myRomOffset) { - uInt16 offset = addr & myRamMask; - access.romAccessBase = &myRomAccessBase[myWriteOffset + offset]; - access.romPeekCounter = &myRomAccessCounter[myWriteOffset + offset]; - access.romPokeCounter = &myRomAccessCounter[myWriteOffset + offset + myAccessSize]; - mySystem->setPageAccess(addr, access); - } + // Setup page access for extended RAM; banked RAM will be setup in bank() + System::PageAccess access(this, System::PageAccessType::READ); - // Set the page accessing method for the RAM reading pages - access.type = System::PageAccessType::READ; - for(uInt16 addr = 0x1000 + myReadOffset; addr < 0x1000 + myReadOffset + myRamSize; addr += System::PAGE_SIZE) - { - uInt16 offset = addr & myRamMask; - access.directPeekBase = &myRAM[offset]; - access.romAccessBase = &myRomAccessBase[myReadOffset + offset]; - access.romPeekCounter = &myRomAccessCounter[myReadOffset + offset]; - access.romPokeCounter = &myRomAccessCounter[myReadOffset + offset + myAccessSize]; - mySystem->setPageAccess(addr, access); + // Set the page accessing method for the RAM writing pages + // Map access to this class, since we need to inspect all accesses to + // check if RWP happens + access.type = System::PageAccessType::WRITE; + for(uInt16 addr = 0x1000 + myWriteOffset; addr < 0x1000 + myWriteOffset + myRamSize; addr += System::PAGE_SIZE) + { + uInt16 offset = addr & myRamMask; + access.romAccessBase = &myRomAccessBase[myWriteOffset + offset]; + access.romPeekCounter = &myRomAccessCounter[myWriteOffset + offset]; + access.romPokeCounter = &myRomAccessCounter[myWriteOffset + offset + myAccessSize]; + mySystem->setPageAccess(addr, access); + } + + // Set the page accessing method for the RAM reading pages + access.type = System::PageAccessType::READ; + for(uInt16 addr = 0x1000 + myReadOffset; addr < 0x1000 + myReadOffset + myRamSize; addr += System::PAGE_SIZE) + { + uInt16 offset = addr & myRamMask; + access.directPeekBase = &myRAM[offset]; + access.romAccessBase = &myRomAccessBase[myReadOffset + offset]; + access.romPeekCounter = &myRomAccessCounter[myReadOffset + offset]; + access.romPokeCounter = &myRomAccessCounter[myReadOffset + offset + myAccessSize]; + mySystem->setPageAccess(addr, access); + } } // Install pages for the startup bank (TODO: currently only in first bank segment) bank(startBank(), 0); if(mySize >= 4_KB && myBankSegs > 1) // Setup the last bank segment to always point to the last ROM segment - bank(bankCount() - 1, myBankSegs - 1); + bank(romBankCount() - 1, myBankSegs - 1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -106,63 +112,103 @@ uInt8 CartridgeEnhanced::peek(uInt16 address) if (hotspot()) checkSwitchBank(address & 0x0FFF); - address &= myBankMask; - // Write port is e.g. at 0xF000 - 0xF07F (128 bytes) - if(address < myReadOffset + myRamSize && address >= myReadOffset) + if(isRamBank(address)) + { + address &= myRamMask; + // This is a read access to a write port! - return peekRAM(myRAM[address], peekAddress); + // 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 & 0xFFF) >> myBankShift] - mySize) >> 1) + address], + peekAddress); + } else - return myImage[myCurrentSegOffset[(peekAddress & 0xFFF) >> myBankShift] + address]; + { + address &= myBankMask; + + // Write port is e.g. at 0xF000 - 0xF07F (128 bytes) + if(address < myReadOffset + myRamSize && address >= myReadOffset) + // This is a read access to a write port! + // Reading from the write port triggers an unwanted write + return peekRAM(myRAM[address], peekAddress); + else + return myImage[myCurrentSegOffset[(peekAddress & 0xFFF) >> myBankShift] + address]; + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeEnhanced::poke(uInt16 address, uInt8 value) { - uInt16 pokeAddress = address; - // Switch banks if necessary + // Note: (TODO?) + // The checkSwitchBank() call makes no difference between ROM and e.g TIA space + // Writing to e.g. 0xf0xx might triger a bankswitch, is (and was!) this a bug??? if (checkSwitchBank(address & 0x0FFF, value)) return false; - address &= myBankMask; if(myRamSize) { - if(bool(address & myRamSize) == myRamWpHigh) + uInt16 pokeAddress = address; + + if(isRamBank(address)) { - pokeRAM(myRAM[address & myRamMask], pokeAddress, value); - return true; + if(bool(address & (myBankSize >> 1)) == myRamWpHigh) + { + address &= myRamMask; + // The RAM banks follow the ROM banks and are half the size of a ROM bank + pokeRAM(myRAM[((myCurrentSegOffset[(pokeAddress & 0xFFF) >> myBankShift] - mySize) >> 1) + address], + pokeAddress, value); + return true; + } + else + { + // Writing to the read port should be ignored, but trigger a break if option enabled + uInt8 dummy; + + pokeRAM(dummy, pokeAddress, value); + myRamWriteAccess = pokeAddress; + } } else { - // Writing to the read port should be ignored, but trigger a break if option enabled - uInt8 dummy; + //address &= myBankMask; + if(bool(address & myRamSize) == myRamWpHigh) + { + pokeRAM(myRAM[address & myRamMask], pokeAddress, value); + return true; + } + else + { + // Writing to the read port should be ignored, but trigger a break if option enabled + uInt8 dummy; - pokeRAM(dummy, pokeAddress, value); - myRamWriteAccess = pokeAddress; + pokeRAM(dummy, pokeAddress, value); + myRamWriteAccess = pokeAddress; + } } } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment, bool isRAM) +bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) { if(bankLocked()) return false; uInt16 segmentOffset = segment << myBankShift; - if(!isRAM) + if(!myRamBankCount || bank < romBankCount()) { // Setup ROM bank - // Remember what bank is in which segment - uInt32 bankOffset = myCurrentSegOffset[segment] = bank << myBankShift; - + uInt16 romBank = bank % romBankCount(); + // Remember what bank is in this segment + uInt32 bankOffset = myCurrentSegOffset[segment] = romBank << myBankShift; uInt16 hotspot = this->hotspot(); uInt16 hotSpotAddr; - uInt16 fromAddr = (segmentOffset + 0x1000 + myRamSize * 2) & ~System::PAGE_MASK; + uInt16 fromAddr = (0x1000 + segmentOffset + myRomOffset) & ~System::PAGE_MASK; // for ROMs < 4_KB, the whole address space will be mapped. - uInt16 toAddr = (segmentOffset + 0x1000 + (mySize < 4_KB ? 0x1000 : myBankSize)) & ~System::PAGE_MASK; + uInt16 toAddr = (0x1000 + segmentOffset + (mySize < 4_KB ? 0x1000 : myBankSize)) & ~System::PAGE_MASK; if(hotspot) hotSpotAddr = (hotspot & ~System::PAGE_MASK); @@ -185,24 +231,24 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment, bool isRAM) mySystem->setPageAccess(addr, access); } } - /*else + else { // Setup RAM bank - // TODO: define offsets on init - uInt16 myWriteBankOffset = myBankSize >> 1; - uInt16 myReadBankOffset = 0; + uInt16 ramBank = (bank - romBankCount()) % myRamBankCount; + // The RAM banks follow the ROM banks and are half the size of a ROM bank + uInt32 bankOffset = uInt32(mySize) + (ramBank << (myBankShift - 1)); - // Remember what bank is in which segment - uInt32 bankOffset = myCurrentSegOffset[segment] = bank << myBankShift; + // Remember what bank is in this segment + myCurrentSegOffset[segment] = bank << myBankShift; // Set the page accessing method for the RAM writing pages - uInt16 fromAddr = (segmentOffset + myWriteBankOffset + 0x1000) & ~System::PAGE_MASK; - uInt16 toAddr = (segmentOffset + myWriteBankOffset + 0x1000 + myBankSize >> 1) & ~System::PAGE_MASK; + uInt16 fromAddr = (0x1000 + segmentOffset + myWriteOffset) & ~System::PAGE_MASK; + uInt16 toAddr = (0x1000 + segmentOffset + myWriteOffset + (myBankSize >> 1)) & ~System::PAGE_MASK; System::PageAccess access(this, System::PageAccessType::WRITE); for(uInt16 addr = fromAddr; addr < toAddr; addr += System::PAGE_SIZE) { - uInt32 offset = bankOffset + (addr & myBankMask); + uInt32 offset = bankOffset + (addr & myRamMask); access.romAccessBase = &myRomAccessBase[offset]; access.romPeekCounter = &myRomAccessCounter[offset]; @@ -211,25 +257,23 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment, bool isRAM) } // Set the page accessing method for the RAM reading pages - fromAddr = (segmentOffset + myReadBankOffset + 0x1000) & ~System::PAGE_MASK; - toAddr = (segmentOffset + myReadBankOffset + 0x1000 + myBankSize >> 1) & ~System::PAGE_MASK; - + fromAddr = (0x1000 + segmentOffset + myReadOffset) & ~System::PAGE_MASK; + toAddr = (0x1000 + segmentOffset + myReadOffset + (myBankSize >> 1)) & ~System::PAGE_MASK; access.type = System::PageAccessType::READ; + for(uInt16 addr = fromAddr; addr < toAddr; addr += System::PAGE_SIZE) { - uInt32 offset = bankOffset + (addr & myBankMask); + uInt32 offset = bankOffset + (addr & myRamMask); - - - uInt16 offset = addr & myRamMask; - access.directPeekBase = &myBankRAM[offset]; + access.directPeekBase = &myRAM[offset - mySize]; access.romAccessBase = &myRomAccessBase[offset]; access.romPeekCounter = &myRomAccessCounter[offset]; access.romPokeCounter = &myRomAccessCounter[offset + myAccessSize]; mySystem->setPageAccess(addr, access); } - }*/ + + } return myBankChanged = true; } @@ -246,23 +290,42 @@ uInt16 CartridgeEnhanced::getSegmentBank(uInt16 segment) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeEnhanced::bankCount() const +uInt16 CartridgeEnhanced::romBankCount() const { return uInt16(mySize >> myBankShift); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt16 CartridgeEnhanced::ramBankCount() const +{ + return myRamBankCount; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CartridgeEnhanced::isRamBank(uInt16 address) const +{ + return myRamBankCount ? getBank(address) >= romBankCount() : false; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeEnhanced::patch(uInt16 address, uInt8 value) { - if((address & myBankMask) < myRamSize * 2) + if(isRamBank(address)) { - // Normally, a write to the read port won't do anything - // However, the patch command is special in that ignores such - // cart restrictions - myRAM[address & myRamMask] = value; + myRAM[((myCurrentSegOffset[(address & 0xFFF) >> myBankShift] - mySize) >> 1) + (address & myRamMask)] = value; } else - myImage[myCurrentSegOffset[(address & 0xFFF) >> myBankShift] + (address & myBankMask)] = value; + { + if((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 + // cart restrictions + myRAM[address & myRamMask] = value; + } + else + myImage[myCurrentSegOffset[(address & 0xFFF) >> myBankShift] + (address & myBankMask)] = value; + } return myBankChanged = true; } diff --git a/src/emucore/CartEnhanced.hxx b/src/emucore/CartEnhanced.hxx index 29046f0ea..3b68101cc 100644 --- a/src/emucore/CartEnhanced.hxx +++ b/src/emucore/CartEnhanced.hxx @@ -62,11 +62,10 @@ class CartridgeEnhanced : public Cartridge @param bank The bank that should be installed in the system @param segment The segment the bank should be using - @param isRAM True if the bank is a RAM bank @return true, if bank has changed */ - bool bank(uInt16 bank, uInt16 segment, bool isRAM = false); + bool bank(uInt16 bank, uInt16 segment); /** Install pages for the specified bank in the system. @@ -94,7 +93,21 @@ class CartridgeEnhanced : public Cartridge /** Query the number of banks supported by the cartridge. */ - uInt16 bankCount() const override; + uInt16 romBankCount() const override; + + /** + Query the number of RAM 'banks' supported by the cartridge. + */ + uInt16 ramBankCount() const override; + + /** + Check if the segment at that address contains a RAM bank + + @param address The address which defines the segment + + @return true, if the segment is currently mapped to a RAM bank + */ + bool isRamBank(uInt16 address) const; /** Patch the cartridge ROM. @@ -162,9 +175,19 @@ class CartridgeEnhanced : public Cartridge // The extra RAM size uInt16 myRamSize{RAM_SIZE}; // default 0 + // The number of RAM banks + uInt16 myRamBankCount{RAM_BANKS}; // default 0 + // The mask for the extra RAM uInt16 myRamMask{0}; // RAM_SIZE - 1, but doesn't matter when RAM_SIZE is 0 + // The offset into ROM space for reading from ROM + // This is zero for types without RAM and with banked RAM + // - xxSC = 0x0100 + // - FA(2) = 0x0200 + // - CV = 0x0800 + uInt16 myRomOffset{0}; + // The offset into ROM space for writing to RAM // - xxSC = 0x0000 // - FA(2) = 0x0000 @@ -202,6 +225,9 @@ class CartridgeEnhanced : public Cartridge // The size of extra RAM in ROM address space static constexpr uInt16 RAM_SIZE = 0; // default = none + // The size of extra RAM in ROM address space + static constexpr uInt16 RAM_BANKS = 0; + // Write port for extra RAM is at low address by default static constexpr bool RAM_HIGH_WP = false; diff --git a/src/emucore/CartFC.cxx b/src/emucore/CartFC.cxx index 741935c06..925718d50 100644 --- a/src/emucore/CartFC.cxx +++ b/src/emucore/CartFC.cxx @@ -61,14 +61,14 @@ bool CartridgeFC::poke(uInt16 address, uInt8 value) case 0x0FF9: // Set the high bits of target 4k bank - if (value << 2 < bankCount()) + if (value << 2 < romBankCount()) { myTargetBank += value << 2; - myTargetBank %= bankCount(); + myTargetBank %= romBankCount(); } else // special handling when both values are identical (e.g. 4/4 or 5/5) - myTargetBank = value % bankCount(); + myTargetBank = value % romBankCount(); break; default: diff --git a/src/emucore/CartMNetwork.cxx b/src/emucore/CartMNetwork.cxx index c5ff0cfab..984769b17 100644 --- a/src/emucore/CartMNetwork.cxx +++ b/src/emucore/CartMNetwork.cxx @@ -36,7 +36,7 @@ void CartridgeMNetwork::initialize(const ByteBuffer& image, size_t size) std::copy_n(image.get(), std::min(romSize(), size), myImage.get()); createRomAccessArrays(romSize() + myRAM.size()); - myRAMSlice = bankCount() - 1; + myRAMSlice = romBankCount() - 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -265,7 +265,7 @@ bool CartridgeMNetwork::patch(uInt16 address, uInt8 value) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeMNetwork::getImage(size_t& size) const { - size = bankCount() * BANK_SIZE; + size = romBankCount() * BANK_SIZE; return myImage.get(); } @@ -310,7 +310,7 @@ bool CartridgeMNetwork::load(Serializer& in) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeMNetwork::bankCount() const +uInt16 CartridgeMNetwork::romBankCount() const { return uInt16(mySize >> 11); } @@ -318,5 +318,5 @@ uInt16 CartridgeMNetwork::bankCount() const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeMNetwork::romSize() const { - return bankCount() * BANK_SIZE; + return romBankCount() * BANK_SIZE; } diff --git a/src/emucore/CartMNetwork.hxx b/src/emucore/CartMNetwork.hxx index ef06aae57..dd9443390 100644 --- a/src/emucore/CartMNetwork.hxx +++ b/src/emucore/CartMNetwork.hxx @@ -108,7 +108,7 @@ class CartridgeMNetwork : public Cartridge /** Query the number of banks supported by the cartridge. */ - uInt16 bankCount() const override; + uInt16 romBankCount() const override; /** Patch the cartridge ROM. diff --git a/src/emucore/CartSB.cxx b/src/emucore/CartSB.cxx index 58dd94522..56973392c 100644 --- a/src/emucore/CartSB.cxx +++ b/src/emucore/CartSB.cxx @@ -64,7 +64,7 @@ bool CartridgeSB::checkSwitchBank(uInt16 address, uInt8) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeSB::peek(uInt16 address) { - address &= (0x17FF + bankCount()); + address &= (0x17FF + romBankCount()); checkSwitchBank(address); @@ -82,7 +82,7 @@ uInt8 CartridgeSB::peek(uInt16 address) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeSB::poke(uInt16 address, uInt8 value) { - address &= (0x17FF + bankCount()); + address &= (0x17FF + romBankCount()); checkSwitchBank(address); diff --git a/src/emucore/CartSB.hxx b/src/emucore/CartSB.hxx index 3682dbb04..1e8a363a9 100644 --- a/src/emucore/CartSB.hxx +++ b/src/emucore/CartSB.hxx @@ -100,7 +100,7 @@ class CartridgeSB : public CartridgeEnhanced uInt16 hotspot() const override { return 0x0840; } - uInt16 getStartBank() const override { return bankCount() - 1; } + uInt16 getStartBank() const override { return romBankCount() - 1; } private: // Previous Device's page access diff --git a/src/emucore/CartWD.cxx b/src/emucore/CartWD.cxx index c6373fa05..9a14be24a 100644 --- a/src/emucore/CartWD.cxx +++ b/src/emucore/CartWD.cxx @@ -250,7 +250,7 @@ uInt16 CartridgeWD::getBank(uInt16) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeWD::bankCount() const +uInt16 CartridgeWD::romBankCount() const { return 16; } diff --git a/src/emucore/CartWD.hxx b/src/emucore/CartWD.hxx index 0e2aad45c..88c59e469 100644 --- a/src/emucore/CartWD.hxx +++ b/src/emucore/CartWD.hxx @@ -101,7 +101,7 @@ class CartridgeWD : public Cartridge /** Query the number of banks supported by the cartridge. */ - uInt16 bankCount() const override; + uInt16 romBankCount() const override; /** Patch the cartridge ROM. diff --git a/src/gui/GameInfoDialog.cxx b/src/gui/GameInfoDialog.cxx index 49ec158b0..bd5d87402 100644 --- a/src/gui/GameInfoDialog.cxx +++ b/src/gui/GameInfoDialog.cxx @@ -445,7 +445,7 @@ void GameInfoDialog::loadEmulationProperties(const Properties& props) VarList::push_back(items, "Auto", "AUTO"); if(instance().hasConsole()) { - uInt16 numBanks = instance().console().cartridge().bankCount(); + uInt16 numBanks = instance().console().cartridge().romBankCount(); for(uInt16 i = 0; i < numBanks; ++i) VarList::push_back(items, i, i); From 1a6640a456d94174d621b2ccb465e6e1ed0b16bc Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 15 Apr 2020 20:59:06 +0200 Subject: [PATCH 109/377] refactored Cart3E+ --- src/debugger/gui/Cart3EPlusWidget.cxx | 196 ++++++-------- src/debugger/gui/CartDebugWidget.cxx | 2 +- src/emucore/Bankswitch.cxx | 2 +- src/emucore/Cart3E.cxx | 2 +- src/emucore/Cart3EPlus.cxx | 359 +++++--------------------- src/emucore/Cart3EPlus.hxx | 160 +++++------- src/emucore/CartEnhanced.cxx | 6 +- 7 files changed, 212 insertions(+), 515 deletions(-) diff --git a/src/debugger/gui/Cart3EPlusWidget.cxx b/src/debugger/gui/Cart3EPlusWidget.cxx index 74935f22b..a93cb8f98 100644 --- a/src/debugger/gui/Cart3EPlusWidget.cxx +++ b/src/debugger/gui/Cart3EPlusWidget.cxx @@ -30,8 +30,8 @@ Cartridge3EPlusWidget::Cartridge3EPlusWidget( size_t size = cart.mySize; ostringstream info; - info << "3EPlus cartridge - (64K ROM + RAM)\n" - << " 4-64K ROM (1K banks), 32K RAM (512b banks)\n" + info << "3EPlus cartridge - (4..64K ROM + RAM)\n" + << " 4..64K ROM (1K banks), ..32K RAM (512b banks)\n" << "Each 1K ROM selected by writing to $3F\n" "Each 512b RAM selected by writing to $3E\n" " Lower 512b of bank x (R)\n" @@ -39,83 +39,78 @@ Cartridge3EPlusWidget::Cartridge3EPlusWidget( << "Startup bank = 0/-1/-1/0 (ROM)\n"; // Eventually, we should query this from the debugger/disassembler - //uInt16 start = (cart.myImage[size-3] << 8) | cart.myImage[size-4]; // Currently the cart starts at bank 0. If we change that, we have to change this too. uInt16 start = (cart.myImage[0x400-3] << 8) | cart.myImage[0x400 - 4]; - start -= start % 0x1000; - info << "Bank RORG" << " = $" << Common::Base::HEX4 << start << "\n"; + start &= 0xF000; + info << "Bank RORG = $" << Common::Base::HEX4 << start << "\n"; int xpos = 2, - ypos = addBaseInformation(size, "T. Jentzsch", info.str()) + - myLineHeight; + ypos = addBaseInformation(size, "Thomas Jentzsch", info.str()) + 8; VariantList bankno; - for(uInt32 i = 0; i < myCart.ROM_BANK_COUNT; ++i) + for(uInt32 i = 0; i < myCart.romBankCount(); ++i) VarList::push_back(bankno, i, i); VariantList banktype; VarList::push_back(banktype, "ROM", "ROM"); VarList::push_back(banktype, "RAM", "RAM"); - for(uInt32 i = 0; i < 4; ++i) + for(uInt32 seg = 0; seg < myCart.myBankSegs; ++seg) { - int xpos_s, ypos_s = ypos; + int xpos_s, ypos_s = ypos + 1; ostringstream label; - label << "Set segment " << i << " as "; + label << "Set segment " << seg << " as "; - new StaticTextWidget(boss, _font, xpos, ypos, _font.getStringWidth(label.str()), - myFontHeight, label.str(), TextAlign::Left); + new StaticTextWidget(boss, _font, xpos, ypos, label.str()); ypos += myLineHeight + 8; - xpos += 20; - myBankNumber[i] = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("Slot "), - myLineHeight, bankno, "Slot ", - 6*_font.getMaxCharWidth()); - addFocusWidget(myBankNumber[i]); + xpos += _font.getMaxCharWidth() * 2; + myBankNumber[seg] = + new PopUpWidget(boss, _font, xpos, ypos-2, 2 *_font.getMaxCharWidth(), + myLineHeight, bankno, "Bank "); + addFocusWidget(myBankNumber[seg]); - xpos += myBankNumber[i]->getWidth(); - myBankType[i] = - new PopUpWidget(boss, _font, xpos, ypos-2, 5*_font.getMaxCharWidth(), - myLineHeight, banktype, " of ", _font.getStringWidth(" of ")); - addFocusWidget(myBankType[i]); + xpos += myBankNumber[seg]->getWidth(); + myBankType[seg] = + new PopUpWidget(boss, _font, xpos, ypos-2, 3 *_font.getMaxCharWidth(), + myLineHeight, banktype, " of "); + addFocusWidget(myBankType[seg]); - xpos += myBankType[i]->getWidth() + 10; + xpos = myBankType[seg]->getRight() + _font.getMaxCharWidth(); - myBankCommit[i] = new ButtonWidget(boss, _font, xpos, ypos-4, + // add "Commit" button (why required?) + myBankCommit[seg] = new ButtonWidget(boss, _font, xpos, ypos-4, _font.getStringWidth(" Commit "), myButtonHeight, - "Commit", bankEnum[i]); - myBankCommit[i]->setTarget(this); - addFocusWidget(myBankCommit[i]); + "Commit", bankEnum[seg]); + myBankCommit[seg]->setTarget(this); + addFocusWidget(myBankCommit[seg]); - xpos_s = xpos + myBankCommit[i]->getWidth() + 20; + xpos_s = myBankCommit[seg]->getRight() + _font.getMaxCharWidth() * 2; StaticTextWidget* t; - int addr1 = start + (i*0x400), addr2 = addr1 + 0x1FF; + int addr1 = start + (seg * 0x400), addr2 = addr1 + 0x200; label.str(""); - label << Common::Base::HEX4 << addr1 << "-" << Common::Base::HEX4 << addr2; - t = new StaticTextWidget(boss, _font, xpos_s, ypos_s+2, - _font.getStringWidth(label.str()), myFontHeight, label.str(), TextAlign::Left); + label << "$" << Common::Base::HEX4 << addr1 << "-$" << Common::Base::HEX4 << (addr1 + 0x1FF); + t = new StaticTextWidget(boss, _font, xpos_s, ypos_s+2, label.str()); - int xoffset = xpos_s+t->getWidth() + 10; - myBankState[2*i] = new EditTextWidget(boss, _font, xoffset, ypos_s, + int xoffset = t->getRight() + _font.getMaxCharWidth(); + myBankState[2*seg] = new EditTextWidget(boss, _font, xoffset, ypos_s, w - xoffset - 10, myLineHeight, ""); - myBankState[2*i]->setEditable(false, true); + myBankState[2*seg]->setEditable(false, true); ypos_s += myLineHeight + 4; label.str(""); - label << Common::Base::HEX4 << (addr2 + 1) << "-" << Common::Base::HEX4 << (addr2 + 1 + 0x1FF); - new StaticTextWidget(boss, _font, xpos_s, ypos_s+2, - _font.getStringWidth(label.str()), myFontHeight, label.str(), TextAlign::Left); + label << "$" << Common::Base::HEX4 << addr2 << "-$" << Common::Base::HEX4 << (addr2 + 0x1FF); + new StaticTextWidget(boss, _font, xpos_s, ypos_s+2, label.str()); - myBankState[2*i+1] = new EditTextWidget(boss, _font, xoffset, ypos_s, + myBankState[2*seg+1] = new EditTextWidget(boss, _font, xoffset, ypos_s, w - xoffset - 10, myLineHeight, ""); - myBankState[2*i+1]->setEditable(false, true); + myBankState[2*seg+1]->setEditable(false, true); - xpos = 10; - ypos+= 2 * myLineHeight; + xpos = 2; + ypos += 2 * myLineHeight; } } @@ -163,15 +158,14 @@ void Cartridge3EPlusWidget::handleCommand(CommandSender* sender, myBankType[segment]->getSelected() < 0) return; - uInt8 bank = (segment << myCart.BANK_BITS) | - (myBankNumber[segment]->getSelected() & myCart.BIT_BANK_MASK); + uInt8 bank = myBankNumber[segment]->getSelected(); myCart.unlockBank(); if(myBankType[segment]->getSelectedTag() == "ROM") - myCart.bankROM(bank); + myCart.bank(bank, segment); else - myCart.bankRAM(bank); + myCart.bank(bank + myCart.romBankCount(), segment); myCart.lockBank(); invalidate(); @@ -183,26 +177,15 @@ string Cartridge3EPlusWidget::bankState() { ostringstream& buf = buffer(); - // In this scheme, consecutive 512b segments are either both ROM or both RAM; - // we only need to look at the lower segment to determine what the 1K bank is - for(int i = 0; i < 4; ++i) + for(int seg = 0; seg < myCart.myBankSegs; ++seg) { - uInt16 bank = myCart.bankInUse[i*2]; + int bank = myCart.getSegmentBank(seg); - if(bank == myCart.BANK_UNDEFINED) // never accessed - { - buf << " U!"; - } + if(bank >= myCart.romBankCount()) // was RAM mapped here? + buf << " RAM " << bank - myCart.romBankCount(); else - { - int bankno = bank & myCart.BIT_BANK_MASK; - - if(bank & myCart.BITMASK_ROMRAM) // was RAM mapped here? - buf << " RAM " << bankno; - else - buf << " ROM " << bankno; - } - if(i < 3) + buf << " ROM " << bank; + if(seg < myCart.myBankSegs - 1) buf << " /"; } @@ -212,68 +195,42 @@ string Cartridge3EPlusWidget::bankState() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3EPlusWidget::updateUIState() { - // Set description for each 512b bank state (@ each index) + // Set description for each 1K bank state (@ each index) // Set contents for actual banks number and type (@ each even index) - for(int i = 0; i < 8; ++i) + for(int seg = 0; seg < myCart.myBankSegs; ++seg) { - uInt16 bank = myCart.bankInUse[i]; + uInt16 bank = myCart.getSegmentBank(seg); + ostringstream buf; - if(bank == myCart.BANK_UNDEFINED) // never accessed + if(bank >= myCart.romBankCount()) // was RAM mapped here? { - myBankState[i]->setText("Undefined"); - if(i % 2 == 0) - { - myBankNumber[i/2]->clearSelection(); - myBankType[i/2]->clearSelection(); - } + uInt16 ramBank = bank - myCart.romBankCount(); + + buf << "RAM " << std::dec << ramBank << " @ $" << Common::Base::HEX4 + << (ramBank << myCart.myBankShift) << "(R)"; + myBankState[seg * 2]->setText(buf.str()); + + buf.str(""); + buf << "RAM " << std::dec << ramBank << " @ $" << Common::Base::HEX4 + << ((ramBank << myCart.myBankShift) + myCart.myBankSize) << "(W)"; + myBankState[seg * 2 + 1]->setText(buf.str()); + + myBankNumber[seg]->setSelected(ramBank); + myBankType[seg]->setSelected("RAM"); } else { - ostringstream buf; - int bankno = bank & myCart.BIT_BANK_MASK; + buf << "ROM " << std::dec << bank << " @ $" << Common::Base::HEX4 + << ((bank << myCart.myBankShift)); + myBankState[seg * 2]->setText(buf.str()); - if(bank & myCart.BITMASK_ROMRAM) // was RAM mapped here? - { - if(bank & myCart.BITMASK_LOWERUPPER) // upper is write port - { - buf << "RAM " << bankno << " @ $" << Common::Base::HEX4 - << (bankno << myCart.RAM_BANK_TO_POWER) << " (W)"; - myBankState[i]->setText(buf.str()); - } - else - { - buf << "RAM " << bankno << " @ $" << Common::Base::HEX4 - << (bankno << myCart.RAM_BANK_TO_POWER) << " (R)"; - myBankState[i]->setText(buf.str()); - } + buf.str(""); + buf << "ROM " << std::dec << bank << " @ $" << Common::Base::HEX4 + << ((bank << myCart.myBankShift) + myCart.myBankSize); + myBankState[seg * 2 + 1]->setText(buf.str()); - if(i % 2 == 0) - { - myBankNumber[i/2]->setSelected(bankno); - myBankType[i/2]->setSelected("RAM"); - } - } - else - { - if(bank & myCart.BITMASK_LOWERUPPER) // upper is high 512b - { - buf << "ROM " << bankno << " @ $" << Common::Base::HEX4 - << ((bankno << myCart.RAM_BANK_TO_POWER) + myCart.RAM_BANK_SIZE); - myBankState[i]->setText(buf.str()); - } - else - { - buf << "ROM " << bankno << " @ $" << Common::Base::HEX4 - << (bankno << myCart.RAM_BANK_TO_POWER); - myBankState[i]->setText(buf.str()); - } - - if(i % 2 == 0) - { - myBankNumber[i/2]->setSelected(bankno); - myBankType[i/2]->setSelected("ROM"); - } - } + myBankNumber[seg]->setSelected(bank); + myBankType[seg]->setSelected("ROM"); } } } @@ -294,9 +251,10 @@ uInt32 Cartridge3EPlusWidget::internalRamRPort(int start) string Cartridge3EPlusWidget::internalRamDescription() { ostringstream desc; + desc << "Accessible 512b at a time via:\n" << " $f000/$f400/$f800/$fc00 for Read Access\n" - << " $f200/$f600/$fa00/$fe00 for Write Access (+$200)"; + << " $f200/$f600/$fa00/$fe00 for Write Access"; return desc.str(); } diff --git a/src/debugger/gui/CartDebugWidget.cxx b/src/debugger/gui/CartDebugWidget.cxx index 9e164f4a6..208eec5a7 100644 --- a/src/debugger/gui/CartDebugWidget.cxx +++ b/src/debugger/gui/CartDebugWidget.cxx @@ -42,7 +42,7 @@ int CartDebugWidget::addBaseInformation(size_t bytes, const string& manufacturer const string& desc, const uInt16 maxlines) { const int lwidth = _font.getStringWidth("Manufacturer "), - fwidth = _w - lwidth - 20; + fwidth = _w - lwidth - 12; EditTextWidget* w = nullptr; ostringstream buf; diff --git a/src/emucore/Bankswitch.cxx b/src/emucore/Bankswitch.cxx index 9726dc6aa..84d0dd037 100644 --- a/src/emucore/Bankswitch.cxx +++ b/src/emucore/Bankswitch.cxx @@ -105,7 +105,7 @@ Bankswitch::BSList = {{ { "128IN1" , "128IN1 Multicart (256/512K)" }, { "2K" , "2K (32-2048 bytes Atari)" }, { "3E" , "3E (32K Tigervision)" }, - { "3E+" , "3E+ (TJ modified DASH)" }, + { "3E+" , "3E+ (TJ modified 3E)" }, { "3F" , "3F (512K Tigervision)" }, { "4A50" , "4A50 (64K 4A50 + RAM)" }, { "4K" , "4K (4K Atari)" }, diff --git a/src/emucore/Cart3E.cxx b/src/emucore/Cart3E.cxx index a927ddd2d..3e7454bda 100644 --- a/src/emucore/Cart3E.cxx +++ b/src/emucore/Cart3E.cxx @@ -35,7 +35,7 @@ void Cartridge3E::install(System& system) { CartridgeEnhanced::install(system); - System::PageAccess access(this, System::PageAccessType::READWRITE); + System::PageAccess access(this, System::PageAccessType::WRITE); // The hotspots ($3E and $3F) are in TIA address space, so we claim it here for(uInt16 addr = 0x00; addr < 0x40; addr += System::PAGE_SIZE) diff --git a/src/emucore/Cart3EPlus.cxx b/src/emucore/Cart3EPlus.cxx index 1fe28a022..f6ac01679 100644 --- a/src/emucore/Cart3EPlus.cxx +++ b/src/emucore/Cart3EPlus.cxx @@ -22,339 +22,104 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge3EPlus::Cartridge3EPlus(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5), - mySize(size) -{ - // Allocate array for the ROM image - myImage = make_unique(mySize); + : CartridgeEnhanced(image, size, md5, settings) - // Copy the ROM image into my buffer - std::copy_n(image.get(), mySize, myImage.get()); - createRomAccessArrays(mySize + myRAM.size()); +{ + myBankShift = BANK_SHIFT; + myRamSize = RAM_SIZE; + myRamBankCount = RAM_BANKS; + myRamWpHigh = RAM_HIGH_WP; + + //// Allocate array for the ROM image + //myImage = make_unique(mySize); + + //// Copy the ROM image into my buffer + //std::copy_n(image.get(), mySize, myImage.get()); + //createRomAccessArrays(mySize + myRAM.size()); } +//// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//void Cartridge3EPlus::reset() +//{ +// initializeRAM(myRAM.data(), myRAM.size()); +// +// // Remember startup bank (0 per spec, rather than last per 3E scheme). +// // Set this to go to 3rd 1K Bank. +// initializeStartBank(0); +// +// // Initialise bank values for all ROM/RAM access +// // This is used to reverse-lookup from address to bank location +// for(auto& b: bankInUse) +// b = BANK_UNDEFINED; // bank is undefined and inaccessible! +// +// initializeBankState(); +// +// // We'll map the startup banks 0 and 3 from the image into the third 1K bank upon reset +// bankROM((0 << BANK_BITS) | 0); +// bankROM((3 << BANK_BITS) | 0); +//} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3EPlus::reset() { - initializeRAM(myRAM.data(), myRAM.size()); + CartridgeEnhanced::reset(); - // Remember startup bank (0 per spec, rather than last per 3E scheme). - // Set this to go to 3rd 1K Bank. - initializeStartBank(0); - - // Initialise bank values for all ROM/RAM access - // This is used to reverse-lookup from address to bank location - for(auto& b: bankInUse) - b = BANK_UNDEFINED; // bank is undefined and inaccessible! - - initializeBankState(); - - // We'll map the startup banks 0 and 3 from the image into the third 1K bank upon reset - bankROM((0 << BANK_BITS) | 0); - bankROM((3 << BANK_BITS) | 0); + bank(mySystem->randGenerator().next() % romBankCount(), 1); + bank(mySystem->randGenerator().next() % romBankCount(), 2); + bank(startBank(), 3); // Stella reads the PC vector always from here (TODO?) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3EPlus::install(System& system) { - mySystem = &system; + CartridgeEnhanced::install(system); - System::PageAccess access(this, System::PageAccessType::READWRITE); + System::PageAccess access(this, System::PageAccessType::WRITE); // The hotspots are in TIA address space, so we claim it here for(uInt16 addr = 0x00; addr < 0x40; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); - - // Initialise bank values for all ROM/RAM access - // This is used to reverse-lookup from address to bank location - for(auto& b: bankInUse) - b = BANK_UNDEFINED; // bank is undefined and inaccessible! - - initializeBankState(); - - // Setup the last segment (of 4, each 1K) to point to the first ROM slice - // Actually we DO NOT want "always". It's just on bootup, and can be out switched later - bankROM((0 << BANK_BITS) | 0); - bankROM((3 << BANK_BITS) | 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 Cartridge3EPlus::getBank(uInt16 address) const +bool Cartridge3EPlus::checkSwitchBank(uInt16 address, uInt8 value) { - return bankInUse[(address & 0xFFF) >> 10]; // 1K slices -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 Cartridge3EPlus::romBankCount() const -{ - return uInt16(mySize >> 10); // 1K slices + // Switch banks if necessary + if(address == 0x003F) { + // Switch ROM bank into segment 0 + bank(value & 0b111111, value >> 6); + return true; + } + else if(address == 0x003E) + { + // Switch RAM bank into segment 0 + bank((value & 0b111111) + romBankCount(), value >> 6); + return true; + } + return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 Cartridge3EPlus::peek(uInt16 address) { uInt16 peekAddress = address; - address &= 0x0FFF; // restrict to 4K address range + address &= 0x0FFF; - uInt8 value = 0; - uInt32 bank = (address >> (ROM_BANK_TO_POWER - 1)) & 7; // convert to 512 byte bank index (0-7) - uInt16 imageBank = bankInUse[bank]; // the ROM/RAM bank that's here + if(address < 0x0040) // TIA peek + return mySystem->tia().peek(address); - if(imageBank == BANK_UNDEFINED) // an uninitialised bank? - { - // accessing invalid bank, so return should be... random? - value = mySystem->randGenerator().next(); - - } - else if(imageBank & BITMASK_ROMRAM) // a RAM bank - { - Int32 ramBank = imageBank & BIT_BANK_MASK; // discard irrelevant bits - Int32 offset = ramBank << RAM_BANK_TO_POWER; // base bank address in RAM - offset += (address & BITMASK_RAM_BANK); // + byte offset in RAM bank - - return peekRAM(myRAM[offset], peekAddress); - } - - return value; + return CartridgeEnhanced::peek(peekAddress); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge3EPlus::poke(uInt16 address, uInt8 value) { - bool changed = false; + if(CartridgeEnhanced::poke(address, value)) + return true; - // Check for write to the bank switch address. RAM/ROM and bank # are encoded in 'value' - // There are NO mirrored hotspots. - - if(address == BANK_SWITCH_HOTSPOT_RAM) - changed = bankRAM(value); - else if(address == BANK_SWITCH_HOTSPOT_ROM) - changed = bankROM(value); - - if(!(address & 0x1000)) - { + if(address < 0x0040) // TIA poke // Handle TIA space that we claimed above - changed = changed || mySystem->tia().poke(address, value); - } - else - { - uInt32 bankNumber = (address >> RAM_BANK_TO_POWER) & 7; // now 512 byte bank # (ie: 0-7) - Int16 whichBankIsThere = bankInUse[bankNumber]; // ROM or RAM bank reference + return mySystem->tia().poke(address, value); - if(whichBankIsThere & BITMASK_ROMRAM) - { - if(address & RAM_BANK_SIZE) - { - uInt32 byteOffset = address & BITMASK_RAM_BANK; - uInt32 baseAddress = ((whichBankIsThere & BIT_BANK_MASK) << RAM_BANK_TO_POWER) + byteOffset; - pokeRAM(myRAM[baseAddress], address, value); - changed = true; - } - else - { - // Writing to the read port should be ignored, but trigger a break if option enabled - uInt8 dummy; - - pokeRAM(dummy, address, value); - myRamWriteAccess = address; - changed = false; - } - } - } - - return changed; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Cartridge3EPlus::bankRAM(uInt8 bank) -{ - if(bankLocked()) // debugger can lock RAM - return false; - -//cerr << "bankRAM " << int(bank) << endl; - - // Each RAM bank uses two slots, separated by 0x200 in memory -- one read, one write. - bankRAMSlot(bank | BITMASK_ROMRAM | 0); - bankRAMSlot(bank | BITMASK_ROMRAM | BITMASK_LOWERUPPER); - - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge3EPlus::bankRAMSlot(uInt16 bank) -{ - uInt16 bankNumber = (bank >> BANK_BITS) & 3; // which bank # we are switching TO (BITS D6,D7) to 512 byte block - uInt16 currentBank = bank & BIT_BANK_MASK; // Wrap around/restrict to valid range - bool upper = bank & BITMASK_LOWERUPPER; // is this the read or write port - - uInt32 startCurrentBank = currentBank << RAM_BANK_TO_POWER; // Effectively * 512 bytes -//cerr << "raw bank=" << std::dec << currentBank << endl -// << "startCurrentBank=$" << std::hex << startCurrentBank << endl; - // Setup the page access methods for the current bank - System::PageAccess access(this, System::PageAccessType::READ); - - if(upper) // We're mapping the write port - { - bankInUse[bankNumber * 2 + 1] = Int16(bank); - access.type = System::PageAccessType::WRITE; - } - else // We're mapping the read port - { - bankInUse[bankNumber * 2] = Int16(bank); - access.type = System::PageAccessType::READ; - } - - uInt16 start = 0x1000 + (bankNumber << (RAM_BANK_TO_POWER+1)) + (upper ? RAM_WRITE_OFFSET : 0); - uInt16 end = start + RAM_BANK_SIZE - 1; - -//cerr << "bank RAM: " << bankNumber << " -> " << (bankNumber * 2 + (upper ? 1 : 0)) << (upper ? " (W)" : " (R)") << endl -// << "start=" << std::hex << start << ", end=" << end << endl << endl; - for(uInt16 addr = start; addr <= end; addr += System::PAGE_SIZE) - { - if(!upper) - access.directPeekBase = &myRAM[startCurrentBank + (addr & (RAM_BANK_SIZE - 1))]; - - access.romAccessBase = &myRomAccessBase[mySize + startCurrentBank + (addr & (RAM_BANK_SIZE - 1))]; - mySystem->setPageAccess(addr, access); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Cartridge3EPlus::bankROM(uInt8 bank) -{ - if(bankLocked()) // debugger can lock ROM - return false; - - // Map ROM bank image into the system into the correct slot - // Memory map is 1K slots at 0x1000, 0x1400, 0x1800, 0x1C00 - // Each ROM uses 2 consecutive 512 byte slots - bankROMSlot(bank | 0); - bankROMSlot(bank | BITMASK_LOWERUPPER); - - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge3EPlus::bankROMSlot(uInt16 bank) -{ - uInt16 bankNumber = (bank >> BANK_BITS) & 3; // which bank # we are switching TO (BITS D6,D7) - uInt16 currentBank = bank & BIT_BANK_MASK; // Wrap around/restrict to valid range - bool upper = bank & BITMASK_LOWERUPPER; // is this the lower or upper 512b - - bankInUse[bankNumber * 2 + (upper ? 1 : 0)] = Int16(bank); // Record which bank switched in (as ROM) - - uInt32 startCurrentBank = currentBank << ROM_BANK_TO_POWER; // Effectively *1K - - // Setup the page access methods for the current bank - System::PageAccess access(this, System::PageAccessType::READ); - - uInt16 start = 0x1000 + (bankNumber << ROM_BANK_TO_POWER) + (upper ? ROM_BANK_SIZE / 2 : 0); - uInt16 end = start + ROM_BANK_SIZE / 2 - 1; - - for(uInt16 addr = start; addr <= end; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[startCurrentBank + (addr & (ROM_BANK_SIZE - 1))]; - access.romAccessBase = &myRomAccessBase[startCurrentBank + (addr & (ROM_BANK_SIZE - 1))]; - mySystem->setPageAccess(addr, access); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge3EPlus::initializeBankState() -{ - // Switch in each 512b slot - for(uInt32 b = 0; b < 8; ++b) - { - if(bankInUse[b] == BANK_UNDEFINED) - { - // All accesses point to peek/poke above - System::PageAccess access(this, System::PageAccessType::READ); - uInt16 start = 0x1000 + (b << RAM_BANK_TO_POWER); - uInt16 end = start + RAM_BANK_SIZE - 1; - for(uInt16 addr = start; addr <= end; addr += System::PAGE_SIZE) - mySystem->setPageAccess(addr, access); - } - else if (bankInUse[b] & BITMASK_ROMRAM) - bankRAMSlot(bankInUse[b]); - else - bankROMSlot(bankInUse[b]); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Cartridge3EPlus::patch(uInt16 address, uInt8 value) -{ -#if 0 - // Patch the cartridge ROM (for debugger) - - myBankChanged = true; - - uInt32 bankNumber = (address >> RAM_BANK_TO_POWER) & 7; // now 512 byte bank # (ie: 0-7) - uInt16 whichBankIsThere = bankInUse[bankNumber]; // ROM or RAM bank reference - - if (whichBankIsThere == BANK_UNDEFINED) { - - // We're trying to access undefined memory (no bank here yet). Fail! - myBankChanged = false; - - } else if (whichBankIsThere & BITMASK_ROMRAM) { // patching RAM (512 byte banks) - - uInt32 byteOffset = address & BITMASK_RAM_BANK; - uInt32 baseAddress = ((whichBankIsThere & BIT_BANK_MASK) << RAM_BANK_TO_POWER) + byteOffset; - myRAM[baseAddress] = value; // write to RAM - - // TODO: Stephen -- should we set 'myBankChanged' true when there's a RAM write? - - } else { // patching ROM (1K banks) - - uInt32 byteOffset = address & BITMASK_ROM_BANK; - uInt32 baseAddress = (whichBankIsThere << ROM_BANK_TO_POWER) + byteOffset; - myImage[baseAddress] = value; // write to the image - } - - return myBankChanged; -#else return false; -#endif -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* Cartridge3EPlus::getImage(size_t& size) const -{ - size = mySize; - return myImage.get(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Cartridge3EPlus::save(Serializer& out) const -{ - try - { - out.putShortArray(bankInUse.data(), bankInUse.size()); - out.putByteArray(myRAM.data(), myRAM.size()); - } - catch (...) - { - cerr << "ERROR: Cartridge3EPlus::save" << endl; - return false; - } - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Cartridge3EPlus::load(Serializer& in) -{ - try - { - in.getShortArray(bankInUse.data(), bankInUse.size()); - in.getByteArray(myRAM.data(), myRAM.size()); - } - catch (...) - { - cerr << "ERROR: Cartridge3EPlus::load" << endl; - return false; - } - - initializeBankState(); - return true; } diff --git a/src/emucore/Cart3EPlus.hxx b/src/emucore/Cart3EPlus.hxx index 70309d308..1a2440e40 100644 --- a/src/emucore/Cart3EPlus.hxx +++ b/src/emucore/Cart3EPlus.hxx @@ -21,7 +21,7 @@ class System; #include "bspf.hxx" -#include "Cart.hxx" +#include "CartEnhanced.hxx" #ifdef DEBUGGER_SUPPORT class Cartridge3EPlusWidget; @@ -29,19 +29,67 @@ class Cartridge3EPlusWidget; #endif /** - Cartridge class from Thomas Jentzsch, mostly based on the 'DASH' scheme - with the following changes: + Cartridge class for new tiling engine "Boulder Dash" format games with RAM. + Kind of a combination of 3F and 3E, with better switchability. + B.Watson's Cart3E was used as a template for building this implementation. - RAM areas: - - read $x000, write $x200 - - read $x400, write $x600 - - read $x800, write $xa00 - - read $xc00, write $xe00 + The destination bank (0-3) is held in the top bits of the value written to + $3E (for RAM switching) or $3F (for ROM switching). The low 6 bits give + the actual bank number (0-63) corresponding to 512 byte blocks for RAM and + 1024 byte blocks for ROM. The maximum size is therefore 32K RAM and 64K ROM. - @author Thomas Jentzsch and Stephen Anthony + D7D6 indicate the bank number (0-3) + D5D4D3D2D1D0 indicate the actual # (0-63) from the image/ram + + ROM: + + 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. + + In this scheme, the 4K address space is broken into four 1K ROM/512b RAM segments + living at 0x1000, 0x1400, 0x1800, 0x1C00 (or, same thing, 0xF000... etc.), + + 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. + + 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. + + 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, + $FC00), and lower 6 bits indicate the 1K bank to switch in. Can handle 64 + x 1K ROM banks (64K total). + + D7 D6 D5D4D3D2D1D0 + 0 0 x x x x x x switch a 1K ROM bank xxxxxx to $F000 + 0 1 switch a 1K ROM bank xxxxxx to $F400 + 1 0 switch a 1K ROM bank xxxxxx to $F800 + 1 1 switch a 1K ROM bank xxxxxx to $FC00 + + RAM switching (write of segment+bank number to $3E) with D7D6 upper 2 bits of + bank # indicates the destination RAM segment (0-3, corresponding to $F000, + $F400, $F800, $FC00). + + Can handle 64 x 512 byte RAM banks (32K total) + + D7 D6 D5D4D3D2D1D0 + 0 0 x x x x x x switch a 512 byte RAM bank xxxxxx to $F000 with write @ $F200 + 0 1 switch a 512 byte RAM bank xxxxxx to $F400 with write @ $F600 + 1 0 switch a 512 byte RAM bank xxxxxx to $F800 with write @ $FA00 + 1 1 switch a 512 byte RAM bank xxxxxx to $FC00 with write @ $FE00 + + @author Thomas Jentzsch and Stephen Anthony */ -class Cartridge3EPlus: public Cartridge +class Cartridge3EPlus: public CartridgeEnhanced { friend class Cartridge3EPlusWidget; @@ -70,51 +118,6 @@ class Cartridge3EPlus: public Cartridge */ void install(System& system) override; - /** - Get the current bank. - - @param address The address to use when querying the bank - */ - uInt16 getBank(uInt16 address = 0) const override; - - /** - Query the number of banks supported by the cartridge. - */ - uInt16 romBankCount() const override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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). @@ -152,47 +155,20 @@ class Cartridge3EPlus: public Cartridge bool poke(uInt16 address, uInt8 value) override; private: - bool bankRAM(uInt8 bank); // switch a RAM bank - bool bankROM(uInt8 bank); // switch a ROM bank + bool checkSwitchBank(uInt16 address, uInt8 value) override; - void bankRAMSlot(uInt16 bank); // switch in a 512b RAM slot (lower or upper 1/2 bank) - void bankROMSlot(uInt16 bank); // switch in a 512b RAM slot (read or write port) + private: + // log(ROM bank segment size) / log(2) + static constexpr uInt16 BANK_SHIFT = 10; // = 1K = 0x0400 - void initializeBankState(); // set all banks according to current bankInUse state + // The size of extra RAM in ROM address space + static constexpr uInt16 RAM_BANKS = 64; - // We have an array that indicates for each of the 8 512 byte areas of the address space, which ROM/RAM - // bank is used in that area. ROM switches 1K so occupies 2 successive entries for each switch. RAM occupies - // two as well, one 512 byte for read and one for write. The RAM locations are +0x800 apart, and the ROM - // are consecutive. This allows us to determine on a read/write exactly where the data is. + // RAM size + static constexpr uInt16 RAM_SIZE = RAM_BANKS << (BANK_SHIFT - 1); // = 32K = 0x4000; - static constexpr uInt16 BANK_UNDEFINED = 0x8000; // bank is undefined and inaccessible - std::array bankInUse; // bank being used for ROM/RAM (eight 512 byte areas) - - static constexpr uInt16 BANK_SWITCH_HOTSPOT_RAM = 0x3E; // writes to this address cause bankswitching - static constexpr uInt16 BANK_SWITCH_HOTSPOT_ROM = 0x3F; // writes to this address cause bankswitching - - static constexpr uInt8 BANK_BITS = 6; // # bits for bank - static constexpr uInt8 BIT_BANK_MASK = (1 << BANK_BITS) - 1; // mask for those bits - static constexpr uInt16 BITMASK_LOWERUPPER = 0x100; // flags lower or upper section of bank (1==upper) - static constexpr uInt16 BITMASK_ROMRAM = 0x200; // flags ROM or RAM bank switching (1==RAM) - - static constexpr uInt16 MAXIMUM_BANK_COUNT = (1 << BANK_BITS); - static constexpr uInt16 RAM_BANK_TO_POWER = 9; // 2^n = 512 - static constexpr uInt16 RAM_BANK_SIZE = (1 << RAM_BANK_TO_POWER); - static constexpr uInt16 BITMASK_RAM_BANK = (RAM_BANK_SIZE - 1); - static constexpr uInt32 RAM_TOTAL_SIZE = MAXIMUM_BANK_COUNT * RAM_BANK_SIZE; - - static constexpr uInt16 ROM_BANK_TO_POWER = 10; // 2^n = 1024 - static constexpr uInt16 ROM_BANK_SIZE = (1 << ROM_BANK_TO_POWER); - static constexpr uInt16 BITMASK_ROM_BANK = (ROM_BANK_SIZE - 1); - - static constexpr uInt16 ROM_BANK_COUNT = 64; - - static constexpr uInt16 RAM_WRITE_OFFSET = 0x200; - - ByteBuffer myImage; // Pointer to a dynamically allocated ROM image of the cartridge - size_t mySize{0}; // Size of the ROM image - std::array myRAM; + // Write port for extra RAM is at high address + static constexpr bool RAM_HIGH_WP = true; private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index b8c1cde13..01cf5cbcb 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -20,7 +20,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeEnhanced::CartridgeEnhanced(const ByteBuffer& image, size_t size, - const string& md5, const Settings& settings) + const string& md5, const Settings& settings) : Cartridge(settings, md5), mySize(size) { @@ -270,9 +270,7 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) access.romPeekCounter = &myRomAccessCounter[offset]; access.romPokeCounter = &myRomAccessCounter[offset + myAccessSize]; mySystem->setPageAccess(addr, access); - } - - + } } return myBankChanged = true; } From 668fb487ba137cd42be5064b5fd14a3dc5a72957 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 15 Apr 2020 21:15:44 +0200 Subject: [PATCH 110/377] removed DASH type (incl. doc update) --- Changes.txt | 2 +- docs/index.html | 3 +- src/debugger/gui/CartDASHWidget.cxx | 371 ---------------------------- src/debugger/gui/CartDASHWidget.hxx | 86 ------- src/debugger/gui/module.mk | 1 - src/emucore/Bankswitch.cxx | 4 - src/emucore/Bankswitch.hxx | 10 +- src/emucore/CartDASH.cxx | 355 -------------------------- src/emucore/CartDASH.hxx | 277 --------------------- src/emucore/CartDetector.cxx | 15 +- src/emucore/CartDetector.hxx | 5 - src/emucore/module.mk | 1 - src/windows/Stella.vcxproj | 8 - src/windows/Stella.vcxproj.filters | 12 - 14 files changed, 8 insertions(+), 1142 deletions(-) delete mode 100644 src/debugger/gui/CartDASHWidget.cxx delete mode 100644 src/debugger/gui/CartDASHWidget.hxx delete mode 100644 src/emucore/CartDASH.cxx delete mode 100644 src/emucore/CartDASH.hxx diff --git a/Changes.txt b/Changes.txt index 7a6b7bc3d..e7faac008 100644 --- a/Changes.txt +++ b/Changes.txt @@ -30,7 +30,7 @@ * Restored 'cfg' directory for Distella config files. - * Removed unused CV+ bank switching type. + * Removed unused CV+ and DASH bank switching types. -Have fun! diff --git a/docs/index.html b/docs/index.html index b0065878b..18aa916dc 100644 --- a/docs/index.html +++ b/docs/index.html @@ -3781,7 +3781,7 @@ Ms Pac-Man (Stella extended codes): - + @@ -3794,7 +3794,6 @@ Ms Pac-Man (Stella extended codes): - diff --git a/src/debugger/gui/CartDASHWidget.cxx b/src/debugger/gui/CartDASHWidget.cxx deleted file mode 100644 index a3dfa1109..000000000 --- a/src/debugger/gui/CartDASHWidget.cxx +++ /dev/null @@ -1,371 +0,0 @@ -//============================================================================ -// -// 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 "CartDASH.hxx" -#include "EditTextWidget.hxx" -#include "PopUpWidget.hxx" -#include "CartDASHWidget.hxx" - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -CartridgeDASHWidget::CartridgeDASHWidget( - GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, - int x, int y, int w, int h, CartridgeDASH& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) -{ - size_t size = cart.mySize; - - ostringstream info; - info << "DASH cartridge - (64K ROM + RAM)\n" - << " 4-64K ROM (1K banks), 32K RAM (512b banks)\n" - << "Each 1K ROM selected by writing to $3F\n" - "Each 512b RAM selected by writing to $3E\n" - " First 512B of bank x (R)\n" - " First 512B of bank x+4 (+$800) (W)\n" - << "Startup bank = 0/-1/-1/0 (ROM)\n"; - - // Eventually, we should query this from the debugger/disassembler - uInt16 start = (cart.myImage[size-3] << 8) | cart.myImage[size-4]; - start -= start % 0x1000; - info << "Bank RORG" << " = $" << Common::Base::HEX4 << start << "\n"; - - int xpos = 2, - ypos = addBaseInformation(size, "A. Davie & T. Jentzsch", info.str()) + - myLineHeight; - - VariantList bankno; - for(uInt32 i = 0; i < myCart.ROM_BANK_COUNT; ++i) - VarList::push_back(bankno, i, i); - - VariantList banktype; - VarList::push_back(banktype, "ROM", "ROM"); - VarList::push_back(banktype, "RAM", "RAM"); - - for(uInt32 i = 0; i < 4; ++i) - { - int xpos_s, ypos_s = ypos; - - ostringstream label; - label << "Set segment " << i << " as: "; - - new StaticTextWidget(boss, _font, xpos, ypos, _font.getStringWidth(label.str()), - myFontHeight, label.str(), TextAlign::Left); - ypos += myLineHeight + 8; - - xpos += 20; - myBankNumber[i] = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("Slot "), - myLineHeight, bankno, "Slot ", - 6*_font.getMaxCharWidth()); - addFocusWidget(myBankNumber[i]); - - xpos += myBankNumber[i]->getWidth(); - myBankType[i] = - new PopUpWidget(boss, _font, xpos, ypos-2, 5*_font.getMaxCharWidth(), - myLineHeight, banktype, " of ", _font.getStringWidth(" of ")); - addFocusWidget(myBankType[i]); - - xpos += myBankType[i]->getWidth() + 10; - - myBankCommit[i] = new ButtonWidget(boss, _font, xpos, ypos-4, - _font.getStringWidth(" Commit "), myButtonHeight, - "Commit", bankEnum[i]); - myBankCommit[i]->setTarget(this); - addFocusWidget(myBankCommit[i]); - - xpos_s = xpos + myBankCommit[i]->getWidth() + 20; - - StaticTextWidget* t; - int addr1 = start + (i*0x400), addr2 = addr1 + 0x1FF; - - label.str(""); - label << Common::Base::HEX4 << addr1 << "-" << Common::Base::HEX4 << addr2; - t = new StaticTextWidget(boss, _font, xpos_s, ypos_s+2, - _font.getStringWidth(label.str()), myFontHeight, label.str(), TextAlign::Left); - - int xoffset = xpos_s+t->getWidth() + 10; - myBankState[2*i] = new EditTextWidget(boss, _font, xoffset, ypos_s, - w - xoffset - 10, myLineHeight, ""); - myBankState[2*i]->setEditable(false, true); - ypos_s += myLineHeight + 4; - - label.str(""); - label << Common::Base::HEX4 << (addr2 + 1) << "-" << Common::Base::HEX4 << (addr2 + 1 + 0x1FF); - new StaticTextWidget(boss, _font, xpos_s, ypos_s+2, - _font.getStringWidth(label.str()), myFontHeight, label.str(), TextAlign::Left); - - myBankState[2*i+1] = new EditTextWidget(boss, _font, xoffset, ypos_s, - w - xoffset - 10, myLineHeight, ""); - myBankState[2*i+1]->setEditable(false, true); - - xpos = 10; - ypos+= 2 * myLineHeight; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeDASHWidget::saveOldState() -{ - myOldState.internalram.clear(); - - for(uInt32 i = 0; i < internalRamSize(); ++i) - myOldState.internalram.push_back(myCart.myRAM[i]); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeDASHWidget::loadConfig() -{ - updateUIState(); - CartDebugWidget::loadConfig(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeDASHWidget::handleCommand(CommandSender* sender, - int cmd, int data, int id) -{ - uInt16 segment = 0; - switch(cmd) - { - case kBank0Changed: - segment = 0; - break; - case kBank1Changed: - segment = 1; - break; - case kBank2Changed: - segment = 2; - break; - case kBank3Changed: - segment = 3; - break; - default: - break; - } - - // Ignore bank if either number or type hasn't been selected - if(myBankNumber[segment]->getSelected() < 0 || - myBankType[segment]->getSelected() < 0) - return; - - uInt8 bank = (segment << myCart.BANK_BITS) | - (myBankNumber[segment]->getSelected() & myCart.BIT_BANK_MASK); - - myCart.unlockBank(); - - if(myBankType[segment]->getSelectedTag() == "ROM") - myCart.bankROM(bank); - else - myCart.bankRAM(bank); - - myCart.lockBank(); - invalidate(); - updateUIState(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeDASHWidget::bankState() -{ - ostringstream& buf = buffer(); - int lastROMBank = -1; - bool lastSlotRAM = false; - - for(int i = 0; i < 8; ++i) - { - uInt16 bank = myCart.bankInUse[i]; - - if(bank == myCart.BANK_UNDEFINED) // never accessed - { - buf << " U!"; - } - else - { - int bankno = bank & myCart.BIT_BANK_MASK; - - if(bank & myCart.BITMASK_ROMRAM) // was RAM mapped here? - { - // RAM will always need a '+' placed somewhere, since it always - // consists of 512B segments - bool inFirstSlot = (i % 2 == 0); - if(!(inFirstSlot || lastSlotRAM)) - { - lastSlotRAM = false; - buf << " +"; - } - - if(bank & myCart.BITMASK_LOWERUPPER) // upper is write port - buf << " RAM " << bankno << "W"; - else - buf << " RAM " << bankno << "R"; - - if(inFirstSlot) - { - buf << " +"; - lastSlotRAM = true; - } - } - else - { - // ROM can be contiguous, since 2 512B segments can form a single - // 1K bank; in this case we only show the info once - bool highBankSame = (i % 2 == 1) && (bankno == lastROMBank); - if(!highBankSame) - { - buf << " ROM " << bankno; - lastROMBank = bankno; - } - else - lastROMBank = -1; - - lastSlotRAM = false; - } - } - - if((i+1) % 2 == 0 && i < 7) - buf << " /"; - } - - return buf.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeDASHWidget::updateUIState() -{ - // Set contents for actual banks number and type - for(int i = 0; i < 4; ++i) - { - uInt16 segment = myCart.segmentInUse[i]; - - if(segment == myCart.BANK_UNDEFINED) - { - myBankNumber[i]->clearSelection(); - myBankType[i]->clearSelection(); - } - else - { - int bankno = segment & myCart.BIT_BANK_MASK; - const string& banktype = (segment & myCart.BITMASK_ROMRAM) ? "RAM" : "ROM"; - - myBankNumber[i]->setSelected(bankno); - myBankType[i]->setSelected(banktype); - } - } - - // Set description for each 512b bank state - for(int i = 0; i < 8; ++i) - { - uInt16 bank = myCart.bankInUse[i]; - - if(bank == myCart.BANK_UNDEFINED) // never accessed - { - myBankState[i]->setText("Undefined"); - } - else - { - ostringstream buf; - int bankno = bank & myCart.BIT_BANK_MASK; - - if(bank & myCart.BITMASK_ROMRAM) // was RAM mapped here? - { - if(bank & myCart.BITMASK_LOWERUPPER) // upper is write port - { - buf << "RAM " << bankno << " @ $" << Common::Base::HEX4 - << (bankno << myCart.RAM_BANK_TO_POWER) << " (W)"; - myBankState[i]->setText(buf.str()); - } - else - { - buf << "RAM " << bankno << " @ $" << Common::Base::HEX4 - << (bankno << myCart.RAM_BANK_TO_POWER) << " (R)"; - myBankState[i]->setText(buf.str()); - } - } - else - { - if(bank & myCart.BITMASK_LOWERUPPER) // upper is high 512b - { - buf << "ROM " << bankno << " @ $" << Common::Base::HEX4 - << ((bankno << myCart.RAM_BANK_TO_POWER) + myCart.RAM_BANK_SIZE); - myBankState[i]->setText(buf.str()); - } - else - { - buf << "ROM " << bankno << " @ $" << Common::Base::HEX4 - << (bankno << myCart.RAM_BANK_TO_POWER); - myBankState[i]->setText(buf.str()); - } - } - } - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 CartridgeDASHWidget::internalRamSize() -{ - return 32*1024; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 CartridgeDASHWidget::internalRamRPort(int start) -{ - return 0x0000 + start; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeDASHWidget::internalRamDescription() -{ - ostringstream desc; - desc << "Accessible 512b at a time via:\n" - << " $F000/$F200/$F400/etc used for Read Access\n" - << " $F800/$FA00/$FC00/etc used for Write Access (+$800)"; - - return desc.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& CartridgeDASHWidget::internalRamOld(int start, int count) -{ - myRamOld.clear(); - for(int i = 0; i < count; i++) - myRamOld.push_back(myOldState.internalram[start + i]); - return myRamOld; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& CartridgeDASHWidget::internalRamCurrent(int start, int count) -{ - myRamCurrent.clear(); - for(int i = 0; i < count; i++) - myRamCurrent.push_back(myCart.myRAM[start + i]); - return myRamCurrent; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeDASHWidget::internalRamSetValue(int addr, uInt8 value) -{ - myCart.myRAM[addr] = value; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeDASHWidget::internalRamGetValue(int addr) -{ - return myCart.myRAM[addr]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const std::array CartridgeDASHWidget::bankEnum = { - kBank0Changed, kBank1Changed, kBank2Changed, kBank3Changed -}; diff --git a/src/debugger/gui/CartDASHWidget.hxx b/src/debugger/gui/CartDASHWidget.hxx deleted file mode 100644 index e738c2292..000000000 --- a/src/debugger/gui/CartDASHWidget.hxx +++ /dev/null @@ -1,86 +0,0 @@ -//============================================================================ -// -// 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 CARTRIDGEDASH_WIDGET_HXX -#define CARTRIDGEDASH_WIDGET_HXX - -class CartridgeDASH; -class ButtonWidget; -class EditTextWidget; -class PopUpWidget; - -#include "CartDebugWidget.hxx" - -class CartridgeDASHWidget : public CartDebugWidget -{ - public: - CartridgeDASHWidget(GuiObject* boss, const GUI::Font& lfont, - const GUI::Font& nfont, - int x, int y, int w, int h, - CartridgeDASH& cart); - virtual ~CartridgeDASHWidget() = default; - - private: - void updateUIState(); - - private: - CartridgeDASH& myCart; - - std::array myBankNumber{nullptr}; - std::array myBankType{nullptr}; - std::array myBankCommit{nullptr}; - std::array myBankState{nullptr}; - - struct CartState { - ByteArray internalram; - }; - CartState myOldState; - - enum BankID { - kBank0Changed = 'b0CH', - kBank1Changed = 'b1CH', - kBank2Changed = 'b2CH', - kBank3Changed = 'b3CH' - }; - static const std::array bankEnum; - - private: - void saveOldState() override; - void loadConfig() override; - void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - - string bankState() override; - - // start of functions for Cartridge RAM tab - uInt32 internalRamSize() override; - uInt32 internalRamRPort(int start) override; - string internalRamDescription() override; - const ByteArray& internalRamOld(int start, int count) override; - const ByteArray& internalRamCurrent(int start, int count) override; - void internalRamSetValue(int addr, uInt8 value) override; - uInt8 internalRamGetValue(int addr) override; - // end of functions for Cartridge RAM tab - - // Following constructors and assignment operators not supported - CartridgeDASHWidget() = delete; - CartridgeDASHWidget(const CartridgeDASHWidget&) = delete; - CartridgeDASHWidget(CartridgeDASHWidget&&) = delete; - CartridgeDASHWidget& operator=(const CartridgeDASHWidget&) = delete; - CartridgeDASHWidget& operator=(CartridgeDASHWidget&&) = delete; -}; - -#endif diff --git a/src/debugger/gui/module.mk b/src/debugger/gui/module.mk index 522d31cf4..f4f94387f 100644 --- a/src/debugger/gui/module.mk +++ b/src/debugger/gui/module.mk @@ -23,7 +23,6 @@ MODULE_OBJS := \ src/debugger/gui/CartCMWidget.o \ src/debugger/gui/CartCTYWidget.o \ src/debugger/gui/CartCVWidget.o \ - src/debugger/gui/CartDASHWidget.o \ src/debugger/gui/CartDFSCWidget.o \ src/debugger/gui/CartDFWidget.o \ src/debugger/gui/CartDPCPlusWidget.o \ diff --git a/src/emucore/Bankswitch.cxx b/src/emucore/Bankswitch.cxx index 84d0dd037..7ce52db58 100644 --- a/src/emucore/Bankswitch.cxx +++ b/src/emucore/Bankswitch.cxx @@ -118,7 +118,6 @@ Bankswitch::BSList = {{ { "CM" , "CM (SpectraVideo CompuMate)" }, { "CTY" , "CTY (CDW - Chetiry)" }, { "CV" , "CV (Commavid extra RAM)" }, - { "DASH" , "DASH (Experimental)" }, { "DF" , "DF (CPUWIZ 128K)" }, { "DFSC" , "DFSC (CPUWIZ 128K + RAM)" }, { "DPC" , "DPC (Pitfall II)" }, @@ -196,8 +195,6 @@ Bankswitch::ExtensionMap Bankswitch::ourExtensions = { { "CM" , Bankswitch::Type::_CM }, { "CTY" , Bankswitch::Type::_CTY }, { "CV" , Bankswitch::Type::_CV }, - { "DAS" , Bankswitch::Type::_DASH }, - { "DASH" , Bankswitch::Type::_DASH }, { "DF" , Bankswitch::Type::_DF }, { "DFS" , Bankswitch::Type::_DFSC }, { "DFSC" , Bankswitch::Type::_DFSC }, @@ -260,7 +257,6 @@ Bankswitch::NameToTypeMap Bankswitch::ourNameToTypes = { { "CM" , Bankswitch::Type::_CM }, { "CTY" , Bankswitch::Type::_CTY }, { "CV" , Bankswitch::Type::_CV }, - { "DASH" , Bankswitch::Type::_DASH }, { "DF" , Bankswitch::Type::_DF }, { "DFSC" , Bankswitch::Type::_DFSC }, { "DPC" , Bankswitch::Type::_DPC }, diff --git a/src/emucore/Bankswitch.hxx b/src/emucore/Bankswitch.hxx index 4ed7cc445..9021a21ed 100644 --- a/src/emucore/Bankswitch.hxx +++ b/src/emucore/Bankswitch.hxx @@ -41,11 +41,11 @@ class Bankswitch _AUTO, _0840, _2IN1, _4IN1, _8IN1, _16IN1, _32IN1, _64IN1, _128IN1, _2K, _3E, _3EP, _3F, _4A50, _4K, _4KSC, _AR, _BF, _BFSC, _BUS, _CDF, - _CM, _CTY, _CV, _DASH, _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, + _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, #ifdef CUSTOM_ARM _CUSTOM, #endif diff --git a/src/emucore/CartDASH.cxx b/src/emucore/CartDASH.cxx deleted file mode 100644 index 6e187d76a..000000000 --- a/src/emucore/CartDASH.cxx +++ /dev/null @@ -1,355 +0,0 @@ -//============================================================================ -// -// 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 "TIA.hxx" -#include "CartDASH.hxx" - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -CartridgeDASH::CartridgeDASH(const ByteBuffer& image, size_t size, - const string& md5, const Settings& settings) - : Cartridge(settings, md5), - mySize(size) -{ - // Allocate array for the ROM image - myImage = make_unique(mySize); - - // Copy the ROM image into my buffer - std::copy_n(image.get(), mySize, myImage.get()); - createRomAccessArrays(mySize + myRAM.size()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeDASH::reset() -{ - initializeRAM(myRAM.data(), myRAM.size()); - - // Remember startup bank (0 per spec, rather than last per 3E scheme). - // Set this to go to 3rd 1K Bank. - initializeStartBank(0); - - // Initialise bank values for all ROM/RAM access - // This is used to reverse-lookup from address to bank location - for(uInt32 b = 0; b < 8; ++b) - { - bankInUse[b] = BANK_UNDEFINED; // bank is undefined and inaccessible! - segmentInUse[b/2] = BANK_UNDEFINED; - } - initializeBankState(); - - // We'll map the startup banks 0 and 3 from the image into the third 1K bank upon reset - bankROM((0 << BANK_BITS) | 0); - bankROM((3 << BANK_BITS) | 0); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeDASH::install(System& system) -{ - mySystem = &system; - - System::PageAccess access(this, System::PageAccessType::READWRITE); - - // The hotspots are in TIA address space, so we claim it here - for (uInt16 addr = 0x00; addr < 0x40; addr += System::PAGE_SIZE) - mySystem->setPageAccess(addr, access); - - // Initialise bank values for all ROM/RAM access - // This is used to reverse-lookup from address to bank location - for (uInt32 b = 0; b < 8; ++b) - { - bankInUse[b] = BANK_UNDEFINED; // bank is undefined and inaccessible! - segmentInUse[b/2] = BANK_UNDEFINED; - } - initializeBankState(); - - // Setup the last segment (of 4, each 1K) to point to the first ROM slice - // Actually we DO NOT want "always". It's just on bootup, and can be out switched later - bankROM((0 << BANK_BITS) | 0); - bankROM((3 << BANK_BITS) | 0); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeDASH::peek(uInt16 address) -{ - uInt16 peekAddress = address; - address &= 0x0FFF; // restrict to 4K address range - - uInt8 value = 0; - uInt32 bank = (address >> (ROM_BANK_TO_POWER - 1)) & 7; // convert to 512 byte bank index (0-7) - uInt16 imageBank = bankInUse[bank]; // the ROM/RAM bank that's here - - if(imageBank == BANK_UNDEFINED) // an uninitialised bank? - { - // accessing invalid bank, so return should be... random? - value = mySystem->randGenerator().next(); - - } - else if(imageBank & BITMASK_ROMRAM) // a RAM bank - { - Int32 ramBank = imageBank & BIT_BANK_MASK; // discard irrelevant bits - Int32 offset = ramBank << RAM_BANK_TO_POWER; // base bank address in RAM - offset += (address & BITMASK_RAM_BANK); // + byte offset in RAM bank - - return peekRAM(myRAM[offset], peekAddress); - } - - return value; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeDASH::poke(uInt16 address, uInt8 value) -{ - bool changed = false; - - // Check for write to the bank switch address. RAM/ROM and bank # are encoded in 'value' - // There are NO mirrored hotspots. - - if (address == BANK_SWITCH_HOTSPOT_RAM) - changed = bankRAM(value); - else if (address == BANK_SWITCH_HOTSPOT_ROM) - changed = bankROM(value); - - if(!(address & 0x1000)) - { - // Handle TIA space that we claimed above - changed = changed || mySystem->tia().poke(address, value); - } - else - { - uInt32 bankNumber = (address >> RAM_BANK_TO_POWER) & 7; // now 512 byte bank # (ie: 0-7) - Int16 whichBankIsThere = bankInUse[bankNumber]; // ROM or RAM bank reference - - if(whichBankIsThere & BITMASK_ROMRAM) - { - if(address & RAM_BANK_SIZE) - { - uInt32 byteOffset = address & BITMASK_RAM_BANK; - uInt32 baseAddress = ((whichBankIsThere & BIT_BANK_MASK) << RAM_BANK_TO_POWER) + byteOffset; - pokeRAM(myRAM[baseAddress], address, value); - changed = true; - } - else - { - // Writing to the read port should be ignored, but trigger a break if option enabled - uInt8 dummy; - - pokeRAM(dummy, address, value); - myRamWriteAccess = address; - changed = false; - } - } - } - - return changed; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeDASH::bankRAM(uInt8 bank) -{ - if (bankLocked()) // debugger can lock RAM - return false; - - // Each RAM bank uses two slots, separated by 0x800 in memory -- one read, one write. - bankRAMSlot(bank | BITMASK_ROMRAM | 0); - bankRAMSlot(bank | BITMASK_ROMRAM | BITMASK_LOWERUPPER); - - // Remember that this hotspot was accessed for RAM - segmentInUse[(bank >> BANK_BITS) & 3] = bank | BITMASK_ROMRAM; - - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeDASH::bankRAMSlot(uInt16 bank) -{ - uInt16 bankNumber = (bank >> BANK_BITS) & 3; // which bank # we are switching TO (BITS D6,D7) to 512 byte block - uInt16 currentBank = bank & BIT_BANK_MASK; // Wrap around/restrict to valid range - bool upper = bank & BITMASK_LOWERUPPER; // is this the read or write port - - uInt32 startCurrentBank = currentBank << RAM_BANK_TO_POWER; // Effectively * 512 bytes - - // Setup the page access methods for the current bank - System::PageAccess access(this, System::PageAccessType::READ); - - if(upper) // We're mapping the write port - { - bankInUse[bankNumber + 4] = Int16(bank); - access.type = System::PageAccessType::WRITE; - } - else // We're mapping the read port - { - bankInUse[bankNumber] = Int16(bank); - access.type = System::PageAccessType::READ; - } - - uInt16 start = 0x1000 + (bankNumber << RAM_BANK_TO_POWER) + (upper ? RAM_WRITE_OFFSET : 0); - uInt16 end = start + RAM_BANK_SIZE - 1; - - for (uInt16 addr = start; addr <= end; addr += System::PAGE_SIZE) - { - if(!upper) - access.directPeekBase = &myRAM[startCurrentBank + (addr & (RAM_BANK_SIZE - 1))]; - - access.romAccessBase = &myRomAccessBase[mySize + startCurrentBank + (addr & (RAM_BANK_SIZE - 1))]; - mySystem->setPageAccess(addr, access); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeDASH::bankROM(uInt8 bank) -{ - if (bankLocked()) // debugger can lock ROM - return false; - - // Map ROM bank image into the system into the correct slot - // Memory map is 1K slots at 0x1000, 0x1400, 0x1800, 0x1C00 - // Each ROM uses 2 consecutive 512 byte slots - bankROMSlot(bank | 0); - bankROMSlot(bank | BITMASK_LOWERUPPER); - - // Remember that this hotspot was accessed for ROM - segmentInUse[(bank >> BANK_BITS) & 3] = bank; - - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeDASH::bankROMSlot(uInt16 bank) -{ - uInt16 bankNumber = (bank >> BANK_BITS) & 3; // which bank # we are switching TO (BITS D6,D7) - uInt16 currentBank = bank & BIT_BANK_MASK; // Wrap around/restrict to valid range - bool upper = bank & BITMASK_LOWERUPPER; // is this the lower or upper 512b - - bankInUse[bankNumber * 2 + (upper ? 1 : 0)] = Int16(bank); // Record which bank switched in (as ROM) - - uInt32 startCurrentBank = currentBank << ROM_BANK_TO_POWER; // Effectively *1K - - // Setup the page access methods for the current bank - System::PageAccess access(this, System::PageAccessType::READ); - - uInt16 start = 0x1000 + (bankNumber << ROM_BANK_TO_POWER) + (upper ? ROM_BANK_SIZE / 2 : 0); - uInt16 end = start + ROM_BANK_SIZE / 2 - 1; - - for (uInt16 addr = start; addr <= end; addr += System::PAGE_SIZE) - { - access.directPeekBase = &myImage[startCurrentBank + (addr & (ROM_BANK_SIZE - 1))]; - access.romAccessBase = &myRomAccessBase[startCurrentBank + (addr & (ROM_BANK_SIZE - 1))]; - mySystem->setPageAccess(addr, access); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeDASH::initializeBankState() -{ - // Switch in each 512b slot - for(uInt32 b = 0; b < 8; ++b) - { - if(bankInUse[b] == BANK_UNDEFINED) - { - // All accesses point to peek/poke above - System::PageAccess access(this, System::PageAccessType::READ); - uInt16 start = 0x1000 + (b << RAM_BANK_TO_POWER); - uInt16 end = start + RAM_BANK_SIZE - 1; - for (uInt16 addr = start; addr <= end; addr += System::PAGE_SIZE) - mySystem->setPageAccess(addr, access); - } - else if (bankInUse[b] & BITMASK_ROMRAM) - bankRAMSlot(bankInUse[b]); - else - bankROMSlot(bankInUse[b]); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeDASH::patch(uInt16 address, uInt8 value) -{ -#if 0 - // Patch the cartridge ROM (for debugger) - - myBankChanged = true; - - uInt32 bankNumber = (address >> RAM_BANK_TO_POWER) & 7; // now 512 byte bank # (ie: 0-7) - Int16 whichBankIsThere = bankInUse[bankNumber]; // ROM or RAM bank reference - - if (whichBankIsThere == BANK_UNDEFINED) { - - // We're trying to access undefined memory (no bank here yet). Fail! - myBankChanged = false; - - } else if (whichBankIsThere & BITMASK_ROMRAM) { // patching RAM (512 byte banks) - - uInt32 byteOffset = address & BITMASK_RAM_BANK; - uInt32 baseAddress = ((whichBankIsThere & BIT_BANK_MASK) << RAM_BANK_TO_POWER) + byteOffset; - myRAM[baseAddress] = value; // write to RAM - - // TODO: Stephen -- should we set 'myBankChanged' true when there's a RAM write? - - } else { // patching ROM (1K banks) - - uInt32 byteOffset = address & BITMASK_ROM_BANK; - uInt32 baseAddress = (whichBankIsThere << ROM_BANK_TO_POWER) + byteOffset; - myImage[baseAddress] = value; // write to the image - } - - return myBankChanged; -#else - return false; -#endif -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeDASH::getImage(size_t& size) const -{ - size = mySize; - return myImage.get(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeDASH::save(Serializer& out) const -{ - try - { - out.putShortArray(bankInUse.data(), bankInUse.size()); - out.putShortArray(segmentInUse.data(), segmentInUse.size()); - out.putByteArray(myRAM.data(), myRAM.size()); - } - catch (...) - { - cerr << "ERROR: CartridgeDASH::save" << endl; - return false; - } - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeDASH::load(Serializer& in) -{ - try - { - in.getShortArray(bankInUse.data(), bankInUse.size()); - in.getShortArray(segmentInUse.data(), segmentInUse.size()); - in.getByteArray(myRAM.data(), myRAM.size()); - } - catch (...) - { - cerr << "ERROR: CartridgeDASH::load" << endl; - return false; - } - - initializeBankState(); - return true; -} diff --git a/src/emucore/CartDASH.hxx b/src/emucore/CartDASH.hxx deleted file mode 100644 index 8bd9fa523..000000000 --- a/src/emucore/CartDASH.hxx +++ /dev/null @@ -1,277 +0,0 @@ -//============================================================================ -// -// 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 CARTRIDGEDASH_HXX -#define CARTRIDGEDASH_HXX - -class System; - -#include "bspf.hxx" -#include "Cart.hxx" - -#ifdef DEBUGGER_SUPPORT -class CartridgeDASHWidget; - #include "CartDASHWidget.hxx" -#endif - -/** - Cartridge class for new tiling engine "Boulder Dash" format games with RAM. - Kind of a combination of 3F and 3E, with better switchability. - B.Watson's Cart3E was used as a template for building this implementation. - - The destination bank (0-3) is held in the top bits of the value written to - $3E (for RAM switching) or $3F (for ROM switching). The low 6 bits give - the actual bank number (0-63) corresponding to 512 byte blocks for RAM and - 1024 byte blocks for ROM. The maximum size is therefore 32K RAM and 64K ROM. - - D7D6 indicate the bank number (0-3) - D5D4D3D2D1D0 indicate the actual # (0-63) from the image/ram - - ROM: - - 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. - - In this scheme, the 4K address space is broken into four 1K ROM segments. - living at 0x1000, 0x1400, 0x1800, 0x1C00 (or, same thing, 0xF000... etc.), - and four 512 byte RAM segments, living at 0x1000, 0x1200, 0x1400, 0x1600 - with write-mirrors +0x800 of these. 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. - - 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. - - 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, - $FC00), and lower 6 bits indicate the 1K bank to switch in. Can handle 64 - x 1K ROM banks (64K total). - - D7 D6 D5D4D3D2D1D0 - 0 0 x x x x x x switch a 1K ROM bank xxxxx to $F000 - 0 1 switch a 1K ROM bank xxxxx to $F400 - 1 0 switch a 1K ROM bank xxxxx to $F800 - 1 1 switch a 1K ROM bank xxxxx to $FC00 - - RAM switching (write of segment+bank number to $3E) with D7D6 upper 2 bits of - bank # indicates the destination RAM segment (0-3, corresponding to $F000, - $F200, $F400, $F600). Note that this allows contiguous 2K of RAM to be - configured by setting 4 consecutive RAM segments each 512 bytes with - consecutive addresses. However, as the write address of RAM is +0x800, this - invalidates ROM access as described below. - - can handle 64 x 512 byte RAM banks (32K total) - - D7 D6 D5D4D3D2D1D0 - 0 0 x x x x x x switch a 512 byte RAM bank xxxxx to $F000 with write @ $F800 - 0 1 switch a 512 byte RAM bank xxxxx to $F200 with write @ $FA00 - 1 0 switch a 512 byte RAM bank xxxxx to $F400 with write @ $FC00 - 1 1 switch a 512 byte RAM bank xxxxx to $F600 with write @ $FE00 - - It is possible to switch multiple RAM banks and ROM banks together - - For example, - F000-F1FF RAM bank A (512 byte READ) - F200-F3FF high 512 bytes of ROM bank previously loaded at F000 - F400 ROM bank 0 (1K) - F800 RAM bank A (512 byte WRITE) - FA00-FBFF high 512 bytes of ROM bank previously loaded at F400 - FC00 ROM bank 1 - - This example shows 512 bytes of RAM, and 2 1K ROM banks and two 512 byte ROM - bank halves. - - Switching RAM blocks (D7D6 of $3E) partially invalidates ROM blocks, as below... - - RAM block Invalidates ROM block - 0 0 (lower half), 2 (lower half) - 1 0 (upper half), 2 (upper half) - 2 1 (lower half), 3 (upper half) - 3 1 (upper half), 3 (lower half) - - For example, RAM block 1 uses address $F200-$F3FF and $FA00-$FBFF - ROM block 0 uses address $F000-$F3FF, and ROM block 2 uses address $F800-$FBFF - Switching in RAM block 1 makes F200-F3FF ROM inaccessible, however F000-F1FF is - still readable. So, care must be paid. - - This crazy RAM layout is useful as it allows contiguous RAM to be switched in, - up to 2K in one sequentially accessible block. This means you CAN have 2K of - consecutive RAM (don't forget to copy your reset vectors!) - - @author Andrew Davie -*/ - -class CartridgeDASH: public Cartridge -{ - friend class CartridgeDASHWidget; - - public: - /** - 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) - */ - CartridgeDASH(const ByteBuffer& image, size_t size, const string& md5, - const Settings& settings); - virtual ~CartridgeDASH() = default; - - public: - /** Reset device to its power-on state */ - void reset() override; - - /** - Install cartridge in the specified system. Invoked by the system - when the cartridge is attached to it. - - @param system The system the device should install itself in - */ - void install(System& system) override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const 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 "CartridgeDASH"; } - - #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 CartridgeDASHWidget(boss, lfont, nfont, x, y, w, h, *this); - } - #endif - - public: - /** - Get the byte at the specified address - - @return The byte at the specified address - */ - uInt8 peek(uInt16 address) override; - - /** - Change the byte at the specified address to the given value - - @param address The address where the value should be stored - @param value The value to be stored at the address - @return True if the poke changed the device address space, else false - */ - bool poke(uInt16 address, uInt8 value) override; - - private: - bool bankRAM(uInt8 bank); // switch a RAM bank - bool bankROM(uInt8 bank); // switch a ROM bank - - void bankRAMSlot(uInt16 bank); // switch in a 512b RAM slot (lower or upper 1/2 bank) - void bankROMSlot(uInt16 bank); // switch in a 512b RAM slot (read or write port) - - void initializeBankState(); // set all banks according to current bankInUse state - - // We have an array that indicates for each of the 8 512 byte areas of the address space, which ROM/RAM - // bank is used in that area. ROM switches 1K so occupies 2 successive entries for each switch. RAM occupies - // two as well, one 512 byte for read and one for write. The RAM locations are +0x800 apart, and the ROM - // are consecutive. This allows us to determine on a read/write exactly where the data is. - - static constexpr uInt16 BANK_UNDEFINED = 0x8000; // bank is undefined and inaccessible - std::array bankInUse; // bank being used for ROM/RAM (eight 512 byte areas) - std::array segmentInUse; // set by bank methods, to know which hotspot was accessed - - static constexpr uInt16 BANK_SWITCH_HOTSPOT_RAM = 0x3E; // writes to this address cause bankswitching - static constexpr uInt16 BANK_SWITCH_HOTSPOT_ROM = 0x3F; // writes to this address cause bankswitching - - static constexpr uInt8 BANK_BITS = 6; // # bits for bank - static constexpr uInt8 BIT_BANK_MASK = (1 << BANK_BITS) - 1; // mask for those bits - static constexpr uInt16 BITMASK_LOWERUPPER = 0x100; // flags lower or upper section of bank (1==upper) - static constexpr uInt16 BITMASK_ROMRAM = 0x200; // flags ROM or RAM bank switching (1==RAM) - - static constexpr uInt16 MAXIMUM_BANK_COUNT = (1 << BANK_BITS); - static constexpr uInt16 RAM_BANK_TO_POWER = 9; // 2^n = 512 - static constexpr uInt16 RAM_BANK_SIZE = (1 << RAM_BANK_TO_POWER); - static constexpr uInt16 BITMASK_RAM_BANK = (RAM_BANK_SIZE - 1); - static constexpr uInt32 RAM_TOTAL_SIZE = MAXIMUM_BANK_COUNT * RAM_BANK_SIZE; - - static constexpr uInt16 ROM_BANK_TO_POWER = 10; // 2^n = 1024 - static constexpr uInt16 ROM_BANK_SIZE = (1 << ROM_BANK_TO_POWER); - static constexpr uInt16 BITMASK_ROM_BANK = (ROM_BANK_SIZE - 1); - - static constexpr uInt16 ROM_BANK_COUNT = 64; - - static constexpr uInt16 RAM_WRITE_OFFSET = 0x800; - - ByteBuffer myImage; // Pointer to a dynamically allocated ROM image of the cartridge - size_t mySize{0}; // Size of the ROM image - std::array myRAM; - - private: - // Following constructors and assignment operators not supported - CartridgeDASH() = delete; - CartridgeDASH(const CartridgeDASH&) = delete; - CartridgeDASH(CartridgeDASH&&) = delete; - CartridgeDASH& operator=(const CartridgeDASH&) = delete; - CartridgeDASH& operator=(CartridgeDASH&&) = delete; -}; - -#endif diff --git a/src/emucore/CartDetector.cxx b/src/emucore/CartDetector.cxx index 09e0def71..4d7a583eb 100644 --- a/src/emucore/CartDetector.cxx +++ b/src/emucore/CartDetector.cxx @@ -33,7 +33,6 @@ #include "CartCM.hxx" #include "CartCTY.hxx" #include "CartCV.hxx" -#include "CartDASH.hxx" #include "CartDF.hxx" #include "CartDFSC.hxx" #include "CartDPC.hxx" @@ -277,8 +276,6 @@ CartDetector::createFromImage(const ByteBuffer& image, size_t size, Bankswitch:: return make_unique(image, size, md5, settings); case Bankswitch::Type::_CV: return make_unique(image, size, md5, settings); - case Bankswitch::Type::_DASH: - return make_unique(image, size, md5, settings); case Bankswitch::Type::_DF: return make_unique(image, size, md5, settings); case Bankswitch::Type::_DFSC: @@ -522,9 +519,7 @@ Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t si } // Variable sized ROM formats are independent of image size and come last - if(isProbablyDASH(image, size)) - type = Bankswitch::Type::_DASH; - else if(isProbably3EPlus(image, size)) + if(isProbably3EPlus(image, size)) type = Bankswitch::Type::_3EP; else if(isProbablyMDM(image, size)) type = Bankswitch::Type::_MDM; @@ -750,14 +745,6 @@ bool CartDetector::isProbablyCV(const ByteBuffer& image, size_t size) return searchForBytes(image.get(), size, signature[1], 3, 1); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartDetector::isProbablyDASH(const ByteBuffer& image, size_t size) -{ - // DASH cart is identified key 'TJAD' in the ROM - uInt8 tjad[] = { 'T', 'J', 'A', 'D' }; - return searchForBytes(image.get(), size, tjad, 4, 1); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbablyDF(const ByteBuffer& image, size_t size, Bankswitch::Type& type) diff --git a/src/emucore/CartDetector.hxx b/src/emucore/CartDetector.hxx index 8f9d04ac9..63a98b053 100644 --- a/src/emucore/CartDetector.hxx +++ b/src/emucore/CartDetector.hxx @@ -175,11 +175,6 @@ class CartDetector */ static bool isProbablyCV(const ByteBuffer& image, size_t size); - /** - Returns true if the image is probably a DASH bankswitching cartridge - */ - static bool isProbablyDASH(const ByteBuffer& image, size_t size); - /** Returns true if the image is probably a DF/DFSC bankswitching cartridge */ diff --git a/src/emucore/module.mk b/src/emucore/module.mk index 4b72d3b22..9c81e28ec 100644 --- a/src/emucore/module.mk +++ b/src/emucore/module.mk @@ -21,7 +21,6 @@ MODULE_OBJS := \ src/emucore/CartCM.o \ src/emucore/CartCTY.o \ src/emucore/CartCV.o \ - src/emucore/CartDASH.o \ src/emucore/CartDPC.o \ src/emucore/CartDPCPlus.o \ src/emucore/CartE0.o \ diff --git a/src/windows/Stella.vcxproj b/src/windows/Stella.vcxproj index 46fd9a877..b081dde0d 100644 --- a/src/windows/Stella.vcxproj +++ b/src/windows/Stella.vcxproj @@ -588,9 +588,6 @@ true - - true - true @@ -721,7 +718,6 @@ - @@ -1595,9 +1591,6 @@ true - - true - true @@ -1740,7 +1733,6 @@ - diff --git a/src/windows/Stella.vcxproj.filters b/src/windows/Stella.vcxproj.filters index 8f9d893f8..f0c9b601d 100644 --- a/src/windows/Stella.vcxproj.filters +++ b/src/windows/Stella.vcxproj.filters @@ -723,9 +723,6 @@ Source Files\emucore - - Source Files\emucore - Source Files\debugger @@ -735,9 +732,6 @@ Source Files\debugger - - Source Files\debugger - Source Files\emucore @@ -1703,9 +1697,6 @@ Header Files\emucore - - Header Files\emucore - Header Files\debugger @@ -1715,9 +1706,6 @@ Header Files\debugger - - Header Files\debugger - Header Files\emucore From 13dfed21828b4f407492eddaa90b46e0733a4b13 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 16 Apr 2020 09:40:15 +0200 Subject: [PATCH 111/377] fix some Clang-Tidy warnings small bugfix for CartFA2 --- src/emucore/Cart3E.cxx | 2 +- src/emucore/Cart3EPlus.cxx | 2 +- src/emucore/CartBF.cxx | 2 +- src/emucore/CartDF.cxx | 2 +- src/emucore/CartEF.cxx | 2 +- src/emucore/CartEnhanced.cxx | 68 ++++++++++++++++++------------------ src/emucore/CartEnhanced.hxx | 10 ++++++ src/emucore/CartFA2.cxx | 6 ++-- src/emucore/CartFE.cxx | 2 +- src/emucore/CartSB.cxx | 3 +- 10 files changed, 54 insertions(+), 45 deletions(-) diff --git a/src/emucore/Cart3E.cxx b/src/emucore/Cart3E.cxx index 3e7454bda..642ac6ce1 100644 --- a/src/emucore/Cart3E.cxx +++ b/src/emucore/Cart3E.cxx @@ -64,7 +64,7 @@ bool Cartridge3E::checkSwitchBank(uInt16 address, uInt8 value) uInt8 Cartridge3E::peek(uInt16 address) { uInt16 peekAddress = address; - address &= 0x0FFF; + address &= ROM_MASK; if(address < 0x0040) // TIA access return mySystem->tia().peek(address); diff --git a/src/emucore/Cart3EPlus.cxx b/src/emucore/Cart3EPlus.cxx index f6ac01679..274e1f9db 100644 --- a/src/emucore/Cart3EPlus.cxx +++ b/src/emucore/Cart3EPlus.cxx @@ -103,7 +103,7 @@ bool Cartridge3EPlus::checkSwitchBank(uInt16 address, uInt8 value) uInt8 Cartridge3EPlus::peek(uInt16 address) { uInt16 peekAddress = address; - address &= 0x0FFF; + address &= ROM_MASK; if(address < 0x0040) // TIA peek return mySystem->tia().peek(address); diff --git a/src/emucore/CartBF.cxx b/src/emucore/CartBF.cxx index 0d1921c17..ce3c53198 100644 --- a/src/emucore/CartBF.cxx +++ b/src/emucore/CartBF.cxx @@ -30,7 +30,7 @@ bool CartridgeBF::checkSwitchBank(uInt16 address, uInt8) { // Due to the way addressing is set up, we will only get here if the // address is in the hotspot range ($1F80 - $1FFF) - address &= 0x0FFF; + address &= ROM_MASK; // Switch banks if necessary if((address >= 0x0F80) && (address <= 0x0FBF)) diff --git a/src/emucore/CartDF.cxx b/src/emucore/CartDF.cxx index db9ab62d2..0f4d9a1ca 100644 --- a/src/emucore/CartDF.cxx +++ b/src/emucore/CartDF.cxx @@ -28,7 +28,7 @@ CartridgeDF::CartridgeDF(const ByteBuffer& image, size_t size, // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDF::checkSwitchBank(uInt16 address, uInt8) { - address &= 0x0FFF; + address &= ROM_MASK; // Switch banks if necessary if((address >= 0x0FC0) && (address <= 0x0FDF)) diff --git a/src/emucore/CartEF.cxx b/src/emucore/CartEF.cxx index 70cd8236b..039f4aa5c 100644 --- a/src/emucore/CartEF.cxx +++ b/src/emucore/CartEF.cxx @@ -28,7 +28,7 @@ CartridgeEF::CartridgeEF(const ByteBuffer& image, size_t size, // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeEF::checkSwitchBank(uInt16 address, uInt8) { - address &= 0x0FFF; + address &= ROM_MASK; // Switch banks if necessary if((address >= 0x0FE0) && (address <= 0x0FEF)) diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index 01cf5cbcb..5816181f2 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -35,18 +35,18 @@ CartridgeEnhanced::CartridgeEnhanced(const ByteBuffer& image, size_t size, void CartridgeEnhanced::install(System& system) { // limit banked RAM size to the size of one RAM bank - uInt16 ramSize = myRamBankCount ? 1 << (myBankShift - 1) : myRamSize; + uInt16 ramSize = myRamBankCount > 0 ? 1 << (myBankShift - 1) : myRamSize; // calculate bank switching and RAM sizes and masks - myBankSize = 1 << myBankShift; // e.g. = 2 ^ 12 = 4K = 0x1000 - myBankMask = myBankSize - 1; // e.g. = 0x0FFF - myBankSegs = 1 << (12 - myBankShift); // e.g. = 1 - myRomOffset = myRamBankCount ? 0 : myRamSize * 2; - myRamMask = ramSize - 1; // e.g. = 0xFFFF (doesn't matter for RAM size 0) - myWriteOffset = myRamWpHigh ? ramSize : 0; - myReadOffset = myRamWpHigh ? 0 : ramSize; + myBankSize = 1 << myBankShift; // e.g. = 2 ^ 12 = 4K = 0x1000 + myBankMask = myBankSize - 1; // e.g. = 0x0FFF + myBankSegs = 1 << (MAX_BANK_SHIFT - myBankShift); // e.g. = 1 + myRomOffset = myRamBankCount > 0 ? 0 : 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 - createRomAccessArrays(mySize + (myRomOffset ? 0 : myRamSize)); + createRomAccessArrays(mySize + (myRomOffset > 0 ? 0 : myRamSize)); // Allocate array for the current bank segments slices myCurrentSegOffset = make_unique(myBankSegs); @@ -56,7 +56,7 @@ void CartridgeEnhanced::install(System& system) mySystem = &system; - if(myRomOffset) + if(myRomOffset > 0) { // Setup page access for extended RAM; banked RAM will be setup in bank() System::PageAccess access(this, System::PageAccessType::READ); @@ -65,7 +65,7 @@ void CartridgeEnhanced::install(System& system) // Map access to this class, since we need to inspect all accesses to // check if RWP happens access.type = System::PageAccessType::WRITE; - for(uInt16 addr = 0x1000 + myWriteOffset; addr < 0x1000 + myWriteOffset + myRamSize; addr += System::PAGE_SIZE) + for(uInt16 addr = ROM_OFFSET + myWriteOffset; addr < ROM_OFFSET + myWriteOffset + myRamSize; addr += System::PAGE_SIZE) { uInt16 offset = addr & myRamMask; access.romAccessBase = &myRomAccessBase[myWriteOffset + offset]; @@ -76,7 +76,7 @@ void CartridgeEnhanced::install(System& system) // Set the page accessing method for the RAM reading pages access.type = System::PageAccessType::READ; - for(uInt16 addr = 0x1000 + myReadOffset; addr < 0x1000 + myReadOffset + myRamSize; addr += System::PAGE_SIZE) + for(uInt16 addr = ROM_OFFSET + myReadOffset; addr < ROM_OFFSET + myReadOffset + myRamSize; addr += System::PAGE_SIZE) { uInt16 offset = addr & myRamMask; access.directPeekBase = &myRAM[offset]; @@ -110,8 +110,8 @@ uInt8 CartridgeEnhanced::peek(uInt16 address) { uInt16 peekAddress = address; - if (hotspot()) - checkSwitchBank(address & 0x0FFF); + if (hotspot() != 0) + checkSwitchBank(address & ROM_MASK); if(isRamBank(address)) { @@ -120,7 +120,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 & 0xFFF) >> myBankShift] - mySize) >> 1) + address], + return peekRAM(myRAM[((myCurrentSegOffset[(peekAddress & ROM_MASK) >> myBankShift] - mySize) >> 1) + address], peekAddress); } else @@ -133,7 +133,7 @@ uInt8 CartridgeEnhanced::peek(uInt16 address) // Reading from the write port triggers an unwanted write return peekRAM(myRAM[address], peekAddress); else - return myImage[myCurrentSegOffset[(peekAddress & 0xFFF) >> myBankShift] + address]; + return myImage[myCurrentSegOffset[(peekAddress & ROM_MASK) >> myBankShift] + address]; } } @@ -144,10 +144,10 @@ bool CartridgeEnhanced::poke(uInt16 address, uInt8 value) // Note: (TODO?) // The checkSwitchBank() call makes no difference between ROM and e.g TIA space // Writing to e.g. 0xf0xx might triger a bankswitch, is (and was!) this a bug??? - if (checkSwitchBank(address & 0x0FFF, value)) + if (checkSwitchBank(address & ROM_MASK, value)) return false; - if(myRamSize) + if(myRamSize > 0) { uInt16 pokeAddress = address; @@ -157,7 +157,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 & 0xFFF) >> myBankShift] - mySize) >> 1) + address], + pokeRAM(myRAM[((myCurrentSegOffset[(pokeAddress & ROM_MASK) >> myBankShift] - mySize) >> 1) + address], pokeAddress, value); return true; } @@ -198,7 +198,7 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) uInt16 segmentOffset = segment << myBankShift; - if(!myRamBankCount || bank < romBankCount()) + if(myRamBankCount == 0 || bank < romBankCount()) { // Setup ROM bank uInt16 romBank = bank % romBankCount(); @@ -206,11 +206,11 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) uInt32 bankOffset = myCurrentSegOffset[segment] = romBank << myBankShift; uInt16 hotspot = this->hotspot(); uInt16 hotSpotAddr; - uInt16 fromAddr = (0x1000 + segmentOffset + myRomOffset) & ~System::PAGE_MASK; + uInt16 fromAddr = (ROM_OFFSET + segmentOffset + myRomOffset) & ~System::PAGE_MASK; // for ROMs < 4_KB, the whole address space will be mapped. - uInt16 toAddr = (0x1000 + segmentOffset + (mySize < 4_KB ? 0x1000 : myBankSize)) & ~System::PAGE_MASK; + uInt16 toAddr = (ROM_OFFSET + segmentOffset + (mySize < 4_KB ? 4_KB : myBankSize)) & ~System::PAGE_MASK; - if(hotspot) + if(hotspot != 0) hotSpotAddr = (hotspot & ~System::PAGE_MASK); else hotSpotAddr = 0xFFFF; // none @@ -242,8 +242,8 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) myCurrentSegOffset[segment] = bank << myBankShift; // Set the page accessing method for the RAM writing pages - uInt16 fromAddr = (0x1000 + segmentOffset + myWriteOffset) & ~System::PAGE_MASK; - uInt16 toAddr = (0x1000 + segmentOffset + myWriteOffset + (myBankSize >> 1)) & ~System::PAGE_MASK; + uInt16 fromAddr = (ROM_OFFSET + segmentOffset + myWriteOffset) & ~System::PAGE_MASK; + uInt16 toAddr = (ROM_OFFSET + segmentOffset + myWriteOffset + (myBankSize >> 1)) & ~System::PAGE_MASK; System::PageAccess access(this, System::PageAccessType::WRITE); for(uInt16 addr = fromAddr; addr < toAddr; addr += System::PAGE_SIZE) @@ -257,8 +257,8 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) } // Set the page accessing method for the RAM reading pages - fromAddr = (0x1000 + segmentOffset + myReadOffset) & ~System::PAGE_MASK; - toAddr = (0x1000 + segmentOffset + myReadOffset + (myBankSize >> 1)) & ~System::PAGE_MASK; + fromAddr = (ROM_OFFSET + segmentOffset + myReadOffset) & ~System::PAGE_MASK; + toAddr = (ROM_OFFSET + segmentOffset + myReadOffset + (myBankSize >> 1)) & ~System::PAGE_MASK; access.type = System::PageAccessType::READ; for(uInt16 addr = fromAddr; addr < toAddr; addr += System::PAGE_SIZE) @@ -270,7 +270,7 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) access.romPeekCounter = &myRomAccessCounter[offset]; access.romPokeCounter = &myRomAccessCounter[offset + myAccessSize]; mySystem->setPageAccess(addr, access); - } + } } return myBankChanged = true; } @@ -278,7 +278,7 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeEnhanced::getBank(uInt16 address) const { - return myCurrentSegOffset[(address & 0xFFF) >> myBankShift] >> myBankShift; + return myCurrentSegOffset[(address & ROM_MASK) >> myBankShift] >> myBankShift; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -302,7 +302,7 @@ uInt16 CartridgeEnhanced::ramBankCount() const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeEnhanced::isRamBank(uInt16 address) const { - return myRamBankCount ? getBank(address) >= romBankCount() : false; + return myRamBankCount > 0 ? getBank(address) >= romBankCount() : false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -310,7 +310,7 @@ bool CartridgeEnhanced::patch(uInt16 address, uInt8 value) { if(isRamBank(address)) { - myRAM[((myCurrentSegOffset[(address & 0xFFF) >> myBankShift] - mySize) >> 1) + (address & myRamMask)] = value; + myRAM[((myCurrentSegOffset[(address & ROM_MASK) >> myBankShift] - mySize) >> 1) + (address & myRamMask)] = value; } else { @@ -322,7 +322,7 @@ bool CartridgeEnhanced::patch(uInt16 address, uInt8 value) myRAM[address & myRamMask] = value; } else - myImage[myCurrentSegOffset[(address & 0xFFF) >> myBankShift] + (address & myBankMask)] = value; + myImage[myCurrentSegOffset[(address & ROM_MASK) >> myBankShift] + (address & myBankMask)] = value; } return myBankChanged = true; @@ -341,7 +341,7 @@ bool CartridgeEnhanced::save(Serializer& out) const try { out.putIntArray(myCurrentSegOffset.get(), myBankSegs); - if(myRamSize) + if(myRamSize > 0) out.putByteArray(myRAM.get(), myRamSize); } catch(...) @@ -359,7 +359,7 @@ bool CartridgeEnhanced::load(Serializer& in) try { in.getIntArray(myCurrentSegOffset.get(), myBankSegs); - if(myRamSize) + if(myRamSize > 0) in.getByteArray(myRAM.get(), myRamSize); } catch(...) diff --git a/src/emucore/CartEnhanced.hxx b/src/emucore/CartEnhanced.hxx index 3b68101cc..e66aeb9f5 100644 --- a/src/emucore/CartEnhanced.hxx +++ b/src/emucore/CartEnhanced.hxx @@ -218,6 +218,13 @@ class CartridgeEnhanced : public Cartridge // The size of the ROM image size_t mySize{0}; + protected: + // The offset into address space for accessing ROM + static constexpr uInt16 ROM_OFFSET = 0x1000; + + // The mask for ROM address space + static constexpr uInt16 ROM_MASK = 0x0FFF; + private: // Calculated as: log(ROM bank segment size) / log(2) static constexpr uInt16 BANK_SHIFT = 12; // default = 4K @@ -231,6 +238,9 @@ class CartridgeEnhanced : public Cartridge // Write port for extra RAM is at low address by default static constexpr bool RAM_HIGH_WP = false; + // The maximum shift (for a 4K bank size) + static constexpr uInt16 MAX_BANK_SHIFT = 12; ; // -> 4K + protected: /** Check hotspots and switch bank if triggered. diff --git a/src/emucore/CartFA2.cxx b/src/emucore/CartFA2.cxx index 1e4251988..6662e8171 100644 --- a/src/emucore/CartFA2.cxx +++ b/src/emucore/CartFA2.cxx @@ -35,7 +35,7 @@ CartridgeFA2::CartridgeFA2(const ByteBuffer& image, size_t size, myImage = make_unique(mySize); // Copy the ROM image into my buffer - std::copy_n(image.get(), mySize, myImage.get()); + std::copy_n(img_ptr, mySize, myImage.get()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -53,7 +53,7 @@ bool CartridgeFA2::checkSwitchBank(uInt16 address, uInt8) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeFA2::peek(uInt16 address) { - if((address & 0x0FFF) == 0x0FF4) + if((address & ROM_MASK) == 0x0FF4) { // Load/save RAM to/from Harmony cart flash if(mySize == 28_KB && !bankLocked()) @@ -66,7 +66,7 @@ uInt8 CartridgeFA2::peek(uInt16 address) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeFA2::poke(uInt16 address, uInt8 value) { - if((address & 0x0FFF) == 0x0FF4) + if((address & ROM_MASK) == 0x0FF4) { // Load/save RAM to/from Harmony cart flash if(mySize == 28_KB && !bankLocked()) diff --git a/src/emucore/CartFE.cxx b/src/emucore/CartFE.cxx index 3a07730e0..7c3debda3 100644 --- a/src/emucore/CartFE.cxx +++ b/src/emucore/CartFE.cxx @@ -63,7 +63,7 @@ bool CartridgeFE::checkSwitchBank(uInt16 address, uInt8 value) uInt8 CartridgeFE::peek(uInt16 address) { uInt8 value = (address < 0x200) ? mySystem->m6532().peek(address) : - myImage[myCurrentSegOffset[(address & 0xFFF) >> myBankShift] + (address & myBankMask)]; + myImage[myCurrentSegOffset[(address & myBankMask) >> myBankShift] + (address & myBankMask)]; // Check if we hit hotspot checkSwitchBank(address, value); diff --git a/src/emucore/CartSB.cxx b/src/emucore/CartSB.cxx index 56973392c..5caa01be7 100644 --- a/src/emucore/CartSB.cxx +++ b/src/emucore/CartSB.cxx @@ -54,13 +54,12 @@ bool CartridgeSB::checkSwitchBank(uInt16 address, uInt8) // Switch banks if necessary if((address & 0x1800) == 0x0800) { - bank(address & startBank()); + bank(address & (romBankCount() - 1)); return true; } return false; } - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeSB::peek(uInt16 address) { From ace948e6edeb10c7266972be57f1fd0978ad6171 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Thu, 16 Apr 2020 10:33:37 -0230 Subject: [PATCH 112/377] Fix compile error for UNIX builds. --- src/debugger/gui/module.mk | 2 +- src/emucore/CartEnhanced.hxx | 2 +- src/emucore/module.mk | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/debugger/gui/module.mk b/src/debugger/gui/module.mk index f4f94387f..d1ffc81c0 100644 --- a/src/debugger/gui/module.mk +++ b/src/debugger/gui/module.mk @@ -21,7 +21,7 @@ MODULE_OBJS := \ src/debugger/gui/CartCDFWidget.o \ src/debugger/gui/CartCDFInfoWidget.o \ src/debugger/gui/CartCMWidget.o \ - src/debugger/gui/CartCTYWidget.o \ + src/debugger/gui/CartCTYWidget.o \ src/debugger/gui/CartCVWidget.o \ src/debugger/gui/CartDFSCWidget.o \ src/debugger/gui/CartDFWidget.o \ diff --git a/src/emucore/CartEnhanced.hxx b/src/emucore/CartEnhanced.hxx index e66aeb9f5..a45e4796e 100644 --- a/src/emucore/CartEnhanced.hxx +++ b/src/emucore/CartEnhanced.hxx @@ -239,7 +239,7 @@ class CartridgeEnhanced : public Cartridge static constexpr bool RAM_HIGH_WP = false; // The maximum shift (for a 4K bank size) - static constexpr uInt16 MAX_BANK_SHIFT = 12; ; // -> 4K + static constexpr uInt16 MAX_BANK_SHIFT = 12; // -> 4K protected: /** diff --git a/src/emucore/module.mk b/src/emucore/module.mk index 9c81e28ec..dc953b86e 100644 --- a/src/emucore/module.mk +++ b/src/emucore/module.mk @@ -20,7 +20,7 @@ MODULE_OBJS := \ src/emucore/CartCDF.o \ src/emucore/CartCM.o \ src/emucore/CartCTY.o \ - src/emucore/CartCV.o \ + src/emucore/CartCV.o \ src/emucore/CartDPC.o \ src/emucore/CartDPCPlus.o \ src/emucore/CartE0.o \ From bb05a04c3cfe55518ae9f9bce903317a812c083a Mon Sep 17 00:00:00 2001 From: Thomas Jentzsch Date: Thu, 16 Apr 2020 18:54:29 +0200 Subject: [PATCH 113/377] small naming alignment between CartBUS and CartCDF --- src/debugger/gui/CartBUSWidget.cxx | 8 ++-- src/debugger/gui/CartCDFWidget.cxx | 8 ++-- src/emucore/CartBUS.cxx | 72 +++++++++++++++--------------- src/emucore/CartBUS.hxx | 4 +- src/emucore/CartCDF.cxx | 56 +++++++++++------------ src/emucore/CartCDF.hxx | 4 +- 6 files changed, 76 insertions(+), 76 deletions(-) diff --git a/src/debugger/gui/CartBUSWidget.cxx b/src/debugger/gui/CartBUSWidget.cxx index b9c25a77d..8f6a9b22b 100644 --- a/src/debugger/gui/CartBUSWidget.cxx +++ b/src/debugger/gui/CartBUSWidget.cxx @@ -238,7 +238,7 @@ void CartridgeBUSWidget::saveOldState() } for(uInt32 i = 0; i < internalRamSize(); ++i) - myOldState.internalram.push_back(myCart.myBUSRAM[i]); + myOldState.internalram.push_back(myCart.myRAM[i]); myOldState.samplepointer.push_back(myCart.getSample()); } @@ -438,18 +438,18 @@ const ByteArray& CartridgeBUSWidget::internalRamCurrent(int start, int count) { myRamCurrent.clear(); for(int i = 0; i < count; i++) - myRamCurrent.push_back(myCart.myBUSRAM[start + i]); + myRamCurrent.push_back(myCart.myRAM[start + i]); return myRamCurrent; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBUSWidget::internalRamSetValue(int addr, uInt8 value) { - myCart.myBUSRAM[addr] = value; + myCart.myRAM[addr] = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeBUSWidget::internalRamGetValue(int addr) { - return myCart.myBUSRAM[addr]; + return myCart.myRAM[addr]; } diff --git a/src/debugger/gui/CartCDFWidget.cxx b/src/debugger/gui/CartCDFWidget.cxx index 60b68d5c4..8c4fdf2fc 100644 --- a/src/debugger/gui/CartCDFWidget.cxx +++ b/src/debugger/gui/CartCDFWidget.cxx @@ -232,7 +232,7 @@ void CartridgeCDFWidget::saveOldState() } for(uInt32 i = 0; i < internalRamSize(); ++i) - myOldState.internalram.push_back(myCart.myCDFRAM[i]); + myOldState.internalram.push_back(myCart.myRAM[i]); myOldState.samplepointer.push_back(myCart.getSample()); } @@ -437,20 +437,20 @@ const ByteArray& CartridgeCDFWidget::internalRamCurrent(int start, int count) { myRamCurrent.clear(); for(int i = 0; i < count; i++) - myRamCurrent.push_back(myCart.myCDFRAM[start + i]); + myRamCurrent.push_back(myCart.myRAM[start + i]); return myRamCurrent; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCDFWidget::internalRamSetValue(int addr, uInt8 value) { - myCart.myCDFRAM[addr] = value; + myCart.myRAM[addr] = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeCDFWidget::internalRamGetValue(int addr) { - return myCart.myCDFRAM[addr]; + return myCart.myRAM[addr]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartBUS.cxx b/src/emucore/CartBUS.cxx index bd6d227c2..e2eb9b74a 100644 --- a/src/emucore/CartBUS.cxx +++ b/src/emucore/CartBUS.cxx @@ -56,16 +56,16 @@ CartridgeBUS::CartridgeBUS(const ByteBuffer& image, size_t size, myProgramImage = myImage.data() + 4_KB; // Pointer to BUS driver in RAM - myBusDriverImage = myBUSRAM.data(); + myDriverImage = myRAM.data(); // Pointer to the display RAM - myDisplayImage = myBUSRAM.data() + DSRAM; + myDisplayImage = myRAM.data() + DSRAM; // Create Thumbulator ARM emulator bool devSettings = settings.getBool("dev.settings"); myThumbEmulator = make_unique( reinterpret_cast(myImage.data()), - reinterpret_cast(myBUSRAM.data()), + reinterpret_cast(myRAM.data()), static_cast(myImage.size()), devSettings ? settings.getBool("dev.thumb.trapfatal") : false, Thumbulator::ConfigureFor::BUS, this ); @@ -76,7 +76,7 @@ CartridgeBUS::CartridgeBUS(const ByteBuffer& image, size_t size, // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBUS::reset() { - initializeRAM(myBUSRAM.data() + 2_KB, 6_KB); + initializeRAM(myRAM.data() + 2_KB, 6_KB); // BUS always starts in bank 6 initializeStartBank(6); @@ -95,7 +95,7 @@ void CartridgeBUS::reset() void CartridgeBUS::setInitialState() { // Copy initial BUS driver to Harmony RAM - std::copy_n(myImage.begin(), 2_KB, myBusDriverImage); + std::copy_n(myImage.begin(), 2_KB, myDriverImage); myMusicWaveformSize.fill(27); @@ -254,7 +254,7 @@ uInt8 CartridgeBUS::peek(uInt16 address) if (sampleaddress < 0x8000) peekvalue = myImage[sampleaddress]; else if (sampleaddress >= 0x40000000 && sampleaddress < 0x40002000) // check for RAM - peekvalue = myBUSRAM[sampleaddress - 0x40000000]; + peekvalue = myRAM[sampleaddress - 0x40000000]; else peekvalue = 0; @@ -552,7 +552,7 @@ bool CartridgeBUS::save(Serializer& out) const out.putShort(myBankOffset); // Harmony RAM - out.putByteArray(myBUSRAM.data(), myBUSRAM.size()); + out.putByteArray(myRAM.data(), myRAM.size()); // Addresses for bus override logic out.putShort(myBusOverdriveAddress); @@ -593,7 +593,7 @@ bool CartridgeBUS::load(Serializer& in) myBankOffset = in.getShort(); // Harmony RAM - in.getByteArray(myBUSRAM.data(), myBUSRAM.size()); + in.getByteArray(myRAM.data(), myRAM.size()); // Addresses for bus override logic myBusOverdriveAddress = in.getShort(); @@ -633,40 +633,40 @@ uInt32 CartridgeBUS::getDatastreamPointer(uInt8 index) const { // index &= 0x0f; - return myBUSRAM[DSxPTR + index*4 + 0] + // low byte - (myBUSRAM[DSxPTR + index*4 + 1] << 8) + - (myBUSRAM[DSxPTR + index*4 + 2] << 16) + - (myBUSRAM[DSxPTR + index*4 + 3] << 24) ; // high byte + return myRAM[DSxPTR + index*4 + 0] + // low byte + (myRAM[DSxPTR + index*4 + 1] << 8) + + (myRAM[DSxPTR + index*4 + 2] << 16) + + (myRAM[DSxPTR + index*4 + 3] << 24) ; // high byte } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBUS::setDatastreamPointer(uInt8 index, uInt32 value) { // index &= 0x0f; - myBUSRAM[DSxPTR + index*4 + 0] = value & 0xff; // low byte - myBUSRAM[DSxPTR + index*4 + 1] = (value >> 8) & 0xff; - myBUSRAM[DSxPTR + index*4 + 2] = (value >> 16) & 0xff; - myBUSRAM[DSxPTR + index*4 + 3] = (value >> 24) & 0xff; // high byte + myRAM[DSxPTR + index*4 + 0] = value & 0xff; // low byte + myRAM[DSxPTR + index*4 + 1] = (value >> 8) & 0xff; + myRAM[DSxPTR + index*4 + 2] = (value >> 16) & 0xff; + myRAM[DSxPTR + index*4 + 3] = (value >> 24) & 0xff; // high byte } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeBUS::getDatastreamIncrement(uInt8 index) const { // index &= 0x0f; - return myBUSRAM[DSxINC + index*4 + 0] + // low byte - (myBUSRAM[DSxINC + index*4 + 1] << 8) + - (myBUSRAM[DSxINC + index*4 + 2] << 16) + - (myBUSRAM[DSxINC + index*4 + 3] << 24) ; // high byte + return myRAM[DSxINC + index*4 + 0] + // low byte + (myRAM[DSxINC + index*4 + 1] << 8) + + (myRAM[DSxINC + index*4 + 2] << 16) + + (myRAM[DSxINC + index*4 + 3] << 24) ; // high byte } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeBUS::getAddressMap(uInt8 index) const { // index &= 0x0f; - return myBUSRAM[DSMAPS + index*4 + 0] + // low byte - (myBUSRAM[DSMAPS + index*4 + 1] << 8) + - (myBUSRAM[DSMAPS + index*4 + 2] << 16) + - (myBUSRAM[DSMAPS + index*4 + 3] << 24) ; // high byte + return myRAM[DSMAPS + index*4 + 0] + // low byte + (myRAM[DSMAPS + index*4 + 1] << 8) + + (myRAM[DSMAPS + index*4 + 2] << 16) + + (myRAM[DSMAPS + index*4 + 3] << 24) ; // high byte } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -686,10 +686,10 @@ uInt32 CartridgeBUS::getWaveform(uInt8 index) const uInt32 result; - result = myBUSRAM[WAVEFORM + index*4 + 0] + // low byte - (myBUSRAM[WAVEFORM + index*4 + 1] << 8) + - (myBUSRAM[WAVEFORM + index*4 + 2] << 16) + - (myBUSRAM[WAVEFORM + index*4 + 3] << 24); // high byte + result = myRAM[WAVEFORM + index*4 + 0] + // low byte + (myRAM[WAVEFORM + index*4 + 1] << 8) + + (myRAM[WAVEFORM + index*4 + 2] << 16) + + (myRAM[WAVEFORM + index*4 + 3] << 24); // high byte result -= 0x40000800; @@ -704,10 +704,10 @@ uInt32 CartridgeBUS::getSample() { uInt32 result; - result = myBUSRAM[WAVEFORM + 0] + // low byte - (myBUSRAM[WAVEFORM + 1] << 8) + - (myBUSRAM[WAVEFORM + 2] << 16) + - (myBUSRAM[WAVEFORM + 3] << 24); // high byte + result = myRAM[WAVEFORM + 0] + // low byte + (myRAM[WAVEFORM + 1] << 8) + + (myRAM[WAVEFORM + 2] << 16) + + (myRAM[WAVEFORM + 3] << 24); // high byte return result; } @@ -722,10 +722,10 @@ uInt32 CartridgeBUS::getWaveformSize(uInt8 index) const void CartridgeBUS::setAddressMap(uInt8 index, uInt32 value) { // index &= 0x0f; - myBUSRAM[DSMAPS + index*4 + 0] = value & 0xff; // low byte - myBUSRAM[DSMAPS + index*4 + 1] = (value >> 8) & 0xff; - myBUSRAM[DSMAPS + index*4 + 2] = (value >> 16) & 0xff; - myBUSRAM[DSMAPS + index*4 + 3] = (value >> 24) & 0xff; // high byte + myRAM[DSMAPS + index*4 + 0] = value & 0xff; // low byte + myRAM[DSMAPS + index*4 + 1] = (value >> 8) & 0xff; + myRAM[DSMAPS + index*4 + 2] = (value >> 16) & 0xff; + myRAM[DSMAPS + index*4 + 3] = (value >> 24) & 0xff; // high byte } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartBUS.hxx b/src/emucore/CartBUS.hxx index 5567f1196..3ab40f7ec 100644 --- a/src/emucore/CartBUS.hxx +++ b/src/emucore/CartBUS.hxx @@ -220,13 +220,13 @@ class CartridgeBUS : public Cartridge uInt8* myDisplayImage{nullptr}; // Pointer to the 2K BUS driver image in RAM - uInt8* myBusDriverImage{nullptr}; + uInt8* myDriverImage{nullptr}; // The BUS 8k RAM image, used as: // $0000 - 2K BUS driver // $0800 - 4K Display Data // $1800 - 2K C Variable & Stack - std::array myBUSRAM; + std::array myRAM; // Pointer to the Thumb ARM emulator object unique_ptr myThumbEmulator; diff --git a/src/emucore/CartCDF.cxx b/src/emucore/CartCDF.cxx index 2758a9825..6f9a5f4f7 100644 --- a/src/emucore/CartCDF.cxx +++ b/src/emucore/CartCDF.cxx @@ -72,10 +72,10 @@ CartridgeCDF::CartridgeCDF(const ByteBuffer& image, size_t size, myProgramImage = myImage.data() + 4_KB; // Pointer to CDF driver in RAM - myBusDriverImage = myCDFRAM.data(); + myDriverImage = myRAM.data(); // Pointer to the display RAM - myDisplayImage = myCDFRAM.data() + DSRAM; + myDisplayImage = myRAM.data() + DSRAM; setupVersion(); @@ -83,7 +83,7 @@ CartridgeCDF::CartridgeCDF(const ByteBuffer& image, size_t size, bool devSettings = settings.getBool("dev.settings"); myThumbEmulator = make_unique( reinterpret_cast(myImage.data()), - reinterpret_cast(myCDFRAM.data()), + reinterpret_cast(myRAM.data()), static_cast(myImage.size()), devSettings ? settings.getBool("dev.thumb.trapfatal") : false, thumulatorConfiguration(myCDFSubtype), this); @@ -93,7 +93,7 @@ CartridgeCDF::CartridgeCDF(const ByteBuffer& image, size_t size, // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCDF::reset() { - initializeRAM(myCDFRAM.data()+2_KB, myCDFRAM.size()-2_KB); + initializeRAM(myRAM.data()+2_KB, myRAM.size()-2_KB); // CDF always starts in bank 6 initializeStartBank(6); @@ -111,7 +111,7 @@ void CartridgeCDF::reset() void CartridgeCDF::setInitialState() { // Copy initial CDF driver to Harmony RAM - std::copy_n(myImage.begin(), 2_KB, myBusDriverImage); + std::copy_n(myImage.begin(), 2_KB, myDriverImage); myMusicWaveformSize.fill(27); @@ -255,7 +255,7 @@ uInt8 CartridgeCDF::peek(uInt16 address) if (sampleaddress < 0x8000) peekvalue = myImage[sampleaddress]; else if (sampleaddress >= 0x40000000 && sampleaddress < 0x40002000) // check for RAM - peekvalue = myCDFRAM[sampleaddress - 0x40000000]; + peekvalue = myRAM[sampleaddress - 0x40000000]; else peekvalue = 0; @@ -508,7 +508,7 @@ bool CartridgeCDF::save(Serializer& out) const out.putShort(myJMPoperandAddress); // Harmony RAM - out.putByteArray(myCDFRAM.data(), myCDFRAM.size()); + out.putByteArray(myRAM.data(), myRAM.size()); // Audio info out.putIntArray(myMusicCounters.data(), myMusicCounters.size()); @@ -548,7 +548,7 @@ bool CartridgeCDF::load(Serializer& in) myJMPoperandAddress = in.getShort(); // Harmony RAM - in.getByteArray(myCDFRAM.data(), myCDFRAM.size()); + in.getByteArray(myRAM.data(), myRAM.size()); // Audio info in.getIntArray(myMusicCounters.data(), myMusicCounters.size()); @@ -577,10 +577,10 @@ uInt32 CartridgeCDF::getDatastreamPointer(uInt8 index) const { uInt16 address = myDatastreamBase + index * 4; - return myCDFRAM[address + 0] + // low byte - (myCDFRAM[address + 1] << 8) + - (myCDFRAM[address + 2] << 16) + - (myCDFRAM[address + 3] << 24) ; // high byte + return myRAM[address + 0] + // low byte + (myRAM[address + 1] << 8) + + (myRAM[address + 2] << 16) + + (myRAM[address + 3] << 24) ; // high byte } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -588,10 +588,10 @@ void CartridgeCDF::setDatastreamPointer(uInt8 index, uInt32 value) { uInt16 address = myDatastreamBase + index * 4; - myCDFRAM[address + 0] = value & 0xff; // low byte - myCDFRAM[address + 1] = (value >> 8) & 0xff; - myCDFRAM[address + 2] = (value >> 16) & 0xff; - myCDFRAM[address + 3] = (value >> 24) & 0xff; // high byte + myRAM[address + 0] = value & 0xff; // low byte + myRAM[address + 1] = (value >> 8) & 0xff; + myRAM[address + 2] = (value >> 16) & 0xff; + myRAM[address + 3] = (value >> 24) & 0xff; // high byte } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -599,10 +599,10 @@ uInt32 CartridgeCDF::getDatastreamIncrement(uInt8 index) const { uInt16 address = myDatastreamIncrementBase + index * 4; - return myCDFRAM[address + 0] + // low byte - (myCDFRAM[address + 1] << 8) + - (myCDFRAM[address + 2] << 16) + - (myCDFRAM[address + 3] << 24) ; // high byte + return myRAM[address + 0] + // low byte + (myRAM[address + 1] << 8) + + (myRAM[address + 2] << 16) + + (myRAM[address + 3] << 24) ; // high byte } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -610,10 +610,10 @@ uInt32 CartridgeCDF::getWaveform(uInt8 index) const { uInt16 address = myWaveformBase + index * 4; - uInt32 result = myCDFRAM[address + 0] + // low byte - (myCDFRAM[address + 1] << 8) + - (myCDFRAM[address + 2] << 16) + - (myCDFRAM[address + 3] << 24); // high byte + uInt32 result = myRAM[address + 0] + // low byte + (myRAM[address + 1] << 8) + + (myRAM[address + 2] << 16) + + (myRAM[address + 3] << 24); // high byte result -= (0x40000000 + DSRAM); @@ -628,10 +628,10 @@ uInt32 CartridgeCDF::getSample() { uInt16 address = myWaveformBase; - uInt32 result = myCDFRAM[address + 0] + // low byte - (myCDFRAM[address + 1] << 8) + - (myCDFRAM[address + 2] << 16) + - (myCDFRAM[address + 3] << 24); // high byte + uInt32 result = myRAM[address + 0] + // low byte + (myRAM[address + 1] << 8) + + (myRAM[address + 2] << 16) + + (myRAM[address + 3] << 24); // high byte return result; } diff --git a/src/emucore/CartCDF.hxx b/src/emucore/CartCDF.hxx index 7c5295f7a..14b1eda26 100644 --- a/src/emucore/CartCDF.hxx +++ b/src/emucore/CartCDF.hxx @@ -220,13 +220,13 @@ class CartridgeCDF : public Cartridge uInt8* myDisplayImage{nullptr}; // Pointer to the 2K CDF driver image in RAM - uInt8* myBusDriverImage{nullptr}; + uInt8* myDriverImage{nullptr}; // The CDF 8k RAM image, used as: // $0000 - 2K CDF driver // $0800 - 4K Display Data // $1800 - 2K C Variable & Stack - std::array myCDFRAM; + std::array myRAM; // Pointer to the Thumb ARM emulator object unique_ptr myThumbEmulator; From b264e7634487545e0b359a1468ad985d4a9a9c19 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Fri, 17 Apr 2020 13:43:49 +0200 Subject: [PATCH 114/377] refactored CartWD fixed CartEnhanced for multi-segment ROMs with extra RAM improved CartEnhanced by enabling directPoke for extra RAM --- src/emucore/Cart3EPlus.cxx | 31 +---- src/emucore/CartEnhanced.cxx | 11 +- src/emucore/CartEnhanced.hxx | 2 +- src/emucore/CartWD.cxx | 221 ++++++----------------------------- src/emucore/CartWD.hxx | 86 +++----------- 5 files changed, 60 insertions(+), 291 deletions(-) diff --git a/src/emucore/Cart3EPlus.cxx b/src/emucore/Cart3EPlus.cxx index 274e1f9db..5803f2136 100644 --- a/src/emucore/Cart3EPlus.cxx +++ b/src/emucore/Cart3EPlus.cxx @@ -29,44 +29,17 @@ Cartridge3EPlus::Cartridge3EPlus(const ByteBuffer& image, size_t size, myRamSize = RAM_SIZE; myRamBankCount = RAM_BANKS; myRamWpHigh = RAM_HIGH_WP; - - //// Allocate array for the ROM image - //myImage = make_unique(mySize); - - //// Copy the ROM image into my buffer - //std::copy_n(image.get(), mySize, myImage.get()); - //createRomAccessArrays(mySize + myRAM.size()); } -//// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -//void Cartridge3EPlus::reset() -//{ -// initializeRAM(myRAM.data(), myRAM.size()); -// -// // Remember startup bank (0 per spec, rather than last per 3E scheme). -// // Set this to go to 3rd 1K Bank. -// initializeStartBank(0); -// -// // Initialise bank values for all ROM/RAM access -// // This is used to reverse-lookup from address to bank location -// for(auto& b: bankInUse) -// b = BANK_UNDEFINED; // bank is undefined and inaccessible! -// -// initializeBankState(); -// -// // We'll map the startup banks 0 and 3 from the image into the third 1K bank upon reset -// bankROM((0 << BANK_BITS) | 0); -// bankROM((3 << BANK_BITS) | 0); -//} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3EPlus::reset() { CartridgeEnhanced::reset(); + // 1st segment in mapped to start bank in CartridgeEnhanced bank(mySystem->randGenerator().next() % romBankCount(), 1); bank(mySystem->randGenerator().next() % romBankCount(), 2); - bank(startBank(), 3); // Stella reads the PC vector always from here (TODO?) + bank(startBank(), 3); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index 5816181f2..d75c77ac8 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -68,6 +68,8 @@ void CartridgeEnhanced::install(System& system) for(uInt16 addr = ROM_OFFSET + myWriteOffset; addr < ROM_OFFSET + myWriteOffset + myRamSize; addr += System::PAGE_SIZE) { uInt16 offset = addr & myRamMask; + + access.directPokeBase = &myRAM[offset]; access.romAccessBase = &myRomAccessBase[myWriteOffset + offset]; access.romPeekCounter = &myRomAccessCounter[myWriteOffset + offset]; access.romPokeCounter = &myRomAccessCounter[myWriteOffset + offset + myAccessSize]; @@ -76,6 +78,7 @@ void CartridgeEnhanced::install(System& system) // Set the page accessing method for the RAM reading pages access.type = System::PageAccessType::READ; + access.directPokeBase = nullptr; for(uInt16 addr = ROM_OFFSET + myReadOffset; addr < ROM_OFFSET + myReadOffset + myRamSize; addr += System::PAGE_SIZE) { uInt16 offset = addr & myRamMask; @@ -125,7 +128,7 @@ uInt8 CartridgeEnhanced::peek(uInt16 address) } else { - address &= myBankMask; + address &= ROM_MASK; // Write port is e.g. at 0xF000 - 0xF07F (128 bytes) if(address < myReadOffset + myRamSize && address >= myReadOffset) @@ -133,7 +136,8 @@ uInt8 CartridgeEnhanced::peek(uInt16 address) // Reading from the write port triggers an unwanted write return peekRAM(myRAM[address], peekAddress); else - return myImage[myCurrentSegOffset[(peekAddress & ROM_MASK) >> myBankShift] + address]; + return myImage[myCurrentSegOffset[(peekAddress & ROM_MASK) >> myBankShift] + + (peekAddress & myBankMask)]; } } @@ -206,7 +210,8 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) uInt32 bankOffset = myCurrentSegOffset[segment] = romBank << myBankShift; uInt16 hotspot = this->hotspot(); uInt16 hotSpotAddr; - uInt16 fromAddr = (ROM_OFFSET + segmentOffset + myRomOffset) & ~System::PAGE_MASK; + // Skip extra RAM; if existing it is only mapped into first segment + uInt16 fromAddr = (ROM_OFFSET + segmentOffset + (segment == 0 ? myRomOffset : 0)) & ~System::PAGE_MASK; // for ROMs < 4_KB, the whole address space will be mapped. uInt16 toAddr = (ROM_OFFSET + segmentOffset + (mySize < 4_KB ? 4_KB : myBankSize)) & ~System::PAGE_MASK; diff --git a/src/emucore/CartEnhanced.hxx b/src/emucore/CartEnhanced.hxx index a45e4796e..10dbfb0d6 100644 --- a/src/emucore/CartEnhanced.hxx +++ b/src/emucore/CartEnhanced.hxx @@ -65,7 +65,7 @@ class CartridgeEnhanced : public Cartridge @return true, if bank has changed */ - bool bank(uInt16 bank, uInt16 segment); + virtual bool bank(uInt16 bank, uInt16 segment); /** Install pages for the specified bank in the system. diff --git a/src/emucore/CartWD.cxx b/src/emucore/CartWD.cxx index 9a14be24a..ff72a2b38 100644 --- a/src/emucore/CartWD.cxx +++ b/src/emucore/CartWD.cxx @@ -23,70 +23,46 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeWD::CartridgeWD(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5), - mySize(std::min(8_KB + 3, size)) + : CartridgeEnhanced(image, size, md5, settings) { // Copy the ROM image into my buffer if (mySize == 8_KB + 3) { - // swap slices 2 & 3 - std::copy_n(image.get(), 1_KB * 2, myImage.begin()); - std::copy_n(image.get() + 1_KB * 3, 1_KB * 1, myImage.begin() + 1_KB * 2); - std::copy_n(image.get() + 1_KB * 2, 1_KB * 1, myImage.begin() + 1_KB * 3); - std::copy_n(image.get() + 1_KB * 4, 1_KB * 4, myImage.begin() + 1_KB * 4); + // swap slices 2 & 3 of bad dump and correct size + std::copy_n(image.get() + 1_KB * 3, 1_KB * 1, myImage.get() + 1_KB * 2); + std::copy_n(image.get() + 1_KB * 2, 1_KB * 1, myImage.get() + 1_KB * 3); + mySize = 8_KB; } - else - std::copy_n(image.get(), mySize, myImage.begin()); - createRomAccessArrays(8_KB); + myDirectPeek = false; + + myBankShift = BANK_SHIFT; + myRamSize = RAM_SIZE; + myRamWpHigh = RAM_HIGH_WP; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeWD::reset() { - initializeRAM(myRAM.data(), myRAM.size()); - initializeStartBank(0); + CartridgeEnhanced::reset(); myCyclesAtBankswitchInit = 0; myPendingBank = 0xF0; // one more than the allowable bank # - - // Setup segments to some default slices - bank(startBank()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeWD::install(System& system) { - mySystem = &system; + CartridgeEnhanced::install(system); - // Set the page accessing method for the RAM reading pages - System::PageAccess read(this, System::PageAccessType::READ); - for(uInt16 addr = 0x1000; addr < 0x1040; addr += System::PAGE_SIZE) - { - read.directPeekBase = &myRAM[addr & 0x003F]; - read.romAccessBase = &myRomAccessBase[addr & 0x003F]; - read.romPeekCounter = &myRomAccessCounter[addr & 0x003F]; - read.romPokeCounter = &myRomAccessCounter[(addr & 0x003F) + 8_KB]; - mySystem->setPageAccess(addr, read); - } + System::PageAccess access(this, System::PageAccessType::READ); - // Set the page accessing method for the RAM writing pages - // Map access to this class, since we need to inspect all accesses to - // check if RWP happens - System::PageAccess write(this, System::PageAccessType::WRITE); - for(uInt16 addr = 0x1040; addr < 0x1080; addr += System::PAGE_SIZE) - { - write.romAccessBase = &myRomAccessBase[addr & 0x003F]; - write.romPeekCounter = &myRomAccessCounter[addr & 0x003F]; - write.romPokeCounter = &myRomAccessCounter[(addr & 0x003F) + 8_KB]; - mySystem->setPageAccess(addr, write); - } + // The hotspots are in TIA address space, so we claim it here + for(uInt16 addr = 0x00; addr < 0x40; addr += System::PAGE_SIZE) + mySystem->setPageAccess(addr, access); // Mirror all access in TIA; by doing so we're taking responsibility // for that address space in peek and poke below. - mySystem->tia().installDelegate(system, *this); - - // Setup segments to some default slices - bank(startBank()); + //mySystem->tia().installDelegate(system, *this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -113,134 +89,31 @@ uInt8 CartridgeWD::peek(uInt16 address) return mySystem->tia().peek(address); } else - { - uInt16 peekAddress = address; - address &= 0x0FFF; - - if(address < 0x0040) // RAM read port - return myRAM[address]; - else if(address < 0x0080) // RAM write port - // Reading from the write port @ $1040 - $107F triggers an unwanted write - return peekRAM(myRAM[address & 0x003F], peekAddress); - else if(address < 0x0400) - return myImage[myOffset[0] + (address & 0x03FF)]; - else if(address < 0x0800) - return myImage[myOffset[1] + (address & 0x03FF)]; - else if(address < 0x0C00) - return myImage[myOffset[2] + (address & 0x03FF)]; - else - return mySegment3[address & 0x03FF]; - } + return CartridgeEnhanced::peek(address); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeWD::poke(uInt16 address, uInt8 value) { - if(!(address & 0x1000)) // TIA addresses + if(address < 0x40) return mySystem->tia().poke(address, value); - else - { - if(address & 0x040) - { - pokeRAM(myRAM[address & 0x003F], address, value); - return true; - } - else - { - // Writing to the read port should be ignored, but trigger a break if option enabled - uInt8 dummy; - pokeRAM(dummy, address, value); - myRamWriteAccess = address; - return false; - } - } + return CartridgeEnhanced::poke(address, value); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeWD::bank(uInt16 bank) +bool CartridgeWD::bank(uInt16 bank, uInt16) { - if(bankLocked() || bank > 15) return false; + if(bankLocked()) return false; - myCurrentBank = bank; + myCurrentBank = bank % romBankCount(); - segmentZero(ourBankOrg[bank & 0x7].zero); - segmentOne(ourBankOrg[bank & 0x7].one); - segmentTwo(ourBankOrg[bank & 0x7].two); - segmentThree(ourBankOrg[bank & 0x7].three); + CartridgeEnhanced::bank(ourBankOrg[myCurrentBank].zero, 0); + CartridgeEnhanced::bank(ourBankOrg[myCurrentBank].one, 1); + CartridgeEnhanced::bank(ourBankOrg[myCurrentBank].two, 2); + CartridgeEnhanced::bank(ourBankOrg[myCurrentBank].three, 3); - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeWD::segmentZero(uInt8 slice) -{ - uInt16 offset = slice << 10; - System::PageAccess access(this, System::PageAccessType::READ); - - // Skip first 128 bytes; it is always RAM - for(uInt16 addr = 0x1080; addr < 0x1400; addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; - access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)]; - access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + 8_KB]; - mySystem->setPageAccess(addr, access); - } - myOffset[0] = offset; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeWD::segmentOne(uInt8 slice) -{ - uInt16 offset = slice << 10; - System::PageAccess access(this, System::PageAccessType::READ); - - for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; - access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)]; - access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + 8_KB]; - mySystem->setPageAccess(addr, access); - } - myOffset[1] = offset; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeWD::segmentTwo(uInt8 slice) -{ - uInt16 offset = slice << 10; - System::PageAccess access(this, System::PageAccessType::READ); - - for(uInt16 addr = 0x1800; addr < 0x1C00; addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; - access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)]; - access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + 8_KB]; - mySystem->setPageAccess(addr, access); - } - myOffset[2] = offset; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeWD::segmentThree(uInt8 slice) -{ - uInt16 offset = slice << 10; - - // Make a copy of the address space pointed to by the slice - // Then overwrite one byte with 0 - std::copy_n(myImage.begin()+offset, mySegment3.size(), mySegment3.begin()); - mySegment3[0x3FC] = 0; - - System::PageAccess access(this, System::PageAccessType::READ); - - for(uInt16 addr = 0x1C00; addr < 0x2000; addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; - access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)]; - access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + 8_KB]; - mySystem->setPageAccess(addr, access); - } - myOffset[3] = offset; + return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -249,41 +122,13 @@ uInt16 CartridgeWD::getBank(uInt16) const return myCurrentBank; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeWD::romBankCount() const -{ - return 16; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeWD::patch(uInt16 address, uInt8 value) -{ - address &= 0x0FFF; - - uInt16 idx = address >> 10; - myImage[myOffset[idx] + (address & 0x03FF)] = value; - - // The upper segment is mirrored, so we need to patch its buffer too - if(idx == 3) - mySegment3[(address & 0x03FF)] = value; - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeWD::getImage(size_t& size) const -{ - size = mySize; - return myImage.data(); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeWD::save(Serializer& out) const { + CartridgeEnhanced::save(out); try { out.putShort(myCurrentBank); - out.putByteArray(myRAM.data(), myRAM.size()); out.putLong(myCyclesAtBankswitchInit); out.putShort(myPendingBank); } @@ -299,10 +144,10 @@ bool CartridgeWD::save(Serializer& out) const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeWD::load(Serializer& in) { + CartridgeEnhanced::load(in); try { myCurrentBank = in.getShort(); - in.getByteArray(myRAM.data(), myRAM.size()); myCyclesAtBankswitchInit = in.getLong(); myPendingBank = in.getShort(); @@ -319,9 +164,9 @@ bool CartridgeWD::load(Serializer& in) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const std::array CartridgeWD::ourBankOrg = {{ - // 0 1 2 3 4 5 6 7 - { 0, 0, 1, 3 }, // Bank 0, 8 2 1 - 1 - - - - - { 0, 1, 2, 3 }, // Bank 1, 9 1 1 1 1 - - - - + // 0 1 2 3 4 5 6 7 + { 0, 0, 1, 3 }, // Bank 0, 8 2 1 - 1 - - - - + { 0, 1, 2, 3 }, // Bank 1, 9 1 1 1 1 - - - - { 4, 5, 6, 7 }, // Bank 2, 10 - - - - 1 1 1 1 { 7, 4, 2, 3 }, // Bank 3, 11 - - 1 1 1 - - 1 { 0, 0, 6, 7 }, // Bank 4, 12 2 - - - - - 1 1 diff --git a/src/emucore/CartWD.hxx b/src/emucore/CartWD.hxx index 88c59e469..9623cfa96 100644 --- a/src/emucore/CartWD.hxx +++ b/src/emucore/CartWD.hxx @@ -21,7 +21,7 @@ class System; #include "bspf.hxx" -#include "Cart.hxx" +#include "CartEnhanced.hxx" #ifdef DEBUGGER_SUPPORT #include "CartWDWidget.hxx" #endif @@ -45,15 +45,15 @@ class System; $0037, $003F: 6,0,5,1 - In the uppermost (third) segment, the byte at $3FC is overwritten by 0. + (Removed: In the uppermost (third) segment, the byte at $3FC is overwritten by 0.) The 64 bytes of RAM are accessible at $1000 - $103F (read port) and $1040 - $107F (write port). Because the RAM takes 128 bytes of address space, the range $1000 - $107F of segment 0 ROM will never be available. - @author Stephen Anthony + @author Stephen Anthony, Thomas Jentzsch */ -class CartridgeWD : public Cartridge +class CartridgeWD : public CartridgeEnhanced { friend class CartridgeWDWidget; @@ -89,7 +89,7 @@ class CartridgeWD : public Cartridge @param bank The bank that should be installed in the system */ - bool bank(uInt16 bank) override; + bool bank(uInt16 bank, uInt16 = 0) override; /** Get the current bank. @@ -98,28 +98,6 @@ class CartridgeWD : public Cartridge */ uInt16 getBank(uInt16 address = 0) const override; - /** - Query the number of banks supported by the cartridge. - */ - uInt16 romBankCount() const override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - 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 - */ - const uInt8* getImage(size_t& size) const override; - /** Save the current state of this cart to the given Serializer. @@ -173,51 +151,9 @@ class CartridgeWD : public Cartridge bool poke(uInt16 address, uInt8 value) override; private: - /** - Install the specified slice for segment zero. - - @param slice The slice to map into the segment - */ - void segmentZero(uInt8 slice); - - /** - Install the specified slice for segment one. - - @param slice The slice to map into the segment - */ - void segmentOne(uInt8 slice); - - /** - Install the specified slice for segment two. - - @param slice The slice to map into the segment - */ - void segmentTwo(uInt8 slice); - - /** - Install the specified slice for segment three. - Note that this method also takes care of setting one byte to 0. - - @param slice The slice to map into the segment - */ - void segmentThree(uInt8 slice); + bool checkSwitchBank(uInt16, uInt8 = 0) override { return false; }; private: - // The 8K ROM image of the cartridge - std::array myImage; - - // Indicates the actual size of the ROM image (either 8K or 8K + 3) - size_t mySize{0}; - - // The 64 bytes RAM of the cartridge - std::array myRAM; - - // The 1K ROM mirror of segment 3 (sometimes contains extra 3 bytes) - std::array mySegment3; - - // Indicates the offset for each of the four segments - std::array myOffset; - // Indicates the cycle at which a bankswitch was initiated uInt64 myCyclesAtBankswitchInit{0}; @@ -233,6 +169,16 @@ class CartridgeWD : public Cartridge }; static const std::array ourBankOrg; + private: + // log(ROM bank segment size) / log(2) + static constexpr uInt16 BANK_SHIFT = 10; // = 1K = 0x0400 + + // RAM size + static constexpr uInt16 RAM_SIZE = 0x40; + + // Write port for extra RAM is at low address by default + static constexpr bool RAM_HIGH_WP = true; + private: // Following constructors and assignment operators not supported CartridgeWD() = delete; From 5587306fb91e58438d45c524f7f0861f14dbfc5c Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Fri, 17 Apr 2020 11:42:11 -0230 Subject: [PATCH 115/377] Fix clang compile warning. --- src/emucore/CartWD.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/emucore/CartWD.hxx b/src/emucore/CartWD.hxx index 9623cfa96..20596868e 100644 --- a/src/emucore/CartWD.hxx +++ b/src/emucore/CartWD.hxx @@ -151,7 +151,7 @@ class CartridgeWD : public CartridgeEnhanced bool poke(uInt16 address, uInt8 value) override; private: - bool checkSwitchBank(uInt16, uInt8 = 0) override { return false; }; + bool checkSwitchBank(uInt16, uInt8 = 0) override { return false; } private: // Indicates the cycle at which a bankswitch was initiated From 5568dd3007f7b4ba5ce00806b0ad3b2f0d7503e3 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Fri, 17 Apr 2020 20:47:29 +0200 Subject: [PATCH 116/377] enable directPokeBase for RAM banks in CartridgeEnhanced --- src/emucore/CartEnhanced.cxx | 46 +++++++++++++++--------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index d75c77ac8..11eb0ca75 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -82,6 +82,7 @@ void CartridgeEnhanced::install(System& system) for(uInt16 addr = ROM_OFFSET + myReadOffset; addr < ROM_OFFSET + myReadOffset + myRamSize; addr += System::PAGE_SIZE) { uInt16 offset = addr & myRamMask; + access.directPeekBase = &myRAM[offset]; access.romAccessBase = &myRomAccessBase[myReadOffset + offset]; access.romPeekCounter = &myRomAccessCounter[myReadOffset + offset]; @@ -126,19 +127,18 @@ uInt8 CartridgeEnhanced::peek(uInt16 address) return peekRAM(myRAM[((myCurrentSegOffset[(peekAddress & ROM_MASK) >> myBankShift] - mySize) >> 1) + address], peekAddress); } - else - { - address &= ROM_MASK; + address &= ROM_MASK; - // Write port is e.g. at 0xF000 - 0xF07F (128 bytes) - if(address < myReadOffset + myRamSize && address >= myReadOffset) - // This is a read access to a write port! - // Reading from the write port triggers an unwanted write - return peekRAM(myRAM[address], peekAddress); - else - return myImage[myCurrentSegOffset[(peekAddress & ROM_MASK) >> myBankShift] - + (peekAddress & myBankMask)]; + // Write port is e.g. at 0xF000 - 0xF07F (128 bytes) + if(address < myReadOffset + myRamSize && address >= myReadOffset) + { + // This is a read access to a write port! + // Reading from the write port triggers an unwanted write + return peekRAM(myRAM[address], peekAddress); } + + return myImage[myCurrentSegOffset[(peekAddress & ROM_MASK) >> myBankShift] + + (peekAddress & myBankMask)]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -153,6 +153,7 @@ bool CartridgeEnhanced::poke(uInt16 address, uInt8 value) if(myRamSize > 0) { + // Code should never get here (System::PageAccess::directPoke() handles this) uInt16 pokeAddress = address; if(isRamBank(address)) @@ -165,14 +166,6 @@ bool CartridgeEnhanced::poke(uInt16 address, uInt8 value) pokeAddress, value); return true; } - else - { - // Writing to the read port should be ignored, but trigger a break if option enabled - uInt8 dummy; - - pokeRAM(dummy, pokeAddress, value); - myRamWriteAccess = pokeAddress; - } } else { @@ -182,15 +175,12 @@ bool CartridgeEnhanced::poke(uInt16 address, uInt8 value) pokeRAM(myRAM[address & myRamMask], pokeAddress, value); return true; } - else - { - // Writing to the read port should be ignored, but trigger a break if option enabled - uInt8 dummy; - - pokeRAM(dummy, pokeAddress, value); - myRamWriteAccess = pokeAddress; - } } + // Writing to the read port should be ignored, but trigger a break if option enabled + uInt8 dummy; + + pokeRAM(dummy, pokeAddress, value); + myRamWriteAccess = pokeAddress; } return false; } @@ -255,6 +245,7 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) { uInt32 offset = bankOffset + (addr & myRamMask); + access.directPokeBase = &myRAM[offset - mySize]; access.romAccessBase = &myRomAccessBase[offset]; access.romPeekCounter = &myRomAccessCounter[offset]; access.romPokeCounter = &myRomAccessCounter[offset + myAccessSize]; @@ -265,6 +256,7 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) fromAddr = (ROM_OFFSET + segmentOffset + myReadOffset) & ~System::PAGE_MASK; toAddr = (ROM_OFFSET + segmentOffset + myReadOffset + (myBankSize >> 1)) & ~System::PAGE_MASK; access.type = System::PageAccessType::READ; + access.directPokeBase = nullptr; for(uInt16 addr = fromAddr; addr < toAddr; addr += System::PAGE_SIZE) { From 51432f713ee3869512b6c31d1943ab47d2981e42 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 18 Apr 2020 17:51:21 +0200 Subject: [PATCH 117/377] fix display of changed PopUpWidget in debugger allow using IDs with PopUpWidget's ContextMenu --- src/gui/ContextMenu.cxx | 10 +++++----- src/gui/ContextMenu.hxx | 4 ++++ src/gui/PopUpWidget.cxx | 10 +++++++++- src/gui/PopUpWidget.hxx | 2 ++ 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/gui/ContextMenu.cxx b/src/gui/ContextMenu.cxx index 11e09e475..cf142255f 100644 --- a/src/gui/ContextMenu.cxx +++ b/src/gui/ContextMenu.cxx @@ -181,7 +181,7 @@ bool ContextMenu::sendSelectionUp() return false; _selectedItem--; - sendCommand(_cmd ? _cmd : ContextMenu::kItemSelectedCmd, _selectedItem, -1); + sendCommand(_cmd ? _cmd : ContextMenu::kItemSelectedCmd, _selectedItem, _id); return true; } @@ -192,7 +192,7 @@ bool ContextMenu::sendSelectionDown() return false; _selectedItem++; - sendCommand(_cmd ? _cmd : ContextMenu::kItemSelectedCmd, _selectedItem, -1); + sendCommand(_cmd ? _cmd : ContextMenu::kItemSelectedCmd, _selectedItem, _id); return true; } @@ -203,7 +203,7 @@ bool ContextMenu::sendSelectionFirst() return false; _selectedItem = 0; - sendCommand(_cmd ? _cmd : ContextMenu::kItemSelectedCmd, _selectedItem, -1); + sendCommand(_cmd ? _cmd : ContextMenu::kItemSelectedCmd, _selectedItem, _id); return true; } @@ -214,7 +214,7 @@ bool ContextMenu::sendSelectionLast() return false; _selectedItem = int(_entries.size()) - 1; - sendCommand(_cmd ? _cmd : ContextMenu::kItemSelectedCmd, _selectedItem, -1); + sendCommand(_cmd ? _cmd : ContextMenu::kItemSelectedCmd, _selectedItem, _id); return true; } @@ -375,7 +375,7 @@ void ContextMenu::sendSelection() // Send any command associated with the selection _selectedItem = item; - sendCommand(_cmd ? _cmd : ContextMenu::kItemSelectedCmd, _selectedItem, -1); + sendCommand(_cmd ? _cmd : ContextMenu::kItemSelectedCmd, _selectedItem, _id); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/gui/ContextMenu.hxx b/src/gui/ContextMenu.hxx index 28d485f1a..40858f8b9 100644 --- a/src/gui/ContextMenu.hxx +++ b/src/gui/ContextMenu.hxx @@ -45,6 +45,9 @@ class ContextMenu : public Dialog, public CommandSender const VariantList& items, int cmd = 0, int width = 0); virtual ~ContextMenu() = default; + /** Set the parent widget's ID */ + void setID(uInt32 id) { _id = id; } + /** Add the given items to the widget. */ void addItems(const VariantList& items); @@ -121,6 +124,7 @@ class ContextMenu : public Dialog, public CommandSender ColorId _scrollUpColor{kColor}, _scrollDnColor{kColor}; int _cmd{0}; + int _id{-1}; uInt32 _xorig{0}, _yorig{0}; uInt32 _maxWidth{0}; diff --git a/src/gui/PopUpWidget.cxx b/src/gui/PopUpWidget.cxx index 6b530f6d1..9cc233060 100644 --- a/src/gui/PopUpWidget.cxx +++ b/src/gui/PopUpWidget.cxx @@ -50,6 +50,14 @@ PopUpWidget::PopUpWidget(GuiObject* boss, const GUI::Font& font, myMenu = make_unique(this, font, list, cmd, w); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PopUpWidget::setID(uInt32 id) +{ + myMenu->setID(id); + + Widget::setID(id); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PopUpWidget::addItems(const VariantList& items) { @@ -219,5 +227,5 @@ void PopUpWidget::drawWidget(bool hilite) TextAlign align = (_font.getStringWidth(name) > w-6) ? TextAlign::Right : TextAlign::Left; s.drawString(_font, name, x+2, _y+myTextY, w-6, - !(isEnabled() && onTop) ? kColor : kTextColor, align); + !(isEnabled() && onTop) ? kColor : _changed ? kDbgChangedTextColor : kTextColor, align); } diff --git a/src/gui/PopUpWidget.hxx b/src/gui/PopUpWidget.hxx index f79e575f8..955263f5f 100644 --- a/src/gui/PopUpWidget.hxx +++ b/src/gui/PopUpWidget.hxx @@ -41,6 +41,8 @@ class PopUpWidget : public Widget, public CommandSender const string& label, int labelWidth = 0, int cmd = 0); virtual ~PopUpWidget() = default; + void setID(uInt32 id); + int getTop() const override { return _y + 1; } int getBottom() const override { return _y + 1 + getHeight(); } From a14a20c9a047797e1467ad7dafb541b4af8047c5 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 18 Apr 2020 19:22:08 +0200 Subject: [PATCH 118/377] fixed description background color in CartRamWidget --- src/debugger/gui/CartRamWidget.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/debugger/gui/CartRamWidget.cxx b/src/debugger/gui/CartRamWidget.cxx index 1dfcfdaac..cfed3d3e5 100644 --- a/src/debugger/gui/CartRamWidget.cxx +++ b/src/debugger/gui/CartRamWidget.cxx @@ -65,13 +65,14 @@ CartRamWidget::CartRamWidget( StringParser bs(desc, (fwidth - kScrollBarWidth) / myFontWidth); const StringList& sl = bs.stringList(); uInt32 lines = uInt32(sl.size()); - if(lines < 3) lines = 3; + if(lines < 2) lines = 2; if(lines > maxlines) lines = maxlines; new StaticTextWidget(_boss, _font, xpos, ypos + 1, "Description "); myDesc = new StringListWidget(boss, nfont, xpos+lwidth, ypos - 1, fwidth, lines * myLineHeight, false); myDesc->setEditable(false); + myDesc->setEnabled(false); myDesc->setList(sl); addFocusWidget(myDesc); From e5b919a8e0d9b84017c4c7590fb94f19fd123a9e Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 19 Apr 2020 10:23:27 +0200 Subject: [PATCH 119/377] refactored multiple CartXXWidget classes --- src/debugger/gui/Cart0840Widget.cxx | 75 +----- src/debugger/gui/Cart0840Widget.hxx | 15 +- src/debugger/gui/Cart2KWidget.cxx | 26 +- src/debugger/gui/Cart2KWidget.hxx | 11 +- src/debugger/gui/Cart3EWidget.cxx | 2 +- src/debugger/gui/Cart4KSCWidget.cxx | 91 +------ src/debugger/gui/Cart4KSCWidget.hxx | 29 +- src/debugger/gui/Cart4KWidget.cxx | 32 ++- src/debugger/gui/Cart4KWidget.hxx | 11 +- src/debugger/gui/CartCVWidget.cxx | 169 ++++++------ src/debugger/gui/CartCVWidget.hxx | 47 ++-- src/debugger/gui/CartDebugWidget.cxx | 2 +- src/debugger/gui/CartE0Widget.cxx | 145 +++------- src/debugger/gui/CartE0Widget.hxx | 24 +- src/debugger/gui/CartEnhancedWidget.cxx | 344 ++++++++++++++++++++++++ src/debugger/gui/CartEnhancedWidget.hxx | 108 ++++++++ src/debugger/gui/CartF0Widget.cxx | 82 +----- src/debugger/gui/CartF0Widget.hxx | 15 +- src/debugger/gui/CartF4SCWidget.cxx | 150 +---------- src/debugger/gui/CartF4SCWidget.hxx | 34 +-- src/debugger/gui/CartF4Widget.cxx | 81 +----- src/debugger/gui/CartF4Widget.hxx | 15 +- src/debugger/gui/CartF6SCWidget.cxx | 144 +--------- src/debugger/gui/CartF6SCWidget.hxx | 32 +-- src/debugger/gui/CartF6Widget.cxx | 75 +----- src/debugger/gui/CartF6Widget.hxx | 15 +- src/debugger/gui/CartF8SCWidget.cxx | 142 +--------- src/debugger/gui/CartF8SCWidget.hxx | 33 +-- src/debugger/gui/CartF8Widget.cxx | 73 +---- src/debugger/gui/CartF8Widget.hxx | 14 +- src/debugger/gui/CartUAWidget.cxx | 82 ++---- src/debugger/gui/CartUAWidget.hxx | 18 +- src/debugger/gui/module.mk | 1 + src/emucore/Cart4K.cxx | 1 - src/emucore/CartEnhanced.cxx | 2 +- src/emucore/CartEnhanced.hxx | 33 ++- src/emucore/CartUA.hxx | 2 + src/windows/Stella.vcxproj | 2 + src/windows/Stella.vcxproj.filters | 6 + 39 files changed, 844 insertions(+), 1339 deletions(-) create mode 100644 src/debugger/gui/CartEnhancedWidget.cxx create mode 100644 src/debugger/gui/CartEnhancedWidget.hxx diff --git a/src/debugger/gui/Cart0840Widget.cxx b/src/debugger/gui/Cart0840Widget.cxx index 6582701bc..c49c86d09 100644 --- a/src/debugger/gui/Cart0840Widget.cxx +++ b/src/debugger/gui/Cart0840Widget.cxx @@ -16,80 +16,25 @@ //============================================================================ #include "Cart0840.hxx" -#include "PopUpWidget.hxx" #include "Cart0840Widget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge0840Widget::Cartridge0840Widget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, Cartridge0840& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) + : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { - uInt16 size = 2 * 4096; + myHotspotDelta = 0x40; + initialize(); +} +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string Cartridge0840Widget::description() +{ ostringstream info; - info << "0840 ECONObanking, two 4K banks\n" - << "Startup bank = " << cart.startBank() << "\n"; - // Eventually, we should query this from the debugger/disassembler - for(uInt32 i = 0, offset = 0xFFC, spot = 0x800; i < 2; - ++i, offset += 0x1000, spot += 0x40) - { - uInt16 start = uInt16((cart.myImage[offset+1] << 8) | cart.myImage[offset]); - start -= start % 0x1000; - info << "Bank " << i << " @ $" << Common::Base::HEX4 << start << " - " - << "$" << (start + 0xFFF) << " (hotspot = $" << spot << ")\n"; - } + info << "0840 ECONObanking, two 4K banks\n"; + info << CartEnhancedWidget::description(); - int xpos = 2, - ypos = addBaseInformation(size, "Fred X. Quimby", info.str()) + myLineHeight; - - VariantList items; - VarList::push_back(items, "0 ($800)"); - VarList::push_back(items, "1 ($840)"); - myBank = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($800)"), - myLineHeight, items, "Set bank ", - 0, kBankChanged); - myBank->setTarget(this); - addFocusWidget(myBank); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge0840Widget::loadConfig() -{ - Debugger& dbg = instance().debugger(); - CartDebug& cart = dbg.cartDebug(); - const CartState& state = static_cast(cart.getState()); - const CartState& oldstate = static_cast(cart.getOldState()); - - myBank->setSelectedIndex(myCart.getBank(), state.bank != oldstate.bank); - - CartDebugWidget::loadConfig(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge0840Widget::handleCommand(CommandSender* sender, - int cmd, int data, int id) -{ - if(cmd == kBankChanged) - { - myCart.unlockBank(); - myCart.bank(myBank->getSelected()); - myCart.lockBank(); - invalidate(); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string Cartridge0840Widget::bankState() -{ - ostringstream& buf = buffer(); - - static const std::array spot = { "$800", "$840" }; - buf << "Bank = " << std::dec << myCart.getBank() - << ", hotspot = " << spot[myCart.getBank()]; - - return buf.str(); + return info.str(); } diff --git a/src/debugger/gui/Cart0840Widget.hxx b/src/debugger/gui/Cart0840Widget.hxx index 239f28bf8..89e8706c6 100644 --- a/src/debugger/gui/Cart0840Widget.hxx +++ b/src/debugger/gui/Cart0840Widget.hxx @@ -19,11 +19,10 @@ #define CARTRIDGE0840_WIDGET_HXX class Cartridge0840; -class PopUpWidget; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class Cartridge0840Widget : public CartDebugWidget +class Cartridge0840Widget : public CartEnhancedWidget { public: Cartridge0840Widget(GuiObject* boss, const GUI::Font& lfont, @@ -33,17 +32,11 @@ class Cartridge0840Widget : public CartDebugWidget virtual ~Cartridge0840Widget() = default; private: - Cartridge0840& myCart; - PopUpWidget* myBank{nullptr}; + string manufacturer() override { return "Fred X. Quimby"; } - enum { kBankChanged = 'bkCH' }; + string description() override; private: - void loadConfig() override; - void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - - string bankState() override; - // Following constructors and assignment operators not supported Cartridge0840Widget() = delete; Cartridge0840Widget(const Cartridge0840Widget&) = delete; diff --git a/src/debugger/gui/Cart2KWidget.cxx b/src/debugger/gui/Cart2KWidget.cxx index 745c52316..c97bc440f 100644 --- a/src/debugger/gui/Cart2KWidget.cxx +++ b/src/debugger/gui/Cart2KWidget.cxx @@ -22,18 +22,18 @@ Cartridge2KWidget::Cartridge2KWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, Cartridge2K& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h) + : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { - // Eventually, we should query this from the debugger/disassembler - size_t size; - - cart.getImage(size); - - uInt16 start = (cart.myImage[size-3] << 8) | cart.myImage[size-4]; - start -= start % size; - - ostringstream info; - info << "Standard 2K cartridge, non-bankswitched\n" - << "Accessible @ $" << Common::Base::HEX4 << start << " - " << "$" << (start + size - 1); - addBaseInformation(size, "Atari", info.str()); + initialize(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string Cartridge2KWidget::description() +{ + ostringstream info; + + info << "Standard 2K cartridge, non-bankswitched\n"; + info << CartEnhancedWidget::description(); + + return info.str(); } diff --git a/src/debugger/gui/Cart2KWidget.hxx b/src/debugger/gui/Cart2KWidget.hxx index 0580078f7..e6e0fe9d2 100644 --- a/src/debugger/gui/Cart2KWidget.hxx +++ b/src/debugger/gui/Cart2KWidget.hxx @@ -20,9 +20,9 @@ class Cartridge2K; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class Cartridge2KWidget : public CartDebugWidget +class Cartridge2KWidget : public CartEnhancedWidget { public: Cartridge2KWidget(GuiObject* boss, const GUI::Font& lfont, @@ -32,10 +32,11 @@ class Cartridge2KWidget : public CartDebugWidget virtual ~Cartridge2KWidget() = default; private: - // No implementation for non-bankswitched ROMs - void loadConfig() override { } - void handleCommand(CommandSender* sender, int cmd, int data, int id) override { } + string manufacturer() override { return "Atari"; } + string description() override; + + private: // Following constructors and assignment operators not supported Cartridge2KWidget() = delete; Cartridge2KWidget(const Cartridge2KWidget&) = delete; diff --git a/src/debugger/gui/Cart3EWidget.cxx b/src/debugger/gui/Cart3EWidget.cxx index e91b268ab..287bdd112 100644 --- a/src/debugger/gui/Cart3EWidget.cxx +++ b/src/debugger/gui/Cart3EWidget.cxx @@ -161,7 +161,7 @@ string Cartridge3EWidget::bankState() if(bank < myCart.romBankCount()) buf << "ROM bank #" << std::dec << bank % myNumRomBanks << ", RAM inactive"; else - buf << "ROM inactive, RAM bank #" << std::dec << bank % myNumRomBanks; + buf << "ROM inactive, RAM bank #" << std::dec << bank % myNumRamBanks; return buf.str(); } diff --git a/src/debugger/gui/Cart4KSCWidget.cxx b/src/debugger/gui/Cart4KSCWidget.cxx index 8729c077f..105136dd5 100644 --- a/src/debugger/gui/Cart4KSCWidget.cxx +++ b/src/debugger/gui/Cart4KSCWidget.cxx @@ -15,8 +15,6 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#include "Debugger.hxx" -#include "CartDebug.hxx" #include "Cart4KSC.hxx" #include "Cart4KSCWidget.hxx" @@ -24,87 +22,18 @@ Cartridge4KSCWidget::Cartridge4KSCWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, Cartridge4KSC& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) + : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { - // Eventually, we should query this from the debugger/disassembler - uInt16 start = (cart.myImage[0xFFD] << 8) | cart.myImage[0xFFC]; - start -= start % 0x1000; + initialize(); +} +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string Cartridge4KSCWidget::description() +{ ostringstream info; - info << "4KSC cartridge, non-bankswitched\n" - << "128 bytes RAM @ $F000 - $F0FF\n" - << " $F080 - $F0FF (R), $F000 - $F07F (W)\n" - << "Accessible @ $" << Common::Base::HEX4 << start << " - " - << "$" << (start + 0xFFF); - addBaseInformation(4096, "homebrew intermediate format", info.str()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge4KSCWidget::saveOldState() -{ - myOldState.internalram.clear(); - - for(uInt32 i = 0; i < internalRamSize(); ++i) - myOldState.internalram.push_back(myCart.myRAM[i]); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 Cartridge4KSCWidget::internalRamSize() -{ - return 128; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 Cartridge4KSCWidget::internalRamRPort(int start) -{ - return 0xF080 + start; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string Cartridge4KSCWidget::internalRamDescription() -{ - ostringstream desc; - desc << "$F000 - $F07F used for Write Access\n" - << "$F080 - $F0FF used for Read Access"; - - return desc.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& Cartridge4KSCWidget::internalRamOld(int start, int count) -{ - myRamOld.clear(); - for(int i = 0; i < count; i++) - myRamOld.push_back(myOldState.internalram[start + i]); - return myRamOld; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& Cartridge4KSCWidget::internalRamCurrent(int start, int count) -{ - myRamCurrent.clear(); - for(int i = 0; i < count; i++) - myRamCurrent.push_back(myCart.myRAM[start + i]); - return myRamCurrent; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge4KSCWidget::internalRamSetValue(int addr, uInt8 value) -{ - myCart.myRAM[addr] = value; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 Cartridge4KSCWidget::internalRamGetValue(int addr) -{ - return myCart.myRAM[addr]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string Cartridge4KSCWidget::internalRamLabel(int addr) -{ - CartDebug& dbg = instance().debugger().cartDebug(); - return dbg.getLabel(addr + 0xF080, false); + info << "4KSC cartridge, non-bankswitched\n"; + info << CartEnhancedWidget::description(); + + return info.str(); } diff --git a/src/debugger/gui/Cart4KSCWidget.hxx b/src/debugger/gui/Cart4KSCWidget.hxx index 6a6ee2d8c..832c2c127 100644 --- a/src/debugger/gui/Cart4KSCWidget.hxx +++ b/src/debugger/gui/Cart4KSCWidget.hxx @@ -20,9 +20,9 @@ class Cartridge4KSC; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class Cartridge4KSCWidget : public CartDebugWidget +class Cartridge4KSCWidget : public CartEnhancedWidget { public: Cartridge4KSCWidget(GuiObject* boss, const GUI::Font& lfont, @@ -32,30 +32,11 @@ class Cartridge4KSCWidget : public CartDebugWidget virtual ~Cartridge4KSCWidget() = default; private: - Cartridge4KSC& myCart; - struct CartState { - ByteArray internalram; - }; - CartState myOldState; + string manufacturer() override { return "homebrew intermediate format"; } + + string description() override; private: - // No implementation for non-bankswitched ROMs - void loadConfig() override { } - void handleCommand(CommandSender* sender, int cmd, int data, int id) override { } - - void saveOldState() override; - - // start of functions for Cartridge RAM tab - uInt32 internalRamSize() override; - uInt32 internalRamRPort(int start) override; - string internalRamDescription() override; - const ByteArray& internalRamOld(int start, int count) override; - const ByteArray& internalRamCurrent(int start, int count) override; - void internalRamSetValue(int addr, uInt8 value) override; - uInt8 internalRamGetValue(int addr) override; - string internalRamLabel(int addr) override; - // end of functions for Cartridge RAM tab - // Following constructors and assignment operators not supported Cartridge4KSCWidget() = delete; Cartridge4KSCWidget(const Cartridge4KSCWidget&) = delete; diff --git a/src/debugger/gui/Cart4KWidget.cxx b/src/debugger/gui/Cart4KWidget.cxx index ed4ef7218..14091bd15 100644 --- a/src/debugger/gui/Cart4KWidget.cxx +++ b/src/debugger/gui/Cart4KWidget.cxx @@ -22,15 +22,29 @@ Cartridge4KWidget::Cartridge4KWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, Cartridge4K& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h) + : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { - // Eventually, we should query this from the debugger/disassembler - uInt16 start = (cart.myImage[0xFFD] << 8) | cart.myImage[0xFFC]; - start -= start % 0x1000; + initialize(); - ostringstream info; - info << "Standard 4K cartridge, non-bankswitched\n" - << "Accessible @ $" << Common::Base::HEX4 << start << " - " - << "$" << (start + 0xFFF); - addBaseInformation(4096, "Atari", info.str()); + //// Eventually, we should query this from the debugger/disassembler + //uInt16 start = (cart.myImage[0xFFD] << 8) | cart.myImage[0xFFC]; + //start -= start % 0x1000; + + //ostringstream info; + //info << "Standard 4K cartridge, non-bankswitched\n" + // << "Accessible @ $" << Common::Base::HEX4 << start << " - " + // << "$" << (start + 0xFFF); + //addBaseInformation(4096, "Atari", info.str()); } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string Cartridge4KWidget::description() +{ + ostringstream info; + + info << "Standard 4K cartridge, non-bankswitched\n"; + info << CartEnhancedWidget::description(); + + return info.str(); +} + diff --git a/src/debugger/gui/Cart4KWidget.hxx b/src/debugger/gui/Cart4KWidget.hxx index 3ba39a3d9..886e2a060 100644 --- a/src/debugger/gui/Cart4KWidget.hxx +++ b/src/debugger/gui/Cart4KWidget.hxx @@ -20,9 +20,9 @@ class Cartridge4K; -#include "CartDebugWidget.hxx" +#include "CartEnhanced.hxx" -class Cartridge4KWidget : public CartDebugWidget +class Cartridge4KWidget : public CartEnhancedWidget { public: Cartridge4KWidget(GuiObject* boss, const GUI::Font& lfont, @@ -32,10 +32,11 @@ class Cartridge4KWidget : public CartDebugWidget virtual ~Cartridge4KWidget() = default; private: - // No implementation for non-bankswitched ROMs - void loadConfig() override { } - void handleCommand(CommandSender* sender, int cmd, int data, int id) override { } + string manufacturer() override { return "Atari"; } + string description() override; + + private: // Following constructors and assignment operators not supported Cartridge4KWidget() = delete; Cartridge4KWidget(const Cartridge4KWidget&) = delete; diff --git a/src/debugger/gui/CartCVWidget.cxx b/src/debugger/gui/CartCVWidget.cxx index bae69cfba..167ff7122 100644 --- a/src/debugger/gui/CartCVWidget.cxx +++ b/src/debugger/gui/CartCVWidget.cxx @@ -24,88 +24,101 @@ CartridgeCVWidget::CartridgeCVWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeCV& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) + : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { - // Eventually, we should query this from the debugger/disassembler - uInt16 size = 2048; - uInt16 start = (cart.myImage[size-3] << 8) | cart.myImage[size-4]; - start -= start % size; + initialize(); + //// Eventually, we should query this from the debugger/disassembler + //uInt16 size = 2048; + //uInt16 start = (cart.myImage[size-3] << 8) | cart.myImage[size-4]; + //start -= start % size; + + //ostringstream info; + //info << "CV 2K ROM + 1K RAM , non-bankswitched\n" + // << "1024 bytes RAM @ $F000 - $F7FF\n" + // << " $F000 - $F3FF (R), $F400 - $F7FF (W)\n" + // << "ROM accessible @ $" << Common::Base::HEX4 << start << " - " + // << "$" << (start + size - 1); + + //addBaseInformation(cart.mySize, "CommaVid", info.str()); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartridgeCVWidget::description() +{ ostringstream info; - info << "CV 2K ROM + 1K RAM , non-bankswitched\n" - << "1024 bytes RAM @ $F000 - $F7FF\n" - << " $F000 - $F3FF (R), $F400 - $F7FF (W)\n" - << "ROM accessible @ $" << Common::Base::HEX4 << start << " - " - << "$" << (start + size - 1); - addBaseInformation(cart.mySize, "CommaVid", info.str()); + info << "CV 2K ROM + 1K RAM , non-bankswitched\n"; + info << CartEnhancedWidget::description(); + + return info.str(); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeCVWidget::saveOldState() -{ - myOldState.internalram.clear(); - for(uInt32 i = 0; i < internalRamSize(); ++i) - myOldState.internalram.push_back(myCart.myRAM[i]); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 CartridgeCVWidget::internalRamSize() -{ - return 1024; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 CartridgeCVWidget::internalRamRPort(int start) -{ - return 0xF000 + start; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeCVWidget::internalRamDescription() -{ - ostringstream desc; - desc << "$F000 - $F3FF used for Read Access\n" - << "$F400 - $F7FF used for Write Access"; - - return desc.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& CartridgeCVWidget::internalRamOld(int start, int count) -{ - myRamOld.clear(); - for(int i = 0; i < count; i++) - myRamOld.push_back(myOldState.internalram[start + i]); - return myRamOld; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& CartridgeCVWidget::internalRamCurrent(int start, int count) -{ - myRamCurrent.clear(); - for(int i = 0; i < count; i++) - myRamCurrent.push_back(myCart.myRAM[start + i]); - return myRamCurrent; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeCVWidget::internalRamSetValue(int addr, uInt8 value) -{ - myCart.myRAM[addr] = value; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeCVWidget::internalRamGetValue(int addr) -{ - return myCart.myRAM[addr]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeCVWidget::internalRamLabel(int addr) -{ - CartDebug& dbg = instance().debugger().cartDebug(); - return dbg.getLabel(addr + 0xF000, false); -} +//// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//void CartridgeCVWidget::saveOldState() +//{ +// myOldState.internalram.clear(); +// +// for(uInt32 i = 0; i < internalRamSize(); ++i) +// myOldState.internalram.push_back(myCart.myRAM[i]); +//} +// +//// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//uInt32 CartridgeCVWidget::internalRamSize() +//{ +// return 1024; +//} +// +//// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//uInt32 CartridgeCVWidget::internalRamRPort(int start) +//{ +// return 0xF000 + start; +//} +// +//// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//string CartridgeCVWidget::internalRamDescription() +//{ +// ostringstream desc; +// desc << "$F000 - $F3FF used for Read Access\n" +// << "$F400 - $F7FF used for Write Access"; +// +// return desc.str(); +//} +// +//// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//const ByteArray& CartridgeCVWidget::internalRamOld(int start, int count) +//{ +// myRamOld.clear(); +// for(int i = 0; i < count; i++) +// myRamOld.push_back(myOldState.internalram[start + i]); +// return myRamOld; +//} +// +//// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//const ByteArray& CartridgeCVWidget::internalRamCurrent(int start, int count) +//{ +// myRamCurrent.clear(); +// for(int i = 0; i < count; i++) +// myRamCurrent.push_back(myCart.myRAM[start + i]); +// return myRamCurrent; +//} +// +//// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//void CartridgeCVWidget::internalRamSetValue(int addr, uInt8 value) +//{ +// myCart.myRAM[addr] = value; +//} +// +//// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//uInt8 CartridgeCVWidget::internalRamGetValue(int addr) +//{ +// return myCart.myRAM[addr]; +//} +// +//// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//string CartridgeCVWidget::internalRamLabel(int addr) +//{ +// CartDebug& dbg = instance().debugger().cartDebug(); +// return dbg.getLabel(addr + 0xF000, false); +//} diff --git a/src/debugger/gui/CartCVWidget.hxx b/src/debugger/gui/CartCVWidget.hxx index f9d59812b..73452204c 100644 --- a/src/debugger/gui/CartCVWidget.hxx +++ b/src/debugger/gui/CartCVWidget.hxx @@ -20,9 +20,9 @@ class CartridgeCV; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class CartridgeCVWidget : public CartDebugWidget +class CartridgeCVWidget : public CartEnhancedWidget { public: CartridgeCVWidget(GuiObject* boss, const GUI::Font& lfont, @@ -32,30 +32,35 @@ class CartridgeCVWidget : public CartDebugWidget virtual ~CartridgeCVWidget() = default; private: - CartridgeCV& myCart; - struct CartState { - ByteArray internalram; - }; - CartState myOldState; + //CartridgeCV& myCart; + //struct CartState { + // ByteArray internalram; + //}; + //CartState myOldState; private: - // No implementation for non-bankswitched ROMs - void loadConfig() override { } - void handleCommand(CommandSender* sender, int cmd, int data, int id) override { } + string manufacturer() override { return "CommaVid"; } - void saveOldState() override; + string description() override; - // start of functions for Cartridge RAM tab - uInt32 internalRamSize() override; - uInt32 internalRamRPort(int start) override; - string internalRamDescription() override; - const ByteArray& internalRamOld(int start, int count) override; - const ByteArray& internalRamCurrent(int start, int count) override; - void internalRamSetValue(int addr, uInt8 value) override; - uInt8 internalRamGetValue(int addr) override; - string internalRamLabel(int addr) override; - // end of functions for Cartridge RAM tab + //// No implementation for non-bankswitched ROMs + //void loadConfig() override { } + //void handleCommand(CommandSender* sender, int cmd, int data, int id) override { } + //void saveOldState() override; + + //// start of functions for Cartridge RAM tab + //uInt32 internalRamSize() override; + //uInt32 internalRamRPort(int start) override; + //string internalRamDescription() override; + //const ByteArray& internalRamOld(int start, int count) override; + //const ByteArray& internalRamCurrent(int start, int count) override; + //void internalRamSetValue(int addr, uInt8 value) override; + //uInt8 internalRamGetValue(int addr) override; + //string internalRamLabel(int addr) override; + //// end of functions for Cartridge RAM tab + + private: // Following constructors and assignment operators not supported CartridgeCVWidget() = delete; CartridgeCVWidget(const CartridgeCVWidget&) = delete; diff --git a/src/debugger/gui/CartDebugWidget.cxx b/src/debugger/gui/CartDebugWidget.cxx index 208eec5a7..25423ebd7 100644 --- a/src/debugger/gui/CartDebugWidget.cxx +++ b/src/debugger/gui/CartDebugWidget.cxx @@ -65,7 +65,7 @@ int CartDebugWidget::addBaseInformation(size_t bytes, const string& manufacturer w->setEditable(false); y += myLineHeight + 4; - StringParser bs(desc, (fwidth - kScrollBarWidth) / myFontWidth - 4); + StringParser bs(desc, (fwidth - kScrollBarWidth - 4) / myFontWidth); const StringList& sl = bs.stringList(); uInt32 lines = uInt32(sl.size()); if(lines < 3) lines = 3; diff --git a/src/debugger/gui/CartE0Widget.cxx b/src/debugger/gui/CartE0Widget.cxx index 861c99228..4588abcdc 100644 --- a/src/debugger/gui/CartE0Widget.cxx +++ b/src/debugger/gui/CartE0Widget.cxx @@ -16,129 +16,60 @@ //============================================================================ #include "CartE0.hxx" -#include "PopUpWidget.hxx" #include "CartE0Widget.hxx" -static constexpr std::array seg0 = { - "0 ($FFE0)", "1 ($FFE1)", "2 ($FFE2)", "3 ($FFE3)", - "4 ($FFE4)", "5 ($FFE5)", "6 ($FFE6)", "7 ($FFE7)" -}; -static constexpr std::array seg1 = { - "0 ($FFE8)", "1 ($FFE9)", "2 ($FFEA)", "3 ($FFEB)", - "4 ($FFEC)", "5 ($FFED)", "6 ($FFEE)", "7 ($FFEF)" -}; -static constexpr std::array seg2 = { - "0 ($FFF0)", "1 ($FFF1)", "2 ($FFF2)", "3 ($FFF3)", - "4 ($FFF4)", "5 ($FFF5)", "6 ($FFF6)", "7 ($FFF7)" -}; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeE0Widget::CartridgeE0Widget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeE0& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) + : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { - uInt32 size = 8 * 1024; + initialize(); +} - string info = - "E0 cartridge, eight 1K slices\n" - "Segment 0 accessible @ $F000 - $F3FF\n" - " Hotspots $FE0 to $FE7\n" - "Segment 1 accessible @ $F400 - $F7FF\n" - " Hotspots $FE8 to $FEF\n" - "Segment 2 accessible @ $F800 - $FBFF\n" - " Hotspots $FF0 to $FF7\n" - "Segment 3 accessible @ $FC00 - $FFFF\n" - " Always points to last 1K of ROM\n" - "Startup slices = 4 / 5 / 6 or undetermined\n"; +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartridgeE0Widget::description() +{ + ostringstream info; -#if 0 - // Eventually, we should query this from the debugger/disassembler - uInt16 start = (cart.myImage[size-3] << 8) | cart.myImage[size-4]; - start -= start % 0x1000; - info << "Bank RORG" << " = $" << HEX4 << start << "\n"; -#endif - int xpos = 2, - ypos = addBaseInformation(size, "Parker Brothers", info) + myLineHeight; + info << "E0 cartridge,\n eight 1K banks mapped into four segments\n"; + info << CartEnhancedWidget::description(); - VariantList items0, items1, items2; - for(int i = 0; i < 8; ++i) + return info.str(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartridgeE0Widget::romDescription() +{ + ostringstream info; + + for(int seg = 0; seg < 4; ++seg) { - VarList::push_back(items0, seg0[i]); - VarList::push_back(items1, seg1[i]); - VarList::push_back(items2, seg2[i]); + uInt16 segmentOffset = seg << 10; // myCart.myBankShift; + + info << "Segment #" << seg << " accessible @ $" + << Common::Base::HEX4 << (ADDR_BASE | segmentOffset) + << " - $" << (ADDR_BASE | segmentOffset + /*myCart.myBankSize - 1*/ 0x3FF) << ",\n"; + if (seg < 3) + info << " Hotspots " << hotspotStr(0, seg) << " - " << hotspotStr(7, seg) << "\n"; + else + info << " Always points to last 1K bank of ROM\n"; } + info << "Startup banks = 4 / 5 / 6 or undetermined"; - const int lwidth = _font.getStringWidth("Set slice for segment X "); - mySlice0 = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("7 ($FFF7)"), - myLineHeight, items0, "Set slice for segment 0 ", - lwidth, kSlice0Changed); - mySlice0->setTarget(this); - addFocusWidget(mySlice0); - ypos += mySlice0->getHeight() + 4; - - mySlice1 = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("7 ($FFF7)"), - myLineHeight, items1, "Set slice for segment 1 ", - lwidth, kSlice1Changed); - mySlice1->setTarget(this); - addFocusWidget(mySlice1); - ypos += mySlice1->getHeight() + 4; - - mySlice2 = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("7 ($FFF7)"), - myLineHeight, items2, "Set slice for segment 2 ", - lwidth, kSlice2Changed); - mySlice2->setTarget(this); - addFocusWidget(mySlice2); + return info.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeE0Widget::loadConfig() +string CartridgeE0Widget::hotspotStr(int bank, int segment) { - mySlice0->setSelectedIndex(myCart.getSegmentBank(0)); - mySlice1->setSelectedIndex(myCart.getSegmentBank(1)); - mySlice2->setSelectedIndex(myCart.getSegmentBank(2)); + ostringstream info; + uInt16 hotspot = myCart.hotspot(); - CartDebugWidget::loadConfig(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeE0Widget::handleCommand(CommandSender* sender, - int cmd, int data, int id) -{ - myCart.unlockBank(); - - switch(cmd) - { - case kSlice0Changed: - myCart.bank(mySlice0->getSelected(), 0); - break; - case kSlice1Changed: - myCart.bank(mySlice1->getSelected(), 1); - break; - case kSlice2Changed: - myCart.bank(mySlice2->getSelected(), 2); - break; - default: - break; - } - - myCart.lockBank(); - invalidate(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeE0Widget::bankState() -{ - ostringstream& buf = buffer(); - - buf << "Slices: " << std::dec - << seg0[myCart.getSegmentBank(0)] << " / " - << seg1[myCart.getSegmentBank(1)] << " / " - << seg2[myCart.getSegmentBank(2)]; - - return buf.str(); + if(hotspot & 0x1000) + hotspot |= ADDR_BASE; + + info << "$" << Common::Base::HEX1 << (hotspot + bank + segment * 8); + + return info.str(); } diff --git a/src/debugger/gui/CartE0Widget.hxx b/src/debugger/gui/CartE0Widget.hxx index bdbe73182..fe3e9d374 100644 --- a/src/debugger/gui/CartE0Widget.hxx +++ b/src/debugger/gui/CartE0Widget.hxx @@ -19,11 +19,10 @@ #define CARTRIDGEE0_WIDGET_HXX class CartridgeE0; -class PopUpWidget; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class CartridgeE0Widget : public CartDebugWidget +class CartridgeE0Widget : public CartEnhancedWidget { public: CartridgeE0Widget(GuiObject* boss, const GUI::Font& lfont, @@ -33,21 +32,16 @@ class CartridgeE0Widget : public CartDebugWidget virtual ~CartridgeE0Widget() = default; private: - CartridgeE0& myCart; - PopUpWidget *mySlice0{nullptr}, *mySlice1{nullptr}, *mySlice2{nullptr}; + string manufacturer() override { return "Parker Brothers"; } - enum { - kSlice0Changed = 's0CH', - kSlice1Changed = 's1CH', - kSlice2Changed = 's2CH' - }; + string description() override; + string romDescription() override; + + string hotspotStr(int bank, int segment) override; + + int bankSegs() override { return 3; } private: - void loadConfig() override; - void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - - string bankState() override; - // Following constructors and assignment operators not supported CartridgeE0Widget() = delete; CartridgeE0Widget(const CartridgeE0Widget&) = delete; diff --git a/src/debugger/gui/CartEnhancedWidget.cxx b/src/debugger/gui/CartEnhancedWidget.cxx new file mode 100644 index 000000000..39732fc80 --- /dev/null +++ b/src/debugger/gui/CartEnhancedWidget.cxx @@ -0,0 +1,344 @@ +//============================================================================ +// +// 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 "PopUpWidget.hxx" +#include "CartEnhanced.hxx" +#include "CartEnhancedWidget.hxx" + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +CartEnhancedWidget::CartEnhancedWidget(GuiObject* boss, const GUI::Font& lfont, + const GUI::Font& nfont, + int x, int y, int w, int h, + CartridgeEnhanced& cart) + : CartDebugWidget(boss, lfont, nfont, x, y, w, h), + myCart(cart) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void CartEnhancedWidget::initialize() +{ + int ypos = addBaseInformation(size(), manufacturer(), description(), descriptionLines()) + + myLineHeight; + + bankSelect(ypos); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +size_t CartEnhancedWidget::size() +{ + size_t size; + + myCart.getImage(size); + + return size; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartEnhancedWidget::description() +{ + ostringstream info; + + if (myCart.myRamSize > 0) + info << ramDescription(); + info << romDescription(); + + return info.str(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int CartEnhancedWidget::descriptionLines() +{ + return 20; // should be enough for almost all types +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartEnhancedWidget::ramDescription() +{ + ostringstream info; + + info << myCart.myRamSize << " bytes RAM @ " + << "$" << Common::Base::HEX4 << ADDR_BASE << " - " + << "$" << (ADDR_BASE | (myCart.myRamSize * 2 - 1)) << "\n" + << " $" << (ADDR_BASE | myCart.myReadOffset) + << " - $" << (ADDR_BASE | (myCart.myReadOffset + myCart.myRamSize - 1)) << " (R)" + << ", $" << (ADDR_BASE | myCart.myWriteOffset) + << " - $" << (ADDR_BASE | (myCart.myWriteOffset + myCart.myRamSize - 1)) << " (W)\n"; + + return info.str(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartEnhancedWidget::romDescription() +{ + ostringstream info; + size_t size; + const uInt8* image = myCart.getImage(size); + + if(myCart.romBankCount() > 1) + { + info << "Startup bank = #" << myCart.startBank() << " or undetermined\n"; + for(int bank = 0, offset = 0xFFC; bank < myCart.romBankCount(); ++bank, offset += 0x1000) + { + uInt16 start = (image[offset + 1] << 8) | image[offset]; + start -= start % 0x1000; + + info << "Bank #" << bank << " @ $" + << Common::Base::HEX4 << (start + myCart.myRomOffset) << " - $" << (start + 0xFFF) + << " (hotspot " << hotspotStr(bank) << ")\n"; + } + } + else + { + uInt16 start = (image[myCart.mySize - 3] << 8) | image[myCart.mySize - 4]; + start -= start % std::min(int(size), 0x1000); + + info << "ROM accessible @ $" + << Common::Base::HEX4 << (start + myCart.myRomOffset) << " - " + << "$" << Common::Base::HEX4 << (start + myCart.mySize - 1); + } + + return info.str(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void CartEnhancedWidget::bankSelect(int& ypos) +{ + if(myCart.romBankCount() > 1) + { + int xpos = 2; + + myBankWidgets = make_unique(bankSegs()); + + for(int seg = 0; seg < bankSegs(); ++seg) + { + // fill bank and hotspot list + uInt16 hotspot = myCart.hotspot(); + VariantList items; + int pw = 0; + + for(int bank = 0; bank < myCart.romBankCount(); ++bank) + { + ostringstream buf; + + buf << std::setw(bank < 10 ? 2 : 1) << "#" << std::dec << bank; + if(hotspot >= 0x100 && myHotspotDelta > 0) + buf << " (" << hotspotStr(bank, seg) << ")"; + VarList::push_back(items, buf.str()); + pw = std::max(pw, _font.getStringWidth(buf.str())); + } + + // create widgets + ostringstream buf; + + buf << "Set bank"; + if(bankSegs() > 1) + buf << " for segment #" << seg << " "; + else + buf << " "; // align with info + + myBankWidgets[seg] = new PopUpWidget(_boss, _font, xpos, ypos - 2, + pw, myLineHeight, items, buf.str(), + 0, kBankChanged); + myBankWidgets[seg]->setTarget(this); + myBankWidgets[seg]->setID(seg); + addFocusWidget(myBankWidgets[seg]); + + ypos += myBankWidgets[seg]->getHeight() + 4; + } + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartEnhancedWidget::bankState() +{ + if(myCart.romBankCount() > 1) + { + ostringstream& buf = buffer(); + uInt16 hotspot = myCart.hotspot(); + bool hasRamBanks = myCart.myRamBankCount > 0; + + if(bankSegs() > 1) + { + buf << "Segments: "; + + for(int seg = 0; seg < bankSegs(); ++seg) + { + int bank = myCart.getSegmentBank(seg); + bool isRamBank = (bank >= myCart.romBankCount()); + + + if(seg > 0) + buf << " / "; + + buf << "#" << std::dec << (bank - (isRamBank ? myCart.romBankCount() : 0)); + + if(isRamBank) // was RAM mapped here? + buf << " RAM"; + else if (hasRamBanks) + buf << " ROM"; + + if(hotspot >= 0x100) + buf << " (" << (bankSegs() < 3 ? "hotspot " : "") << hotspotStr(bank) << ")"; + } + } + else + { + buf << "Bank #" << std::dec << myCart.getBank(); + + if(hotspot >= 0x100) + buf << " (hotspot " << hotspotStr(myCart.getSegmentBank()) << ")"; + } + return buf.str(); + } + return "0 (non-bankswitched)"; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartEnhancedWidget::hotspotStr(int bank, int segment) +{ + ostringstream info; + uInt16 hotspot = myCart.hotspot(); + + if(hotspot & 0x1000) + hotspot |= ADDR_BASE; + + info << "$" << Common::Base::HEX1 << (hotspot + bank * myHotspotDelta); + + return info.str(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int CartEnhancedWidget::bankSegs() +{ + return myCart.myBankSegs; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void CartEnhancedWidget::saveOldState() +{ + myOldState.internalRam.clear(); + for(uInt32 i = 0; i < myCart.myRamSize; ++i) + myOldState.internalRam.push_back(myCart.myRAM[i]); + + myOldState.banks.clear(); + for(int seg = 0; seg < bankSegs(); ++seg) + myOldState.banks.push_back(myCart.getSegmentBank(seg)); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void CartEnhancedWidget::loadConfig() +{ + if(myBankWidgets != nullptr) + { + for(int seg = 0; seg < bankSegs(); ++seg) + myBankWidgets[seg]->setSelectedIndex(myCart.getSegmentBank(seg), + myCart.getSegmentBank(seg) != myOldState.banks[seg]); + } + CartDebugWidget::loadConfig(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void CartEnhancedWidget::handleCommand(CommandSender* sender, + int cmd, int data, int id) +{ + if(cmd == kBankChanged) + { + myCart.unlockBank(); + myCart.bank(myBankWidgets[id]->getSelected(), id); + myCart.lockBank(); + invalidate(); + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt32 CartEnhancedWidget::internalRamSize() +{ + return myCart.myRamSize; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt32 CartEnhancedWidget::internalRamRPort(int start) +{ + return ADDR_BASE + myCart.myReadOffset + start; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartEnhancedWidget::internalRamDescription() +{ + ostringstream desc; + + // order RW by addresses + if(myCart.myReadOffset <= myCart.myWriteOffset) + { + desc << "$" << Common::Base::HEX4 << (ADDR_BASE | myCart.myReadOffset) + << " - $" << (ADDR_BASE | (myCart.myReadOffset + myCart.myRamSize - 1)) + << " used for Read Access\n"; + } + + desc + << "$" << Common::Base::HEX4 << (ADDR_BASE | myCart.myWriteOffset) + << " - $" << (ADDR_BASE | (myCart.myWriteOffset + myCart.myRamSize - 1)) + << " used for Write Access"; + + if(myCart.myReadOffset > myCart.myWriteOffset) + { + desc << "\n$" << Common::Base::HEX4 << (ADDR_BASE | myCart.myReadOffset) + << " - $" << (ADDR_BASE | (myCart.myReadOffset + myCart.myRamSize - 1)) + << " used for Read Access"; + } + + return desc.str(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const ByteArray& CartEnhancedWidget::internalRamOld(int start, int count) +{ + myRamOld.clear(); + for(int i = 0; i < count; i++) + myRamOld.push_back(myOldState.internalRam[start + i]); + return myRamOld; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const ByteArray& CartEnhancedWidget::internalRamCurrent(int start, int count) +{ + myRamCurrent.clear(); + for(int i = 0; i < count; i++) + myRamCurrent.push_back(myCart.myRAM[start + i]); + return myRamCurrent; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void CartEnhancedWidget::internalRamSetValue(int addr, uInt8 value) +{ + myCart.myRAM[addr] = value; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt8 CartEnhancedWidget::internalRamGetValue(int addr) +{ + return myCart.myRAM[addr]; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartEnhancedWidget::internalRamLabel(int addr) +{ + CartDebug& dbg = instance().debugger().cartDebug(); + return dbg.getLabel(addr + ADDR_BASE + myCart.myReadOffset, false); +} diff --git a/src/debugger/gui/CartEnhancedWidget.hxx b/src/debugger/gui/CartEnhancedWidget.hxx new file mode 100644 index 000000000..3bff6350a --- /dev/null +++ b/src/debugger/gui/CartEnhancedWidget.hxx @@ -0,0 +1,108 @@ +//============================================================================ +// +// 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 CART_ENHANCED_WIDGET_HXX +#define CART_ENHANCED_WIDGET_HXX + +class CartridgeEnhanced; +class PopUpWidget; + +namespace GUI { + class Font; +} + +#include "CartDebugWidget.hxx" + +class CartEnhancedWidget : public CartDebugWidget +{ + public: + CartEnhancedWidget(GuiObject* boss, const GUI::Font& lfont, + const GUI::Font& nfont, + int x, int y, int w, int h, + CartridgeEnhanced& cart); + virtual ~CartEnhancedWidget() = default; + + protected: + void initialize(); + + virtual size_t size(); + + virtual string manufacturer() = 0; + + virtual string description(); + + virtual int descriptionLines(); + + virtual string ramDescription(); + + virtual string romDescription(); + + virtual void bankSelect(int& ypos); + + virtual string hotspotStr(int bank, int segment = 0); + + virtual int bankSegs(); // { return myCart.myBankSegs; } + + void saveOldState() override; + void loadConfig() override; + + void handleCommand(CommandSender* sender, int cmd, int data, int id) override; + + string bankState() override; + + // start of functions for Cartridge RAM tab + uInt32 internalRamSize() override; + uInt32 internalRamRPort(int start) override; + string internalRamDescription() override; + const ByteArray& internalRamOld(int start, int count) override; + const ByteArray& internalRamCurrent(int start, int count) override; + void internalRamSetValue(int addr, uInt8 value) override; + uInt8 internalRamGetValue(int addr) override; + string internalRamLabel(int addr) override; + // end of functions for Cartridge RAM tab + + protected: + enum { kBankChanged = 'bkCH' }; + + struct CartState { + ByteArray internalRam; + ByteArray banks; + }; + CartState myOldState; + + CartridgeEnhanced& myCart; + + // Distance between two hotspots + int myHotspotDelta{1}; + + std::unique_ptr myBankWidgets{nullptr}; + + + // Display all addresses based on this + static constexpr uInt16 ADDR_BASE = 0xF000; + + private: + // Following constructors and assignment operators not supported + CartEnhancedWidget() = delete; + CartEnhancedWidget(const CartEnhancedWidget&) = delete; + CartEnhancedWidget(CartEnhancedWidget&&) = delete; + CartEnhancedWidget& operator=(const CartEnhancedWidget&) = delete; + CartEnhancedWidget& operator=(CartEnhancedWidget&&) = delete; +}; + +#endif + diff --git a/src/debugger/gui/CartF0Widget.cxx b/src/debugger/gui/CartF0Widget.cxx index c7564cefa..c4826249e 100644 --- a/src/debugger/gui/CartF0Widget.cxx +++ b/src/debugger/gui/CartF0Widget.cxx @@ -16,85 +16,28 @@ //============================================================================ #include "CartF0.hxx" -#include "PopUpWidget.hxx" #include "CartF0Widget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF0Widget::CartridgeF0Widget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeF0& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) + : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { - uInt32 size = 16 * 4096; + myHotspotDelta = 0; + initialize(); +} +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartridgeF0Widget::description() +{ ostringstream info; - info << "64K Megaboy F0 cartridge, 16 4K banks\n" - << "Startup bank = #" << cart.startBank() << " or undetermined\n" - << "Bankswitch triggered by accessing $1FF0\n"; - // Eventually, we should query this from the debugger/disassembler - for(uInt32 i = 0, offset = 0xFFC; i < 16; ++i, offset += 0x1000) - { - uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; - start -= start % 0x1000; - info << "Bank " << std::dec << i << " @ $" << Common::Base::HEX4 << start - << " - " << "$" << (start + 0xFFF) << "\n"; - } + info << "Megaboy F0 cartridge, 16 4K banks\n" + << "Startup bank = #" << myCart.startBank() << " or undetermined\n" + << "Bankswitch triggered by accessing $" << Common::Base::HEX4 << 0xFFF0 << "\n"; - int xpos = 2, - ypos = addBaseInformation(size, "Dynacom Megaboy", - info.str()) + myLineHeight; - - VariantList items; - VarList::push_back(items, " 0"); - VarList::push_back(items, " 1"); - VarList::push_back(items, " 2"); - VarList::push_back(items, " 3"); - VarList::push_back(items, " 4"); - VarList::push_back(items, " 5"); - VarList::push_back(items, " 6"); - VarList::push_back(items, " 7"); - VarList::push_back(items, " 8"); - VarList::push_back(items, " 9"); - VarList::push_back(items, " 10"); - VarList::push_back(items, " 11"); - VarList::push_back(items, " 12"); - VarList::push_back(items, " 13"); - VarList::push_back(items, " 14"); - VarList::push_back(items, " 15"); - myBank = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth(" 15"), - myLineHeight, items, "Set bank #", - 0, kBankChanged); - myBank->setTarget(this); - addFocusWidget(myBank); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF0Widget::loadConfig() -{ - Debugger& dbg = instance().debugger(); - CartDebug& cart = dbg.cartDebug(); - const CartState& state = static_cast(cart.getState()); - const CartState& oldstate = static_cast(cart.getOldState()); - - myBank->setSelectedIndex(myCart.getBank(), state.bank != oldstate.bank); - - CartDebugWidget::loadConfig(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF0Widget::handleCommand(CommandSender* sender, - int cmd, int data, int id) -{ - if(cmd == kBankChanged) - { - myCart.unlockBank(); - myCart.bank(myBank->getSelected()); - myCart.lockBank(); - invalidate(); - } + return info.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -102,7 +45,8 @@ string CartridgeF0Widget::bankState() { ostringstream& buf = buffer(); - buf << "Bank = #" << std::dec << myCart.getBank() << ", hotspot = $FFF0"; + buf << "Bank #" << std::dec << myCart.getBank() + << " (hotspot $" << Common::Base::HEX4 << 0xFFF0 << ")"; return buf.str(); } diff --git a/src/debugger/gui/CartF0Widget.hxx b/src/debugger/gui/CartF0Widget.hxx index 6225fff71..b7aa701bc 100644 --- a/src/debugger/gui/CartF0Widget.hxx +++ b/src/debugger/gui/CartF0Widget.hxx @@ -19,11 +19,10 @@ #define CARTRIDGEF0_WIDGET_HXX class CartridgeF0; -class PopUpWidget; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class CartridgeF0Widget : public CartDebugWidget +class CartridgeF0Widget : public CartEnhancedWidget { public: CartridgeF0Widget(GuiObject* boss, const GUI::Font& lfont, @@ -33,17 +32,13 @@ class CartridgeF0Widget : public CartDebugWidget virtual ~CartridgeF0Widget() = default; private: - CartridgeF0& myCart; - PopUpWidget* myBank{nullptr}; + string manufacturer() override { return "Dynacom Megaboy"; } - enum { kBankChanged = 'bkCH' }; - - private: - void loadConfig() override; - void handleCommand(CommandSender* sender, int cmd, int data, int id) override; + string description() override; string bankState() override; +private: // Following constructors and assignment operators not supported CartridgeF0Widget() = delete; CartridgeF0Widget(const CartridgeF0Widget&) = delete; diff --git a/src/debugger/gui/CartF4SCWidget.cxx b/src/debugger/gui/CartF4SCWidget.cxx index 512edba55..b85251cbe 100644 --- a/src/debugger/gui/CartF4SCWidget.cxx +++ b/src/debugger/gui/CartF4SCWidget.cxx @@ -15,157 +15,25 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#include "Debugger.hxx" -#include "CartDebug.hxx" #include "CartF4SC.hxx" -#include "PopUpWidget.hxx" #include "CartF4SCWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF4SCWidget::CartridgeF4SCWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeF4SC& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) + : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { - uInt16 size = 8 * 4096; + initialize(); +} +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartridgeF4SCWidget::description() +{ ostringstream info; - info << "Standard F4SC cartridge, eight 4K banks\n" - << "128 bytes RAM @ $F000 - $F0FF\n" - << " $F080 - $F0FF (R), $F000 - $F07F (W)\n" - << "Startup bank = " << cart.startBank() << " or undetermined\n"; - // Eventually, we should query this from the debugger/disassembler - for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF4; i < 8; ++i, offset += 0x1000) - { - uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; - start -= start % 0x1000; - info << "Bank " << i << " @ $" << Common::Base::HEX4 << (start + 0x100) << " - " - << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; - } + info << "Standard F4SC cartridge, eight 4K banks\n"; + info << CartEnhancedWidget::description(); - int xpos = 2, - ypos = addBaseInformation(size, "Atari", info.str(), 15) + myLineHeight; - - VariantList items; - VarList::push_back(items, "0 ($FFF4)"); - VarList::push_back(items, "1 ($FFF5)"); - VarList::push_back(items, "2 ($FFF6)"); - VarList::push_back(items, "3 ($FFF7)"); - VarList::push_back(items, "4 ($FFF8)"); - VarList::push_back(items, "5 ($FFF9)"); - VarList::push_back(items, "6 ($FFFA)"); - VarList::push_back(items, "7 ($FFFB)"); - myBank = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFFx)"), - myLineHeight, items, "Set bank ", - 0, kBankChanged); - myBank->setTarget(this); - addFocusWidget(myBank); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF4SCWidget::saveOldState() -{ - myOldState.internalram.clear(); - - for(uInt32 i = 0; i < internalRamSize(); ++i) - myOldState.internalram.push_back(myCart.myRAM[i]); - - myOldState.bank = myCart.getBank(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF4SCWidget::loadConfig() -{ - myBank->setSelectedIndex(myCart.getBank(), myCart.getBank() != myOldState.bank); - - CartDebugWidget::loadConfig(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF4SCWidget::handleCommand(CommandSender* sender, - int cmd, int data, int id) -{ - if(cmd == kBankChanged) - { - myCart.unlockBank(); - myCart.bank(myBank->getSelected()); - myCart.lockBank(); - invalidate(); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeF4SCWidget::bankState() -{ - ostringstream& buf = buffer(); - - static constexpr std::array spot = { - "$FFF4", "$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB" - }; - buf << "Bank = " << std::dec << myCart.getBank() - << ", hotspot = " << spot[myCart.getBank()]; - - return buf.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 CartridgeF4SCWidget::internalRamSize() -{ - return 128; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 CartridgeF4SCWidget::internalRamRPort(int start) -{ - return 0xF080 + start; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeF4SCWidget::internalRamDescription() -{ - ostringstream desc; - desc << "$F000 - $F07F used for Write Access\n" - << "$F080 - $F0FF used for Read Access"; - - return desc.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& CartridgeF4SCWidget::internalRamOld(int start, int count) -{ - myRamOld.clear(); - for(int i = 0; i < count; i++) - myRamOld.push_back(myOldState.internalram[start + i]); - return myRamOld; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& CartridgeF4SCWidget::internalRamCurrent(int start, int count) -{ - myRamCurrent.clear(); - for(int i = 0; i < count; i++) - myRamCurrent.push_back(myCart.myRAM[start + i]); - return myRamCurrent; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF4SCWidget::internalRamSetValue(int addr, uInt8 value) -{ - myCart.myRAM[addr] = value; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeF4SCWidget::internalRamGetValue(int addr) -{ - return myCart.myRAM[addr]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeF4SCWidget::internalRamLabel(int addr) -{ - CartDebug& dbg = instance().debugger().cartDebug(); - return dbg.getLabel(addr + 0xF080, false); + return info.str(); } diff --git a/src/debugger/gui/CartF4SCWidget.hxx b/src/debugger/gui/CartF4SCWidget.hxx index e2ec21f06..8c22c6d74 100644 --- a/src/debugger/gui/CartF4SCWidget.hxx +++ b/src/debugger/gui/CartF4SCWidget.hxx @@ -19,11 +19,10 @@ #define CARTRIDGEF4SC_WIDGET_HXX class CartridgeF4SC; -class PopUpWidget; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class CartridgeF4SCWidget : public CartDebugWidget +class CartridgeF4SCWidget : public CartEnhancedWidget { public: CartridgeF4SCWidget(GuiObject* boss, const GUI::Font& lfont, @@ -33,36 +32,11 @@ class CartridgeF4SCWidget : public CartDebugWidget virtual ~CartridgeF4SCWidget() = default; private: - CartridgeF4SC& myCart; - PopUpWidget* myBank{nullptr}; + string manufacturer() override { return "Atari"; } - struct CartState { - ByteArray internalram; - uInt16 bank{0}; - }; - CartState myOldState; - - - enum { kBankChanged = 'bkCH' }; + string description() override; private: - void saveOldState() override; - void loadConfig() override; - void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - - string bankState() override; - - // start of functions for Cartridge RAM tab - uInt32 internalRamSize() override; - uInt32 internalRamRPort(int start) override; - string internalRamDescription() override; - const ByteArray& internalRamOld(int start, int count) override; - const ByteArray& internalRamCurrent(int start, int count) override; - void internalRamSetValue(int addr, uInt8 value) override; - uInt8 internalRamGetValue(int addr) override; - string internalRamLabel(int addr) override; - // end of functions for Cartridge RAM tab - // Following constructors and assignment operators not supported CartridgeF4SCWidget() = delete; CartridgeF4SCWidget(const CartridgeF4SCWidget&) = delete; diff --git a/src/debugger/gui/CartF4Widget.cxx b/src/debugger/gui/CartF4Widget.cxx index 3d5848cd0..ae884cfa9 100644 --- a/src/debugger/gui/CartF4Widget.cxx +++ b/src/debugger/gui/CartF4Widget.cxx @@ -16,87 +16,24 @@ //============================================================================ #include "CartF4.hxx" -#include "PopUpWidget.hxx" #include "CartF4Widget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF4Widget::CartridgeF4Widget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeF4& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) + : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { - uInt16 size = 8 * 4096; + initialize(); +} +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartridgeF4Widget::description() +{ ostringstream info; - info << "Standard F4 cartridge, eight 4K banks\n" - << "Startup bank = " << cart.startBank() << " or undetermined\n"; - // Eventually, we should query this from the debugger/disassembler - for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF4; i < 8; ++i, offset += 0x1000) - { - uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; - start -= start % 0x1000; - info << "Bank " << i << " @ $" << Common::Base::HEX4 << start << " - " - << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; - } + info << "Standard F4 cartridge, eight 4K banks\n"; + info << CartEnhancedWidget::description(); - int xpos = 2, - ypos = addBaseInformation(size, "Atari", info.str(), 15) + myLineHeight; - - VariantList items; - VarList::push_back(items, "0 ($FFF4)"); - VarList::push_back(items, "1 ($FFF5)"); - VarList::push_back(items, "2 ($FFF6)"); - VarList::push_back(items, "3 ($FFF7)"); - VarList::push_back(items, "4 ($FFF8)"); - VarList::push_back(items, "5 ($FFF9)"); - VarList::push_back(items, "6 ($FFFA)"); - VarList::push_back(items, "7 ($FFFB)"); - myBank = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFFx)"), - myLineHeight, items, "Set bank ", - 0, kBankChanged); - myBank->setTarget(this); - addFocusWidget(myBank); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF4Widget::loadConfig() -{ - Debugger& dbg = instance().debugger(); - CartDebug& cart = dbg.cartDebug(); - const CartState& state = static_cast(cart.getState()); - const CartState& oldstate = static_cast(cart.getOldState()); - - myBank->setSelectedIndex(myCart.getBank(), state.bank != oldstate.bank); - - CartDebugWidget::loadConfig(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF4Widget::handleCommand(CommandSender* sender, - int cmd, int data, int id) -{ - if(cmd == kBankChanged) - { - myCart.unlockBank(); - myCart.bank(myBank->getSelected()); - myCart.lockBank(); - invalidate(); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeF4Widget::bankState() -{ - ostringstream& buf = buffer(); - - static constexpr std::array spot = { - "$FFF4", "$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB" - }; - buf << "Bank = " << std::dec << myCart.getBank() - << ", hotspot = " << spot[myCart.getBank()]; - - return buf.str(); + return info.str(); } diff --git a/src/debugger/gui/CartF4Widget.hxx b/src/debugger/gui/CartF4Widget.hxx index 7487a1b4b..2201b246b 100644 --- a/src/debugger/gui/CartF4Widget.hxx +++ b/src/debugger/gui/CartF4Widget.hxx @@ -19,11 +19,10 @@ #define CARTRIDGEF4_WIDGET_HXX class CartridgeF4; -class PopUpWidget; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class CartridgeF4Widget : public CartDebugWidget +class CartridgeF4Widget : public CartEnhancedWidget { public: CartridgeF4Widget(GuiObject* boss, const GUI::Font& lfont, @@ -33,17 +32,11 @@ class CartridgeF4Widget : public CartDebugWidget virtual ~CartridgeF4Widget() = default; private: - CartridgeF4& myCart; - PopUpWidget* myBank{nullptr}; + string manufacturer() override { return "Atari"; } - enum { kBankChanged = 'bkCH' }; + string description() override; private: - void loadConfig() override; - void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - - string bankState() override; - // Following constructors and assignment operators not supported CartridgeF4Widget() = delete; CartridgeF4Widget(const CartridgeF4Widget&) = delete; diff --git a/src/debugger/gui/CartF6SCWidget.cxx b/src/debugger/gui/CartF6SCWidget.cxx index 863ff2948..bfa99b5c5 100644 --- a/src/debugger/gui/CartF6SCWidget.cxx +++ b/src/debugger/gui/CartF6SCWidget.cxx @@ -15,151 +15,25 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#include "Debugger.hxx" -#include "CartDebug.hxx" #include "CartF6SC.hxx" -#include "PopUpWidget.hxx" #include "CartF6SCWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF6SCWidget::CartridgeF6SCWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeF6SC& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) + : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { - uInt16 size = 4 * 4096; + initialize(); +} +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartridgeF6SCWidget::description() +{ ostringstream info; - info << "Standard F6SC cartridge, four 4K banks\n" - << "128 bytes RAM @ $F000 - $F0FF\n" - << " $F080 - $F0FF (R), $F000 - $F07F (W)\n" - << "Startup bank = " << cart.startBank() << " or undetermined\n"; - // Eventually, we should query this from the debugger/disassembler - for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF6; i < 4; ++i, offset += 0x1000) - { - uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; - start -= start % 0x1000; - info << "Bank " << i << " @ $" << Common::Base::HEX4 << (start + 0x100) << " - " - << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; - } + info << "Standard F6SC cartridge, four 4K banks\n"; + info << CartEnhancedWidget::description(); - int xpos = 2, - ypos = addBaseInformation(size, "Atari", info.str()) + myLineHeight; - - VariantList items; - VarList::push_back(items, "0 ($FFF6)"); - VarList::push_back(items, "1 ($FFF7)"); - VarList::push_back(items, "2 ($FFF8)"); - VarList::push_back(items, "3 ($FFF9)"); - myBank = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFFx)"), - myLineHeight, items, "Set bank ", - 0, kBankChanged); - myBank->setTarget(this); - addFocusWidget(myBank); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF6SCWidget::saveOldState() -{ - myOldState.internalram.clear(); - - for(uInt32 i = 0; i < internalRamSize(); ++i) - myOldState.internalram.push_back(myCart.myRAM[i]); - - myOldState.bank = myCart.getBank(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF6SCWidget::loadConfig() -{ - myBank->setSelectedIndex(myCart.getBank(), myCart.getBank() != myOldState.bank); - - CartDebugWidget::loadConfig(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF6SCWidget::handleCommand(CommandSender* sender, - int cmd, int data, int id) -{ - if(cmd == kBankChanged) - { - myCart.unlockBank(); - myCart.bank(myBank->getSelected()); - myCart.lockBank(); - invalidate(); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeF6SCWidget::bankState() -{ - ostringstream& buf = buffer(); - - static constexpr std::array spot = { "$FFF6", "$FFF7", "$FFF8", "$FFF9" }; - buf << "Bank = " << std::dec << myCart.getBank() - << ", hotspot = " << spot[myCart.getBank()]; - - return buf.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 CartridgeF6SCWidget::internalRamSize() -{ - return 128; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 CartridgeF6SCWidget::internalRamRPort(int start) -{ - return 0xF080 + start; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeF6SCWidget::internalRamDescription() -{ - ostringstream desc; - desc << "$F000 - $F07F used for Write Access\n" - << "$F080 - $F0FF used for Read Access"; - - return desc.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& CartridgeF6SCWidget::internalRamOld(int start, int count) -{ - myRamOld.clear(); - for(int i = 0; i < count; i++) - myRamOld.push_back(myOldState.internalram[start + i]); - return myRamOld; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& CartridgeF6SCWidget::internalRamCurrent(int start, int count) -{ - myRamCurrent.clear(); - for(int i = 0; i < count; i++) - myRamCurrent.push_back(myCart.myRAM[start + i]); - return myRamCurrent; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF6SCWidget::internalRamSetValue(int addr, uInt8 value) -{ - myCart.myRAM[addr] = value; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeF6SCWidget::internalRamGetValue(int addr) -{ - return myCart.myRAM[addr]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeF6SCWidget::internalRamLabel(int addr) -{ - CartDebug& dbg = instance().debugger().cartDebug(); - return dbg.getLabel(addr + 0xF080, false); + return info.str(); } diff --git a/src/debugger/gui/CartF6SCWidget.hxx b/src/debugger/gui/CartF6SCWidget.hxx index deee0e836..6b0aab9f8 100644 --- a/src/debugger/gui/CartF6SCWidget.hxx +++ b/src/debugger/gui/CartF6SCWidget.hxx @@ -19,11 +19,10 @@ #define CARTRIDGEF6SC_WIDGET_HXX class CartridgeF6SC; -class PopUpWidget; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class CartridgeF6SCWidget : public CartDebugWidget +class CartridgeF6SCWidget : public CartEnhancedWidget { public: CartridgeF6SCWidget(GuiObject* boss, const GUI::Font& lfont, @@ -33,34 +32,11 @@ class CartridgeF6SCWidget : public CartDebugWidget virtual ~CartridgeF6SCWidget() = default; private: - struct CartState { - ByteArray internalram; - uInt16 bank{0}; - }; - CartridgeF6SC& myCart; - PopUpWidget* myBank{nullptr}; - CartState myOldState; + string manufacturer() override { return "Atari"; } - enum { kBankChanged = 'bkCH' }; + string description() override; private: - void saveOldState() override; - void loadConfig() override; - void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - - string bankState() override; - - // start of functions for Cartridge RAM tab - uInt32 internalRamSize() override; - uInt32 internalRamRPort(int start) override; - string internalRamDescription() override; - const ByteArray& internalRamOld(int start, int count) override; - const ByteArray& internalRamCurrent(int start, int count) override; - void internalRamSetValue(int addr, uInt8 value) override; - uInt8 internalRamGetValue(int addr) override; - string internalRamLabel(int addr) override; - // end of functions for Cartridge RAM tab - // Following constructors and assignment operators not supported CartridgeF6SCWidget() = delete; CartridgeF6SCWidget(const CartridgeF6SCWidget&) = delete; diff --git a/src/debugger/gui/CartF6Widget.cxx b/src/debugger/gui/CartF6Widget.cxx index 114d20e18..692c40258 100644 --- a/src/debugger/gui/CartF6Widget.cxx +++ b/src/debugger/gui/CartF6Widget.cxx @@ -16,81 +16,24 @@ //============================================================================ #include "CartF6.hxx" -#include "PopUpWidget.hxx" #include "CartF6Widget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF6Widget::CartridgeF6Widget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeF6& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) + : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { - uInt16 size = 4 * 4096; + initialize(); +} +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartridgeF6Widget::description() +{ ostringstream info; - info << "Standard F6 cartridge, four 4K banks\n" - << "Startup bank = " << cart.startBank() << " or undetermined\n"; - // Eventually, we should query this from the debugger/disassembler - for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF6; i < 4; ++i, offset += 0x1000) - { - uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; - start -= start % 0x1000; - info << "Bank " << i << " @ $" << Common::Base::HEX4 << start << " - " - << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; - } + info << "Standard F6 cartridge, four 4K banks\n"; + info << CartEnhancedWidget::description(); - int xpos = 2, - ypos = addBaseInformation(size, "Atari", info.str()) + myLineHeight; - - VariantList items; - VarList::push_back(items, "0 ($FFF6)"); - VarList::push_back(items, "1 ($FFF7)"); - VarList::push_back(items, "2 ($FFF8)"); - VarList::push_back(items, "3 ($FFF9)"); - myBank = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFFx) "), - myLineHeight, items, "Set bank ", - 0, kBankChanged); - myBank->setTarget(this); - addFocusWidget(myBank); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF6Widget::loadConfig() -{ - Debugger& dbg = instance().debugger(); - CartDebug& cart = dbg.cartDebug(); - const CartState& state = static_cast(cart.getState()); - const CartState& oldstate = static_cast(cart.getOldState()); - - myBank->setSelectedIndex(myCart.getBank(), state.bank != oldstate.bank); - - CartDebugWidget::loadConfig(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF6Widget::handleCommand(CommandSender* sender, - int cmd, int data, int id) -{ - if(cmd == kBankChanged) - { - myCart.unlockBank(); - myCart.bank(myBank->getSelected()); - myCart.lockBank(); - invalidate(); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeF6Widget::bankState() -{ - ostringstream& buf = buffer(); - - static constexpr std::array spot = { "$FFF6", "$FFF7", "$FFF8", "$FFF9" }; - buf << "Bank = " << std::dec << myCart.getBank() - << ", hotspot = " << spot[myCart.getBank()]; - - return buf.str(); + return info.str(); } diff --git a/src/debugger/gui/CartF6Widget.hxx b/src/debugger/gui/CartF6Widget.hxx index 392eb6a0c..e36933ac7 100644 --- a/src/debugger/gui/CartF6Widget.hxx +++ b/src/debugger/gui/CartF6Widget.hxx @@ -19,11 +19,10 @@ #define CARTRIDGEF6_WIDGET_HXX class CartridgeF6; -class PopUpWidget; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class CartridgeF6Widget : public CartDebugWidget +class CartridgeF6Widget : public CartEnhancedWidget { public: CartridgeF6Widget(GuiObject* boss, const GUI::Font& lfont, @@ -33,17 +32,11 @@ class CartridgeF6Widget : public CartDebugWidget virtual ~CartridgeF6Widget() = default; private: - CartridgeF6& myCart; - PopUpWidget* myBank{nullptr}; + string manufacturer() override { return "Atari"; } - enum { kBankChanged = 'bkCH' }; + string description() override; private: - void loadConfig() override; - void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - - string bankState() override; - // Following constructors and assignment operators not supported CartridgeF6Widget() = delete; CartridgeF6Widget(const CartridgeF6Widget&) = delete; diff --git a/src/debugger/gui/CartF8SCWidget.cxx b/src/debugger/gui/CartF8SCWidget.cxx index 1f432e224..78e1c70a9 100644 --- a/src/debugger/gui/CartF8SCWidget.cxx +++ b/src/debugger/gui/CartF8SCWidget.cxx @@ -15,149 +15,25 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#include "Debugger.hxx" -#include "CartDebug.hxx" #include "CartF8SC.hxx" -#include "PopUpWidget.hxx" #include "CartF8SCWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF8SCWidget::CartridgeF8SCWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeF8SC& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) + : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { - uInt16 size = 8192; + initialize(); +} +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartridgeF8SCWidget::description() +{ ostringstream info; - info << "Standard F8SC cartridge, two 4K banks\n" - << "128 bytes RAM @ $F000 - $F0FF\n" - << " $F080 - $F0FF (R), $F000 - $F07F (W)\n" - << "Startup bank = " << cart.startBank() << " or undetermined\n"; - // Eventually, we should query this from the debugger/disassembler - for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF8; i < 2; ++i, offset += 0x1000) - { - uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; - start -= start % 0x1000; - info << "Bank " << i << " @ $" << Common::Base::HEX4 << (start + 0x100) << " - " - << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; - } + info << "Standard F8SC cartridge, two 4K banks\n"; + info << CartEnhancedWidget::description(); - int xpos = 2, - ypos = addBaseInformation(size, "Atari", info.str()) + myLineHeight; - - VariantList items; - VarList::push_back(items, "0 ($FFF8)"); - VarList::push_back(items, "1 ($FFF9)"); - myBank = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFFx)"), - myLineHeight, items, "Set bank ", - 0, kBankChanged); - myBank->setTarget(this); - addFocusWidget(myBank); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF8SCWidget::saveOldState() -{ - myOldState.internalram.clear(); - - for(uInt32 i = 0; i < internalRamSize(); ++i) - myOldState.internalram.push_back(myCart.myRAM[i]); - - myOldState.bank = myCart.getBank(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF8SCWidget::loadConfig() -{ - myBank->setSelectedIndex(myCart.getBank(), myCart.getBank() != myOldState.bank); - - CartDebugWidget::loadConfig(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF8SCWidget::handleCommand(CommandSender* sender, - int cmd, int data, int id) -{ - if(cmd == kBankChanged) - { - myCart.unlockBank(); - myCart.bank(myBank->getSelected()); - myCart.lockBank(); - invalidate(); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeF8SCWidget::bankState() -{ - ostringstream& buf = buffer(); - - static constexpr std::array spot = { "$FFF8", "$FFF9" }; - buf << "Bank = " << std::dec << myCart.getBank() - << ", hotspot = " << spot[myCart.getBank()]; - - return buf.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 CartridgeF8SCWidget::internalRamSize() -{ - return 128; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 CartridgeF8SCWidget::internalRamRPort(int start) -{ - return 0xF080 + start; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeF8SCWidget::internalRamDescription() -{ - ostringstream desc; - desc << "$F000 - $F07F used for Write Access\n" - << "$F080 - $F0FF used for Read Access"; - - return desc.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& CartridgeF8SCWidget::internalRamOld(int start, int count) -{ - myRamOld.clear(); - for(int i = 0; i < count; i++) - myRamOld.push_back(myOldState.internalram[start + i]); - return myRamOld; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& CartridgeF8SCWidget::internalRamCurrent(int start, int count) -{ - myRamCurrent.clear(); - for(int i = 0; i < count; i++) - myRamCurrent.push_back(myCart.myRAM[start + i]); - return myRamCurrent; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF8SCWidget::internalRamSetValue(int addr, uInt8 value) -{ - myCart.myRAM[addr] = value; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeF8SCWidget::internalRamGetValue(int addr) -{ - return myCart.myRAM[addr]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeF8SCWidget::internalRamLabel(int addr) -{ - CartDebug& dbg = instance().debugger().cartDebug(); - return dbg.getLabel(addr + 0xF080, false); + return info.str(); } diff --git a/src/debugger/gui/CartF8SCWidget.hxx b/src/debugger/gui/CartF8SCWidget.hxx index 7bebef602..3332f9a4b 100644 --- a/src/debugger/gui/CartF8SCWidget.hxx +++ b/src/debugger/gui/CartF8SCWidget.hxx @@ -19,11 +19,10 @@ #define CARTRIDGEF8SC_WIDGET_HXX class CartridgeF8SC; -class PopUpWidget; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class CartridgeF8SCWidget : public CartDebugWidget +class CartridgeF8SCWidget : public CartEnhancedWidget { public: CartridgeF8SCWidget(GuiObject* boss, const GUI::Font& lfont, @@ -33,35 +32,11 @@ class CartridgeF8SCWidget : public CartDebugWidget virtual ~CartridgeF8SCWidget() = default; private: - CartridgeF8SC& myCart; - PopUpWidget* myBank{nullptr}; + string manufacturer() override { return "Atari"; } - struct CartState { - ByteArray internalram; - uInt16 bank{0}; - }; - CartState myOldState; - - enum { kBankChanged = 'bkCH' }; + string description() override; private: - void saveOldState() override; - void loadConfig() override; - void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - - string bankState() override; - - // start of functions for Cartridge RAM tab - uInt32 internalRamSize() override; - uInt32 internalRamRPort(int start) override; - string internalRamDescription() override; - const ByteArray& internalRamOld(int start, int count) override; - const ByteArray& internalRamCurrent(int start, int count) override; - void internalRamSetValue(int addr, uInt8 value) override; - uInt8 internalRamGetValue(int addr) override; - string internalRamLabel(int addr) override; - // end of functions for Cartridge RAM tab - // Following constructors and assignment operators not supported CartridgeF8SCWidget() = delete; CartridgeF8SCWidget(const CartridgeF8SCWidget&) = delete; diff --git a/src/debugger/gui/CartF8Widget.cxx b/src/debugger/gui/CartF8Widget.cxx index ca648b5f1..ed1481b2a 100644 --- a/src/debugger/gui/CartF8Widget.cxx +++ b/src/debugger/gui/CartF8Widget.cxx @@ -16,79 +16,24 @@ //============================================================================ #include "CartF8.hxx" -#include "PopUpWidget.hxx" #include "CartF8Widget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF8Widget::CartridgeF8Widget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeF8& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) + : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { - uInt16 size = 2 * 4096; + initialize(); +} +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartridgeF8Widget::description() +{ ostringstream info; - info << "Standard F8 cartridge, two 4K banks\n" - << "Startup bank = " << cart.startBank() << " or undetermined\n"; - // Eventually, we should query this from the debugger/disassembler - for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF8; i < 2; ++i, offset += 0x1000) - { - uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; - start -= start % 0x1000; - info << "Bank " << i << " @ $" << Common::Base::HEX4 << start << " - " - << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; - } + info << "Standard F8 cartridge, two 4K banks\n"; + info << CartEnhancedWidget::description(); - int xpos = 2, - ypos = addBaseInformation(size, "Atari", info.str()) + myLineHeight; - - VariantList items; - VarList::push_back(items, "0 ($FFF8)"); - VarList::push_back(items, "1 ($FFF9)"); - myBank = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFFx)"), - myLineHeight, items, "Set bank ", - 0, kBankChanged); - myBank->setTarget(this); - addFocusWidget(myBank); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF8Widget::loadConfig() -{ - Debugger& dbg = instance().debugger(); - CartDebug& cart = dbg.cartDebug(); - const CartState& state = static_cast(cart.getState()); - const CartState& oldstate = static_cast(cart.getOldState()); - - myBank->setSelectedIndex(myCart.getBank(), state.bank != oldstate.bank); - - CartDebugWidget::loadConfig(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeF8Widget::handleCommand(CommandSender* sender, - int cmd, int data, int id) -{ - if(cmd == kBankChanged) - { - myCart.unlockBank(); - myCart.bank(myBank->getSelected()); - myCart.lockBank(); - invalidate(); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeF8Widget::bankState() -{ - ostringstream& buf = buffer(); - - static constexpr std::array spot = { "$FFF8", "$FFF9" }; - buf << "Bank = " << std::dec << myCart.getBank() - << ", hotspot = " << spot[myCart.getBank()]; - - return buf.str(); + return info.str(); } diff --git a/src/debugger/gui/CartF8Widget.hxx b/src/debugger/gui/CartF8Widget.hxx index 507ad464b..34856f2ee 100644 --- a/src/debugger/gui/CartF8Widget.hxx +++ b/src/debugger/gui/CartF8Widget.hxx @@ -21,9 +21,9 @@ class CartridgeF8; class PopUpWidget; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class CartridgeF8Widget : public CartDebugWidget +class CartridgeF8Widget : public CartEnhancedWidget { public: CartridgeF8Widget(GuiObject* boss, const GUI::Font& lfont, @@ -33,17 +33,11 @@ class CartridgeF8Widget : public CartDebugWidget virtual ~CartridgeF8Widget() = default; private: - CartridgeF8& myCart; - PopUpWidget* myBank{nullptr}; + string manufacturer() override { return "Atari"; } - enum { kBankChanged = 'bkCH' }; + string description() override; private: - void loadConfig() override; - void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - - string bankState() override; - // Following constructors and assignment operators not supported CartridgeF8Widget() = delete; CartridgeF8Widget(const CartridgeF8Widget&) = delete; diff --git a/src/debugger/gui/CartUAWidget.cxx b/src/debugger/gui/CartUAWidget.cxx index 7417d8b44..f3865b998 100644 --- a/src/debugger/gui/CartUAWidget.cxx +++ b/src/debugger/gui/CartUAWidget.cxx @@ -16,89 +16,37 @@ //============================================================================ #include "CartUA.hxx" -#include "PopUpWidget.hxx" #include "CartUAWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeUAWidget::CartridgeUAWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeUA& cart, bool swapHotspots) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart), + : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart), mySwappedHotspots(swapHotspots) { - uInt16 size = 2 * 4096; + myHotspotDelta = 0x20; + initialize(); +} +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartridgeUAWidget::description() +{ ostringstream info; - info << "8K UA cartridge" << (mySwappedHotspots ? " (swapped banks)" : "") << ", two 4K banks\n" - << "Startup bank = " << cart.startBank() << " or undetermined\n"; - // Eventually, we should query this from the debugger/disassembler - for(uInt32 i = 0, offset = 0xFFC, spot = mySwappedHotspots ? 0x240 : 0x220; i < 2; - ++i, offset += 0x1000, spot += mySwappedHotspots ? -0x20 : 0x20) - { - uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; - start -= start % 0x1000; - info << "Bank " << i << " @ $" << Common::Base::HEX4 << start << " - " - << "$" << (start + 0xFFF) << " (hotspots = $" << spot << ", $" << (spot | 0x80) << ")\n"; - } + info << "8K UA cartridge" << (mySwappedHotspots ? " (swapped banks)" : "") << ", two 4K banks\n"; + info << CartEnhancedWidget::description(); - int xpos = 2, - ypos = addBaseInformation(size, "UA Limited", info.str()) + myLineHeight; - - VariantList items; - if (swapHotspots) - { - VarList::push_back(items, "0 ($240, $2C0)"); - VarList::push_back(items, "1 ($220, $2A0)"); - } - else - { - VarList::push_back(items, "0 ($220, $2A0)"); - VarList::push_back(items, "1 ($240, $2C0)"); - } - myBank = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFx, $FFx)"), - myLineHeight, items, "Set bank ", - 0, kBankChanged); - myBank->setTarget(this); - addFocusWidget(myBank); + return info.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeUAWidget::loadConfig() +string CartridgeUAWidget::hotspotStr(int bank, int) { - Debugger& dbg = instance().debugger(); - CartDebug& cart = dbg.cartDebug(); - const CartState& state = static_cast(cart.getState()); - const CartState& oldstate = static_cast(cart.getOldState()); + ostringstream info; + uInt16 hotspot = myCart.hotspot() + (bank ^ (mySwappedHotspots ? 1 : 0)) * myHotspotDelta; - myBank->setSelectedIndex(myCart.getBank(), state.bank != oldstate.bank); + info << "$" << Common::Base::HEX1 << hotspot << ", $" << (hotspot | 0x80); - CartDebugWidget::loadConfig(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeUAWidget::handleCommand(CommandSender* sender, - int cmd, int data, int id) -{ - if(cmd == kBankChanged) - { - myCart.unlockBank(); - myCart.bank(myBank->getSelected()); - myCart.lockBank(); - invalidate(); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeUAWidget::bankState() -{ - ostringstream& buf = buffer(); - - static constexpr std::array spot = { "$220, $2A0", "$240, $2C0" }; - buf << "Bank = " << std::dec << myCart.getBank() - << ", hotspots = " << spot[myCart.getBank() ^ (mySwappedHotspots ? 1U : 0U)]; - - return buf.str(); + return info.str(); } diff --git a/src/debugger/gui/CartUAWidget.hxx b/src/debugger/gui/CartUAWidget.hxx index 346b1c1d2..bb61d25c9 100644 --- a/src/debugger/gui/CartUAWidget.hxx +++ b/src/debugger/gui/CartUAWidget.hxx @@ -19,11 +19,10 @@ #define CARTRIDGEUA_WIDGET_HXX class CartridgeUA; -class PopUpWidget; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class CartridgeUAWidget : public CartDebugWidget +class CartridgeUAWidget : public CartEnhancedWidget { public: CartridgeUAWidget(GuiObject* boss, const GUI::Font& lfont, @@ -33,19 +32,16 @@ class CartridgeUAWidget : public CartDebugWidget virtual ~CartridgeUAWidget() = default; private: - CartridgeUA& myCart; - PopUpWidget* myBank{nullptr}; + string manufacturer() override { return "UA Limited"; } - bool mySwappedHotspots; + string description() override; - enum { kBankChanged = 'bkCH' }; + string hotspotStr(int bank, int) override; private: - void loadConfig() override; - void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - - string bankState() override; + const bool mySwappedHotspots; + private: // Following constructors and assignment operators not supported CartridgeUAWidget() = delete; CartridgeUAWidget(const CartridgeUAWidget&) = delete; diff --git a/src/debugger/gui/module.mk b/src/debugger/gui/module.mk index d1ffc81c0..8f19ce5fa 100644 --- a/src/debugger/gui/module.mk +++ b/src/debugger/gui/module.mk @@ -28,6 +28,7 @@ MODULE_OBJS := \ src/debugger/gui/CartDPCPlusWidget.o \ src/debugger/gui/CartDPCWidget.o \ src/debugger/gui/CartE0Widget.o \ + src/debugger/gui/CartEnhancedWidget.o \ src/debugger/gui/CartMNetworkWidget.o \ src/debugger/gui/CartE7Widget.o \ src/debugger/gui/CartE78KWidget.o \ diff --git a/src/emucore/Cart4K.cxx b/src/emucore/Cart4K.cxx index d26ccfec0..9e684afad 100644 --- a/src/emucore/Cart4K.cxx +++ b/src/emucore/Cart4K.cxx @@ -23,5 +23,4 @@ Cartridge4K::Cartridge4K(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) : CartridgeEnhanced(image, size, md5, settings) { - cerr << "Cartridge4K" << endl; } diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index 11eb0ca75..05f954e3e 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -205,7 +205,7 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) // for ROMs < 4_KB, the whole address space will be mapped. uInt16 toAddr = (ROM_OFFSET + segmentOffset + (mySize < 4_KB ? 4_KB : myBankSize)) & ~System::PAGE_MASK; - if(hotspot != 0) + if(hotspot & 0x1000) hotSpotAddr = (hotspot & ~System::PAGE_MASK); else hotSpotAddr = 0xFFFF; // none diff --git a/src/emucore/CartEnhanced.hxx b/src/emucore/CartEnhanced.hxx index 10dbfb0d6..ecf8a0a58 100644 --- a/src/emucore/CartEnhanced.hxx +++ b/src/emucore/CartEnhanced.hxx @@ -22,6 +22,9 @@ class System; #include "bspf.hxx" #include "Cart.hxx" +#ifdef DEBUGGER_SUPPORT + #include "CartEnhancedWidget.hxx" +#endif /** Enhanced cartridge base class used for multiple cart types. @@ -30,6 +33,8 @@ class System; */ class CartridgeEnhanced : public Cartridge { + friend class CartEnhancedWidget; + public: /** Create a new cartridge using the specified image @@ -142,7 +147,6 @@ class CartridgeEnhanced : public Cartridge */ bool load(Serializer& in) override; - public: /** Get the byte at the specified address. @@ -159,19 +163,25 @@ class CartridgeEnhanced : public Cartridge */ bool poke(uInt16 address, uInt8 value) override; + /** + Get the hotspot in ROM address space. + + @return The first hotspot address (ususally in ROM) space or 0 + */ + virtual uInt16 hotspot() const { return 0; } + // TODO: handle cases where there the hotspots cover multiple pages + protected: // The '2 ^ N = bank segment size' exponent uInt16 myBankShift{BANK_SHIFT}; // default 12 (-> one 4K segment) // The size of a bank's segment - uInt16 myBankSize{0}; + uInt16 myBankSize{uInt16(4_KB)}; // The mask for a bank segment - uInt16 myBankMask{0}; - - // The number of segments a bank is split into - uInt16 myBankSegs{0}; + uInt16 myBankMask{ROM_MASK}; + protected: // The extra RAM size uInt16 myRamSize{RAM_SIZE}; // default 0 @@ -181,6 +191,9 @@ class CartridgeEnhanced : public Cartridge // The mask for the extra RAM uInt16 myRamMask{0}; // RAM_SIZE - 1, but doesn't matter when RAM_SIZE is 0 + // The number of segments a bank is split into (default 1) + uInt16 myBankSegs{1}; + // The offset into ROM space for reading from ROM // This is zero for types without RAM and with banked RAM // - xxSC = 0x0100 @@ -259,14 +272,6 @@ class CartridgeEnhanced : public Cartridge */ virtual uInt16 getStartBank() const { return 0; } - /** - Get the hotspot in ROM address space. - - @return The first hotspot address (ususally in ROM) space or 0 - */ - virtual uInt16 hotspot() const { return 0; } - // TODO: handle cases where there the hotspots cover multiple pages - private: // Following constructors and assignment operators not supported CartridgeEnhanced() = delete; diff --git a/src/emucore/CartUA.hxx b/src/emucore/CartUA.hxx index 97569dd76..77b83d10b 100644 --- a/src/emucore/CartUA.hxx +++ b/src/emucore/CartUA.hxx @@ -100,6 +100,8 @@ class CartridgeUA : public CartridgeEnhanced private: bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; + uInt16 hotspot() const override { return 0x0220; } + private: // Previous Device's page access std::array myHotSpotPageAccess; diff --git a/src/windows/Stella.vcxproj b/src/windows/Stella.vcxproj index b081dde0d..28b0efe29 100644 --- a/src/windows/Stella.vcxproj +++ b/src/windows/Stella.vcxproj @@ -618,6 +618,7 @@ true + true @@ -1621,6 +1622,7 @@ true + true diff --git a/src/windows/Stella.vcxproj.filters b/src/windows/Stella.vcxproj.filters index f0c9b601d..536cf54eb 100644 --- a/src/windows/Stella.vcxproj.filters +++ b/src/windows/Stella.vcxproj.filters @@ -996,6 +996,9 @@ Source Files\emucore + + Source Files\debugger + @@ -2045,6 +2048,9 @@ Header Files\emucore + + Header Files\debugger + From e702653355843dd47fddf449f41bce5bd509b8a8 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 19 Apr 2020 10:31:00 +0200 Subject: [PATCH 120/377] fix #617 (3E RAM banks) --- src/debugger/gui/Cart3EWidget.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/debugger/gui/Cart3EWidget.cxx b/src/debugger/gui/Cart3EWidget.cxx index 3880f2026..8055cd23b 100644 --- a/src/debugger/gui/Cart3EWidget.cxx +++ b/src/debugger/gui/Cart3EWidget.cxx @@ -161,7 +161,7 @@ string Cartridge3EWidget::bankState() if(bank < 256) buf << "ROM bank #" << std::dec << bank % myNumRomBanks << ", RAM inactive"; else - buf << "ROM inactive, RAM bank #" << std::dec << bank % myNumRomBanks; + buf << "ROM inactive, RAM bank #" << std::dec << bank % myNumRamBanks; return buf.str(); } From 12f6588d5d385578e9f534c3153dc9cf01415669 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 19 Apr 2020 10:45:22 +0200 Subject: [PATCH 121/377] renamed 'Exit' button in debugger into 'Run' (TODO: update screenshots) (fixes #614) --- docs/debugger.html | 20 ++++++++++---------- src/debugger/gui/DebuggerDialog.cxx | 4 ++-- src/debugger/gui/DebuggerDialog.hxx | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/debugger.html b/docs/debugger.html index 46e38d079..4f0c1cf6f 100644 --- a/docs/debugger.html +++ b/docs/debugger.html @@ -331,7 +331,7 @@ previous rewind operation. The rewind buffer is 100 levels deep by default, the size can be configured e.g. in the Developer Settings - Time Machine dialog.

      -

      The other operations are Step, Trace, Scan+1, Frame+1 and Exit (debugger).

      +

      The other operations are Step, Trace, Scan+1, Frame+1 and Run.

      You can also use the buttons from anywhere in the GUI via hotkeys.

      @@ -382,12 +382,12 @@ size can be configured e.g. in the

      - +
      Cartridge.Name:
      128IN1 ¹256/512K Multicart .128, .128N1
      2K 32-2048 byte Atari .2K
      3E 32K Tigervision .3E
      3E+ 3E+ (TJ modified DASH) .3EP, .3E+
      3E+ 3E+ (TJ modified 3E) .3EP, .3E+
      3F 512K Tigervision .3F
      4A50 ²64K 4A50 + RAM .4A5, .4A50
      4K 4K Atari .4K
      CM ¹Spectravideo CompuMate .CM
      CTY ²CDW - Chetiry .CTY
      CV CommaVid extra RAM .CV
      DASH Boulder Dash 2 .DAS, .DASH
      DF CPUWIZ 128K .DF
      DFSC CPUWIZ 128K + RAM.DFS, .DFSC
      DPC Pitfall II .DPC
      Backquote (`)ExitRun

      For MacOS use 'Cmd' instead of  'Alt' key. -

      To the left of the global buttons, you find the "Options..." button.

      +

      To the left of the global buttons, you find the 'Options...' button.

      @@ -608,7 +608,7 @@ created a symbol file, you can use labels for the expression.

      Example: You have got a label called "kernel". To break there, the command is "break kernel". After you've set the breakpoint, -exit the debugger ("quit" or click the Exit button). The emulator +exit the debugger (enter "run" or click the 'Run' button). The emulator will run until it gets to the breakpoint, then it will enter the debugger with the Program Counter pointing to the instruction at the breakpoint.

      @@ -1027,8 +1027,8 @@ graphics and positions, and the playfield.

      of the displays are editable. You can even toggle individual bits in the GRP0/1 and playfield registers (remember to double-click).

      -

      The group of buttons labelled "Strobes" allows you to write to any -of the strobe registers at any time.

      +

      The buttons allow you to write to any of the strobe registers at +any time.

      The collision registers are displayed in decoded format, in a table. You can see exactly which objects have hit what. These are read-only @@ -1103,7 +1103,7 @@ or TV effects are enabled, you won't see the effects here; this shows the raw TIA image only.

      To e.g. watch the TIA draw the frame one scanline at a time, you can -use the "Scan+1" button, the prompt "scan" command or the Control-L key.

      +use the 'Scan+1' button, the prompt "scan" command or the Control-L key.

      You can also right-click anywhere in this window to show a context menu, as illustrated:

      @@ -1213,7 +1213,7 @@ section for details.

      All the registers and flags are displayed, and can be changed by double-clicking on them (to the left). Flags are toggled on double-click. -Selected registers here can also be changed by using the "Data Operations" buttons, +Selected registers here can also be changed by using the 'Data Operations' buttons, further described in (J). All items are shown in hex. Any label defined for the current PC value is shown to the right. Decimal and binary equivalents are shown for SP/A/X/Y to the right (first decimal, then binary).

      @@ -1631,7 +1631,7 @@ but it helps to know at least a little about 6502 programming.

    3. Enter the debugger by pressing the ` (backquote) key. Don't get killed before you do this, though. You should still have all 5 lives.
    4. -
    5. In the RAM display, click the "Search" button and enter "5" for input. +
    6. In the RAM display, click the 'Search' button and enter "5" for input. This searches RAM for your value and highlights all addresses that match the input. You should see two addresses highlighted: "00a5" and "00ba". These are the only two addresses that currently have the value 5, so they're @@ -1647,7 +1647,7 @@ but it helps to know at least a little about 6502 programming.

    7. Get killed! Ram an enemy tank, or let him shoot you. Wait for the explosion to finish. You will now have 4 lives.
    8. -
    9. Enter the debugger again. Click the "Compare" button in RAM widget and enter +
    10. Enter the debugger again. Click the 'Compare...' button in RAM widget and enter a value of 4. Now the RAM widget should only show one highlighted address: "00ba". What we did was search within our previous results (the ones that were 5 before) for the new value 4. Address $00ba used to have the value 5, diff --git a/src/debugger/gui/DebuggerDialog.cxx b/src/debugger/gui/DebuggerDialog.cxx index 47e05da04..ac3c8d6c9 100644 --- a/src/debugger/gui/DebuggerDialog.cxx +++ b/src/debugger/gui/DebuggerDialog.cxx @@ -231,7 +231,7 @@ void DebuggerDialog::handleCommand(CommandSender* sender, int cmd, doUnwind(); break; - case kDDExitCmd: + case kDDRunCmd: doExitDebugger(); break; @@ -541,7 +541,7 @@ void DebuggerDialog::addRomArea() wid2.push_back(b); buttonY += bheight + 4; b = new ButtonWidget(this, *myLFont, buttonX, buttonY, - bwidth, bheight, "Exit", kDDExitCmd); + bwidth, bheight, "Run", kDDRunCmd); wid2.push_back(b); addCancelWidget(b); diff --git a/src/debugger/gui/DebuggerDialog.hxx b/src/debugger/gui/DebuggerDialog.hxx index f9f11e459..b1b42211a 100644 --- a/src/debugger/gui/DebuggerDialog.hxx +++ b/src/debugger/gui/DebuggerDialog.hxx @@ -110,7 +110,7 @@ class DebuggerDialog : public Dialog kDDSAdvCmd = 'DDsv', kDDRewindCmd = 'DDrw', kDDUnwindCmd = 'DDuw', - kDDExitCmd = 'DDex', + kDDRunCmd = 'DDex', kDDExitFatalCmd = 'DDer', kDDOptionsCmd = 'DDop' }; From 8f6cdf689dc31bec82a7248295fd8e8f702857c8 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 18 Apr 2020 17:51:21 +0200 Subject: [PATCH 122/377] fix display of changed PopUpWidget in debugger allow using IDs with PopUpWidget's ContextMenu --- src/gui/ContextMenu.cxx | 10 +++++----- src/gui/ContextMenu.hxx | 4 ++++ src/gui/PopUpWidget.cxx | 10 +++++++++- src/gui/PopUpWidget.hxx | 2 ++ 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/gui/ContextMenu.cxx b/src/gui/ContextMenu.cxx index 11e09e475..cf142255f 100644 --- a/src/gui/ContextMenu.cxx +++ b/src/gui/ContextMenu.cxx @@ -181,7 +181,7 @@ bool ContextMenu::sendSelectionUp() return false; _selectedItem--; - sendCommand(_cmd ? _cmd : ContextMenu::kItemSelectedCmd, _selectedItem, -1); + sendCommand(_cmd ? _cmd : ContextMenu::kItemSelectedCmd, _selectedItem, _id); return true; } @@ -192,7 +192,7 @@ bool ContextMenu::sendSelectionDown() return false; _selectedItem++; - sendCommand(_cmd ? _cmd : ContextMenu::kItemSelectedCmd, _selectedItem, -1); + sendCommand(_cmd ? _cmd : ContextMenu::kItemSelectedCmd, _selectedItem, _id); return true; } @@ -203,7 +203,7 @@ bool ContextMenu::sendSelectionFirst() return false; _selectedItem = 0; - sendCommand(_cmd ? _cmd : ContextMenu::kItemSelectedCmd, _selectedItem, -1); + sendCommand(_cmd ? _cmd : ContextMenu::kItemSelectedCmd, _selectedItem, _id); return true; } @@ -214,7 +214,7 @@ bool ContextMenu::sendSelectionLast() return false; _selectedItem = int(_entries.size()) - 1; - sendCommand(_cmd ? _cmd : ContextMenu::kItemSelectedCmd, _selectedItem, -1); + sendCommand(_cmd ? _cmd : ContextMenu::kItemSelectedCmd, _selectedItem, _id); return true; } @@ -375,7 +375,7 @@ void ContextMenu::sendSelection() // Send any command associated with the selection _selectedItem = item; - sendCommand(_cmd ? _cmd : ContextMenu::kItemSelectedCmd, _selectedItem, -1); + sendCommand(_cmd ? _cmd : ContextMenu::kItemSelectedCmd, _selectedItem, _id); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/gui/ContextMenu.hxx b/src/gui/ContextMenu.hxx index 28d485f1a..40858f8b9 100644 --- a/src/gui/ContextMenu.hxx +++ b/src/gui/ContextMenu.hxx @@ -45,6 +45,9 @@ class ContextMenu : public Dialog, public CommandSender const VariantList& items, int cmd = 0, int width = 0); virtual ~ContextMenu() = default; + /** Set the parent widget's ID */ + void setID(uInt32 id) { _id = id; } + /** Add the given items to the widget. */ void addItems(const VariantList& items); @@ -121,6 +124,7 @@ class ContextMenu : public Dialog, public CommandSender ColorId _scrollUpColor{kColor}, _scrollDnColor{kColor}; int _cmd{0}; + int _id{-1}; uInt32 _xorig{0}, _yorig{0}; uInt32 _maxWidth{0}; diff --git a/src/gui/PopUpWidget.cxx b/src/gui/PopUpWidget.cxx index 6b530f6d1..9cc233060 100644 --- a/src/gui/PopUpWidget.cxx +++ b/src/gui/PopUpWidget.cxx @@ -50,6 +50,14 @@ PopUpWidget::PopUpWidget(GuiObject* boss, const GUI::Font& font, myMenu = make_unique(this, font, list, cmd, w); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PopUpWidget::setID(uInt32 id) +{ + myMenu->setID(id); + + Widget::setID(id); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PopUpWidget::addItems(const VariantList& items) { @@ -219,5 +227,5 @@ void PopUpWidget::drawWidget(bool hilite) TextAlign align = (_font.getStringWidth(name) > w-6) ? TextAlign::Right : TextAlign::Left; s.drawString(_font, name, x+2, _y+myTextY, w-6, - !(isEnabled() && onTop) ? kColor : kTextColor, align); + !(isEnabled() && onTop) ? kColor : _changed ? kDbgChangedTextColor : kTextColor, align); } diff --git a/src/gui/PopUpWidget.hxx b/src/gui/PopUpWidget.hxx index f79e575f8..955263f5f 100644 --- a/src/gui/PopUpWidget.hxx +++ b/src/gui/PopUpWidget.hxx @@ -41,6 +41,8 @@ class PopUpWidget : public Widget, public CommandSender const string& label, int labelWidth = 0, int cmd = 0); virtual ~PopUpWidget() = default; + void setID(uInt32 id); + int getTop() const override { return _y + 1; } int getBottom() const override { return _y + 1 + getHeight(); } From 4e314a5fe23adc0bdaa1abe3a1b3f04b11aeb6fa Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 19 Apr 2020 12:19:44 +0200 Subject: [PATCH 123/377] improve bankswitching masking in CartEnhanced --- src/emucore/Cart3F.hxx | 2 ++ src/emucore/CartE0.cxx | 2 ++ src/emucore/CartEnhanced.cxx | 7 ++++--- src/emucore/CartEnhanced.hxx | 3 +++ src/emucore/CartF0.cxx | 2 +- src/emucore/CartF4.cxx | 4 ++-- src/emucore/CartF6.cxx | 4 ++-- src/emucore/CartF8.cxx | 4 ++-- src/emucore/CartFA.cxx | 4 ++-- src/emucore/CartFA2.cxx | 4 ++-- src/emucore/CartFC.cxx | 2 +- 11 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/emucore/Cart3F.hxx b/src/emucore/Cart3F.hxx index d9f3e9fa6..7bdcbd99c 100644 --- a/src/emucore/Cart3F.hxx +++ b/src/emucore/Cart3F.hxx @@ -87,6 +87,8 @@ class Cartridge3F : public CartridgeEnhanced private: bool checkSwitchBank(uInt16 address, uInt8 value) override; + uInt16 hotspot() const override { return 0x003F; } + private: // log(ROM bank segment size) / log(2) static constexpr uInt16 BANK_SHIFT = 11; // = 2K = 0x0800 diff --git a/src/emucore/CartE0.cxx b/src/emucore/CartE0.cxx index 97752e447..d9c37d7e4 100644 --- a/src/emucore/CartE0.cxx +++ b/src/emucore/CartE0.cxx @@ -48,6 +48,8 @@ void CartridgeE0::reset() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeE0::checkSwitchBank(uInt16 address, uInt8) { + address &= ROM_MASK; + // Switch banks if necessary if((address >= 0x0FE0) && (address <= 0x0FE7)) { diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index 05f954e3e..ea167b1d5 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -114,8 +114,9 @@ uInt8 CartridgeEnhanced::peek(uInt16 address) { uInt16 peekAddress = address; - if (hotspot() != 0) - checkSwitchBank(address & ROM_MASK); + // hotspots in TIA range are reacting to pokes only + if (hotspot() >= 0x80) + checkSwitchBank(address & ADDR_MASK); if(isRamBank(address)) { @@ -148,7 +149,7 @@ bool CartridgeEnhanced::poke(uInt16 address, uInt8 value) // Note: (TODO?) // The checkSwitchBank() call makes no difference between ROM and e.g TIA space // Writing to e.g. 0xf0xx might triger a bankswitch, is (and was!) this a bug??? - if (checkSwitchBank(address & ROM_MASK, value)) + if (checkSwitchBank(address & ADDR_MASK, value)) return false; if(myRamSize > 0) diff --git a/src/emucore/CartEnhanced.hxx b/src/emucore/CartEnhanced.hxx index ecf8a0a58..c3702d118 100644 --- a/src/emucore/CartEnhanced.hxx +++ b/src/emucore/CartEnhanced.hxx @@ -232,6 +232,9 @@ class CartridgeEnhanced : public Cartridge size_t mySize{0}; protected: + // The mask for 6507 address space + static constexpr uInt16 ADDR_MASK = 0x1FFF; + // The offset into address space for accessing ROM static constexpr uInt16 ROM_OFFSET = 0x1000; diff --git a/src/emucore/CartF0.cxx b/src/emucore/CartF0.cxx index 9f021a685..8747c57f3 100644 --- a/src/emucore/CartF0.cxx +++ b/src/emucore/CartF0.cxx @@ -28,7 +28,7 @@ CartridgeF0::CartridgeF0(const ByteBuffer& image, size_t size, bool CartridgeF0::checkSwitchBank(uInt16 address, uInt8) { // Switch banks if necessary - if(address == 0x0FF0) + if(address == 0x1FF0) { // Switch to next bank uInt8 nextBank = ((getBank()) + 1) & 0x0F; diff --git a/src/emucore/CartF4.cxx b/src/emucore/CartF4.cxx index 0cb689228..6a8cd6e00 100644 --- a/src/emucore/CartF4.cxx +++ b/src/emucore/CartF4.cxx @@ -29,9 +29,9 @@ bool CartridgeF4::checkSwitchBank(uInt16 address, uInt8) { // Switch banks if necessary // Note: addresses could be calculated from hotspot and bank count - if((address >= 0x0FF4) && (address <= 0x0FFB)) + if((address >= 0x1FF4) && (address <= 0x1FFB)) { - bank(address - 0x0FF4); + bank(address - 0x1FF4); return true; } return false; diff --git a/src/emucore/CartF6.cxx b/src/emucore/CartF6.cxx index 567424d7a..50e993e26 100644 --- a/src/emucore/CartF6.cxx +++ b/src/emucore/CartF6.cxx @@ -29,9 +29,9 @@ bool CartridgeF6::checkSwitchBank(uInt16 address, uInt8) { // Switch banks if necessary // Note: addresses could be calculated from hotspot and bank count - if((address >= 0x0FF6) && (address <= 0x0FF9)) + if((address >= 0x1FF6) && (address <= 0x1FF9)) { - bank(address - 0x0FF6); + bank(address - 0x1FF6); return true; } return false; diff --git a/src/emucore/CartF8.cxx b/src/emucore/CartF8.cxx index 79b4708c4..5d898091c 100644 --- a/src/emucore/CartF8.cxx +++ b/src/emucore/CartF8.cxx @@ -30,12 +30,12 @@ bool CartridgeF8::checkSwitchBank(uInt16 address, uInt8) // Switch banks if necessary switch(address) { - case 0x0FF8: + case 0x1FF8: // Set the current bank to the lower 4k bank bank(0); return true; - case 0x0FF9: + case 0x1FF9: // Set the current bank to the upper 4k bank bank(1); return true; diff --git a/src/emucore/CartFA.cxx b/src/emucore/CartFA.cxx index 3f1062f41..082e403f7 100644 --- a/src/emucore/CartFA.cxx +++ b/src/emucore/CartFA.cxx @@ -30,9 +30,9 @@ CartridgeFA::CartridgeFA(const ByteBuffer& image, size_t size, bool CartridgeFA::checkSwitchBank(uInt16 address, uInt8) { // Switch banks if necessary - if((address >= 0x0FF8) && (address <= 0x0FFA)) + if((address >= 0x1FF8) && (address <= 0x1FFA)) { - bank(address - 0x0FF8); + bank(address - 0x1FF8); return true; } return false; diff --git a/src/emucore/CartFA2.cxx b/src/emucore/CartFA2.cxx index 6662e8171..14c8f2156 100644 --- a/src/emucore/CartFA2.cxx +++ b/src/emucore/CartFA2.cxx @@ -42,9 +42,9 @@ CartridgeFA2::CartridgeFA2(const ByteBuffer& image, size_t size, bool CartridgeFA2::checkSwitchBank(uInt16 address, uInt8) { // Switch banks if necessary - if((address >= 0x0FF5) && (address <= 0x0FFB)) + if((address >= 0x1FF5) && (address <= 0x1FFB)) { - bank(address - 0x0FF5); + bank(address - 0x1FF5); return true; } return false; diff --git a/src/emucore/CartFC.cxx b/src/emucore/CartFC.cxx index 925718d50..c415ba1af 100644 --- a/src/emucore/CartFC.cxx +++ b/src/emucore/CartFC.cxx @@ -37,7 +37,7 @@ void CartridgeFC::reset() bool CartridgeFC::checkSwitchBank(uInt16 address, uInt8) { // Switch banks if necessary - if(address == 0x0FFC) + if(address == 0x1FFC) { // Trigger the bank switch bank(myTargetBank); From 453cb84060d119b09e23f9c4e1013575b3b6f2a2 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 19 Apr 2020 18:59:07 +0200 Subject: [PATCH 124/377] refactored Cart3F, CartCV and CartBF(SC) widgets --- src/debugger/gui/Cart3FWidget.cxx | 79 ++------- src/debugger/gui/Cart3FWidget.hxx | 17 +- src/debugger/gui/CartBFSCWidget.cxx | 218 ++---------------------- src/debugger/gui/CartBFSCWidget.hxx | 33 +--- src/debugger/gui/CartBFWidget.cxx | 145 +--------------- src/debugger/gui/CartBFWidget.hxx | 15 +- src/debugger/gui/CartCVWidget.cxx | 85 +-------- src/debugger/gui/CartE0Widget.hxx | 1 + src/debugger/gui/CartEnhancedWidget.cxx | 17 +- src/debugger/gui/CartEnhancedWidget.hxx | 2 +- src/debugger/gui/CartF0Widget.hxx | 2 +- src/emucore/CartEnhanced.cxx | 3 - 12 files changed, 65 insertions(+), 552 deletions(-) diff --git a/src/debugger/gui/Cart3FWidget.cxx b/src/debugger/gui/Cart3FWidget.cxx index 13cd851bd..76f331502 100644 --- a/src/debugger/gui/Cart3FWidget.cxx +++ b/src/debugger/gui/Cart3FWidget.cxx @@ -16,80 +16,33 @@ //============================================================================ #include "Cart3F.hxx" -#include "PopUpWidget.hxx" #include "Cart3FWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge3FWidget::Cartridge3FWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, Cartridge3F& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) + : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) +{ + myHotspotDelta = 0; + initialize(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string Cartridge3FWidget::description() { ostringstream info; size_t size; + const uInt8* image = myCart.getImage(size); - cart.getImage(size); - info << "Tigervision 3F cartridge, 2-256 2K banks\n" - << "Startup bank = " << cart.startBank() << " or undetermined\n" - << "First 2K bank selected by writing to $3F\n" - << "Last 2K always points to last 2K of ROM\n"; - + info << "Tigervision 3F cartridge, 2 - 256 2K banks\n" + << "First 2K bank selected by writing to " << hotspotStr() << "\n" + << "Last 2K always points to last 2K of ROM\n" + << "Startup bank = " << myCart.startBank() << " or undetermined\n"; // Eventually, we should query this from the debugger/disassembler - uInt16 start = (cart.myImage[size-3] << 8) | cart.myImage[size-4]; + uInt16 start = (image[size-3] << 8) | image[size-4]; start -= start % 0x1000; - info << "Bank RORG" << " = $" << Common::Base::HEX4 << start << "\n"; + info << "Bank RORG $" << Common::Base::HEX4 << start << "\n"; - int xpos = 2, - ypos = addBaseInformation(size, "TigerVision", info.str()) + myLineHeight; - - VariantList items; - for(uInt16 i = 0; i < cart.romBankCount(); ++i) - VarList::push_back(items, Variant(i).toString() + " ($3F)"); - - ostringstream label; - label << "Set bank ($" << Common::Base::HEX4 << start << " - $" << - (start+0x7FF) << ") "; - myBank = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($3F) "), - myLineHeight, items, label.str(), - _font.getStringWidth(label.str()), kBankChanged); - myBank->setTarget(this); - addFocusWidget(myBank); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge3FWidget::loadConfig() -{ - Debugger& dbg = instance().debugger(); - CartDebug& cart = dbg.cartDebug(); - const CartState& state = static_cast(cart.getState()); - const CartState& oldstate = static_cast(cart.getOldState()); - - myBank->setSelectedIndex(myCart.getBank(0), state.bank != oldstate.bank); - - CartDebugWidget::loadConfig(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge3FWidget::handleCommand(CommandSender* sender, - int cmd, int data, int id) -{ - if(cmd == kBankChanged) - { - myCart.unlockBank(); - myCart.bank(myBank->getSelected()); - myCart.lockBank(); - invalidate(); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string Cartridge3FWidget::bankState() -{ - ostringstream& buf = buffer(); - - buf << "Bank = #" << std::dec << myCart.getSegmentBank() << ", hotspot = $3F"; - - return buf.str(); + return info.str(); } diff --git a/src/debugger/gui/Cart3FWidget.hxx b/src/debugger/gui/Cart3FWidget.hxx index 859184057..7e3ee65e9 100644 --- a/src/debugger/gui/Cart3FWidget.hxx +++ b/src/debugger/gui/Cart3FWidget.hxx @@ -19,11 +19,10 @@ #define CARTRIDGE3F_WIDGET_HXX class Cartridge3F; -class PopUpWidget; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class Cartridge3FWidget : public CartDebugWidget +class Cartridge3FWidget : public CartEnhancedWidget { public: Cartridge3FWidget(GuiObject* boss, const GUI::Font& lfont, @@ -33,17 +32,13 @@ class Cartridge3FWidget : public CartDebugWidget virtual ~Cartridge3FWidget() = default; private: - Cartridge3F& myCart; - PopUpWidget* myBank{nullptr}; + string manufacturer() override { return "TigerVision"; } - enum { kBankChanged = 'bkCH' }; + string description() override; + + int bankSegs() override { return 1; } private: - void loadConfig() override; - void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - - string bankState() override; - // Following constructors and assignment operators not supported Cartridge3FWidget() = delete; Cartridge3FWidget(const Cartridge3FWidget&) = delete; diff --git a/src/debugger/gui/CartBFSCWidget.cxx b/src/debugger/gui/CartBFSCWidget.cxx index 819e72b39..00109d9e9 100644 --- a/src/debugger/gui/CartBFSCWidget.cxx +++ b/src/debugger/gui/CartBFSCWidget.cxx @@ -15,221 +15,25 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#include "Debugger.hxx" -#include "CartDebug.hxx" #include "CartBFSC.hxx" -#include "PopUpWidget.hxx" #include "CartBFSCWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeBFSCWidget::CartridgeBFSCWidget( - GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, - int x, int y, int w, int h, CartridgeBFSC& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) + GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, + int x, int y, int w, int h, CartridgeBFSC& cart) + : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { - uInt32 size = 64 * 4096; + initialize(); +} +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartridgeBFSCWidget::description() +{ ostringstream info; - info << "256K BFSC + RAM, 64 4K banks\n" - << "128 bytes RAM @ $F000 - $F0FF\n" - << " $F080 - $F0FF (R), $F000 - $F07F (W)\n" - << "Startup bank = " << cart.startBank() << "\n"; - // Eventually, we should query this from the debugger/disassembler - for(uInt32 i = 0, offset = 0xFFC, spot = 0xF80; i < 64; ++i, offset += 0x1000) - { - uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; - start -= start % 0x1000; - info << "Bank " << std::dec << i << " @ $" << Common::Base::HEX4 << (start + 0x100) - << " - " << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; - } + info << "256K BFSC + RAM, 64 4K banks\n"; + info << CartEnhancedWidget::description(); - int xpos = 2, - ypos = addBaseInformation(size, "CPUWIZ", info.str()) + myLineHeight; - - VariantList items; - VarList::push_back(items, " 0 ($FF80)"); - VarList::push_back(items, " 1 ($FF81)"); - VarList::push_back(items, " 2 ($FF82)"); - VarList::push_back(items, " 3 ($FF83)"); - VarList::push_back(items, " 4 ($FF84)"); - VarList::push_back(items, " 5 ($FF85)"); - VarList::push_back(items, " 6 ($FF86)"); - VarList::push_back(items, " 7 ($FF87)"); - VarList::push_back(items, " 8 ($FF88)"); - VarList::push_back(items, " 9 ($FF89)"); - VarList::push_back(items, "10 ($FF8A)"); - VarList::push_back(items, "11 ($FF8B)"); - VarList::push_back(items, "12 ($FF8C)"); - VarList::push_back(items, "13 ($FF8D)"); - VarList::push_back(items, "14 ($FF8E)"); - VarList::push_back(items, "15 ($FF8F)"); - VarList::push_back(items, "16 ($FF90)"); - VarList::push_back(items, "17 ($FF91)"); - VarList::push_back(items, "18 ($FF92)"); - VarList::push_back(items, "19 ($FF93)"); - VarList::push_back(items, "20 ($FF94)"); - VarList::push_back(items, "21 ($FF95)"); - VarList::push_back(items, "22 ($FF96)"); - VarList::push_back(items, "23 ($FF97)"); - VarList::push_back(items, "24 ($FF98)"); - VarList::push_back(items, "25 ($FF99)"); - VarList::push_back(items, "26 ($FF9A)"); - VarList::push_back(items, "27 ($FF9B)"); - VarList::push_back(items, "28 ($FF9C)"); - VarList::push_back(items, "29 ($FF9D)"); - VarList::push_back(items, "30 ($FF9E)"); - VarList::push_back(items, "31 ($FF9F)"); - VarList::push_back(items, "32 ($FFA0)"); - VarList::push_back(items, "33 ($FFA1)"); - VarList::push_back(items, "34 ($FFA2)"); - VarList::push_back(items, "35 ($FFA3)"); - VarList::push_back(items, "36 ($FFA4)"); - VarList::push_back(items, "37 ($FFA5)"); - VarList::push_back(items, "38 ($FFA6)"); - VarList::push_back(items, "39 ($FFA7)"); - VarList::push_back(items, "40 ($FFA8)"); - VarList::push_back(items, "41 ($FFA9)"); - VarList::push_back(items, "42 ($FFAA)"); - VarList::push_back(items, "43 ($FFAB)"); - VarList::push_back(items, "44 ($FFAC)"); - VarList::push_back(items, "45 ($FFAD)"); - VarList::push_back(items, "46 ($FFAE)"); - VarList::push_back(items, "47 ($FFAF)"); - VarList::push_back(items, "48 ($FFB0)"); - VarList::push_back(items, "49 ($FFB1)"); - VarList::push_back(items, "50 ($FFB2)"); - VarList::push_back(items, "51 ($FFB3)"); - VarList::push_back(items, "52 ($FFB4)"); - VarList::push_back(items, "53 ($FFB5)"); - VarList::push_back(items, "54 ($FFB6)"); - VarList::push_back(items, "55 ($FFB7)"); - VarList::push_back(items, "56 ($FFB8)"); - VarList::push_back(items, "57 ($FFB9)"); - VarList::push_back(items, "58 ($FFBA)"); - VarList::push_back(items, "59 ($FFBB)"); - VarList::push_back(items, "60 ($FFBC)"); - VarList::push_back(items, "61 ($FFBD)"); - VarList::push_back(items, "62 ($FFBE)"); - VarList::push_back(items, "63 ($FFBF)"); - - myBank = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("63 ($FFBF)"), - myLineHeight, items, "Set bank ", - 0, kBankChanged); - myBank->setTarget(this); - addFocusWidget(myBank); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeBFSCWidget::saveOldState() -{ - myOldState.internalram.clear(); - - for(uInt32 i = 0; i < internalRamSize(); ++i) - myOldState.internalram.push_back(myCart.myRAM[i]); - - myOldState.bank = myCart.getBank(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeBFSCWidget::loadConfig() -{ - myBank->setSelectedIndex(myCart.getBank(), myCart.getBank() != myOldState.bank); - - CartDebugWidget::loadConfig(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeBFSCWidget::handleCommand(CommandSender* sender, - int cmd, int data, int id) -{ - if(cmd == kBankChanged) - { - myCart.unlockBank(); - myCart.bank(myBank->getSelected()); - myCart.lockBank(); - invalidate(); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeBFSCWidget::bankState() -{ - ostringstream& buf = buffer(); - - static constexpr std::array spot = { - "$FF80", "$FF81", "$FF82", "$FF83", "$FF84", "$FF85", "$FF86", "$FF87", - "$FF88", "$FF89", "$FF8A", "$FF8B", "$FF8C", "$FF8D", "$FF8E", "$FF8F", - "$FF90", "$FF91", "$FF92", "$FF93", "$FF94", "$FF95", "$FF96", "$FF97", - "$FF98", "$FF99", "$FF9A", "$FF9B", "$FF9C", "$FF9D", "$FF9E", "$FF9F", - "$FFA0", "$FFA1", "$FFA2", "$FFA3", "$FFA4", "$FFA5", "$FFA6", "$FFA7", - "$FFA8", "$FFA9", "$FFAA", "$FFAB", "$FFAC", "$FFAD", "$FFAE", "$FFAF", - "$FFB0", "$FFB1", "$FFB2", "$FFB3", "$FFB4", "$FFB5", "$FFB6", "$FFB7", - "$FFB8", "$FFB9", "$FFBA", "$FFBB", "$FFBC", "$FFBD", "$FFBE", "$FFBF" - }; - buf << "Bank = " << std::dec << myCart.getBank() - << ", hotspot = " << spot[myCart.getBank()]; - - return buf.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 CartridgeBFSCWidget::internalRamSize() -{ - return 128; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 CartridgeBFSCWidget::internalRamRPort(int start) -{ - return 0xF080 + start; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeBFSCWidget::internalRamDescription() -{ - ostringstream desc; - desc << "$F000 - $F07F used for Write Access\n" - << "$F080 - $F0FF used for Read Access"; - - return desc.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& CartridgeBFSCWidget::internalRamOld(int start, int count) -{ - myRamOld.clear(); - for(int i = 0; i < count; i++) - myRamOld.push_back(myOldState.internalram[start + i]); - return myRamOld; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& CartridgeBFSCWidget::internalRamCurrent(int start, int count) -{ - myRamCurrent.clear(); - for(int i = 0; i < count; i++) - myRamCurrent.push_back(myCart.myRAM[start + i]); - return myRamCurrent; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeBFSCWidget::internalRamSetValue(int addr, uInt8 value) -{ - myCart.myRAM[addr] = value; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeBFSCWidget::internalRamGetValue(int addr) -{ - return myCart.myRAM[addr]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeBFSCWidget::internalRamLabel(int addr) -{ - CartDebug& dbg = instance().debugger().cartDebug(); - return dbg.getLabel(addr + 0xF080, false); + return info.str(); } diff --git a/src/debugger/gui/CartBFSCWidget.hxx b/src/debugger/gui/CartBFSCWidget.hxx index 3068672f0..5e394eae5 100644 --- a/src/debugger/gui/CartBFSCWidget.hxx +++ b/src/debugger/gui/CartBFSCWidget.hxx @@ -19,11 +19,10 @@ #define CARTRIDGEBFSC_WIDGET_HXX class CartridgeBFSC; -class PopUpWidget; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class CartridgeBFSCWidget : public CartDebugWidget +class CartridgeBFSCWidget : public CartEnhancedWidget { public: CartridgeBFSCWidget(GuiObject* boss, const GUI::Font& lfont, @@ -33,35 +32,11 @@ class CartridgeBFSCWidget : public CartDebugWidget virtual ~CartridgeBFSCWidget() = default; private: - CartridgeBFSC& myCart; - PopUpWidget* myBank{nullptr}; + string manufacturer() override { return "CPUWIZ"; } - struct CartState { - ByteArray internalram; - uInt16 bank{0}; - }; - CartState myOldState; - - enum { kBankChanged = 'bkCH' }; + string description() override; private: - void saveOldState() override; - void loadConfig() override; - void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - - string bankState() override; - - // start of functions for Cartridge RAM tab - uInt32 internalRamSize() override; - uInt32 internalRamRPort(int start) override; - string internalRamDescription() override; - const ByteArray& internalRamOld(int start, int count) override; - const ByteArray& internalRamCurrent(int start, int count) override; - void internalRamSetValue(int addr, uInt8 value) override; - uInt8 internalRamGetValue(int addr) override; - string internalRamLabel(int addr) override; - // end of functions for Cartridge RAM tab - // Following constructors and assignment operators not supported CartridgeBFSCWidget() = delete; CartridgeBFSCWidget(const CartridgeBFSCWidget&) = delete; diff --git a/src/debugger/gui/CartBFWidget.cxx b/src/debugger/gui/CartBFWidget.cxx index 96ddc5662..001f50658 100644 --- a/src/debugger/gui/CartBFWidget.cxx +++ b/src/debugger/gui/CartBFWidget.cxx @@ -16,151 +16,24 @@ //============================================================================ #include "CartBF.hxx" -#include "PopUpWidget.hxx" #include "CartBFWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeBFWidget::CartridgeBFWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeBF& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) + : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { - uInt32 size = 64 * 4096; + initialize(); +} +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartridgeBFWidget::description() +{ ostringstream info; - info << "BF cartridge, 64 4K banks\n" - << "Startup bank = " << cart.startBank() << "\n"; - // Eventually, we should query this from the debugger/disassembler - for(uInt32 i = 0, offset = 0xFFC, spot = 0xF80; i < 64; ++i, offset += 0x1000) - { - uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; - start -= start % 0x1000; - info << "Bank " << std::dec << i << " @ $" << Common::Base::HEX4 << start << " - " - << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; - } + info << "256K BF cartridge, 64 4K banks\n"; + info << CartEnhancedWidget::description(); - int xpos = 2, - ypos = addBaseInformation(size, "CPUWIZ", info.str()) + myLineHeight; - - VariantList items; - VarList::push_back(items, " 0 ($FF80)"); - VarList::push_back(items, " 1 ($FF81)"); - VarList::push_back(items, " 2 ($FF82)"); - VarList::push_back(items, " 3 ($FF83)"); - VarList::push_back(items, " 4 ($FF84)"); - VarList::push_back(items, " 5 ($FF85)"); - VarList::push_back(items, " 6 ($FF86)"); - VarList::push_back(items, " 7 ($FF87)"); - VarList::push_back(items, " 8 ($FF88)"); - VarList::push_back(items, " 9 ($FF89)"); - VarList::push_back(items, "10 ($FF8A)"); - VarList::push_back(items, "11 ($FF8B)"); - VarList::push_back(items, "12 ($FF8C)"); - VarList::push_back(items, "13 ($FF8D)"); - VarList::push_back(items, "14 ($FF8E)"); - VarList::push_back(items, "15 ($FF8F)"); - VarList::push_back(items, "16 ($FF90)"); - VarList::push_back(items, "17 ($FF91)"); - VarList::push_back(items, "18 ($FF92)"); - VarList::push_back(items, "19 ($FF93)"); - VarList::push_back(items, "20 ($FF94)"); - VarList::push_back(items, "21 ($FF95)"); - VarList::push_back(items, "22 ($FF96)"); - VarList::push_back(items, "23 ($FF97)"); - VarList::push_back(items, "24 ($FF98)"); - VarList::push_back(items, "25 ($FF99)"); - VarList::push_back(items, "26 ($FF9A)"); - VarList::push_back(items, "27 ($FF9B)"); - VarList::push_back(items, "28 ($FF9C)"); - VarList::push_back(items, "29 ($FF9D)"); - VarList::push_back(items, "30 ($FF9E)"); - VarList::push_back(items, "31 ($FF9F)"); - VarList::push_back(items, "32 ($FFA0)"); - VarList::push_back(items, "33 ($FFA1)"); - VarList::push_back(items, "34 ($FFA2)"); - VarList::push_back(items, "35 ($FFA3)"); - VarList::push_back(items, "36 ($FFA4)"); - VarList::push_back(items, "37 ($FFA5)"); - VarList::push_back(items, "38 ($FFA6)"); - VarList::push_back(items, "39 ($FFA7)"); - VarList::push_back(items, "40 ($FFA8)"); - VarList::push_back(items, "41 ($FFA9)"); - VarList::push_back(items, "42 ($FFAA)"); - VarList::push_back(items, "43 ($FFAB)"); - VarList::push_back(items, "44 ($FFAC)"); - VarList::push_back(items, "45 ($FFAD)"); - VarList::push_back(items, "46 ($FFAE)"); - VarList::push_back(items, "47 ($FFAF)"); - VarList::push_back(items, "48 ($FFB0)"); - VarList::push_back(items, "49 ($FFB1)"); - VarList::push_back(items, "50 ($FFB2)"); - VarList::push_back(items, "51 ($FFB3)"); - VarList::push_back(items, "52 ($FFB4)"); - VarList::push_back(items, "53 ($FFB5)"); - VarList::push_back(items, "54 ($FFB6)"); - VarList::push_back(items, "55 ($FFB7)"); - VarList::push_back(items, "56 ($FFB8)"); - VarList::push_back(items, "57 ($FFB9)"); - VarList::push_back(items, "58 ($FFBA)"); - VarList::push_back(items, "59 ($FFBB)"); - VarList::push_back(items, "60 ($FFBC)"); - VarList::push_back(items, "61 ($FFBD)"); - VarList::push_back(items, "62 ($FFBE)"); - VarList::push_back(items, "63 ($FFBF)"); - - myBank = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("64 ($FFBF)"), - myLineHeight, items, "Set bank ", - 0, kBankChanged); - myBank->setTarget(this); - addFocusWidget(myBank); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeBFWidget::loadConfig() -{ - Debugger& dbg = instance().debugger(); - CartDebug& cart = dbg.cartDebug(); - const CartState& state = static_cast(cart.getState()); - const CartState& oldstate = static_cast(cart.getOldState()); - - myBank->setSelectedIndex(myCart.getBank(), state.bank != oldstate.bank); - - CartDebugWidget::loadConfig(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeBFWidget::handleCommand(CommandSender* sender, - int cmd, int data, int id) -{ - if(cmd == kBankChanged) - { - myCart.unlockBank(); - myCart.bank(myBank->getSelected()); - myCart.lockBank(); - invalidate(); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeBFWidget::bankState() -{ - ostringstream& buf = buffer(); - - static constexpr std::array spot = { - "$FF80", "$FF81", "$FF82", "$FF83", "$FF84", "$FF85", "$FF86", "$FF87", - "$FF88", "$FF89", "$FF8A", "$FF8B", "$FF8C", "$FF8D", "$FF8E", "$FF8F", - "$FF90", "$FF91", "$FF92", "$FF93", "$FF94", "$FF95", "$FF96", "$FF97", - "$FF98", "$FF99", "$FF9A", "$FF9B", "$FF9C", "$FF9D", "$FF9E", "$FF9F", - "$FFA0", "$FFA1", "$FFA2", "$FFA3", "$FFA4", "$FFA5", "$FFA6", "$FFA7", - "$FFA8", "$FFA9", "$FFAA", "$FFAB", "$FFAC", "$FFAD", "$FFAE", "$FFAF", - "$FFB0", "$FFB1", "$FFB2", "$FFB3", "$FFB4", "$FFB5", "$FFB6", "$FFB7", - "$FFB8", "$FFB9", "$FFBA", "$FFBB", "$FFBC", "$FFBD", "$FFBE", "$FFBF" - }; - buf << "Bank = " << std::dec << myCart.getBank() - << ", hotspot = " << spot[myCart.getBank()]; - - return buf.str(); + return info.str(); } diff --git a/src/debugger/gui/CartBFWidget.hxx b/src/debugger/gui/CartBFWidget.hxx index d084dbbc3..6c8d37257 100644 --- a/src/debugger/gui/CartBFWidget.hxx +++ b/src/debugger/gui/CartBFWidget.hxx @@ -19,11 +19,10 @@ #define CARTRIDGEBF_WIDGET_HXX class CartridgeBF; -class PopUpWidget; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class CartridgeBFWidget : public CartDebugWidget +class CartridgeBFWidget : public CartEnhancedWidget { public: CartridgeBFWidget(GuiObject* boss, const GUI::Font& lfont, @@ -33,17 +32,11 @@ class CartridgeBFWidget : public CartDebugWidget virtual ~CartridgeBFWidget() = default; private: - CartridgeBF& myCart; - PopUpWidget* myBank{nullptr}; + string manufacturer() override { return "CPUWIZ"; } - enum { kBankChanged = 'bkCH' }; + string description() override; private: - void loadConfig() override; - void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - - string bankState() override; - // Following constructors and assignment operators not supported CartridgeBFWidget() = delete; CartridgeBFWidget(const CartridgeBFWidget&) = delete; diff --git a/src/debugger/gui/CartCVWidget.cxx b/src/debugger/gui/CartCVWidget.cxx index 167ff7122..1517cc843 100644 --- a/src/debugger/gui/CartCVWidget.cxx +++ b/src/debugger/gui/CartCVWidget.cxx @@ -27,20 +27,6 @@ CartridgeCVWidget::CartridgeCVWidget( : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { initialize(); - - //// Eventually, we should query this from the debugger/disassembler - //uInt16 size = 2048; - //uInt16 start = (cart.myImage[size-3] << 8) | cart.myImage[size-4]; - //start -= start % size; - - //ostringstream info; - //info << "CV 2K ROM + 1K RAM , non-bankswitched\n" - // << "1024 bytes RAM @ $F000 - $F7FF\n" - // << " $F000 - $F3FF (R), $F400 - $F7FF (W)\n" - // << "ROM accessible @ $" << Common::Base::HEX4 << start << " - " - // << "$" << (start + size - 1); - - //addBaseInformation(cart.mySize, "CommaVid", info.str()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -48,77 +34,8 @@ string CartridgeCVWidget::description() { ostringstream info; - info << "CV 2K ROM + 1K RAM , non-bankswitched\n"; + info << "CV 2K ROM + 1K RAM, non-bankswitched\n"; info << CartEnhancedWidget::description(); return info.str(); } - - -//// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -//void CartridgeCVWidget::saveOldState() -//{ -// myOldState.internalram.clear(); -// -// for(uInt32 i = 0; i < internalRamSize(); ++i) -// myOldState.internalram.push_back(myCart.myRAM[i]); -//} -// -//// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -//uInt32 CartridgeCVWidget::internalRamSize() -//{ -// return 1024; -//} -// -//// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -//uInt32 CartridgeCVWidget::internalRamRPort(int start) -//{ -// return 0xF000 + start; -//} -// -//// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -//string CartridgeCVWidget::internalRamDescription() -//{ -// ostringstream desc; -// desc << "$F000 - $F3FF used for Read Access\n" -// << "$F400 - $F7FF used for Write Access"; -// -// return desc.str(); -//} -// -//// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -//const ByteArray& CartridgeCVWidget::internalRamOld(int start, int count) -//{ -// myRamOld.clear(); -// for(int i = 0; i < count; i++) -// myRamOld.push_back(myOldState.internalram[start + i]); -// return myRamOld; -//} -// -//// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -//const ByteArray& CartridgeCVWidget::internalRamCurrent(int start, int count) -//{ -// myRamCurrent.clear(); -// for(int i = 0; i < count; i++) -// myRamCurrent.push_back(myCart.myRAM[start + i]); -// return myRamCurrent; -//} -// -//// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -//void CartridgeCVWidget::internalRamSetValue(int addr, uInt8 value) -//{ -// myCart.myRAM[addr] = value; -//} -// -//// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -//uInt8 CartridgeCVWidget::internalRamGetValue(int addr) -//{ -// return myCart.myRAM[addr]; -//} -// -//// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -//string CartridgeCVWidget::internalRamLabel(int addr) -//{ -// CartDebug& dbg = instance().debugger().cartDebug(); -// return dbg.getLabel(addr + 0xF000, false); -//} diff --git a/src/debugger/gui/CartE0Widget.hxx b/src/debugger/gui/CartE0Widget.hxx index fe3e9d374..0bc5694ea 100644 --- a/src/debugger/gui/CartE0Widget.hxx +++ b/src/debugger/gui/CartE0Widget.hxx @@ -41,6 +41,7 @@ class CartridgeE0Widget : public CartEnhancedWidget string hotspotStr(int bank, int segment) override; int bankSegs() override { return 3; } + private: // Following constructors and assignment operators not supported CartridgeE0Widget() = delete; diff --git a/src/debugger/gui/CartEnhancedWidget.cxx b/src/debugger/gui/CartEnhancedWidget.cxx index 39732fc80..d38c5534c 100644 --- a/src/debugger/gui/CartEnhancedWidget.cxx +++ b/src/debugger/gui/CartEnhancedWidget.cxx @@ -92,25 +92,30 @@ string CartEnhancedWidget::romDescription() if(myCart.romBankCount() > 1) { - info << "Startup bank = #" << myCart.startBank() << " or undetermined\n"; for(int bank = 0, offset = 0xFFC; bank < myCart.romBankCount(); ++bank, offset += 0x1000) { uInt16 start = (image[offset + 1] << 8) | image[offset]; start -= start % 0x1000; - info << "Bank #" << bank << " @ $" + info << "Bank #" << std::dec << bank << " @ $" << Common::Base::HEX4 << (start + myCart.myRomOffset) << " - $" << (start + 0xFFF) << " (hotspot " << hotspotStr(bank) << ")\n"; } + info << "Startup bank = #" << std::dec << myCart.startBank() << " or undetermined\n"; } else { uInt16 start = (image[myCart.mySize - 3] << 8) | image[myCart.mySize - 4]; - start -= start % std::min(int(size), 0x1000); + start -= start % std::min(int(size), 0x1000); + // special check for ROMs where the extra RAM is not included in the image (e.g. CV). + if((start & 0xFFF) < size) + { + start += myCart.myRomOffset; + } info << "ROM accessible @ $" - << Common::Base::HEX4 << (start + myCart.myRomOffset) << " - " - << "$" << Common::Base::HEX4 << (start + myCart.mySize - 1); + << Common::Base::HEX4 << start << " - $" + << Common::Base::HEX4 << (start + myCart.mySize - 1); } return info.str(); @@ -201,7 +206,7 @@ string CartEnhancedWidget::bankState() { buf << "Bank #" << std::dec << myCart.getBank(); - if(hotspot >= 0x100) + //if(hotspot >= 0x100) buf << " (hotspot " << hotspotStr(myCart.getSegmentBank()) << ")"; } return buf.str(); diff --git a/src/debugger/gui/CartEnhancedWidget.hxx b/src/debugger/gui/CartEnhancedWidget.hxx index 3bff6350a..dccc9fde0 100644 --- a/src/debugger/gui/CartEnhancedWidget.hxx +++ b/src/debugger/gui/CartEnhancedWidget.hxx @@ -53,7 +53,7 @@ class CartEnhancedWidget : public CartDebugWidget virtual void bankSelect(int& ypos); - virtual string hotspotStr(int bank, int segment = 0); + virtual string hotspotStr(int bank = 0, int segment = 0); virtual int bankSegs(); // { return myCart.myBankSegs; } diff --git a/src/debugger/gui/CartF0Widget.hxx b/src/debugger/gui/CartF0Widget.hxx index b7aa701bc..9ba5aa3ab 100644 --- a/src/debugger/gui/CartF0Widget.hxx +++ b/src/debugger/gui/CartF0Widget.hxx @@ -38,7 +38,7 @@ class CartridgeF0Widget : public CartEnhancedWidget string bankState() override; -private: + private: // Following constructors and assignment operators not supported CartridgeF0Widget() = delete; CartridgeF0Widget(const CartridgeF0Widget&) = delete; diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index ea167b1d5..3e69a06f8 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -146,9 +146,6 @@ uInt8 CartridgeEnhanced::peek(uInt16 address) bool CartridgeEnhanced::poke(uInt16 address, uInt8 value) { // Switch banks if necessary - // Note: (TODO?) - // The checkSwitchBank() call makes no difference between ROM and e.g TIA space - // Writing to e.g. 0xf0xx might triger a bankswitch, is (and was!) this a bug??? if (checkSwitchBank(address & ADDR_MASK, value)) return false; From e782d60e71104b2ef26cfd6f31c26eaa8843133e Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sun, 19 Apr 2020 15:04:59 -0230 Subject: [PATCH 125/377] Update Windows appveyor build to use latest SDL (2.0.12). --- appveyor.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index a087f4e42..211b69a24 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,15 +7,15 @@ environment: matrix: - Platform: x64 - Platform: Win32 - + Configuration: Release - SDL2_version: 2.0.10 + SDL2_version: 2.0.12 install: - cmd: | - curl -o "C:\SDL2-devel.zip" https://www.libsdl.org/release/SDL2-devel-2.0.10-VC.zip + curl -o "C:\SDL2-devel.zip" "https://www.libsdl.org/release/SDL2-devel-%SDL2_version%-VC.zip" 7z x "C:\SDL2-devel.zip" -o"C:\" xcopy /S "C:\SDL2-%SDL2_version%\include" src\common From 538728579ece3d6b95f294aaac11ff48974d4c80 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sun, 19 Apr 2020 15:10:23 -0230 Subject: [PATCH 126/377] Updated copyright date in Makefile. --- Makefile | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Makefile b/Makefile index b0e41062b..939f0d7cf 100644 --- a/Makefile +++ b/Makefile @@ -8,14 +8,11 @@ ## SS SS tt ee ll ll aa aa ## SSSS ttt eeeee llll llll aaaaa ## -## Copyright (c) 1995-2016 by Bradford W. Mott, Stephen Anthony +## 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. -## -## Based on code from ScummVM - Scumm Interpreter -## Copyright (C) 2002-2004 The ScummVM project ##============================================================================ ####################################################################### From 62c15ec5897491e6499ad7d046641d0ff3589179 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 19 Apr 2020 23:08:25 +0200 Subject: [PATCH 127/377] added 'Turbo" mode --- Changes.txt | 2 ++ docs/index.html | 51 ++++++++++++++++++++------------- src/common/FrameBufferSDL2.cxx | 3 +- src/common/PKeyboardHandler.cxx | 1 + src/emucore/Console.cxx | 22 +++++++++++++- src/emucore/Console.hxx | 5 ++++ src/emucore/Event.hxx | 1 + src/emucore/EventHandler.cxx | 6 ++++ src/emucore/EventHandler.hxx | 2 +- src/emucore/FrameBuffer.cxx | 5 +++- src/emucore/Settings.cxx | 2 ++ 11 files changed, 76 insertions(+), 24 deletions(-) diff --git a/Changes.txt b/Changes.txt index e7faac008..61989ecd9 100644 --- a/Changes.txt +++ b/Changes.txt @@ -22,6 +22,8 @@ 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 'Turbo' mode, runs the game as fast as the computer allows. + * Added option which lets default ROM path follow launcher navigation (TODO: Doc) * Added displaying last write address in the debugger. diff --git a/docs/index.html b/docs/index.html index 18aa916dc..c7185ebe1 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1626,6 +1626,12 @@ Control + i + + Toggle 'Turbo' mode + Control + t + Control + t + + Toggle sound on/off Control + ] @@ -2004,6 +2010,11 @@ Control the emulation speed (as a percentage, 10 - 1000). + +
      -turbo <1|0>
      + Enable 'Turbo' mode for maximum emulation speed. + +
      -uimessages <1|0>
      Enable or disable display of message in the UI. Note that messages @@ -2063,29 +2074,29 @@ Set the pitch o f Pitfall II music. - -
      -tia.zoom <zoom>
      - Use the specified zoom level (integer) while in TIA/emulation mode. - - + +
      -tia.zoom <zoom>
      + Use the specified zoom level (integer) while in TIA/emulation mode. + + - -
      -tia.vsizeadjust <-5 - 5>
      - Adjust the display height of the TIA image - - + +
      -tia.vsizeadjust <-5 - 5>
      + Adjust the display height of the TIA image + + - -
      -tia.inter <1|0>
      - Use interpolation for the TIA image (results in blending/smoothing - of the image). - + +
      -tia.inter <1|0>
      + Use interpolation for the TIA image (results in blending/smoothing + of the image). + - -
      -tia.fs_stretch <1|0>
      - Stretch TIA image completely while in fullscreen mode, vs. keeping the correct - aspect ratio. - + +
      -tia.fs_stretch <1|0>
      + Stretch TIA image completely while in fullscreen mode, vs. keeping the correct + aspect ratio. +
      -tia.fs_overscan <0 - 10>
      diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index d7b9ecb17..bce5c2e7c 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -320,7 +320,8 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) } uInt32 renderFlags = SDL_RENDERER_ACCELERATED; - if(myOSystem.settings().getBool("vsync")) // V'synced blits option + 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 != "") diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index 76d48dd1a..bc2c545ca 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -468,6 +468,7 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo {Event::ToggleColorLoss, KBDK_L, KBDM_CTRL}, {Event::TogglePalette, KBDK_P, KBDM_CTRL}, {Event::ToggleInter, KBDK_I, KBDM_CTRL}, + {Event::ToggleTurbo, KBDK_T, KBDM_CTRL}, {Event::ToggleJitter, KBDK_J, MOD3}, {Event::ToggleFrameStats, KBDK_L, MOD3}, {Event::ToggleTimeMachine, KBDK_T, MOD3}, diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 518030966..fc5c1e9be 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -563,6 +563,24 @@ void Console::toggleInter() myOSystem.frameBuffer().showMessage(ss.str()); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Console::toggleTurbo() +{ + bool enabled = myOSystem.settings().getBool("turbo"); + + myOSystem.settings().setValue("turbo", !enabled); + + // update speed + initializeAudio(); + + // update VSync + myOSystem.createFrameBuffer(); + + ostringstream ss; + ss << "Turbo mode " << (!enabled ? "enabled" : "disabled"); + myOSystem.frameBuffer().showMessage(ss.str()); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::togglePhosphor() { @@ -657,7 +675,9 @@ void Console::initializeAudio() .updatePlaybackPeriod(myAudioSettings.fragmentSize()) .updateAudioQueueExtraFragments(myAudioSettings.bufferSize()) .updateAudioQueueHeadroom(myAudioSettings.headroom()) - .updateSpeedFactor(myOSystem.settings().getFloat("speed")); + .updateSpeedFactor(myOSystem.settings().getBool("turbo") + ? 20.0F + : myOSystem.settings().getFloat("speed")); createAudioQueue(); myTIA->setAudioQueue(myAudioQueue); diff --git a/src/emucore/Console.hxx b/src/emucore/Console.hxx index eb85025a6..33c3b117c 100644 --- a/src/emucore/Console.hxx +++ b/src/emucore/Console.hxx @@ -221,6 +221,11 @@ class Console : public Serializable, public ConsoleIO */ void toggleInter(); + /** + Toggle turbo mode on/off + */ + void toggleTurbo(); + /** Toggles phosphor effect. diff --git a/src/emucore/Event.hxx b/src/emucore/Event.hxx index b82bb7f50..c45fc1e0a 100644 --- a/src/emucore/Event.hxx +++ b/src/emucore/Event.hxx @@ -120,6 +120,7 @@ class Event ToggleFrameStats, ToggleSAPortOrder, ExitGame, // add new events from here to avoid that user remapped events get overwritten + ToggleTurbo, LastType }; diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 4433ed244..1a11c604b 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -539,6 +539,10 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) if (pressed && !repeated) myOSystem.console().toggleInter(); return; + case Event::ToggleTurbo: + if (pressed && !repeated) myOSystem.console().toggleTurbo(); + return; + case Event::ToggleJitter: if (pressed && !repeated) myOSystem.console().toggleJitter(); return; @@ -1815,6 +1819,7 @@ EventHandler::EmulActionList EventHandler::ourEmulActionList = { { { Event::TogglePauseMode, "Toggle Pause mode", "" }, { Event::StartPauseMode, "Start Pause mode", "" }, { Event::Fry, "Fry cartridge", "" }, + { Event::ToggleTurbo, "Toggle Turbo mode", "" }, { Event::DebuggerMode, "Toggle Debugger mode", "" }, { Event::ConsoleSelect, "Select", "" }, @@ -2023,6 +2028,7 @@ EventHandler::MenuActionList EventHandler::ourMenuActionList = { { const Event::EventSet EventHandler::MiscEvents = { Event::Quit, Event::ReloadConsole, Event::Fry, Event::StartPauseMode, Event::TogglePauseMode, Event::OptionsMenuMode, Event::CmdMenuMode, Event::ExitMode, + Event::ToggleTurbo, Event::TakeSnapshot, Event::ToggleContSnapshots, Event::ToggleContSnapshotsFrame, // Event::MouseAxisXMove, Event::MouseAxisYMove, // Event::MouseButtonLeftValue, Event::MouseButtonRightValue, diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx index 7fa56d17d..8148fa085 100644 --- a/src/emucore/EventHandler.hxx +++ b/src/emucore/EventHandler.hxx @@ -468,7 +468,7 @@ class EventHandler #else PNG_SIZE = 0, #endif - EMUL_ACTIONLIST_SIZE = 144 + PNG_SIZE + COMBO_SIZE, + EMUL_ACTIONLIST_SIZE = 145 + PNG_SIZE + COMBO_SIZE, MENU_ACTIONLIST_SIZE = 18 ; diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 68b6e8caa..3c64c5d8f 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -502,7 +502,10 @@ void FrameBuffer::drawFrameStats(float framesPerSecond) ss << std::fixed << std::setprecision(1) << framesPerSecond << "fps @ " - << std::fixed << std::setprecision(0) << 100 * myOSystem.settings().getFloat("speed") + << std::fixed << std::setprecision(0) << 100 * + (myOSystem.settings().getBool("turbo") + ? 20.0F + : myOSystem.settings().getFloat("speed")) << "% speed"; myStatsMsg.surface->drawString(f, ss.str(), xPos, yPos, diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index c3feece37..50e45cd06 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -157,6 +157,7 @@ Settings::Settings() setPermanent("threads", "false"); setTemporary("romloadcount", "0"); setTemporary("maxres", ""); + setTemporary("turbo", "0"); #ifdef DEBUGGER_SUPPORT // Debugger/disassembly options @@ -400,6 +401,7 @@ void Settings::usage() const << " z26|\n" << " user>\n" << " -speed Run emulation at the given speed\n" + << " -turbo <1|0> Enable 'Turbo' mode for maximum emulation speed\n" << " -uimessages <1|0> Show onscreen UI messages for different events\n" << endl #ifdef SOUND_SUPPORT From 77fb0ef009c81c672dd1e9101021f5024c53e6c3 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 19 Apr 2020 23:21:08 +0200 Subject: [PATCH 128/377] some cleanup in CartCVWidget --- src/debugger/gui/CartCVWidget.hxx | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/src/debugger/gui/CartCVWidget.hxx b/src/debugger/gui/CartCVWidget.hxx index 73452204c..dd8e971ab 100644 --- a/src/debugger/gui/CartCVWidget.hxx +++ b/src/debugger/gui/CartCVWidget.hxx @@ -31,35 +31,11 @@ class CartridgeCVWidget : public CartEnhancedWidget CartridgeCV& cart); virtual ~CartridgeCVWidget() = default; - private: - //CartridgeCV& myCart; - //struct CartState { - // ByteArray internalram; - //}; - //CartState myOldState; - private: string manufacturer() override { return "CommaVid"; } string description() override; - //// No implementation for non-bankswitched ROMs - //void loadConfig() override { } - //void handleCommand(CommandSender* sender, int cmd, int data, int id) override { } - - //void saveOldState() override; - - //// start of functions for Cartridge RAM tab - //uInt32 internalRamSize() override; - //uInt32 internalRamRPort(int start) override; - //string internalRamDescription() override; - //const ByteArray& internalRamOld(int start, int count) override; - //const ByteArray& internalRamCurrent(int start, int count) override; - //void internalRamSetValue(int addr, uInt8 value) override; - //uInt8 internalRamGetValue(int addr) override; - //string internalRamLabel(int addr) override; - //// end of functions for Cartridge RAM tab - private: // Following constructors and assignment operators not supported CartridgeCVWidget() = delete; From 4e6734b1803a06d697b01c86a86e50b4779c15ec Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 19 Apr 2020 23:08:25 +0200 Subject: [PATCH 129/377] added 'Turbo" mode --- Changes.txt | 4 ++- docs/index.html | 51 ++++++++++++++++++++------------- src/common/FrameBufferSDL2.cxx | 3 +- src/common/PKeyboardHandler.cxx | 1 + src/emucore/Console.cxx | 22 +++++++++++++- src/emucore/Console.hxx | 5 ++++ src/emucore/Event.hxx | 1 + src/emucore/EventHandler.cxx | 6 ++++ src/emucore/EventHandler.hxx | 2 +- src/emucore/FrameBuffer.cxx | 5 +++- src/emucore/Settings.cxx | 2 ++ 11 files changed, 77 insertions(+), 25 deletions(-) diff --git a/Changes.txt b/Changes.txt index 60fd29f4e..a12cef9d1 100644 --- a/Changes.txt +++ b/Changes.txt @@ -22,7 +22,9 @@ 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) - * Add option which lets default ROM path follow launcher navigation (TODO: Doc) + * Added 'Turbo' mode, runs the game as fast as the computer allows. + + * Added option which lets default ROM path follow launcher navigation (TODO: Doc) * Added displaying last write address in the debugger. diff --git a/docs/index.html b/docs/index.html index 68be48e0d..e57dd3d51 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1626,6 +1626,12 @@ Control + i + + Toggle 'Turbo' mode + Control + t + Control + t + + Toggle sound on/off Control + ] @@ -2004,6 +2010,11 @@ Control the emulation speed (as a percentage, 10 - 1000). + +
      -turbo <1|0>
      + Enable 'Turbo' mode for maximum emulation speed. + +
      -uimessages <1|0>
      Enable or disable display of message in the UI. Note that messages @@ -2063,29 +2074,29 @@ Set the pitch o f Pitfall II music. - -
      -tia.zoom <zoom>
      - Use the specified zoom level (integer) while in TIA/emulation mode. - - + +
      -tia.zoom <zoom>
      + Use the specified zoom level (integer) while in TIA/emulation mode. + + - -
      -tia.vsizeadjust <-5 - 5>
      - Adjust the display height of the TIA image - - + +
      -tia.vsizeadjust <-5 - 5>
      + Adjust the display height of the TIA image + + - -
      -tia.inter <1|0>
      - Use interpolation for the TIA image (results in blending/smoothing - of the image). - + +
      -tia.inter <1|0>
      + Use interpolation for the TIA image (results in blending/smoothing + of the image). + - -
      -tia.fs_stretch <1|0>
      - Stretch TIA image completely while in fullscreen mode, vs. keeping the correct - aspect ratio. - + +
      -tia.fs_stretch <1|0>
      + Stretch TIA image completely while in fullscreen mode, vs. keeping the correct + aspect ratio. +
      -tia.fs_overscan <0 - 10>
      diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index d7b9ecb17..bce5c2e7c 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -320,7 +320,8 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) } uInt32 renderFlags = SDL_RENDERER_ACCELERATED; - if(myOSystem.settings().getBool("vsync")) // V'synced blits option + 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 != "") diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index 76d48dd1a..bc2c545ca 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -468,6 +468,7 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo {Event::ToggleColorLoss, KBDK_L, KBDM_CTRL}, {Event::TogglePalette, KBDK_P, KBDM_CTRL}, {Event::ToggleInter, KBDK_I, KBDM_CTRL}, + {Event::ToggleTurbo, KBDK_T, KBDM_CTRL}, {Event::ToggleJitter, KBDK_J, MOD3}, {Event::ToggleFrameStats, KBDK_L, MOD3}, {Event::ToggleTimeMachine, KBDK_T, MOD3}, diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 518030966..fc5c1e9be 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -563,6 +563,24 @@ void Console::toggleInter() myOSystem.frameBuffer().showMessage(ss.str()); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Console::toggleTurbo() +{ + bool enabled = myOSystem.settings().getBool("turbo"); + + myOSystem.settings().setValue("turbo", !enabled); + + // update speed + initializeAudio(); + + // update VSync + myOSystem.createFrameBuffer(); + + ostringstream ss; + ss << "Turbo mode " << (!enabled ? "enabled" : "disabled"); + myOSystem.frameBuffer().showMessage(ss.str()); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::togglePhosphor() { @@ -657,7 +675,9 @@ void Console::initializeAudio() .updatePlaybackPeriod(myAudioSettings.fragmentSize()) .updateAudioQueueExtraFragments(myAudioSettings.bufferSize()) .updateAudioQueueHeadroom(myAudioSettings.headroom()) - .updateSpeedFactor(myOSystem.settings().getFloat("speed")); + .updateSpeedFactor(myOSystem.settings().getBool("turbo") + ? 20.0F + : myOSystem.settings().getFloat("speed")); createAudioQueue(); myTIA->setAudioQueue(myAudioQueue); diff --git a/src/emucore/Console.hxx b/src/emucore/Console.hxx index eb85025a6..33c3b117c 100644 --- a/src/emucore/Console.hxx +++ b/src/emucore/Console.hxx @@ -221,6 +221,11 @@ class Console : public Serializable, public ConsoleIO */ void toggleInter(); + /** + Toggle turbo mode on/off + */ + void toggleTurbo(); + /** Toggles phosphor effect. diff --git a/src/emucore/Event.hxx b/src/emucore/Event.hxx index b82bb7f50..c45fc1e0a 100644 --- a/src/emucore/Event.hxx +++ b/src/emucore/Event.hxx @@ -120,6 +120,7 @@ class Event ToggleFrameStats, ToggleSAPortOrder, ExitGame, // add new events from here to avoid that user remapped events get overwritten + ToggleTurbo, LastType }; diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 4433ed244..1a11c604b 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -539,6 +539,10 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) if (pressed && !repeated) myOSystem.console().toggleInter(); return; + case Event::ToggleTurbo: + if (pressed && !repeated) myOSystem.console().toggleTurbo(); + return; + case Event::ToggleJitter: if (pressed && !repeated) myOSystem.console().toggleJitter(); return; @@ -1815,6 +1819,7 @@ EventHandler::EmulActionList EventHandler::ourEmulActionList = { { { Event::TogglePauseMode, "Toggle Pause mode", "" }, { Event::StartPauseMode, "Start Pause mode", "" }, { Event::Fry, "Fry cartridge", "" }, + { Event::ToggleTurbo, "Toggle Turbo mode", "" }, { Event::DebuggerMode, "Toggle Debugger mode", "" }, { Event::ConsoleSelect, "Select", "" }, @@ -2023,6 +2028,7 @@ EventHandler::MenuActionList EventHandler::ourMenuActionList = { { const Event::EventSet EventHandler::MiscEvents = { Event::Quit, Event::ReloadConsole, Event::Fry, Event::StartPauseMode, Event::TogglePauseMode, Event::OptionsMenuMode, Event::CmdMenuMode, Event::ExitMode, + Event::ToggleTurbo, Event::TakeSnapshot, Event::ToggleContSnapshots, Event::ToggleContSnapshotsFrame, // Event::MouseAxisXMove, Event::MouseAxisYMove, // Event::MouseButtonLeftValue, Event::MouseButtonRightValue, diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx index 7fa56d17d..8148fa085 100644 --- a/src/emucore/EventHandler.hxx +++ b/src/emucore/EventHandler.hxx @@ -468,7 +468,7 @@ class EventHandler #else PNG_SIZE = 0, #endif - EMUL_ACTIONLIST_SIZE = 144 + PNG_SIZE + COMBO_SIZE, + EMUL_ACTIONLIST_SIZE = 145 + PNG_SIZE + COMBO_SIZE, MENU_ACTIONLIST_SIZE = 18 ; diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 68b6e8caa..3c64c5d8f 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -502,7 +502,10 @@ void FrameBuffer::drawFrameStats(float framesPerSecond) ss << std::fixed << std::setprecision(1) << framesPerSecond << "fps @ " - << std::fixed << std::setprecision(0) << 100 * myOSystem.settings().getFloat("speed") + << std::fixed << std::setprecision(0) << 100 * + (myOSystem.settings().getBool("turbo") + ? 20.0F + : myOSystem.settings().getFloat("speed")) << "% speed"; myStatsMsg.surface->drawString(f, ss.str(), xPos, yPos, diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index c3feece37..50e45cd06 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -157,6 +157,7 @@ Settings::Settings() setPermanent("threads", "false"); setTemporary("romloadcount", "0"); setTemporary("maxres", ""); + setTemporary("turbo", "0"); #ifdef DEBUGGER_SUPPORT // Debugger/disassembly options @@ -400,6 +401,7 @@ void Settings::usage() const << " z26|\n" << " user>\n" << " -speed Run emulation at the given speed\n" + << " -turbo <1|0> Enable 'Turbo' mode for maximum emulation speed\n" << " -uimessages <1|0> Show onscreen UI messages for different events\n" << endl #ifdef SOUND_SUPPORT From c198372c2996c88556581199a7c683fcb3cfa73a Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 20 Apr 2020 12:45:05 +0200 Subject: [PATCH 130/377] sort single file ZIP files correctly (fixes #612) --- src/emucore/FSNode.cxx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/emucore/FSNode.cxx b/src/emucore/FSNode.cxx index 6965839ef..64af7212e 100644 --- a/src/emucore/FSNode.cxx +++ b/src/emucore/FSNode.cxx @@ -58,6 +58,20 @@ bool FilesystemNode::getChildren(FSList& fslist, ListMode mode, if (!_realNode->getChildren(tmp, mode)) return false; + #if defined(ZIP_SUPPORT) + // before sorting, replace single file ZIP archive names with contained file names + // because they are displayed using their contained file names + for (auto& i : tmp) + { + if (BSPF::endsWithIgnoreCase(i->getPath(), ".zip")) + { + FilesystemNodeZIP node(i->getPath()); + + i->setName(node.getName()); + } + } + #endif + std::sort(tmp.begin(), tmp.end(), [](const AbstractFSNodePtr& node1, const AbstractFSNodePtr& node2) { From b61f83bad60062031314fa8e75e1f7a65c362f5b Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 20 Apr 2020 12:45:05 +0200 Subject: [PATCH 131/377] sort single file ZIP files correctly (fixes #612) --- src/emucore/FSNode.cxx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/emucore/FSNode.cxx b/src/emucore/FSNode.cxx index 6965839ef..64af7212e 100644 --- a/src/emucore/FSNode.cxx +++ b/src/emucore/FSNode.cxx @@ -58,6 +58,20 @@ bool FilesystemNode::getChildren(FSList& fslist, ListMode mode, if (!_realNode->getChildren(tmp, mode)) return false; + #if defined(ZIP_SUPPORT) + // before sorting, replace single file ZIP archive names with contained file names + // because they are displayed using their contained file names + for (auto& i : tmp) + { + if (BSPF::endsWithIgnoreCase(i->getPath(), ".zip")) + { + FilesystemNodeZIP node(i->getPath()); + + i->setName(node.getName()); + } + } + #endif + std::sort(tmp.begin(), tmp.end(), [](const AbstractFSNodePtr& node1, const AbstractFSNodePtr& node2) { From e8f7bbce6547ea895b3d98555459ac2120009726 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 20 Apr 2020 20:46:28 +0200 Subject: [PATCH 132/377] Improved 3E auto detection --- src/emucore/CartDetector.cxx | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/emucore/CartDetector.cxx b/src/emucore/CartDetector.cxx index 4d7a583eb..b40e75c49 100644 --- a/src/emucore/CartDetector.cxx +++ b/src/emucore/CartDetector.cxx @@ -620,11 +620,16 @@ bool CartDetector::isProbably0840(const ByteBuffer& image, size_t size) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbably3E(const ByteBuffer& image, size_t size) { - // 3E cart bankswitching is triggered by storing the bank number - // in address 3E using 'STA $3E', commonly followed by an - // immediate mode LDA - uInt8 signature[] = { 0x85, 0x3E, 0xA9, 0x00 }; // STA $3E; LDA #$00 - return searchForBytes(image.get(), size, signature, 4, 1); + // 3E cart RAM bankswitching is triggered by storing the bank number + // in address 3E using 'STA $3E', ROM bankswitching is triggered by + // storing the bank number in address 3F using 'STA $3F'. + // We expect the latter will be present at least 2 times, since there + // are at least two banks + + uInt8 signature1[] = { 0x85, 0x3E }; // STA $3E + uInt8 signature2[] = { 0x85, 0x3F }; // STA $3F + return searchForBytes(image.get(), size, signature1, 2, 1) + && searchForBytes(image.get(), size, signature2, 2, 2); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From cc78be70d5be07b23ed4c2eac7d2d75ede71b117 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 20 Apr 2020 21:06:16 +0200 Subject: [PATCH 133/377] refactored CartDF(SC)Widget and CartEF(SC)Widget classes --- src/debugger/gui/CartDFSCWidget.cxx | 178 ++-------------------------- src/debugger/gui/CartDFSCWidget.hxx | 33 +----- src/debugger/gui/CartDFWidget.cxx | 109 ++--------------- src/debugger/gui/CartDFWidget.hxx | 15 +-- src/debugger/gui/CartEFSCWidget.cxx | 160 ++----------------------- src/debugger/gui/CartEFSCWidget.hxx | 33 +----- src/debugger/gui/CartEFWidget.cxx | 91 ++------------ src/debugger/gui/CartEFWidget.hxx | 15 +-- 8 files changed, 52 insertions(+), 582 deletions(-) diff --git a/src/debugger/gui/CartDFSCWidget.cxx b/src/debugger/gui/CartDFSCWidget.cxx index e03fbf1c6..0744ca182 100644 --- a/src/debugger/gui/CartDFSCWidget.cxx +++ b/src/debugger/gui/CartDFSCWidget.cxx @@ -15,185 +15,25 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#include "Debugger.hxx" -#include "CartDebug.hxx" #include "CartDFSC.hxx" -#include "PopUpWidget.hxx" #include "CartDFSCWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeDFSCWidget::CartridgeDFSCWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeDFSC& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) + : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { - uInt32 size = 32 * 4096; + initialize(); +} +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartridgeDFSCWidget::description() +{ ostringstream info; - info << "128K DFSC + RAM, 32 4K banks\n" - << "128 bytes RAM @ $F000 - $F0FF\n" - << " $F080 - $F0FF (R), $F000 - $F07F (W)\n" - << "Startup bank = " << cart.startBank() << "\n"; - // Eventually, we should query this from the debugger/disassembler - for(uInt32 i = 0, offset = 0xFFC, spot = 0xFC0; i < 32; ++i, offset += 0x1000) - { - uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; - start -= start % 0x1000; - info << "Bank " << std::dec << i << " @ $" << Common::Base::HEX4 << (start + 0x100) - << " - " << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; - } + info << "128K DFSC + RAM, 32 4K banks\n"; + info << CartEnhancedWidget::description(); - int xpos = 2, - ypos = addBaseInformation(size, "CPUWIZ", info.str()) + myLineHeight; - - VariantList items; - VarList::push_back(items, " 0 ($FFC0)"); - VarList::push_back(items, " 1 ($FFC1)"); - VarList::push_back(items, " 2 ($FFC2)"); - VarList::push_back(items, " 3 ($FFC3)"); - VarList::push_back(items, " 4 ($FFC4)"); - VarList::push_back(items, " 5 ($FFC5)"); - VarList::push_back(items, " 6 ($FFC6)"); - VarList::push_back(items, " 7 ($FFC7)"); - VarList::push_back(items, " 8 ($FFC8)"); - VarList::push_back(items, " 9 ($FFC9)"); - VarList::push_back(items, "10 ($FFCA)"); - VarList::push_back(items, "11 ($FFCB)"); - VarList::push_back(items, "12 ($FFCC)"); - VarList::push_back(items, "13 ($FFCD)"); - VarList::push_back(items, "14 ($FFCE)"); - VarList::push_back(items, "15 ($FFCF)"); - VarList::push_back(items, "16 ($FFD0)"); - VarList::push_back(items, "17 ($FFD1)"); - VarList::push_back(items, "18 ($FFD2)"); - VarList::push_back(items, "19 ($FFD3)"); - VarList::push_back(items, "20 ($FFD4)"); - VarList::push_back(items, "21 ($FFD5)"); - VarList::push_back(items, "22 ($FFD6)"); - VarList::push_back(items, "23 ($FFD7)"); - VarList::push_back(items, "24 ($FFD8)"); - VarList::push_back(items, "25 ($FFD9)"); - VarList::push_back(items, "26 ($FFDA)"); - VarList::push_back(items, "27 ($FFDB)"); - VarList::push_back(items, "28 ($FFDC)"); - VarList::push_back(items, "29 ($FFDD)"); - VarList::push_back(items, "30 ($FFDE)"); - VarList::push_back(items, "31 ($FFDF)"); - - myBank = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("31 ($FFE0)"), - myLineHeight, items, "Set bank ", - 0, kBankChanged); - myBank->setTarget(this); - addFocusWidget(myBank); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeDFSCWidget::saveOldState() -{ - myOldState.internalram.clear(); - - for(uInt32 i = 0; i < internalRamSize(); ++i) - myOldState.internalram.push_back(myCart.myRAM[i]); - - myOldState.bank = myCart.getBank(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeDFSCWidget::loadConfig() -{ - myBank->setSelectedIndex(myCart.getBank(), myCart.getBank() != myOldState.bank); - - CartDebugWidget::loadConfig(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeDFSCWidget::handleCommand(CommandSender* sender, - int cmd, int data, int id) -{ - if(cmd == kBankChanged) - { - myCart.unlockBank(); - myCart.bank(myBank->getSelected()); - myCart.lockBank(); - invalidate(); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeDFSCWidget::bankState() -{ - ostringstream& buf = buffer(); - - static constexpr std::array spot = { - "$FFC0", "$FFC1", "$FFC2", "$FFC3", "$FFC4", "$FFC5", "$FFC6", "$FFC7", - "$FFC8", "$FFC9", "$FFCA", "$FFCB", "$FFCC", "$FFCD", "$FFCE", "$FFCF", - "$FFD0", "$FFD1", "$FFD2", "$FFD3", "$FFD4", "$FFD5", "$FFD6", "$FFE7", - "$FFD8", "$FFD9", "$FFDA", "$FFDB", "$FFDC", "$FFDD", "$FFDE", "$FFDF" - }; - buf << "Bank = " << std::dec << myCart.getBank() - << ", hotspot = " << spot[myCart.getBank()]; - - return buf.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 CartridgeDFSCWidget::internalRamSize() -{ - return 128; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 CartridgeDFSCWidget::internalRamRPort(int start) -{ - return 0xF080 + start; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeDFSCWidget::internalRamDescription() -{ - ostringstream desc; - desc << "$F000 - $F07F used for Write Access\n" - << "$F080 - $F0FF used for Read Access"; - - return desc.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& CartridgeDFSCWidget::internalRamOld(int start, int count) -{ - myRamOld.clear(); - for(int i = 0; i < count; i++) - myRamOld.push_back(myOldState.internalram[start + i]); - return myRamOld; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& CartridgeDFSCWidget::internalRamCurrent(int start, int count) -{ - myRamCurrent.clear(); - for(int i = 0; i < count; i++) - myRamCurrent.push_back(myCart.myRAM[start + i]); - return myRamCurrent; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeDFSCWidget::internalRamSetValue(int addr, uInt8 value) -{ - myCart.myRAM[addr] = value; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeDFSCWidget::internalRamGetValue(int addr) -{ - return myCart.myRAM[addr]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeDFSCWidget::internalRamLabel(int addr) -{ - CartDebug& dbg = instance().debugger().cartDebug(); - return dbg.getLabel(addr + 0xF080, false); + return info.str(); } diff --git a/src/debugger/gui/CartDFSCWidget.hxx b/src/debugger/gui/CartDFSCWidget.hxx index 4d4a07feb..7aff641ee 100644 --- a/src/debugger/gui/CartDFSCWidget.hxx +++ b/src/debugger/gui/CartDFSCWidget.hxx @@ -19,11 +19,10 @@ #define CARTRIDGEDFSC_WIDGET_HXX class CartridgeDFSC; -class PopUpWidget; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class CartridgeDFSCWidget : public CartDebugWidget +class CartridgeDFSCWidget : public CartEnhancedWidget { public: CartridgeDFSCWidget(GuiObject* boss, const GUI::Font& lfont, @@ -33,35 +32,11 @@ class CartridgeDFSCWidget : public CartDebugWidget virtual ~CartridgeDFSCWidget() = default; private: - CartridgeDFSC& myCart; - PopUpWidget* myBank{nullptr}; + string manufacturer() override { return "CPUWIZ"; } - struct CartState { - ByteArray internalram; - uInt16 bank{0}; - }; - CartState myOldState; - - enum { kBankChanged = 'bkCH' }; + string description() override; private: - void saveOldState() override; - void loadConfig() override; - void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - - string bankState() override; - - // start of functions for Cartridge RAM tab - uInt32 internalRamSize() override; - uInt32 internalRamRPort(int start) override; - string internalRamDescription() override; - const ByteArray& internalRamOld(int start, int count) override; - const ByteArray& internalRamCurrent(int start, int count) override; - void internalRamSetValue(int addr, uInt8 value) override; - uInt8 internalRamGetValue(int addr) override; - string internalRamLabel(int addr) override; - // end of functions for Cartridge RAM tab - // Following constructors and assignment operators not supported CartridgeDFSCWidget() = delete; CartridgeDFSCWidget(const CartridgeDFSCWidget&) = delete; diff --git a/src/debugger/gui/CartDFWidget.cxx b/src/debugger/gui/CartDFWidget.cxx index c8fde5fff..cdb6d4f1b 100644 --- a/src/debugger/gui/CartDFWidget.cxx +++ b/src/debugger/gui/CartDFWidget.cxx @@ -16,115 +16,24 @@ //============================================================================ #include "CartDF.hxx" -#include "PopUpWidget.hxx" #include "CartDFWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeDFWidget::CartridgeDFWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeDF& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) + : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { - uInt32 size = 32 * 4096; + initialize(); +} +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartridgeDFWidget::description() +{ ostringstream info; - info << "EF 2 cartridge, 32 4K banks\n" - << "Startup bank = " << cart.startBank() << "\n"; - // Eventually, we should query this from the debugger/disassembler - for(uInt32 i = 0, offset = 0xFFC, spot = 0xFD0; i < 32; ++i, offset += 0x1000) - { - uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; - start -= start % 0x1000; - info << "Bank " << std::dec << i << " @ $" << Common::Base::HEX4 << start << " - " - << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; - } + info << "128K DF, 32 4K banks\n"; + info << CartEnhancedWidget::description(); - int xpos = 2, - ypos = addBaseInformation(size, "CPUWIZ", info.str()) + myLineHeight; - - VariantList items; - VarList::push_back(items, " 0 ($FFC0)"); - VarList::push_back(items, " 1 ($FFC1)"); - VarList::push_back(items, " 2 ($FFC2)"); - VarList::push_back(items, " 3 ($FFC3)"); - VarList::push_back(items, " 4 ($FFC4)"); - VarList::push_back(items, " 5 ($FFC5)"); - VarList::push_back(items, " 6 ($FFC6)"); - VarList::push_back(items, " 7 ($FFC7)"); - VarList::push_back(items, " 8 ($FFC8)"); - VarList::push_back(items, " 9 ($FFC9)"); - VarList::push_back(items, "10 ($FFCA)"); - VarList::push_back(items, "11 ($FFCB)"); - VarList::push_back(items, "12 ($FFCC)"); - VarList::push_back(items, "13 ($FFCD)"); - VarList::push_back(items, "14 ($FFCE)"); - VarList::push_back(items, "15 ($FFCF)"); - VarList::push_back(items, "16 ($FFD0)"); - VarList::push_back(items, "17 ($FFD1)"); - VarList::push_back(items, "18 ($FFD2)"); - VarList::push_back(items, "19 ($FFD3)"); - VarList::push_back(items, "20 ($FFD4)"); - VarList::push_back(items, "21 ($FFD5)"); - VarList::push_back(items, "22 ($FFD6)"); - VarList::push_back(items, "23 ($FFD7)"); - VarList::push_back(items, "24 ($FFD8)"); - VarList::push_back(items, "25 ($FFD9)"); - VarList::push_back(items, "26 ($FFDA)"); - VarList::push_back(items, "27 ($FFDB)"); - VarList::push_back(items, "28 ($FFDC)"); - VarList::push_back(items, "29 ($FFDD)"); - VarList::push_back(items, "30 ($FFDE)"); - VarList::push_back(items, "31 ($FFDF)"); - - myBank = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("31 ($FFDF)"), - myLineHeight, items, "Set bank ", - 0, kBankChanged); - myBank->setTarget(this); - addFocusWidget(myBank); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeDFWidget::loadConfig() -{ - Debugger& dbg = instance().debugger(); - CartDebug& cart = dbg.cartDebug(); - const CartState& state = static_cast(cart.getState()); - const CartState& oldstate = static_cast(cart.getOldState()); - - myBank->setSelectedIndex(myCart.getBank(), state.bank != oldstate.bank); - - CartDebugWidget::loadConfig(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeDFWidget::handleCommand(CommandSender* sender, - int cmd, int data, int id) -{ - if(cmd == kBankChanged) - { - myCart.unlockBank(); - myCart.bank(myBank->getSelected()); - myCart.lockBank(); - invalidate(); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeDFWidget::bankState() -{ - ostringstream& buf = buffer(); - - static constexpr std::array spot = { - "$FFC0", "$FFC1", "$FFC2", "$FFC3", "$FFC4", "$FFC5", "$FFC6", "$FFC7", - "$FFC8", "$FFC9", "$FFCA", "$FFCB", "$FFCC", "$FFCD", "$FFCE", "$FFCF", - "$FFD0", "$FFD1", "$FFD2", "$FFD3", "$FFD4", "$FFD5", "$FFD6", "$FFD7", - "$FFD8", "$FFD9", "$FFDA", "$FFDB", "$FFDC", "$FFDD", "$FFDE", "$FFDF" - }; - buf << "Bank = " << std::dec << myCart.getBank() - << ", hotspot = " << spot[myCart.getBank()]; - - return buf.str(); + return info.str(); } diff --git a/src/debugger/gui/CartDFWidget.hxx b/src/debugger/gui/CartDFWidget.hxx index 146763b75..d37176627 100644 --- a/src/debugger/gui/CartDFWidget.hxx +++ b/src/debugger/gui/CartDFWidget.hxx @@ -19,11 +19,10 @@ #define CARTRIDGEDF_WIDGET_HXX class CartridgeDF; -class PopUpWidget; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class CartridgeDFWidget : public CartDebugWidget +class CartridgeDFWidget : public CartEnhancedWidget { public: CartridgeDFWidget(GuiObject* boss, const GUI::Font& lfont, @@ -33,17 +32,11 @@ class CartridgeDFWidget : public CartDebugWidget virtual ~CartridgeDFWidget() = default; private: - CartridgeDF& myCart; - PopUpWidget* myBank{nullptr}; + string manufacturer() override { return "CPUWIZ"; } - enum { kBankChanged = 'bkCH' }; + string description() override; private: - void loadConfig() override; - void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - - string bankState() override; - // Following constructors and assignment operators not supported CartridgeDFWidget() = delete; CartridgeDFWidget(const CartridgeDFWidget&) = delete; diff --git a/src/debugger/gui/CartEFSCWidget.cxx b/src/debugger/gui/CartEFSCWidget.cxx index a7bae36c7..8783ca09f 100644 --- a/src/debugger/gui/CartEFSCWidget.cxx +++ b/src/debugger/gui/CartEFSCWidget.cxx @@ -15,167 +15,25 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#include "Debugger.hxx" -#include "CartDebug.hxx" #include "CartEFSC.hxx" -#include "PopUpWidget.hxx" #include "CartEFSCWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeEFSCWidget::CartridgeEFSCWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeEFSC& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) + : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { - uInt32 size = 16 * 4096; + initialize(); +} +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartridgeEFSCWidget::description() +{ ostringstream info; - info << "64K H. Runner EFSC + RAM, 16 4K banks\n" - << "128 bytes RAM @ $F000 - $F0FF\n" - << " $F080 - $F0FF (R), $F000 - $F07F (W)\n" - << "Startup bank = " << cart.startBank() << "\n"; - // Eventually, we should query this from the debugger/disassembler - for(uInt32 i = 0, offset = 0xFFC, spot = 0xFE0; i < 16; ++i, offset += 0x1000) - { - uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; - start -= start % 0x1000; - info << "Bank " << std::dec << i << " @ $" << Common::Base::HEX4 << (start + 0x100) - << " - " << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; - } + info << "64K H. Runner EFSC + RAM, 16 4K banks\n"; + info << CartEnhancedWidget::description(); - int xpos = 2, - ypos = addBaseInformation(size, "Paul Slocum / Homestar Runner", - info.str()) + myLineHeight; - - VariantList items; - VarList::push_back(items, " 0 ($FFE0)"); - VarList::push_back(items, " 1 ($FFE1)"); - VarList::push_back(items, " 2 ($FFE2)"); - VarList::push_back(items, " 3 ($FFE3)"); - VarList::push_back(items, " 4 ($FFE4)"); - VarList::push_back(items, " 5 ($FFE5)"); - VarList::push_back(items, " 6 ($FFE6)"); - VarList::push_back(items, " 7 ($FFE7)"); - VarList::push_back(items, " 8 ($FFE8)"); - VarList::push_back(items, " 9 ($FFE9)"); - VarList::push_back(items, "10 ($FFEA)"); - VarList::push_back(items, "11 ($FFEB)"); - VarList::push_back(items, "12 ($FFEC)"); - VarList::push_back(items, "13 ($FFED)"); - VarList::push_back(items, "14 ($FFEE)"); - VarList::push_back(items, "15 ($FFEF)"); - myBank = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("15 ($FFE0)"), - myLineHeight, items, "Set bank ", - 0, kBankChanged); - myBank->setTarget(this); - addFocusWidget(myBank); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeEFSCWidget::saveOldState() -{ - myOldState.internalram.clear(); - - for(uInt32 i = 0; i < internalRamSize(); ++i) - myOldState.internalram.push_back(myCart.myRAM[i]); - - myOldState.bank = myCart.getBank(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeEFSCWidget::loadConfig() -{ - myBank->setSelectedIndex(myCart.getBank(), myCart.getBank() != myOldState.bank); - - CartDebugWidget::loadConfig(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeEFSCWidget::handleCommand(CommandSender* sender, - int cmd, int data, int id) -{ - if(cmd == kBankChanged) - { - myCart.unlockBank(); - myCart.bank(myBank->getSelected()); - myCart.lockBank(); - invalidate(); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeEFSCWidget::bankState() -{ - ostringstream& buf = buffer(); - - static constexpr std::array spot = { - "$FFE0", "$FFE1", "$FFE2", "$FFE3", "$FFE4", "$FFE5", "$FFE6", "$FFE7", - "$FFE8", "$FFE9", "$FFEA", "$FFEB", "$FFEC", "$FFED", "$FFEE", "$FFEF" - }; - buf << "Bank = " << std::dec << myCart.getBank() - << ", hotspot = " << spot[myCart.getBank()]; - - return buf.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 CartridgeEFSCWidget::internalRamSize() -{ - return 128; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 CartridgeEFSCWidget::internalRamRPort(int start) -{ - return 0xF080 + start; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeEFSCWidget::internalRamDescription() -{ - ostringstream desc; - desc << "$F000 - $F07F used for Write Access\n" - << "$F080 - $F0FF used for Read Access"; - - return desc.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& CartridgeEFSCWidget::internalRamOld(int start, int count) -{ - myRamOld.clear(); - for(int i = 0; i < count; i++) - myRamOld.push_back(myOldState.internalram[start + i]); - return myRamOld; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& CartridgeEFSCWidget::internalRamCurrent(int start, int count) -{ - myRamCurrent.clear(); - for(int i = 0; i < count; i++) - myRamCurrent.push_back(myCart.myRAM[start + i]); - return myRamCurrent; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeEFSCWidget::internalRamSetValue(int addr, uInt8 value) -{ - myCart.myRAM[addr] = value; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeEFSCWidget::internalRamGetValue(int addr) -{ - return myCart.myRAM[addr]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeEFSCWidget::internalRamLabel(int addr) -{ - CartDebug& dbg = instance().debugger().cartDebug(); - return dbg.getLabel(addr + 0xF080, false); + return info.str(); } diff --git a/src/debugger/gui/CartEFSCWidget.hxx b/src/debugger/gui/CartEFSCWidget.hxx index b9e902f69..c5d6c4eeb 100644 --- a/src/debugger/gui/CartEFSCWidget.hxx +++ b/src/debugger/gui/CartEFSCWidget.hxx @@ -19,11 +19,10 @@ #define CARTRIDGEEFSC_WIDGET_HXX class CartridgeEFSC; -class PopUpWidget; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class CartridgeEFSCWidget : public CartDebugWidget +class CartridgeEFSCWidget : public CartEnhancedWidget { public: CartridgeEFSCWidget(GuiObject* boss, const GUI::Font& lfont, @@ -33,35 +32,11 @@ class CartridgeEFSCWidget : public CartDebugWidget virtual ~CartridgeEFSCWidget() = default; private: - CartridgeEFSC& myCart; - PopUpWidget* myBank{nullptr}; + string manufacturer() override { return "Paul Slocum / Homestar Runner"; } - struct CartState { - ByteArray internalram; - uInt16 bank{0}; - }; - CartState myOldState; - - enum { kBankChanged = 'bkCH' }; + string description() override; private: - void saveOldState() override; - void loadConfig() override; - void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - - string bankState() override; - - // start of functions for Cartridge RAM tab - uInt32 internalRamSize() override; - uInt32 internalRamRPort(int start) override; - string internalRamDescription() override; - const ByteArray& internalRamOld(int start, int count) override; - const ByteArray& internalRamCurrent(int start, int count) override; - void internalRamSetValue(int addr, uInt8 value) override; - uInt8 internalRamGetValue(int addr) override; - string internalRamLabel(int addr) override; - // end of functions for Cartridge RAM tab - // Following constructors and assignment operators not supported CartridgeEFSCWidget() = delete; CartridgeEFSCWidget(const CartridgeEFSCWidget&) = delete; diff --git a/src/debugger/gui/CartEFWidget.cxx b/src/debugger/gui/CartEFWidget.cxx index 165c205bf..4fbc9a030 100644 --- a/src/debugger/gui/CartEFWidget.cxx +++ b/src/debugger/gui/CartEFWidget.cxx @@ -16,97 +16,24 @@ //============================================================================ #include "CartEF.hxx" -#include "PopUpWidget.hxx" #include "CartEFWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeEFWidget::CartridgeEFWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeEF& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) + : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { - uInt32 size = 16 * 4096; + initialize(); +} +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartridgeEFWidget::description() +{ ostringstream info; - info << "64K H. Runner EF cartridge, 16 4K banks\n" - << "Startup bank = " << cart.startBank() << "\n"; - // Eventually, we should query this from the debugger/disassembler - for(uInt32 i = 0, offset = 0xFFC, spot = 0xFE0; i < 16; ++i, offset += 0x1000) - { - uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; - start -= start % 0x1000; - info << "Bank " << std::dec << i << " @ $" << Common::Base::HEX4 << start << " - " - << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; - } + info << "64K H. Runner EF cartridge, 16 4K banks\n"; + info << CartEnhancedWidget::description(); - int xpos = 2, - ypos = addBaseInformation(size, "Paul Slocum / Homestar Runner", - info.str()) + myLineHeight; - - VariantList items; - VarList::push_back(items, " 0 ($FFE0)"); - VarList::push_back(items, " 1 ($FFE1)"); - VarList::push_back(items, " 2 ($FFE2)"); - VarList::push_back(items, " 3 ($FFE3)"); - VarList::push_back(items, " 4 ($FFE4)"); - VarList::push_back(items, " 5 ($FFE5)"); - VarList::push_back(items, " 6 ($FFE6)"); - VarList::push_back(items, " 7 ($FFE7)"); - VarList::push_back(items, " 8 ($FFE8)"); - VarList::push_back(items, " 9 ($FFE9)"); - VarList::push_back(items, "10 ($FFEA)"); - VarList::push_back(items, "11 ($FFEB)"); - VarList::push_back(items, "12 ($FFEC)"); - VarList::push_back(items, "13 ($FFED)"); - VarList::push_back(items, "14 ($FFEE)"); - VarList::push_back(items, "15 ($FFEF)"); - myBank = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("15 ($FFE0)"), - myLineHeight, items, "Set bank ", - 0, kBankChanged); - myBank->setTarget(this); - addFocusWidget(myBank); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeEFWidget::loadConfig() -{ - Debugger& dbg = instance().debugger(); - CartDebug& cart = dbg.cartDebug(); - const CartState& state = static_cast(cart.getState()); - const CartState& oldstate = static_cast(cart.getOldState()); - - myBank->setSelectedIndex(myCart.getBank(), state.bank != oldstate.bank); - - CartDebugWidget::loadConfig(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeEFWidget::handleCommand(CommandSender* sender, - int cmd, int data, int id) -{ - if(cmd == kBankChanged) - { - myCart.unlockBank(); - myCart.bank(myBank->getSelected()); - myCart.lockBank(); - invalidate(); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeEFWidget::bankState() -{ - ostringstream& buf = buffer(); - - static constexpr std::array spot = { - "$FFE0", "$FFE1", "$FFE2", "$FFE3", "$FFE4", "$FFE5", "$FFE6", "$FFE7", - "$FFE8", "$FFE9", "$FFEA", "$FFEB", "$FFEC", "$FFED", "$FFEE", "$FFEF" - }; - buf << "Bank = " << std::dec << myCart.getBank() - << ", hotspot = " << spot[myCart.getBank()]; - - return buf.str(); + return info.str(); } diff --git a/src/debugger/gui/CartEFWidget.hxx b/src/debugger/gui/CartEFWidget.hxx index 3f34fa6cb..7299b22d3 100644 --- a/src/debugger/gui/CartEFWidget.hxx +++ b/src/debugger/gui/CartEFWidget.hxx @@ -19,11 +19,10 @@ #define CARTRIDGEEF_WIDGET_HXX class CartridgeEF; -class PopUpWidget; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class CartridgeEFWidget : public CartDebugWidget +class CartridgeEFWidget : public CartEnhancedWidget { public: CartridgeEFWidget(GuiObject* boss, const GUI::Font& lfont, @@ -33,17 +32,11 @@ class CartridgeEFWidget : public CartDebugWidget virtual ~CartridgeEFWidget() = default; private: - CartridgeEF& myCart; - PopUpWidget* myBank{nullptr}; + string manufacturer() override { return "Paul Slocum / Homestar Runner"; } - enum { kBankChanged = 'bkCH' }; + string description() override; private: - void loadConfig() override; - void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - - string bankState() override; - // Following constructors and assignment operators not supported CartridgeEFWidget() = delete; CartridgeEFWidget(const CartridgeEFWidget&) = delete; From 1abfcd648c52c3b2c5a3bccc7931788174852b87 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 21 Apr 2020 09:42:51 +0200 Subject: [PATCH 134/377] refactored CartWDWidget and CartX07Widget improved cart info formatting --- src/debugger/gui/CartE0Widget.cxx | 9 +- src/debugger/gui/CartE0Widget.hxx | 2 +- src/debugger/gui/CartEnhancedWidget.cxx | 49 +++++--- src/debugger/gui/CartEnhancedWidget.hxx | 2 +- src/debugger/gui/CartUAWidget.cxx | 4 +- src/debugger/gui/CartUAWidget.hxx | 2 +- src/debugger/gui/CartWDWidget.cxx | 156 ++++-------------------- src/debugger/gui/CartWDWidget.hxx | 35 ++---- src/debugger/gui/CartX07Widget.cxx | 86 ++----------- src/debugger/gui/CartX07Widget.hxx | 15 +-- src/emucore/CartWD.hxx | 2 + 11 files changed, 86 insertions(+), 276 deletions(-) diff --git a/src/debugger/gui/CartE0Widget.cxx b/src/debugger/gui/CartE0Widget.cxx index 4588abcdc..b2b6368dc 100644 --- a/src/debugger/gui/CartE0Widget.cxx +++ b/src/debugger/gui/CartE0Widget.cxx @@ -51,7 +51,7 @@ string CartridgeE0Widget::romDescription() << Common::Base::HEX4 << (ADDR_BASE | segmentOffset) << " - $" << (ADDR_BASE | segmentOffset + /*myCart.myBankSize - 1*/ 0x3FF) << ",\n"; if (seg < 3) - info << " Hotspots " << hotspotStr(0, seg) << " - " << hotspotStr(7, seg) << "\n"; + info << " Hotspots " << hotspotStr(0, seg, true) << " - " << hotspotStr(7, seg, true) << "\n"; else info << " Always points to last 1K bank of ROM\n"; } @@ -61,15 +61,14 @@ string CartridgeE0Widget::romDescription() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeE0Widget::hotspotStr(int bank, int segment) +string CartridgeE0Widget::hotspotStr(int bank, int segment, bool noBrackets) { ostringstream info; uInt16 hotspot = myCart.hotspot(); - if(hotspot & 0x1000) - hotspot |= ADDR_BASE; - + info << (noBrackets ? "" : "("); info << "$" << Common::Base::HEX1 << (hotspot + bank + segment * 8); + info << (noBrackets ? "" : ")"); return info.str(); } diff --git a/src/debugger/gui/CartE0Widget.hxx b/src/debugger/gui/CartE0Widget.hxx index 0bc5694ea..8d0dbb386 100644 --- a/src/debugger/gui/CartE0Widget.hxx +++ b/src/debugger/gui/CartE0Widget.hxx @@ -38,7 +38,7 @@ class CartridgeE0Widget : public CartEnhancedWidget string romDescription() override; - string hotspotStr(int bank, int segment) override; + string hotspotStr(int bank, int segment, bool noBrackets = false) override; int bankSegs() override { return 3; } diff --git a/src/debugger/gui/CartEnhancedWidget.cxx b/src/debugger/gui/CartEnhancedWidget.cxx index d38c5534c..f9e1e7772 100644 --- a/src/debugger/gui/CartEnhancedWidget.cxx +++ b/src/debugger/gui/CartEnhancedWidget.cxx @@ -96,18 +96,23 @@ string CartEnhancedWidget::romDescription() { uInt16 start = (image[offset + 1] << 8) | image[offset]; start -= start % 0x1000; + string hash = myCart.romBankCount() > 10 && bank < 10 ? " #" : "#"; - info << "Bank #" << std::dec << bank << " @ $" - << Common::Base::HEX4 << (start + myCart.myRomOffset) << " - $" << (start + 0xFFF) - << " (hotspot " << hotspotStr(bank) << ")\n"; + info << "Bank " << hash << std::dec << bank << " @ $" + << Common::Base::HEX4 << (start + myCart.myRomOffset) << " - $" << (start + 0xFFF); + if(myCart.hotspot() != 0) + info << " " << hotspotStr(bank, 0, true); + info << "\n"; } info << "Startup bank = #" << std::dec << myCart.startBank() << " or undetermined\n"; } else { uInt16 start = (image[myCart.mySize - 3] << 8) | image[myCart.mySize - 4]; + uInt16 end; 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) { @@ -115,7 +120,7 @@ string CartEnhancedWidget::romDescription() } info << "ROM accessible @ $" << Common::Base::HEX4 << start << " - $" - << Common::Base::HEX4 << (start + myCart.mySize - 1); + << Common::Base::HEX4 << end; } return info.str(); @@ -133,7 +138,6 @@ void CartEnhancedWidget::bankSelect(int& ypos) for(int seg = 0; seg < bankSegs(); ++seg) { // fill bank and hotspot list - uInt16 hotspot = myCart.hotspot(); VariantList items; int pw = 0; @@ -142,8 +146,9 @@ void CartEnhancedWidget::bankSelect(int& ypos) ostringstream buf; buf << std::setw(bank < 10 ? 2 : 1) << "#" << std::dec << bank; - if(hotspot >= 0x100 && myHotspotDelta > 0) - buf << " (" << hotspotStr(bank, seg) << ")"; + //if(myCart.hotspot() >= 0x100 && myHotspotDelta > 0) + if(myCart.hotspot() != 0 && myHotspotDelta > 0) + buf << " " << hotspotStr(bank, seg); VarList::push_back(items, buf.str()); pw = std::max(pw, _font.getStringWidth(buf.str())); } @@ -198,16 +203,17 @@ string CartEnhancedWidget::bankState() else if (hasRamBanks) buf << " ROM"; - if(hotspot >= 0x100) - buf << " (" << (bankSegs() < 3 ? "hotspot " : "") << hotspotStr(bank) << ")"; + //if(hotspot >= 0x100) + if(hotspot != 0 && myHotspotDelta > 0) + buf << " " << hotspotStr(bank, 0, bankSegs() < 3); } } else { buf << "Bank #" << std::dec << myCart.getBank(); - //if(hotspot >= 0x100) - buf << " (hotspot " << hotspotStr(myCart.getSegmentBank()) << ")"; + if(hotspot != 0 && myHotspotDelta > 0) + buf << " " << hotspotStr(myCart.getBank(), 0, true); } return buf.str(); } @@ -215,7 +221,7 @@ string CartEnhancedWidget::bankState() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartEnhancedWidget::hotspotStr(int bank, int segment) +string CartEnhancedWidget::hotspotStr(int bank, int segment, bool prefix) { ostringstream info; uInt16 hotspot = myCart.hotspot(); @@ -223,7 +229,9 @@ string CartEnhancedWidget::hotspotStr(int bank, int segment) if(hotspot & 0x1000) hotspot |= ADDR_BASE; + info << "(" << (prefix ? "hotspot " : ""); info << "$" << Common::Base::HEX1 << (hotspot + bank * myHotspotDelta); + info << ")"; return info.str(); } @@ -242,8 +250,11 @@ void CartEnhancedWidget::saveOldState() myOldState.internalRam.push_back(myCart.myRAM[i]); myOldState.banks.clear(); - for(int seg = 0; seg < bankSegs(); ++seg) - myOldState.banks.push_back(myCart.getSegmentBank(seg)); + if (bankSegs() > 1) + for(int seg = 0; seg < bankSegs(); ++seg) + myOldState.banks.push_back(myCart.getSegmentBank(seg)); + else + myOldState.banks.push_back(myCart.getBank()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -251,9 +262,13 @@ void CartEnhancedWidget::loadConfig() { if(myBankWidgets != nullptr) { - for(int seg = 0; seg < bankSegs(); ++seg) - myBankWidgets[seg]->setSelectedIndex(myCart.getSegmentBank(seg), - myCart.getSegmentBank(seg) != myOldState.banks[seg]); + if (bankSegs() > 1) + for(int seg = 0; seg < bankSegs(); ++seg) + myBankWidgets[seg]->setSelectedIndex(myCart.getSegmentBank(seg), + myCart.getSegmentBank(seg) != myOldState.banks[seg]); + else + myBankWidgets[0]->setSelectedIndex(myCart.getBank(), + myCart.getBank() != myOldState.banks[0]); } CartDebugWidget::loadConfig(); } diff --git a/src/debugger/gui/CartEnhancedWidget.hxx b/src/debugger/gui/CartEnhancedWidget.hxx index dccc9fde0..a3b0e54cf 100644 --- a/src/debugger/gui/CartEnhancedWidget.hxx +++ b/src/debugger/gui/CartEnhancedWidget.hxx @@ -53,7 +53,7 @@ class CartEnhancedWidget : public CartDebugWidget virtual void bankSelect(int& ypos); - virtual string hotspotStr(int bank = 0, int segment = 0); + virtual string hotspotStr(int bank = 0, int segment = 0, bool prefix = false); virtual int bankSegs(); // { return myCart.myBankSegs; } diff --git a/src/debugger/gui/CartUAWidget.cxx b/src/debugger/gui/CartUAWidget.cxx index f3865b998..ffaef806b 100644 --- a/src/debugger/gui/CartUAWidget.cxx +++ b/src/debugger/gui/CartUAWidget.cxx @@ -41,12 +41,14 @@ string CartridgeUAWidget::description() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeUAWidget::hotspotStr(int bank, int) +string CartridgeUAWidget::hotspotStr(int bank, int, bool prefix) { ostringstream info; uInt16 hotspot = myCart.hotspot() + (bank ^ (mySwappedHotspots ? 1 : 0)) * myHotspotDelta; + info << "(" << (prefix ? "hotspot " : ""); info << "$" << Common::Base::HEX1 << hotspot << ", $" << (hotspot | 0x80); + info << ")"; return info.str(); } diff --git a/src/debugger/gui/CartUAWidget.hxx b/src/debugger/gui/CartUAWidget.hxx index bb61d25c9..8a49136a2 100644 --- a/src/debugger/gui/CartUAWidget.hxx +++ b/src/debugger/gui/CartUAWidget.hxx @@ -36,7 +36,7 @@ class CartridgeUAWidget : public CartEnhancedWidget string description() override; - string hotspotStr(int bank, int) override; + string hotspotStr(int bank, int seg, bool prefix = false) override; private: const bool mySwappedHotspots; diff --git a/src/debugger/gui/CartWDWidget.cxx b/src/debugger/gui/CartWDWidget.cxx index c89c3c8c8..16fe416ec 100644 --- a/src/debugger/gui/CartWDWidget.cxx +++ b/src/debugger/gui/CartWDWidget.cxx @@ -15,157 +15,45 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#include "Debugger.hxx" -#include "CartDebug.hxx" #include "CartWD.hxx" -#include "PopUpWidget.hxx" #include "CartWDWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeWDWidget::CartridgeWDWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeWD& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) + : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { - string info = - "This scheme has eight 1K slices, which can be mapped into four 1K " - "segments in various combinations. Each 'bank' selects a predefined " - "segment arrangement (indicated in square brackets)\n" - "In the third (uppermost) segment the byte at $3FC is overwritten with 0.\n\n" - "64 bytes RAM @ $F000 - $F080\n" - " $F000 - $F03F (R), $F040 - $F07F (W)\n"; - - int xpos = 2, - ypos = addBaseInformation(myCart.mySize, "Wickstead Design", info, 12) + myLineHeight; - - VariantList items; - VarList::push_back(items, "0 ($30) [0,0,1,3]", 0); - VarList::push_back(items, "1 ($31) [0,1,2,3]", 1); - VarList::push_back(items, "2 ($32) [4,5,6,7]", 2); - VarList::push_back(items, "3 ($33) [7,4,2,3]", 3); - VarList::push_back(items, "4 ($34) [0,0,6,7]", 4); - VarList::push_back(items, "5 ($35) [0,1,7,6]", 5); - VarList::push_back(items, "6 ($36) [2,3,4,5]", 6); - VarList::push_back(items, "7 ($37) [6,0,5,1]", 7); - VarList::push_back(items, "8 ($38) [0,0,1,3]", 8); - VarList::push_back(items, "9 ($39) [0,1,2,3]", 9); - VarList::push_back(items, "10 ($3A) [4,5,6,7]", 10); - VarList::push_back(items, "11 ($3B) [7,4,2,3]", 11); - VarList::push_back(items, "12 ($3C) [0,0,6,7]", 12); - VarList::push_back(items, "13 ($3D) [0,1,7,6]", 13); - VarList::push_back(items, "14 ($3E) [2,3,4,5]", 14); - VarList::push_back(items, "15 ($3F) [6,0,5,1]", 15); - myBank = new PopUpWidget(boss, _font, xpos, ypos-2, - _font.getStringWidth("15 ($3F) [6,0,5,1]"), - myLineHeight, items, "Set bank ", - 0, kBankChanged); - myBank->setTarget(this); - addFocusWidget(myBank); + initialize(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeWDWidget::saveOldState() +string CartridgeWDWidget::description() { - myOldState.internalram.clear(); + ostringstream info; - for(uInt32 i = 0; i < internalRamSize(); ++i) - myOldState.internalram.push_back(myCart.myRAM[i]); + info << "8K + RAM Wickstead Design cartridge, \n" + << " eight 1K banks, mapped into four segments\n" + << "Hotspots $" << Common::Base::HEX1 << myCart.hotspot() << " - $" << (myCart.hotspot() + 7) << ", " + << "each hotspot selects a [predefined bank mapping]\n"; + info << ramDescription(); - myOldState.bank = myCart.getBank(); + return info.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeWDWidget::loadConfig() +string CartridgeWDWidget::hotspotStr(int bank, int segment, bool prefix) { - myBank->setSelectedIndex(myCart.getBank(), myCart.getBank() != myOldState.bank); + ostringstream info; + CartridgeWD& cart = dynamic_cast(myCart); + CartridgeWD::BankOrg banks = cart.ourBankOrg[bank]; - CartDebugWidget::loadConfig(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeWDWidget::handleCommand(CommandSender* sender, - int cmd, int data, int id) -{ - if(cmd == kBankChanged) - { - myCart.unlockBank(); - myCart.bank(myBank->getSelected()); - myCart.lockBank(); - invalidate(); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeWDWidget::bankState() -{ - ostringstream& buf = buffer(); - - static constexpr std::array segments = { - "[0,0,1,3]", "[0,1,2,3]", "[4,5,6,7]", "[7,4,2,3]", - "[0,0,6,7]", "[0,1,7,6]", "[2,3,4,5]", "[6,0,5,1]" - }; - uInt16 bank = myCart.getBank(); - buf << "Bank = " << std::dec << bank << ", segments = " << segments[bank & 0x7]; - - return buf.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 CartridgeWDWidget::internalRamSize() -{ - return 64; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 CartridgeWDWidget::internalRamRPort(int start) -{ - return 0xF000 + start; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeWDWidget::internalRamDescription() -{ - ostringstream desc; - desc << "$F000 - $F03F used for Read Access\n" - << "$F040 - $F07F used for Write Access"; - - return desc.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& CartridgeWDWidget::internalRamOld(int start, int count) -{ - myRamOld.clear(); - for(int i = 0; i < count; ++i) - myRamOld.push_back(myOldState.internalram[start + i]); - return myRamOld; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& CartridgeWDWidget::internalRamCurrent(int start, int count) -{ - myRamCurrent.clear(); - for(int i = 0; i < count; ++i) - myRamCurrent.push_back(myCart.myRAM[start + i]); - return myRamCurrent; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeWDWidget::internalRamSetValue(int addr, uInt8 value) -{ - myCart.myRAM[addr] = value; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeWDWidget::internalRamGetValue(int addr) -{ - return myCart.myRAM[addr]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeWDWidget::internalRamLabel(int addr) -{ - CartDebug& dbg = instance().debugger().cartDebug(); - return dbg.getLabel(addr + 0xF000, false); + info << "(" << (prefix ? "hotspot " : "") + << "$" << Common::Base::HEX1 << (myCart.hotspot() + bank) << ") [" + << uInt16(banks.zero) << ", " + << uInt16(banks.one) << ", " + << uInt16(banks.two) << ", " + << uInt16(banks.three) << "]"; + + return info.str(); } diff --git a/src/debugger/gui/CartWDWidget.hxx b/src/debugger/gui/CartWDWidget.hxx index f52f4a2a9..9bab7af30 100644 --- a/src/debugger/gui/CartWDWidget.hxx +++ b/src/debugger/gui/CartWDWidget.hxx @@ -19,11 +19,10 @@ #define CARTRIDGEWD_WIDGET_HXX class CartridgeWD; -class PopUpWidget; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class CartridgeWDWidget : public CartDebugWidget +class CartridgeWDWidget : public CartEnhancedWidget { public: CartridgeWDWidget(GuiObject* boss, const GUI::Font& lfont, @@ -33,35 +32,15 @@ class CartridgeWDWidget : public CartDebugWidget virtual ~CartridgeWDWidget() = default; private: - CartridgeWD& myCart; - PopUpWidget* myBank{nullptr}; + string manufacturer() override { return "Wickstead Design"; } - struct CartState { - ByteArray internalram; - uInt16 bank{0}; // Current banking layout - }; - CartState myOldState; + string description() override; - enum { kBankChanged = 'bkCH' }; + string hotspotStr(int bank, int seg = 0, bool prefix = false) override; + + int bankSegs() override { return 1; } private: - void saveOldState() override; - void loadConfig() override; - void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - - string bankState() override; - - // start of functions for Cartridge RAM tab - uInt32 internalRamSize() override; - uInt32 internalRamRPort(int start) override; - string internalRamDescription() override; - const ByteArray& internalRamOld(int start, int count) override; - const ByteArray& internalRamCurrent(int start, int count) override; - void internalRamSetValue(int addr, uInt8 value) override; - uInt8 internalRamGetValue(int addr) override; - string internalRamLabel(int addr) override; - // end of functions for Cartridge RAM tab - // Following constructors and assignment operators not supported CartridgeWDWidget() = delete; CartridgeWDWidget(const CartridgeWDWidget&) = delete; diff --git a/src/debugger/gui/CartX07Widget.cxx b/src/debugger/gui/CartX07Widget.cxx index 0c6bc5b95..4fb31a9ca 100644 --- a/src/debugger/gui/CartX07Widget.cxx +++ b/src/debugger/gui/CartX07Widget.cxx @@ -16,94 +16,26 @@ //============================================================================ #include "CartX07.hxx" -#include "PopUpWidget.hxx" #include "CartX07Widget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeX07Widget::CartridgeX07Widget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeX07& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) + : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { - uInt32 size = 16 * 4096; + initialize(); +} +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartridgeX07Widget::description() +{ ostringstream info; + info << "64K X07 cartridge, 16 4K banks\n" - << "Startup bank = " << cart.startBank() << "\n" << "Multiple hotspots, all below $1000\n" << "See documentation for further details\n"; + info << CartEnhancedWidget::description(); - // Eventually, we should query this from the debugger/disassembler - for(uInt32 i = 0, offset = 0xFFC; i < 16; ++i, offset += 0x1000) - { - uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; - start -= start % 0x1000; - info << "Bank " << std::dec << i << " @ $" << Common::Base::HEX4 << start - << " - " << "$" << (start + 0xFFF) << "\n"; - } - - int xpos = 2, - ypos = addBaseInformation(size, "AtariAge / John Payson / Fred Quimby", - info.str()) + myLineHeight; - - VariantList items; - VarList::push_back(items, " 0"); - VarList::push_back(items, " 1"); - VarList::push_back(items, " 2"); - VarList::push_back(items, " 3"); - VarList::push_back(items, " 4"); - VarList::push_back(items, " 5"); - VarList::push_back(items, " 6"); - VarList::push_back(items, " 7"); - VarList::push_back(items, " 8"); - VarList::push_back(items, " 9"); - VarList::push_back(items, " 10"); - VarList::push_back(items, " 11"); - VarList::push_back(items, " 12"); - VarList::push_back(items, " 13"); - VarList::push_back(items, " 14"); - VarList::push_back(items, " 15"); - myBank = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth(" 15"), - myLineHeight, items, "Set bank ", - 0, kBankChanged); - myBank->setTarget(this); - addFocusWidget(myBank); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeX07Widget::loadConfig() -{ - Debugger& dbg = instance().debugger(); - CartDebug& cart = dbg.cartDebug(); - const CartState& state = static_cast(cart.getState()); - const CartState& oldstate = static_cast(cart.getOldState()); - - myBank->setSelectedIndex(myCart.getBank(), state.bank != oldstate.bank); - - CartDebugWidget::loadConfig(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeX07Widget::handleCommand(CommandSender* sender, - int cmd, int data, int id) -{ - if(cmd == kBankChanged) - { - myCart.unlockBank(); - myCart.bank(myBank->getSelected()); - myCart.lockBank(); - invalidate(); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeX07Widget::bankState() -{ - ostringstream& buf = buffer(); - - buf << "Bank = " << std::dec << myCart.getBank(); - - return buf.str(); + return info.str(); } diff --git a/src/debugger/gui/CartX07Widget.hxx b/src/debugger/gui/CartX07Widget.hxx index 00782dca8..a096c5d0d 100644 --- a/src/debugger/gui/CartX07Widget.hxx +++ b/src/debugger/gui/CartX07Widget.hxx @@ -19,11 +19,10 @@ #define CARTRIDGEX07_WIDGET_HXX class CartridgeX07; -class PopUpWidget; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class CartridgeX07Widget : public CartDebugWidget +class CartridgeX07Widget : public CartEnhancedWidget { public: CartridgeX07Widget(GuiObject* boss, const GUI::Font& lfont, @@ -33,17 +32,11 @@ class CartridgeX07Widget : public CartDebugWidget virtual ~CartridgeX07Widget() = default; private: - CartridgeX07& myCart; - PopUpWidget* myBank{nullptr}; + string manufacturer() override { return "AtariAge / John Payson / Fred Quimby"; } - enum { kBankChanged = 'bkCH' }; + string description() override; private: - void loadConfig() override; - void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - - string bankState() override; - // Following constructors and assignment operators not supported CartridgeX07Widget() = delete; CartridgeX07Widget(const CartridgeX07Widget&) = delete; diff --git a/src/emucore/CartWD.hxx b/src/emucore/CartWD.hxx index 20596868e..1fd42ac71 100644 --- a/src/emucore/CartWD.hxx +++ b/src/emucore/CartWD.hxx @@ -153,6 +153,8 @@ class CartridgeWD : public CartridgeEnhanced private: bool checkSwitchBank(uInt16, uInt8 = 0) override { return false; } + uInt16 hotspot() const override { return 0x0030; } + private: // Indicates the cycle at which a bankswitch was initiated uInt64 myCyclesAtBankswitchInit{0}; From 1ea0fab16ac0da3e973223fb904357af8a55e89b Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 21 Apr 2020 12:15:28 +0200 Subject: [PATCH 135/377] refactored CartFA(2), CartFC and CartFE widget classes --- src/debugger/gui/CartEnhancedWidget.cxx | 13 +- src/debugger/gui/CartEnhancedWidget.hxx | 2 +- src/debugger/gui/CartFA2Widget.cxx | 160 +++--------------------- src/debugger/gui/CartFA2Widget.hxx | 34 ++--- src/debugger/gui/CartFAWidget.cxx | 143 ++------------------- src/debugger/gui/CartFAWidget.hxx | 33 +---- src/debugger/gui/CartFCWidget.cxx | 78 ++++-------- src/debugger/gui/CartFCWidget.hxx | 17 +-- src/debugger/gui/CartFEWidget.cxx | 66 +++------- src/debugger/gui/CartFEWidget.hxx | 18 +-- src/emucore/CartFA2.hxx | 2 +- src/emucore/CartFE.hxx | 2 + 12 files changed, 100 insertions(+), 468 deletions(-) diff --git a/src/debugger/gui/CartEnhancedWidget.cxx b/src/debugger/gui/CartEnhancedWidget.cxx index f9e1e7772..a2e22c094 100644 --- a/src/debugger/gui/CartEnhancedWidget.cxx +++ b/src/debugger/gui/CartEnhancedWidget.cxx @@ -31,12 +31,14 @@ CartEnhancedWidget::CartEnhancedWidget(GuiObject* boss, const GUI::Font& lfont, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartEnhancedWidget::initialize() +int CartEnhancedWidget::initialize() { int ypos = addBaseInformation(size(), manufacturer(), description(), descriptionLines()) + myLineHeight; bankSelect(ypos); + + return ypos; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -64,7 +66,7 @@ string CartEnhancedWidget::description() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int CartEnhancedWidget::descriptionLines() { - return 20; // should be enough for almost all types + return 18; // should be enough for almost all types } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -101,7 +103,12 @@ string CartEnhancedWidget::romDescription() info << "Bank " << hash << std::dec << bank << " @ $" << Common::Base::HEX4 << (start + myCart.myRomOffset) << " - $" << (start + 0xFFF); if(myCart.hotspot() != 0) - info << " " << hotspotStr(bank, 0, true); + { + string hs = hotspotStr(bank, 0, true); + if(hs.length() > 22) + info << "\n "; + info << " " << hs; + } info << "\n"; } info << "Startup bank = #" << std::dec << myCart.startBank() << " or undetermined\n"; diff --git a/src/debugger/gui/CartEnhancedWidget.hxx b/src/debugger/gui/CartEnhancedWidget.hxx index a3b0e54cf..2cbd22ced 100644 --- a/src/debugger/gui/CartEnhancedWidget.hxx +++ b/src/debugger/gui/CartEnhancedWidget.hxx @@ -37,7 +37,7 @@ class CartEnhancedWidget : public CartDebugWidget virtual ~CartEnhancedWidget() = default; protected: - void initialize(); + int initialize(); virtual size_t size(); diff --git a/src/debugger/gui/CartFA2Widget.cxx b/src/debugger/gui/CartFA2Widget.cxx index 9a24eb5a7..40fab9d4d 100644 --- a/src/debugger/gui/CartFA2Widget.cxx +++ b/src/debugger/gui/CartFA2Widget.cxx @@ -15,65 +15,25 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#include "Debugger.hxx" -#include "CartDebug.hxx" #include "CartFA2.hxx" -#include "PopUpWidget.hxx" #include "CartFA2Widget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeFA2Widget::CartridgeFA2Widget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeFA2& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) + : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { - size_t size = cart.mySize; - - ostringstream info; - info << "Modified FA RAM+, six or seven 4K banks\n" - << "256 bytes RAM @ $F000 - $F1FF\n" - << " $F100 - $F1FF (R), $F000 - $F0FF (W)\n" - << "RAM can be loaded/saved to Harmony flash by accessing $FFF4\n" - << "Startup bank = " << cart.startBank() << " or undetermined\n"; - - // Eventually, we should query this from the debugger/disassembler - for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF5; i < cart.romBankCount(); - ++i, offset += 0x1000) - { - uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; - start -= start % 0x1000; - info << "Bank " << i << " @ $" << Common::Base::HEX4 << (start + 0x200) << " - " - << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; - } - int xpos = 2, - ypos = addBaseInformation(size, "Chris D. Walton (Star Castle 2600)", - info.str(), 15) + myLineHeight; + ypos = initialize(); - VariantList items; - VarList::push_back(items, "0 ($FFF5)"); - VarList::push_back(items, "1 ($FFF6)"); - VarList::push_back(items, "2 ($FFF7)"); - VarList::push_back(items, "3 ($FFF8)"); - VarList::push_back(items, "4 ($FFF9)"); - VarList::push_back(items, "5 ($FFFA)"); - if(cart.romBankCount() == 7) - VarList::push_back(items, "6 ($FFFB)"); - - myBank = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFFx)"), - myLineHeight, items, "Set bank ", - 0, kBankChanged); - myBank->setTarget(this); - addFocusWidget(myBank); - ypos += myLineHeight + 20; + ypos += 12; const int bwidth = _font.getStringWidth("Erase") + 20; StaticTextWidget* t = new StaticTextWidget(boss, _font, xpos, ypos, - _font.getStringWidth("Harmony Flash "), - myFontHeight, "Harmony Flash ", TextAlign::Left); + _font.getStringWidth("Harmony flash memory "), + myFontHeight, "Harmony flash memory ", TextAlign::Left); xpos += t->getWidth() + 4; myFlashErase = @@ -98,123 +58,39 @@ CartridgeFA2Widget::CartridgeFA2Widget( } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeFA2Widget::saveOldState() +string CartridgeFA2Widget::description() { - myOldState.internalram.clear(); + ostringstream info; - for(uInt32 i = 0; i < internalRamSize(); ++i) - myOldState.internalram.push_back(myCart.myRAM[i]); + info << "Modified FA RAM+, six or seven 4K banks\n"; + info << "RAM+ can be loaded/saved to Harmony flash memory by accessing $" + << Common::Base::HEX4 << 0xFFF4 << "\n"; + info << CartEnhancedWidget::description(); - myOldState.bank = myCart.getBank(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeFA2Widget::loadConfig() -{ - myBank->setSelectedIndex(myCart.getBank(), myCart.getBank() != myOldState.bank); - - CartDebugWidget::loadConfig(); + return info.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFA2Widget::handleCommand(CommandSender* sender, int cmd, int data, int id) { + CartridgeFA2& cart = dynamic_cast(myCart); + switch(cmd) { - case kBankChanged: - myCart.unlockBank(); - myCart.bank(myBank->getSelected()); - myCart.lockBank(); - invalidate(); - break; - case kFlashErase: - myCart.flash(0); + cart.flash(0); break; case kFlashLoad: - myCart.flash(1); + cart.flash(1); break; case kFlashSave: - myCart.flash(2); + cart.flash(2); break; default: - break; + CartEnhancedWidget::handleCommand(sender, cmd, data, id); } } - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeFA2Widget::bankState() -{ - ostringstream& buf = buffer(); - - static constexpr std::array spot = { - "$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB" - }; - buf << "Bank = " << std::dec << myCart.getBank() - << ", hotspot = " << spot[myCart.getBank()]; - - return buf.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 CartridgeFA2Widget::internalRamSize() -{ - return 256; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 CartridgeFA2Widget::internalRamRPort(int start) -{ - return 0xF100 + start; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeFA2Widget::internalRamDescription() -{ - ostringstream desc; - desc << "$F000 - $F0FF used for Write Access\n" - << "$F100 - $F1FF used for Read Access"; - - return desc.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& CartridgeFA2Widget::internalRamOld(int start, int count) -{ - myRamOld.clear(); - for(int i = 0; i < count; i++) - myRamOld.push_back(myOldState.internalram[start + i]); - return myRamOld; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& CartridgeFA2Widget::internalRamCurrent(int start, int count) -{ - myRamCurrent.clear(); - for(int i = 0; i < count; i++) - myRamCurrent.push_back(myCart.myRAM[start + i]); - return myRamCurrent; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeFA2Widget::internalRamSetValue(int addr, uInt8 value) -{ - myCart.myRAM[addr] = value; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeFA2Widget::internalRamGetValue(int addr) -{ - return myCart.myRAM[addr]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeFA2Widget::internalRamLabel(int addr) -{ - CartDebug& dbg = instance().debugger().cartDebug(); - return dbg.getLabel(addr + 0xF100, false); -} diff --git a/src/debugger/gui/CartFA2Widget.hxx b/src/debugger/gui/CartFA2Widget.hxx index 0b5fe3fb4..30b1ec81f 100644 --- a/src/debugger/gui/CartFA2Widget.hxx +++ b/src/debugger/gui/CartFA2Widget.hxx @@ -20,11 +20,10 @@ class CartridgeFA2; class ButtonWidget; -class PopUpWidget; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class CartridgeFA2Widget : public CartDebugWidget +class CartridgeFA2Widget : public CartEnhancedWidget { public: CartridgeFA2Widget(GuiObject* boss, const GUI::Font& lfont, @@ -34,41 +33,22 @@ class CartridgeFA2Widget : public CartDebugWidget virtual ~CartridgeFA2Widget() = default; private: - CartridgeFA2& myCart; - PopUpWidget* myBank{nullptr}; + string manufacturer() override { return "Chris D. Walton (Star Castle 2600 Arcade)"; } + + string description() override; + ButtonWidget *myFlashErase{nullptr}, *myFlashLoad{nullptr}, *myFlashSave{nullptr}; - struct CartState { - ByteArray internalram; - uInt16 bank{0}; - }; - CartState myOldState; - enum { - kBankChanged = 'bkCH', kFlashErase = 'flER', kFlashLoad = 'flLD', kFlashSave = 'flSV' }; private: - void saveOldState() override; - void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - string bankState() override; - - // start of functions for Cartridge RAM tab - uInt32 internalRamSize() override; - uInt32 internalRamRPort(int start) override; - string internalRamDescription() override; - const ByteArray& internalRamOld(int start, int count) override; - const ByteArray& internalRamCurrent(int start, int count) override; - void internalRamSetValue(int addr, uInt8 value) override; - uInt8 internalRamGetValue(int addr) override; - string internalRamLabel(int addr) override; - // end of functions for Cartridge RAM tab - + private: // Following constructors and assignment operators not supported CartridgeFA2Widget() = delete; CartridgeFA2Widget(const CartridgeFA2Widget&) = delete; diff --git a/src/debugger/gui/CartFAWidget.cxx b/src/debugger/gui/CartFAWidget.cxx index e32a3eec0..b3fefff6d 100644 --- a/src/debugger/gui/CartFAWidget.cxx +++ b/src/debugger/gui/CartFAWidget.cxx @@ -15,150 +15,25 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#include "Debugger.hxx" -#include "CartDebug.hxx" #include "CartFA.hxx" -#include "PopUpWidget.hxx" #include "CartFAWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeFAWidget::CartridgeFAWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeFA& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) + : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { - uInt16 size = 3 * 4096; + initialize(); +} +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartridgeFAWidget::description() +{ ostringstream info; - info << "CBS RAM+ FA cartridge, three 4K banks\n" - << "256 bytes RAM @ $F000 - $F1FF\n" - << " $F100 - $F1FF (R), $F000 - $F0FF (W)\n" - << "Startup bank = " << cart.startBank() << " or undetermined\n"; - // Eventually, we should query this from the debugger/disassembler - for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF8; i < 3; ++i, offset += 0x1000) - { - uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; - start -= start % 0x1000; - info << "Bank " << i << " @ $" << Common::Base::HEX4 << (start + 0x200) << " - " - << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; - } + info << "CBS RAM+ FA cartridge, three 4K banks\n"; + info << CartEnhancedWidget::description(); - int xpos = 2, - ypos = addBaseInformation(size, "CBS", info.str()) + myLineHeight; - - VariantList items; - VarList::push_back(items, "0 ($FFF8)"); - VarList::push_back(items, "1 ($FFF9)"); - VarList::push_back(items, "2 ($FFFA)"); - myBank = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFFx)"), - myLineHeight, items, "Set bank ", - 0, kBankChanged); - myBank->setTarget(this); - addFocusWidget(myBank); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeFAWidget::saveOldState() -{ - myOldState.internalram.clear(); - - for(uInt32 i = 0; i < internalRamSize(); ++i) - myOldState.internalram.push_back(myCart.myRAM[i]); - - myOldState.bank = myCart.getBank(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeFAWidget::loadConfig() -{ - myBank->setSelectedIndex(myCart.getBank(), myCart.getBank() != myOldState.bank); - - CartDebugWidget::loadConfig(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeFAWidget::handleCommand(CommandSender* sender, - int cmd, int data, int id) -{ - if(cmd == kBankChanged) - { - myCart.unlockBank(); - myCart.bank(myBank->getSelected()); - myCart.lockBank(); - invalidate(); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeFAWidget::bankState() -{ - ostringstream& buf = buffer(); - - static constexpr std::array spot = { "$FFF8", "$FFF9", "$FFFA" }; - buf << "Bank = " << std::dec << myCart.getBank() - << ", hotspot = " << spot[myCart.getBank()]; - - return buf.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 CartridgeFAWidget::internalRamSize() -{ - return 256; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 CartridgeFAWidget::internalRamRPort(int start) -{ - return 0xF100 + start; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeFAWidget::internalRamDescription() -{ - ostringstream desc; - desc << "$F000 - $F0FF used for Write Access\n" - << "$F100 - $F1FF used for Read Access"; - - return desc.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& CartridgeFAWidget::internalRamOld(int start, int count) -{ - myRamOld.clear(); - for(int i = 0; i < count; i++) - myRamOld.push_back(myOldState.internalram[start + i]); - return myRamOld; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& CartridgeFAWidget::internalRamCurrent(int start, int count) -{ - myRamCurrent.clear(); - for(int i = 0; i < count; i++) - myRamCurrent.push_back(myCart.myRAM[start + i]); - return myRamCurrent; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeFAWidget::internalRamSetValue(int addr, uInt8 value) -{ - myCart.myRAM[addr] = value; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeFAWidget::internalRamGetValue(int addr) -{ - return myCart.myRAM[addr]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeFAWidget::internalRamLabel(int addr) -{ - CartDebug& dbg = instance().debugger().cartDebug(); - return dbg.getLabel(addr + 0xF100, false); + return info.str(); } diff --git a/src/debugger/gui/CartFAWidget.hxx b/src/debugger/gui/CartFAWidget.hxx index e4e1da416..b7fbb3308 100644 --- a/src/debugger/gui/CartFAWidget.hxx +++ b/src/debugger/gui/CartFAWidget.hxx @@ -19,11 +19,10 @@ #define CARTRIDGEFA_WIDGET_HXX class CartridgeFA; -class PopUpWidget; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class CartridgeFAWidget : public CartDebugWidget +class CartridgeFAWidget : public CartEnhancedWidget { public: CartridgeFAWidget(GuiObject* boss, const GUI::Font& lfont, @@ -33,35 +32,11 @@ class CartridgeFAWidget : public CartDebugWidget virtual ~CartridgeFAWidget() = default; private: - CartridgeFA& myCart; - PopUpWidget* myBank{nullptr}; + string manufacturer() override { return "CBS"; } - struct CartState { - ByteArray internalram; - uInt16 bank{0}; - }; - CartState myOldState; - - enum { kBankChanged = 'bkCH' }; + string description() override; private: - void saveOldState() override; - void loadConfig() override; - void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - - string bankState() override; - - // start of functions for Cartridge RAM tab - uInt32 internalRamSize() override; - uInt32 internalRamRPort(int start) override; - string internalRamDescription() override; - const ByteArray& internalRamOld(int start, int count) override; - const ByteArray& internalRamCurrent(int start, int count) override; - void internalRamSetValue(int addr, uInt8 value) override; - uInt8 internalRamGetValue(int addr) override; - string internalRamLabel(int addr) override; - // end of functions for Cartridge RAM tab - // Following constructors and assignment operators not supported CartridgeFAWidget() = delete; CartridgeFAWidget(const CartridgeFAWidget&) = delete; diff --git a/src/debugger/gui/CartFCWidget.cxx b/src/debugger/gui/CartFCWidget.cxx index a034b56e3..8210eed2e 100644 --- a/src/debugger/gui/CartFCWidget.cxx +++ b/src/debugger/gui/CartFCWidget.cxx @@ -16,80 +16,44 @@ //============================================================================ #include "CartFC.hxx" -#include "PopUpWidget.hxx" #include "CartFCWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeFCWidget::CartridgeFCWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeFC& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) + : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { - uInt16 size = cart.romBankCount() * 4096; + initialize(); +} +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartridgeFCWidget::description() +{ ostringstream info; - info << "FC cartridge, up to eight 4K banks\n" - << "Startup bank = " << cart.startBank() << " or undetermined\n"; + uInt16 hotspot = myCart.hotspot() | ADDR_BASE; - // Eventually, we should query this from the debugger/disassembler + info << "FC cartridge, up to eight 4K banks\n"; info << "Bank selected by hotspots\n" - << " $FFF8 (defines low 2 bits)\n" - << " $FFF9 (defines high bits)\n" - << " $FFFC (triggers bank switch)"; + << " $" << Common::Base::HEX4 << hotspot << " (defines low 2 bits)\n" + << " $" << Common::Base::HEX4 << (hotspot + 1) << " (defines high bits)\n" + << " $" << Common::Base::HEX4 << (hotspot + 4) << " (triggers bank switch)\n"; - int xpos = 2, - ypos = addBaseInformation(size, "Amiga Corp.", info.str()) + myLineHeight; + info << CartEnhancedWidget::description(); - VariantList items; - for (uInt16 i = 0; i < cart.romBankCount(); ++i) - VarList::push_back(items, Variant(i).toString() + - " ($FFF8 = " + Variant(i & 0b11).toString() + - "/$FFF9 = " + Variant(i >> 2).toString() +")"); - - myBank = new PopUpWidget(boss, _font, xpos, ypos - 2, - _font.getStringWidth("7 ($FFF8 = 3/$FFF9 = 1)"), - myLineHeight, items, "Set bank ", - 0, kBankChanged); - myBank->setTarget(this); - addFocusWidget(myBank); + return info.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeFCWidget::loadConfig() +string CartridgeFCWidget::hotspotStr(int bank, int, bool prefix) { - Debugger& dbg = instance().debugger(); - CartDebug& cart = dbg.cartDebug(); - const CartState& state = static_cast(cart.getState()); - const CartState& oldstate = static_cast(cart.getOldState()); + ostringstream info; + uInt16 hotspot = myCart.hotspot() | ADDR_BASE; - myBank->setSelectedIndex(myCart.getBank(), state.bank != oldstate.bank); + info << "(" << (prefix ? "hotspots " : ""); + info << "$" << Common::Base::HEX4 << hotspot << " = " << (bank & 0b11); + info << ", $" << Common::Base::HEX4 << (hotspot + 1) << " = " << (bank >> 2); + info << ")"; - CartDebugWidget::loadConfig(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeFCWidget::handleCommand(CommandSender* sender, - int cmd, int data, int id) -{ - if (cmd == kBankChanged) - { - myCart.unlockBank(); - myCart.bank(myBank->getSelected()); - myCart.lockBank(); - invalidate(); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeFCWidget::bankState() -{ - ostringstream& buf = buffer(); - uInt16 bank = myCart.getBank(); - - buf << "Bank = #" << std::dec << bank - << ", hotspots $FFF8 = " << (bank & 0b11) - << "/$FF99 = " << (bank >> 2); - - return buf.str(); + return info.str(); } diff --git a/src/debugger/gui/CartFCWidget.hxx b/src/debugger/gui/CartFCWidget.hxx index 0e74246ed..f1bb4a50f 100644 --- a/src/debugger/gui/CartFCWidget.hxx +++ b/src/debugger/gui/CartFCWidget.hxx @@ -19,11 +19,10 @@ #define CARTRIDGEFC_WIDGET_HXX class CartridgeFC; -class PopUpWidget; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class CartridgeFCWidget : public CartDebugWidget +class CartridgeFCWidget : public CartEnhancedWidget { public: CartridgeFCWidget(GuiObject* boss, const GUI::Font& lfont, @@ -33,17 +32,13 @@ class CartridgeFCWidget : public CartDebugWidget virtual ~CartridgeFCWidget() = default; private: - CartridgeFC& myCart; - PopUpWidget* myBank{nullptr}; + string manufacturer() override { return "Amiga Corp."; } - enum { kBankChanged = 'bkCH' }; + string description() override; + + string hotspotStr(int bank, int seg = 0, bool prefix = false) override; private: - void loadConfig() override; - void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - - string bankState() override; - // Following constructors and assignment operators not supported CartridgeFCWidget() = delete; CartridgeFCWidget(const CartridgeFCWidget&) = delete; diff --git a/src/debugger/gui/CartFEWidget.cxx b/src/debugger/gui/CartFEWidget.cxx index afccb359f..dbe992a4f 100644 --- a/src/debugger/gui/CartFEWidget.cxx +++ b/src/debugger/gui/CartFEWidget.cxx @@ -16,72 +16,36 @@ //============================================================================ #include "CartFE.hxx" -#include "PopUpWidget.hxx" #include "CartFEWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeFEWidget::CartridgeFEWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeFE& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) + : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { - string info = - "FE cartridge, two 4K banks\n" - "Monitors access to hotspot $01FE, and uses " - "upper 3 bits of databus for bank number:\n" - "Bank 0 @ $F000 - $FFFF (DATA = 111, D5 = 1)\n" - "Bank 1 @ $D000 - $DFFF (DATA = 110, D5 = 0)\n"; - - int xpos = 2, - ypos = addBaseInformation(2 * 4096, "Activision", info) + myLineHeight; - - VariantList items; - VarList::push_back(items, "0 ($01FE, D5=1)"); - VarList::push_back(items, "1 ($01FE, D5=0)"); - myBank = - new PopUpWidget(boss, _font, xpos, ypos-2, - _font.getStringWidth("0 ($01FE, D5=1)"), - myLineHeight, items, "Set bank ", - 0, kBankChanged); - myBank->setTarget(this); - addFocusWidget(myBank); + initialize(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeFEWidget::loadConfig() +string CartridgeFEWidget::description() { - Debugger& dbg = instance().debugger(); - CartDebug& cart = dbg.cartDebug(); - const CartState& state = static_cast(cart.getState()); - const CartState& oldstate = static_cast(cart.getOldState()); + ostringstream info; - myBank->setSelectedIndex(myCart.getBank(), state.bank != oldstate.bank); + info << "FE cartridge, two 4K banks\n" + << "Monitors access to hotspot $01FE, and uses " + << "upper 3 bits of databus for bank number:\n"; + info << CartEnhancedWidget::description(); - CartDebugWidget::loadConfig(); + return info.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeFEWidget::handleCommand(CommandSender* sender, - int cmd, int data, int id) +string CartridgeFEWidget::hotspotStr(int bank, int, bool) { - if(cmd == kBankChanged) - { - myCart.unlockBank(); - myCart.bank(myBank->getSelected()); - myCart.lockBank(); - invalidate(); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeFEWidget::bankState() -{ - ostringstream& buf = buffer(); - - static constexpr std::array range = { "$F000", "$D000" }; - buf << "Bank = " << std::dec << myCart.getBank() - << ", address range = " << range[myCart.getBank()]; - - return buf.str(); + ostringstream info; + + info << "(DATA = 11" << !bank << ", D5 = " << !bank << ")"; + + return info.str(); } diff --git a/src/debugger/gui/CartFEWidget.hxx b/src/debugger/gui/CartFEWidget.hxx index a9f37190c..05a320a71 100644 --- a/src/debugger/gui/CartFEWidget.hxx +++ b/src/debugger/gui/CartFEWidget.hxx @@ -19,11 +19,10 @@ #define CARTRIDGEFE_WIDGET_HXX class CartridgeFE; -class PopUpWidget; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class CartridgeFEWidget : public CartDebugWidget +class CartridgeFEWidget : public CartEnhancedWidget { public: CartridgeFEWidget(GuiObject* boss, const GUI::Font& lfont, @@ -33,18 +32,13 @@ class CartridgeFEWidget : public CartDebugWidget virtual ~CartridgeFEWidget() = default; private: - CartridgeFE& myCart; - PopUpWidget* myBank{nullptr}; + string manufacturer() override { return "Activision"; } - enum { kBankChanged = 'bkCH' }; + string description() override; + + string hotspotStr(int bank, int, bool) override; private: - // No implementation for non-bankswitched ROMs - void loadConfig() override; - void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - - string bankState() override; - // Following constructors and assignment operators not supported CartridgeFEWidget() = delete; CartridgeFEWidget(const CartridgeFEWidget&) = delete; diff --git a/src/emucore/CartFA2.hxx b/src/emucore/CartFA2.hxx index 8175f4cdc..16d33bf2b 100644 --- a/src/emucore/CartFA2.hxx +++ b/src/emucore/CartFA2.hxx @@ -110,7 +110,7 @@ class CartridgeFA2 : public CartridgeFA private: bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; - uInt16 hotspot() const override { return 0x1FF4; } + uInt16 hotspot() const override { return 0x1FF5; } uInt16 getStartBank() const override { return 0; } diff --git a/src/emucore/CartFE.hxx b/src/emucore/CartFE.hxx index 3132704cd..6c453d284 100644 --- a/src/emucore/CartFE.hxx +++ b/src/emucore/CartFE.hxx @@ -165,6 +165,8 @@ class CartridgeFE : public CartridgeEnhanced */ bool checkSwitchBank(uInt16 address, uInt8 value) override; + uInt16 hotspot() const override { return 0x01FE; } + private: // Whether previous address by peek/poke equals $01FE (hotspot) bool myLastAccessWasFE{false}; From eaf1d5bba668c19bbadf489986788aa2b22fdbb5 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 21 Apr 2020 12:40:19 +0200 Subject: [PATCH 136/377] renamed CartridgeEnhancedWidget class --- src/debugger/gui/Cart0840Widget.cxx | 4 +-- src/debugger/gui/Cart0840Widget.hxx | 2 +- src/debugger/gui/Cart2KWidget.cxx | 4 +-- src/debugger/gui/Cart2KWidget.hxx | 2 +- src/debugger/gui/Cart3FWidget.cxx | 2 +- src/debugger/gui/Cart3FWidget.hxx | 2 +- src/debugger/gui/Cart4KSCWidget.cxx | 4 +-- src/debugger/gui/Cart4KSCWidget.hxx | 2 +- src/debugger/gui/Cart4KWidget.cxx | 4 +-- src/debugger/gui/Cart4KWidget.hxx | 2 +- src/debugger/gui/CartBFSCWidget.cxx | 4 +-- src/debugger/gui/CartBFSCWidget.hxx | 2 +- src/debugger/gui/CartBFWidget.cxx | 4 +-- src/debugger/gui/CartBFWidget.hxx | 2 +- src/debugger/gui/CartCVWidget.cxx | 4 +-- src/debugger/gui/CartCVWidget.hxx | 2 +- src/debugger/gui/CartDFSCWidget.cxx | 4 +-- src/debugger/gui/CartDFSCWidget.hxx | 2 +- src/debugger/gui/CartDFWidget.cxx | 4 +-- src/debugger/gui/CartDFWidget.hxx | 2 +- src/debugger/gui/CartE0Widget.cxx | 4 +-- src/debugger/gui/CartE0Widget.hxx | 2 +- src/debugger/gui/CartEFSCWidget.cxx | 4 +-- src/debugger/gui/CartEFSCWidget.hxx | 2 +- src/debugger/gui/CartEFWidget.cxx | 4 +-- src/debugger/gui/CartEFWidget.hxx | 2 +- src/debugger/gui/CartEnhancedWidget.cxx | 44 ++++++++++++------------- src/debugger/gui/CartEnhancedWidget.hxx | 22 ++++++------- src/debugger/gui/CartF0Widget.cxx | 2 +- src/debugger/gui/CartF0Widget.hxx | 2 +- src/debugger/gui/CartF4SCWidget.cxx | 4 +-- src/debugger/gui/CartF4SCWidget.hxx | 2 +- src/debugger/gui/CartF4Widget.cxx | 4 +-- src/debugger/gui/CartF4Widget.hxx | 2 +- src/debugger/gui/CartF6SCWidget.cxx | 4 +-- src/debugger/gui/CartF6SCWidget.hxx | 2 +- src/debugger/gui/CartF6Widget.cxx | 4 +-- src/debugger/gui/CartF6Widget.hxx | 2 +- src/debugger/gui/CartF8SCWidget.cxx | 4 +-- src/debugger/gui/CartF8SCWidget.hxx | 2 +- src/debugger/gui/CartF8Widget.cxx | 4 +-- src/debugger/gui/CartF8Widget.hxx | 2 +- src/debugger/gui/CartFA2Widget.cxx | 6 ++-- src/debugger/gui/CartFA2Widget.hxx | 2 +- src/debugger/gui/CartFAWidget.cxx | 4 +-- src/debugger/gui/CartFAWidget.hxx | 2 +- src/debugger/gui/CartFCWidget.cxx | 4 +-- src/debugger/gui/CartFCWidget.hxx | 2 +- src/debugger/gui/CartFEWidget.cxx | 4 +-- src/debugger/gui/CartFEWidget.hxx | 2 +- src/debugger/gui/CartUAWidget.cxx | 4 +-- src/debugger/gui/CartUAWidget.hxx | 2 +- src/debugger/gui/CartWDWidget.cxx | 2 +- src/debugger/gui/CartWDWidget.hxx | 2 +- src/debugger/gui/CartX07Widget.cxx | 4 +-- src/debugger/gui/CartX07Widget.hxx | 2 +- src/emucore/CartEnhanced.hxx | 2 +- 57 files changed, 113 insertions(+), 113 deletions(-) diff --git a/src/debugger/gui/Cart0840Widget.cxx b/src/debugger/gui/Cart0840Widget.cxx index c49c86d09..eb9275035 100644 --- a/src/debugger/gui/Cart0840Widget.cxx +++ b/src/debugger/gui/Cart0840Widget.cxx @@ -22,7 +22,7 @@ Cartridge0840Widget::Cartridge0840Widget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, Cartridge0840& cart) - : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { myHotspotDelta = 0x40; initialize(); @@ -34,7 +34,7 @@ string Cartridge0840Widget::description() ostringstream info; info << "0840 ECONObanking, two 4K banks\n"; - info << CartEnhancedWidget::description(); + info << CartridgeEnhancedWidget::description(); return info.str(); } diff --git a/src/debugger/gui/Cart0840Widget.hxx b/src/debugger/gui/Cart0840Widget.hxx index 89e8706c6..00605b262 100644 --- a/src/debugger/gui/Cart0840Widget.hxx +++ b/src/debugger/gui/Cart0840Widget.hxx @@ -22,7 +22,7 @@ class Cartridge0840; #include "CartEnhancedWidget.hxx" -class Cartridge0840Widget : public CartEnhancedWidget +class Cartridge0840Widget : public CartridgeEnhancedWidget { public: Cartridge0840Widget(GuiObject* boss, const GUI::Font& lfont, diff --git a/src/debugger/gui/Cart2KWidget.cxx b/src/debugger/gui/Cart2KWidget.cxx index c97bc440f..d87445ed3 100644 --- a/src/debugger/gui/Cart2KWidget.cxx +++ b/src/debugger/gui/Cart2KWidget.cxx @@ -22,7 +22,7 @@ Cartridge2KWidget::Cartridge2KWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, Cartridge2K& cart) - : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { initialize(); } @@ -33,7 +33,7 @@ string Cartridge2KWidget::description() ostringstream info; info << "Standard 2K cartridge, non-bankswitched\n"; - info << CartEnhancedWidget::description(); + info << CartridgeEnhancedWidget::description(); return info.str(); } diff --git a/src/debugger/gui/Cart2KWidget.hxx b/src/debugger/gui/Cart2KWidget.hxx index e6e0fe9d2..123e3ddf5 100644 --- a/src/debugger/gui/Cart2KWidget.hxx +++ b/src/debugger/gui/Cart2KWidget.hxx @@ -22,7 +22,7 @@ class Cartridge2K; #include "CartEnhancedWidget.hxx" -class Cartridge2KWidget : public CartEnhancedWidget +class Cartridge2KWidget : public CartridgeEnhancedWidget { public: Cartridge2KWidget(GuiObject* boss, const GUI::Font& lfont, diff --git a/src/debugger/gui/Cart3FWidget.cxx b/src/debugger/gui/Cart3FWidget.cxx index 76f331502..ff5b0d219 100644 --- a/src/debugger/gui/Cart3FWidget.cxx +++ b/src/debugger/gui/Cart3FWidget.cxx @@ -22,7 +22,7 @@ Cartridge3FWidget::Cartridge3FWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, Cartridge3F& cart) - : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { myHotspotDelta = 0; initialize(); diff --git a/src/debugger/gui/Cart3FWidget.hxx b/src/debugger/gui/Cart3FWidget.hxx index 7e3ee65e9..e5f97a392 100644 --- a/src/debugger/gui/Cart3FWidget.hxx +++ b/src/debugger/gui/Cart3FWidget.hxx @@ -22,7 +22,7 @@ class Cartridge3F; #include "CartEnhancedWidget.hxx" -class Cartridge3FWidget : public CartEnhancedWidget +class Cartridge3FWidget : public CartridgeEnhancedWidget { public: Cartridge3FWidget(GuiObject* boss, const GUI::Font& lfont, diff --git a/src/debugger/gui/Cart4KSCWidget.cxx b/src/debugger/gui/Cart4KSCWidget.cxx index 105136dd5..b6bc05d51 100644 --- a/src/debugger/gui/Cart4KSCWidget.cxx +++ b/src/debugger/gui/Cart4KSCWidget.cxx @@ -22,7 +22,7 @@ Cartridge4KSCWidget::Cartridge4KSCWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, Cartridge4KSC& cart) - : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { initialize(); } @@ -33,7 +33,7 @@ string Cartridge4KSCWidget::description() ostringstream info; info << "4KSC cartridge, non-bankswitched\n"; - info << CartEnhancedWidget::description(); + info << CartridgeEnhancedWidget::description(); return info.str(); } diff --git a/src/debugger/gui/Cart4KSCWidget.hxx b/src/debugger/gui/Cart4KSCWidget.hxx index 832c2c127..624a5623a 100644 --- a/src/debugger/gui/Cart4KSCWidget.hxx +++ b/src/debugger/gui/Cart4KSCWidget.hxx @@ -22,7 +22,7 @@ class Cartridge4KSC; #include "CartEnhancedWidget.hxx" -class Cartridge4KSCWidget : public CartEnhancedWidget +class Cartridge4KSCWidget : public CartridgeEnhancedWidget { public: Cartridge4KSCWidget(GuiObject* boss, const GUI::Font& lfont, diff --git a/src/debugger/gui/Cart4KWidget.cxx b/src/debugger/gui/Cart4KWidget.cxx index 14091bd15..deca594fb 100644 --- a/src/debugger/gui/Cart4KWidget.cxx +++ b/src/debugger/gui/Cart4KWidget.cxx @@ -22,7 +22,7 @@ Cartridge4KWidget::Cartridge4KWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, Cartridge4K& cart) - : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { initialize(); @@ -43,7 +43,7 @@ string Cartridge4KWidget::description() ostringstream info; info << "Standard 4K cartridge, non-bankswitched\n"; - info << CartEnhancedWidget::description(); + info << CartridgeEnhancedWidget::description(); return info.str(); } diff --git a/src/debugger/gui/Cart4KWidget.hxx b/src/debugger/gui/Cart4KWidget.hxx index 886e2a060..3fd18eb66 100644 --- a/src/debugger/gui/Cart4KWidget.hxx +++ b/src/debugger/gui/Cart4KWidget.hxx @@ -22,7 +22,7 @@ class Cartridge4K; #include "CartEnhanced.hxx" -class Cartridge4KWidget : public CartEnhancedWidget +class Cartridge4KWidget : public CartridgeEnhancedWidget { public: Cartridge4KWidget(GuiObject* boss, const GUI::Font& lfont, diff --git a/src/debugger/gui/CartBFSCWidget.cxx b/src/debugger/gui/CartBFSCWidget.cxx index 00109d9e9..15f10ff62 100644 --- a/src/debugger/gui/CartBFSCWidget.cxx +++ b/src/debugger/gui/CartBFSCWidget.cxx @@ -22,7 +22,7 @@ CartridgeBFSCWidget::CartridgeBFSCWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeBFSC& cart) - : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { initialize(); } @@ -33,7 +33,7 @@ string CartridgeBFSCWidget::description() ostringstream info; info << "256K BFSC + RAM, 64 4K banks\n"; - info << CartEnhancedWidget::description(); + info << CartridgeEnhancedWidget::description(); return info.str(); } diff --git a/src/debugger/gui/CartBFSCWidget.hxx b/src/debugger/gui/CartBFSCWidget.hxx index 5e394eae5..739f41388 100644 --- a/src/debugger/gui/CartBFSCWidget.hxx +++ b/src/debugger/gui/CartBFSCWidget.hxx @@ -22,7 +22,7 @@ class CartridgeBFSC; #include "CartEnhancedWidget.hxx" -class CartridgeBFSCWidget : public CartEnhancedWidget +class CartridgeBFSCWidget : public CartridgeEnhancedWidget { public: CartridgeBFSCWidget(GuiObject* boss, const GUI::Font& lfont, diff --git a/src/debugger/gui/CartBFWidget.cxx b/src/debugger/gui/CartBFWidget.cxx index 001f50658..cbaabf076 100644 --- a/src/debugger/gui/CartBFWidget.cxx +++ b/src/debugger/gui/CartBFWidget.cxx @@ -22,7 +22,7 @@ CartridgeBFWidget::CartridgeBFWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeBF& cart) - : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { initialize(); } @@ -33,7 +33,7 @@ string CartridgeBFWidget::description() ostringstream info; info << "256K BF cartridge, 64 4K banks\n"; - info << CartEnhancedWidget::description(); + info << CartridgeEnhancedWidget::description(); return info.str(); } diff --git a/src/debugger/gui/CartBFWidget.hxx b/src/debugger/gui/CartBFWidget.hxx index 6c8d37257..b67391c63 100644 --- a/src/debugger/gui/CartBFWidget.hxx +++ b/src/debugger/gui/CartBFWidget.hxx @@ -22,7 +22,7 @@ class CartridgeBF; #include "CartEnhancedWidget.hxx" -class CartridgeBFWidget : public CartEnhancedWidget +class CartridgeBFWidget : public CartridgeEnhancedWidget { public: CartridgeBFWidget(GuiObject* boss, const GUI::Font& lfont, diff --git a/src/debugger/gui/CartCVWidget.cxx b/src/debugger/gui/CartCVWidget.cxx index 1517cc843..f76718375 100644 --- a/src/debugger/gui/CartCVWidget.cxx +++ b/src/debugger/gui/CartCVWidget.cxx @@ -24,7 +24,7 @@ CartridgeCVWidget::CartridgeCVWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeCV& cart) - : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { initialize(); } @@ -35,7 +35,7 @@ string CartridgeCVWidget::description() ostringstream info; info << "CV 2K ROM + 1K RAM, non-bankswitched\n"; - info << CartEnhancedWidget::description(); + info << CartridgeEnhancedWidget::description(); return info.str(); } diff --git a/src/debugger/gui/CartCVWidget.hxx b/src/debugger/gui/CartCVWidget.hxx index dd8e971ab..63fc6f237 100644 --- a/src/debugger/gui/CartCVWidget.hxx +++ b/src/debugger/gui/CartCVWidget.hxx @@ -22,7 +22,7 @@ class CartridgeCV; #include "CartEnhancedWidget.hxx" -class CartridgeCVWidget : public CartEnhancedWidget +class CartridgeCVWidget : public CartridgeEnhancedWidget { public: CartridgeCVWidget(GuiObject* boss, const GUI::Font& lfont, diff --git a/src/debugger/gui/CartDFSCWidget.cxx b/src/debugger/gui/CartDFSCWidget.cxx index 0744ca182..ed792acb4 100644 --- a/src/debugger/gui/CartDFSCWidget.cxx +++ b/src/debugger/gui/CartDFSCWidget.cxx @@ -22,7 +22,7 @@ CartridgeDFSCWidget::CartridgeDFSCWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeDFSC& cart) - : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { initialize(); } @@ -33,7 +33,7 @@ string CartridgeDFSCWidget::description() ostringstream info; info << "128K DFSC + RAM, 32 4K banks\n"; - info << CartEnhancedWidget::description(); + info << CartridgeEnhancedWidget::description(); return info.str(); } diff --git a/src/debugger/gui/CartDFSCWidget.hxx b/src/debugger/gui/CartDFSCWidget.hxx index 7aff641ee..9e4481fa8 100644 --- a/src/debugger/gui/CartDFSCWidget.hxx +++ b/src/debugger/gui/CartDFSCWidget.hxx @@ -22,7 +22,7 @@ class CartridgeDFSC; #include "CartEnhancedWidget.hxx" -class CartridgeDFSCWidget : public CartEnhancedWidget +class CartridgeDFSCWidget : public CartridgeEnhancedWidget { public: CartridgeDFSCWidget(GuiObject* boss, const GUI::Font& lfont, diff --git a/src/debugger/gui/CartDFWidget.cxx b/src/debugger/gui/CartDFWidget.cxx index cdb6d4f1b..653588e56 100644 --- a/src/debugger/gui/CartDFWidget.cxx +++ b/src/debugger/gui/CartDFWidget.cxx @@ -22,7 +22,7 @@ CartridgeDFWidget::CartridgeDFWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeDF& cart) - : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { initialize(); } @@ -33,7 +33,7 @@ string CartridgeDFWidget::description() ostringstream info; info << "128K DF, 32 4K banks\n"; - info << CartEnhancedWidget::description(); + info << CartridgeEnhancedWidget::description(); return info.str(); } diff --git a/src/debugger/gui/CartDFWidget.hxx b/src/debugger/gui/CartDFWidget.hxx index d37176627..9b45552b9 100644 --- a/src/debugger/gui/CartDFWidget.hxx +++ b/src/debugger/gui/CartDFWidget.hxx @@ -22,7 +22,7 @@ class CartridgeDF; #include "CartEnhancedWidget.hxx" -class CartridgeDFWidget : public CartEnhancedWidget +class CartridgeDFWidget : public CartridgeEnhancedWidget { public: CartridgeDFWidget(GuiObject* boss, const GUI::Font& lfont, diff --git a/src/debugger/gui/CartE0Widget.cxx b/src/debugger/gui/CartE0Widget.cxx index b2b6368dc..12205c463 100644 --- a/src/debugger/gui/CartE0Widget.cxx +++ b/src/debugger/gui/CartE0Widget.cxx @@ -22,7 +22,7 @@ CartridgeE0Widget::CartridgeE0Widget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeE0& cart) - : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { initialize(); } @@ -33,7 +33,7 @@ string CartridgeE0Widget::description() ostringstream info; info << "E0 cartridge,\n eight 1K banks mapped into four segments\n"; - info << CartEnhancedWidget::description(); + info << CartridgeEnhancedWidget::description(); return info.str(); } diff --git a/src/debugger/gui/CartE0Widget.hxx b/src/debugger/gui/CartE0Widget.hxx index 8d0dbb386..a9d84b461 100644 --- a/src/debugger/gui/CartE0Widget.hxx +++ b/src/debugger/gui/CartE0Widget.hxx @@ -22,7 +22,7 @@ class CartridgeE0; #include "CartEnhancedWidget.hxx" -class CartridgeE0Widget : public CartEnhancedWidget +class CartridgeE0Widget : public CartridgeEnhancedWidget { public: CartridgeE0Widget(GuiObject* boss, const GUI::Font& lfont, diff --git a/src/debugger/gui/CartEFSCWidget.cxx b/src/debugger/gui/CartEFSCWidget.cxx index 8783ca09f..d6f60ddba 100644 --- a/src/debugger/gui/CartEFSCWidget.cxx +++ b/src/debugger/gui/CartEFSCWidget.cxx @@ -22,7 +22,7 @@ CartridgeEFSCWidget::CartridgeEFSCWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeEFSC& cart) - : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { initialize(); } @@ -33,7 +33,7 @@ string CartridgeEFSCWidget::description() ostringstream info; info << "64K H. Runner EFSC + RAM, 16 4K banks\n"; - info << CartEnhancedWidget::description(); + info << CartridgeEnhancedWidget::description(); return info.str(); } diff --git a/src/debugger/gui/CartEFSCWidget.hxx b/src/debugger/gui/CartEFSCWidget.hxx index c5d6c4eeb..975f17f8a 100644 --- a/src/debugger/gui/CartEFSCWidget.hxx +++ b/src/debugger/gui/CartEFSCWidget.hxx @@ -22,7 +22,7 @@ class CartridgeEFSC; #include "CartEnhancedWidget.hxx" -class CartridgeEFSCWidget : public CartEnhancedWidget +class CartridgeEFSCWidget : public CartridgeEnhancedWidget { public: CartridgeEFSCWidget(GuiObject* boss, const GUI::Font& lfont, diff --git a/src/debugger/gui/CartEFWidget.cxx b/src/debugger/gui/CartEFWidget.cxx index 4fbc9a030..c00d2c3f6 100644 --- a/src/debugger/gui/CartEFWidget.cxx +++ b/src/debugger/gui/CartEFWidget.cxx @@ -22,7 +22,7 @@ CartridgeEFWidget::CartridgeEFWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeEF& cart) - : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { initialize(); } @@ -33,7 +33,7 @@ string CartridgeEFWidget::description() ostringstream info; info << "64K H. Runner EF cartridge, 16 4K banks\n"; - info << CartEnhancedWidget::description(); + info << CartridgeEnhancedWidget::description(); return info.str(); } diff --git a/src/debugger/gui/CartEFWidget.hxx b/src/debugger/gui/CartEFWidget.hxx index 7299b22d3..7d173836a 100644 --- a/src/debugger/gui/CartEFWidget.hxx +++ b/src/debugger/gui/CartEFWidget.hxx @@ -22,7 +22,7 @@ class CartridgeEF; #include "CartEnhancedWidget.hxx" -class CartridgeEFWidget : public CartEnhancedWidget +class CartridgeEFWidget : public CartridgeEnhancedWidget { public: CartridgeEFWidget(GuiObject* boss, const GUI::Font& lfont, diff --git a/src/debugger/gui/CartEnhancedWidget.cxx b/src/debugger/gui/CartEnhancedWidget.cxx index a2e22c094..d4c6b4cf0 100644 --- a/src/debugger/gui/CartEnhancedWidget.cxx +++ b/src/debugger/gui/CartEnhancedWidget.cxx @@ -21,7 +21,7 @@ #include "CartEnhancedWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -CartEnhancedWidget::CartEnhancedWidget(GuiObject* boss, const GUI::Font& lfont, +CartridgeEnhancedWidget::CartridgeEnhancedWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeEnhanced& cart) @@ -31,7 +31,7 @@ CartEnhancedWidget::CartEnhancedWidget(GuiObject* boss, const GUI::Font& lfont, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int CartEnhancedWidget::initialize() +int CartridgeEnhancedWidget::initialize() { int ypos = addBaseInformation(size(), manufacturer(), description(), descriptionLines()) + myLineHeight; @@ -42,7 +42,7 @@ int CartEnhancedWidget::initialize() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -size_t CartEnhancedWidget::size() +size_t CartridgeEnhancedWidget::size() { size_t size; @@ -52,7 +52,7 @@ size_t CartEnhancedWidget::size() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartEnhancedWidget::description() +string CartridgeEnhancedWidget::description() { ostringstream info; @@ -64,13 +64,13 @@ string CartEnhancedWidget::description() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int CartEnhancedWidget::descriptionLines() +int CartridgeEnhancedWidget::descriptionLines() { return 18; // should be enough for almost all types } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartEnhancedWidget::ramDescription() +string CartridgeEnhancedWidget::ramDescription() { ostringstream info; @@ -86,7 +86,7 @@ string CartEnhancedWidget::ramDescription() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartEnhancedWidget::romDescription() +string CartridgeEnhancedWidget::romDescription() { ostringstream info; size_t size; @@ -134,7 +134,7 @@ string CartEnhancedWidget::romDescription() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartEnhancedWidget::bankSelect(int& ypos) +void CartridgeEnhancedWidget::bankSelect(int& ypos) { if(myCart.romBankCount() > 1) { @@ -182,7 +182,7 @@ void CartEnhancedWidget::bankSelect(int& ypos) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartEnhancedWidget::bankState() +string CartridgeEnhancedWidget::bankState() { if(myCart.romBankCount() > 1) { @@ -228,7 +228,7 @@ string CartEnhancedWidget::bankState() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartEnhancedWidget::hotspotStr(int bank, int segment, bool prefix) +string CartridgeEnhancedWidget::hotspotStr(int bank, int segment, bool prefix) { ostringstream info; uInt16 hotspot = myCart.hotspot(); @@ -244,13 +244,13 @@ string CartEnhancedWidget::hotspotStr(int bank, int segment, bool prefix) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int CartEnhancedWidget::bankSegs() +int CartridgeEnhancedWidget::bankSegs() { return myCart.myBankSegs; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartEnhancedWidget::saveOldState() +void CartridgeEnhancedWidget::saveOldState() { myOldState.internalRam.clear(); for(uInt32 i = 0; i < myCart.myRamSize; ++i) @@ -265,7 +265,7 @@ void CartEnhancedWidget::saveOldState() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartEnhancedWidget::loadConfig() +void CartridgeEnhancedWidget::loadConfig() { if(myBankWidgets != nullptr) { @@ -281,7 +281,7 @@ void CartEnhancedWidget::loadConfig() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartEnhancedWidget::handleCommand(CommandSender* sender, +void CartridgeEnhancedWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) @@ -294,19 +294,19 @@ void CartEnhancedWidget::handleCommand(CommandSender* sender, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 CartEnhancedWidget::internalRamSize() +uInt32 CartridgeEnhancedWidget::internalRamSize() { return myCart.myRamSize; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 CartEnhancedWidget::internalRamRPort(int start) +uInt32 CartridgeEnhancedWidget::internalRamRPort(int start) { return ADDR_BASE + myCart.myReadOffset + start; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartEnhancedWidget::internalRamDescription() +string CartridgeEnhancedWidget::internalRamDescription() { ostringstream desc; @@ -334,7 +334,7 @@ string CartEnhancedWidget::internalRamDescription() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& CartEnhancedWidget::internalRamOld(int start, int count) +const ByteArray& CartridgeEnhancedWidget::internalRamOld(int start, int count) { myRamOld.clear(); for(int i = 0; i < count; i++) @@ -343,7 +343,7 @@ const ByteArray& CartEnhancedWidget::internalRamOld(int start, int count) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& CartEnhancedWidget::internalRamCurrent(int start, int count) +const ByteArray& CartridgeEnhancedWidget::internalRamCurrent(int start, int count) { myRamCurrent.clear(); for(int i = 0; i < count; i++) @@ -352,19 +352,19 @@ const ByteArray& CartEnhancedWidget::internalRamCurrent(int start, int count) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartEnhancedWidget::internalRamSetValue(int addr, uInt8 value) +void CartridgeEnhancedWidget::internalRamSetValue(int addr, uInt8 value) { myCart.myRAM[addr] = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartEnhancedWidget::internalRamGetValue(int addr) +uInt8 CartridgeEnhancedWidget::internalRamGetValue(int addr) { return myCart.myRAM[addr]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartEnhancedWidget::internalRamLabel(int addr) +string CartridgeEnhancedWidget::internalRamLabel(int addr) { CartDebug& dbg = instance().debugger().cartDebug(); return dbg.getLabel(addr + ADDR_BASE + myCart.myReadOffset, false); diff --git a/src/debugger/gui/CartEnhancedWidget.hxx b/src/debugger/gui/CartEnhancedWidget.hxx index 2cbd22ced..42ffce1c9 100644 --- a/src/debugger/gui/CartEnhancedWidget.hxx +++ b/src/debugger/gui/CartEnhancedWidget.hxx @@ -27,14 +27,14 @@ namespace GUI { #include "CartDebugWidget.hxx" -class CartEnhancedWidget : public CartDebugWidget +class CartridgeEnhancedWidget : public CartDebugWidget { public: - CartEnhancedWidget(GuiObject* boss, const GUI::Font& lfont, - const GUI::Font& nfont, - int x, int y, int w, int h, - CartridgeEnhanced& cart); - virtual ~CartEnhancedWidget() = default; + CartridgeEnhancedWidget(GuiObject* boss, const GUI::Font& lfont, + const GUI::Font& nfont, + int x, int y, int w, int h, + CartridgeEnhanced& cart); + virtual ~CartridgeEnhancedWidget() = default; protected: int initialize(); @@ -97,11 +97,11 @@ class CartEnhancedWidget : public CartDebugWidget private: // Following constructors and assignment operators not supported - CartEnhancedWidget() = delete; - CartEnhancedWidget(const CartEnhancedWidget&) = delete; - CartEnhancedWidget(CartEnhancedWidget&&) = delete; - CartEnhancedWidget& operator=(const CartEnhancedWidget&) = delete; - CartEnhancedWidget& operator=(CartEnhancedWidget&&) = delete; + CartridgeEnhancedWidget() = delete; + CartridgeEnhancedWidget(const CartridgeEnhancedWidget&) = delete; + CartridgeEnhancedWidget(CartridgeEnhancedWidget&&) = delete; + CartridgeEnhancedWidget& operator=(const CartridgeEnhancedWidget&) = delete; + CartridgeEnhancedWidget& operator=(CartridgeEnhancedWidget&&) = delete; }; #endif diff --git a/src/debugger/gui/CartF0Widget.cxx b/src/debugger/gui/CartF0Widget.cxx index c4826249e..78b13f2d9 100644 --- a/src/debugger/gui/CartF0Widget.cxx +++ b/src/debugger/gui/CartF0Widget.cxx @@ -22,7 +22,7 @@ CartridgeF0Widget::CartridgeF0Widget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeF0& cart) - : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { myHotspotDelta = 0; initialize(); diff --git a/src/debugger/gui/CartF0Widget.hxx b/src/debugger/gui/CartF0Widget.hxx index 9ba5aa3ab..017d88e78 100644 --- a/src/debugger/gui/CartF0Widget.hxx +++ b/src/debugger/gui/CartF0Widget.hxx @@ -22,7 +22,7 @@ class CartridgeF0; #include "CartEnhancedWidget.hxx" -class CartridgeF0Widget : public CartEnhancedWidget +class CartridgeF0Widget : public CartridgeEnhancedWidget { public: CartridgeF0Widget(GuiObject* boss, const GUI::Font& lfont, diff --git a/src/debugger/gui/CartF4SCWidget.cxx b/src/debugger/gui/CartF4SCWidget.cxx index b85251cbe..8f75b6fce 100644 --- a/src/debugger/gui/CartF4SCWidget.cxx +++ b/src/debugger/gui/CartF4SCWidget.cxx @@ -22,7 +22,7 @@ CartridgeF4SCWidget::CartridgeF4SCWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeF4SC& cart) - : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { initialize(); } @@ -33,7 +33,7 @@ string CartridgeF4SCWidget::description() ostringstream info; info << "Standard F4SC cartridge, eight 4K banks\n"; - info << CartEnhancedWidget::description(); + info << CartridgeEnhancedWidget::description(); return info.str(); } diff --git a/src/debugger/gui/CartF4SCWidget.hxx b/src/debugger/gui/CartF4SCWidget.hxx index 8c22c6d74..c6570a9fa 100644 --- a/src/debugger/gui/CartF4SCWidget.hxx +++ b/src/debugger/gui/CartF4SCWidget.hxx @@ -22,7 +22,7 @@ class CartridgeF4SC; #include "CartEnhancedWidget.hxx" -class CartridgeF4SCWidget : public CartEnhancedWidget +class CartridgeF4SCWidget : public CartridgeEnhancedWidget { public: CartridgeF4SCWidget(GuiObject* boss, const GUI::Font& lfont, diff --git a/src/debugger/gui/CartF4Widget.cxx b/src/debugger/gui/CartF4Widget.cxx index ae884cfa9..5069f029d 100644 --- a/src/debugger/gui/CartF4Widget.cxx +++ b/src/debugger/gui/CartF4Widget.cxx @@ -22,7 +22,7 @@ CartridgeF4Widget::CartridgeF4Widget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeF4& cart) - : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { initialize(); } @@ -33,7 +33,7 @@ string CartridgeF4Widget::description() ostringstream info; info << "Standard F4 cartridge, eight 4K banks\n"; - info << CartEnhancedWidget::description(); + info << CartridgeEnhancedWidget::description(); return info.str(); } diff --git a/src/debugger/gui/CartF4Widget.hxx b/src/debugger/gui/CartF4Widget.hxx index 2201b246b..d444a5956 100644 --- a/src/debugger/gui/CartF4Widget.hxx +++ b/src/debugger/gui/CartF4Widget.hxx @@ -22,7 +22,7 @@ class CartridgeF4; #include "CartEnhancedWidget.hxx" -class CartridgeF4Widget : public CartEnhancedWidget +class CartridgeF4Widget : public CartridgeEnhancedWidget { public: CartridgeF4Widget(GuiObject* boss, const GUI::Font& lfont, diff --git a/src/debugger/gui/CartF6SCWidget.cxx b/src/debugger/gui/CartF6SCWidget.cxx index bfa99b5c5..d2556799c 100644 --- a/src/debugger/gui/CartF6SCWidget.cxx +++ b/src/debugger/gui/CartF6SCWidget.cxx @@ -22,7 +22,7 @@ CartridgeF6SCWidget::CartridgeF6SCWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeF6SC& cart) - : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { initialize(); } @@ -33,7 +33,7 @@ string CartridgeF6SCWidget::description() ostringstream info; info << "Standard F6SC cartridge, four 4K banks\n"; - info << CartEnhancedWidget::description(); + info << CartridgeEnhancedWidget::description(); return info.str(); } diff --git a/src/debugger/gui/CartF6SCWidget.hxx b/src/debugger/gui/CartF6SCWidget.hxx index 6b0aab9f8..1ed6378a7 100644 --- a/src/debugger/gui/CartF6SCWidget.hxx +++ b/src/debugger/gui/CartF6SCWidget.hxx @@ -22,7 +22,7 @@ class CartridgeF6SC; #include "CartEnhancedWidget.hxx" -class CartridgeF6SCWidget : public CartEnhancedWidget +class CartridgeF6SCWidget : public CartridgeEnhancedWidget { public: CartridgeF6SCWidget(GuiObject* boss, const GUI::Font& lfont, diff --git a/src/debugger/gui/CartF6Widget.cxx b/src/debugger/gui/CartF6Widget.cxx index 692c40258..66bcbc6a7 100644 --- a/src/debugger/gui/CartF6Widget.cxx +++ b/src/debugger/gui/CartF6Widget.cxx @@ -22,7 +22,7 @@ CartridgeF6Widget::CartridgeF6Widget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeF6& cart) - : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { initialize(); } @@ -33,7 +33,7 @@ string CartridgeF6Widget::description() ostringstream info; info << "Standard F6 cartridge, four 4K banks\n"; - info << CartEnhancedWidget::description(); + info << CartridgeEnhancedWidget::description(); return info.str(); } diff --git a/src/debugger/gui/CartF6Widget.hxx b/src/debugger/gui/CartF6Widget.hxx index e36933ac7..2d0eb3734 100644 --- a/src/debugger/gui/CartF6Widget.hxx +++ b/src/debugger/gui/CartF6Widget.hxx @@ -22,7 +22,7 @@ class CartridgeF6; #include "CartEnhancedWidget.hxx" -class CartridgeF6Widget : public CartEnhancedWidget +class CartridgeF6Widget : public CartridgeEnhancedWidget { public: CartridgeF6Widget(GuiObject* boss, const GUI::Font& lfont, diff --git a/src/debugger/gui/CartF8SCWidget.cxx b/src/debugger/gui/CartF8SCWidget.cxx index 78e1c70a9..baae2360a 100644 --- a/src/debugger/gui/CartF8SCWidget.cxx +++ b/src/debugger/gui/CartF8SCWidget.cxx @@ -22,7 +22,7 @@ CartridgeF8SCWidget::CartridgeF8SCWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeF8SC& cart) - : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { initialize(); } @@ -33,7 +33,7 @@ string CartridgeF8SCWidget::description() ostringstream info; info << "Standard F8SC cartridge, two 4K banks\n"; - info << CartEnhancedWidget::description(); + info << CartridgeEnhancedWidget::description(); return info.str(); } diff --git a/src/debugger/gui/CartF8SCWidget.hxx b/src/debugger/gui/CartF8SCWidget.hxx index 3332f9a4b..3f6199783 100644 --- a/src/debugger/gui/CartF8SCWidget.hxx +++ b/src/debugger/gui/CartF8SCWidget.hxx @@ -22,7 +22,7 @@ class CartridgeF8SC; #include "CartEnhancedWidget.hxx" -class CartridgeF8SCWidget : public CartEnhancedWidget +class CartridgeF8SCWidget : public CartridgeEnhancedWidget { public: CartridgeF8SCWidget(GuiObject* boss, const GUI::Font& lfont, diff --git a/src/debugger/gui/CartF8Widget.cxx b/src/debugger/gui/CartF8Widget.cxx index ed1481b2a..d3dd88c23 100644 --- a/src/debugger/gui/CartF8Widget.cxx +++ b/src/debugger/gui/CartF8Widget.cxx @@ -22,7 +22,7 @@ CartridgeF8Widget::CartridgeF8Widget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeF8& cart) - : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { initialize(); } @@ -33,7 +33,7 @@ string CartridgeF8Widget::description() ostringstream info; info << "Standard F8 cartridge, two 4K banks\n"; - info << CartEnhancedWidget::description(); + info << CartridgeEnhancedWidget::description(); return info.str(); } diff --git a/src/debugger/gui/CartF8Widget.hxx b/src/debugger/gui/CartF8Widget.hxx index 34856f2ee..a0577f250 100644 --- a/src/debugger/gui/CartF8Widget.hxx +++ b/src/debugger/gui/CartF8Widget.hxx @@ -23,7 +23,7 @@ class PopUpWidget; #include "CartEnhancedWidget.hxx" -class CartridgeF8Widget : public CartEnhancedWidget +class CartridgeF8Widget : public CartridgeEnhancedWidget { public: CartridgeF8Widget(GuiObject* boss, const GUI::Font& lfont, diff --git a/src/debugger/gui/CartFA2Widget.cxx b/src/debugger/gui/CartFA2Widget.cxx index 40fab9d4d..1c2562628 100644 --- a/src/debugger/gui/CartFA2Widget.cxx +++ b/src/debugger/gui/CartFA2Widget.cxx @@ -22,7 +22,7 @@ CartridgeFA2Widget::CartridgeFA2Widget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeFA2& cart) - : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { int xpos = 2, ypos = initialize(); @@ -65,7 +65,7 @@ string CartridgeFA2Widget::description() info << "Modified FA RAM+, six or seven 4K banks\n"; info << "RAM+ can be loaded/saved to Harmony flash memory by accessing $" << Common::Base::HEX4 << 0xFFF4 << "\n"; - info << CartEnhancedWidget::description(); + info << CartridgeEnhancedWidget::description(); return info.str(); } @@ -91,6 +91,6 @@ void CartridgeFA2Widget::handleCommand(CommandSender* sender, break; default: - CartEnhancedWidget::handleCommand(sender, cmd, data, id); + CartridgeEnhancedWidget::handleCommand(sender, cmd, data, id); } } diff --git a/src/debugger/gui/CartFA2Widget.hxx b/src/debugger/gui/CartFA2Widget.hxx index 30b1ec81f..98508644c 100644 --- a/src/debugger/gui/CartFA2Widget.hxx +++ b/src/debugger/gui/CartFA2Widget.hxx @@ -23,7 +23,7 @@ class ButtonWidget; #include "CartEnhancedWidget.hxx" -class CartridgeFA2Widget : public CartEnhancedWidget +class CartridgeFA2Widget : public CartridgeEnhancedWidget { public: CartridgeFA2Widget(GuiObject* boss, const GUI::Font& lfont, diff --git a/src/debugger/gui/CartFAWidget.cxx b/src/debugger/gui/CartFAWidget.cxx index b3fefff6d..aea8a2061 100644 --- a/src/debugger/gui/CartFAWidget.cxx +++ b/src/debugger/gui/CartFAWidget.cxx @@ -22,7 +22,7 @@ CartridgeFAWidget::CartridgeFAWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeFA& cart) - : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { initialize(); } @@ -33,7 +33,7 @@ string CartridgeFAWidget::description() ostringstream info; info << "CBS RAM+ FA cartridge, three 4K banks\n"; - info << CartEnhancedWidget::description(); + info << CartridgeEnhancedWidget::description(); return info.str(); } diff --git a/src/debugger/gui/CartFAWidget.hxx b/src/debugger/gui/CartFAWidget.hxx index b7fbb3308..2d7311a71 100644 --- a/src/debugger/gui/CartFAWidget.hxx +++ b/src/debugger/gui/CartFAWidget.hxx @@ -22,7 +22,7 @@ class CartridgeFA; #include "CartEnhancedWidget.hxx" -class CartridgeFAWidget : public CartEnhancedWidget +class CartridgeFAWidget : public CartridgeEnhancedWidget { public: CartridgeFAWidget(GuiObject* boss, const GUI::Font& lfont, diff --git a/src/debugger/gui/CartFCWidget.cxx b/src/debugger/gui/CartFCWidget.cxx index 8210eed2e..d206ec694 100644 --- a/src/debugger/gui/CartFCWidget.cxx +++ b/src/debugger/gui/CartFCWidget.cxx @@ -22,7 +22,7 @@ CartridgeFCWidget::CartridgeFCWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeFC& cart) - : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { initialize(); } @@ -39,7 +39,7 @@ string CartridgeFCWidget::description() << " $" << Common::Base::HEX4 << (hotspot + 1) << " (defines high bits)\n" << " $" << Common::Base::HEX4 << (hotspot + 4) << " (triggers bank switch)\n"; - info << CartEnhancedWidget::description(); + info << CartridgeEnhancedWidget::description(); return info.str(); } diff --git a/src/debugger/gui/CartFCWidget.hxx b/src/debugger/gui/CartFCWidget.hxx index f1bb4a50f..f6d56af71 100644 --- a/src/debugger/gui/CartFCWidget.hxx +++ b/src/debugger/gui/CartFCWidget.hxx @@ -22,7 +22,7 @@ class CartridgeFC; #include "CartEnhancedWidget.hxx" -class CartridgeFCWidget : public CartEnhancedWidget +class CartridgeFCWidget : public CartridgeEnhancedWidget { public: CartridgeFCWidget(GuiObject* boss, const GUI::Font& lfont, diff --git a/src/debugger/gui/CartFEWidget.cxx b/src/debugger/gui/CartFEWidget.cxx index dbe992a4f..ce7267e6e 100644 --- a/src/debugger/gui/CartFEWidget.cxx +++ b/src/debugger/gui/CartFEWidget.cxx @@ -22,7 +22,7 @@ CartridgeFEWidget::CartridgeFEWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeFE& cart) - : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { initialize(); } @@ -35,7 +35,7 @@ string CartridgeFEWidget::description() info << "FE cartridge, two 4K banks\n" << "Monitors access to hotspot $01FE, and uses " << "upper 3 bits of databus for bank number:\n"; - info << CartEnhancedWidget::description(); + info << CartridgeEnhancedWidget::description(); return info.str(); } diff --git a/src/debugger/gui/CartFEWidget.hxx b/src/debugger/gui/CartFEWidget.hxx index 05a320a71..468fcc144 100644 --- a/src/debugger/gui/CartFEWidget.hxx +++ b/src/debugger/gui/CartFEWidget.hxx @@ -22,7 +22,7 @@ class CartridgeFE; #include "CartEnhancedWidget.hxx" -class CartridgeFEWidget : public CartEnhancedWidget +class CartridgeFEWidget : public CartridgeEnhancedWidget { public: CartridgeFEWidget(GuiObject* boss, const GUI::Font& lfont, diff --git a/src/debugger/gui/CartUAWidget.cxx b/src/debugger/gui/CartUAWidget.cxx index ffaef806b..f6ae16bc7 100644 --- a/src/debugger/gui/CartUAWidget.cxx +++ b/src/debugger/gui/CartUAWidget.cxx @@ -22,7 +22,7 @@ CartridgeUAWidget::CartridgeUAWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeUA& cart, bool swapHotspots) - : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart), + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart), mySwappedHotspots(swapHotspots) { myHotspotDelta = 0x20; @@ -35,7 +35,7 @@ string CartridgeUAWidget::description() ostringstream info; info << "8K UA cartridge" << (mySwappedHotspots ? " (swapped banks)" : "") << ", two 4K banks\n"; - info << CartEnhancedWidget::description(); + info << CartridgeEnhancedWidget::description(); return info.str(); } diff --git a/src/debugger/gui/CartUAWidget.hxx b/src/debugger/gui/CartUAWidget.hxx index 8a49136a2..a610a1316 100644 --- a/src/debugger/gui/CartUAWidget.hxx +++ b/src/debugger/gui/CartUAWidget.hxx @@ -22,7 +22,7 @@ class CartridgeUA; #include "CartEnhancedWidget.hxx" -class CartridgeUAWidget : public CartEnhancedWidget +class CartridgeUAWidget : public CartridgeEnhancedWidget { public: CartridgeUAWidget(GuiObject* boss, const GUI::Font& lfont, diff --git a/src/debugger/gui/CartWDWidget.cxx b/src/debugger/gui/CartWDWidget.cxx index 16fe416ec..94d7e8060 100644 --- a/src/debugger/gui/CartWDWidget.cxx +++ b/src/debugger/gui/CartWDWidget.cxx @@ -22,7 +22,7 @@ CartridgeWDWidget::CartridgeWDWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeWD& cart) - : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { initialize(); } diff --git a/src/debugger/gui/CartWDWidget.hxx b/src/debugger/gui/CartWDWidget.hxx index 9bab7af30..746d62e63 100644 --- a/src/debugger/gui/CartWDWidget.hxx +++ b/src/debugger/gui/CartWDWidget.hxx @@ -22,7 +22,7 @@ class CartridgeWD; #include "CartEnhancedWidget.hxx" -class CartridgeWDWidget : public CartEnhancedWidget +class CartridgeWDWidget : public CartridgeEnhancedWidget { public: CartridgeWDWidget(GuiObject* boss, const GUI::Font& lfont, diff --git a/src/debugger/gui/CartX07Widget.cxx b/src/debugger/gui/CartX07Widget.cxx index 4fb31a9ca..2c4a167d4 100644 --- a/src/debugger/gui/CartX07Widget.cxx +++ b/src/debugger/gui/CartX07Widget.cxx @@ -22,7 +22,7 @@ CartridgeX07Widget::CartridgeX07Widget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeX07& cart) - : CartEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { initialize(); } @@ -35,7 +35,7 @@ string CartridgeX07Widget::description() info << "64K X07 cartridge, 16 4K banks\n" << "Multiple hotspots, all below $1000\n" << "See documentation for further details\n"; - info << CartEnhancedWidget::description(); + info << CartridgeEnhancedWidget::description(); return info.str(); } diff --git a/src/debugger/gui/CartX07Widget.hxx b/src/debugger/gui/CartX07Widget.hxx index a096c5d0d..58492e7e6 100644 --- a/src/debugger/gui/CartX07Widget.hxx +++ b/src/debugger/gui/CartX07Widget.hxx @@ -22,7 +22,7 @@ class CartridgeX07; #include "CartEnhancedWidget.hxx" -class CartridgeX07Widget : public CartEnhancedWidget +class CartridgeX07Widget : public CartridgeEnhancedWidget { public: CartridgeX07Widget(GuiObject* boss, const GUI::Font& lfont, diff --git a/src/emucore/CartEnhanced.hxx b/src/emucore/CartEnhanced.hxx index c3702d118..ad97409a9 100644 --- a/src/emucore/CartEnhanced.hxx +++ b/src/emucore/CartEnhanced.hxx @@ -33,7 +33,7 @@ class System; */ class CartridgeEnhanced : public Cartridge { - friend class CartEnhancedWidget; + friend class CartridgeEnhancedWidget; public: /** From 069703f4897622aa02ec7fb1d5bcfe7889d37263 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 21 Apr 2020 15:14:52 +0200 Subject: [PATCH 137/377] remove dynamic casting --- src/debugger/gui/CartFA2Widget.cxx | 11 +++++------ src/debugger/gui/CartFA2Widget.hxx | 9 ++++++--- src/debugger/gui/CartWDWidget.cxx | 6 +++--- src/debugger/gui/CartWDWidget.hxx | 3 +++ 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/debugger/gui/CartFA2Widget.cxx b/src/debugger/gui/CartFA2Widget.cxx index 1c2562628..e7dcba933 100644 --- a/src/debugger/gui/CartFA2Widget.cxx +++ b/src/debugger/gui/CartFA2Widget.cxx @@ -22,7 +22,8 @@ CartridgeFA2Widget::CartridgeFA2Widget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeFA2& cart) - : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart), + myCartFA2(cart) { int xpos = 2, ypos = initialize(); @@ -74,20 +75,18 @@ string CartridgeFA2Widget::description() void CartridgeFA2Widget::handleCommand(CommandSender* sender, int cmd, int data, int id) { - CartridgeFA2& cart = dynamic_cast(myCart); - switch(cmd) { case kFlashErase: - cart.flash(0); + myCartFA2.flash(0); break; case kFlashLoad: - cart.flash(1); + myCartFA2.flash(1); break; case kFlashSave: - cart.flash(2); + myCartFA2.flash(2); break; default: diff --git a/src/debugger/gui/CartFA2Widget.hxx b/src/debugger/gui/CartFA2Widget.hxx index 98508644c..06865c495 100644 --- a/src/debugger/gui/CartFA2Widget.hxx +++ b/src/debugger/gui/CartFA2Widget.hxx @@ -33,9 +33,7 @@ class CartridgeFA2Widget : public CartridgeEnhancedWidget virtual ~CartridgeFA2Widget() = default; private: - string manufacturer() override { return "Chris D. Walton (Star Castle 2600 Arcade)"; } - - string description() override; + CartridgeFA2& myCartFA2; ButtonWidget *myFlashErase{nullptr}, *myFlashLoad{nullptr}, *myFlashSave{nullptr}; @@ -45,6 +43,11 @@ class CartridgeFA2Widget : public CartridgeEnhancedWidget kFlashSave = 'flSV' }; + private: + string manufacturer() override { return "Chris D. Walton (Star Castle 2600 Arcade)"; } + + string description() override; + private: void handleCommand(CommandSender* sender, int cmd, int data, int id) override; diff --git a/src/debugger/gui/CartWDWidget.cxx b/src/debugger/gui/CartWDWidget.cxx index 94d7e8060..268e81bf1 100644 --- a/src/debugger/gui/CartWDWidget.cxx +++ b/src/debugger/gui/CartWDWidget.cxx @@ -22,7 +22,8 @@ CartridgeWDWidget::CartridgeWDWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeWD& cart) - : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart), + myCartWD(cart) { initialize(); } @@ -45,8 +46,7 @@ string CartridgeWDWidget::description() string CartridgeWDWidget::hotspotStr(int bank, int segment, bool prefix) { ostringstream info; - CartridgeWD& cart = dynamic_cast(myCart); - CartridgeWD::BankOrg banks = cart.ourBankOrg[bank]; + CartridgeWD::BankOrg banks = myCartWD.ourBankOrg[bank]; info << "(" << (prefix ? "hotspot " : "") << "$" << Common::Base::HEX1 << (myCart.hotspot() + bank) << ") [" diff --git a/src/debugger/gui/CartWDWidget.hxx b/src/debugger/gui/CartWDWidget.hxx index 746d62e63..0201cffa5 100644 --- a/src/debugger/gui/CartWDWidget.hxx +++ b/src/debugger/gui/CartWDWidget.hxx @@ -31,6 +31,9 @@ class CartridgeWDWidget : public CartridgeEnhancedWidget CartridgeWD& cart); virtual ~CartridgeWDWidget() = default; +private: + CartridgeWD& myCartWD; + private: string manufacturer() override { return "Wickstead Design"; } From 1064a1153fd05f9fc6e506684bcba89246de7a53 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 21 Apr 2020 16:20:37 +0200 Subject: [PATCH 138/377] order KeyMap and JoyMap when saving --- src/common/JoyMap.cxx | 28 +++++++++++++++++++++++++++- src/common/KeyMap.cxx | 24 +++++++++++++++++++++--- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/common/JoyMap.cxx b/src/common/JoyMap.cxx index 2a20b4a8b..266dd5e74 100644 --- a/src/common/JoyMap.cxx +++ b/src/common/JoyMap.cxx @@ -185,9 +185,35 @@ JoyMap::JoyMappingArray JoyMap::getEventMapping(const Event::Type event, const E // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string JoyMap::saveMapping(const EventMode mode) const { + using MapType = std::pair; + std::vector sortedMap(myMap.begin(), myMap.end()); + + std::sort(sortedMap.begin(), sortedMap.end(), + [](const MapType& a, const MapType& b) + { + // Event::Type first + if(a.second != b.second) + return a.second < b.second; + + if(a.first.button != b.first.button) + return a.first.button < b.first.button; + + if(a.first.axis != b.first.axis) + return a.first.axis < b.first.axis; + + if(a.first.adir != b.first.adir) + return a.first.adir < b.first.adir; + + if(a.first.hat != b.first.hat) + return a.first.hat < b.first.hat; + + return a.first.hdir < b.first.hdir; + } + ); + ostringstream buf; - for (auto item : myMap) + for (auto item : sortedMap) { if (item.first.mode == mode) { diff --git a/src/common/KeyMap.cxx b/src/common/KeyMap.cxx index eca0369ec..47b34dc9c 100644 --- a/src/common/KeyMap.cxx +++ b/src/common/KeyMap.cxx @@ -16,11 +16,12 @@ //============================================================================ #include "KeyMap.hxx" +#include // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void KeyMap::add(const Event::Type event, const Mapping& mapping) { - myMap[convertMod(mapping)] = event; + myMap[convertMod(mapping)] = event; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -32,7 +33,7 @@ void KeyMap::add(const Event::Type event, const EventMode mode, const int key, c // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void KeyMap::erase(const Mapping& mapping) { - myMap.erase(convertMod(mapping)); + myMap.erase(convertMod(mapping)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -170,9 +171,26 @@ KeyMap::MappingArray KeyMap::getEventMapping(const Event::Type event, const Even // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string KeyMap::saveMapping(const EventMode mode) const { + using MapType = std::pair; + std::vector sortedMap(myMap.begin(), myMap.end()); + + std::sort(sortedMap.begin(), sortedMap.end(), + [](const MapType& a, const MapType& b) + { + // Event::Type first + if(a.second != b.second) + return a.second < b.second; + + if(a.first.key != b.first.key) + return a.first.key < b.first.key; + + return a.first.mod < b.first.mod; + } + ); + ostringstream buf; - for (auto item : myMap) + for (auto item : sortedMap) { if (item.first.mode == mode) { From 7ad10aa5d3a24b34f2926fcf65aaff731bd8b29f Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 21 Apr 2020 17:21:08 +0200 Subject: [PATCH 139/377] fix checking for existing mapping when applying default mappings (fixes #620) --- src/common/PJoystickHandler.cxx | 4 ++-- src/common/PKeyboardHandler.cxx | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/common/PJoystickHandler.cxx b/src/common/PJoystickHandler.cxx index e67793078..3b2452798 100644 --- a/src/common/PJoystickHandler.cxx +++ b/src/common/PJoystickHandler.cxx @@ -250,9 +250,9 @@ void PhysicalJoystickHandler::setDefaultAction(int stick, if(updateDefaults) { - // if there is no existing mapping for the event or + // if there is no existing mapping for the event and // the default mapping for the event is unused, set default key for event - if(j->joyMap.getEventMapping(map.event, mode).size() == 0 || + if(j->joyMap.getEventMapping(map.event, mode).size() == 0 && !j->joyMap.check(mode, map.button, map.axis, map.adir, map.hat, map.hdir)) { if (map.hat == JOY_CTRL_NONE) diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index bc2c545ca..b1a16eeef 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -80,11 +80,16 @@ void PhysicalKeyboardHandler::setDefaultKey(EventMapping map, Event::Type event, if (updateDefaults) { - // if there is no existing mapping for the event or + if (map.event == Event::ToggleSAPortOrder) + int i = 0; + + // if there is no existing mapping for the event and // the default mapping for the event is unused, set default key for event - if (myKeyMap.getEventMapping(map.event, mode).size() == 0 || + if (myKeyMap.getEventMapping(map.event, mode).size() == 0 && !myKeyMap.check(mode, map.key, map.mod)) { + if (map.event == Event::ConsoleReset) + int i = 0; addMapping(map.event, mode, map.key, StellaMod(map.mod)); } } From 7eb3bd33db2482e130923eab1ed5a03222d4f63c Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 21 Apr 2020 16:20:37 +0200 Subject: [PATCH 140/377] order KeyMap and JoyMap when saving --- src/common/JoyMap.cxx | 28 +++++++++++++++++++++++++++- src/common/KeyMap.cxx | 24 +++++++++++++++++++++--- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/common/JoyMap.cxx b/src/common/JoyMap.cxx index 2a20b4a8b..266dd5e74 100644 --- a/src/common/JoyMap.cxx +++ b/src/common/JoyMap.cxx @@ -185,9 +185,35 @@ JoyMap::JoyMappingArray JoyMap::getEventMapping(const Event::Type event, const E // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string JoyMap::saveMapping(const EventMode mode) const { + using MapType = std::pair; + std::vector sortedMap(myMap.begin(), myMap.end()); + + std::sort(sortedMap.begin(), sortedMap.end(), + [](const MapType& a, const MapType& b) + { + // Event::Type first + if(a.second != b.second) + return a.second < b.second; + + if(a.first.button != b.first.button) + return a.first.button < b.first.button; + + if(a.first.axis != b.first.axis) + return a.first.axis < b.first.axis; + + if(a.first.adir != b.first.adir) + return a.first.adir < b.first.adir; + + if(a.first.hat != b.first.hat) + return a.first.hat < b.first.hat; + + return a.first.hdir < b.first.hdir; + } + ); + ostringstream buf; - for (auto item : myMap) + for (auto item : sortedMap) { if (item.first.mode == mode) { diff --git a/src/common/KeyMap.cxx b/src/common/KeyMap.cxx index eca0369ec..47b34dc9c 100644 --- a/src/common/KeyMap.cxx +++ b/src/common/KeyMap.cxx @@ -16,11 +16,12 @@ //============================================================================ #include "KeyMap.hxx" +#include // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void KeyMap::add(const Event::Type event, const Mapping& mapping) { - myMap[convertMod(mapping)] = event; + myMap[convertMod(mapping)] = event; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -32,7 +33,7 @@ void KeyMap::add(const Event::Type event, const EventMode mode, const int key, c // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void KeyMap::erase(const Mapping& mapping) { - myMap.erase(convertMod(mapping)); + myMap.erase(convertMod(mapping)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -170,9 +171,26 @@ KeyMap::MappingArray KeyMap::getEventMapping(const Event::Type event, const Even // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string KeyMap::saveMapping(const EventMode mode) const { + using MapType = std::pair; + std::vector sortedMap(myMap.begin(), myMap.end()); + + std::sort(sortedMap.begin(), sortedMap.end(), + [](const MapType& a, const MapType& b) + { + // Event::Type first + if(a.second != b.second) + return a.second < b.second; + + if(a.first.key != b.first.key) + return a.first.key < b.first.key; + + return a.first.mod < b.first.mod; + } + ); + ostringstream buf; - for (auto item : myMap) + for (auto item : sortedMap) { if (item.first.mode == mode) { From f5492febdd5acc74305cbb0559f8ee19aeb563d4 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 21 Apr 2020 17:21:08 +0200 Subject: [PATCH 141/377] fix checking for existing mapping when applying default mappings (fixes #620) --- src/common/PJoystickHandler.cxx | 4 ++-- src/common/PKeyboardHandler.cxx | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/common/PJoystickHandler.cxx b/src/common/PJoystickHandler.cxx index e67793078..3b2452798 100644 --- a/src/common/PJoystickHandler.cxx +++ b/src/common/PJoystickHandler.cxx @@ -250,9 +250,9 @@ void PhysicalJoystickHandler::setDefaultAction(int stick, if(updateDefaults) { - // if there is no existing mapping for the event or + // if there is no existing mapping for the event and // the default mapping for the event is unused, set default key for event - if(j->joyMap.getEventMapping(map.event, mode).size() == 0 || + if(j->joyMap.getEventMapping(map.event, mode).size() == 0 && !j->joyMap.check(mode, map.button, map.axis, map.adir, map.hat, map.hdir)) { if (map.hat == JOY_CTRL_NONE) diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index bc2c545ca..b1a16eeef 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -80,11 +80,16 @@ void PhysicalKeyboardHandler::setDefaultKey(EventMapping map, Event::Type event, if (updateDefaults) { - // if there is no existing mapping for the event or + if (map.event == Event::ToggleSAPortOrder) + int i = 0; + + // if there is no existing mapping for the event and // the default mapping for the event is unused, set default key for event - if (myKeyMap.getEventMapping(map.event, mode).size() == 0 || + if (myKeyMap.getEventMapping(map.event, mode).size() == 0 && !myKeyMap.check(mode, map.key, map.mod)) { + if (map.event == Event::ConsoleReset) + int i = 0; addMapping(map.event, mode, map.key, StellaMod(map.mod)); } } From 0ef598a96a51807ef87652bb8c62a9c5d5184cae Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 21 Apr 2020 17:25:03 +0200 Subject: [PATCH 142/377] removed forgotten debug code --- src/common/PKeyboardHandler.cxx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index b1a16eeef..57a3bfd4b 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -80,16 +80,11 @@ void PhysicalKeyboardHandler::setDefaultKey(EventMapping map, Event::Type event, if (updateDefaults) { - if (map.event == Event::ToggleSAPortOrder) - int i = 0; - // if there is no existing mapping for the event and // the default mapping for the event is unused, set default key for event if (myKeyMap.getEventMapping(map.event, mode).size() == 0 && !myKeyMap.check(mode, map.key, map.mod)) { - if (map.event == Event::ConsoleReset) - int i = 0; addMapping(map.event, mode, map.key, StellaMod(map.mod)); } } From 9d5a631fb6537e593916442ff8b589d6e750a8ac Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 21 Apr 2020 19:48:53 +0200 Subject: [PATCH 143/377] 2nd attempt to fix #620 --- src/common/PKeyboardHandler.cxx | 12 +++++++++++- src/common/PKeyboardHandler.hxx | 3 +++ src/emucore/EventHandlerConstants.hxx | 3 ++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index 57a3bfd4b..f9a37664f 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -66,6 +66,16 @@ PhysicalKeyboardHandler::PhysicalKeyboardHandler(OSystem& system, EventHandler& setDefaultMapping(Event::NoType, EventMode::kMenuMode, true); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool PhysicalKeyboardHandler::isMappingUsed(EventMapping map) +{ + for(int i = 0; i < int(EventMode::kNumModes); ++i) + if(myKeyMap.check(EventMode(i), map.key, map.mod)) + return true; + + return false; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Depending on parameters, this method does the following: // 1. update all events with default (event == Event::NoType, updateDefault == true) @@ -83,7 +93,7 @@ void PhysicalKeyboardHandler::setDefaultKey(EventMapping map, Event::Type event, // if there is no existing mapping for the event and // the default mapping for the event is unused, set default key for event if (myKeyMap.getEventMapping(map.event, mode).size() == 0 && - !myKeyMap.check(mode, map.key, map.mod)) + !isMappingUsed(map)) { addMapping(map.event, mode, map.key, StellaMod(map.mod)); } diff --git a/src/common/PKeyboardHandler.hxx b/src/common/PKeyboardHandler.hxx index adb9b5106..33e19b421 100644 --- a/src/common/PKeyboardHandler.hxx +++ b/src/common/PKeyboardHandler.hxx @@ -87,6 +87,9 @@ class PhysicalKeyboardHandler }; using EventMappingArray = std::vector; + // Checks if the given mapping is used by any event mode + bool isMappingUsed(EventMapping map); + void setDefaultKey(EventMapping map, Event::Type event = Event::NoType, EventMode mode = EventMode::kEmulationMode, bool updateDefaults = false); diff --git a/src/emucore/EventHandlerConstants.hxx b/src/emucore/EventHandlerConstants.hxx index 7246983eb..8f11ecab6 100644 --- a/src/emucore/EventHandlerConstants.hxx +++ b/src/emucore/EventHandlerConstants.hxx @@ -82,7 +82,8 @@ enum class EventMode { kPaddlesMode, kKeypadMode, kCompuMateMode, // cannot be remapped - kCommonMode // mapping common between controllers + kCommonMode, // mapping common between controllers + kNumModes }; namespace GUI From b889bf1f456af89750a391a1e08c8ed15f341f65 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 22 Apr 2020 08:25:35 +0200 Subject: [PATCH 144/377] another final fix for #620 --- src/common/PKeyboardHandler.cxx | 27 +++++++++++++++++++++------ src/common/PKeyboardHandler.hxx | 2 +- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index f9a37664f..fa1139d66 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -67,13 +67,28 @@ PhysicalKeyboardHandler::PhysicalKeyboardHandler(OSystem& system, EventHandler& } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool PhysicalKeyboardHandler::isMappingUsed(EventMapping map) +bool PhysicalKeyboardHandler::isMappingUsed(EventMode mode, const EventMapping& map) const { - for(int i = 0; i < int(EventMode::kNumModes); ++i) - if(myKeyMap.check(EventMode(i), map.key, map.mod)) - return true; + // Menu events can only interfere with + // - other menu events + if(mode == EventMode::kMenuMode) + return myKeyMap.check(EventMode::kMenuMode, map.key, map.mod); - return false; + // Controller events can interfere with + // - other events of the same controller + // - and common emulation events + if(mode != EventMode::kCommonMode) + return myKeyMap.check(mode, map.key, map.mod) + || myKeyMap.check(EventMode::kCommonMode, map.key, map.mod); + + // Common emulation events can interfere with + // - other common emulation events + // - and all controller events + return myKeyMap.check(EventMode::kCommonMode, map.key, map.mod) + || myKeyMap.check(EventMode::kJoystickMode, map.key, map.mod) + || myKeyMap.check(EventMode::kPaddlesMode, map.key, map.mod) + || myKeyMap.check(EventMode::kKeypadMode, map.key, map.mod) + || myKeyMap.check(EventMode::kCompuMateMode, map.key, map.mod); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -93,7 +108,7 @@ void PhysicalKeyboardHandler::setDefaultKey(EventMapping map, Event::Type event, // if there is no existing mapping for the event and // the default mapping for the event is unused, set default key for event if (myKeyMap.getEventMapping(map.event, mode).size() == 0 && - !isMappingUsed(map)) + !isMappingUsed(mode, map)) { addMapping(map.event, mode, map.key, StellaMod(map.mod)); } diff --git a/src/common/PKeyboardHandler.hxx b/src/common/PKeyboardHandler.hxx index 33e19b421..ede6aa55a 100644 --- a/src/common/PKeyboardHandler.hxx +++ b/src/common/PKeyboardHandler.hxx @@ -88,7 +88,7 @@ class PhysicalKeyboardHandler using EventMappingArray = std::vector; // Checks if the given mapping is used by any event mode - bool isMappingUsed(EventMapping map); + bool isMappingUsed(EventMode mode, const EventMapping& map) const; void setDefaultKey(EventMapping map, Event::Type event = Event::NoType, EventMode mode = EventMode::kEmulationMode, bool updateDefaults = false); From 50ae9f7a621899ebbc7cc7bfc47f7439ac552052 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 22 Apr 2020 10:08:36 +0200 Subject: [PATCH 145/377] add 3EX bankswitching type (addresses #619) (TODO: debugger details) --- src/debugger/gui/Cart3EWidget.cxx | 2 +- src/debugger/gui/CartEnhancedWidget.cxx | 2 +- src/emucore/Bankswitch.cxx | 5 +- src/emucore/Bankswitch.hxx | 16 ++--- src/emucore/Cart3E.hxx | 6 +- src/emucore/Cart3EPlus.hxx | 2 +- src/emucore/Cart3EX.cxx | 27 ++++++++ src/emucore/Cart3EX.hxx | 87 +++++++++++++++++++++++++ src/emucore/Cart4KSC.hxx | 2 +- src/emucore/CartBFSC.hxx | 2 +- src/emucore/CartCV.hxx | 2 +- src/emucore/CartDFSC.hxx | 2 +- src/emucore/CartDetector.cxx | 33 ++++++++-- src/emucore/CartDetector.hxx | 5 ++ src/emucore/CartEFSC.hxx | 2 +- src/emucore/CartEnhanced.cxx | 4 +- src/emucore/CartEnhanced.hxx | 6 +- src/emucore/CartF4SC.hxx | 2 +- src/emucore/CartF6SC.hxx | 2 +- src/emucore/CartF8SC.hxx | 2 +- src/emucore/CartFA.hxx | 2 +- src/emucore/CartWD.hxx | 2 +- src/emucore/module.mk | 1 + src/windows/Stella.vcxproj | 2 + src/windows/Stella.vcxproj.filters | 6 ++ 25 files changed, 190 insertions(+), 34 deletions(-) create mode 100644 src/emucore/Cart3EX.cxx create mode 100644 src/emucore/Cart3EX.hxx diff --git a/src/debugger/gui/Cart3EWidget.cxx b/src/debugger/gui/Cart3EWidget.cxx index 287bdd112..b2ab3584c 100644 --- a/src/debugger/gui/Cart3EWidget.cxx +++ b/src/debugger/gui/Cart3EWidget.cxx @@ -169,7 +169,7 @@ string Cartridge3EWidget::bankState() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 Cartridge3EWidget::internalRamSize() { - return 32*1024; + return uInt32(myCart.myRamSize); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/debugger/gui/CartEnhancedWidget.cxx b/src/debugger/gui/CartEnhancedWidget.cxx index d4c6b4cf0..35c5f9e25 100644 --- a/src/debugger/gui/CartEnhancedWidget.cxx +++ b/src/debugger/gui/CartEnhancedWidget.cxx @@ -296,7 +296,7 @@ void CartridgeEnhancedWidget::handleCommand(CommandSender* sender, // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeEnhancedWidget::internalRamSize() { - return myCart.myRamSize; + return uInt32(myCart.myRamSize); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Bankswitch.cxx b/src/emucore/Bankswitch.cxx index 7ce52db58..1b907eea7 100644 --- a/src/emucore/Bankswitch.cxx +++ b/src/emucore/Bankswitch.cxx @@ -104,7 +104,8 @@ Bankswitch::BSList = {{ { "64IN1" , "64IN1 Multicart (128/256K)" }, { "128IN1" , "128IN1 Multicart (256/512K)" }, { "2K" , "2K (32-2048 bytes Atari)" }, - { "3E" , "3E (32K Tigervision)" }, + { "3E" , "3E (Tigervision, 32K RAM)" }, + { "3EX" , "3EX (Tigervision, 256K RAM)" }, { "3E+" , "3E+ (TJ modified 3E)" }, { "3F" , "3F (512K Tigervision)" }, { "4A50" , "4A50 (64K 4A50 + RAM)" }, @@ -178,6 +179,7 @@ Bankswitch::ExtensionMap Bankswitch::ourExtensions = { { "128N1" , Bankswitch::Type::_128IN1 }, { "2K" , Bankswitch::Type::_2K }, { "3E" , Bankswitch::Type::_3E }, + { "3EX" , Bankswitch::Type::_3EX }, { "3EP" , Bankswitch::Type::_3EP }, { "3E+" , Bankswitch::Type::_3EP }, { "3F" , Bankswitch::Type::_3F }, @@ -245,6 +247,7 @@ Bankswitch::NameToTypeMap Bankswitch::ourNameToTypes = { { "2K" , Bankswitch::Type::_2K }, { "3E" , Bankswitch::Type::_3E }, { "3E+" , Bankswitch::Type::_3EP }, + { "3EX" , Bankswitch::Type::_3EX }, { "3F" , Bankswitch::Type::_3F }, { "4A50" , Bankswitch::Type::_4A50 }, { "4K" , Bankswitch::Type::_4K }, diff --git a/src/emucore/Bankswitch.hxx b/src/emucore/Bankswitch.hxx index 9021a21ed..0dd3871c7 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, _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, _UA, _UASW, + _WD, _WDSW, _X07, #ifdef CUSTOM_ARM _CUSTOM, #endif diff --git a/src/emucore/Cart3E.hxx b/src/emucore/Cart3E.hxx index 4871c67a6..613fa610c 100644 --- a/src/emucore/Cart3E.hxx +++ b/src/emucore/Cart3E.hxx @@ -116,15 +116,15 @@ class Cartridge3E : public CartridgeEnhanced private: bool checkSwitchBank(uInt16 address, uInt8 value) override; - private: + protected: // log(ROM bank segment size) / log(2) static constexpr uInt16 BANK_SHIFT = 11; // = 2K = 0x0800 - // The size of extra RAM in ROM address space + // The number of RAM banks static constexpr uInt16 RAM_BANKS = 32; // RAM size - static constexpr uInt16 RAM_SIZE = RAM_BANKS << (BANK_SHIFT - 1); // = 32K = 0x4000; + static constexpr size_t RAM_SIZE = RAM_BANKS << (BANK_SHIFT - 1); // = 32K = 0x8000; // Write port for extra RAM is at high address static constexpr bool RAM_HIGH_WP = true; diff --git a/src/emucore/Cart3EPlus.hxx b/src/emucore/Cart3EPlus.hxx index 1a2440e40..209ab89dc 100644 --- a/src/emucore/Cart3EPlus.hxx +++ b/src/emucore/Cart3EPlus.hxx @@ -165,7 +165,7 @@ class Cartridge3EPlus: public CartridgeEnhanced static constexpr uInt16 RAM_BANKS = 64; // RAM size - static constexpr uInt16 RAM_SIZE = RAM_BANKS << (BANK_SHIFT - 1); // = 32K = 0x4000; + static constexpr size_t RAM_SIZE = RAM_BANKS << (BANK_SHIFT - 1); // = 32K = 0x4000; // Write port for extra RAM is at high address static constexpr bool RAM_HIGH_WP = true; diff --git a/src/emucore/Cart3EX.cxx b/src/emucore/Cart3EX.cxx new file mode 100644 index 000000000..4f9c7ac45 --- /dev/null +++ b/src/emucore/Cart3EX.cxx @@ -0,0 +1,27 @@ +//============================================================================ +// +// 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 "Cart3EX.hxx" + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Cartridge3EX::Cartridge3EX(const ByteBuffer& image, size_t size, + const string& md5, const Settings& settings) + : Cartridge3E(image, size, md5, settings) +{ + myRamSize = RAM_SIZE; + myRamBankCount = RAM_BANKS; +} diff --git a/src/emucore/Cart3EX.hxx b/src/emucore/Cart3EX.hxx new file mode 100644 index 000000000..99181cffd --- /dev/null +++ b/src/emucore/Cart3EX.hxx @@ -0,0 +1,87 @@ +//============================================================================ +// +// 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 CARTRIDGE3EX_HXX +#define CARTRIDGE3EX_HXX + +class System; + +#include "Cart3E.hxx" +#ifdef DEBUGGER_SUPPORT +//#include "Cart3EXWidget.hxx" +#endif + +/** + This is an enhanced version of 3E which supports up to 256KB RAM. + + @author Thomas Jentzsch +*/ + +class Cartridge3EX : public Cartridge3E +{ + //friend class Cartridge3EXWidget; + +public: + /** + 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) + */ + Cartridge3EX(const ByteBuffer& image, size_t size, const string& md5, + const Settings& settings); + virtual ~Cartridge3EX() = default; + +public: + /** + Get a descriptor for the device name (used in error checking). + + @return The name of the object + */ + string name() const override { return "Cartridge3EX"; } + +#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 Cartridge3EXWidget(boss, lfont, nfont, x, y, w, h, *this); + //} +#endif + +private: + // The number of RAM banks + static constexpr uInt16 RAM_BANKS = 256; + + // RAM size + static constexpr size_t RAM_SIZE = RAM_BANKS << (BANK_SHIFT - 1); // = 256K = 0x40000; + +private: + // Following constructors and assignment operators not supported + Cartridge3EX() = delete; + Cartridge3EX(const Cartridge3EX&) = delete; + Cartridge3EX(Cartridge3EX&&) = delete; + Cartridge3EX& operator=(const Cartridge3EX&) = delete; + Cartridge3EX& operator=(Cartridge3EX&&) = delete; +}; + +#endif diff --git a/src/emucore/Cart4KSC.hxx b/src/emucore/Cart4KSC.hxx index 64dde3c39..3f28de9ce 100644 --- a/src/emucore/Cart4KSC.hxx +++ b/src/emucore/Cart4KSC.hxx @@ -72,7 +72,7 @@ class Cartridge4KSC : public Cartridge4K private: // RAM size - static constexpr uInt16 RAM_SIZE = 0x80; + static constexpr size_t RAM_SIZE = 0x80; private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartBFSC.hxx b/src/emucore/CartBFSC.hxx index 35c4b84ca..9bb22aa0a 100644 --- a/src/emucore/CartBFSC.hxx +++ b/src/emucore/CartBFSC.hxx @@ -74,7 +74,7 @@ class CartridgeBFSC : public CartridgeBF private: // RAM size - static constexpr uInt16 RAM_SIZE = 0x80; + static constexpr uInt32 RAM_SIZE = 0x80; private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartCV.hxx b/src/emucore/CartCV.hxx index 1b4773e5e..a5403b19f 100644 --- a/src/emucore/CartCV.hxx +++ b/src/emucore/CartCV.hxx @@ -89,7 +89,7 @@ class CartridgeCV : public CartridgeEnhanced static constexpr uInt16 BANK_SHIFT = 11; // 2K // RAM size - static constexpr uInt16 RAM_SIZE = 0x400; // 1K + static constexpr uInt32 RAM_SIZE = 0x400; // 1K // Write port for extra RAM is at high address static constexpr bool RAM_HIGH_WP = true; diff --git a/src/emucore/CartDFSC.hxx b/src/emucore/CartDFSC.hxx index cf3661039..637dde3da 100644 --- a/src/emucore/CartDFSC.hxx +++ b/src/emucore/CartDFSC.hxx @@ -72,7 +72,7 @@ class CartridgeDFSC : public CartridgeDF private: // RAM size - static constexpr uInt16 RAM_SIZE = 0x80; + static constexpr size_t RAM_SIZE = 0x80; private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartDetector.cxx b/src/emucore/CartDetector.cxx index b40e75c49..8544a72f0 100644 --- a/src/emucore/CartDetector.cxx +++ b/src/emucore/CartDetector.cxx @@ -20,6 +20,7 @@ #include "Cart0840.hxx" #include "Cart2K.hxx" #include "Cart3E.hxx" +#include "Cart3EX.hxx" #include "Cart3EPlus.hxx" #include "Cart3F.hxx" #include "Cart4A50.hxx" @@ -250,6 +251,8 @@ CartDetector::createFromImage(const ByteBuffer& image, size_t size, Bankswitch:: 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: @@ -380,6 +383,8 @@ Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t si type = Bankswitch::Type::_4K; else if(isProbablyE0(image, size)) type = Bankswitch::Type::_E0; + else if(isProbably3EX(image, size)) + type = Bankswitch::Type::_3EX; else if(isProbably3E(image, size)) type = Bankswitch::Type::_3E; else if(isProbably3F(image, size)) @@ -419,6 +424,8 @@ Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t si type = Bankswitch::Type::_E7; else if (isProbablyFC(image, size)) type = Bankswitch::Type::_FC; + else if(isProbably3EX(image, size)) + type = Bankswitch::Type::_3EX; else if(isProbably3E(image, size)) type = Bankswitch::Type::_3E; /* no known 16K 3F ROMS @@ -445,6 +452,8 @@ Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t si type = Bankswitch::Type::_CTY; else if(isProbablySC(image, size)) type = Bankswitch::Type::_F4SC; + else if(isProbably3EX(image, size)) + type = Bankswitch::Type::_3EX; else if(isProbably3E(image, size)) type = Bankswitch::Type::_3E; else if(isProbably3F(image, size)) @@ -471,7 +480,9 @@ Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t si } else if(size == 64_KB) { - if(isProbably3E(image, size)) + 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; @@ -486,7 +497,9 @@ Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t si } else if(size == 128_KB) { - if(isProbably3E(image, size)) + if(isProbably3EX(image, size)) + type = Bankswitch::Type::_3EX; + else if(isProbably3E(image, size)) type = Bankswitch::Type::_3E; else if(isProbablyDF(image, size, type)) ; // type has been set directly in the function @@ -499,7 +512,9 @@ Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t si } else if(size == 256_KB) { - if(isProbably3E(image, size)) + if(isProbably3EX(image, size)) + type = Bankswitch::Type::_3EX; + else if(isProbably3E(image, size)) type = Bankswitch::Type::_3E; else if(isProbablyBF(image, size, type)) ; // type has been set directly in the function @@ -510,7 +525,9 @@ Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t si } else // what else can we do? { - if(isProbably3E(image, size)) + 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; @@ -632,6 +649,14 @@ bool CartDetector::isProbably3E(const ByteBuffer& image, size_t size) && searchForBytes(image.get(), size, signature2, 2, 2); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CartDetector::isProbably3EX(const ByteBuffer& image, size_t size) +{ + // 3EX cart have at least 2 occurrences of the string "3EX" + uInt8 _3EX[] = { '3', 'E', 'X'}; + return searchForBytes(image.get(), size, _3EX, 3, 2); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbably3EPlus(const ByteBuffer& image, size_t size) { diff --git a/src/emucore/CartDetector.hxx b/src/emucore/CartDetector.hxx index 63a98b053..8dc734b42 100644 --- a/src/emucore/CartDetector.hxx +++ b/src/emucore/CartDetector.hxx @@ -130,6 +130,11 @@ class CartDetector */ static bool isProbably3E(const ByteBuffer& image, size_t size); + /** + Returns true if the image is probably a 3EX bankswitching cartridge + */ + static bool isProbably3EX(const ByteBuffer& image, size_t size); + /** Returns true if the image is probably a 3E+ bankswitching cartridge */ diff --git a/src/emucore/CartEFSC.hxx b/src/emucore/CartEFSC.hxx index d204d1ef5..f6c7e40ea 100644 --- a/src/emucore/CartEFSC.hxx +++ b/src/emucore/CartEFSC.hxx @@ -76,7 +76,7 @@ class CartridgeEFSC : public CartridgeEF private: // RAM size - static constexpr uInt16 RAM_SIZE = 0x80; + static constexpr size_t RAM_SIZE = 0x80; private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index 3e69a06f8..0bb6f54fb 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -35,13 +35,13 @@ CartridgeEnhanced::CartridgeEnhanced(const ByteBuffer& image, size_t size, void CartridgeEnhanced::install(System& system) { // limit banked RAM size to the size of one RAM bank - uInt16 ramSize = myRamBankCount > 0 ? 1 << (myBankShift - 1) : myRamSize; + uInt32 ramSize = myRamBankCount > 0 ? 1 << (myBankShift - 1) : uInt32(myRamSize); // calculate bank switching and RAM sizes and masks myBankSize = 1 << myBankShift; // e.g. = 2 ^ 12 = 4K = 0x1000 myBankMask = myBankSize - 1; // e.g. = 0x0FFF myBankSegs = 1 << (MAX_BANK_SHIFT - myBankShift); // e.g. = 1 - myRomOffset = myRamBankCount > 0 ? 0 : myRamSize * 2; + myRomOffset = myRamBankCount > 0 ? 0 : uInt32(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 diff --git a/src/emucore/CartEnhanced.hxx b/src/emucore/CartEnhanced.hxx index ad97409a9..743a4b50e 100644 --- a/src/emucore/CartEnhanced.hxx +++ b/src/emucore/CartEnhanced.hxx @@ -183,7 +183,7 @@ class CartridgeEnhanced : public Cartridge protected: // The extra RAM size - uInt16 myRamSize{RAM_SIZE}; // default 0 + size_t myRamSize{RAM_SIZE}; // default 0 // The number of RAM banks uInt16 myRamBankCount{RAM_BANKS}; // default 0 @@ -246,9 +246,9 @@ class CartridgeEnhanced : public Cartridge static constexpr uInt16 BANK_SHIFT = 12; // default = 4K // The size of extra RAM in ROM address space - static constexpr uInt16 RAM_SIZE = 0; // default = none + static constexpr size_t RAM_SIZE = 0; // default = none - // The size of extra RAM in ROM address space + // The number of RAM banks static constexpr uInt16 RAM_BANKS = 0; // Write port for extra RAM is at low address by default diff --git a/src/emucore/CartF4SC.hxx b/src/emucore/CartF4SC.hxx index 5f49a33a6..58b255e42 100644 --- a/src/emucore/CartF4SC.hxx +++ b/src/emucore/CartF4SC.hxx @@ -69,7 +69,7 @@ class CartridgeF4SC : public CartridgeF4 private: // RAM size - static constexpr uInt16 RAM_SIZE = 0x80; + static constexpr size_t RAM_SIZE = 0x80; // RAM mask static constexpr uInt16 RAM_MASK = RAM_SIZE - 1; diff --git a/src/emucore/CartF6SC.hxx b/src/emucore/CartF6SC.hxx index a791a538d..c61c9715f 100644 --- a/src/emucore/CartF6SC.hxx +++ b/src/emucore/CartF6SC.hxx @@ -69,7 +69,7 @@ class CartridgeF6SC : public CartridgeF6 private: // RAM size - static constexpr uInt16 RAM_SIZE = 0x80; + static constexpr size_t RAM_SIZE = 0x80; // RAM mask static constexpr uInt16 RAM_MASK = RAM_SIZE - 1; diff --git a/src/emucore/CartF8SC.hxx b/src/emucore/CartF8SC.hxx index 25fe0dfe3..c5a005543 100644 --- a/src/emucore/CartF8SC.hxx +++ b/src/emucore/CartF8SC.hxx @@ -69,7 +69,7 @@ class CartridgeF8SC : public CartridgeF8 private: // RAM size - static constexpr uInt16 RAM_SIZE = 0x80; + static constexpr size_t RAM_SIZE = 0x80; private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartFA.hxx b/src/emucore/CartFA.hxx index 920f2bdec..a2f197b75 100644 --- a/src/emucore/CartFA.hxx +++ b/src/emucore/CartFA.hxx @@ -79,7 +79,7 @@ class CartridgeFA : public CartridgeEnhanced private: // RAM size - static constexpr uInt16 RAM_SIZE = 0x100; + static constexpr size_t RAM_SIZE = 0x100; private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartWD.hxx b/src/emucore/CartWD.hxx index 1fd42ac71..6feb6be63 100644 --- a/src/emucore/CartWD.hxx +++ b/src/emucore/CartWD.hxx @@ -176,7 +176,7 @@ class CartridgeWD : public CartridgeEnhanced static constexpr uInt16 BANK_SHIFT = 10; // = 1K = 0x0400 // RAM size - static constexpr uInt16 RAM_SIZE = 0x40; + static constexpr size_t RAM_SIZE = 0x40; // Write port for extra RAM is at low address by default static constexpr bool RAM_HIGH_WP = true; diff --git a/src/emucore/module.mk b/src/emucore/module.mk index dc953b86e..e0dd4f96f 100644 --- a/src/emucore/module.mk +++ b/src/emucore/module.mk @@ -11,6 +11,7 @@ MODULE_OBJS := \ src/emucore/Cart2K.o \ src/emucore/Cart3E.o \ src/emucore/Cart3EPlus.o \ + src/emucore/Cart3EX.o \ src/emucore/Cart3F.o \ src/emucore/Cart4A50.o \ src/emucore/Cart4K.o \ diff --git a/src/windows/Stella.vcxproj b/src/windows/Stella.vcxproj index 28b0efe29..1095f2c09 100644 --- a/src/windows/Stella.vcxproj +++ b/src/windows/Stella.vcxproj @@ -711,6 +711,7 @@ + @@ -1727,6 +1728,7 @@ + diff --git a/src/windows/Stella.vcxproj.filters b/src/windows/Stella.vcxproj.filters index 536cf54eb..fb763da4c 100644 --- a/src/windows/Stella.vcxproj.filters +++ b/src/windows/Stella.vcxproj.filters @@ -999,6 +999,9 @@ Source Files\debugger + + Source Files\emucore + @@ -2051,6 +2054,9 @@ Header Files\debugger + + Header Files\emucore + From 619d12018c74a9ee3ecbeee6dd2386e520c46ca1 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 22 Apr 2020 12:50:26 +0200 Subject: [PATCH 146/377] 3EX now reads number of RAM banks - 1 from 0xfffa --- Changes.txt | 2 ++ docs/index.html | 7 ++++--- src/emucore/Cart3EX.cxx | 3 ++- src/emucore/Cart3EX.hxx | 3 --- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Changes.txt b/Changes.txt index 61989ecd9..20ed3e411 100644 --- a/Changes.txt +++ b/Changes.txt @@ -32,6 +32,8 @@ * Restored 'cfg' directory for Distella config files. + * Added 3EX bank switching type. + * Removed unused CV+ and DASH bank switching types. -Have fun! diff --git a/docs/index.html b/docs/index.html index c7185ebe1..6f9fb85a9 100644 --- a/docs/index.html +++ b/docs/index.html @@ -3790,8 +3790,9 @@ Ms Pac-Man (Stella extended codes): 32IN1 ¹64-128K Multicart (32 games) .32N, .32N1 64IN1 ¹64/128K Multicart .64N, .64N1 128IN1 ¹256/512K Multicart .128, .128N1 - 2K 32-2048 byte Atari .2K - 3E 32K Tigervision .3E + 2K 32-2048 bytes Atari .2K + 3E 512K Tigervision + 32K RAM.3E + 3EX 512K Tigervision + 256K RAM.3EX 3E+ 3E+ (TJ modified 3E) .3EP, .3E+ 3F 512K Tigervision .3F 4A50 ²64K 4A50 + RAM .4A5, .4A50 @@ -3826,7 +3827,7 @@ Ms Pac-Man (Stella extended codes): FC Amiga Power Play Aracde 16/32K .FC FE 8K Decathlon .FE MDM Menu Driven Megacart .MDM - SB 128-256k SUPERbanking .SB + SB 128-256K SUPERbanking .SB UA 8K UA Ltd. .UA UASW 8K UA Ltd. (swapped banks).UASW WD Wickstead Design (Pink Panther) .WD diff --git a/src/emucore/Cart3EX.cxx b/src/emucore/Cart3EX.cxx index 4f9c7ac45..889935a07 100644 --- a/src/emucore/Cart3EX.cxx +++ b/src/emucore/Cart3EX.cxx @@ -23,5 +23,6 @@ Cartridge3EX::Cartridge3EX(const ByteBuffer& image, size_t size, : Cartridge3E(image, size, md5, settings) { myRamSize = RAM_SIZE; - myRamBankCount = RAM_BANKS; + // 0xFFFA contains RAM bank count - 1; + myRamBankCount = image[size - 6] + 1; } diff --git a/src/emucore/Cart3EX.hxx b/src/emucore/Cart3EX.hxx index 99181cffd..e7ba2ecfd 100644 --- a/src/emucore/Cart3EX.hxx +++ b/src/emucore/Cart3EX.hxx @@ -69,9 +69,6 @@ public: #endif private: - // The number of RAM banks - static constexpr uInt16 RAM_BANKS = 256; - // RAM size static constexpr size_t RAM_SIZE = RAM_BANKS << (BANK_SHIFT - 1); // = 256K = 0x40000; From c8eacc854c50b632c3b27e36e9951183590bb330 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 22 Apr 2020 19:58:40 +0200 Subject: [PATCH 147/377] refactored Cart3EWidget (also supports 3EX) added RAM bank support to CartEnhancedWidget --- src/common/PKeyboardHandler.cxx | 5 - src/debugger/gui/Cart3EWidget.cxx | 225 ++++++++++-------------- src/debugger/gui/Cart3EWidget.hxx | 42 ++--- src/debugger/gui/CartEnhancedWidget.cxx | 75 +++++--- src/debugger/gui/CartEnhancedWidget.hxx | 2 + src/emucore/Cart3EX.cxx | 2 +- src/emucore/Cart3EX.hxx | 16 -- 7 files changed, 157 insertions(+), 210 deletions(-) diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index b1a16eeef..57a3bfd4b 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -80,16 +80,11 @@ void PhysicalKeyboardHandler::setDefaultKey(EventMapping map, Event::Type event, if (updateDefaults) { - if (map.event == Event::ToggleSAPortOrder) - int i = 0; - // if there is no existing mapping for the event and // the default mapping for the event is unused, set default key for event if (myKeyMap.getEventMapping(map.event, mode).size() == 0 && !myKeyMap.check(mode, map.key, map.mod)) { - if (map.event == Event::ConsoleReset) - int i = 0; addMapping(map.event, mode, map.key, StellaMod(map.mod)); } } diff --git a/src/debugger/gui/Cart3EWidget.cxx b/src/debugger/gui/Cart3EWidget.cxx index b2ab3584c..4683ea7d4 100644 --- a/src/debugger/gui/Cart3EWidget.cxx +++ b/src/debugger/gui/Cart3EWidget.cxx @@ -23,129 +23,134 @@ Cartridge3EWidget::Cartridge3EWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, Cartridge3E& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart), - myNumRomBanks(myCart.romBankCount()), - myNumRamBanks(myCart.ramBankCount()) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { - size_t size = cart.mySize; - - ostringstream info; - info << "3E cartridge - (3F + RAM)\n" - << " 2-256 2K ROM (currently " << myNumRomBanks << "), 32 1K RAM\n" - << "First 2K (ROM) selected by writing to $3F\n" - "First 2K (RAM) selected by writing to $3E\n" - " $F000 - $F3FF (R), $F400 - $F7FF (W)\n" - "Last 2K always points to last 2K of ROM\n"; - if(cart.startBank() < myNumRomBanks) - info << "Startup bank = " << cart.startBank() << " (ROM)\n"; - else - info << "Startup bank = " << (cart.startBank()-myNumRomBanks) << " (RAM)\n"; - - // Eventually, we should query this from the debugger/disassembler - uInt16 start = (cart.myImage[size-3] << 8) | cart.myImage[size-4]; - start -= start % 0x1000; - info << "Bank RORG" << " = $" << Common::Base::HEX4 << start << "\n"; - - int xpos = 2, - ypos = addBaseInformation(size, "TigerVision", info.str()) + myLineHeight; - - VariantList romitems; - for(uInt32 i = 0; i < myNumRomBanks; ++i) - VarList::push_back(romitems, i); - VarList::push_back(romitems, "Inactive", ""); - - VariantList ramitems; - for(uInt32 i = 0; i < myNumRamBanks; ++i) - VarList::push_back(ramitems, i); - VarList::push_back(ramitems, "Inactive", ""); - - ostringstream label; - label << "Set bank ($" << Common::Base::HEX4 << start << " - $" - << (start+0x7FF) << "): "; - - new StaticTextWidget(_boss, _font, xpos, ypos, _font.getStringWidth(label.str()), - myFontHeight, label.str(), TextAlign::Left); - ypos += myLineHeight + 8; - - xpos += 40; - myROMBank = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($3E) "), - myLineHeight, romitems, "ROM ($3F) ", - _font.getStringWidth("ROM ($3F) "), kROMBankChanged); - myROMBank->setTarget(this); - addFocusWidget(myROMBank); - - xpos += myROMBank->getWidth() + 20; - myRAMBank = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($3E) "), - myLineHeight, ramitems, "RAM ($3E) ", - _font.getStringWidth("RAM ($3E) "), kRAMBankChanged); - myRAMBank->setTarget(this); - addFocusWidget(myRAMBank); + initialize(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge3EWidget::saveOldState() +string Cartridge3EWidget::description() { - myOldState.internalram.clear(); + ostringstream info; + size_t size; + const uInt8* image = myCart.getImage(size); + uInt16 numRomBanks = myCart.romBankCount(); + uInt16 numRamBanks = myCart.ramBankCount(); - for(uInt32 i = 0; i < internalRamSize(); ++i) - myOldState.internalram.push_back(myCart.myRAM[i]); - myOldState.bank = myCart.getBank(); + info << "3E cartridge (3F + RAM),\n" + << " " << numRomBanks << " 2K ROM banks, " << numRamBanks << " 1K RAM banks\n" + << "First 2K (ROM) selected by writing to $3F\n" + "First 2K (RAM) selected by writing to $3E\n"; + info << CartridgeEnhancedWidget::ramDescription(); + info << "Last 2K always points to last 2K of ROM\n"; + + if(myCart.startBank() < numRomBanks) + info << "Startup bank = " << myCart.startBank() << " (ROM)\n"; + else + info << "Startup bank = " << (myCart.startBank() - numRomBanks) << " (RAM)\n"; + + // Eventually, we should query this from the debugger/disassembler + uInt16 start = (image[size-3] << 8) | image[size-4]; + start -= start % 0x1000; + info << "Bank RORG" << " = $" << Common::Base::HEX4 << start << "\n"; + + return info.str(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Cartridge3EWidget::bankList(uInt16 bankCount, int seg, VariantList& items, int& width) +{ + CartridgeEnhancedWidget::bankList(bankCount, seg, items, width); + + VarList::push_back(items, "Inactive", ""); + width = _font.getStringWidth("Inactive"); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Cartridge3EWidget::bankSelect(int& ypos) +{ + int xpos = 2; + VariantList items; + int pw; + + myBankWidgets = make_unique(2); + + bankList(myCart.romBankCount(), 0, items, pw); + myBankWidgets[0] = + new PopUpWidget(_boss, _font, xpos, ypos - 2, pw, + myLineHeight, items, "Set bank ", + _font.getStringWidth("Set bank "), kBankChanged); + myBankWidgets[0]->setTarget(this); + myBankWidgets[0]->setID(0); + addFocusWidget(myBankWidgets[0]); + + StaticTextWidget* t = new StaticTextWidget(_boss, _font, myBankWidgets[0]->getRight(), ypos - 1, " (ROM)"); + + xpos = t->getRight() + 20; + items.clear(); + bankList(myCart.ramBankCount(), 0, items, pw); + myBankWidgets[1] = + new PopUpWidget(_boss, _font, xpos, ypos - 2, pw, + myLineHeight, items, "", 0, kRAMBankChanged); + myBankWidgets[1]->setTarget(this); + myBankWidgets[1]->setID(1); + addFocusWidget(myBankWidgets[1]); + + new StaticTextWidget(_boss, _font, myBankWidgets[1]->getRight(), ypos - 1, " (RAM)"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3EWidget::loadConfig() { + uInt16 oldBank = myOldState.banks[0]; + uInt16 bank = myCart.getBank(); + if(myCart.getBank() < myCart.romBankCount()) { - myROMBank->setSelectedIndex(myCart.getBank() % myNumRomBanks, myOldState.bank != myCart.getBank()); - myRAMBank->setSelectedMax(myOldState.bank >= myCart.romBankCount()); + myBankWidgets[0]->setSelectedIndex(bank, oldBank != bank); + myBankWidgets[1]->setSelectedMax(oldBank >= myCart.romBankCount()); } else { - myROMBank->setSelectedMax(myOldState.bank < myCart.romBankCount()); - myRAMBank->setSelectedIndex(myCart.getBank() - myCart.romBankCount(), myOldState.bank != myCart.getBank()); + myBankWidgets[0]->setSelectedMax(oldBank < myCart.romBankCount()); + myBankWidgets[1]->setSelectedIndex(bank - myCart.romBankCount(), oldBank != bank); } CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge3EWidget::handleCommand(CommandSender* sender, - int cmd, int data, int id) +void Cartridge3EWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { uInt16 bank = 0; - if(cmd == kROMBankChanged) + if(cmd == kBankChanged) { - if(myROMBank->getSelected() < int(myNumRomBanks)) + if(myBankWidgets[0]->getSelected() < myCart.romBankCount()) { - bank = myROMBank->getSelected(); - myRAMBank->setSelectedMax(); + bank = myBankWidgets[0]->getSelected(); + myBankWidgets[1]->setSelectedMax(); } else { bank = myCart.romBankCount(); // default to first RAM bank - myRAMBank->setSelectedIndex(0); + myBankWidgets[1]->setSelectedIndex(0); } } else if(cmd == kRAMBankChanged) { - if(myRAMBank->getSelected() < int(myNumRamBanks)) + if(myBankWidgets[1]->getSelected() < myCart.ramBankCount()) { - myROMBank->setSelectedMax(); - bank = myRAMBank->getSelected() + myCart.romBankCount(); + myBankWidgets[0]->setSelectedMax(); + bank = myBankWidgets[1]->getSelected() + myCart.romBankCount(); } else { bank = 0; // default to first ROM bank - myROMBank->setSelectedIndex(0); + myBankWidgets[0]->setSelectedIndex(0); } } - myCart.unlockBank(); myCart.bank(bank); myCart.lockBank(); @@ -156,65 +161,13 @@ void Cartridge3EWidget::handleCommand(CommandSender* sender, string Cartridge3EWidget::bankState() { ostringstream& buf = buffer(); - uInt16 bank = myCart.getBank(); + if(bank < myCart.romBankCount()) - buf << "ROM bank #" << std::dec << bank % myNumRomBanks << ", RAM inactive"; + buf << "ROM bank #" << std::dec << bank % myCart.romBankCount() << ", RAM inactive"; else - buf << "ROM inactive, RAM bank #" << std::dec << bank % myNumRamBanks; + buf << "ROM inactive, RAM bank #" + << std::dec << (bank - myCart.romBankCount()) % myCart.ramBankCount(); return buf.str(); } - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 Cartridge3EWidget::internalRamSize() -{ - return uInt32(myCart.myRamSize); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 Cartridge3EWidget::internalRamRPort(int start) -{ - return 0x0000 + start; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string Cartridge3EWidget::internalRamDescription() -{ - ostringstream desc; - desc << "Accessible 1K at a time via:\n" - << " $F000 - $F3FF used for Read Access\n" - << " $F400 - $F7FF used for Write Access"; - - return desc.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& Cartridge3EWidget::internalRamOld(int start, int count) -{ - myRamOld.clear(); - for(int i = 0; i < count; i++) - myRamOld.push_back(myOldState.internalram[start + i]); - return myRamOld; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& Cartridge3EWidget::internalRamCurrent(int start, int count) -{ - myRamCurrent.clear(); - for(int i = 0; i < count; i++) - myRamCurrent.push_back(myCart.myRAM[start + i]); - return myRamCurrent; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge3EWidget::internalRamSetValue(int addr, uInt8 value) -{ - myCart.myRAM[addr] = value; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 Cartridge3EWidget::internalRamGetValue(int addr) -{ - return myCart.myRAM[addr]; -} diff --git a/src/debugger/gui/Cart3EWidget.hxx b/src/debugger/gui/Cart3EWidget.hxx index 623a8877e..e1d4f266b 100644 --- a/src/debugger/gui/Cart3EWidget.hxx +++ b/src/debugger/gui/Cart3EWidget.hxx @@ -19,11 +19,12 @@ #define CARTRIDGE3E_WIDGET_HXX class Cartridge3E; -class PopUpWidget; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class Cartridge3EWidget : public CartDebugWidget +// Note: This class supports 3EX too + +class Cartridge3EWidget : public CartridgeEnhancedWidget { public: Cartridge3EWidget(GuiObject* boss, const GUI::Font& lfont, @@ -33,39 +34,28 @@ class Cartridge3EWidget : public CartDebugWidget virtual ~Cartridge3EWidget() = default; private: - Cartridge3E& myCart; - const uInt32 myNumRomBanks{0}; - const uInt32 myNumRamBanks{0}; - PopUpWidget *myROMBank{nullptr}, *myRAMBank{nullptr}; - - struct CartState { - ByteArray internalram; - uInt16 bank; - }; - CartState myOldState; - enum { - kROMBankChanged = 'rmCH', kRAMBankChanged = 'raCH' }; private: - void saveOldState() override; + string manufacturer() override { return "Andrew Davie & Thomas Jentzsch"; } + + string description() override; + + void bankList(uInt16 bankCount, int seg, VariantList& items, int& width) override; + + void bankSelect(int& ypos) override; + + int bankSegs() override { return 1; } + void loadConfig() override; + void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; - // start of functions for Cartridge RAM tab - uInt32 internalRamSize() override; - uInt32 internalRamRPort(int start) override; - string internalRamDescription() override; - const ByteArray& internalRamOld(int start, int count) override; - const ByteArray& internalRamCurrent(int start, int count) override; - void internalRamSetValue(int addr, uInt8 value) override; - uInt8 internalRamGetValue(int addr) override; - // end of functions for Cartridge RAM tab - + private: // Following constructors and assignment operators not supported Cartridge3EWidget() = delete; Cartridge3EWidget(const Cartridge3EWidget&) = delete; diff --git a/src/debugger/gui/CartEnhancedWidget.cxx b/src/debugger/gui/CartEnhancedWidget.cxx index 35c5f9e25..a59e4f985 100644 --- a/src/debugger/gui/CartEnhancedWidget.cxx +++ b/src/debugger/gui/CartEnhancedWidget.cxx @@ -74,13 +74,15 @@ string CartridgeEnhancedWidget::ramDescription() { ostringstream info; - info << myCart.myRamSize << " bytes RAM @ " - << "$" << Common::Base::HEX4 << ADDR_BASE << " - " - << "$" << (ADDR_BASE | (myCart.myRamSize * 2 - 1)) << "\n" - << " $" << (ADDR_BASE | myCart.myReadOffset) - << " - $" << (ADDR_BASE | (myCart.myReadOffset + myCart.myRamSize - 1)) << " (R)" + if(myCart.ramBankCount() == 0) + info << myCart.myRamSize << " bytes RAM @ " + << "$" << Common::Base::HEX4 << ADDR_BASE << " - " + << "$" << (ADDR_BASE | (myCart.myRamSize * 2 - 1)) << "\n"; + + info << " $" << Common::Base::HEX4 << (ADDR_BASE | myCart.myReadOffset) + << " - $" << (ADDR_BASE | (myCart.myReadOffset + myCart.myRamMask)) << " (R)" << ", $" << (ADDR_BASE | myCart.myWriteOffset) - << " - $" << (ADDR_BASE | (myCart.myWriteOffset + myCart.myRamSize - 1)) << " (W)\n"; + << " - $" << (ADDR_BASE | (myCart.myWriteOffset + myCart.myRamMask)) << " (W)\n"; return info.str(); } @@ -133,6 +135,23 @@ string CartridgeEnhancedWidget::romDescription() return info.str(); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void CartridgeEnhancedWidget::bankList(uInt16 bankCount, int seg, VariantList& items, int& width) +{ + width = 0; + + for(int bank = 0; bank < bankCount; ++bank) + { + ostringstream buf; + + buf << std::setw(bank < 10 ? 2 : 1) << "#" << std::dec << bank; + if(myCart.hotspot() != 0 && myHotspotDelta > 0) + buf << " " << hotspotStr(bank, seg); + VarList::push_back(items, buf.str()); + width = std::max(width, _font.getStringWidth(buf.str())); + } +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeEnhancedWidget::bankSelect(int& ypos) { @@ -148,17 +167,7 @@ void CartridgeEnhancedWidget::bankSelect(int& ypos) VariantList items; int pw = 0; - for(int bank = 0; bank < myCart.romBankCount(); ++bank) - { - ostringstream buf; - - buf << std::setw(bank < 10 ? 2 : 1) << "#" << std::dec << bank; - //if(myCart.hotspot() >= 0x100 && myHotspotDelta > 0) - if(myCart.hotspot() != 0 && myHotspotDelta > 0) - buf << " " << hotspotStr(bank, seg); - VarList::push_back(items, buf.str()); - pw = std::max(pw, _font.getStringWidth(buf.str())); - } + bankList(myCart.romBankCount(), seg, items, pw); // create widgets ostringstream buf; @@ -282,7 +291,7 @@ void CartridgeEnhancedWidget::loadConfig() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeEnhancedWidget::handleCommand(CommandSender* sender, - int cmd, int data, int id) + int cmd, int data, int id) { if(cmd == kBankChanged) { @@ -302,31 +311,45 @@ uInt32 CartridgeEnhancedWidget::internalRamSize() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeEnhancedWidget::internalRamRPort(int start) { - return ADDR_BASE + myCart.myReadOffset + start; + if(myCart.ramBankCount() == 0) + return ADDR_BASE + myCart.myReadOffset + start; + else + return start; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeEnhancedWidget::internalRamDescription() { ostringstream desc; + string indent = ""; + + if(myCart.ramBankCount()) + { + desc << "Accessible "; + if (myCart.bankSize() >> 1 >= 1024) + desc << ((myCart.bankSize() >> 1) / 1024) << "K"; + else + desc << (myCart.bankSize() >> 1) << " bytes"; + desc << " at a time via:\n"; + indent = " "; + } // order RW by addresses if(myCart.myReadOffset <= myCart.myWriteOffset) { - desc << "$" << Common::Base::HEX4 << (ADDR_BASE | myCart.myReadOffset) - << " - $" << (ADDR_BASE | (myCart.myReadOffset + myCart.myRamSize - 1)) + desc << indent << "$" << Common::Base::HEX4 << (ADDR_BASE | myCart.myReadOffset) + << " - $" << (ADDR_BASE | (myCart.myReadOffset + myCart.myRamMask)) << " used for Read Access\n"; } - desc - << "$" << Common::Base::HEX4 << (ADDR_BASE | myCart.myWriteOffset) - << " - $" << (ADDR_BASE | (myCart.myWriteOffset + myCart.myRamSize - 1)) + desc << indent << "$" << Common::Base::HEX4 << (ADDR_BASE | myCart.myWriteOffset) + << " - $" << (ADDR_BASE | (myCart.myWriteOffset + myCart.myRamMask)) << " used for Write Access"; if(myCart.myReadOffset > myCart.myWriteOffset) { - desc << "\n$" << Common::Base::HEX4 << (ADDR_BASE | myCart.myReadOffset) - << " - $" << (ADDR_BASE | (myCart.myReadOffset + myCart.myRamSize - 1)) + desc << indent << "\n$" << Common::Base::HEX4 << (ADDR_BASE | myCart.myReadOffset) + << " - $" << (ADDR_BASE | (myCart.myReadOffset + myCart.myRamMask)) << " used for Read Access"; } diff --git a/src/debugger/gui/CartEnhancedWidget.hxx b/src/debugger/gui/CartEnhancedWidget.hxx index 42ffce1c9..1f4ae6f30 100644 --- a/src/debugger/gui/CartEnhancedWidget.hxx +++ b/src/debugger/gui/CartEnhancedWidget.hxx @@ -51,6 +51,8 @@ class CartridgeEnhancedWidget : public CartDebugWidget virtual string romDescription(); + virtual void bankList(uInt16 bankCount, int seg, VariantList& items, int& width); + virtual void bankSelect(int& ypos); virtual string hotspotStr(int bank = 0, int segment = 0, bool prefix = false); diff --git a/src/emucore/Cart3EX.cxx b/src/emucore/Cart3EX.cxx index 889935a07..c71fdd242 100644 --- a/src/emucore/Cart3EX.cxx +++ b/src/emucore/Cart3EX.cxx @@ -22,7 +22,7 @@ Cartridge3EX::Cartridge3EX(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) : Cartridge3E(image, size, md5, settings) { - myRamSize = RAM_SIZE; // 0xFFFA contains RAM bank count - 1; myRamBankCount = image[size - 6] + 1; + myRamSize = (myBankSize >> 1) * myRamBankCount; } diff --git a/src/emucore/Cart3EX.hxx b/src/emucore/Cart3EX.hxx index e7ba2ecfd..7df53593e 100644 --- a/src/emucore/Cart3EX.hxx +++ b/src/emucore/Cart3EX.hxx @@ -21,9 +21,6 @@ class System; #include "Cart3E.hxx" -#ifdef DEBUGGER_SUPPORT -//#include "Cart3EXWidget.hxx" -#endif /** This is an enhanced version of 3E which supports up to 256KB RAM. @@ -33,7 +30,6 @@ class System; class Cartridge3EX : public Cartridge3E { - //friend class Cartridge3EXWidget; public: /** @@ -56,18 +52,6 @@ public: */ string name() const override { return "Cartridge3EX"; } -#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 Cartridge3EXWidget(boss, lfont, nfont, x, y, w, h, *this); - //} -#endif - private: // RAM size static constexpr size_t RAM_SIZE = RAM_BANKS << (BANK_SHIFT - 1); // = 256K = 0x40000; From a27b6a7f3d61f79786d992b690ec9a6d85a0570b Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 23 Apr 2020 10:46:09 +0200 Subject: [PATCH 148/377] refactored CartMDM and CartSB widget classes --- src/debugger/gui/CartMDMWidget.cxx | 82 +++++++++++------------------- src/debugger/gui/CartMDMWidget.hxx | 21 +++++--- src/debugger/gui/CartSBWidget.cxx | 79 ++++------------------------ src/debugger/gui/CartSBWidget.hxx | 15 ++---- src/emucore/CartMDM.hxx | 2 + src/emucore/CartSB.hxx | 2 +- 6 files changed, 59 insertions(+), 142 deletions(-) diff --git a/src/debugger/gui/CartMDMWidget.cxx b/src/debugger/gui/CartMDMWidget.cxx index 48afbaf77..a3509cb34 100644 --- a/src/debugger/gui/CartMDMWidget.cxx +++ b/src/debugger/gui/CartMDMWidget.cxx @@ -17,45 +17,39 @@ #include "CartMDM.hxx" #include "PopUpWidget.hxx" -#include "Widget.hxx" #include "CartMDMWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeMDMWidget::CartridgeMDMWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeMDM& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart), + myCartMDM(cart) +{ + initialize(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartridgeMDMWidget::description() { ostringstream info; - size_t size; - myCart.getImage(size); - info << "Menu Driven Megacart, containing up to 128 4K banks\n" - << "Startup bank = " << cart.startBank() << "\n" - << "\nBanks are selected by reading from $800 - $BFF, where the lower " - "byte determines the 4K bank to use."; + info << "Menu Driven Megacart, " << myCart.romBankCount() << " 4K banks\n" + << "Banks are selected by reading from $800 - $" << Common::Base::HEX1 << 0xBFF + << ", where the lower byte determines the 4K bank to use.\n"; + info << CartridgeEnhancedWidget::description(); - int xpos = 2, - ypos = addBaseInformation(size, "Edwin Blink", info.str(), 15) + myLineHeight; + return info.str(); +} - VariantList items; - for(uInt32 i = 0x800; i < (0x800U + myCart.romBankCount()); ++i) - { - info.str(""); - info << std::dec << (i & 0xFF) << " ($" << Common::Base::HEX4 << i << ")"; - VarList::push_back(items, info.str()); - } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void CartridgeMDMWidget::bankSelect(int& ypos) +{ + CartridgeEnhancedWidget::bankSelect(ypos); + int xpos = myBankWidgets[0]->getRight() + 20; + ypos = myBankWidgets[0]->getTop(); - myBank = - new PopUpWidget(boss, _font, xpos, ypos, _font.getStringWidth("xxx ($0FFF)"), - myLineHeight, items, "Set bank ", - 0, kBankChanged); - myBank->setTarget(this); - addFocusWidget(myBank); - - xpos += myBank->getWidth() + 30; - myBankDisabled = new CheckboxWidget(boss, _font, xpos, ypos + 1, + myBankDisabled = new CheckboxWidget(_boss, _font, xpos, ypos + 1, "Bankswitching is locked/disabled", kBankDisabled); myBankDisabled->setTarget(this); @@ -65,39 +59,21 @@ CartridgeMDMWidget::CartridgeMDMWidget( // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeMDMWidget::loadConfig() { - myBank->setSelectedIndex(myCart.getBank()); - myBank->setEnabled(!myCart.myBankingDisabled); - myBankDisabled->setState(myCart.myBankingDisabled); + myBankWidgets[0]->setEnabled(!myCartMDM.myBankingDisabled); + myBankDisabled->setState(myCartMDM.myBankingDisabled); - CartDebugWidget::loadConfig(); + CartridgeEnhancedWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeMDMWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { - if(cmd == kBankChanged) + if(cmd == kBankDisabled) { - myCart.unlockBank(); - myCart.bank(myBank->getSelected()); - myCart.lockBank(); - invalidate(); - } - else if(cmd == kBankDisabled) - { - myCart.myBankingDisabled = myBankDisabled->getState(); - myBank->setEnabled(!myCart.myBankingDisabled); + myCartMDM.myBankingDisabled = myBankDisabled->getState(); + myBankWidgets[0]->setEnabled(!myCartMDM.myBankingDisabled); } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeMDMWidget::bankState() -{ - ostringstream& buf = buffer(); - - buf << "Bank = " << std::dec << myCart.getBank() - << ", hotspot = " << "$" << Common::Base::HEX4 - << (myCart.getBank()+0x800); - - return buf.str(); + else + CartridgeEnhancedWidget::handleCommand(sender, cmd, data, id); } diff --git a/src/debugger/gui/CartMDMWidget.hxx b/src/debugger/gui/CartMDMWidget.hxx index adf242b68..c7add24d7 100644 --- a/src/debugger/gui/CartMDMWidget.hxx +++ b/src/debugger/gui/CartMDMWidget.hxx @@ -20,11 +20,10 @@ class CartridgeMDM; class CheckboxWidget; -class PopUpWidget; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class CartridgeMDMWidget : public CartDebugWidget +class CartridgeMDMWidget : public CartridgeEnhancedWidget { public: CartridgeMDMWidget(GuiObject* boss, const GUI::Font& lfont, @@ -34,18 +33,24 @@ class CartridgeMDMWidget : public CartDebugWidget virtual ~CartridgeMDMWidget() = default; private: - CartridgeMDM& myCart; - PopUpWidget* myBank{nullptr}; + string manufacturer() override { return "Edwin Blink"; } + + string description() override; + + void bankSelect(int& ypos) override; + + CartridgeMDM& myCartMDM; CheckboxWidget* myBankDisabled{nullptr}; - enum { kBankChanged = 'bkCH', kBankDisabled = 'bkDI' }; + enum { + kBankDisabled = 'bkDI' + }; private: void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - string bankState() override; - + private: // Following constructors and assignment operators not supported CartridgeMDMWidget() = delete; CartridgeMDMWidget(const CartridgeMDMWidget&) = delete; diff --git a/src/debugger/gui/CartSBWidget.cxx b/src/debugger/gui/CartSBWidget.cxx index 7a82ba8e0..b564781bc 100644 --- a/src/debugger/gui/CartSBWidget.cxx +++ b/src/debugger/gui/CartSBWidget.cxx @@ -16,86 +16,27 @@ //============================================================================ #include "CartSB.hxx" -#include "PopUpWidget.hxx" #include "CartSBWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeSBWidget::CartridgeSBWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeSB& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart) { - VariantList items; - ostringstream info, bank; - size_t size; - - myCart.getImage(size); - info << "SB SUPERbanking, 32 or 64 4K banks\n" - << "Hotspots are from $800 to $" - << Common::Base::HEX2 << (0x800 + myCart.romBankCount() - 1) << ", including\n" - << "mirrors ($900, $A00, $B00, ...)\n" - << "Startup bank = " << std::dec << cart.startBank() << "\n"; - - // Eventually, we should query this from the debugger/disassembler - for(uInt32 i = 0, offset = 0xFFC, spot = 0x800; i < myCart.romBankCount(); - ++i, offset += 0x1000, ++spot) - { - uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; - start -= start % 0x1000; - info << "Bank " << std::dec << i << " @ $" << Common::Base::HEX4 << start << " - " - << "$" << (start + 0xFFF) << " (hotspot = $" << spot << ")\n"; - - bank << std::dec << std::setw(2) << std::setfill(' ') << i << " ($" - << Common::Base::HEX2 << spot << ")"; - VarList::push_back(items, bank.str()); - bank.str(""); - } - - int xpos = 2, - ypos = addBaseInformation(size, "Fred X. Quimby", info.str()) + myLineHeight; - - myBank = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("XX ($800)"), - myLineHeight, items, "Set bank ", - 0, kBankChanged); - myBank->setTarget(this); - addFocusWidget(myBank); + initialize(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeSBWidget::loadConfig() +string CartridgeSBWidget::description() { - Debugger& dbg = instance().debugger(); - CartDebug& cart = dbg.cartDebug(); - const CartState& state = static_cast(cart.getState()); - const CartState& oldstate = static_cast(cart.getOldState()); + ostringstream info; - myBank->setSelectedIndex(myCart.getBank(), state.bank != oldstate.bank); + info << "SB SUPERbanking, " << myCart.romBankCount() << " 4K banks\n" + << "Hotspots are from $800 to $" + << Common::Base::HEX2 << (0x800 + myCart.romBankCount() - 1) << ", including\n" + << "mirrors ($900, $" << 0xA00 << ", $" << 0xB00 << ", ...)\n"; + info << CartridgeEnhancedWidget::description(); - CartDebugWidget::loadConfig(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeSBWidget::handleCommand(CommandSender* sender, - int cmd, int data, int id) -{ - if(cmd == kBankChanged) - { - myCart.unlockBank(); - myCart.bank(myBank->getSelected()); - myCart.lockBank(); - invalidate(); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string CartridgeSBWidget::bankState() -{ - ostringstream& buf = buffer(); - - buf << "Bank = " << std::dec << myCart.getBank() - << ", hotspot = $" << Common::Base::HEX2 << (myCart.getBank() + 0x800); - - return buf.str(); + return info.str(); } diff --git a/src/debugger/gui/CartSBWidget.hxx b/src/debugger/gui/CartSBWidget.hxx index 5819dec02..91cc90ec1 100644 --- a/src/debugger/gui/CartSBWidget.hxx +++ b/src/debugger/gui/CartSBWidget.hxx @@ -19,11 +19,10 @@ #define CARTRIDGESB_WIDGET_HXX class CartridgeSB; -class PopUpWidget; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class CartridgeSBWidget : public CartDebugWidget +class CartridgeSBWidget : public CartridgeEnhancedWidget { public: CartridgeSBWidget(GuiObject* boss, const GUI::Font& lfont, @@ -33,17 +32,11 @@ class CartridgeSBWidget : public CartDebugWidget virtual ~CartridgeSBWidget() = default; private: - CartridgeSB& myCart; - PopUpWidget* myBank{nullptr}; + string manufacturer() override { return "Fred X. Quimby"; } - enum { kBankChanged = 'bkCH' }; + string description() override; private: - void loadConfig() override; - void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - - string bankState() override; - // Following constructors and assignment operators not supported CartridgeSBWidget() = delete; CartridgeSBWidget(const CartridgeSBWidget&) = delete; diff --git a/src/emucore/CartMDM.hxx b/src/emucore/CartMDM.hxx index 6fd7435a3..4b0786e42 100644 --- a/src/emucore/CartMDM.hxx +++ b/src/emucore/CartMDM.hxx @@ -100,6 +100,8 @@ class CartridgeMDM : public CartridgeEnhanced */ string name() const override { return "CartridgeMDM"; } + uInt16 hotspot() const override { return 0x0800; } + #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings diff --git a/src/emucore/CartSB.hxx b/src/emucore/CartSB.hxx index 1e8a363a9..85c8e9ccb 100644 --- a/src/emucore/CartSB.hxx +++ b/src/emucore/CartSB.hxx @@ -98,7 +98,7 @@ class CartridgeSB : public CartridgeEnhanced private: bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; - uInt16 hotspot() const override { return 0x0840; } + uInt16 hotspot() const override { return 0x0800; } uInt16 getStartBank() const override { return romBankCount() - 1; } From 34b57d4205b23ff4644a62f4ab100e79676dc1f6 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 23 Apr 2020 12:34:27 +0200 Subject: [PATCH 149/377] refactored Cart3EPlus widget --- src/debugger/gui/Cart3EPlusWidget.cxx | 210 +++++++++--------------- src/debugger/gui/Cart3EPlusWidget.hxx | 42 ++--- src/debugger/gui/Cart3EWidget.hxx | 2 +- src/debugger/gui/Cart3FWidget.hxx | 2 +- src/debugger/gui/CartE0Widget.hxx | 2 +- src/debugger/gui/CartEnhancedWidget.cxx | 8 +- src/debugger/gui/CartEnhancedWidget.hxx | 2 +- src/debugger/gui/CartWDWidget.hxx | 2 +- src/emucore/Cart3EPlus.cxx | 16 +- src/emucore/Cart3EPlus.hxx | 15 +- 10 files changed, 106 insertions(+), 195 deletions(-) diff --git a/src/debugger/gui/Cart3EPlusWidget.cxx b/src/debugger/gui/Cart3EPlusWidget.cxx index a93cb8f98..8e7cdf063 100644 --- a/src/debugger/gui/Cart3EPlusWidget.cxx +++ b/src/debugger/gui/Cart3EPlusWidget.cxx @@ -18,116 +18,124 @@ #include "Cart3EPlus.hxx" #include "EditTextWidget.hxx" #include "PopUpWidget.hxx" -#include "Cart3EPlusWidget.hxx" +#include "CartEnhancedWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge3EPlusWidget::Cartridge3EPlusWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, Cartridge3EPlus& cart) - : CartDebugWidget(boss, lfont, nfont, x, y, w, h), - myCart(cart) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart), + myCart3EP(cart) { - size_t size = cart.mySize; + initialize(); +} +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string Cartridge3EPlusWidget::description() +{ ostringstream info; - info << "3EPlus cartridge - (4..64K ROM + RAM)\n" - << " 4..64K ROM (1K banks), ..32K RAM (512b banks)\n" - << "Each 1K ROM selected by writing to $3F\n" - "Each 512b RAM selected by writing to $3E\n" - " Lower 512b of bank x (R)\n" - " Upper 512b of bank x (+$200) (W)\n" - << "Startup bank = 0/-1/-1/0 (ROM)\n"; + size_t size; + const uInt8* image = myCart.getImage(size); + uInt16 numRomBanks = myCart.romBankCount(); + uInt16 numRamBanks = myCart.ramBankCount(); + + info << "3E+ cartridge - (4..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"; // Eventually, we should query this from the debugger/disassembler - // Currently the cart starts at bank 0. If we change that, we have to change this too. - uInt16 start = (cart.myImage[0x400-3] << 8) | cart.myImage[0x400 - 4]; - start &= 0xF000; - info << "Bank RORG = $" << Common::Base::HEX4 << start << "\n"; + uInt16 start = (image[0x400 - 3] << 8) | image[0x400 - 4]; + start -= start % 0x1000; + info << "Bank RORG" << " = $" << Common::Base::HEX4 << start << "\n"; - int xpos = 2, - ypos = addBaseInformation(size, "Thomas Jentzsch", info.str()) + 8; - - VariantList bankno; - for(uInt32 i = 0; i < myCart.romBankCount(); ++i) - VarList::push_back(bankno, i, i); + return info.str(); +} +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Cartridge3EPlusWidget::bankSelect(int& ypos) +{ + size_t size; + const uInt8* image = myCart.getImage(size); VariantList banktype; + VarList::push_back(banktype, "ROM", "ROM"); VarList::push_back(banktype, "RAM", "RAM"); - for(uInt32 seg = 0; seg < myCart.myBankSegs; ++seg) - { - int xpos_s, ypos_s = ypos + 1; + myBankWidgets = make_unique(bankSegs()); + for(uInt32 seg = 0; seg < bankSegs(); ++seg) + { + int xpos = 2, xpos_s, ypos_s = ypos + 1, width; ostringstream label; + VariantList items; + label << "Set segment " << seg << " as "; - new StaticTextWidget(boss, _font, xpos, ypos, label.str()); + new StaticTextWidget(_boss, _font, xpos, ypos, label.str()); ypos += myLineHeight + 8; xpos += _font.getMaxCharWidth() * 2; - myBankNumber[seg] = - new PopUpWidget(boss, _font, xpos, ypos-2, 2 *_font.getMaxCharWidth(), - myLineHeight, bankno, "Bank "); - addFocusWidget(myBankNumber[seg]); - xpos += myBankNumber[seg]->getWidth(); + CartridgeEnhancedWidget::bankList(myCart.romBankCount(), seg, items, width); + myBankWidgets[seg] = + new PopUpWidget(_boss, _font, xpos, ypos - 2, width, + myLineHeight, items, "Bank "); + addFocusWidget(myBankWidgets[seg]); + + xpos += myBankWidgets[seg]->getWidth(); myBankType[seg] = - new PopUpWidget(boss, _font, xpos, ypos-2, 3 *_font.getMaxCharWidth(), + new PopUpWidget(_boss, _font, xpos, ypos - 2, 3 * _font.getMaxCharWidth(), myLineHeight, banktype, " of "); addFocusWidget(myBankType[seg]); xpos = myBankType[seg]->getRight() + _font.getMaxCharWidth(); // add "Commit" button (why required?) - myBankCommit[seg] = new ButtonWidget(boss, _font, xpos, ypos-4, - _font.getStringWidth(" Commit "), myButtonHeight, - "Commit", bankEnum[seg]); + myBankCommit[seg] = new ButtonWidget(_boss, _font, xpos, ypos - 4, + _font.getStringWidth(" Commit "), myButtonHeight, + "Commit", bankEnum[seg]); myBankCommit[seg]->setTarget(this); addFocusWidget(myBankCommit[seg]); xpos_s = myBankCommit[seg]->getRight() + _font.getMaxCharWidth() * 2; StaticTextWidget* t; + uInt16 start = (image[0x400 - 3] << 8) | image[0x400 - 4]; + start -= start % 0x1000; int addr1 = start + (seg * 0x400), addr2 = addr1 + 0x200; label.str(""); label << "$" << Common::Base::HEX4 << addr1 << "-$" << Common::Base::HEX4 << (addr1 + 0x1FF); - t = new StaticTextWidget(boss, _font, xpos_s, ypos_s+2, label.str()); + t = new StaticTextWidget(_boss, _font, xpos_s, ypos_s + 2, label.str()); int xoffset = t->getRight() + _font.getMaxCharWidth(); - myBankState[2*seg] = new EditTextWidget(boss, _font, xoffset, ypos_s, - w - xoffset - 10, myLineHeight, ""); - myBankState[2*seg]->setEditable(false, true); + myBankState[2 * seg] = new EditTextWidget(_boss, _font, xoffset, ypos_s, + _w - xoffset - 10, myLineHeight, ""); + myBankState[2 * seg]->setEditable(false, true); ypos_s += myLineHeight + 4; label.str(""); label << "$" << Common::Base::HEX4 << addr2 << "-$" << Common::Base::HEX4 << (addr2 + 0x1FF); - new StaticTextWidget(boss, _font, xpos_s, ypos_s+2, label.str()); + new StaticTextWidget(_boss, _font, xpos_s, ypos_s + 2, label.str()); - myBankState[2*seg+1] = new EditTextWidget(boss, _font, xoffset, ypos_s, - w - xoffset - 10, myLineHeight, ""); - myBankState[2*seg+1]->setEditable(false, true); + myBankState[2 * seg + 1] = new EditTextWidget(_boss, _font, xoffset, ypos_s, + _w - xoffset - 10, myLineHeight, ""); + myBankState[2 * seg + 1]->setEditable(false, true); - xpos = 2; ypos += 2 * myLineHeight; } } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge3EPlusWidget::saveOldState() -{ - myOldState.internalram.clear(); - - for(uInt32 i = 0; i < internalRamSize(); ++i) - myOldState.internalram.push_back(myCart.myRAM[i]); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3EPlusWidget::loadConfig() { + CartridgeEnhancedWidget::loadConfig(); updateUIState(); - CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -154,11 +162,11 @@ void Cartridge3EPlusWidget::handleCommand(CommandSender* sender, } // Ignore bank if either number or type hasn't been selected - if(myBankNumber[segment]->getSelected() < 0 || + if(myBankWidgets[segment]->getSelected() < 0 || myBankType[segment]->getSelected() < 0) return; - uInt8 bank = myBankNumber[segment]->getSelected(); + uInt8 bank = myBankWidgets[segment]->getSelected(); myCart.unlockBank(); @@ -172,123 +180,61 @@ void Cartridge3EPlusWidget::handleCommand(CommandSender* sender, updateUIState(); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string Cartridge3EPlusWidget::bankState() -{ - ostringstream& buf = buffer(); - - for(int seg = 0; seg < myCart.myBankSegs; ++seg) - { - int bank = myCart.getSegmentBank(seg); - - if(bank >= myCart.romBankCount()) // was RAM mapped here? - buf << " RAM " << bank - myCart.romBankCount(); - else - buf << " ROM " << bank; - if(seg < myCart.myBankSegs - 1) - buf << " /"; - } - - return buf.str(); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3EPlusWidget::updateUIState() { - // Set description for each 1K bank state (@ each index) + // Set description for each 1K segment state (@ each index) // Set contents for actual banks number and type (@ each even index) - for(int seg = 0; seg < myCart.myBankSegs; ++seg) + for(int seg = 0; seg < myCart3EP.myBankSegs; ++seg) { uInt16 bank = myCart.getSegmentBank(seg); ostringstream buf; - if(bank >= myCart.romBankCount()) // was RAM mapped here? + if(bank >= myCart.romBankCount()) // was RAM mapped here? { uInt16 ramBank = bank - myCart.romBankCount(); - buf << "RAM " << std::dec << ramBank << " @ $" << Common::Base::HEX4 - << (ramBank << myCart.myBankShift) << "(R)"; + buf << "RAM @ $" << Common::Base::HEX4 + << (ramBank << myCart3EP.myBankShift) << " (R)"; myBankState[seg * 2]->setText(buf.str()); buf.str(""); - buf << "RAM " << std::dec << ramBank << " @ $" << Common::Base::HEX4 - << ((ramBank << myCart.myBankShift) + myCart.myBankSize) << "(W)"; + buf << "RAM @ $" << Common::Base::HEX4 + << ((ramBank << myCart3EP.myBankShift) + myCart3EP.myBankSize) << " (W)"; myBankState[seg * 2 + 1]->setText(buf.str()); - myBankNumber[seg]->setSelected(ramBank); + myBankWidgets[seg]->setSelectedIndex(ramBank); myBankType[seg]->setSelected("RAM"); } else { - buf << "ROM " << std::dec << bank << " @ $" << Common::Base::HEX4 - << ((bank << myCart.myBankShift)); + buf << "ROM @ $" << Common::Base::HEX4 + << ((bank << myCart3EP.myBankShift)); myBankState[seg * 2]->setText(buf.str()); buf.str(""); - buf << "ROM " << std::dec << bank << " @ $" << Common::Base::HEX4 - << ((bank << myCart.myBankShift) + myCart.myBankSize); + buf << "ROM @ $" << Common::Base::HEX4 + << ((bank << myCart3EP.myBankShift) + myCart3EP.myBankSize); myBankState[seg * 2 + 1]->setText(buf.str()); - myBankNumber[seg]->setSelected(bank); + myBankWidgets[seg]->setSelectedIndex(bank); myBankType[seg]->setSelected("ROM"); } } } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 Cartridge3EPlusWidget::internalRamSize() -{ - return 32*1024; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 Cartridge3EPlusWidget::internalRamRPort(int start) -{ - return 0x0000 + start; -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Cartridge3EPlusWidget::internalRamDescription() { ostringstream desc; desc << "Accessible 512b at a time via:\n" - << " $f000/$f400/$f800/$fc00 for Read Access\n" - << " $f200/$f600/$fa00/$fe00 for Write Access"; + << " $f000/$f400/$f800/$fc00 for read access\n" + << " $f200/$f600/$fa00/$fe00 for write access"; return desc.str(); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& Cartridge3EPlusWidget::internalRamOld(int start, int count) -{ - myRamOld.clear(); - for(int i = 0; i < count; i++) - myRamOld.push_back(myOldState.internalram[start + i]); - return myRamOld; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const ByteArray& Cartridge3EPlusWidget::internalRamCurrent(int start, int count) -{ - myRamCurrent.clear(); - for(int i = 0; i < count; i++) - myRamCurrent.push_back(myCart.myRAM[start + i]); - return myRamCurrent; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge3EPlusWidget::internalRamSetValue(int addr, uInt8 value) -{ - myCart.myRAM[addr] = value; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 Cartridge3EPlusWidget::internalRamGetValue(int addr) -{ - return myCart.myRAM[addr]; -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const std::array Cartridge3EPlusWidget::bankEnum = { kBank0Changed, kBank1Changed, kBank2Changed, kBank3Changed diff --git a/src/debugger/gui/Cart3EPlusWidget.hxx b/src/debugger/gui/Cart3EPlusWidget.hxx index 723003376..7cde61042 100644 --- a/src/debugger/gui/Cart3EPlusWidget.hxx +++ b/src/debugger/gui/Cart3EPlusWidget.hxx @@ -23,9 +23,9 @@ class ButtonWidget; class EditTextWidget; class PopUpWidget; -#include "CartDebugWidget.hxx" +#include "CartEnhancedWidget.hxx" -class Cartridge3EPlusWidget : public CartDebugWidget +class Cartridge3EPlusWidget : public CartridgeEnhancedWidget { public: Cartridge3EPlusWidget(GuiObject* boss, const GUI::Font& lfont, @@ -35,21 +35,27 @@ class Cartridge3EPlusWidget : public CartDebugWidget virtual ~Cartridge3EPlusWidget() = default; private: + string manufacturer() override { return "Thomas Jentzsch"; } + + string description() override; + + void bankSelect(int& ypos) override; + + void handleCommand(CommandSender* sender, int cmd, int data, int id) override; + void updateUIState(); - private: - Cartridge3EPlus& myCart; + void loadConfig() override; + + string internalRamDescription() override; + + private: + Cartridge3EPlus& myCart3EP; - std::array myBankNumber{nullptr}; std::array myBankType{nullptr}; std::array myBankCommit{nullptr}; std::array myBankState{nullptr}; - struct CartState { - ByteArray internalram; - }; - CartState myOldState; - enum BankID { kBank0Changed = 'b0CH', kBank1Changed = 'b1CH', @@ -59,22 +65,6 @@ class Cartridge3EPlusWidget : public CartDebugWidget static const std::array bankEnum; private: - void saveOldState() override; - void loadConfig() override; - void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - - string bankState() override; - - // start of functions for Cartridge RAM tab - uInt32 internalRamSize() override; - uInt32 internalRamRPort(int start) override; - string internalRamDescription() override; - const ByteArray& internalRamOld(int start, int count) override; - const ByteArray& internalRamCurrent(int start, int count) override; - void internalRamSetValue(int addr, uInt8 value) override; - uInt8 internalRamGetValue(int addr) override; - // end of functions for Cartridge RAM tab - // Following constructors and assignment operators not supported Cartridge3EPlusWidget() = delete; Cartridge3EPlusWidget(const Cartridge3EPlusWidget&) = delete; diff --git a/src/debugger/gui/Cart3EWidget.hxx b/src/debugger/gui/Cart3EWidget.hxx index e1d4f266b..424d9a577 100644 --- a/src/debugger/gui/Cart3EWidget.hxx +++ b/src/debugger/gui/Cart3EWidget.hxx @@ -47,7 +47,7 @@ class Cartridge3EWidget : public CartridgeEnhancedWidget void bankSelect(int& ypos) override; - int bankSegs() override { return 1; } + uInt16 bankSegs() override { return 1; } void loadConfig() override; diff --git a/src/debugger/gui/Cart3FWidget.hxx b/src/debugger/gui/Cart3FWidget.hxx index e5f97a392..ad24d8e56 100644 --- a/src/debugger/gui/Cart3FWidget.hxx +++ b/src/debugger/gui/Cart3FWidget.hxx @@ -36,7 +36,7 @@ class Cartridge3FWidget : public CartridgeEnhancedWidget string description() override; - int bankSegs() override { return 1; } + uInt16 bankSegs() override { return 1; } private: // Following constructors and assignment operators not supported diff --git a/src/debugger/gui/CartE0Widget.hxx b/src/debugger/gui/CartE0Widget.hxx index a9d84b461..a50893e84 100644 --- a/src/debugger/gui/CartE0Widget.hxx +++ b/src/debugger/gui/CartE0Widget.hxx @@ -40,7 +40,7 @@ class CartridgeE0Widget : public CartridgeEnhancedWidget string hotspotStr(int bank, int segment, bool noBrackets = false) override; - int bankSegs() override { return 3; } + uInt16 bankSegs() override { return 3; } private: // Following constructors and assignment operators not supported diff --git a/src/debugger/gui/CartEnhancedWidget.cxx b/src/debugger/gui/CartEnhancedWidget.cxx index a59e4f985..8001c1292 100644 --- a/src/debugger/gui/CartEnhancedWidget.cxx +++ b/src/debugger/gui/CartEnhancedWidget.cxx @@ -253,7 +253,7 @@ string CartridgeEnhancedWidget::hotspotStr(int bank, int segment, bool prefix) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int CartridgeEnhancedWidget::bankSegs() +uInt16 CartridgeEnhancedWidget::bankSegs() { return myCart.myBankSegs; } @@ -339,18 +339,18 @@ string CartridgeEnhancedWidget::internalRamDescription() { desc << indent << "$" << Common::Base::HEX4 << (ADDR_BASE | myCart.myReadOffset) << " - $" << (ADDR_BASE | (myCart.myReadOffset + myCart.myRamMask)) - << " used for Read Access\n"; + << " used for read Access\n"; } desc << indent << "$" << Common::Base::HEX4 << (ADDR_BASE | myCart.myWriteOffset) << " - $" << (ADDR_BASE | (myCart.myWriteOffset + myCart.myRamMask)) - << " used for Write Access"; + << " used for write Access"; if(myCart.myReadOffset > myCart.myWriteOffset) { desc << indent << "\n$" << Common::Base::HEX4 << (ADDR_BASE | myCart.myReadOffset) << " - $" << (ADDR_BASE | (myCart.myReadOffset + myCart.myRamMask)) - << " used for Read Access"; + << " used for read Access"; } return desc.str(); diff --git a/src/debugger/gui/CartEnhancedWidget.hxx b/src/debugger/gui/CartEnhancedWidget.hxx index 1f4ae6f30..968a4bbf0 100644 --- a/src/debugger/gui/CartEnhancedWidget.hxx +++ b/src/debugger/gui/CartEnhancedWidget.hxx @@ -57,7 +57,7 @@ class CartridgeEnhancedWidget : public CartDebugWidget virtual string hotspotStr(int bank = 0, int segment = 0, bool prefix = false); - virtual int bankSegs(); // { return myCart.myBankSegs; } + virtual uInt16 bankSegs(); // { return myCart.myBankSegs; } void saveOldState() override; void loadConfig() override; diff --git a/src/debugger/gui/CartWDWidget.hxx b/src/debugger/gui/CartWDWidget.hxx index 0201cffa5..2ccdd7437 100644 --- a/src/debugger/gui/CartWDWidget.hxx +++ b/src/debugger/gui/CartWDWidget.hxx @@ -41,7 +41,7 @@ private: string hotspotStr(int bank, int seg = 0, bool prefix = false) override; - int bankSegs() override { return 1; } + uInt16 bankSegs() override { return 1; } private: // Following constructors and assignment operators not supported diff --git a/src/emucore/Cart3EPlus.cxx b/src/emucore/Cart3EPlus.cxx index 5803f2136..6c9fe7c2a 100644 --- a/src/emucore/Cart3EPlus.cxx +++ b/src/emucore/Cart3EPlus.cxx @@ -22,13 +22,11 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge3EPlus::Cartridge3EPlus(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, md5, settings) - + : Cartridge3E(image, size, md5, settings) { myBankShift = BANK_SHIFT; myRamSize = RAM_SIZE; myRamBankCount = RAM_BANKS; - myRamWpHigh = RAM_HIGH_WP; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -42,18 +40,6 @@ void Cartridge3EPlus::reset() bank(startBank(), 3); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge3EPlus::install(System& system) -{ - CartridgeEnhanced::install(system); - - System::PageAccess access(this, System::PageAccessType::WRITE); - - // The hotspots are in TIA address space, so we claim it here - for(uInt16 addr = 0x00; addr < 0x40; addr += System::PAGE_SIZE) - mySystem->setPageAccess(addr, access); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge3EPlus::checkSwitchBank(uInt16 address, uInt8 value) { diff --git a/src/emucore/Cart3EPlus.hxx b/src/emucore/Cart3EPlus.hxx index 209ab89dc..c2ce64cd8 100644 --- a/src/emucore/Cart3EPlus.hxx +++ b/src/emucore/Cart3EPlus.hxx @@ -21,7 +21,7 @@ class System; #include "bspf.hxx" -#include "CartEnhanced.hxx" +#include "Cart3E.hxx" #ifdef DEBUGGER_SUPPORT class Cartridge3EPlusWidget; @@ -89,7 +89,7 @@ class Cartridge3EPlusWidget; @author Thomas Jentzsch and Stephen Anthony */ -class Cartridge3EPlus: public CartridgeEnhanced +class Cartridge3EPlus: public Cartridge3E { friend class Cartridge3EPlusWidget; @@ -110,14 +110,6 @@ class Cartridge3EPlus: public CartridgeEnhanced /** Reset device to its power-on state */ void reset() override; - /** - Install cartridge in the specified system. Invoked by the system - when the cartridge is attached to it. - - @param system The system the device should install itself in - */ - void install(System& system) override; - /** Get a descriptor for the device name (used in error checking). @@ -167,9 +159,6 @@ class Cartridge3EPlus: public CartridgeEnhanced // RAM size static constexpr size_t RAM_SIZE = RAM_BANKS << (BANK_SHIFT - 1); // = 32K = 0x4000; - // Write port for extra RAM is at high address - static constexpr bool RAM_HIGH_WP = true; - private: // Following constructors and assignment operators not supported Cartridge3EPlus() = delete; From f095991317d301733ab4fd9148e0585ddc1e9199 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Thu, 23 Apr 2020 14:14:59 -0230 Subject: [PATCH 150/377] Fix loading of ROM twice on each selection in the ROM launcher. It was being opened once for the snapshots, and again for the controllers. --- src/gui/LauncherDialog.cxx | 8 +------- src/gui/RomInfoWidget.cxx | 28 ++++++++++++++-------------- src/gui/RomInfoWidget.hxx | 2 +- 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/src/gui/LauncherDialog.cxx b/src/gui/LauncherDialog.cxx index fc47f9bbe..5df9d3f8d 100644 --- a/src/gui/LauncherDialog.cxx +++ b/src/gui/LauncherDialog.cxx @@ -428,13 +428,7 @@ void LauncherDialog::loadRomInfo() const string& md5 = selectedRomMD5(); if(md5 != EmptyString) - { - // Get the properties for this entry - Properties props; - instance().propSet().getMD5WithInsert(currentNode(), md5, props); - - myRomInfoWidget->setProperties(props, currentNode()); - } + myRomInfoWidget->setProperties(currentNode(), md5); else myRomInfoWidget->clearProperties(); } diff --git a/src/gui/RomInfoWidget.cxx b/src/gui/RomInfoWidget.cxx index 752876735..0df0610d3 100644 --- a/src/gui/RomInfoWidget.cxx +++ b/src/gui/RomInfoWidget.cxx @@ -27,6 +27,7 @@ #include "Logger.hxx" #include "Props.hxx" #include "PNGLibrary.hxx" +#include "PropsSet.hxx" #include "Rect.hxx" #include "Widget.hxx" #include "RomInfoWidget.hxx" @@ -44,20 +45,10 @@ RomInfoWidget::RomInfoWidget(GuiObject* boss, const GUI::Font& font, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void RomInfoWidget::reloadProperties(const FilesystemNode& node) -{ - // The ROM may have changed since we were last in the browser, either - // by saving a different image or through a change in video renderer, - // so we reload the properties - if(myHaveProperties) - parseProperties(node); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void RomInfoWidget::setProperties(const Properties& props, const FilesystemNode& node) +void RomInfoWidget::setProperties(const FilesystemNode& node, const string& md5) { myHaveProperties = true; - myProperties = props; + instance().propSet().getMD5(md5, myProperties); // Decide whether the information should be shown immediately if(instance().eventHandler().state() == EventHandlerState::LAUNCHER) @@ -76,6 +67,16 @@ void RomInfoWidget::clearProperties() setDirty(); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void RomInfoWidget::reloadProperties(const FilesystemNode& node) +{ + // The ROM may have changed since we were last in the browser, either + // by saving a different image or through a change in video renderer, + // so we reload the properties + if(myHaveProperties) + parseProperties(node); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomInfoWidget::parseProperties(const FilesystemNode& node) { @@ -140,8 +141,7 @@ void RomInfoWidget::parseProperties(const FilesystemNode& node) try { ByteBuffer image; - string md5 = myProperties.get(PropType::Cart_MD5); - size_t size = 0; + string md5 = ""; size_t size = 0; if(node.exists() && !node.isDirectory() && (image = instance().openROM(node, md5, size)) != nullptr) diff --git a/src/gui/RomInfoWidget.hxx b/src/gui/RomInfoWidget.hxx index e1a964263..e2ea566ca 100644 --- a/src/gui/RomInfoWidget.hxx +++ b/src/gui/RomInfoWidget.hxx @@ -35,7 +35,7 @@ class RomInfoWidget : public Widget const Common::Size& imgSize); virtual ~RomInfoWidget() = default; - void setProperties(const Properties& props, const FilesystemNode& node); + void setProperties(const FilesystemNode& node, const string& md5); void clearProperties(); void reloadProperties(const FilesystemNode& node); From 9ca329b986021523c4058ce68aef31e46528c80b Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Thu, 23 Apr 2020 19:53:38 -0230 Subject: [PATCH 151/377] Fixed error in ROM properties; a ROM was misconfigured for Mindlink controller. --- src/emucore/DefProps.hxx | 2 +- src/emucore/stella.pro | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/emucore/DefProps.hxx b/src/emucore/DefProps.hxx index d5bb3533e..b8db6bf24 100644 --- a/src/emucore/DefProps.hxx +++ b/src/emucore/DefProps.hxx @@ -2090,7 +2090,7 @@ static const BSPF::array2D DefProps = {{ { "95a69cf8c08ef1522b050529464f0bca", "", "", "Grid Pattern Demo 1 (20-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "95a89d1bf767d7cc9d0d5093d579ba61", "PlayAround - J.H.M.", "204", "Lady in Wading (1982) (PlayAround)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "95e1d834c57cdd525dd0bd6048a57f7b", "Atari, Bill Aspromonte, John Russell, Michael Sierchio, Robert Zdybel", "CX26114", "Pigs in Space (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, - { "95e542a7467c94b1e4ab24a3ebe907f1", "Suntek", "SS-021", "Dragon Defender (1983) (Suntek) (PAL)", "", "", "", "", "", "", "", "", "", "MINDLINK", "", "", "", "", "", "", "", "YES", "" }, + { "95e542a7467c94b1e4ab24a3ebe907f1", "Suntek", "SS-021", "Dragon Defender (1983) (Suntek) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "95fd6097dc27c20666f039cfe34f7c69", "", "", "Oh No! (Version 1) (17-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "961112b74a920a5242e233480326c356", "Activision, Alan Miller", "AG-007, CAG-007", "Tennis (1981) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "962ffd3eaf865230a7a312b80e6c5cfd", "Imagic, Wilfredo 'Willy' Aguilar, Michael Becker, Rob Fulop", "13205", "Fathom (1983) (Imagic) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, diff --git a/src/emucore/stella.pro b/src/emucore/stella.pro index 4a8ba020e..6a7944a91 100644 --- a/src/emucore/stella.pro +++ b/src/emucore/stella.pro @@ -12560,7 +12560,6 @@ "Cart.Manufacturer" "Suntek" "Cart.ModelNo" "SS-021" "Cart.Name" "Dragon Defender (1983) (Suntek) (PAL)" -"Controller.Left" "MINDLINK" "Display.Phosphor" "YES" "" From fa09f3e583b1b5e7ab18584ae851a4b337d31382 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Fri, 24 Apr 2020 11:20:01 +0200 Subject: [PATCH 152/377] refactored CartDPC class replaced DPC ROM --- src/emucore/CartDPC.cxx | 151 +++++++--------------------------------- src/emucore/CartDPC.hxx | 57 +++------------ 2 files changed, 37 insertions(+), 171 deletions(-) diff --git a/src/emucore/CartDPC.cxx b/src/emucore/CartDPC.cxx index c8a038c25..481e385be 100644 --- a/src/emucore/CartDPC.cxx +++ b/src/emucore/CartDPC.cxx @@ -22,45 +22,36 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeDPC::CartridgeDPC(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5), - mySize(size) + : CartridgeF8(image, size, md5, settings) { - // Make a copy of the entire image - std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessArrays(8_KB); - - // Pointer to the program ROM (8K @ 0 byte offset) - myProgramImage = myImage.data(); - - // Pointer to the display ROM (2K @ 8K offset) - myDisplayImage = myProgramImage + 8_KB; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDPC::reset() { + CartridgeEnhanced::reset(); + myAudioCycles = 0; myFractionalClocks = 0.0; - - // Upon reset we switch to the startup bank - initializeStartBank(1); - bank(startBank()); - myDpcPitch = mySettings.getInt(AudioSettings::SETTING_DPC_PITCH); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDPC::install(System& system) { - mySystem = &system; + CartridgeEnhanced::install(system); + + myRomOffset = 0x80; + + // Pointer to the display ROM (2K @ 8K offset) + myDisplayImage = myImage.get() + 8_KB; + + createRomAccessArrays(8_KB); // Set the page accessing method for the DPC reading & writing pages System::PageAccess access(this, System::PageAccessType::READWRITE); for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); - - // Install pages for the startup bank - bank(startBank()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -128,12 +119,15 @@ inline void CartridgeDPC::updateMusicModeDataFetchers() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeDPC::peek(uInt16 address) { + uInt16 peekAddress = address; + address &= 0x0FFF; // In debugger/bank-locked mode, we ignore all hotspots and in general // anything that can change the internal state of the cart if(bankLocked()) - return myProgramImage[myBankOffset + address]; + return myImage[myCurrentSegOffset[0] + address]; + // Clock the random number generator. This should be done for every // cartridge access, however, we're only doing it for the DPC and @@ -232,30 +226,14 @@ uInt8 CartridgeDPC::peek(uInt16 address) return result; } else - { - // Switch banks if necessary - switch(address) - { - case 0x0FF8: - // Set the current bank to the lower 4k bank - bank(0); - break; - - case 0x0FF9: - // Set the current bank to the upper 4k bank - bank(1); - break; - - default: - break; - } - return myProgramImage[myBankOffset + address]; - } + return CartridgeEnhanced::peek(peekAddress); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDPC::poke(uInt16 address, uInt8 value) { + uInt16 pokeAddress = address; + address &= 0x0FFF; // Clock the random number generator. This should be done for every @@ -338,102 +316,31 @@ bool CartridgeDPC::poke(uInt16 address, uInt8 value) } } else - { - // Switch banks if necessary - switch(address) - { - case 0x0FF8: - // Set the current bank to the lower 4k bank - bank(0); - break; + CartridgeEnhanced::poke(pokeAddress, value); - case 0x0FF9: - // Set the current bank to the upper 4k bank - bank(1); - break; - - default: - break; - } - } return false; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeDPC::bank(uInt16 bank) -{ - if(bankLocked()) return false; - - // Remember what bank we're in - myBankOffset = bank << 12; - - System::PageAccess access(this, System::PageAccessType::READ); - - // Set the page accessing methods for the hot spots - for(uInt16 addr = (0x1FF8 & ~System::PAGE_MASK); addr < 0x2000; - addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - - // Setup the page access methods for the current bank - for(uInt16 addr = 0x1080; addr < static_cast(0x1FF8U & ~System::PAGE_MASK); - addr += System::PAGE_SIZE) - { - access.directPeekBase = &myProgramImage[myBankOffset + (addr & 0x0FFF)]; - access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; - access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize]; - mySystem->setPageAccess(addr, access); - } - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeDPC::getBank(uInt16) const -{ - return myBankOffset >> 12; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeDPC::romBankCount() const -{ - return 2; -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDPC::patch(uInt16 address, uInt8 value) { - address &= 0x0FFF; - // For now, we ignore attempts to patch the DPC address space - if(address >= 0x0080) + if((address & ADDR_MASK) >= ROM_OFFSET + myRomOffset) { - myProgramImage[myBankOffset + (address & 0x0FFF)] = value; - return myBankChanged = true; + return CartridgeEnhanced::patch(address, value); } else return false; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeDPC::getImage(size_t& size) const -{ - size = mySize; - return myImage.data(); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDPC::save(Serializer& out) const { + if(!CartridgeEnhanced::save(out)) + return false; + try { - // Indicates which bank is currently active - out.putShort(myBankOffset); - // The top registers for the data fetchers out.putByteArray(myTops.data(), myTops.size()); @@ -468,11 +375,11 @@ bool CartridgeDPC::save(Serializer& out) const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDPC::load(Serializer& in) { + if(!CartridgeEnhanced::load(in)) + return false; + try { - // Indicates which bank is currently active - myBankOffset = in.getShort(); - // The top registers for the data fetchers in.getByteArray(myTops.data(), myTops.size()); @@ -501,9 +408,5 @@ bool CartridgeDPC::load(Serializer& in) cerr << "ERROR: CartridgeDPC::load" << endl; return false; } - - // Now, go to the current bank - bank(myBankOffset >> 12); - return true; } diff --git a/src/emucore/CartDPC.hxx b/src/emucore/CartDPC.hxx index 6c186bfdb..e0a1b866e 100644 --- a/src/emucore/CartDPC.hxx +++ b/src/emucore/CartDPC.hxx @@ -18,10 +18,7 @@ #ifndef CARTRIDGE_DPC_HXX #define CARTRIDGE_DPC_HXX -class System; - -#include "bspf.hxx" -#include "Cart.hxx" +#include "CartF8.hxx" #ifdef DEBUGGER_SUPPORT #include "CartDPCWidget.hxx" #endif @@ -35,9 +32,9 @@ class System; For complete details on the DPC chip see David P. Crane's United States Patent Number 4,644,495. - @author Bradford W. Mott + @author Bradford W. Mott, Thomas Jentzsch */ -class CartridgeDPC : public Cartridge +class CartridgeDPC : public CartridgeF8 { friend class CartridgeDPCWidget; @@ -55,11 +52,6 @@ class CartridgeDPC : public Cartridge virtual ~CartridgeDPC() = default; public: - /** - Reset device to its power-on state - */ - void reset() override; - /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @@ -69,23 +61,9 @@ class CartridgeDPC : public Cartridge void install(System& system) override; /** - Install pages for the specified bank in the system. - - @param bank The bank that should be installed in the system + Reset device to its power-on state */ - bool bank(uInt16 bank) override; - - /** - Get the current bank. - - @param address The address to use when querying the bank - */ - uInt16 getBank(uInt16 address = 0) const override; - - /** - Query the number of banks supported by the cartridge. - */ - uInt16 romBankCount() const override; + void reset() override; /** Patch the cartridge ROM. @@ -96,14 +74,6 @@ class CartridgeDPC : public Cartridge */ bool patch(uInt16 address, uInt8 value) override; - /** - 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 - */ - const uInt8* getImage(size_t& size) const override; - /** Save the current state of this cart to the given Serializer. @@ -127,6 +97,11 @@ class CartridgeDPC : public Cartridge */ string name() const override { return "CartridgeDPC"; } + /** + Change the DPC audio pitch + + @param pitch The new pitch value + */ void setDpcPitch(double pitch) { myDpcPitch = pitch; } #ifdef DEBUGGER_SUPPORT @@ -171,15 +146,6 @@ class CartridgeDPC : public Cartridge void updateMusicModeDataFetchers(); private: - // The ROM image - std::array myImage; - - // (Actual) Size of the ROM image - size_t mySize{0}; - - // Pointer to the 8K program ROM image of the cartridge - uInt8* myProgramImage{nullptr}; - // Pointer to the 2K display ROM image of the cartridge uInt8* myDisplayImage{nullptr}; @@ -207,9 +173,6 @@ class CartridgeDPC : public Cartridge // Fractional DPC music OSC clocks unused during the last update double myFractionalClocks{0.0}; - // Indicates the offset into the ROM image (aligns to current bank) - uInt16 myBankOffset{0}; - // DPC pitch double myDpcPitch{0.0}; From 6ae8d92ebfa9f3daa3afe790b718d738852eddf4 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Fri, 24 Apr 2020 12:42:52 +0200 Subject: [PATCH 153/377] replaced "slice" with "bank" in many Cart(Widget) classes minor UI fixed for CartDPCWidget --- src/debugger/gui/CartDPCWidget.cxx | 72 ++++++++++++------------- src/debugger/gui/CartDPCWidget.hxx | 1 + src/debugger/gui/CartDebugWidget.cxx | 2 +- src/debugger/gui/CartDebugWidget.hxx | 3 +- src/debugger/gui/CartE78KWidget.cxx | 27 +++++----- src/debugger/gui/CartE7Widget.cxx | 17 +++--- src/debugger/gui/CartEnhancedWidget.cxx | 8 +-- src/debugger/gui/CartMNetworkWidget.cxx | 26 ++++----- src/debugger/gui/CartRamWidget.cxx | 2 +- src/debugger/gui/DebuggerDialog.cxx | 2 +- src/debugger/gui/RomWidget.cxx | 7 +-- src/emucore/Cart.hxx | 2 +- src/emucore/CartE0.cxx | 2 +- src/emucore/CartE0.hxx | 6 +-- src/emucore/CartEnhanced.cxx | 2 +- src/emucore/CartMNetwork.cxx | 44 +++++++-------- src/emucore/CartMNetwork.hxx | 14 +++-- src/emucore/CartWD.cxx | 2 +- src/emucore/CartWD.hxx | 4 +- 19 files changed, 120 insertions(+), 123 deletions(-) diff --git a/src/debugger/gui/CartDPCWidget.cxx b/src/debugger/gui/CartDPCWidget.cxx index c07ae8739..681b3692d 100644 --- a/src/debugger/gui/CartDPCWidget.cxx +++ b/src/debugger/gui/CartDPCWidget.cxx @@ -27,12 +27,13 @@ CartridgeDPCWidget::CartridgeDPCWidget( : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { + const int V_GAP = 4; size_t size = cart.mySize; - ostringstream info; + info << "DPC cartridge, two 4K banks + 2K display bank\n" - << "DPC registers accessible @ $F000 - $F07F\n" - << " $F000 - $F03F (R), $F040 - $F07F (W)\n" + << "DPC registers accessible @ $" << Common::Base::HEX4 << 0xF000 << " - $" << 0xF07F << "\n" + << " $" << 0xF000 << " - " << 0xF03F << " (R), $" << 0xF040 << " - $" << 0xF07F << " (W)\n" << "Startup bank = " << cart.startBank() << " or undetermined\n"; @@ -42,7 +43,7 @@ CartridgeDPCWidget::CartridgeDPCWidget( uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; start -= start % 0x1000; info << "Bank " << i << " @ $" << Common::Base::HEX4 << (start + 0x80) << " - " - << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; + << "$" << (start + 0xFFF) << " (hotspot = $" << (0xF000 + spot + i) << ")\n"; } int xpos = 2, @@ -50,26 +51,30 @@ CartridgeDPCWidget::CartridgeDPCWidget( myLineHeight; VariantList items; - VarList::push_back(items, "0 ($FFF8)"); - VarList::push_back(items, "1 ($FFF9)"); + for(int bank = 0; bank < 2; ++bank) + { + ostringstream buf; + + buf << "#" << std::dec << bank << " ($" << Common::Base::HEX4 << (0xFFF8 + bank) << ")"; + VarList::push_back(items, buf.str()); + } + myBank = - new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFFx)"), + new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("#0 ($FFFx)"), myLineHeight, items, "Set bank ", 0, kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); - ypos += myLineHeight + 8; + ypos += myLineHeight + V_GAP * 3; // Data fetchers - int lwidth = _font.getStringWidth("Data Fetchers "); - new StaticTextWidget(boss, _font, xpos, ypos, lwidth, - myFontHeight, "Data Fetchers ", TextAlign::Left); + int lwidth = _font.getStringWidth("Data fetchers "); + new StaticTextWidget(boss, _font, xpos, ypos, "Data fetchers "); // Top registers - lwidth = _font.getStringWidth("Counter Registers "); - xpos = 18; ypos += myLineHeight + 4; - new StaticTextWidget(boss, _font, xpos, ypos, lwidth, - myFontHeight, "Top Registers ", TextAlign::Left); + lwidth = _font.getStringWidth("Counter registers "); + xpos = 2 + _font.getMaxCharWidth() * 2; ypos += myLineHeight + 4; + new StaticTextWidget(boss, _font, xpos, ypos, "Top registers "); xpos += lwidth; myTops = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 2, 8, Common::Base::Fmt::_16); @@ -77,9 +82,8 @@ CartridgeDPCWidget::CartridgeDPCWidget( myTops->setEditable(false); // Bottom registers - xpos = 10; ypos += myLineHeight + 4; - new StaticTextWidget(boss, _font, xpos, ypos, lwidth, - myFontHeight, "Bottom Registers ", TextAlign::Left); + xpos = 2 + _font.getMaxCharWidth() * 2; ypos += myLineHeight + 4; + new StaticTextWidget(boss, _font, xpos, ypos, "Bottom registers "); xpos += lwidth; myBottoms = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 2, 8, Common::Base::Fmt::_16); @@ -87,9 +91,8 @@ CartridgeDPCWidget::CartridgeDPCWidget( myBottoms->setEditable(false); // Counter registers - xpos = 10; ypos += myLineHeight + 4; - new StaticTextWidget(boss, _font, xpos, ypos, lwidth, - myFontHeight, "Counter Registers ", TextAlign::Left); + xpos = 2 + _font.getMaxCharWidth() * 2; ypos += myLineHeight + 4; + new StaticTextWidget(boss, _font, xpos, ypos, "Counter registers "); xpos += lwidth; myCounters = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 4, 16, Common::Base::Fmt::_16_4); @@ -97,9 +100,8 @@ CartridgeDPCWidget::CartridgeDPCWidget( myCounters->setEditable(false); // Flag registers - xpos = 10; ypos += myLineHeight + 4; - new StaticTextWidget(boss, _font, xpos, ypos, lwidth, - myFontHeight, "Flag Registers ", TextAlign::Left); + xpos = 2 + _font.getMaxCharWidth() * 2; ypos += myLineHeight + 4; + new StaticTextWidget(boss, _font, xpos, ypos, "Flag registers "); xpos += lwidth; myFlags = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 2, 8, Common::Base::Fmt::_16); @@ -107,10 +109,9 @@ CartridgeDPCWidget::CartridgeDPCWidget( myFlags->setEditable(false); // Music mode - xpos = 2; ypos += myLineHeight + 12; + xpos = 2; ypos += myLineHeight + V_GAP * 3; lwidth = _font.getStringWidth("Music mode (DF5/DF6/DF7) "); - new StaticTextWidget(boss, _font, xpos, ypos, lwidth, - myFontHeight, "Music mode (DF5/DF6/DF7) ", TextAlign::Left); + new StaticTextWidget(boss, _font, xpos, ypos, "Music mode (DF5/DF6/DF7) "); xpos += lwidth; myMusicMode = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 2, 8, Common::Base::Fmt::_16); @@ -118,9 +119,8 @@ CartridgeDPCWidget::CartridgeDPCWidget( myMusicMode->setEditable(false); // Current random number - xpos = 10; ypos += myLineHeight + 4; - new StaticTextWidget(boss, _font, xpos, ypos, lwidth, - myFontHeight, "Current random number ", TextAlign::Left); + xpos = 2; ypos += myLineHeight + V_GAP * 3; + new StaticTextWidget(boss, _font, xpos, ypos, "Current random number "); xpos += lwidth; myRandom = new DataGridWidget(boss, _nfont, xpos, ypos-2, 1, 1, 2, 8, Common::Base::Fmt::_16); @@ -229,9 +229,8 @@ string CartridgeDPCWidget::bankState() { ostringstream& buf = buffer(); - static constexpr std::array spot = { "$FFF8", "$FFF9" }; - buf << "Bank = " << std::dec << myCart.getBank() - << ", hotspot = " << spot[myCart.getBank()]; + buf << "Bank #" << std::dec << myCart.getBank() + << " (hotspot $" << Common::Base::HEX4 << (0xFFF8 + myCart.getBank()) << ")"; return buf.str(); } @@ -252,10 +251,9 @@ uInt32 CartridgeDPCWidget::internalRamRPort(int start) string CartridgeDPCWidget::internalRamDescription() { ostringstream desc; - desc << "$0000 - $07FF - 2K display data\n" - << " indirectly accessible to 6507\n" - << " via DPC+'s Data Fetcher\n" - << " registers\n"; + desc << "2K display data @ $0000 - $" << Common::Base::HEX4 << 0x07FF << "\n" + << " indirectly accessible to 6507 via DPC's\n" + << " data fetcher registers\n"; return desc.str(); } diff --git a/src/debugger/gui/CartDPCWidget.hxx b/src/debugger/gui/CartDPCWidget.hxx index ff57ddc1d..0a675a2c8 100644 --- a/src/debugger/gui/CartDPCWidget.hxx +++ b/src/debugger/gui/CartDPCWidget.hxx @@ -75,6 +75,7 @@ class CartridgeDPCWidget : public CartDebugWidget const ByteArray& internalRamCurrent(int start, int count) override; void internalRamSetValue(int addr, uInt8 value) override; uInt8 internalRamGetValue(int addr) override; + string tabLabel() override { return " DPC Display Data "; } // end of functions for Cartridge RAM tab // Following constructors and assignment operators not supported diff --git a/src/debugger/gui/CartDebugWidget.cxx b/src/debugger/gui/CartDebugWidget.cxx index 25423ebd7..5d0bb5c98 100644 --- a/src/debugger/gui/CartDebugWidget.cxx +++ b/src/debugger/gui/CartDebugWidget.cxx @@ -49,7 +49,7 @@ int CartDebugWidget::addBaseInformation(size_t bytes, const string& manufacturer int x = 2, y = 8; // Add ROM size, manufacturer and bankswitch info - new StaticTextWidget(_boss, _font, x, y + 1, "ROM Size "); + new StaticTextWidget(_boss, _font, x, y + 1, "ROM size "); buf << bytes << " bytes"; if(bytes >= 1024) buf << " / " << (bytes/1024) << "KB"; diff --git a/src/debugger/gui/CartDebugWidget.hxx b/src/debugger/gui/CartDebugWidget.hxx index 7789cbb16..7bdcbf472 100644 --- a/src/debugger/gui/CartDebugWidget.hxx +++ b/src/debugger/gui/CartDebugWidget.hxx @@ -58,7 +58,7 @@ class CartDebugWidget : public Widget, public CommandSender virtual string bankState() { return "0 (non-bankswitched)"; } // To make the Cartridge RAM show up in the debugger, implement - // the following 8 functions for cartridges with internal RAM + // the following 9 functions for cartridges with internal RAM virtual uInt32 internalRamSize() { return 0; } virtual uInt32 internalRamRPort(int start) { return 0; } virtual string internalRamDescription() { return EmptyString; } @@ -67,6 +67,7 @@ class CartDebugWidget : public Widget, public CommandSender virtual void internalRamSetValue(int addr, uInt8 value) { } virtual uInt8 internalRamGetValue(int addr) { return 0; } virtual string internalRamLabel(int addr) { return "Not available/applicable"; } + virtual string tabLabel() { return " Cartridge RAM "; } protected: // Arrays used to hold current and previous internal RAM values diff --git a/src/debugger/gui/CartE78KWidget.cxx b/src/debugger/gui/CartE78KWidget.cxx index b14d24809..2ad1c012e 100644 --- a/src/debugger/gui/CartE78KWidget.cxx +++ b/src/debugger/gui/CartE78KWidget.cxx @@ -27,17 +27,18 @@ CartridgeE78KWidget::CartridgeE78KWidget( : CartridgeMNetworkWidget(boss, lfont, nfont, x, y, w, h, cart) { ostringstream info; - info << "E78K cartridge, 4 2K slices ROM + 2 1K RAM\n" - << "Lower 2K accessible @ $F000 - $F7FF\n" - << " Slice 0 - 2 of ROM (hotspots $FE4 to $FE6)\n" - << " Slice 7 (1K) of RAM (hotspot $FE7)\n" - << " $F400 - $F7FF (R), $F000 - $F3FF (W)\n" - << "256B RAM accessible @ $F800 - $F9FF\n" - << " Hotspots $FE8 - $FEB (256B of RAM slice 1)\n" - << " $F900 - $F9FF (R), $F800 - $F8FF (W)\n" - << "Upper 1.5K ROM accessible @ $FA00 - $FFFF\n" - << " Always points to last 1.5K of ROM\n" - << "Startup slices = 0 / 0 or undetermined\n"; + info << "E78K cartridge, four 2K banks ROM + 2K RAM,\n" + << " mapped into three segments\n" + << "Lower 2K accessible @ $F000 - $F7FF\n" + << " ROM banks 0 - 2 (hotspots $FFE4 to $FFE6)\n" + << " 1K RAM bank 3 (hotspot $FFE7)\n" + << " $F400 - $F7FF (R), $F000 - $F3FF (W)\n" + << "256B RAM accessible @ $F800 - $F9FF\n" + << " RAM banks 0 - 3 (hotspots $FFE8 - $FFEB)\n" + << " $F900 - $F9FF (R), $F800 - $F8FF (W)\n" + << "Upper 1.5K ROM accessible @ $FA00 - $FFFF\n" + << " Always points to last 1.5K of ROM\n" + << "Startup segments = 0 / 0 or undetermined\n"; #if 0 // Eventually, we should query this from the debugger/disassembler @@ -53,7 +54,7 @@ CartridgeE78KWidget::CartridgeE78KWidget( const char* CartridgeE78KWidget::getSpotLower(int idx) { static constexpr std::array spot_lower = { - "0 - ROM ($FFE4)", "1 - ROM ($FFE5)", "2 - ROM ($FFE6)", "3 - RAM ($FFE7)" + "#0 - ROM ($FFE4)", "#1 - ROM ($FFE5)", "#2 - ROM ($FFE6)", "#3 - RAM ($FFE7)" }; return spot_lower[idx]; @@ -63,7 +64,7 @@ const char* CartridgeE78KWidget::getSpotLower(int idx) const char* CartridgeE78KWidget::getSpotUpper(int idx) { static constexpr std::array spot_upper = { - "0 - RAM ($FFE8)", "1 - RAM ($FFE9)", "2 - RAM ($FFEA)", "3 - RAM ($FFEB)" + "#0 - RAM ($FFE8)", "#1 - RAM ($FFE9)", "#2 - RAM ($FFEA)", "#3 - RAM ($FFEB)" }; return spot_upper[idx]; diff --git a/src/debugger/gui/CartE7Widget.cxx b/src/debugger/gui/CartE7Widget.cxx index f4a5ea3dd..8546e84eb 100644 --- a/src/debugger/gui/CartE7Widget.cxx +++ b/src/debugger/gui/CartE7Widget.cxx @@ -26,17 +26,18 @@ CartridgeE7Widget::CartridgeE7Widget( : CartridgeMNetworkWidget(boss, lfont, nfont, x, y, w, h, cart) { ostringstream info; - info << "E7 cartridge, 8 2K slices ROM + 2 1K RAM\n" + info << "E7 cartridge, eight 2K banks ROM + 2K RAM,\n" + << " mapped into three segments\n" << "Lower 2K accessible @ $F000 - $F7FF\n" - << " Slice 0 - 6 of ROM (hotspots $FE0 to $FE6)\n" - << " Slice 7 (1K) of RAM (hotspot $FE7)\n" + << " ROM Banks 0 - 6 (hotspots $FFE0 to $FFE6)\n" + << " 1K RAM Bank 7 (hotspot $FFE7)\n" << " $F400 - $F7FF (R), $F000 - $F3FF (W)\n" << "256B RAM accessible @ $F800 - $F9FF\n" - << " Hotspots $FE8 - $FEB (256B of RAM slice 1)\n" + << " RAM banks 0 - 3 (hotspots $FFE8 - $FFEB)\n" << " $F900 - $F9FF (R), $F800 - $F8FF (W)\n" << "Upper 1.5K ROM accessible @ $FA00 - $FFFF\n" << " Always points to last 1.5K of ROM\n" - << "Startup slices = 0 / 0 or undetermined\n"; + << "Startup segments = 0 / 0 or undetermined\n"; #if 0 // Eventually, we should query this from the debugger/disassembler @@ -52,8 +53,8 @@ CartridgeE7Widget::CartridgeE7Widget( const char* CartridgeE7Widget::getSpotLower(int idx) { static constexpr std::array spot_lower = { - "0 - ROM ($FFE0)", "1 - ROM ($FFE1)", "2 - ROM ($FFE2)", "3 - ROM ($FFE3)", - "4 - ROM ($FFE4)", "5 - ROM ($FFE5)", "6 - ROM ($FFE6)", "7 - RAM ($FFE7)" + "#0 - ROM ($FFE0)", "#1 - ROM ($FFE1)", "#2 - ROM ($FFE2)", "#3 - ROM ($FFE3)", + "#4 - ROM ($FFE4)", "#5 - ROM ($FFE5)", "#6 - ROM ($FFE6)", "#7 - RAM ($FFE7)" }; return spot_lower[idx]; @@ -63,7 +64,7 @@ const char* CartridgeE7Widget::getSpotLower(int idx) const char* CartridgeE7Widget::getSpotUpper(int idx) { static constexpr std::array spot_upper = { - "0 - RAM ($FFE8)", "1 - RAM ($FFE9)", "2 - RAM ($FFEA)", "3 - RAM ($FFEB)" + "#0 - RAM ($FFE8)", "#1 - RAM ($FFE9)", "#2 - RAM ($FFEA)", "#3 - RAM ($FFEB)" }; return spot_upper[idx]; diff --git a/src/debugger/gui/CartEnhancedWidget.cxx b/src/debugger/gui/CartEnhancedWidget.cxx index 8001c1292..f864a21c0 100644 --- a/src/debugger/gui/CartEnhancedWidget.cxx +++ b/src/debugger/gui/CartEnhancedWidget.cxx @@ -233,7 +233,7 @@ string CartridgeEnhancedWidget::bankState() } return buf.str(); } - return "0 (non-bankswitched)"; + return "non-bankswitched"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -339,18 +339,18 @@ string CartridgeEnhancedWidget::internalRamDescription() { desc << indent << "$" << Common::Base::HEX4 << (ADDR_BASE | myCart.myReadOffset) << " - $" << (ADDR_BASE | (myCart.myReadOffset + myCart.myRamMask)) - << " used for read Access\n"; + << " used for read access\n"; } desc << indent << "$" << Common::Base::HEX4 << (ADDR_BASE | myCart.myWriteOffset) << " - $" << (ADDR_BASE | (myCart.myWriteOffset + myCart.myRamMask)) - << " used for write Access"; + << " used for write access"; if(myCart.myReadOffset > myCart.myWriteOffset) { desc << indent << "\n$" << Common::Base::HEX4 << (ADDR_BASE | myCart.myReadOffset) << " - $" << (ADDR_BASE | (myCart.myReadOffset + myCart.myRamMask)) - << " used for read Access"; + << " used for read access"; } return desc.str(); diff --git a/src/debugger/gui/CartMNetworkWidget.cxx b/src/debugger/gui/CartMNetworkWidget.cxx index 37d382a7e..e9cc68869 100644 --- a/src/debugger/gui/CartMNetworkWidget.cxx +++ b/src/debugger/gui/CartMNetworkWidget.cxx @@ -47,18 +47,18 @@ void CartridgeMNetworkWidget::initialize(GuiObject* boss, CartridgeMNetwork& car for(int i = 0; i < 4; ++i) VarList::push_back(items1, getSpotUpper(i)); - const int lwidth = _font.getStringWidth("Set slice for upper 256B "), - fwidth = _font.getStringWidth("3 - RAM ($FFEB)"); + const int lwidth = _font.getStringWidth("Set bank for upper 256B segment "), + fwidth = _font.getStringWidth("#3 - RAM ($FFEB)"); myLower2K = new PopUpWidget(boss, _font, xpos, ypos - 2, fwidth, myLineHeight, items0, - "Set slice for lower 2K ", lwidth, kLowerChanged); + "Set bank for lower 2K segment", lwidth, kLowerChanged); myLower2K->setTarget(this); addFocusWidget(myLower2K); ypos += myLower2K->getHeight() + 4; myUpper256B = new PopUpWidget(boss, _font, xpos, ypos - 2, fwidth, myLineHeight, items1, - "Set slice for upper 256B ", lwidth, kUpperChanged); + "Set bank for upper 256B segment ", lwidth, kUpperChanged); myUpper256B->setTarget(this); addFocusWidget(myUpper256B); } @@ -71,14 +71,14 @@ void CartridgeMNetworkWidget::saveOldState() for(uInt32 i = 0; i < internalRamSize(); ++i) myOldState.internalram.push_back(myCart.myRAM[i]); - myOldState.lowerBank = myCart.myCurrentSlice[0]; + myOldState.lowerBank = myCart.myCurrentBank[0]; myOldState.upperBank = myCart.myCurrentRAM; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeMNetworkWidget::loadConfig() { - myLower2K->setSelectedIndex(myCart.myCurrentSlice[0], myCart.myCurrentSlice[0] != myOldState.lowerBank); + myLower2K->setSelectedIndex(myCart.myCurrentBank[0], myCart.myCurrentBank[0] != myOldState.lowerBank); myUpper256B->setSelectedIndex(myCart.myCurrentRAM, myCart.myCurrentRAM != myOldState.upperBank); CartDebugWidget::loadConfig(); @@ -111,8 +111,8 @@ string CartridgeMNetworkWidget::bankState() { ostringstream& buf = buffer(); - buf << "Slices: " << std::dec - << getSpotLower(myCart.myCurrentSlice[0]) << " / " + buf << "Segments: " << std::dec + << getSpotLower(myCart.myCurrentBank[0]) << " / " << getSpotUpper(myCart.myCurrentRAM); return buf.str(); @@ -135,11 +135,11 @@ string CartridgeMNetworkWidget::internalRamDescription() { ostringstream desc; desc << "First 1K accessible via:\n" - << " $F000 - $F3FF used for Write Access\n" - << " $F400 - $F7FF used for Read Access\n" - << "256K of second 1K accessible via:\n" - << " $F800 - $F8FF used for Write Access\n" - << " $F900 - $F9FF used for Read Access"; + << " $F000 - $F3FF used for write access\n" + << " $F400 - $F7FF used for read access\n" + << "256 bytes of second 1K accessible via:\n" + << " $F800 - $F8FF used for write access\n" + << " $F900 - $F9FF used for read access"; return desc.str(); } diff --git a/src/debugger/gui/CartRamWidget.cxx b/src/debugger/gui/CartRamWidget.cxx index cfed3d3e5..10bfb5c23 100644 --- a/src/debugger/gui/CartRamWidget.cxx +++ b/src/debugger/gui/CartRamWidget.cxx @@ -47,7 +47,7 @@ CartRamWidget::CartRamWidget( int xpos = 2, ypos = 8; // Add RAM size - new StaticTextWidget(_boss, _font, xpos, ypos + 1, "RAM Size "); + new StaticTextWidget(_boss, _font, xpos, ypos + 1, "RAM size "); uInt32 ramsize = cartDebug.internalRamSize(); buf << ramsize << " bytes"; diff --git a/src/debugger/gui/DebuggerDialog.cxx b/src/debugger/gui/DebuggerDialog.cxx index 3143dbc10..ed98fa879 100644 --- a/src/debugger/gui/DebuggerDialog.cxx +++ b/src/debugger/gui/DebuggerDialog.cxx @@ -640,7 +640,7 @@ void DebuggerDialog::addRomArea() // The cartridge RAM tab if (myCartDebug->internalRamSize() > 0) { - tabID = myRomTab->addTab(" Cartridge RAM ", TabWidget::AUTO_WIDTH); + tabID = myRomTab->addTab(myCartDebug->tabLabel(), TabWidget::AUTO_WIDTH); myCartRam = new CartRamWidget(myRomTab, *myLFont, *myNFont, 2, 2, tabWidth - 1, tabHeight - myRomTab->getTabHeight() - 2, *myCartDebug); diff --git a/src/debugger/gui/RomWidget.cxx b/src/debugger/gui/RomWidget.cxx index e62fe0a17..3279ca5d9 100644 --- a/src/debugger/gui/RomWidget.cxx +++ b/src/debugger/gui/RomWidget.cxx @@ -41,12 +41,9 @@ RomWidget::RomWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& n // Show current bank state xpos = x; ypos = y + 7; - t = new StaticTextWidget(boss, lfont, xpos, ypos, - lfont.getStringWidth("Bank"), - lfont.getFontHeight(), - "Bank", TextAlign::Left); + t = new StaticTextWidget(boss, lfont, xpos, ypos, "Info "); - xpos += t->getWidth() + 5; + xpos += t->getRight(); myBank = new EditTextWidget(boss, nfont, xpos, ypos-2, _w - 2 - xpos, nfont.getLineHeight()); myBank->setEditable(false); diff --git a/src/emucore/Cart.hxx b/src/emucore/Cart.hxx index a7488f551..6fbf1a68d 100644 --- a/src/emucore/Cart.hxx +++ b/src/emucore/Cart.hxx @@ -189,7 +189,7 @@ class Cartridge : public Device cases where ROMs have 2K blocks in some preset area, the bankCount is the number of such blocks. Finally, in some esoteric schemes, the number of ways that the addressing can change (multiple ROM and - RAM slices at multiple access points) is so complicated that the + RAM segments at multiple access points) is so complicated that the cart will report having only one 'virtual' bank. */ virtual uInt16 romBankCount() const { return 1; } diff --git a/src/emucore/CartE0.cxx b/src/emucore/CartE0.cxx index d9c37d7e4..07afae5a2 100644 --- a/src/emucore/CartE0.cxx +++ b/src/emucore/CartE0.cxx @@ -29,7 +29,7 @@ CartridgeE0::CartridgeE0(const ByteBuffer& image, size_t size, // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeE0::reset() { - // Setup segments to some default slices + // Setup segments to some default banks if(randomStartBank()) { bank(mySystem->randGenerator().next() % 8, 0); diff --git a/src/emucore/CartE0.hxx b/src/emucore/CartE0.hxx index 7c1fe18e3..84c9ae667 100644 --- a/src/emucore/CartE0.hxx +++ b/src/emucore/CartE0.hxx @@ -29,10 +29,10 @@ class System; /** This is the cartridge class for Parker Brothers' 8K games. In this bankswitching scheme the 2600's 4K cartridge address space - is broken into four 1K segments. The desired 1K slice of the + is broken into four 1K segments. The desired 1K bank of the ROM is selected by accessing $1FE0 to $1FE7 for the first 1K. - $1FE8 to $1FEF selects the slice for the second 1K, and $1FF0 to - $1FF7 selects the slice for the third 1K. The last 1K segment + $1FE8 to $1FEF selects the bank for the second 1K, and $1FF0 to + $1FF7 selects the bank for the third 1K. The last 1K segment always points to the last 1K of the ROM image. Because of the complexity of this scheme, the cart reports having diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index 0bb6f54fb..d5ccf6591 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -48,7 +48,7 @@ void CartridgeEnhanced::install(System& system) createRomAccessArrays(mySize + (myRomOffset > 0 ? 0 : myRamSize)); - // Allocate array for the current bank segments slices + // Allocate array for the segment's current bank offset myCurrentSegOffset = make_unique(myBankSegs); // Allocate array for the RAM area diff --git a/src/emucore/CartMNetwork.cxx b/src/emucore/CartMNetwork.cxx index 984769b17..c6542b2b8 100644 --- a/src/emucore/CartMNetwork.cxx +++ b/src/emucore/CartMNetwork.cxx @@ -36,7 +36,7 @@ void CartridgeMNetwork::initialize(const ByteBuffer& image, size_t size) std::copy_n(image.get(), std::min(romSize(), size), myImage.get()); createRomAccessArrays(romSize() + myRAM.size()); - myRAMSlice = romBankCount() - 1; + myRAMBank = romBankCount() - 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -96,10 +96,10 @@ void CartridgeMNetwork::install(System& system) /*setAccess(0x1FE0 & ~System::PAGE_MASK, System::PAGE_SIZE, 0, nullptr, 0x1fc0, System::PA_NONE, 0x1fc0);*/ - // Setup the second segment to always point to the last ROM slice + // Setup the second segment to always point to the last ROM bank setAccess(0x1A00, 0x1FE0U & (~System::PAGE_MASK - 0x1A00), - myRAMSlice * BANK_SIZE, myImage.get(), myRAMSlice * BANK_SIZE, System::PageAccessType::READ, BANK_SIZE - 1); - myCurrentSlice[1] = myRAMSlice; + myRAMBank * BANK_SIZE, myImage.get(), myRAMBank * BANK_SIZE, System::PageAccessType::READ, BANK_SIZE - 1); + myCurrentBank[1] = myRAMBank; // Install some default banks for the RAM and first segment bankRAM(0); @@ -115,7 +115,7 @@ uInt8 CartridgeMNetwork::peek(uInt16 address) // Switch banks if necessary checkSwitchBank(address); - if((myCurrentSlice[0] == myRAMSlice) && (address < BANK_SIZE / 2)) + if((myCurrentBank[0] == myRAMBank) && (address < BANK_SIZE / 2)) { // Reading from the 1K write port @ $1000 triggers an unwanted write return peekRAM(myRAM[address & (BANK_SIZE / 2 - 1)], peekAddress); @@ -126,7 +126,7 @@ uInt8 CartridgeMNetwork::peek(uInt16 address) return peekRAM(myRAM[0x0400 + (myCurrentRAM << 8) + (address & 0x00FF)], peekAddress); } else - return myImage[(myCurrentSlice[address >> 11] << 11) + (address & (BANK_SIZE - 1))]; + return myImage[(myCurrentBank[address >> 11] << 11) + (address & (BANK_SIZE - 1))]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -139,9 +139,9 @@ bool CartridgeMNetwork::poke(uInt16 address, uInt8 value) checkSwitchBank(address); // All RAM writes are mapped here - if((myCurrentSlice[0] == myRAMSlice) && (address < BANK_SIZE / 2)) + if((myCurrentBank[0] == myRAMBank) && (address < BANK_SIZE / 2)) { - // RAM slices + // RAM banks if(!(address & 0x0400)) { pokeRAM(myRAM[address & (BANK_SIZE / 2 - 1)], pokeAddress, value); @@ -189,7 +189,7 @@ void CartridgeMNetwork::bankRAM(uInt16 bank) // Remember what bank we're in myCurrentRAM = bank; - uInt16 offset = bank << 8; // * RAM_SLICE_SIZE (256) + uInt16 offset = bank << 8; // * RAM_BANK_SIZE (256) // Setup the page access methods for the current bank // Set the page accessing method for the 256 bytes of RAM reading pages @@ -201,26 +201,26 @@ void CartridgeMNetwork::bankRAM(uInt16 bank) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeMNetwork::bank(uInt16 slice) +bool CartridgeMNetwork::bank(uInt16 bank) { if(bankLocked()) return false; // Remember what bank we're in - myCurrentSlice[0] = slice; + myCurrentBank[0] = bank; // Setup the page access methods for the current bank - if(slice != myRAMSlice) + if(bank != myRAMBank) { - uInt16 offset = slice << 11; // * BANK_SIZE (2048) + uInt16 offset = bank << 11; // * BANK_SIZE (2048) // Map ROM image into first segment setAccess(0x1000, BANK_SIZE, offset, myImage.get(), offset, System::PageAccessType::READ); } else { - // Set the page accessing method for the 1K slice of RAM writing pages + // Set the page accessing method for the 1K bank of RAM writing pages setAccess(0x1000, BANK_SIZE / 2, 0, myRAM.data(), romSize(), System::PageAccessType::WRITE); - // Set the page accessing method for the 1K slice of RAM reading pages + // Set the page accessing method for the 1K bank of RAM reading pages setAccess(0x1000 + BANK_SIZE / 2, BANK_SIZE / 2, 0, myRAM.data(), romSize(), System::PageAccessType::READ); } return myBankChanged = true; @@ -229,7 +229,7 @@ bool CartridgeMNetwork::bank(uInt16 slice) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeMNetwork::getBank(uInt16 address) const { - return myCurrentSlice[(address & 0xFFF) >> 11]; // 2K slices + return myCurrentBank[(address & 0xFFF) >> 11]; // 2K segments } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -239,7 +239,7 @@ bool CartridgeMNetwork::patch(uInt16 address, uInt8 value) if(address < 0x0800) { - if(myCurrentSlice[0] == myRAMSlice) + if(myCurrentBank[0] == myRAMBank) { // Normally, a write to the read port won't do anything // However, the patch command is special in that ignores such @@ -247,7 +247,7 @@ bool CartridgeMNetwork::patch(uInt16 address, uInt8 value) myRAM[address & 0x03FF] = value; } else - myImage[(myCurrentSlice[0] << 11) + (address & (BANK_SIZE-1))] = value; + myImage[(myCurrentBank[0] << 11) + (address & (BANK_SIZE-1))] = value; } else if(address < 0x0900) { @@ -257,7 +257,7 @@ bool CartridgeMNetwork::patch(uInt16 address, uInt8 value) myRAM[0x0400 + (myCurrentRAM << 8) + (address & 0x00FF)] = value; } else - myImage[(myCurrentSlice[address >> 11] << 11) + (address & (BANK_SIZE-1))] = value; + myImage[(myCurrentBank[address >> 11] << 11) + (address & (BANK_SIZE-1))] = value; return myBankChanged = true; } @@ -274,7 +274,7 @@ bool CartridgeMNetwork::save(Serializer& out) const { try { - out.putShortArray(myCurrentSlice.data(), myCurrentSlice.size()); + out.putShortArray(myCurrentBank.data(), myCurrentBank.size()); out.putShort(myCurrentRAM); out.putByteArray(myRAM.data(), myRAM.size()); } @@ -292,7 +292,7 @@ bool CartridgeMNetwork::load(Serializer& in) { try { - in.getShortArray(myCurrentSlice.data(), myCurrentSlice.size()); + in.getShortArray(myCurrentBank.data(), myCurrentBank.size()); myCurrentRAM = in.getShort(); in.getByteArray(myRAM.data(), myRAM.size()); } @@ -304,7 +304,7 @@ bool CartridgeMNetwork::load(Serializer& in) // Set up the previously used banks for the RAM and segment bankRAM(myCurrentRAM); - bank(myCurrentSlice[0]); + bank(myCurrentBank[0]); return true; } diff --git a/src/emucore/CartMNetwork.hxx b/src/emucore/CartMNetwork.hxx index dd9443390..95cd24b56 100644 --- a/src/emucore/CartMNetwork.hxx +++ b/src/emucore/CartMNetwork.hxx @@ -51,7 +51,7 @@ here by accessing 1FE8 to 1FEB. This cart reports having 8 banks; 1 for each of the possible 7 - slices in the lower 2K area, and the last for RAM in the lower + bank in the lower 2K area, and the last for RAM in the lower 2K area." There are 8K, 12K and 16K variations, with or without RAM. @@ -179,7 +179,7 @@ class CartridgeMNetwork : public Cartridge private: // Size of RAM in the cart static constexpr uInt32 RAM_SIZE = 0x800; // 1K + 4 * 256B = 2K - // Number of slices with 4K address space + // Number of segment within the 4K address space static constexpr uInt32 NUM_SEGMENTS = 2; /** @@ -198,8 +198,6 @@ class CartridgeMNetwork : public Cartridge private: // Pointer to a dynamically allocated ROM image of the cartridge ByteBuffer myImage; - // The 16K ROM image of the cartridge (works for E78K too) - //uInt8 myImage[BANK_SIZE * 8]; // Size of the ROM image size_t mySize{0}; @@ -207,14 +205,14 @@ class CartridgeMNetwork : public Cartridge // The 2K of RAM std::array myRAM; - // Indicates which slice is in the segment - std::array myCurrentSlice; + // Indicates which bank is in the segment + std::array myCurrentBank; // Indicates which 256 byte bank of RAM is being used uInt16 myCurrentRAM{0}; - // The number of the RAM slice (== bankCount() - 1) - uInt32 myRAMSlice{0}; + // The number of the RAM bank (== bankCount() - 1) + uInt32 myRAMBank{0}; private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartWD.cxx b/src/emucore/CartWD.cxx index ff72a2b38..11ebc653e 100644 --- a/src/emucore/CartWD.cxx +++ b/src/emucore/CartWD.cxx @@ -28,7 +28,7 @@ CartridgeWD::CartridgeWD(const ByteBuffer& image, size_t size, // Copy the ROM image into my buffer if (mySize == 8_KB + 3) { - // swap slices 2 & 3 of bad dump and correct size + // 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); std::copy_n(image.get() + 1_KB * 2, 1_KB * 1, myImage.get() + 1_KB * 3); mySize = 8_KB; diff --git a/src/emucore/CartWD.hxx b/src/emucore/CartWD.hxx index 6feb6be63..398571a52 100644 --- a/src/emucore/CartWD.hxx +++ b/src/emucore/CartWD.hxx @@ -30,8 +30,8 @@ class System; This is the cartridge class for a "Wickstead Design" prototype cart. The ROM has 64 bytes of RAM. In this bankswitching scheme the 2600's 4K cartridge address space - is broken into four 1K segments. The desired arrangement of 1K slices - is selected by accessing $30 - $3F of TIA address space. The slices + is broken into four 1K segments. The desired arrangement of 1K banks + is selected by accessing $30 - $3F of TIA address space. The banks are mapped into all 4 segments at once as follows: $0030, $0038: 0,0,1,3 From 8935248a859e6bd1911314ac606cf97621f9bc1b Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sat, 25 Apr 2020 14:03:24 -0230 Subject: [PATCH 154/377] Synchronize 6.1.2 changelog to master. --- Changes.txt | 12 +++++++++++- debian/changelog | 7 +++++++ src/unix/stella.spec | 5 ++++- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Changes.txt b/Changes.txt index a12cef9d1..ae41de878 100644 --- a/Changes.txt +++ b/Changes.txt @@ -12,7 +12,7 @@ Release History =========================================================================== -6.1 to 6.2: (??? ??, 2020) +6.1.2 to 6.2: (??? ??, 2020) * Added that paddle centering and sensitivity can be adjusted (TODO: Doc) @@ -35,6 +35,16 @@ -Have fun! +6.1.1 to 6.1.2: (April 25, 2020) + + * Fixed bug with remapped events not being reloaded in certain cases. + + * Fixed bug in debugger for 3E scheme when displaying active RAM bank. + + * Fixed bug in "Dragon Defender" ROM being misconfigured for Mindlink + controller. + + 6.1 to 6.1.1: (April 4, 2020) * Fixed crash in 3E bankswitching scheme when writing to ROM addresses. diff --git a/debian/changelog b/debian/changelog index af319a670..81ab67bce 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +stella (6.1.2-1) stable; urgency=high + + * Version 6.1.2 release + + -- Stephen Anthony Sat, 25 Apr 2020 17:09:59 -0230 + + stella (6.1.1-1) stable; urgency=high * Version 6.1.1 release diff --git a/src/unix/stella.spec b/src/unix/stella.spec index a4236c38f..796217ea6 100644 --- a/src/unix/stella.spec +++ b/src/unix/stella.spec @@ -1,5 +1,5 @@ %define name stella -%define version 6.1 +%define version 6.1.2 %define rel 1 %define enable_sound 1 @@ -100,6 +100,9 @@ rm -rf $RPM_BUILD_DIR/%{name}-%{version} %_datadir/icons/large/%{name}.png %changelog +* Sat Apr 25 2020 Stephen Anthony 6.1.2-1 +- Version 6.1.2 release + * Sat Apr 04 2020 Stephen Anthony 6.1.1-1 - Version 6.1.1 release From 5d152e2306e39207d8ddbf82ea0d07d72d349d2f Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Tue, 28 Apr 2020 15:01:09 -0230 Subject: [PATCH 155/377] Automaticall load a properties file with the same name as the ROM from the ROM directory. Still TODO is support loading if the properties file is in a ZIP file. --- src/emucore/OSystem.cxx | 32 ++++++++++++++++++++++++++++---- src/emucore/PropsSet.cxx | 24 ++---------------------- src/emucore/PropsSet.hxx | 17 +++-------------- 3 files changed, 33 insertions(+), 40 deletions(-) diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index 832b1ce35..bbaa72aa5 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -646,11 +646,35 @@ ByteBuffer OSystem::openROM(const FilesystemNode& rom, string& md5, size_t& size if(md5 == "") md5 = MD5::hash(image, size); - // Some games may not have a name, since there may not - // be an entry in stella.pro. In that case, we use the rom name - // and reinsert the properties object + // Handle ROM properties, do some error checking + // Only add to the database when necessary + bool toInsert = false; + + // First, does this ROM have a per-ROM properties entry? + // If so, load it into the database + FilesystemNode propsNode(rom.getPathWithExt(".pro")); + if(propsNode.exists() && propsNode.isFile()) + { + Logger::info("Loading per-ROM properties: " + propsNode.getShortPath()); + myPropSet->load(propsNode.getPath(), false); + } + + // Next, make sure we have a valid md5 and name Properties props; - myPropSet->getMD5WithInsert(rom, md5, props); + if(!myPropSet->getMD5(md5, props)) + { + props.set(PropType::Cart_MD5, md5); + toInsert = true; + } + if(toInsert || props.get(PropType::Cart_Name) == EmptyString) + { + props.set(PropType::Cart_Name, rom.getNameWithExt("")); + toInsert = true; + } + + // Finally, insert properties if any info was missing + if(toInsert) + myPropSet->insert(props, false); return image; } diff --git a/src/emucore/PropsSet.cxx b/src/emucore/PropsSet.cxx index 5375a269e..a13a9c759 100644 --- a/src/emucore/PropsSet.cxx +++ b/src/emucore/PropsSet.cxx @@ -24,13 +24,13 @@ #include "PropsSet.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PropertiesSet::load(const string& filename) +void PropertiesSet::load(const string& filename, bool save) { ifstream in(filename); Properties prop; while(in >> prop) - insert(prop); + insert(prop, save); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -117,26 +117,6 @@ bool PropertiesSet::getMD5(const string& md5, Properties& properties, return found; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PropertiesSet::getMD5WithInsert(const FilesystemNode& rom, - const string& md5, Properties& properties) -{ - bool toInsert = false; - - if(!getMD5(md5, properties)) - { - properties.set(PropType::Cart_MD5, md5); - toInsert = true; - } - if(toInsert || properties.get(PropType::Cart_Name) == EmptyString) - { - properties.set(PropType::Cart_Name, rom.getNameWithExt("")); - toInsert = true; - } - if(toInsert) - insert(properties, false); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PropertiesSet::insert(const Properties& properties, bool save) { diff --git a/src/emucore/PropsSet.hxx b/src/emucore/PropsSet.hxx index 684137817..71924749a 100644 --- a/src/emucore/PropsSet.hxx +++ b/src/emucore/PropsSet.hxx @@ -49,8 +49,10 @@ class PropertiesSet searchable list. @param filename Full pathname of input file to use + @param save Indicates whether the properties should be saved + when the program exits */ - void load(const string& filename); + void load(const string& filename, bool save = true); /** Save properties to the specified file. @@ -78,19 +80,6 @@ class PropertiesSet bool getMD5(const string& md5, Properties& properties, bool useDefaults = false) const; - /** - Get the property from the set with the given MD5, at the same time - checking if it exists. If it doesn't, insert a temporary copy into - the set. - - @param rom The ROM file used to calculate the MD5 - @param md5 The md5 of the property to get - @param properties The properties with the given MD5, or the default - properties if not found - */ - void getMD5WithInsert(const FilesystemNode& rom, const string& md5, - Properties& properties); - /** Insert the properties into the set. If a duplicate is inserted the old properties are overwritten with the new ones. From 2b40cf0dc2ee300b9b5a30e027999112269ccd79 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Tue, 28 Apr 2020 15:05:16 -0230 Subject: [PATCH 156/377] Use getPathWithExt() method correctly. --- src/debugger/CartDebug.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index a52732cfe..c929efa2a 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -728,7 +728,7 @@ string CartDebug::loadListFile() if(myListFile == "") { - FilesystemNode lst(myOSystem.romFile().getPathWithExt("") + ".lst"); + FilesystemNode lst(myOSystem.romFile().getPathWithExt(".lst")); if(lst.isFile() && lst.isReadable()) myListFile = lst.getPath(); else @@ -788,7 +788,7 @@ string CartDebug::loadSymbolFile() if(mySymbolFile == "") { - FilesystemNode sym(myOSystem.romFile().getPathWithExt("") + ".sym"); + FilesystemNode sym(myOSystem.romFile().getPathWithExt(".sym")); if(sym.isFile() && sym.isReadable()) mySymbolFile = sym.getPath(); else @@ -848,7 +848,7 @@ string CartDebug::loadConfigFile() if(myCfgFile == "") { - FilesystemNode romNode(myOSystem.romFile().getPathWithExt("") + ".cfg"); + FilesystemNode romNode(myOSystem.romFile().getPathWithExt(".cfg")); FilesystemNode cfg(myOSystem.cfgDir() + romNode.getName()); if(cfg.isFile() && cfg.isReadable()) myCfgFile = cfg.getPath(); @@ -970,7 +970,7 @@ string CartDebug::saveConfigFile() if(myCfgFile == "") { - FilesystemNode romNode(myOSystem.romFile().getPathWithExt("") + ".cfg"); + FilesystemNode romNode(myOSystem.romFile().getPathWithExt(".cfg")); FilesystemNode cfg(myOSystem.cfgDir() + romNode.getName()); if(cfg.getParent().isWritable()) myCfgFile = cfg.getPath(); From a8789f9a6d0912d948ee9deac5a9ab28d06c2568 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 29 Apr 2020 09:23:55 +0200 Subject: [PATCH 157/377] fix #623 (Rom info too large) --- src/gui/LauncherDialog.hxx | 6 +++--- src/gui/RomInfoWidget.cxx | 9 +++++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/gui/LauncherDialog.hxx b/src/gui/LauncherDialog.hxx index dc1058356..bfa0cecba 100644 --- a/src/gui/LauncherDialog.hxx +++ b/src/gui/LauncherDialog.hxx @@ -94,9 +94,9 @@ class LauncherDialog : public Dialog private: static constexpr int MIN_LAUNCHER_CHARS = 24; - static constexpr int MIN_ROMINFO_CHARS = 24; + static constexpr int MIN_ROMINFO_CHARS = 30; static constexpr int MIN_ROMINFO_ROWS = 7; // full lines - static constexpr int MIN_ROMINFO_LINES = 2; // extra lines + static constexpr int MIN_ROMINFO_LINES = 4; // extra lines void center() override { positionAt(0); } void handleKeyDown(StellaKey key, StellaMod mod, bool repeated) override; @@ -132,7 +132,7 @@ class LauncherDialog : public Dialog unique_ptr myROMInfoFont; ButtonWidget* myStartButton{nullptr}; - ButtonWidget* myPrevDirButton{nullptr}; + ButtonWidget* myPrevDirButton{nullptr}; ButtonWidget* myOptionsButton{nullptr}; ButtonWidget* myQuitButton{nullptr}; diff --git a/src/gui/RomInfoWidget.cxx b/src/gui/RomInfoWidget.cxx index 0df0610d3..16a6790cb 100644 --- a/src/gui/RomInfoWidget.cxx +++ b/src/gui/RomInfoWidget.cxx @@ -203,11 +203,16 @@ void RomInfoWidget::drawWidget(bool hilite) } int xpos = _x + 8, ypos = _y + yoff + 5; - for(const auto& info: myRomInfo) + for(const auto& info : myRomInfo) { + + + int lines = s.drawString(_font, info, xpos, ypos, _w - 16, _font.getFontHeight() * 3, onTop ? _textcolor : _shadowcolor); - if(ypos >= _h) break; ypos += _font.getLineHeight() + (lines - 1) * _font.getFontHeight(); + // assume 2 lines for next entry + if(ypos >= _h + _y - _font.getLineHeight() - _font.getFontHeight()) + break; } } From bb7888d8ab0e53ba3c2b852f9297832ceee3d318 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 29 Apr 2020 11:00:18 +0200 Subject: [PATCH 158/377] improved Rom info size check --- src/debugger/gui/RomListWidget.cxx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/debugger/gui/RomListWidget.cxx b/src/debugger/gui/RomListWidget.cxx index b4af0daf7..64ca2df9d 100644 --- a/src/debugger/gui/RomListWidget.cxx +++ b/src/debugger/gui/RomListWidget.cxx @@ -42,11 +42,12 @@ RomListWidget::RomListWidget(GuiObject* boss, const GUI::Font& lfont, _rows = h / _fontHeight; // Set real dimensions - _w = w - kScrollBarWidth; + _w = w - ScrollBarWidget::scrollBarWidth(_font); _h = h + 2; // Create scrollbar and attach to the list - myScrollBar = new ScrollBarWidget(boss, lfont, _x + _w, _y, kScrollBarWidth, _h); + myScrollBar = new ScrollBarWidget(boss, lfont, _x + _w, _y, + ScrollBarWidget::scrollBarWidth(_font), _h); myScrollBar->setTarget(this); // Add settings menu @@ -65,7 +66,7 @@ RomListWidget::RomListWidget(GuiObject* boss, const GUI::Font& lfont, // rowheight is determined by largest item on a line, // possibly meaning that number of rows will change - _fontHeight = std::max(_fontHeight, CheckboxWidget::boxSize()); + _fontHeight = std::max(_fontHeight, CheckboxWidget::boxSize(_font)); _rows = h / _fontHeight; // Create a CheckboxWidget for each row in the list @@ -465,7 +466,7 @@ void RomListWidget::drawWidget(bool hilite) // Draw a thin frame around the list and to separate columns s.frameRect(_x, _y, _w + 1, _h, hilite ? kWidColorHi : kColor); - s.vLine(_x + CheckboxWidget::boxSize() + 5, _y, _y + _h - 1, kColor); + s.vLine(_x + CheckboxWidget::boxSize(_font) + 5, _y, _y + _h - 1, kColor); // Draw the list items int cycleCountW = _fontWidth * 8, @@ -476,7 +477,7 @@ void RomListWidget::drawWidget(bool hilite) if(actualWidth < codeDisasmW) codeDisasmW = actualWidth; - xpos = _x + CheckboxWidget::boxSize() + 10; ypos = _y + 2; + xpos = _x + CheckboxWidget::boxSize(_font) + 10; ypos = _y + 2; for (i = 0, pos = _currentPos; i < _rows && pos < len; i++, pos++, ypos += _fontHeight) { ColorId bytesColor = textColor; @@ -566,7 +567,7 @@ void RomListWidget::drawWidget(bool hilite) Common::Rect RomListWidget::getLineRect() const { const int yoffset = std::max(0, (_selectedItem - _currentPos) * _fontHeight), - xoffset = CheckboxWidget::boxSize() + 10; + xoffset = CheckboxWidget::boxSize(_font) + 10; return Common::Rect(2 + xoffset, 1 + yoffset, _w - (xoffset - 15), _fontHeight + yoffset); From 3c8118a9479c4be8197723e568777d85053010e2 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 29 Apr 2020 14:25:54 +0200 Subject: [PATCH 159/377] Part 1 of the changes for #600 (UI fonts) --- Changes.txt | 2 + src/cheat/CheatCodeDialog.cxx | 32 ++-- src/debugger/gui/CartDebugWidget.cxx | 2 +- src/debugger/gui/CartRamWidget.cxx | 2 +- src/debugger/gui/DataGridWidget.cxx | 5 +- src/debugger/gui/PromptWidget.cxx | 9 +- src/emucore/FrameBuffer.cxx | 141 ++++++++++------- src/emucore/FrameBuffer.hxx | 15 +- src/emucore/Settings.cxx | 6 + src/gui/AboutDialog.cxx | 27 ++-- src/gui/AudioDialog.cxx | 12 +- src/gui/CheckListWidget.cxx | 6 +- src/gui/CommandDialog.cxx | 20 ++- src/gui/DeveloperDialog.cxx | 149 +++++++++++------- src/gui/Dialog.cxx | 31 ++-- src/gui/EventMappingWidget.cxx | 26 ++-- src/gui/GameInfoDialog.cxx | 55 +++---- src/gui/HelpDialog.cxx | 34 +++-- src/gui/InputDialog.cxx | 32 ++-- src/gui/LauncherDialog.cxx | 8 +- src/gui/ListWidget.cxx | 7 +- src/gui/LoggerDialog.cxx | 21 ++- src/gui/OptionsDialog.cxx | 24 ++- src/gui/OptionsDialog.hxx | 1 + src/gui/PopUpWidget.cxx | 17 ++- src/gui/RadioButtonWidget.cxx | 221 ++++++++++++++++++++++++--- src/gui/RadioButtonWidget.hxx | 5 + src/gui/RomAuditDialog.cxx | 24 ++- src/gui/RomInfoWidget.cxx | 17 ++- src/gui/ScrollBarWidget.cxx | 143 +++++++++++------ src/gui/ScrollBarWidget.hxx | 15 +- src/gui/SnapshotDialog.cxx | 30 ++-- src/gui/UIDialog.cxx | 107 ++++++++----- src/gui/UIDialog.hxx | 1 + src/gui/VideoDialog.cxx | 36 +++-- src/gui/Widget.cxx | 54 +++++-- src/gui/Widget.hxx | 15 +- 37 files changed, 922 insertions(+), 430 deletions(-) diff --git a/Changes.txt b/Changes.txt index ae41de878..2c4118cd7 100644 --- a/Changes.txt +++ b/Changes.txt @@ -24,6 +24,8 @@ * Added 'Turbo' mode, runs the game as fast as the computer allows. + * Added selectable dialog fonts (TODO: Doc) + * Added option which lets default ROM path follow launcher navigation (TODO: Doc) * Added displaying last write address in the debugger. diff --git a/src/cheat/CheatCodeDialog.cxx b/src/cheat/CheatCodeDialog.cxx index 780fbea2f..5ce380e0b 100644 --- a/src/cheat/CheatCodeDialog.cxx +++ b/src/cheat/CheatCodeDialog.cxx @@ -35,46 +35,50 @@ CheatCodeDialog::CheatCodeDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font) : Dialog(osystem, parent, font, "Cheat codes") { - const int lineHeight = font.getLineHeight(), - fontWidth = font.getMaxCharWidth(), - buttonWidth = font.getStringWidth("Defaults") + 20, - buttonHeight = font.getLineHeight() + 4; - const int HBORDER = 10; - const int VBORDER = 10 + _th; + const int lineHeight = font.getLineHeight(), + fontHeight = font.getFontHeight(), + fontWidth = font.getMaxCharWidth(), + buttonWidth = font.getStringWidth("One shot ") + fontWidth * 2.5, + buttonHeight = font.getLineHeight() * 1.25; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = fontWidth * 2; + const int VGAP = fontHeight / 4; + int xpos, ypos; WidgetArray wid; ButtonWidget* b; // Set real dimensions _w = 45 * fontWidth + HBORDER * 2; - _h = 11 * (lineHeight + 4) + VBORDER; + _h = _th + 11 * (lineHeight + 4) + VBORDER * 2; // List of cheats, with checkboxes to enable/disable - xpos = HBORDER; ypos = VBORDER; + xpos = HBORDER; ypos = _th + VBORDER; myCheatList = - new CheckListWidget(this, font, xpos, ypos, _w - buttonWidth - HBORDER * 2 - 8, - _h - 2*buttonHeight - VBORDER); + new CheckListWidget(this, font, xpos, ypos, _w - buttonWidth - HBORDER * 2 - fontWidth, + _h - _th - buttonHeight - VBORDER * 3); myCheatList->setEditable(false); wid.push_back(myCheatList); - xpos += myCheatList->getWidth() + 8; ypos = VBORDER; + xpos += myCheatList->getWidth() + fontWidth; ypos = _th + VBORDER; b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Add" + ELLIPSIS, kAddCheatCmd); wid.push_back(b); - ypos += lineHeight + 8; + ypos += lineHeight + VGAP * 2; myEditButton = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Edit" + ELLIPSIS, kEditCheatCmd); wid.push_back(myEditButton); - ypos += lineHeight + 8; + ypos += lineHeight + VGAP * 2; myRemoveButton = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Remove", kRemCheatCmd); wid.push_back(myRemoveButton); - ypos += lineHeight + 8 * 3; + ypos += lineHeight + VGAP * 2 * 3; b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "One shot" + ELLIPSIS, kAddOneShotCmd); diff --git a/src/debugger/gui/CartDebugWidget.cxx b/src/debugger/gui/CartDebugWidget.cxx index 9e164f4a6..c7bfe5085 100644 --- a/src/debugger/gui/CartDebugWidget.cxx +++ b/src/debugger/gui/CartDebugWidget.cxx @@ -65,7 +65,7 @@ int CartDebugWidget::addBaseInformation(size_t bytes, const string& manufacturer w->setEditable(false); y += myLineHeight + 4; - StringParser bs(desc, (fwidth - kScrollBarWidth) / myFontWidth - 4); + StringParser bs(desc, (fwidth - ScrollBarWidget::scrollBarWidth(_font)) / myFontWidth - 4); const StringList& sl = bs.stringList(); uInt32 lines = uInt32(sl.size()); if(lines < 3) lines = 3; diff --git a/src/debugger/gui/CartRamWidget.cxx b/src/debugger/gui/CartRamWidget.cxx index 1dfcfdaac..be2eb984b 100644 --- a/src/debugger/gui/CartRamWidget.cxx +++ b/src/debugger/gui/CartRamWidget.cxx @@ -62,7 +62,7 @@ CartRamWidget::CartRamWidget( // Add Description const string& desc = cartDebug.internalRamDescription(); const uInt16 maxlines = 6; - StringParser bs(desc, (fwidth - kScrollBarWidth) / myFontWidth); + StringParser bs(desc, (fwidth - ScrollBarWidget::scrollBarWidth(_font)) / myFontWidth); const StringList& sl = bs.stringList(); uInt32 lines = uInt32(sl.size()); if(lines < 3) lines = 3; diff --git a/src/debugger/gui/DataGridWidget.cxx b/src/debugger/gui/DataGridWidget.cxx index 9d9d25886..6b663609c 100644 --- a/src/debugger/gui/DataGridWidget.cxx +++ b/src/debugger/gui/DataGridWidget.cxx @@ -67,7 +67,8 @@ DataGridWidget::DataGridWidget(GuiObject* boss, const GUI::Font& font, // Add a scrollbar if necessary if(useScrollbar) { - _scrollBar = new ScrollBarWidget(boss, font, _x + _w, _y, kScrollBarWidth, _h); + _scrollBar = new ScrollBarWidget(boss, font, _x + _w, _y, + ScrollBarWidget::scrollBarWidth(_font), _h); _scrollBar->setTarget(this); _scrollBar->_numEntries = 1; _scrollBar->_currentPos = 0; @@ -675,7 +676,7 @@ Common::Rect DataGridWidget::getEditRect() const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int DataGridWidget::getWidth() const { - return _w + (_scrollBar ? kScrollBarWidth : 0); + return _w + (_scrollBar ? ScrollBarWidget::scrollBarWidth(_font) : 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/debugger/gui/PromptWidget.cxx b/src/debugger/gui/PromptWidget.cxx index a7910f8e8..b803adc17 100644 --- a/src/debugger/gui/PromptWidget.cxx +++ b/src/debugger/gui/PromptWidget.cxx @@ -33,7 +33,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PromptWidget::PromptWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h) - : Widget(boss, font, x, y, w - kScrollBarWidth, h), + : Widget(boss, font, x, y, w - ScrollBarWidget::scrollBarWidth(font), h), CommandSender(boss), _historySize(0), _historyIndex(0), @@ -53,12 +53,13 @@ PromptWidget::PromptWidget(GuiObject* boss, const GUI::Font& font, _kConsoleLineHeight = _kConsoleCharHeight + 2; // Calculate depending values - _lineWidth = (_w - kScrollBarWidth - 2) / _kConsoleCharWidth; + _lineWidth = (_w - ScrollBarWidget::scrollBarWidth(_font) - 2) / _kConsoleCharWidth; _linesPerPage = (_h - 2) / _kConsoleLineHeight; _linesInBuffer = kBufferSize / _lineWidth; // Add scrollbar - _scrollBar = new ScrollBarWidget(boss, font, _x + _w, _y, kScrollBarWidth, _h); + _scrollBar = new ScrollBarWidget(boss, font, _x + _w, _y, + ScrollBarWidget::scrollBarWidth(_font), _h); _scrollBar->setTarget(this); // Init colors @@ -546,7 +547,7 @@ void PromptWidget::loadConfig() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int PromptWidget::getWidth() const { - return _w + kScrollBarWidth; + return _w + ScrollBarWidget::scrollBarWidth(_font); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 3c64c5d8f..8e2a0b14d 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -36,6 +36,7 @@ #ifdef GUI_SUPPORT #include "Font.hxx" #include "StellaFont.hxx" + #include "ConsoleMediumFont.hxx" #include "ConsoleMediumBFont.hxx" #include "StellaMediumFont.hxx" #include "StellaLargeFont.hxx" @@ -97,56 +98,7 @@ bool FrameBuffer::initialize() } #ifdef GUI_SUPPORT - //////////////////////////////////////////////////////////////////// - // Create fonts to draw text - // NOTE: the logic determining appropriate font sizes is done here, - // so that the UI classes can just use the font they expect, - // and not worry about it - // This logic should also take into account the size of the - // framebuffer, and try to be intelligent about font sizes - // We can probably add ifdefs to take care of corner cases, - // but that means we've failed to abstract it enough ... - //////////////////////////////////////////////////////////////////// - - // This font is used in a variety of situations when a really small - // font is needed; we let the specific widget/dialog decide when to - // use it - mySmallFont = make_unique(GUI::stellaDesc); // 6x10 - - // The general font used in all UI elements - // This is determined by the size of the framebuffer - if(myOSystem.settings().getBool("minimal_ui")) - { - myFont = make_unique(GUI::stella12x24tDesc); // 12x24 - // The info font used in all UI elements - // This is determined by the size of the framebuffer - myInfoFont = make_unique(GUI::stellaLargeDesc); // 10x20 - } - else - { - myFont = make_unique(GUI::stellaMediumDesc); // 9x18 - // The info font used in all UI elements - // This is determined by the size of the framebuffer - myInfoFont = make_unique(GUI::consoleDesc); // 8x13 - } - - - // The font used by the ROM launcher - const string& lf = myOSystem.settings().getString("launcherfont"); - if(lf == "small") - myLauncherFont = make_unique(GUI::consoleBDesc); // 8x13 - else if(lf == "low_medium") - myLauncherFont = make_unique(GUI::consoleMediumBDesc); // 9x15 - else if(lf == "medium") - myLauncherFont = make_unique(GUI::stellaMediumDesc); // 9x18 - else if(lf == "large" || lf == "large10") - myLauncherFont = make_unique(GUI::stellaLargeDesc); // 10x20 - else if(lf == "large12") - myLauncherFont = make_unique(GUI::stella12x24tDesc); // 12x24 - else if(lf == "large14") - myLauncherFont = make_unique(GUI::stella14x28tDesc); // 14x28 - else // "large16" - myLauncherFont = make_unique(GUI::stella16x32tDesc); // 16x32 + setupFonts(); #endif // Determine possible TIA windowed zoom levels @@ -164,6 +116,93 @@ bool FrameBuffer::initialize() return true; } +#ifdef GUI_SUPPORT +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FrameBuffer::setupFonts() +{ + //////////////////////////////////////////////////////////////////// + // Create fonts to draw text + // NOTE: the logic determining appropriate font sizes is done here, + // so that the UI classes can just use the font they expect, + // and not worry about it + // This logic should also take into account the size of the + // framebuffer, and try to be intelligent about font sizes + // We can probably add ifdefs to take care of corner cases, + // but that means we've failed to abstract it enough ... + //////////////////////////////////////////////////////////////////// + + // This font is used in a variety of situations when a really small + // font is needed; we let the specific widget/dialog decide when to + // use it + mySmallFont = make_unique(GUI::stellaDesc); // 6x10 + + if(myOSystem.settings().getBool("minimal_ui")) + { + // The general font used in all UI elements + myFont = make_unique(GUI::stella12x24tDesc); // 12x24 + // The info font used in all UI elements + myInfoFont = make_unique(GUI::stellaLargeDesc); // 10x20 + } + else + { + const int NUM_FONTS = 7; + FontDesc FONT_DESC[NUM_FONTS] = {GUI::consoleDesc, GUI::consoleMediumDesc, GUI::stellaMediumDesc, + GUI::stellaLargeDesc, GUI::stella12x24tDesc, GUI::stella14x28tDesc, GUI::stella16x32tDesc}; + const string& dialogFont = myOSystem.settings().getString("dialogfont"); + FontDesc fd = getFontDesc(dialogFont); + + // The general font used in all UI elements + myFont = make_unique(fd); // default: 9x18 + // The info font used in all UI elements, + // automatically determined aiming for 1 / 1.4 (~= 18 / 13) size + int fontIdx = 0; + for(int i = 0; i < NUM_FONTS; ++i) + { + if(fd.height <= FONT_DESC[i].height * 1.4) + { + fontIdx = i; + break; + } + } + myInfoFont = make_unique(FONT_DESC[fontIdx]); // default 8x13 + + // Determine minimal zoom level based on the default font + // So what fits with default font should fit for any font. + // However, we have to make sure all Dialogs are sized using the fontsize. + int zoom_h = (fd.height * 4 * 2) / GUI::stellaMediumDesc.height; + int zoom_w = (fd.maxwidth * 4 * 2) / GUI::stellaMediumDesc.maxwidth; + int zoom = std::max(zoom_w, zoom_h); + myTIAMinZoom = std::max(2 * 4, zoom) / 4.F; // round to 25% steps + } + + + // The font used by the ROM launcher + const string& lf = myOSystem.settings().getString("launcherfont"); + + + myLauncherFont = make_unique(getFontDesc(lf)); // 8x13 +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +FontDesc FrameBuffer::getFontDesc(const string& name) const +{ + if(name == "small") + return GUI::consoleBDesc; // 8x13 + else if(name == "low_medium") + return GUI::consoleMediumBDesc; // 9x15 + else if(name == "medium") + return GUI::stellaMediumDesc; // 9x18 + else if(name == "large" || name == "large10") + return GUI::stellaLargeDesc; // 10x20 + else if(name == "large12") + return GUI::stella12x24tDesc; // 12x24 + else if(name == "large14") + return GUI::stella14x28tDesc; // 14x28 + else // "large16" + return GUI::stella16x32tDesc; // 16x32 +} +#endif + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBInitStatus FrameBuffer::createDisplay(const string& title, uInt32 width, uInt32 height, @@ -965,7 +1004,7 @@ void FrameBuffer::setAvailableVidModes(uInt32 baseWidth, uInt32 baseHeight) if(tiaMode) { // TIA windowed modes - uInt32 minZoom = supportedTIAMinZoom(); + float minZoom = supportedTIAMinZoom(); myTIAMaxZoom = maxZoomForScreen(baseWidth, baseHeight, myAbsDesktopSize.w, myAbsDesktopSize.h); // Determine all zoom levels diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index 67628ee84..1e61b39b4 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -35,6 +35,7 @@ namespace GUI { #include "TIAConstants.hxx" #include "FrameBufferConstants.hxx" #include "EventHandlerConstants.hxx" +#include "Font.hxx" #include "bspf.hxx" /** @@ -223,7 +224,7 @@ class FrameBuffer Get the minimum/maximum supported TIA zoom level (windowed mode) for the framebuffer. */ - float supportedTIAMinZoom() const { return 2 * hidpiScaleFactor(); } + float supportedTIAMinZoom() const { return myTIAMinZoom * hidpiScaleFactor(); } float supportedTIAMaxZoom() const { return myTIAMaxZoom; } /** @@ -480,6 +481,16 @@ class FrameBuffer */ void resetSurfaces(); + #ifdef GUI_SUPPORT + /** + Setup the UI fonts + */ + void setupFonts(); + + + FontDesc getFontDesc(const string& name) const; + #endif + /** Calculate the maximum level by which the base window can be zoomed and still fit in the given screen dimensions. @@ -619,6 +630,8 @@ class FrameBuffer VideoModeList myWindowedModeList; vector myFullscreenModeLists; + // Minimum TIA zoom level that can be used for this framebuffer + float myTIAMinZoom{2.F}; // Maximum TIA zoom level that can be used for this framebuffer float myTIAMaxZoom{1.F}; diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index 50e45cd06..599c8badf 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -146,6 +146,7 @@ Settings::Settings() setPermanent("ctrldelay", "400"); setPermanent("ctrlrate", "20"); setPermanent("basic_settings", false); + setPermanent("dialogfont", "medium"); setPermanent("dialogpos", 0); setPermanent("confirmexit", false); @@ -510,6 +511,11 @@ void Settings::usage() const << " -uipalette \n" << " -hidpi <0|1> Enable HiDPI mode\n" + << " -dialogfont \n" << " -dialogpos <0..4> Display all dialogs at given positions\n" << " -confirmexit <0|1> Display a confirm dialog when exiting emulation\n" << " -listdelay Time to wait between keypresses in list widgets\n" diff --git a/src/gui/AboutDialog.cxx b/src/gui/AboutDialog.cxx index 168520138..05db4b695 100644 --- a/src/gui/AboutDialog.cxx +++ b/src/gui/AboutDialog.cxx @@ -28,44 +28,49 @@ AboutDialog::AboutDialog(OSystem& osystem, DialogContainer& parent, : Dialog(osystem, parent, font, "About Stella") { const int lineHeight = font.getLineHeight(), - fontWidth = font.getMaxCharWidth(), - fontHeight = font.getFontHeight(), - buttonWidth = font.getStringWidth("Defaults") + 20, - buttonHeight = font.getLineHeight() + 4; + fontWidth = font.getMaxCharWidth(), + fontHeight = font.getFontHeight(), + buttonWidth = font.getStringWidth("Previous") + fontWidth * 2.5, + buttonHeight = font.getLineHeight() * 1.25; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = fontWidth * 2; + const int VGAP = fontHeight / 4; + int xpos, ypos; WidgetArray wid; // Set real dimensions - _w = 55 * fontWidth + 8; - _h = 15 * lineHeight + 20 + _th; + _w = 55 * fontWidth + HBORDER * 2; + _h = _th + 14 * lineHeight + VGAP * 3 + buttonHeight + VBORDER * 2; // Add Previous, Next and Close buttons - xpos = 10; ypos = _h - buttonHeight - 10; + xpos = HBORDER; ypos = _h - buttonHeight - VBORDER; myPrevButton = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Previous", GuiObject::kPrevCmd); myPrevButton->clearFlags(Widget::FLAG_ENABLED); wid.push_back(myPrevButton); - xpos += buttonWidth + 8; + xpos += buttonWidth + fontWidth; myNextButton = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Next", GuiObject::kNextCmd); wid.push_back(myNextButton); - xpos = _w - buttonWidth - 10; + xpos = _w - buttonWidth - HBORDER; ButtonWidget* b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Close", GuiObject::kCloseCmd); wid.push_back(b); addCancelWidget(b); - xpos = 5; ypos = 5 + _th; + xpos = HBORDER; ypos = _th + VBORDER; myTitle = new StaticTextWidget(this, font, xpos, ypos, _w - xpos * 2, fontHeight, "", TextAlign::Center); myTitle->setTextColor(kTextColorEm); - xpos = 16; ypos += lineHeight + 4; + xpos = HBORDER * 2; ypos += lineHeight + VGAP * 2; for(int i = 0; i < myLinesPerPage; i++) { myDesc.push_back(new StaticTextWidget(this, font, xpos, ypos, _w - xpos * 2, diff --git a/src/gui/AudioDialog.cxx b/src/gui/AudioDialog.cxx index cb73dee42..1f97c2f8b 100644 --- a/src/gui/AudioDialog.cxx +++ b/src/gui/AudioDialog.cxx @@ -40,12 +40,14 @@ AudioDialog::AudioDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font) : Dialog(osystem, parent, font, "Audio settings") { - const int VBORDER = 10; - const int HBORDER = 10; - const int INDENT = 20; - const int VGAP = 4; const int lineHeight = font.getLineHeight(), + fontHeight = font.getFontHeight(), fontWidth = font.getMaxCharWidth(); + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = fontWidth * 2; + const int VGAP = fontHeight / 4; + int xpos, ypos; int lwidth = font.getStringWidth("Volume "), pwidth; @@ -64,7 +66,7 @@ AudioDialog::AudioDialog(OSystem& osystem, DialogContainer& parent, "Enable sound", kSoundEnableChanged); wid.push_back(mySoundEnableCheckbox); ypos += lineHeight + VGAP; - xpos += INDENT; + xpos += CheckboxWidget::prefixSize(font); // Volume myVolumeSlider = new SliderWidget(this, font, xpos, ypos, diff --git a/src/gui/CheckListWidget.cxx b/src/gui/CheckListWidget.cxx index f228407d4..0e5a46d82 100644 --- a/src/gui/CheckListWidget.cxx +++ b/src/gui/CheckListWidget.cxx @@ -29,7 +29,7 @@ CheckListWidget::CheckListWidget(GuiObject* boss, const GUI::Font& font, // rowheight is determined by largest item on a line, // possibly meaning that number of rows will change - _fontHeight = std::max(_fontHeight, CheckboxWidget::boxSize()); + _fontHeight = std::max(_fontHeight, CheckboxWidget::boxSize(_font)); _rows = h / _fontHeight; // Create a CheckboxWidget for each row in the list @@ -100,7 +100,7 @@ void CheckListWidget::drawWidget(bool hilite) // Draw a thin frame around the list and to separate columns s.frameRect(_x, _y, _w, _h, hilite ? kWidColorHi : kColor); - s.vLine(_x + CheckboxWidget::boxSize() + 5, _y, _y + _h - 1, kColor); + s.vLine(_x + CheckboxWidget::boxSize(_font) + 5, _y, _y + _h - 1, kColor); // Draw the list items for (i = 0, pos = _currentPos; i < _rows && pos < len; i++, pos++) @@ -150,7 +150,7 @@ void CheckListWidget::drawWidget(bool hilite) Common::Rect CheckListWidget::getEditRect() const { const int yoffset = (_selectedItem - _currentPos) * _fontHeight, - xoffset = CheckboxWidget::boxSize() + 10; + xoffset = CheckboxWidget::boxSize(_font) + 10; return Common::Rect(2 + xoffset, 1 + yoffset, _w - (xoffset - 15), _fontHeight + yoffset); diff --git a/src/gui/CommandDialog.cxx b/src/gui/CommandDialog.cxx index 6eaf714b7..31fd7b2cb 100644 --- a/src/gui/CommandDialog.cxx +++ b/src/gui/CommandDialog.cxx @@ -33,16 +33,20 @@ CommandDialog::CommandDialog(OSystem& osystem, DialogContainer& parent) : Dialog(osystem, parent, osystem.frameBuffer().font(), "Commands") { - const int HBORDER = 10; - const int VBORDER = 10; - const int HGAP = 8; - const int VGAP = 4; - const int buttonWidth = _font.getStringWidth("Time Machine On") + 16, - buttonHeight = _font.getLineHeight() + 6, - rowHeight = buttonHeight + VGAP; + const int lineHeight = _font.getLineHeight(), + fontHeight = _font.getFontHeight(), + fontWidth = _font.getMaxCharWidth(), + buttonHeight = _font.getLineHeight() * 1.5, + buttonWidth = _font.getStringWidth("Time Machine On") + fontWidth * 2; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = fontWidth * 2; + const int VGAP = fontHeight / 4; + const int HGAP = VGAP * 2; + const int rowHeight = buttonHeight + VGAP; // Set real dimensions - _w = 3 * (buttonWidth + 5) + HBORDER * 2; + _w = 3 * (buttonWidth + HGAP) - HGAP + HBORDER * 2; _h = 6 * rowHeight - VGAP + VBORDER * 2 + _th; ButtonWidget* bw = nullptr; WidgetArray wid; diff --git a/src/gui/DeveloperDialog.cxx b/src/gui/DeveloperDialog.cxx index 1d3d59aa5..e59f9555e 100644 --- a/src/gui/DeveloperDialog.cxx +++ b/src/gui/DeveloperDialog.cxx @@ -48,18 +48,27 @@ DeveloperDialog::DeveloperDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, int max_w, int max_h) : Dialog(osystem, parent, font, "Developer settings") { - const int VGAP = 4; const int lineHeight = font.getLineHeight(), - fontWidth = font.getMaxCharWidth(), - buttonHeight = font.getLineHeight() + 4; + fontHeight = font.getFontHeight(), + fontWidth = font.getMaxCharWidth(), + buttonHeight = font.getLineHeight() * 1.25; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = fontWidth * 2; + const int VGAP = fontHeight / 4; + int xpos, ypos; // Set real dimensions - setSize(54 * fontWidth + 10, 16 * (lineHeight + VGAP) + 14 + _th, max_w, max_h); + setSize(53 * fontWidth + HBORDER * 2, + _th + VGAP * 3 + lineHeight + 13 * (lineHeight + VGAP) + buttonHeight + VBORDER * 3, + max_w, max_h); // The tab widget - xpos = 2; ypos = 4; - myTab = new TabWidget(this, font, xpos, ypos + _th, _w - 2 * xpos, _h - _th - buttonHeight - 16 - ypos); + xpos = 2; ypos = VGAP; + myTab = new TabWidget(this, font, xpos, ypos + _th, + _w - 2 * xpos, + _h - _th - VGAP - buttonHeight - VBORDER * 2); addTabWidget(myTab); addEmulationTab(font); @@ -79,12 +88,16 @@ DeveloperDialog::DeveloperDialog(OSystem& osystem, DialogContainer& parent, // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DeveloperDialog::addEmulationTab(const GUI::Font& font) { - const int HBORDER = 10; - const int INDENT = 16+4; - const int VBORDER = 8; - const int VGAP = 4; + const int lineHeight = font.getLineHeight(), + fontHeight = font.getFontHeight(), + fontWidth = font.getMaxCharWidth(), + buttonHeight = font.getLineHeight() * 1.25; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = fontWidth * 2; + const int VGAP = fontHeight / 4; + int ypos = VBORDER; - int lineHeight = font.getLineHeight(); WidgetArray wid; VariantList items; int tabID = myTab->addTab(" Emulation ", TabWidget::AUTO_WIDTH); @@ -136,13 +149,13 @@ void DeveloperDialog::addEmulationTab(const GUI::Font& font) myRandomizeCPULabel = new StaticTextWidget(myTab, font, HBORDER + INDENT * 2, ypos + 1, "Randomize CPU "); wid.push_back(myRandomizeCPULabel); - int xpos = myRandomizeCPULabel->getRight() + 10; + int xpos = myRandomizeCPULabel->getRight() + fontWidth * 1.25; for(int i = 0; i < 5; ++i) { myRandomizeCPUWidget[i] = new CheckboxWidget(myTab, font, xpos, ypos + 1, ourCPUregs[i], kRandCPUID); wid.push_back(myRandomizeCPUWidget[i]); - xpos += CheckboxWidget::boxSize() + font.getStringWidth("XX") + 20; + xpos += CheckboxWidget::boxSize(font) + font.getStringWidth("XX") + fontWidth * 2.5; } ypos += lineHeight + VGAP; @@ -182,12 +195,16 @@ void DeveloperDialog::addEmulationTab(const GUI::Font& font) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DeveloperDialog::addTiaTab(const GUI::Font& font) { - const int HBORDER = 10; - const int INDENT = 16 + 4; - const int VBORDER = 8; - const int VGAP = 4; + const int lineHeight = font.getLineHeight(), + fontHeight = font.getFontHeight(), + fontWidth = font.getMaxCharWidth(), + buttonHeight = font.getLineHeight() * 1.25; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = fontWidth * 2; + const int VGAP = fontHeight / 4; + int ypos = VBORDER; - int lineHeight = font.getLineHeight(); int pwidth = font.getStringWidth("Faulty Cosmic Ark stars"); WidgetArray wid; VariantList items; @@ -268,13 +285,16 @@ void DeveloperDialog::addTiaTab(const GUI::Font& font) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DeveloperDialog::addVideoTab(const GUI::Font& font) { - const int HBORDER = 10; - const int INDENT = 16 + 4; - const int VBORDER = 8; - const int VGAP = 4; + const int lineHeight = font.getLineHeight(), + fontHeight = font.getFontHeight(), + fontWidth = font.getMaxCharWidth(), + buttonHeight = font.getLineHeight() * 1.25; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = fontWidth * 2; + const int VGAP = fontHeight / 4; + int ypos = VBORDER; - int lineHeight = font.getLineHeight(); - int fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(); int lwidth = font.getStringWidth("Intensity "); int pwidth = font.getMaxCharWidth() * 6; WidgetArray wid; @@ -340,7 +360,7 @@ void DeveloperDialog::addVideoTab(const GUI::Font& font) myDbgColour[idx] = new PopUpWidget(myTab, font, x, ypos - 1, pwidth, lineHeight, items, desc, lwidth, dbg_cmds[idx]); wid.push_back(myDbgColour[idx]); - x += myDbgColour[idx]->getWidth() + 10; + x += myDbgColour[idx]->getWidth() + fontWidth * 1.25; myDbgColourSwatch[idx] = new ColorWidget(myTab, font, x, ypos - 1, uInt32(2 * lineHeight), lineHeight); ypos += lineHeight + VGAP * 1; @@ -355,8 +375,11 @@ void DeveloperDialog::addVideoTab(const GUI::Font& font) // Add message concerning usage const GUI::Font& infofont = instance().frameBuffer().infoFont(); - ypos = myTab->getHeight() - 5 - fontHeight - infofont.getFontHeight() - 10; - new StaticTextWidget(myTab, infofont, HBORDER, ypos, "(*) Colors identical for player and developer settings"); + ypos = myTab->getHeight() - fontHeight - infofont.getFontHeight() - VGAP - VBORDER; + lwidth = infofont.getStringWidth("(*) Colors identical for player and developer settings"); + new StaticTextWidget(myTab, infofont, HBORDER, ypos, + std::min(lwidth, _w - HBORDER * 2), infofont.getFontHeight(), + "(*) Colors identical for player and developer settings"); // Add items for tab 2 addToFocusList(wid, myTab, tabID); @@ -403,37 +426,42 @@ void DeveloperDialog::addTimeMachineTab(const GUI::Font& font) "30m", "60m" }; - const int HBORDER = 10; - const int INDENT = 16+4; - const int VBORDER = 8; - const int VGAP = 4; - int ypos = VBORDER; - int lineHeight = font.getLineHeight(), - fontHeight = font.getFontHeight(), - fontWidth = font.getMaxCharWidth(), - lwidth = fontWidth * 11; + const int lineHeight = font.getLineHeight(), + fontHeight = font.getFontHeight(), + fontWidth = font.getMaxCharWidth(), + buttonHeight = font.getLineHeight() * 1.25; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = fontWidth * 2; + const int VGAP = fontHeight / 4; + + int xpos = HBORDER, + ypos = VBORDER, + lwidth = fontWidth * 11; WidgetArray wid; VariantList items; int tabID = myTab->addTab(" Time Machine ", TabWidget::AUTO_WIDTH); // settings set mySettingsGroupTM = new RadioButtonGroup(); - RadioButtonWidget* r = new RadioButtonWidget(myTab, font, HBORDER, ypos + 1, + RadioButtonWidget* r = new RadioButtonWidget(myTab, font, xpos, ypos + 1, "Player settings", mySettingsGroupTM, kPlrSettings); wid.push_back(r); ypos += lineHeight + VGAP; - r = new RadioButtonWidget(myTab, font, HBORDER, ypos + 1, + r = new RadioButtonWidget(myTab, font, xpos, ypos + 1, "Developer settings", mySettingsGroupTM, kDevSettings); wid.push_back(r); + xpos += INDENT; ypos += lineHeight + VGAP * 1; - myTimeMachineWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT, ypos + 1, + myTimeMachineWidget = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Time Machine", kTimeMachine); wid.push_back(myTimeMachineWidget); + xpos += CheckboxWidget::prefixSize(font); ypos += lineHeight + VGAP; int swidth = fontWidth * 12 + 5; // width of PopUpWidgets below - myStateSizeWidget = new SliderWidget(myTab, font, HBORDER + INDENT * 2, ypos - 1, swidth, lineHeight, + myStateSizeWidget = new SliderWidget(myTab, font, xpos, ypos - 1, swidth, lineHeight, "Buffer size (*) ", 0, kSizeChanged, lwidth, " states"); myStateSizeWidget->setMinValue(20); #ifdef RETRON77 @@ -446,7 +474,7 @@ void DeveloperDialog::addTimeMachineTab(const GUI::Font& font) wid.push_back(myStateSizeWidget); ypos += lineHeight + VGAP; - myUncompressedWidget = new SliderWidget(myTab, font, HBORDER + INDENT * 2, ypos - 1, swidth, lineHeight, + myUncompressedWidget = new SliderWidget(myTab, font, xpos, ypos - 1, swidth, lineHeight, "Uncompressed size ", 0, kUncompressedChanged, lwidth, " states"); myUncompressedWidget->setMinValue(0); #ifdef RETRON77 @@ -463,7 +491,7 @@ void DeveloperDialog::addTimeMachineTab(const GUI::Font& font) for(int i = 0; i < NUM_INTERVALS; ++i) VarList::push_back(items, INTERVALS[i], INT_SETTINGS[i]); int pwidth = font.getStringWidth("10 seconds"); - myStateIntervalWidget = new PopUpWidget(myTab, font, HBORDER + INDENT * 2, ypos, pwidth, + myStateIntervalWidget = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, "Interval ", 0, kIntervalChanged); wid.push_back(myStateIntervalWidget); ypos += lineHeight + VGAP; @@ -471,37 +499,42 @@ void DeveloperDialog::addTimeMachineTab(const GUI::Font& font) items.clear(); for(int i = 0; i < NUM_HORIZONS; ++i) VarList::push_back(items, HORIZONS[i], HOR_SETTINGS[i]); - myStateHorizonWidget = new PopUpWidget(myTab, font, HBORDER + INDENT * 2, ypos, pwidth, + myStateHorizonWidget = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, "Horizon ~ ", 0, kHorizonChanged); wid.push_back(myStateHorizonWidget); + xpos = HBORDER + INDENT; ypos += lineHeight + VGAP * 2; new StaticTextWidget(myTab, font, HBORDER, ypos + 1, "When entering/exiting emulation:"); ypos += lineHeight + VGAP; mySaveOnExitGroup = new RadioButtonGroup(); - r = new RadioButtonWidget(myTab, font, HBORDER + INDENT, ypos + 1, + r = new RadioButtonWidget(myTab, font, xpos, ypos + 1, "Do nothing", mySaveOnExitGroup); wid.push_back(r); ypos += lineHeight + VGAP; - r = new RadioButtonWidget(myTab, font, HBORDER + INDENT, ypos + 1, + r = new RadioButtonWidget(myTab, font, xpos, ypos + 1, "Save current state in current slot", mySaveOnExitGroup); wid.push_back(r); ypos += lineHeight + VGAP; - r = new RadioButtonWidget(myTab, font, HBORDER + INDENT, ypos + 1, + r = new RadioButtonWidget(myTab, font, xpos, ypos + 1, "Load/save all Time Machine states", mySaveOnExitGroup); wid.push_back(r); ypos += lineHeight + VGAP; + xpos = HBORDER; - myAutoSlotWidget = new CheckboxWidget(myTab, font, HBORDER, ypos + 1, "Automatically change save state slots"); + myAutoSlotWidget = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Automatically change save state slots"); wid.push_back(myAutoSlotWidget); ypos += lineHeight + VGAP; // Add message concerning usage const GUI::Font& infofont = instance().frameBuffer().infoFont(); - ypos = myTab->getHeight() - 5 - fontHeight - infofont.getFontHeight() - 10; - new StaticTextWidget(myTab, infofont, HBORDER, ypos, "(*) Any size change clears the buffer"); + ypos = myTab->getHeight() - fontHeight - infofont.getFontHeight() - VGAP - VBORDER; + lwidth = infofont.getStringWidth("(*) Any size change clears the buffer"); + new StaticTextWidget(myTab, infofont, HBORDER, ypos, + std::min(lwidth, _w - HBORDER * 2), infofont.getFontHeight(), + "(*) Any size change clears the buffer"); addToFocusList(wid, myTab, tabID); } @@ -513,14 +546,16 @@ void DeveloperDialog::addDebuggerTab(const GUI::Font& font) WidgetArray wid; #ifdef DEBUGGER_SUPPORT - const int HBORDER = 10; - const int VBORDER = 8; - const int VGAP = 4; + const int lineHeight = font.getLineHeight(), + fontHeight = font.getFontHeight(), + fontWidth = font.getMaxCharWidth(), + buttonHeight = font.getLineHeight() * 1.25; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = fontWidth * 2; + const int VGAP = fontHeight / 4; VariantList items; - int fontWidth = font.getMaxCharWidth(), - fontHeight = font.getFontHeight(), - lineHeight = font.getLineHeight(); int xpos, ypos, pwidth; const Common::Size& ds = instance().frameBuffer().desktopSize(); @@ -537,7 +572,7 @@ void DeveloperDialog::addDebuggerTab(const GUI::Font& font) new PopUpWidget(myTab, font, HBORDER, ypos + 1, pwidth, lineHeight, items, "Font size (*) ", 0, kDFontSizeChanged); wid.push_back(myDebuggerFontSize); - ypos += lineHeight + 4; + ypos += lineHeight + VGAP; // Font style (bold label vs. text, etc) items.clear(); @@ -580,7 +615,7 @@ void DeveloperDialog::addDebuggerTab(const GUI::Font& font) // Add message concerning usage const GUI::Font& infofont = instance().frameBuffer().infoFont(); - ypos = myTab->getHeight() - 5 - fontHeight - infofont.getFontHeight() - 10; + ypos = myTab->getHeight() - fontHeight - infofont.getFontHeight() - VGAP - VBORDER; new StaticTextWidget(myTab, infofont, HBORDER, ypos, "(*) Changes require a ROM reload"); #if defined(DEBUGGER_SUPPORT) && defined(WINDOWED_SUPPORT) diff --git a/src/gui/Dialog.cxx b/src/gui/Dialog.cxx index a9c60f3d1..0195fa8f9 100644 --- a/src/gui/Dialog.cxx +++ b/src/gui/Dialog.cxx @@ -139,7 +139,7 @@ void Dialog::setTitle(const string& title) if(title.empty()) _th = 0; else - _th = _font.getLineHeight() + 4; + _th = _font.getLineHeight() * 1.25; _h += _th; } @@ -383,7 +383,8 @@ void Dialog::drawDialog() if(_th) { s.fillRect(_x, _y, _w, _th, _onTop ? kColorTitleBar : kColorTitleBarLo); - s.drawString(_font, _title, _x + 10, _y + 2 + 1, _font.getStringWidth(_title), + s.drawString(_font, _title, _x + _font.getMaxCharWidth() * 1.25, _y + _font.getFontHeight() / 6, + _font.getStringWidth(_title), _onTop ? kColorTitleText : kColorTitleTextLo); } } @@ -771,15 +772,18 @@ void Dialog::addOKCancelBGroup(WidgetArray& wid, const GUI::Font& font, const string& okText, const string& cancelText, bool focusOKButton, int buttonWidth) { - const int HBORDER = 10; - const int VBORDER = 10; - const int BTN_BORDER = 20; - const int BUTTON_GAP = 8; + const int lineHeight = font.getLineHeight(), + 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; buttonWidth = std::max(buttonWidth, std::max(font.getStringWidth("Defaults"), std::max(font.getStringWidth(okText), font.getStringWidth(cancelText))) + BTN_BORDER); - int buttonHeight = font.getLineHeight() + 4; _w = std::max(HBORDER * 2 + buttonWidth * 2 + BUTTON_GAP, _w); @@ -817,11 +821,14 @@ void Dialog::addDefaultsOKCancelBGroup(WidgetArray& wid, const GUI::Font& font, const string& defaultsText, bool focusOKButton) { - const int HBORDER = 10; - const int VBORDER = 10; - const int BTN_BORDER = 20; - int buttonWidth = font.getStringWidth(defaultsText) + BTN_BORDER; - int buttonHeight = font.getLineHeight() + 4; + const int lineHeight = font.getLineHeight(), + 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 buttonWidth = font.getStringWidth(defaultsText) + BTN_BORDER; addDefaultWidget(new ButtonWidget(this, font, HBORDER, _h - buttonHeight - VBORDER, buttonWidth, buttonHeight, defaultsText, GuiObject::kDefaultsCmd)); diff --git a/src/gui/EventMappingWidget.cxx b/src/gui/EventMappingWidget.cxx index 3d55dffe7..1438e3d4f 100644 --- a/src/gui/EventMappingWidget.cxx +++ b/src/gui/EventMappingWidget.cxx @@ -44,10 +44,12 @@ EventMappingWidget::EventMappingWidget(GuiObject* boss, const GUI::Font& font, { const int fontHeight = font.getFontHeight(), lineHeight = font.getLineHeight(), + fontWidth = font.getMaxCharWidth(), buttonWidth = font.getStringWidth("Defaults") + 10, - buttonHeight = font.getLineHeight() + 4; - const int HBORDER = 8; - const int VBORDER = 8; + buttonHeight = font.getLineHeight() * 1.25; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int VGAP = fontHeight / 4; const int ACTION_LINES = 2; int xpos = HBORDER, ypos = VBORDER; const int listWidth = _w - buttonWidth - HBORDER * 2 - 8; @@ -74,8 +76,8 @@ EventMappingWidget::EventMappingWidget(GuiObject* boss, const GUI::Font& font, items, "Events ", 0, kFilterCmd); myFilterPopup->setTarget(this); addFocusWidget(myFilterPopup); - ypos += lineHeight + 8; - listHeight -= lineHeight + 8; + ypos += lineHeight * 1.5; + listHeight -= lineHeight * 1.5; } myActionsList = new StringListWidget(boss, font, xpos, ypos, listWidth, listHeight); @@ -91,7 +93,7 @@ EventMappingWidget::EventMappingWidget(GuiObject* boss, const GUI::Font& font, myMapButton->setTarget(this); addFocusWidget(myMapButton); - ypos += lineHeight + 10; + ypos += buttonHeight + VGAP; myCancelMapButton = new ButtonWidget(boss, font, xpos, ypos, buttonWidth, buttonHeight, "Cancel", kStopMapCmd); @@ -99,14 +101,14 @@ EventMappingWidget::EventMappingWidget(GuiObject* boss, const GUI::Font& font, myCancelMapButton->clearFlags(Widget::FLAG_ENABLED); addFocusWidget(myCancelMapButton); - ypos += lineHeight + 20; + ypos += buttonHeight + VGAP * 2; myEraseButton = new ButtonWidget(boss, font, xpos, ypos, buttonWidth, buttonHeight, "Erase", kEraseCmd); myEraseButton->setTarget(this); addFocusWidget(myEraseButton); - ypos += lineHeight + 10; + ypos += buttonHeight + VGAP; myResetButton = new ButtonWidget(boss, font, xpos, ypos, buttonWidth, buttonHeight, "Reset", kResetCmd); @@ -115,7 +117,7 @@ EventMappingWidget::EventMappingWidget(GuiObject* boss, const GUI::Font& font, if(mode == EventMode::kEmulationMode) { - ypos += lineHeight + 20; + ypos += buttonHeight + VGAP * 2; myComboButton = new ButtonWidget(boss, font, xpos, ypos, buttonWidth, buttonHeight, "Combo" + ELLIPSIS, kComboCmd); @@ -128,13 +130,13 @@ EventMappingWidget::EventMappingWidget(GuiObject* boss, const GUI::Font& font, // Show message for currently selected event xpos = HBORDER; - ypos = myActionsList->getBottom() + 8; + ypos = myActionsList->getBottom() + VGAP * 2; StaticTextWidget* t; t = new StaticTextWidget(boss, font, xpos, ypos+2, font.getStringWidth("Action"), fontHeight, "Action", TextAlign::Left); - myKeyMapping = new EditTextWidget(boss, font, xpos + t->getWidth() + 8, ypos, - _w - xpos - t->getWidth() - 8 - HBORDER, + myKeyMapping = new EditTextWidget(boss, font, xpos + t->getWidth() + fontWidth, ypos, + _w - xpos - t->getWidth() - fontWidth - HBORDER, lineHeight + font.getFontHeight() * (ACTION_LINES - 1), ""); myKeyMapping->setEditable(false, true); myKeyMapping->clearFlags(Widget::FLAG_RETAIN_FOCUS); diff --git a/src/gui/GameInfoDialog.cxx b/src/gui/GameInfoDialog.cxx index 49ec158b0..6e6e89620 100644 --- a/src/gui/GameInfoDialog.cxx +++ b/src/gui/GameInfoDialog.cxx @@ -52,14 +52,16 @@ GameInfoDialog::GameInfoDialog( CommandSender(boss) { const GUI::Font& ifont = instance().frameBuffer().infoFont(); - const int lineHeight = font.getLineHeight(), - fontWidth = font.getMaxCharWidth(), - fontHeight = font.getFontHeight(), - buttonHeight = font.getLineHeight() + 4, + + const int lineHeight = font.getLineHeight(), + fontHeight = font.getFontHeight(), + fontWidth = font.getMaxCharWidth(), + buttonHeight = font.getLineHeight() * 1.25, infoLineHeight = ifont.getLineHeight(); - const int VBORDER = 8; - const int HBORDER = 10; - const int VGAP = 4; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = fontWidth * 2; + const int VGAP = fontHeight / 4; int xpos, ypos, lwidth, fwidth, pwidth, tabID; WidgetArray wid; @@ -67,19 +69,20 @@ GameInfoDialog::GameInfoDialog( StaticTextWidget* t; // Set real dimensions - setSize(55 * fontWidth + 8, - 8 * (lineHeight + VGAP) + 1 * (infoLineHeight + VGAP) + VBORDER * 2 + _th + - buttonHeight + fontHeight + ifont.getLineHeight() + 20, + setSize(54 * fontWidth + HBORDER * 2, + _th + VGAP * 3 + lineHeight + 8 * (lineHeight + VGAP) + 1 * (infoLineHeight + VGAP) + + ifont.getLineHeight() + VGAP + buttonHeight + VBORDER * 2, max_w, max_h); // The tab widget - myTab = new TabWidget(this, font, 2, 4 + _th, _w - 2 * 2, - _h - (_th + buttonHeight + 20)); + myTab = new TabWidget(this, font, 2, 4 + _th, + _w - 2 * 2, + _h - _th - VGAP - buttonHeight - VBORDER * 2); addTabWidget(myTab); ////////////////////////////////////////////////////////////////////////////// // 1) Emulation properties - tabID = myTab->addTab("Emulation"); + tabID = myTab->addTab(" Emulation ", TabWidget::AUTO_WIDTH); ypos = VBORDER; @@ -88,12 +91,12 @@ GameInfoDialog::GameInfoDialog( items.clear(); for(uInt32 i = 0; i < uInt32(Bankswitch::Type::NumSchemes); ++i) VarList::push_back(items, Bankswitch::BSList[i].desc, Bankswitch::BSList[i].name); - myBSType = new PopUpWidget(myTab, font, t->getRight() + 8, ypos, + myBSType = new PopUpWidget(myTab, font, t->getRight() + fontWidth, ypos, pwidth, lineHeight, items, ""); wid.push_back(myBSType); ypos += lineHeight + VGAP; - myTypeDetected = new StaticTextWidget(myTab, ifont, t->getRight() + 8, ypos, + myTypeDetected = new StaticTextWidget(myTab, ifont, t->getRight() + fontWidth, ypos, "CM (SpectraVideo CompuMate) detected"); ypos += ifont.getLineHeight() + VGAP; @@ -119,7 +122,7 @@ GameInfoDialog::GameInfoDialog( pwidth, lineHeight, items, "", 0, 0); wid.push_back(myFormat); - myFormatDetected = new StaticTextWidget(myTab, ifont, myFormat->getRight() + 8, ypos + 4, + myFormatDetected = new StaticTextWidget(myTab, ifont, myFormat->getRight() + fontWidth, ypos + 4, "SECAM60 detected"); // Phosphor @@ -130,7 +133,7 @@ GameInfoDialog::GameInfoDialog( ypos += lineHeight + VGAP * 0; myPPBlend = new SliderWidget(myTab, font, - HBORDER + 20, ypos, + HBORDER + fontWidth * 2, ypos, "Blend ", 0, kPPBlendChanged, 4 * fontWidth, "%"); myPPBlend->setMinValue(0); myPPBlend->setMaxValue(100); myPPBlend->setTickmarkIntervals(2); @@ -138,7 +141,7 @@ GameInfoDialog::GameInfoDialog( ypos += lineHeight + VGAP; t = new StaticTextWidget(myTab, font, HBORDER, ypos + 1, "V-Center "); - myVCenter = new SliderWidget(myTab, font, t->getRight() + 2, ypos, "", + myVCenter = new SliderWidget(myTab, font, t->getRight(), ypos, "", 0, kVCenterChanged, 7 * fontWidth, "px", 0, true); myVCenter->setMinValue(TIAConstants::minVcenter); @@ -151,7 +154,7 @@ GameInfoDialog::GameInfoDialog( wid.push_back(mySound); // Add message concerning usage - ypos = myTab->getHeight() - 5 - fontHeight - ifont.getFontHeight() - 10; + ypos = myTab->getHeight() - fontHeight - ifont.getFontHeight() - VGAP - VBORDER; new StaticTextWidget(myTab, ifont, HBORDER, ypos, "(*) Changes require a ROM reload"); @@ -161,7 +164,7 @@ GameInfoDialog::GameInfoDialog( ////////////////////////////////////////////////////////////////////////////// // 2) Console properties wid.clear(); - tabID = myTab->addTab("Console"); + tabID = myTab->addTab(" Console ", TabWidget::AUTO_WIDTH); xpos = HBORDER; ypos = VBORDER; lwidth = font.getStringWidth(GUI::RIGHT_DIFFICULTY + " "); @@ -204,7 +207,7 @@ GameInfoDialog::GameInfoDialog( ////////////////////////////////////////////////////////////////////////////// // 3) Controller properties wid.clear(); - tabID = myTab->addTab("Controllers"); + tabID = myTab->addTab(" Controllers ", TabWidget::AUTO_WIDTH); ctrls.clear(); VarList::push_back(ctrls, "Auto-detect", "AUTO"); @@ -271,7 +274,7 @@ GameInfoDialog::GameInfoDialog( myPaddlesCenter = new StaticTextWidget(myTab, font, xpos, ypos, "Paddles center:"); ypos += lineHeight + VGAP; - xpos += 20; + xpos += INDENT; myPaddleXCenter = new SliderWidget(myTab, font, xpos, ypos - 1, "X ", 0, kPXCenterChanged, fontWidth * 6, "px", 0 ,true); myPaddleXCenter->setMinValue(Paddles::MIN_ANALOG_CENTER); @@ -288,7 +291,7 @@ GameInfoDialog::GameInfoDialog( wid.push_back(myPaddleYCenter); // Mouse - xpos = HBORDER + fontWidth * 24 - 20; + xpos = HBORDER + fontWidth * 24 - INDENT; ypos = myPaddlesCenter->getTop(); myMouseControl = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Specific mouse axes", kMCtrlChanged); @@ -307,7 +310,7 @@ GameInfoDialog::GameInfoDialog( VarList::push_back(items, "MindLink 0", static_cast(MouseControl::Type::MindLink0)); VarList::push_back(items, "MindLink 1", static_cast(MouseControl::Type::MindLink1)); - xpos += 20; + xpos += CheckboxWidget::prefixSize(font); ypos += lineHeight + VGAP; myMouseX = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, "X-Axis is "); @@ -318,7 +321,7 @@ GameInfoDialog::GameInfoDialog( "Y-Axis is "); wid.push_back(myMouseY); - xpos -= 20; ypos += lineHeight + VGAP; + xpos -= CheckboxWidget::prefixSize(font); ypos += lineHeight + VGAP; myMouseRange = new SliderWidget(myTab, font, xpos, ypos, "Mouse axes range ", 0, 0, fontWidth * 4, "%"); myMouseRange->setMinValue(1); myMouseRange->setMaxValue(100); @@ -331,7 +334,7 @@ GameInfoDialog::GameInfoDialog( ////////////////////////////////////////////////////////////////////////////// // 4) Cartridge properties wid.clear(); - tabID = myTab->addTab("Cartridge"); + tabID = myTab->addTab(" Cartridge ", TabWidget::AUTO_WIDTH); xpos = HBORDER; ypos = VBORDER; lwidth = font.getStringWidth("Manufacturer "); diff --git a/src/gui/HelpDialog.cxx b/src/gui/HelpDialog.cxx index bc86026b0..9a0bd2bdd 100644 --- a/src/gui/HelpDialog.cxx +++ b/src/gui/HelpDialog.cxx @@ -31,49 +31,55 @@ HelpDialog::HelpDialog(OSystem& osystem, DialogContainer& parent, const int lineHeight = font.getLineHeight(), fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(), - buttonWidth = font.getStringWidth("Defaults") + 20, - buttonHeight = font.getLineHeight() + 4; + buttonWidth = font.getStringWidth("Previous") + fontWidth * 2.5, + buttonHeight = font.getLineHeight() * 1.25; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = fontWidth * 2; + const int VGAP = fontHeight / 4; + int xpos, ypos; WidgetArray wid; // Set real dimensions - _w = 46 * fontWidth + 10; - _h = 12 * lineHeight + 20 + _th; + _w = 46 * fontWidth + HBORDER * 2; + _h = _th + 11 * lineHeight + VGAP * 3 + buttonHeight + VBORDER * 2; // Add Previous, Next and Close buttons - xpos = 10; ypos = _h - buttonHeight - 10; + xpos = HBORDER; ypos = _h - buttonHeight - VBORDER; myPrevButton = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Previous", GuiObject::kPrevCmd); myPrevButton->clearFlags(Widget::FLAG_ENABLED); wid.push_back(myPrevButton); - xpos += buttonWidth + 8; + xpos += buttonWidth + fontWidth; myNextButton = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Next", GuiObject::kNextCmd); wid.push_back(myNextButton); - xpos = _w - buttonWidth - 10; + xpos = _w - buttonWidth - HBORDER; ButtonWidget* b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Close", GuiObject::kCloseCmd); wid.push_back(b); addCancelWidget(b); - xpos = 5; ypos = 5 + _th; - myTitle = new StaticTextWidget(this, font, xpos, ypos, _w - 10, fontHeight, + xpos = HBORDER; ypos = VBORDER + _th; + myTitle = new StaticTextWidget(this, font, xpos, ypos, _w - HBORDER * 2, fontHeight, "", TextAlign::Center); + myTitle->setTextColor(kTextColorEm); - int lwidth = 13 * fontWidth; - xpos += 5; ypos += lineHeight + 4; - for(uInt8 i = 0; i < LINES_PER_PAGE; ++i) + int lwidth = 15 * fontWidth; + ypos += lineHeight + VGAP * 2; + for(int i = 0; i < LINES_PER_PAGE; ++i) { myKey[i] = new StaticTextWidget(this, font, xpos, ypos, lwidth, fontHeight, "", TextAlign::Left); myDesc[i] = - new StaticTextWidget(this, font, xpos+lwidth, ypos, _w - xpos - lwidth - 5, + new StaticTextWidget(this, font, xpos+lwidth, ypos, _w - xpos - lwidth - HBORDER, fontHeight, "", TextAlign::Left); ypos += fontHeight; } @@ -158,7 +164,7 @@ void HelpDialog::updateStrings(uInt8 page, uInt8 lines, string& title) case 5: title = "All other commands"; ADD_LINE(); - ADD_BIND("Remapped Even", "ts"); + ADD_BIND("Remapped Events", ""); ADD_TEXT("Most other commands can be"); ADD_TEXT("remapped. Please consult the"); ADD_TEXT("'Options/Input" + ELLIPSIS + "' dialog for"); diff --git a/src/gui/InputDialog.cxx b/src/gui/InputDialog.cxx index e5eaa9057..bfa914c63 100644 --- a/src/gui/InputDialog.cxx +++ b/src/gui/InputDialog.cxx @@ -45,16 +45,23 @@ InputDialog::InputDialog(OSystem& osystem, DialogContainer& parent, { const int lineHeight = _font.getLineHeight(), fontWidth = _font.getMaxCharWidth(), - buttonHeight = _font.getLineHeight() + 4; - const int vBorder = 4; + fontHeight = _font.getFontHeight(), + buttonHeight = _font.getLineHeight() * 1.25; + const int VBORDER = fontHeight / 2; + const int VGAP = fontHeight / 4; + const int HBORDER = fontWidth * 1.25; int xpos, ypos, tabID; // Set real dimensions - setSize(51 * fontWidth + 10, 17 * (lineHeight + 4) + 16 + _th, max_w, max_h); + setSize(50 * fontWidth + HBORDER * 2, + _th + VGAP * 3 + lineHeight + 13 * (lineHeight + VGAP) + VGAP * 7 + buttonHeight + VBORDER * 3, + max_w, max_h); // The tab widget - xpos = 2; ypos = vBorder + _th; - myTab = new TabWidget(this, _font, xpos, ypos, _w - 2*xpos, _h -_th - buttonHeight - 20); + xpos = 2; ypos = VGAP + _th; + myTab = new TabWidget(this, _font, xpos, ypos, + _w - 2*xpos, + _h -_th - VGAP - buttonHeight - VBORDER * 2); addTabWidget(myTab); // 1) Event mapper for emulation actions @@ -102,11 +109,11 @@ void InputDialog::addDevicePortTab() const int lineHeight = _font.getLineHeight(), fontWidth = _font.getMaxCharWidth(), fontHeight = _font.getFontHeight(); + const int VGAP = fontHeight / 4; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; int xpos, ypos, lwidth, tabID; WidgetArray wid; - const int VGAP = 4; - const int VBORDER = 8; - const int HBORDER = 8; // Devices/ports tabID = myTab->addTab("Devices & Ports", TabWidget::AUTO_WIDTH); @@ -239,13 +246,14 @@ void InputDialog::addDevicePortTab() void InputDialog::addMouseTab() { const int lineHeight = _font.getLineHeight(), - fontWidth = _font.getMaxCharWidth(); + fontWidth = _font.getMaxCharWidth(), + fontHeight = _font.getFontHeight(); + const int VGAP = fontHeight / 4; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; int ypos, lwidth, pwidth, tabID; WidgetArray wid; VariantList items; - const int VGAP = 4; - const int VBORDER = 8; - const int HBORDER = 8; // Mouse tabID = myTab->addTab(" Mouse ", TabWidget::AUTO_WIDTH); diff --git a/src/gui/LauncherDialog.cxx b/src/gui/LauncherDialog.cxx index 5df9d3f8d..a92b16e4a 100644 --- a/src/gui/LauncherDialog.cxx +++ b/src/gui/LauncherDialog.cxx @@ -61,14 +61,14 @@ LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font = instance().frameBuffer().launcherFont(); - const int HBORDER = 10; - const int BUTTON_GAP = 8; const int fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(), lineHeight = font.getLineHeight(), - bwidth = (_w - 2 * HBORDER - BUTTON_GAP * (4 - 1)), bheight = myUseMinimalUI ? lineHeight - 4 : lineHeight + 4, - LBL_GAP = fontWidth; + LBL_GAP = fontWidth, + HBORDER = 10,//fontWidth * 1.25, + BUTTON_GAP = fontWidth, + bwidth = (_w - 2 * HBORDER - BUTTON_GAP * (4 - 1)); int xpos = 0, ypos = 0, lwidth = 0, lwidth2 = 0; WidgetArray wid; diff --git a/src/gui/ListWidget.cxx b/src/gui/ListWidget.cxx index 850b7710b..aa8ed9455 100644 --- a/src/gui/ListWidget.cxx +++ b/src/gui/ListWidget.cxx @@ -39,11 +39,12 @@ ListWidget::ListWidget(GuiObject* boss, const GUI::Font& font, _rows = h / _fontHeight; // Set real dimensions - _w = w - kScrollBarWidth; + _w = w - ScrollBarWidget::scrollBarWidth(_font); _h = h + 2; // Create scrollbar and attach to the list - _scrollBar = new ScrollBarWidget(boss, font, _x + _w, _y, kScrollBarWidth, _h); + _scrollBar = new ScrollBarWidget(boss, font, _x + _w, _y, + ScrollBarWidget::scrollBarWidth(_font), _h); _scrollBar->setTarget(this); } @@ -144,7 +145,7 @@ void ListWidget::scrollTo(int item) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int ListWidget::getWidth() const { - return _w + kScrollBarWidth; + return _w + ScrollBarWidget::scrollBarWidth(_font); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/gui/LoggerDialog.cxx b/src/gui/LoggerDialog.cxx index 779cd1868..57a0161fc 100644 --- a/src/gui/LoggerDialog.cxx +++ b/src/gui/LoggerDialog.cxx @@ -37,8 +37,15 @@ LoggerDialog::LoggerDialog(OSystem& osystem, DialogContainer& parent, : Dialog(osystem, parent, font, "System logs") { const int lineHeight = font.getLineHeight(), - buttonWidth = font.getStringWidth("Save log to disk") + 20, - buttonHeight = font.getLineHeight() + 4; + fontWidth = font.getMaxCharWidth(), + fontHeight = font.getFontHeight(), + buttonWidth = font.getStringWidth("Save log to disk") + fontWidth * 2.5, + buttonHeight = font.getLineHeight() * 1.25; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = fontWidth * 2; + const int VGAP = fontHeight / 4; + int xpos, ypos; WidgetArray wid; @@ -47,13 +54,13 @@ LoggerDialog::LoggerDialog(OSystem& osystem, DialogContainer& parent, setSize(4000, 4000, max_w, max_h); // Test listing of the log output - xpos = 10; ypos = 10 + _th; + xpos = HBORDER; ypos = VBORDER + _th; myLogInfo = new StringListWidget(this, uselargefont ? font : instance().frameBuffer().infoFont(), xpos, ypos, _w - 2 * xpos, - _h - buttonHeight - ypos - 20 - 2 * lineHeight, false); + _h - buttonHeight - ypos - VBORDER - lineHeight - VGAP * 4, false); myLogInfo->setEditable(false); wid.push_back(myLogInfo); - ypos += myLogInfo->getHeight() + 8; + ypos += myLogInfo->getHeight() + VGAP * 2; // Level of logging (how much info to print) VariantList items; @@ -67,13 +74,13 @@ LoggerDialog::LoggerDialog(OSystem& osystem, DialogContainer& parent, wid.push_back(myLogLevel); // Should log output also be shown on the console? - xpos += myLogLevel->getWidth() + 32; + xpos += myLogLevel->getWidth() + fontWidth * 4; myLogToConsole = new CheckboxWidget(this, font, xpos, ypos + 1, "Print to console"); wid.push_back(myLogToConsole); // Add Save, OK and Cancel buttons ButtonWidget* b; - b = new ButtonWidget(this, font, 10, _h - buttonHeight - 10, + b = new ButtonWidget(this, font, HBORDER, _h - buttonHeight - VBORDER, buttonWidth, buttonHeight, "Save log to disk", GuiObject::kDefaultsCmd); wid.push_back(b); diff --git a/src/gui/OptionsDialog.cxx b/src/gui/OptionsDialog.cxx index 1b03b8cfc..0a0934d7b 100644 --- a/src/gui/OptionsDialog.cxx +++ b/src/gui/OptionsDialog.cxx @@ -49,15 +49,19 @@ OptionsDialog::OptionsDialog(OSystem& osystem, DialogContainer& parent, GuiObject* boss, int max_w, int max_h, Menu::AppMode mode) : Dialog(osystem, parent, osystem.frameBuffer().font(), "Options"), + myBoss(boss), myMode(mode) { // do not show basic settings options in debugger bool minSettings = osystem.settings().getBool("minimal_ui") && mode != Menu::AppMode::debugger; - const int buttonHeight = _font.getLineHeight() + 6, - GAP = buttonHeight > 26 ? 5 : 4, + const int lineHeight = _font.getLineHeight(), + fontWidth = _font.getMaxCharWidth(), + fontHeight = _font.getFontHeight(), + buttonHeight = _font.getLineHeight() * 1.25, + GAP = fontWidth / 2, rowHeight = buttonHeight + GAP; - const int VBORDER = GAP * 2 + 2; - const int HBORDER = GAP * 2 + 2; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; int buttonWidth = _font.getStringWidth("Game Properties" + ELLIPSIS) + GAP * 5; _w = 2 * buttonWidth + HBORDER * 3; @@ -243,8 +247,20 @@ void OptionsDialog::handleCommand(CommandSender* sender, int cmd, } case kUsrIfaceCmd: + { + // This dialog is resizable under certain conditions, so we need + // to re-create it as necessary + uInt32 w = 0, h = 0; + + if(myUIDialog == nullptr || myUIDialog->shouldResize(w, h)) + { + myUIDialog = make_unique(instance(), parent(), + instance().frameBuffer().font(), myBoss, w, h); + } + myUIDialog->open(); break; + } case kSnapCmd: { diff --git a/src/gui/OptionsDialog.hxx b/src/gui/OptionsDialog.hxx index 5842bc482..3b5598693 100644 --- a/src/gui/OptionsDialog.hxx +++ b/src/gui/OptionsDialog.hxx @@ -71,6 +71,7 @@ class OptionsDialog : public Dialog ButtonWidget* myGameInfoButton{nullptr}; ButtonWidget* myCheatCodeButton{nullptr}; + GuiObject* myBoss; // Indicates if this dialog is used for global (vs. in-game) settings Menu::AppMode myMode{Menu::AppMode::emulator}; diff --git a/src/gui/PopUpWidget.cxx b/src/gui/PopUpWidget.cxx index 9cc233060..89805621c 100644 --- a/src/gui/PopUpWidget.cxx +++ b/src/gui/PopUpWidget.cxx @@ -187,7 +187,7 @@ void PopUpWidget::handleCommand(CommandSender* sender, int cmd, int data, int id // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PopUpWidget::drawWidget(bool hilite) { - // Little down arrow + // Small down arrow static constexpr std::array down_arrow = { 0b100000001, 0b110000011, @@ -198,6 +198,21 @@ void PopUpWidget::drawWidget(bool hilite) 0b000010000, 0b000000000 }; + // Large down arrow + static constexpr std::array down_arrow_large = { + 0b00000000000, + 0b10000000001, + 0b11000000011, + 0b11100000111, + 0b11110001111, + 0b01111011110, + 0b00111111100, + 0b00011111000, + 0b00001110000, + 0b00000100000, + 0b00000000000 + }; + //cerr << "PopUpWidget::drawWidget\n"; FBSurface& s = dialog().surface(); diff --git a/src/gui/RadioButtonWidget.cxx b/src/gui/RadioButtonWidget.cxx index 7480122a2..e2b5e34df 100644 --- a/src/gui/RadioButtonWidget.cxx +++ b/src/gui/RadioButtonWidget.cxx @@ -21,6 +21,7 @@ #include "RadioButtonWidget.hxx" /* Radiobutton bitmaps */ +// small versions static constexpr std::array radio_img_outercircle = { 0b00001111110000, 0b00110000001100, 0b01000000000010, 0b01000000000010, 0b10000000000001, 0b10000000000001, @@ -33,16 +34,188 @@ static constexpr std::array radio_img_innercircle = { 0b111111111111, 0b111111111111, 0b111111111111, 0b111111111111, 0b111111111111, 0b011111111110, 0b011111111110, 0b000111111000 }; -static constexpr uInt32 RADIO_IMG_FILL_SIZE = 10; -static constexpr std::array radio_img_active = { +static constexpr std::array radio_img_active = { 0b0011111100, 0b0111111110, 0b1111111111, 0b1111111111, 0b1111111111, 0b1111111111, 0b1111111111, 0b1111111111, 0b0111111110, 0b0011111100, }; -static constexpr std::array radio_img_inactive = { +static constexpr std::array radio_img_inactive = { 0b0011111100, 0b0111111110, 0b1111001111, 0b1110000111, 0b1100000011, 0b1100000011, 0b1110000111, 0b1111001111, 0b0111111110, 0b0011111100 }; +// large versions +static constexpr std::array radio_img_outercircle_large = { + // thinner version + //0b0000000011111100000000, + //0b0000001100000011000000, + //0b0000110000000000110000, + //0b0001000000000000001000, + //0b0010000000000000000100, + //0b0010000000000000000100, + //0b0100000000000000000010, + //0b0100000000000000000010, + //0b1000000000000000000001, + //0b1000000000000000000001, + //0b1000000000000000000001, + //0b1000000000000000000001, + //0b1000000000000000000001, + //0b1000000000000000000001, + //0b0100000000000000000010, + //0b0100000000000000000010, + //0b0010000000000000000100, + //0b0010000000000000000100, + //0b0001000000000000001000, + //0b0000110000000000110000, + //0b0000001100000011000000, + //0b0000000011111100000000 + + 0b0000000011111100000000, + 0b0000001110000111000000, + 0b0000111000000001110000, + 0b0001100000000000011000, + 0b0011000000000000001100, + 0b0010000000000000000100, + 0b0110000000000000000110, + 0b0100000000000000000010, + 0b1100000000000000000011, + 0b1000000000000000000001, + 0b1000000000000000000001, + 0b1000000000000000000001, + 0b1000000000000000000001, + 0b1100000000000000000011, + 0b0100000000000000000010, + 0b0110000000000000000110, + 0b0010000000000000000100, + 0b0011000000000000001100, + 0b0001100000000000011000, + 0b0000111000000001110000, + 0b0000001110000111000000, + 0b0000000011111100000000 + +}; +static constexpr std::array radio_img_innercircle_large = { + //0b00000001111110000000, + //0b00000111111111100000, + //0b00011111111111111000, + //0b00111111111111111100, + //0b00111111111111111100, + //0b01111111111111111110, + //0b01111111111111111110, + //0b11111111111111111111, + //0b11111111111111111111, + //0b11111111111111111111, + //0b11111111111111111111, + //0b11111111111111111111, + //0b11111111111111111111, + //0b01111111111111111110, + //0b01111111111111111110, + //0b00111111111111111100, + //0b00111111111111111100, + //0b00011111111111111000, + //0b00000111111111100000, + //0b00000001111110000000 + + 0b00000000111100000000, + 0b00000011111111000000, + 0b00001111111111110000, + 0b00011111111111111000, + 0b00111111111111111100, + 0b00111111111111111100, + 0b01111111111111111110, + 0b01111111111111111110, + 0b11111111111111111111, + 0b11111111111111111111, + 0b11111111111111111111, + 0b11111111111111111111, + 0b01111111111111111110, + 0b01111111111111111110, + 0b00111111111111111100, + 0b00111111111111111100, + 0b00011111111111111000, + 0b00001111111111110000, + 0b00000011111111000000, + 0b00000000111100000000 + +}; +static constexpr std::array radio_img_active_large = { + //0b000000111111000000, + //0b000011111111110000, + //0b000111111111111000, + //0b001111111111111100, + //0b011111111111111110, + //0b011111111111111110, + //0b111111111111111111, + //0b111111111111111111, + //0b111111111111111111, + //0b111111111111111111, + //0b111111111111111111, + //0b111111111111111111, + //0b011111111111111110, + //0b011111111111111110, + //0b001111111111111100, + //0b000111111111111000, + //0b000011111111110000, + //0b000000111111000000 + + 0b000000000000000000, + 0b000000111111000000, + 0b000011111111110000, + 0b000111111111111000, + 0b001111111111111100, + 0b001111111111111100, + 0b011111111111111110, + 0b011111111111111110, + 0b011111111111111110, + 0b011111111111111110, + 0b011111111111111110, + 0b011111111111111110, + 0b001111111111111100, + 0b001111111111111100, + 0b000111111111111000, + 0b000011111111110000, + 0b000000111111000000, + 0b000000000000000000 +}; +static constexpr std::array radio_img_inactive_large = { + //0b000001111111100000, + //0b000111111111111000, + //0b001111111111111100, + //0b011111100001111110, + //0b011110000000011110, + //0b111100000000001111, + //0b111100000000001111, + //0b111000000000000111, + //0b111000000000000111, + //0b111000000000000111, + //0b111000000000000111, + //0b111100000000001111, + //0b111100000000001111, + //0b011110000000011110, + //0b011111100001111110, + //0b001111111111111100, + //0b010111111111111000, + //0b000001111111100000 + + 0b000000000000000000, + 0b000000111111000000, + 0b000011111111110000, + 0b000111111111111000, + 0b001111100001111100, + 0b001111000000111100, + 0b011110000000011110, + 0b011100000000001110, + 0b011100000000001110, + 0b011100000000001110, + 0b011100000000001110, + 0b011110000000011110, + 0b001111000000111100, + 0b001111100001111100, + 0b000111111111111000, + 0b000011111111110000, + 0b000000111111000000, + 0b000000000000000000 +}; + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RadioButtonWidget::RadioButtonWidget(GuiObject* boss, const GUI::Font& font, int x, int y, const string& label, @@ -54,19 +227,31 @@ RadioButtonWidget::RadioButtonWidget(GuiObject* boss, const GUI::Font& font, _bgcolor = _bgcolorhi = kWidColor; _editable = true; + _buttonSize = buttonSize(font); // 14 | 22 + + if(_buttonSize == 14) + { + _outerCircle = radio_img_outercircle.data(); + _innerCircle = radio_img_innercircle.data(); + } + else + { + _outerCircle = radio_img_outercircle_large.data(); + _innerCircle = radio_img_innercircle_large.data(); + } if(label == "") - _w = 14; + _w = _buttonSize; else - _w = font.getStringWidth(label) + 20; - _h = font.getFontHeight() < 14 ? 14 : font.getFontHeight(); + _w = font.getStringWidth(label) + _buttonSize + font.getMaxCharWidth() * 0.75; + _h = font.getFontHeight() < int(_buttonSize) ? _buttonSize : font.getFontHeight(); // Depending on font size, either the font or box will need to be // centered vertically - if(_h > 14) // center box - _boxY = (_h - 14) / 2; + if(_h > int(_buttonSize)) // center box + _boxY = (_h - _buttonSize) / 2; else // center text - _textY = (14 - _font.getFontHeight()) / 2; + _textY = (_buttonSize - _font.getFontHeight()) / 2; setFill(CheckboxWidget::FillType::Normal); myGroup->addWidget(this); @@ -102,10 +287,10 @@ void RadioButtonWidget::setFill(FillType type) switch(type) { case CheckboxWidget::FillType::Normal: - _img = radio_img_active.data(); + _img = _buttonSize == 14 ? radio_img_active.data() : radio_img_active_large.data(); break; case CheckboxWidget::FillType::Inactive: - _img = radio_img_inactive.data(); + _img = _buttonSize == 14 ? radio_img_inactive.data(): radio_img_inactive_large.data(); break; default: break; @@ -118,25 +303,23 @@ void RadioButtonWidget::drawWidget(bool hilite) FBSurface& s = _boss->dialog().surface(); // Draw the outer bounding circle - s.drawBitmap(radio_img_outercircle.data(), _x, _y + _boxY, + s.drawBitmap(_outerCircle, _x, _y + _boxY, hilite ? kWidColorHi : kColor, - static_cast(radio_img_outercircle.size()), - static_cast(radio_img_outercircle.size())); + _buttonSize); // Draw the inner bounding circle with enabled color - s.drawBitmap(radio_img_innercircle.data(), _x + 1, _y + _boxY + 1, + s.drawBitmap(_innerCircle, _x + 1, _y + _boxY + 1, isEnabled() ? _bgcolor : kColor, - static_cast(radio_img_innercircle.size()), - static_cast(radio_img_innercircle.size())); + _buttonSize - 2); // draw state if(_state) s.drawBitmap(_img, _x + 2, _y + _boxY + 2, isEnabled() ? hilite ? kWidColorHi : kCheckColor - : kColor, RADIO_IMG_FILL_SIZE); + : kColor, _buttonSize - 4); // Finally draw the label - s.drawString(_font, _label, _x + 20, _y + _textY, _w, + s.drawString(_font, _label, _x + _buttonSize + _font.getMaxCharWidth() * 0.75, _y + _textY, _w, isEnabled() ? kTextColor : kColor); } diff --git a/src/gui/RadioButtonWidget.hxx b/src/gui/RadioButtonWidget.hxx index 840cc2dd2..8003a8627 100644 --- a/src/gui/RadioButtonWidget.hxx +++ b/src/gui/RadioButtonWidget.hxx @@ -40,9 +40,14 @@ class RadioButtonWidget : public CheckboxWidget protected: void setFill(FillType type); void drawWidget(bool hilite) override; + static int buttonSize(const GUI::Font& font) + { + return font.getFontHeight() < 24 ? 14 : 22; // box is square + } private: RadioButtonGroup* myGroup{nullptr}; + uInt32 _buttonSize{14}; private: // Following constructors and assignment operators not supported diff --git a/src/gui/RomAuditDialog.cxx b/src/gui/RomAuditDialog.cxx index f83586d45..580263730 100644 --- a/src/gui/RomAuditDialog.cxx +++ b/src/gui/RomAuditDialog.cxx @@ -40,15 +40,17 @@ RomAuditDialog::RomAuditDialog(OSystem& osystem, DialogContainer& parent, myMaxWidth(max_w), myMaxHeight(max_h) { - const int VBORDER = 10 + _th; - const int HBORDER = 10; - const int lineHeight = font.getLineHeight(), fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(), - buttonWidth = font.getStringWidth("Audit path" + ELLIPSIS) + 20, - buttonHeight = font.getLineHeight() + 4, + buttonWidth = font.getStringWidth("Audit path" + ELLIPSIS) + fontWidth * 2.5, + buttonHeight = font.getLineHeight() * 1.25, lwidth = font.getStringWidth("ROMs without properties (skipped) "); + const int VBORDER = _th + fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = fontWidth * 2; + const int VGAP = fontHeight / 4; + int xpos, ypos = VBORDER; WidgetArray wid; @@ -62,28 +64,24 @@ RomAuditDialog::RomAuditDialog(OSystem& osystem, DialogContainer& parent, "Audit path" + ELLIPSIS, kChooseAuditDirCmd); wid.push_back(romButton); xpos = HBORDER + buttonWidth + 8; - myRomPath = new EditTextWidget(this, font, xpos, ypos + 1, + myRomPath = new EditTextWidget(this, font, xpos, ypos + (buttonHeight - lineHeight) / 2 - 1, _w - xpos - HBORDER, lineHeight, ""); wid.push_back(myRomPath); // Show results of ROM audit ypos += buttonHeight + 16; - new StaticTextWidget(this, font, HBORDER, ypos, lwidth, fontHeight, - "ROMs with properties (renamed) ", TextAlign::Left); + new StaticTextWidget(this, font, HBORDER, ypos, "ROMs with properties (renamed) "); myResults1 = new EditTextWidget(this, font, HBORDER + lwidth, ypos - 2, fontWidth * 6, lineHeight, ""); myResults1->setEditable(false, true); ypos += buttonHeight; - new StaticTextWidget(this, font, HBORDER, ypos, lwidth, fontHeight, - "ROMs without properties (skipped) ", TextAlign::Left); + new StaticTextWidget(this, font, HBORDER, ypos, "ROMs without properties (skipped) "); myResults2 = new EditTextWidget(this, font, HBORDER + lwidth, ypos - 2, fontWidth * 6, lineHeight, ""); myResults2->setEditable(false, true); ypos += buttonHeight + 8; - new StaticTextWidget(this, font, HBORDER, ypos, _w - 20, fontHeight, - "(*) WARNING: Operation cannot be undone!", - TextAlign::Left); + new StaticTextWidget(this, font, HBORDER, ypos, "(*) WARNING: Operation cannot be undone!"); // Add OK and Cancel buttons addOKCancelBGroup(wid, font, "Audit", "Close"); diff --git a/src/gui/RomInfoWidget.cxx b/src/gui/RomInfoWidget.cxx index 16a6790cb..c935f54dc 100644 --- a/src/gui/RomInfoWidget.cxx +++ b/src/gui/RomInfoWidget.cxx @@ -205,14 +205,21 @@ void RomInfoWidget::drawWidget(bool hilite) int xpos = _x + 8, ypos = _y + yoff + 5; for(const auto& info : myRomInfo) { + if(info.length() * _font.getMaxCharWidth() <= _w - 16) - - + { + // 1 line for next entry + if(ypos + _font.getFontHeight() > _h + _y) + break; + } + else + { + // assume 2 lines for next entry + if(ypos + _font.getLineHeight() + _font.getFontHeight() > _h + _y ) + break; + } int lines = s.drawString(_font, info, xpos, ypos, _w - 16, _font.getFontHeight() * 3, onTop ? _textcolor : _shadowcolor); ypos += _font.getLineHeight() + (lines - 1) * _font.getFontHeight(); - // assume 2 lines for next entry - if(ypos >= _h + _y - _font.getLineHeight() - _font.getFontHeight()) - break; } } diff --git a/src/gui/ScrollBarWidget.cxx b/src/gui/ScrollBarWidget.cxx index 4d055a027..335b716de 100644 --- a/src/gui/ScrollBarWidget.cxx +++ b/src/gui/ScrollBarWidget.cxx @@ -28,8 +28,6 @@ * and we thus should not highlight the arrows/slider. */ -#define UP_DOWN_BOX_HEIGHT 18 - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ScrollBarWidget::ScrollBarWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h) @@ -38,6 +36,76 @@ ScrollBarWidget::ScrollBarWidget(GuiObject* boss, const GUI::Font& font, _flags = Widget::FLAG_ENABLED | Widget::FLAG_TRACK_MOUSE | Widget::FLAG_CLEARBG; _bgcolor = kWidColor; _bgcolorhi = kWidColor; + + _scrollBarWidth = scrollBarWidth(font); + + setArrows(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void ScrollBarWidget::setArrows() +{ + // Small up arrow + static constexpr std::array up_arrow = { + 0b0001000, + 0b0011100, + 0b0111110, + 0b1110111, + 0b1100011, + 0b1000001, + }; + // Small down arrow + static constexpr std::array down_arrow = { + 0b1000001, + 0b1100011, + 0b1110111, + 0b0111110, + 0b0011100, + 0b0001000 + }; + + // Large up arrow + static constexpr std::array up_arrow_large = { + 0b00000100000, + 0b00001110000, + 0b00011111000, + 0b00111111100, + 0b01111011110, + 0b11110001111, + 0b11100000111, + 0b11000000011, + 0b10000000001, + }; + // Large down arrow + static constexpr std::array down_arrow_large = { + 0b10000000001, + 0b11000000011, + 0b11100000111, + 0b11110001111, + 0b01111011110, + 0b00111111100, + 0b00011111000, + 0b00001110000, + 0b00000100000 + }; + + + if(_font.getFontHeight() < 24) + { + _upDownWidth = 7; + _upDownHeight = 6; + _upDownBoxHeight = 18; + _upImg = up_arrow.data(); + _downImg = down_arrow.data(); + } + else + { + _upDownWidth = 11; + _upDownHeight = 9; + _upDownBoxHeight = 27; + _upImg = up_arrow_large.data(); + _downImg = down_arrow_large.data(); + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -54,13 +122,13 @@ void ScrollBarWidget::handleMouseDown(int x, int y, MouseButton b, if(_numEntries <= _entriesPerPage) return; - if (y <= UP_DOWN_BOX_HEIGHT) + if (y <= _upDownBoxHeight) { // Up arrow _currentPos--; _draggingPart = Part::UpArrow; } - else if(y >= _h - UP_DOWN_BOX_HEIGHT) + else if(y >= _h - _upDownBoxHeight) { // Down arrow _currentPos++; @@ -120,23 +188,23 @@ void ScrollBarWidget::handleMouseMoved(int x, int y) int old_pos = _currentPos; _sliderPos = y - _sliderDeltaMouseDownPos; - if(_sliderPos < UP_DOWN_BOX_HEIGHT) - _sliderPos = UP_DOWN_BOX_HEIGHT; + if(_sliderPos < _upDownBoxHeight) + _sliderPos = _upDownBoxHeight; - if(_sliderPos > _h - UP_DOWN_BOX_HEIGHT - _sliderHeight) - _sliderPos = _h - UP_DOWN_BOX_HEIGHT - _sliderHeight; + if(_sliderPos > _h - _upDownBoxHeight - _sliderHeight) + _sliderPos = _h - _upDownBoxHeight - _sliderHeight; - _currentPos = (_sliderPos - UP_DOWN_BOX_HEIGHT) * (_numEntries - _entriesPerPage) / - (_h - 2 * UP_DOWN_BOX_HEIGHT - _sliderHeight); + _currentPos = (_sliderPos - _upDownBoxHeight) * (_numEntries - _entriesPerPage) / + (_h - 2 * _upDownBoxHeight - _sliderHeight); checkBounds(old_pos); } else { Part old_part = _part; - if(y <= UP_DOWN_BOX_HEIGHT) // Up arrow + if(y <= _upDownBoxHeight) // Up arrow _part = Part::UpArrow; - else if(y >= _h - UP_DOWN_BOX_HEIGHT) // Down arrow + else if(y >= _h - _upDownBoxHeight) // Down arrow _part = Part::DownArrow; else if(y < _sliderPos) _part = Part::PageUp; @@ -193,19 +261,19 @@ void ScrollBarWidget::recalc() //cerr << "ScrollBarWidget::recalc()\n"; if(_numEntries > _entriesPerPage) { - _sliderHeight = (_h - 2 * UP_DOWN_BOX_HEIGHT) * _entriesPerPage / _numEntries; - if(_sliderHeight < UP_DOWN_BOX_HEIGHT) - _sliderHeight = UP_DOWN_BOX_HEIGHT; + _sliderHeight = (_h - 2 * _upDownBoxHeight) * _entriesPerPage / _numEntries; + if(_sliderHeight < _upDownBoxHeight) + _sliderHeight = _upDownBoxHeight; - _sliderPos = UP_DOWN_BOX_HEIGHT + (_h - 2 * UP_DOWN_BOX_HEIGHT - _sliderHeight) * + _sliderPos = _upDownBoxHeight + (_h - 2 * _upDownBoxHeight - _sliderHeight) * _currentPos / (_numEntries - _entriesPerPage); if(_sliderPos < 0) _sliderPos = 0; } else { - _sliderHeight = _h - 2 * UP_DOWN_BOX_HEIGHT; - _sliderPos = UP_DOWN_BOX_HEIGHT; + _sliderHeight = _h - 2 * _upDownBoxHeight; + _sliderPos = _upDownBoxHeight; } setDirty(); @@ -214,30 +282,6 @@ void ScrollBarWidget::recalc() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ScrollBarWidget::drawWidget(bool hilite) { - // Up arrow - static constexpr std::array up_arrow = { - 0b00000000, - 0b00010000, - 0b00111000, - 0b01111100, - 0b11101110, - 0b11000110, - 0b10000010, - 0b00000000 - }; - - // Down arrow - static constexpr std::array down_arrow = { - 0b00000000, - 0b10000010, - 0b11000110, - 0b11101110, - 0b01111100, - 0b00111000, - 0b00010000, - 0b00000000 - }; - //cerr << "ScrollBarWidget::drawWidget\n"; FBSurface& s = _boss->dialog().surface(); bool onTop = _boss->dialog().isOnTop(); @@ -251,17 +295,19 @@ void ScrollBarWidget::drawWidget(bool hilite) // Up arrow if(hilite && _part == Part::UpArrow) - s.fillRect(_x + 1, _y + 1, _w - 2, UP_DOWN_BOX_HEIGHT - 2, kScrollColor); - s.drawBitmap(up_arrow.data(), _x+4, _y+5, + s.fillRect(_x + 1, _y + 1, _w - 2, _upDownBoxHeight - 2, kScrollColor); + s.drawBitmap(_upImg, _x + (_scrollBarWidth - _upDownWidth) / 2, + _y + (_upDownBoxHeight - _upDownHeight) / 2, onTop ? isSinglePage ? kColor : (hilite && _part == Part::UpArrow) ? kWidColor - : kTextColor : kColor, 8); + : kTextColor : kColor, _upDownWidth, _upDownHeight); // Down arrow if(hilite && _part == Part::DownArrow) - s.fillRect(_x + 1, bottomY - UP_DOWN_BOX_HEIGHT + 1, _w - 2, UP_DOWN_BOX_HEIGHT - 2, kScrollColor); - s.drawBitmap(down_arrow.data(), _x+4, bottomY - UP_DOWN_BOX_HEIGHT + 5, + s.fillRect(_x + 1, bottomY - _upDownBoxHeight + 1, _w - 2, _upDownBoxHeight - 2, kScrollColor); + s.drawBitmap(_downImg, _x + (_scrollBarWidth - _upDownWidth) / 2, + bottomY - _upDownBoxHeight + (_upDownBoxHeight - _upDownHeight) / 2, onTop ? isSinglePage ? kColor : (hilite && _part == Part::DownArrow) ? - kWidColor : kTextColor : kColor, 8); + kWidColor : kTextColor : kColor, _upDownWidth, _upDownHeight); // Slider if(!isSinglePage) @@ -273,3 +319,4 @@ void ScrollBarWidget::drawWidget(bool hilite) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int ScrollBarWidget::_WHEEL_LINES = 4; + diff --git a/src/gui/ScrollBarWidget.hxx b/src/gui/ScrollBarWidget.hxx index bbe227559..eddcd18d2 100644 --- a/src/gui/ScrollBarWidget.hxx +++ b/src/gui/ScrollBarWidget.hxx @@ -24,10 +24,6 @@ class GuiObject; #include "Command.hxx" #include "bspf.hxx" -enum { - kScrollBarWidth = 15 -}; - class ScrollBarWidget : public Widget, public CommandSender { public: @@ -40,6 +36,10 @@ class ScrollBarWidget : public Widget, public CommandSender static void setWheelLines(int lines) { _WHEEL_LINES = lines; } static int getWheelLines() { return _WHEEL_LINES; } + static int scrollBarWidth(const GUI::Font& font) + { + return ((int(font.getMaxCharWidth() * 1.67) >> 1) << 1) + 1; + } private: void drawWidget(bool hilite) override; @@ -51,6 +51,7 @@ class ScrollBarWidget : public Widget, public CommandSender bool handleMouseClicks(int x, int y, MouseButton b) override; void handleMouseEntered() override; void handleMouseLeft() override; + void setArrows(); public: int _numEntries{0}; @@ -66,6 +67,12 @@ class ScrollBarWidget : public Widget, public CommandSender int _sliderHeight{0}; int _sliderPos{0}; int _sliderDeltaMouseDownPos{0}; + int _upDownWidth{0}; + int _upDownHeight{0}; + int _upDownBoxHeight{0}; + int _scrollBarWidth{0}; + const uInt32* _upImg{nullptr}; + const uInt32* _downImg{nullptr}; static int _WHEEL_LINES; diff --git a/src/gui/SnapshotDialog.cxx b/src/gui/SnapshotDialog.cxx index c1f94d52f..2c0534ffa 100644 --- a/src/gui/SnapshotDialog.cxx +++ b/src/gui/SnapshotDialog.cxx @@ -30,20 +30,22 @@ SnapshotDialog::SnapshotDialog(OSystem& osystem, DialogContainer& parent, : Dialog(osystem, parent, font, "Snapshot settings"), myFont(font) { - const int VBORDER = 10; - const int HBORDER = 10; - const int INDENT = 16; - const int V_GAP = 4; const int lineHeight = font.getLineHeight(), + fontHeight = _font.getFontHeight(), fontWidth = font.getMaxCharWidth(), - buttonWidth = font.getStringWidth("Save path" + ELLIPSIS) + 20, - buttonHeight = font.getLineHeight() + 4; + buttonWidth = font.getStringWidth("Save path" + ELLIPSIS) + fontWidth * 2.5, + buttonHeight = font.getLineHeight() * 1.25; + const int HBORDER = fontWidth * 1.25; + const int VBORDER = fontHeight / 4; + const int INDENT = fontWidth * 2; + const int VGAP = fontHeight / 4; + int xpos, ypos, fwidth; WidgetArray wid; ButtonWidget* b; // Set real dimensions - setSize(64 * fontWidth + HBORDER * 2, 9 * (lineHeight + 4) + VBORDER + _th, max_w, max_h); + setSize(64 * fontWidth + HBORDER * 2, 9 * (lineHeight + VGAP) + VBORDER + _th, max_w, max_h); xpos = HBORDER; ypos = VBORDER + _th; @@ -51,13 +53,13 @@ SnapshotDialog::SnapshotDialog(OSystem& osystem, DialogContainer& parent, b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Save path" + ELLIPSIS, kChooseSnapSaveDirCmd); wid.push_back(b); - xpos += buttonWidth + 8; - mySnapSavePath = new EditTextWidget(this, font, xpos, ypos + 1, + xpos += buttonWidth + fontWidth; + mySnapSavePath = new EditTextWidget(this, font, xpos, ypos + (buttonHeight - lineHeight) / 2 - 1, _w - xpos - HBORDER, lineHeight, ""); wid.push_back(mySnapSavePath); // Snapshot naming - xpos = HBORDER; ypos += buttonHeight + V_GAP * 4; + xpos = HBORDER; ypos += buttonHeight + VGAP * 4; // Snapshot interval (continuous mode) mySnapInterval = new SliderWidget(this, font, xpos, ypos, @@ -70,21 +72,21 @@ SnapshotDialog::SnapshotDialog(OSystem& osystem, DialogContainer& parent, // Booleans for saving snapshots fwidth = font.getStringWidth("When saving snapshots:"); - xpos = HBORDER; ypos += lineHeight + V_GAP * 3; + xpos = HBORDER; ypos += lineHeight + VGAP * 3; new StaticTextWidget(this, font, xpos, ypos, fwidth, lineHeight, "When saving snapshots:", TextAlign::Left); // Snapshot single or multiple saves - xpos += INDENT; ypos += lineHeight + V_GAP; + xpos += INDENT; ypos += lineHeight + VGAP; mySnapName = new CheckboxWidget(this, font, xpos, ypos, "Use actual ROM name"); wid.push_back(mySnapName); - ypos += lineHeight + V_GAP; + ypos += lineHeight + VGAP; mySnapSingle = new CheckboxWidget(this, font, xpos, ypos, "Overwrite existing files"); wid.push_back(mySnapSingle); // Snapshot in 1x mode (ignore scaling) - ypos += lineHeight + V_GAP; + ypos += lineHeight + VGAP; mySnap1x = new CheckboxWidget(this, font, xpos, ypos, "Ignore scaling (1x mode)"); wid.push_back(mySnap1x); diff --git a/src/gui/UIDialog.cxx b/src/gui/UIDialog.cxx index fd52fa483..27d0ad9ee 100644 --- a/src/gui/UIDialog.cxx +++ b/src/gui/UIDialog.cxx @@ -48,12 +48,11 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, const int lineHeight = font.getLineHeight(), fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(), - buttonHeight = font.getLineHeight() + 4; - - const int VBORDER = 8; - const int HBORDER = 10; - const int INDENT = 16; - const int V_GAP = 4; + buttonHeight = font.getLineHeight() * 1.25; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = fontWidth * 2; + const int VGAP = fontHeight / 4; int xpos, ypos, tabID; int lwidth, pwidth, bwidth; WidgetArray wid; @@ -61,11 +60,14 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, const Common::Size& ds = instance().frameBuffer().desktopSize(); // Set real dimensions - setSize(64 * fontWidth + HBORDER * 2, 11 * (lineHeight + V_GAP) + V_GAP * 9 + VBORDER + _th, + setSize(64 * fontWidth + HBORDER * 2, + _th + VGAP * 3 + lineHeight + 10 * (lineHeight + VGAP) + VGAP * 2 + buttonHeight + VBORDER * 3, max_w, max_h); // The tab widget - myTab = new TabWidget(this, font, 2, 4 + _th, _w - 2*2, _h - _th - buttonHeight - 20); + myTab = new TabWidget(this, font, 2, VGAP + _th, + _w - 2*2, + _h - _th - VGAP - buttonHeight - VBORDER * 2); addTabWidget(myTab); ////////////////////////////////////////////////////////// @@ -85,12 +87,27 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, myPalettePopup = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, "Theme ", lwidth); wid.push_back(myPalettePopup); + ypos += lineHeight + VGAP; + + + // Dialog font + items.clear(); + VarList::push_back(items, "Small", "small"); // 8x13 + VarList::push_back(items, "Low Medium", "low_medium"); // 9x15 + VarList::push_back(items, "Medium", "medium"); // 9x18 + VarList::push_back(items, "Large (10pt)", "large"); // 10x20 + VarList::push_back(items, "Large (12pt)", "large12"); // 12x24 + VarList::push_back(items, "Large (14pt)", "large14"); // 14x28 + VarList::push_back(items, "Large (16pt)", "large16"); // 16x32 + myDialogFontPopup = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, + items, "Dialogs font (*)", lwidth); + wid.push_back(myDialogFontPopup); // Enable HiDPI mode - myHidpiWidget = new CheckboxWidget(myTab, font, myPalettePopup->getRight() + 40, - ypos, "HiDPI mode (*)"); + myHidpiWidget = new CheckboxWidget(myTab, font, myDialogFontPopup->getRight() + fontWidth * 5, + ypos + 1, "HiDPI mode (*)"); wid.push_back(myHidpiWidget); - ypos += lineHeight + V_GAP; + ypos += lineHeight + VGAP; // Dialog position items.clear(); @@ -100,14 +117,14 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, VarList::push_back(items, "Right bottom", 3); VarList::push_back(items, "Left bottom", 4); myPositionPopup = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, - items, "Dialogs position ", lwidth); + items, "Dialogs position", lwidth); wid.push_back(myPositionPopup); - ypos += lineHeight + V_GAP * 2; + ypos += lineHeight + VGAP * 2; // Confirm dialog when exiting emulation myConfirmExitWidget = new CheckboxWidget(myTab, font, xpos, ypos, "Confirm exiting emulation"); wid.push_back(myConfirmExitWidget); - ypos += lineHeight + V_GAP * 3; + ypos += lineHeight + VGAP * 3; // Delay between quick-selecting characters in ListWidget int swidth = myPalettePopup->getWidth() - lwidth; @@ -119,7 +136,7 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, myListDelaySlider->setStepValue(50); myListDelaySlider->setTickmarkIntervals(5); wid.push_back(myListDelaySlider); - ypos += lineHeight + V_GAP; + ypos += lineHeight + VGAP; // Number of lines a mouse wheel will scroll myWheelLinesSlider = new SliderWidget(myTab, font, xpos, ypos, swidth, lineHeight, @@ -129,7 +146,7 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, myWheelLinesSlider->setMaxValue(10); myWheelLinesSlider->setTickmarkIntervals(3); wid.push_back(myWheelLinesSlider); - ypos += lineHeight + V_GAP; + ypos += lineHeight + VGAP; // Mouse double click speed myDoubleClickSlider = new SliderWidget(myTab, font, xpos, ypos, swidth, lineHeight, @@ -140,7 +157,7 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, myDoubleClickSlider->setStepValue(50); myDoubleClickSlider->setTickmarkIntervals(8); wid.push_back(myDoubleClickSlider); - ypos += lineHeight + V_GAP; + ypos += lineHeight + VGAP; // Initial delay before controller input will start repeating myControllerDelaySlider = new SliderWidget(myTab, font, xpos, ypos, swidth, lineHeight, @@ -151,7 +168,7 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, myControllerDelaySlider->setStepValue(100); myControllerDelaySlider->setTickmarkIntervals(4); wid.push_back(myControllerDelaySlider); - ypos += lineHeight + V_GAP; + ypos += lineHeight + VGAP; // Controller repeat rate myControllerRateSlider = new SliderWidget(myTab, font, xpos, ypos, swidth, lineHeight, @@ -164,10 +181,11 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, wid.push_back(myControllerRateSlider); // Add message concerning usage - ypos = myTab->getHeight() - 5 - fontHeight - ifont.getFontHeight() - 10; - lwidth = ifont.getStringWidth("(*) Change requires application restart"); - new StaticTextWidget(myTab, ifont, xpos, ypos, std::min(lwidth, _w - 20), fontHeight, - "(*) Change requires application restart"); + ypos = myTab->getHeight() - fontHeight - ifont.getFontHeight() - VGAP - VBORDER; + lwidth = ifont.getStringWidth("(*) Changes require application restart"); + new StaticTextWidget(myTab, ifont, xpos, ypos, + std::min(lwidth, _w - HBORDER * 2), ifont.getFontHeight(), + "(*) Changes require application restart"); // Add items for tab 0 addToFocusList(wid, myTab, tabID); @@ -185,18 +203,18 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, new ButtonWidget(myTab, font, xpos, ypos, bwidth, buttonHeight, "ROM path" + ELLIPSIS, kChooseRomDirCmd); wid.push_back(romButton); - xpos = romButton->getRight() + 8; - myRomPath = new EditTextWidget(myTab, font, xpos, ypos + 1, + xpos = romButton->getRight() + fontWidth; + myRomPath = new EditTextWidget(myTab, font, xpos, ypos + (buttonHeight - lineHeight) / 2 - 1, _w - xpos - HBORDER - 2, lineHeight, ""); wid.push_back(myRomPath); - xpos = _w - HBORDER - font.getStringWidth("Follow Launcher path") - 24; - ypos += lineHeight + V_GAP * 2; + xpos = _w - HBORDER - font.getStringWidth("Follow Launcher path") - CheckboxWidget::prefixSize(font); + ypos += lineHeight + VGAP * 2; myFollowLauncherWidget = new CheckboxWidget(myTab, font, xpos, ypos, "Follow Launcher path"); wid.push_back(myFollowLauncherWidget); xpos = HBORDER; - ypos += V_GAP * 2; + ypos += VGAP * 2; // Launcher width and height myLauncherWidthSlider = new SliderWidget(myTab, font, xpos, ypos, "Launcher width ", @@ -207,7 +225,7 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, // one tickmark every ~100 pixel myLauncherWidthSlider->setTickmarkIntervals((ds.w - FBMinimum::Width + 50) / 100); wid.push_back(myLauncherWidthSlider); - ypos += lineHeight + V_GAP; + ypos += lineHeight + VGAP; myLauncherHeightSlider = new SliderWidget(myTab, font, xpos, ypos, "Launcher height ", lwidth, 0, 6 * fontWidth, "px"); @@ -217,7 +235,7 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, // one tickmark every ~100 pixel myLauncherHeightSlider->setTickmarkIntervals((ds.h - FBMinimum::Height + 50) / 100); wid.push_back(myLauncherHeightSlider); - ypos += lineHeight + V_GAP; + ypos += lineHeight + VGAP; // Launcher font pwidth = font.getStringWidth("2x (1000x760)"); @@ -233,7 +251,7 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, new PopUpWidget(myTab, font, xpos, ypos + 1, pwidth, lineHeight, items, "Launcher font ", lwidth); wid.push_back(myLauncherFontPopup); - ypos += lineHeight + V_GAP * 4; + ypos += lineHeight + VGAP * 4; // ROM launcher info/snapshot viewer myRomViewerSize = new SliderWidget(myTab, font, xpos, ypos, "ROM info width ", @@ -245,19 +263,20 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, myRomViewerSize->setTickmarkIntervals((myRomViewerSize->getMaxValue() - myRomViewerSize->getMinValue()) / 20); wid.push_back(myRomViewerSize); - ypos += lineHeight + V_GAP; + ypos += lineHeight + VGAP; // Snapshot path (load files) xpos = HBORDER + INDENT; - bwidth = font.getStringWidth("Image path" + ELLIPSIS) + 20 + 1; + bwidth = font.getStringWidth("Image path" + ELLIPSIS) + fontWidth * 2 + 1; myOpenBrowserButton = new ButtonWidget(myTab, font, xpos, ypos, bwidth, buttonHeight, "Image path" + ELLIPSIS, kChooseSnapLoadDirCmd); wid.push_back(myOpenBrowserButton); - mySnapLoadPath = new EditTextWidget(myTab, font, HBORDER + lwidth, ypos + 1, + mySnapLoadPath = new EditTextWidget(myTab, font, HBORDER + lwidth, + ypos + (buttonHeight - lineHeight) / 2 - 1, _w - lwidth - HBORDER * 2 - 2, lineHeight, ""); wid.push_back(mySnapLoadPath); - ypos += lineHeight + V_GAP * 4; + ypos += lineHeight + VGAP * 4; // Exit to Launcher xpos = HBORDER; @@ -266,9 +285,10 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, // Add message concerning usage xpos = HBORDER; - ypos = myTab->getHeight() - 5 - fontHeight - ifont.getFontHeight() - 10; + ypos = myTab->getHeight() - fontHeight - ifont.getFontHeight() - VGAP - VBORDER; lwidth = ifont.getStringWidth("(*) Changes require application restart"); - new StaticTextWidget(myTab, ifont, xpos, ypos, std::min(lwidth, _w - 20), fontHeight, + new StaticTextWidget(myTab, ifont, xpos, ypos, + std::min(lwidth, _w - HBORDER * 2), ifont.getFontHeight(), "(*) Changes require application restart"); // Add items for tab 1 @@ -319,8 +339,8 @@ void UIDialog::loadConfig() myFollowLauncherWidget->setState(settings.getBool("followlauncher")); // Launcher font - const string& font = settings.getString("launcherfont"); - myLauncherFontPopup->setSelected(font, "medium"); + const string& launcherFont = settings.getString("launcherfont"); + myLauncherFontPopup->setSelected(launcherFont, "medium"); // ROM launcher info viewer float zoom = instance().settings().getFloat("romviewer"); @@ -352,6 +372,10 @@ void UIDialog::loadConfig() // Confirm dialog when exiting emulation myConfirmExitWidget->setState(settings.getBool("confirmexit")); + // Dialog font + const string& dialogFont = settings.getString("dialogfont"); + myDialogFontPopup->setSelected(dialogFont, "medium"); + // Dialog position myPositionPopup->setSelected(settings.getString("dialogpos"), "0"); @@ -398,7 +422,7 @@ void UIDialog::saveConfig() // Launcher font settings.setValue("launcherfont", - myLauncherFontPopup->getSelectedTag().toString()); + myLauncherFontPopup->getSelectedTag().toString()); // ROM launcher info viewer int w = myLauncherWidthSlider->getValue(); @@ -419,6 +443,10 @@ void UIDialog::saveConfig() // Enable HiDPI mode settings.setValue("hidpi", myHidpiWidget->getState()); + // Dialog font + settings.setValue("dialogfont", + myDialogFontPopup->getSelectedTag().toString()); + // Dialog position settings.setValue("dialogpos", myPositionPopup->getSelectedTag().toString()); @@ -458,6 +486,7 @@ void UIDialog::setDefaults() case 0: // Misc. options myPalettePopup->setSelected("standard"); myHidpiWidget->setState(false); + myDialogFontPopup->setSelected("medium", ""); myPositionPopup->setSelected("0"); myConfirmExitWidget->setState(false); myListDelaySlider->setValue(300); diff --git a/src/gui/UIDialog.hxx b/src/gui/UIDialog.hxx index 4517396d0..5a0b8ae03 100644 --- a/src/gui/UIDialog.hxx +++ b/src/gui/UIDialog.hxx @@ -66,6 +66,7 @@ class UIDialog : public Dialog, public CommandSender // Misc options PopUpWidget* myPalettePopup{nullptr}; CheckboxWidget* myHidpiWidget{nullptr}; + PopUpWidget* myDialogFontPopup{nullptr}; PopUpWidget* myPositionPopup{nullptr}; CheckboxWidget* myConfirmExitWidget{nullptr}; SliderWidget* myListDelaySlider{nullptr}; diff --git a/src/gui/VideoDialog.cxx b/src/gui/VideoDialog.cxx index 981e1a4e0..b7aa2a2d5 100644 --- a/src/gui/VideoDialog.cxx +++ b/src/gui/VideoDialog.cxx @@ -78,27 +78,33 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, int max_w, int max_h) : Dialog(osystem, parent, font, "Video settings") { - const int VGAP = 4; - const int VBORDER = 8; - const int HBORDER = 10; - const int INDENT = 20; const int lineHeight = font.getLineHeight(), + fontHeight = font.getFontHeight(), fontWidth = font.getMaxCharWidth(), - buttonHeight = font.getLineHeight() + 4; + buttonHeight = font.getLineHeight() * 1.25; + const int VGAP = fontHeight / 4; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = fontWidth * 2; + int xpos, ypos, tabID; int lwidth = font.getStringWidth("V-Size adjust "), - pwidth = font.getStringWidth("XXXXxXXXX"), - swidth = font.getMaxCharWidth() * 10 - 2; + pwidth = font.getStringWidth("XXXXxXXXX"), + swidth = font.getMaxCharWidth() * 10 - 2; WidgetArray wid; VariantList items; // Set real dimensions - setSize(60 * fontWidth + HBORDER * 2, 14 * (lineHeight + VGAP) + 14 + _th, max_w, max_h); + setSize(60 * fontWidth + HBORDER * 2, + _th + VGAP * 3 + lineHeight + 11 * (lineHeight + VGAP) + buttonHeight + VBORDER * 3, + max_w, max_h); // The tab widget - xpos = 2; ypos = 4; - myTab = new TabWidget(this, font, xpos, ypos + _th, _w - 2*xpos, _h - _th - buttonHeight - 20); + xpos = 2; ypos = VGAP; + myTab = new TabWidget(this, font, xpos, ypos + _th, + _w - 2*xpos, + _h - _th - VGAP - buttonHeight - VBORDER * 2); addTabWidget(myTab); xpos = HBORDER; ypos = VBORDER; @@ -160,7 +166,7 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, wid.push_back(myUseVSync); // Move over to the next column - xpos += mySpeed->getWidth() + 44; + xpos = myVSizeAdjust->getRight() + fontWidth * 3; ypos = VBORDER; // Fullscreen @@ -216,7 +222,7 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, tabID = myTab->addTab(" TV Effects "); xpos = HBORDER; ypos = VBORDER; - swidth = font.getMaxCharWidth() * 8 - 4; + swidth = fontWidth * 8 - fontWidth / 2; // TV Mode items.clear(); @@ -258,7 +264,7 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, CREATE_CUSTOM_SLIDERS(Fringe, "Fringing ", 0) CREATE_CUSTOM_SLIDERS(Bleed, "Bleeding ", 0) - xpos += myTVContrast->getWidth() + 30; + xpos += myTVContrast->getWidth() + fontWidth * 4; ypos = VBORDER; lwidth = font.getStringWidth("Intensity "); @@ -272,7 +278,7 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, xpos += INDENT; swidth = font.getMaxCharWidth() * 10; CREATE_CUSTOM_SLIDERS(PhosLevel, "Blend ", kPhosBlendChanged) - ypos += 8; + ypos += VGAP * 2; // Scanline intensity and interpolation xpos -= INDENT; @@ -291,7 +297,7 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, new ButtonWidget(myTab, font, xpos, ypos, cloneWidth, buttonHeight,\ desc, kClone ## obj ##Cmd); \ wid.push_back(myClone ## obj); \ - ypos += lineHeight + 4 + VGAP; + ypos += buttonHeight + VGAP; ypos += VGAP; CREATE_CLONE_BUTTON(RGB, "Clone RGB") diff --git a/src/gui/Widget.cxx b/src/gui/Widget.cxx index 895f68158..c86472f28 100644 --- a/src/gui/Widget.cxx +++ b/src/gui/Widget.cxx @@ -482,26 +482,28 @@ void ButtonWidget::drawWidget(bool hilite) CheckboxWidget::CheckboxWidget(GuiObject* boss, const GUI::Font& font, int x, int y, const string& label, int cmd) - : ButtonWidget(boss, font, x, y, 16, 16, label, cmd) + : ButtonWidget(boss, font, x, y, font.getFontHeight() < 24 ? 16 : 24, + font.getFontHeight() < 24 ? 16 : 24, label, cmd) { _flags = Widget::FLAG_ENABLED; _bgcolor = _bgcolorhi = kWidColor; _bgcolorlo = kDlgColor; _editable = true; + _boxSize = boxSize(font); if(label == "") - _w = 14; + _w = _boxSize; else - _w = font.getStringWidth(label) + 20; - _h = font.getFontHeight() < 14 ? 14 : font.getFontHeight(); + _w = font.getStringWidth(label) + _boxSize + font.getMaxCharWidth() * 0.75; + _h = font.getFontHeight() < _boxSize ? _boxSize : font.getFontHeight(); // Depending on font size, either the font or box will need to be // centered vertically - if(_h > 14) // center box - _boxY = (_h - 14) / 2; + if(_h > _boxSize) // center box + _boxY = (_h - _boxSize) / 2; else // center text - _textY = (14 - _font.getFontHeight()) / 2; + _textY = (_boxSize - _font.getFontHeight()) / 2; setFill(CheckboxWidget::FillType::Normal); } @@ -549,7 +551,8 @@ void CheckboxWidget::setEditable(bool editable) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheckboxWidget::setFill(FillType type) { - /* 8x8 checkbox bitmap */ + /* 10x10 checkbox bitmap */ + // small versions static constexpr std::array checked_img_active = { 0b1111111111, 0b1111111111, 0b1111111111, 0b1111111111, 0b1111111111, 0b1111111111, 0b1111111111, 0b1111111111, 0b1111111111, 0b1111111111 @@ -565,17 +568,36 @@ void CheckboxWidget::setFill(FillType type) 0b1111111111, 0b1111111111, 0b0111111110, 0b0111111110, 0b0001111000 }; + /* 18x18 checkbox bitmap */ + // large versions + static constexpr std::array checked_img_active_large = { + 0b111111111111111111, 0b111111111111111111, 0b111111111111111111, 0b111111111111111111, + 0b111111111111111111, 0b111111111111111111, 0b111111111111111111, 0b111111111111111111, + 0b111111111111111111, 0b111111111111111111, 0b111111111111111111, 0b111111111111111111, + 0b111111111111111111, 0b111111111111111111, 0b111111111111111111, 0b111111111111111111, + 0b111111111111111111, 0b111111111111111111 + }; + + static constexpr std::array checked_img_inactive_large = { + 0b111111111111111111, 0b111111111111111111, 0b111111111111111111, + 0b111111110011111111, 0b111111100001111111, 0b111111000000111111, 0b111110000000011111, + 0b111100000000001111, 0b111000000000000111, 0b111000000000000111, 0b111100000000001111, + 0b111110000000011111, 0b111111000000111111, 0b111111100001111111, 0b111111110011111111, + 0b111111111111111111, 0b111111111111111111, 0b111111111111111111 + }; + switch(type) { case CheckboxWidget::FillType::Normal: - _img = checked_img_active.data(); + _img = _boxSize == 14 ? checked_img_active.data() : checked_img_active_large.data(); _drawBox = true; break; case CheckboxWidget::FillType::Inactive: - _img = checked_img_inactive.data(); + _img = _boxSize == 14 ? checked_img_inactive.data() : checked_img_inactive_large.data(); _drawBox = true; break; case CheckboxWidget::FillType::Circle: + // only used in debugger which only has smaller fonts _img = checked_img_circle.data(); _drawBox = false; break; @@ -601,17 +623,17 @@ void CheckboxWidget::drawWidget(bool hilite) bool onTop = _boss->dialog().isOnTop(); if(_drawBox) - s.frameRect(_x, _y + _boxY, 14, 14, onTop && hilite && isEnabled() && isEditable() ? kWidColorHi : kColor); + s.frameRect(_x, _y + _boxY, _boxSize, _boxSize, onTop && hilite && isEnabled() && isEditable() ? kWidColorHi : kColor); // Do we draw a square or cross? - s.fillRect(_x + 1, _y + _boxY + 1, 12, 12, + s.fillRect(_x + 1, _y + _boxY + 1, _boxSize - 2, _boxSize - 2, _changed ? onTop ? kDbgChangedColor : kDlgColor : isEnabled() && onTop ? _bgcolor : kDlgColor); if(_state) s.drawBitmap(_img, _x + 2, _y + _boxY + 2, onTop && isEnabled() ? hilite && isEditable() ? kWidColorHi : kCheckColor - : kColor, 10); + : kColor, _boxSize - 4); // Finally draw the label - s.drawString(_font, _label, _x + 20, _y + _textY, _w, + s.drawString(_font, _label, _x + prefixSize(_font), _y + _textY, _w, onTop && isEnabled() ? kTextColor : kColor); setDirty(); @@ -640,7 +662,7 @@ SliderWidget::SliderWidget(GuiObject* boss, const GUI::Font& font, if(_valueLabelWidth == 0) _valueLabelGap = 0; if(_valueLabelGap == 0) - _valueLabelGap = DEF_LBL_GAP; + _valueLabelGap = font.getMaxCharWidth() / 2; _w = w + _labelWidth + _valueLabelGap + _valueLabelWidth; } @@ -807,7 +829,7 @@ void SliderWidget::drawWidget(bool hilite) s.drawString(_font, _label, _x, _y + 2, _labelWidth, isEnabled() ? kTextColor : kColor); int p = valueToPos(_value), - h = _h - 10, + h = _h - _font.getFontHeight() / 2 - 1, x = _x + _labelWidth, y = _y + (_h - h) / 2 + 1; diff --git a/src/gui/Widget.hxx b/src/gui/Widget.hxx index aa45a5420..eb31f7cd4 100644 --- a/src/gui/Widget.hxx +++ b/src/gui/Widget.hxx @@ -285,7 +285,14 @@ class CheckboxWidget : public ButtonWidget void handleMouseEntered() override; void handleMouseLeft() override; - static int boxSize() { return 14; } // box is square + static int boxSize(const GUI::Font& font) + { + return font.getFontHeight() < 24 ? 14 : 22; // box is square + } + static int prefixSize(const GUI::Font& font) + { + return boxSize(font) + font.getMaxCharWidth() * 0.75; + } protected: void drawWidget(bool hilite) override; @@ -296,10 +303,13 @@ class CheckboxWidget : public ButtonWidget bool _drawBox{true}; bool _changed{false}; + const uInt32* _outerCircle{nullptr}; + const uInt32* _innerCircle{nullptr}; const uInt32* _img{nullptr}; ColorId _fillColor{kColor}; int _boxY{0}; int _textY{0}; + int _boxSize{14}; private: // Following constructors and assignment operators not supported @@ -342,9 +352,6 @@ class SliderWidget : public ButtonWidget void setTickmarkIntervals(int numIntervals); - protected: - const int DEF_LBL_GAP = 4; - protected: void handleMouseMoved(int x, int y) override; void handleMouseDown(int x, int y, MouseButton b, int clickCount) override; From dddc93bbdb99c1be8baabd5e98d4419264f3e2b6 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Wed, 29 Apr 2020 14:52:15 -0230 Subject: [PATCH 160/377] libretro: Fix compile error; conditionally include Font class. --- src/emucore/FrameBuffer.hxx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index 1e61b39b4..a6872eeac 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -26,16 +26,15 @@ class Settings; class FBSurface; class TIASurface; -namespace GUI { - class Font; -} +#ifdef GUI_SUPPORT + #include "Font.hxx" +#endif #include "Rect.hxx" #include "Variant.hxx" #include "TIAConstants.hxx" #include "FrameBufferConstants.hxx" #include "EventHandlerConstants.hxx" -#include "Font.hxx" #include "bspf.hxx" /** From a178b4b80c76c5e1ab1078fd3fd2c1411eba8f4d Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 29 Apr 2020 23:49:00 +0200 Subject: [PATCH 161/377] Part 2 of the changes for #600 (UI fonts) --- src/emucore/FrameBuffer.cxx | 22 +++++--- src/gui/BrowserDialog.cxx | 32 +++++++----- src/gui/ComboDialog.cxx | 19 ++++--- src/gui/CommandDialog.cxx | 3 +- src/gui/ContextMenu.cxx | 61 +++++++++++++++++++-- src/gui/ContextMenu.hxx | 6 +++ src/gui/EventMappingWidget.cxx | 10 ++-- src/gui/GlobalPropsDialog.cxx | 48 ++++++++++------- src/gui/InputTextDialog.cxx | 27 ++++++---- src/gui/JoystickDialog.cxx | 27 ++++++---- src/gui/LauncherDialog.cxx | 96 ++++++++++++++++++---------------- src/gui/MessageBox.cxx | 17 +++--- src/gui/OptionsDialog.cxx | 23 ++++---- src/gui/PopUpWidget.cxx | 69 +++++++++++++++--------- src/gui/PopUpWidget.hxx | 11 ++++ src/gui/ProgressDialog.cxx | 13 +++-- src/gui/ScrollBarWidget.hxx | 2 +- 17 files changed, 314 insertions(+), 172 deletions(-) diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 8e2a0b14d..73b276e32 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -307,7 +307,7 @@ FBInitStatus FrameBuffer::createDisplay(const string& title, } if(!myMsg.surface) - myMsg.surface = allocateSurface(FBMinimum::Width, font().getFontHeight()+10); + myMsg.surface = allocateSurface(FBMinimum::Width, font().getFontHeight() * 1.5); #endif // Print initial usage message, but only print it later if the status has changed @@ -493,14 +493,20 @@ void FrameBuffer::showMessage(const string& message, MessagePosition position, if(myMsg.surface == nullptr || !(force || myOSystem.settings().getBool("uimessages"))) return; + const int fontWidth = font().getMaxCharWidth(), + fontHeight = font().getFontHeight(); + const int VBORDER = fontHeight / 4; + const int HBORDER = fontWidth * 1.25 / 2.0; + // Precompute the message coordinates myMsg.text = message; myMsg.counter = uInt32(myOSystem.frameRate()) << 1; // Show message for 2 seconds if(myMsg.counter == 0) myMsg.counter = 60; myMsg.color = kBtnTextColor; - myMsg.w = font().getStringWidth(myMsg.text) + 10; - myMsg.h = font().getFontHeight() + 8; + myMsg.w = font().getStringWidth(myMsg.text) + HBORDER * 2; + myMsg.h = fontHeight + VBORDER * 2; + myMsg.surface->setSrcSize(myMsg.w, myMsg.h); myMsg.surface->setDstSize(myMsg.w * hidpiScaleFactor(), myMsg.h * hidpiScaleFactor()); myMsg.position = position; @@ -619,6 +625,10 @@ inline bool FrameBuffer::drawMessage() // Draw the bounded box and text const Common::Rect& dst = myMsg.surface->dstRect(); + const int fontWidth = font().getMaxCharWidth(), + fontHeight = font().getFontHeight(); + const int VBORDER = fontHeight / 4; + const int HBORDER = fontWidth * 1.25 / 2.0; switch(myMsg.position) { @@ -669,10 +679,10 @@ inline bool FrameBuffer::drawMessage() } myMsg.surface->setDstPos(myMsg.x + myImageRect.x(), myMsg.y + myImageRect.y()); - myMsg.surface->fillRect(1, 1, myMsg.w-2, myMsg.h-2, kBtnColor); + myMsg.surface->fillRect(1, 1, myMsg.w - 2, myMsg.h - 2, kBtnColor); myMsg.surface->frameRect(0, 0, myMsg.w, myMsg.h, kColor); - myMsg.surface->drawString(font(), myMsg.text, 5, 4, - myMsg.w, myMsg.color, TextAlign::Left); + myMsg.surface->drawString(font(), myMsg.text, HBORDER, VBORDER, + myMsg.w, myMsg.color); myMsg.surface->render(); myMsg.counter--; #endif diff --git a/src/gui/BrowserDialog.cxx b/src/gui/BrowserDialog.cxx index b64edf525..544ff4518 100644 --- a/src/gui/BrowserDialog.cxx +++ b/src/gui/BrowserDialog.cxx @@ -42,13 +42,19 @@ BrowserDialog::BrowserDialog(GuiObject* boss, const GUI::Font& font, _h = max_h; const int lineHeight = font.getLineHeight(), - buttonWidth = font.getStringWidth("Defaults") + 20, - buttonHeight = font.getLineHeight() + 4, - selectHeight = lineHeight + 12; + fontWidth = font.getMaxCharWidth(), + fontHeight = font.getFontHeight(), + buttonHeight = font.getLineHeight() * 1.25, + buttonWidth = font.getStringWidth("Base Dir") + fontWidth * 2.5; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int VGAP = fontHeight / 4; + const int BUTTON_GAP = fontWidth; + const int selectHeight = lineHeight + VGAP * 3; int xpos, ypos; ButtonWidget* b; - xpos = 10; ypos = 4 + _th; + xpos = HBORDER; ypos = VBORDER + _th; // Current path - TODO: handle long paths ? StaticTextWidget* t = new StaticTextWidget(this, font, xpos, ypos + 2, "Path "); @@ -56,14 +62,14 @@ BrowserDialog::BrowserDialog(GuiObject* boss, const GUI::Font& font, _w - t->getWidth() - 2 * xpos, lineHeight); _currentPath->setEditable(false); // Add file list - ypos += lineHeight + 8; + ypos += lineHeight + VGAP * 2; _fileList = new FileListWidget(this, font, xpos, ypos, _w - 2 * xpos, - _h - selectHeight - buttonHeight - ypos - 20); + _h - selectHeight - buttonHeight - ypos - VBORDER * 2); _fileList->setEditable(false); addFocusWidget(_fileList); // Add currently selected item - ypos += _fileList->getHeight() + 8; + ypos += _fileList->getHeight() + VGAP * 2; _type = new StaticTextWidget(this, font, xpos, ypos + 2, "Name "); _selected = new EditTextWidget(this, font, xpos + _type->getWidth(), ypos, @@ -71,30 +77,30 @@ BrowserDialog::BrowserDialog(GuiObject* boss, const GUI::Font& font, _selected->setEditable(false); // Buttons - _goUpButton = new ButtonWidget(this, font, 10, _h - buttonHeight - 10, + _goUpButton = new ButtonWidget(this, font, xpos, _h - buttonHeight - VBORDER, buttonWidth, buttonHeight, "Go up", kGoUpCmd); addFocusWidget(_goUpButton); _basedirButton = - new ButtonWidget(this, font, 15 + buttonWidth, _h - buttonHeight - 10, + new ButtonWidget(this, font, _goUpButton->getRight() + BUTTON_GAP, _h - buttonHeight - VBORDER, buttonWidth, buttonHeight, "Base Dir", kBaseDirCmd); addFocusWidget(_basedirButton); #ifndef BSPF_MACOS - b = new ButtonWidget(this, font, _w - 2 * (buttonWidth + 7), _h - buttonHeight - 10, + b = new ButtonWidget(this, font, _w - (2 * buttonWidth + BUTTON_GAP + HBORDER), _h - buttonHeight - VBORDER, buttonWidth, buttonHeight, "Choose", kChooseCmd); addFocusWidget(b); addOKWidget(b); - b = new ButtonWidget(this, font, _w - (buttonWidth + 10), _h - buttonHeight - 10, + b = new ButtonWidget(this, font, _w - (buttonWidth + HBORDER), _h - buttonHeight - VBORDER, buttonWidth, buttonHeight, "Cancel", GuiObject::kCloseCmd); addFocusWidget(b); addCancelWidget(b); #else - b = new ButtonWidget(this, font, _w - 2 * (buttonWidth + 7), _h - buttonHeight - 10, + b = new ButtonWidget(this, font, _w - (2 * buttonWidth + BUTTON_GAP + HBORDER), _h - buttonHeight - VBORDER, buttonWidth, buttonHeight, "Cancel", GuiObject::kCloseCmd); addFocusWidget(b); addCancelWidget(b); - b = new ButtonWidget(this, font, _w - (buttonWidth + 10), _h - buttonHeight - 10, + b = new ButtonWidget(this, font, _w - (buttonWidth + HBORDER), _h - buttonHeight - VBORDER, buttonWidth, buttonHeight, "Choose", kChooseCmd); addFocusWidget(b); addOKWidget(b); diff --git a/src/gui/ComboDialog.cxx b/src/gui/ComboDialog.cxx index a18e3920b..524a1a3e2 100644 --- a/src/gui/ComboDialog.cxx +++ b/src/gui/ComboDialog.cxx @@ -32,7 +32,14 @@ ComboDialog::ComboDialog(GuiObject* boss, const GUI::Font& font, : Dialog(boss->instance(), boss->parent(), font, "Add...") { const int lineHeight = font.getLineHeight(), - fontWidth = font.getMaxCharWidth(); + fontWidth = font.getMaxCharWidth(), + fontHeight = font.getFontHeight(), + buttonHeight = font.getLineHeight() * 1.25; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = fontWidth * 2; + const int VGAP = fontHeight / 4; + int xpos, ypos; WidgetArray wid; @@ -42,10 +49,10 @@ ComboDialog::ComboDialog(GuiObject* boss, const GUI::Font& font, pwidth = std::max(font.getStringWidth(s.first), pwidth); // Set real dimensions - _w = 11 * fontWidth + pwidth-4 + 10 * 2; - _h = 10 * (lineHeight + 4) + 10 + _th; - xpos = 10; - ypos = 10 + _th; + _w = 8 * fontWidth + pwidth + PopUpWidget::dropDownWidth(font) + HBORDER * 2; + _h = 8 * (lineHeight + VGAP) + VGAP + buttonHeight + VBORDER * 2 + _th; + xpos = HBORDER; + ypos = VBORDER + _th; // Add event popup for 8 events myEvents.fill(nullptr); @@ -54,7 +61,7 @@ ComboDialog::ComboDialog(GuiObject* boss, const GUI::Font& font, myEvents[idx] = new PopUpWidget(this, font, xpos, ypos, pwidth, lineHeight, combolist, label); wid.push_back(myEvents[idx]); - ypos += lineHeight + 4; + ypos += lineHeight + VGAP; }; ADD_EVENT_POPUP(0, "Event 1 "); ADD_EVENT_POPUP(1, "Event 2 "); diff --git a/src/gui/CommandDialog.cxx b/src/gui/CommandDialog.cxx index 31fd7b2cb..f1ee4b4a0 100644 --- a/src/gui/CommandDialog.cxx +++ b/src/gui/CommandDialog.cxx @@ -40,9 +40,8 @@ CommandDialog::CommandDialog(OSystem& osystem, DialogContainer& parent) buttonWidth = _font.getStringWidth("Time Machine On") + fontWidth * 2; const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; - const int INDENT = fontWidth * 2; const int VGAP = fontHeight / 4; - const int HGAP = VGAP * 2; + const int HGAP = fontWidth; const int rowHeight = buttonHeight + VGAP; // Set real dimensions diff --git a/src/gui/ContextMenu.cxx b/src/gui/ContextMenu.cxx index cf142255f..41f049ba2 100644 --- a/src/gui/ContextMenu.cxx +++ b/src/gui/ContextMenu.cxx @@ -23,6 +23,7 @@ #include "Dialog.hxx" #include "DialogContainer.hxx" #include "ScrollBarWidget.hxx" +#include "PopUpWidget.hxx" #include "ContextMenu.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -35,6 +36,7 @@ ContextMenu::ContextMenu(GuiObject* boss, const GUI::Font& font, _maxWidth(width) { addItems(items); + setArrows(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -49,7 +51,7 @@ void ContextMenu::addItems(const VariantList& items) maxwidth = std::max(maxwidth, _font.getStringWidth(e.first)); _x = _y = 0; - _w = maxwidth + 23; + _w = maxwidth + PopUpWidget::dropDownWidth(_font); // 23; _h = 1; // recalculate this in ::recalc() _scrollUpColor = _firstEntry > 0 ? kScrollColor : kColor; @@ -509,7 +511,7 @@ void ContextMenu::scrollDown(int distance) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ContextMenu::drawDialog() +void ContextMenu::setArrows() { static constexpr std::array up_arrow = { 0b00011000, @@ -532,6 +534,55 @@ void ContextMenu::drawDialog() 0b00011000 }; + static constexpr std::array up_arrow_large = { + 0b000001100000, + 0b000001100000, + 0b000011110000, + 0b000011110000, + 0b000111111000, + 0b000111111000, + 0b001111111100, + 0b001111111100, + 0b011111111110, + 0b011111111110, + 0b111111111111, + 0b111111111111 + }; + static constexpr std::array down_arrow_large = { + 0b111111111111, + 0b111111111111, + 0b011111111110, + 0b011111111110, + 0b001111111100, + 0b001111111100, + 0b000111111000, + 0b000111111000, + 0b000011110000, + 0b000011110000, + 0b000001100000, + 0b000001100000 + }; + + if(_font.getFontHeight() < 24) + { + _textOfs = 2; + _arrowSize = 8; + _upImg = up_arrow.data(); + _downImg = down_arrow.data(); + } + else + { + _textOfs = 4; + _arrowSize = 12; + _upImg = up_arrow_large.data(); + _downImg = down_arrow_large.data(); + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void ContextMenu::drawDialog() +{ + // Normally we add widgets and let Dialog::draw() take care of this // logic. But for some reason, this Dialog was written differently // by the ScummVM guys, so I'm not going to mess with it. @@ -549,7 +600,7 @@ void ContextMenu::drawDialog() if(_showScroll) { s.hLine(x, y+_rowHeight-1, w+2, kColor); - s.drawBitmap(up_arrow.data(), ((_w-_x)>>1)-4, (_rowHeight>>1)+y-4, _scrollUpColor, 8); + s.drawBitmap(_upImg, ((_w-_x)>>1)-4, (_rowHeight>>1)+y-4, _scrollUpColor, _arrowSize); y += _rowHeight; offset--; } @@ -558,7 +609,7 @@ void ContextMenu::drawDialog() { bool hilite = offset == current; if(hilite) s.fillRect(x, y, w, _rowHeight, kTextColorHi); - s.drawString(_font, _entries[i].first, x + 1, y + 2, w, + s.drawString(_font, _entries[i].first, x + _textOfs, y + 2, w, !hilite ? kTextColor : kTextColorInv); y += _rowHeight; } @@ -567,7 +618,7 @@ void ContextMenu::drawDialog() if(_showScroll) { s.hLine(x, y, w+2, kColor); - s.drawBitmap(down_arrow.data(), ((_w-_x)>>1)-4, (_rowHeight>>1)+y-4, _scrollDnColor, 8); + s.drawBitmap(_downImg, ((_w-_x)>>1)-4, (_rowHeight>>1)+y-4, _scrollDnColor, _arrowSize); } setDirty(); diff --git a/src/gui/ContextMenu.hxx b/src/gui/ContextMenu.hxx index 40858f8b9..221b90a30 100644 --- a/src/gui/ContextMenu.hxx +++ b/src/gui/ContextMenu.hxx @@ -95,6 +95,7 @@ class ContextMenu : public Dialog, public CommandSender bool handleJoyHat(int stick, int hat, JoyHatDir vahdirlue, int button) override; void handleEvent(Event::Type e); + void setArrows(); void drawDialog() override; void recalc(const Common::Rect& image); @@ -129,6 +130,11 @@ class ContextMenu : public Dialog, public CommandSender uInt32 _xorig{0}, _yorig{0}; uInt32 _maxWidth{0}; + int _textOfs{0}; + int _arrowSize{0}; + const uInt32* _upImg{nullptr}; + const uInt32* _downImg{nullptr}; + private: // Following constructors and assignment operators not supported ContextMenu() = delete; diff --git a/src/gui/EventMappingWidget.cxx b/src/gui/EventMappingWidget.cxx index 1438e3d4f..bb4088173 100644 --- a/src/gui/EventMappingWidget.cxx +++ b/src/gui/EventMappingWidget.cxx @@ -45,14 +45,14 @@ EventMappingWidget::EventMappingWidget(GuiObject* boss, const GUI::Font& font, const int fontHeight = font.getFontHeight(), lineHeight = font.getLineHeight(), fontWidth = font.getMaxCharWidth(), - buttonWidth = font.getStringWidth("Defaults") + 10, + buttonWidth = font.getStringWidth("Defaults") + fontWidth * 1.25, buttonHeight = font.getLineHeight() * 1.25; const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; const int VGAP = fontHeight / 4; const int ACTION_LINES = 2; int xpos = HBORDER, ypos = VBORDER; - const int listWidth = _w - buttonWidth - HBORDER * 2 - 8; + const int listWidth = _w - buttonWidth - HBORDER * 2 - fontWidth; int listHeight = _h - (2 + ACTION_LINES) * lineHeight - VBORDER + 2; if(mode == EventMode::kEmulationMode) @@ -72,8 +72,8 @@ EventMappingWidget::EventMappingWidget(GuiObject* boss, const GUI::Font& font, VarList::push_back(items, "Debug", Event::Group::Debug); myFilterPopup = new PopUpWidget(boss, font, xpos, ypos, - listWidth - font.getStringWidth("Events ") - 23, lineHeight, - items, "Events ", 0, kFilterCmd); + listWidth - font.getStringWidth("Events ") - PopUpWidget::dropDownWidth(font), + lineHeight, items, "Events ", 0, kFilterCmd); myFilterPopup->setTarget(this); addFocusWidget(myFilterPopup); ypos += lineHeight * 1.5; @@ -136,7 +136,7 @@ EventMappingWidget::EventMappingWidget(GuiObject* boss, const GUI::Font& font, fontHeight, "Action", TextAlign::Left); myKeyMapping = new EditTextWidget(boss, font, xpos + t->getWidth() + fontWidth, ypos, - _w - xpos - t->getWidth() - fontWidth - HBORDER, + _w - xpos - t->getWidth() - fontWidth - HBORDER + 2, lineHeight + font.getFontHeight() * (ACTION_LINES - 1), ""); myKeyMapping->setEditable(false, true); myKeyMapping->clearFlags(Widget::FLAG_RETAIN_FOCUS); diff --git a/src/gui/GlobalPropsDialog.cxx b/src/gui/GlobalPropsDialog.cxx index b4f296596..d8226a2d5 100644 --- a/src/gui/GlobalPropsDialog.cxx +++ b/src/gui/GlobalPropsDialog.cxx @@ -36,20 +36,25 @@ GlobalPropsDialog::GlobalPropsDialog(GuiObject* boss, const GUI::Font& font) const int lineHeight = font.getLineHeight(), fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(), - buttonHeight = font.getLineHeight() + 4; + buttonHeight = lineHeight * 1.25; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = fontWidth * 2; + const int VGAP = fontHeight / 4; + int xpos, ypos; int lwidth = font.getStringWidth("Right difficulty "), pwidth = font.getStringWidth("CM (SpectraVideo CompuMate)"); - const int VGAP = 4; WidgetArray wid; VariantList items; const GUI::Font& infofont = instance().frameBuffer().infoFont(); // Set real dimensions - _w = lwidth + pwidth + fontWidth*3 + 15; - _h = 15 * (lineHeight + 4) + buttonHeight + 16 + _th; + _w = HBORDER * 2 + std::max(lwidth + pwidth + PopUpWidget::dropDownWidth(font), + 49 * infofont.getMaxCharWidth()); + _h = _th + 11 * (lineHeight + VGAP) + 3 * infofont.getLineHeight() + VGAP * 12 + buttonHeight + VBORDER * 2; - xpos = 10; ypos = 10 + _th; + xpos = HBORDER; ypos = VBORDER + _th; // Bankswitch type new StaticTextWidget(this, font, xpos, ypos+1, "Bankswitch type"); @@ -112,12 +117,12 @@ GlobalPropsDialog::GlobalPropsDialog(GuiObject* boss, const GUI::Font& font) "(automatically released shortly after start)"); // Start with console joystick direction/buttons held down - xpos = 32; ypos += infofont.getLineHeight() + VGAP * 2; + xpos = fontWidth * 4; ypos += infofont.getLineHeight() + VGAP * 2; ypos = addHoldWidgets(font, xpos, ypos, wid); // Add message concerning usage - xpos = 10; ypos += 2 * fontHeight; - ypos = _h - fontHeight * 2 - infofont.getLineHeight() - 24; + xpos = HBORDER; + ypos = _h - VBORDER - buttonHeight - VGAP * 3 - infofont.getLineHeight() * 2; new StaticTextWidget(this, infofont, xpos, ypos, "(*) These options are not saved, but apply to all"); ypos += infofont.getLineHeight(); @@ -134,21 +139,24 @@ GlobalPropsDialog::GlobalPropsDialog(GuiObject* boss, const GUI::Font& font) int GlobalPropsDialog::addHoldWidgets(const GUI::Font& font, int x, int y, WidgetArray& wid) { - int xpos = x, ypos = y; - const int VGAP = 4; + const int fontWidth = font.getMaxCharWidth(), + fontHeight = font.getFontHeight(); + const int VGAP = fontHeight / 4; + + int xpos = x, ypos = y, xdiff = CheckboxWidget::boxSize(font) - 9; // Left joystick - StaticTextWidget* t = new StaticTextWidget(this, font, xpos, ypos+2, "Left joy"); - xpos += t->getWidth()/2 - 7; ypos += t->getHeight() + VGAP; + StaticTextWidget* t = new StaticTextWidget(this, font, xpos, ypos + 2, "Left joy"); + xpos += t->getWidth()/2 - xdiff - 2; ypos += t->getHeight() + VGAP; myJoy[kJ0Up] = new CheckboxWidget(this, font, xpos, ypos, "", kJ0Up); ypos += myJoy[kJ0Up]->getHeight() * 2 + VGAP * 2; myJoy[kJ0Down] = new CheckboxWidget(this, font, xpos, ypos, "", kJ0Down); - xpos -= myJoy[kJ0Up]->getWidth() + 5; + xpos -= myJoy[kJ0Up]->getWidth() + xdiff; ypos -= myJoy[kJ0Up]->getHeight() + VGAP; myJoy[kJ0Left] = new CheckboxWidget(this, font, xpos, ypos, "", kJ0Left); - xpos += (myJoy[kJ0Up]->getWidth() + 5) * 2; + xpos += (myJoy[kJ0Up]->getWidth() + xdiff) * 2; myJoy[kJ0Right] = new CheckboxWidget(this, font, xpos, ypos, "", kJ0Right); - xpos -= (myJoy[kJ0Up]->getWidth() + 5) * 2; + xpos -= (myJoy[kJ0Up]->getWidth() + xdiff) * 2; ypos += myJoy[kJ0Down]->getHeight() * 2 + VGAP * 2; myJoy[kJ0Fire] = new CheckboxWidget(this, font, xpos, ypos, "Fire", kJ0Fire); @@ -157,20 +165,20 @@ int GlobalPropsDialog::addHoldWidgets(const GUI::Font& font, int x, int y, // Right joystick t = new StaticTextWidget(this, font, xpos, ypos + 2, "Right joy"); - xpos += t->getWidth()/2 - 7; ypos += t->getHeight() + VGAP; + xpos += t->getWidth()/2 - xdiff - 2; ypos += t->getHeight() + VGAP; myJoy[kJ1Up] = new CheckboxWidget(this, font, xpos, ypos, "", kJ1Up); ypos += myJoy[kJ1Up]->getHeight() * 2 + VGAP * 2; myJoy[kJ1Down] = new CheckboxWidget(this, font, xpos, ypos, "", kJ1Down); - xpos -= myJoy[kJ1Up]->getWidth() + 5; + xpos -= myJoy[kJ1Up]->getWidth() + xdiff; ypos -= myJoy[kJ1Up]->getHeight() + VGAP; myJoy[kJ1Left] = new CheckboxWidget(this, font, xpos, ypos, "", kJ1Left); - xpos += (myJoy[kJ1Up]->getWidth() + 5) * 2; + xpos += (myJoy[kJ1Up]->getWidth() + xdiff) * 2; myJoy[kJ1Right] = new CheckboxWidget(this, font, xpos, ypos, "", kJ1Right); - xpos -= (myJoy[kJ1Up]->getWidth() + 5) * 2; + xpos -= (myJoy[kJ1Up]->getWidth() + xdiff) * 2; ypos += myJoy[kJ1Down]->getHeight() * 2 + VGAP * 2; myJoy[kJ1Fire] = new CheckboxWidget(this, font, xpos, ypos, "Fire", kJ1Fire); - xpos = 2 * _w / 3 + 8; ypos = y; + xpos = 2 * _w / 3 + fontWidth; ypos = y; // Console Select/Reset t = new StaticTextWidget(this, font, xpos, ypos+2, "Console"); diff --git a/src/gui/InputTextDialog.cxx b/src/gui/InputTextDialog.cxx index b543d9729..12e7a66d4 100644 --- a/src/gui/InputTextDialog.cxx +++ b/src/gui/InputTextDialog.cxx @@ -50,15 +50,20 @@ InputTextDialog::InputTextDialog(GuiObject* boss, const GUI::Font& lfont, void InputTextDialog::initialize(const GUI::Font& lfont, const GUI::Font& nfont, const StringList& labels) { - const int fontWidth = lfont.getMaxCharWidth(), - fontHeight = lfont.getFontHeight(), - lineHeight = lfont.getLineHeight(); + const int lineHeight = lfont.getLineHeight(), + fontWidth = lfont.getMaxCharWidth(), + fontHeight = lfont.getFontHeight(), + buttonHeight = lfont.getLineHeight() * 1.25; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int VGAP = fontHeight / 4; + uInt32 xpos, ypos, i, lwidth = 0, maxIdx = 0; WidgetArray wid; // Calculate real dimensions - _w = fontWidth * 41; - _h = lineHeight * 4 + int(labels.size()) * (lineHeight + 5) + _th; + _w = HBORDER * 2 + fontWidth * 39; + _h = buttonHeight + lineHeight + VGAP + int(labels.size()) * (lineHeight + VGAP) + _th + VBORDER * 2; // Determine longest label for(i = 0; i < labels.size(); ++i) @@ -72,25 +77,25 @@ void InputTextDialog::initialize(const GUI::Font& lfont, const GUI::Font& nfont, lwidth = lfont.getStringWidth(labels[maxIdx]); // Create editboxes for all labels - ypos = lineHeight + _th; + ypos = VBORDER + _th; for(i = 0; i < labels.size(); ++i) { - xpos = 10; + xpos = HBORDER; new StaticTextWidget(this, lfont, xpos, ypos + 2, lwidth, fontHeight, labels[i], TextAlign::Left); xpos += lwidth + fontWidth; EditTextWidget* w = new EditTextWidget(this, nfont, xpos, ypos, - _w - xpos - 10, lineHeight, ""); + _w - xpos - HBORDER, lineHeight, ""); wid.push_back(w); myInput.push_back(w); - ypos += lineHeight + 5; + ypos += lineHeight + VGAP; } - xpos = 10; - myMessage = new StaticTextWidget(this, lfont, xpos, ypos, _w - 2*xpos, fontHeight, + xpos = HBORDER; ypos += VGAP; + myMessage = new StaticTextWidget(this, lfont, xpos, ypos, _w - 2 * xpos, fontHeight, "", TextAlign::Left); myMessage->setTextColor(kTextColorEm); diff --git a/src/gui/JoystickDialog.cxx b/src/gui/JoystickDialog.cxx index 16f8e84f0..266822eda 100644 --- a/src/gui/JoystickDialog.cxx +++ b/src/gui/JoystickDialog.cxx @@ -32,33 +32,40 @@ JoystickDialog::JoystickDialog(GuiObject* boss, const GUI::Font& font, int xpos, ypos; WidgetArray wid; - int buttonWidth = font.getStringWidth("Remove ") + 20, - buttonHeight = font.getLineHeight() + 4; + const int lineHeight = font.getLineHeight(), + fontWidth = font.getMaxCharWidth(), + fontHeight = font.getFontHeight(), + buttonWidth = font.getStringWidth("Remove") + fontWidth * 2.5, + buttonHeight = font.getLineHeight() * 1.25; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = fontWidth * 2; + const int VGAP = fontHeight / 4; // Joystick list - xpos = 10; ypos = 10 + _th; + xpos = HBORDER; ypos = VBORDER + _th; int w = _w - 2 * xpos; - int h = _h - buttonHeight - ypos - 20; + int h = _h - buttonHeight - ypos - VBORDER * 2; myJoyList = new StringListWidget(this, font, xpos, ypos, w, h); myJoyList->setEditable(false); wid.push_back(myJoyList); // Joystick ID - ypos = _h - buttonHeight - 10; + ypos = _h - VBORDER - (buttonHeight + lineHeight) / 2; StaticTextWidget* t = new StaticTextWidget(this, font, xpos, ypos+2, "Joystick ID "); - xpos += t->getWidth() + 4; + xpos += t->getWidth(); myJoyText = new EditTextWidget(this, font, xpos, ypos, - font.getStringWidth("Unplugged")+8, font.getLineHeight(), ""); + font.getStringWidth("Unplugged "), font.getLineHeight(), ""); myJoyText->setEditable(false); // Add buttons at bottom - xpos = _w - buttonWidth - 10; + xpos = _w - buttonWidth - HBORDER; + ypos = _h - VBORDER - buttonHeight; myCloseBtn = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Close", GuiObject::kCloseCmd); addOKWidget(myCloseBtn); addCancelWidget(myCloseBtn); - buttonWidth = font.getStringWidth("Remove") + 20; - xpos -= buttonWidth + 8; + xpos -= buttonWidth + fontWidth; myRemoveBtn = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Remove", kRemoveCmd); myRemoveBtn->clearFlags(Widget::FLAG_ENABLED); diff --git a/src/gui/LauncherDialog.cxx b/src/gui/LauncherDialog.cxx index a92b16e4a..3e9936cdf 100644 --- a/src/gui/LauncherDialog.cxx +++ b/src/gui/LauncherDialog.cxx @@ -60,25 +60,26 @@ LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent, myUseMinimalUI = instance().settings().getBool("minimal_ui"); const GUI::Font& font = instance().frameBuffer().launcherFont(); - const int fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(), lineHeight = font.getLineHeight(), - bheight = myUseMinimalUI ? lineHeight - 4 : lineHeight + 4, - LBL_GAP = fontWidth, - HBORDER = 10,//fontWidth * 1.25, + HBORDER = fontWidth * 1.25, + VBORDER = fontHeight / 2, BUTTON_GAP = fontWidth, - bwidth = (_w - 2 * HBORDER - BUTTON_GAP * (4 - 1)); - int xpos = 0, ypos = 0, lwidth = 0, lwidth2 = 0; - WidgetArray wid; + LBL_GAP = fontWidth, + VGAP = fontHeight / 4, + buttonHeight = myUseMinimalUI ? lineHeight - VGAP * 2: lineHeight * 1.25, + buttonWidth = (_w - 2 * HBORDER - BUTTON_GAP * (4 - 1)); + int xpos = HBORDER, ypos = VBORDER, lwidth = 0, lwidth2 = 0; + WidgetArray wid; string lblRom = "Select a ROM from the list" + ELLIPSIS; const string& lblFilter = "Filter"; const string& lblAllFiles = "Show all files"; const string& lblFound = "XXXX items found"; lwidth = font.getStringWidth(lblRom); - lwidth2 = font.getStringWidth(lblAllFiles) + 20; + lwidth2 = font.getStringWidth(lblAllFiles) + CheckboxWidget::boxSize(font); int lwidth3 = font.getStringWidth(lblFilter); int lwidth4 = font.getStringWidth(lblFound); @@ -97,14 +98,12 @@ LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent, #if defined(RETRON77) ver << " for RetroN 77"; #endif - ypos += 8; - new StaticTextWidget(this, font, xpos, ypos, _w - 20, fontHeight, + new StaticTextWidget(this, font, 0, ypos, _w, fontHeight, ver.str(), TextAlign::Center); - ypos += fontHeight - 4; + ypos += lineHeight; } // Show the header - xpos += HBORDER; ypos += 8; new StaticTextWidget(this, font, xpos, ypos, lblRom); // Shop the files counter xpos = _w - HBORDER - lwidth4; @@ -132,12 +131,12 @@ LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent, // Add list with game titles // Before we add the list, we need to know the size of the RomInfoWidget - int listHeight = _h - 43 - bheight - fontHeight - lineHeight; + int listHeight = _h - VBORDER * 2 - buttonHeight - lineHeight * 2 - VGAP * 6; float imgZoom = getRomInfoZoom(listHeight); int romWidth = imgZoom * TIAConstants::viewableWidth; - if(romWidth > 0) romWidth += 10; - int listWidth = _w - (romWidth > 0 ? romWidth+8 : 0) - 20; - xpos = HBORDER; ypos += lineHeight + 4; + if(romWidth > 0) romWidth += HBORDER; + int listWidth = _w - (romWidth > 0 ? romWidth + fontWidth : 0) - HBORDER * 2; + xpos = HBORDER; ypos += lineHeight + VGAP; myList = new FileListWidget(this, font, xpos, ypos, listWidth, listHeight); myList->setEditable(false); myList->setListMode(FilesystemNode::ListMode::All); @@ -146,14 +145,14 @@ LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent, // Add ROM info area (if enabled) if(romWidth > 0) { - xpos += myList->getWidth() + 8; + xpos += myList->getWidth() + fontWidth; // Initial surface size is the same as the viewable area Common::Size imgSize(TIAConstants::viewableWidth*imgZoom, TIAConstants::viewableHeight*imgZoom); // Calculate font area, and in the process the font that can be used - Common::Size fontArea(romWidth - 16, myList->getHeight() - imgSize.h - 12); + Common::Size fontArea(romWidth - fontWidth * 2, myList->getHeight() - imgSize.h - VGAP * 3); setRomInfoFont(fontArea); myRomInfoWidget = new RomInfoWidget(this, *myROMInfoFont, @@ -162,7 +161,7 @@ LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent, // Add textfield to show current directory xpos = HBORDER; - ypos += myList->getHeight() + 8; + ypos += myList->getHeight() + VGAP * 2; lwidth = font.getStringWidth("Path") + LBL_GAP; myDirLabel = new StaticTextWidget(this, font, xpos, ypos+2, lwidth, fontHeight, "Path", TextAlign::Left); @@ -174,43 +173,43 @@ LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent, if(!myUseMinimalUI) { // Add four buttons at the bottom - xpos = HBORDER; ypos += myDir->getHeight() + 8; + xpos = HBORDER; ypos = _h - VBORDER - buttonHeight; #ifndef BSPF_MACOS - myStartButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 0) / 4, bheight, + myStartButton = new ButtonWidget(this, font, xpos, ypos, (buttonWidth + 0) / 4, buttonHeight, "Select", kLoadROMCmd); wid.push_back(myStartButton); - xpos += (bwidth + 0) / 4 + BUTTON_GAP; - myPrevDirButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 1) / 4, bheight, + xpos += (buttonWidth + 0) / 4 + BUTTON_GAP; + myPrevDirButton = new ButtonWidget(this, font, xpos, ypos, (buttonWidth + 1) / 4, buttonHeight, "Go Up", kPrevDirCmd); wid.push_back(myPrevDirButton); - xpos += (bwidth + 1) / 4 + BUTTON_GAP; - myOptionsButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 3) / 4, bheight, + xpos += (buttonWidth + 1) / 4 + BUTTON_GAP; + myOptionsButton = new ButtonWidget(this, font, xpos, ypos, (buttonWidth + 3) / 4, buttonHeight, "Options" + ELLIPSIS, kOptionsCmd); wid.push_back(myOptionsButton); - xpos += (bwidth + 2) / 4 + BUTTON_GAP; - myQuitButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 4) / 4, bheight, + xpos += (buttonWidth + 2) / 4 + BUTTON_GAP; + myQuitButton = new ButtonWidget(this, font, xpos, ypos, (buttonWidth + 4) / 4, buttonHeight, "Quit", kQuitCmd); wid.push_back(myQuitButton); #else - myQuitButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 0) / 4, bheight, + myQuitButton = new ButtonWidget(this, font, xpos, ypos, (buttonWidth + 0) / 4, buttonHeight, "Quit", kQuitCmd); wid.push_back(myQuitButton); - xpos += (bwidth + 0) / 4 + BUTTON_GAP; - myOptionsButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 1) / 4, bheight, + xpos += (buttonWidth + 0) / 4 + BUTTON_GAP; + myOptionsButton = new ButtonWidget(this, font, xpos, ypos, (buttonWidth + 1) / 4, buttonHeight, "Options" + ELLIPSIS, kOptionsCmd); wid.push_back(myOptionsButton); - xpos += (bwidth + 1) / 4 + BUTTON_GAP; - myPrevDirButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 2) / 4, bheight, + xpos += (buttonWidth + 1) / 4 + BUTTON_GAP; + myPrevDirButton = new ButtonWidget(this, font, xpos, ypos, (buttonWidth + 2) / 4, buttonHeight, "Go Up", kPrevDirCmd); wid.push_back(myPrevDirButton); - xpos += (bwidth + 2) / 4 + BUTTON_GAP; - myStartButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 3) / 4, bheight, + xpos += (buttonWidth + 2) / 4 + BUTTON_GAP; + myStartButton = new ButtonWidget(this, font, xpos, ypos, (buttonWidth + 3) / 4, buttonHeight, "Select", kLoadROMCmd); wid.push_back(myStartButton); #endif @@ -223,7 +222,7 @@ LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent, addToFocusList(wid); // Create (empty) context menu for ROM list options - myMenu = make_unique(this, osystem.frameBuffer().font(), EmptyVarList); + myMenu = make_unique(this, osystem.frameBuffer().launcherFont(), EmptyVarList); // Create global props dialog, which is used to temporarily override // ROM properties @@ -363,28 +362,33 @@ float LauncherDialog::getRomInfoZoom(int listHeight) const if(zoom > 0.F) { - // upper zoom limit - at least 24 launchers chars/line and 8 ROM info lines - if((_w - 58 - zoom * TIAConstants::viewableWidth) - / instance().frameBuffer().launcherFont().getMaxCharWidth() < MIN_LAUNCHER_CHARS) + const GUI::Font& font = instance().frameBuffer().launcherFont(); + const GUI::Font& smallFont = instance().frameBuffer().smallFont(); + const int fontWidth = font.getMaxCharWidth(), + HBORDER = fontWidth * 1.25; + + // upper zoom limit - at least 24 launchers chars/line and 7 + 4 ROM info lines + if((_w - (HBORDER * 2 + fontWidth + 30) - zoom * TIAConstants::viewableWidth) + / font.getMaxCharWidth() < MIN_LAUNCHER_CHARS) { - zoom = float(_w - 58 - MIN_LAUNCHER_CHARS * instance().frameBuffer().launcherFont().getMaxCharWidth()) + zoom = float(_w - (HBORDER * 2 + fontWidth + 30) - MIN_LAUNCHER_CHARS * font.getMaxCharWidth()) / TIAConstants::viewableWidth; } if((listHeight - 12 - zoom * TIAConstants::viewableHeight) < - MIN_ROMINFO_ROWS * instance().frameBuffer().smallFont().getLineHeight() + - MIN_ROMINFO_LINES * instance().frameBuffer().smallFont().getFontHeight()) + MIN_ROMINFO_ROWS * smallFont.getLineHeight() + + MIN_ROMINFO_LINES * smallFont.getFontHeight()) { zoom = float(listHeight - 12 - - MIN_ROMINFO_ROWS * instance().frameBuffer().smallFont().getLineHeight() - - MIN_ROMINFO_LINES * instance().frameBuffer().smallFont().getFontHeight()) + MIN_ROMINFO_ROWS * smallFont.getLineHeight() - + MIN_ROMINFO_LINES * smallFont.getFontHeight()) / TIAConstants::viewableHeight; } - // lower zoom limit - at least 24 ROM info chars/line + // lower zoom limit - at least 30 ROM info chars/line if((zoom * TIAConstants::viewableWidth) - / instance().frameBuffer().smallFont().getMaxCharWidth() < MIN_ROMINFO_CHARS + 6) + / smallFont.getMaxCharWidth() < MIN_ROMINFO_CHARS + 6) { - zoom = float(MIN_ROMINFO_CHARS * instance().frameBuffer().smallFont().getMaxCharWidth() + 6) + zoom = float(MIN_ROMINFO_CHARS * smallFont.getMaxCharWidth() + 6) / TIAConstants::viewableWidth; } } diff --git a/src/gui/MessageBox.cxx b/src/gui/MessageBox.cxx index 30bdc88d0..d5b5cf11b 100644 --- a/src/gui/MessageBox.cxx +++ b/src/gui/MessageBox.cxx @@ -79,21 +79,24 @@ MessageBox::MessageBox(GuiObject* boss, const GUI::Font& font, // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void MessageBox::addText(const GUI::Font& font, const StringList& text) { - const int fontWidth = font.getMaxCharWidth(), - fontHeight = font.getFontHeight(); - int xpos, ypos; + const int fontWidth = font.getMaxCharWidth(), + fontHeight = font.getFontHeight(); + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + int xpos, ypos; // Set real dimensions int str_w = 0; + for(const auto& s: text) str_w = std::max(int(s.length()), str_w); - _w = std::min(str_w * fontWidth + 20, _w); - _h = std::min(uInt32((text.size() + 2) * fontHeight + 20 + _th), uInt32(_h)); + _w = std::min(str_w * fontWidth + HBORDER * 2, _w); + _h = std::min(uInt32((text.size() + 2) * fontHeight + VBORDER * 2 + _th), uInt32(_h)); - xpos = 10; ypos = 10 + _th; + xpos = HBORDER; ypos = VBORDER + _th; for(const auto& s: text) { - new StaticTextWidget(this, font, xpos, ypos, _w - 20, + new StaticTextWidget(this, font, xpos, ypos, _w - HBORDER * 2, fontHeight, s, TextAlign::Left); ypos += fontHeight; } diff --git a/src/gui/OptionsDialog.cxx b/src/gui/OptionsDialog.cxx index 0a0934d7b..9b8087b34 100644 --- a/src/gui/OptionsDialog.cxx +++ b/src/gui/OptionsDialog.cxx @@ -58,14 +58,15 @@ OptionsDialog::OptionsDialog(OSystem& osystem, DialogContainer& parent, fontWidth = _font.getMaxCharWidth(), fontHeight = _font.getFontHeight(), buttonHeight = _font.getLineHeight() * 1.25, - GAP = fontWidth / 2, - rowHeight = buttonHeight + GAP; + VGAP = fontHeight / 4, + HGAP = fontWidth, + rowHeight = buttonHeight + VGAP; const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; - int buttonWidth = _font.getStringWidth("Game Properties" + ELLIPSIS) + GAP * 5; + int buttonWidth = _font.getStringWidth("Game Properties" + ELLIPSIS) + fontWidth * 2.5; - _w = 2 * buttonWidth + HBORDER * 3; - _h = 7 * rowHeight + VBORDER * 2 - GAP + _th; + _w = 2 * buttonWidth + HBORDER * 2 + HGAP; + _h = 7 * rowHeight + VBORDER * 2 - VGAP + _th; int xoffset = HBORDER, yoffset = VBORDER + _th; WidgetArray wid; @@ -76,8 +77,8 @@ OptionsDialog::OptionsDialog(OSystem& osystem, DialogContainer& parent, ButtonWidget* bw = new ButtonWidget(this, _font, xoffset, yoffset, _w - HBORDER * 2, buttonHeight, "Use Basic Settings", kBasSetCmd); wid.push_back(bw); - yoffset += rowHeight + GAP * 2; - _h += rowHeight + GAP * 2; + yoffset += rowHeight + VGAP * 2; + _h += rowHeight + VGAP * 2; } auto ADD_OD_BUTTON = [&](const string& label, int cmd) @@ -111,8 +112,8 @@ OptionsDialog::OptionsDialog(OSystem& osystem, DialogContainer& parent, wid.push_back(b); // Move to second column - xoffset += buttonWidth + HBORDER; - yoffset = minSettings ? VBORDER + _th + rowHeight + GAP * 2 : VBORDER + _th; + xoffset += buttonWidth + HGAP; + yoffset = minSettings ? VBORDER + _th + rowHeight + VGAP * 2 : VBORDER + _th; myGameInfoButton = ADD_OD_BUTTON("Game Properties" + ELLIPSIS, kInfoCmd); wid.push_back(myGameInfoButton); @@ -135,8 +136,8 @@ OptionsDialog::OptionsDialog(OSystem& osystem, DialogContainer& parent, b = ADD_OD_BUTTON("About" + ELLIPSIS, kAboutCmd); wid.push_back(b); - buttonWidth = _font.getStringWidth(" Close ") + GAP * 5; - xoffset -= (buttonWidth + HBORDER) / 2; + buttonWidth = _font.getStringWidth(" Close ") + fontWidth * 2.5; + xoffset -= (buttonWidth + HGAP) / 2; b = ADD_OD_BUTTON("Close", kExitCmd); wid.push_back(b); addCancelWidget(b); diff --git a/src/gui/PopUpWidget.cxx b/src/gui/PopUpWidget.cxx index 89805621c..589c34660 100644 --- a/src/gui/PopUpWidget.cxx +++ b/src/gui/PopUpWidget.cxx @@ -41,11 +41,13 @@ PopUpWidget::PopUpWidget(GuiObject* boss, const GUI::Font& font, if(!_label.empty() && _labelWidth == 0) _labelWidth = _font.getStringWidth(_label); - _w = w + _labelWidth + 23; + setArrow(); + + _w = w + _labelWidth + dropDownWidth(font); // 23 // vertically center the arrows and text myTextY = (_h - _font.getFontHeight()) / 2; - myArrowsY = (_h - 8) / 2; + myArrowsY = (_h - _arrowHeight) / 2; myMenu = make_unique(this, font, list, cmd, w); } @@ -185,10 +187,10 @@ void PopUpWidget::handleCommand(CommandSender* sender, int cmd, int data, int id } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PopUpWidget::drawWidget(bool hilite) +void PopUpWidget::setArrow() { // Small down arrow - static constexpr std::array down_arrow = { + static constexpr std::array down_arrow = { 0b100000001, 0b110000011, 0b111000111, @@ -196,24 +198,40 @@ void PopUpWidget::drawWidget(bool hilite) 0b001111100, 0b000111000, 0b000010000, - 0b000000000 }; // Large down arrow - static constexpr std::array down_arrow_large = { - 0b00000000000, - 0b10000000001, - 0b11000000011, - 0b11100000111, - 0b11110001111, - 0b01111011110, - 0b00111111100, - 0b00011111000, - 0b00001110000, - 0b00000100000, - 0b00000000000 + static constexpr std::array down_arrow_large = { + 0b1000000000001, + 0b1100000000011, + 0b1110000000111, + 0b1111000001111, + 0b0111100011110, + 0b0011110111100, + 0b0001111111000, + 0b0000111110000, + 0b0000011100000, + 0b0000001000000 }; + if(_font.getFontHeight() < 24) + { + _textOfs = 3; + _arrowWidth = 9; + _arrowHeight = 7; + _arrowImg = down_arrow.data(); + } + else + { + _textOfs = 5; + _arrowWidth = 13; + _arrowHeight = 10; + _arrowImg = down_arrow_large.data(); + } +} +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PopUpWidget::drawWidget(bool hilite) +{ //cerr << "PopUpWidget::drawWidget\n"; FBSurface& s = dialog().surface(); bool onTop = _boss->dialog().isOnTop(); @@ -228,19 +246,22 @@ void PopUpWidget::drawWidget(bool hilite) // Draw a thin frame around us. s.frameRect(x, _y, w, _h, isEnabled() && hilite ? kWidColorHi : kColor); - s.frameRect(x + w - 16, _y + 1, 15, _h - 2, isEnabled() && hilite ? kWidColorHi : kBGColorLo); + s.frameRect(x + w - (_arrowWidth * 2 - 2), _y + 1, (_arrowWidth * 2 - 3), _h - 2, + isEnabled() && hilite ? kWidColorHi : kBGColorLo); // Fill the background - s.fillRect(x + 1, _y + 1, w - 17, _h - 2, onTop ? _changed ? kDbgChangedColor : kWidColor : kDlgColor); - s.fillRect(x + w - 15, _y + 2, 13, _h - 4, onTop ? isEnabled() && hilite ? kWidColor : kBGColorHi : kBGColorLo); + s.fillRect(x + 1, _y + 1, w - (_arrowWidth * 2 - 1), _h - 2, + onTop ? _changed ? kDbgChangedColor : kWidColor : kDlgColor); + s.fillRect(x + w - (_arrowWidth * 2 - 3), _y + 2, (_arrowWidth * 2 - 5), _h - 4, + onTop ? isEnabled() && hilite ? kWidColor : kBGColorHi : kBGColorLo); // Draw an arrow pointing down at the right end to signal this is a dropdown/popup - s.drawBitmap(down_arrow.data(), x + w - 13, _y + myArrowsY + 1, - !(isEnabled() && onTop) ? kColor : kTextColor, 9U, 8U); + s.drawBitmap(_arrowImg, x + w - (_arrowWidth * 1.5 - 1), _y + myArrowsY + 1, + !(isEnabled() && onTop) ? kColor : kTextColor, _arrowWidth, _arrowHeight); // Draw the selected entry, if any const string& name = myMenu->getSelectedName(); - TextAlign align = (_font.getStringWidth(name) > w-6) ? + TextAlign align = (_font.getStringWidth(name) > w - 6) ? TextAlign::Right : TextAlign::Left; - s.drawString(_font, name, x+2, _y+myTextY, w-6, + s.drawString(_font, name, x + _textOfs, _y + myTextY, w - 6, !(isEnabled() && onTop) ? kColor : _changed ? kDbgChangedTextColor : kTextColor, align); } diff --git a/src/gui/PopUpWidget.hxx b/src/gui/PopUpWidget.hxx index 955263f5f..c9817e6dd 100644 --- a/src/gui/PopUpWidget.hxx +++ b/src/gui/PopUpWidget.hxx @@ -62,6 +62,10 @@ class PopUpWidget : public Widget, public CommandSender const Variant& getSelectedTag() const; bool wantsFocus() const override { return true; } + static int dropDownWidth(const GUI::Font& font) + { + return font.getFontHeight() < 24 ? (9 * 2 + 3) : (13 * 2 + 7); + } protected: void handleMouseDown(int x, int y, MouseButton b, int clickCount) override; @@ -70,6 +74,8 @@ class PopUpWidget : public Widget, public CommandSender void handleMouseLeft() override; bool handleEvent(Event::Type e) override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; + + void setArrow(); void drawWidget(bool hilite) override; private: @@ -81,6 +87,11 @@ class PopUpWidget : public Widget, public CommandSender int _labelWidth{0}; bool _changed{false}; + int _textOfs{0}; + int _arrowWidth{0}; + int _arrowHeight{0}; + const uInt32* _arrowImg{nullptr}; + private: // Following constructors and assignment operators not supported PopUpWidget() = delete; diff --git a/src/gui/ProgressDialog.cxx b/src/gui/ProgressDialog.cxx index 5ff6f7698..04bc2adae 100644 --- a/src/gui/ProgressDialog.cxx +++ b/src/gui/ProgressDialog.cxx @@ -31,20 +31,23 @@ ProgressDialog::ProgressDialog(GuiObject* boss, const GUI::Font& font, { const int fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(), - lineHeight = font.getLineHeight(); + lineHeight = font.getLineHeight(), + VBORDER = fontHeight / 2, + HBORDER = fontWidth * 1.25, + VGAP = fontHeight / 4; int xpos, ypos, lwidth; // Calculate real dimensions lwidth = font.getStringWidth(message); - _w = lwidth + 2 * fontWidth; - _h = lineHeight * 5; + _w = HBORDER * 2 + lwidth; + _h = VBORDER * 2 + lineHeight * 2 + VGAP * 2; - xpos = fontWidth; ypos = lineHeight; + xpos = HBORDER; ypos = VBORDER; myMessage = new StaticTextWidget(this, font, xpos, ypos, lwidth, fontHeight, message, TextAlign::Center); myMessage->setTextColor(kTextColorEm); - xpos = fontWidth; ypos += 2 * lineHeight; + xpos = HBORDER; ypos += lineHeight + VGAP * 2; mySlider = new SliderWidget(this, font, xpos, ypos, lwidth, lineHeight, "", 0, 0); mySlider->setMinValue(1); mySlider->setMaxValue(100); diff --git a/src/gui/ScrollBarWidget.hxx b/src/gui/ScrollBarWidget.hxx index eddcd18d2..7752e8ab7 100644 --- a/src/gui/ScrollBarWidget.hxx +++ b/src/gui/ScrollBarWidget.hxx @@ -38,7 +38,7 @@ class ScrollBarWidget : public Widget, public CommandSender static int getWheelLines() { return _WHEEL_LINES; } static int scrollBarWidth(const GUI::Font& font) { - return ((int(font.getMaxCharWidth() * 1.67) >> 1) << 1) + 1; + return font.getFontHeight() < 24 ? 15 : 23; } private: From d7f129cefe7eda16834a5ca0363c1828e920f672 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 30 Apr 2020 09:39:42 +0200 Subject: [PATCH 162/377] Part 3 of the changes for #600 (UI fonts) --- src/debugger/gui/FlashWidget.cxx | 5 ++--- src/debugger/gui/RiotWidget.cxx | 2 +- src/gui/DeveloperDialog.cxx | 2 +- src/gui/EditTextWidget.cxx | 13 +++++++++++-- src/gui/EditTextWidget.hxx | 1 + src/gui/GameInfoDialog.cxx | 2 +- src/gui/StringListWidget.cxx | 12 +++++++++++- src/gui/StringListWidget.hxx | 1 + src/gui/TimeMachineDialog.cxx | 7 ++++--- src/gui/UIDialog.cxx | 8 ++++---- src/gui/Widget.cxx | 2 +- 11 files changed, 38 insertions(+), 17 deletions(-) diff --git a/src/debugger/gui/FlashWidget.cxx b/src/debugger/gui/FlashWidget.cxx index ace5e30cb..3c2614659 100644 --- a/src/debugger/gui/FlashWidget.cxx +++ b/src/debugger/gui/FlashWidget.cxx @@ -30,7 +30,6 @@ FlashWidget::FlashWidget(GuiObject* boss, const GUI::Font& font, // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FlashWidget::init(GuiObject* boss, const GUI::Font& font, int x, int y) { - const GUI::Font& ifont = instance().frameBuffer().infoFont(); const int lineHeight = font.getLineHeight(); int xpos = x, ypos = y; @@ -38,14 +37,14 @@ void FlashWidget::init(GuiObject* boss, const GUI::Font& font, int x, int y) ypos += lineHeight + 6; - new StaticTextWidget(boss, ifont, xpos, ypos, "Pages/Ranges used:"); + new StaticTextWidget(boss, font, xpos, ypos, "Pages/Ranges used:"); ypos += lineHeight + 2; xpos += 8; for(uInt32 page = 0; page < MAX_PAGES; ++page) { - myPage[page] = new StaticTextWidget(boss, ifont, xpos, ypos, + myPage[page] = new StaticTextWidget(boss, font, xpos, ypos, page ? " " : "none "); ypos += lineHeight; } diff --git a/src/debugger/gui/RiotWidget.cxx b/src/debugger/gui/RiotWidget.cxx index eef3cce66..43514e072 100644 --- a/src/debugger/gui/RiotWidget.cxx +++ b/src/debugger/gui/RiotWidget.cxx @@ -214,7 +214,7 @@ RiotWidget::RiotWidget(GuiObject* boss, const GUI::Font& lfont, // 2600/7800 mode lwidth = lfont.getStringWidth("Console") + 29; - pwidth = lfont.getStringWidth("Atari 2600") + 4; + pwidth = lfont.getStringWidth("Atari 2600") + 6; new StaticTextWidget(boss, lfont, 10, ypos+1, "Console"); myConsole = new EditTextWidget(boss, lfont, 10 + lwidth, ypos - 1, pwidth, lineHeight); myConsole->setEditable(false, true); diff --git a/src/gui/DeveloperDialog.cxx b/src/gui/DeveloperDialog.cxx index e59f9555e..0bcbe32e6 100644 --- a/src/gui/DeveloperDialog.cxx +++ b/src/gui/DeveloperDialog.cxx @@ -616,7 +616,7 @@ void DeveloperDialog::addDebuggerTab(const GUI::Font& font) // Add message concerning usage const GUI::Font& infofont = instance().frameBuffer().infoFont(); ypos = myTab->getHeight() - fontHeight - infofont.getFontHeight() - VGAP - VBORDER; - new StaticTextWidget(myTab, infofont, HBORDER, ypos, "(*) Changes require a ROM reload"); + new StaticTextWidget(myTab, infofont, HBORDER, ypos, "(*) Change requires a ROM reload"); #if defined(DEBUGGER_SUPPORT) && defined(WINDOWED_SUPPORT) // Debugger is only realistically available in windowed modes 800x600 or greater diff --git a/src/gui/EditTextWidget.cxx b/src/gui/EditTextWidget.cxx index 09c9f3106..ff53ced5a 100644 --- a/src/gui/EditTextWidget.cxx +++ b/src/gui/EditTextWidget.cxx @@ -29,6 +29,15 @@ EditTextWidget::EditTextWidget(GuiObject* boss, const GUI::Font& font, _flags = Widget::FLAG_ENABLED | Widget::FLAG_CLEARBG | Widget::FLAG_RETAIN_FOCUS; EditableWidget::startEditMode(); // We're always in edit mode + + if(_font.getFontHeight() < 24) + { + _textOfs = 3; + } + else + { + _textOfs = 5; + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -92,7 +101,7 @@ void EditTextWidget::drawWidget(bool hilite) // Draw the text adjustOffset(); - s.drawString(_font, editString(), _x + 2, _y + 2, getEditRect().w(), getEditRect().h(), + s.drawString(_font, editString(), _x + _textOfs, _y + 2, getEditRect().w(), getEditRect().h(), _changed && onTop && isEnabled() ? kDbgChangedTextColor : onTop && isEnabled() ? _textcolor : kColor, @@ -105,7 +114,7 @@ void EditTextWidget::drawWidget(bool hilite) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Common::Rect EditTextWidget::getEditRect() const { - return Common::Rect(2, 1, _w - 2, _h); + return Common::Rect(_textOfs, 1, _w - _textOfs, _h); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/gui/EditTextWidget.hxx b/src/gui/EditTextWidget.hxx index 50f8bfdc8..56c6d0bd4 100644 --- a/src/gui/EditTextWidget.hxx +++ b/src/gui/EditTextWidget.hxx @@ -49,6 +49,7 @@ class EditTextWidget : public EditableWidget protected: string _backupString; bool _changed{false}; + int _textOfs{0}; private: // Following constructors and assignment operators not supported diff --git a/src/gui/GameInfoDialog.cxx b/src/gui/GameInfoDialog.cxx index 6e6e89620..cfa50e193 100644 --- a/src/gui/GameInfoDialog.cxx +++ b/src/gui/GameInfoDialog.cxx @@ -156,7 +156,7 @@ GameInfoDialog::GameInfoDialog( // Add message concerning usage ypos = myTab->getHeight() - fontHeight - ifont.getFontHeight() - VGAP - VBORDER; new StaticTextWidget(myTab, ifont, HBORDER, ypos, - "(*) Changes require a ROM reload"); + "(*) Change requires a ROM reload"); // Add items for tab 0 addToFocusList(wid, myTab, tabID); diff --git a/src/gui/StringListWidget.cxx b/src/gui/StringListWidget.cxx index 8af0fcb80..46aed13ba 100644 --- a/src/gui/StringListWidget.cxx +++ b/src/gui/StringListWidget.cxx @@ -29,6 +29,16 @@ StringListWidget::StringListWidget(GuiObject* boss, const GUI::Font& font, _hilite(hilite) { _bgcolorlo = kDlgColor; + + + if(_font.getFontHeight() < 24) + { + _textOfs = 3; + } + else + { + _textOfs = 5; + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -106,5 +116,5 @@ void StringListWidget::drawWidget(bool hilite) Common::Rect StringListWidget::getEditRect() const { const int offset = std::max(0, (_selectedItem - _currentPos) * _fontHeight); - return Common::Rect(2, 1 + offset, _w - 2, _fontHeight + offset); + return Common::Rect(_textOfs, 1 + offset, _w - _textOfs, _fontHeight + offset); } diff --git a/src/gui/StringListWidget.hxx b/src/gui/StringListWidget.hxx index 18080a7c7..10c197509 100644 --- a/src/gui/StringListWidget.hxx +++ b/src/gui/StringListWidget.hxx @@ -39,6 +39,7 @@ class StringListWidget : public ListWidget protected: bool _hilite{false}; + int _textOfs{0}; private: // Following constructors and assignment operators not supported diff --git a/src/gui/TimeMachineDialog.cxx b/src/gui/TimeMachineDialog.cxx index e5881ef01..65e7c8033 100644 --- a/src/gui/TimeMachineDialog.cxx +++ b/src/gui/TimeMachineDialog.cxx @@ -196,7 +196,7 @@ TimeMachineDialog::TimeMachineDialog(OSystem& osystem, DialogContainer& parent, // Set real dimensions _w = width; // Parent determines our width (based on window size) - _h = V_BORDER * 2 + rowHeight + buttonHeight + 2; + _h = V_BORDER * 2 + rowHeight + std::max(buttonHeight + 2, rowHeight); this->clearFlags(Widget::FLAG_CLEARBG); // does only work combined with blending (0..100)! this->clearFlags(Widget::FLAG_BORDER); @@ -221,9 +221,10 @@ TimeMachineDialog::TimeMachineDialog(OSystem& osystem, DialogContainer& parent, ypos += rowHeight; // Add time info - myCurrentTimeWidget = new StaticTextWidget(this, font, xpos, ypos + 3, "00:00.00", TextAlign::Left, kBGColor); + int ypos_s = ypos + (buttonHeight - font.getFontHeight() + 1) / 2; // align to button vertical center + myCurrentTimeWidget = new StaticTextWidget(this, font, xpos, ypos_s, "00:00.00", TextAlign::Left, kBGColor); myCurrentTimeWidget->setTextColor(kColorInfo); - myLastTimeWidget = new StaticTextWidget(this, font, _w - H_BORDER - font.getStringWidth("00:00.00"), ypos + 3, + myLastTimeWidget = new StaticTextWidget(this, font, _w - H_BORDER - font.getStringWidth("00:00.00"), ypos_s, "00:00.00", TextAlign::Right, kBGColor); myLastTimeWidget->setTextColor(kColorInfo); xpos = myCurrentTimeWidget->getRight() + BUTTON_GAP * 4; diff --git a/src/gui/UIDialog.cxx b/src/gui/UIDialog.cxx index 27d0ad9ee..7533755f3 100644 --- a/src/gui/UIDialog.cxx +++ b/src/gui/UIDialog.cxx @@ -182,10 +182,10 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, // Add message concerning usage ypos = myTab->getHeight() - fontHeight - ifont.getFontHeight() - VGAP - VBORDER; - lwidth = ifont.getStringWidth("(*) Changes require application restart"); + lwidth = ifont.getStringWidth("(*) Change requires an application restart"); new StaticTextWidget(myTab, ifont, xpos, ypos, std::min(lwidth, _w - HBORDER * 2), ifont.getFontHeight(), - "(*) Changes require application restart"); + "(*) Change requires an application restart"); // Add items for tab 0 addToFocusList(wid, myTab, tabID); @@ -286,10 +286,10 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, // Add message concerning usage xpos = HBORDER; ypos = myTab->getHeight() - fontHeight - ifont.getFontHeight() - VGAP - VBORDER; - lwidth = ifont.getStringWidth("(*) Changes require application restart"); + lwidth = ifont.getStringWidth("(*) Changes require an application restart"); new StaticTextWidget(myTab, ifont, xpos, ypos, std::min(lwidth, _w - HBORDER * 2), ifont.getFontHeight(), - "(*) Changes require application restart"); + "(*) Changes require an application restart"); // Add items for tab 1 addToFocusList(wid, myTab, tabID); diff --git a/src/gui/Widget.cxx b/src/gui/Widget.cxx index c86472f28..ed6ba2f02 100644 --- a/src/gui/Widget.cxx +++ b/src/gui/Widget.cxx @@ -831,7 +831,7 @@ void SliderWidget::drawWidget(bool hilite) int p = valueToPos(_value), h = _h - _font.getFontHeight() / 2 - 1, x = _x + _labelWidth, - y = _y + (_h - h) / 2 + 1; + y = _y + 2 + _font.desc().ascent - (_font.getFontHeight() + 1) / 2 - 1; // align to bottom of font // Fill the box s.fillRect(x, y, _w - _labelWidth - _valueLabelGap - _valueLabelWidth, h, From 5d1d8e68bbd30b503d1f35dd64a01def929055f9 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 30 Apr 2020 10:33:42 +0200 Subject: [PATCH 163/377] update documentation --- Changes.txt | 4 ++-- docs/graphics/options_misc.png | Bin 4123 -> 4416 bytes docs/graphics/options_misc_classic.png | Bin 4033 -> 3809 bytes docs/graphics/options_misc_light.png | Bin 4100 -> 5797 bytes docs/graphics/options_ui.png | Bin 3363 -> 3673 bytes docs/index.html | 15 +++++++++++++-- 6 files changed, 15 insertions(+), 4 deletions(-) diff --git a/Changes.txt b/Changes.txt index 2c4118cd7..c3c0304e1 100644 --- a/Changes.txt +++ b/Changes.txt @@ -24,9 +24,9 @@ * Added 'Turbo' mode, runs the game as fast as the computer allows. - * Added selectable dialog fonts (TODO: Doc) + * Added selectable dialog fonts - * Added option which lets default ROM path follow launcher navigation (TODO: Doc) + * Added option which lets default ROM path follow launcher navigation * Added displaying last write address in the debugger. diff --git a/docs/graphics/options_misc.png b/docs/graphics/options_misc.png index aa382419f4c5678bbfb04b784119b697fce6c0a6..b1930b45d7a246f7cc729bb5c0ef6e4cc70e0431 100644 GIT binary patch literal 4416 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 xCqQ5R5*PML;8VuK4z&hdyt14m#s}>+kn%Q}qA< literal 3363 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 Ul#q-``}SlpHaMzZtm_!_A4m^S{{R30 diff --git a/docs/index.html b/docs/index.html index e57dd3d51..c845b487f 100644 --- a/docs/index.html +++ b/docs/index.html @@ -2404,6 +2404,11 @@ Use the specified palette for UI elements. + +
      -dialogfont <small|low_medium|medium|large|large12|large14|large16>
      + Set the size of the font in the dialogs. + +
      -dialogpos <0 - 4>
      Set the position of dialogs within Stella windows (0 = center). @@ -2448,7 +2453,12 @@
      -romdir <dir>
      - Set the directory where the ROM launcher will start. + Set the path where the ROM launcher will start. + + + +
      -followlauncher <0|1>
      + Make the start path follow ROM launcher navigation. @@ -2914,8 +2924,9 @@ - + + From ad3f86796a9f358b8fead216af50288dcb71cf65 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 30 Apr 2020 11:24:10 +0200 Subject: [PATCH 164/377] adjust minimal launcher size based on dialog font --- src/emucore/FrameBuffer.cxx | 3 +-- src/emucore/FrameBuffer.hxx | 12 +++++++++--- src/gui/UIDialog.cxx | 39 +++++++++++++++++++++++++++++-------- src/gui/UIDialog.hxx | 3 ++- 4 files changed, 43 insertions(+), 14 deletions(-) diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 73b276e32..eb35cfe5c 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -171,8 +171,7 @@ void FrameBuffer::setupFonts() // However, we have to make sure all Dialogs are sized using the fontsize. int zoom_h = (fd.height * 4 * 2) / GUI::stellaMediumDesc.height; int zoom_w = (fd.maxwidth * 4 * 2) / GUI::stellaMediumDesc.maxwidth; - int zoom = std::max(zoom_w, zoom_h); - myTIAMinZoom = std::max(2 * 4, zoom) / 4.F; // round to 25% steps + myTIAMinZoom = std::max(zoom_w, zoom_h) / 4.F; // round to 25% steps } diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index a6872eeac..35c656cf0 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -307,6 +307,15 @@ class FrameBuffer const GUI::Font& infoFont() const { return *myInfoFont; } const GUI::Font& smallFont() const { return *mySmallFont; } const GUI::Font& launcherFont() const { return *myLauncherFont; } + + /** + Get the font description from the font name + + @param name The settings name of the font + + @return The description of the font + */ + FontDesc getFontDesc(const string& name) const; #endif ////////////////////////////////////////////////////////////////////// @@ -485,9 +494,6 @@ class FrameBuffer Setup the UI fonts */ void setupFonts(); - - - FontDesc getFontDesc(const string& name) const; #endif /** diff --git a/src/gui/UIDialog.cxx b/src/gui/UIDialog.cxx index 7533755f3..099886b9b 100644 --- a/src/gui/UIDialog.cxx +++ b/src/gui/UIDialog.cxx @@ -30,6 +30,7 @@ #include "TabWidget.hxx" #include "Widget.hxx" #include "Font.hxx" +#include "StellaMediumFont.hxx" #include "LauncherDialog.hxx" #ifdef DEBUGGER_SUPPORT #include "DebuggerDialog.hxx" @@ -100,7 +101,7 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, VarList::push_back(items, "Large (14pt)", "large14"); // 14x28 VarList::push_back(items, "Large (16pt)", "large16"); // 16x32 myDialogFontPopup = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, - items, "Dialogs font (*)", lwidth); + items, "Dialogs font (*)", lwidth, kDialogFont); wid.push_back(myDialogFontPopup); // Enable HiDPI mode @@ -208,7 +209,7 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, _w - xpos - HBORDER - 2, lineHeight, ""); wid.push_back(myRomPath); - xpos = _w - HBORDER - font.getStringWidth("Follow Launcher path") - CheckboxWidget::prefixSize(font); + xpos = _w - HBORDER - font.getStringWidth("Follow Launcher path") - CheckboxWidget::prefixSize(font) - 1; ypos += lineHeight + VGAP * 2; myFollowLauncherWidget = new CheckboxWidget(myTab, font, xpos, ypos, "Follow Launcher path"); wid.push_back(myFollowLauncherWidget); @@ -219,21 +220,15 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, // Launcher width and height myLauncherWidthSlider = new SliderWidget(myTab, font, xpos, ypos, "Launcher width ", lwidth, 0, 6 * fontWidth, "px"); - myLauncherWidthSlider->setMinValue(FBMinimum::Width); myLauncherWidthSlider->setMaxValue(ds.w); myLauncherWidthSlider->setStepValue(10); - // one tickmark every ~100 pixel - myLauncherWidthSlider->setTickmarkIntervals((ds.w - FBMinimum::Width + 50) / 100); wid.push_back(myLauncherWidthSlider); ypos += lineHeight + VGAP; myLauncherHeightSlider = new SliderWidget(myTab, font, xpos, ypos, "Launcher height ", lwidth, 0, 6 * fontWidth, "px"); - myLauncherHeightSlider->setMinValue(FBMinimum::Height); myLauncherHeightSlider->setMaxValue(ds.h); myLauncherHeightSlider->setStepValue(10); - // one tickmark every ~100 pixel - myLauncherHeightSlider->setTickmarkIntervals((ds.h - FBMinimum::Height + 50) / 100); wid.push_back(myLauncherHeightSlider); ypos += lineHeight + VGAP; @@ -399,6 +394,7 @@ void UIDialog::loadConfig() int cr = settings.getInt("ctrlrate"); myControllerRateSlider->setValue(cr); + handleLauncherSize(); handleRomViewer(); myTab->loadConfig(); @@ -530,6 +526,10 @@ void UIDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) setDefaults(); break; + case kDialogFont: + handleLauncherSize(); + break; + case kListDelay: if(myListDelaySlider->getValue() == 0) { @@ -600,6 +600,29 @@ void UIDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) } } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void UIDialog::handleLauncherSize() +{ + // Determine minimal launcher sizebased on the default font + // So what fits with default font should fit for any font. + FontDesc fd = instance().frameBuffer().getFontDesc(myDialogFontPopup->getSelectedTag().toString()); + int w = std::max(FBMinimum::Width, FBMinimum::Width * fd.maxwidth / GUI::stellaMediumDesc.maxwidth); + int h = std::max(FBMinimum::Height, FBMinimum::Height * fd.height / GUI::stellaMediumDesc.height); + const Common::Size& ds = instance().frameBuffer().desktopSize(); + + myLauncherWidthSlider->setMinValue(w); + if(myLauncherWidthSlider->getValue() < myLauncherWidthSlider->getMinValue()) + myLauncherWidthSlider->setValue(w); + // one tickmark every ~100 pixel + myLauncherWidthSlider->setTickmarkIntervals((ds.w - w + 67) / 100); + + myLauncherHeightSlider->setMinValue(h); + if(myLauncherHeightSlider->getValue() < myLauncherHeightSlider->getMinValue()) + myLauncherHeightSlider->setValue(h); + // one tickmark every ~100 pixel + myLauncherHeightSlider->setTickmarkIntervals((ds.h - h + 67) / 100); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /*void UIDialog::handleLauncherSize() // an attempt to limit the minimal and maximal ROM info percentages diff --git a/src/gui/UIDialog.hxx b/src/gui/UIDialog.hxx index 5a0b8ae03..83851e971 100644 --- a/src/gui/UIDialog.hxx +++ b/src/gui/UIDialog.hxx @@ -33,13 +33,14 @@ class UIDialog : public Dialog, public CommandSender void setDefaults() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - //void handleLauncherSize(); + void handleLauncherSize(); void handleRomViewer(); void createBrowser(const string& title); private: enum { + kDialogFont = 'UIDf', kListDelay = 'UILd', kMouseWheel = 'UIMw', kControllerDelay = 'UIcd', From 3107c1e44ed7eb9efd89073829d374e8427c1797 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 30 Apr 2020 16:11:08 +0200 Subject: [PATCH 165/377] Two minor formatting fixes --- src/gui/CommandDialog.cxx | 2 +- src/gui/TimeMachineDialog.cxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/CommandDialog.cxx b/src/gui/CommandDialog.cxx index f1ee4b4a0..86fc6f8c9 100644 --- a/src/gui/CommandDialog.cxx +++ b/src/gui/CommandDialog.cxx @@ -36,7 +36,7 @@ CommandDialog::CommandDialog(OSystem& osystem, DialogContainer& parent) const int lineHeight = _font.getLineHeight(), fontHeight = _font.getFontHeight(), fontWidth = _font.getMaxCharWidth(), - buttonHeight = _font.getLineHeight() * 1.5, + buttonHeight = _font.getLineHeight() * 1.25, buttonWidth = _font.getStringWidth("Time Machine On") + fontWidth * 2; const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; diff --git a/src/gui/TimeMachineDialog.cxx b/src/gui/TimeMachineDialog.cxx index 65e7c8033..e84c50223 100644 --- a/src/gui/TimeMachineDialog.cxx +++ b/src/gui/TimeMachineDialog.cxx @@ -263,7 +263,7 @@ TimeMachineDialog::TimeMachineDialog(OSystem& osystem, DialogContainer& parent, xpos = myLoadAllWidget->getRight() + BUTTON_GAP * 4; // Add message - myMessageWidget = new StaticTextWidget(this, font, xpos, ypos + 3, + myMessageWidget = new StaticTextWidget(this, font, xpos, ypos_s, " ", TextAlign::Left, kBGColor); myMessageWidget->setTextColor(kColorInfo); } From ea53c742c43470c034323fd3aca4aca4ae16962c Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 30 Apr 2020 23:45:14 +0200 Subject: [PATCH 166/377] fix disassembly for segmented bankswitching types --- src/debugger/CartDebug.cxx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index c929efa2a..9666fc6d2 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -71,12 +71,16 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem) } // Create bank information for each potential bank, and an extra one for ZP RAM + // ROM sizes greater than 4096 indicate multi-bank ROMs, but we handle only + // 4K pieces at a time + // ROM sizes less than 4K use the actual value + size_t romSize = 0; + myConsole.cartridge().getImage(romSize); + BankInfo info; + info.size = std::min(romSize, 4_KB); for(uInt32 i = 0; i < myConsole.cartridge().bankCount(); ++i) - { - info.size = myConsole.cartridge().bankSize(i); myBankInfo.push_back(info); - } info.size = 128; // ZP RAM myBankInfo.push_back(info); From 07dcdc83b0ae271c67f9923d158fec51245a2739 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 30 Apr 2020 23:45:14 +0200 Subject: [PATCH 167/377] fix disassembly for segmented bankswitching types --- src/debugger/CartDebug.cxx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index ef6924187..5192f84e8 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -71,18 +71,19 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem) } // Create bank information for each potential bank, and an extra one for ZP RAM + // ROM sizes greater than 4096 indicate multi-bank ROMs, but we handle only + // 4K pieces at a time + // ROM sizes less than 4K use the actual value + size_t romSize = 0; + myConsole.cartridge().getImage(romSize); + BankInfo info; + info.size = std::min(romSize, 4_KB); for(uInt32 i = 0; i < myConsole.cartridge().romBankCount(); ++i) - { - info.size = myConsole.cartridge().bankSize(i); myBankInfo.push_back(info); - } for(uInt32 i = 0; i < myConsole.cartridge().ramBankCount(); ++i) - { - info.size = myConsole.cartridge().bankSize(i) >> 1; myBankInfo.push_back(info); - } info.size = 128; // ZP RAM myBankInfo.push_back(info); From e35c748cb42a3df5aeb670445eb284aa3a47a5c8 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Fri, 1 May 2020 12:10:00 +0200 Subject: [PATCH 168/377] small fix in debugger dialog --- src/debugger/gui/TiaInfoWidget.cxx | 13 ++++++------- src/gui/EditTextWidget.hxx | 12 ++++++++++++ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/debugger/gui/TiaInfoWidget.cxx b/src/debugger/gui/TiaInfoWidget.cxx index 33ea5c7cf..21681d2c0 100644 --- a/src/debugger/gui/TiaInfoWidget.cxx +++ b/src/debugger/gui/TiaInfoWidget.cxx @@ -34,15 +34,16 @@ TiaInfoWidget::TiaInfoWidget(GuiObject* boss, const GUI::Font& lfont, : Widget(boss, lfont, x, y, 16, 16), CommandSender(boss) { - bool longstr = 34 * lfont.getMaxCharWidth() <= max_w; + bool longstr = 11 + 32 * lfont.getMaxCharWidth() + 9 + + EditTextWidget::calcWidth(lfont) * 3 <= max_w; const int VGAP = 5; x += 11; const int lineHeight = lfont.getLineHeight(); int xpos = x, ypos = y + 10; int lwidth = lfont.getStringWidth(longstr ? "Frame Cycle " : "F. Cycle "); - int fwidth = 5 * lfont.getMaxCharWidth() + 4; - int twidth = 8 * lfont.getMaxCharWidth() + 4; + int fwidth = EditTextWidget::calcWidth(lfont, 5); + int twidth = EditTextWidget::calcWidth(lfont, 8); // Add frame info // 1st column @@ -78,11 +79,9 @@ TiaInfoWidget::TiaInfoWidget(GuiObject* boss, const GUI::Font& lfont, // 2nd column xpos = x + lwidth + myFrameCycles->getWidth() + 9; ypos = y + 10; lwidth = lfont.getStringWidth(longstr ? "Color Clock " : "Pixel Pos "); - fwidth = 3 * lfont.getMaxCharWidth() + 4; + fwidth = EditTextWidget::calcWidth(lfont, 3); - new StaticTextWidget(boss, lfont, xpos, ypos, - lfont.getStringWidth(longstr ? "Scanline" : "Scn Ln"), lineHeight, - longstr ? "Scanline" : "Scn Ln", TextAlign::Left); + new StaticTextWidget(boss, lfont, xpos, ypos, longstr ? "Scanline" : "Scn Ln"); myScanlineCountLast = new EditTextWidget(boss, nfont, xpos+lwidth, ypos-1, fwidth, lineHeight, ""); myScanlineCountLast->setEditable(false, true); diff --git a/src/gui/EditTextWidget.hxx b/src/gui/EditTextWidget.hxx index 56c6d0bd4..f752ae385 100644 --- a/src/gui/EditTextWidget.hxx +++ b/src/gui/EditTextWidget.hxx @@ -32,6 +32,18 @@ class EditTextWidget : public EditableWidget void setText(const string& str, bool changed = false) override; + // Get total width of widget + static int calcWidth(const GUI::Font& font, int length = 0) + { + return length * font.getMaxCharWidth() + + (font.getFontHeight() < 24 ? 3 * 2 : 5 * 2); + } + // Get total width of widget + static int calcWidth(const GUI::Font& font, const string& str) + { + return calcWidth(font, int(str.length())); + } + protected: void drawWidget(bool hilite) override; void lostFocusWidget() override; From 436a1a686145ee8709c935947ddeb75c1453fed6 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Fri, 1 May 2020 20:49:45 +0200 Subject: [PATCH 169/377] fix #613 (debugger focus) --- src/debugger/Debugger.cxx | 1 + src/debugger/gui/DebuggerDialog.cxx | 16 ++++++++++------ src/debugger/gui/DebuggerDialog.hxx | 4 +++- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/debugger/Debugger.cxx b/src/debugger/Debugger.cxx index cfb16a1e5..a96f208ec 100644 --- a/src/debugger/Debugger.cxx +++ b/src/debugger/Debugger.cxx @@ -688,6 +688,7 @@ void Debugger::setStartState() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::setQuitState() { + myDialog->saveConfig(); saveOldState(); // Bus must be unlocked for normal operation when leaving debugger mode diff --git a/src/debugger/gui/DebuggerDialog.cxx b/src/debugger/gui/DebuggerDialog.cxx index ac3c8d6c9..fd15820c4 100644 --- a/src/debugger/gui/DebuggerDialog.cxx +++ b/src/debugger/gui/DebuggerDialog.cxx @@ -71,12 +71,11 @@ DebuggerDialog::DebuggerDialog(OSystem& osystem, DialogContainer& parent, // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::loadConfig() { - // set initial focus to myPrompt - if (myFirstLoad) - { - setFocus(myPrompt); - myFirstLoad = false; - } + if(myFocusedWidget == nullptr) + // Set initial focus to prompt tab + myFocusedWidget = myPrompt; + // Restore focus + setFocus(myFocusedWidget); myTab->loadConfig(); myTiaInfo->loadConfig(); @@ -89,6 +88,11 @@ void DebuggerDialog::loadConfig() myMessageBox->setText(""); } +void DebuggerDialog::saveConfig() +{ + myFocusedWidget = _focusedWidget; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::handleKeyDown(StellaKey key, StellaMod mod, bool repeated) { diff --git a/src/debugger/gui/DebuggerDialog.hxx b/src/debugger/gui/DebuggerDialog.hxx index b1b42211a..2fa007214 100644 --- a/src/debugger/gui/DebuggerDialog.hxx +++ b/src/debugger/gui/DebuggerDialog.hxx @@ -71,6 +71,7 @@ class DebuggerDialog : public Dialog ButtonWidget& unwindButton() const { return *myUnwindButton; } void showFatalMessage(const string& msg); + void saveConfig(); private: void center() override { positionAt(0); } @@ -136,7 +137,8 @@ class DebuggerDialog : public Dialog unique_ptr myLFont; // used for labels unique_ptr myNFont; // used for normal text - bool myFirstLoad{true}; + Widget* myFocusedWidget{nullptr}; + private: // Following constructors and assignment operators not supported From f2caf9509c2256aa2dd19e0caefe6e5e346bf74b Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 2 May 2020 09:20:22 +0200 Subject: [PATCH 170/377] added some more MDM test ROMs and their properties --- src/emucore/DefProps.hxx | 5 ++++- src/emucore/stella.pro | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/emucore/DefProps.hxx b/src/emucore/DefProps.hxx index d5bb3533e..354f68d30 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 = 3510; +static constexpr uInt32 DEF_PROPS_SIZE = 3513; static const BSPF::array2D DefProps = {{ { "000509d1ed2b8d30a9d94be1b3b5febb", "Greg Zumwalt", "", "Jungle Jane (2003) (Greg Zumwalt) (Hack)", "Hack of Pitfall!", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -1032,6 +1032,7 @@ static const BSPF::array2D DefProps = {{ { "4904a2550759b9b4570e886374f9d092", "Parker Brothers, Charlie Heath", "931506", "Reactor (1983) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "490e3cc59d82f85fae817cdf767ea7a0", "", "", "Berzerk (Unknown) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "490eed07d4691b27f473953fbea6541a", "Activision, Steve Cartwright, David Crane", "AB-035-04", "Pitfall II (1983) (Activision) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "49366f41aa7a54baf263426e99ce4312", "", "", "POP-MDM-Test (PAL) (63 games)", "", "", "", "", "MDM", "", "", "", "", "JOYSTICK", "JOYSTICK", "", "", "", "", "", "", "", "" }, { "493daaf9fb1ba450eba6b8ed53ffb37d", "", "", "3-D Corridor Demo (27-03-2003) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "493de059b32f84ab29cde6213964aeee", "Atari, Bill Aspromonte, Andrew Fuchs", "CX26120", "Stargate (1984) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "493e90602a4434b117c91c95e73828d1", "Telegames", "", "Lock 'n' Chase (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -1366,6 +1367,7 @@ static const BSPF::array2D DefProps = {{ { "61719a8bdafbd8dab3ca9ce7b171b9e2", "", "", "Enduro (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "61728c6cfb052e62a9ed088c5bf407ba", "", "", "Sprite Demo 4 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "619de46281eb2e0adbb98255732483b4", "", "", "Time Warp (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "61baadddc2c8f6e5faa57d4d0f285462", "", "", "208-in-1 MDM-Test (PAL) (127 games)", "", "", "", "", "MDM", "", "", "", "", "JOYSTICK", "JOYSTICK", "", "", "", "", "", "", "", "" }, { "61dbe94f110f30ca4ec524ae5ce2d026", "CCE", "C-820", "Space Invaders (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "61e0f5e1cc207e98704d0758c68df317", "Star Game", "007", "Tennis (Star Game)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "61ef8c2fc43be9a04fe13fdb79ff2bd9", "", "", "Gas Gauge Demo - Revisited (2001) (Joe Grand) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -2326,6 +2328,7 @@ static const BSPF::array2D DefProps = {{ { "a89a3e0547d6887279c34aba4b17a560", "M Network, Steve Crandall, Patricia Lewis Du Long", "MT4646", "Rocky & Bullwinkle (1983) (Mattel) (Prototype)", "", "Prototype", "", "", "4K", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a8a703e073183a89c94d4d99b9661b7f", "Franklin Cruz", "", "Spice Invaders (Franklin Cruz) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a8b3ea6836b99bea77c8f603cf1ea187", "CCE", "C-861", "Boxing (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "a8c447efbec3a2b5d08b05a09999bd92", "", "", "MegaCart Menu", "", "", "", "", "", "", "", "", "", "JOYSTICK", "JOYSTICK", "", "", "", "", "", "", "", "" }, { "a8c48b4e0bf35fe97cc84fdd2c507f78", "Puzzy - Bit Corporation", "PG201", "Seamonster (1982) (Puzzy)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a8d0a4a77cd71ac601bd71df5a060e4c", "", "", "Space Shuttle (1983) (Activision) [t2] (Fuel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a8d4a9500b18b0a067a1f272f869e094", "", "", "Red And White Checkerboard Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, diff --git a/src/emucore/stella.pro b/src/emucore/stella.pro index 4a8ba020e..ef12c4369 100644 --- a/src/emucore/stella.pro +++ b/src/emucore/stella.pro @@ -6131,6 +6131,13 @@ "Cart.Name" "Pitfall II (1983) (Activision) [a]" "" +"Cart.MD5" "49366f41aa7a54baf263426e99ce4312" +"Cart.Name" "POP-MDM-Test (PAL) (63 games)" +"Cart.Type" "MDM" +"Controller.Left" "JOYSTICK" +"Controller.Right" "JOYSTICK" +"" + "Cart.MD5" "493daaf9fb1ba450eba6b8ed53ffb37d" "Cart.Name" "3-D Corridor Demo (27-03-2003) (MP)" "" @@ -8158,6 +8165,13 @@ "Cart.Name" "Time Warp (Unknown)" "" +"Cart.MD5" "61baadddc2c8f6e5faa57d4d0f285462" +"Cart.Name" "208-in-1 MDM-Test (PAL) (127 games)" +"Cart.Type" "MDM" +"Controller.Left" "JOYSTICK" +"Controller.Right" "JOYSTICK" +"" + "Cart.MD5" "61dbe94f110f30ca4ec524ae5ce2d026" "Cart.Manufacturer" "CCE" "Cart.ModelNo" "C-820" @@ -13974,6 +13988,12 @@ "Cart.Name" "Boxing (1983) (CCE)" "" +"Cart.MD5" "a8c447efbec3a2b5d08b05a09999bd92" +"Cart.Name" "MegaCart Menu" +"Controller.Left" "JOYSTICK" +"Controller.Right" "JOYSTICK" +"" + "Cart.MD5" "a8c48b4e0bf35fe97cc84fdd2c507f78" "Cart.Manufacturer" "Puzzy - Bit Corporation" "Cart.ModelNo" "PG201" From d9113560542f17e7dbddb98df893cd88a01c67cc Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 2 May 2020 16:46:37 +0200 Subject: [PATCH 171/377] Make windows positioning independent for launcher, emulator and debugger (resolves #615) --- docs/index.html | 30 ++++++++++++++ src/common/FrameBufferSDL2.cxx | 72 ++++++++++++++++------------------ src/common/FrameBufferSDL2.hxx | 22 ++++++++--- src/debugger/Debugger.cxx | 3 +- src/emucore/Console.cxx | 4 +- src/emucore/FrameBuffer.cxx | 58 ++++++++++++++++++++++++++- src/emucore/FrameBuffer.hxx | 42 ++++++++++++++++---- src/emucore/OSystem.cxx | 3 +- src/emucore/Settings.cxx | 14 +++++-- src/gui/Launcher.cxx | 3 +- 10 files changed, 190 insertions(+), 61 deletions(-) diff --git a/docs/index.html b/docs/index.html index c845b487f..dc6246702 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1999,6 +1999,16 @@ + + + + + + + + + + + + + + + + + + + + @@ -2522,6 +2542,16 @@ + + + + + + + + + + diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index bce5c2e7c..4d013a35d 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -48,8 +48,6 @@ FrameBufferSDL2::FrameBufferSDL2(OSystem& osystem) // since the structure may be needed before any FBSurface's have // been created myPixelFormat = SDL_AllocFormat(SDL_PIXELFORMAT_ARGB8888); - - myWindowedPos = myOSystem.settings().getPoint("windowedpos"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -183,27 +181,34 @@ void FrameBufferSDL2::queryHardware(vector& fullscreenRes, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Int32 FrameBufferSDL2::getCurrentDisplayIndex() +bool FrameBufferSDL2::isCurrentWindowPositioned() const +{ + ASSERT_MAIN_THREAD; + + return !myCenter + && myWindow && !(SDL_GetWindowFlags(myWindow) & SDL_WINDOW_FULLSCREEN_DESKTOP); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Common::Point FrameBufferSDL2::getCurrentWindowPos() const +{ + ASSERT_MAIN_THREAD; + + Common::Point pos; + + SDL_GetWindowPosition(myWindow, &pos.x, &pos.y); + + return pos; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Int32 FrameBufferSDL2::getCurrentDisplayIndex() const { ASSERT_MAIN_THREAD; return SDL_GetWindowDisplayIndex(myWindow); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBufferSDL2::updateWindowedPos() -{ - ASSERT_MAIN_THREAD; - - // only save if the window is not centered and not in full screen mode - if (!myCenter && myWindow && !(SDL_GetWindowFlags(myWindow) & SDL_WINDOW_FULLSCREEN_DESKTOP)) - { - // save current windowed position - SDL_GetWindowPosition(myWindow, &myWindowedPos.x, &myWindowedPos.y); - myOSystem.settings().setValue("windowedpos", myWindowedPos); - } -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) { @@ -213,24 +218,13 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) if(SDL_WasInit(SDL_INIT_VIDEO) == 0) return false; - Int32 displayIndex = mode.fsIndex; - if (displayIndex == -1) - { - // windowed mode - if (myWindow) - { - // Show it on same screen as the previous window - displayIndex = SDL_GetWindowDisplayIndex(myWindow); - } - if (displayIndex < 0) - { - // fallback to the last used screen if still existing - displayIndex = std::min(myNumDisplays, myOSystem.settings().getInt("display")); - } - } + // TODO: On multiple displays, switching from centered mode, does not respect + // current window's display (which many not be centered anymore) - // save and get last windowed window's position - updateWindowedPos(); + // 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) @@ -249,7 +243,7 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) posX = myWindowedPos.x; posY = myWindowedPos.y; - // make sure the window is at least partially visibile + // Make sure the window is at least partially visibile int x0 = 0, y0 = 0, x1 = 0, y1 = 0; for (int display = SDL_GetNumVideoDisplays() - 1; display >= 0; display--) @@ -276,13 +270,15 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) // toggling fullscreen windowed mode // So we have a special case for macOS #ifndef BSPF_MACOS - // Don't re-create the window if its size hasn't changed, as it's not - // necessary, and causes flashing in fullscreen mode + // 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); int w, h; + SDL_GetWindowSize(myWindow, &w, &h); - if(uInt32(w) != mode.screen.w || uInt32(h) != mode.screen.h) + if(d != displayIndex || uInt32(w) != mode.screen.w || uInt32(h) != mode.screen.h) { SDL_DestroyWindow(myWindow); myWindow = nullptr; diff --git a/src/common/FrameBufferSDL2.hxx b/src/common/FrameBufferSDL2.hxx index 857891685..d2825037c 100644 --- a/src/common/FrameBufferSDL2.hxx +++ b/src/common/FrameBufferSDL2.hxx @@ -95,6 +95,21 @@ class FrameBufferSDL2 : public FrameBuffer */ void readPixels(uInt8* buffer, uInt32 pitch, const Common::Rect& rect) const override; + /** + This method is called to query if the current window is not centered + or fullscreen. + + @return True, if the current window is positioned + */ + bool isCurrentWindowPositioned() const override; + + /** + This method is called to query the video hardware for position of + the current window + + @return The position of the currently displayed window + */ + Common::Point getCurrentWindowPos() const override; /** This method is called to query the video hardware for the index of the display the current window is displayed on @@ -102,12 +117,7 @@ class FrameBufferSDL2 : public FrameBuffer @return the current display index or a negative value if no window is displayed */ - Int32 getCurrentDisplayIndex() override; - - /** - This method is called to preserve the last current windowed position. - */ - void updateWindowedPos() override; + Int32 getCurrentDisplayIndex() const override; /** Clear the frame buffer. diff --git a/src/debugger/Debugger.cxx b/src/debugger/Debugger.cxx index a96f208ec..6f5078228 100644 --- a/src/debugger/Debugger.cxx +++ b/src/debugger/Debugger.cxx @@ -115,7 +115,8 @@ void Debugger::initialize() FBInitStatus Debugger::initializeVideo() { string title = string("Stella ") + STELLA_VERSION + ": Debugger mode"; - return myOSystem.frameBuffer().createDisplay(title, myWidth, myHeight); + return myOSystem.frameBuffer().createDisplay(title, FrameBuffer::BufferType::Debugger, + myWidth, myHeight); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index fc5c1e9be..3fe69b147 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -574,7 +574,7 @@ void Console::toggleTurbo() initializeAudio(); // update VSync - myOSystem.createFrameBuffer(); + initializeVideo(); ostringstream ss; ss << "Turbo mode " << (!enabled ? "enabled" : "disabled"); @@ -651,7 +651,7 @@ FBInitStatus Console::initializeVideo(bool full) bool devSettings = myOSystem.settings().getBool("dev.settings"); const string& title = string("Stella ") + STELLA_VERSION + ": \"" + myProperties.get(PropType::Cart_Name) + "\""; - fbstatus = myOSystem.frameBuffer().createDisplay(title, + fbstatus = myOSystem.frameBuffer().createDisplay(title, FrameBuffer::BufferType::Emulator, TIAConstants::viewableWidth, TIAConstants::viewableHeight, false); if(fbstatus != FBInitStatus::Success) return fbstatus; diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index eb35cfe5c..250a895cf 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -203,10 +203,14 @@ FontDesc FrameBuffer::getFontDesc(const string& name) const #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -FBInitStatus FrameBuffer::createDisplay(const string& title, +FBInitStatus FrameBuffer::createDisplay(const string& title, BufferType type, uInt32 width, uInt32 height, bool honourHiDPI) { + // always save, maybe only the mode of the window has changed + saveCurrentWindowPosition(); + myBufferType = type; + ++myInitializedCount; myScreenTitle = title; @@ -789,6 +793,58 @@ void FrameBuffer::stateChanged(EventHandlerState state) update(true); // force full update } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string FrameBuffer::getDisplayKey() +{ + // save current window's display and position + switch(myBufferType) + { + case BufferType::Launcher: + return "launcherdisplay"; + + case BufferType::Emulator: + return "display"; + + #ifdef DEBUGGER_SUPPORT + case BufferType::Debugger: + return "dbg.display"; + #endif + + default: + return ""; + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string FrameBuffer::getPositionKey() +{ + // save current window's display and position + switch(myBufferType) + { + case BufferType::Launcher: + return "launcherpos"; + + case BufferType::Emulator: + return "windowedpos"; + + #ifdef DEBUGGER_SUPPORT + case BufferType::Debugger: + return "dbg.pos"; + #endif + + default: + return ""; + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FrameBuffer::saveCurrentWindowPosition() +{ + myOSystem.settings().setValue(getDisplayKey(), getCurrentDisplayIndex()); + if(isCurrentWindowPositioned()) + myOSystem.settings().setValue(getPositionKey(), getCurrentWindowPos()); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::setFullscreen(bool enable) { diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index 35c656cf0..a73b01ffb 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -81,6 +81,13 @@ class FrameBuffer } }; + enum class BufferType { + None, + Launcher, + Emulator, + Debugger + }; + enum class ScalingInterpolation { none, sharp, @@ -115,7 +122,8 @@ class FrameBuffer @return Status of initialization (see FBInitStatus 'enum') */ - FBInitStatus createDisplay(const string& title, uInt32 width, uInt32 height, + FBInitStatus createDisplay(const string& title, BufferType type, + uInt32 width, uInt32 height, bool honourHiDPI = true); /** @@ -299,6 +307,13 @@ class FrameBuffer bool hidpiEnabled() const { return myHiDPIEnabled; } uInt32 hidpiScaleFactor() const { return myHiDPIEnabled ? 2 : 1; } + /** + These methods are used to load/save position and display of the current window. + */ + string getPositionKey(); + string getDisplayKey(); + void saveCurrentWindowPosition(); + #ifdef GUI_SUPPORT /** Get the font object(s) of the framebuffer @@ -371,6 +386,21 @@ class FrameBuffer */ virtual void readPixels(uInt8* buffer, uInt32 pitch, const Common::Rect& rect) const = 0; + /** + This method is called to query if the current window is not centered or fullscreen. + + @return True, if the current window is positioned + */ + virtual bool isCurrentWindowPositioned() const = 0; + + /** + This method is called to query the video hardware for position of + the current window + + @return The position of the currently displayed window + */ + virtual Common::Point getCurrentWindowPos() const = 0; + /** This method is called to query the video hardware for the index of the display the current window is displayed on @@ -378,12 +408,7 @@ class FrameBuffer @return the current display index or a negative value if no window is displayed */ - virtual Int32 getCurrentDisplayIndex() = 0; - - /** - This method is called to preserve the last current windowed position. - */ - virtual void updateWindowedPos() = 0; + virtual Int32 getCurrentDisplayIndex() const = 0; /** Clear the framebuffer. @@ -554,6 +579,9 @@ class FrameBuffer // Title of the main window/screen string myScreenTitle; + // Type of the frame buffer + BufferType myBufferType{BufferType::None}; + // Number of displays int myNumDisplays{1}; diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index bbaa72aa5..ccf6838cb 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -239,8 +239,7 @@ void OSystem::saveConfig() if(myFrameBuffer) { // Save the last windowed position and display on system shutdown - myFrameBuffer->updateWindowedPos(); - settings().setValue("display", myFrameBuffer->getCurrentDisplayIndex()); + myFrameBuffer->saveCurrentWindowPosition(); Logger::debug("Saving TV effects options ..."); myFrameBuffer->tiaSurface().ntsc().saveConfig(settings()); diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index 599c8badf..b0e5cd7a6 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -126,6 +126,8 @@ Settings::Settings() // ROM browser options setPermanent("exitlauncher", "false"); setPermanent("followlauncher", "false"); + setPermanent("launcherpos", Common::Point(50, 50)); + setPermanent("launcherdisplay", 0); setPermanent("launcherres", Common::Size(900, 600)); setPermanent("launcherfont", "medium"); setPermanent("launcherroms", "true"); @@ -137,6 +139,8 @@ Settings::Settings() setPermanent("dbg.res", Common::Size(DebuggerDialog::kMediumFontMinW, DebuggerDialog::kMediumFontMinH)); + setPermanent("dbg.pos", Common::Point(50, 50)); + setPermanent("dbg.display", 0); #endif setPermanent("uipalette", "standard"); setPermanent("hidpi", "false"); @@ -396,8 +400,8 @@ void Settings::usage() const << " -vsync <1|0> Enable 'synchronize to vertical blank interrupt'\n" << " -fullscreen <1|0> Enable fullscreen mode\n" << " -center <1|0> Centers game window in windowed modes\n" - << " -windowedpos Sets the window position in windowed modes\n" - << " -display Sets the display for Stella\n" + << " -windowedpos Sets the window position in windowed emulator mode\n" + << " -display Sets the display for Stella's emulator\n" << " -palette \n" @@ -493,8 +497,10 @@ void Settings::usage() const << " -rominfo Display detailed information for the given ROM\n" << " -listrominfo Display contents of stella.pro, one line per ROM\n" << " entry\n" - << endl + << endl << " -exitlauncher <1|0> On exiting a ROM, go back to the ROM launcher\n" + << " -launcherpos Sets the window position in windowed EOM launcher mode\n" + << " -launcherdisplay Sets the display for the ROM launcher\n" << " -launcherres The resolution to use in ROM launcher mode\n" << " -launcherfont Relocate calls out of address range in\n" << " disassembler\n" << endl + << " -dbg.pos Sets the window position in windowed debugger mode\n" + << " -dbg.display Sets the display for the debugger\n" << " -dbg.res The resolution to use in debugger mode\n" << " -dbg.fontsize \n" diff --git a/src/gui/Launcher.cxx b/src/gui/Launcher.cxx index 379d9841e..315a14f41 100644 --- a/src/gui/Launcher.cxx +++ b/src/gui/Launcher.cxx @@ -59,7 +59,8 @@ Launcher::~Launcher() FBInitStatus Launcher::initializeVideo() { string title = string("Stella ") + STELLA_VERSION; - return myOSystem.frameBuffer().createDisplay(title, myWidth, myHeight); + return myOSystem.frameBuffer().createDisplay(title, FrameBuffer::BufferType::Launcher, + myWidth, myHeight); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 6f144b5310ca983b7ec454e2468d75808362835e Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 2 May 2020 16:47:54 +0200 Subject: [PATCH 172/377] Changelog update for "Make windows positioning independent for launcher, emulator and debugger" --- Changes.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Changes.txt b/Changes.txt index c3c0304e1..19905a413 100644 --- a/Changes.txt +++ b/Changes.txt @@ -26,6 +26,8 @@ * Added selectable dialog fonts + * Added separate positioning of launcher, emulator and debugger + * Added option which lets default ROM path follow launcher navigation * Added displaying last write address in the debugger. From cd2e9f63f2b5bc61544b8dc16c5fe9df98d6e99f Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sat, 2 May 2020 14:39:23 -0230 Subject: [PATCH 173/377] libretro: Fix #625. --- src/libretro/FrameBufferLIBRETRO.hxx | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/libretro/FrameBufferLIBRETRO.hxx b/src/libretro/FrameBufferLIBRETRO.hxx index 6b2035397..4ac6dbb30 100644 --- a/src/libretro/FrameBufferLIBRETRO.hxx +++ b/src/libretro/FrameBufferLIBRETRO.hxx @@ -115,6 +115,21 @@ class FrameBufferLIBRETRO : public FrameBuffer vector& windowedRes, VariantList& renderers) override; + /** + This method is called to query if the current window is not centered or fullscreen. + + @return True, if the current window is positioned + */ + bool isCurrentWindowPositioned() const override { return true; } + + /** + This method is called to query the video hardware for position of + the current window + + @return The position of the currently displayed window + */ + Common::Point getCurrentWindowPos() const override { return Common::Point{}; } + /** This method is called to query the video hardware for the index of the display the current window is displayed on @@ -122,12 +137,7 @@ class FrameBufferLIBRETRO : public FrameBuffer @return the current display index or a negative value if no window is displayed */ - Int32 getCurrentDisplayIndex() override { return 0; } - - /** - This method is called to preserve the last current windowed position. - */ - void updateWindowedPos() override { } + Int32 getCurrentDisplayIndex() const override { return 0; } /** This method is called to change to the given video mode. From 328c6821dccc73d5c10fd5ea285f841cba004388 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sat, 2 May 2020 16:07:12 -0230 Subject: [PATCH 174/377] Fix warnings from clang. --- src/cheat/CheatCodeDialog.cxx | 1 - src/debugger/gui/DebuggerDialog.hxx | 2 +- src/gui/AboutDialog.cxx | 1 - src/gui/ComboDialog.cxx | 1 - src/gui/CommandDialog.cxx | 3 +-- src/gui/DeveloperDialog.cxx | 17 +++++------------ src/gui/Dialog.cxx | 6 ++---- src/gui/GlobalPropsDialog.cxx | 1 - src/gui/HelpDialog.cxx | 3 +-- src/gui/JoystickDialog.cxx | 2 -- src/gui/LoggerDialog.cxx | 1 - src/gui/OptionsDialog.cxx | 2 +- src/gui/RomAuditDialog.cxx | 2 -- src/gui/RomInfoWidget.cxx | 2 +- 14 files changed, 12 insertions(+), 32 deletions(-) diff --git a/src/cheat/CheatCodeDialog.cxx b/src/cheat/CheatCodeDialog.cxx index 5ce380e0b..09ac1cd3c 100644 --- a/src/cheat/CheatCodeDialog.cxx +++ b/src/cheat/CheatCodeDialog.cxx @@ -42,7 +42,6 @@ CheatCodeDialog::CheatCodeDialog(OSystem& osystem, DialogContainer& parent, buttonHeight = font.getLineHeight() * 1.25; const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; - const int INDENT = fontWidth * 2; const int VGAP = fontHeight / 4; int xpos, ypos; diff --git a/src/debugger/gui/DebuggerDialog.hxx b/src/debugger/gui/DebuggerDialog.hxx index 2fa007214..b66ae37a6 100644 --- a/src/debugger/gui/DebuggerDialog.hxx +++ b/src/debugger/gui/DebuggerDialog.hxx @@ -71,7 +71,7 @@ class DebuggerDialog : public Dialog ButtonWidget& unwindButton() const { return *myUnwindButton; } void showFatalMessage(const string& msg); - void saveConfig(); + void saveConfig() override; private: void center() override { positionAt(0); } diff --git a/src/gui/AboutDialog.cxx b/src/gui/AboutDialog.cxx index 05db4b695..8393e2009 100644 --- a/src/gui/AboutDialog.cxx +++ b/src/gui/AboutDialog.cxx @@ -34,7 +34,6 @@ AboutDialog::AboutDialog(OSystem& osystem, DialogContainer& parent, buttonHeight = font.getLineHeight() * 1.25; const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; - const int INDENT = fontWidth * 2; const int VGAP = fontHeight / 4; int xpos, ypos; diff --git a/src/gui/ComboDialog.cxx b/src/gui/ComboDialog.cxx index 524a1a3e2..e8b087c53 100644 --- a/src/gui/ComboDialog.cxx +++ b/src/gui/ComboDialog.cxx @@ -37,7 +37,6 @@ ComboDialog::ComboDialog(GuiObject* boss, const GUI::Font& font, buttonHeight = font.getLineHeight() * 1.25; const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; - const int INDENT = fontWidth * 2; const int VGAP = fontHeight / 4; int xpos, ypos; diff --git a/src/gui/CommandDialog.cxx b/src/gui/CommandDialog.cxx index 86fc6f8c9..934b9e645 100644 --- a/src/gui/CommandDialog.cxx +++ b/src/gui/CommandDialog.cxx @@ -33,8 +33,7 @@ CommandDialog::CommandDialog(OSystem& osystem, DialogContainer& parent) : Dialog(osystem, parent, osystem.frameBuffer().font(), "Commands") { - const int lineHeight = _font.getLineHeight(), - fontHeight = _font.getFontHeight(), + const int fontHeight = _font.getFontHeight(), fontWidth = _font.getMaxCharWidth(), buttonHeight = _font.getLineHeight() * 1.25, buttonWidth = _font.getStringWidth("Time Machine On") + fontWidth * 2; diff --git a/src/gui/DeveloperDialog.cxx b/src/gui/DeveloperDialog.cxx index 0bcbe32e6..2dd607a4b 100644 --- a/src/gui/DeveloperDialog.cxx +++ b/src/gui/DeveloperDialog.cxx @@ -54,7 +54,6 @@ DeveloperDialog::DeveloperDialog(OSystem& osystem, DialogContainer& parent, buttonHeight = font.getLineHeight() * 1.25; const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; - const int INDENT = fontWidth * 2; const int VGAP = fontHeight / 4; int xpos, ypos; @@ -90,8 +89,7 @@ void DeveloperDialog::addEmulationTab(const GUI::Font& font) { const int lineHeight = font.getLineHeight(), fontHeight = font.getFontHeight(), - fontWidth = font.getMaxCharWidth(), - buttonHeight = font.getLineHeight() * 1.25; + fontWidth = font.getMaxCharWidth(); const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; const int INDENT = fontWidth * 2; @@ -197,8 +195,7 @@ void DeveloperDialog::addTiaTab(const GUI::Font& font) { const int lineHeight = font.getLineHeight(), fontHeight = font.getFontHeight(), - fontWidth = font.getMaxCharWidth(), - buttonHeight = font.getLineHeight() * 1.25; + fontWidth = font.getMaxCharWidth(); const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; const int INDENT = fontWidth * 2; @@ -287,8 +284,7 @@ void DeveloperDialog::addVideoTab(const GUI::Font& font) { const int lineHeight = font.getLineHeight(), fontHeight = font.getFontHeight(), - fontWidth = font.getMaxCharWidth(), - buttonHeight = font.getLineHeight() * 1.25; + fontWidth = font.getMaxCharWidth(); const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; const int INDENT = fontWidth * 2; @@ -428,8 +424,7 @@ void DeveloperDialog::addTimeMachineTab(const GUI::Font& font) }; const int lineHeight = font.getLineHeight(), fontHeight = font.getFontHeight(), - fontWidth = font.getMaxCharWidth(), - buttonHeight = font.getLineHeight() * 1.25; + fontWidth = font.getMaxCharWidth(); const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; const int INDENT = fontWidth * 2; @@ -548,11 +543,9 @@ void DeveloperDialog::addDebuggerTab(const GUI::Font& font) #ifdef DEBUGGER_SUPPORT const int lineHeight = font.getLineHeight(), fontHeight = font.getFontHeight(), - fontWidth = font.getMaxCharWidth(), - buttonHeight = font.getLineHeight() * 1.25; + fontWidth = font.getMaxCharWidth(); const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; - const int INDENT = fontWidth * 2; const int VGAP = fontHeight / 4; VariantList items; diff --git a/src/gui/Dialog.cxx b/src/gui/Dialog.cxx index 0195fa8f9..1cc0b3b8c 100644 --- a/src/gui/Dialog.cxx +++ b/src/gui/Dialog.cxx @@ -772,8 +772,7 @@ void Dialog::addOKCancelBGroup(WidgetArray& wid, const GUI::Font& font, const string& okText, const string& cancelText, bool focusOKButton, int buttonWidth) { - const int lineHeight = font.getLineHeight(), - fontWidth = font.getMaxCharWidth(), + const int fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(), buttonHeight = font.getLineHeight() * 1.25; const int VBORDER = fontHeight / 2; @@ -821,8 +820,7 @@ void Dialog::addDefaultsOKCancelBGroup(WidgetArray& wid, const GUI::Font& font, const string& defaultsText, bool focusOKButton) { - const int lineHeight = font.getLineHeight(), - fontWidth = font.getMaxCharWidth(), + const int fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(), buttonHeight = font.getLineHeight() * 1.25; const int VBORDER = fontHeight / 2; diff --git a/src/gui/GlobalPropsDialog.cxx b/src/gui/GlobalPropsDialog.cxx index d8226a2d5..232968f1c 100644 --- a/src/gui/GlobalPropsDialog.cxx +++ b/src/gui/GlobalPropsDialog.cxx @@ -39,7 +39,6 @@ GlobalPropsDialog::GlobalPropsDialog(GuiObject* boss, const GUI::Font& font) buttonHeight = lineHeight * 1.25; const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; - const int INDENT = fontWidth * 2; const int VGAP = fontHeight / 4; int xpos, ypos; diff --git a/src/gui/HelpDialog.cxx b/src/gui/HelpDialog.cxx index 9a0bd2bdd..5c9a6b1d3 100644 --- a/src/gui/HelpDialog.cxx +++ b/src/gui/HelpDialog.cxx @@ -35,7 +35,6 @@ HelpDialog::HelpDialog(OSystem& osystem, DialogContainer& parent, buttonHeight = font.getLineHeight() * 1.25; const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; - const int INDENT = fontWidth * 2; const int VGAP = fontHeight / 4; int xpos, ypos; @@ -73,7 +72,7 @@ HelpDialog::HelpDialog(OSystem& osystem, DialogContainer& parent, int lwidth = 15 * fontWidth; ypos += lineHeight + VGAP * 2; - for(int i = 0; i < LINES_PER_PAGE; ++i) + for(uInt32 i = 0; i < LINES_PER_PAGE; ++i) { myKey[i] = new StaticTextWidget(this, font, xpos, ypos, lwidth, diff --git a/src/gui/JoystickDialog.cxx b/src/gui/JoystickDialog.cxx index 266822eda..218179e72 100644 --- a/src/gui/JoystickDialog.cxx +++ b/src/gui/JoystickDialog.cxx @@ -39,8 +39,6 @@ JoystickDialog::JoystickDialog(GuiObject* boss, const GUI::Font& font, buttonHeight = font.getLineHeight() * 1.25; const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; - const int INDENT = fontWidth * 2; - const int VGAP = fontHeight / 4; // Joystick list xpos = HBORDER; ypos = VBORDER + _th; diff --git a/src/gui/LoggerDialog.cxx b/src/gui/LoggerDialog.cxx index 57a0161fc..f9b05911b 100644 --- a/src/gui/LoggerDialog.cxx +++ b/src/gui/LoggerDialog.cxx @@ -43,7 +43,6 @@ LoggerDialog::LoggerDialog(OSystem& osystem, DialogContainer& parent, buttonHeight = font.getLineHeight() * 1.25; const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; - const int INDENT = fontWidth * 2; const int VGAP = fontHeight / 4; int xpos, ypos; diff --git a/src/gui/OptionsDialog.cxx b/src/gui/OptionsDialog.cxx index 9b8087b34..84ea9f605 100644 --- a/src/gui/OptionsDialog.cxx +++ b/src/gui/OptionsDialog.cxx @@ -54,7 +54,7 @@ OptionsDialog::OptionsDialog(OSystem& osystem, DialogContainer& parent, { // do not show basic settings options in debugger bool minSettings = osystem.settings().getBool("minimal_ui") && mode != Menu::AppMode::debugger; - const int lineHeight = _font.getLineHeight(), + const int fontWidth = _font.getMaxCharWidth(), fontHeight = _font.getFontHeight(), buttonHeight = _font.getLineHeight() * 1.25, diff --git a/src/gui/RomAuditDialog.cxx b/src/gui/RomAuditDialog.cxx index 580263730..890da7e95 100644 --- a/src/gui/RomAuditDialog.cxx +++ b/src/gui/RomAuditDialog.cxx @@ -48,8 +48,6 @@ RomAuditDialog::RomAuditDialog(OSystem& osystem, DialogContainer& parent, lwidth = font.getStringWidth("ROMs without properties (skipped) "); const int VBORDER = _th + fontHeight / 2; const int HBORDER = fontWidth * 1.25; - const int INDENT = fontWidth * 2; - const int VGAP = fontHeight / 4; int xpos, ypos = VBORDER; WidgetArray wid; diff --git a/src/gui/RomInfoWidget.cxx b/src/gui/RomInfoWidget.cxx index c935f54dc..8b1852528 100644 --- a/src/gui/RomInfoWidget.cxx +++ b/src/gui/RomInfoWidget.cxx @@ -205,7 +205,7 @@ void RomInfoWidget::drawWidget(bool hilite) int xpos = _x + 8, ypos = _y + yoff + 5; for(const auto& info : myRomInfo) { - if(info.length() * _font.getMaxCharWidth() <= _w - 16) + if(info.length() * _font.getMaxCharWidth() <= uInt64(_w - 16)) { // 1 line for next entry From 1b2ba3ff9a69615b14bd5add03d5959c7c8e6f2c Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sat, 2 May 2020 16:12:56 -0230 Subject: [PATCH 175/377] libretro: Fix Makefile for recent cart refactoring. --- src/libretro/Makefile.common | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libretro/Makefile.common b/src/libretro/Makefile.common index 34268a29d..616504e1a 100644 --- a/src/libretro/Makefile.common +++ b/src/libretro/Makefile.common @@ -37,10 +37,14 @@ SOURCES_CXX := \ $(CORE_DIR)/emucore/AtariVox.cxx \ $(CORE_DIR)/emucore/Bankswitch.cxx \ $(CORE_DIR)/emucore/Booster.cxx \ + $(CORE_DIR)/emucore/Cart.cxx \ + $(CORE_DIR)/emucore/CartDetector.cxx \ + $(CORE_DIR)/emucore/CartEnhanced.o \ $(CORE_DIR)/emucore/Cart0840.cxx \ $(CORE_DIR)/emucore/Cart2K.cxx \ $(CORE_DIR)/emucore/Cart3E.cxx \ $(CORE_DIR)/emucore/Cart3EPlus.cxx \ + $(CORE_DIR)/emucore/Cart3EX.cxx \ $(CORE_DIR)/emucore/Cart3F.cxx \ $(CORE_DIR)/emucore/Cart4A50.cxx \ $(CORE_DIR)/emucore/Cart4K.cxx \ @@ -53,10 +57,6 @@ SOURCES_CXX := \ $(CORE_DIR)/emucore/CartCM.cxx \ $(CORE_DIR)/emucore/CartCTY.cxx \ $(CORE_DIR)/emucore/CartCV.cxx \ - $(CORE_DIR)/emucore/CartCVPlus.cxx \ - $(CORE_DIR)/emucore/Cart.cxx \ - $(CORE_DIR)/emucore/CartDASH.cxx \ - $(CORE_DIR)/emucore/CartDetector.cxx \ $(CORE_DIR)/emucore/CartDF.cxx \ $(CORE_DIR)/emucore/CartDFSC.cxx \ $(CORE_DIR)/emucore/CartDPC.cxx \ From 9d2b53a226455e1cbec74a7ee6c71ab218190c08 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sat, 2 May 2020 18:15:27 -0230 Subject: [PATCH 176/377] Fix crash in cart autodetect; if we can't find a match, use 4K. --- src/emucore/CartDetector.cxx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/emucore/CartDetector.cxx b/src/emucore/CartDetector.cxx index 8544a72f0..7eb8bb0e5 100644 --- a/src/emucore/CartDetector.cxx +++ b/src/emucore/CartDetector.cxx @@ -531,8 +531,6 @@ Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t si type = Bankswitch::Type::_3E; else if(isProbably3F(image, size)) type = Bankswitch::Type::_3F; - else - type = Bankswitch::Type::_4K; // Most common bankswitching type } // Variable sized ROM formats are independent of image size and come last @@ -541,8 +539,11 @@ Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t si else if(isProbablyMDM(image, size)) type = Bankswitch::Type::_MDM; - ostringstream ss; + // If we get here and autodetection failed, then we force '4K' + if(type == Bankswitch::Type::_AUTO) + type = Bankswitch::Type::_4K; // Most common bankswitching type + ostringstream ss; ss << "Bankswitching type '" << Bankswitch::typeToDesc(type) << "' detected"; Logger::debug(ss.str()); From 92d30c2a9c2e0d72909463f012e3191614473de2 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 3 May 2020 08:45:15 +0200 Subject: [PATCH 177/377] fixed 3E bankswitching --- src/emucore/Cart3E.cxx | 15 +++++++++++++++ src/emucore/Cart3E.hxx | 9 +++++++++ src/emucore/CartEnhanced.cxx | 2 +- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/emucore/Cart3E.cxx b/src/emucore/Cart3E.cxx index 642ac6ce1..be69d105d 100644 --- a/src/emucore/Cart3E.cxx +++ b/src/emucore/Cart3E.cxx @@ -71,3 +71,18 @@ uInt8 Cartridge3E::peek(uInt16 address) return CartridgeEnhanced::peek(peekAddress); } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool Cartridge3E::poke(uInt16 address, uInt8 value) +{ + uInt16 pokeAddress = address; + address &= ROM_MASK; + + if(address < 0x0040) // TIA access + { + checkSwitchBank(address, value); + return mySystem->tia().poke(address, value); + } + + return CartridgeEnhanced::poke(pokeAddress, value); +} diff --git a/src/emucore/Cart3E.hxx b/src/emucore/Cart3E.hxx index 613fa610c..f2ead51f5 100644 --- a/src/emucore/Cart3E.hxx +++ b/src/emucore/Cart3E.hxx @@ -113,6 +113,15 @@ class Cartridge3E : public CartridgeEnhanced */ uInt8 peek(uInt16 address) override; + /** + Change the byte at the specified address to the given value + + @param address The address where the value should be stored + @param value The value to be stored at the address + @return True if the poke changed the device address space, else false + */ + bool poke(uInt16 address, uInt8 value) override; + private: bool checkSwitchBank(uInt16 address, uInt8 value) override; diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index d5ccf6591..f5c38c9a3 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -232,7 +232,7 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) uInt32 bankOffset = uInt32(mySize) + (ramBank << (myBankShift - 1)); // Remember what bank is in this segment - myCurrentSegOffset[segment] = bank << myBankShift; + myCurrentSegOffset[segment] = uInt32(mySize) + (ramBank << myBankShift); // Set the page accessing method for the RAM writing pages uInt16 fromAddr = (ROM_OFFSET + segmentOffset + myWriteOffset) & ~System::PAGE_MASK; From cb37e905e56d3ca9469a8e06837f824d154ae097 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 4 May 2020 09:34:33 +0200 Subject: [PATCH 178/377] add properties for test ROM "spin4a50" --- src/emucore/DefProps.hxx | 3 ++- src/emucore/stella.pro | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/emucore/DefProps.hxx b/src/emucore/DefProps.hxx index 36db315de..fc0fe6155 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 = 3513; +static constexpr uInt32 DEF_PROPS_SIZE = 3514; static const BSPF::array2D DefProps = {{ { "000509d1ed2b8d30a9d94be1b3b5febb", "Greg Zumwalt", "", "Jungle Jane (2003) (Greg Zumwalt) (Hack)", "Hack of Pitfall!", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -341,6 +341,7 @@ static const BSPF::array2D DefProps = {{ { "15fe28d0c8893be9223e8cb2d032e557", "", "", "Towering Inferno (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "1619bc27632f9148d8480cd813aa74c3", "Thomas Jentzsch", "", "Steeple Chase (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "A", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "161ded4a85d3c78e44fffd40426f537f", "Thomas Jentzsch", "", "JtzBall (Alpha) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "16229d61d7b0c89b01853660a8da22bb", "", "", "spin4a50", "", "", "", "", "4A50", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "163e7e757e2dc44469123ff0e5daec5e", "", "", "Many Blue Bars and Text Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "169d4c7bd3a4d09e184a3b993823d048", "", "", "Superman (Unknown) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "16cb43492987d2f32b423817cdaaf7c4", "Atari, Larry Kaplan - Sears", "CX2602 - 99802, 6-99802, 49-75102", "Air-Sea Battle (1977) (Atari)", "AKA Target Fun (Anti-Aircraft)", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, diff --git a/src/emucore/stella.pro b/src/emucore/stella.pro index 4c589fe72..8b783bba4 100644 --- a/src/emucore/stella.pro +++ b/src/emucore/stella.pro @@ -1900,6 +1900,11 @@ "Cart.Name" "JtzBall (Alpha) (TJ)" "" +"Cart.MD5" "16229d61d7b0c89b01853660a8da22bb" +"Cart.Name" "spin4a50" +"Cart.Type" "4A50" +"" + "Cart.MD5" "163e7e757e2dc44469123ff0e5daec5e" "Cart.Name" "Many Blue Bars and Text Demo 2 (PD)" "" From 2318af1685fdd0646ab1e927a9dab0ac369fb30d Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 4 May 2020 09:46:04 +0200 Subject: [PATCH 179/377] small optimizations of detection code --- src/emucore/CartDetector.cxx | 91 ++++++++++++++++++------------------ src/emucore/CartDetector.hxx | 9 +++- 2 files changed, 53 insertions(+), 47 deletions(-) diff --git a/src/emucore/CartDetector.cxx b/src/emucore/CartDetector.cxx index 7eb8bb0e5..6c68bf6e4 100644 --- a/src/emucore/CartDetector.cxx +++ b/src/emucore/CartDetector.cxx @@ -374,8 +374,8 @@ Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t si { 0x8D, 0xF9, 0x1F }, // STA $1FF9 { 0x8D, 0xF9, 0xFF } // STA $FFF9 }; - bool f8 = searchForBytes(image.get(), size, signature[0], 3, 2) || - searchForBytes(image.get(), size, signature[1], 3, 2); + bool f8 = searchForBytes(image, size, signature[0], 3, 2) || + searchForBytes(image, size, signature[1], 3, 2); if(isProbablySC(image, size)) type = Bankswitch::Type::_F8SC; @@ -507,7 +507,7 @@ Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t si type = Bankswitch::Type::_3F; else if(isProbably4A50(image, size)) type = Bankswitch::Type::_4A50; - else if(isProbablySB(image, size)) + else /*if(isProbablySB(image, size))*/ type = Bankswitch::Type::_SB; } else if(size == 256_KB) @@ -556,26 +556,25 @@ bool CartDetector::searchForBytes(const uInt8* image, size_t imagesize, uInt32 minhits) { uInt32 count = 0; + for(uInt32 i = 0; i < imagesize - sigsize; ++i) { - uInt32 matches = 0; - for(uInt32 j = 0; j < sigsize; ++j) + uInt32 j; + + for(j = 0; j < sigsize; ++j) { - if(image[i+j] == signature[j]) - ++matches; - else + if(image[i + j] != signature[j]) break; } - if(matches == sigsize) + if(j == sigsize) { - ++count; + if(++count == minhits) + break; i += sigsize; // skip past this signature 'window' entirely } - if(count >= minhits) - break; } - return (count >= minhits); + return (count == minhits); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -604,10 +603,10 @@ bool CartDetector::isProbablyARM(const ByteBuffer& image, size_t size) { 0xA0, 0xC1, 0x1F, 0xE0 }, { 0x00, 0x80, 0x02, 0xE0 } }; - if(searchForBytes(image.get(), std::min(size, 1_KB), signature[0], 4, 1)) + if(searchForBytes(image, std::min(size, 1_KB), signature[0], 4)) return true; else - return searchForBytes(image.get(), std::min(size, 1_KB), signature[1], 4, 1); + return searchForBytes(image, std::min(size, 1_KB), signature[1], 4); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -621,7 +620,7 @@ bool CartDetector::isProbably0840(const ByteBuffer& image, size_t size) { 0x2C, 0x00, 0x08 } // BIT $0800 }; for(uInt32 i = 0; i < 3; ++i) - if(searchForBytes(image.get(), size, signature1[i], 3, 2)) + if(searchForBytes(image, size, signature1[i], 3, 2)) return true; uInt8 signature2[2][4] = { @@ -629,7 +628,7 @@ bool CartDetector::isProbably0840(const ByteBuffer& image, size_t size) { 0x0C, 0xFF, 0x0F, 0x4C } // NOP $0FFF; JMP ... }; for(uInt32 i = 0; i < 2; ++i) - if(searchForBytes(image.get(), size, signature2[i], 4, 2)) + if(searchForBytes(image, size, signature2[i], 4, 2)) return true; return false; @@ -646,8 +645,8 @@ bool CartDetector::isProbably3E(const ByteBuffer& image, size_t size) uInt8 signature1[] = { 0x85, 0x3E }; // STA $3E uInt8 signature2[] = { 0x85, 0x3F }; // STA $3F - return searchForBytes(image.get(), size, signature1, 2, 1) - && searchForBytes(image.get(), size, signature2, 2, 2); + return searchForBytes(image, size, signature1, 2) + && searchForBytes(image, size, signature2, 2, 2); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -655,7 +654,7 @@ bool CartDetector::isProbably3EX(const ByteBuffer& image, size_t size) { // 3EX cart have at least 2 occurrences of the string "3EX" uInt8 _3EX[] = { '3', 'E', 'X'}; - return searchForBytes(image.get(), size, _3EX, 3, 2); + return searchForBytes(image, size, _3EX, 3, 2); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -663,7 +662,7 @@ bool CartDetector::isProbably3EPlus(const ByteBuffer& image, size_t size) { // 3E+ cart is identified key 'TJ3E' in the ROM uInt8 tj3e[] = { 'T', 'J', '3', 'E' }; - return searchForBytes(image.get(), size, tj3e, 4, 1); + return searchForBytes(image, size, tj3e, 4); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -674,7 +673,7 @@ bool CartDetector::isProbably3F(const ByteBuffer& image, size_t size) // We expect it will be present at least 2 times, since there are // at least two banks uInt8 signature[] = { 0x85, 0x3F }; // STA $3F - return searchForBytes(image.get(), size, signature, 2, 2); + return searchForBytes(image, size, signature, 2, 2); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -720,12 +719,12 @@ bool CartDetector::isProbablyBF(const ByteBuffer& image, size_t size, // This signature is attributed to "RevEng" of AtariAge uInt8 bf[] = { 'B', 'F', 'B', 'F' }; uInt8 bfsc[] = { 'B', 'F', 'S', 'C' }; - if(searchForBytes(image.get()+size-8, 8, bf, 4, 1)) + if(searchForBytes(image.get()+size-8, 8, bf, 4)) { type = Bankswitch::Type::_BF; return true; } - else if(searchForBytes(image.get()+size-8, 8, bfsc, 4, 1)) + else if(searchForBytes(image.get()+size-8, 8, bfsc, 4)) { type = Bankswitch::Type::_BFSC; return true; @@ -741,7 +740,7 @@ bool CartDetector::isProbablyBUS(const ByteBuffer& image, size_t size) // Note: all Harmony/Melody custom drivers also contain the value // 0x10adab1e (LOADABLE) if needed for future improvement uInt8 bus[] = { 'B', 'U', 'S'}; - return searchForBytes(image.get(), size, bus, 3, 2); + return searchForBytes(image, size, bus, 3, 2); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -751,14 +750,14 @@ bool CartDetector::isProbablyCDF(const ByteBuffer& image, size_t size) // Note: all Harmony/Melody custom drivers also contain the value // 0x10adab1e (LOADABLE) if needed for future improvement uInt8 cdf[] = { 'C', 'D', 'F' }; - return searchForBytes(image.get(), size, cdf, 3, 3); + return searchForBytes(image, size, cdf, 3, 3); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbablyCTY(const ByteBuffer& image, size_t size) { uInt8 lenin[] = { 'L', 'E', 'N', 'I', 'N' }; - return searchForBytes(image.get(), size, lenin, 5, 1); + return searchForBytes(image, size, lenin, 5); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -770,10 +769,10 @@ bool CartDetector::isProbablyCV(const ByteBuffer& image, size_t size) { 0x9D, 0xFF, 0xF3 }, // STA $F3FF.X { 0x99, 0x00, 0xF4 } // STA $F400.Y }; - if(searchForBytes(image.get(), size, signature[0], 3, 1)) + if(searchForBytes(image, size, signature[0], 3)) return true; else - return searchForBytes(image.get(), size, signature[1], 3, 1); + return searchForBytes(image, size, signature[1], 3); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -785,12 +784,12 @@ bool CartDetector::isProbablyDF(const ByteBuffer& image, size_t size, // This signature is attributed to "RevEng" of AtariAge uInt8 df[] = { 'D', 'F', 'D', 'F' }; uInt8 dfsc[] = { 'D', 'F', 'S', 'C' }; - if(searchForBytes(image.get()+size-8, 8, df, 4, 1)) + if(searchForBytes(image.get()+size-8, 8, df, 4)) { type = Bankswitch::Type::_DF; return true; } - else if(searchForBytes(image.get()+size-8, 8, dfsc, 4, 1)) + else if(searchForBytes(image.get()+size-8, 8, dfsc, 4)) { type = Bankswitch::Type::_DFSC; return true; @@ -806,7 +805,7 @@ bool CartDetector::isProbablyDPCplus(const ByteBuffer& image, size_t size) // Note: all Harmony/Melody custom drivers also contain the value // 0x10adab1e (LOADABLE) if needed for future improvement uInt8 dpcp[] = { 'D', 'P', 'C', '+' }; - return searchForBytes(image.get(), size, dpcp, 4, 2); + return searchForBytes(image, size, dpcp, 4, 2); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -829,7 +828,7 @@ bool CartDetector::isProbablyE0(const ByteBuffer& image, size_t size) { 0xAD, 0xF3, 0xBF } // LDA $BFF3 }; for(uInt32 i = 0; i < 8; ++i) - if(searchForBytes(image.get(), size, signature[i], 3, 1)) + if(searchForBytes(image, size, signature[i], 3)) return true; return false; @@ -854,7 +853,7 @@ bool CartDetector::isProbablyE7(const ByteBuffer& image, size_t size) { 0x8D, 0xE7, 0x1F } // STA $1FE7 }; for(uInt32 i = 0; i < 7; ++i) - if(searchForBytes(image.get(), size, signature[i], 3, 1)) + if(searchForBytes(image, size, signature[i], 3)) return true; return false; @@ -873,7 +872,7 @@ bool CartDetector::isProbablyE78K(const ByteBuffer& image, size_t size) { 0xAD, 0xE6, 0xFF }, // LDA $FFE6 }; for(uInt32 i = 0; i < 3; ++i) - if(searchForBytes(image.get(), size, signature[i], 3, 1)) + if(searchForBytes(image, size, signature[i], 3)) return true; return false; @@ -887,12 +886,12 @@ bool CartDetector::isProbablyEF(const ByteBuffer& image, size_t size, // This signature is attributed to "RevEng" of AtariAge uInt8 efef[] = { 'E', 'F', 'E', 'F' }; uInt8 efsc[] = { 'E', 'F', 'S', 'C' }; - if(searchForBytes(image.get()+size-8, 8, efef, 4, 1)) + if(searchForBytes(image.get()+size-8, 8, efef, 4)) { type = Bankswitch::Type::_EF; return true; } - else if(searchForBytes(image.get()+size-8, 8, efsc, 4, 1)) + else if(searchForBytes(image.get()+size-8, 8, efsc, 4)) { type = Bankswitch::Type::_EFSC; return true; @@ -910,7 +909,7 @@ bool CartDetector::isProbablyEF(const ByteBuffer& image, size_t size, }; for(uInt32 i = 0; i < 4; ++i) { - if(searchForBytes(image.get(), size, signature[i], 3, 1)) + if(searchForBytes(image, size, signature[i], 3)) { isEF = true; break; @@ -953,7 +952,7 @@ bool CartDetector::isProbablyFC(const ByteBuffer& image, size_t size) { 0x8c, 0xf9, 0xff, 0xad, 0xfc, 0xff } // STY $FFF9, LDA $FFFC 3-D Havoc }; for(uInt32 i = 0; i < 3; ++i) - if(searchForBytes(image.get(), size, signature[i], 6, 1)) + if(searchForBytes(image, size, signature[i], 6)) return true; return false; @@ -972,7 +971,7 @@ bool CartDetector::isProbablyFE(const ByteBuffer& image, size_t size) { 0x20, 0x00, 0xF0, 0x84, 0xD6 } // JSR $F000; $84, $D6 }; for(uInt32 i = 0; i < 4; ++i) - if(searchForBytes(image.get(), size, signature[i], 5, 1)) + if(searchForBytes(image, size, signature[i], 5)) return true; return false; @@ -983,7 +982,7 @@ bool CartDetector::isProbablyMDM(const ByteBuffer& image, size_t size) { // MDM cart is identified key 'MDMC' in the first 8K of ROM uInt8 mdmc[] = { 'M', 'D', 'M', 'C' }; - return searchForBytes(image.get(), std::min(size, 8_KB), mdmc, 4, 1); + return searchForBytes(image, std::min(size, 8_KB), mdmc, 4); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -994,10 +993,10 @@ bool CartDetector::isProbablySB(const ByteBuffer& image, size_t size) { 0xBD, 0x00, 0x08 }, // LDA $0800,x { 0xAD, 0x00, 0x08 } // LDA $0800 }; - if(searchForBytes(image.get(), size, signature[0], 3, 1)) + if(searchForBytes(image, size, signature[0], 3)) return true; else - return searchForBytes(image.get(), size, signature[1], 3, 1); + return searchForBytes(image, size, signature[1], 3); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1016,7 +1015,7 @@ bool CartDetector::isProbablyUA(const ByteBuffer& image, size_t size) { 0xAD, 0xC0, 0x02 } // LDA $2C0 (Mickey) }; for(uInt32 i = 0; i < 6; ++i) - if(searchForBytes(image.get(), size, signature[i], 3, 1)) + if(searchForBytes(image, size, signature[i], 3)) return true; return false; @@ -1029,7 +1028,7 @@ bool CartDetector::isProbablyWD(const ByteBuffer& image, size_t size) uInt8 signature[1][3] = { { 0xA5, 0x39, 0x4C } // LDA $39, JMP }; - return searchForBytes(image.get(), size, signature[0], 3, 1); + return searchForBytes(image, size, signature[0], 3); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1045,7 +1044,7 @@ bool CartDetector::isProbablyX07(const ByteBuffer& image, size_t size) { 0x0C, 0x2D, 0x08 } // NOP $082D }; for(uInt32 i = 0; i < 6; ++i) - if(searchForBytes(image.get(), size, signature[i], 3, 1)) + if(searchForBytes(image, size, signature[i], 3)) return true; return false; diff --git a/src/emucore/CartDetector.hxx b/src/emucore/CartDetector.hxx index 8dc734b42..706731b0f 100644 --- a/src/emucore/CartDetector.hxx +++ b/src/emucore/CartDetector.hxx @@ -107,7 +107,14 @@ class CartDetector */ static bool searchForBytes(const uInt8* image, size_t imagesize, const uInt8* signature, uInt32 sigsize, - uInt32 minhits); + uInt32 minhits = 1); + + static bool searchForBytes(const ByteBuffer& image, size_t imagesize, + const uInt8* signature, uInt32 sigsize, + uInt32 minhits = 1) + { + return searchForBytes(image.get(), imagesize, signature, sigsize, minhits); + } /** Returns true if the image is probably a SuperChip (128 bytes RAM) From d1e89660d17a462787591d97bf8540f0c1011515 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 4 May 2020 10:28:46 +0200 Subject: [PATCH 180/377] minor UI alignment fixes --- src/gui/EventMappingWidget.cxx | 2 +- src/gui/InputDialog.cxx | 21 +++++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/gui/EventMappingWidget.cxx b/src/gui/EventMappingWidget.cxx index bb4088173..8051e4a56 100644 --- a/src/gui/EventMappingWidget.cxx +++ b/src/gui/EventMappingWidget.cxx @@ -86,7 +86,7 @@ EventMappingWidget::EventMappingWidget(GuiObject* boss, const GUI::Font& font, addFocusWidget(myActionsList); // Add remap, erase, cancel and default buttons - xpos = _w - HBORDER - buttonWidth; + xpos = _w - HBORDER - buttonWidth + 2; myMapButton = new ButtonWidget(boss, font, xpos, ypos, buttonWidth, buttonHeight, "Map" + ELLIPSIS, kStartMapCmd); diff --git a/src/gui/InputDialog.cxx b/src/gui/InputDialog.cxx index bfa914c63..03cedb644 100644 --- a/src/gui/InputDialog.cxx +++ b/src/gui/InputDialog.cxx @@ -54,7 +54,7 @@ InputDialog::InputDialog(OSystem& osystem, DialogContainer& parent, // Set real dimensions setSize(50 * fontWidth + HBORDER * 2, - _th + VGAP * 3 + lineHeight + 13 * (lineHeight + VGAP) + VGAP * 7 + buttonHeight + VBORDER * 3, + _th + VGAP * 3 + lineHeight + 13 * (lineHeight + VGAP) + VGAP * 8 + buttonHeight + VBORDER * 3, max_w, max_h); // The tab widget @@ -68,7 +68,7 @@ InputDialog::InputDialog(OSystem& osystem, DialogContainer& parent, tabID = myTab->addTab(" Emul. Events ", TabWidget::AUTO_WIDTH); myEmulEventMapper = new EventMappingWidget(myTab, _font, 2, 2, myTab->getWidth(), - myTab->getHeight() - 4, + myTab->getHeight() - VGAP, EventMode::kEmulationMode); myTab->setParentWidget(tabID, myEmulEventMapper); addToFocusList(myEmulEventMapper->getFocusList(), myTab, tabID); @@ -77,7 +77,7 @@ InputDialog::InputDialog(OSystem& osystem, DialogContainer& parent, tabID = myTab->addTab(" UI Events ", TabWidget::AUTO_WIDTH); myMenuEventMapper = new EventMappingWidget(myTab, _font, 2, 2, myTab->getWidth(), - myTab->getHeight() - 4, + myTab->getHeight() - VGAP, EventMode::kMenuMode); myTab->setParentWidget(tabID, myMenuEventMapper); addToFocusList(myMenuEventMapper->getFocusList(), myTab, tabID); @@ -108,7 +108,8 @@ void InputDialog::addDevicePortTab() { const int lineHeight = _font.getLineHeight(), fontWidth = _font.getMaxCharWidth(), - fontHeight = _font.getFontHeight(); + fontHeight = _font.getFontHeight(), + buttonHeight = _font.getLineHeight() * 1.25; const int VGAP = fontHeight / 4; const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; @@ -213,26 +214,26 @@ void InputDialog::addDevicePortTab() // Add EEPROM erase (part 1/2) ypos += VGAP * 3; fwidth = _font.getStringWidth("AtariVox/SaveKey"); - lwidth = _font.getStringWidth("AtariVox/SaveKey"); - new StaticTextWidget(myTab, _font, _w - HBORDER - 4 - (fwidth + lwidth) / 2, ypos, + new StaticTextWidget(myTab, _font, _w - HBORDER - 2 - fwidth, ypos, "AtariVox/SaveKey"); // Show joystick database ypos += lineHeight; - myJoyDlgButton = new ButtonWidget(myTab, _font, HBORDER, ypos, 20, + lwidth = _font.getStringWidth("Joystick Database" + ELLIPSIS) + fontWidth * 2.5; + myJoyDlgButton = new ButtonWidget(myTab, _font, HBORDER, ypos, lwidth, buttonHeight, "Joystick Database" + ELLIPSIS, kDBButtonPressed); wid.push_back(myJoyDlgButton); // Add EEPROM erase (part 1/2) - myEraseEEPROMButton = new ButtonWidget(myTab, _font, _w - HBORDER - 4 - fwidth, ypos, - fwidth, lineHeight+4, + myEraseEEPROMButton = new ButtonWidget(myTab, _font, _w - HBORDER - 2 - fwidth, ypos, + fwidth, buttonHeight, "Erase EEPROM", kEEButtonPressed); wid.push_back(myEraseEEPROMButton); // Add AtariVox serial port ypos += lineHeight + VGAP * 2; lwidth = _font.getStringWidth("AVox serial port "); - fwidth = _w - HBORDER * 2 - 4 - lwidth; + fwidth = _w - HBORDER * 2 - 2 - lwidth; new StaticTextWidget(myTab, _font, HBORDER, ypos + 2, "AVox serial port "); myAVoxPort = new EditTextWidget(myTab, _font, HBORDER + lwidth, ypos, fwidth, fontHeight); From ffb265dfda12ded69e45c700553862c6b7281bad Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Mon, 4 May 2020 12:25:43 -0230 Subject: [PATCH 181/377] libretro: Fix #627. --- src/libretro/Makefile.common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libretro/Makefile.common b/src/libretro/Makefile.common index 616504e1a..1893fa57b 100644 --- a/src/libretro/Makefile.common +++ b/src/libretro/Makefile.common @@ -39,7 +39,7 @@ SOURCES_CXX := \ $(CORE_DIR)/emucore/Booster.cxx \ $(CORE_DIR)/emucore/Cart.cxx \ $(CORE_DIR)/emucore/CartDetector.cxx \ - $(CORE_DIR)/emucore/CartEnhanced.o \ + $(CORE_DIR)/emucore/CartEnhanced.cxx \ $(CORE_DIR)/emucore/Cart0840.cxx \ $(CORE_DIR)/emucore/Cart2K.cxx \ $(CORE_DIR)/emucore/Cart3E.cxx \ From a379ad4c1aed147a3dd33e2fc8c613dda8695aca Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Mon, 4 May 2020 14:19:02 -0230 Subject: [PATCH 182/377] Added '_scanend' pseudo-register to track scanlines at end of last frame. Fixes #624. --- Changes.txt | 3 +++ docs/debugger.html | 1 + src/debugger/Debugger.cxx | 5 +++-- src/debugger/Debugger.hxx | 2 +- src/yacc/YaccParser.cxx | 4 +++- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Changes.txt b/Changes.txt index 2fe5ad2b5..2fb02da2b 100644 --- a/Changes.txt +++ b/Changes.txt @@ -40,6 +40,9 @@ * Removed unused CV+ and DASH bank switching types. + * Added debugger pseudo-register '_scanend', which gives the number of + scanlines at the end of the last frame. + -Have fun! diff --git a/docs/debugger.html b/docs/debugger.html index 4f0c1cf6f..91e71bd47 100644 --- a/docs/debugger.html +++ b/docs/debugger.html @@ -755,6 +755,7 @@ that holds 'number of scanlines' on an actual console).

      + diff --git a/src/debugger/Debugger.cxx b/src/debugger/Debugger.cxx index 6f5078228..b46570a6a 100644 --- a/src/debugger/Debugger.cxx +++ b/src/debugger/Debugger.cxx @@ -875,7 +875,7 @@ std::array Debugger::ourBuiltinFunctions = { { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Names are defined here, but processed in YaccParser -std::array Debugger::ourPseudoRegisters = { { +std::array Debugger::ourPseudoRegisters = { { // Debugger::PseudoRegister Debugger::ourPseudoRegisters[NUM_PSEUDO_REGS] = { { "_bank", "Currently selected bank" }, { "_cclocks", "Color clocks on current scanline" }, @@ -883,8 +883,9 @@ std::array Debugger::ourPseudoRegisters = { { { "_cycleslo", "Lower 32 bits of number of cycles since emulation started" }, { "_fcount", "Number of frames since emulation started" }, { "_fcycles", "Number of cycles since frame started" }, - { "_icycles", "Number of cycles of last instruction" }, + { "_icycles", "Number of cycles of last instruction" }, { "_scan", "Current scanline count" }, + { "_scanend", "Scanline count at end of last frame" }, { "_scycles", "Number of cycles in current scanline" }, { "_vblank", "Whether vertical blank is enabled (1 or 0)" }, { "_vsync", "Whether vertical sync is enabled (1 or 0)" } diff --git a/src/debugger/Debugger.hxx b/src/debugger/Debugger.hxx index 2b0ce6c1c..d063f2e90 100644 --- a/src/debugger/Debugger.hxx +++ b/src/debugger/Debugger.hxx @@ -363,7 +363,7 @@ class Debugger : public DialogContainer string name, help; }; static std::array ourBuiltinFunctions; - static std::array ourPseudoRegisters; + static std::array ourPseudoRegisters; private: // rewind/unwind n states diff --git a/src/yacc/YaccParser.cxx b/src/yacc/YaccParser.cxx index 82163c433..8bc728ca0 100644 --- a/src/yacc/YaccParser.cxx +++ b/src/yacc/YaccParser.cxx @@ -234,7 +234,9 @@ TiaMethod getTiaSpecial(char* ch) { if(BSPF::equalsIgnoreCase(ch, "_scan")) return &TIADebug::scanlines; - if(BSPF::equalsIgnoreCase(ch, "_scycles")) + else if(BSPF::equalsIgnoreCase(ch, "_scanend")) + return &TIADebug::scanlinesLastFrame; + else if(BSPF::equalsIgnoreCase(ch, "_scycles")) return &TIADebug::cyclesThisLine; else if(BSPF::equalsIgnoreCase(ch, "_fcount")) return &TIADebug::frameCount; From a1c7a080e2887ed1f167b6331a9d90f2aac032cb Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 6 May 2020 21:30:43 +0200 Subject: [PATCH 183/377] initial commit --- Changes.txt | 2 + docs/index.html | 23 +++- src/common/PKeyboardHandler.cxx | 2 + src/emucore/Console.cxx | 221 +++++++++++++++++++++++++++++--- src/emucore/Console.hxx | 31 +++++ src/emucore/Event.hxx | 1 + src/emucore/EventHandler.cxx | 18 ++- src/emucore/EventHandler.hxx | 2 +- src/emucore/Settings.cxx | 10 +- src/gui/CommandDialog.cxx | 4 +- src/gui/ConsoleBFont.hxx | 39 +++++- src/gui/ConsoleMediumBFont.hxx | 43 ++++++- src/gui/DeveloperDialog.cxx | 5 +- src/gui/GuiObject.hxx | 3 +- src/gui/Stella12x24tFont.hxx | 60 ++++++++- src/gui/Stella14x28tFont.hxx | 71 +++++++++- src/gui/Stella16x32tFont.hxx | 76 ++++++++++- src/gui/StellaLargeFont.hxx | 53 +++++++- src/gui/StellaMediumFont.hxx | 50 +++++++- src/gui/VideoDialog.cxx | 93 ++++++++++++-- src/gui/VideoDialog.hxx | 6 + 21 files changed, 756 insertions(+), 57 deletions(-) diff --git a/Changes.txt b/Changes.txt index 2fe5ad2b5..e17995176 100644 --- a/Changes.txt +++ b/Changes.txt @@ -22,6 +22,8 @@ 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 'Custom' palette, generated from user controlled phase shifts. + * Added 'Turbo' mode, runs the game as fast as the computer allows. * Added selectable dialog fonts diff --git a/docs/index.html b/docs/index.html index 028062bb4..f40f67e0a 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1615,7 +1615,7 @@ - + @@ -2010,9 +2010,20 @@ - + + emulator, a user-defined palette, or a custom palette generated + from user-defined phase shifts. + + + + + + + + + + @@ -2847,6 +2858,8 @@ + + @@ -4124,6 +4137,10 @@ Ms Pac-Man (Stella extended codes): + + + +
      ItemBrief descriptionFor more information,
      see CommandLine
      ThemeTheme to use for UI elements (see examples)-uipalette
      Dialogs positionPosition of dialogs with Stella window-dialogpos
      Dialogs fontThe font used in the dialogs-dialogfont
      HiDPI modeScales the UI by a factor of two when enabled-hidpi
      Dialogs positionPosition of dialogs with Stella window-dialogpos
      Confirm exiting...Display a popup when emulation is exited-confirmexit
      List input delayMaximum delay between keypresses in filelist-widgets before a search string resets. -listdelay
      Mouse wheel scrollNumber of lines a mouse scroll will move in list-widgets-mwheel
      Centers game window (if possible).
      -windowedpos <WxH>
      Sets the window position in windowed emulator mode.
      -display <number>
      Sets the display for Stella's emulator.
      -palette <standard|z26|user>
      Set the palette to either normal Stella, the one used in the z26 @@ -2376,6 +2386,16 @@ launcher only happens when started with the launcher).
      -launcherpos <WxH>
      Sets the window position in windowed ROM launcher mode.
      -launcherdisplay <number>
      Sets the display for the ROM launcher.
      -launcherres <WxH>
      Set the size of the ROM launcher.Relocate calls out of address range in the disassembler.
      -dbg.pos <WxH>
      Sets the window position in windowed debugger mode.
      -dbg.display <number>
      Sets the display for the debugger.
      -dbg.res <WxH>
      Set the size of the debugger window.
      _fcycles Number of cycles since frame started
      _icycles Number of cycles of last instruction
      _scan Current scanline count
      _scanend Scanline count at end of last frame
      _scycles Number of cycles in current scanline
      _vblank Whether vertical blank is enabled (1 or 0)
      _vsync Whether vertical sync is enabled (1 or 0)
      Switch palette (Standard/Z26/User)Switch palette (Standard/Z26/User/Custom) Control + p Control + p
      -palette <standard|z26|user>
      -palette <standard|z26|user|custom>
      Set the palette to either normal Stella, the one used in the z26 - emulator, or a user-defined palette.
      -phase_ntsc <number>
      Set phase shift for custom NTSC palette.
      -phase_pal <number>
      Set phase shift for custom PAL palette.
      ItemBrief descriptionFor more information,
      see CommandLine
      RendererUse specified rendering mode-video
      PalettePalette for emulation mode-palette
      NTSC phasePhase shift for custom NTSC palette-phase_ntsc
      PAL phasePhase shift for custom PAL palette-phase_pal
      InterpolationInterpolation for TIA image-tia.inter
      ZoomZoom level for emulation mode -tia.zoom
      V-Size adjustAdjust height of TIA image-tia.vsizeadjust
      user An external palette file, supplied by the user.
      customA palette generate from user-defined phase shift.

      A user-defined palette has certain restrictions, further described as follows: diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index fa1139d66..f32600345 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -492,6 +492,8 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo {Event::ScanlinesIncrease, KBDK_0, MOD3}, {Event::ToggleColorLoss, KBDK_L, KBDM_CTRL}, {Event::TogglePalette, KBDK_P, KBDM_CTRL}, + {Event::ColorShiftDecrease, KBDK_9, KBDM_SHIFT | KBDM_CTRL}, + {Event::ColorShiftIncrease, KBDK_9, KBDM_CTRL}, {Event::ToggleInter, KBDK_I, KBDM_CTRL}, {Event::ToggleTurbo, KBDK_T, KBDM_CTRL}, {Event::ToggleJitter, KBDK_J, MOD3}, diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 3fe69b147..04962c9bd 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -62,6 +62,7 @@ #include "AudioSettings.hxx" #include "frame-manager/FrameManager.hxx" #include "frame-manager/FrameLayoutDetector.hxx" +#include "GuiObject.hxx" #ifdef CHEATCODE_SUPPORT #include "CheatManager.hxx" @@ -84,6 +85,10 @@ Console::Console(OSystem& osystem, unique_ptr& cart, // Load user-defined palette for this ROM loadUserPalette(); + // Generate custom palette + generateCustomPalette(0); + generateCustomPalette(1); + // Create subsystems for the console my6502 = make_unique(myOSystem.settings()); myRiot = make_unique(*this, myOSystem.settings()); @@ -473,6 +478,21 @@ void Console::enableColorLoss(bool state) myTIA->enableColorLoss(state); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int Console::getPaletteNum(const string& name) const +{ + if(name == "z26") + return PaletteType::Z26; + + if(name == "user" && myUserPaletteDefined) + return PaletteType::User; + + if(name == "custom") + return PaletteType::Custom; + + return PaletteType::Standard; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::togglePalette() { @@ -499,7 +519,12 @@ void Console::togglePalette() message = "Standard Stella palette"; } } - else if(palette == "user") // switch to standard + else if(palette == "user") // switch to custom + { + palette = "custom"; + message = "Custom palette"; + } + else if(palette == "custom") // switch to standard { palette = "standard"; message = "Standard Stella palette"; @@ -521,20 +546,20 @@ void Console::setPalette(const string& type) { // Look at all the palettes, since we don't know which one is // currently active - static constexpr BSPF::array2D palettes = {{ - { &ourNTSCPalette, &ourPALPalette, &ourSECAMPalette }, - { &ourNTSCPaletteZ26, &ourPALPaletteZ26, &ourSECAMPaletteZ26 }, - { &ourUserNTSCPalette, &ourUserPALPalette, &ourUserSECAMPalette } + static constexpr BSPF::array2D palettes = {{ + { &ourNTSCPalette, &ourPALPalette, &ourSECAMPalette }, + { &ourNTSCPaletteZ26, &ourPALPaletteZ26, &ourSECAMPaletteZ26 }, + { &ourUserNTSCPalette, &ourUserPALPalette, &ourUserSECAMPalette }, + { &ourCustomNTSCPalette, &ourCustomPALPalette, &ourSECAMPalette } }}; // See which format we should be using - int paletteNum = 0; - if(type == "standard") - paletteNum = 0; - else if(type == "z26") - paletteNum = 1; - else if(type == "user" && myUserPaletteDefined) - paletteNum = 2; + int paletteNum = getPaletteNum(type); + + if(paletteNum == PaletteType::Custom) + { + + } // Now consider the current display format const PaletteArray* palette = @@ -658,6 +683,8 @@ FBInitStatus Console::initializeVideo(bool full) myOSystem.frameBuffer().showFrameStats( myOSystem.settings().getBool(devSettings ? "dev.stats" : "plr.stats")); + generateCustomPalette(0); + generateCustomPalette(1); generateColorLossPalette(); } setPalette(myOSystem.settings().getString("palette")); @@ -805,6 +832,46 @@ void Console::changeScanlineAdjust(int direction) myOSystem.frameBuffer().showMessage(ss.str()); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Console::changeColorPhaseShift(int direction) +{ + const char DEGREE = 0x1c; + const float NTSC_SHIFT = 26.2F; + const float PAL_SHIFT = 31.3F; // 360 / 11.5 + const bool isNTSC = myDisplayFormat == "NTSC" || myDisplayFormat == "NTSC50"; + const bool isPAL = myDisplayFormat == "PAL" || myDisplayFormat == "PAL60"; + + // SECAM is not supported + if(isNTSC || isPAL) + { + const string key = isNTSC ? "phase_ntsc" : "phase_pal"; + const float shift = isNTSC ? NTSC_SHIFT : PAL_SHIFT; + float phase = myOSystem.settings().getFloat(key); + + if(direction == +1) // increase color phase shift + { + phase += 0.3F; + phase = std::min(phase, shift + 4.5F); + } + else if(direction == -1) // decrease color phase shift + { + phase -= 0.3F; + phase = std::max(phase, shift - 4.5F); + } + myOSystem.settings().setValue(key, phase); + generateCustomPalette(isNTSC ? 0 : 1); + + myOSystem.settings().setValue("palette", "custom"); + setPalette("custom"); + + ostringstream ss; + ss << "Color phase shift at " + << std::fixed << std::setprecision(1) << phase << DEGREE; + + myOSystem.frameBuffer().showMessage(ss.str()); + } +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::setTIAProperties() { @@ -1056,15 +1123,129 @@ void Console::loadUserPalette() myUserPaletteDefined = true; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Console::generateCustomPalette(int type) +{ + const int NUM_CHROMA = 16; + const int NUM_LUMA = 8; + const double SATURATION = 0.25; + + double color[NUM_CHROMA][2] = {{0.0}}; + + if(type == 0) + { + // YIQ is YUV shifted by 33° + const double offset = 33 * (2 * M_PI / 360); + const double shift = myOSystem.settings().getFloat("phase_ntsc") * (2 * M_PI / 360); + + // color 0 is grayscale + for(int chroma = 1; chroma < NUM_CHROMA; chroma++) + { + color[chroma][0] = SATURATION * sin(offset + shift * (chroma - 1)); + color[chroma][1] = SATURATION * sin(offset + shift * (chroma - 1 - M_PI)); + } + + for(int chroma = 0; chroma < NUM_CHROMA; chroma++) + { + const double I = color[chroma][0]; + const double Q = color[chroma][1]; + + for(int luma = 0; luma < NUM_LUMA; luma++) + { + const double Y = 0.05 + luma / 8.24; // 0.05..~0.90 + + double R = Y + 0.956 * I + 0.621 * Q; + double G = Y - 0.272 * I - 0.647 * Q; + double B = Y - 1.106 * I + 1.703 * Q; + + if(R < 0) R = 0; + if(G < 0) G = 0; + if(B < 0) B = 0; + + R = pow(R, 0.9); + G = pow(G, 0.9); + B = pow(B, 0.9); + + if(R > 1) R = 1; + if(G > 1) G = 1; + if(B > 1) B = 1; + + int r = R * 255.F; + int g = G * 255.F; + int b = B * 255.F; + + ourCustomNTSCPalette[(chroma * NUM_LUMA + luma) << 1] = (r << 16) + (g << 8) + b; + } + } + } + else + { + const double offset = 180 * (2 * M_PI / 360); + const double shift = myOSystem.settings().getFloat("phase_pal") * (2 * M_PI / 360); + const double fixedShift = 22.5 * (2 * M_PI / 360); + + // colors 0, 1, 14 and 15 are grayscale + for(int chroma = 2; chroma < NUM_CHROMA - 2; chroma++) + { + int idx = NUM_CHROMA - 1 - chroma; + color[idx][0] = SATURATION * sin(offset - fixedShift * chroma); + if ((idx & 1) == 0) + color[idx][1] = SATURATION * sin(offset - shift * (chroma - 3.5) / 2.F); + else + color[idx][1] = SATURATION * -sin(offset - shift * chroma / 2.F); + } + + for(int chroma = 0; chroma < NUM_CHROMA; chroma++) + { + const double U = color[chroma][0]; + const double V = color[chroma][1]; + + for(int luma = 0; luma < NUM_LUMA; luma++) + { + const double Y = 0.05 + luma / 8.24; // 0.05..~0.90 + + // Most sources + double R = Y + 1.403 * V; + double G = Y - 0.344 * U - 0.714 * V; + double B = Y + 1.770 * U; + + // German Wikipedia, huh??? + //double B = Y + 1 / 0.493 * U; + //double R = Y + 1 / 0.877 * V; + //double G = 1.704 * Y - 0.590 * R - 0.194 * B; + + if(R < 0) R = 0.0; + if(G < 0) G = 0.0; + if(B < 0) B = 0.0; + + R = pow(R, 1.2); + G = pow(G, 1.2); + B = pow(B, 1.2); + + if(R > 1) R = 1; + if(G > 1) G = 1; + if(B > 1) B = 1; + + int r = R * 255.F; + int g = G * 255.F; + int b = B * 255.F; + + ourCustomPALPalette[(chroma * NUM_LUMA + luma) << 1] = (r << 16) + (g << 8) + b; + } + } + } +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::generateColorLossPalette() { // Look at all the palettes, since we don't know which one is // currently active - std::array palette = { - ourNTSCPalette.data(), ourPALPalette.data(), ourSECAMPalette.data(), - ourNTSCPaletteZ26.data(), ourPALPaletteZ26.data(), ourSECAMPaletteZ26.data(), - nullptr, nullptr, nullptr + std::array palette = { + ourNTSCPalette.data(), ourPALPalette.data(), ourSECAMPalette.data(), + ourNTSCPaletteZ26.data(), ourPALPaletteZ26.data(), ourSECAMPaletteZ26.data(), + nullptr, nullptr, nullptr, + ourCustomNTSCPalette.data(), ourCustomPALPalette.data(), ourSECAMPalette.data(), }; if(myUserPaletteDefined) { @@ -1073,7 +1254,7 @@ void Console::generateColorLossPalette() palette[8] = ourUserSECAMPalette.data(); } - for(int i = 0; i < 9; ++i) + for(int i = 0; i < 3 * PaletteType::NumTypes; ++i) { if(palette[i] == nullptr) continue; @@ -1388,3 +1569,9 @@ PaletteArray Console::ourUserPALPalette = { 0 }; // filled from external file // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PaletteArray Console::ourUserSECAMPalette = { 0 }; // filled from external file + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PaletteArray Console::ourCustomNTSCPalette = { 0 }; // filled by function + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PaletteArray Console::ourCustomPALPalette = { 0 }; // filled by function diff --git a/src/emucore/Console.hxx b/src/emucore/Console.hxx index 33c3b117c..9ff4b002c 100644 --- a/src/emucore/Console.hxx +++ b/src/emucore/Console.hxx @@ -209,6 +209,11 @@ class Console : public Serializable, public ConsoleIO */ void togglePalette(); + /** + Generates a custom palette, based on user defined phase shifts. + */ + void generateCustomPalette(int type); + /** Sets the palette according to the given palette name. @@ -283,6 +288,16 @@ class Console : public Serializable, public ConsoleIO */ void changeScanlineAdjust(int direction); + /** + Change the "phase shift" variable. + Note that there are two of these (NTSC and PAL). The currently + active mode will determine which one is used. + + @param direction +1 indicates increase, -1 indicates decrease. + + */ + void changeColorPhaseShift(int direction); + /** Returns the current framerate. */ @@ -377,10 +392,22 @@ class Console : public Serializable, public ConsoleIO */ void generateColorLossPalette(); + int getPaletteNum(const string& name) const; + + void toggleTIABit(TIABit bit, const string& bitname, bool show = true) const; void toggleTIACollision(TIABit bit, const string& bitname, bool show = true) const; private: + + enum PaletteType { + Standard, + Z26, + User, + Custom, + NumTypes + }; + // Reference to the osystem object OSystem& myOSystem; @@ -462,6 +489,10 @@ class Console : public Serializable, public ConsoleIO static PaletteArray ourUserPALPalette; static PaletteArray ourUserSECAMPalette; + // Table of RGB values for NTSC, PAL - custom-defined + static PaletteArray ourCustomNTSCPalette; + static PaletteArray ourCustomPALPalette; + private: // Following constructors and assignment operators not supported Console() = delete; diff --git a/src/emucore/Event.hxx b/src/emucore/Event.hxx index c45fc1e0a..915461e97 100644 --- a/src/emucore/Event.hxx +++ b/src/emucore/Event.hxx @@ -121,6 +121,7 @@ class Event // add new events from here to avoid that user remapped events get overwritten ToggleTurbo, + ColorShiftDecrease, ColorShiftIncrease, LastType }; diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 1a11c604b..c9fa85835 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -435,6 +435,14 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) if (pressed) myOSystem.console().changeScanlineAdjust(+1); return; + case Event::ColorShiftDecrease: + if (pressed) myOSystem.console().changeColorPhaseShift(-1); + return; + + case Event::ColorShiftIncrease: + if (pressed) myOSystem.console().changeColorPhaseShift(+1); + return; + case Event::ToggleFullScreen: if (pressed && !repeated) myOSystem.frameBuffer().toggleFullscreen(); return; @@ -1915,15 +1923,16 @@ EventHandler::EmulActionList EventHandler::ourEmulActionList = { { { Event::OverscanIncrease, "Increase overscan in fullscreen mode", "" }, { Event::VidmodeDecrease, "Previous zoom level", "" }, { Event::VidmodeIncrease, "Next zoom level", "" }, - { Event::ScanlineAdjustIncrease, "Increase vertical display size", "" }, { Event::ScanlineAdjustDecrease, "Decrease vertical display size", "" }, + { Event::ScanlineAdjustIncrease, "Increase vertical display size", "" }, { Event::VCenterDecrease, "Move display up", "" }, { Event::VCenterIncrease, "Move display down", "" }, { Event::FormatDecrease, "Decrease display format", "" }, { Event::FormatIncrease, "Increase display format", "" }, - { Event::TogglePalette, "Switch palette (Standard/Z26/User)", "" }, + { Event::TogglePalette, "Switch palette (Std./Z26/User/Cust.)", "" }, + { Event::ColorShiftDecrease, "Decrease custom palette phase shift", "" }, + { Event::ColorShiftIncrease, "Increase custom palette phase shift", "" }, { Event::ToggleInter, "Toggle display interpolation", "" }, - // TV effects: { Event::VidmodeStd, "Disable TV effects", "" }, { Event::VidmodeRGB, "Select 'RGB' preset", "" }, @@ -2049,7 +2058,8 @@ const Event::EventSet EventHandler::AudioVideoEvents = { Event::VCenterDecrease, Event::VCenterIncrease, Event::ScanlineAdjustDecrease, Event::ScanlineAdjustIncrease, Event::OverscanDecrease, Event::OverscanIncrease, - Event::TogglePalette, Event::ToggleInter + Event::TogglePalette, Event::ColorShiftDecrease, Event::ColorShiftIncrease, + Event::ToggleInter }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx index 8148fa085..8fe4c7821 100644 --- a/src/emucore/EventHandler.hxx +++ b/src/emucore/EventHandler.hxx @@ -468,7 +468,7 @@ class EventHandler #else PNG_SIZE = 0, #endif - EMUL_ACTIONLIST_SIZE = 145 + PNG_SIZE + COMBO_SIZE, + EMUL_ACTIONLIST_SIZE = 149 + PNG_SIZE + COMBO_SIZE, MENU_ACTIONLIST_SIZE = 18 ; diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index b0e5cd7a6..c1c64dd20 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -46,6 +46,8 @@ Settings::Settings() setPermanent("windowedpos", Common::Point(50, 50)); setPermanent("display", 0); setPermanent("palette", "standard"); + setPermanent("phase_ntsc", "26.2"); + setPermanent("phase_pal", "31.3"); setPermanent("uimessages", "true"); // TIA specific options @@ -356,7 +358,7 @@ void Settings::validate() else if(i > 10) setValue("ssinterval", "10"); s = getString("palette"); - if(s != "standard" && s != "z26" && s != "user") + if(s != "standard" && s != "z26" && s != "user" && s != "custom") setValue("palette", "standard"); s = getString("launcherfont"); @@ -403,8 +405,10 @@ void Settings::usage() const << " -windowedpos Sets the window position in windowed emulator mode\n" << " -display Sets the display for Stella's emulator\n" << " -palette \n" + << " z26|user|\n" + << " custom>\n" + << " -phase_ntsc Phase shift for NTSC custom color palette\n" + << " -phase_pal Phase shift for PAL custom color palette\n" << " -speed Run emulation at the given speed\n" << " -turbo <1|0> Enable 'Turbo' mode for maximum emulation speed\n" << " -uimessages <1|0> Show onscreen UI messages for different events\n" diff --git a/src/gui/CommandDialog.cxx b/src/gui/CommandDialog.cxx index 934b9e645..5c734a52e 100644 --- a/src/gui/CommandDialog.cxx +++ b/src/gui/CommandDialog.cxx @@ -273,7 +273,9 @@ void CommandDialog::updatePalette() label = "Stella Palette"; else if(BSPF::equalsIgnoreCase(palette, "z26")) label = "Z26 Palette"; - else + else if(BSPF::equalsIgnoreCase(palette, "user")) label = "User Palette"; + else + label = "Custom Palette"; myPaletteButton->setLabel(label); } diff --git a/src/gui/ConsoleBFont.hxx b/src/gui/ConsoleBFont.hxx index c47d4e375..b55797a89 100644 --- a/src/gui/ConsoleBFont.hxx +++ b/src/gui/ConsoleBFont.hxx @@ -42,6 +42,41 @@ namespace GUI { // Font character bitmap data. static const uInt16 consoleB_font_bits[] = { // NOLINT : too complicated to convert + /* MODIFIED + Character 28 (0x1c): + width 8 + bbx ( 8, 13, 0, -2 ) + + +--------+ + | | + | XXXX | + | XX XX | + | XX XX | + | XX XX | + | XXXX | + | | + | | + | | + | | + | | + | | + | | + +--------+ + */ + 0x0000, + 0b0011110000000000, + 0b0110011000000000, + 0b0110011000000000, + 0b0110011000000000, + 0b0011110000000000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + /* MODIFIED Character 29 (0x1d): @@ -3386,8 +3421,8 @@ static const FontDesc consoleBDesc = { 13, 8, 13, 0, -2, 11, - 29, - 98, + 28, + 99, consoleB_font_bits, nullptr, /* no encode table*/ nullptr, /* fixed width*/ diff --git a/src/gui/ConsoleMediumBFont.hxx b/src/gui/ConsoleMediumBFont.hxx index 63116d64e..9c8081619 100644 --- a/src/gui/ConsoleMediumBFont.hxx +++ b/src/gui/ConsoleMediumBFont.hxx @@ -42,6 +42,45 @@ namespace GUI { // Font character bitmap data. static const uInt16 consoleMediumB_font_bits[] = { // NOLINT : too complicated to convert + /* MODIFIED + Character 28 (0x1c): ellipsis + width 9 + bbx ( 9, 15, 0, -3 ) + + +---------+ + | | + | | + | XXXX | + | XX XX | + | XX XX | + | XX XX | + | XXXX | + | | + | | + | | + | | + | | + | | + | | + | | + +---------+ + */ + 0x0000, + 0x0000, + 0b0011110000000000, + 0b0110011000000000, + 0b0110011000000000, + 0b0110011000000000, + 0b0011110000000000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + /* MODIFIED Character 29 (0x1d): ellipsis width 9 @@ -3777,8 +3816,8 @@ static const FontDesc consoleMediumBDesc = { 15, 9, 15, 0, -3, 12, - 29, - 98, + 28, + 99, consoleMediumB_font_bits, nullptr, /* no encode table*/ nullptr, /* fixed width*/ diff --git a/src/gui/DeveloperDialog.cxx b/src/gui/DeveloperDialog.cxx index 2dd607a4b..5badbc513 100644 --- a/src/gui/DeveloperDialog.cxx +++ b/src/gui/DeveloperDialog.cxx @@ -264,8 +264,9 @@ void DeveloperDialog::addTiaTab(const GUI::Font& font) wid.push_back(myPFColorWidget); ypos += lineHeight + VGAP * 1; - mySwapLabel = new StaticTextWidget(myTab, font, HBORDER + INDENT * 2, ypos + 1, - "Delayed VDEL" + ELLIPSIS + " swap for"); + ostringstream ss; + ss << "Delayed VDEL" << ELLIPSIS << " swap for"; + mySwapLabel = new StaticTextWidget(myTab, font, HBORDER + INDENT * 2, ypos + 1, ss.str()); wid.push_back(mySwapLabel); ypos += lineHeight + VGAP * 1; diff --git a/src/gui/GuiObject.hxx b/src/gui/GuiObject.hxx index 4e4325132..3f473867b 100644 --- a/src/gui/GuiObject.hxx +++ b/src/gui/GuiObject.hxx @@ -90,8 +90,9 @@ class GuiObject : public CommandReceiver /** Redraw the focus list */ virtual void redrawFocus() { } - /** Special character for menues */ + /** Special characters for menues */ const string ELLIPSIS = "\x1d"; + const string DEGREE = "\x1c"; protected: virtual void releaseFocus() = 0; diff --git a/src/gui/Stella12x24tFont.hxx b/src/gui/Stella12x24tFont.hxx index 88bb67ae4..e1e3e07d7 100644 --- a/src/gui/Stella12x24tFont.hxx +++ b/src/gui/Stella12x24tFont.hxx @@ -42,6 +42,62 @@ namespace GUI { // Font character bitmap data. static const uInt16 stella12x24t_font_bits[] = { // NOLINT : too complicated to convert +/* Character 28 (0x1c): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0b0000111000000000, +0b0001101100000000, +0b0011000110000000, +0b0011000110000000, +0b0011000110000000, +0b0001101100000000, +0b0000111000000000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + /* Character 29 (0x1d): width 12 bbx ( 12, 24, 0, -5 ) @@ -5538,8 +5594,8 @@ static const FontDesc stella12x24tDesc = { 24, 12, 24, 0, -5, 19, - 29, - 98, + 28, + 99, stella12x24t_font_bits, nullptr, /* no encode table*/ nullptr, /* fixed width*/ diff --git a/src/gui/Stella14x28tFont.hxx b/src/gui/Stella14x28tFont.hxx index 2ce818d7c..8b1e262a5 100644 --- a/src/gui/Stella14x28tFont.hxx +++ b/src/gui/Stella14x28tFont.hxx @@ -42,7 +42,72 @@ namespace GUI { // Font character bitmap data. static const uInt16 stella14x28t_font_bits[] = { // NOLINT : too complicated to convert -/* Character 32 (0x20): +/* Character 28 (0x1c): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0b0000011110000000, +0b0000111111000000, +0b0001110011100000, +0b0001100001100000, +0b0001100001100000, +0b0001110011100000, +0b0000111111000000, +0b0000011110000000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + + +/* Character 29 (0x1d): width 14 bbx ( 14, 28, 0, -6 ) @@ -6322,8 +6387,8 @@ static const FontDesc stella14x28tDesc = { 28, 14, 28, 0, -6, 22, - 29, - 98, + 28, + 99, stella14x28t_font_bits, nullptr, /* no encode table*/ nullptr, /* fixed width*/ diff --git a/src/gui/Stella16x32tFont.hxx b/src/gui/Stella16x32tFont.hxx index 15c1e7b4c..63708f473 100644 --- a/src/gui/Stella16x32tFont.hxx +++ b/src/gui/Stella16x32tFont.hxx @@ -42,6 +42,78 @@ namespace GUI { // Font character bitmap data. static const uInt16 stella16x32t_font_bits[] = { // NOLINT : too complicated to convert +/* Character 28 (0x1c): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0b0000111110000000, +0b0001111111000000, +0b0011110111100000, +0b0011100011100000, +0b0011100011100000, +0b0011110111100000, +0b0001111111000000, +0b0000111110000000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + /* Character 29 (0x1d): width 16 bbx ( 16, 32, 0, -6 ) @@ -7106,8 +7178,8 @@ static const FontDesc stella16x32tDesc = { 32, 16, 32, 0, -6, 26, - 29, - 98, + 28, + 99, stella16x32t_font_bits, nullptr, /* no encode table*/ nullptr, /* fixed width*/ diff --git a/src/gui/StellaLargeFont.hxx b/src/gui/StellaLargeFont.hxx index 39b181b8f..3c04ffa44 100644 --- a/src/gui/StellaLargeFont.hxx +++ b/src/gui/StellaLargeFont.hxx @@ -42,6 +42,55 @@ namespace GUI { // Font character bitmap data. static const uInt16 stellaLarge_font_bits[] = { // NOLINT : too complicated to convert + /* MODIFIED + Character 28 (0x1c): + width 10 + bbx ( 10, 20, 0, -4 ) + + +----------+ + | | + | | + | | + | XXXX | + | XX XX | + | XX XX | + | XX XX | + | XX XX | + | XXXX | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +----------+ + */ + 0x0000, + 0x0000, + 0x0000, + 0b0001111000000000, + 0b0011001100000000, + 0b0011001100000000, + 0b0011001100000000, + 0b0011001100000000, + 0b0001111000000000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + /* MODIFIED Character 29 (0x1d): width 10 @@ -4759,8 +4808,8 @@ static const FontDesc stellaLargeDesc = { 20, 10, 20, 0, -4, 16, - 29, - 98, + 28, + 99, stellaLarge_font_bits, nullptr, /* no encode table*/ nullptr, /* fixed width*/ diff --git a/src/gui/StellaMediumFont.hxx b/src/gui/StellaMediumFont.hxx index e0fd43629..e81422454 100644 --- a/src/gui/StellaMediumFont.hxx +++ b/src/gui/StellaMediumFont.hxx @@ -43,6 +43,52 @@ namespace GUI { static const uInt16 stellaMedium_font_bits[] = { // NOLINT : too complicated to convert + /* MODIFIED + Character 28 (0x1c): degree + width 9 + bbx ( 9, 15, 0, -3 ) + + +---------+ + | | + | | + | | + | | + | | + | XXXXXX | + | X X| + | X X| + | XXXXXX | + | | + | | + | | + | XX XX XX| + | XX XX XX| + | | + | | + | | + | | + +---------+ + */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0b0001111000000000, + 0b0011001100000000, + 0b0011001100000000, + 0b0011001100000000, + 0b0001111000000000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + /* MODIFIED Character 29 (0x1d): ellipsis width 9 @@ -4367,8 +4413,8 @@ static const FontDesc stellaMediumDesc = { 18, 9, 18, 0, -4, 14, - 29, - 98, + 28, + 99, stellaMedium_font_bits, nullptr, /* no encode table*/ nullptr, /* fixed width*/ diff --git a/src/gui/VideoDialog.cxx b/src/gui/VideoDialog.cxx index b7aa2a2d5..30b7a6ccc 100644 --- a/src/gui/VideoDialog.cxx +++ b/src/gui/VideoDialog.cxx @@ -89,14 +89,13 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, int xpos, ypos, tabID; int lwidth = font.getStringWidth("V-Size adjust "), - pwidth = font.getStringWidth("XXXXxXXXX"), - swidth = font.getMaxCharWidth() * 10 - 2; + pwidth = font.getStringWidth("XXXXxXXXX"); WidgetArray wid; VariantList items; // Set real dimensions - setSize(60 * fontWidth + HBORDER * 2, + setSize(57 * fontWidth + HBORDER * 2 + PopUpWidget::dropDownWidth(font) * 2, _th + VGAP * 3 + lineHeight + 11 * (lineHeight + VGAP) + buttonHeight + VBORDER * 3, max_w, max_h); @@ -125,11 +124,32 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, VarList::push_back(items, "z26", "z26"); if (instance().checkUserPalette()) VarList::push_back(items, "User", "user"); + VarList::push_back(items, "Custom", "custom"); myTIAPalette = new PopUpWidget(myTab, font, xpos, ypos, pwidth, - lineHeight, items, "Palette ", lwidth); + lineHeight, items, "Palette ", lwidth, kPaletteChanged); wid.push_back(myTIAPalette); ypos += lineHeight + VGAP; + int swidth = myTIAPalette->getWidth() - lwidth; + int plWidth = font.getStringWidth("NTSC phase "); + int pswidth = swidth - INDENT + lwidth - plWidth; + + myPhaseShiftNtsc = + new SliderWidget(myTab, font, xpos + INDENT, ypos-1, pswidth, lineHeight, + "NTSC phase", plWidth, kNtscShiftChanged, fontWidth * 5); + myPhaseShiftNtsc->setMinValue(262 - 45); myPhaseShiftNtsc->setMaxValue(262 + 45); + myPhaseShiftNtsc->setTickmarkIntervals(4); + wid.push_back(myPhaseShiftNtsc); + ypos += lineHeight + VGAP; + + myPhaseShiftPal = + new SliderWidget(myTab, font, xpos + INDENT, ypos-1, pswidth, lineHeight, + "PAL phase", plWidth, kPalShiftChanged, fontWidth * 5); + myPhaseShiftPal->setMinValue(313 - 45); myPhaseShiftPal->setMaxValue(313 + 45); + myPhaseShiftPal->setTickmarkIntervals(4); + wid.push_back(myPhaseShiftPal); + ypos += lineHeight + VGAP * 4; + // TIA interpolation myTIAInterpolate = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Interpolation "); wid.push_back(myTIAInterpolate); ypos += lineHeight + VGAP; @@ -264,7 +284,7 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, CREATE_CUSTOM_SLIDERS(Fringe, "Fringing ", 0) CREATE_CUSTOM_SLIDERS(Bleed, "Bleeding ", 0) - xpos += myTVContrast->getWidth() + fontWidth * 4; + xpos += myTVContrast->getWidth() + fontWidth * 6; ypos = VBORDER; lwidth = font.getStringWidth("Intensity "); @@ -287,7 +307,7 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, xpos += INDENT; CREATE_CUSTOM_SLIDERS(ScanIntense, "Intensity ", kScanlinesChanged) - ypos += lineHeight + 2; + ypos += VGAP * 3; // Adjustable presets xpos -= INDENT; @@ -345,6 +365,11 @@ void VideoDialog::loadConfig() myTIAPalette->setSelected( instance().settings().getString("palette"), "standard"); + // Custom Palette + myPhaseShiftNtsc->setValue(instance().settings().getFloat("phase_ntsc") * 10); + myPhaseShiftPal->setValue(instance().settings().getFloat("phase_pal") * 10); + handlePaletteChange(); + // TIA interpolation myTIAInterpolate->setState(instance().settings().getBool("tia.inter")); @@ -417,6 +442,10 @@ void VideoDialog::saveConfig() instance().settings().setValue("palette", myTIAPalette->getSelectedTag().toString()); + // Custom Palette + instance().settings().setValue("phase_ntsc", myPhaseShiftNtsc->getValue() / 10.0); + instance().settings().setValue("phase_pal", myPhaseShiftPal->getValue() / 10.0); + // TIA interpolation instance().settings().setValue("tia.inter", myTIAInterpolate->getState()); @@ -484,12 +513,21 @@ void VideoDialog::saveConfig() // TV scanline intensity instance().settings().setValue("tv.scanlines", myTVScanIntense->getValueLabel()); - if (instance().hasConsole()) + if(instance().hasConsole()) + { instance().console().setTIAProperties(); - if (vsizeChanged && instance().hasConsole()) { - instance().console().tia().clearFrameBuffer(); - instance().console().initializeVideo(); + if(instance().settings().getString("palette") == "custom") + { + instance().console().generateCustomPalette(0); + instance().console().generateCustomPalette(1); + } + + if(vsizeChanged) + { + instance().console().tia().clearFrameBuffer(); + instance().console().initializeVideo(); + } } // Finally, issue a complete framebuffer re-initialization... @@ -509,6 +547,8 @@ void VideoDialog::setDefaults() myRenderer->setSelectedIndex(0); myTIAZoom->setValue(300); myTIAPalette->setSelected("standard", ""); + myPhaseShiftNtsc->setValue(262); + myPhaseShiftPal->setValue(313); myTIAInterpolate->setState(false); myVSizeAdjust->setValue(0); mySpeed->setValue(0); @@ -521,6 +561,8 @@ void VideoDialog::setDefaults() myCenter->setState(false); myFastSCBios->setState(true); myUseThreads->setState(false); + + handlePaletteChange(); break; } @@ -586,6 +628,15 @@ void VideoDialog::loadTVAdjustables(NTSCFilter::Preset preset) myTVGamma->setValue(adj.gamma); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void VideoDialog::handlePaletteChange() +{ + bool enable = myTIAPalette->getSelectedTag().toString() == "custom"; + + myPhaseShiftNtsc->setEnabled(enable); + myPhaseShiftPal->setEnabled(enable); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void VideoDialog::handleFullScreenChange() { @@ -627,6 +678,28 @@ void VideoDialog::handleCommand(CommandSender* sender, int cmd, setDefaults(); break; + case kPaletteChanged: + handlePaletteChange(); + break; + + case kNtscShiftChanged: + { + std::ostringstream ss; + + ss << std::setw(4) << std::fixed << std::setprecision(1) + << (0.1 * abs(myPhaseShiftNtsc->getValue())) << DEGREE; + myPhaseShiftNtsc->setValueLabel(ss.str()); + break; + } + case kPalShiftChanged: + { + std::ostringstream ss; + + ss << std::setw(4) << std::fixed << std::setprecision(1) + << (0.1 * abs(myPhaseShiftPal->getValue())) << DEGREE; + myPhaseShiftPal->setValueLabel(ss.str()); + break; + } case kVSizeChanged: { int adjust = myVSizeAdjust->getValue(); diff --git a/src/gui/VideoDialog.hxx b/src/gui/VideoDialog.hxx index 34931481d..429290082 100644 --- a/src/gui/VideoDialog.hxx +++ b/src/gui/VideoDialog.hxx @@ -45,6 +45,7 @@ class VideoDialog : public Dialog void handleTVModeChange(NTSCFilter::Preset); void loadTVAdjustables(NTSCFilter::Preset preset); + void handlePaletteChange(); void handleFullScreenChange(); void handleOverscanChange(); void handlePhosphorChange(); @@ -57,6 +58,8 @@ class VideoDialog : public Dialog PopUpWidget* myRenderer{nullptr}; SliderWidget* myTIAZoom{nullptr}; PopUpWidget* myTIAPalette{nullptr}; + SliderWidget* myPhaseShiftNtsc{nullptr}; + SliderWidget* myPhaseShiftPal{nullptr}; CheckboxWidget* myTIAInterpolate{nullptr}; SliderWidget* myVSizeAdjust{nullptr}; SliderWidget* mySpeed{nullptr}; @@ -100,6 +103,9 @@ class VideoDialog : public Dialog ButtonWidget* myCloneCustom{nullptr}; enum { + kPaletteChanged = 'VDpl', + kNtscShiftChanged = 'VDns', + kPalShiftChanged = 'VDps', kSpeedupChanged = 'VDSp', kVSizeChanged = 'VDVs', kFullScreenChanged = 'VDFs', From ef87297f25e251b5f6e5eaf174e4bce2486a3b50 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Wed, 6 May 2020 21:56:47 -0230 Subject: [PATCH 184/377] libretro: Fix compilation error when including unnecessary header file. Fixes #628. --- src/emucore/Console.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 04962c9bd..99dd8413d 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -62,7 +62,6 @@ #include "AudioSettings.hxx" #include "frame-manager/FrameManager.hxx" #include "frame-manager/FrameLayoutDetector.hxx" -#include "GuiObject.hxx" #ifdef CHEATCODE_SUPPORT #include "CheatManager.hxx" From 1db8084b6b292356ae0907ecc14f200419d7b4cc Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 7 May 2020 10:36:36 +0200 Subject: [PATCH 185/377] fixed palette cycling updated doc for phase shift hotkeys improved scanlines hotkey messages --- docs/index.html | 44 ++++++++++++++++++++++++-------------- src/emucore/Console.cxx | 9 ++------ src/emucore/TIASurface.cxx | 14 +++++++++++- 3 files changed, 43 insertions(+), 24 deletions(-) diff --git a/docs/index.html b/docs/index.html index f40f67e0a..851aea9dc 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1396,19 +1396,19 @@ - Toggle 'phosphor' effect + Toggle 'phosphor' mode Alt + p Cmd + p - Decrease 'phosphor' blend in phosphor mode + Decrease 'phosphor' blend Shift-Alt + 9 Shift-Cmd + 9 - Increase 'phosphor' blend in phosphor mode + Increase 'phosphor' blend Alt + 9 Cmd + 9 @@ -1426,7 +1426,7 @@

      - Items marked as (*) are only available in 'Custom' preset mode
      + Items marked as (*) will also switch to 'Custom' preset mode @@ -1578,18 +1578,18 @@ Cmd + Enter - - Increase overscan in fullscreen mode - Shift + PageUp - Shift + PageUp - - Decrease overscan in fullscreen mode Shift + PageDown Shift + PageDown + + Increase overscan in fullscreen mode + Shift + PageUp + Shift + PageUp + + Move display up (uses "Display.VCenter") Alt + PageUp @@ -1602,24 +1602,36 @@ Cmd + PageDown - - Switch display format in increasing order (NTSC/PAL/SECAM etc.) - Control + f - Control + f - - Switch display format in decreasing order (NTSC/PAL/SECAM etc.) Shift-Control + f Shift-Control + f + + Switch display format in increasing order (NTSC/PAL/SECAM etc.) + Control + f + Control + f + + Switch palette (Standard/Z26/User/Custom) Control + p Control + p + + Decrease custom palette phase shift (switches to 'Custom' palette) + Shift-Control + 9 + Shift-Control + 9 + + + + Increase custom palette phase shift (switches to 'Custom' palette) + Control + 9 + Control + 9 + + Toggle display interpolation Control + i diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 99dd8413d..29fe2bfac 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -514,8 +514,8 @@ void Console::togglePalette() } else { - palette = "standard"; - message = "Standard Stella palette"; + palette = "custom"; + message = "Custom palette"; } } else if(palette == "user") // switch to custom @@ -523,11 +523,6 @@ void Console::togglePalette() palette = "custom"; message = "Custom palette"; } - else if(palette == "custom") // switch to standard - { - palette = "standard"; - message = "Standard Stella palette"; - } else // switch to standard mode if we get this far { palette = "standard"; diff --git a/src/emucore/TIASurface.cxx b/src/emucore/TIASurface.cxx index a98f21a4a..a13a9fd83 100644 --- a/src/emucore/TIASurface.cxx +++ b/src/emucore/TIASurface.cxx @@ -193,9 +193,21 @@ void TIASurface::setScanlineIntensity(int amount) { ostringstream buf; uInt32 intensity = enableScanlines(amount); - buf << "Scanline intensity at " << intensity << "%"; + + if(intensity == 0) + buf << "Scanlines disabled"; + else + { + buf << "Scanline intensity at "; + if(intensity < 100) + buf << intensity << "%"; + else + buf << "maximum"; + } myOSystem.settings().setValue("tv.scanlines", intensity); + enableNTSC(ntscEnabled()); + myFB.showMessage(buf.str()); } From c34d33511d1b3aa69a95672d0051d95f51b7dd0e Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 7 May 2020 23:09:11 +0200 Subject: [PATCH 186/377] fix window position saving when changing zoom via hotkey --- docs/index.html | 4 ++-- src/emucore/FrameBuffer.cxx | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/index.html b/docs/index.html index 851aea9dc..82b8c4a38 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1621,13 +1621,13 @@ - Decrease custom palette phase shift (switches to 'Custom' palette) + Decrease 'Custom' palette's phase shift Shift-Control + 9 Shift-Control + 9 - Increase custom palette phase shift (switches to 'Custom' palette) + Increase 'Custom' palette's phase shift Control + 9 Control + 9 diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 250a895cf..ce2d4cf46 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -939,6 +939,8 @@ bool FrameBuffer::changeVidMode(int direction) else return false; + saveCurrentWindowPosition(); + // Changing the video mode can take some time, during which the last // sound played may get 'stuck' // So we mute the sound until the operation completes From 4cccff1a17cb14359682bdc8e929cab7fad5f751 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Fri, 8 May 2020 02:12:58 -0230 Subject: [PATCH 187/377] Use our own version of PI, since M_PI isn't defined everywhere. Fixes #630. Also, consistently use float instead of mixing float and double (compiler complains otherwise). --- src/emucore/Console.cxx | 70 +++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 29fe2bfac..46078f09d 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -1120,45 +1120,46 @@ void Console::loadUserPalette() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::generateCustomPalette(int type) { - const int NUM_CHROMA = 16; - const int NUM_LUMA = 8; - const double SATURATION = 0.25; + constexpr int NUM_CHROMA = 16; + constexpr int NUM_LUMA = 8; + constexpr float SATURATION = 0.25F; - double color[NUM_CHROMA][2] = {{0.0}}; + float color[NUM_CHROMA][2] = {{0.0F}}; if(type == 0) { // YIQ is YUV shifted by 33° - const double offset = 33 * (2 * M_PI / 360); - const double shift = myOSystem.settings().getFloat("phase_ntsc") * (2 * M_PI / 360); + constexpr float offset = 33 * (2 * BSPF::PI_f / 360); + const float shift = myOSystem.settings().getFloat("phase_ntsc") * + (2 * BSPF::PI_f / 360); // color 0 is grayscale for(int chroma = 1; chroma < NUM_CHROMA; chroma++) { color[chroma][0] = SATURATION * sin(offset + shift * (chroma - 1)); - color[chroma][1] = SATURATION * sin(offset + shift * (chroma - 1 - M_PI)); + color[chroma][1] = SATURATION * sin(offset + shift * (chroma - 1 - BSPF::PI_f)); } for(int chroma = 0; chroma < NUM_CHROMA; chroma++) { - const double I = color[chroma][0]; - const double Q = color[chroma][1]; + const float I = color[chroma][0]; + const float Q = color[chroma][1]; for(int luma = 0; luma < NUM_LUMA; luma++) { - const double Y = 0.05 + luma / 8.24; // 0.05..~0.90 + const float Y = 0.05F + luma / 8.24F; // 0.05..~0.90 - double R = Y + 0.956 * I + 0.621 * Q; - double G = Y - 0.272 * I - 0.647 * Q; - double B = Y - 1.106 * I + 1.703 * Q; + float R = Y + 0.956F * I + 0.621F * Q; + float G = Y - 0.272F * I - 0.647F * Q; + float B = Y - 1.106F * I + 1.703F * Q; if(R < 0) R = 0; if(G < 0) G = 0; if(B < 0) B = 0; - R = pow(R, 0.9); - G = pow(G, 0.9); - B = pow(B, 0.9); + R = powf(R, 0.9F); + G = powf(G, 0.9F); + B = powf(B, 0.9F); if(R > 1) R = 1; if(G > 1) G = 1; @@ -1174,47 +1175,48 @@ void Console::generateCustomPalette(int type) } else { - const double offset = 180 * (2 * M_PI / 360); - const double shift = myOSystem.settings().getFloat("phase_pal") * (2 * M_PI / 360); - const double fixedShift = 22.5 * (2 * M_PI / 360); + constexpr float offset = 180 * (2 * BSPF::PI_f / 360); + float shift = myOSystem.settings().getFloat("phase_pal") * + (2 * BSPF::PI_f / 360); + constexpr float fixedShift = 22.5F * (2 * BSPF::PI_f / 360); // colors 0, 1, 14 and 15 are grayscale for(int chroma = 2; chroma < NUM_CHROMA - 2; chroma++) { int idx = NUM_CHROMA - 1 - chroma; - color[idx][0] = SATURATION * sin(offset - fixedShift * chroma); + color[idx][0] = SATURATION * sinf(offset - fixedShift * chroma); if ((idx & 1) == 0) - color[idx][1] = SATURATION * sin(offset - shift * (chroma - 3.5) / 2.F); + color[idx][1] = SATURATION * sinf(offset - shift * (chroma - 3.5F) / 2.F); else - color[idx][1] = SATURATION * -sin(offset - shift * chroma / 2.F); + color[idx][1] = SATURATION * -sinf(offset - shift * chroma / 2.F); } for(int chroma = 0; chroma < NUM_CHROMA; chroma++) { - const double U = color[chroma][0]; - const double V = color[chroma][1]; + const float U = color[chroma][0]; + const float V = color[chroma][1]; for(int luma = 0; luma < NUM_LUMA; luma++) { - const double Y = 0.05 + luma / 8.24; // 0.05..~0.90 + const float Y = 0.05F + luma / 8.24F; // 0.05..~0.90 // Most sources - double R = Y + 1.403 * V; - double G = Y - 0.344 * U - 0.714 * V; - double B = Y + 1.770 * U; + float R = Y + 1.403F * V; + float G = Y - 0.344F * U - 0.714F * V; + float B = Y + 1.770F * U; // German Wikipedia, huh??? - //double B = Y + 1 / 0.493 * U; - //double R = Y + 1 / 0.877 * V; - //double G = 1.704 * Y - 0.590 * R - 0.194 * B; + //float B = Y + 1 / 0.493 * U; + //float R = Y + 1 / 0.877 * V; + //float G = 1.704 * Y - 0.590 * R - 0.194 * B; if(R < 0) R = 0.0; if(G < 0) G = 0.0; if(B < 0) B = 0.0; - R = pow(R, 1.2); - G = pow(G, 1.2); - B = pow(B, 1.2); + R = powf(R, 1.2); + G = powf(G, 1.2); + B = powf(B, 1.2); if(R > 1) R = 1; if(G > 1) G = 1; From 8422b6e44b4895230d5b3763b1facdb5ce579a5c Mon Sep 17 00:00:00 2001 From: thrust26 Date: Fri, 8 May 2020 17:51:19 +0200 Subject: [PATCH 188/377] refactor palette handling into own class convert brightness, contrast, saturation and gamma --- src/common/PKeyboardHandler.cxx | 3 +- src/common/PaletteHandler.cxx | 721 +++++++++++++++++++++++++++++ src/common/PaletteHandler.hxx | 155 +++++++ src/common/module.mk | 1 + src/emucore/Console.cxx | 574 +---------------------- src/emucore/Console.hxx | 82 +--- src/emucore/ConsoleTiming.hxx | 3 +- src/emucore/Event.hxx | 4 +- src/emucore/EventHandler.cxx | 19 +- src/emucore/EventHandler.hxx | 2 +- src/emucore/Settings.cxx | 2 +- src/gui/CommandDialog.cxx | 3 +- src/gui/HelpDialog.cxx | 2 +- src/gui/VideoDialog.cxx | 5 +- src/windows/Stella.vcxproj | 2 + src/windows/Stella.vcxproj.filters | 6 + 16 files changed, 925 insertions(+), 659 deletions(-) create mode 100644 src/common/PaletteHandler.cxx create mode 100644 src/common/PaletteHandler.hxx diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index f32600345..639d8ae31 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -491,7 +491,8 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo {Event::ScanlinesDecrease, KBDK_0, KBDM_SHIFT | MOD3}, {Event::ScanlinesIncrease, KBDK_0, MOD3}, {Event::ToggleColorLoss, KBDK_L, KBDM_CTRL}, - {Event::TogglePalette, KBDK_P, KBDM_CTRL}, + {Event::PaletteDecrease, KBDK_P, KBDM_SHIFT | KBDM_CTRL}, + {Event::PaletteIncrease, KBDK_P, KBDM_CTRL}, {Event::ColorShiftDecrease, KBDK_9, KBDM_SHIFT | KBDM_CTRL}, {Event::ColorShiftIncrease, KBDK_9, KBDM_CTRL}, {Event::ToggleInter, KBDK_I, KBDM_CTRL}, diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx new file mode 100644 index 000000000..e1d71f123 --- /dev/null +++ b/src/common/PaletteHandler.cxx @@ -0,0 +1,721 @@ +//============================================================================ +// +// 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 "Console.hxx" +#include "FrameBuffer.hxx" + +#include "PaletteHandler.hxx" + +PaletteHandler::PaletteHandler(OSystem& system) + : myOSystem(system) +{ + // Load user-defined palette for this ROM + loadUserPalette(); + + //// Generate custom palette + //generateCustomPalette(ConsoleTiming::ntsc); + //generateCustomPalette(ConsoleTiming::pal); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PaletteHandler::PaletteType PaletteHandler::toPaletteType(const string& name) const +{ + if(name == SETTING_Z26) + return PaletteType::Z26; + + if(name == SETTING_USER && myUserPaletteDefined) + return PaletteType::User; + + if(name == SETTING_CUSTOM) + return PaletteType::Custom; + + return PaletteType::Standard; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string PaletteHandler::toPaletteName(PaletteType type) const +{ + string SETTING_NAMES[int(PaletteType::NumTypes)] = { + SETTING_STANDARD, SETTING_Z26, SETTING_USER, SETTING_CUSTOM + }; + + return SETTING_NAMES[type]; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::changePalette(bool increase) +{ + string MESSAGES[PaletteType::NumTypes] = { + "Standard Stella", "Z26", "User-defined", "Custom" + }; + + string palette, message; + palette = myOSystem.settings().getString("palette"); + + + int type = toPaletteType(myOSystem.settings().getString("palette")); + + if(increase) + { + if(type == PaletteType::MaxType) + type = PaletteType::Standard; + else + type++; + // If we have no user-defined palette, we will skip it + if(type == PaletteType::User && !myUserPaletteDefined) + type++; + } + else + { + if(type == PaletteType::MinType) + type = PaletteType::MaxType; + else + type--; + // If we have no user-defined palette, we will skip it + if(type == PaletteType::User && !myUserPaletteDefined) + type--; + } + + palette = toPaletteName(PaletteType(type)); + message = MESSAGES[type] + " palette"; + + myOSystem.frameBuffer().showMessage(message); + + setPalette(palette); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::generatePalettes() +{ + generateCustomPalette(ConsoleTiming::ntsc); + generateCustomPalette(ConsoleTiming::pal); + generateColorLossPalette(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::changeColorPhaseShift(bool increase) +{ + const char DEGREE = 0x1c; + const float NTSC_SHIFT = 26.2F; + const float PAL_SHIFT = 31.3F; // 360 / 11.5 + const ConsoleTiming timing = myOSystem.console().timing(); + const bool isNTSC = timing == ConsoleTiming::ntsc; + const bool isPAL = timing == ConsoleTiming::pal; + + // SECAM is not supported + if(isNTSC || isPAL) + { + const string key = isNTSC ? "phase_ntsc" : "phase_pal"; + const float shift = isNTSC ? NTSC_SHIFT : PAL_SHIFT; + float phase = myOSystem.settings().getFloat(key); + + if(increase) // increase color phase shift + { + phase += 0.3F; + phase = std::min(phase, shift + 4.5F); + } + else // decrease color phase shift + { + phase -= 0.3F; + phase = std::max(phase, shift - 4.5F); + } + myOSystem.settings().setValue(key, phase); + generateCustomPalette(timing); + + setPalette("custom"); + + ostringstream ss; + ss << "Color phase shift at " + << std::fixed << std::setprecision(1) << phase << DEGREE; + + myOSystem.frameBuffer().showMessage(ss.str()); + } +} + + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::setPalette(const string& name) +{ + myOSystem.settings().setValue("palette", name); + + setPalette(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::setPalette() +{ + const string& name = myOSystem.settings().getString("palette"); + + // Look at all the palettes, since we don't know which one is + // currently active + static constexpr BSPF::array2D palettes = {{ + { &ourNTSCPalette, &ourPALPalette, &ourSECAMPalette }, + { &ourNTSCPaletteZ26, &ourPALPaletteZ26, &ourSECAMPaletteZ26 }, + { &ourUserNTSCPalette, &ourUserPALPalette, &ourUserSECAMPalette }, + { &ourCustomNTSCPalette, &ourCustomPALPalette, &ourSECAMPalette } + }}; + // See which format we should be using + const ConsoleTiming timing = myOSystem.console().timing(); + const PaletteType paletteType = toPaletteType(name); + // Now consider the current display format + const PaletteArray* palette = palettes[paletteType][int(timing)]; + + myOSystem.frameBuffer().setTIAPalette(adjustPalette(*palette)); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PaletteArray PaletteHandler::adjustPalette(const PaletteArray& palette) +{ + PaletteArray destPalette; + // Constants for saturation and gray scale calculation + const float PR = .2989F; + const float PG = .5870F; + const float PB = .1140F; + // Generate adjust table + const int ADJUST_SIZE = 256; + const int RGB_UNIT = 1 << 8; + const float RGB_OFFSET = 0.5F; + const float brightness = myBrightness * (0.5F * RGB_UNIT) + RGB_OFFSET; + const float contrast = myContrast * (0.5F * RGB_UNIT) + RGB_UNIT; + const float saturation = mySaturation + 1; + const float gamma = 1.1333F - myGamma * 0.5F; + /* match common PC's 2.2 gamma to TV's 2.65 gamma */ + const float toFloat = 1.F / (ADJUST_SIZE - 1); + std::array adjust; + + for(int i = 0; i < ADJUST_SIZE; i++) + adjust[i] = powf(i * toFloat, gamma) * contrast + brightness; + + // Transform original palette into destination palette + for(int i = 0; i < destPalette.size(); i += 2) + { + const uInt32 pixel = palette[i]; + int r = (pixel >> 16) & 0xff; + int g = (pixel >> 8) & 0xff; + int b = (pixel >> 0) & 0xff; + + // TOOD: adjust hue (different for NTSC and PAL?) + + // adjust saturation + float P = sqrt(r * r * PR + g * g * PG + b * b * PB) ; + + r = P + (r - P) * saturation; + g = P + (g - P) * saturation; + b = P + (b - P) * saturation; + + r = BSPF::clamp(r, 0, 255); + g = BSPF::clamp(g, 0, 255); + b = BSPF::clamp(b, 0, 255); + + // adjust contrast, brightness, gamma + r = adjust[r]; + g = adjust[g]; + b = adjust[b]; + + r = BSPF::clamp(r, 0, 255); + g = BSPF::clamp(g, 0, 255); + b = BSPF::clamp(b, 0, 255); + + destPalette[i] = (r << 16) + (g << 8) + b; + + // Fill the odd numbered palette entries with gray values (calculated + // using the standard RGB -> grayscale conversion formula) + const uInt8 lum = static_cast((r * PR) + (g * PG) + (b * PB)); + + destPalette[i + 1] = (lum << 16) + (lum << 8) + lum; + } + return destPalette; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::loadUserPalette() +{ + if (!myOSystem.checkUserPalette(true)) + return; + + const string& palette = myOSystem.paletteFile(); + ifstream in(palette, std::ios::binary); + + // Now that we have valid data, create the user-defined palettes + std::array pixbuf; // Temporary buffer for one 24-bit pixel + + for(int i = 0; i < 128; i++) // NTSC palette + { + in.read(reinterpret_cast(pixbuf.data()), 3); + uInt32 pixel = (int(pixbuf[0]) << 16) + (int(pixbuf[1]) << 8) + int(pixbuf[2]); + ourUserNTSCPalette[(i<<1)] = pixel; + } + for(int i = 0; i < 128; i++) // PAL palette + { + in.read(reinterpret_cast(pixbuf.data()), 3); + uInt32 pixel = (int(pixbuf[0]) << 16) + (int(pixbuf[1]) << 8) + int(pixbuf[2]); + ourUserPALPalette[(i<<1)] = pixel; + } + + std::array secam; // All 8 24-bit pixels, plus 8 colorloss pixels + for(int i = 0; i < 8; i++) // SECAM palette + { + in.read(reinterpret_cast(pixbuf.data()), 3); + uInt32 pixel = (int(pixbuf[0]) << 16) + (int(pixbuf[1]) << 8) + int(pixbuf[2]); + secam[(i<<1)] = pixel; + secam[(i<<1)+1] = 0; + } + uInt32* ptr = ourUserSECAMPalette.data(); + for(int i = 0; i < 16; ++i) + { + const uInt32* s = secam.data(); + for(int j = 0; j < 16; ++j) + *ptr++ = *s++; + } + + myUserPaletteDefined = true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::generateCustomPalette(ConsoleTiming timing) +{ + constexpr int NUM_CHROMA = 16; + constexpr int NUM_LUMA = 8; + constexpr float SATURATION = 0.25F; + + float color[NUM_CHROMA][2] = {{0.0F}}; + + if(timing == ConsoleTiming::ntsc) + { + // YIQ is YUV shifted by 33° + constexpr float offset = 33 * (2 * BSPF::PI_f / 360); + const float shift = myOSystem.settings().getFloat("phase_ntsc") * + (2 * BSPF::PI_f / 360); + + // color 0 is grayscale + for(int chroma = 1; chroma < NUM_CHROMA; chroma++) + { + color[chroma][0] = SATURATION * sin(offset + shift * (chroma - 1)); + color[chroma][1] = SATURATION * sin(offset + shift * (chroma - 1 - BSPF::PI_f)); + } + + for(int chroma = 0; chroma < NUM_CHROMA; chroma++) + { + const float I = color[chroma][0]; + const float Q = color[chroma][1]; + + for(int luma = 0; luma < NUM_LUMA; luma++) + { + const float Y = 0.05F + luma / 8.24F; // 0.05..~0.90 + + float R = Y + 0.956F * I + 0.621F * Q; + float G = Y - 0.272F * I - 0.647F * Q; + float B = Y - 1.106F * I + 1.703F * Q; + + if(R < 0) R = 0; + if(G < 0) G = 0; + if(B < 0) B = 0; + + R = powf(R, 0.9F); + G = powf(G, 0.9F); + B = powf(B, 0.9F); + + if(R > 1) R = 1; + if(G > 1) G = 1; + if(B > 1) B = 1; + + int r = R * 255.F; + int g = G * 255.F; + int b = B * 255.F; + + ourCustomNTSCPalette[(chroma * NUM_LUMA + luma) << 1] = (r << 16) + (g << 8) + b; + } + } + } + else + { + constexpr float offset = 180 * (2 * BSPF::PI_f / 360); + float shift = myOSystem.settings().getFloat("phase_pal") * + (2 * BSPF::PI_f / 360); + constexpr float fixedShift = 22.5F * (2 * BSPF::PI_f / 360); + + // colors 0, 1, 14 and 15 are grayscale + for(int chroma = 2; chroma < NUM_CHROMA - 2; chroma++) + { + int idx = NUM_CHROMA - 1 - chroma; + color[idx][0] = SATURATION * sinf(offset - fixedShift * chroma); + if ((idx & 1) == 0) + color[idx][1] = SATURATION * sinf(offset - shift * (chroma - 3.5F) / 2.F); + else + color[idx][1] = SATURATION * -sinf(offset - shift * chroma / 2.F); + } + + for(int chroma = 0; chroma < NUM_CHROMA; chroma++) + { + const float U = color[chroma][0]; + const float V = color[chroma][1]; + + for(int luma = 0; luma < NUM_LUMA; luma++) + { + const float Y = 0.05F + luma / 8.24F; // 0.05..~0.90 + + // Most sources + float R = Y + 1.403F * V; + float G = Y - 0.344F * U - 0.714F * V; + float B = Y + 1.770F * U; + + // German Wikipedia, huh??? + //float B = Y + 1 / 0.493 * U; + //float R = Y + 1 / 0.877 * V; + //float G = 1.704 * Y - 0.590 * R - 0.194 * B; + + if(R < 0) R = 0.0; + if(G < 0) G = 0.0; + if(B < 0) B = 0.0; + + R = powf(R, 1.2F); + G = powf(G, 1.2F); + B = powf(B, 1.2F); + + if(R > 1) R = 1; + if(G > 1) G = 1; + if(B > 1) B = 1; + + int r = R * 255.F; + int g = G * 255.F; + int b = B * 255.F; + + ourCustomPALPalette[(chroma * NUM_LUMA + luma) << 1] = (r << 16) + (g << 8) + b; + } + } + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::changeSaturation(int& R, int& G, int& B, float change) +{ + // public-domain function by Darel Rex Finley + // + // The passed-in RGB values can be on any desired scale, such as 0 to + // to 1, or 0 to 255. (But use the same scale for all three!) + // + // The "change" parameter works like this: + // 0.0 creates a black-and-white image. + // 0.5 reduces the color saturation by half. + // 1.0 causes no change. + // 2.0 doubles the color saturation. + // Note: A "change" value greater than 1.0 may project your RGB values + // beyond their normal range, in which case you probably should truncate + // them to the desired range before trying to use them in an image. + constexpr float PR = .2989F; + constexpr float PG = .5870F; + constexpr float PB = .1140F; + + float P = sqrt(R * R * PR + G * G * PG + B * B * PB) ; + + R = P + (R - P) * change; + G = P + (G - P) * change; + B = P + (B - P) * change; + + R = BSPF::clamp(R, 0, 255); + G = BSPF::clamp(G, 0, 255); + B = BSPF::clamp(B, 0, 255); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::changeSaturation(float& R, float& G, float& B, float change) +{ + constexpr float PR = .2989F; + constexpr float PG = .5870F; + constexpr float PB = .1140F; + + float P = sqrt(R * R * PR + G * G * PG + B * B * PB) ; + + R = P + (R - P) * change; + G = P + (G - P) * change; + B = P + (B - P) * change; + + if(R < 0) R = 0; + if(G < 0) G = 0; + if(B < 0) B = 0; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::generateColorLossPalette() +{ + // Look at all the palettes, since we don't know which one is + // currently active + std::array palette = { + ourNTSCPalette.data(), ourPALPalette.data(), ourSECAMPalette.data(), + ourNTSCPaletteZ26.data(), ourPALPaletteZ26.data(), ourSECAMPaletteZ26.data(), + nullptr, nullptr, nullptr, + ourCustomNTSCPalette.data(), ourCustomPALPalette.data(), ourSECAMPalette.data(), + }; + + if(myUserPaletteDefined) + { + int idx = PaletteType::User * int(ConsoleTiming::numTimings); + palette[idx + int(ConsoleTiming::ntsc)] = ourUserNTSCPalette.data(); + palette[idx + int(ConsoleTiming::pal)] = ourUserPALPalette.data(); + palette[idx + int(ConsoleTiming::secam)] = ourUserSECAMPalette.data(); + } + + for(int i = 0; i < int(ConsoleTiming::numTimings) * PaletteType::NumTypes; ++i) + { + if(palette[i] == nullptr) + continue; + + // Fill the odd numbered palette entries with gray values (calculated + // using the standard RGB -> grayscale conversion formula) + for(int j = 0; j < 128; ++j) + { + const uInt32 pixel = palette[i][(j<<1)]; + const uInt8 r = (pixel >> 16) & 0xff; + const uInt8 g = (pixel >> 8) & 0xff; + const uInt8 b = (pixel >> 0) & 0xff; + const uInt8 sum = static_cast((r * 0.2989) + (g * 0.5870) + (b * 0.1140)); + palette[i][(j<<1)+1] = (sum << 16) + (sum << 8) + sum; + } + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PaletteArray PaletteHandler::ourNTSCPalette = { + 0x000000, 0, 0x4a4a4a, 0, 0x6f6f6f, 0, 0x8e8e8e, 0, + 0xaaaaaa, 0, 0xc0c0c0, 0, 0xd6d6d6, 0, 0xececec, 0, + 0x484800, 0, 0x69690f, 0, 0x86861d, 0, 0xa2a22a, 0, + 0xbbbb35, 0, 0xd2d240, 0, 0xe8e84a, 0, 0xfcfc54, 0, + 0x7c2c00, 0, 0x904811, 0, 0xa26221, 0, 0xb47a30, 0, + 0xc3903d, 0, 0xd2a44a, 0, 0xdfb755, 0, 0xecc860, 0, + 0x901c00, 0, 0xa33915, 0, 0xb55328, 0, 0xc66c3a, 0, + 0xd5824a, 0, 0xe39759, 0, 0xf0aa67, 0, 0xfcbc74, 0, + 0x940000, 0, 0xa71a1a, 0, 0xb83232, 0, 0xc84848, 0, + 0xd65c5c, 0, 0xe46f6f, 0, 0xf08080, 0, 0xfc9090, 0, + 0x840064, 0, 0x97197a, 0, 0xa8308f, 0, 0xb846a2, 0, + 0xc659b3, 0, 0xd46cc3, 0, 0xe07cd2, 0, 0xec8ce0, 0, + 0x500084, 0, 0x68199a, 0, 0x7d30ad, 0, 0x9246c0, 0, + 0xa459d0, 0, 0xb56ce0, 0, 0xc57cee, 0, 0xd48cfc, 0, + 0x140090, 0, 0x331aa3, 0, 0x4e32b5, 0, 0x6848c6, 0, + 0x7f5cd5, 0, 0x956fe3, 0, 0xa980f0, 0, 0xbc90fc, 0, + 0x000094, 0, 0x181aa7, 0, 0x2d32b8, 0, 0x4248c8, 0, + 0x545cd6, 0, 0x656fe4, 0, 0x7580f0, 0, 0x8490fc, 0, + 0x001c88, 0, 0x183b9d, 0, 0x2d57b0, 0, 0x4272c2, 0, + 0x548ad2, 0, 0x65a0e1, 0, 0x75b5ef, 0, 0x84c8fc, 0, + 0x003064, 0, 0x185080, 0, 0x2d6d98, 0, 0x4288b0, 0, + 0x54a0c5, 0, 0x65b7d9, 0, 0x75cceb, 0, 0x84e0fc, 0, + 0x004030, 0, 0x18624e, 0, 0x2d8169, 0, 0x429e82, 0, + 0x54b899, 0, 0x65d1ae, 0, 0x75e7c2, 0, 0x84fcd4, 0, + 0x004400, 0, 0x1a661a, 0, 0x328432, 0, 0x48a048, 0, + 0x5cba5c, 0, 0x6fd26f, 0, 0x80e880, 0, 0x90fc90, 0, + 0x143c00, 0, 0x355f18, 0, 0x527e2d, 0, 0x6e9c42, 0, + 0x87b754, 0, 0x9ed065, 0, 0xb4e775, 0, 0xc8fc84, 0, + 0x303800, 0, 0x505916, 0, 0x6d762b, 0, 0x88923e, 0, + 0xa0ab4f, 0, 0xb7c25f, 0, 0xccd86e, 0, 0xe0ec7c, 0, + 0x482c00, 0, 0x694d14, 0, 0x866a26, 0, 0xa28638, 0, + 0xbb9f47, 0, 0xd2b656, 0, 0xe8cc63, 0, 0xfce070, 0 +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PaletteArray PaletteHandler::ourPALPalette = { + 0x000000, 0, 0x121212, 0, 0x242424, 0, 0x484848, 0, // 180 0 + 0x6c6c6c, 0, 0x909090, 0, 0xb4b4b4, 0, 0xd8d8d8, 0, // was 0x111111..0xcccccc + 0x000000, 0, 0x121212, 0, 0x242424, 0, 0x484848, 0, // 198 1 + 0x6c6c6c, 0, 0x909090, 0, 0xb4b4b4, 0, 0xd8d8d8, 0, + 0x1d0f00, 0, 0x3f2700, 0, 0x614900, 0, 0x836b01, 0, // 1b0 2 + 0xa58d23, 0, 0xc7af45, 0, 0xe9d167, 0, 0xffe789, 0, // was ..0xfff389 + 0x002400, 0, 0x004600, 0, 0x216800, 0, 0x438a07, 0, // 1c8 3 + 0x65ac29, 0, 0x87ce4b, 0, 0xa9f06d, 0, 0xcbff8f, 0, + 0x340000, 0, 0x561400, 0, 0x783602, 0, 0x9a5824, 0, // 1e0 4 + 0xbc7a46, 0, 0xde9c68, 0, 0xffbe8a, 0, 0xffd0ad, 0, // was ..0xffe0ac + 0x002700, 0, 0x004900, 0, 0x0c6b0c, 0, 0x2e8d2e, 0, // 1f8 5 + 0x50af50, 0, 0x72d172, 0, 0x94f394, 0, 0xb6ffb6, 0, + 0x3d0008, 0, 0x610511, 0, 0x832733, 0, 0xa54955, 0, // 210 6 + 0xc76b77, 0, 0xe98d99, 0, 0xffafbb, 0, 0xffd1d7, 0, // was 0x3f0000..0xffd1dd + 0x001e12, 0, 0x004228, 0, 0x046540, 0, 0x268762, 0, // 228 7 + 0x48a984, 0, 0x6acba6, 0, 0x8cedc8, 0, 0xafffe0, 0, // was 0x002100, 0x00431e..0xaeffff + 0x300025, 0, 0x5f0047, 0, 0x811e69, 0, 0xa3408b, 0, // 240 8 + 0xc562ad, 0, 0xe784cf, 0, 0xffa8ea, 0, 0xffc9f2, 0, // was ..0xffa6f1, 0xffc8ff + 0x001431, 0, 0x003653, 0, 0x0a5875, 0, 0x2c7a97, 0, // 258 9 + 0x4e9cb9, 0, 0x70bedb, 0, 0x92e0fd, 0, 0xb4ffff, 0, + 0x2c0052, 0, 0x4e0074, 0, 0x701d96, 0, 0x923fb8, 0, // 270 a + 0xb461da, 0, 0xd683fc, 0, 0xe2a5ff, 0, 0xeec9ff, 0, // was ..0xf8a5ff, 0xffc7ff + 0x001759, 0, 0x00247c, 0, 0x1d469e, 0, 0x3f68c0, 0, // 288 b + 0x618ae2, 0, 0x83acff, 0, 0xa5ceff, 0, 0xc7f0ff, 0, + 0x12006d, 0, 0x34038f, 0, 0x5625b1, 0, 0x7847d3, 0, // 2a0 c + 0x9a69f5, 0, 0xb48cff, 0, 0xc9adff, 0, 0xe1d1ff, 0, // was ..0xbc8bff, 0xdeadff, 0xffcfff, + 0x000070, 0, 0x161292, 0, 0x3834b4, 0, 0x5a56d6, 0, // 2b8 d + 0x7c78f8, 0, 0x9e9aff, 0, 0xc0bcff, 0, 0xe2deff, 0, + 0x000000, 0, 0x121212, 0, 0x242424, 0, 0x484848, 0, // 2d0 e + 0x6c6c6c, 0, 0x909090, 0, 0xb4b4b4, 0, 0xd8d8d8, 0, + 0x000000, 0, 0x121212, 0, 0x242424, 0, 0x484848, 0, // 2e8 f + 0x6c6c6c, 0, 0x909090, 0, 0xb4b4b4, 0, 0xd8d8d8, 0, +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PaletteArray PaletteHandler::ourSECAMPalette = { + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0 +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PaletteArray PaletteHandler::ourNTSCPaletteZ26 = { + 0x000000, 0, 0x505050, 0, 0x646464, 0, 0x787878, 0, + 0x8c8c8c, 0, 0xa0a0a0, 0, 0xb4b4b4, 0, 0xc8c8c8, 0, + 0x445400, 0, 0x586800, 0, 0x6c7c00, 0, 0x809000, 0, + 0x94a414, 0, 0xa8b828, 0, 0xbccc3c, 0, 0xd0e050, 0, + 0x673900, 0, 0x7b4d00, 0, 0x8f6100, 0, 0xa37513, 0, + 0xb78927, 0, 0xcb9d3b, 0, 0xdfb14f, 0, 0xf3c563, 0, + 0x7b2504, 0, 0x8f3918, 0, 0xa34d2c, 0, 0xb76140, 0, + 0xcb7554, 0, 0xdf8968, 0, 0xf39d7c, 0, 0xffb190, 0, + 0x7d122c, 0, 0x912640, 0, 0xa53a54, 0, 0xb94e68, 0, + 0xcd627c, 0, 0xe17690, 0, 0xf58aa4, 0, 0xff9eb8, 0, + 0x730871, 0, 0x871c85, 0, 0x9b3099, 0, 0xaf44ad, 0, + 0xc358c1, 0, 0xd76cd5, 0, 0xeb80e9, 0, 0xff94fd, 0, + 0x5d0b92, 0, 0x711fa6, 0, 0x8533ba, 0, 0x9947ce, 0, + 0xad5be2, 0, 0xc16ff6, 0, 0xd583ff, 0, 0xe997ff, 0, + 0x401599, 0, 0x5429ad, 0, 0x683dc1, 0, 0x7c51d5, 0, + 0x9065e9, 0, 0xa479fd, 0, 0xb88dff, 0, 0xcca1ff, 0, + 0x252593, 0, 0x3939a7, 0, 0x4d4dbb, 0, 0x6161cf, 0, + 0x7575e3, 0, 0x8989f7, 0, 0x9d9dff, 0, 0xb1b1ff, 0, + 0x0f3480, 0, 0x234894, 0, 0x375ca8, 0, 0x4b70bc, 0, + 0x5f84d0, 0, 0x7398e4, 0, 0x87acf8, 0, 0x9bc0ff, 0, + 0x04425a, 0, 0x18566e, 0, 0x2c6a82, 0, 0x407e96, 0, + 0x5492aa, 0, 0x68a6be, 0, 0x7cbad2, 0, 0x90cee6, 0, + 0x044f30, 0, 0x186344, 0, 0x2c7758, 0, 0x408b6c, 0, + 0x549f80, 0, 0x68b394, 0, 0x7cc7a8, 0, 0x90dbbc, 0, + 0x0f550a, 0, 0x23691e, 0, 0x377d32, 0, 0x4b9146, 0, + 0x5fa55a, 0, 0x73b96e, 0, 0x87cd82, 0, 0x9be196, 0, + 0x1f5100, 0, 0x336505, 0, 0x477919, 0, 0x5b8d2d, 0, + 0x6fa141, 0, 0x83b555, 0, 0x97c969, 0, 0xabdd7d, 0, + 0x344600, 0, 0x485a00, 0, 0x5c6e14, 0, 0x708228, 0, + 0x84963c, 0, 0x98aa50, 0, 0xacbe64, 0, 0xc0d278, 0, + 0x463e00, 0, 0x5a5205, 0, 0x6e6619, 0, 0x827a2d, 0, + 0x968e41, 0, 0xaaa255, 0, 0xbeb669, 0, 0xd2ca7d, 0 +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PaletteArray PaletteHandler::ourPALPaletteZ26 = { + 0x000000, 0, 0x4c4c4c, 0, 0x606060, 0, 0x747474, 0, + 0x888888, 0, 0x9c9c9c, 0, 0xb0b0b0, 0, 0xc4c4c4, 0, + 0x000000, 0, 0x4c4c4c, 0, 0x606060, 0, 0x747474, 0, + 0x888888, 0, 0x9c9c9c, 0, 0xb0b0b0, 0, 0xc4c4c4, 0, + 0x533a00, 0, 0x674e00, 0, 0x7b6203, 0, 0x8f7617, 0, + 0xa38a2b, 0, 0xb79e3f, 0, 0xcbb253, 0, 0xdfc667, 0, + 0x1b5800, 0, 0x2f6c00, 0, 0x438001, 0, 0x579415, 0, + 0x6ba829, 0, 0x7fbc3d, 0, 0x93d051, 0, 0xa7e465, 0, + 0x6a2900, 0, 0x7e3d12, 0, 0x925126, 0, 0xa6653a, 0, + 0xba794e, 0, 0xce8d62, 0, 0xe2a176, 0, 0xf6b58a, 0, + 0x075b00, 0, 0x1b6f11, 0, 0x2f8325, 0, 0x439739, 0, + 0x57ab4d, 0, 0x6bbf61, 0, 0x7fd375, 0, 0x93e789, 0, + 0x741b2f, 0, 0x882f43, 0, 0x9c4357, 0, 0xb0576b, 0, + 0xc46b7f, 0, 0xd87f93, 0, 0xec93a7, 0, 0xffa7bb, 0, + 0x00572e, 0, 0x106b42, 0, 0x247f56, 0, 0x38936a, 0, + 0x4ca77e, 0, 0x60bb92, 0, 0x74cfa6, 0, 0x88e3ba, 0, + 0x6d165f, 0, 0x812a73, 0, 0x953e87, 0, 0xa9529b, 0, + 0xbd66af, 0, 0xd17ac3, 0, 0xe58ed7, 0, 0xf9a2eb, 0, + 0x014c5e, 0, 0x156072, 0, 0x297486, 0, 0x3d889a, 0, + 0x519cae, 0, 0x65b0c2, 0, 0x79c4d6, 0, 0x8dd8ea, 0, + 0x5f1588, 0, 0x73299c, 0, 0x873db0, 0, 0x9b51c4, 0, + 0xaf65d8, 0, 0xc379ec, 0, 0xd78dff, 0, 0xeba1ff, 0, + 0x123b87, 0, 0x264f9b, 0, 0x3a63af, 0, 0x4e77c3, 0, + 0x628bd7, 0, 0x769feb, 0, 0x8ab3ff, 0, 0x9ec7ff, 0, + 0x451e9d, 0, 0x5932b1, 0, 0x6d46c5, 0, 0x815ad9, 0, + 0x956eed, 0, 0xa982ff, 0, 0xbd96ff, 0, 0xd1aaff, 0, + 0x2a2b9e, 0, 0x3e3fb2, 0, 0x5253c6, 0, 0x6667da, 0, + 0x7a7bee, 0, 0x8e8fff, 0, 0xa2a3ff, 0, 0xb6b7ff, 0, + 0x000000, 0, 0x4c4c4c, 0, 0x606060, 0, 0x747474, 0, + 0x888888, 0, 0x9c9c9c, 0, 0xb0b0b0, 0, 0xc4c4c4, 0, + 0x000000, 0, 0x4c4c4c, 0, 0x606060, 0, 0x747474, 0, + 0x888888, 0, 0x9c9c9c, 0, 0xb0b0b0, 0, 0xc4c4c4, 0 +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PaletteArray PaletteHandler::ourSECAMPaletteZ26 = { + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0 +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PaletteArray PaletteHandler::ourUserNTSCPalette = { 0 }; // filled from external file + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PaletteArray PaletteHandler::ourUserPALPalette = { 0 }; // filled from external file + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PaletteArray PaletteHandler::ourUserSECAMPalette = { 0 }; // filled from external file + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PaletteArray PaletteHandler::ourCustomNTSCPalette = { 0 }; // filled by function + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PaletteArray PaletteHandler::ourCustomPALPalette = { 0 }; // filled by function diff --git a/src/common/PaletteHandler.hxx b/src/common/PaletteHandler.hxx new file mode 100644 index 000000000..6b26b918a --- /dev/null +++ b/src/common/PaletteHandler.hxx @@ -0,0 +1,155 @@ +//============================================================================ +// +// 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 PALETTE_HANDLER_HXX +#define PALETTE_HANDLER_HXX + +#include "bspf.hxx" +#include "OSystem.hxx" + +class PaletteHandler +{ + public: + static constexpr const char* SETTING_STANDARD = "standard"; + static constexpr const char* SETTING_Z26 = "z26"; + static constexpr const char* SETTING_USER = "user"; + static constexpr const char* SETTING_CUSTOM = "custom"; + + enum DisplayType { + NTSC, + PAL, + SECAM, + NumDisplayTypes + }; + + + public: + PaletteHandler(OSystem& system); + virtual ~PaletteHandler() = default; + + /** + Switch between the available palettes. + */ + void changePalette(bool increase = true); + + + /** + Change the "phase shift" variable. + Note that there are two of these (NTSC and PAL). The currently + active mode will determine which one is used. + + @param increase increase if true, else decrease. + */ + void changeColorPhaseShift(bool increase = true); + + void changeSaturation(int& R, int& G, int& B, float change); + void changeSaturation(float& R, float& G, float& B, float change); + + /** + Sets the palette according to the given palette name. + + @param palette The palette to switch to. + */ + void setPalette(const string& name); + + + /** + Sets the palette from current settings. + */ + void setPalette(); + + + void generatePalettes(); + + /** + Loads all defined palettes with PAL color-loss data, even those that + normally can't have it enabled (NTSC), since it's also used for + 'greying out' the frame in the debugger. + */ + void generateColorLossPalette(); + + + /** + Generates a custom palette, based on user defined phase shifts. + */ + void generateCustomPalette(ConsoleTiming timing); + + private: + enum PaletteType { + Standard, + Z26, + User, + Custom, + NumTypes, + MinType = Standard, + MaxType = Custom + }; + + PaletteType toPaletteType(const string& name) const; + string toPaletteName(PaletteType type) const; + + PaletteArray adjustPalette(const PaletteArray& source); + + /** + Loads a user-defined palette file (from OSystem::paletteFile), filling the + appropriate user-defined palette arrays. + */ + void loadUserPalette(); + + + private: + OSystem& myOSystem; + + // range -1.0 to +1.0 (as in AtariNTSC) + float myContrast{0.0F}; + float myBrightness{0.0F}; + float myHue{0.0F}; + float mySaturation{0.0F}; + float myGamma{0.0F}; + + // Indicates whether an external palette was found and + // successfully loaded + bool myUserPaletteDefined{false}; + + // Table of RGB values for NTSC, PAL and SECAM + static PaletteArray ourNTSCPalette; + static PaletteArray ourPALPalette; + static PaletteArray ourSECAMPalette; + + // Table of RGB values for NTSC, PAL and SECAM - Z26 version + static PaletteArray ourNTSCPaletteZ26; + static PaletteArray ourPALPaletteZ26; + static PaletteArray ourSECAMPaletteZ26; + + // Table of RGB values for NTSC, PAL and SECAM - user-defined + static PaletteArray ourUserNTSCPalette; + static PaletteArray ourUserPALPalette; + static PaletteArray ourUserSECAMPalette; + + // Table of RGB values for NTSC, PAL - custom-defined + static PaletteArray ourCustomNTSCPalette; + static PaletteArray ourCustomPALPalette; + + private: + PaletteHandler() = delete; + PaletteHandler(const PaletteHandler&) = delete; + PaletteHandler(PaletteHandler&&) = delete; + PaletteHandler& operator=(const PaletteHandler&) = delete; + PaletteHandler& operator=(const PaletteHandler&&) = delete; +}; + +#endif // PALETTE_HANDLER_HXX diff --git a/src/common/module.mk b/src/common/module.mk index f7a228189..1aae6cd0a 100644 --- a/src/common/module.mk +++ b/src/common/module.mk @@ -11,6 +11,7 @@ MODULE_OBJS := \ src/common/Logger.o \ src/common/main.o \ src/common/MouseControl.o \ + src/common/PaletteHandler.o \ src/common/PhosphorHandler.o \ src/common/PhysicalJoystick.o \ src/common/PJoystickHandler.o \ diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 46078f09d..299b1ea3a 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -62,6 +62,7 @@ #include "AudioSettings.hxx" #include "frame-manager/FrameManager.hxx" #include "frame-manager/FrameLayoutDetector.hxx" +#include "PaletteHandler.hxx" #ifdef CHEATCODE_SUPPORT #include "CheatManager.hxx" @@ -81,19 +82,13 @@ Console::Console(OSystem& osystem, unique_ptr& cart, myCart(std::move(cart)), myAudioSettings(audioSettings) { - // Load user-defined palette for this ROM - loadUserPalette(); - - // Generate custom palette - generateCustomPalette(0); - generateCustomPalette(1); - // Create subsystems for the console my6502 = make_unique(myOSystem.settings()); myRiot = make_unique(*this, myOSystem.settings()); myTIA = make_unique(*this, [this]() { return timing(); }, myOSystem.settings()); myFrameManager = make_unique(); mySwitches = make_unique(myEvent, myProperties, myOSystem.settings()); + myPaletteHandler = make_unique(myOSystem); myTIA->setFrameManager(myFrameManager.get()); @@ -441,7 +436,7 @@ void Console::setFormat(uInt32 format) myConsoleInfo.DisplayFormat = myDisplayFormat + autodetected; - setPalette(myOSystem.settings().getString("palette")); + myPaletteHandler->setPalette(); setTIAProperties(); initializeVideo(); // takes care of refreshing the screen initializeAudio(); // ensure that audio synthesis is set up to match emulation speed @@ -477,96 +472,6 @@ void Console::enableColorLoss(bool state) myTIA->enableColorLoss(state); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int Console::getPaletteNum(const string& name) const -{ - if(name == "z26") - return PaletteType::Z26; - - if(name == "user" && myUserPaletteDefined) - return PaletteType::User; - - if(name == "custom") - return PaletteType::Custom; - - return PaletteType::Standard; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::togglePalette() -{ - string palette, message; - palette = myOSystem.settings().getString("palette"); - - if(palette == "standard") // switch to z26 - { - palette = "z26"; - message = "Z26 palette"; - } - else if(palette == "z26") // switch to user or standard - { - // If we have a user-defined palette, it will come next in - // the sequence; otherwise loop back to the standard one - if(myUserPaletteDefined) - { - palette = "user"; - message = "User-defined palette"; - } - else - { - palette = "custom"; - message = "Custom palette"; - } - } - else if(palette == "user") // switch to custom - { - palette = "custom"; - message = "Custom palette"; - } - else // switch to standard mode if we get this far - { - palette = "standard"; - message = "Standard Stella palette"; - } - - myOSystem.settings().setValue("palette", palette); - myOSystem.frameBuffer().showMessage(message); - - setPalette(palette); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::setPalette(const string& type) -{ - // Look at all the palettes, since we don't know which one is - // currently active - static constexpr BSPF::array2D palettes = {{ - { &ourNTSCPalette, &ourPALPalette, &ourSECAMPalette }, - { &ourNTSCPaletteZ26, &ourPALPaletteZ26, &ourSECAMPaletteZ26 }, - { &ourUserNTSCPalette, &ourUserPALPalette, &ourUserSECAMPalette }, - { &ourCustomNTSCPalette, &ourCustomPALPalette, &ourSECAMPalette } - }}; - - // See which format we should be using - int paletteNum = getPaletteNum(type); - - if(paletteNum == PaletteType::Custom) - { - - } - - // Now consider the current display format - const PaletteArray* palette = - (myDisplayFormat.compare(0, 3, "PAL") == 0) ? palettes[paletteNum][1] : - (myDisplayFormat.compare(0, 5, "SECAM") == 0) ? palettes[paletteNum][2] : - palettes[paletteNum][0]; - - myOSystem.frameBuffer().setTIAPalette(*palette); - - if(myTIA->usingFixedColors()) - myTIA->enableFixedColors(true); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::toggleInter() { @@ -677,11 +582,9 @@ FBInitStatus Console::initializeVideo(bool full) myOSystem.frameBuffer().showFrameStats( myOSystem.settings().getBool(devSettings ? "dev.stats" : "plr.stats")); - generateCustomPalette(0); - generateCustomPalette(1); - generateColorLossPalette(); + myPaletteHandler->generatePalettes(); } - setPalette(myOSystem.settings().getString("palette")); + myPaletteHandler->setPalette(); return fbstatus; } @@ -826,46 +729,6 @@ void Console::changeScanlineAdjust(int direction) myOSystem.frameBuffer().showMessage(ss.str()); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::changeColorPhaseShift(int direction) -{ - const char DEGREE = 0x1c; - const float NTSC_SHIFT = 26.2F; - const float PAL_SHIFT = 31.3F; // 360 / 11.5 - const bool isNTSC = myDisplayFormat == "NTSC" || myDisplayFormat == "NTSC50"; - const bool isPAL = myDisplayFormat == "PAL" || myDisplayFormat == "PAL60"; - - // SECAM is not supported - if(isNTSC || isPAL) - { - const string key = isNTSC ? "phase_ntsc" : "phase_pal"; - const float shift = isNTSC ? NTSC_SHIFT : PAL_SHIFT; - float phase = myOSystem.settings().getFloat(key); - - if(direction == +1) // increase color phase shift - { - phase += 0.3F; - phase = std::min(phase, shift + 4.5F); - } - else if(direction == -1) // decrease color phase shift - { - phase -= 0.3F; - phase = std::max(phase, shift - 4.5F); - } - myOSystem.settings().setValue(key, phase); - generateCustomPalette(isNTSC ? 0 : 1); - - myOSystem.settings().setValue("palette", "custom"); - setPalette("custom"); - - ostringstream ss; - ss << "Color phase shift at " - << std::fixed << std::setprecision(1) << phase << DEGREE; - - myOSystem.frameBuffer().showMessage(ss.str()); - } -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::setTIAProperties() { @@ -1073,202 +936,6 @@ unique_ptr Console::getControllerPort(const Controller::Type type, return controller; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::loadUserPalette() -{ - if (!myOSystem.checkUserPalette(true)) - return; - - const string& palette = myOSystem.paletteFile(); - ifstream in(palette, std::ios::binary); - - // Now that we have valid data, create the user-defined palettes - std::array pixbuf; // Temporary buffer for one 24-bit pixel - - for(int i = 0; i < 128; i++) // NTSC palette - { - in.read(reinterpret_cast(pixbuf.data()), 3); - uInt32 pixel = (int(pixbuf[0]) << 16) + (int(pixbuf[1]) << 8) + int(pixbuf[2]); - ourUserNTSCPalette[(i<<1)] = pixel; - } - for(int i = 0; i < 128; i++) // PAL palette - { - in.read(reinterpret_cast(pixbuf.data()), 3); - uInt32 pixel = (int(pixbuf[0]) << 16) + (int(pixbuf[1]) << 8) + int(pixbuf[2]); - ourUserPALPalette[(i<<1)] = pixel; - } - - std::array secam; // All 8 24-bit pixels, plus 8 colorloss pixels - for(int i = 0; i < 8; i++) // SECAM palette - { - in.read(reinterpret_cast(pixbuf.data()), 3); - uInt32 pixel = (int(pixbuf[0]) << 16) + (int(pixbuf[1]) << 8) + int(pixbuf[2]); - secam[(i<<1)] = pixel; - secam[(i<<1)+1] = 0; - } - uInt32* ptr = ourUserSECAMPalette.data(); - for(int i = 0; i < 16; ++i) - { - const uInt32* s = secam.data(); - for(int j = 0; j < 16; ++j) - *ptr++ = *s++; - } - - myUserPaletteDefined = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::generateCustomPalette(int type) -{ - constexpr int NUM_CHROMA = 16; - constexpr int NUM_LUMA = 8; - constexpr float SATURATION = 0.25F; - - float color[NUM_CHROMA][2] = {{0.0F}}; - - if(type == 0) - { - // YIQ is YUV shifted by 33° - constexpr float offset = 33 * (2 * BSPF::PI_f / 360); - const float shift = myOSystem.settings().getFloat("phase_ntsc") * - (2 * BSPF::PI_f / 360); - - // color 0 is grayscale - for(int chroma = 1; chroma < NUM_CHROMA; chroma++) - { - color[chroma][0] = SATURATION * sin(offset + shift * (chroma - 1)); - color[chroma][1] = SATURATION * sin(offset + shift * (chroma - 1 - BSPF::PI_f)); - } - - for(int chroma = 0; chroma < NUM_CHROMA; chroma++) - { - const float I = color[chroma][0]; - const float Q = color[chroma][1]; - - for(int luma = 0; luma < NUM_LUMA; luma++) - { - const float Y = 0.05F + luma / 8.24F; // 0.05..~0.90 - - float R = Y + 0.956F * I + 0.621F * Q; - float G = Y - 0.272F * I - 0.647F * Q; - float B = Y - 1.106F * I + 1.703F * Q; - - if(R < 0) R = 0; - if(G < 0) G = 0; - if(B < 0) B = 0; - - R = powf(R, 0.9F); - G = powf(G, 0.9F); - B = powf(B, 0.9F); - - if(R > 1) R = 1; - if(G > 1) G = 1; - if(B > 1) B = 1; - - int r = R * 255.F; - int g = G * 255.F; - int b = B * 255.F; - - ourCustomNTSCPalette[(chroma * NUM_LUMA + luma) << 1] = (r << 16) + (g << 8) + b; - } - } - } - else - { - constexpr float offset = 180 * (2 * BSPF::PI_f / 360); - float shift = myOSystem.settings().getFloat("phase_pal") * - (2 * BSPF::PI_f / 360); - constexpr float fixedShift = 22.5F * (2 * BSPF::PI_f / 360); - - // colors 0, 1, 14 and 15 are grayscale - for(int chroma = 2; chroma < NUM_CHROMA - 2; chroma++) - { - int idx = NUM_CHROMA - 1 - chroma; - color[idx][0] = SATURATION * sinf(offset - fixedShift * chroma); - if ((idx & 1) == 0) - color[idx][1] = SATURATION * sinf(offset - shift * (chroma - 3.5F) / 2.F); - else - color[idx][1] = SATURATION * -sinf(offset - shift * chroma / 2.F); - } - - for(int chroma = 0; chroma < NUM_CHROMA; chroma++) - { - const float U = color[chroma][0]; - const float V = color[chroma][1]; - - for(int luma = 0; luma < NUM_LUMA; luma++) - { - const float Y = 0.05F + luma / 8.24F; // 0.05..~0.90 - - // Most sources - float R = Y + 1.403F * V; - float G = Y - 0.344F * U - 0.714F * V; - float B = Y + 1.770F * U; - - // German Wikipedia, huh??? - //float B = Y + 1 / 0.493 * U; - //float R = Y + 1 / 0.877 * V; - //float G = 1.704 * Y - 0.590 * R - 0.194 * B; - - if(R < 0) R = 0.0; - if(G < 0) G = 0.0; - if(B < 0) B = 0.0; - - R = powf(R, 1.2); - G = powf(G, 1.2); - B = powf(B, 1.2); - - if(R > 1) R = 1; - if(G > 1) G = 1; - if(B > 1) B = 1; - - int r = R * 255.F; - int g = G * 255.F; - int b = B * 255.F; - - ourCustomPALPalette[(chroma * NUM_LUMA + luma) << 1] = (r << 16) + (g << 8) + b; - } - } - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::generateColorLossPalette() -{ - // Look at all the palettes, since we don't know which one is - // currently active - std::array palette = { - ourNTSCPalette.data(), ourPALPalette.data(), ourSECAMPalette.data(), - ourNTSCPaletteZ26.data(), ourPALPaletteZ26.data(), ourSECAMPaletteZ26.data(), - nullptr, nullptr, nullptr, - ourCustomNTSCPalette.data(), ourCustomPALPalette.data(), ourSECAMPalette.data(), - }; - if(myUserPaletteDefined) - { - palette[6] = ourUserNTSCPalette.data(); - palette[7] = ourUserPALPalette.data(); - palette[8] = ourUserSECAMPalette.data(); - } - - for(int i = 0; i < 3 * PaletteType::NumTypes; ++i) - { - if(palette[i] == nullptr) - continue; - - // Fill the odd numbered palette entries with gray values (calculated - // using the standard RGB -> grayscale conversion formula) - for(int j = 0; j < 128; ++j) - { - const uInt32 pixel = palette[i][(j<<1)]; - const uInt8 r = (pixel >> 16) & 0xff; - const uInt8 g = (pixel >> 8) & 0xff; - const uInt8 b = (pixel >> 0) & 0xff; - const uInt8 sum = static_cast((r * 0.2989) + (g * 0.5870) + (b * 0.1140)); - palette[i][(j<<1)+1] = (sum << 16) + (sum << 8) + sum; - } - } -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - float Console::getFramerate() const { @@ -1340,234 +1007,3 @@ void Console::stateChanged(EventHandlerState state) { // only the CompuMate used to care about state changes } - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray Console::ourNTSCPalette = { - 0x000000, 0, 0x4a4a4a, 0, 0x6f6f6f, 0, 0x8e8e8e, 0, - 0xaaaaaa, 0, 0xc0c0c0, 0, 0xd6d6d6, 0, 0xececec, 0, - 0x484800, 0, 0x69690f, 0, 0x86861d, 0, 0xa2a22a, 0, - 0xbbbb35, 0, 0xd2d240, 0, 0xe8e84a, 0, 0xfcfc54, 0, - 0x7c2c00, 0, 0x904811, 0, 0xa26221, 0, 0xb47a30, 0, - 0xc3903d, 0, 0xd2a44a, 0, 0xdfb755, 0, 0xecc860, 0, - 0x901c00, 0, 0xa33915, 0, 0xb55328, 0, 0xc66c3a, 0, - 0xd5824a, 0, 0xe39759, 0, 0xf0aa67, 0, 0xfcbc74, 0, - 0x940000, 0, 0xa71a1a, 0, 0xb83232, 0, 0xc84848, 0, - 0xd65c5c, 0, 0xe46f6f, 0, 0xf08080, 0, 0xfc9090, 0, - 0x840064, 0, 0x97197a, 0, 0xa8308f, 0, 0xb846a2, 0, - 0xc659b3, 0, 0xd46cc3, 0, 0xe07cd2, 0, 0xec8ce0, 0, - 0x500084, 0, 0x68199a, 0, 0x7d30ad, 0, 0x9246c0, 0, - 0xa459d0, 0, 0xb56ce0, 0, 0xc57cee, 0, 0xd48cfc, 0, - 0x140090, 0, 0x331aa3, 0, 0x4e32b5, 0, 0x6848c6, 0, - 0x7f5cd5, 0, 0x956fe3, 0, 0xa980f0, 0, 0xbc90fc, 0, - 0x000094, 0, 0x181aa7, 0, 0x2d32b8, 0, 0x4248c8, 0, - 0x545cd6, 0, 0x656fe4, 0, 0x7580f0, 0, 0x8490fc, 0, - 0x001c88, 0, 0x183b9d, 0, 0x2d57b0, 0, 0x4272c2, 0, - 0x548ad2, 0, 0x65a0e1, 0, 0x75b5ef, 0, 0x84c8fc, 0, - 0x003064, 0, 0x185080, 0, 0x2d6d98, 0, 0x4288b0, 0, - 0x54a0c5, 0, 0x65b7d9, 0, 0x75cceb, 0, 0x84e0fc, 0, - 0x004030, 0, 0x18624e, 0, 0x2d8169, 0, 0x429e82, 0, - 0x54b899, 0, 0x65d1ae, 0, 0x75e7c2, 0, 0x84fcd4, 0, - 0x004400, 0, 0x1a661a, 0, 0x328432, 0, 0x48a048, 0, - 0x5cba5c, 0, 0x6fd26f, 0, 0x80e880, 0, 0x90fc90, 0, - 0x143c00, 0, 0x355f18, 0, 0x527e2d, 0, 0x6e9c42, 0, - 0x87b754, 0, 0x9ed065, 0, 0xb4e775, 0, 0xc8fc84, 0, - 0x303800, 0, 0x505916, 0, 0x6d762b, 0, 0x88923e, 0, - 0xa0ab4f, 0, 0xb7c25f, 0, 0xccd86e, 0, 0xe0ec7c, 0, - 0x482c00, 0, 0x694d14, 0, 0x866a26, 0, 0xa28638, 0, - 0xbb9f47, 0, 0xd2b656, 0, 0xe8cc63, 0, 0xfce070, 0 -}; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray Console::ourPALPalette = { - 0x000000, 0, 0x121212, 0, 0x242424, 0, 0x484848, 0, // 180 0 - 0x6c6c6c, 0, 0x909090, 0, 0xb4b4b4, 0, 0xd8d8d8, 0, // was 0x111111..0xcccccc - 0x000000, 0, 0x121212, 0, 0x242424, 0, 0x484848, 0, // 198 1 - 0x6c6c6c, 0, 0x909090, 0, 0xb4b4b4, 0, 0xd8d8d8, 0, - 0x1d0f00, 0, 0x3f2700, 0, 0x614900, 0, 0x836b01, 0, // 1b0 2 - 0xa58d23, 0, 0xc7af45, 0, 0xe9d167, 0, 0xffe789, 0, // was ..0xfff389 - 0x002400, 0, 0x004600, 0, 0x216800, 0, 0x438a07, 0, // 1c8 3 - 0x65ac29, 0, 0x87ce4b, 0, 0xa9f06d, 0, 0xcbff8f, 0, - 0x340000, 0, 0x561400, 0, 0x783602, 0, 0x9a5824, 0, // 1e0 4 - 0xbc7a46, 0, 0xde9c68, 0, 0xffbe8a, 0, 0xffd0ad, 0, // was ..0xffe0ac - 0x002700, 0, 0x004900, 0, 0x0c6b0c, 0, 0x2e8d2e, 0, // 1f8 5 - 0x50af50, 0, 0x72d172, 0, 0x94f394, 0, 0xb6ffb6, 0, - 0x3d0008, 0, 0x610511, 0, 0x832733, 0, 0xa54955, 0, // 210 6 - 0xc76b77, 0, 0xe98d99, 0, 0xffafbb, 0, 0xffd1d7, 0, // was 0x3f0000..0xffd1dd - 0x001e12, 0, 0x004228, 0, 0x046540, 0, 0x268762, 0, // 228 7 - 0x48a984, 0, 0x6acba6, 0, 0x8cedc8, 0, 0xafffe0, 0, // was 0x002100, 0x00431e..0xaeffff - 0x300025, 0, 0x5f0047, 0, 0x811e69, 0, 0xa3408b, 0, // 240 8 - 0xc562ad, 0, 0xe784cf, 0, 0xffa8ea, 0, 0xffc9f2, 0, // was ..0xffa6f1, 0xffc8ff - 0x001431, 0, 0x003653, 0, 0x0a5875, 0, 0x2c7a97, 0, // 258 9 - 0x4e9cb9, 0, 0x70bedb, 0, 0x92e0fd, 0, 0xb4ffff, 0, - 0x2c0052, 0, 0x4e0074, 0, 0x701d96, 0, 0x923fb8, 0, // 270 a - 0xb461da, 0, 0xd683fc, 0, 0xe2a5ff, 0, 0xeec9ff, 0, // was ..0xf8a5ff, 0xffc7ff - 0x001759, 0, 0x00247c, 0, 0x1d469e, 0, 0x3f68c0, 0, // 288 b - 0x618ae2, 0, 0x83acff, 0, 0xa5ceff, 0, 0xc7f0ff, 0, - 0x12006d, 0, 0x34038f, 0, 0x5625b1, 0, 0x7847d3, 0, // 2a0 c - 0x9a69f5, 0, 0xb48cff, 0, 0xc9adff, 0, 0xe1d1ff, 0, // was ..0xbc8bff, 0xdeadff, 0xffcfff, - 0x000070, 0, 0x161292, 0, 0x3834b4, 0, 0x5a56d6, 0, // 2b8 d - 0x7c78f8, 0, 0x9e9aff, 0, 0xc0bcff, 0, 0xe2deff, 0, - 0x000000, 0, 0x121212, 0, 0x242424, 0, 0x484848, 0, // 2d0 e - 0x6c6c6c, 0, 0x909090, 0, 0xb4b4b4, 0, 0xd8d8d8, 0, - 0x000000, 0, 0x121212, 0, 0x242424, 0, 0x484848, 0, // 2e8 f - 0x6c6c6c, 0, 0x909090, 0, 0xb4b4b4, 0, 0xd8d8d8, 0, -}; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray Console::ourSECAMPalette = { - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0 -}; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray Console::ourNTSCPaletteZ26 = { - 0x000000, 0, 0x505050, 0, 0x646464, 0, 0x787878, 0, - 0x8c8c8c, 0, 0xa0a0a0, 0, 0xb4b4b4, 0, 0xc8c8c8, 0, - 0x445400, 0, 0x586800, 0, 0x6c7c00, 0, 0x809000, 0, - 0x94a414, 0, 0xa8b828, 0, 0xbccc3c, 0, 0xd0e050, 0, - 0x673900, 0, 0x7b4d00, 0, 0x8f6100, 0, 0xa37513, 0, - 0xb78927, 0, 0xcb9d3b, 0, 0xdfb14f, 0, 0xf3c563, 0, - 0x7b2504, 0, 0x8f3918, 0, 0xa34d2c, 0, 0xb76140, 0, - 0xcb7554, 0, 0xdf8968, 0, 0xf39d7c, 0, 0xffb190, 0, - 0x7d122c, 0, 0x912640, 0, 0xa53a54, 0, 0xb94e68, 0, - 0xcd627c, 0, 0xe17690, 0, 0xf58aa4, 0, 0xff9eb8, 0, - 0x730871, 0, 0x871c85, 0, 0x9b3099, 0, 0xaf44ad, 0, - 0xc358c1, 0, 0xd76cd5, 0, 0xeb80e9, 0, 0xff94fd, 0, - 0x5d0b92, 0, 0x711fa6, 0, 0x8533ba, 0, 0x9947ce, 0, - 0xad5be2, 0, 0xc16ff6, 0, 0xd583ff, 0, 0xe997ff, 0, - 0x401599, 0, 0x5429ad, 0, 0x683dc1, 0, 0x7c51d5, 0, - 0x9065e9, 0, 0xa479fd, 0, 0xb88dff, 0, 0xcca1ff, 0, - 0x252593, 0, 0x3939a7, 0, 0x4d4dbb, 0, 0x6161cf, 0, - 0x7575e3, 0, 0x8989f7, 0, 0x9d9dff, 0, 0xb1b1ff, 0, - 0x0f3480, 0, 0x234894, 0, 0x375ca8, 0, 0x4b70bc, 0, - 0x5f84d0, 0, 0x7398e4, 0, 0x87acf8, 0, 0x9bc0ff, 0, - 0x04425a, 0, 0x18566e, 0, 0x2c6a82, 0, 0x407e96, 0, - 0x5492aa, 0, 0x68a6be, 0, 0x7cbad2, 0, 0x90cee6, 0, - 0x044f30, 0, 0x186344, 0, 0x2c7758, 0, 0x408b6c, 0, - 0x549f80, 0, 0x68b394, 0, 0x7cc7a8, 0, 0x90dbbc, 0, - 0x0f550a, 0, 0x23691e, 0, 0x377d32, 0, 0x4b9146, 0, - 0x5fa55a, 0, 0x73b96e, 0, 0x87cd82, 0, 0x9be196, 0, - 0x1f5100, 0, 0x336505, 0, 0x477919, 0, 0x5b8d2d, 0, - 0x6fa141, 0, 0x83b555, 0, 0x97c969, 0, 0xabdd7d, 0, - 0x344600, 0, 0x485a00, 0, 0x5c6e14, 0, 0x708228, 0, - 0x84963c, 0, 0x98aa50, 0, 0xacbe64, 0, 0xc0d278, 0, - 0x463e00, 0, 0x5a5205, 0, 0x6e6619, 0, 0x827a2d, 0, - 0x968e41, 0, 0xaaa255, 0, 0xbeb669, 0, 0xd2ca7d, 0 -}; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray Console::ourPALPaletteZ26 = { - 0x000000, 0, 0x4c4c4c, 0, 0x606060, 0, 0x747474, 0, - 0x888888, 0, 0x9c9c9c, 0, 0xb0b0b0, 0, 0xc4c4c4, 0, - 0x000000, 0, 0x4c4c4c, 0, 0x606060, 0, 0x747474, 0, - 0x888888, 0, 0x9c9c9c, 0, 0xb0b0b0, 0, 0xc4c4c4, 0, - 0x533a00, 0, 0x674e00, 0, 0x7b6203, 0, 0x8f7617, 0, - 0xa38a2b, 0, 0xb79e3f, 0, 0xcbb253, 0, 0xdfc667, 0, - 0x1b5800, 0, 0x2f6c00, 0, 0x438001, 0, 0x579415, 0, - 0x6ba829, 0, 0x7fbc3d, 0, 0x93d051, 0, 0xa7e465, 0, - 0x6a2900, 0, 0x7e3d12, 0, 0x925126, 0, 0xa6653a, 0, - 0xba794e, 0, 0xce8d62, 0, 0xe2a176, 0, 0xf6b58a, 0, - 0x075b00, 0, 0x1b6f11, 0, 0x2f8325, 0, 0x439739, 0, - 0x57ab4d, 0, 0x6bbf61, 0, 0x7fd375, 0, 0x93e789, 0, - 0x741b2f, 0, 0x882f43, 0, 0x9c4357, 0, 0xb0576b, 0, - 0xc46b7f, 0, 0xd87f93, 0, 0xec93a7, 0, 0xffa7bb, 0, - 0x00572e, 0, 0x106b42, 0, 0x247f56, 0, 0x38936a, 0, - 0x4ca77e, 0, 0x60bb92, 0, 0x74cfa6, 0, 0x88e3ba, 0, - 0x6d165f, 0, 0x812a73, 0, 0x953e87, 0, 0xa9529b, 0, - 0xbd66af, 0, 0xd17ac3, 0, 0xe58ed7, 0, 0xf9a2eb, 0, - 0x014c5e, 0, 0x156072, 0, 0x297486, 0, 0x3d889a, 0, - 0x519cae, 0, 0x65b0c2, 0, 0x79c4d6, 0, 0x8dd8ea, 0, - 0x5f1588, 0, 0x73299c, 0, 0x873db0, 0, 0x9b51c4, 0, - 0xaf65d8, 0, 0xc379ec, 0, 0xd78dff, 0, 0xeba1ff, 0, - 0x123b87, 0, 0x264f9b, 0, 0x3a63af, 0, 0x4e77c3, 0, - 0x628bd7, 0, 0x769feb, 0, 0x8ab3ff, 0, 0x9ec7ff, 0, - 0x451e9d, 0, 0x5932b1, 0, 0x6d46c5, 0, 0x815ad9, 0, - 0x956eed, 0, 0xa982ff, 0, 0xbd96ff, 0, 0xd1aaff, 0, - 0x2a2b9e, 0, 0x3e3fb2, 0, 0x5253c6, 0, 0x6667da, 0, - 0x7a7bee, 0, 0x8e8fff, 0, 0xa2a3ff, 0, 0xb6b7ff, 0, - 0x000000, 0, 0x4c4c4c, 0, 0x606060, 0, 0x747474, 0, - 0x888888, 0, 0x9c9c9c, 0, 0xb0b0b0, 0, 0xc4c4c4, 0, - 0x000000, 0, 0x4c4c4c, 0, 0x606060, 0, 0x747474, 0, - 0x888888, 0, 0x9c9c9c, 0, 0xb0b0b0, 0, 0xc4c4c4, 0 -}; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray Console::ourSECAMPaletteZ26 = { - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0 -}; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray Console::ourUserNTSCPalette = { 0 }; // filled from external file - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray Console::ourUserPALPalette = { 0 }; // filled from external file - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray Console::ourUserSECAMPalette = { 0 }; // filled from external file - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray Console::ourCustomNTSCPalette = { 0 }; // filled by function - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray Console::ourCustomPALPalette = { 0 }; // filled by function diff --git a/src/emucore/Console.hxx b/src/emucore/Console.hxx index 9ff4b002c..36c680539 100644 --- a/src/emucore/Console.hxx +++ b/src/emucore/Console.hxx @@ -29,6 +29,7 @@ class CompuMate; class Debugger; class AudioQueue; class AudioSettings; +class PaletteHandler; #include "bspf.hxx" #include "ConsoleIO.hxx" @@ -186,6 +187,11 @@ class Console : public Serializable, public ConsoleIO */ EmulationTiming& emulationTiming() { return myEmulationTiming; } + /** + Retrieve palette handler. + */ + PaletteHandler& paletteHandler() const { return *myPaletteHandler; } + public: /** Toggle between NTSC/PAL/SECAM (and variants) display format. @@ -204,23 +210,6 @@ class Console : public Serializable, public ConsoleIO */ string getFormatString() const { return myDisplayFormat; } - /** - Toggle between the available palettes. - */ - void togglePalette(); - - /** - Generates a custom palette, based on user defined phase shifts. - */ - void generateCustomPalette(int type); - - /** - Sets the palette according to the given palette name. - - @param palette The palette to switch to. - */ - void setPalette(const string& palette); - /** Toggle interpolation on/off */ @@ -288,16 +277,6 @@ class Console : public Serializable, public ConsoleIO */ void changeScanlineAdjust(int direction); - /** - Change the "phase shift" variable. - Note that there are two of these (NTSC and PAL). The currently - active mode will determine which one is used. - - @param direction +1 indicates increase, -1 indicates decrease. - - */ - void changeColorPhaseShift(int direction); - /** Returns the current framerate. */ @@ -379,35 +358,10 @@ class Console : public Serializable, public ConsoleIO unique_ptr getControllerPort(const Controller::Type type, const Controller::Jack port, const string& romMd5); - /** - Loads a user-defined palette file (from OSystem::paletteFile), filling the - appropriate user-defined palette arrays. - */ - void loadUserPalette(); - - /** - Loads all defined palettes with PAL color-loss data, even those that - normally can't have it enabled (NTSC), since it's also used for - 'greying out' the frame in the debugger. - */ - void generateColorLossPalette(); - - int getPaletteNum(const string& name) const; - - void toggleTIABit(TIABit bit, const string& bitname, bool show = true) const; void toggleTIACollision(TIABit bit, const string& bitname, bool show = true) const; private: - - enum PaletteType { - Standard, - Z26, - User, - Custom, - NumTypes - }; - // Reference to the osystem object OSystem& myOSystem; @@ -457,10 +411,6 @@ class Console : public Serializable, public ConsoleIO // Is the TV format autodetected? bool myFormatAutodetected{false}; - // Indicates whether an external palette was found and - // successfully loaded - bool myUserPaletteDefined{false}; - // Contains detailed info about this console ConsoleInfo myConsoleInfo; @@ -474,24 +424,8 @@ class Console : public Serializable, public ConsoleIO // The audio settings AudioSettings& myAudioSettings; - // Table of RGB values for NTSC, PAL and SECAM - static PaletteArray ourNTSCPalette; - static PaletteArray ourPALPalette; - static PaletteArray ourSECAMPalette; - - // Table of RGB values for NTSC, PAL and SECAM - Z26 version - static PaletteArray ourNTSCPaletteZ26; - static PaletteArray ourPALPaletteZ26; - static PaletteArray ourSECAMPaletteZ26; - - // Table of RGB values for NTSC, PAL and SECAM - user-defined - static PaletteArray ourUserNTSCPalette; - static PaletteArray ourUserPALPalette; - static PaletteArray ourUserSECAMPalette; - - // Table of RGB values for NTSC, PAL - custom-defined - static PaletteArray ourCustomNTSCPalette; - static PaletteArray ourCustomPALPalette; + // The palette handling + unique_ptrmyPaletteHandler; private: // Following constructors and assignment operators not supported diff --git a/src/emucore/ConsoleTiming.hxx b/src/emucore/ConsoleTiming.hxx index 1f75db469..fd43caa98 100644 --- a/src/emucore/ConsoleTiming.hxx +++ b/src/emucore/ConsoleTiming.hxx @@ -25,7 +25,8 @@ enum class ConsoleTiming { ntsc, // console with CPU running at 1.193182 MHz, NTSC colours pal, // console with CPU running at 1.182298 MHz, PAL colours - secam // console with CPU running at 1.187500 MHz, SECAM colours + secam, // console with CPU running at 1.187500 MHz, SECAM colours + numTimings }; #endif // CONSOLE_TIMING_HXX diff --git a/src/emucore/Event.hxx b/src/emucore/Event.hxx index 915461e97..5dbb71126 100644 --- a/src/emucore/Event.hxx +++ b/src/emucore/Event.hxx @@ -100,7 +100,7 @@ class Event Unwind1Menu, Unwind10Menu, UnwindAllMenu, RewindPause, UnwindPause, - FormatDecrease, FormatIncrease, TogglePalette, ToggleColorLoss, + FormatDecrease, FormatIncrease, PaletteIncrease, ToggleColorLoss, ToggleFullScreen, VidmodeDecrease, VidmodeIncrease, VCenterDecrease, VCenterIncrease, ScanlineAdjustDecrease, ScanlineAdjustIncrease, OverscanDecrease, OverscanIncrease, @@ -120,7 +120,7 @@ class Event ToggleFrameStats, ToggleSAPortOrder, ExitGame, // add new events from here to avoid that user remapped events get overwritten - ToggleTurbo, + ToggleTurbo, PaletteDecrease, ColorShiftDecrease, ColorShiftIncrease, LastType diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index c9fa85835..04dd852d0 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -22,6 +22,7 @@ #include "Base.hxx" #include "Console.hxx" +#include "PaletteHandler.hxx" #include "FrameBuffer.hxx" #include "FSNode.hxx" #include "OSystem.hxx" @@ -436,11 +437,11 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::ColorShiftDecrease: - if (pressed) myOSystem.console().changeColorPhaseShift(-1); + if (pressed) myOSystem.console().paletteHandler().changeColorPhaseShift(false); return; case Event::ColorShiftIncrease: - if (pressed) myOSystem.console().changeColorPhaseShift(+1); + if (pressed) myOSystem.console().paletteHandler().changeColorPhaseShift(); return; case Event::ToggleFullScreen: @@ -539,8 +540,12 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) if (pressed && !repeated) myOSystem.console().toggleColorLoss(); return; - case Event::TogglePalette: - if (pressed && !repeated) myOSystem.console().togglePalette(); + case Event::PaletteDecrease: + if (pressed && !repeated) myOSystem.console().paletteHandler().changePalette(false); + return; + + case Event::PaletteIncrease: + if (pressed && !repeated) myOSystem.console().paletteHandler().changePalette(); return; case Event::ToggleInter: @@ -1929,7 +1934,8 @@ EventHandler::EmulActionList EventHandler::ourEmulActionList = { { { Event::VCenterIncrease, "Move display down", "" }, { Event::FormatDecrease, "Decrease display format", "" }, { Event::FormatIncrease, "Increase display format", "" }, - { Event::TogglePalette, "Switch palette (Std./Z26/User/Cust.)", "" }, + { Event::PaletteDecrease, "Switch to previous palette", "" }, + { Event::PaletteIncrease, "Switch to next palette", "" }, { Event::ColorShiftDecrease, "Decrease custom palette phase shift", "" }, { Event::ColorShiftIncrease, "Increase custom palette phase shift", "" }, { Event::ToggleInter, "Toggle display interpolation", "" }, @@ -2058,7 +2064,8 @@ const Event::EventSet EventHandler::AudioVideoEvents = { Event::VCenterDecrease, Event::VCenterIncrease, Event::ScanlineAdjustDecrease, Event::ScanlineAdjustIncrease, Event::OverscanDecrease, Event::OverscanIncrease, - Event::TogglePalette, Event::ColorShiftDecrease, Event::ColorShiftIncrease, + Event::PaletteDecrease, Event::PaletteIncrease, + Event::ColorShiftDecrease, Event::ColorShiftIncrease, Event::ToggleInter }; diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx index 8fe4c7821..10259780a 100644 --- a/src/emucore/EventHandler.hxx +++ b/src/emucore/EventHandler.hxx @@ -468,7 +468,7 @@ class EventHandler #else PNG_SIZE = 0, #endif - EMUL_ACTIONLIST_SIZE = 149 + PNG_SIZE + COMBO_SIZE, + EMUL_ACTIONLIST_SIZE = 150 + PNG_SIZE + COMBO_SIZE, MENU_ACTIONLIST_SIZE = 18 ; diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index c1c64dd20..a8100d99d 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -64,12 +64,12 @@ Settings::Settings() setPermanent("tv.phosphor", "byrom"); setPermanent("tv.phosblend", "50"); setPermanent("tv.scanlines", "25"); - // TV options when using 'custom' mode setPermanent("tv.contrast", "0.0"); setPermanent("tv.brightness", "0.0"); setPermanent("tv.hue", "0.0"); setPermanent("tv.saturation", "0.0"); setPermanent("tv.gamma", "0.0"); + // TV options when using 'custom' mode setPermanent("tv.sharpness", "0.0"); setPermanent("tv.resolution", "0.0"); setPermanent("tv.artifacts", "0.0"); diff --git a/src/gui/CommandDialog.cxx b/src/gui/CommandDialog.cxx index 5c734a52e..9efa56a7b 100644 --- a/src/gui/CommandDialog.cxx +++ b/src/gui/CommandDialog.cxx @@ -16,6 +16,7 @@ //============================================================================ #include "Console.hxx" +#include "PaletteHandler.hxx" #include "TIA.hxx" #include "Switches.hxx" #include "Dialog.hxx" @@ -203,7 +204,7 @@ void CommandDialog::handleCommand(CommandSender* sender, int cmd, break; case kPaletteCmd: - instance().console().togglePalette(); + instance().console().paletteHandler().changePalette(); updatePalette(); break; diff --git a/src/gui/HelpDialog.cxx b/src/gui/HelpDialog.cxx index 5c9a6b1d3..77c01f174 100644 --- a/src/gui/HelpDialog.cxx +++ b/src/gui/HelpDialog.cxx @@ -121,7 +121,7 @@ void HelpDialog::updateStrings(uInt8 page, uInt8 lines, string& title) case 2: title = "Special commands"; ADD_EVENT(Event::FormatIncrease, "Switch between NTSC/PAL/SECAM"); - ADD_EVENT(Event::TogglePalette, "Switch palette"); + ADD_EVENT(Event::PaletteIncrease, "Switch to next palette"); ADD_EVENT(Event::TogglePhosphor, "Toggle 'phosphor' effect"); ADD_LINE(); ADD_EVENT(Event::ToggleGrabMouse, "Grab mouse (keep in window)"); diff --git a/src/gui/VideoDialog.cxx b/src/gui/VideoDialog.cxx index 30b7a6ccc..606553562 100644 --- a/src/gui/VideoDialog.cxx +++ b/src/gui/VideoDialog.cxx @@ -25,6 +25,7 @@ #include "EditTextWidget.hxx" #include "PopUpWidget.hxx" #include "Console.hxx" +#include "PaletteHandler.hxx" #include "TIA.hxx" #include "Settings.hxx" #include "Widget.hxx" @@ -519,8 +520,8 @@ void VideoDialog::saveConfig() if(instance().settings().getString("palette") == "custom") { - instance().console().generateCustomPalette(0); - instance().console().generateCustomPalette(1); + instance().console().paletteHandler().generateCustomPalette(ConsoleTiming::ntsc); + instance().console().paletteHandler().generateCustomPalette(ConsoleTiming::pal); } if(vsizeChanged) diff --git a/src/windows/Stella.vcxproj b/src/windows/Stella.vcxproj index 1095f2c09..bc0724d09 100644 --- a/src/windows/Stella.vcxproj +++ b/src/windows/Stella.vcxproj @@ -503,6 +503,7 @@ + @@ -1503,6 +1504,7 @@ + diff --git a/src/windows/Stella.vcxproj.filters b/src/windows/Stella.vcxproj.filters index fb763da4c..62e324fa4 100644 --- a/src/windows/Stella.vcxproj.filters +++ b/src/windows/Stella.vcxproj.filters @@ -1002,6 +1002,9 @@ Source Files\emucore + + Source Files +
      @@ -2057,6 +2060,9 @@ Header Files\emucore + + Header Files + From 2a521200ad9b9cae73dff08a38655dc45e771b73 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sat, 9 May 2020 15:13:08 -0230 Subject: [PATCH 189/377] Don't create an array of size 0. --- src/emucore/CartEnhanced.cxx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index f5c38c9a3..0bd964890 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -52,7 +52,8 @@ void CartridgeEnhanced::install(System& system) myCurrentSegOffset = make_unique(myBankSegs); // Allocate array for the RAM area - myRAM = make_unique(myRamSize); + if(myRamSize > 0) + myRAM = make_unique(myRamSize); mySystem = &system; @@ -101,7 +102,8 @@ void CartridgeEnhanced::install(System& system) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeEnhanced::reset() { - initializeRAM(myRAM.get(), myRamSize); + if(myRamSize > 0) + initializeRAM(myRAM.get(), myRamSize); initializeStartBank(getStartBank()); From 498b931ab956aa6a38dff90ae3375df5e5cc077e Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 9 May 2020 21:36:22 +0200 Subject: [PATCH 190/377] remove palette functionality from NTSCFilter load and save config values in PaletteHandler --- src/common/KeyMap.hxx | 1 + src/common/PKeyboardHandler.cxx | 34 +++-- src/common/PaletteHandler.cxx | 194 +++++++++++++++------------ src/common/PaletteHandler.hxx | 59 +++++--- src/common/tv_filters/AtariNTSC.cxx | 43 +++++- src/common/tv_filters/AtariNTSC.hxx | 12 ++ src/common/tv_filters/NTSCFilter.cxx | 45 ++++--- src/common/tv_filters/NTSCFilter.hxx | 8 ++ src/emucore/Console.cxx | 6 - src/emucore/Console.hxx | 10 -- src/emucore/Event.hxx | 13 +- src/emucore/EventHandler.cxx | 45 ++++++- src/emucore/EventHandler.hxx | 4 +- src/emucore/OSystem.cxx | 3 + src/emucore/Settings.cxx | 4 +- src/emucore/TIASurface.cxx | 32 +++++ src/emucore/TIASurface.hxx | 17 ++- src/gui/CommandDialog.cxx | 2 +- src/gui/VideoDialog.cxx | 59 ++++---- src/gui/Widget.hxx | 1 + 20 files changed, 389 insertions(+), 203 deletions(-) diff --git a/src/common/KeyMap.hxx b/src/common/KeyMap.hxx index 94d3b4242..0b7eff2fe 100644 --- a/src/common/KeyMap.hxx +++ b/src/common/KeyMap.hxx @@ -21,6 +21,7 @@ #include #include "Event.hxx" #include "EventHandlerConstants.hxx" +#include "StellaKeys.hxx" /** This class handles keyboard mappings in Stella. diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index 639d8ae31..1a0fe6499 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -15,15 +15,7 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#include "OSystem.hxx" -#include "Console.hxx" -#include "Settings.hxx" #include "EventHandler.hxx" -#include "Sound.hxx" -#include "StateManager.hxx" -#include "StellaKeys.hxx" -#include "TIASurface.hxx" -#include "PNGLibrary.hxx" #include "PKeyboardHandler.hxx" #ifdef DEBUGGER_SUPPORT @@ -475,16 +467,22 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo {Event::ToggleFullScreen, KBDK_RETURN, MOD3}, {Event::OverscanDecrease, KBDK_PAGEDOWN, KBDM_SHIFT}, {Event::OverscanIncrease, KBDK_PAGEUP, KBDM_SHIFT}, - {Event::VidmodeStd, KBDK_1, MOD3}, - {Event::VidmodeRGB, KBDK_2, MOD3}, - {Event::VidmodeSVideo, KBDK_3, MOD3}, - {Event::VidModeComposite, KBDK_4, MOD3}, - {Event::VidModeBad, KBDK_5, MOD3}, - {Event::VidModeCustom, KBDK_6, MOD3}, - {Event::PreviousAttribute, KBDK_7, KBDM_SHIFT | MOD3}, - {Event::NextAttribute, KBDK_7, MOD3}, - {Event::DecreaseAttribute, KBDK_8, KBDM_SHIFT | MOD3}, - {Event::IncreaseAttribute, KBDK_8, MOD3}, + //{Event::VidmodeStd, KBDK_1, MOD3}, + //{Event::VidmodeRGB, KBDK_2, MOD3}, + //{Event::VidmodeSVideo, KBDK_3, MOD3}, + //{Event::VidModeComposite, KBDK_4, MOD3}, + //{Event::VidModeBad, KBDK_5, MOD3}, + //{Event::VidModeCustom, KBDK_6, MOD3}, + {Event::PreviousVideoMode, KBDK_1, KBDM_SHIFT | MOD3}, + {Event::NextVideoMode, KBDK_1, MOD3}, + {Event::PreviousAttribute, KBDK_2, KBDM_SHIFT | MOD3}, + {Event::NextAttribute, KBDK_2, MOD3}, + {Event::DecreaseAttribute, KBDK_3, KBDM_SHIFT | MOD3}, + {Event::IncreaseAttribute, KBDK_3, MOD3}, + {Event::PreviousPaletteAttribute, KBDK_4, KBDM_SHIFT | MOD3}, + {Event::NextPaletteAttribute, KBDK_4, MOD3}, + {Event::PaletteAttributeDecrease, KBDK_5, KBDM_SHIFT | MOD3}, + {Event::PaletteAttributeIncrease, KBDK_5, MOD3}, {Event::PhosphorDecrease, KBDK_9, KBDM_SHIFT | MOD3}, {Event::PhosphorIncrease, KBDK_9, MOD3}, {Event::TogglePhosphor, KBDK_P, MOD3}, diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index e1d71f123..4e61199d0 100644 --- a/src/common/PaletteHandler.cxx +++ b/src/common/PaletteHandler.cxx @@ -26,10 +26,6 @@ PaletteHandler::PaletteHandler(OSystem& system) { // Load user-defined palette for this ROM loadUserPalette(); - - //// Generate custom palette - //generateCustomPalette(ConsoleTiming::ntsc); - //generateCustomPalette(ConsoleTiming::pal); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -100,27 +96,118 @@ void PaletteHandler::changePalette(bool increase) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PaletteHandler::generatePalettes() +void PaletteHandler::selectAdjustable(bool next) { - generateCustomPalette(ConsoleTiming::ntsc); - generateCustomPalette(ConsoleTiming::pal); - generateColorLossPalette(); + if(next) + { + if(myCurrentAdjustable == NUM_ADJUSTABLES - 1) + myCurrentAdjustable = 0; + else + myCurrentAdjustable++; + } + else + { + if(myCurrentAdjustable == 0) + myCurrentAdjustable = NUM_ADJUSTABLES - 1; + else + myCurrentAdjustable--; + } + + ostringstream buf; + buf << "Palette adjustable '" << myAdjustables[myCurrentAdjustable].type + << "' selected"; + + myOSystem.frameBuffer().showMessage(buf.str()); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::changeAdjustable(bool increase) +{ + + if(myCurrentAdjustable == NUM_ADJUSTABLES - 1) + changeColorPhaseShift(increase); + else + { + float newVal = (*myAdjustables[myCurrentAdjustable].value); + + if(increase) + { + newVal += 0.05F; + if(newVal > 1.0F) + newVal = 1.0F; + } + else + { + newVal -= 0.05F; + if(newVal < -1.0F) + newVal = -1.0F; + } + *myAdjustables[myCurrentAdjustable].value = newVal; + + ostringstream buf; + buf << "Custom '" << myAdjustables[myCurrentAdjustable].type + << "' set to " << int((newVal + 1.0F) * 100.0F + 0.5F) << "%"; + + myOSystem.frameBuffer().showMessage(buf.str()); + setPalette(); + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::loadConfig(const Settings& settings) +{ + // Load adjustables + myHue = BSPF::clamp(settings.getFloat("tv.hue"), -1.0F, 1.0F); + mySaturation = BSPF::clamp(settings.getFloat("tv.saturation"), -1.0F, 1.0F); + myContrast = BSPF::clamp(settings.getFloat("tv.contrast"), -1.0F, 1.0F); + myBrightness = BSPF::clamp(settings.getFloat("tv.brightness"), -1.0F, 1.0F); + myGamma = BSPF::clamp(settings.getFloat("tv.gamma"), -1.0F, 1.0F); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::saveConfig(Settings& settings) const +{ + // Save adjustables + settings.setValue("tv.hue", myHue); + settings.setValue("tv.saturation", mySaturation); + settings.setValue("tv.contrast", myContrast); + settings.setValue("tv.brightness", myBrightness); + settings.setValue("tv.gamma", myGamma); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::setAdjustables(Adjustable& adjustable) +{ + myHue = scaleFrom100(adjustable.hue); + mySaturation = scaleFrom100(adjustable.saturation); + myContrast = scaleFrom100(adjustable.contrast); + myBrightness = scaleFrom100(adjustable.brightness); + myGamma = scaleFrom100(adjustable.gamma); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::getAdjustables(Adjustable& adjustable) const +{ + adjustable.hue = scaleTo100(myHue); + adjustable.saturation = scaleTo100(mySaturation); + adjustable.contrast = scaleTo100(myContrast); + adjustable.brightness = scaleTo100(myBrightness); + adjustable.gamma = scaleTo100(myGamma); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaletteHandler::changeColorPhaseShift(bool increase) { - const char DEGREE = 0x1c; - const float NTSC_SHIFT = 26.2F; - const float PAL_SHIFT = 31.3F; // 360 / 11.5 const ConsoleTiming timing = myOSystem.console().timing(); - const bool isNTSC = timing == ConsoleTiming::ntsc; - const bool isPAL = timing == ConsoleTiming::pal; // SECAM is not supported - if(isNTSC || isPAL) + if(timing != ConsoleTiming::secam) { - const string key = isNTSC ? "phase_ntsc" : "phase_pal"; + const char DEGREE = 0x1c; + const float NTSC_SHIFT = 26.2F; + const float PAL_SHIFT = 31.3F; // 360 / 11.5 + const bool isNTSC = timing == ConsoleTiming::ntsc; + const string key = isNTSC ? "tv.phase_ntsc" : "tv.phase_pal"; const float shift = isNTSC ? NTSC_SHIFT : PAL_SHIFT; float phase = myOSystem.settings().getFloat(key); @@ -175,6 +262,9 @@ void PaletteHandler::setPalette() // Now consider the current display format const PaletteArray* palette = palettes[paletteType][int(timing)]; + if(paletteType == PaletteType::Custom) + generateCustomPalette(timing); + myOSystem.frameBuffer().setTIAPalette(adjustPalette(*palette)); } @@ -212,15 +302,7 @@ PaletteArray PaletteHandler::adjustPalette(const PaletteArray& palette) // TOOD: adjust hue (different for NTSC and PAL?) // adjust saturation - float P = sqrt(r * r * PR + g * g * PG + b * b * PB) ; - - r = P + (r - P) * saturation; - g = P + (g - P) * saturation; - b = P + (b - P) * saturation; - - r = BSPF::clamp(r, 0, 255); - g = BSPF::clamp(g, 0, 255); - b = BSPF::clamp(b, 0, 255); + changeSaturation(r, g, b, saturation); // adjust contrast, brightness, gamma r = adjust[r]; @@ -235,6 +317,7 @@ PaletteArray PaletteHandler::adjustPalette(const PaletteArray& palette) // Fill the odd numbered palette entries with gray values (calculated // using the standard RGB -> grayscale conversion formula) + // Used for PAL color-loss data and 'greying out' the frame in the debugger. const uInt8 lum = static_cast((r * PR) + (g * PG) + (b * PB)); destPalette[i + 1] = (lum << 16) + (lum << 8) + lum; @@ -299,7 +382,7 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) { // YIQ is YUV shifted by 33° constexpr float offset = 33 * (2 * BSPF::PI_f / 360); - const float shift = myOSystem.settings().getFloat("phase_ntsc") * + const float shift = myOSystem.settings().getFloat("tv.phase_ntsc") * (2 * BSPF::PI_f / 360); // color 0 is grayscale @@ -342,10 +425,10 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) } } } - else + else if(timing == ConsoleTiming::pal) { constexpr float offset = 180 * (2 * BSPF::PI_f / 360); - float shift = myOSystem.settings().getFloat("phase_pal") * + float shift = myOSystem.settings().getFloat("tv.phase_pal") * (2 * BSPF::PI_f / 360); constexpr float fixedShift = 22.5F * (2 * BSPF::PI_f / 360); @@ -432,63 +515,6 @@ void PaletteHandler::changeSaturation(int& R, int& G, int& B, float change) B = BSPF::clamp(B, 0, 255); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PaletteHandler::changeSaturation(float& R, float& G, float& B, float change) -{ - constexpr float PR = .2989F; - constexpr float PG = .5870F; - constexpr float PB = .1140F; - - float P = sqrt(R * R * PR + G * G * PG + B * B * PB) ; - - R = P + (R - P) * change; - G = P + (G - P) * change; - B = P + (B - P) * change; - - if(R < 0) R = 0; - if(G < 0) G = 0; - if(B < 0) B = 0; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PaletteHandler::generateColorLossPalette() -{ - // Look at all the palettes, since we don't know which one is - // currently active - std::array palette = { - ourNTSCPalette.data(), ourPALPalette.data(), ourSECAMPalette.data(), - ourNTSCPaletteZ26.data(), ourPALPaletteZ26.data(), ourSECAMPaletteZ26.data(), - nullptr, nullptr, nullptr, - ourCustomNTSCPalette.data(), ourCustomPALPalette.data(), ourSECAMPalette.data(), - }; - - if(myUserPaletteDefined) - { - int idx = PaletteType::User * int(ConsoleTiming::numTimings); - palette[idx + int(ConsoleTiming::ntsc)] = ourUserNTSCPalette.data(); - palette[idx + int(ConsoleTiming::pal)] = ourUserPALPalette.data(); - palette[idx + int(ConsoleTiming::secam)] = ourUserSECAMPalette.data(); - } - - for(int i = 0; i < int(ConsoleTiming::numTimings) * PaletteType::NumTypes; ++i) - { - if(palette[i] == nullptr) - continue; - - // Fill the odd numbered palette entries with gray values (calculated - // using the standard RGB -> grayscale conversion formula) - for(int j = 0; j < 128; ++j) - { - const uInt32 pixel = palette[i][(j<<1)]; - const uInt8 r = (pixel >> 16) & 0xff; - const uInt8 g = (pixel >> 8) & 0xff; - const uInt8 b = (pixel >> 0) & 0xff; - const uInt8 sum = static_cast((r * 0.2989) + (g * 0.5870) + (b * 0.1140)); - palette[i][(j<<1)+1] = (sum << 16) + (sum << 8) + sum; - } - } -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PaletteArray PaletteHandler::ourNTSCPalette = { 0x000000, 0, 0x4a4a4a, 0, 0x6f6f6f, 0, 0x8e8e8e, 0, diff --git a/src/common/PaletteHandler.hxx b/src/common/PaletteHandler.hxx index 6b26b918a..d8e5518c0 100644 --- a/src/common/PaletteHandler.hxx +++ b/src/common/PaletteHandler.hxx @@ -36,6 +36,9 @@ class PaletteHandler NumDisplayTypes }; + struct Adjustable { + uInt32 hue, saturation, contrast, brightness, gamma; + }; public: PaletteHandler(OSystem& system); @@ -46,6 +49,14 @@ class PaletteHandler */ void changePalette(bool increase = true); + void selectAdjustable(bool next = true); + void changeAdjustable(bool increase = true); + + + void loadConfig(const Settings& settings); + void saveConfig(Settings& settings) const; + void setAdjustables(Adjustable& adjustable); + void getAdjustables(Adjustable& adjustable) const; /** Change the "phase shift" variable. @@ -56,9 +67,6 @@ class PaletteHandler */ void changeColorPhaseShift(bool increase = true); - void changeSaturation(int& R, int& G, int& B, float change); - void changeSaturation(float& R, float& G, float& B, float change); - /** Sets the palette according to the given palette name. @@ -72,17 +80,6 @@ class PaletteHandler */ void setPalette(); - - void generatePalettes(); - - /** - Loads all defined palettes with PAL color-loss data, even those that - normally can't have it enabled (NTSC), since it's also used for - 'greying out' the frame in the debugger. - */ - void generateColorLossPalette(); - - /** Generates a custom palette, based on user defined phase shifts. */ @@ -99,11 +96,16 @@ class PaletteHandler MaxType = Custom }; + float scaleFrom100(float x) const { return (x / 100.F) - 1.F; } + uInt32 scaleTo100(float x) const { return uInt32(100 * (x + 1.F)); } + PaletteType toPaletteType(const string& name) const; string toPaletteName(PaletteType type) const; PaletteArray adjustPalette(const PaletteArray& source); + void changeSaturation(int& R, int& G, int& B, float change); + /** Loads a user-defined palette file (from OSystem::paletteFile), filling the appropriate user-defined palette arrays. @@ -112,14 +114,33 @@ class PaletteHandler private: + static const int NUM_ADJUSTABLES = 6; + OSystem& myOSystem; + uInt32 myCurrentAdjustable{0}; + struct AdjustableTag { + const char* const type{nullptr}; + float* value{nullptr}; + }; + const std::array myAdjustables = + { { + { "contrast", &myContrast }, + { "brightness", &myBrightness }, + { "hue", &myHue }, + { "saturation", &mySaturation }, + { "gamma", &myGamma }, + { "phase shift", nullptr }, + } }; + // range -1.0 to +1.0 (as in AtariNTSC) - float myContrast{0.0F}; - float myBrightness{0.0F}; - float myHue{0.0F}; - float mySaturation{0.0F}; - float myGamma{0.0F}; + // Basic parameters + float myContrast{0.0F}; // -1 = dark (0.5) +1 = light (1.5) + float myHue{0.0F}; // -1 = -180 degrees +1 = +180 degrees + float mySaturation{0.0F}; // -1 = grayscale (0.0) +1 = oversaturated colors (2.0) + float myBrightness{0.0F}; // -1 = dark (0.5) +1 = light (1.5) + // Advanced parameters + float myGamma{0.0F}; // -1 = dark (1.5) +1 = light (0.5) // Indicates whether an external palette was found and // successfully loaded diff --git a/src/common/tv_filters/AtariNTSC.cxx b/src/common/tv_filters/AtariNTSC.cxx index a0b9ef169..ad57a12f8 100644 --- a/src/common/tv_filters/AtariNTSC.cxx +++ b/src/common/tv_filters/AtariNTSC.cxx @@ -57,9 +57,15 @@ void AtariNTSC::generateKernels() const uInt8* ptr = myRGBPalette.data(); for(size_t entry = 0; entry < myRGBPalette.size() / 3; ++entry) { + #ifdef BLARGG_PALETTE float r = myImpl.to_float[*ptr++], g = myImpl.to_float[*ptr++], b = myImpl.to_float[*ptr++]; + #else + float r = (*ptr++) / 255.F * rgb_unit + rgb_offset, + g = (*ptr++) / 255.F * rgb_unit + rgb_offset, + b = (*ptr++) / 255.F * rgb_unit + rgb_offset; + #endif float y, i, q; RGB_TO_YIQ( r, g, b, y, i, q ); // Generate kernel @@ -319,8 +325,10 @@ void AtariNTSC::renderWithPhosphorThread(const uInt8* atari_in, const uInt32 in_ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AtariNTSC::init(init_t& impl, const Setup& setup) { +#ifdef BLARGG_PALETTE impl.brightness = setup.brightness * (0.5F * rgb_unit) + rgb_offset; impl.contrast = setup.contrast * (0.5F * rgb_unit) + rgb_unit; +#endif impl.artifacts = setup.artifacts; if ( impl.artifacts > 0 ) @@ -334,6 +342,7 @@ void AtariNTSC::init(init_t& impl, const Setup& setup) initFilters(impl, setup); +#ifdef BLARGG_PALETTE /* generate gamma table */ if (true) /* was (gamma_size > 1) */ { @@ -341,19 +350,22 @@ void AtariNTSC::init(init_t& impl, const Setup& setup) float const gamma = 1.1333F - setup.gamma * 0.5F; /* match common PC's 2.2 gamma to TV's 2.65 gamma */ int i; - for ( i = 0; i < gamma_size; i++ ) - impl.to_float [i] = - powf( i * to_float, gamma ) * impl.contrast + impl.brightness; + for(i = 0; i < gamma_size; i++) + impl.to_float[i] = + powf(i * to_float, gamma) * impl.contrast + impl.brightness; } +#endif /* setup decoder matricies */ { + #ifdef BLARGG_PALETTE float hue = setup.hue * BSPF::PI_f + BSPF::PI_f / 180 * ext_decoder_hue; float sat = setup.saturation + 1; hue += BSPF::PI_f / 180 * (std_decoder_hue - ext_decoder_hue); - float s = sinf( hue ) * sat; - float c = cosf( hue ) * sat; + float s = sinf(hue)*sat; + float c = cosf(hue)*sat; + #endif float* out = impl.to_rgb.data(); int n; @@ -366,8 +378,13 @@ void AtariNTSC::init(init_t& impl, const Setup& setup) { float i = *in++; float q = *in++; + #ifdef BLARGG_PALETTE *out++ = i * c - q * s; *out++ = i * s + q * c; + #else + *out++ = i ; + *out++ = q; + #endif } while ( --n2 ); #if 0 // burst_count is always 0 @@ -544,16 +561,32 @@ void AtariNTSC::genKernel(init_t& impl, float y, float i, float q, uInt32* out) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const AtariNTSC::Setup AtariNTSC::TV_Composite = { +#ifdef BLARGG_PALETTE 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.15F, 0.0F, 0.0F, 0.0F +#else + 0.0F, 0.15F, 0.0F, 0.0F, 0.0F +#endif }; const AtariNTSC::Setup AtariNTSC::TV_SVideo = { +#ifdef BLARGG_PALETTE 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.45F, -1.0F, -1.0F, 0.0F +#else + 0.0F, 0.45F, -1.0F, -1.0F, 0.0F +#endif }; const AtariNTSC::Setup AtariNTSC::TV_RGB = { +#ifdef BLARGG_PALETTE 0.0F, 0.0F, 0.0F, 0.0F, 0.2F, 0.0F, 0.70F, -1.0F, -1.0F, -1.0F +#else + 0.2F, 0.70F, -1.0F, -1.0F, -1.0F +#endif }; const AtariNTSC::Setup AtariNTSC::TV_Bad = { +#ifdef BLARGG_PALETTE 0.1F, -0.3F, 0.3F, 0.25F, 0.2F, 0.0F, 0.1F, 0.5F, 0.5F, 0.5F +#else + 0.2F, 0.1F, 0.5F, 0.5F, 0.5F +#endif }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/tv_filters/AtariNTSC.hxx b/src/common/tv_filters/AtariNTSC.hxx index 4ae7b666f..eb75bce3d 100644 --- a/src/common/tv_filters/AtariNTSC.hxx +++ b/src/common/tv_filters/AtariNTSC.hxx @@ -46,6 +46,8 @@ #include "FrameBufferConstants.hxx" #include "bspf.hxx" +//#define BLARGG_PALETTE // also modify contrast, brightness, saturation, gamma and hue when defined + class AtariNTSC { public: @@ -57,14 +59,18 @@ class AtariNTSC struct Setup { // Basic parameters + #ifdef BLARGG_PALETTE float hue{0.F}; // -1 = -180 degrees +1 = +180 degrees float saturation{0.F}; // -1 = grayscale (0.0) +1 = oversaturated colors (2.0) float contrast{0.F}; // -1 = dark (0.5) +1 = light (1.5) float brightness{0.F}; // -1 = dark (0.5) +1 = light (1.5) + #endif float sharpness{0.F}; // edge contrast enhancement/blurring // Advanced parameters + #ifdef BLARGG_PALETTE float gamma{0.F}; // -1 = dark (1.5) +1 = light (0.5) + #endif float resolution{0.F}; // image resolution float artifacts{0.F}; // artifacts caused by color changes float fringing{0.F}; // color artifacts caused by brightness changes @@ -127,7 +133,9 @@ class AtariNTSC burst_size = entry_size / burst_count, kernel_half = 16, kernel_size = kernel_half * 2 + 1, + #ifdef BLARGG_PALETTE gamma_size = 256, + #endif rgb_builder = ((1 << 21) | (1 << 11) | (1 << 1)), rgb_kernel_size = burst_size / alignment_count, @@ -162,16 +170,20 @@ class AtariNTSC struct init_t { std::array to_rgb{0.F}; + #ifdef BLARGG_PALETTE std::array to_float{0.F}; float contrast{0.F}; float brightness{0.F}; + #endif float artifacts{0.F}; float fringing{0.F}; std::array kernel{0.F}; init_t() { to_rgb.fill(0.0); + #ifdef BLARGG_PALETTE to_float.fill(0.0); + #endif kernel.fill(0.0); } }; diff --git a/src/common/tv_filters/NTSCFilter.cxx b/src/common/tv_filters/NTSCFilter.cxx index 6ec1afc8c..9e46b6426 100644 --- a/src/common/tv_filters/NTSCFilter.cxx +++ b/src/common/tv_filters/NTSCFilter.cxx @@ -140,13 +140,16 @@ string NTSCFilter::decreaseAdjustable() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void NTSCFilter::loadConfig(const Settings& settings) { + // Load adjustables for custom mode +#ifdef BLARGG_PALETTE myCustomSetup.hue = BSPF::clamp(settings.getFloat("tv.hue"), -1.0F, 1.0F); myCustomSetup.saturation = BSPF::clamp(settings.getFloat("tv.saturation"), -1.0F, 1.0F); myCustomSetup.contrast = BSPF::clamp(settings.getFloat("tv.contrast"), -1.0F, 1.0F); myCustomSetup.brightness = BSPF::clamp(settings.getFloat("tv.brightness"), -1.0F, 1.0F); - myCustomSetup.sharpness = BSPF::clamp(settings.getFloat("tv.sharpness"), -1.0F, 1.0F); myCustomSetup.gamma = BSPF::clamp(settings.getFloat("tv.gamma"), -1.0F, 1.0F); +#endif + myCustomSetup.sharpness = BSPF::clamp(settings.getFloat("tv.sharpness"), -1.0F, 1.0F); myCustomSetup.resolution = BSPF::clamp(settings.getFloat("tv.resolution"), -1.0F, 1.0F); myCustomSetup.artifacts = BSPF::clamp(settings.getFloat("tv.artifacts"), -1.0F, 1.0F); myCustomSetup.fringing = BSPF::clamp(settings.getFloat("tv.fringing"), -1.0F, 1.0F); @@ -157,12 +160,14 @@ void NTSCFilter::loadConfig(const Settings& settings) void NTSCFilter::saveConfig(Settings& settings) const { // Save adjustables for custom mode - settings.setValue("tv.hue", myCustomSetup.hue); - settings.setValue("tv.saturation", myCustomSetup.saturation); - settings.setValue("tv.contrast", myCustomSetup.contrast); - settings.setValue("tv.brightness", myCustomSetup.brightness); +#ifdef BLARGG_PALETTE + //settings.setValue("tv.hue", myCustomSetup.hue); + //settings.setValue("tv.saturation", myCustomSetup.saturation); + //settings.setValue("tv.contrast", myCustomSetup.contrast); + //settings.setValue("tv.brightness", myCustomSetup.brightness); + //settings.setValue("tv.gamma", myCustomSetup.gamma); +#endif settings.setValue("tv.sharpness", myCustomSetup.sharpness); - settings.setValue("tv.gamma", myCustomSetup.gamma); settings.setValue("tv.resolution", myCustomSetup.resolution); settings.setValue("tv.artifacts", myCustomSetup.artifacts); settings.setValue("tv.fringing", myCustomSetup.fringing); @@ -192,12 +197,14 @@ void NTSCFilter::getAdjustables(Adjustable& adjustable, Preset preset) const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void NTSCFilter::setCustomAdjustables(Adjustable& adjustable) { - myCustomSetup.hue = scaleFrom100(adjustable.hue); - myCustomSetup.saturation = scaleFrom100(adjustable.saturation); - myCustomSetup.contrast = scaleFrom100(adjustable.contrast); - myCustomSetup.brightness = scaleFrom100(adjustable.brightness); +#ifdef BLARGG_PALETTE + //myCustomSetup.hue = scaleFrom100(adjustable.hue); + //myCustomSetup.saturation = scaleFrom100(adjustable.saturation); + //myCustomSetup.contrast = scaleFrom100(adjustable.contrast); + //myCustomSetup.brightness = scaleFrom100(adjustable.brightness); + //myCustomSetup.gamma = scaleFrom100(adjustable.gamma); +#endif myCustomSetup.sharpness = scaleFrom100(adjustable.sharpness); - myCustomSetup.gamma = scaleFrom100(adjustable.gamma); myCustomSetup.resolution = scaleFrom100(adjustable.resolution); myCustomSetup.artifacts = scaleFrom100(adjustable.artifacts); myCustomSetup.fringing = scaleFrom100(adjustable.fringing); @@ -208,12 +215,14 @@ void NTSCFilter::setCustomAdjustables(Adjustable& adjustable) void NTSCFilter::convertToAdjustable(Adjustable& adjustable, const AtariNTSC::Setup& setup) const { - adjustable.hue = scaleTo100(setup.hue); - adjustable.saturation = scaleTo100(setup.saturation); - adjustable.contrast = scaleTo100(setup.contrast); - adjustable.brightness = scaleTo100(setup.brightness); +#ifdef BLARGG_PALETTE + //adjustable.hue = scaleTo100(setup.hue); + //adjustable.saturation = scaleTo100(setup.saturation); + //adjustable.contrast = scaleTo100(setup.contrast); + //adjustable.brightness = scaleTo100(setup.brightness); + //adjustable.gamma = scaleTo100(setup.gamma); +#endif adjustable.sharpness = scaleTo100(setup.sharpness); - adjustable.gamma = scaleTo100(setup.gamma); adjustable.resolution = scaleTo100(setup.resolution); adjustable.artifacts = scaleTo100(setup.artifacts); adjustable.fringing = scaleTo100(setup.fringing); @@ -224,12 +233,16 @@ void NTSCFilter::convertToAdjustable(Adjustable& adjustable, AtariNTSC::Setup NTSCFilter::myCustomSetup = AtariNTSC::TV_Composite; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +#ifdef BLARGG_PALETTE const std::array NTSCFilter::ourCustomAdjustables = { { { "contrast", &myCustomSetup.contrast }, { "brightness", &myCustomSetup.brightness }, { "hue", &myCustomSetup.hue }, { "saturation", &myCustomSetup.saturation }, { "gamma", &myCustomSetup.gamma }, +#else +const std::array NTSCFilter::ourCustomAdjustables = { { +#endif { "sharpness", &myCustomSetup.sharpness }, { "resolution", &myCustomSetup.resolution }, { "artifacts", &myCustomSetup.artifacts }, diff --git a/src/common/tv_filters/NTSCFilter.hxx b/src/common/tv_filters/NTSCFilter.hxx index b4a5e0e3d..f7e897916 100644 --- a/src/common/tv_filters/NTSCFilter.hxx +++ b/src/common/tv_filters/NTSCFilter.hxx @@ -51,8 +51,12 @@ class NTSCFilter /* Normally used in conjunction with custom mode, contains all aspects currently adjustable in NTSC TV emulation. */ struct Adjustable { + #ifdef BLARGG_PALETTE uInt32 hue, saturation, contrast, brightness, gamma, sharpness, resolution, artifacts, fringing, bleed; + #else + uInt32 sharpness, resolution, artifacts, fringing, bleed; + #endif }; public: @@ -139,7 +143,11 @@ class NTSCFilter float* value{nullptr}; }; uInt32 myCurrentAdjustable{0}; + #ifdef BLARGG_PALETTE static const std::array ourCustomAdjustables; + #else + static const std::array ourCustomAdjustables; + #endif private: // Following constructors and assignment operators not supported diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 299b1ea3a..bf7d20abf 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -62,7 +62,6 @@ #include "AudioSettings.hxx" #include "frame-manager/FrameManager.hxx" #include "frame-manager/FrameLayoutDetector.hxx" -#include "PaletteHandler.hxx" #ifdef CHEATCODE_SUPPORT #include "CheatManager.hxx" @@ -88,7 +87,6 @@ Console::Console(OSystem& osystem, unique_ptr& cart, myTIA = make_unique(*this, [this]() { return timing(); }, myOSystem.settings()); myFrameManager = make_unique(); mySwitches = make_unique(myEvent, myProperties, myOSystem.settings()); - myPaletteHandler = make_unique(myOSystem); myTIA->setFrameManager(myFrameManager.get()); @@ -436,7 +434,6 @@ void Console::setFormat(uInt32 format) myConsoleInfo.DisplayFormat = myDisplayFormat + autodetected; - myPaletteHandler->setPalette(); setTIAProperties(); initializeVideo(); // takes care of refreshing the screen initializeAudio(); // ensure that audio synthesis is set up to match emulation speed @@ -582,10 +579,7 @@ FBInitStatus Console::initializeVideo(bool full) myOSystem.frameBuffer().showFrameStats( myOSystem.settings().getBool(devSettings ? "dev.stats" : "plr.stats")); - myPaletteHandler->generatePalettes(); } - myPaletteHandler->setPalette(); - return fbstatus; } diff --git a/src/emucore/Console.hxx b/src/emucore/Console.hxx index 36c680539..ac26415d7 100644 --- a/src/emucore/Console.hxx +++ b/src/emucore/Console.hxx @@ -29,7 +29,6 @@ class CompuMate; class Debugger; class AudioQueue; class AudioSettings; -class PaletteHandler; #include "bspf.hxx" #include "ConsoleIO.hxx" @@ -40,7 +39,6 @@ class PaletteHandler; #include "FrameBufferConstants.hxx" #include "Serializable.hxx" #include "EventHandlerConstants.hxx" -#include "NTSCFilter.hxx" #include "EmulationTiming.hxx" #include "ConsoleTiming.hxx" #include "frame-manager/AbstractFrameManager.hxx" @@ -187,11 +185,6 @@ class Console : public Serializable, public ConsoleIO */ EmulationTiming& emulationTiming() { return myEmulationTiming; } - /** - Retrieve palette handler. - */ - PaletteHandler& paletteHandler() const { return *myPaletteHandler; } - public: /** Toggle between NTSC/PAL/SECAM (and variants) display format. @@ -424,9 +417,6 @@ class Console : public Serializable, public ConsoleIO // The audio settings AudioSettings& myAudioSettings; - // The palette handling - unique_ptrmyPaletteHandler; - private: // Following constructors and assignment operators not supported Console() = delete; diff --git a/src/emucore/Event.hxx b/src/emucore/Event.hxx index 5dbb71126..ae82ef810 100644 --- a/src/emucore/Event.hxx +++ b/src/emucore/Event.hxx @@ -22,7 +22,6 @@ #include #include "bspf.hxx" -#include "StellaKeys.hxx" /** @author Stephen Anthony, Christian Speckner, Thomas Jentzsch @@ -92,6 +91,7 @@ class Event TogglePauseMode, StartPauseMode, OptionsMenuMode, CmdMenuMode, DebuggerMode, ExitMode, TakeSnapshot, ToggleContSnapshots, ToggleContSnapshotsFrame, + ToggleTurbo, NextState, PreviousState, LoadState, SaveState, SaveAllStates, LoadAllStates, @@ -100,12 +100,16 @@ class Event Unwind1Menu, Unwind10Menu, UnwindAllMenu, RewindPause, UnwindPause, - FormatDecrease, FormatIncrease, PaletteIncrease, ToggleColorLoss, + FormatDecrease, FormatIncrease, PaletteDecrease, PaletteIncrease, ToggleColorLoss, + ColorShiftDecrease, ColorShiftIncrease, + PreviousPaletteAttribute, NextPaletteAttribute, + PaletteAttributeDecrease, PaletteAttributeIncrease, ToggleFullScreen, VidmodeDecrease, VidmodeIncrease, VCenterDecrease, VCenterIncrease, ScanlineAdjustDecrease, ScanlineAdjustIncrease, OverscanDecrease, OverscanIncrease, VidmodeStd, VidmodeRGB, VidmodeSVideo, VidModeComposite, VidModeBad, VidModeCustom, + PreviousVideoMode, NextVideoMode, PreviousAttribute, NextAttribute, DecreaseAttribute, IncreaseAttribute, ScanlinesDecrease, ScanlinesIncrease, PhosphorDecrease, PhosphorIncrease, TogglePhosphor, ToggleInter, ToggleJitter, @@ -118,10 +122,7 @@ class Event ToggleCollisions, ToggleBits, ToggleFixedColors, ToggleFrameStats, ToggleSAPortOrder, ExitGame, - // add new events from here to avoid that user remapped events get overwritten - ToggleTurbo, PaletteDecrease, - ColorShiftDecrease, ColorShiftIncrease, LastType }; @@ -136,7 +137,7 @@ class Event }; // Event list version, update only if the id of existing(!) event types changed - static constexpr Int32 VERSION = 3; + static constexpr Int32 VERSION = 4; using EventSet = std::set; diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 04dd852d0..325438765 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -436,12 +436,28 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) if (pressed) myOSystem.console().changeScanlineAdjust(+1); return; + case Event::PreviousPaletteAttribute: + if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().selectAdjustable(false); + return; + + case Event::NextPaletteAttribute: + if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().selectAdjustable(true); + return; + + case Event::PaletteAttributeDecrease: + if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().changeAdjustable(false); + return; + + case Event::PaletteAttributeIncrease: + if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().changeAdjustable(true); + return; + case Event::ColorShiftDecrease: - if (pressed) myOSystem.console().paletteHandler().changeColorPhaseShift(false); + if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().changeColorPhaseShift(false); return; case Event::ColorShiftIncrease: - if (pressed) myOSystem.console().paletteHandler().changeColorPhaseShift(); + if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().changeColorPhaseShift(true); return; case Event::ToggleFullScreen: @@ -456,6 +472,14 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) if (pressed) myOSystem.frameBuffer().changeOverscan(1); return; + case Event::PreviousVideoMode: + if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().changeNTSC(false); + return; + + case Event::NextVideoMode: + if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().changeNTSC(true); + return; + case Event::VidmodeStd: if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::OFF); return; @@ -541,11 +565,11 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::PaletteDecrease: - if (pressed && !repeated) myOSystem.console().paletteHandler().changePalette(false); + if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().paletteHandler().changePalette(false); return; case Event::PaletteIncrease: - if (pressed && !repeated) myOSystem.console().paletteHandler().changePalette(); + if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().paletteHandler().changePalette(true); return; case Event::ToggleInter: @@ -1934,22 +1958,30 @@ EventHandler::EmulActionList EventHandler::ourEmulActionList = { { { Event::VCenterIncrease, "Move display down", "" }, { Event::FormatDecrease, "Decrease display format", "" }, { Event::FormatIncrease, "Increase display format", "" }, + // Palette settings { Event::PaletteDecrease, "Switch to previous palette", "" }, { Event::PaletteIncrease, "Switch to next palette", "" }, + { Event::PreviousPaletteAttribute,"Select previous palette attribute", "" }, + { Event::NextPaletteAttribute, "Select next palette attribute", "" }, + { Event::PaletteAttributeDecrease,"Decrease selected palette attribute", "" }, + { Event::PaletteAttributeIncrease,"Increase selected palette attribute", "" }, { Event::ColorShiftDecrease, "Decrease custom palette phase shift", "" }, { Event::ColorShiftIncrease, "Increase custom palette phase shift", "" }, { Event::ToggleInter, "Toggle display interpolation", "" }, - // TV effects: + // Blargg TV effects: { Event::VidmodeStd, "Disable TV effects", "" }, { Event::VidmodeRGB, "Select 'RGB' preset", "" }, { Event::VidmodeSVideo, "Select 'S-Video' preset", "" }, { Event::VidModeComposite, "Select 'Composite' preset", "" }, { Event::VidModeBad, "Select 'Badly adjusted' preset", "" }, { Event::VidModeCustom, "Select 'Custom' preset", "" }, + { Event::PreviousVideoMode, "Select previous TV effect mode preset", "" }, + { Event::NextVideoMode, "Select next TV effect mode preset", "" }, { Event::PreviousAttribute, "Select previous 'Custom' attribute", "" }, { Event::NextAttribute, "Select next 'Custom' attribute", "" }, { Event::DecreaseAttribute, "Decrease selected 'Custom' attribute", "" }, { Event::IncreaseAttribute, "Increase selected 'Custom' attribute", "" }, + // Other TV effects { Event::TogglePhosphor, "Toggle 'phosphor' effect", "" }, { Event::PhosphorDecrease, "Decrease 'phosphor' blend", "" }, { Event::PhosphorIncrease, "Increase 'phosphor' blend", "" }, @@ -2066,6 +2098,9 @@ const Event::EventSet EventHandler::AudioVideoEvents = { Event::OverscanDecrease, Event::OverscanIncrease, Event::PaletteDecrease, Event::PaletteIncrease, Event::ColorShiftDecrease, Event::ColorShiftIncrease, + Event::PreviousVideoMode, Event::NextVideoMode, + Event::PreviousPaletteAttribute, Event::NextPaletteAttribute, + Event::PaletteAttributeDecrease, Event::PaletteAttributeIncrease, Event::ToggleInter }; diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx index 10259780a..fd8522e5f 100644 --- a/src/emucore/EventHandler.hxx +++ b/src/emucore/EventHandler.hxx @@ -25,6 +25,7 @@ class OSystem; class MouseControl; class DialogContainer; class PhysicalJoystick; +class Variant; namespace GUI { class Font; @@ -36,7 +37,6 @@ namespace GUI { #include "StellaKeys.hxx" #include "PKeyboardHandler.hxx" #include "PJoystickHandler.hxx" -#include "Variant.hxx" #include "bspf.hxx" /** @@ -468,7 +468,7 @@ class EventHandler #else PNG_SIZE = 0, #endif - EMUL_ACTIONLIST_SIZE = 150 + PNG_SIZE + COMBO_SIZE, + EMUL_ACTIONLIST_SIZE = 154 + PNG_SIZE + COMBO_SIZE, MENU_ACTIONLIST_SIZE = 18 ; diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index ccf6838cb..8d60f6fb1 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -49,6 +49,7 @@ #include "CartDetector.hxx" #include "FrameBuffer.hxx" #include "TIASurface.hxx" +#include "PaletteHandler.hxx" #include "TIAConstants.hxx" #include "Settings.hxx" #include "PropsSet.hxx" @@ -243,6 +244,8 @@ void OSystem::saveConfig() Logger::debug("Saving TV effects options ..."); myFrameBuffer->tiaSurface().ntsc().saveConfig(settings()); + Logger::debug("Saving palette settings..."); + myFrameBuffer->tiaSurface().paletteHandler().saveConfig(settings()); } Logger::debug("Saving config options ..."); diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index a8100d99d..a959cc255 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -46,8 +46,6 @@ Settings::Settings() setPermanent("windowedpos", Common::Point(50, 50)); setPermanent("display", 0); setPermanent("palette", "standard"); - setPermanent("phase_ntsc", "26.2"); - setPermanent("phase_pal", "31.3"); setPermanent("uimessages", "true"); // TIA specific options @@ -64,6 +62,8 @@ Settings::Settings() setPermanent("tv.phosphor", "byrom"); setPermanent("tv.phosblend", "50"); setPermanent("tv.scanlines", "25"); + setPermanent("tv.phase_ntsc", "26.2"); + setPermanent("tv.phase_pal", "31.3"); setPermanent("tv.contrast", "0.0"); setPermanent("tv.brightness", "0.0"); setPermanent("tv.hue", "0.0"); diff --git a/src/emucore/TIASurface.cxx b/src/emucore/TIASurface.cxx index a13a9fd83..19e817b0d 100644 --- a/src/emucore/TIASurface.cxx +++ b/src/emucore/TIASurface.cxx @@ -23,6 +23,7 @@ #include "Console.hxx" #include "TIA.hxx" #include "PNGLibrary.hxx" +#include "PaletteHandler.hxx" #include "TIASurface.hxx" namespace { @@ -76,6 +77,9 @@ TIASurface::TIASurface(OSystem& system) // Enable/disable threading in the NTSC TV effects renderer myNTSCFilter.enableThreading(myOSystem.settings().getBool("threads")); + + myPaletteHandler = make_unique(myOSystem); + myPaletteHandler->loadConfig(myOSystem.settings()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -89,6 +93,8 @@ void TIASurface::initialize(const Console& console, mySLineSurface->setDstPos(mode.image.x(), mode.image.y()); mySLineSurface->setDstSize(mode.image.w(), mode.image.h()); + myPaletteHandler->setPalette(); + // Phosphor mode can be enabled either globally or per-ROM int p_blend = 0; bool enable = false; @@ -188,6 +194,32 @@ void TIASurface::setNTSC(NTSCFilter::Preset preset, bool show) if(show) myFB.showMessage(buf.str()); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIASurface::changeNTSC(bool next, bool show) +{ + constexpr NTSCFilter::Preset PRESETS[] = { + NTSCFilter::Preset::OFF, NTSCFilter::Preset::RGB, NTSCFilter::Preset::SVIDEO, + NTSCFilter::Preset::COMPOSITE, NTSCFilter::Preset::BAD, NTSCFilter::Preset::CUSTOM + }; + int preset = myOSystem.settings().getInt("tv.filter"); + + if(next) + { + if(preset == int(NTSCFilter::Preset::CUSTOM)) + preset = int(NTSCFilter::Preset::OFF); + else + preset++; + } + else + { + if(preset == int(NTSCFilter::Preset::OFF)) + preset = int(NTSCFilter::Preset::CUSTOM); + else + preset--; + } + setNTSC(PRESETS[preset], show); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIASurface::setScanlineIntensity(int amount) { diff --git a/src/emucore/TIASurface.hxx b/src/emucore/TIASurface.hxx index c87ddc881..9dbda5b14 100644 --- a/src/emucore/TIASurface.hxx +++ b/src/emucore/TIASurface.hxx @@ -22,6 +22,7 @@ class TIA; class Console; class OSystem; class FBSurface; +class PaletteHandler; #include @@ -49,6 +50,8 @@ class TIASurface */ explicit TIASurface(OSystem& system); + virtual ~TIASurface() = default; + /** Set the TIA object, which is needed for actually rendering the TIA image. */ @@ -87,6 +90,16 @@ class TIASurface */ void setNTSC(NTSCFilter::Preset preset, bool show = true); + /** + Switch to next/previous NTSC filtering effect. + */ + void changeNTSC(bool next, bool show = true); + + /** + Retrieve palette handler. + */ + PaletteHandler& paletteHandler() const { return *myPaletteHandler; } + /** Increase/decrease current scanline intensity by given relative amount. */ @@ -100,7 +113,6 @@ class TIASurface @return New current intensity */ uInt32 enableScanlines(int relative, int absolute = 50); - void enableScanlineInterpolation(bool enable); /** Enable/disable/query phosphor effect. @@ -183,6 +195,9 @@ class TIASurface // Flag for saving a snapshot bool mySaveSnapFlag{false}; + // The palette handler + unique_ptrmyPaletteHandler; + private: // Following constructors and assignment operators not supported TIASurface() = delete; diff --git a/src/gui/CommandDialog.cxx b/src/gui/CommandDialog.cxx index 9efa56a7b..0d8729635 100644 --- a/src/gui/CommandDialog.cxx +++ b/src/gui/CommandDialog.cxx @@ -204,7 +204,7 @@ void CommandDialog::handleCommand(CommandSender* sender, int cmd, break; case kPaletteCmd: - instance().console().paletteHandler().changePalette(); + instance().frameBuffer().tiaSurface().paletteHandler().changePalette(); updatePalette(); break; diff --git a/src/gui/VideoDialog.cxx b/src/gui/VideoDialog.cxx index 606553562..610ba18ff 100644 --- a/src/gui/VideoDialog.cxx +++ b/src/gui/VideoDialog.cxx @@ -367,8 +367,8 @@ void VideoDialog::loadConfig() instance().settings().getString("palette"), "standard"); // Custom Palette - myPhaseShiftNtsc->setValue(instance().settings().getFloat("phase_ntsc") * 10); - myPhaseShiftPal->setValue(instance().settings().getFloat("phase_pal") * 10); + myPhaseShiftNtsc->setValue(instance().settings().getFloat("tv.phase_ntsc") * 10); + myPhaseShiftPal->setValue(instance().settings().getFloat("tv.phase_pal") * 10); handlePaletteChange(); // TIA interpolation @@ -413,6 +413,15 @@ void VideoDialog::loadConfig() int preset = instance().settings().getInt("tv.filter"); handleTVModeChange(NTSCFilter::Preset(preset)); + // Palette adjustables + PaletteHandler::Adjustable paletteAdj; + instance().frameBuffer().tiaSurface().paletteHandler().getAdjustables(paletteAdj); + myTVHue->setValue(paletteAdj.hue); + myTVBright->setValue(paletteAdj.brightness); + myTVContrast->setValue(paletteAdj.contrast); + myTVSatur->setValue(paletteAdj.saturation); + myTVGamma->setValue(paletteAdj.gamma); + // TV Custom adjustables loadTVAdjustables(NTSCFilter::Preset::CUSTOM); @@ -444,8 +453,8 @@ void VideoDialog::saveConfig() myTIAPalette->getSelectedTag().toString()); // Custom Palette - instance().settings().setValue("phase_ntsc", myPhaseShiftNtsc->getValue() / 10.0); - instance().settings().setValue("phase_pal", myPhaseShiftPal->getValue() / 10.0); + instance().settings().setValue("tv.phase_ntsc", myPhaseShiftNtsc->getValue() / 10.0); + instance().settings().setValue("tv.phase_pal", myPhaseShiftPal->getValue() / 10.0); // TIA interpolation instance().settings().setValue("tia.inter", myTIAInterpolate->getState()); @@ -490,19 +499,23 @@ void VideoDialog::saveConfig() instance().settings().setValue("tv.filter", myTVMode->getSelectedTag().toString()); + // Palette adjustables + PaletteHandler::Adjustable paletteAdj; + paletteAdj.hue = myTVHue->getValue(); + paletteAdj.saturation = myTVSatur->getValue(); + paletteAdj.contrast = myTVContrast->getValue(); + paletteAdj.brightness = myTVBright->getValue(); + paletteAdj.gamma = myTVGamma->getValue(); + instance().frameBuffer().tiaSurface().paletteHandler().setAdjustables(paletteAdj); + // TV Custom adjustables - NTSCFilter::Adjustable adj; - adj.hue = myTVHue->getValue(); - adj.saturation = myTVSatur->getValue(); - adj.contrast = myTVContrast->getValue(); - adj.brightness = myTVBright->getValue(); - adj.sharpness = myTVSharp->getValue(); - adj.gamma = myTVGamma->getValue(); - adj.resolution = myTVRes->getValue(); - adj.artifacts = myTVArtifacts->getValue(); - adj.fringing = myTVFringe->getValue(); - adj.bleed = myTVBleed->getValue(); - instance().frameBuffer().tiaSurface().ntsc().setCustomAdjustables(adj); + NTSCFilter::Adjustable ntscAdj; + ntscAdj.sharpness = myTVSharp->getValue(); + ntscAdj.resolution = myTVRes->getValue(); + ntscAdj.artifacts = myTVArtifacts->getValue(); + ntscAdj.fringing = myTVFringe->getValue(); + ntscAdj.bleed = myTVBleed->getValue(); + instance().frameBuffer().tiaSurface().ntsc().setCustomAdjustables(ntscAdj); // TV phosphor mode instance().settings().setValue("tv.phosphor", @@ -520,8 +533,8 @@ void VideoDialog::saveConfig() if(instance().settings().getString("palette") == "custom") { - instance().console().paletteHandler().generateCustomPalette(ConsoleTiming::ntsc); - instance().console().paletteHandler().generateCustomPalette(ConsoleTiming::pal); + instance().frameBuffer().tiaSurface().paletteHandler().generateCustomPalette(ConsoleTiming::ntsc); + instance().frameBuffer().tiaSurface().paletteHandler().generateCustomPalette(ConsoleTiming::pal); } if(vsizeChanged) @@ -595,15 +608,10 @@ void VideoDialog::handleTVModeChange(NTSCFilter::Preset preset) bool enable = preset == NTSCFilter::Preset::CUSTOM; myTVSharp->setEnabled(enable); - myTVHue->setEnabled(enable); myTVRes->setEnabled(enable); myTVArtifacts->setEnabled(enable); myTVFringe->setEnabled(enable); myTVBleed->setEnabled(enable); - myTVBright->setEnabled(enable); - myTVContrast->setEnabled(enable); - myTVSatur->setEnabled(enable); - myTVGamma->setEnabled(enable); myCloneComposite->setEnabled(enable); myCloneSvideo->setEnabled(enable); myCloneRGB->setEnabled(enable); @@ -618,15 +626,10 @@ void VideoDialog::loadTVAdjustables(NTSCFilter::Preset preset) instance().frameBuffer().tiaSurface().ntsc().getAdjustables( adj, NTSCFilter::Preset(preset)); myTVSharp->setValue(adj.sharpness); - myTVHue->setValue(adj.hue); myTVRes->setValue(adj.resolution); myTVArtifacts->setValue(adj.artifacts); myTVFringe->setValue(adj.fringing); myTVBleed->setValue(adj.bleed); - myTVBright->setValue(adj.brightness); - myTVContrast->setValue(adj.contrast); - myTVSatur->setValue(adj.saturation); - myTVGamma->setValue(adj.gamma); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/gui/Widget.hxx b/src/gui/Widget.hxx index eb31f7cd4..c2a0b6b65 100644 --- a/src/gui/Widget.hxx +++ b/src/gui/Widget.hxx @@ -31,6 +31,7 @@ namespace GUI { #include "bspf.hxx" #include "Event.hxx" +#include "StellaKeys.hxx" #include "GuiObject.hxx" #include "Font.hxx" From b660bd3466d77591bc1b4366f49ed0a240eb10d1 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 9 May 2020 23:00:16 +0200 Subject: [PATCH 191/377] started refactoring VideoDialog fixed selecting adjustable in NTSCFilter --- src/common/PaletteHandler.cxx | 29 +-- src/common/PaletteHandler.hxx | 10 +- src/common/tv_filters/NTSCFilter.cxx | 9 + src/gui/VideoDialog.cxx | 286 ++++++++++++++++----------- src/gui/VideoDialog.hxx | 3 + 5 files changed, 206 insertions(+), 131 deletions(-) diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index 4e61199d0..b260842b1 100644 --- a/src/common/PaletteHandler.cxx +++ b/src/common/PaletteHandler.cxx @@ -98,20 +98,22 @@ void PaletteHandler::changePalette(bool increase) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaletteHandler::selectAdjustable(bool next) { - if(next) - { - if(myCurrentAdjustable == NUM_ADJUSTABLES - 1) - myCurrentAdjustable = 0; - else + bool isCustomPalette = "custom" == myOSystem.settings().getString("palette"); + + do { + if(next) + { myCurrentAdjustable++; - } - else - { - if(myCurrentAdjustable == 0) - myCurrentAdjustable = NUM_ADJUSTABLES - 1; + myCurrentAdjustable %= NUM_ADJUSTABLES; + } else - myCurrentAdjustable--; - } + { + if(myCurrentAdjustable == 0) + myCurrentAdjustable = NUM_ADJUSTABLES - 1; + else + myCurrentAdjustable--; + } + } while(!isCustomPalette && myAdjustables[myCurrentAdjustable].value == nullptr); ostringstream buf; buf << "Palette adjustable '" << myAdjustables[myCurrentAdjustable].type @@ -123,8 +125,7 @@ void PaletteHandler::selectAdjustable(bool next) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaletteHandler::changeAdjustable(bool increase) { - - if(myCurrentAdjustable == NUM_ADJUSTABLES - 1) + if(myAdjustables[myCurrentAdjustable].value == nullptr) changeColorPhaseShift(increase); else { diff --git a/src/common/PaletteHandler.hxx b/src/common/PaletteHandler.hxx index d8e5518c0..995018e1e 100644 --- a/src/common/PaletteHandler.hxx +++ b/src/common/PaletteHandler.hxx @@ -96,8 +96,8 @@ class PaletteHandler MaxType = Custom }; - float scaleFrom100(float x) const { return (x / 100.F) - 1.F; } - uInt32 scaleTo100(float x) const { return uInt32(100 * (x + 1.F)); } + float scaleFrom100(float x) const { return (x / 50.F) - 1.F; } + uInt32 scaleTo100(float x) const { return uInt32(50 * (x + 1.F)); } PaletteType toPaletteType(const string& name) const; string toPaletteName(PaletteType type) const; @@ -125,12 +125,12 @@ class PaletteHandler }; const std::array myAdjustables = { { - { "contrast", &myContrast }, - { "brightness", &myBrightness }, + { "phase shift", nullptr }, { "hue", &myHue }, { "saturation", &mySaturation }, + { "contrast", &myContrast }, + { "brightness", &myBrightness }, { "gamma", &myGamma }, - { "phase shift", nullptr }, } }; // range -1.0 to +1.0 (as in AtariNTSC) diff --git a/src/common/tv_filters/NTSCFilter.cxx b/src/common/tv_filters/NTSCFilter.cxx index 9e46b6426..8a40ddd2c 100644 --- a/src/common/tv_filters/NTSCFilter.cxx +++ b/src/common/tv_filters/NTSCFilter.cxx @@ -77,7 +77,12 @@ string NTSCFilter::setNextAdjustable() if(myPreset != Preset::CUSTOM) return "'Custom' TV mode not selected"; +#ifdef BLARGG_PALETTE myCurrentAdjustable = (myCurrentAdjustable + 1) % 10; +#else + myCurrentAdjustable = (myCurrentAdjustable + 1) % 5; +#endif + ostringstream buf; buf << "Custom adjustable '" << ourCustomAdjustables[myCurrentAdjustable].type << "' selected"; @@ -91,7 +96,11 @@ string NTSCFilter::setPreviousAdjustable() if(myPreset != Preset::CUSTOM) return "'Custom' TV mode not selected"; +#ifdef BLARGG_PALETTE if(myCurrentAdjustable == 0) myCurrentAdjustable = 9; +#else + if(myCurrentAdjustable == 0) myCurrentAdjustable = 4; +#endif else --myCurrentAdjustable; ostringstream buf; buf << "Custom adjustable '" << ourCustomAdjustables[myCurrentAdjustable].type diff --git a/src/gui/VideoDialog.cxx b/src/gui/VideoDialog.cxx index 610ba18ff..bc890ede1 100644 --- a/src/gui/VideoDialog.cxx +++ b/src/gui/VideoDialog.cxx @@ -79,21 +79,14 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, int max_w, int max_h) : Dialog(osystem, parent, font, "Video settings") { - const int lineHeight = font.getLineHeight(), - fontHeight = font.getFontHeight(), - fontWidth = font.getMaxCharWidth(), - buttonHeight = font.getLineHeight() * 1.25; + const int lineHeight = _font.getLineHeight(), + fontHeight = _font.getFontHeight(), + fontWidth = _font.getMaxCharWidth(), + buttonHeight = _font.getLineHeight() * 1.25; const int VGAP = fontHeight / 4; const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; - const int INDENT = fontWidth * 2; - - int xpos, ypos, tabID; - int lwidth = font.getStringWidth("V-Size adjust "), - pwidth = font.getStringWidth("XXXXxXXXX"); - - WidgetArray wid; - VariantList items; + int xpos, ypos; // Set real dimensions setSize(57 * fontWidth + HBORDER * 2 + PopUpWidget::dropDownWidth(font) * 2, @@ -107,65 +100,69 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, _h - _th - VGAP - buttonHeight - VBORDER * 2); addTabWidget(myTab); - xpos = HBORDER; ypos = VBORDER; - ////////////////////////////////////////////////////////// - // 1) General options + addGeneralTab(); + addPaletteTab(); + addTVEffectsTab(); + + // Add Defaults, OK and Cancel buttons + WidgetArray wid; + addDefaultsOKCancelBGroup(wid, _font); + addBGroupToFocusList(wid); + + // Activate the first tab + myTab->setActiveTab(0); + + // Disable certain functions when we know they aren't present +#ifndef WINDOWED_SUPPORT + myFullscreen->clearFlags(Widget::FLAG_ENABLED); + myCenter->clearFlags(Widget::FLAG_ENABLED); +#endif +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void VideoDialog::addGeneralTab() +{ + const int lineHeight = _font.getLineHeight(), + fontHeight = _font.getFontHeight(), + fontWidth = _font.getMaxCharWidth(), + buttonHeight = _font.getLineHeight() * 1.25; + const int VGAP = fontHeight / 4; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = fontWidth * 2; + + int xpos, ypos, tabID; + int lwidth = _font.getStringWidth("V-Size adjust "), + pwidth = _font.getStringWidth("XXXXxXXXX"), + swidth = fontWidth * 8 - fontWidth / 2; + WidgetArray wid; + VariantList items; + tabID = myTab->addTab(" General "); + xpos = HBORDER; ypos = VBORDER; // Video renderer - myRenderer = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, + myRenderer = new PopUpWidget(myTab, _font, xpos, ypos, pwidth, lineHeight, instance().frameBuffer().supportedRenderers(), "Renderer ", lwidth); wid.push_back(myRenderer); ypos += lineHeight + VGAP; - // TIA Palette - items.clear(); - VarList::push_back(items, "Standard", "standard"); - VarList::push_back(items, "z26", "z26"); - if (instance().checkUserPalette()) - VarList::push_back(items, "User", "user"); - VarList::push_back(items, "Custom", "custom"); - myTIAPalette = new PopUpWidget(myTab, font, xpos, ypos, pwidth, - lineHeight, items, "Palette ", lwidth, kPaletteChanged); - wid.push_back(myTIAPalette); - ypos += lineHeight + VGAP; - - int swidth = myTIAPalette->getWidth() - lwidth; - int plWidth = font.getStringWidth("NTSC phase "); - int pswidth = swidth - INDENT + lwidth - plWidth; - - myPhaseShiftNtsc = - new SliderWidget(myTab, font, xpos + INDENT, ypos-1, pswidth, lineHeight, - "NTSC phase", plWidth, kNtscShiftChanged, fontWidth * 5); - myPhaseShiftNtsc->setMinValue(262 - 45); myPhaseShiftNtsc->setMaxValue(262 + 45); - myPhaseShiftNtsc->setTickmarkIntervals(4); - wid.push_back(myPhaseShiftNtsc); - ypos += lineHeight + VGAP; - - myPhaseShiftPal = - new SliderWidget(myTab, font, xpos + INDENT, ypos-1, pswidth, lineHeight, - "PAL phase", plWidth, kPalShiftChanged, fontWidth * 5); - myPhaseShiftPal->setMinValue(313 - 45); myPhaseShiftPal->setMaxValue(313 + 45); - myPhaseShiftPal->setTickmarkIntervals(4); - wid.push_back(myPhaseShiftPal); - ypos += lineHeight + VGAP * 4; - // TIA interpolation - myTIAInterpolate = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Interpolation "); + myTIAInterpolate = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Interpolation "); wid.push_back(myTIAInterpolate); ypos += lineHeight + VGAP; // TIA zoom levels (will be dynamically filled later) - myTIAZoom = new SliderWidget(myTab, font, xpos, ypos - 1, swidth, lineHeight, - "Zoom ", lwidth, 0, fontWidth * 4, "%"); + myTIAZoom = new SliderWidget(myTab, _font, xpos, ypos - 1, swidth, lineHeight, + "Zoom ", lwidth, 0, fontWidth * 4, "%"); myTIAZoom->setMinValue(200); myTIAZoom->setStepValue(FrameBuffer::ZOOM_STEPS * 100); wid.push_back(myTIAZoom); ypos += lineHeight + VGAP; // Aspect ratio (NTSC mode) myVSizeAdjust = - new SliderWidget(myTab, font, xpos, ypos-1, swidth, lineHeight, + new SliderWidget(myTab, _font, xpos, ypos-1, swidth, lineHeight, "V-Size adjust", lwidth, kVSizeChanged, fontWidth * 7, "%", 0, true); myVSizeAdjust->setMinValue(-5); myVSizeAdjust->setMaxValue(5); myVSizeAdjust->setTickmarkIntervals(2); @@ -174,7 +171,7 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, // Speed mySpeed = - new SliderWidget(myTab, font, xpos, ypos-1, swidth, lineHeight, + new SliderWidget(myTab, _font, xpos, ypos-1, swidth, lineHeight, "Emul. speed ", lwidth, kSpeedupChanged, fontWidth * 5, "%"); mySpeed->setMinValue(MIN_SPEED); mySpeed->setMaxValue(MAX_SPEED); mySpeed->setStepValue(SPEED_STEP); @@ -183,7 +180,7 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, ypos += lineHeight + VGAP; // Use sync to vblank - myUseVSync = new CheckboxWidget(myTab, font, xpos, ypos + 1, "VSync"); + myUseVSync = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "VSync"); wid.push_back(myUseVSync); // Move over to the next column @@ -191,7 +188,7 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, ypos = VBORDER; // Fullscreen - myFullscreen = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Fullscreen", kFullScreenChanged); + myFullscreen = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Fullscreen", kFullScreenChanged); wid.push_back(myFullscreen); ypos += lineHeight + VGAP; @@ -202,13 +199,13 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, ypos += lineHeight + VGAP;*/ // FS stretch - myUseStretch = new CheckboxWidget(myTab, font, xpos + INDENT, ypos + 1, "Stretch"); + myUseStretch = new CheckboxWidget(myTab, _font, xpos + INDENT, ypos + 1, "Stretch"); wid.push_back(myUseStretch); ypos += lineHeight + VGAP; // FS overscan - myTVOverscan = new SliderWidget(myTab, font, xpos + INDENT, ypos - 1, swidth, lineHeight, - "Overscan", font.getStringWidth("Overscan "), kOverscanChanged, fontWidth * 3, "%"); + myTVOverscan = new SliderWidget(myTab, _font, xpos + INDENT, ypos - 1, swidth, lineHeight, + "Overscan", _font.getStringWidth("Overscan "), kOverscanChanged, fontWidth * 3, "%"); myTVOverscan->setMinValue(0); myTVOverscan->setMaxValue(10); myTVOverscan->setTickmarkIntervals(2); wid.push_back(myTVOverscan); @@ -216,36 +213,120 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, // Skip progress load bars for SuperCharger ROMs // Doesn't really belong here, but I couldn't find a better place for it - myFastSCBios = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Fast SuperCharger load"); + myFastSCBios = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Fast SuperCharger load"); wid.push_back(myFastSCBios); ypos += lineHeight + VGAP; // Show UI messages onscreen - myUIMessages = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Show UI messages"); + myUIMessages = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Show UI messages"); wid.push_back(myUIMessages); ypos += lineHeight + VGAP; // Center window (in windowed mode) - myCenter = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Center window"); + myCenter = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Center window"); wid.push_back(myCenter); ypos += (lineHeight + VGAP) * 2; // Use multi-threading - myUseThreads = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Multi-threading"); + myUseThreads = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Multi-threading"); wid.push_back(myUseThreads); // Add items for tab 0 addToFocusList(wid, myTab, tabID); +} - ////////////////////////////////////////////////////////// - // 2) TV effects options - wid.clear(); - tabID = myTab->addTab(" TV Effects "); - xpos = HBORDER; - ypos = VBORDER; - swidth = fontWidth * 8 - fontWidth / 2; +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void VideoDialog::addPaletteTab() +{ + const int lineHeight = _font.getLineHeight(), + fontHeight = _font.getFontHeight(), + fontWidth = _font.getMaxCharWidth(), + buttonHeight = _font.getLineHeight() * 1.25; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = fontWidth * 2; + const int VGAP = fontHeight / 4; + int xpos = HBORDER, + ypos = VBORDER; + int swidth = fontWidth * 8 - fontWidth / 2; + int lwidth = _font.getStringWidth("Saturation "); + int pwidth = _font.getStringWidth("Standard"); + WidgetArray wid; + VariantList items; + + int tabID = myTab->addTab(" Palettes "); + + // TIA Palette + items.clear(); + VarList::push_back(items, "Standard", "standard"); + VarList::push_back(items, "z26", "z26"); + if (instance().checkUserPalette()) + VarList::push_back(items, "User", "user"); + VarList::push_back(items, "Custom", "custom"); + myTIAPalette = new PopUpWidget(myTab, _font, xpos, ypos, pwidth, + lineHeight, items, "Palette ", lwidth, kPaletteChanged); + wid.push_back(myTIAPalette); + ypos += lineHeight + VGAP; + + swidth = myTIAPalette->getWidth() - lwidth; + int plWidth = _font.getStringWidth("NTSC phase "); + int pswidth = swidth - INDENT + lwidth - plWidth; + + myPhaseShiftNtsc = + new SliderWidget(myTab, _font, xpos + INDENT, ypos-1, pswidth, lineHeight, + "NTSC phase", plWidth, kNtscShiftChanged, fontWidth * 5); + myPhaseShiftNtsc->setMinValue(262 - 45); myPhaseShiftNtsc->setMaxValue(262 + 45); + myPhaseShiftNtsc->setTickmarkIntervals(4); + wid.push_back(myPhaseShiftNtsc); + ypos += lineHeight + VGAP; + + myPhaseShiftPal = + new SliderWidget(myTab, _font, xpos + INDENT, ypos-1, pswidth, lineHeight, + "PAL phase", plWidth, kPalShiftChanged, fontWidth * 5); + myPhaseShiftPal->setMinValue(313 - 45); myPhaseShiftPal->setMaxValue(313 + 45); + myPhaseShiftPal->setTickmarkIntervals(4); + wid.push_back(myPhaseShiftPal); + ypos += lineHeight + VGAP; + +#define CREATE_CUSTOM_SLIDERS(obj, desc, cmd) \ + myTV ## obj = \ + new SliderWidget(myTab, _font, xpos, ypos-1, swidth, lineHeight, \ + desc, lwidth, cmd, fontWidth*4, "%"); \ + myTV ## obj->setMinValue(0); myTV ## obj->setMaxValue(100); \ + myTV ## obj->setTickmarkIntervals(2); \ + wid.push_back(myTV ## obj); \ + ypos += lineHeight + VGAP; + + CREATE_CUSTOM_SLIDERS(Hue, "Hue ", 0) + CREATE_CUSTOM_SLIDERS(Satur, "Saturation ", 0) + CREATE_CUSTOM_SLIDERS(Contrast, "Contrast ", 0) + CREATE_CUSTOM_SLIDERS(Bright, "Brightness ", 0) + CREATE_CUSTOM_SLIDERS(Gamma, "Gamma ", 0) + + // Add items for tab 2 + addToFocusList(wid, myTab, tabID); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void VideoDialog::addTVEffectsTab() +{ + const int lineHeight = _font.getLineHeight(), + fontHeight = _font.getFontHeight(), + fontWidth = _font.getMaxCharWidth(), + buttonHeight = _font.getLineHeight() * 1.25; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = fontWidth * 2; + const int VGAP = fontHeight / 4; + int xpos = HBORDER, + ypos = VBORDER; + int swidth = fontWidth * 8 - fontWidth / 2; + int lwidth = _font.getStringWidth("TV Mode "); + int pwidth = _font.getStringWidth("Bad adjust"); + WidgetArray wid; + VariantList items; + int tabID = myTab->addTab(" TV Effects "); - // TV Mode items.clear(); VarList::push_back(items, "Disabled", static_cast(NTSCFilter::Preset::OFF)); VarList::push_back(items, "RGB", static_cast(NTSCFilter::Preset::RGB)); @@ -253,32 +334,25 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, VarList::push_back(items, "Composite", static_cast(NTSCFilter::Preset::COMPOSITE)); VarList::push_back(items, "Bad adjust", static_cast(NTSCFilter::Preset::BAD)); VarList::push_back(items, "Custom", static_cast(NTSCFilter::Preset::CUSTOM)); - lwidth = font.getStringWidth("TV Mode "); - pwidth = font.getStringWidth("Bad adjust"); myTVMode = - new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, + new PopUpWidget(myTab, _font, xpos, ypos, pwidth, lineHeight, items, "TV mode ", lwidth, kTVModeChanged); wid.push_back(myTVMode); ypos += lineHeight + VGAP; // Custom adjustables (using macro voodoo) xpos += INDENT - 2; ypos += 0; - lwidth = font.getStringWidth("Saturation "); + lwidth = _font.getStringWidth("Saturation "); #define CREATE_CUSTOM_SLIDERS(obj, desc, cmd) \ myTV ## obj = \ - new SliderWidget(myTab, font, xpos, ypos-1, swidth, lineHeight, \ + new SliderWidget(myTab, _font, xpos, ypos-1, swidth, lineHeight, \ desc, lwidth, cmd, fontWidth*4, "%"); \ myTV ## obj->setMinValue(0); myTV ## obj->setMaxValue(100); \ myTV ## obj->setTickmarkIntervals(2); \ wid.push_back(myTV ## obj); \ ypos += lineHeight + VGAP; - CREATE_CUSTOM_SLIDERS(Contrast, "Contrast ", 0) - CREATE_CUSTOM_SLIDERS(Bright, "Brightness ", 0) - CREATE_CUSTOM_SLIDERS(Hue, "Hue ", 0) - CREATE_CUSTOM_SLIDERS(Satur, "Saturation ", 0) - CREATE_CUSTOM_SLIDERS(Gamma, "Gamma ", 0) CREATE_CUSTOM_SLIDERS(Sharp, "Sharpness ", 0) CREATE_CUSTOM_SLIDERS(Res, "Resolution ", 0) CREATE_CUSTOM_SLIDERS(Artifacts, "Artifacts ", 0) @@ -288,22 +362,22 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, xpos += myTVContrast->getWidth() + fontWidth * 6; ypos = VBORDER; - lwidth = font.getStringWidth("Intensity "); + lwidth = _font.getStringWidth("Intensity "); // TV Phosphor effect - myTVPhosphor = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Phosphor for all ROMs", kPhosphorChanged); + myTVPhosphor = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Phosphor for all ROMs", kPhosphorChanged); wid.push_back(myTVPhosphor); ypos += lineHeight + VGAP / 2; // TV Phosphor blend level xpos += INDENT; - swidth = font.getMaxCharWidth() * 10; + swidth = _font.getMaxCharWidth() * 10; CREATE_CUSTOM_SLIDERS(PhosLevel, "Blend ", kPhosBlendChanged) - ypos += VGAP * 2; + ypos += VGAP * 2; // Scanline intensity and interpolation xpos -= INDENT; - myTVScanLabel = new StaticTextWidget(myTab, font, xpos, ypos, "Scanlines:"); + myTVScanLabel = new StaticTextWidget(myTab, _font, xpos, ypos, "Scanlines:"); ypos += lineHeight + VGAP / 2; xpos += INDENT; @@ -312,10 +386,10 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, // Adjustable presets xpos -= INDENT; - int cloneWidth = font.getStringWidth("Clone Bad Adjust") + 20; + int cloneWidth = _font.getStringWidth("Clone Bad Adjust") + 20; #define CREATE_CLONE_BUTTON(obj, desc) \ myClone ## obj = \ - new ButtonWidget(myTab, font, xpos, ypos, cloneWidth, buttonHeight,\ + new ButtonWidget(myTab, _font, xpos, ypos, cloneWidth, buttonHeight,\ desc, kClone ## obj ##Cmd); \ wid.push_back(myClone ## obj); \ ypos += buttonHeight + VGAP; @@ -327,22 +401,8 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, CREATE_CLONE_BUTTON(Bad, "Clone Bad adjust") CREATE_CLONE_BUTTON(Custom, "Revert") - // Add items for tab 2 + // Add items for tab 3 addToFocusList(wid, myTab, tabID); - - // Activate the first tab - myTab->setActiveTab(0); - - // Add Defaults, OK and Cancel buttons - wid.clear(); - addDefaultsOKCancelBGroup(wid, font); - addBGroupToFocusList(wid); - - // Disable certain functions when we know they aren't present -#ifndef WINDOWED_SUPPORT - myFullscreen->clearFlags(Widget::FLAG_ENABLED); - myCenter->clearFlags(Widget::FLAG_ENABLED); -#endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -531,12 +591,6 @@ void VideoDialog::saveConfig() { instance().console().setTIAProperties(); - if(instance().settings().getString("palette") == "custom") - { - instance().frameBuffer().tiaSurface().paletteHandler().generateCustomPalette(ConsoleTiming::ntsc); - instance().frameBuffer().tiaSurface().paletteHandler().generateCustomPalette(ConsoleTiming::pal); - } - if(vsizeChanged) { instance().console().tia().clearFrameBuffer(); @@ -560,9 +614,6 @@ void VideoDialog::setDefaults() { myRenderer->setSelectedIndex(0); myTIAZoom->setValue(300); - myTIAPalette->setSelected("standard", ""); - myPhaseShiftNtsc->setValue(262); - myPhaseShiftPal->setValue(313); myTIAInterpolate->setState(false); myVSizeAdjust->setValue(0); mySpeed->setValue(0); @@ -580,7 +631,18 @@ void VideoDialog::setDefaults() break; } - case 1: // TV effects + case 1: // Palettes + myTIAPalette->setSelected("standard", ""); + myPhaseShiftNtsc->setValue(262); + myPhaseShiftPal->setValue(313); + myTVHue->setValue(50); + myTVSatur->setValue(50); + myTVContrast->setValue(50); + myTVBright->setValue(50); + myTVGamma->setValue(50); + break; + + case 2: // TV effects { myTVMode->setSelected("0", "0"); diff --git a/src/gui/VideoDialog.hxx b/src/gui/VideoDialog.hxx index 429290082..459990e13 100644 --- a/src/gui/VideoDialog.hxx +++ b/src/gui/VideoDialog.hxx @@ -43,6 +43,9 @@ class VideoDialog : public Dialog void saveConfig() override; void setDefaults() override; + void addGeneralTab(); + void addPaletteTab(); + void addTVEffectsTab(); void handleTVModeChange(NTSCFilter::Preset); void loadTVAdjustables(NTSCFilter::Preset preset); void handlePaletteChange(); From 8fc7413d8f1dc646d0fa138f232e12754afccf45 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 10 May 2020 12:46:54 +0200 Subject: [PATCH 192/377] improved VideoDialog alignment moved "Center Windows" to UIDialog --- src/gui/UIDialog.cxx | 45 ++++++++----- src/gui/UIDialog.hxx | 3 +- src/gui/VideoDialog.cxx | 136 +++++++++++++++++----------------------- src/gui/VideoDialog.hxx | 4 +- 4 files changed, 95 insertions(+), 93 deletions(-) diff --git a/src/gui/UIDialog.cxx b/src/gui/UIDialog.cxx index 099886b9b..94032a4ce 100644 --- a/src/gui/UIDialog.cxx +++ b/src/gui/UIDialog.cxx @@ -105,12 +105,13 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, wid.push_back(myDialogFontPopup); // Enable HiDPI mode - myHidpiWidget = new CheckboxWidget(myTab, font, myDialogFontPopup->getRight() + fontWidth * 5, + xpos = myDialogFontPopup->getRight() + fontWidth * 5; + myHidpiWidget = new CheckboxWidget(myTab, font, xpos, ypos + 1, "HiDPI mode (*)"); wid.push_back(myHidpiWidget); - ypos += lineHeight + VGAP; // Dialog position + xpos = HBORDER; ypos += lineHeight + VGAP; items.clear(); VarList::push_back(items, "Centered", 0); VarList::push_back(items, "Left top", 1); @@ -120,9 +121,14 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, myPositionPopup = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, "Dialogs position", lwidth); wid.push_back(myPositionPopup); - ypos += lineHeight + VGAP * 2; + + // Center window (in windowed mode) + xpos = myHidpiWidget->getLeft(); + myCenter = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Center windows"); + wid.push_back(myCenter); // Confirm dialog when exiting emulation + xpos = HBORDER; ypos += lineHeight + VGAP * 2; myConfirmExitWidget = new CheckboxWidget(myTab, font, xpos, ypos, "Confirm exiting emulation"); wid.push_back(myConfirmExitWidget); ypos += lineHeight + VGAP * 3; @@ -303,6 +309,10 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, wid.clear(); addDefaultsOKCancelBGroup(wid, font); addBGroupToFocusList(wid); + +#ifndef WINDOWED_SUPPORT + myCenter->clearFlags(Widget::FLAG_ENABLED); +#endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -353,6 +363,10 @@ void UIDialog::loadConfig() const string& pal = settings.getString("uipalette"); myPalettePopup->setSelected(pal, "standard"); + // Dialog font + const string& dialogFont = settings.getString("dialogfont"); + myDialogFontPopup->setSelected(dialogFont, "medium"); + // Enable HiDPI mode if (!instance().frameBuffer().hidpiAllowed()) { @@ -364,16 +378,15 @@ void UIDialog::loadConfig() myHidpiWidget->setState(settings.getBool("hidpi")); } - // Confirm dialog when exiting emulation - myConfirmExitWidget->setState(settings.getBool("confirmexit")); - - // Dialog font - const string& dialogFont = settings.getString("dialogfont"); - myDialogFontPopup->setSelected(dialogFont, "medium"); - // Dialog position myPositionPopup->setSelected(settings.getString("dialogpos"), "0"); + // Center window + myCenter->setState(settings.getBool("center")); + + // Confirm dialog when exiting emulation + myConfirmExitWidget->setState(settings.getBool("confirmexit")); + // Listwidget quick delay int delay = settings.getInt("listdelay"); myListDelaySlider->setValue(delay); @@ -436,16 +449,19 @@ void UIDialog::saveConfig() myPalettePopup->getSelectedTag().toString()); instance().frameBuffer().setUIPalette(); - // Enable HiDPI mode - settings.setValue("hidpi", myHidpiWidget->getState()); - // Dialog font settings.setValue("dialogfont", myDialogFontPopup->getSelectedTag().toString()); + // Enable HiDPI mode + settings.setValue("hidpi", myHidpiWidget->getState()); + // Dialog position settings.setValue("dialogpos", myPositionPopup->getSelectedTag().toString()); + // Center window + settings.setValue("center", myCenter->getState()); + // Confirm dialog when exiting emulation settings.setValue("confirmexit", myConfirmExitWidget->getState()); @@ -481,9 +497,10 @@ void UIDialog::setDefaults() { case 0: // Misc. options myPalettePopup->setSelected("standard"); - myHidpiWidget->setState(false); myDialogFontPopup->setSelected("medium", ""); + myHidpiWidget->setState(false); myPositionPopup->setSelected("0"); + myCenter->setState(false); myConfirmExitWidget->setState(false); myListDelaySlider->setValue(300); myWheelLinesSlider->setValue(4); diff --git a/src/gui/UIDialog.hxx b/src/gui/UIDialog.hxx index 83851e971..91bc7ff82 100644 --- a/src/gui/UIDialog.hxx +++ b/src/gui/UIDialog.hxx @@ -66,9 +66,10 @@ class UIDialog : public Dialog, public CommandSender // Misc options PopUpWidget* myPalettePopup{nullptr}; - CheckboxWidget* myHidpiWidget{nullptr}; PopUpWidget* myDialogFontPopup{nullptr}; + CheckboxWidget* myHidpiWidget{nullptr}; PopUpWidget* myPositionPopup{nullptr}; + CheckboxWidget* myCenter{nullptr}; CheckboxWidget* myConfirmExitWidget{nullptr}; SliderWidget* myListDelaySlider{nullptr}; SliderWidget* myWheelLinesSlider{nullptr}; diff --git a/src/gui/VideoDialog.cxx b/src/gui/VideoDialog.cxx index bc890ede1..26ed93a33 100644 --- a/src/gui/VideoDialog.cxx +++ b/src/gui/VideoDialog.cxx @@ -115,7 +115,8 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, // Disable certain functions when we know they aren't present #ifndef WINDOWED_SUPPORT myFullscreen->clearFlags(Widget::FLAG_ENABLED); - myCenter->clearFlags(Widget::FLAG_ENABLED); + myUseStretch->clearFlags(Widget::FLAG_ENABLED); + myTVOverscan->clearFlags(Widget::FLAG_ENABLED); #endif } @@ -129,17 +130,14 @@ void VideoDialog::addGeneralTab() const int VGAP = fontHeight / 4; const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; - const int INDENT = fontWidth * 2; - - int xpos, ypos, tabID; - int lwidth = _font.getStringWidth("V-Size adjust "), - pwidth = _font.getStringWidth("XXXXxXXXX"), - swidth = fontWidth * 8 - fontWidth / 2; + const int INDENT = CheckboxWidget::prefixSize(_font); + const int lwidth = _font.getStringWidth("V-Size adjust "), + pwidth = _font.getStringWidth("XXXXxXXXX"); + int xpos = HBORDER, + ypos = VBORDER; WidgetArray wid; VariantList items; - - tabID = myTab->addTab(" General "); - xpos = HBORDER; ypos = VBORDER; + const int tabID = myTab->addTab(" General "); // Video renderer myRenderer = new PopUpWidget(myTab, _font, xpos, ypos, pwidth, lineHeight, @@ -150,8 +148,32 @@ void VideoDialog::addGeneralTab() // TIA interpolation myTIAInterpolate = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Interpolation "); - wid.push_back(myTIAInterpolate); ypos += lineHeight + VGAP; + wid.push_back(myTIAInterpolate); ypos += lineHeight + VGAP * 4; + // Fullscreen + myFullscreen = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Fullscreen", kFullScreenChanged); + 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); + ypos += lineHeight + VGAP; + + // FS overscan + const int swidth = myRenderer->getWidth() - lwidth; + 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; // TIA zoom levels (will be dynamically filled later) myTIAZoom = new SliderWidget(myTab, _font, xpos, ypos - 1, swidth, lineHeight, @@ -160,14 +182,14 @@ void VideoDialog::addGeneralTab() wid.push_back(myTIAZoom); ypos += lineHeight + VGAP; - // Aspect ratio (NTSC mode) + // Vertical size myVSizeAdjust = new SliderWidget(myTab, _font, xpos, ypos-1, swidth, lineHeight, "V-Size adjust", lwidth, kVSizeChanged, fontWidth * 7, "%", 0, true); myVSizeAdjust->setMinValue(-5); myVSizeAdjust->setMaxValue(5); myVSizeAdjust->setTickmarkIntervals(2); wid.push_back(myVSizeAdjust); - ypos += lineHeight + VGAP; + ypos += lineHeight + VGAP * 4; // Speed mySpeed = @@ -187,30 +209,6 @@ void VideoDialog::addGeneralTab() xpos = myVSizeAdjust->getRight() + fontWidth * 3; ypos = VBORDER; - // Fullscreen - myFullscreen = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Fullscreen", kFullScreenChanged); - 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); - ypos += lineHeight + VGAP; - - // FS overscan - myTVOverscan = new SliderWidget(myTab, _font, xpos + INDENT, ypos - 1, swidth, lineHeight, - "Overscan", _font.getStringWidth("Overscan "), kOverscanChanged, fontWidth * 3, "%"); - myTVOverscan->setMinValue(0); myTVOverscan->setMaxValue(10); - myTVOverscan->setTickmarkIntervals(2); - wid.push_back(myTVOverscan); - ypos += (lineHeight + VGAP) * 2; - // Skip progress load bars for SuperCharger ROMs // Doesn't really belong here, but I couldn't find a better place for it myFastSCBios = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Fast SuperCharger load"); @@ -222,11 +220,6 @@ void VideoDialog::addGeneralTab() wid.push_back(myUIMessages); ypos += lineHeight + VGAP; - // Center window (in windowed mode) - myCenter = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Center window"); - wid.push_back(myCenter); - ypos += (lineHeight + VGAP) * 2; - // Use multi-threading myUseThreads = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Multi-threading"); wid.push_back(myUseThreads); @@ -246,15 +239,13 @@ void VideoDialog::addPaletteTab() const int HBORDER = fontWidth * 1.25; const int INDENT = fontWidth * 2; const int VGAP = fontHeight / 4; + const int lwidth = _font.getStringWidth(" NTSC phase "); + const int pwidth = _font.getStringWidth("Standard"); int xpos = HBORDER, ypos = VBORDER; - int swidth = fontWidth * 8 - fontWidth / 2; - int lwidth = _font.getStringWidth("Saturation "); - int pwidth = _font.getStringWidth("Standard"); WidgetArray wid; VariantList items; - - int tabID = myTab->addTab(" Palettes "); + const int tabID = myTab->addTab(" Palettes "); // TIA Palette items.clear(); @@ -268,9 +259,9 @@ void VideoDialog::addPaletteTab() wid.push_back(myTIAPalette); ypos += lineHeight + VGAP; - swidth = myTIAPalette->getWidth() - lwidth; - int plWidth = _font.getStringWidth("NTSC phase "); - int pswidth = swidth - INDENT + lwidth - plWidth; + const int swidth = myTIAPalette->getWidth() - lwidth; + const int plWidth = _font.getStringWidth("NTSC phase "); + const int pswidth = swidth - INDENT + lwidth - plWidth; myPhaseShiftNtsc = new SliderWidget(myTab, _font, xpos + INDENT, ypos-1, pswidth, lineHeight, @@ -316,16 +307,15 @@ void VideoDialog::addTVEffectsTab() buttonHeight = _font.getLineHeight() * 1.25; const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; - const int INDENT = fontWidth * 2; + const int INDENT = CheckboxWidget::prefixSize(_font);// fontWidth * 2; const int VGAP = fontHeight / 4; int xpos = HBORDER, ypos = VBORDER; - int swidth = fontWidth * 8 - fontWidth / 2; - int lwidth = _font.getStringWidth("TV Mode "); - int pwidth = _font.getStringWidth("Bad adjust"); + const int lwidth = _font.getStringWidth("Saturation "); + const int pwidth = _font.getStringWidth("Bad adjust "); WidgetArray wid; VariantList items; - int tabID = myTab->addTab(" TV Effects "); + const int tabID = myTab->addTab(" TV Effects "); items.clear(); VarList::push_back(items, "Disabled", static_cast(NTSCFilter::Preset::OFF)); @@ -334,15 +324,14 @@ void VideoDialog::addTVEffectsTab() VarList::push_back(items, "Composite", static_cast(NTSCFilter::Preset::COMPOSITE)); VarList::push_back(items, "Bad adjust", static_cast(NTSCFilter::Preset::BAD)); VarList::push_back(items, "Custom", static_cast(NTSCFilter::Preset::CUSTOM)); - myTVMode = - new PopUpWidget(myTab, _font, xpos, ypos, pwidth, lineHeight, - items, "TV mode ", lwidth, kTVModeChanged); + myTVMode = new PopUpWidget(myTab, _font, xpos, ypos, pwidth, lineHeight, + items, "TV mode ", 0, kTVModeChanged); wid.push_back(myTVMode); ypos += lineHeight + VGAP; // Custom adjustables (using macro voodoo) - xpos += INDENT - 2; ypos += 0; - lwidth = _font.getStringWidth("Saturation "); + const int swidth = myTVMode->getWidth() - INDENT - lwidth; + xpos += INDENT; #define CREATE_CUSTOM_SLIDERS(obj, desc, cmd) \ myTV ## obj = \ @@ -359,10 +348,9 @@ void VideoDialog::addTVEffectsTab() CREATE_CUSTOM_SLIDERS(Fringe, "Fringing ", 0) CREATE_CUSTOM_SLIDERS(Bleed, "Bleeding ", 0) - xpos += myTVContrast->getWidth() + fontWidth * 6; - ypos = VBORDER; + ypos += VGAP * 3; - lwidth = _font.getStringWidth("Intensity "); + xpos = HBORDER; // TV Phosphor effect myTVPhosphor = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Phosphor for all ROMs", kPhosphorChanged); @@ -371,9 +359,8 @@ void VideoDialog::addTVEffectsTab() // TV Phosphor blend level xpos += INDENT; - swidth = _font.getMaxCharWidth() * 10; - CREATE_CUSTOM_SLIDERS(PhosLevel, "Blend ", kPhosBlendChanged) - ypos += VGAP * 2; + CREATE_CUSTOM_SLIDERS(PhosLevel, "Blend", kPhosBlendChanged) + ypos += VGAP; // Scanline intensity and interpolation xpos -= INDENT; @@ -381,12 +368,14 @@ void VideoDialog::addTVEffectsTab() ypos += lineHeight + VGAP / 2; xpos += INDENT; - CREATE_CUSTOM_SLIDERS(ScanIntense, "Intensity ", kScanlinesChanged) - ypos += VGAP * 3; + CREATE_CUSTOM_SLIDERS(ScanIntense, "Intensity", kScanlinesChanged) + + // Create buttons in 2nd column + xpos = myTVSharp->getRight() + fontWidth * 2; + ypos = VBORDER - VGAP / 2; // Adjustable presets - xpos -= INDENT; - int cloneWidth = _font.getStringWidth("Clone Bad Adjust") + 20; + int cloneWidth = _font.getStringWidth("Clone Bad Adjust") + fontWidth * 2.5; #define CREATE_CLONE_BUTTON(obj, desc) \ myClone ## obj = \ new ButtonWidget(myTab, _font, xpos, ypos, cloneWidth, buttonHeight,\ @@ -458,9 +447,6 @@ void VideoDialog::loadConfig() // Show UI messages myUIMessages->setState(instance().settings().getBool("uimessages")); - // Center window - myCenter->setState(instance().settings().getBool("center")); - // Fast loading of Supercharger BIOS myFastSCBios->setState(instance().settings().getBool("fastscbios")); @@ -544,9 +530,6 @@ void VideoDialog::saveConfig() // Show UI messages instance().settings().setValue("uimessages", myUIMessages->getState()); - // Center window - instance().settings().setValue("center", myCenter->getState()); - // Fast loading of Supercharger BIOS instance().settings().setValue("fastscbios", myFastSCBios->getState()); @@ -623,7 +606,6 @@ void VideoDialog::setDefaults() myUseStretch->setState(false); myUseVSync->setState(true); myUIMessages->setState(true); - myCenter->setState(false); myFastSCBios->setState(true); myUseThreads->setState(false); diff --git a/src/gui/VideoDialog.hxx b/src/gui/VideoDialog.hxx index 459990e13..d780a508f 100644 --- a/src/gui/VideoDialog.hxx +++ b/src/gui/VideoDialog.hxx @@ -22,6 +22,7 @@ class CommandSender; class CheckboxWidget; class DialogContainer; class PopUpWidget; +class RadioButtonGroup; class SliderWidget; class StaticTextWidget; class TabWidget; @@ -67,13 +68,13 @@ class VideoDialog : public Dialog SliderWidget* myVSizeAdjust{nullptr}; SliderWidget* mySpeed{nullptr}; + RadioButtonGroup* myZoomGroup{nullptr}; CheckboxWidget* myFullscreen{nullptr}; //PopUpWidget* myFullScreenMode; CheckboxWidget* myUseStretch{nullptr}; SliderWidget* myTVOverscan{nullptr}; CheckboxWidget* myUseVSync{nullptr}; CheckboxWidget* myUIMessages{nullptr}; - CheckboxWidget* myCenter{nullptr}; CheckboxWidget* myFastSCBios{nullptr}; CheckboxWidget* myUseThreads{nullptr}; @@ -112,6 +113,7 @@ class VideoDialog : public Dialog kSpeedupChanged = 'VDSp', kVSizeChanged = 'VDVs', kFullScreenChanged = 'VDFs', + kZoomChanged = 'VDZo', kOverscanChanged = 'VDOv', kTVModeChanged = 'VDtv', From 441aa6c8678e62378b64d3283c32659f4ea6cf4e Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 10 May 2020 19:53:59 +0200 Subject: [PATCH 193/377] added interactive palette display to VideoDialog --- src/common/PaletteHandler.cxx | 147 +++++++++++++----------- src/common/PaletteHandler.hxx | 26 +++-- src/gui/ColorWidget.cxx | 18 ++- src/gui/ColorWidget.hxx | 3 +- src/gui/VideoDialog.cxx | 210 ++++++++++++++++++++++++---------- src/gui/VideoDialog.hxx | 12 ++ 6 files changed, 274 insertions(+), 142 deletions(-) diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index b260842b1..e6bce1494 100644 --- a/src/common/PaletteHandler.cxx +++ b/src/common/PaletteHandler.cxx @@ -46,7 +46,7 @@ PaletteHandler::PaletteType PaletteHandler::toPaletteType(const string& name) co // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string PaletteHandler::toPaletteName(PaletteType type) const { - string SETTING_NAMES[int(PaletteType::NumTypes)] = { + const string SETTING_NAMES[int(PaletteType::NumTypes)] = { SETTING_STANDARD, SETTING_Z26, SETTING_USER, SETTING_CUSTOM }; @@ -56,7 +56,7 @@ string PaletteHandler::toPaletteName(PaletteType type) const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaletteHandler::changePalette(bool increase) { - string MESSAGES[PaletteType::NumTypes] = { + const string MESSAGES[PaletteType::NumTypes] = { "Standard Stella", "Z26", "User-defined", "Custom" }; @@ -98,7 +98,7 @@ void PaletteHandler::changePalette(bool increase) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaletteHandler::selectAdjustable(bool next) { - bool isCustomPalette = "custom" == myOSystem.settings().getString("palette"); + const bool isCustomPalette = "custom" == myOSystem.settings().getString("palette"); do { if(next) @@ -154,10 +154,54 @@ void PaletteHandler::changeAdjustable(bool increase) } } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::changeColorPhaseShift(bool increase) +{ + const ConsoleTiming timing = myOSystem.console().timing(); + + // SECAM is not supported + if(timing != ConsoleTiming::secam) + { + constexpr char DEGREE = 0x1c; + const bool isNTSC = timing == ConsoleTiming::ntsc; + const float shift = isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT; + float phase = isNTSC ? myPhaseNTSC : myPhasePAL; + + if(increase) // increase color phase shift + { + phase += 0.3F; + phase = std::min(phase, shift + MAX_SHIFT); + } + else // decrease color phase shift + { + phase -= 0.3F; + phase = std::max(phase, shift - MAX_SHIFT); + } + if(isNTSC) + myPhaseNTSC = phase; + else + myPhasePAL = phase; + + generateCustomPalette(timing); + setPalette("custom"); + + ostringstream ss; + ss << "Color phase shift at " + << std::fixed << std::setprecision(1) << phase << DEGREE; + + myOSystem.frameBuffer().showMessage(ss.str()); + } +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaletteHandler::loadConfig(const Settings& settings) { // Load adjustables + myPhaseNTSC = BSPF::clamp(settings.getFloat("tv.phase_ntsc"), + DEF_NTSC_SHIFT - MAX_SHIFT, DEF_NTSC_SHIFT + MAX_SHIFT); + myPhasePAL = BSPF::clamp(settings.getFloat("tv.phase_pal"), + DEF_PAL_SHIFT - MAX_SHIFT, DEF_PAL_SHIFT + MAX_SHIFT); + myHue = BSPF::clamp(settings.getFloat("tv.hue"), -1.0F, 1.0F); mySaturation = BSPF::clamp(settings.getFloat("tv.saturation"), -1.0F, 1.0F); myContrast = BSPF::clamp(settings.getFloat("tv.contrast"), -1.0F, 1.0F); @@ -169,6 +213,9 @@ void PaletteHandler::loadConfig(const Settings& settings) void PaletteHandler::saveConfig(Settings& settings) const { // Save adjustables + settings.setValue("tv.phase_ntsc", myPhaseNTSC); + settings.setValue("tv.phase_pal", myPhasePAL); + settings.setValue("tv.hue", myHue); settings.setValue("tv.saturation", mySaturation); settings.setValue("tv.contrast", myContrast); @@ -177,8 +224,11 @@ void PaletteHandler::saveConfig(Settings& settings) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PaletteHandler::setAdjustables(Adjustable& adjustable) +void PaletteHandler::setAdjustables(const Adjustable& adjustable) { + myPhaseNTSC = adjustable.phaseNtsc / 10.F; + myPhasePAL = adjustable.phasePal / 10.F; + myHue = scaleFrom100(adjustable.hue); mySaturation = scaleFrom100(adjustable.saturation); myContrast = scaleFrom100(adjustable.contrast); @@ -189,6 +239,9 @@ void PaletteHandler::setAdjustables(Adjustable& adjustable) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaletteHandler::getAdjustables(Adjustable& adjustable) const { + adjustable.phaseNtsc = myPhaseNTSC * 10.F; + adjustable.phasePal = myPhasePAL * 10.F; + adjustable.hue = scaleTo100(myHue); adjustable.saturation = scaleTo100(mySaturation); adjustable.contrast = scaleTo100(myContrast); @@ -196,46 +249,6 @@ void PaletteHandler::getAdjustables(Adjustable& adjustable) const adjustable.gamma = scaleTo100(myGamma); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PaletteHandler::changeColorPhaseShift(bool increase) -{ - const ConsoleTiming timing = myOSystem.console().timing(); - - // SECAM is not supported - if(timing != ConsoleTiming::secam) - { - const char DEGREE = 0x1c; - const float NTSC_SHIFT = 26.2F; - const float PAL_SHIFT = 31.3F; // 360 / 11.5 - const bool isNTSC = timing == ConsoleTiming::ntsc; - const string key = isNTSC ? "tv.phase_ntsc" : "tv.phase_pal"; - const float shift = isNTSC ? NTSC_SHIFT : PAL_SHIFT; - float phase = myOSystem.settings().getFloat(key); - - if(increase) // increase color phase shift - { - phase += 0.3F; - phase = std::min(phase, shift + 4.5F); - } - else // decrease color phase shift - { - phase -= 0.3F; - phase = std::max(phase, shift - 4.5F); - } - myOSystem.settings().setValue(key, phase); - generateCustomPalette(timing); - - setPalette("custom"); - - ostringstream ss; - ss << "Color phase shift at " - << std::fixed << std::setprecision(1) << phase << DEGREE; - - myOSystem.frameBuffer().showMessage(ss.str()); - } -} - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaletteHandler::setPalette(const string& name) { @@ -251,7 +264,7 @@ void PaletteHandler::setPalette() // Look at all the palettes, since we don't know which one is // currently active - static constexpr BSPF::array2D palettes = {{ + static constexpr BSPF::array2D palettes = {{ { &ourNTSCPalette, &ourPALPalette, &ourSECAMPalette }, { &ourNTSCPaletteZ26, &ourPALPaletteZ26, &ourSECAMPaletteZ26 }, { &ourUserNTSCPalette, &ourUserPALPalette, &ourUserSECAMPalette }, @@ -274,19 +287,19 @@ PaletteArray PaletteHandler::adjustPalette(const PaletteArray& palette) { PaletteArray destPalette; // Constants for saturation and gray scale calculation - const float PR = .2989F; - const float PG = .5870F; - const float PB = .1140F; + constexpr float PR = .2989F; + constexpr float PG = .5870F; + constexpr float PB = .1140F; // Generate adjust table - const int ADJUST_SIZE = 256; - const int RGB_UNIT = 1 << 8; - const float RGB_OFFSET = 0.5F; + constexpr int ADJUST_SIZE = 256; + constexpr int RGB_UNIT = 1 << 8; + constexpr float RGB_OFFSET = 0.5F; const float brightness = myBrightness * (0.5F * RGB_UNIT) + RGB_OFFSET; const float contrast = myContrast * (0.5F * RGB_UNIT) + RGB_UNIT; const float saturation = mySaturation + 1; const float gamma = 1.1333F - myGamma * 0.5F; /* match common PC's 2.2 gamma to TV's 2.65 gamma */ - const float toFloat = 1.F / (ADJUST_SIZE - 1); + constexpr float toFloat = 1.F / (ADJUST_SIZE - 1); std::array adjust; for(int i = 0; i < ADJUST_SIZE; i++) @@ -341,13 +354,13 @@ void PaletteHandler::loadUserPalette() for(int i = 0; i < 128; i++) // NTSC palette { in.read(reinterpret_cast(pixbuf.data()), 3); - uInt32 pixel = (int(pixbuf[0]) << 16) + (int(pixbuf[1]) << 8) + int(pixbuf[2]); + const uInt32 pixel = (int(pixbuf[0]) << 16) + (int(pixbuf[1]) << 8) + int(pixbuf[2]); ourUserNTSCPalette[(i<<1)] = pixel; } for(int i = 0; i < 128; i++) // PAL palette { in.read(reinterpret_cast(pixbuf.data()), 3); - uInt32 pixel = (int(pixbuf[0]) << 16) + (int(pixbuf[1]) << 8) + int(pixbuf[2]); + const uInt32 pixel = (int(pixbuf[0]) << 16) + (int(pixbuf[1]) << 8) + int(pixbuf[2]); ourUserPALPalette[(i<<1)] = pixel; } @@ -355,7 +368,7 @@ void PaletteHandler::loadUserPalette() for(int i = 0; i < 8; i++) // SECAM palette { in.read(reinterpret_cast(pixbuf.data()), 3); - uInt32 pixel = (int(pixbuf[0]) << 16) + (int(pixbuf[1]) << 8) + int(pixbuf[2]); + const uInt32 pixel = (int(pixbuf[0]) << 16) + (int(pixbuf[1]) << 8) + int(pixbuf[2]); secam[(i<<1)] = pixel; secam[(i<<1)+1] = 0; } @@ -383,8 +396,7 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) { // YIQ is YUV shifted by 33° constexpr float offset = 33 * (2 * BSPF::PI_f / 360); - const float shift = myOSystem.settings().getFloat("tv.phase_ntsc") * - (2 * BSPF::PI_f / 360); + const float shift = myPhaseNTSC * (2 * BSPF::PI_f / 360); // color 0 is grayscale for(int chroma = 1; chroma < NUM_CHROMA; chroma++) @@ -429,8 +441,7 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) else if(timing == ConsoleTiming::pal) { constexpr float offset = 180 * (2 * BSPF::PI_f / 360); - float shift = myOSystem.settings().getFloat("tv.phase_pal") * - (2 * BSPF::PI_f / 360); + const float shift = myPhasePAL * (2 * BSPF::PI_f / 360); constexpr float fixedShift = 22.5F * (2 * BSPF::PI_f / 360); // colors 0, 1, 14 and 15 are grayscale @@ -453,11 +464,10 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) { const float Y = 0.05F + luma / 8.24F; // 0.05..~0.90 - // Most sources + // Most sources float R = Y + 1.403F * V; float G = Y - 0.344F * U - 0.714F * V; float B = Y + 1.770F * U; - // German Wikipedia, huh??? //float B = Y + 1 / 0.493 * U; //float R = Y + 1 / 0.877 * V; @@ -504,8 +514,7 @@ void PaletteHandler::changeSaturation(int& R, int& G, int& B, float change) constexpr float PR = .2989F; constexpr float PG = .5870F; constexpr float PB = .1140F; - - float P = sqrt(R * R * PR + G * G * PG + B * B * PB) ; + const float P = sqrt(R * R * PR + G * G * PG + B * B * PB) ; R = P + (R - P) * change; G = P + (G - P) * change; @@ -517,7 +526,7 @@ void PaletteHandler::changeSaturation(int& R, int& G, int& B, float change) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray PaletteHandler::ourNTSCPalette = { +const PaletteArray PaletteHandler::ourNTSCPalette = { 0x000000, 0, 0x4a4a4a, 0, 0x6f6f6f, 0, 0x8e8e8e, 0, 0xaaaaaa, 0, 0xc0c0c0, 0, 0xd6d6d6, 0, 0xececec, 0, 0x484800, 0, 0x69690f, 0, 0x86861d, 0, 0xa2a22a, 0, @@ -553,7 +562,7 @@ PaletteArray PaletteHandler::ourNTSCPalette = { }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray PaletteHandler::ourPALPalette = { +const PaletteArray PaletteHandler::ourPALPalette = { 0x000000, 0, 0x121212, 0, 0x242424, 0, 0x484848, 0, // 180 0 0x6c6c6c, 0, 0x909090, 0, 0xb4b4b4, 0, 0xd8d8d8, 0, // was 0x111111..0xcccccc 0x000000, 0, 0x121212, 0, 0x242424, 0, 0x484848, 0, // 198 1 @@ -589,7 +598,7 @@ PaletteArray PaletteHandler::ourPALPalette = { }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray PaletteHandler::ourSECAMPalette = { +const PaletteArray PaletteHandler::ourSECAMPalette = { 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, @@ -625,7 +634,7 @@ PaletteArray PaletteHandler::ourSECAMPalette = { }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray PaletteHandler::ourNTSCPaletteZ26 = { +const PaletteArray PaletteHandler::ourNTSCPaletteZ26 = { 0x000000, 0, 0x505050, 0, 0x646464, 0, 0x787878, 0, 0x8c8c8c, 0, 0xa0a0a0, 0, 0xb4b4b4, 0, 0xc8c8c8, 0, 0x445400, 0, 0x586800, 0, 0x6c7c00, 0, 0x809000, 0, @@ -661,7 +670,7 @@ PaletteArray PaletteHandler::ourNTSCPaletteZ26 = { }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray PaletteHandler::ourPALPaletteZ26 = { +const PaletteArray PaletteHandler::ourPALPaletteZ26 = { 0x000000, 0, 0x4c4c4c, 0, 0x606060, 0, 0x747474, 0, 0x888888, 0, 0x9c9c9c, 0, 0xb0b0b0, 0, 0xc4c4c4, 0, 0x000000, 0, 0x4c4c4c, 0, 0x606060, 0, 0x747474, 0, @@ -697,7 +706,7 @@ PaletteArray PaletteHandler::ourPALPaletteZ26 = { }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray PaletteHandler::ourSECAMPaletteZ26 = { +const PaletteArray PaletteHandler::ourSECAMPaletteZ26 = { 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, diff --git a/src/common/PaletteHandler.hxx b/src/common/PaletteHandler.hxx index 995018e1e..7c0f69dfc 100644 --- a/src/common/PaletteHandler.hxx +++ b/src/common/PaletteHandler.hxx @@ -20,6 +20,7 @@ #include "bspf.hxx" #include "OSystem.hxx" +#include "ConsoleTiming.hxx" class PaletteHandler { @@ -29,6 +30,10 @@ class PaletteHandler static constexpr const char* SETTING_USER = "user"; static constexpr const char* SETTING_CUSTOM = "custom"; + static constexpr float DEF_NTSC_SHIFT = 26.2F; + static constexpr float DEF_PAL_SHIFT = 31.3F; // 360 / 11.5 + static constexpr float MAX_SHIFT = 4.5F; + enum DisplayType { NTSC, PAL, @@ -37,6 +42,7 @@ class PaletteHandler }; struct Adjustable { + float phaseNtsc, phasePal; uInt32 hue, saturation, contrast, brightness, gamma; }; @@ -55,7 +61,7 @@ class PaletteHandler void loadConfig(const Settings& settings); void saveConfig(Settings& settings) const; - void setAdjustables(Adjustable& adjustable); + void setAdjustables(const Adjustable& adjustable); void getAdjustables(Adjustable& adjustable) const; /** @@ -114,7 +120,7 @@ class PaletteHandler private: - static const int NUM_ADJUSTABLES = 6; + static constexpr int NUM_ADJUSTABLES = 6; OSystem& myOSystem; @@ -133,11 +139,13 @@ class PaletteHandler { "gamma", &myGamma }, } }; + float myPhaseNTSC{0.0F}; + float myPhasePAL{0.0F}; // range -1.0 to +1.0 (as in AtariNTSC) // Basic parameters - float myContrast{0.0F}; // -1 = dark (0.5) +1 = light (1.5) float myHue{0.0F}; // -1 = -180 degrees +1 = +180 degrees float mySaturation{0.0F}; // -1 = grayscale (0.0) +1 = oversaturated colors (2.0) + float myContrast{0.0F}; // -1 = dark (0.5) +1 = light (1.5) float myBrightness{0.0F}; // -1 = dark (0.5) +1 = light (1.5) // Advanced parameters float myGamma{0.0F}; // -1 = dark (1.5) +1 = light (0.5) @@ -147,14 +155,14 @@ class PaletteHandler bool myUserPaletteDefined{false}; // Table of RGB values for NTSC, PAL and SECAM - static PaletteArray ourNTSCPalette; - static PaletteArray ourPALPalette; - static PaletteArray ourSECAMPalette; + static const PaletteArray ourNTSCPalette; + static const PaletteArray ourPALPalette; + static const PaletteArray ourSECAMPalette; // Table of RGB values for NTSC, PAL and SECAM - Z26 version - static PaletteArray ourNTSCPaletteZ26; - static PaletteArray ourPALPaletteZ26; - static PaletteArray ourSECAMPaletteZ26; + static const PaletteArray ourNTSCPaletteZ26; + static const PaletteArray ourPALPaletteZ26; + static const PaletteArray ourSECAMPaletteZ26; // Table of RGB values for NTSC, PAL and SECAM - user-defined static PaletteArray ourUserNTSCPalette; diff --git a/src/gui/ColorWidget.cxx b/src/gui/ColorWidget.cxx index 6aa58a049..8052bf029 100644 --- a/src/gui/ColorWidget.cxx +++ b/src/gui/ColorWidget.cxx @@ -25,10 +25,11 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ColorWidget::ColorWidget(GuiObject* boss, const GUI::Font& font, - int x, int y, int w, int h, int cmd) + int x, int y, int w, int h, int cmd, bool framed) : Widget(boss, font, x, y, w, h), CommandSender(boss), - _cmd(cmd) + _cmd(cmd), + _framed(framed) { _flags = Widget::FLAG_ENABLED | Widget::FLAG_CLEARBG | Widget::FLAG_RETAIN_FOCUS; } @@ -46,11 +47,18 @@ void ColorWidget::drawWidget(bool hilite) FBSurface& s = dialog().surface(); bool onTop = _boss->dialog().isOnTop(); + if(_framed) + { // Draw a thin frame around us. - s.frameRect(_x, _y, _w, _h + 1, kColor); + s.frameRect(_x, _y, _w, _h + 1, kColor); - // Show the currently selected color - s.fillRect(_x+1, _y+1, _w-2, _h-1, onTop ? isEnabled() ? _color : kWidColor : kBGColorLo); + // Show the currently selected color + s.fillRect(_x + 1, _y + 1, _w - 2, _h - 1, onTop ? isEnabled() ? _color : kWidColor : kBGColorLo); + } + else + { + s.fillRect(_x, _y, _w, _h, onTop ? isEnabled() ? _color : kWidColor : kBGColorLo); + } // Cross out the grid? if(_crossGrid) diff --git a/src/gui/ColorWidget.hxx b/src/gui/ColorWidget.hxx index 7691ff6ad..9169c2153 100644 --- a/src/gui/ColorWidget.hxx +++ b/src/gui/ColorWidget.hxx @@ -36,7 +36,7 @@ class ColorWidget : public Widget, public CommandSender public: ColorWidget(GuiObject* boss, const GUI::Font& font, - int x, int y, int w, int h, int cmd = 0); + int x, int y, int w, int h, int cmd = 0, bool framed = true); virtual ~ColorWidget() = default; void setColor(ColorId color); @@ -49,6 +49,7 @@ class ColorWidget : public Widget, public CommandSender protected: ColorId _color{kNone}; + bool _framed{true}; int _cmd{0}; bool _crossGrid{false}; diff --git a/src/gui/VideoDialog.cxx b/src/gui/VideoDialog.cxx index 26ed93a33..41460d9ba 100644 --- a/src/gui/VideoDialog.cxx +++ b/src/gui/VideoDialog.cxx @@ -18,12 +18,14 @@ #include #include "bspf.hxx" +#include "Base.hxx" #include "Control.hxx" #include "Dialog.hxx" #include "Menu.hxx" #include "OSystem.hxx" #include "EditTextWidget.hxx" #include "PopUpWidget.hxx" +#include "ColorWidget.hxx" #include "Console.hxx" #include "PaletteHandler.hxx" #include "TIA.hxx" @@ -104,6 +106,14 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, addPaletteTab(); addTVEffectsTab(); + //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); @@ -266,7 +276,8 @@ void VideoDialog::addPaletteTab() myPhaseShiftNtsc = new SliderWidget(myTab, _font, xpos + INDENT, ypos-1, pswidth, lineHeight, "NTSC phase", plWidth, kNtscShiftChanged, fontWidth * 5); - myPhaseShiftNtsc->setMinValue(262 - 45); myPhaseShiftNtsc->setMaxValue(262 + 45); + myPhaseShiftNtsc->setMinValue((PaletteHandler::DEF_NTSC_SHIFT - PaletteHandler::MAX_SHIFT) * 10); + myPhaseShiftNtsc->setMaxValue((PaletteHandler::DEF_NTSC_SHIFT + PaletteHandler::MAX_SHIFT) * 10); myPhaseShiftNtsc->setTickmarkIntervals(4); wid.push_back(myPhaseShiftNtsc); ypos += lineHeight + VGAP; @@ -274,7 +285,8 @@ void VideoDialog::addPaletteTab() myPhaseShiftPal = new SliderWidget(myTab, _font, xpos + INDENT, ypos-1, pswidth, lineHeight, "PAL phase", plWidth, kPalShiftChanged, fontWidth * 5); - myPhaseShiftPal->setMinValue(313 - 45); myPhaseShiftPal->setMaxValue(313 + 45); + myPhaseShiftPal->setMinValue((PaletteHandler::DEF_PAL_SHIFT - PaletteHandler::MAX_SHIFT) * 10); + myPhaseShiftPal->setMaxValue((PaletteHandler::DEF_PAL_SHIFT + PaletteHandler::MAX_SHIFT) * 10); myPhaseShiftPal->setTickmarkIntervals(4); wid.push_back(myPhaseShiftPal); ypos += lineHeight + VGAP; @@ -288,11 +300,15 @@ void VideoDialog::addPaletteTab() wid.push_back(myTV ## obj); \ ypos += lineHeight + VGAP; - CREATE_CUSTOM_SLIDERS(Hue, "Hue ", 0) - CREATE_CUSTOM_SLIDERS(Satur, "Saturation ", 0) - CREATE_CUSTOM_SLIDERS(Contrast, "Contrast ", 0) - CREATE_CUSTOM_SLIDERS(Bright, "Brightness ", 0) - CREATE_CUSTOM_SLIDERS(Gamma, "Gamma ", 0) + CREATE_CUSTOM_SLIDERS(Hue, "Hue ", kPaletteUpdated) + CREATE_CUSTOM_SLIDERS(Satur, "Saturation ", kPaletteUpdated) + CREATE_CUSTOM_SLIDERS(Contrast, "Contrast ", kPaletteUpdated) + CREATE_CUSTOM_SLIDERS(Bright, "Brightness ", kPaletteUpdated) + CREATE_CUSTOM_SLIDERS(Gamma, "Gamma ", kPaletteUpdated) + + // The resulting palette + addPalette(myPhaseShiftNtsc->getRight() + fontWidth * 2, VBORDER, + fontWidth * 2 * 8, myTVGamma->getBottom() - myTIAPalette->getTop()); // Add items for tab 2 addToFocusList(wid, myTab, tabID); @@ -412,13 +428,20 @@ void VideoDialog::loadConfig() myTIAZoom->setValue(instance().settings().getFloat("tia.zoom") * 100); // TIA Palette - myTIAPalette->setSelected( - instance().settings().getString("palette"), "standard"); + myPalette = instance().settings().getString("palette"); + myTIAPalette->setSelected(myPalette, "standard"); - // Custom Palette - myPhaseShiftNtsc->setValue(instance().settings().getFloat("tv.phase_ntsc") * 10); - myPhaseShiftPal->setValue(instance().settings().getFloat("tv.phase_pal") * 10); + // Palette adjustables + instance().frameBuffer().tiaSurface().paletteHandler().getAdjustables(myPaletteAdj); + myPhaseShiftNtsc->setValue(myPaletteAdj.phaseNtsc); + myPhaseShiftPal->setValue(myPaletteAdj.phasePal); + myTVHue->setValue(myPaletteAdj.hue); + myTVBright->setValue(myPaletteAdj.brightness); + myTVContrast->setValue(myPaletteAdj.contrast); + myTVSatur->setValue(myPaletteAdj.saturation); + myTVGamma->setValue(myPaletteAdj.gamma); handlePaletteChange(); + colorPalette(); // TIA interpolation myTIAInterpolate->setState(instance().settings().getBool("tia.inter")); @@ -459,15 +482,6 @@ void VideoDialog::loadConfig() int preset = instance().settings().getInt("tv.filter"); handleTVModeChange(NTSCFilter::Preset(preset)); - // Palette adjustables - PaletteHandler::Adjustable paletteAdj; - instance().frameBuffer().tiaSurface().paletteHandler().getAdjustables(paletteAdj); - myTVHue->setValue(paletteAdj.hue); - myTVBright->setValue(paletteAdj.brightness); - myTVContrast->setValue(paletteAdj.contrast); - myTVSatur->setValue(paletteAdj.saturation); - myTVGamma->setValue(paletteAdj.gamma); - // TV Custom adjustables loadTVAdjustables(NTSCFilter::Preset::CUSTOM); @@ -491,31 +505,12 @@ void VideoDialog::saveConfig() instance().settings().setValue("video", myRenderer->getSelectedTag().toString()); - // TIA zoom levels - instance().settings().setValue("tia.zoom", myTIAZoom->getValue() / 100.0); - - // TIA Palette - instance().settings().setValue("palette", - myTIAPalette->getSelectedTag().toString()); - - // Custom Palette - instance().settings().setValue("tv.phase_ntsc", myPhaseShiftNtsc->getValue() / 10.0); - instance().settings().setValue("tv.phase_pal", myPhaseShiftPal->getValue() / 10.0); - // TIA interpolation instance().settings().setValue("tia.inter", myTIAInterpolate->getState()); - // Aspect ratio setting (NTSC and PAL) - int oldAdjust = instance().settings().getInt("tia.vsizeadjust"); - int newAdjust = myVSizeAdjust->getValue(); - bool vsizeChanged = oldAdjust != newAdjust; - instance().settings().setValue("tia.vsizeadjust", newAdjust); + // Note: Palette values are saved directly when changed! - // Speed - int speedup = mySpeed->getValue(); - instance().settings().setValue("speed", unmapSpeed(speedup)); - if (instance().hasConsole()) instance().console().initializeAudio(); // Fullscreen instance().settings().setValue("fullscreen", myFullscreen->getState()); @@ -524,6 +519,22 @@ void VideoDialog::saveConfig() // Fullscreen overscan instance().settings().setValue("tia.fs_overscan", myTVOverscan->getValueLabel()); + // TIA zoom levels + instance().settings().setValue("tia.zoom", myTIAZoom->getValue() / 100.0); + + // Aspect ratio setting (NTSC and PAL) + const int oldAdjust = instance().settings().getInt("tia.vsizeadjust"); + const int newAdjust = myVSizeAdjust->getValue(); + const bool vsizeChanged = oldAdjust != newAdjust; + + instance().settings().setValue("tia.vsizeadjust", newAdjust); + + // Speed + const int speedup = mySpeed->getValue(); + instance().settings().setValue("speed", unmapSpeed(speedup)); + if (instance().hasConsole()) + instance().console().initializeAudio(); + // Use sync to vertical blank instance().settings().setValue("vsync", myUseVSync->getState()); @@ -541,16 +552,6 @@ void VideoDialog::saveConfig() // TV Mode instance().settings().setValue("tv.filter", myTVMode->getSelectedTag().toString()); - - // Palette adjustables - PaletteHandler::Adjustable paletteAdj; - paletteAdj.hue = myTVHue->getValue(); - paletteAdj.saturation = myTVSatur->getValue(); - paletteAdj.contrast = myTVContrast->getValue(); - paletteAdj.brightness = myTVBright->getValue(); - paletteAdj.gamma = myTVGamma->getValue(); - instance().frameBuffer().tiaSurface().paletteHandler().setAdjustables(paletteAdj); - // TV Custom adjustables NTSCFilter::Adjustable ntscAdj; ntscAdj.sharpness = myTVSharp->getValue(); @@ -596,32 +597,36 @@ void VideoDialog::setDefaults() case 0: // General { myRenderer->setSelectedIndex(0); - myTIAZoom->setValue(300); myTIAInterpolate->setState(false); - myVSizeAdjust->setValue(0); - mySpeed->setValue(0); - + // screen size myFullscreen->setState(false); //myFullScreenMode->setSelectedIndex(0); myUseStretch->setState(false); + myTVOverscan->setValue(0); + myTIAZoom->setValue(300); + myVSizeAdjust->setValue(0); + // speed + mySpeed->setValue(0); myUseVSync->setState(true); + // misc myUIMessages->setState(true); myFastSCBios->setState(true); myUseThreads->setState(false); - handlePaletteChange(); + handleFullScreenChange(); break; } case 1: // Palettes myTIAPalette->setSelected("standard", ""); - myPhaseShiftNtsc->setValue(262); - myPhaseShiftPal->setValue(313); + myPhaseShiftNtsc->setValue(PaletteHandler::DEF_NTSC_SHIFT * 10); + myPhaseShiftPal->setValue(PaletteHandler::DEF_PAL_SHIFT * 10); myTVHue->setValue(50); myTVSatur->setValue(50); myTVContrast->setValue(50); myTVBright->setValue(50); myTVGamma->setValue(50); + handlePaletteChange(); break; case 2: // TV effects @@ -685,6 +690,27 @@ void VideoDialog::handlePaletteChange() myPhaseShiftPal->setEnabled(enable); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void VideoDialog::handlePaletteUpdate() +{ + // TIA Palette + instance().settings().setValue("palette", + myTIAPalette->getSelectedTag().toString()); + // Palette adjustables + PaletteHandler::Adjustable paletteAdj; + paletteAdj.phaseNtsc = myPhaseShiftNtsc->getValue(); + paletteAdj.phasePal = myPhaseShiftPal->getValue(); + paletteAdj.hue = myTVHue->getValue(); + paletteAdj.saturation = myTVSatur->getValue(); + paletteAdj.contrast = myTVContrast->getValue(); + paletteAdj.brightness = myTVBright->getValue(); + paletteAdj.gamma = myTVGamma->getValue(); + instance().frameBuffer().tiaSurface().paletteHandler().setAdjustables(paletteAdj); + + if(instance().hasConsole()) + instance().frameBuffer().tiaSurface().paletteHandler().setPalette(); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void VideoDialog::handleFullScreenChange() { @@ -722,12 +748,24 @@ void VideoDialog::handleCommand(CommandSender* sender, int cmd, close(); break; + case GuiObject::kCloseCmd: + // restore palette settings + instance().frameBuffer().tiaSurface().paletteHandler().setAdjustables(myPaletteAdj); + instance().frameBuffer().tiaSurface().paletteHandler().setPalette(myPalette); + Dialog::handleCommand(sender, cmd, data, 0); + break; + case GuiObject::kDefaultsCmd: setDefaults(); break; case kPaletteChanged: handlePaletteChange(); + handlePaletteUpdate(); + break; + + case kPaletteUpdated: + handlePaletteUpdate(); break; case kNtscShiftChanged: @@ -737,6 +775,7 @@ void VideoDialog::handleCommand(CommandSender* sender, int cmd, ss << std::setw(4) << std::fixed << std::setprecision(1) << (0.1 * abs(myPhaseShiftNtsc->getValue())) << DEGREE; myPhaseShiftNtsc->setValueLabel(ss.str()); + handlePaletteUpdate(); break; } case kPalShiftChanged: @@ -746,6 +785,7 @@ void VideoDialog::handleCommand(CommandSender* sender, int cmd, ss << std::setw(4) << std::fixed << std::setprecision(1) << (0.1 * abs(myPhaseShiftPal->getValue())) << DEGREE; myPhaseShiftPal->setValueLabel(ss.str()); + handlePaletteUpdate(); break; } case kVSizeChanged: @@ -818,3 +858,57 @@ void VideoDialog::handleCommand(CommandSender* sender, int cmd, break; } } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void VideoDialog::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; + + 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) + { + myColor[idx][lum] = new ColorWidget(myTab, _font, x + lwidth + lum * COLW, y + idx * COLH, + COLW + 1, COLH + 1, 0, false); + } + } + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void VideoDialog::colorPalette() +{ + if(instance().hasConsole()) + { + constexpr int NUM_LUMA = 8; + constexpr int NUM_CHROMA = 16; + const int order[2][NUM_CHROMA] = + { + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {0, 1, 2, 4, 6, 8, 10, 12, 13, 11, 9, 7, 5, 3, 14, 15} + }; + const int type = instance().console().timing() == ConsoleTiming::pal ? 1 : 0; + + for(int idx = 0; idx < NUM_CHROMA; ++idx) + { + ostringstream ss; + const int color = order[type][idx]; + + ss << Common::Base::HEX1 << std::uppercase << color; + myColorLbl[idx]->setLabel(ss.str()); + for(int lum = 0; lum < NUM_LUMA; ++lum) + { + myColor[idx][lum]->setColor(color * NUM_CHROMA + lum * 2); // skip grayscale colors + } + } + } +} diff --git a/src/gui/VideoDialog.hxx b/src/gui/VideoDialog.hxx index d780a508f..7d01b6808 100644 --- a/src/gui/VideoDialog.hxx +++ b/src/gui/VideoDialog.hxx @@ -20,6 +20,7 @@ class CommandSender; class CheckboxWidget; +class ColorWidget; class DialogContainer; class PopUpWidget; class RadioButtonGroup; @@ -29,6 +30,7 @@ class TabWidget; class OSystem; #include "Dialog.hxx" +#include "PaletteHandler.hxx" #include "NTSCFilter.hxx" #include "bspf.hxx" @@ -50,10 +52,13 @@ class VideoDialog : public Dialog void handleTVModeChange(NTSCFilter::Preset); void loadTVAdjustables(NTSCFilter::Preset preset); void handlePaletteChange(); + void handlePaletteUpdate(); void handleFullScreenChange(); void handleOverscanChange(); void handlePhosphorChange(); void handleCommand(CommandSender* sender, int cmd, int data, int id) override; + void addPalette(int x, int y, int h, int w); + void colorPalette(); private: TabWidget* myTab; @@ -77,6 +82,9 @@ class VideoDialog : public Dialog CheckboxWidget* myUIMessages{nullptr}; CheckboxWidget* myFastSCBios{nullptr}; CheckboxWidget* myUseThreads{nullptr}; + std::array myColorLbl{nullptr}; + //std::array myColor{nullptr}; + ColorWidget* myColor[16][8]{nullptr}; // TV effects adjustables (custom mode) PopUpWidget* myTVMode{nullptr}; @@ -106,10 +114,14 @@ class VideoDialog : public Dialog ButtonWidget* myCloneBad{nullptr}; ButtonWidget* myCloneCustom{nullptr}; + string myPalette; + PaletteHandler::Adjustable myPaletteAdj{0.0F}; + enum { kPaletteChanged = 'VDpl', kNtscShiftChanged = 'VDns', kPalShiftChanged = 'VDps', + kPaletteUpdated = 'VDpu', kSpeedupChanged = 'VDSp', kVSizeChanged = 'VDVs', kFullScreenChanged = 'VDFs', From 31124cabef21afbca71cd80437617532ad6a1451 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 10 May 2020 21:53:02 +0200 Subject: [PATCH 194/377] add hue adjustment code to PaletteHandler --- src/common/PaletteHandler.cxx | 26 +++++++++++++++++++++++--- src/common/PaletteHandler.hxx | 3 ++- src/gui/VideoDialog.cxx | 28 ++++++++++------------------ 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index e6bce1494..f6fed70cf 100644 --- a/src/common/PaletteHandler.cxx +++ b/src/common/PaletteHandler.cxx @@ -294,6 +294,7 @@ PaletteArray PaletteHandler::adjustPalette(const PaletteArray& palette) constexpr int ADJUST_SIZE = 256; constexpr int RGB_UNIT = 1 << 8; constexpr float RGB_OFFSET = 0.5F; + const float hue = myHue; const float brightness = myBrightness * (0.5F * RGB_UNIT) + RGB_OFFSET; const float contrast = myContrast * (0.5F * RGB_UNIT) + RGB_UNIT; const float saturation = mySaturation + 1; @@ -313,10 +314,11 @@ PaletteArray PaletteHandler::adjustPalette(const PaletteArray& palette) int g = (pixel >> 8) & 0xff; int b = (pixel >> 0) & 0xff; - // TOOD: adjust hue (different for NTSC and PAL?) + // adjust hue (different for NTSC and PAL?) + adjustHue(r, g, b, hue); // adjust saturation - changeSaturation(r, g, b, saturation); + adustSaturation(r, g, b, saturation); // adjust contrast, brightness, gamma r = adjust[r]; @@ -496,7 +498,25 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PaletteHandler::changeSaturation(int& R, int& G, int& B, float change) +void PaletteHandler::adjustHue(int& R, int& G, int& B, float change) +{ + const float U = cos(-change * BSPF::PI_f); + const float W = sin(-change * BSPF::PI_f); + const float R_out = (.299 + .701 * U + .168 * W) * R + + (.587 - .587 * U + .330 * W) * G + + (.114 - .114 * U - .497 * W) * B; + const float G_out = (.299 - .299 * U - .328 * W) * R + + (.587 + .413 * U + .035 * W) * G + + (.114 - .114 * U + .292 * W) * B; + const float B_out = (.299 - .3 * U + 1.25 * W) * R + + (.587 - .588 * U - 1.05 * W) * G + + (.114 + .886 * U - .203 * W) * B; + + R = R_out; G = G_out; B = B_out; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::adustSaturation(int& R, int& G, int& B, float change) { // public-domain function by Darel Rex Finley // diff --git a/src/common/PaletteHandler.hxx b/src/common/PaletteHandler.hxx index 7c0f69dfc..ddb4bfaa1 100644 --- a/src/common/PaletteHandler.hxx +++ b/src/common/PaletteHandler.hxx @@ -110,7 +110,8 @@ class PaletteHandler PaletteArray adjustPalette(const PaletteArray& source); - void changeSaturation(int& R, int& G, int& B, float change); + void adjustHue(int& R, int& G, int& B, float change); + void adustSaturation(int& R, int& G, int& B, float change); /** Loads a user-defined palette file (from OSystem::paletteFile), filling the diff --git a/src/gui/VideoDialog.cxx b/src/gui/VideoDialog.cxx index 41460d9ba..a90657892 100644 --- a/src/gui/VideoDialog.cxx +++ b/src/gui/VideoDialog.cxx @@ -76,6 +76,16 @@ namespace { } } +#define CREATE_CUSTOM_SLIDERS(obj, desc, cmd) \ + myTV ## obj = \ + 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->setTickmarkIntervals(2); \ + wid.push_back(myTV ## obj); \ + ypos += lineHeight + VGAP; + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, int max_w, int max_h) @@ -291,15 +301,6 @@ void VideoDialog::addPaletteTab() wid.push_back(myPhaseShiftPal); ypos += lineHeight + VGAP; -#define CREATE_CUSTOM_SLIDERS(obj, desc, cmd) \ - myTV ## obj = \ - new SliderWidget(myTab, _font, xpos, ypos-1, swidth, lineHeight, \ - desc, lwidth, cmd, fontWidth*4, "%"); \ - myTV ## obj->setMinValue(0); myTV ## obj->setMaxValue(100); \ - myTV ## obj->setTickmarkIntervals(2); \ - wid.push_back(myTV ## obj); \ - ypos += lineHeight + VGAP; - CREATE_CUSTOM_SLIDERS(Hue, "Hue ", kPaletteUpdated) CREATE_CUSTOM_SLIDERS(Satur, "Saturation ", kPaletteUpdated) CREATE_CUSTOM_SLIDERS(Contrast, "Contrast ", kPaletteUpdated) @@ -349,15 +350,6 @@ void VideoDialog::addTVEffectsTab() const int swidth = myTVMode->getWidth() - INDENT - lwidth; xpos += INDENT; -#define CREATE_CUSTOM_SLIDERS(obj, desc, cmd) \ - myTV ## obj = \ - new SliderWidget(myTab, _font, xpos, ypos-1, swidth, lineHeight, \ - desc, lwidth, cmd, fontWidth*4, "%"); \ - myTV ## obj->setMinValue(0); myTV ## obj->setMaxValue(100); \ - myTV ## obj->setTickmarkIntervals(2); \ - wid.push_back(myTV ## obj); \ - ypos += lineHeight + VGAP; - CREATE_CUSTOM_SLIDERS(Sharp, "Sharpness ", 0) CREATE_CUSTOM_SLIDERS(Res, "Resolution ", 0) CREATE_CUSTOM_SLIDERS(Artifacts, "Artifacts ", 0) From 72bd162951a1930d3c73f585cd3a80ebf4a5844d Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 10 May 2020 22:53:58 +0200 Subject: [PATCH 195/377] some transformation code cleanup --- src/common/PaletteHandler.cxx | 68 +++++++++++------------------------ src/common/PaletteHandler.hxx | 3 +- 2 files changed, 21 insertions(+), 50 deletions(-) diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index f6fed70cf..dbca46ff2 100644 --- a/src/common/PaletteHandler.cxx +++ b/src/common/PaletteHandler.cxx @@ -314,11 +314,8 @@ PaletteArray PaletteHandler::adjustPalette(const PaletteArray& palette) int g = (pixel >> 8) & 0xff; int b = (pixel >> 0) & 0xff; - // adjust hue (different for NTSC and PAL?) - adjustHue(r, g, b, hue); - - // adjust saturation - adustSaturation(r, g, b, saturation); + // adjust hue (different for NTSC and PAL?) and saturation + adjustHueSaturation(r, g, b, hue, saturation); // adjust contrast, brightness, gamma r = adjust[r]; @@ -498,51 +495,26 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PaletteHandler::adjustHue(int& R, int& G, int& B, float change) +void PaletteHandler::adjustHueSaturation(int& R, int& G, int& B, float H, float S) { - const float U = cos(-change * BSPF::PI_f); - const float W = sin(-change * BSPF::PI_f); - const float R_out = (.299 + .701 * U + .168 * W) * R - + (.587 - .587 * U + .330 * W) * G - + (.114 - .114 * U - .497 * W) * B; - const float G_out = (.299 - .299 * U - .328 * W) * R - + (.587 + .413 * U + .035 * W) * G - + (.114 - .114 * U + .292 * W) * B; - const float B_out = (.299 - .3 * U + 1.25 * W) * R - + (.587 - .588 * U - 1.05 * W) * G - + (.114 + .886 * U - .203 * W) * B; + // Adapted from http://beesbuzz.biz/code/16-hsv-color-transforms + // (C) J. “Fluffy” Shagam + // License: CC BY-SA 4.0 + const float su = S * cos(-H * BSPF::PI_f); + const float sw = S * sin(-H * BSPF::PI_f); + const float r = (.299 + .701 * su + .168 * sw) * R + + (.587 - .587 * su + .330 * sw) * G + + (.114 - .114 * su - .497 * sw) * B; + const float g = (.299 - .299 * su - .328 * sw) * R + + (.587 + .413 * su + .035 * sw) * G + + (.114 - .114 * su + .292 * sw) * B; + const float b = (.299 - .300 * su + 1.25 * sw) * R + + (.587 - .588 * su - 1.05 * sw) * G + + (.114 + .886 * su - .203 * sw) * B; - R = R_out; G = G_out; B = B_out; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PaletteHandler::adustSaturation(int& R, int& G, int& B, float change) -{ - // public-domain function by Darel Rex Finley - // - // The passed-in RGB values can be on any desired scale, such as 0 to - // to 1, or 0 to 255. (But use the same scale for all three!) - // - // The "change" parameter works like this: - // 0.0 creates a black-and-white image. - // 0.5 reduces the color saturation by half. - // 1.0 causes no change. - // 2.0 doubles the color saturation. - // Note: A "change" value greater than 1.0 may project your RGB values - // beyond their normal range, in which case you probably should truncate - // them to the desired range before trying to use them in an image. - constexpr float PR = .2989F; - constexpr float PG = .5870F; - constexpr float PB = .1140F; - const float P = sqrt(R * R * PR + G * G * PG + B * B * PB) ; - - R = P + (R - P) * change; - G = P + (G - P) * change; - B = P + (B - P) * change; - - R = BSPF::clamp(R, 0, 255); - G = BSPF::clamp(G, 0, 255); - B = BSPF::clamp(B, 0, 255); + R = BSPF::clamp(r, 0.F, 255.F); + G = BSPF::clamp(g, 0.F, 255.F); + B = BSPF::clamp(b, 0.F, 255.F); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/PaletteHandler.hxx b/src/common/PaletteHandler.hxx index ddb4bfaa1..cffdc2ad4 100644 --- a/src/common/PaletteHandler.hxx +++ b/src/common/PaletteHandler.hxx @@ -110,8 +110,7 @@ class PaletteHandler PaletteArray adjustPalette(const PaletteArray& source); - void adjustHue(int& R, int& G, int& B, float change); - void adustSaturation(int& R, int& G, int& B, float change); + void adjustHueSaturation(int& R, int& G, int& B, float H, float S); /** Loads a user-defined palette file (from OSystem::paletteFile), filling the From a3ed86846ad192b92c71b701e15a1c56c36876a9 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 11 May 2020 10:47:43 +0200 Subject: [PATCH 196/377] code cleanup and bug fixing --- src/common/PKeyboardHandler.cxx | 2 - src/common/PaletteHandler.cxx | 150 ++++++++++++--------------- src/common/PaletteHandler.hxx | 122 ++++++++++++++++------ src/common/tv_filters/NTSCFilter.cxx | 26 ++--- src/emucore/Event.hxx | 1 - src/emucore/EventHandler.cxx | 19 +--- src/emucore/EventHandler.hxx | 2 +- src/emucore/Settings.cxx | 10 +- src/gui/CommandDialog.cxx | 8 +- src/gui/VideoDialog.cxx | 12 +-- 10 files changed, 193 insertions(+), 159 deletions(-) diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index 1a0fe6499..3edd7698d 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -491,8 +491,6 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo {Event::ToggleColorLoss, KBDK_L, KBDM_CTRL}, {Event::PaletteDecrease, KBDK_P, KBDM_SHIFT | KBDM_CTRL}, {Event::PaletteIncrease, KBDK_P, KBDM_CTRL}, - {Event::ColorShiftDecrease, KBDK_9, KBDM_SHIFT | KBDM_CTRL}, - {Event::ColorShiftIncrease, KBDK_9, KBDM_CTRL}, {Event::ToggleInter, KBDK_I, KBDM_CTRL}, {Event::ToggleTurbo, KBDK_T, KBDM_CTRL}, {Event::ToggleJitter, KBDK_J, MOD3}, diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index dbca46ff2..3f1066724 100644 --- a/src/common/PaletteHandler.cxx +++ b/src/common/PaletteHandler.cxx @@ -54,19 +54,14 @@ string PaletteHandler::toPaletteName(PaletteType type) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PaletteHandler::changePalette(bool increase) +void PaletteHandler::cyclePalette(bool next) { const string MESSAGES[PaletteType::NumTypes] = { "Standard Stella", "Z26", "User-defined", "Custom" }; - - string palette, message; - palette = myOSystem.settings().getString("palette"); - - int type = toPaletteType(myOSystem.settings().getString("palette")); - if(increase) + if(next) { if(type == PaletteType::MaxType) type = PaletteType::Standard; @@ -87,8 +82,8 @@ void PaletteHandler::changePalette(bool increase) type--; } - palette = toPaletteName(PaletteType(type)); - message = MESSAGES[type] + " palette"; + const string palette = toPaletteName(PaletteType(type)); + const string message = MESSAGES[type] + " palette"; myOSystem.frameBuffer().showMessage(message); @@ -96,9 +91,10 @@ void PaletteHandler::changePalette(bool increase) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PaletteHandler::selectAdjustable(bool next) +void PaletteHandler::cycleAdjustable(bool next) { - const bool isCustomPalette = "custom" == myOSystem.settings().getString("palette"); + const bool isCustomPalette = SETTING_CUSTOM == myOSystem.settings().getString("palette"); + bool isPhaseShift; do { if(next) @@ -113,11 +109,19 @@ void PaletteHandler::selectAdjustable(bool next) else myCurrentAdjustable--; } - } while(!isCustomPalette && myAdjustables[myCurrentAdjustable].value == nullptr); + isPhaseShift = myAdjustables[myCurrentAdjustable].value == nullptr; + + // skip phase shift when 'Custom' palette is not selected + } while(isPhaseShift && !isCustomPalette); ostringstream buf; - buf << "Palette adjustable '" << myAdjustables[myCurrentAdjustable].type - << "' selected"; + buf << "Palette adjustable '" << myAdjustables[myCurrentAdjustable].name + << "' selected ("; + if(isPhaseShift) + buf << (myOSystem.console().timing() == ConsoleTiming::pal ? myPhasePAL : myPhaseNTSC) + << DEGREE << ")"; + else + buf << scaleTo100(*myAdjustables[myCurrentAdjustable].value) << "%)"; myOSystem.frameBuffer().showMessage(buf.str()); } @@ -129,25 +133,19 @@ void PaletteHandler::changeAdjustable(bool increase) changeColorPhaseShift(increase); else { - float newVal = (*myAdjustables[myCurrentAdjustable].value); + int newVal = scaleTo100(*myAdjustables[myCurrentAdjustable].value); if(increase) - { - newVal += 0.05F; - if(newVal > 1.0F) - newVal = 1.0F; - } + newVal += 2; // += 2% else - { - newVal -= 0.05F; - if(newVal < -1.0F) - newVal = -1.0F; - } - *myAdjustables[myCurrentAdjustable].value = newVal; + newVal -= 2; // -= 2% + newVal = BSPF::clamp(newVal, 0, 100); + + *myAdjustables[myCurrentAdjustable].value = scaleFrom100(newVal); ostringstream buf; - buf << "Custom '" << myAdjustables[myCurrentAdjustable].type - << "' set to " << int((newVal + 1.0F) * 100.0F + 0.5F) << "%"; + buf << "Custom '" << myAdjustables[myCurrentAdjustable].name + << "' set to " << newVal << "%"; myOSystem.frameBuffer().showMessage(buf.str()); setPalette(); @@ -162,32 +160,27 @@ void PaletteHandler::changeColorPhaseShift(bool increase) // SECAM is not supported if(timing != ConsoleTiming::secam) { - constexpr char DEGREE = 0x1c; const bool isNTSC = timing == ConsoleTiming::ntsc; const float shift = isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT; - float phase = isNTSC ? myPhaseNTSC : myPhasePAL; + float newPhase = isNTSC ? myPhaseNTSC : myPhasePAL; if(increase) // increase color phase shift - { - phase += 0.3F; - phase = std::min(phase, shift + MAX_SHIFT); - } + newPhase += 0.3F; else // decrease color phase shift - { - phase -= 0.3F; - phase = std::max(phase, shift - MAX_SHIFT); - } + newPhase -= 0.3F; + newPhase = BSPF::clamp(newPhase, shift - MAX_SHIFT, shift + MAX_SHIFT); + if(isNTSC) - myPhaseNTSC = phase; + myPhaseNTSC = newPhase; else - myPhasePAL = phase; + myPhasePAL = newPhase; generateCustomPalette(timing); - setPalette("custom"); + setPalette(SETTING_CUSTOM); ostringstream ss; ss << "Color phase shift at " - << std::fixed << std::setprecision(1) << phase << DEGREE; + << std::fixed << std::setprecision(1) << newPhase << DEGREE; myOSystem.frameBuffer().showMessage(ss.str()); } @@ -260,30 +253,33 @@ void PaletteHandler::setPalette(const string& name) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaletteHandler::setPalette() { - const string& name = myOSystem.settings().getString("palette"); + if(myOSystem.hasConsole()) + { + const string& name = myOSystem.settings().getString("palette"); - // Look at all the palettes, since we don't know which one is - // currently active - static constexpr BSPF::array2D palettes = {{ - { &ourNTSCPalette, &ourPALPalette, &ourSECAMPalette }, - { &ourNTSCPaletteZ26, &ourPALPaletteZ26, &ourSECAMPaletteZ26 }, - { &ourUserNTSCPalette, &ourUserPALPalette, &ourUserSECAMPalette }, - { &ourCustomNTSCPalette, &ourCustomPALPalette, &ourSECAMPalette } - }}; - // See which format we should be using - const ConsoleTiming timing = myOSystem.console().timing(); - const PaletteType paletteType = toPaletteType(name); - // Now consider the current display format - const PaletteArray* palette = palettes[paletteType][int(timing)]; + // Look at all the palettes, since we don't know which one is + // currently active + static constexpr BSPF::array2D palettes = {{ + { &ourNTSCPalette, &ourPALPalette, &ourSECAMPalette }, + { &ourNTSCPaletteZ26, &ourPALPaletteZ26, &ourSECAMPaletteZ26 }, + { &ourUserNTSCPalette, &ourUserPALPalette, &ourUserSECAMPalette }, + { &ourCustomNTSCPalette, &ourCustomPALPalette, &ourSECAMPalette } + }}; + // See which format we should be using + const ConsoleTiming timing = myOSystem.console().timing(); + const PaletteType paletteType = toPaletteType(name); + // Now consider the current display format + const PaletteArray* palette = palettes[paletteType][int(timing)]; - if(paletteType == PaletteType::Custom) - generateCustomPalette(timing); + if(paletteType == PaletteType::Custom) + generateCustomPalette(timing); - myOSystem.frameBuffer().setTIAPalette(adjustPalette(*palette)); + myOSystem.frameBuffer().setTIAPalette(adjustedPalette(*palette)); + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray PaletteHandler::adjustPalette(const PaletteArray& palette) +PaletteArray PaletteHandler::adjustedPalette(const PaletteArray& palette) { PaletteArray destPalette; // Constants for saturation and gray scale calculation @@ -387,15 +383,15 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) { constexpr int NUM_CHROMA = 16; constexpr int NUM_LUMA = 8; - constexpr float SATURATION = 0.25F; + constexpr float SATURATION = 0.25F; // default saturation float color[NUM_CHROMA][2] = {{0.0F}}; if(timing == ConsoleTiming::ntsc) { // YIQ is YUV shifted by 33° - constexpr float offset = 33 * (2 * BSPF::PI_f / 360); - const float shift = myPhaseNTSC * (2 * BSPF::PI_f / 360); + constexpr float offset = 33 * BSPF::PI_f / 180; + const float shift = myPhaseNTSC * BSPF::PI_f / 180; // color 0 is grayscale for(int chroma = 1; chroma < NUM_CHROMA; chroma++) @@ -425,13 +421,9 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) G = powf(G, 0.9F); B = powf(B, 0.9F); - if(R > 1) R = 1; - if(G > 1) G = 1; - if(B > 1) B = 1; - - int r = R * 255.F; - int g = G * 255.F; - int b = B * 255.F; + int r = BSPF::clamp(R * 255.F, 0.F, 255.F); + int g = BSPF::clamp(G * 255.F, 0.F, 255.F); + int b = BSPF::clamp(B * 255.F, 0.F, 255.F); ourCustomNTSCPalette[(chroma * NUM_LUMA + luma) << 1] = (r << 16) + (g << 8) + b; } @@ -439,9 +431,9 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) } else if(timing == ConsoleTiming::pal) { - constexpr float offset = 180 * (2 * BSPF::PI_f / 360); - const float shift = myPhasePAL * (2 * BSPF::PI_f / 360); - constexpr float fixedShift = 22.5F * (2 * BSPF::PI_f / 360); + constexpr float offset = BSPF::PI_f; + const float shift = myPhasePAL * BSPF::PI_f / 180; + constexpr float fixedShift = 22.5F * BSPF::PI_f / 180; // colors 0, 1, 14 and 15 are grayscale for(int chroma = 2; chroma < NUM_CHROMA - 2; chroma++) @@ -470,7 +462,7 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) // German Wikipedia, huh??? //float B = Y + 1 / 0.493 * U; //float R = Y + 1 / 0.877 * V; - //float G = 1.704 * Y - 0.590 * R - 0.194 * B; + //float G = 1.704 * Y - 0.590 * R - 0.194 * B; if(R < 0) R = 0.0; if(G < 0) G = 0.0; @@ -480,13 +472,9 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) G = powf(G, 1.2F); B = powf(B, 1.2F); - if(R > 1) R = 1; - if(G > 1) G = 1; - if(B > 1) B = 1; - - int r = R * 255.F; - int g = G * 255.F; - int b = B * 255.F; + int r = BSPF::clamp(R * 255.F, 0.F, 255.F); + int g = BSPF::clamp(G * 255.F, 0.F, 255.F); + int b = BSPF::clamp(B * 255.F, 0.F, 255.F); ourCustomPALPalette[(chroma * NUM_LUMA + luma) << 1] = (r << 16) + (g << 8) + b; } diff --git a/src/common/PaletteHandler.hxx b/src/common/PaletteHandler.hxx index cffdc2ad4..237d9b878 100644 --- a/src/common/PaletteHandler.hxx +++ b/src/common/PaletteHandler.hxx @@ -25,22 +25,18 @@ class PaletteHandler { public: + // Setting names of palette types static constexpr const char* SETTING_STANDARD = "standard"; static constexpr const char* SETTING_Z26 = "z26"; static constexpr const char* SETTING_USER = "user"; static constexpr const char* SETTING_CUSTOM = "custom"; + // Phase shift default and limits static constexpr float DEF_NTSC_SHIFT = 26.2F; - static constexpr float DEF_PAL_SHIFT = 31.3F; // 360 / 11.5 + static constexpr float DEF_PAL_SHIFT = 31.3F; // ~= 360 / 11.5 static constexpr float MAX_SHIFT = 4.5F; - enum DisplayType { - NTSC, - PAL, - SECAM, - NumDisplayTypes - }; - + // Externally used adjustment parameters struct Adjustable { float phaseNtsc, phasePal; uInt32 hue, saturation, contrast, brightness, gamma; @@ -51,28 +47,38 @@ class PaletteHandler virtual ~PaletteHandler() = default; /** - Switch between the available palettes. - */ - void changePalette(bool increase = true); + Cycle through available palettes. - void selectAdjustable(bool next = true); + @param next Select next palette, else previous one + */ + void cyclePalette(bool next = true); + + /* + Cycle through each palette adjustable + + @param next Select next adjustable, else previous one + */ + void cycleAdjustable(bool next = true); + + /* + Increase or decrease current palette adjustable + + @param increase Increase adjustable if true, else decrease + */ void changeAdjustable(bool increase = true); - + // Load adjustables from settings void loadConfig(const Settings& settings); + + // Save adjustables to settings void saveConfig(Settings& settings) const; + + // Set adjustables void setAdjustables(const Adjustable& adjustable); + + // Retrieve current adjustables void getAdjustables(Adjustable& adjustable) const; - /** - Change the "phase shift" variable. - Note that there are two of these (NTSC and PAL). The currently - active mode will determine which one is used. - - @param increase increase if true, else decrease. - */ - void changeColorPhaseShift(bool increase = true); - /** Sets the palette according to the given palette name. @@ -80,18 +86,14 @@ class PaletteHandler */ void setPalette(const string& name); - /** Sets the palette from current settings. */ void setPalette(); - /** - Generates a custom palette, based on user defined phase shifts. - */ - void generateCustomPalette(ConsoleTiming timing); - private: + static constexpr char DEGREE = 0x1c; + enum PaletteType { Standard, Z26, @@ -102,14 +104,64 @@ class PaletteHandler MaxType = Custom }; + /** + Convert adjustables from/to 100% scale + */ float scaleFrom100(float x) const { return (x / 50.F) - 1.F; } uInt32 scaleTo100(float x) const { return uInt32(50 * (x + 1.F)); } + /** + Convert palette settings name to enumeration + + @param name The given palette's settings name + + @return The palette type + */ PaletteType toPaletteType(const string& name) const; + + /** + Convert enumeration to palette settings name + + @param type The given palette type + + @return The palette's settings name + */ string toPaletteName(PaletteType type) const; - PaletteArray adjustPalette(const PaletteArray& source); + /** + Change the "phase shift" variable. + Note that there are two of these (NTSC and PAL). The currently + active mode will determine which one is used. + @param increase Increase if true, else decrease. + */ + void changeColorPhaseShift(bool increase = true); + + /** + Generates a custom palette, based on user defined phase shifts. + + @param timing Use NTSC or PAL phase shift and generate according palette + */ + void generateCustomPalette(ConsoleTiming timing); + + /** + Create new palette by applying palette adjustments on given palette + + @param type The palette which should be adjusted + + @return An adjusted palette + */ + PaletteArray adjustedPalette(const PaletteArray& source); + + /** + Adjust hue and saturation for given RGB values + + @param R The red value to adjust + @param G The green value to adjust + @param B The blue value to adjust + @param H The hue adjustment value + @param S The saturation + */ void adjustHueSaturation(int& R, int& G, int& B, float H, float S); /** @@ -118,15 +170,16 @@ class PaletteHandler */ void loadUserPalette(); - private: static constexpr int NUM_ADJUSTABLES = 6; OSystem& myOSystem; + // The currently selected adjustable uInt32 myCurrentAdjustable{0}; + struct AdjustableTag { - const char* const type{nullptr}; + const char* const name{nullptr}; float* value{nullptr}; }; const std::array myAdjustables = @@ -139,8 +192,9 @@ class PaletteHandler { "gamma", &myGamma }, } }; - float myPhaseNTSC{0.0F}; - float myPhasePAL{0.0F}; + // NTSC and PAL color phase shifts + float myPhaseNTSC{DEF_NTSC_SHIFT}; + float myPhasePAL{DEF_PAL_SHIFT}; // range -1.0 to +1.0 (as in AtariNTSC) // Basic parameters float myHue{0.0F}; // -1 = -180 degrees +1 = +180 degrees @@ -169,7 +223,7 @@ class PaletteHandler static PaletteArray ourUserPALPalette; static PaletteArray ourUserSECAMPalette; - // Table of RGB values for NTSC, PAL - custom-defined + // Table of RGB values for NTSC, PAL - custom-defined and generated static PaletteArray ourCustomNTSCPalette; static PaletteArray ourCustomPALPalette; diff --git a/src/common/tv_filters/NTSCFilter.cxx b/src/common/tv_filters/NTSCFilter.cxx index 8a40ddd2c..64f26da2b 100644 --- a/src/common/tv_filters/NTSCFilter.cxx +++ b/src/common/tv_filters/NTSCFilter.cxx @@ -74,8 +74,8 @@ string NTSCFilter::getPreset() const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string NTSCFilter::setNextAdjustable() { - if(myPreset != Preset::CUSTOM) - return "'Custom' TV mode not selected"; + //if(myPreset != Preset::CUSTOM) + // return "'Custom' TV mode not selected"; #ifdef BLARGG_PALETTE myCurrentAdjustable = (myCurrentAdjustable + 1) % 10; @@ -85,7 +85,8 @@ string NTSCFilter::setNextAdjustable() ostringstream buf; buf << "Custom adjustable '" << ourCustomAdjustables[myCurrentAdjustable].type - << "' selected"; + << "' selected (" + << scaleTo100(*ourCustomAdjustables[myCurrentAdjustable].value) << "%)"; return buf.str(); } @@ -93,8 +94,8 @@ string NTSCFilter::setNextAdjustable() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string NTSCFilter::setPreviousAdjustable() { - if(myPreset != Preset::CUSTOM) - return "'Custom' TV mode not selected"; + //if(myPreset != Preset::CUSTOM) + // return "'Custom' TV mode not selected"; #ifdef BLARGG_PALETTE if(myCurrentAdjustable == 0) myCurrentAdjustable = 9; @@ -104,7 +105,8 @@ string NTSCFilter::setPreviousAdjustable() else --myCurrentAdjustable; ostringstream buf; buf << "Custom adjustable '" << ourCustomAdjustables[myCurrentAdjustable].type - << "' selected"; + << "' selected (" + << scaleTo100(*ourCustomAdjustables[myCurrentAdjustable].value) << "%)"; return buf.str(); } @@ -112,8 +114,8 @@ string NTSCFilter::setPreviousAdjustable() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string NTSCFilter::increaseAdjustable() { - if(myPreset != Preset::CUSTOM) - return "'Custom' TV mode not selected"; + //if(myPreset != Preset::CUSTOM) + // return "'Custom' TV mode not selected"; uInt32 newval = scaleTo100(*ourCustomAdjustables[myCurrentAdjustable].value); newval += 2; if(newval > 100) newval = 100; @@ -121,7 +123,7 @@ string NTSCFilter::increaseAdjustable() ostringstream buf; buf << "Custom '" << ourCustomAdjustables[myCurrentAdjustable].type - << "' set to " << newval; + << "' set to " << newval << "%"; setPreset(myPreset); return buf.str(); @@ -130,8 +132,8 @@ string NTSCFilter::increaseAdjustable() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string NTSCFilter::decreaseAdjustable() { - if(myPreset != Preset::CUSTOM) - return "'Custom' TV mode not selected"; + //if(myPreset != Preset::CUSTOM) + // return "'Custom' TV mode not selected"; uInt32 newval = scaleTo100(*ourCustomAdjustables[myCurrentAdjustable].value); if(newval < 2) newval = 0; @@ -140,7 +142,7 @@ string NTSCFilter::decreaseAdjustable() ostringstream buf; buf << "Custom '" << ourCustomAdjustables[myCurrentAdjustable].type - << "' set to " << newval; + << "' set to " << newval << "%"; setPreset(myPreset); return buf.str(); diff --git a/src/emucore/Event.hxx b/src/emucore/Event.hxx index ae82ef810..fba15b6fb 100644 --- a/src/emucore/Event.hxx +++ b/src/emucore/Event.hxx @@ -101,7 +101,6 @@ class Event RewindPause, UnwindPause, FormatDecrease, FormatIncrease, PaletteDecrease, PaletteIncrease, ToggleColorLoss, - ColorShiftDecrease, ColorShiftIncrease, PreviousPaletteAttribute, NextPaletteAttribute, PaletteAttributeDecrease, PaletteAttributeIncrease, ToggleFullScreen, VidmodeDecrease, VidmodeIncrease, diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 325438765..362625909 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -437,11 +437,11 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::PreviousPaletteAttribute: - if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().selectAdjustable(false); + if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().cycleAdjustable(false); return; case Event::NextPaletteAttribute: - if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().selectAdjustable(true); + if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().cycleAdjustable(true); return; case Event::PaletteAttributeDecrease: @@ -452,14 +452,6 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().changeAdjustable(true); return; - case Event::ColorShiftDecrease: - if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().changeColorPhaseShift(false); - return; - - case Event::ColorShiftIncrease: - if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().changeColorPhaseShift(true); - return; - case Event::ToggleFullScreen: if (pressed && !repeated) myOSystem.frameBuffer().toggleFullscreen(); return; @@ -565,11 +557,11 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::PaletteDecrease: - if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().paletteHandler().changePalette(false); + if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().paletteHandler().cyclePalette(false); return; case Event::PaletteIncrease: - if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().paletteHandler().changePalette(true); + if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().paletteHandler().cyclePalette(true); return; case Event::ToggleInter: @@ -1965,8 +1957,6 @@ EventHandler::EmulActionList EventHandler::ourEmulActionList = { { { Event::NextPaletteAttribute, "Select next palette attribute", "" }, { Event::PaletteAttributeDecrease,"Decrease selected palette attribute", "" }, { Event::PaletteAttributeIncrease,"Increase selected palette attribute", "" }, - { Event::ColorShiftDecrease, "Decrease custom palette phase shift", "" }, - { Event::ColorShiftIncrease, "Increase custom palette phase shift", "" }, { Event::ToggleInter, "Toggle display interpolation", "" }, // Blargg TV effects: { Event::VidmodeStd, "Disable TV effects", "" }, @@ -2097,7 +2087,6 @@ const Event::EventSet EventHandler::AudioVideoEvents = { Event::ScanlineAdjustDecrease, Event::ScanlineAdjustIncrease, Event::OverscanDecrease, Event::OverscanIncrease, Event::PaletteDecrease, Event::PaletteIncrease, - Event::ColorShiftDecrease, Event::ColorShiftIncrease, Event::PreviousVideoMode, Event::NextVideoMode, Event::PreviousPaletteAttribute, Event::NextPaletteAttribute, Event::PaletteAttributeDecrease, Event::PaletteAttributeIncrease, diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx index fd8522e5f..6d19b685b 100644 --- a/src/emucore/EventHandler.hxx +++ b/src/emucore/EventHandler.hxx @@ -468,7 +468,7 @@ class EventHandler #else PNG_SIZE = 0, #endif - EMUL_ACTIONLIST_SIZE = 154 + PNG_SIZE + COMBO_SIZE, + EMUL_ACTIONLIST_SIZE = 152 + PNG_SIZE + COMBO_SIZE, MENU_ACTIONLIST_SIZE = 18 ; diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index a959cc255..07c41e0f3 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -21,6 +21,7 @@ #include "Version.hxx" #include "Logger.hxx" #include "AudioSettings.hxx" +#include "PaletteHandler.hxx" #include "Paddles.hxx" #ifdef DEBUGGER_SUPPORT @@ -45,7 +46,7 @@ Settings::Settings() setPermanent("center", "true"); setPermanent("windowedpos", Common::Point(50, 50)); setPermanent("display", 0); - setPermanent("palette", "standard"); + setPermanent("palette", PaletteHandler::SETTING_STANDARD); setPermanent("uimessages", "true"); // TIA specific options @@ -358,8 +359,11 @@ void Settings::validate() else if(i > 10) setValue("ssinterval", "10"); s = getString("palette"); - if(s != "standard" && s != "z26" && s != "user" && s != "custom") - setValue("palette", "standard"); + if(s != PaletteHandler::SETTING_STANDARD + && s != PaletteHandler::SETTING_Z26 + && s != PaletteHandler::SETTING_USER + && s != PaletteHandler::SETTING_CUSTOM) + setValue("palette", PaletteHandler::SETTING_STANDARD); s = getString("launcherfont"); if(s != "small" && s != "low_medium" && s != "medium" && s != "large" diff --git a/src/gui/CommandDialog.cxx b/src/gui/CommandDialog.cxx index 0d8729635..5790f7193 100644 --- a/src/gui/CommandDialog.cxx +++ b/src/gui/CommandDialog.cxx @@ -204,7 +204,7 @@ void CommandDialog::handleCommand(CommandSender* sender, int cmd, break; case kPaletteCmd: - instance().frameBuffer().tiaSurface().paletteHandler().changePalette(); + instance().frameBuffer().tiaSurface().paletteHandler().cyclePalette(); updatePalette(); break; @@ -270,11 +270,11 @@ void CommandDialog::updatePalette() string palette, label; palette = instance().settings().getString("palette"); - if(BSPF::equalsIgnoreCase(palette, "standard")) + if(BSPF::equalsIgnoreCase(palette, PaletteHandler::SETTING_STANDARD)) label = "Stella Palette"; - else if(BSPF::equalsIgnoreCase(palette, "z26")) + else if(BSPF::equalsIgnoreCase(palette, PaletteHandler::SETTING_Z26)) label = "Z26 Palette"; - else if(BSPF::equalsIgnoreCase(palette, "user")) + else if(BSPF::equalsIgnoreCase(palette, PaletteHandler::SETTING_USER)) label = "User Palette"; else label = "Custom Palette"; diff --git a/src/gui/VideoDialog.cxx b/src/gui/VideoDialog.cxx index a90657892..bc1fdfa36 100644 --- a/src/gui/VideoDialog.cxx +++ b/src/gui/VideoDialog.cxx @@ -269,11 +269,11 @@ void VideoDialog::addPaletteTab() // TIA Palette items.clear(); - VarList::push_back(items, "Standard", "standard"); - VarList::push_back(items, "z26", "z26"); + VarList::push_back(items, "Standard", PaletteHandler::SETTING_STANDARD); + VarList::push_back(items, "z26", PaletteHandler::SETTING_Z26); if (instance().checkUserPalette()) - VarList::push_back(items, "User", "user"); - VarList::push_back(items, "Custom", "custom"); + VarList::push_back(items, "User", PaletteHandler::SETTING_USER); + VarList::push_back(items, "Custom", PaletteHandler::SETTING_CUSTOM); myTIAPalette = new PopUpWidget(myTab, _font, xpos, ypos, pwidth, lineHeight, items, "Palette ", lwidth, kPaletteChanged); wid.push_back(myTIAPalette); @@ -421,7 +421,7 @@ void VideoDialog::loadConfig() // TIA Palette myPalette = instance().settings().getString("palette"); - myTIAPalette->setSelected(myPalette, "standard"); + myTIAPalette->setSelected(myPalette, PaletteHandler::SETTING_STANDARD); // Palette adjustables instance().frameBuffer().tiaSurface().paletteHandler().getAdjustables(myPaletteAdj); @@ -610,7 +610,7 @@ void VideoDialog::setDefaults() } case 1: // Palettes - myTIAPalette->setSelected("standard", ""); + myTIAPalette->setSelected(PaletteHandler::SETTING_STANDARD); myPhaseShiftNtsc->setValue(PaletteHandler::DEF_NTSC_SHIFT * 10); myPhaseShiftPal->setValue(PaletteHandler::DEF_PAL_SHIFT * 10); myTVHue->setValue(50); From 208969fcbe39ea9b8032e4b83f6f935a9b0e9e8e Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 11 May 2020 16:15:12 +0200 Subject: [PATCH 197/377] refactored Video and Audio dialogs into common dialog created new EmulationDialog (re)moved some includes to reduce compile time --- src/debugger/gui/CartDebugWidget.hxx | 3 - src/debugger/gui/CartEnhancedWidget.cxx | 2 + src/debugger/gui/DebuggerDialog.hxx | 2 +- src/emucore/OSystem.hxx | 2 +- src/gui/AudioDialog.cxx | 353 ------------ src/gui/AudioDialog.hxx | 77 --- src/gui/DeveloperDialog.cxx | 42 -- src/gui/DeveloperDialog.hxx | 2 - src/gui/EmulationDialog.cxx | 283 ++++++++++ src/gui/EmulationDialog.hxx | 63 +++ src/gui/InputDialog.cxx | 2 +- src/gui/OptionsDialog.cxx | 26 +- src/gui/OptionsDialog.hxx | 10 +- src/gui/UIDialog.cxx | 14 +- src/gui/UIDialog.hxx | 1 - .../{VideoDialog.cxx => VideoAudioDialog.cxx} | 528 ++++++++++++------ .../{VideoDialog.hxx => VideoAudioDialog.hxx} | 89 +-- src/gui/module.mk | 4 +- src/libpng/pngconf.h | 6 +- src/windows/Stella.vcxproj | 8 +- src/windows/Stella.vcxproj.filters | 24 +- 21 files changed, 795 insertions(+), 746 deletions(-) delete mode 100644 src/gui/AudioDialog.cxx delete mode 100644 src/gui/AudioDialog.hxx create mode 100644 src/gui/EmulationDialog.cxx create mode 100644 src/gui/EmulationDialog.hxx rename src/gui/{VideoDialog.cxx => VideoAudioDialog.cxx} (66%) rename src/gui/{VideoDialog.hxx => VideoAudioDialog.hxx} (75%) diff --git a/src/debugger/gui/CartDebugWidget.hxx b/src/debugger/gui/CartDebugWidget.hxx index 7bdcbf472..27c3befa5 100644 --- a/src/debugger/gui/CartDebugWidget.hxx +++ b/src/debugger/gui/CartDebugWidget.hxx @@ -19,7 +19,6 @@ #define CART_DEBUG_WIDGET_HXX class GuiObject; -class ButtonWidget; class StringListWidget; namespace GUI { @@ -29,8 +28,6 @@ namespace GUI { #include "Base.hxx" // not needed here, but all child classes need it #include "Command.hxx" #include "Widget.hxx" -#include "Debugger.hxx" -#include "CartDebug.hxx" class CartDebugWidget : public Widget, public CommandSender { diff --git a/src/debugger/gui/CartEnhancedWidget.cxx b/src/debugger/gui/CartEnhancedWidget.cxx index f864a21c0..d955a803a 100644 --- a/src/debugger/gui/CartEnhancedWidget.cxx +++ b/src/debugger/gui/CartEnhancedWidget.cxx @@ -17,6 +17,8 @@ #include "PopUpWidget.hxx" +#include "Debugger.hxx" +#include "CartDebug.hxx" #include "CartEnhanced.hxx" #include "CartEnhancedWidget.hxx" diff --git a/src/debugger/gui/DebuggerDialog.hxx b/src/debugger/gui/DebuggerDialog.hxx index b66ae37a6..bfd7c332b 100644 --- a/src/debugger/gui/DebuggerDialog.hxx +++ b/src/debugger/gui/DebuggerDialog.hxx @@ -33,6 +33,7 @@ class TiaOutputWidget; class TiaZoomWidget; class CartDebugWidget; class CartRamWidget; +class OptionsDialog; namespace Common { struct Rect; @@ -40,7 +41,6 @@ namespace Common { #include "Dialog.hxx" #include "MessageBox.hxx" -#include "OptionsDialog.hxx" class DebuggerDialog : public Dialog { diff --git a/src/emucore/OSystem.hxx b/src/emucore/OSystem.hxx index b23cbdb83..2bc5368c6 100644 --- a/src/emucore/OSystem.hxx +++ b/src/emucore/OSystem.hxx @@ -41,7 +41,7 @@ class AudioSettings; class Menu; class MessageMenu; class TimeMachine; - class VideoDialog; + class VideoAudioDialog; #endif #ifdef PNG_SUPPORT class PNGLibrary; diff --git a/src/gui/AudioDialog.cxx b/src/gui/AudioDialog.cxx deleted file mode 100644 index 1f97c2f8b..000000000 --- a/src/gui/AudioDialog.cxx +++ /dev/null @@ -1,353 +0,0 @@ -//============================================================================ -// -// 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 - -#include "bspf.hxx" - -#include "Console.hxx" -#include "Cart.hxx" -#include "CartDPC.hxx" -#include "Control.hxx" -#include "Dialog.hxx" -#include "Font.hxx" -#include "Menu.hxx" -#include "OSystem.hxx" -#include "PopUpWidget.hxx" -#include "Settings.hxx" -#include "Sound.hxx" -#include "Widget.hxx" -#include "AudioSettings.hxx" - -#include "AudioDialog.hxx" - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AudioDialog::AudioDialog(OSystem& osystem, DialogContainer& parent, - const GUI::Font& font) - : Dialog(osystem, parent, font, "Audio settings") -{ - const int lineHeight = font.getLineHeight(), - fontHeight = font.getFontHeight(), - fontWidth = font.getMaxCharWidth(); - const int VBORDER = fontHeight / 2; - const int HBORDER = fontWidth * 1.25; - const int INDENT = fontWidth * 2; - const int VGAP = fontHeight / 4; - - int xpos, ypos; - int lwidth = font.getStringWidth("Volume "), - pwidth; - - WidgetArray wid; - VariantList items; - - // Set real dimensions - _w = 48 * fontWidth + HBORDER * 2; - _h = 12 * (lineHeight + VGAP) + VBORDER + _th; - - xpos = HBORDER; ypos = VBORDER + _th; - - // Enable sound - mySoundEnableCheckbox = new CheckboxWidget(this, font, xpos, ypos, - "Enable sound", kSoundEnableChanged); - wid.push_back(mySoundEnableCheckbox); - ypos += lineHeight + VGAP; - xpos += CheckboxWidget::prefixSize(font); - - // Volume - myVolumeSlider = new SliderWidget(this, font, xpos, ypos, - "Volume", lwidth, 0, 4 * fontWidth, "%"); - myVolumeSlider->setMinValue(1); myVolumeSlider->setMaxValue(100); - myVolumeSlider->setTickmarkIntervals(4); - wid.push_back(myVolumeSlider); - ypos += lineHeight + VGAP; - - // Mode - items.clear(); - VarList::push_back(items, "Low quality, medium lag", static_cast(AudioSettings::Preset::lowQualityMediumLag)); - VarList::push_back(items, "High quality, medium lag", static_cast(AudioSettings::Preset::highQualityMediumLag)); - VarList::push_back(items, "High quality, low lag", static_cast(AudioSettings::Preset::highQualityLowLag)); - VarList::push_back(items, "Ultra quality, minimal lag", static_cast(AudioSettings::Preset::ultraQualityMinimalLag)); - VarList::push_back(items, "Custom", static_cast(AudioSettings::Preset::custom)); - myModePopup = new PopUpWidget(this, font, xpos, ypos, - font.getStringWidth("Ultry quality, minimal lag"), lineHeight, - items, "Mode", lwidth, kModeChanged); - wid.push_back(myModePopup); - ypos += lineHeight + VGAP; - xpos += INDENT; - - // Fragment size - pwidth = font.getStringWidth("512 samples") + 7; - lwidth = font.getStringWidth("Resampling quality "); - items.clear(); - VarList::push_back(items, "128 samples", 128); - VarList::push_back(items, "256 samples", 256); - VarList::push_back(items, "512 samples", 512); - VarList::push_back(items, "1k samples", 1024); - VarList::push_back(items, "2k samples", 2048); - VarList::push_back(items, "4K samples", 4096); - myFragsizePopup = new PopUpWidget(this, font, xpos, ypos, - pwidth, lineHeight, - items, "Fragment size", lwidth); - wid.push_back(myFragsizePopup); - ypos += lineHeight + VGAP; - - // Output frequency - items.clear(); - VarList::push_back(items, "44100 Hz", 44100); - VarList::push_back(items, "48000 Hz", 48000); - VarList::push_back(items, "96000 Hz", 96000); - myFreqPopup = new PopUpWidget(this, font, xpos, ypos, - pwidth, lineHeight, - items, "Sample rate", lwidth); - wid.push_back(myFreqPopup); - ypos += lineHeight + VGAP; - - // Resampling quality - items.clear(); - VarList::push_back(items, "Low", static_cast(AudioSettings::ResamplingQuality::nearestNeightbour)); - VarList::push_back(items, "High", static_cast(AudioSettings::ResamplingQuality::lanczos_2)); - VarList::push_back(items, "Ultra", static_cast(AudioSettings::ResamplingQuality::lanczos_3)); - myResamplingPopup = new PopUpWidget(this, font, xpos, ypos, - pwidth, lineHeight, - items, "Resampling quality ", lwidth); - wid.push_back(myResamplingPopup); - ypos += lineHeight + VGAP; - - // Param 1 - int swidth = pwidth+23; - myHeadroomSlider = new SliderWidget(this, font, xpos, ypos, swidth, lineHeight, - "Headroom ", 0, kHeadroomChanged, 10 * fontWidth); - myHeadroomSlider->setMinValue(0); myHeadroomSlider->setMaxValue(AudioSettings::MAX_HEADROOM); - myHeadroomSlider->setTickmarkIntervals(5); - wid.push_back(myHeadroomSlider); - ypos += lineHeight + VGAP; - - // Param 2 - myBufferSizeSlider = new SliderWidget(this, font, xpos, ypos, swidth, lineHeight, - "Buffer size ", 0, kBufferSizeChanged, 10 * fontWidth); - myBufferSizeSlider->setMinValue(0); myBufferSizeSlider->setMaxValue(AudioSettings::MAX_BUFFER_SIZE); - myBufferSizeSlider->setTickmarkIntervals(5); - wid.push_back(myBufferSizeSlider); - ypos += lineHeight + VGAP; - - // Stereo sound - xpos -= INDENT; - myStereoSoundCheckbox = new CheckboxWidget(this, font, xpos, ypos, - "Stereo for all ROMs"); - wid.push_back(myStereoSoundCheckbox); - ypos += lineHeight + VGAP; - - myDpcPitch = new SliderWidget(this, font, xpos, ypos, swidth - 16, lineHeight, - "Pitfall II music pitch ", 0, 0, 5 * fontWidth); - myDpcPitch->setMinValue(10000); myDpcPitch->setMaxValue(30000); - myDpcPitch->setStepValue(100); - myDpcPitch->setTickmarkIntervals(2); - wid.push_back(myDpcPitch); - - // Add Defaults, OK and Cancel buttons - addDefaultsOKCancelBGroup(wid, font); - - addToFocusList(wid); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void AudioDialog::loadConfig() -{ - AudioSettings& audioSettings = instance().audioSettings(); - - // Enable sound - mySoundEnableCheckbox->setState(audioSettings.enabled()); - - // Volume - myVolumeSlider->setValue(audioSettings.volume()); - - // Stereo - myStereoSoundCheckbox->setState(audioSettings.stereo()); - - // DPC Pitch - myDpcPitch->setValue(audioSettings.dpcPitch()); - - // Preset / mode - myModePopup->setSelected(static_cast(audioSettings.preset())); - - updateSettingsWithPreset(instance().audioSettings()); - - updateEnabledState(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void AudioDialog::updateSettingsWithPreset(AudioSettings& audioSettings) -{ - // Fragsize - myFragsizePopup->setSelected(audioSettings.fragmentSize()); - - // Output frequency - myFreqPopup->setSelected(audioSettings.sampleRate()); - - // Headroom - myHeadroomSlider->setValue(audioSettings.headroom()); - - // Buffer size - myBufferSizeSlider->setValue(audioSettings.bufferSize()); - - // Resampling quality - myResamplingPopup->setSelected(static_cast(audioSettings.resamplingQuality())); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void AudioDialog::saveConfig() -{ - AudioSettings& audioSettings = instance().audioSettings(); - - // Enabled - audioSettings.setEnabled(mySoundEnableCheckbox->getState()); - instance().sound().setEnabled(mySoundEnableCheckbox->getState()); - - // Volume - audioSettings.setVolume(myVolumeSlider->getValue()); - instance().sound().setVolume(myVolumeSlider->getValue()); - - // Stereo - audioSettings.setStereo(myStereoSoundCheckbox->getState()); - - // DPC Pitch - audioSettings.setDpcPitch(myDpcPitch->getValue()); - // update if current cart is Pitfall II - if (instance().hasConsole() && instance().console().cartridge().name() == "CartridgeDPC") - { - CartridgeDPC& cart = static_cast(instance().console().cartridge()); - cart.setDpcPitch(myDpcPitch->getValue()); - } - - AudioSettings::Preset preset = static_cast(myModePopup->getSelectedTag().toInt()); - audioSettings.setPreset(preset); - - if (preset == AudioSettings::Preset::custom) { - // Fragsize - audioSettings.setFragmentSize(myFragsizePopup->getSelectedTag().toInt()); - audioSettings.setSampleRate(myFreqPopup->getSelectedTag().toInt()); - audioSettings.setHeadroom(myHeadroomSlider->getValue()); - audioSettings.setBufferSize(myBufferSizeSlider->getValue()); - audioSettings.setResamplingQuality(static_cast(myResamplingPopup->getSelectedTag().toInt())); - } - - // Only force a re-initialization when necessary, since it can - // be a time-consuming operation - if(instance().hasConsole()) - instance().console().initializeAudio(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void AudioDialog::setDefaults() -{ - mySoundEnableCheckbox->setState(AudioSettings::DEFAULT_ENABLED); - myVolumeSlider->setValue(AudioSettings::DEFAULT_VOLUME); - myStereoSoundCheckbox->setState(AudioSettings::DEFAULT_STEREO); - myDpcPitch->setValue(AudioSettings::DEFAULT_DPC_PITCH); - myModePopup->setSelected(static_cast(AudioSettings::DEFAULT_PRESET)); - - if (AudioSettings::DEFAULT_PRESET == AudioSettings::Preset::custom) { - myResamplingPopup->setSelected(static_cast(AudioSettings::DEFAULT_RESAMPLING_QUALITY)); - myFragsizePopup->setSelected(AudioSettings::DEFAULT_FRAGMENT_SIZE); - myFreqPopup->setSelected(AudioSettings::DEFAULT_SAMPLE_RATE); - myHeadroomSlider->setValue(AudioSettings::DEFAULT_HEADROOM); - myBufferSizeSlider->setValue(AudioSettings::DEFAULT_BUFFER_SIZE); - } - else updatePreset(); - - updateEnabledState(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void AudioDialog::updateEnabledState() -{ - bool active = mySoundEnableCheckbox->getState(); - AudioSettings::Preset preset = static_cast(myModePopup->getSelectedTag().toInt()); - bool userMode = preset == AudioSettings::Preset::custom; - - myVolumeSlider->setEnabled(active); - myStereoSoundCheckbox->setEnabled(active); - myModePopup->setEnabled(active); - // enable only for Pitfall II cart - myDpcPitch->setEnabled(active && instance().hasConsole() && instance().console().cartridge().name() == "CartridgeDPC"); - - myFragsizePopup->setEnabled(active && userMode); - myFreqPopup->setEnabled(active && userMode); - myResamplingPopup->setEnabled(active && userMode); - myHeadroomSlider->setEnabled(active && userMode); - myBufferSizeSlider->setEnabled(active && userMode); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void AudioDialog::updatePreset() -{ - AudioSettings::Preset preset = static_cast(myModePopup->getSelectedTag().toInt()); - - // Make a copy that does not affect the actual settings... - AudioSettings audioSettings = instance().audioSettings(); - audioSettings.setPersistent(false); - // ... and set the requested preset - audioSettings.setPreset(preset); - - updateSettingsWithPreset(audioSettings); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void AudioDialog::handleCommand(CommandSender* sender, int cmd, - int data, int id) -{ - switch(cmd) - { - case GuiObject::kOKCmd: - saveConfig(); - close(); - break; - - case GuiObject::kDefaultsCmd: - setDefaults(); - break; - - case kSoundEnableChanged: - updateEnabledState(); - break; - - case kModeChanged: - updatePreset(); - updateEnabledState(); - break; - - case kHeadroomChanged: - { - std::ostringstream ss; - ss << std::fixed << std::setprecision(1) << (0.5 * myHeadroomSlider->getValue()) << " frames"; - myHeadroomSlider->setValueLabel(ss.str()); - break; - } - case kBufferSizeChanged: - { - std::ostringstream ss; - ss << std::fixed << std::setprecision(1) << (0.5 * myBufferSizeSlider->getValue()) << " frames"; - myBufferSizeSlider->setValueLabel(ss.str()); - break; - } - - default: - Dialog::handleCommand(sender, cmd, data, 0); - break; - } -} diff --git a/src/gui/AudioDialog.hxx b/src/gui/AudioDialog.hxx deleted file mode 100644 index b7aa35c65..000000000 --- a/src/gui/AudioDialog.hxx +++ /dev/null @@ -1,77 +0,0 @@ -//============================================================================ -// -// 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 AUDIO_DIALOG_HXX -#define AUDIO_DIALOG_HXX - -class CommandSender; -class Dialog; -class DialogContainer; -class PopUpWidget; -class SliderWidget; -class StaticTextWidget; -class CheckboxWidget; -class OSystem; -class AudioSettings; - -#include "bspf.hxx" - -class AudioDialog : public Dialog -{ - public: - AudioDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font); - virtual ~AudioDialog() = default; - - private: - void loadConfig() override; - void saveConfig() override; - void setDefaults() override; - - void updatePreset(); - void updateEnabledState(); - void updateSettingsWithPreset(AudioSettings&); - void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - - private: - enum { - kSoundEnableChanged = 'ADse', - kModeChanged = 'ADmc', - kHeadroomChanged = 'ADhc', - kBufferSizeChanged = 'ADbc' - }; - - CheckboxWidget* mySoundEnableCheckbox{nullptr}; - SliderWidget* myVolumeSlider{nullptr}; - CheckboxWidget* myStereoSoundCheckbox{nullptr}; - PopUpWidget* myModePopup{nullptr}; - PopUpWidget* myFragsizePopup{nullptr}; - PopUpWidget* myFreqPopup{nullptr}; - PopUpWidget* myResamplingPopup{nullptr}; - SliderWidget* myHeadroomSlider{nullptr}; - SliderWidget* myBufferSizeSlider{nullptr}; - SliderWidget* myDpcPitch{nullptr}; - - private: - // Following constructors and assignment operators not supported - AudioDialog() = delete; - AudioDialog(const AudioDialog&) = delete; - AudioDialog(AudioDialog&&) = delete; - AudioDialog& operator=(const AudioDialog&) = delete; - AudioDialog& operator=(AudioDialog&&) = delete; -}; - -#endif diff --git a/src/gui/DeveloperDialog.cxx b/src/gui/DeveloperDialog.cxx index 5badbc513..288fb6a40 100644 --- a/src/gui/DeveloperDialog.cxx +++ b/src/gui/DeveloperDialog.cxx @@ -499,31 +499,6 @@ void DeveloperDialog::addTimeMachineTab(const GUI::Font& font) lineHeight, items, "Horizon ~ ", 0, kHorizonChanged); wid.push_back(myStateHorizonWidget); - xpos = HBORDER + INDENT; - ypos += lineHeight + VGAP * 2; - new StaticTextWidget(myTab, font, HBORDER, ypos + 1, - "When entering/exiting emulation:"); - ypos += lineHeight + VGAP; - mySaveOnExitGroup = new RadioButtonGroup(); - r = new RadioButtonWidget(myTab, font, xpos, ypos + 1, - "Do nothing", mySaveOnExitGroup); - wid.push_back(r); - ypos += lineHeight + VGAP; - r = new RadioButtonWidget(myTab, font, xpos, ypos + 1, - "Save current state in current slot", mySaveOnExitGroup); - wid.push_back(r); - ypos += lineHeight + VGAP; - r = new RadioButtonWidget(myTab, font, xpos, ypos + 1, - "Load/save all Time Machine states", mySaveOnExitGroup); - wid.push_back(r); - ypos += lineHeight + VGAP; - xpos = HBORDER; - - - myAutoSlotWidget = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Automatically change save state slots"); - wid.push_back(myAutoSlotWidget); - ypos += lineHeight + VGAP; - // Add message concerning usage const GUI::Font& infofont = instance().frameBuffer().infoFont(); ypos = myTab->getHeight() - fontHeight - infofont.getFontHeight() - VGAP - VBORDER; @@ -678,8 +653,6 @@ void DeveloperDialog::loadSettings(SettingsSet set) myUncompressed[set] = instance().settings().getInt(prefix + "tm.uncompressed"); myStateInterval[set] = instance().settings().getString(prefix + "tm.interval"); myStateHorizon[set] = instance().settings().getString(prefix + "tm.horizon"); - - } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -871,12 +844,6 @@ void DeveloperDialog::loadConfig() // Debug colours handleDebugColours(instance().settings().getString("tia.dbgcolors")); - // Save on exit - string saveOnExit = instance().settings().getString("saveonexit"); - mySaveOnExitGroup->setSelected(saveOnExit == "all" ? 2 : saveOnExit == "current" ? 1 : 0); - // Automatically change save state slots - myAutoSlotWidget->setState(instance().settings().getBool("autoslot")); - #ifdef DEBUGGER_SUPPORT uInt32 w, h; @@ -953,13 +920,6 @@ void DeveloperDialog::saveConfig() instance().state().setRewindMode(myTimeMachineWidget->getState() ? StateManager::Mode::TimeMachine : StateManager::Mode::Off); - // Save on exit - int saveOnExit = mySaveOnExitGroup->getSelected(); - instance().settings().setValue("saveonexit", - saveOnExit == 0 ? "none" : saveOnExit == 1 ? "current" : "all"); - // Automatically change save state slots - instance().settings().setValue("autoslot", myAutoSlotWidget->getState()); - #ifdef DEBUGGER_SUPPORT // Debugger font style instance().settings().setValue("dbg.fontstyle", @@ -1050,8 +1010,6 @@ void DeveloperDialog::setDefaults() myStateHorizon[set] = devSettings ? "30s" : "10m"; setWidgetStates(set); - mySaveOnExitGroup->setSelected(0); - myAutoSlotWidget->setState(false); break; case 4: // Debugger options diff --git a/src/gui/DeveloperDialog.hxx b/src/gui/DeveloperDialog.hxx index ddee5468d..8bd84ab91 100644 --- a/src/gui/DeveloperDialog.hxx +++ b/src/gui/DeveloperDialog.hxx @@ -135,8 +135,6 @@ class DeveloperDialog : public Dialog SliderWidget* myUncompressedWidget{nullptr}; PopUpWidget* myStateIntervalWidget{nullptr}; PopUpWidget* myStateHorizonWidget{nullptr}; - RadioButtonGroup* mySaveOnExitGroup{nullptr}; - CheckboxWidget* myAutoSlotWidget{nullptr}; #ifdef DEBUGGER_SUPPORT // Debugger UI widgets diff --git a/src/gui/EmulationDialog.cxx b/src/gui/EmulationDialog.cxx new file mode 100644 index 000000000..111fa12f9 --- /dev/null +++ b/src/gui/EmulationDialog.cxx @@ -0,0 +1,283 @@ +//============================================================================ +// +// 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 "Console.hxx" +#include "FrameBuffer.hxx" +#include "RadioButtonWidget.hxx" +#include "TIASurface.hxx" + +#include "EmulationDialog.hxx" + +namespace { + // Emulation speed is a positive float that multiplies the framerate. However, the UI controls + // adjust speed in terms of a speedup factor (1/10, 1/9 .. 1/2, 1, 2, 3, .., 10). The following + // mapping and formatting functions implement this conversion. The speedup factor is represented + // by an integer value between -900 and 900 (0 means no speedup). + + constexpr int MAX_SPEED = 900; + constexpr int MIN_SPEED = -900; + constexpr int SPEED_STEP = 10; + + int mapSpeed(float speed) + { + speed = std::abs(speed); + + return BSPF::clamp( + static_cast(round(100 * (speed >= 1 ? speed - 1 : -1 / speed + 1))), + MIN_SPEED, MAX_SPEED + ); + } + + float unmapSpeed(int speed) + { + float f_speed = static_cast(speed) / 100; + + return speed < 0 ? -1 / (f_speed - 1) : 1 + f_speed; + } + + string formatSpeed(int speed) { + stringstream ss; + + ss + << std::setw(3) << std::fixed << std::setprecision(0) + << (unmapSpeed(speed) * 100); + + return ss.str(); + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +EmulationDialog::EmulationDialog(OSystem& osystem, DialogContainer& parent, + const GUI::Font& font, int max_w, int max_h) + : Dialog(osystem, parent, font, "Emulation settings") +{ + const int lineHeight = font.getLineHeight(), + fontHeight = font.getFontHeight(), + fontWidth = font.getMaxCharWidth(), + buttonHeight = font.getLineHeight() * 1.25; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = fontWidth * 2; + const int VGAP = fontHeight / 4; + + int xpos, ypos; + int lwidth = font.getStringWidth("Emulation speed "); + WidgetArray wid; + VariantList items; + const int swidth = fontWidth * 10; + + // Set real dimensions + _w = 37 * fontWidth + HBORDER * 2 + CheckboxWidget::prefixSize(_font); + _h = 12 * (lineHeight + VGAP) + VGAP * 7 + VBORDER * 3 + _th + buttonHeight; + + xpos = HBORDER; ypos = VBORDER + _th; + + // Speed + mySpeed = + new SliderWidget(this, _font, xpos, ypos-1, swidth, lineHeight, + "Emulation speed ", lwidth, kSpeedupChanged, fontWidth * 5, "%"); + mySpeed->setMinValue(MIN_SPEED); mySpeed->setMaxValue(MAX_SPEED); + mySpeed->setStepValue(SPEED_STEP); + mySpeed->setTickmarkIntervals(2); + wid.push_back(mySpeed); + ypos += lineHeight + VGAP; + + // Use sync to vblank + myUseVSync = new CheckboxWidget(this, _font, xpos, ypos + 1, "VSync"); + wid.push_back(myUseVSync); + ypos += lineHeight + VGAP; + + + myTurbo = new CheckboxWidget(this, _font, xpos, ypos + 1, "Turbo mode"); + wid.push_back(myTurbo); + ypos += lineHeight + VGAP * 3; + + // Use multi-threading + myUseThreads = new CheckboxWidget(this, _font, xpos, ypos + 1, "Multi-threading"); + wid.push_back(myUseThreads); + ypos += lineHeight + VGAP; + + // Skip progress load bars for SuperCharger ROMs + // Doesn't really belong here, but I couldn't find a better place for it + myFastSCBios = new CheckboxWidget(this, _font, xpos, ypos + 1, "Fast SuperCharger load"); + wid.push_back(myFastSCBios); + ypos += lineHeight + VGAP; + + // Show UI messages onscreen + myUIMessages = new CheckboxWidget(this, _font, xpos, ypos + 1, "Show UI messages"); + wid.push_back(myUIMessages); + ypos += lineHeight + VGAP; + + // Confirm dialog when exiting emulation + xpos = HBORDER; ypos += VGAP * 3; + myConfirmExitWidget = new CheckboxWidget(this, _font, xpos, ypos, "Confirm exiting emulation"); + wid.push_back(myConfirmExitWidget); + + xpos = HBORDER + INDENT; + ypos += lineHeight + VGAP * 3; + new StaticTextWidget(this, font, HBORDER, ypos + 1, + "When entering/exiting emulation:"); + ypos += lineHeight + VGAP; + mySaveOnExitGroup = new RadioButtonGroup(); + RadioButtonWidget* r; + r = new RadioButtonWidget(this, font, xpos, ypos + 1, + "Do nothing", mySaveOnExitGroup); + wid.push_back(r); + ypos += lineHeight + VGAP; + r = new RadioButtonWidget(this, font, xpos, ypos + 1, + "Save current state in current slot", mySaveOnExitGroup); + wid.push_back(r); + ypos += lineHeight + VGAP; + r = new RadioButtonWidget(this, font, xpos, ypos + 1, + "Load/save all Time Machine states", mySaveOnExitGroup); + wid.push_back(r); + ypos += lineHeight + VGAP; + xpos = HBORDER; + + + myAutoSlotWidget = new CheckboxWidget(this, font, xpos, ypos + 1, "Automatically change save state slots"); + wid.push_back(myAutoSlotWidget); + ypos += lineHeight + VGAP; + + // Add Defaults, OK and Cancel buttons + addDefaultsOKCancelBGroup(wid, font); + + addToFocusList(wid); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void EmulationDialog::loadConfig() +{ + Settings& settings = instance().settings(); + + // Emulation speed + int speed = mapSpeed(settings.getFloat("speed")); + mySpeed->setValue(speed); + mySpeed->setValueLabel(formatSpeed(speed)); + + // Use sync to vertical blank + myUseVSync->setState(settings.getBool("vsync")); + + // Enable 'Turbo' mode + myTurbo->setState(settings.getBool("turbo")); + + // Show UI messages + myUIMessages->setState(settings.getBool("uimessages")); + + // Fast loading of Supercharger BIOS + myFastSCBios->setState(settings.getBool("fastscbios")); + + // Multi-threaded rendering + myUseThreads->setState(settings.getBool("threads")); + + // Confirm dialog when exiting emulation + myConfirmExitWidget->setState(settings.getBool("confirmexit")); + + // Save on exit + string saveOnExit = settings.getString("saveonexit"); + mySaveOnExitGroup->setSelected(saveOnExit == "all" ? 2 : saveOnExit == "current" ? 1 : 0); + // Automatically change save state slots + myAutoSlotWidget->setState(settings.getBool("autoslot")); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void EmulationDialog::saveConfig() +{ + Settings& settings = instance().settings(); + + // Speed + const int speedup = mySpeed->getValue(); + settings.setValue("speed", unmapSpeed(speedup)); + if(instance().hasConsole()) + instance().console().initializeAudio(); + + // Use sync to vertical blank + settings.setValue("vsync", myUseVSync->getState()); + + // Enable 'Turbo' mode + settings.setValue("turbo", myTurbo->getState()); + + // Show UI messages + settings.setValue("uimessages", myUIMessages->getState()); + + // Fast loading of Supercharger BIOS + settings.setValue("fastscbios", myFastSCBios->getState()); + + // Multi-threaded rendering + settings.setValue("threads", myUseThreads->getState()); + + // Confirm dialog when exiting emulation + settings.setValue("confirmexit", myConfirmExitWidget->getState()); + + // Save on exit + int saveOnExit = mySaveOnExitGroup->getSelected(); + settings.setValue("saveonexit", + saveOnExit == 0 ? "none" : saveOnExit == 1 ? "current" : "all"); + // Automatically change save state slots + settings.setValue("autoslot", myAutoSlotWidget->getState()); + + if(instance().hasConsole()) + { + // update speed + instance().console().initializeAudio(); + // update VSync + instance().console().initializeVideo(); + + instance().frameBuffer().tiaSurface().ntsc().enableThreading(myUseThreads->getState()); + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void EmulationDialog::setDefaults() +{ + // speed + mySpeed->setValue(0); + myUseVSync->setState(true); + // misc + myUIMessages->setState(true); + myFastSCBios->setState(true); + myUseThreads->setState(false); + myConfirmExitWidget->setState(false); + + mySaveOnExitGroup->setSelected(0); + myAutoSlotWidget->setState(false); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void EmulationDialog::handleCommand(CommandSender* sender, int cmd, + int data, int id) +{ + switch(cmd) + { + case GuiObject::kOKCmd: + saveConfig(); + close(); + break; + + case GuiObject::kDefaultsCmd: + setDefaults(); + break; + + case kSpeedupChanged: + mySpeed->setValueLabel(formatSpeed(mySpeed->getValue())); + break; + + default: + Dialog::handleCommand(sender, cmd, data, 0); + break; + } +} \ No newline at end of file diff --git a/src/gui/EmulationDialog.hxx b/src/gui/EmulationDialog.hxx new file mode 100644 index 000000000..f1470d7bb --- /dev/null +++ b/src/gui/EmulationDialog.hxx @@ -0,0 +1,63 @@ +//============================================================================ +// +// 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 EMULATION_DIALOG_HXX +#define EMULATION_DIALOG_HXX + +class RadioButtonGroup; + +#include "Dialog.hxx" + +class EmulationDialog : public Dialog +{ +public: + EmulationDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, + int max_w, int max_h); + virtual ~EmulationDialog() = default; + +private: + void loadConfig() override; + void saveConfig() override; + void setDefaults() override; + + void handleCommand(CommandSender* sender, int cmd, int data, int id) override; + +private: + SliderWidget* mySpeed{nullptr}; + CheckboxWidget* myUseVSync{nullptr}; + CheckboxWidget* myTurbo{nullptr}; + CheckboxWidget* myUIMessages{nullptr}; + CheckboxWidget* myFastSCBios{nullptr}; + CheckboxWidget* myUseThreads{nullptr}; + CheckboxWidget* myConfirmExitWidget{nullptr}; + RadioButtonGroup* mySaveOnExitGroup{nullptr}; + CheckboxWidget* myAutoSlotWidget{nullptr}; + + enum { + kSpeedupChanged = 'EDSp', + }; + +private: + // Following constructors and assignment operators not supported + EmulationDialog() = delete; + EmulationDialog(const EmulationDialog&) = delete; + EmulationDialog(EmulationDialog&&) = delete; + EmulationDialog& operator=(const EmulationDialog&) = delete; + EmulationDialog& operator=(EmulationDialog&&) = delete; +}; + +#endif diff --git a/src/gui/InputDialog.cxx b/src/gui/InputDialog.cxx index 03cedb644..c3959c742 100644 --- a/src/gui/InputDialog.cxx +++ b/src/gui/InputDialog.cxx @@ -53,7 +53,7 @@ InputDialog::InputDialog(OSystem& osystem, DialogContainer& parent, int xpos, ypos, tabID; // Set real dimensions - setSize(50 * fontWidth + HBORDER * 2, + setSize(48 * fontWidth + PopUpWidget::dropDownWidth(_font) + HBORDER * 2, _th + VGAP * 3 + lineHeight + 13 * (lineHeight + VGAP) + VGAP * 8 + buttonHeight + VBORDER * 3, max_w, max_h); diff --git a/src/gui/OptionsDialog.cxx b/src/gui/OptionsDialog.cxx index 84ea9f605..865103822 100644 --- a/src/gui/OptionsDialog.cxx +++ b/src/gui/OptionsDialog.cxx @@ -23,8 +23,8 @@ #include "Widget.hxx" #include "Font.hxx" #include "Control.hxx" -#include "VideoDialog.hxx" -#include "AudioDialog.hxx" +#include "EmulationDialog.hxx" +#include "VideoAudioDialog.hxx" #include "InputDialog.hxx" #include "UIDialog.hxx" #include "SnapshotDialog.hxx" @@ -89,13 +89,10 @@ OptionsDialog::OptionsDialog(OSystem& osystem, DialogContainer& parent, return bw; }; - b = ADD_OD_BUTTON("Video" + ELLIPSIS, kVidCmd); + b = ADD_OD_BUTTON("Video & Audio" + ELLIPSIS, kVidCmd); wid.push_back(b); - b = ADD_OD_BUTTON("Audio" + ELLIPSIS, kAudCmd); -#ifndef SOUND_SUPPORT - b->clearFlags(Widget::FLAG_ENABLED); -#endif + b = ADD_OD_BUTTON("Emulation" + ELLIPSIS, kEmuCmd); wid.push_back(b); b = ADD_OD_BUTTON("Input" + ELLIPSIS, kInptCmd); @@ -143,8 +140,8 @@ OptionsDialog::OptionsDialog(OSystem& osystem, DialogContainer& parent, addCancelWidget(b); // Now create all the dialogs attached to each menu button - myVideoDialog = make_unique(osystem, parent, _font, max_w, max_h); - myAudioDialog = make_unique(osystem, parent, _font); + myVideoDialog = make_unique(osystem, parent, _font, max_w, max_h); + myEmulationDialog= make_unique(osystem, parent, _font, max_w, max_h); myInputDialog = make_unique(osystem, parent, _font, max_w, max_h); myUIDialog = make_unique(osystem, parent, _font, boss, max_w, max_h); mySnapshotDialog = make_unique(osystem, parent, _font, max_w, max_h); @@ -212,6 +209,10 @@ void OptionsDialog::handleCommand(CommandSender* sender, int cmd, instance().eventHandler().leaveMenuMode(); break; + case kEmuCmd: + myEmulationDialog->open(); + break; + case kVidCmd: { // This dialog is resizable under certain conditions, so we need @@ -220,17 +221,12 @@ void OptionsDialog::handleCommand(CommandSender* sender, int cmd, if(myVideoDialog == nullptr || myVideoDialog->shouldResize(w, h)) { - myVideoDialog = make_unique(instance(), parent(), + myVideoDialog = make_unique(instance(), parent(), instance().frameBuffer().font(), w, h); } myVideoDialog->open(); break; } - - case kAudCmd: - myAudioDialog->open(); - break; - case kInptCmd: { // This dialog is resizable under certain conditions, so we need diff --git a/src/gui/OptionsDialog.hxx b/src/gui/OptionsDialog.hxx index 3b5598693..001fad73b 100644 --- a/src/gui/OptionsDialog.hxx +++ b/src/gui/OptionsDialog.hxx @@ -22,8 +22,8 @@ class CommandSender; class DialogContainer; class GuiObject; class OSystem; -class VideoDialog; -class AudioDialog; +class EmulationDialog; +class VideoAudioDialog; class InputDialog; class UIDialog; class SnapshotDialog; @@ -52,8 +52,8 @@ class OptionsDialog : public Dialog void handleCommand(CommandSender* sender, int cmd, int data, int id) override; private: - unique_ptr myVideoDialog; - unique_ptr myAudioDialog; + unique_ptr myVideoDialog; + unique_ptr myEmulationDialog; unique_ptr myInputDialog; unique_ptr myUIDialog; unique_ptr mySnapshotDialog; @@ -78,7 +78,7 @@ class OptionsDialog : public Dialog enum { kBasSetCmd = 'BAST', kVidCmd = 'VIDO', - kAudCmd = 'AUDO', + kEmuCmd = 'EMUO', kInptCmd = 'INPT', kUsrIfaceCmd = 'URIF', kSnapCmd = 'SNAP', diff --git a/src/gui/UIDialog.cxx b/src/gui/UIDialog.cxx index 94032a4ce..eafc2e00b 100644 --- a/src/gui/UIDialog.cxx +++ b/src/gui/UIDialog.cxx @@ -127,13 +127,8 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, myCenter = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Center windows"); wid.push_back(myCenter); - // Confirm dialog when exiting emulation - xpos = HBORDER; ypos += lineHeight + VGAP * 2; - myConfirmExitWidget = new CheckboxWidget(myTab, font, xpos, ypos, "Confirm exiting emulation"); - wid.push_back(myConfirmExitWidget); - ypos += lineHeight + VGAP * 3; - // Delay between quick-selecting characters in ListWidget + xpos = HBORDER; ypos += lineHeight + VGAP * 4; int swidth = myPalettePopup->getWidth() - lwidth; myListDelaySlider = new SliderWidget(myTab, font, xpos, ypos, swidth, lineHeight, "List input delay ", 0, kListDelay, @@ -384,9 +379,6 @@ void UIDialog::loadConfig() // Center window myCenter->setState(settings.getBool("center")); - // Confirm dialog when exiting emulation - myConfirmExitWidget->setState(settings.getBool("confirmexit")); - // Listwidget quick delay int delay = settings.getInt("listdelay"); myListDelaySlider->setValue(delay); @@ -462,9 +454,6 @@ void UIDialog::saveConfig() // Center window settings.setValue("center", myCenter->getState()); - // Confirm dialog when exiting emulation - settings.setValue("confirmexit", myConfirmExitWidget->getState()); - // Listwidget quick delay settings.setValue("listdelay", myListDelaySlider->getValue()); FileListWidget::setQuickSelectDelay(myListDelaySlider->getValue()); @@ -501,7 +490,6 @@ void UIDialog::setDefaults() myHidpiWidget->setState(false); myPositionPopup->setSelected("0"); myCenter->setState(false); - myConfirmExitWidget->setState(false); myListDelaySlider->setValue(300); myWheelLinesSlider->setValue(4); myDoubleClickSlider->setValue(500); diff --git a/src/gui/UIDialog.hxx b/src/gui/UIDialog.hxx index 91bc7ff82..6ed1c655f 100644 --- a/src/gui/UIDialog.hxx +++ b/src/gui/UIDialog.hxx @@ -70,7 +70,6 @@ class UIDialog : public Dialog, public CommandSender CheckboxWidget* myHidpiWidget{nullptr}; PopUpWidget* myPositionPopup{nullptr}; CheckboxWidget* myCenter{nullptr}; - CheckboxWidget* myConfirmExitWidget{nullptr}; SliderWidget* myListDelaySlider{nullptr}; SliderWidget* myWheelLinesSlider{nullptr}; SliderWidget* myControllerRateSlider{nullptr}; diff --git a/src/gui/VideoDialog.cxx b/src/gui/VideoAudioDialog.cxx similarity index 66% rename from src/gui/VideoDialog.cxx rename to src/gui/VideoAudioDialog.cxx index bc1fdfa36..dbab74acf 100644 --- a/src/gui/VideoDialog.cxx +++ b/src/gui/VideoAudioDialog.cxx @@ -20,6 +20,8 @@ #include "bspf.hxx" #include "Base.hxx" #include "Control.hxx" +#include "Cart.hxx" +#include "CartDPC.hxx" #include "Dialog.hxx" #include "Menu.hxx" #include "OSystem.hxx" @@ -30,51 +32,15 @@ #include "PaletteHandler.hxx" #include "TIA.hxx" #include "Settings.hxx" +#include "Sound.hxx" +#include "AudioSettings.hxx" #include "Widget.hxx" #include "Font.hxx" #include "TabWidget.hxx" #include "NTSCFilter.hxx" #include "TIASurface.hxx" -#include "VideoDialog.hxx" - -namespace { - // Emulation speed is a positive float that multiplies the framerate. However, the UI controls - // adjust speed in terms of a speedup factor (1/10, 1/9 .. 1/2, 1, 2, 3, .., 10). The following - // mapping and formatting functions implement this conversion. The speedup factor is represented - // by an integer value between -900 and 900 (0 means no speedup). - - constexpr int MAX_SPEED = 900; - constexpr int MIN_SPEED = -900; - constexpr int SPEED_STEP = 10; - - int mapSpeed(float speed) - { - speed = std::abs(speed); - - return BSPF::clamp( - static_cast(round(100 * (speed >= 1 ? speed - 1 : -1 / speed + 1))), - MIN_SPEED, MAX_SPEED - ); - } - - float unmapSpeed(int speed) - { - float f_speed = static_cast(speed) / 100; - - return speed < 0 ? -1 / (f_speed - 1) : 1 + f_speed; - } - - string formatSpeed(int speed) { - stringstream ss; - - ss - << std::setw(3) << std::fixed << std::setprecision(0) - << (unmapSpeed(speed) * 100); - - return ss.str(); - } -} +#include "VideoAudioDialog.hxx" #define CREATE_CUSTOM_SLIDERS(obj, desc, cmd) \ myTV ## obj = \ @@ -87,9 +53,9 @@ namespace { ypos += lineHeight + VGAP; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, +VideoAudioDialog::VideoAudioDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, int max_w, int max_h) - : Dialog(osystem, parent, font, "Video settings") + : Dialog(osystem, parent, font, "Video & Audio settings") { const int lineHeight = _font.getLineHeight(), fontHeight = _font.getFontHeight(), @@ -101,8 +67,8 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, int xpos, ypos; // Set real dimensions - setSize(57 * fontWidth + HBORDER * 2 + PopUpWidget::dropDownWidth(font) * 2, - _th + VGAP * 3 + lineHeight + 11 * (lineHeight + VGAP) + buttonHeight + VBORDER * 3, + setSize(44 * fontWidth + HBORDER * 2 + PopUpWidget::dropDownWidth(font) * 2, + _th + VGAP * 6 + lineHeight + 10 * (lineHeight + VGAP) + buttonHeight + VBORDER * 3, max_w, max_h); // The tab widget @@ -112,9 +78,10 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, _h - _th - VGAP - buttonHeight - VBORDER * 2); addTabWidget(myTab); - addGeneralTab(); + addDisplayTab(); addPaletteTab(); addTVEffectsTab(); + addAudioTab(); //const int req_w = std::max(myFastSCBios->getRight(), myCloneBad->getRight()) + HBORDER + 1; //const int req_h = _th + VGAP * 3 @@ -141,7 +108,7 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::addGeneralTab() +void VideoAudioDialog::addDisplayTab() { const int lineHeight = _font.getLineHeight(), fontHeight = _font.getFontHeight(), @@ -152,24 +119,32 @@ void VideoDialog::addGeneralTab() const int HBORDER = fontWidth * 1.25; const int INDENT = CheckboxWidget::prefixSize(_font); const int lwidth = _font.getStringWidth("V-Size adjust "), - pwidth = _font.getStringWidth("XXXXxXXXX"); + pwidth = _font.getStringWidth("OpenGLES2"); int xpos = HBORDER, ypos = VBORDER; WidgetArray wid; VariantList items; - const int tabID = myTab->addTab(" General "); + const int tabID = myTab->addTab(" Display ", TabWidget::AUTO_WIDTH); // Video renderer myRenderer = new PopUpWidget(myTab, _font, xpos, ypos, pwidth, lineHeight, instance().frameBuffer().supportedRenderers(), "Renderer ", lwidth); wid.push_back(myRenderer); + const int swidth = myRenderer->getWidth() - lwidth; ypos += lineHeight + VGAP; // TIA interpolation myTIAInterpolate = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Interpolation "); wid.push_back(myTIAInterpolate); ypos += lineHeight + VGAP * 4; + // TIA zoom levels (will be dynamically filled later) + myTIAZoom = new SliderWidget(myTab, _font, xpos, ypos - 1, swidth, lineHeight, + "Zoom ", lwidth, 0, fontWidth * 4, "%"); + myTIAZoom->setMinValue(200); myTIAZoom->setStepValue(FrameBuffer::ZOOM_STEPS * 100); + wid.push_back(myTIAZoom); + ypos += lineHeight + VGAP; + // Fullscreen myFullscreen = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Fullscreen", kFullScreenChanged); wid.push_back(myFullscreen); @@ -187,7 +162,6 @@ void VideoDialog::addGeneralTab() ypos += lineHeight + VGAP; // FS overscan - const int swidth = myRenderer->getWidth() - lwidth; myTVOverscan = new SliderWidget(myTab, _font, xpos + INDENT, ypos - 1, swidth, lineHeight, "Overscan", lwidth - INDENT, kOverscanChanged, fontWidth * 3, "%"); myTVOverscan->setMinValue(0); myTVOverscan->setMaxValue(10); @@ -195,13 +169,6 @@ void VideoDialog::addGeneralTab() wid.push_back(myTVOverscan); ypos += lineHeight + VGAP; - // TIA zoom levels (will be dynamically filled later) - myTIAZoom = new SliderWidget(myTab, _font, xpos, ypos - 1, swidth, lineHeight, - "Zoom ", lwidth, 0, fontWidth * 4, "%"); - myTIAZoom->setMinValue(200); myTIAZoom->setStepValue(FrameBuffer::ZOOM_STEPS * 100); - wid.push_back(myTIAZoom); - ypos += lineHeight + VGAP; - // Vertical size myVSizeAdjust = new SliderWidget(myTab, _font, xpos, ypos-1, swidth, lineHeight, @@ -209,47 +176,13 @@ void VideoDialog::addGeneralTab() myVSizeAdjust->setMinValue(-5); myVSizeAdjust->setMaxValue(5); myVSizeAdjust->setTickmarkIntervals(2); wid.push_back(myVSizeAdjust); - ypos += lineHeight + VGAP * 4; - - // Speed - mySpeed = - new SliderWidget(myTab, _font, xpos, ypos-1, swidth, lineHeight, - "Emul. speed ", lwidth, kSpeedupChanged, fontWidth * 5, "%"); - mySpeed->setMinValue(MIN_SPEED); mySpeed->setMaxValue(MAX_SPEED); - mySpeed->setStepValue(SPEED_STEP); - mySpeed->setTickmarkIntervals(2); - wid.push_back(mySpeed); - ypos += lineHeight + VGAP; - - // Use sync to vblank - myUseVSync = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "VSync"); - wid.push_back(myUseVSync); - - // Move over to the next column - xpos = myVSizeAdjust->getRight() + fontWidth * 3; - ypos = VBORDER; - - // Skip progress load bars for SuperCharger ROMs - // Doesn't really belong here, but I couldn't find a better place for it - myFastSCBios = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Fast SuperCharger load"); - wid.push_back(myFastSCBios); - ypos += lineHeight + VGAP; - - // Show UI messages onscreen - myUIMessages = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Show UI messages"); - wid.push_back(myUIMessages); - ypos += lineHeight + VGAP; - - // Use multi-threading - myUseThreads = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Multi-threading"); - wid.push_back(myUseThreads); // Add items for tab 0 addToFocusList(wid, myTab, tabID); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::addPaletteTab() +void VideoAudioDialog::addPaletteTab() { const int lineHeight = _font.getLineHeight(), fontHeight = _font.getFontHeight(), @@ -265,7 +198,7 @@ void VideoDialog::addPaletteTab() ypos = VBORDER; WidgetArray wid; VariantList items; - const int tabID = myTab->addTab(" Palettes "); + const int tabID = myTab->addTab(" Palettes ", TabWidget::AUTO_WIDTH); // TIA Palette items.clear(); @@ -308,15 +241,16 @@ void VideoDialog::addPaletteTab() CREATE_CUSTOM_SLIDERS(Gamma, "Gamma ", kPaletteUpdated) // The resulting palette - addPalette(myPhaseShiftNtsc->getRight() + fontWidth * 2, VBORDER, - fontWidth * 2 * 8, myTVGamma->getBottom() - myTIAPalette->getTop()); + xpos = myPhaseShiftNtsc->getRight() + fontWidth * 2; + addPalette(xpos, VBORDER, _w - 2 * 2 - HBORDER - xpos, + myTVGamma->getBottom() - myTIAPalette->getTop()); // Add items for tab 2 addToFocusList(wid, myTab, tabID); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::addTVEffectsTab() +void VideoAudioDialog::addTVEffectsTab() { const int lineHeight = _font.getLineHeight(), fontHeight = _font.getFontHeight(), @@ -332,7 +266,7 @@ void VideoDialog::addTVEffectsTab() const int pwidth = _font.getStringWidth("Bad adjust "); WidgetArray wid; VariantList items; - const int tabID = myTab->addTab(" TV Effects "); + const int tabID = myTab->addTab(" TV Effects ", TabWidget::AUTO_WIDTH); items.clear(); VarList::push_back(items, "Disabled", static_cast(NTSCFilter::Preset::OFF)); @@ -403,11 +337,138 @@ void VideoDialog::addTVEffectsTab() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::loadConfig() +void VideoAudioDialog::addAudioTab() { + const int lineHeight = _font.getLineHeight(), + fontHeight = _font.getFontHeight(), + fontWidth = _font.getMaxCharWidth(); + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = CheckboxWidget::prefixSize(_font); + const int VGAP = fontHeight / 4; + + int xpos, ypos; + int lwidth = _font.getStringWidth("Volume "), + pwidth; + WidgetArray wid; + VariantList items; + const int tabID = myTab->addTab(" Audio ", TabWidget::AUTO_WIDTH); + + xpos = HBORDER; ypos = VBORDER; + + // Enable sound + mySoundEnableCheckbox = new CheckboxWidget(myTab, _font, xpos, ypos, + "Enable sound", kSoundEnableChanged); + wid.push_back(mySoundEnableCheckbox); + ypos += lineHeight + VGAP; + xpos += CheckboxWidget::prefixSize(_font); + + // Volume + myVolumeSlider = new SliderWidget(myTab, _font, xpos, ypos, + "Volume", lwidth, 0, 4 * fontWidth, "%"); + myVolumeSlider->setMinValue(1); myVolumeSlider->setMaxValue(100); + myVolumeSlider->setTickmarkIntervals(4); + wid.push_back(myVolumeSlider); + ypos += lineHeight + VGAP; + + // Mode + items.clear(); + VarList::push_back(items, "Low quality, medium lag", static_cast(AudioSettings::Preset::lowQualityMediumLag)); + VarList::push_back(items, "High quality, medium lag", static_cast(AudioSettings::Preset::highQualityMediumLag)); + VarList::push_back(items, "High quality, low lag", static_cast(AudioSettings::Preset::highQualityLowLag)); + VarList::push_back(items, "Ultra quality, minimal lag", static_cast(AudioSettings::Preset::ultraQualityMinimalLag)); + VarList::push_back(items, "Custom", static_cast(AudioSettings::Preset::custom)); + myModePopup = new PopUpWidget(myTab, _font, xpos, ypos, + _font.getStringWidth("Ultry quality, minimal lag"), lineHeight, + items, "Mode", lwidth, kModeChanged); + wid.push_back(myModePopup); + ypos += lineHeight + VGAP; + xpos += INDENT; + + // Fragment size + lwidth = _font.getStringWidth("Resampling quality "); + pwidth = myModePopup->getRight() - xpos - lwidth - PopUpWidget::dropDownWidth(_font); + items.clear(); + VarList::push_back(items, "128 samples", 128); + VarList::push_back(items, "256 samples", 256); + VarList::push_back(items, "512 samples", 512); + VarList::push_back(items, "1k samples", 1024); + VarList::push_back(items, "2k samples", 2048); + VarList::push_back(items, "4K samples", 4096); + myFragsizePopup = new PopUpWidget(myTab, _font, xpos, ypos, + pwidth, lineHeight, + items, "Fragment size", lwidth); + wid.push_back(myFragsizePopup); + ypos += lineHeight + VGAP; + + // Output frequency + items.clear(); + VarList::push_back(items, "44100 Hz", 44100); + VarList::push_back(items, "48000 Hz", 48000); + VarList::push_back(items, "96000 Hz", 96000); + myFreqPopup = new PopUpWidget(myTab, _font, xpos, ypos, + pwidth, lineHeight, + items, "Sample rate", lwidth); + wid.push_back(myFreqPopup); + ypos += lineHeight + VGAP; + + // Resampling quality + items.clear(); + VarList::push_back(items, "Low", static_cast(AudioSettings::ResamplingQuality::nearestNeightbour)); + VarList::push_back(items, "High", static_cast(AudioSettings::ResamplingQuality::lanczos_2)); + VarList::push_back(items, "Ultra", static_cast(AudioSettings::ResamplingQuality::lanczos_3)); + myResamplingPopup = new PopUpWidget(myTab, _font, xpos, ypos, + pwidth, lineHeight, + items, "Resampling quality ", lwidth); + wid.push_back(myResamplingPopup); + ypos += lineHeight + VGAP; + + // Param 1 + int swidth = pwidth + PopUpWidget::dropDownWidth(_font); + myHeadroomSlider = new SliderWidget(myTab, _font, xpos, ypos, swidth, lineHeight, + "Headroom ", 0, kHeadroomChanged, 10 * fontWidth); + myHeadroomSlider->setMinValue(0); myHeadroomSlider->setMaxValue(AudioSettings::MAX_HEADROOM); + myHeadroomSlider->setTickmarkIntervals(5); + wid.push_back(myHeadroomSlider); + ypos += lineHeight + VGAP; + + // Param 2 + myBufferSizeSlider = new SliderWidget(myTab, _font, xpos, ypos, swidth, lineHeight, + "Buffer size ", 0, kBufferSizeChanged, 10 * fontWidth); + myBufferSizeSlider->setMinValue(0); myBufferSizeSlider->setMaxValue(AudioSettings::MAX_BUFFER_SIZE); + myBufferSizeSlider->setTickmarkIntervals(5); + wid.push_back(myBufferSizeSlider); + ypos += lineHeight + VGAP; + + // Stereo sound + xpos -= INDENT; + myStereoSoundCheckbox = new CheckboxWidget(myTab, _font, xpos, ypos, + "Stereo for all ROMs"); + wid.push_back(myStereoSoundCheckbox); + ypos += lineHeight + VGAP; + + swidth += INDENT - fontWidth * 4; + myDpcPitch = new SliderWidget(myTab, _font, xpos, ypos, swidth, lineHeight, + "Pitfall II music pitch ", 0, 0, 5 * fontWidth); + myDpcPitch->setMinValue(10000); myDpcPitch->setMaxValue(30000); + myDpcPitch->setStepValue(100); + myDpcPitch->setTickmarkIntervals(2); + wid.push_back(myDpcPitch); + + // Add items for tab 4 + addToFocusList(wid, myTab, tabID); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void VideoAudioDialog::loadConfig() +{ + // Display tab // Renderer settings myRenderer->setSelected(instance().settings().getString("video"), "default"); + // TIA interpolation + myTIAInterpolate->setState(instance().settings().getBool("tia.inter")); + // TIA zoom levels // These are dynamically loaded, since they depend on the size of // the desktop and which renderer we're using @@ -419,6 +480,21 @@ void VideoDialog::loadConfig() myTIAZoom->setTickmarkIntervals((maxZoom - minZoom) * 2); // every ~50% myTIAZoom->setValue(instance().settings().getFloat("tia.zoom") * 100); + // 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")); + // Fullscreen overscan setting + myTVOverscan->setValue(instance().settings().getInt("tia.fs_overscan")); + handleFullScreenChange(); + + // Aspect ratio setting (NTSC and PAL) + myVSizeAdjust->setValue(instance().settings().getInt("tia.vsizeadjust")); + + ///////////////////////////////////////////////////////////////////////////// + // Palettes tab // TIA Palette myPalette = instance().settings().getString("palette"); myTIAPalette->setSelected(myPalette, PaletteHandler::SETTING_STANDARD); @@ -435,39 +511,8 @@ void VideoDialog::loadConfig() handlePaletteChange(); colorPalette(); - // TIA interpolation - myTIAInterpolate->setState(instance().settings().getBool("tia.inter")); - - // Aspect ratio setting (NTSC and PAL) - myVSizeAdjust->setValue(instance().settings().getInt("tia.vsizeadjust")); - - // Emulation speed - int speed = mapSpeed(instance().settings().getFloat("speed")); - mySpeed->setValue(speed); - mySpeed->setValueLabel(formatSpeed(speed)); - - // 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")); - // Fullscreen overscan setting - myTVOverscan->setValue(instance().settings().getInt("tia.fs_overscan")); - handleFullScreenChange(); - - // Use sync to vertical blank - myUseVSync->setState(instance().settings().getBool("vsync")); - - // Show UI messages - myUIMessages->setState(instance().settings().getBool("uimessages")); - - // Fast loading of Supercharger BIOS - myFastSCBios->setState(instance().settings().getBool("fastscbios")); - - // Multi-threaded rendering - myUseThreads->setState(instance().settings().getBool("threads")); - + ///////////////////////////////////////////////////////////////////////////// + // TV Effects tab // TV Mode myTVMode->setSelected( instance().settings().getString("tv.filter"), "0"); @@ -487,12 +532,60 @@ void VideoDialog::loadConfig() // TV scanline intensity and interpolation myTVScanIntense->setValue(instance().settings().getInt("tv.scanlines")); + ///////////////////////////////////////////////////////////////////////////// + // Audio tab + AudioSettings& audioSettings = instance().audioSettings(); + + // Enable sound +#ifndef SOUND_SUPPORT + mySoundEnableCheckbox->setState(audioSettings.enabled()); +#else + mySoundEnableCheckbox->setState(false); +#endif + + // Volume + myVolumeSlider->setValue(audioSettings.volume()); + + // Stereo + myStereoSoundCheckbox->setState(audioSettings.stereo()); + + // DPC Pitch + myDpcPitch->setValue(audioSettings.dpcPitch()); + + // Preset / mode + myModePopup->setSelected(static_cast(audioSettings.preset())); + + updateSettingsWithPreset(instance().audioSettings()); + + updateEnabledState(); + myTab->loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::saveConfig() +void VideoAudioDialog::updateSettingsWithPreset(AudioSettings& audioSettings) { + // Fragsize + myFragsizePopup->setSelected(audioSettings.fragmentSize()); + + // Output frequency + myFreqPopup->setSelected(audioSettings.sampleRate()); + + // Headroom + myHeadroomSlider->setValue(audioSettings.headroom()); + + // Buffer size + myBufferSizeSlider->setValue(audioSettings.bufferSize()); + + // Resampling quality + myResamplingPopup->setSelected(static_cast(audioSettings.resamplingQuality())); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void VideoAudioDialog::saveConfig() +{ + ///////////////////////////////////////////////////////////////////////////// + // Display tab // Renderer setting instance().settings().setValue("video", myRenderer->getSelectedTag().toString()); @@ -500,10 +593,6 @@ void VideoDialog::saveConfig() // TIA interpolation instance().settings().setValue("tia.inter", myTIAInterpolate->getState()); - - // Note: Palette values are saved directly when changed! - - // Fullscreen instance().settings().setValue("fullscreen", myFullscreen->getState()); // Fullscreen stretch setting @@ -521,26 +610,12 @@ void VideoDialog::saveConfig() instance().settings().setValue("tia.vsizeadjust", newAdjust); - // Speed - const int speedup = mySpeed->getValue(); - instance().settings().setValue("speed", unmapSpeed(speedup)); - if (instance().hasConsole()) - instance().console().initializeAudio(); - // Use sync to vertical blank - instance().settings().setValue("vsync", myUseVSync->getState()); + // Note: Palette values are saved directly when changed! - // Show UI messages - instance().settings().setValue("uimessages", myUIMessages->getState()); - - // Fast loading of Supercharger BIOS - instance().settings().setValue("fastscbios", myFastSCBios->getState()); - - // Multi-threaded rendering - instance().settings().setValue("threads", myUseThreads->getState()); - if (instance().hasConsole()) - instance().frameBuffer().tiaSurface().ntsc().enableThreading(myUseThreads->getState()); + ///////////////////////////////////////////////////////////////////////////// + // TV Effects tab // TV Mode instance().settings().setValue("tv.filter", myTVMode->getSelectedTag().toString()); @@ -579,10 +654,51 @@ void VideoDialog::saveConfig() // ... and apply potential setting changes to the TIA surface instance().frameBuffer().tiaSurface().updateSurfaceSettings(); + + ///////////////////////////////////////////////////////////////////////////// + // Audio tab + AudioSettings& audioSettings = instance().audioSettings(); + + // Enabled + audioSettings.setEnabled(mySoundEnableCheckbox->getState()); + instance().sound().setEnabled(mySoundEnableCheckbox->getState()); + + // Volume + audioSettings.setVolume(myVolumeSlider->getValue()); + instance().sound().setVolume(myVolumeSlider->getValue()); + + // Stereo + audioSettings.setStereo(myStereoSoundCheckbox->getState()); + + // DPC Pitch + audioSettings.setDpcPitch(myDpcPitch->getValue()); + // update if current cart is Pitfall II + if (instance().hasConsole() && instance().console().cartridge().name() == "CartridgeDPC") + { + CartridgeDPC& cart = static_cast(instance().console().cartridge()); + cart.setDpcPitch(myDpcPitch->getValue()); + } + + AudioSettings::Preset preset = static_cast(myModePopup->getSelectedTag().toInt()); + audioSettings.setPreset(preset); + + if (preset == AudioSettings::Preset::custom) { + // Fragsize + audioSettings.setFragmentSize(myFragsizePopup->getSelectedTag().toInt()); + audioSettings.setSampleRate(myFreqPopup->getSelectedTag().toInt()); + audioSettings.setHeadroom(myHeadroomSlider->getValue()); + audioSettings.setBufferSize(myBufferSizeSlider->getValue()); + audioSettings.setResamplingQuality(static_cast(myResamplingPopup->getSelectedTag().toInt())); + } + + // Only force a re-initialization when necessary, since it can + // be a time-consuming operation + if(instance().hasConsole()) + instance().console().initializeAudio(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::setDefaults() +void VideoAudioDialog::setDefaults() { switch(myTab->getActiveTab()) { @@ -597,13 +713,6 @@ void VideoDialog::setDefaults() myTVOverscan->setValue(0); myTIAZoom->setValue(300); myVSizeAdjust->setValue(0); - // speed - mySpeed->setValue(0); - myUseVSync->setState(true); - // misc - myUIMessages->setState(true); - myFastSCBios->setState(true); - myUseThreads->setState(false); handleFullScreenChange(); break; @@ -640,11 +749,29 @@ void VideoDialog::setDefaults() loadTVAdjustables(NTSCFilter::Preset::CUSTOM); break; } + case 3: // Audio + mySoundEnableCheckbox->setState(AudioSettings::DEFAULT_ENABLED); + myVolumeSlider->setValue(AudioSettings::DEFAULT_VOLUME); + myStereoSoundCheckbox->setState(AudioSettings::DEFAULT_STEREO); + myDpcPitch->setValue(AudioSettings::DEFAULT_DPC_PITCH); + myModePopup->setSelected(static_cast(AudioSettings::DEFAULT_PRESET)); + + if (AudioSettings::DEFAULT_PRESET == AudioSettings::Preset::custom) { + myResamplingPopup->setSelected(static_cast(AudioSettings::DEFAULT_RESAMPLING_QUALITY)); + myFragsizePopup->setSelected(AudioSettings::DEFAULT_FRAGMENT_SIZE); + myFreqPopup->setSelected(AudioSettings::DEFAULT_SAMPLE_RATE); + myHeadroomSlider->setValue(AudioSettings::DEFAULT_HEADROOM); + myBufferSizeSlider->setValue(AudioSettings::DEFAULT_BUFFER_SIZE); + } + else updatePreset(); + + updateEnabledState(); + break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::handleTVModeChange(NTSCFilter::Preset preset) +void VideoAudioDialog::handleTVModeChange(NTSCFilter::Preset preset) { bool enable = preset == NTSCFilter::Preset::CUSTOM; @@ -661,7 +788,7 @@ void VideoDialog::handleTVModeChange(NTSCFilter::Preset preset) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::loadTVAdjustables(NTSCFilter::Preset preset) +void VideoAudioDialog::loadTVAdjustables(NTSCFilter::Preset preset) { NTSCFilter::Adjustable adj; instance().frameBuffer().tiaSurface().ntsc().getAdjustables( @@ -674,7 +801,7 @@ void VideoDialog::loadTVAdjustables(NTSCFilter::Preset preset) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::handlePaletteChange() +void VideoAudioDialog::handlePaletteChange() { bool enable = myTIAPalette->getSelectedTag().toString() == "custom"; @@ -683,7 +810,7 @@ void VideoDialog::handlePaletteChange() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::handlePaletteUpdate() +void VideoAudioDialog::handlePaletteUpdate() { // TIA Palette instance().settings().setValue("palette", @@ -704,7 +831,7 @@ void VideoDialog::handlePaletteUpdate() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::handleFullScreenChange() +void VideoAudioDialog::handleFullScreenChange() { bool enable = myFullscreen->getState(); myUseStretch->setEnabled(enable); @@ -712,7 +839,7 @@ void VideoDialog::handleFullScreenChange() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::handleOverscanChange() +void VideoAudioDialog::handleOverscanChange() { if (myTVOverscan->getValue() == 0) { @@ -724,13 +851,13 @@ void VideoDialog::handleOverscanChange() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::handlePhosphorChange() +void VideoAudioDialog::handlePhosphorChange() { myTVPhosLevel->setEnabled(myTVPhosphor->getState()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::handleCommand(CommandSender* sender, int cmd, +void VideoAudioDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch (cmd) @@ -793,11 +920,6 @@ void VideoDialog::handleCommand(CommandSender* sender, int cmd, myVSizeAdjust->setValueUnit("%"); break; } - - case kSpeedupChanged: - mySpeed->setValueLabel(formatSpeed(mySpeed->getValue())); - break; - case kFullScreenChanged: handleFullScreenChange(); break; @@ -845,6 +967,30 @@ void VideoDialog::handleCommand(CommandSender* sender, int cmd, myTVPhosLevel->setValueUnit("%"); break; + case kSoundEnableChanged: + updateEnabledState(); + break; + + case kModeChanged: + updatePreset(); + updateEnabledState(); + break; + + case kHeadroomChanged: + { + std::ostringstream ss; + ss << std::fixed << std::setprecision(1) << (0.5 * myHeadroomSlider->getValue()) << " frames"; + myHeadroomSlider->setValueLabel(ss.str()); + break; + } + case kBufferSizeChanged: + { + std::ostringstream ss; + ss << std::fixed << std::setprecision(1) << (0.5 * myBufferSizeSlider->getValue()) << " frames"; + myBufferSizeSlider->setValueLabel(ss.str()); + break; + } + default: Dialog::handleCommand(sender, cmd, data, 0); break; @@ -852,7 +998,7 @@ void VideoDialog::handleCommand(CommandSender* sender, int cmd, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::addPalette(int x, int y, int w, int h) +void VideoAudioDialog::addPalette(int x, int y, int w, int h) { if(instance().hasConsole()) { @@ -877,7 +1023,7 @@ void VideoDialog::addPalette(int x, int y, int w, int h) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::colorPalette() +void VideoAudioDialog::colorPalette() { if(instance().hasConsole()) { @@ -904,3 +1050,37 @@ void VideoDialog::colorPalette() } } } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void VideoAudioDialog::updateEnabledState() +{ + bool active = mySoundEnableCheckbox->getState(); + AudioSettings::Preset preset = static_cast(myModePopup->getSelectedTag().toInt()); + bool userMode = preset == AudioSettings::Preset::custom; + + myVolumeSlider->setEnabled(active); + myStereoSoundCheckbox->setEnabled(active); + myModePopup->setEnabled(active); + // enable only for Pitfall II cart + myDpcPitch->setEnabled(active && instance().hasConsole() && instance().console().cartridge().name() == "CartridgeDPC"); + + myFragsizePopup->setEnabled(active && userMode); + myFreqPopup->setEnabled(active && userMode); + myResamplingPopup->setEnabled(active && userMode); + myHeadroomSlider->setEnabled(active && userMode); + myBufferSizeSlider->setEnabled(active && userMode); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void VideoAudioDialog::updatePreset() +{ + AudioSettings::Preset preset = static_cast(myModePopup->getSelectedTag().toInt()); + + // Make a copy that does not affect the actual settings... + AudioSettings audioSettings = instance().audioSettings(); + audioSettings.setPersistent(false); + // ... and set the requested preset + audioSettings.setPreset(preset); + + updateSettingsWithPreset(audioSettings); +} diff --git a/src/gui/VideoDialog.hxx b/src/gui/VideoAudioDialog.hxx similarity index 75% rename from src/gui/VideoDialog.hxx rename to src/gui/VideoAudioDialog.hxx index 7d01b6808..6380ae352 100644 --- a/src/gui/VideoDialog.hxx +++ b/src/gui/VideoAudioDialog.hxx @@ -15,8 +15,8 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#ifndef VIDEO_DIALOG_HXX -#define VIDEO_DIALOG_HXX +#ifndef VIDEOAUDIO_DIALOG_HXX +#define VIDEOAUDIO_DIALOG_HXX class CommandSender; class CheckboxWidget; @@ -34,21 +34,22 @@ class OSystem; #include "NTSCFilter.hxx" #include "bspf.hxx" -class VideoDialog : public Dialog +class VideoAudioDialog : public Dialog { public: - VideoDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, + VideoAudioDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, int max_w, int max_h); - virtual ~VideoDialog() = default; + virtual ~VideoAudioDialog() = default; private: void loadConfig() override; void saveConfig() override; void setDefaults() override; - void addGeneralTab(); + void addDisplayTab(); void addPaletteTab(); void addTVEffectsTab(); + void addAudioTab(); void handleTVModeChange(NTSCFilter::Preset); void loadTVAdjustables(NTSCFilter::Preset preset); void handlePaletteChange(); @@ -59,45 +60,30 @@ class VideoDialog : public Dialog void handleCommand(CommandSender* sender, int cmd, int data, int id) override; void addPalette(int x, int y, int h, int w); void colorPalette(); + void updatePreset(); + void updateEnabledState(); + void updateSettingsWithPreset(AudioSettings&); private: TabWidget* myTab; // General options PopUpWidget* myRenderer{nullptr}; - SliderWidget* myTIAZoom{nullptr}; - PopUpWidget* myTIAPalette{nullptr}; - SliderWidget* myPhaseShiftNtsc{nullptr}; - SliderWidget* myPhaseShiftPal{nullptr}; CheckboxWidget* myTIAInterpolate{nullptr}; - SliderWidget* myVSizeAdjust{nullptr}; - SliderWidget* mySpeed{nullptr}; - - RadioButtonGroup* myZoomGroup{nullptr}; CheckboxWidget* myFullscreen{nullptr}; //PopUpWidget* myFullScreenMode; CheckboxWidget* myUseStretch{nullptr}; SliderWidget* myTVOverscan{nullptr}; - CheckboxWidget* myUseVSync{nullptr}; - CheckboxWidget* myUIMessages{nullptr}; - CheckboxWidget* myFastSCBios{nullptr}; - CheckboxWidget* myUseThreads{nullptr}; - std::array myColorLbl{nullptr}; - //std::array myColor{nullptr}; - ColorWidget* myColor[16][8]{nullptr}; + SliderWidget* myTIAZoom{nullptr}; + SliderWidget* myVSizeAdjust{nullptr}; // TV effects adjustables (custom mode) PopUpWidget* myTVMode{nullptr}; SliderWidget* myTVSharp{nullptr}; - SliderWidget* myTVHue{nullptr}; SliderWidget* myTVRes{nullptr}; SliderWidget* myTVArtifacts{nullptr}; SliderWidget* myTVFringe{nullptr}; SliderWidget* myTVBleed{nullptr}; - SliderWidget* myTVBright{nullptr}; - SliderWidget* myTVContrast{nullptr}; - SliderWidget* myTVSatur{nullptr}; - SliderWidget* myTVGamma{nullptr}; // TV phosphor effect CheckboxWidget* myTVPhosphor{nullptr}; @@ -114,19 +100,43 @@ class VideoDialog : public Dialog ButtonWidget* myCloneBad{nullptr}; ButtonWidget* myCloneCustom{nullptr}; + // Palettes + PopUpWidget* myTIAPalette{nullptr}; + SliderWidget* myPhaseShiftNtsc{nullptr}; + SliderWidget* myPhaseShiftPal{nullptr}; + SliderWidget* myTVHue{nullptr}; + SliderWidget* myTVSatur{nullptr}; + SliderWidget* myTVBright{nullptr}; + SliderWidget* myTVContrast{nullptr}; + SliderWidget* myTVGamma{nullptr}; + std::array myColorLbl{nullptr}; + ColorWidget* myColor[16][8]{nullptr}; + + // Audio + CheckboxWidget* mySoundEnableCheckbox{nullptr}; + SliderWidget* myVolumeSlider{nullptr}; + CheckboxWidget* myStereoSoundCheckbox{nullptr}; + PopUpWidget* myModePopup{nullptr}; + PopUpWidget* myFragsizePopup{nullptr}; + PopUpWidget* myFreqPopup{nullptr}; + PopUpWidget* myResamplingPopup{nullptr}; + SliderWidget* myHeadroomSlider{nullptr}; + SliderWidget* myBufferSizeSlider{nullptr}; + SliderWidget* myDpcPitch{nullptr}; + string myPalette; PaletteHandler::Adjustable myPaletteAdj{0.0F}; enum { + kZoomChanged = 'VDZo', + kVSizeChanged = 'VDVs', + kFullScreenChanged = 'VDFs', + kOverscanChanged = 'VDOv', + kPaletteChanged = 'VDpl', kNtscShiftChanged = 'VDns', kPalShiftChanged = 'VDps', kPaletteUpdated = 'VDpu', - kSpeedupChanged = 'VDSp', - kVSizeChanged = 'VDVs', - kFullScreenChanged = 'VDFs', - kZoomChanged = 'VDZo', - kOverscanChanged = 'VDOv', kTVModeChanged = 'VDtv', kCloneCompositeCmd = 'CLcp', @@ -136,16 +146,21 @@ class VideoDialog : public Dialog kCloneCustomCmd = 'CLcu', kPhosphorChanged = 'VDph', kPhosBlendChanged = 'VDbl', - kScanlinesChanged = 'VDsc' + kScanlinesChanged = 'VDsc', + + kSoundEnableChanged = 'ADse', + kModeChanged = 'ADmc', + kHeadroomChanged = 'ADhc', + kBufferSizeChanged = 'ADbc' }; private: // Following constructors and assignment operators not supported - VideoDialog() = delete; - VideoDialog(const VideoDialog&) = delete; - VideoDialog(VideoDialog&&) = delete; - VideoDialog& operator=(const VideoDialog&) = delete; - VideoDialog& operator=(VideoDialog&&) = delete; + VideoAudioDialog() = delete; + VideoAudioDialog(const VideoAudioDialog&) = delete; + VideoAudioDialog(VideoAudioDialog&&) = delete; + VideoAudioDialog& operator=(const VideoAudioDialog&) = delete; + VideoAudioDialog& operator=(VideoAudioDialog&&) = delete; }; #endif diff --git a/src/gui/module.mk b/src/gui/module.mk index f550e167d..1447b8195 100644 --- a/src/gui/module.mk +++ b/src/gui/module.mk @@ -2,7 +2,6 @@ MODULE := src/gui MODULE_OBJS := \ src/gui/AboutDialog.o \ - src/gui/AudioDialog.o \ src/gui/BrowserDialog.o \ src/gui/CheckListWidget.o \ src/gui/ColorWidget.o \ @@ -15,6 +14,7 @@ MODULE_OBJS := \ src/gui/Dialog.o \ src/gui/EditableWidget.o \ src/gui/EditTextWidget.o \ + src/gui/EmulationDialog.o \ src/gui/EventMappingWidget.o \ src/gui/FileListWidget.o \ src/gui/Font.o \ @@ -49,7 +49,7 @@ MODULE_OBJS := \ src/gui/TimeMachineDialog.o \ src/gui/TimeMachine.o \ src/gui/UIDialog.o \ - src/gui/VideoDialog.o \ + src/gui/VideoAudioDialog.o \ src/gui/Widget.o MODULE_DIRS += \ diff --git a/src/libpng/pngconf.h b/src/libpng/pngconf.h index 927a769db..b5f468ae5 100644 --- a/src/libpng/pngconf.h +++ b/src/libpng/pngconf.h @@ -230,7 +230,7 @@ * the type. */ # ifndef PNG_EXPORT_TYPE -# define PNG_EXPORT_TYPE(type) type PNG_IMPEXP +# define PNG_EXPORT_TYPE(name) name PNG_IMPEXP # endif # define PNG_DLL_EXPORT __export # else /* newer compiler */ @@ -450,7 +450,7 @@ # define PNG_FP_EXPORT(ordinal, type, name, args)\ PNG_EXPORT(ordinal, type, name, args); # else /* No floating point APIs */ -# define PNG_FP_EXPORT(ordinal, type, name, args) +# define PNG_FP_EXPORT(ordinal, name, name, args) # endif #endif #ifndef PNG_FIXED_EXPORT /* A fixed point API. */ @@ -458,7 +458,7 @@ # define PNG_FIXED_EXPORT(ordinal, type, name, args)\ PNG_EXPORT(ordinal, type, name, args); # else /* No fixed point APIs */ -# define PNG_FIXED_EXPORT(ordinal, type, name, args) +# define PNG_FIXED_EXPORT(ordinal, name, name, args) # endif #endif diff --git a/src/windows/Stella.vcxproj b/src/windows/Stella.vcxproj index bc0724d09..6fef5d589 100644 --- a/src/windows/Stella.vcxproj +++ b/src/windows/Stella.vcxproj @@ -758,6 +758,7 @@ + @@ -907,7 +908,6 @@ true - @@ -939,7 +939,7 @@ - + CompileAsC @@ -1791,6 +1791,7 @@ + @@ -1967,7 +1968,6 @@ - @@ -2003,7 +2003,7 @@ - + diff --git a/src/windows/Stella.vcxproj.filters b/src/windows/Stella.vcxproj.filters index 62e324fa4..0e4f58929 100644 --- a/src/windows/Stella.vcxproj.filters +++ b/src/windows/Stella.vcxproj.filters @@ -342,9 +342,6 @@ Source Files\gui - - Source Files\gui - Source Files\gui @@ -438,9 +435,6 @@ Source Files\gui - - Source Files\gui - Source Files\gui @@ -1005,6 +999,12 @@ Source Files + + Source Files\gui + + + Source Files\gui + @@ -1316,9 +1316,6 @@ Header Files\gui - - Header Files\gui - Header Files\gui @@ -1424,9 +1421,6 @@ Header Files\gui - - Header Files\gui - Header Files\gui @@ -2063,6 +2057,12 @@ Header Files + + Header Files\gui + + + Header Files\gui + From a867eb6b4f6e0674f8cc505a069a5ac053d568e8 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 11 May 2020 16:18:43 +0200 Subject: [PATCH 198/377] bugfix audio widgets enabling --- src/gui/VideoAudioDialog.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/VideoAudioDialog.cxx b/src/gui/VideoAudioDialog.cxx index dbab74acf..b5f155f40 100644 --- a/src/gui/VideoAudioDialog.cxx +++ b/src/gui/VideoAudioDialog.cxx @@ -537,7 +537,7 @@ void VideoAudioDialog::loadConfig() AudioSettings& audioSettings = instance().audioSettings(); // Enable sound -#ifndef SOUND_SUPPORT +#ifdef SOUND_SUPPORT mySoundEnableCheckbox->setState(audioSettings.enabled()); #else mySoundEnableCheckbox->setState(false); From 5a069cd44bbef2a890dbea77154d5724ecd1006d Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Mon, 11 May 2020 14:57:01 -0230 Subject: [PATCH 199/377] Fixes for warnings in latest g++ and clang, and update libretro port to latest changes. --- src/common/PKeyboardHandler.cxx | 2 ++ src/common/PaletteHandler.cxx | 37 +++++++++++++++-------------- src/common/PaletteHandler.hxx | 26 ++++++++++---------- src/debugger/gui/CartARWidget.cxx | 2 ++ src/debugger/gui/CartE0Widget.cxx | 2 +- src/debugger/gui/DebuggerDialog.hxx | 2 +- src/emucore/PointingDevice.cxx | 2 ++ src/emucore/TIASurface.hxx | 2 +- src/emucore/Thumbulator.cxx | 1 + src/gui/ColorWidget.cxx | 4 ++-- src/gui/DialogContainer.cxx | 1 - src/gui/EmulationDialog.cxx | 2 +- src/gui/VideoAudioDialog.cxx | 6 ++--- src/gui/VideoAudioDialog.hxx | 4 ++-- src/libretro/Makefile.common | 1 + src/libretro/StellaLIBRETRO.cxx | 13 +++------- src/libretro/StellaLIBRETRO.hxx | 2 +- src/libretro/libretro.cxx | 18 ++++++-------- 18 files changed, 61 insertions(+), 66 deletions(-) diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index 3edd7698d..9384d3232 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -15,6 +15,8 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include "OSystem.hxx" +#include "Console.hxx" #include "EventHandler.hxx" #include "PKeyboardHandler.hxx" diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index 3f1066724..2aecc6abf 100644 --- a/src/common/PaletteHandler.cxx +++ b/src/common/PaletteHandler.cxx @@ -15,6 +15,7 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include #include "Console.hxx" #include "FrameBuffer.hxx" @@ -303,7 +304,7 @@ PaletteArray PaletteHandler::adjustedPalette(const PaletteArray& palette) adjust[i] = powf(i * toFloat, gamma) * contrast + brightness; // Transform original palette into destination palette - for(int i = 0; i < destPalette.size(); i += 2) + for(size_t i = 0; i < destPalette.size(); i += 2) { const uInt32 pixel = palette[i]; int r = (pixel >> 16) & 0xff; @@ -396,8 +397,8 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) // color 0 is grayscale for(int chroma = 1; chroma < NUM_CHROMA; chroma++) { - color[chroma][0] = SATURATION * sin(offset + shift * (chroma - 1)); - color[chroma][1] = SATURATION * sin(offset + shift * (chroma - 1 - BSPF::PI_f)); + color[chroma][0] = SATURATION * sinf(offset + shift * (chroma - 1)); + color[chroma][1] = SATURATION * sinf(offset + shift * (chroma - 1 - BSPF::PI_f)); } for(int chroma = 0; chroma < NUM_CHROMA; chroma++) @@ -488,17 +489,17 @@ void PaletteHandler::adjustHueSaturation(int& R, int& G, int& B, float H, float // Adapted from http://beesbuzz.biz/code/16-hsv-color-transforms // (C) J. “Fluffy” Shagam // License: CC BY-SA 4.0 - const float su = S * cos(-H * BSPF::PI_f); - const float sw = S * sin(-H * BSPF::PI_f); - const float r = (.299 + .701 * su + .168 * sw) * R - + (.587 - .587 * su + .330 * sw) * G - + (.114 - .114 * su - .497 * sw) * B; - const float g = (.299 - .299 * su - .328 * sw) * R - + (.587 + .413 * su + .035 * sw) * G - + (.114 - .114 * su + .292 * sw) * B; - const float b = (.299 - .300 * su + 1.25 * sw) * R - + (.587 - .588 * su - 1.05 * sw) * G - + (.114 + .886 * su - .203 * sw) * B; + const float su = S * cosf(-H * BSPF::PI_f); + const float sw = S * sinf(-H * BSPF::PI_f); + const float r = (.299F + .701F * su + .168F * sw) * R + + (.587F - .587F * su + .330F * sw) * G + + (.114F - .114F * su - .497F * sw) * B; + const float g = (.299F - .299F * su - .328F * sw) * R + + (.587F + .413F * su + .035F * sw) * G + + (.114F - .114F * su + .292F * sw) * B; + const float b = (.299F - .300F * su + 1.25F * sw) * R + + (.587F - .588F * su - 1.05F * sw) * G + + (.114F + .886F * su - .203F * sw) * B; R = BSPF::clamp(r, 0.F, 255.F); G = BSPF::clamp(g, 0.F, 255.F); @@ -724,14 +725,14 @@ const PaletteArray PaletteHandler::ourSECAMPaletteZ26 = { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PaletteArray PaletteHandler::ourUserNTSCPalette = { 0 }; // filled from external file - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PaletteArray PaletteHandler::ourUserPALPalette = { 0 }; // filled from external file - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PaletteArray PaletteHandler::ourUserSECAMPalette = { 0 }; // filled from external file - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PaletteArray PaletteHandler::ourCustomNTSCPalette = { 0 }; // filled by function - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PaletteArray PaletteHandler::ourCustomPALPalette = { 0 }; // filled by function diff --git a/src/common/PaletteHandler.hxx b/src/common/PaletteHandler.hxx index 237d9b878..3a8c5c9e3 100644 --- a/src/common/PaletteHandler.hxx +++ b/src/common/PaletteHandler.hxx @@ -38,8 +38,8 @@ class PaletteHandler // Externally used adjustment parameters struct Adjustable { - float phaseNtsc, phasePal; - uInt32 hue, saturation, contrast, brightness, gamma; + float phaseNtsc{0.F}, phasePal{0.F}; + uInt32 hue{0}, saturation{0}, contrast{0}, brightness{0}, gamma{0}; }; public: @@ -54,14 +54,14 @@ class PaletteHandler void cyclePalette(bool next = true); /* - Cycle through each palette adjustable + Cycle through each palette adjustable. @param next Select next adjustable, else previous one */ void cycleAdjustable(bool next = true); /* - Increase or decrease current palette adjustable + Increase or decrease current palette adjustable. @param increase Increase adjustable if true, else decrease */ @@ -82,7 +82,7 @@ class PaletteHandler /** Sets the palette according to the given palette name. - @param palette The palette to switch to. + @param name The palette to switch to */ void setPalette(const string& name); @@ -107,11 +107,11 @@ class PaletteHandler /** Convert adjustables from/to 100% scale */ - float scaleFrom100(float x) const { return (x / 50.F) - 1.F; } - uInt32 scaleTo100(float x) const { return uInt32(50 * (x + 1.F)); } + constexpr float scaleFrom100(float x) const { return (x / 50.F) - 1.F; } + constexpr uInt32 scaleTo100(float x) const { return uInt32(50 * (x + 1.F)); } /** - Convert palette settings name to enumeration + Convert palette settings name to enumeration. @param name The given palette's settings name @@ -120,7 +120,7 @@ class PaletteHandler PaletteType toPaletteType(const string& name) const; /** - Convert enumeration to palette settings name + Convert enumeration to palette settings name. @param type The given palette type @@ -133,7 +133,7 @@ class PaletteHandler Note that there are two of these (NTSC and PAL). The currently active mode will determine which one is used. - @param increase Increase if true, else decrease. + @param increase Increase if true, else decrease */ void changeColorPhaseShift(bool increase = true); @@ -145,16 +145,16 @@ class PaletteHandler void generateCustomPalette(ConsoleTiming timing); /** - Create new palette by applying palette adjustments on given palette + Create new palette by applying palette adjustments on given palette. - @param type The palette which should be adjusted + @param source The palette which should be adjusted @return An adjusted palette */ PaletteArray adjustedPalette(const PaletteArray& source); /** - Adjust hue and saturation for given RGB values + Adjust hue and saturation for given RGB values. @param R The red value to adjust @param G The green value to adjust diff --git a/src/debugger/gui/CartARWidget.cxx b/src/debugger/gui/CartARWidget.cxx index 6037849f6..aa552d78e 100644 --- a/src/debugger/gui/CartARWidget.cxx +++ b/src/debugger/gui/CartARWidget.cxx @@ -16,6 +16,8 @@ //============================================================================ #include "CartAR.hxx" +#include "Debugger.hxx" +#include "CartDebug.hxx" #include "PopUpWidget.hxx" #include "CartARWidget.hxx" diff --git a/src/debugger/gui/CartE0Widget.cxx b/src/debugger/gui/CartE0Widget.cxx index 12205c463..08ccc802a 100644 --- a/src/debugger/gui/CartE0Widget.cxx +++ b/src/debugger/gui/CartE0Widget.cxx @@ -49,7 +49,7 @@ string CartridgeE0Widget::romDescription() info << "Segment #" << seg << " accessible @ $" << Common::Base::HEX4 << (ADDR_BASE | segmentOffset) - << " - $" << (ADDR_BASE | segmentOffset + /*myCart.myBankSize - 1*/ 0x3FF) << ",\n"; + << " - $" << (ADDR_BASE | (segmentOffset + /*myCart.myBankSize - 1*/ 0x3FF)) << ",\n"; if (seg < 3) info << " Hotspots " << hotspotStr(0, seg, true) << " - " << hotspotStr(7, seg, true) << "\n"; else diff --git a/src/debugger/gui/DebuggerDialog.hxx b/src/debugger/gui/DebuggerDialog.hxx index bfd7c332b..b66ae37a6 100644 --- a/src/debugger/gui/DebuggerDialog.hxx +++ b/src/debugger/gui/DebuggerDialog.hxx @@ -33,7 +33,6 @@ class TiaOutputWidget; class TiaZoomWidget; class CartDebugWidget; class CartRamWidget; -class OptionsDialog; namespace Common { struct Rect; @@ -41,6 +40,7 @@ namespace Common { #include "Dialog.hxx" #include "MessageBox.hxx" +#include "OptionsDialog.hxx" class DebuggerDialog : public Dialog { diff --git a/src/emucore/PointingDevice.cxx b/src/emucore/PointingDevice.cxx index 1a2c781b4..4d91d010c 100644 --- a/src/emucore/PointingDevice.cxx +++ b/src/emucore/PointingDevice.cxx @@ -15,6 +15,8 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include + #include "Control.hxx" #include "Event.hxx" #include "System.hxx" diff --git a/src/emucore/TIASurface.hxx b/src/emucore/TIASurface.hxx index 9dbda5b14..6552c26ca 100644 --- a/src/emucore/TIASurface.hxx +++ b/src/emucore/TIASurface.hxx @@ -22,13 +22,13 @@ class TIA; class Console; class OSystem; class FBSurface; -class PaletteHandler; #include #include "Rect.hxx" #include "FrameBuffer.hxx" #include "NTSCFilter.hxx" +#include "PaletteHandler.hxx" #include "PhosphorHandler.hxx" #include "bspf.hxx" #include "TIAConstants.hxx" diff --git a/src/emucore/Thumbulator.cxx b/src/emucore/Thumbulator.cxx index c5bd3e637..2984159cd 100644 --- a/src/emucore/Thumbulator.cxx +++ b/src/emucore/Thumbulator.cxx @@ -108,6 +108,7 @@ void Thumbulator::setConsoleTiming(ConsoleTiming timing) case ConsoleTiming::ntsc: timing_factor = NTSC; break; case ConsoleTiming::secam: timing_factor = SECAM; break; case ConsoleTiming::pal: timing_factor = PAL; break; + default: break; // satisfy compiler } } diff --git a/src/gui/ColorWidget.cxx b/src/gui/ColorWidget.cxx index 8052bf029..27f4bc3cf 100644 --- a/src/gui/ColorWidget.cxx +++ b/src/gui/ColorWidget.cxx @@ -28,8 +28,8 @@ ColorWidget::ColorWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h, int cmd, bool framed) : Widget(boss, font, x, y, w, h), CommandSender(boss), - _cmd(cmd), - _framed(framed) + _framed(framed), + _cmd(cmd) { _flags = Widget::FLAG_ENABLED | Widget::FLAG_CLEARBG | Widget::FLAG_RETAIN_FOCUS; } diff --git a/src/gui/DialogContainer.cxx b/src/gui/DialogContainer.cxx index b60faf6d4..950d71c06 100644 --- a/src/gui/DialogContainer.cxx +++ b/src/gui/DialogContainer.cxx @@ -384,4 +384,3 @@ void DialogContainer::reset() uInt64 DialogContainer::_DOUBLE_CLICK_DELAY = 500; uInt64 DialogContainer::_REPEAT_INITIAL_DELAY = 400; uInt64 DialogContainer::_REPEAT_SUSTAIN_DELAY = 50; - diff --git a/src/gui/EmulationDialog.cxx b/src/gui/EmulationDialog.cxx index 111fa12f9..ad86e2e60 100644 --- a/src/gui/EmulationDialog.cxx +++ b/src/gui/EmulationDialog.cxx @@ -280,4 +280,4 @@ void EmulationDialog::handleCommand(CommandSender* sender, int cmd, Dialog::handleCommand(sender, cmd, data, 0); break; } -} \ No newline at end of file +} diff --git a/src/gui/VideoAudioDialog.cxx b/src/gui/VideoAudioDialog.cxx index b5f155f40..5d569014a 100644 --- a/src/gui/VideoAudioDialog.cxx +++ b/src/gui/VideoAudioDialog.cxx @@ -112,8 +112,7 @@ void VideoAudioDialog::addDisplayTab() { const int lineHeight = _font.getLineHeight(), fontHeight = _font.getFontHeight(), - fontWidth = _font.getMaxCharWidth(), - buttonHeight = _font.getLineHeight() * 1.25; + fontWidth = _font.getMaxCharWidth(); const int VGAP = fontHeight / 4; const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; @@ -186,8 +185,7 @@ void VideoAudioDialog::addPaletteTab() { const int lineHeight = _font.getLineHeight(), fontHeight = _font.getFontHeight(), - fontWidth = _font.getMaxCharWidth(), - buttonHeight = _font.getLineHeight() * 1.25; + fontWidth = _font.getMaxCharWidth(); const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; const int INDENT = fontWidth * 2; diff --git a/src/gui/VideoAudioDialog.hxx b/src/gui/VideoAudioDialog.hxx index 6380ae352..f46740ae6 100644 --- a/src/gui/VideoAudioDialog.hxx +++ b/src/gui/VideoAudioDialog.hxx @@ -110,7 +110,7 @@ class VideoAudioDialog : public Dialog SliderWidget* myTVContrast{nullptr}; SliderWidget* myTVGamma{nullptr}; std::array myColorLbl{nullptr}; - ColorWidget* myColor[16][8]{nullptr}; + ColorWidget* myColor[16][8]{{nullptr}}; // Audio CheckboxWidget* mySoundEnableCheckbox{nullptr}; @@ -125,7 +125,7 @@ class VideoAudioDialog : public Dialog SliderWidget* myDpcPitch{nullptr}; string myPalette; - PaletteHandler::Adjustable myPaletteAdj{0.0F}; + PaletteHandler::Adjustable myPaletteAdj; enum { kZoomChanged = 'VDZo', diff --git a/src/libretro/Makefile.common b/src/libretro/Makefile.common index 1893fa57b..5fafdd855 100644 --- a/src/libretro/Makefile.common +++ b/src/libretro/Makefile.common @@ -23,6 +23,7 @@ SOURCES_CXX := \ $(CORE_DIR)/common/KeyMap.cxx \ $(CORE_DIR)/common/Logger.cxx \ $(CORE_DIR)/common/MouseControl.cxx \ + $(CORE_DIR)/common/PaletteHandler.cxx \ $(CORE_DIR)/common/PhosphorHandler.cxx \ $(CORE_DIR)/common/PhysicalJoystick.cxx \ $(CORE_DIR)/common/PJoystickHandler.cxx \ diff --git a/src/libretro/StellaLIBRETRO.cxx b/src/libretro/StellaLIBRETRO.cxx index e3cb5073a..065917c15 100644 --- a/src/libretro/StellaLIBRETRO.cxx +++ b/src/libretro/StellaLIBRETRO.cxx @@ -40,7 +40,7 @@ StellaLIBRETRO::StellaLIBRETRO() video_aspect_ntsc = 0; video_aspect_pal = 0; - video_palette = "standard"; + video_palette = PaletteHandler::SETTING_STANDARD; video_filter = NTSCFilter::Preset::OFF; video_ready = false; @@ -374,19 +374,12 @@ void StellaLIBRETRO::setVideoFilter(NTSCFilter::Preset mode) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void StellaLIBRETRO::setVideoPalette(uInt32 mode) +void StellaLIBRETRO::setVideoPalette(const string& mode) { - switch (mode) - { - case 0: video_palette = "standard"; break; - case 1: video_palette = "z26"; break; - case 2: video_palette = "user"; break; - } - if (system_ready) { myOSystem->settings().setValue("palette", video_palette); - myOSystem->console().setPalette(video_palette); + myOSystem->frameBuffer().tiaSurface().paletteHandler().setPalette(video_palette); } } diff --git a/src/libretro/StellaLIBRETRO.hxx b/src/libretro/StellaLIBRETRO.hxx index f48a13708..3078e8eb1 100644 --- a/src/libretro/StellaLIBRETRO.hxx +++ b/src/libretro/StellaLIBRETRO.hxx @@ -104,7 +104,7 @@ class StellaLIBRETRO void setVideoAspectPAL(uInt32 value) { video_aspect_pal = value; }; void setVideoFilter(NTSCFilter::Preset mode); - void setVideoPalette(uInt32 mode); + void setVideoPalette(const string& mode); void setVideoPhosphor(uInt32 mode, uInt32 blend); void setAudioStereo(int mode); diff --git a/src/libretro/libretro.cxx b/src/libretro/libretro.cxx index 6babbf07f..8caae3765 100644 --- a/src/libretro/libretro.cxx +++ b/src/libretro/libretro.cxx @@ -15,6 +15,7 @@ #include "StellaLIBRETRO.hxx" #include "Event.hxx" #include "NTSCFilter.hxx" +#include "PaletteHandler.hxx" #include "Version.hxx" @@ -30,11 +31,12 @@ static retro_audio_sample_batch_t audio_batch_cb; // libretro UI settings static int setting_ntsc, setting_pal; -static int setting_stereo, setting_palette; +static int setting_stereo; static int setting_phosphor, setting_console, setting_phosphor_blend; static int stella_paddle_joypad_sensitivity; static int setting_crop_hoverscan, crop_left; static NTSCFilter::Preset setting_filter; +static const char* setting_palette; static bool system_reset; @@ -275,17 +277,11 @@ static void update_variables(bool init = false) RETRO_GET("stella_palette") { - int value = 0; - - if(!strcmp(var.value, "standard")) value = 0; - else if(!strcmp(var.value, "z26")) value = 1; - else if(!strcmp(var.value, "user")) value = 2; - - if(setting_palette != value) + if(setting_palette != var.value) { - stella.setVideoPalette(value); + stella.setVideoPalette(var.value); - setting_palette = value; + setting_palette = var.value; } } @@ -494,7 +490,7 @@ void retro_set_environment(retro_environment_t cb) static struct retro_variable variables[] = { // Adding more variables and rearranging them is safe. { "stella_console", "Console display; auto|ntsc|pal|secam|ntsc50|pal60|secam60" }, - { "stella_palette", "Palette colors; standard|z26|user" }, + { "stella_palette", "Palette colors; standard|z26|user|custom" }, { "stella_filter", "TV effects; disabled|composite|s-video|rgb|badly adjusted" }, { "stella_ntsc_aspect", "NTSC aspect %; par|100|101|102|103|104|105|106|107|108|109|110|111|112|113|114|115|116|117|118|119|120|121|122|123|124|125|50|75|76|77|78|79|80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95|96|97|98|99" }, { "stella_pal_aspect", "PAL aspect %; par|100|101|102|103|104|105|106|107|108|109|110|111|112|113|114|115|116|117|118|119|120|121|122|123|124|125|50|75|76|77|78|79|80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95|96|97|98|99" }, From 1e0c6c382c13b113f6bc8855feee2e2ed83eb0de Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Mon, 11 May 2020 15:33:42 -0230 Subject: [PATCH 200/377] Update Xcode project for class changes. --- src/debugger/DiStella.cxx | 2 +- src/macos/stella.xcodeproj/project.pbxproj | 96 +++++++++++----------- 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/debugger/DiStella.cxx b/src/debugger/DiStella.cxx index 8aff0b568..c77d1eabf 100644 --- a/src/debugger/DiStella.cxx +++ b/src/debugger/DiStella.cxx @@ -1179,7 +1179,7 @@ void DiStella::outputColors() color = SECAM_COLOR[(byte >> 1) & 0x7]; myDisasmBuf << "$" << Base::HEX1 << (byte >> 4) << "|" << color; } - myDisasmBuf << std::setw(16 - color.length()) << std::setfill(' '); + myDisasmBuf << std::setw(int(16 - color.length())) << std::setfill(' '); // output address myDisasmBuf << "; $" << Base::HEX4 << myPC + myOffset << " " diff --git a/src/macos/stella.xcodeproj/project.pbxproj b/src/macos/stella.xcodeproj/project.pbxproj index 33eccde69..d59aac510 100644 --- a/src/macos/stella.xcodeproj/project.pbxproj +++ b/src/macos/stella.xcodeproj/project.pbxproj @@ -44,7 +44,6 @@ 2D9173FA09BA90380026E9FF /* FrameBuffer.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D733D71062895B2006265D9 /* FrameBuffer.hxx */; }; 2D9173FB09BA90380026E9FF /* Settings.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D733D77062895F1006265D9 /* Settings.hxx */; }; 2D91740009BA90380026E9FF /* AboutDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAA4084578BF00812C11 /* AboutDialog.hxx */; }; - 2D91740109BA90380026E9FF /* AudioDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAA7084578BF00812C11 /* AudioDialog.hxx */; }; 2D91740209BA90380026E9FF /* BrowserDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAA9084578BF00812C11 /* BrowserDialog.hxx */; }; 2D91740309BA90380026E9FF /* Command.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAAA084578BF00812C11 /* Command.hxx */; }; 2D91740409BA90380026E9FF /* Dialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAAC084578BF00812C11 /* Dialog.hxx */; }; @@ -61,7 +60,6 @@ 2D91741209BA90380026E9FF /* ProgressDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAC9084578BF00812C11 /* ProgressDialog.hxx */; }; 2D91741309BA90380026E9FF /* ScrollBarWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEACB084578BF00812C11 /* ScrollBarWidget.hxx */; }; 2D91741609BA90380026E9FF /* TabWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAD1084578BF00812C11 /* TabWidget.hxx */; }; - 2D91741709BA90380026E9FF /* VideoDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAD3084578BF00812C11 /* VideoDialog.hxx */; }; 2D91741809BA90380026E9FF /* Widget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAD5084578BF00812C11 /* Widget.hxx */; }; 2D91741909BA90380026E9FF /* CartUA.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEB7108457B7D00812C11 /* CartUA.hxx */; }; 2D91741A09BA90380026E9FF /* FSNode.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEB7308457B7D00812C11 /* FSNode.hxx */; }; @@ -142,7 +140,6 @@ 2D9174A309BA90380026E9FF /* Settings.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D944848062904E800DD9879 /* Settings.cxx */; }; 2D9174A809BA90380026E9FF /* FSNodePOSIX.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEA0C0845708800812C11 /* FSNodePOSIX.cxx */; }; 2D9174AA09BA90380026E9FF /* AboutDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAA3084578BF00812C11 /* AboutDialog.cxx */; }; - 2D9174AB09BA90380026E9FF /* AudioDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAA6084578BF00812C11 /* AudioDialog.cxx */; }; 2D9174AC09BA90380026E9FF /* BrowserDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAA8084578BF00812C11 /* BrowserDialog.cxx */; }; 2D9174AD09BA90380026E9FF /* Dialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAAB084578BF00812C11 /* Dialog.cxx */; }; 2D9174AE09BA90380026E9FF /* DialogContainer.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAAD084578BF00812C11 /* DialogContainer.cxx */; }; @@ -157,7 +154,6 @@ 2D9174B909BA90380026E9FF /* ProgressDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAC8084578BF00812C11 /* ProgressDialog.cxx */; }; 2D9174BA09BA90380026E9FF /* ScrollBarWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEACA084578BF00812C11 /* ScrollBarWidget.cxx */; }; 2D9174BB09BA90380026E9FF /* TabWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAD0084578BF00812C11 /* TabWidget.cxx */; }; - 2D9174BC09BA90380026E9FF /* VideoDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAD2084578BF00812C11 /* VideoDialog.cxx */; }; 2D9174BD09BA90380026E9FF /* Widget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAD4084578BF00812C11 /* Widget.cxx */; }; 2D9174BE09BA90380026E9FF /* CartUA.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEB7008457B7D00812C11 /* CartUA.cxx */; }; 2D9174BF09BA90380026E9FF /* FSNode.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEB7208457B7D00812C11 /* FSNode.cxx */; }; @@ -233,8 +229,6 @@ DC2410E32274BDA8007A4CBF /* MinUICommandDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC2410E12274BDA7007A4CBF /* MinUICommandDialog.hxx */; }; DC2410E42274BDA8007A4CBF /* MinUICommandDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC2410E22274BDA8007A4CBF /* MinUICommandDialog.cxx */; }; DC2874071F8F2278004BF21A /* TrapArray.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC2874061F8F2278004BF21A /* TrapArray.hxx */; }; - DC2AADAE194F389C0026C7A4 /* CartDASH.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC2AADAA194F389C0026C7A4 /* CartDASH.cxx */; }; - DC2AADAF194F389C0026C7A4 /* CartDASH.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC2AADAB194F389C0026C7A4 /* CartDASH.hxx */; }; DC2AADB0194F389C0026C7A4 /* TIASurface.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC2AADAC194F389C0026C7A4 /* TIASurface.cxx */; }; DC2AADB1194F389C0026C7A4 /* TIASurface.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC2AADAD194F389C0026C7A4 /* TIASurface.hxx */; }; DC2AADB4194F390F0026C7A4 /* CartRamWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC2AADB2194F390F0026C7A4 /* CartRamWidget.cxx */; }; @@ -250,6 +244,18 @@ DC368F5918A2FB710084199C /* SoundSDL2.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC368F5318A2FB710084199C /* SoundSDL2.hxx */; }; DC36D2C814CAFAB0007DC821 /* CartFA2.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC36D2C614CAFAB0007DC821 /* CartFA2.cxx */; }; DC36D2C914CAFAB0007DC821 /* CartFA2.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC36D2C714CAFAB0007DC821 /* CartFA2.hxx */; }; + DC3C9BC52469C8F700CF2D47 /* PaletteHandler.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC3C9BC32469C8F700CF2D47 /* PaletteHandler.cxx */; }; + DC3C9BC62469C8F700CF2D47 /* PaletteHandler.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC3C9BC42469C8F700CF2D47 /* PaletteHandler.hxx */; }; + DC3C9BCB2469C93D00CF2D47 /* VideoAudioDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC3C9BC72469C93D00CF2D47 /* VideoAudioDialog.cxx */; }; + DC3C9BCC2469C93D00CF2D47 /* EmulationDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC3C9BC82469C93D00CF2D47 /* EmulationDialog.cxx */; }; + DC3C9BCD2469C93D00CF2D47 /* VideoAudioDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC3C9BC92469C93D00CF2D47 /* VideoAudioDialog.hxx */; }; + DC3C9BCE2469C93D00CF2D47 /* EmulationDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC3C9BCA2469C93D00CF2D47 /* EmulationDialog.hxx */; }; + DC3C9BD32469C9A200CF2D47 /* CartEnhanced.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC3C9BCF2469C9A200CF2D47 /* CartEnhanced.cxx */; }; + DC3C9BD42469C9A200CF2D47 /* Cart3EX.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC3C9BD02469C9A200CF2D47 /* Cart3EX.hxx */; }; + DC3C9BD52469C9A200CF2D47 /* CartEnhanced.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC3C9BD12469C9A200CF2D47 /* CartEnhanced.hxx */; }; + DC3C9BD62469C9A200CF2D47 /* Cart3EX.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC3C9BD22469C9A200CF2D47 /* Cart3EX.cxx */; }; + DC3C9BD92469C9C700CF2D47 /* CartEnhancedWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC3C9BD72469C9C700CF2D47 /* CartEnhancedWidget.cxx */; }; + DC3C9BDA2469C9C700CF2D47 /* CartEnhancedWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC3C9BD82469C9C700CF2D47 /* CartEnhancedWidget.hxx */; }; DC3DAFAC1F2E233B00A64410 /* PointingDevice.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC3DAFAB1F2E233B00A64410 /* PointingDevice.hxx */; }; DC3EE8561E2C0E6D00905161 /* adler32.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3EE83C1E2C0E6D00905161 /* adler32.c */; settings = {COMPILER_FLAGS = "-w"; }; }; DC3EE8571E2C0E6D00905161 /* compress.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3EE83D1E2C0E6D00905161 /* compress.c */; settings = {COMPILER_FLAGS = "-w"; }; }; @@ -393,8 +399,6 @@ DC73BD891915E5E3003FAFAD /* FBSurface.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC73BD871915E5E3003FAFAD /* FBSurface.cxx */; }; DC73BD8A1915E5E3003FAFAD /* FBSurface.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC73BD881915E5E3003FAFAD /* FBSurface.hxx */; }; DC74D6A2138D4D7E00F05C5C /* StringParser.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC74D6A0138D4D7E00F05C5C /* StringParser.hxx */; }; - DC74E5C6198AF12700F37E36 /* CartDASHWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC74E5C4198AF12700F37E36 /* CartDASHWidget.cxx */; }; - DC74E5C7198AF12700F37E36 /* CartDASHWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC74E5C5198AF12700F37E36 /* CartDASHWidget.hxx */; }; DC79F81217A88D9E00288B91 /* Base.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC79F81017A88D9E00288B91 /* Base.cxx */; }; DC79F81317A88D9E00288B91 /* Base.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC79F81117A88D9E00288B91 /* Base.hxx */; }; DC7A24D5173B1CF600B20FE9 /* Variant.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC7A24D4173B1CF600B20FE9 /* Variant.hxx */; }; @@ -494,10 +498,6 @@ DCAAE5F11715887B0080BB82 /* CartFAWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAAE5D01715887B0080BB82 /* CartFAWidget.hxx */; }; DCAAE5F21715887B0080BB82 /* CartUAWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAAE5D11715887B0080BB82 /* CartUAWidget.cxx */; }; DCAAE5F31715887B0080BB82 /* CartUAWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAAE5D21715887B0080BB82 /* CartUAWidget.hxx */; }; - DCACBAD01C54296300703A9B /* CartCVPlusWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCACBACE1C54296300703A9B /* CartCVPlusWidget.cxx */; }; - DCACBAD11C54296300703A9B /* CartCVPlusWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCACBACF1C54296300703A9B /* CartCVPlusWidget.hxx */; }; - DCACBAD41C54298300703A9B /* CartCVPlus.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCACBAD21C54298300703A9B /* CartCVPlus.cxx */; }; - DCACBAD51C54298300703A9B /* CartCVPlus.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCACBAD31C54298300703A9B /* CartCVPlus.hxx */; }; DCAD60A81152F8BD00BC4184 /* CartDPCPlus.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAD60A61152F8BD00BC4184 /* CartDPCPlus.cxx */; }; DCAD60A91152F8BD00BC4184 /* CartDPCPlus.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAD60A71152F8BD00BC4184 /* CartDPCPlus.hxx */; }; DCB20EC71A0C506C0048F595 /* main.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCB20EC61A0C506C0048F595 /* main.cxx */; }; @@ -828,8 +828,6 @@ 2DDBEA0C0845708800812C11 /* FSNodePOSIX.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = FSNodePOSIX.cxx; sourceTree = ""; }; 2DDBEAA3084578BF00812C11 /* AboutDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = AboutDialog.cxx; sourceTree = ""; }; 2DDBEAA4084578BF00812C11 /* AboutDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = AboutDialog.hxx; sourceTree = ""; }; - 2DDBEAA6084578BF00812C11 /* AudioDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = AudioDialog.cxx; sourceTree = ""; }; - 2DDBEAA7084578BF00812C11 /* AudioDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = AudioDialog.hxx; sourceTree = ""; }; 2DDBEAA8084578BF00812C11 /* BrowserDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = BrowserDialog.cxx; sourceTree = ""; }; 2DDBEAA9084578BF00812C11 /* BrowserDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = BrowserDialog.hxx; sourceTree = ""; }; 2DDBEAAA084578BF00812C11 /* Command.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Command.hxx; sourceTree = ""; }; @@ -860,8 +858,6 @@ 2DDBEACB084578BF00812C11 /* ScrollBarWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = ScrollBarWidget.hxx; sourceTree = ""; }; 2DDBEAD0084578BF00812C11 /* TabWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = TabWidget.cxx; sourceTree = ""; }; 2DDBEAD1084578BF00812C11 /* TabWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = TabWidget.hxx; sourceTree = ""; }; - 2DDBEAD2084578BF00812C11 /* VideoDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = VideoDialog.cxx; sourceTree = ""; }; - 2DDBEAD3084578BF00812C11 /* VideoDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = VideoDialog.hxx; sourceTree = ""; }; 2DDBEAD4084578BF00812C11 /* Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Widget.cxx; sourceTree = ""; }; 2DDBEAD5084578BF00812C11 /* Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Widget.hxx; sourceTree = ""; }; 2DDBEB7008457B7D00812C11 /* CartUA.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CartUA.cxx; sourceTree = ""; }; @@ -972,8 +968,6 @@ DC2410E12274BDA7007A4CBF /* MinUICommandDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MinUICommandDialog.hxx; sourceTree = ""; }; DC2410E22274BDA8007A4CBF /* MinUICommandDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MinUICommandDialog.cxx; sourceTree = ""; }; DC2874061F8F2278004BF21A /* TrapArray.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TrapArray.hxx; sourceTree = ""; }; - DC2AADAA194F389C0026C7A4 /* CartDASH.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartDASH.cxx; sourceTree = ""; }; - DC2AADAB194F389C0026C7A4 /* CartDASH.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartDASH.hxx; sourceTree = ""; }; DC2AADAC194F389C0026C7A4 /* TIASurface.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TIASurface.cxx; sourceTree = ""; }; DC2AADAD194F389C0026C7A4 /* TIASurface.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TIASurface.hxx; sourceTree = ""; }; DC2AADB2194F390F0026C7A4 /* CartRamWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartRamWidget.cxx; sourceTree = ""; }; @@ -989,6 +983,18 @@ DC368F5318A2FB710084199C /* SoundSDL2.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SoundSDL2.hxx; sourceTree = ""; }; DC36D2C614CAFAB0007DC821 /* CartFA2.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartFA2.cxx; sourceTree = ""; }; DC36D2C714CAFAB0007DC821 /* CartFA2.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartFA2.hxx; sourceTree = ""; }; + DC3C9BC32469C8F700CF2D47 /* PaletteHandler.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PaletteHandler.cxx; sourceTree = ""; }; + DC3C9BC42469C8F700CF2D47 /* PaletteHandler.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PaletteHandler.hxx; sourceTree = ""; }; + DC3C9BC72469C93D00CF2D47 /* VideoAudioDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VideoAudioDialog.cxx; sourceTree = ""; }; + DC3C9BC82469C93D00CF2D47 /* EmulationDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EmulationDialog.cxx; sourceTree = ""; }; + DC3C9BC92469C93D00CF2D47 /* VideoAudioDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = VideoAudioDialog.hxx; sourceTree = ""; }; + DC3C9BCA2469C93D00CF2D47 /* EmulationDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = EmulationDialog.hxx; sourceTree = ""; }; + DC3C9BCF2469C9A200CF2D47 /* CartEnhanced.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartEnhanced.cxx; sourceTree = ""; }; + DC3C9BD02469C9A200CF2D47 /* Cart3EX.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Cart3EX.hxx; sourceTree = ""; }; + DC3C9BD12469C9A200CF2D47 /* CartEnhanced.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartEnhanced.hxx; sourceTree = ""; }; + DC3C9BD22469C9A200CF2D47 /* Cart3EX.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Cart3EX.cxx; sourceTree = ""; }; + DC3C9BD72469C9C700CF2D47 /* CartEnhancedWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartEnhancedWidget.cxx; sourceTree = ""; }; + DC3C9BD82469C9C700CF2D47 /* CartEnhancedWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartEnhancedWidget.hxx; sourceTree = ""; }; DC3DAFAB1F2E233B00A64410 /* PointingDevice.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PointingDevice.hxx; sourceTree = ""; }; DC3EE83C1E2C0E6D00905161 /* adler32.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = adler32.c; sourceTree = ""; }; DC3EE83D1E2C0E6D00905161 /* compress.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = compress.c; sourceTree = ""; }; @@ -1132,8 +1138,6 @@ DC73BD871915E5E3003FAFAD /* FBSurface.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FBSurface.cxx; sourceTree = ""; }; DC73BD881915E5E3003FAFAD /* FBSurface.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FBSurface.hxx; sourceTree = ""; }; DC74D6A0138D4D7E00F05C5C /* StringParser.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StringParser.hxx; sourceTree = ""; }; - DC74E5C4198AF12700F37E36 /* CartDASHWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartDASHWidget.cxx; sourceTree = ""; }; - DC74E5C5198AF12700F37E36 /* CartDASHWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartDASHWidget.hxx; sourceTree = ""; }; DC79F81017A88D9E00288B91 /* Base.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Base.cxx; sourceTree = ""; }; DC79F81117A88D9E00288B91 /* Base.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Base.hxx; sourceTree = ""; }; DC7A24D4173B1CF600B20FE9 /* Variant.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Variant.hxx; sourceTree = ""; }; @@ -1234,10 +1238,6 @@ DCAAE5D01715887B0080BB82 /* CartFAWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartFAWidget.hxx; sourceTree = ""; }; DCAAE5D11715887B0080BB82 /* CartUAWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartUAWidget.cxx; sourceTree = ""; }; DCAAE5D21715887B0080BB82 /* CartUAWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartUAWidget.hxx; sourceTree = ""; }; - DCACBACE1C54296300703A9B /* CartCVPlusWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartCVPlusWidget.cxx; sourceTree = ""; }; - DCACBACF1C54296300703A9B /* CartCVPlusWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartCVPlusWidget.hxx; sourceTree = ""; }; - DCACBAD21C54298300703A9B /* CartCVPlus.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartCVPlus.cxx; sourceTree = ""; }; - DCACBAD31C54298300703A9B /* CartCVPlus.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartCVPlus.hxx; sourceTree = ""; }; DCAD60A61152F8BD00BC4184 /* CartDPCPlus.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartDPCPlus.cxx; sourceTree = ""; }; DCAD60A71152F8BD00BC4184 /* CartDPCPlus.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartDPCPlus.hxx; sourceTree = ""; }; DCB20EC61A0C506C0048F595 /* main.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cxx; sourceTree = ""; }; @@ -1589,12 +1589,8 @@ DC676A2C1729A0B000E4E73D /* CartCMWidget.hxx */, DC676A2D1729A0B000E4E73D /* CartCTYWidget.cxx */, DC676A2E1729A0B000E4E73D /* CartCTYWidget.hxx */, - DCACBACE1C54296300703A9B /* CartCVPlusWidget.cxx */, - DCACBACF1C54296300703A9B /* CartCVPlusWidget.hxx */, DCAAE5BA1715887B0080BB82 /* CartCVWidget.cxx */, DCAAE5BB1715887B0080BB82 /* CartCVWidget.hxx */, - DC74E5C4198AF12700F37E36 /* CartDASHWidget.cxx */, - DC74E5C5198AF12700F37E36 /* CartDASHWidget.hxx */, DC5ACB5D1FBFCEB800A213FD /* CartDebugWidget.cxx */, DCAAE5BC1715887B0080BB82 /* CartDebugWidget.hxx */, DCAACB0A188D636F00A4D282 /* CartDFSCWidget.cxx */, @@ -1615,6 +1611,8 @@ DCAAE5BE1715887B0080BB82 /* CartEFSCWidget.hxx */, DCAAE5BF1715887B0080BB82 /* CartEFWidget.cxx */, DCAAE5C01715887B0080BB82 /* CartEFWidget.hxx */, + DC3C9BD72469C9C700CF2D47 /* CartEnhancedWidget.cxx */, + DC3C9BD82469C9C700CF2D47 /* CartEnhancedWidget.hxx */, DCAAE5C11715887B0080BB82 /* CartF0Widget.cxx */, DCAAE5C21715887B0080BB82 /* CartF0Widget.hxx */, DCAAE5C31715887B0080BB82 /* CartF4SCWidget.cxx */, @@ -1744,6 +1742,8 @@ DCB87E571A104C1E00BF2A3B /* MediaFactory.hxx */, DC56FCDC14CCCC4900A31CC3 /* MouseControl.cxx */, DC56FCDD14CCCC4900A31CC3 /* MouseControl.hxx */, + DC3C9BC32469C8F700CF2D47 /* PaletteHandler.cxx */, + DC3C9BC42469C8F700CF2D47 /* PaletteHandler.hxx */, DCA233AE23B583FE0032ABF3 /* PhosphorHandler.cxx */, DCA233AF23B583FE0032ABF3 /* PhosphorHandler.hxx */, DC6DC91A205DB879004A5FC3 /* PhysicalJoystick.cxx */, @@ -1824,6 +1824,8 @@ 2D9555DA0880E78000466554 /* Cart3E.hxx */, DCBDDE9C1D6A5F2F009DF1E9 /* Cart3EPlus.cxx */, DCBDDE9D1D6A5F2F009DF1E9 /* Cart3EPlus.hxx */, + DC3C9BD22469C9A200CF2D47 /* Cart3EX.cxx */, + DC3C9BD02469C9A200CF2D47 /* Cart3EX.hxx */, 2DE2DF160627AE07006BEC99 /* Cart3F.cxx */, 2DE2DF170627AE07006BEC99 /* Cart3F.hxx */, DCD56D360B247D920092F9F8 /* Cart4A50.cxx */, @@ -1850,10 +1852,6 @@ DC6727091556F4860023653B /* CartCTY.hxx */, 2DE2DF1C0627AE07006BEC99 /* CartCV.cxx */, 2DE2DF1D0627AE07006BEC99 /* CartCV.hxx */, - DCACBAD21C54298300703A9B /* CartCVPlus.cxx */, - DCACBAD31C54298300703A9B /* CartCVPlus.hxx */, - DC2AADAA194F389C0026C7A4 /* CartDASH.cxx */, - DC2AADAB194F389C0026C7A4 /* CartDASH.hxx */, DCB2ECAC1F0AECA3009738A6 /* CartDetector.cxx */, DCB2ECAD1F0AECA3009738A6 /* CartDetector.hxx */, DCAACAF2188D631500A4D282 /* CartDF.cxx */, @@ -1874,6 +1872,8 @@ DCF467BF0F939A1400B25D7A /* CartEF.hxx */, DCF467C00F939A1400B25D7A /* CartEFSC.cxx */, DCF467C10F939A1400B25D7A /* CartEFSC.hxx */, + DC3C9BCF2469C9A200CF2D47 /* CartEnhanced.cxx */, + DC3C9BD12469C9A200CF2D47 /* CartEnhanced.hxx */, DCF7B0D910A762FC007A2870 /* CartF0.cxx */, DCF7B0DA10A762FC007A2870 /* CartF0.hxx */, 2DE2DF240627AE07006BEC99 /* CartF4.cxx */, @@ -2003,8 +2003,6 @@ children = ( 2DDBEAA3084578BF00812C11 /* AboutDialog.cxx */, 2DDBEAA4084578BF00812C11 /* AboutDialog.hxx */, - 2DDBEAA6084578BF00812C11 /* AudioDialog.cxx */, - 2DDBEAA7084578BF00812C11 /* AudioDialog.hxx */, 2DDBEAA8084578BF00812C11 /* BrowserDialog.cxx */, 2DDBEAA9084578BF00812C11 /* BrowserDialog.hxx */, 2DEF21F808BC033500B246B4 /* CheckListWidget.cxx */, @@ -2034,6 +2032,8 @@ 2D403BA1086116D1001E31A1 /* EditableWidget.hxx */, 2D403BA4086116D1001E31A1 /* EditTextWidget.cxx */, 2D403BA5086116D1001E31A1 /* EditTextWidget.hxx */, + DC3C9BC82469C93D00CF2D47 /* EmulationDialog.cxx */, + DC3C9BCA2469C93D00CF2D47 /* EmulationDialog.hxx */, 2D05FF5E096E269100A518FE /* EventMappingWidget.cxx */, 2D05FF5F096E269100A518FE /* EventMappingWidget.hxx */, DC7A24DD173B1DBC00B20FE9 /* FileListWidget.cxx */, @@ -2107,8 +2107,8 @@ DCA82C701FEB4E780059340F /* TimeMachineDialog.hxx */, DC8078E60B4BD697005E9305 /* UIDialog.cxx */, DC8078E70B4BD697005E9305 /* UIDialog.hxx */, - 2DDBEAD2084578BF00812C11 /* VideoDialog.cxx */, - 2DDBEAD3084578BF00812C11 /* VideoDialog.hxx */, + DC3C9BC72469C93D00CF2D47 /* VideoAudioDialog.cxx */, + DC3C9BC92469C93D00CF2D47 /* VideoAudioDialog.hxx */, 2DDBEAD4084578BF00812C11 /* Widget.cxx */, 2DDBEAD5084578BF00812C11 /* Widget.hxx */, ); @@ -2391,10 +2391,9 @@ DC5AAC2D1FCB24DF00C420A6 /* RadioButtonWidget.hxx in Headers */, 2D9173E309BA90380026E9FF /* Driving.hxx in Headers */, 2D9173E409BA90380026E9FF /* Event.hxx in Headers */, + DC3C9BCD2469C93D00CF2D47 /* VideoAudioDialog.hxx in Headers */, 2D9173E509BA90380026E9FF /* Joystick.hxx in Headers */, 2D9173E609BA90380026E9FF /* Keyboard.hxx in Headers */, - DCACBAD51C54298300703A9B /* CartCVPlus.hxx in Headers */, - DCACBAD11C54296300703A9B /* CartCVPlusWidget.hxx in Headers */, DC1B2EC81E50036100F62837 /* TrakBall.hxx in Headers */, 2D9173E709BA90380026E9FF /* M6532.hxx in Headers */, E0893AF3211B9842008B170D /* HighPass.hxx in Headers */, @@ -2417,7 +2416,7 @@ DCF3A6EE1DFC75E3008A8AF3 /* DelayQueueMember.hxx in Headers */, DC96162F1F817830008A2206 /* AtariMouseWidget.hxx in Headers */, DCF4907A1A0ECE5B00A67AA9 /* Vec.hxx in Headers */, - 2D91740109BA90380026E9FF /* AudioDialog.hxx in Headers */, + DC3C9BCE2469C93D00CF2D47 /* EmulationDialog.hxx in Headers */, DC71EA9E1FDA06D2008827CB /* CartE78K.hxx in Headers */, 2D91740209BA90380026E9FF /* BrowserDialog.hxx in Headers */, 2D91740309BA90380026E9FF /* Command.hxx in Headers */, @@ -2446,7 +2445,6 @@ 2D91741309BA90380026E9FF /* ScrollBarWidget.hxx in Headers */, 2D91741609BA90380026E9FF /* TabWidget.hxx in Headers */, DCB2ECB01F0AECA3009738A6 /* CartDetector.hxx in Headers */, - 2D91741709BA90380026E9FF /* VideoDialog.hxx in Headers */, 2D91741809BA90380026E9FF /* Widget.hxx in Headers */, 2D91741909BA90380026E9FF /* CartUA.hxx in Headers */, DCE8B1871E7E03B300189864 /* FrameLayout.hxx in Headers */, @@ -2476,6 +2474,7 @@ DC3EE86C1E2C0E6D00905161 /* zconf.h in Headers */, 2D91743609BA90380026E9FF /* DebuggerSystem.hxx in Headers */, 2D91743A09BA90380026E9FF /* Expression.hxx in Headers */, + DC3C9BDA2469C9C700CF2D47 /* CartEnhancedWidget.hxx in Headers */, 2D91744F09BA90380026E9FF /* InputTextDialog.hxx in Headers */, DC1B2EC61E50036100F62837 /* AtariMouse.hxx in Headers */, DC9616331F817830008A2206 /* PointingDeviceWidget.hxx in Headers */, @@ -2502,7 +2501,7 @@ DCA078351F8C1B04008EFEE5 /* SDL_lib.hxx in Headers */, DCDA03B11A2009BB00711920 /* CartWD.hxx in Headers */, 2D91745909BA90380026E9FF /* PromptWidget.hxx in Headers */, - DC2AADAF194F389C0026C7A4 /* CartDASH.hxx in Headers */, + DC3C9BC62469C8F700CF2D47 /* PaletteHandler.hxx in Headers */, 2D91745A09BA90380026E9FF /* RamWidget.hxx in Headers */, 2D91745B09BA90380026E9FF /* RomListWidget.hxx in Headers */, 2D91745C09BA90380026E9FF /* RomWidget.hxx in Headers */, @@ -2513,6 +2512,7 @@ 2D91746109BA90380026E9FF /* TogglePixelWidget.hxx in Headers */, 2D91746209BA90380026E9FF /* ToggleWidget.hxx in Headers */, 2D91746409BA90380026E9FF /* TiaZoomWidget.hxx in Headers */, + DC3C9BD52469C9A200CF2D47 /* CartEnhanced.hxx in Headers */, DC1BC6672066B4390076F74A /* PKeyboardHandler.hxx in Headers */, 2D91746609BA90380026E9FF /* AudioWidget.hxx in Headers */, DC70065E241EC97900A459AB /* Stella14x28tFont.hxx in Headers */, @@ -2593,7 +2593,6 @@ DCD6FC7111C281ED005DA767 /* png.h in Headers */, DCD6FC7211C281ED005DA767 /* pngconf.h in Headers */, DCF3A6F41DFC75E3008A8AF3 /* LatchedInput.hxx in Headers */, - DC74E5C7198AF12700F37E36 /* CartDASHWidget.hxx in Headers */, DCD6FC7711C281ED005DA767 /* pngpriv.h in Headers */, CFE3F60C1E84A9A200A8204E /* CartBUSWidget.hxx in Headers */, DCD6FC9411C28C6F005DA767 /* PNGLibrary.hxx in Headers */, @@ -2637,6 +2636,7 @@ DCE395EF16CB0B5F008DB1E5 /* FSNodeFactory.hxx in Headers */, DCE395F116CB0B5F008DB1E5 /* FSNodeZIP.hxx in Headers */, DCE395F316CB0B5F008DB1E5 /* ZipHandler.hxx in Headers */, + DC3C9BD42469C9A200CF2D47 /* Cart3EX.hxx in Headers */, DCAAE5D41715887B0080BB82 /* Cart2KWidget.hxx in Headers */, DCF7F129223D796000701A47 /* ProfilingRunner.hxx in Headers */, DCAAE5D61715887B0080BB82 /* Cart3FWidget.hxx in Headers */, @@ -2816,7 +2816,9 @@ E0A755792244294600101889 /* CartCDFInfoWidget.cxx in Sources */, E0406FB81F81A85400A82AE0 /* FrameManager.cxx in Sources */, 2D91747409BA90380026E9FF /* SDLMain.m in Sources */, + DC3C9BC52469C8F700CF2D47 /* PaletteHandler.cxx in Sources */, 2D91747509BA90380026E9FF /* Booster.cxx in Sources */, + DC3C9BD62469C9A200CF2D47 /* Cart3EX.cxx in Sources */, DC3EE8671E2C0E6D00905161 /* inftrees.c in Sources */, 2D91747609BA90380026E9FF /* Cart.cxx in Sources */, 2D91747709BA90380026E9FF /* Cart2K.cxx in Sources */, @@ -2844,6 +2846,7 @@ DCF3A6FA1DFC75E3008A8AF3 /* Player.cxx in Sources */, 2D91748609BA90380026E9FF /* CartFE.cxx in Sources */, 2D91748909BA90380026E9FF /* Console.cxx in Sources */, + DC3C9BD32469C9A200CF2D47 /* CartEnhanced.cxx in Sources */, DC6DC91E205DB879004A5FC3 /* PhysicalJoystick.cxx in Sources */, E08FCD5323A037EB0051F59B /* QisBlitter.cxx in Sources */, DCCE0355225104BF008C246F /* StellaSettingsDialog.cxx in Sources */, @@ -2867,7 +2870,6 @@ 2D9174A309BA90380026E9FF /* Settings.cxx in Sources */, 2D9174A809BA90380026E9FF /* FSNodePOSIX.cxx in Sources */, 2D9174AA09BA90380026E9FF /* AboutDialog.cxx in Sources */, - 2D9174AB09BA90380026E9FF /* AudioDialog.cxx in Sources */, 2D9174AC09BA90380026E9FF /* BrowserDialog.cxx in Sources */, 2D9174AD09BA90380026E9FF /* Dialog.cxx in Sources */, 2D9174AE09BA90380026E9FF /* DialogContainer.cxx in Sources */, @@ -2877,6 +2879,7 @@ 2D9174B309BA90380026E9FF /* LauncherDialog.cxx in Sources */, 2D9174B509BA90380026E9FF /* ListWidget.cxx in Sources */, 2D9174B609BA90380026E9FF /* Menu.cxx in Sources */, + DC3C9BD92469C9C700CF2D47 /* CartEnhancedWidget.cxx in Sources */, CFE3F60D1E84A9A200A8204E /* CartCDFWidget.cxx in Sources */, 2D9174B709BA90380026E9FF /* OptionsDialog.cxx in Sources */, 2D9174B809BA90380026E9FF /* PopUpWidget.cxx in Sources */, @@ -2886,7 +2889,6 @@ 2D9174B909BA90380026E9FF /* ProgressDialog.cxx in Sources */, 2D9174BA09BA90380026E9FF /* ScrollBarWidget.cxx in Sources */, 2D9174BB09BA90380026E9FF /* TabWidget.cxx in Sources */, - 2D9174BC09BA90380026E9FF /* VideoDialog.cxx in Sources */, DC6A18FC19B3E67A00DEB242 /* CartMDM.cxx in Sources */, 2D9174BD09BA90380026E9FF /* Widget.cxx in Sources */, 2D9174BE09BA90380026E9FF /* CartUA.cxx in Sources */, @@ -2914,7 +2916,6 @@ 2D9174F109BA90380026E9FF /* InputTextDialog.cxx in Sources */, DC6DC920205DB879004A5FC3 /* PJoystickHandler.cxx in Sources */, DC2410E42274BDA8007A4CBF /* MinUICommandDialog.cxx in Sources */, - DC74E5C6198AF12700F37E36 /* CartDASHWidget.cxx in Sources */, 2D9174F209BA90380026E9FF /* CheckListWidget.cxx in Sources */, 2D9174F309BA90380026E9FF /* StringListWidget.cxx in Sources */, 2D9174F409BA90380026E9FF /* CommandDialog.cxx in Sources */, @@ -2931,7 +2932,6 @@ DC5963132139FA14002736F2 /* Bankswitch.cxx in Sources */, DCDFF08120B781B0001227C0 /* DispatchResult.cxx in Sources */, 2D9174FC09BA90380026E9FF /* RamWidget.cxx in Sources */, - DC2AADAE194F389C0026C7A4 /* CartDASH.cxx in Sources */, DC21E5C121CA903E007D0E1A /* SerialPortMACOS.cxx in Sources */, E007231F210FBF5E002CF343 /* FpsMeter.cxx in Sources */, 2D9174FD09BA90380026E9FF /* RomListWidget.cxx in Sources */, @@ -2960,7 +2960,6 @@ DC47455A09C34BFA00EDDA3A /* CheatManager.cxx in Sources */, DC47455C09C34BFA00EDDA3A /* CheetahCheat.cxx in Sources */, DC62E6471960E87B007AEF05 /* AtariVoxWidget.cxx in Sources */, - DCACBAD41C54298300703A9B /* CartCVPlus.cxx in Sources */, DC47455E09C34BFA00EDDA3A /* RamCheat.cxx in Sources */, E0FABEEC20E9948200EB8E28 /* AudioSettings.cxx in Sources */, DCD56D380B247D920092F9F8 /* Cart4A50.cxx in Sources */, @@ -3003,6 +3002,7 @@ DC6B2BA411037FF200F199A7 /* CartDebug.cxx in Sources */, DCB20EC71A0C506C0048F595 /* main.cxx in Sources */, DC6B2BA611037FF200F199A7 /* DiStella.cxx in Sources */, + DC3C9BCB2469C93D00CF2D47 /* VideoAudioDialog.cxx in Sources */, CFE3F6151E84A9CE00A8204E /* CartCDF.cxx in Sources */, E08D2F3E23089B9B000BD709 /* JoyMap.cxx in Sources */, DCA82C711FEB4E780059340F /* TimeMachine.cxx in Sources */, @@ -3103,6 +3103,7 @@ DC676A531729A0B000E4E73D /* CartFA2Widget.cxx in Sources */, DC676A551729A0B000E4E73D /* CartFEWidget.cxx in Sources */, DC676A591729A0B000E4E73D /* CartSBWidget.cxx in Sources */, + DC3C9BCC2469C93D00CF2D47 /* EmulationDialog.cxx in Sources */, DC676A5B1729A0B000E4E73D /* CartX07Widget.cxx in Sources */, DC7A24DF173B1DBC00B20FE9 /* FileListWidget.cxx in Sources */, DC13B53F176FF2F500B8B4BB /* RomListSettings.cxx in Sources */, @@ -3116,7 +3117,6 @@ DCAACAFC188D631500A4D282 /* CartDF.cxx in Sources */, DCAACAFE188D631500A4D282 /* CartDFSC.cxx in Sources */, DCAACB0E188D636F00A4D282 /* Cart4KSCWidget.cxx in Sources */, - DCACBAD01C54296300703A9B /* CartCVPlusWidget.cxx in Sources */, DCAACB10188D636F00A4D282 /* CartBFSCWidget.cxx in Sources */, DCAACB12188D636F00A4D282 /* CartBFWidget.cxx in Sources */, DCAACB14188D636F00A4D282 /* CartDFSCWidget.cxx in Sources */, From d3bca5f9a67816096358038b74494534307085b4 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Mon, 11 May 2020 16:15:34 -0230 Subject: [PATCH 201/377] Don't include some header files when we don't need to. --- src/debugger/gui/DebuggerDialog.cxx | 5 +++++ src/debugger/gui/DebuggerDialog.hxx | 8 +++++--- src/emucore/TIASurface.cxx | 5 +++++ src/emucore/TIASurface.hxx | 5 ++--- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/debugger/gui/DebuggerDialog.cxx b/src/debugger/gui/DebuggerDialog.cxx index 5d8404d06..f62df7724 100644 --- a/src/debugger/gui/DebuggerDialog.cxx +++ b/src/debugger/gui/DebuggerDialog.cxx @@ -68,6 +68,11 @@ DebuggerDialog::DebuggerDialog(OSystem& osystem, DialogContainer& parent, Menu::AppMode::debugger); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +DebuggerDialog::~DebuggerDialog() +{ +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::loadConfig() { diff --git a/src/debugger/gui/DebuggerDialog.hxx b/src/debugger/gui/DebuggerDialog.hxx index b66ae37a6..f38e8b2dc 100644 --- a/src/debugger/gui/DebuggerDialog.hxx +++ b/src/debugger/gui/DebuggerDialog.hxx @@ -33,14 +33,16 @@ class TiaOutputWidget; class TiaZoomWidget; class CartDebugWidget; class CartRamWidget; +class OptionsDialog; +namespace GUI { + class MessageBox; +} namespace Common { struct Rect; } #include "Dialog.hxx" -#include "MessageBox.hxx" -#include "OptionsDialog.hxx" class DebuggerDialog : public Dialog { @@ -55,7 +57,7 @@ class DebuggerDialog : public Dialog DebuggerDialog(OSystem& osystem, DialogContainer& parent, int x, int y, int w, int h); - virtual ~DebuggerDialog() = default; + virtual ~DebuggerDialog(); const GUI::Font& lfont() const { return *myLFont; } const GUI::Font& nfont() const { return *myNFont; } diff --git a/src/emucore/TIASurface.cxx b/src/emucore/TIASurface.cxx index 19e817b0d..8ff9f3e17 100644 --- a/src/emucore/TIASurface.cxx +++ b/src/emucore/TIASurface.cxx @@ -82,6 +82,11 @@ TIASurface::TIASurface(OSystem& system) myPaletteHandler->loadConfig(myOSystem.settings()); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +TIASurface::~TIASurface() +{ +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIASurface::initialize(const Console& console, const FrameBuffer::VideoMode& mode) diff --git a/src/emucore/TIASurface.hxx b/src/emucore/TIASurface.hxx index 6552c26ca..b2c00f912 100644 --- a/src/emucore/TIASurface.hxx +++ b/src/emucore/TIASurface.hxx @@ -22,13 +22,13 @@ class TIA; class Console; class OSystem; class FBSurface; +class PaletteHandler; #include #include "Rect.hxx" #include "FrameBuffer.hxx" #include "NTSCFilter.hxx" -#include "PaletteHandler.hxx" #include "PhosphorHandler.hxx" #include "bspf.hxx" #include "TIAConstants.hxx" @@ -49,8 +49,7 @@ class TIASurface Creates a new TIASurface object */ explicit TIASurface(OSystem& system); - - virtual ~TIASurface() = default; + virtual ~TIASurface(); /** Set the TIA object, which is needed for actually rendering the TIA image. From 20dc4e9374258ab7fc8a25989d51a19ba3e79674 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 11 May 2020 21:18:49 +0200 Subject: [PATCH 202/377] Fixed minimal zoom and message area width --- Changes.txt | 2 ++ src/emucore/FrameBuffer.cxx | 5 ++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Changes.txt b/Changes.txt index f0c1b4acc..222b1e8a3 100644 --- a/Changes.txt +++ b/Changes.txt @@ -22,6 +22,8 @@ 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 interactive palette to Video & Audio settings + * Added 'Custom' palette, generated from user controlled phase shifts. * Added 'Turbo' mode, runs the game as fast as the computer allows. diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index ce2d4cf46..14f620373 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -171,10 +171,9 @@ void FrameBuffer::setupFonts() // However, we have to make sure all Dialogs are sized using the fontsize. int zoom_h = (fd.height * 4 * 2) / GUI::stellaMediumDesc.height; int zoom_w = (fd.maxwidth * 4 * 2) / GUI::stellaMediumDesc.maxwidth; - myTIAMinZoom = std::max(zoom_w, zoom_h) / 4.F; // round to 25% steps + myTIAMinZoom = std::max(std::max(zoom_w, zoom_h) / 4.F, 2.F); // round to 25% steps, >= 200% } - // The font used by the ROM launcher const string& lf = myOSystem.settings().getString("launcherfont"); @@ -310,7 +309,7 @@ FBInitStatus FrameBuffer::createDisplay(const string& title, BufferType type, } if(!myMsg.surface) - myMsg.surface = allocateSurface(FBMinimum::Width, font().getFontHeight() * 1.5); + myMsg.surface = allocateSurface(font().getMaxCharWidth() * 56, font().getFontHeight() * 1.5); #endif // Print initial usage message, but only print it later if the status has changed From e618af818202ef7943a816f29b4528922677c3f0 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 12 May 2020 15:21:15 +0200 Subject: [PATCH 203/377] Moved two more mouse settings to Mouse tab --- src/gui/InputDialog.cxx | 81 +++++++++++++++++++++++------------------ src/gui/InputDialog.hxx | 16 ++++---- 2 files changed, 54 insertions(+), 43 deletions(-) diff --git a/src/gui/InputDialog.cxx b/src/gui/InputDialog.cxx index c3959c742..3cced561b 100644 --- a/src/gui/InputDialog.cxx +++ b/src/gui/InputDialog.cxx @@ -127,10 +127,9 @@ void InputDialog::addDevicePortTab() "Joystick deadzone size", lwidth, kDeadzoneChanged, 5 * fontWidth); myDeadzone->setMinValue(0); myDeadzone->setMaxValue(29); myDeadzone->setTickmarkIntervals(4); - xpos = HBORDER + myDeadzone->getWidth() + 5; wid.push_back(myDeadzone); - xpos = HBORDER; ypos += lineHeight + VGAP * 2; + xpos = HBORDER; ypos += lineHeight + VGAP * 4; new StaticTextWidget(myTab, _font, xpos, ypos+1, "Analog paddle:"); xpos += fontWidth * 2; @@ -165,7 +164,7 @@ void InputDialog::addDevicePortTab() wid.push_back(myDejitterDiff); // Add paddle speed (digital emulation) - ypos += lineHeight + VGAP * 3; + ypos += lineHeight + VGAP * 4; myDPaddleSpeed = new SliderWidget(myTab, _font, HBORDER, ypos - 1, 13 * fontWidth, lineHeight, "Digital paddle sensitivity", lwidth, kDPSpeedChanged, 4 * fontWidth, "%"); @@ -173,26 +172,8 @@ void InputDialog::addDevicePortTab() myDPaddleSpeed->setTickmarkIntervals(4); wid.push_back(myDPaddleSpeed); - // Add trackball speed - ypos += lineHeight + VGAP; - myTrackBallSpeed = new SliderWidget(myTab, _font, HBORDER, ypos - 1, 13 * fontWidth, lineHeight, - "Trackball sensitivity", - lwidth, kTBSpeedChanged, 4 * fontWidth, "%"); - myTrackBallSpeed->setMinValue(1); myTrackBallSpeed->setMaxValue(20); - myTrackBallSpeed->setTickmarkIntervals(4); - wid.push_back(myTrackBallSpeed); - - // Add driving controller speed - ypos += lineHeight + VGAP; - myDrivingSpeed = new SliderWidget(myTab, _font, HBORDER, ypos - 1, 13 * fontWidth, lineHeight, - "Driving contr. sensitivity", - lwidth, kDCSpeedChanged, 4 * fontWidth, "%"); - myDrivingSpeed->setMinValue(1); myDrivingSpeed->setMaxValue(20); - myDrivingSpeed->setTickmarkIntervals(4); - wid.push_back(myDrivingSpeed); - // Add 'allow all 4 directions' for joystick - ypos += lineHeight + VGAP * 3; + ypos += lineHeight + VGAP * 4; myAllowAll4 = new CheckboxWidget(myTab, _font, HBORDER, ypos, "Allow all 4 directions on joystick"); wid.push_back(myAllowAll4); @@ -231,7 +212,7 @@ void InputDialog::addDevicePortTab() wid.push_back(myEraseEEPROMButton); // Add AtariVox serial port - ypos += lineHeight + VGAP * 2; + ypos += lineHeight + VGAP * 3; lwidth = _font.getStringWidth("AVox serial port "); fwidth = _w - HBORDER * 2 - 2 - lwidth; new StaticTextWidget(myTab, _font, HBORDER, ypos + 2, "AVox serial port "); @@ -252,7 +233,8 @@ void InputDialog::addMouseTab() const int VGAP = fontHeight / 4; const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; - int ypos, lwidth, pwidth, tabID; + const int INDENT = fontWidth * 2; + int xpos = HBORDER, ypos, lwidth, pwidth, tabID; WidgetArray wid; VariantList items; @@ -267,21 +249,43 @@ void InputDialog::addMouseTab() VarList::push_back(items, "Always", "always"); VarList::push_back(items, "Analog devices", "analog"); VarList::push_back(items, "Never", "never"); - myMouseControl = new PopUpWidget(myTab, _font, HBORDER, ypos, pwidth, lineHeight, items, + myMouseControl = new PopUpWidget(myTab, _font, xpos, ypos, pwidth, lineHeight, items, "Use mouse as a controller ", lwidth, kMouseCtrlChanged); wid.push_back(myMouseControl); - // Add paddle speed (mouse emulation) ypos += lineHeight + VGAP; - myMPaddleSpeed = new SliderWidget(myTab, _font, HBORDER, ypos - 1, 13 * fontWidth, lineHeight, - "Mouse paddle sensitivity ", + myMouseSensitivity = new StaticTextWidget(myTab, _font, xpos, ypos + 1, "Sensitivity:"); + + // Add paddle speed (mouse emulation) + xpos += INDENT; ypos += lineHeight + VGAP; + lwidth -= INDENT; + myMPaddleSpeed = new SliderWidget(myTab, _font, xpos, ypos - 1, 13 * fontWidth, lineHeight, + "Paddle", lwidth, kMPSpeedChanged, 4 * fontWidth, "%"); myMPaddleSpeed->setMinValue(1); myMPaddleSpeed->setMaxValue(20); myMPaddleSpeed->setTickmarkIntervals(4); wid.push_back(myMPaddleSpeed); + // Add trackball speed + ypos += lineHeight + VGAP; + myTrackBallSpeed = new SliderWidget(myTab, _font, xpos, ypos - 1, 13 * fontWidth, lineHeight, + "Trackball", + lwidth, kTBSpeedChanged, 4 * fontWidth, "%"); + myTrackBallSpeed->setMinValue(1); myTrackBallSpeed->setMaxValue(20); + myTrackBallSpeed->setTickmarkIntervals(4); + wid.push_back(myTrackBallSpeed); + + // Add driving controller speed + ypos += lineHeight + VGAP; + myDrivingSpeed = new SliderWidget(myTab, _font, xpos, ypos - 1, 13 * fontWidth, lineHeight, + "Driving controller", + lwidth, kDCSpeedChanged, 4 * fontWidth, "%"); + myDrivingSpeed->setMinValue(1); myDrivingSpeed->setMaxValue(20); + myDrivingSpeed->setTickmarkIntervals(4); + wid.push_back(myDrivingSpeed); // Mouse cursor state + lwidth += INDENT; ypos += lineHeight + VGAP * 4; items.clear(); VarList::push_back(items, "-UI, -Emulation", "0"); @@ -473,9 +477,6 @@ void InputDialog::setDefaults() myDejitterBase->setValue(0); myDejitterDiff->setValue(0); #endif - myDrivingSpeed->setValue(10); - myTrackBallSpeed->setValue(10); - // AtariVox serial port myAVoxPort->setText(""); @@ -491,15 +492,17 @@ void InputDialog::setDefaults() // Use mouse as a controller myMouseControl->setSelected("analog"); + // Paddle speed (mouse) + myMPaddleSpeed->setValue(10); + myTrackBallSpeed->setValue(10); + myDrivingSpeed->setValue(10); + // Mouse cursor state myCursorState->setSelected("2"); // Grab mouse myGrabMouse->setState(true); - // Paddle speed (mouse) - myMPaddleSpeed->setValue(10); - handleMouseControlState(); handleCursorState(); break; @@ -691,6 +694,7 @@ void InputDialog::handleCommand(CommandSender* sender, int cmd, case kMouseCtrlChanged: handleMouseControlState(); + handleCursorState(); break; case kCursorStateChanged: @@ -725,14 +729,19 @@ void InputDialog::updateDejitterReaction() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputDialog::handleMouseControlState() { - myMPaddleSpeed->setEnabled(myMouseControl->getSelected() != 2); + bool enable = myMouseControl->getSelected() != 2; + + myMouseSensitivity->setEnabled(enable); + myMPaddleSpeed->setEnabled(enable); + myTrackBallSpeed->setEnabled(enable); + myDrivingSpeed->setEnabled(enable); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputDialog::handleCursorState() { int state = myCursorState->getSelected(); - bool enableGrab = state != 1 && state != 3; + bool enableGrab = state != 1 && state != 3 && myMouseControl->getSelected() != 2; myGrabMouse->setEnabled(enableGrab); } diff --git a/src/gui/InputDialog.hxx b/src/gui/InputDialog.hxx index 54fde4a91..1c8c04367 100644 --- a/src/gui/InputDialog.hxx +++ b/src/gui/InputDialog.hxx @@ -91,9 +91,7 @@ class InputDialog : public Dialog EventMappingWidget* myEmulEventMapper{nullptr}; EventMappingWidget* myMenuEventMapper{nullptr}; - CheckboxWidget* mySAPort{nullptr}; - PopUpWidget* myMouseControl{nullptr}; - PopUpWidget* myCursorState{nullptr}; + CheckboxWidget* mySAPort{nullptr}; EditTextWidget* myAVoxPort{nullptr}; @@ -102,16 +100,20 @@ class InputDialog : public Dialog SliderWidget* myDejitterBase{nullptr}; SliderWidget* myDejitterDiff{nullptr}; SliderWidget* myDPaddleSpeed{nullptr}; - SliderWidget* myMPaddleSpeed{nullptr}; - SliderWidget* myTrackBallSpeed{nullptr}; - SliderWidget* myDrivingSpeed{nullptr}; CheckboxWidget* myAllowAll4{nullptr}; - CheckboxWidget* myGrabMouse{nullptr}; CheckboxWidget* myModCombo{nullptr}; ButtonWidget* myJoyDlgButton{nullptr}; ButtonWidget* myEraseEEPROMButton{nullptr}; + PopUpWidget* myMouseControl{nullptr}; + StaticTextWidget* myMouseSensitivity{nullptr}; + SliderWidget* myMPaddleSpeed{nullptr}; + SliderWidget* myTrackBallSpeed{nullptr}; + SliderWidget* myDrivingSpeed{nullptr}; + PopUpWidget* myCursorState{nullptr}; + CheckboxWidget* myGrabMouse{nullptr}; + // Show the list of joysticks that the eventhandler knows about unique_ptr myJoyDialog; From bbd418ddb8564979bef3399678e81eb679e55a37 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 12 May 2020 16:09:39 +0200 Subject: [PATCH 204/377] renamed palette settings prefix --- src/common/PaletteHandler.cxx | 28 ++++++++++----------- src/common/tv_filters/NTSCFilter.cxx | 10 ++++---- src/emucore/Settings.cxx | 37 ++++++++++++++-------------- 3 files changed, 37 insertions(+), 38 deletions(-) diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index 2aecc6abf..70867d116 100644 --- a/src/common/PaletteHandler.cxx +++ b/src/common/PaletteHandler.cxx @@ -191,30 +191,30 @@ void PaletteHandler::changeColorPhaseShift(bool increase) void PaletteHandler::loadConfig(const Settings& settings) { // Load adjustables - myPhaseNTSC = BSPF::clamp(settings.getFloat("tv.phase_ntsc"), + myPhaseNTSC = BSPF::clamp(settings.getFloat("pal.phase_ntsc"), DEF_NTSC_SHIFT - MAX_SHIFT, DEF_NTSC_SHIFT + MAX_SHIFT); - myPhasePAL = BSPF::clamp(settings.getFloat("tv.phase_pal"), + myPhasePAL = BSPF::clamp(settings.getFloat("pal.phase_pal"), DEF_PAL_SHIFT - MAX_SHIFT, DEF_PAL_SHIFT + MAX_SHIFT); - myHue = BSPF::clamp(settings.getFloat("tv.hue"), -1.0F, 1.0F); - mySaturation = BSPF::clamp(settings.getFloat("tv.saturation"), -1.0F, 1.0F); - myContrast = BSPF::clamp(settings.getFloat("tv.contrast"), -1.0F, 1.0F); - myBrightness = BSPF::clamp(settings.getFloat("tv.brightness"), -1.0F, 1.0F); - myGamma = BSPF::clamp(settings.getFloat("tv.gamma"), -1.0F, 1.0F); + myHue = BSPF::clamp(settings.getFloat("pal.hue"), -1.0F, 1.0F); + mySaturation = BSPF::clamp(settings.getFloat("pal.saturation"), -1.0F, 1.0F); + myContrast = BSPF::clamp(settings.getFloat("pal.contrast"), -1.0F, 1.0F); + myBrightness = BSPF::clamp(settings.getFloat("pal.brightness"), -1.0F, 1.0F); + myGamma = BSPF::clamp(settings.getFloat("pal.gamma"), -1.0F, 1.0F); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaletteHandler::saveConfig(Settings& settings) const { // Save adjustables - settings.setValue("tv.phase_ntsc", myPhaseNTSC); - settings.setValue("tv.phase_pal", myPhasePAL); + settings.setValue("pal.phase_ntsc", myPhaseNTSC); + settings.setValue("pal.phase_pal", myPhasePAL); - settings.setValue("tv.hue", myHue); - settings.setValue("tv.saturation", mySaturation); - settings.setValue("tv.contrast", myContrast); - settings.setValue("tv.brightness", myBrightness); - settings.setValue("tv.gamma", myGamma); + settings.setValue("pal.hue", myHue); + settings.setValue("pal.saturation", mySaturation); + settings.setValue("pal.contrast", myContrast); + settings.setValue("pal.brightness", myBrightness); + settings.setValue("pal.gamma", myGamma); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/tv_filters/NTSCFilter.cxx b/src/common/tv_filters/NTSCFilter.cxx index 64f26da2b..5a275fbf2 100644 --- a/src/common/tv_filters/NTSCFilter.cxx +++ b/src/common/tv_filters/NTSCFilter.cxx @@ -172,11 +172,11 @@ void NTSCFilter::saveConfig(Settings& settings) const { // Save adjustables for custom mode #ifdef BLARGG_PALETTE - //settings.setValue("tv.hue", myCustomSetup.hue); - //settings.setValue("tv.saturation", myCustomSetup.saturation); - //settings.setValue("tv.contrast", myCustomSetup.contrast); - //settings.setValue("tv.brightness", myCustomSetup.brightness); - //settings.setValue("tv.gamma", myCustomSetup.gamma); + settings.setValue("tv.hue", myCustomSetup.hue); + settings.setValue("tv.saturation", myCustomSetup.saturation); + settings.setValue("tv.contrast", myCustomSetup.contrast); + settings.setValue("tv.brightness", myCustomSetup.brightness); + settings.setValue("tv.gamma", myCustomSetup.gamma); #endif settings.setValue("tv.sharpness", myCustomSetup.sharpness); settings.setValue("tv.resolution", myCustomSetup.resolution); diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index 07c41e0f3..f5e120408 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -46,30 +46,29 @@ Settings::Settings() setPermanent("center", "true"); setPermanent("windowedpos", Common::Point(50, 50)); setPermanent("display", 0); - setPermanent("palette", PaletteHandler::SETTING_STANDARD); setPermanent("uimessages", "true"); - // TIA specific options - setPermanent("tia.zoom", "3"); setPermanent("tia.inter", "false"); - setPermanent("tia.vsizeadjust", 0); + setPermanent("tia.zoom", "3"); setPermanent("fullscreen", "false"); setPermanent("tia.fs_stretch", "false"); setPermanent("tia.fs_overscan", "0"); + setPermanent("tia.vsizeadjust", 0); setPermanent("tia.dbgcolors", "roygpb"); - + // Palette options + setPermanent("palette", PaletteHandler::SETTING_STANDARD); + setPermanent("pal.phase_ntsc", "26.2"); + setPermanent("pal.phase_pal", "31.3"); + setPermanent("pal.contrast", "0.0"); + setPermanent("pal.brightness", "0.0"); + setPermanent("pal.hue", "0.0"); + setPermanent("pal.saturation", "0.0"); + setPermanent("pal.gamma", "0.0"); // TV filtering options setPermanent("tv.filter", "0"); setPermanent("tv.phosphor", "byrom"); setPermanent("tv.phosblend", "50"); setPermanent("tv.scanlines", "25"); - setPermanent("tv.phase_ntsc", "26.2"); - setPermanent("tv.phase_pal", "31.3"); - setPermanent("tv.contrast", "0.0"); - setPermanent("tv.brightness", "0.0"); - setPermanent("tv.hue", "0.0"); - setPermanent("tv.saturation", "0.0"); - setPermanent("tv.gamma", "0.0"); // TV options when using 'custom' mode setPermanent("tv.sharpness", "0.0"); setPermanent("tv.resolution", "0.0"); @@ -411,8 +410,13 @@ void Settings::usage() const << " -palette \n" - << " -phase_ntsc Phase shift for NTSC custom color palette\n" - << " -phase_pal Phase shift for PAL custom color palette\n" + << " -pal.phase_ntsc Phase shift for NTSC 'custom' palette\n" + << " -pal.phase_pal Phase shift for PAL 'custom' palette\n" + << " -pal.hue <-1.0 - 1.0> Adjust hue for current palette\n" + << " -pal.saturation <-1.0 - 1.0> Adjust saturation of current palette\n" + << " -pal.contrast <-1.0 - 1.0> Adjust contrast of current palette\n" + << " -pal.brightness <-1.0 - 1.0> Adjust brightness of current palette\n" + << " -pal.gamma <-1.0 - 1.0> Adjust gamma of current palette\n" << " -speed Run emulation at the given speed\n" << " -turbo <1|0> Enable 'Turbo' mode for maximum emulation speed\n" << " -uimessages <1|0> Show onscreen UI messages for different events\n" @@ -447,11 +451,6 @@ void Settings::usage() const << " -tv.phosblend <0-100> Set default blend level in phosphor mode\n" << " -tv.scanlines <0-100> Set scanline intensity to percentage\n" << " (0 disables completely)\n" - << " -tv.contrast <-1.0 - 1.0> Set TV effects custom contrast\n" - << " -tv.brightness <-1.0 - 1.0> Set TV effects custom brightness\n" - << " -tv.hue <-1.0 - 1.0> Set TV effects custom hue\n" - << " -tv.saturation <-1.0 - 1.0> Set TV effects custom saturation\n" - << " -tv.gamma <-1.0 - 1.0> Set TV effects custom gamma\n" << " -tv.sharpness <-1.0 - 1.0> Set TV effects custom sharpness\n" << " -tv.resolution <-1.0 - 1.0> Set TV effects custom resolution\n" << " -tv.artifacts <-1.0 - 1.0> Set TV effects custom artifacts\n" From 39b5a663e92694db355d97b5f6667f8b3488dfd7 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 12 May 2020 16:10:22 +0200 Subject: [PATCH 205/377] updated doc --- Changes.txt | 13 +- docs/debugger.html | 1 + docs/graphics/eventmapping.png | Bin 4538 -> 4210 bytes docs/graphics/eventmapping_devsports.png | Bin 8669 -> 7375 bytes docs/graphics/eventmapping_remap.png | Bin 4583 -> 4494 bytes docs/graphics/options.png | Bin 3613 -> 2066 bytes docs/graphics/options_audio.png | Bin 5815 -> 3879 bytes .../options_developer_timemachine.png | Bin 4782 -> 3527 bytes docs/graphics/options_gameinfo_controller.png | Bin 6882 -> 4057 bytes docs/graphics/options_misc.png | Bin 4416 -> 4318 bytes docs/graphics/options_video.png | Bin 3927 -> 2744 bytes docs/graphics/options_video_tv.png | Bin 7899 -> 3847 bytes docs/index.html | 249 +++++++++++------- 13 files changed, 170 insertions(+), 93 deletions(-) diff --git a/Changes.txt b/Changes.txt index 222b1e8a3..83f2abc26 100644 --- a/Changes.txt +++ b/Changes.txt @@ -14,26 +14,29 @@ 6.1.2 to 6.2: (??? ??, 2020) - * Added that paddle centering and sensitivity can be adjusted (TODO: Doc) - - * Added that Driving controller sensitivity can be adjusted (TODO: Doc) - * 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 interactive palette to Video & Audio settings + * Added interactive palette to Video & Audio settings. * Added 'Custom' palette, generated from user controlled phase shifts. * 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 mouse sensitivity for Driving controller can be adjusted + * Added selectable dialog fonts * Added separate positioning of launcher, emulator and debugger * Added option which lets default ROM path follow launcher navigation + * Added debugger 'saveaccess' function, which saves memory access counts to + a CSV file. + * Added displaying last write address in the debugger. * Added detection of color and audio data in DiStella. diff --git a/docs/debugger.html b/docs/debugger.html index 91e71bd47..423a20aa1 100644 --- a/docs/debugger.html +++ b/docs/debugger.html @@ -978,6 +978,7 @@ clearsavestateifs - Clear all savestate points runtopc - Run until PC is set to value xx s - Set Stack Pointer to value xx save - Save breaks, watches, traps and functions to file xx + saveaccess - Save access counters to CSV file saveconfig - Save Distella config file (with default name) savedis - Save Distella disassembly (with default name) saverom - Save (possibly patched) ROM (with default name) diff --git a/docs/graphics/eventmapping.png b/docs/graphics/eventmapping.png index 86deacd4aa8ced58e82776d4f402bd2c67778325..f9b089b6d70f6058d740a30112d8b58777a19515 100644 GIT binary patch delta 4138 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 bBhZBe`c(CT@Z0I1&+d$~HO=xofAW6-B`-Rj delta 4468 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 literal 8669 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 P2knNsH+2YFc2WNYVT?VX diff --git a/docs/graphics/eventmapping_remap.png b/docs/graphics/eventmapping_remap.png index a2e3ce94954fe294c4fc56445d34237b1e5c0981..34df629373d86aa9e469d82bdc8506dc982d522e 100644 GIT binary patch delta 4424 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

      FHR#LhXmbjUoS{PuDpAZo0ie_x;)-sJ4S< z>;s1Mz}c-h1{&2f2nad~TcZsNr8YG)l!Pv9wc9c5r{fL-b!fO)P`1`aag|$6t}tvA zcnMoun8tm0^TPWi@tbh=^-iMd4P_k{yc<~<@_$%^hQ+I6D{U$UIT`r8lZPi((zV7~ zbsMp(2|?lg*Bo8C{iU%;MN7M7>|TAUKOb1QPTkgEaa!br=qgNyVIAYc3(ojIivOiM z?%t*Zt{1l4prB#Ww2SSg6UUyuLFK%Gl^b53CoY?1H8Qi^D)b>xRYqLT!H)8q(Is=g za~BI`0P59aqIeAfR=8p$U3`>Ui0-Sl>?+_1AKs7;-XNW;I8B=b!iiG1^e{H(B(N`h z@Y#d!t|eVMI{#Rca+z8@-{x5AhLSViZ;EmIK20HTz?AmvI&ngUwi10|Eb}Ntl~Q$) z)w_Bx(l}S0y(M$C>2uV&P{RiAADI~Lsh_bdvaEA8yR?9?W*1FUT;ucl zAx~HbB}QfyZyPW0dTJTa?p@4(ceidaZx&?yEpj^LBF~fCLGLU}i@YCWxq&P)Ft%WN zuSerHpfUbbQ z1^idPTy$dZ`}PsSzH4as&+hysilr}n`{w>$kM%h;No*+0IKV!J24?>G_44BH3$)9P zW^f9WhO(k`JZh=SlQQ^Vwbh3RzZ}2gt zyr1;VK2;&a-a~8k0q2_}cs)K8#DUu#N_ZL5yP%3IgvR>7nGkLK|N(Qs{{AgKAOey4~Ksc71@6mU@MkK8XQfy52 zo^c%-3AfE2RGdCa^S)6a^^bRltp3J>GEyU<`4BKuY@ZC?v|NAp|EQA-9N0~5IiG$# b=9h7doC`W9N7i@$bA-bhdc~Y%>Jj%pJoUsU delta 4513 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 literal 3613 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 SH*;@$<*~G|K3{9*5%+&xM}~?3 literal 5815 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 Wy*Rj9bF$;;2@#1fhqvgv$NdA>S|xM< diff --git a/docs/graphics/options_developer_timemachine.png b/docs/graphics/options_developer_timemachine.png index ddb58f28e654942d25b01309383ff6b3317efe2e..498f83c0f7cce460505db2f3e21f4fb749a66426 100644 GIT binary patch literal 3527 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 literal 4782 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 diff --git a/docs/graphics/options_gameinfo_controller.png b/docs/graphics/options_gameinfo_controller.png index 9b9413ab25b29a0e3d563a1e074f196bfefc41b8..04cc025db75520f97063cec392956647b1f79a04 100644 GIT binary patch literal 4057 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 DZ8%y~ literal 6882 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 E04+ZjRR910 diff --git a/docs/graphics/options_misc.png b/docs/graphics/options_misc.png index b1930b45d7a246f7cc729bb5c0ef6e4cc70e0431..1faa756b5ce1fd194c32b74aef1dd9dfe606b887 100644 GIT binary patch literal 4318 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 Q|9(sDtkG6Ar?83t0!3{^{Qv*} literal 7899 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 diff --git a/docs/index.html b/docs/index.html index 82b8c4a38..b2da54d33 100644 --- a/docs/index.html +++ b/docs/index.html @@ -19,7 +19,7 @@

      A multi-platform Atari 2600 VCS emulator

      -

      Release 6.1

      +

      Release 6.2



      User's Guide

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


      -
      February 1999 - March 2020
      +
      February 1999 - ??? 2020
      The Stella Team
      Stella Homepage
      @@ -2008,11 +2008,11 @@
      -center <1|0>
      - Centers game window (if possible). + Centers all windows (if possible). -
      -windowedpos <WxH>
      +
      -windowedpos <XxY>
      Sets the window position in windowed emulator mode. @@ -2029,13 +2029,38 @@ -
      -phase_ntsc <number>
      - Set phase shift for custom NTSC palette. +
      -pal.phase_ntsc <number>
      + Adjust phase shift of 'custom' NTSC palette. -
      -phase_pal <number>
      - Set phase shift for custom PAL palette. +
      -pal.phase_pal <number>
      + Adjust phase shift of 'custom' PAL palette. + + + +
      -pal.hue <number>
      + Adjust hue of current palette (range -1.0 to 1.0). + + + +
      -pal.saturation <number>
      + Adjust saturation of current palette (range -1.0 to 1.0). + + + +
      -pal.contrast <number>
      + Adjust contrast of current palette (range -1.0 to 1.0). + + + +
      -pal.brightness <number>
      + Adjust brightness of current palette (range -1.0 to 1.0). + + + +
      -pal.gamma <number>
      + Adjust gamma of current palette (range -1.0 to 1.0). @@ -2152,36 +2177,6 @@ and 'Custom' modes. - -
      -tv.contrast <number>
      - Blargg TV effects 'contrast' (only available in custom mode, - range -1.0 to 1.0). - - - -
      -tv.brightness <number>
      - Blargg TV effects 'brightness' (only available in custom mode, - range -1.0 to 1.0). - - - -
      -tv.hue <number>
      - Blargg TV effects 'hue' (only available in custom mode, - range -1.0 to 1.0). - - - -
      -tv.saturation <number>
      - Blargg TV effects 'saturation' (only available in custom mode, - range -1.0 to 1.0). - - - -
      -tv.gamma <number>
      - Blargg TV effects 'gamma' (only available in custom mode, - range -1.0 to 1.0). - -
      -tv.sharpness <number>
      Blargg TV effects 'sharpness' (only available in custom mode, @@ -2319,6 +2314,13 @@ faster movement. + +
      -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. + +
      -saport <lr|rl>
      Determines how to enumerate the Stelladaptor/2600-daptor devices in the @@ -2410,7 +2412,7 @@ -
      -launcherpos <WxH>
      +
      -launcherpos <XxY>
      Sets the window position in windowed ROM launcher mode. @@ -2566,7 +2568,7 @@ -
      -dbg.pos <WxH>
      +
      -dbg.pos <XxY>
      Sets the window position in windowed debugger mode. @@ -2703,6 +2705,16 @@ Set "Controller.SwapPaddles" property. + +
      -pxcenter <-10..30>
      + Set "Controller.PaddlesXCenter" property. + + + +
      -pycenter <-10..30>
      + Set "Controller.PaddlesYCenter" property. + +
      -ma <Auto|XY>
      Set "Controller.MouseAxis" property. @@ -2860,7 +2872,7 @@

      Options Menu dialog:



      -

      Video Settings dialog:

      +

      Video & Audio Settings dialog (Display):

      @@ -2869,29 +2881,42 @@
      - - - - - - - - + + - - - - +
      ItemBrief descriptionFor more information,
      see CommandLine
      RendererUse specified rendering mode-video
      PalettePalette for emulation mode-palette
      NTSC phasePhase shift for custom NTSC palette-phase_ntsc
      PAL phasePhase shift for custom PAL palette-phase_pal
      InterpolationInterpolation for TIA image-tia.inter
      ZoomZoom level for emulation mode -tia.zoom
      V-Size adjustAdjust height of TIA image-tia.vsizeadjust
      Emul. speedEmulation speed-speed
      VSyncEnable vertical synced updates-vsync
      InterpolationInterpolation of TIA image-tia.inter
      ZoomZoom level of 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
      OverscanIn fullscreen mode, add overscan to the TIA image-tia.fs_overscan
      Fast SuperCharger loadSkip progress loading bars for SuperCharger ROMs-fastscbios
      Show UI messagesOverlay UI messages onscreen-uimessages
      Center windowAttempt to center application windows, else position at last position-center
      Multi-threadingEnable multi-threaded rendering-threads
      V-Size adjustAdjust height of TIA image-tia.vsizeadjust

      -

      Video Settings dialog (TV Effects):

      +

      Video & Audio Settings dialog (Palettes):

      + + + + + + +
           + + + + + + + + + + +
      ItemBrief descriptionFor more information,
      see CommandLine
      PalettePalette used for emulation mode-palette
      NTSC phaseAdjust phase shift for 'Custom' NTSC palette-pal.phase_ntsc
      PAL phaseAdjust phase shift for 'Custom' PAL palette-pal.phase_pal
      HueAdjust hue of currently selected palette-pal.hue
      SaturationAdjust saturation of currently selected palette-pal.saturation
      ContrastAdjust contrast of currently selected palette-pal.contrast
      BrightnessAdjust brightness of currently selected palette-pal.brightness
      GammaAdjust gamma of currently selected palette-pal.gamma
      +
      +
      + +

      Video & Audio Settings dialog (TV Effects):

      @@ -2900,24 +2925,24 @@
      - + - - - - - + + + + +
      ItemBrief descriptionFor more information,
      see CommandLine
      TV modeDisable TV effects, or select TV preset-tv.filter
      Adjustable slidersSet specific attribute in 'Custom' TV mode-tv.contrast, -tv.hue, etc.
      Adjustable slidersSet specific attribute in 'Custom' TV mode-tv.sharpness, -tv.resolution, etc.
      Phosphor for all ROMsEnable phosphor mode for all ROMs-tv.phosphor
      Blend (phosphor)Blend level to use in phosphor mode for all ROMs (needs to be manually adjusted for your particular hardware)-tv.phosblend
      Scanline intensitySets scanline black-level intensity.
      Note: No scanlines in 1x mode snapshots.
      -tv.scanlines
      Clone CompositeCopy 'Composite' attributes to 'Custom' sliders 
      Clone S-VideoCopy 'S-Video' attributes to 'Custom' sliders 
      Clone RGBCopy 'RGB' attributes to 'Custom' sliders 
      Clone Bad adjustCopy 'Bad Adjust' attributes to 'Custom' sliders 
      RevertRevert attribute sliders to saved 'Custom' settings 
      Clone RGBCopy 'RGB' attributes to 'Custom' TV mode sliders 
      Clone S-VideoCopy 'S-Video' attributes to 'Custom' TV mode sliders 
      Clone CompositeCopy 'Composite' attributes to 'Custom' TV mode sliders 
      Clone Bad adjustCopy 'Bad Adjust' attributes to 'Custom' TV mode sliders 
      RevertRevert attribute sliders to saved 'Custom' TV mode settings 

      -

      Audio Settings dialog:

      +

      Video & Audio Settings dialog (Audio):

      @@ -2941,7 +2966,7 @@ - +
      -audio.resampling_quality
      HeadroomNumber of frames to buffer before playback starts. Higher values increase latency, but reduce the potential for dropouts.-audio.headroom
      Buffer sizeMaximum size of the audio buffer. Higher values increase maximum latency, but reduce the potential for dropouts-audio.buffer_size
      Stereo for all ROMsEnables stereo mode for all ROMs.-audio.stereo
      Stereo for all ROMsEnable stereo mode for all ROMs.-audio.stereo
      Pitfall II music pitchDefines the pitch of Pitfall II music (which may vary between carts).-audio.dpc_pitch

      @@ -2960,6 +2985,44 @@
      + +

      Emulation dialog:

      + + + + + + +
           + + + + + + + + + + + + + + + + + + +
      ItemBrief descriptionFor more information,
      see CommandLine
      Emulation speedEmulation speed-speed
      VSyncEnable vertical synced updates-vsync
      TurboEnable 'Turbo' mode for maximum emulation speed. This overwrites 'Emulation speed' setting and disables 'VSync'.-turbo
      Multi-threadingEnable multi-threaded rendering-threads
      Fast SuperCharger loadSkip progress loading bars for SuperCharger ROMs-fastscbios
      Show UI messagesOverlay UI messages onscreen-uimessages
      Confirm exiting...Display a popup when emulation is exited-confirmexit
      When entering/exiting emulation: + Automatically save no, current or all Time Machine states when exiting emulation.
      + The latter also loads all states when entering emulation. When this is enabled, you + can always continue your game session from where you exited it. Even including the + Time Machine buffer! +
      -saveonexit
      Automatically change... + Automatically change to the next available save state slot after saving a ROM state file. + -autoslot
      +
      +
      +

      Input Settings dialog:

      @@ -2980,9 +3043,9 @@ - + - + @@ -3129,16 +3192,12 @@
      ItemBrief descriptionFor more information,
      see CommandLine
      ThemeTheme to use for UI elements (see examples)-uipalette
      Dialogs fontThe font used in the dialogs-dialogfont
      HiDPI modeScales the UI by a factor of two when enabled-hidpi
      HiDPI modeScale the UI by a factor of two when enabled-hidpi
      Dialogs positionPosition of dialogs with Stella window-dialogpos
      Confirm exiting...Display a popup when emulation is exited-confirmexit
      Center windowsAttempt to center application windows, else position at last position-center
      List input delayMaximum delay between keypresses in filelist-widgets before a search string resets. -listdelay
      Mouse wheel scrollNumber of lines a mouse scroll will move in list-widgets-mwheel
      Double-click speedSpeed of mouse double-clicks-mdouble
      - - - + + + - - - @@ -3148,6 +3207,27 @@
      ItemBrief descriptionFor more information,
      see CommandLine
      Use mouse as ...Allow the mouse to emulate various controllers-usemouse
      Mouse cursor visibilityShow/hide cursor depending on current state-cursor
      Joystick deadzone sizeDeadzone area for axes on joysticks/gamepads-joydeadzone
      Paddle dejitter strengthStrenght of paddle input averaging (base) and reaction to fast paddle movements (diff)-dejitter.base, -dejitter.diff
      (Analog paddle) SensitivitySensitivity of an analog paddle-psense
      Analog paddle) Dejitter averagingStrength of paddle input averaging, suppresses mouse jitter-dejitter.base
      (Analog paddle) Dejitter reactionStrength of paddle reaction to fast paddle movements, suppresses mouse jitter-dejitter.diff
      Digital paddle sensitivitySensitivity used when emulating a paddle using a digital device-dsense
      Mouse paddle sensitivitySensitivity used when emulating a paddle using a mouse-msense
      Trackball sensitivitySensitivity used when emulating a trackball device using a mouse-tsense
      Allow all 4 directions ...Allow all 4 joystick directions to be pressed simultaneously-joyallow4
      Grab mouse ...Keep mouse in window in emulation mode
      (only when used as controller)
      - Note: The sensitivity may greatly vary when the mouse is not grabbed.
      -grabmouse
      Use modifier key combosEnable using modifier keys in keyboard actions-modcombo
      Swap Stelladaptor portsSwap the order of the detected Stelladaptors/2600-daptors (see Advanced Configuration - Stelladaptor/2600-daptor Support)-saport
      Joystick databaseShow all joysticks that Stella knows about, with the option to remove them 
      + +

      Mouse settings can be configured under the 'Mouse' tab, shown below:

      + + + + + + +
           + + + + + + + + +
      ItemBrief descriptionFor more information,
      see CommandLine
      Use mouse as ...Allow the mouse to emulate various controllers-usemouse
      (Sensitivity) PaddleSensitivity used when emulating a paddle using a mouse-msense
      (Sensitivity) TrackballSensitivity used when emulating a trackball device using a mouse-tsense
      (Sensitivity) Driving controllerSensitivity used when emulating a driving controller device using a mouse-dcsense
      Mouse cursor visibilityShow/hide cursor depending on current state-cursor
      Grab mouse ...Keep mouse in window in emulation mode
      (only when used as controller)
      + Note: The sensitivity may greatly vary when the mouse is not grabbed.
      -grabmouse
      +
      +

      ROM Launcher

      @@ -3233,8 +3313,6 @@
    11. - -
    12. Show only ROM files: Selecting this reloads the current listing, showing only files that have a valid ROM extension.
    13. @@ -3518,21 +3596,6 @@ 'Buffer size'. -plr.tm.horizon
      -dev.tm.horizon - - When entering/exiting emulation: - - Automatically save no, current or all Time Machine states when exiting emulation.
      - The latter also loads all states when entering emulation. When this is enabled, you - can always continue your game session from where you exited it. Even including the - Time Machine buffer! - - -saveonexit - - Automatically change... - - Automatically change to the next available save state slot after saving a ROM state file. - - -autoslot @@ -4032,6 +4095,16 @@ Ms Pac-Man (Stella extended codes): 'Console.SwapPorts'. The value must be Yes or No. + + Controller.PaddlesXCenter: + Defines the horizontal center of the paddles (range -10..30). + + + + Controller.PaddlesYCenter: + Defines the vertical center of the paddles (range -10..30). + + Controller.MouseAxis: Indicates how the mouse should emulate virtual controllers. From b8a7128ad0180547a22e432fa7d64fa49e60bac0 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 12 May 2020 16:11:02 +0200 Subject: [PATCH 206/377] added missing screen shots --- docs/graphics/eventmapping_mouse.png | Bin 0 -> 3359 bytes docs/graphics/options_emulation.png | Bin 0 -> 3431 bytes docs/graphics/options_video_palettes.png | Bin 0 -> 7989 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/graphics/eventmapping_mouse.png create mode 100644 docs/graphics/options_emulation.png create mode 100644 docs/graphics/options_video_palettes.png diff --git a/docs/graphics/eventmapping_mouse.png b/docs/graphics/eventmapping_mouse.png new file mode 100644 index 0000000000000000000000000000000000000000..daac75b09f09c09507673d50da49878caa05717a GIT binary patch literal 3359 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 h1jX87X3m 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 I*`HVb2mfmGH2?qr literal 0 HcmV?d00001 From a0505a9739839fb9f394291401c4e825258d8917 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 12 May 2020 16:12:03 +0200 Subject: [PATCH 207/377] removed audio dialog screenshot --- docs/graphics/options_audio.png | Bin 3879 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/graphics/options_audio.png diff --git a/docs/graphics/options_audio.png b/docs/graphics/options_audio.png deleted file mode 100644 index f37f07c6f33333eb2756b43a5e6fddaf2e48ad85..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3879 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 From 8807e91d04908d578610fc33531936ba4fa38a09 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Tue, 12 May 2020 11:51:55 -0230 Subject: [PATCH 208/377] libretro: Fixed #634. --- src/libretro/StellaLIBRETRO.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libretro/StellaLIBRETRO.cxx b/src/libretro/StellaLIBRETRO.cxx index 065917c15..e86709490 100644 --- a/src/libretro/StellaLIBRETRO.cxx +++ b/src/libretro/StellaLIBRETRO.cxx @@ -21,6 +21,7 @@ #include "FrameBufferLIBRETRO.hxx" #include "AtariNTSC.hxx" +#include "PaletteHandler.hxx" #include "AudioSettings.hxx" #include "Serializer.hxx" #include "StateManager.hxx" From 7532fbf88aeea26ab089787b63fa4404c5c997d8 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Tue, 12 May 2020 13:52:33 -0230 Subject: [PATCH 209/377] Some more header file cleanups, hopefully resulting in faster compile times. --- src/common/JoyMap.hxx | 1 + src/common/RewindManager.cxx | 1 + src/common/SoundNull.hxx | 7 ++- src/common/SoundSDL2.hxx | 2 +- src/common/sdl_blitter/BilinearBlitter.cxx | 4 +- src/common/sdl_blitter/BilinearBlitter.hxx | 3 +- src/common/sdl_blitter/QisBlitter.cxx | 4 +- src/common/sdl_blitter/QisBlitter.hxx | 3 +- src/debugger/DebuggerParser.cxx | 1 + src/debugger/gui/CartARWidget.cxx | 1 + src/debugger/gui/CartCMWidget.cxx | 1 + src/debugger/gui/CartCTYWidget.cxx | 1 + src/debugger/gui/CartEnhancedWidget.cxx | 2 +- src/debugger/gui/CartEnhancedWidget.hxx | 1 + src/debugger/gui/ControllerWidget.hxx | 1 + src/debugger/gui/DataGridWidget.cxx | 1 + src/debugger/gui/DebuggerDialog.cxx | 2 + src/debugger/gui/PromptWidget.cxx | 1 + src/debugger/gui/RiotRamWidget.cxx | 1 + src/debugger/gui/RomListWidget.cxx | 1 + src/debugger/gui/RomWidget.cxx | 1 + src/emucore/AtariVox.cxx | 5 ++ src/emucore/AtariVox.hxx | 4 +- src/emucore/Cart.hxx | 9 ++- src/emucore/Cart3EPlus.hxx | 1 - src/emucore/Cart3EX.hxx | 57 ++++++++++--------- src/emucore/CartAR.cxx | 1 + src/emucore/CartDPC.cxx | 1 + src/emucore/CartDetector.cxx | 1 + src/emucore/CartDetector.hxx | 2 +- src/emucore/CompuMate.cxx | 3 + src/emucore/CompuMate.hxx | 7 ++- src/emucore/Console.cxx | 1 + src/emucore/ConsoleIO.hxx | 6 +- src/emucore/Control.hxx | 2 +- src/emucore/ControllerDetector.hxx | 2 + src/emucore/Device.hxx | 4 +- src/emucore/Joystick.hxx | 2 +- src/emucore/Keyboard.hxx | 2 +- src/emucore/Lightgun.hxx | 5 ++ src/emucore/PointingDevice.hxx | 1 - src/emucore/ProfilingRunner.cxx | 1 - src/emucore/ProfilingRunner.hxx | 17 +++--- src/emucore/Switches.hxx | 2 +- src/emucore/System.hxx | 3 +- src/emucore/tia/Audio.hxx | 4 +- src/emucore/tia/Background.hxx | 4 +- src/emucore/tia/Ball.hxx | 6 +- src/emucore/tia/DelayQueueIterator.hxx | 2 - src/emucore/tia/DelayQueueIteratorImpl.hxx | 1 - src/emucore/tia/DelayQueueMember.hxx | 2 +- src/emucore/tia/Missile.hxx | 6 +- src/emucore/tia/PaddleReader.hxx | 2 +- src/emucore/tia/Player.hxx | 4 +- src/emucore/tia/Playfield.hxx | 6 +- .../tia/frame-manager/FrameLayoutDetector.hxx | 2 +- src/gui/CommandMenu.cxx | 2 + src/gui/EditTextWidget.hxx | 1 - src/gui/EmulationDialog.cxx | 1 + src/gui/GuiObject.hxx | 1 - src/gui/InputDialog.hxx | 1 - src/gui/LauncherDialog.hxx | 4 +- src/gui/Menu.cxx | 1 + src/gui/MessageDialog.cxx | 1 + src/gui/MessageMenu.cxx | 1 + src/gui/RomAuditDialog.cxx | 1 + src/gui/SnapshotDialog.cxx | 1 + src/gui/StellaSettingsDialog.cxx | 6 ++ src/gui/StellaSettingsDialog.hxx | 4 +- src/gui/Widget.hxx | 6 +- src/libretro/SoundLIBRETRO.hxx | 1 - src/libretro/StellaLIBRETRO.cxx | 1 + 72 files changed, 148 insertions(+), 103 deletions(-) diff --git a/src/common/JoyMap.hxx b/src/common/JoyMap.hxx index 6448de1ff..e3cc7ff7a 100644 --- a/src/common/JoyMap.hxx +++ b/src/common/JoyMap.hxx @@ -19,6 +19,7 @@ #define CONTROLLERMAP_HXX #include + #include "Event.hxx" #include "EventHandlerConstants.hxx" diff --git a/src/common/RewindManager.cxx b/src/common/RewindManager.cxx index d16bbd6c3..6bafbeeaa 100644 --- a/src/common/RewindManager.cxx +++ b/src/common/RewindManager.cxx @@ -18,6 +18,7 @@ #include #include "OSystem.hxx" +#include "Console.hxx" #include "Serializer.hxx" #include "StateManager.hxx" #include "TIA.hxx" diff --git a/src/common/SoundNull.hxx b/src/common/SoundNull.hxx index 87ba7736a..f2aafbff8 100644 --- a/src/common/SoundNull.hxx +++ b/src/common/SoundNull.hxx @@ -18,12 +18,13 @@ #ifndef SOUND_NULL_HXX #define SOUND_NULL_HXX +class OSystem; +class AudioQueue; +class EmulationTiming; + #include "bspf.hxx" #include "Logger.hxx" #include "Sound.hxx" -#include "OSystem.hxx" -#include "AudioQueue.hxx" -#include "EmulationTiming.hxx" /** This class implements a Null sound object, where-by sound generation diff --git a/src/common/SoundSDL2.hxx b/src/common/SoundSDL2.hxx index 85fb86031..613e6980d 100644 --- a/src/common/SoundSDL2.hxx +++ b/src/common/SoundSDL2.hxx @@ -24,12 +24,12 @@ class OSystem; class AudioQueue; class EmulationTiming; class AudioSettings; +class Resampler; #include "SDL_lib.hxx" #include "bspf.hxx" #include "Sound.hxx" -#include "audio/Resampler.hxx" /** This class implements the sound API for SDL. diff --git a/src/common/sdl_blitter/BilinearBlitter.cxx b/src/common/sdl_blitter/BilinearBlitter.cxx index bae05207c..295d8e8e2 100644 --- a/src/common/sdl_blitter/BilinearBlitter.cxx +++ b/src/common/sdl_blitter/BilinearBlitter.cxx @@ -15,9 +15,9 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#include "BilinearBlitter.hxx" - +#include "FrameBufferSDL2.hxx" #include "ThreadDebugging.hxx" +#include "BilinearBlitter.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BilinearBlitter::BilinearBlitter(FrameBufferSDL2& fb, bool interpolate) diff --git a/src/common/sdl_blitter/BilinearBlitter.hxx b/src/common/sdl_blitter/BilinearBlitter.hxx index e18cba6bf..84c550ad1 100644 --- a/src/common/sdl_blitter/BilinearBlitter.hxx +++ b/src/common/sdl_blitter/BilinearBlitter.hxx @@ -18,8 +18,9 @@ #ifndef BILINEAR_BLITTER_HXX #define BILINEAR_BLITTER_HXX +class FrameBufferSDL2; + #include "Blitter.hxx" -#include "FrameBufferSDL2.hxx" #include "SDL_lib.hxx" class BilinearBlitter : public Blitter { diff --git a/src/common/sdl_blitter/QisBlitter.cxx b/src/common/sdl_blitter/QisBlitter.cxx index 95d958565..c68c4bff9 100644 --- a/src/common/sdl_blitter/QisBlitter.cxx +++ b/src/common/sdl_blitter/QisBlitter.cxx @@ -15,9 +15,9 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#include "QisBlitter.hxx" - +#include "FrameBufferSDL2.hxx" #include "ThreadDebugging.hxx" +#include "QisBlitter.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - QisBlitter::QisBlitter(FrameBufferSDL2& fb) diff --git a/src/common/sdl_blitter/QisBlitter.hxx b/src/common/sdl_blitter/QisBlitter.hxx index 77ab2b51d..14ee84fcc 100644 --- a/src/common/sdl_blitter/QisBlitter.hxx +++ b/src/common/sdl_blitter/QisBlitter.hxx @@ -18,8 +18,9 @@ #ifndef QIS_BLITTER_HXX #define QIS_BLITTER_HXX +class FrameBufferSDL2; + #include "Blitter.hxx" -#include "FrameBufferSDL2.hxx" #include "SDL_lib.hxx" class QisBlitter : public Blitter { diff --git a/src/debugger/DebuggerParser.cxx b/src/debugger/DebuggerParser.cxx index da3b0bc5f..d6be07b68 100644 --- a/src/debugger/DebuggerParser.cxx +++ b/src/debugger/DebuggerParser.cxx @@ -30,6 +30,7 @@ #include "M6502.hxx" #include "Expression.hxx" #include "FSNode.hxx" +#include "OSystem.hxx" #include "Settings.hxx" #include "PromptWidget.hxx" #include "RomWidget.hxx" diff --git a/src/debugger/gui/CartARWidget.cxx b/src/debugger/gui/CartARWidget.cxx index aa552d78e..ec4c4037a 100644 --- a/src/debugger/gui/CartARWidget.cxx +++ b/src/debugger/gui/CartARWidget.cxx @@ -16,6 +16,7 @@ //============================================================================ #include "CartAR.hxx" +#include "OSystem.hxx" #include "Debugger.hxx" #include "CartDebug.hxx" #include "PopUpWidget.hxx" diff --git a/src/debugger/gui/CartCMWidget.cxx b/src/debugger/gui/CartCMWidget.cxx index 8fa72f0bb..e4d11ba55 100644 --- a/src/debugger/gui/CartCMWidget.cxx +++ b/src/debugger/gui/CartCMWidget.cxx @@ -16,6 +16,7 @@ //============================================================================ #include "CartCM.hxx" +#include "OSystem.hxx" #include "Debugger.hxx" #include "CartDebug.hxx" #include "RiotDebug.hxx" diff --git a/src/debugger/gui/CartCTYWidget.cxx b/src/debugger/gui/CartCTYWidget.cxx index 76230fa21..659fb9bea 100644 --- a/src/debugger/gui/CartCTYWidget.cxx +++ b/src/debugger/gui/CartCTYWidget.cxx @@ -15,6 +15,7 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include "OSystem.hxx" #include "Debugger.hxx" #include "CartDebug.hxx" #include "CartCTY.hxx" diff --git a/src/debugger/gui/CartEnhancedWidget.cxx b/src/debugger/gui/CartEnhancedWidget.cxx index d955a803a..0bf38f529 100644 --- a/src/debugger/gui/CartEnhancedWidget.cxx +++ b/src/debugger/gui/CartEnhancedWidget.cxx @@ -15,8 +15,8 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ - #include "PopUpWidget.hxx" +#include "OSystem.hxx" #include "Debugger.hxx" #include "CartDebug.hxx" #include "CartEnhanced.hxx" diff --git a/src/debugger/gui/CartEnhancedWidget.hxx b/src/debugger/gui/CartEnhancedWidget.hxx index 968a4bbf0..a367e8def 100644 --- a/src/debugger/gui/CartEnhancedWidget.hxx +++ b/src/debugger/gui/CartEnhancedWidget.hxx @@ -25,6 +25,7 @@ namespace GUI { class Font; } +#include "Variant.hxx" #include "CartDebugWidget.hxx" class CartridgeEnhancedWidget : public CartDebugWidget diff --git a/src/debugger/gui/ControllerWidget.hxx b/src/debugger/gui/ControllerWidget.hxx index e552be284..d14c1ba69 100644 --- a/src/debugger/gui/ControllerWidget.hxx +++ b/src/debugger/gui/ControllerWidget.hxx @@ -23,6 +23,7 @@ class ButtonWidget; #include "Font.hxx" #include "Widget.hxx" +#include "OSystem.hxx" #include "Console.hxx" #include "Command.hxx" #include "ControlLowLevel.hxx" diff --git a/src/debugger/gui/DataGridWidget.cxx b/src/debugger/gui/DataGridWidget.cxx index 6b663609c..719eebef2 100644 --- a/src/debugger/gui/DataGridWidget.cxx +++ b/src/debugger/gui/DataGridWidget.cxx @@ -18,6 +18,7 @@ #include "Widget.hxx" #include "Dialog.hxx" #include "Font.hxx" +#include "OSystem.hxx" #include "Debugger.hxx" #include "FrameBuffer.hxx" #include "FBSurface.hxx" diff --git a/src/debugger/gui/DebuggerDialog.cxx b/src/debugger/gui/DebuggerDialog.cxx index f62df7724..6674311f6 100644 --- a/src/debugger/gui/DebuggerDialog.cxx +++ b/src/debugger/gui/DebuggerDialog.cxx @@ -47,6 +47,8 @@ #include "OptionsDialog.hxx" #include "StateManager.hxx" #include "FrameManager.hxx" +#include "OSystem.hxx" +#include "Console.hxx" #include "DebuggerDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/debugger/gui/PromptWidget.cxx b/src/debugger/gui/PromptWidget.cxx index b803adc17..eb27f5258 100644 --- a/src/debugger/gui/PromptWidget.cxx +++ b/src/debugger/gui/PromptWidget.cxx @@ -20,6 +20,7 @@ #include "Font.hxx" #include "StellaKeys.hxx" #include "Version.hxx" +#include "OSystem.hxx" #include "Debugger.hxx" #include "DebuggerDialog.hxx" #include "DebuggerParser.hxx" diff --git a/src/debugger/gui/RiotRamWidget.cxx b/src/debugger/gui/RiotRamWidget.cxx index 2666182ec..5f3d5c0ab 100644 --- a/src/debugger/gui/RiotRamWidget.cxx +++ b/src/debugger/gui/RiotRamWidget.cxx @@ -15,6 +15,7 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include "OSystem.hxx" #include "Debugger.hxx" #include "CartDebug.hxx" diff --git a/src/debugger/gui/RomListWidget.cxx b/src/debugger/gui/RomListWidget.cxx index 64ca2df9d..6e450e334 100644 --- a/src/debugger/gui/RomListWidget.cxx +++ b/src/debugger/gui/RomListWidget.cxx @@ -16,6 +16,7 @@ //============================================================================ #include "bspf.hxx" +#include "OSystem.hxx" #include "Debugger.hxx" #include "DiStella.hxx" #include "Widget.hxx" diff --git a/src/debugger/gui/RomWidget.cxx b/src/debugger/gui/RomWidget.cxx index 3279ca5d9..bf459d8f7 100644 --- a/src/debugger/gui/RomWidget.cxx +++ b/src/debugger/gui/RomWidget.cxx @@ -15,6 +15,7 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include "OSystem.hxx" #include "Settings.hxx" #include "Debugger.hxx" #include "CartDebug.hxx" diff --git a/src/emucore/AtariVox.cxx b/src/emucore/AtariVox.cxx index 3314ac08c..700789352 100644 --- a/src/emucore/AtariVox.cxx +++ b/src/emucore/AtariVox.cxx @@ -36,6 +36,11 @@ AtariVox::AtariVox(Jack jack, const Event& event, const System& system, setPin(DigitalPin::Four, true); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +AtariVox::~AtariVox() +{ +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool AtariVox::read(DigitalPin pin) { diff --git a/src/emucore/AtariVox.hxx b/src/emucore/AtariVox.hxx index b21ec38b0..e0c2e72c7 100644 --- a/src/emucore/AtariVox.hxx +++ b/src/emucore/AtariVox.hxx @@ -19,10 +19,10 @@ #define ATARIVOX_HXX class OSystem; +class SerialPort; #include "Control.hxx" #include "SaveKey.hxx" -#include "SerialPort.hxx" /** Richard Hutchinson's AtariVox "controller": A speech synthesizer and @@ -49,7 +49,7 @@ class AtariVox : public SaveKey AtariVox(Jack jack, const Event& event, const System& system, const string& portname, const string& eepromfile, const onMessageCallback& callback); - virtual ~AtariVox() = default; + virtual ~AtariVox(); public: using Controller::read; diff --git a/src/emucore/Cart.hxx b/src/emucore/Cart.hxx index 6fbf1a68d..b04a95f10 100644 --- a/src/emucore/Cart.hxx +++ b/src/emucore/Cart.hxx @@ -23,15 +23,18 @@ class Properties; class CartDebugWidget; class CartRamWidget; class GuiObject; +class Settings; + +#include #include "bspf.hxx" #include "Device.hxx" -#include "Settings.hxx" #ifdef DEBUGGER_SUPPORT - #include "Font.hxx" + namespace GUI { + class Font; + } #endif - /** A cartridge is a device which contains the machine code for a game and handles any bankswitching performed by the cartridge. diff --git a/src/emucore/Cart3EPlus.hxx b/src/emucore/Cart3EPlus.hxx index c2ce64cd8..fe6a0a263 100644 --- a/src/emucore/Cart3EPlus.hxx +++ b/src/emucore/Cart3EPlus.hxx @@ -24,7 +24,6 @@ class System; #include "Cart3E.hxx" #ifdef DEBUGGER_SUPPORT -class Cartridge3EPlusWidget; #include "Cart3EPlusWidget.hxx" #endif diff --git a/src/emucore/Cart3EX.hxx b/src/emucore/Cart3EX.hxx index 7df53593e..c949a0c9c 100644 --- a/src/emucore/Cart3EX.hxx +++ b/src/emucore/Cart3EX.hxx @@ -19,7 +19,9 @@ #define CARTRIDGE3EX_HXX class System; +class Settings; +#include "bspf.hxx" #include "Cart3E.hxx" /** @@ -30,39 +32,38 @@ class System; class Cartridge3EX : public Cartridge3E { + public: + /** + Create a new cartridge using the specified image and size -public: - /** - 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) + */ + Cartridge3EX(const ByteBuffer& image, size_t size, const string& md5, + const Settings& settings); + virtual ~Cartridge3EX() = default; - @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) - */ - Cartridge3EX(const ByteBuffer& image, size_t size, const string& md5, - const Settings& settings); - virtual ~Cartridge3EX() = default; + public: + /** + Get a descriptor for the device name (used in error checking). -public: - /** - Get a descriptor for the device name (used in error checking). + @return The name of the object + */ + string name() const override { return "Cartridge3EX"; } - @return The name of the object - */ - string name() const override { return "Cartridge3EX"; } + private: + // RAM size + static constexpr size_t RAM_SIZE = RAM_BANKS << (BANK_SHIFT - 1); // = 256K = 0x40000; -private: - // RAM size - static constexpr size_t RAM_SIZE = RAM_BANKS << (BANK_SHIFT - 1); // = 256K = 0x40000; - -private: - // Following constructors and assignment operators not supported - Cartridge3EX() = delete; - Cartridge3EX(const Cartridge3EX&) = delete; - Cartridge3EX(Cartridge3EX&&) = delete; - Cartridge3EX& operator=(const Cartridge3EX&) = delete; - Cartridge3EX& operator=(Cartridge3EX&&) = delete; + private: + // Following constructors and assignment operators not supported + Cartridge3EX() = delete; + Cartridge3EX(const Cartridge3EX&) = delete; + Cartridge3EX(Cartridge3EX&&) = delete; + Cartridge3EX& operator=(const Cartridge3EX&) = delete; + Cartridge3EX& operator=(Cartridge3EX&&) = delete; }; #endif diff --git a/src/emucore/CartAR.cxx b/src/emucore/CartAR.cxx index 2d8b204b6..a0eea7486 100644 --- a/src/emucore/CartAR.cxx +++ b/src/emucore/CartAR.cxx @@ -17,6 +17,7 @@ #include "M6502.hxx" #include "System.hxx" +#include "Settings.hxx" #include "CartAR.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartDPC.cxx b/src/emucore/CartDPC.cxx index 481e385be..bc8962b1b 100644 --- a/src/emucore/CartDPC.cxx +++ b/src/emucore/CartDPC.cxx @@ -15,6 +15,7 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include "Settings.hxx" #include "System.hxx" #include "AudioSettings.hxx" #include "CartDPC.hxx" diff --git a/src/emucore/CartDetector.cxx b/src/emucore/CartDetector.cxx index 6c68bf6e4..976d56579 100644 --- a/src/emucore/CartDetector.cxx +++ b/src/emucore/CartDetector.cxx @@ -62,6 +62,7 @@ #include "MD5.hxx" #include "Props.hxx" #include "Logger.hxx" +#include "OSystem.hxx" #include "CartDetector.hxx" diff --git a/src/emucore/CartDetector.hxx b/src/emucore/CartDetector.hxx index 706731b0f..9ff193c87 100644 --- a/src/emucore/CartDetector.hxx +++ b/src/emucore/CartDetector.hxx @@ -20,10 +20,10 @@ class Cartridge; class Properties; +class Settings; #include "Bankswitch.hxx" #include "bspf.hxx" -#include "Settings.hxx" /** Auto-detect cart type based on various attributes (file size, signatures, diff --git a/src/emucore/CompuMate.cxx b/src/emucore/CompuMate.cxx index b39e46ab4..a3a0367cc 100644 --- a/src/emucore/CompuMate.cxx +++ b/src/emucore/CompuMate.cxx @@ -15,6 +15,9 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include "Console.hxx" +#include "Event.hxx" +#include "System.hxx" #include "CompuMate.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CompuMate.hxx b/src/emucore/CompuMate.hxx index ff0e0f781..8b8d772e8 100644 --- a/src/emucore/CompuMate.hxx +++ b/src/emucore/CompuMate.hxx @@ -18,11 +18,12 @@ #ifndef COMPUMATE_HXX #define COMPUMATE_HXX +class Console; +class Event; +class System; + #include "bspf.hxx" -#include "CartCM.hxx" #include "Control.hxx" -#include "Event.hxx" -#include "Console.hxx" /** Handler for SpectraVideo CompuMate bankswitched games. diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index bf7d20abf..dda0c9fdd 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -24,6 +24,7 @@ #include "Cart.hxx" #include "Control.hxx" #include "Cart.hxx" +#include "CartCM.hxx" #include "Driving.hxx" #include "Event.hxx" #include "EventHandler.hxx" diff --git a/src/emucore/ConsoleIO.hxx b/src/emucore/ConsoleIO.hxx index d8ae106a6..2fde50ed8 100644 --- a/src/emucore/ConsoleIO.hxx +++ b/src/emucore/ConsoleIO.hxx @@ -15,12 +15,12 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#include "Control.hxx" -#include "Switches.hxx" - #ifndef CONSOLE_IO_HXX #define CONSOLE_IO_HXX +class Controller; +class Switches; + class ConsoleIO { public: diff --git a/src/emucore/Control.hxx b/src/emucore/Control.hxx index 3647d1bc0..a670f39f6 100644 --- a/src/emucore/Control.hxx +++ b/src/emucore/Control.hxx @@ -25,8 +25,8 @@ class System; #include -#include "Serializable.hxx" #include "bspf.hxx" +#include "Serializable.hxx" /** A controller is a device that plugs into either the left or right diff --git a/src/emucore/ControllerDetector.hxx b/src/emucore/ControllerDetector.hxx index 737ea36f2..d37076eb1 100644 --- a/src/emucore/ControllerDetector.hxx +++ b/src/emucore/ControllerDetector.hxx @@ -18,6 +18,8 @@ #ifndef CONTROLLER_DETECTOR_HXX #define CONTROLLER_DETECTOR_HXX +class Settings; + #include "Control.hxx" /** diff --git a/src/emucore/Device.hxx b/src/emucore/Device.hxx index 7c175852b..fb2423a35 100644 --- a/src/emucore/Device.hxx +++ b/src/emucore/Device.hxx @@ -20,9 +20,9 @@ class System; -#include "Console.hxx" -#include "Serializable.hxx" #include "bspf.hxx" +#include "ConsoleTiming.hxx" +#include "Serializable.hxx" /** Abstract base class for devices which can be attached to a 6502 diff --git a/src/emucore/Joystick.hxx b/src/emucore/Joystick.hxx index 7acd631bc..505294456 100644 --- a/src/emucore/Joystick.hxx +++ b/src/emucore/Joystick.hxx @@ -19,8 +19,8 @@ #define JOYSTICK_HXX #include "bspf.hxx" -#include "Control.hxx" #include "Event.hxx" +#include "Control.hxx" /** The standard Atari 2600 joystick controller. diff --git a/src/emucore/Keyboard.hxx b/src/emucore/Keyboard.hxx index a241cbc37..9ec176d71 100644 --- a/src/emucore/Keyboard.hxx +++ b/src/emucore/Keyboard.hxx @@ -19,8 +19,8 @@ #define KEYBOARD_HXX #include "bspf.hxx" -#include "Control.hxx" #include "Event.hxx" +#include "Control.hxx" /** The standard Atari 2600 keyboard controller diff --git a/src/emucore/Lightgun.hxx b/src/emucore/Lightgun.hxx index 7bec4f4e2..facdffe1e 100644 --- a/src/emucore/Lightgun.hxx +++ b/src/emucore/Lightgun.hxx @@ -18,6 +18,11 @@ #ifndef LIGHTGUN_HXX #define LIGHTGUN_HXX +class FrameBuffer; + +#include "bspf.hxx" +#include "Control.hxx" + /** This class handles the lightgun controller diff --git a/src/emucore/PointingDevice.hxx b/src/emucore/PointingDevice.hxx index 4f0a007b5..11b9fcd2d 100644 --- a/src/emucore/PointingDevice.hxx +++ b/src/emucore/PointingDevice.hxx @@ -18,7 +18,6 @@ #ifndef POINTING_DEVICE_HXX #define POINTING_DEVICE_HXX -class Controller; class Event; #include "Control.hxx" diff --git a/src/emucore/ProfilingRunner.cxx b/src/emucore/ProfilingRunner.cxx index f561dc7a1..e7d81b997 100644 --- a/src/emucore/ProfilingRunner.cxx +++ b/src/emucore/ProfilingRunner.cxx @@ -54,7 +54,6 @@ namespace { } } - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ProfilingRunner::ProfilingRunner(int argc, char* argv[]) : profilingRuns(std::max(argc - 2, 0)) diff --git a/src/emucore/ProfilingRunner.hxx b/src/emucore/ProfilingRunner.hxx index 1194cfdda..a3523b98f 100644 --- a/src/emucore/ProfilingRunner.hxx +++ b/src/emucore/ProfilingRunner.hxx @@ -18,10 +18,9 @@ #ifndef PROFILING_RUNNER #define PROFILING_RUNNER -class Control; -class Switches; - #include "bspf.hxx" +#include "Control.hxx" +#include "Switches.hxx" #include "Settings.hxx" #include "ConsoleIO.hxx" #include "Props.hxx" @@ -41,13 +40,13 @@ class ProfilingRunner { }; struct IO: public ConsoleIO { - Controller& leftController() const override { return *myLeftControl; } - Controller& rightController() const override { return *myRightControl; } - Switches& switches() const override { return *mySwitches; } + Controller& leftController() const override { return *myLeftControl; } + Controller& rightController() const override { return *myRightControl; } + Switches& switches() const override { return *mySwitches; } - unique_ptr myLeftControl; - unique_ptr myRightControl; - unique_ptr mySwitches; + unique_ptr myLeftControl; + unique_ptr myRightControl; + unique_ptr mySwitches; }; private: diff --git a/src/emucore/Switches.hxx b/src/emucore/Switches.hxx index fb7ae4539..16c4dba74 100644 --- a/src/emucore/Switches.hxx +++ b/src/emucore/Switches.hxx @@ -22,8 +22,8 @@ class Event; class Properties; class Settings; -#include "Serializable.hxx" #include "bspf.hxx" +#include "Serializable.hxx" /** This class represents the console switches of the game console. diff --git a/src/emucore/System.hxx b/src/emucore/System.hxx index 1c36acf53..dab87b28a 100644 --- a/src/emucore/System.hxx +++ b/src/emucore/System.hxx @@ -18,11 +18,10 @@ #ifndef SYSTEM_HXX #define SYSTEM_HXX -class Device; class M6502; class M6532; class TIA; -class NullDevice; +class Cartridge; #include "bspf.hxx" #include "Device.hxx" diff --git a/src/emucore/tia/Audio.hxx b/src/emucore/tia/Audio.hxx index 92e854a0d..5ab53ecae 100644 --- a/src/emucore/tia/Audio.hxx +++ b/src/emucore/tia/Audio.hxx @@ -18,12 +18,12 @@ #ifndef TIA_AUDIO_HXX #define TIA_AUDIO_HXX +class AudioQueue; + #include "bspf.hxx" #include "AudioChannel.hxx" #include "Serializable.hxx" -class AudioQueue; - class Audio : public Serializable { public: diff --git a/src/emucore/tia/Background.hxx b/src/emucore/tia/Background.hxx index 3004c7978..ea84aed96 100644 --- a/src/emucore/tia/Background.hxx +++ b/src/emucore/tia/Background.hxx @@ -18,11 +18,11 @@ #ifndef TIA_BACKGROUND #define TIA_BACKGROUND +class TIA; + #include "Serializable.hxx" #include "bspf.hxx" -class TIA; - class Background : public Serializable { public: diff --git a/src/emucore/tia/Ball.hxx b/src/emucore/tia/Ball.hxx index 5b9b3a604..0a40250e2 100644 --- a/src/emucore/tia/Ball.hxx +++ b/src/emucore/tia/Ball.hxx @@ -18,11 +18,11 @@ #ifndef TIA_BALL #define TIA_BALL -#include "Serializable.hxx" +class TIA; + #include "bspf.hxx" #include "TIAConstants.hxx" - -class TIA; +#include "Serializable.hxx" class Ball : public Serializable { diff --git a/src/emucore/tia/DelayQueueIterator.hxx b/src/emucore/tia/DelayQueueIterator.hxx index 31e5251e8..3b615e3d4 100644 --- a/src/emucore/tia/DelayQueueIterator.hxx +++ b/src/emucore/tia/DelayQueueIterator.hxx @@ -19,8 +19,6 @@ #define TIA_DELAY_QUEUE_ITERATOR #include "bspf.hxx" -#include "DelayQueue.hxx" -#include "DelayQueueMember.hxx" class DelayQueueIterator { diff --git a/src/emucore/tia/DelayQueueIteratorImpl.hxx b/src/emucore/tia/DelayQueueIteratorImpl.hxx index b556cb279..9f9e4d4c7 100644 --- a/src/emucore/tia/DelayQueueIteratorImpl.hxx +++ b/src/emucore/tia/DelayQueueIteratorImpl.hxx @@ -20,7 +20,6 @@ #include "bspf.hxx" #include "DelayQueue.hxx" -#include "DelayQueueMember.hxx" #include "DelayQueueIterator.hxx" template diff --git a/src/emucore/tia/DelayQueueMember.hxx b/src/emucore/tia/DelayQueueMember.hxx index f87c9b459..653167b6f 100644 --- a/src/emucore/tia/DelayQueueMember.hxx +++ b/src/emucore/tia/DelayQueueMember.hxx @@ -18,8 +18,8 @@ #ifndef TIA_DELAY_QUEUE_MEMBER #define TIA_DELAY_QUEUE_MEMBER -#include "Serializable.hxx" #include "bspf.hxx" +#include "Serializable.hxx" template class DelayQueueMember : public Serializable { diff --git a/src/emucore/tia/Missile.hxx b/src/emucore/tia/Missile.hxx index dda9b493c..cd5cce582 100644 --- a/src/emucore/tia/Missile.hxx +++ b/src/emucore/tia/Missile.hxx @@ -18,13 +18,13 @@ #ifndef TIA_MISSILE #define TIA_MISSILE +class TIA; +class Player; + #include "Serializable.hxx" #include "bspf.hxx" -#include "Player.hxx" #include "TIAConstants.hxx" -class TIA; - class Missile : public Serializable { public: diff --git a/src/emucore/tia/PaddleReader.hxx b/src/emucore/tia/PaddleReader.hxx index abbc013c6..8071617c6 100644 --- a/src/emucore/tia/PaddleReader.hxx +++ b/src/emucore/tia/PaddleReader.hxx @@ -20,7 +20,7 @@ #include "bspf.hxx" #include "Serializable.hxx" -#include "Console.hxx" +#include "ConsoleTiming.hxx" class PaddleReader : public Serializable { diff --git a/src/emucore/tia/Player.hxx b/src/emucore/tia/Player.hxx index 454bfcd9f..60dfbe3c5 100644 --- a/src/emucore/tia/Player.hxx +++ b/src/emucore/tia/Player.hxx @@ -18,12 +18,12 @@ #ifndef TIA_PLAYER #define TIA_PLAYER +class TIA; + #include "bspf.hxx" #include "Serializable.hxx" #include "TIAConstants.hxx" -class TIA; - class Player : public Serializable { public: diff --git a/src/emucore/tia/Playfield.hxx b/src/emucore/tia/Playfield.hxx index fe811d53a..4a1376991 100644 --- a/src/emucore/tia/Playfield.hxx +++ b/src/emucore/tia/Playfield.hxx @@ -18,11 +18,11 @@ #ifndef TIA_PLAYFIELD #define TIA_PLAYFIELD -#include "Serializable.hxx" +class TIA; + #include "bspf.hxx" #include "TIAConstants.hxx" - -class TIA; +#include "Serializable.hxx" class Playfield : public Serializable { diff --git a/src/emucore/tia/frame-manager/FrameLayoutDetector.hxx b/src/emucore/tia/frame-manager/FrameLayoutDetector.hxx index fa7e50308..443b9c20c 100644 --- a/src/emucore/tia/frame-manager/FrameLayoutDetector.hxx +++ b/src/emucore/tia/frame-manager/FrameLayoutDetector.hxx @@ -18,8 +18,8 @@ #ifndef TIA_FRAME_LAYOUT_DETECTOR #define TIA_FRAME_LAYOUT_DETECTOR -#include "AbstractFrameManager.hxx" #include "FrameLayout.hxx" +#include "AbstractFrameManager.hxx" /** * This frame manager performs frame layout autodetection. It counts the scanlines diff --git a/src/gui/CommandMenu.cxx b/src/gui/CommandMenu.cxx index 68e9a0fef..1a6708f71 100644 --- a/src/gui/CommandMenu.cxx +++ b/src/gui/CommandMenu.cxx @@ -16,6 +16,8 @@ //============================================================================ #include "Dialog.hxx" +#include "OSystem.hxx" +#include "Settings.hxx" #include "CommandDialog.hxx" #include "MinUICommandDialog.hxx" #include "CommandMenu.hxx" diff --git a/src/gui/EditTextWidget.hxx b/src/gui/EditTextWidget.hxx index f752ae385..c7a346804 100644 --- a/src/gui/EditTextWidget.hxx +++ b/src/gui/EditTextWidget.hxx @@ -21,7 +21,6 @@ #include "Rect.hxx" #include "EditableWidget.hxx" - /* EditTextWidget */ class EditTextWidget : public EditableWidget { diff --git a/src/gui/EmulationDialog.cxx b/src/gui/EmulationDialog.cxx index ad86e2e60..e9bb3804a 100644 --- a/src/gui/EmulationDialog.cxx +++ b/src/gui/EmulationDialog.cxx @@ -15,6 +15,7 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include "OSystem.hxx" #include "Console.hxx" #include "FrameBuffer.hxx" #include "RadioButtonWidget.hxx" diff --git a/src/gui/GuiObject.hxx b/src/gui/GuiObject.hxx index 3f473867b..fc8f77285 100644 --- a/src/gui/GuiObject.hxx +++ b/src/gui/GuiObject.hxx @@ -27,7 +27,6 @@ class Widget; class OSystem; #include "Command.hxx" -#include "OSystem.hxx" #include "Vec.hxx" using WidgetArray = vector; diff --git a/src/gui/InputDialog.hxx b/src/gui/InputDialog.hxx index 1c8c04367..48e1629a3 100644 --- a/src/gui/InputDialog.hxx +++ b/src/gui/InputDialog.hxx @@ -62,7 +62,6 @@ class InputDialog : public Dialog void addDevicePortTab(); void addMouseTab(); - void handleMouseControlState(); void handleCursorState(); void updateDejitterAveraging(); diff --git a/src/gui/LauncherDialog.hxx b/src/gui/LauncherDialog.hxx index bfa0cecba..faeea2598 100644 --- a/src/gui/LauncherDialog.hxx +++ b/src/gui/LauncherDialog.hxx @@ -32,6 +32,9 @@ class EditTextWidget; class FileListWidget; class RomInfoWidget; class StaticTextWidget; +namespace Common { + struct Size; +} namespace GUI { class MessageBox; } @@ -41,7 +44,6 @@ namespace GUI { #include "bspf.hxx" #include "Dialog.hxx" #include "FSNode.hxx" -#include "Stack.hxx" class LauncherDialog : public Dialog { diff --git a/src/gui/Menu.cxx b/src/gui/Menu.cxx index c2976857f..547f8e2ac 100644 --- a/src/gui/Menu.cxx +++ b/src/gui/Menu.cxx @@ -19,6 +19,7 @@ #include "FrameBufferConstants.hxx" #include "OptionsDialog.hxx" #include "StellaSettingsDialog.hxx" +#include "OSystem.hxx" #include "FrameBuffer.hxx" #include "bspf.hxx" #include "Menu.hxx" diff --git a/src/gui/MessageDialog.cxx b/src/gui/MessageDialog.cxx index d00acc5a5..ca52c99e6 100644 --- a/src/gui/MessageDialog.cxx +++ b/src/gui/MessageDialog.cxx @@ -15,6 +15,7 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include "OSystem.hxx" #include "Console.hxx" #include "EventHandler.hxx" #include "Font.hxx" diff --git a/src/gui/MessageMenu.cxx b/src/gui/MessageMenu.cxx index f7c7f0faa..19b700ae7 100644 --- a/src/gui/MessageMenu.cxx +++ b/src/gui/MessageMenu.cxx @@ -16,6 +16,7 @@ //============================================================================ #include "Dialog.hxx" +#include "OSystem.hxx" #include "FrameBuffer.hxx" #include "MessageDialog.hxx" #include "MessageMenu.hxx" diff --git a/src/gui/RomAuditDialog.cxx b/src/gui/RomAuditDialog.cxx index 890da7e95..58b9acaba 100644 --- a/src/gui/RomAuditDialog.cxx +++ b/src/gui/RomAuditDialog.cxx @@ -25,6 +25,7 @@ #include "FSNode.hxx" #include "Font.hxx" #include "MessageBox.hxx" +#include "OSystem.hxx" #include "FrameBuffer.hxx" #include "MD5.hxx" #include "Props.hxx" diff --git a/src/gui/SnapshotDialog.cxx b/src/gui/SnapshotDialog.cxx index 2c0534ffa..870a82b54 100644 --- a/src/gui/SnapshotDialog.cxx +++ b/src/gui/SnapshotDialog.cxx @@ -21,6 +21,7 @@ #include "FSNode.hxx" #include "Font.hxx" #include "LauncherDialog.hxx" +#include "OSystem.hxx" #include "Settings.hxx" #include "SnapshotDialog.hxx" diff --git a/src/gui/StellaSettingsDialog.cxx b/src/gui/StellaSettingsDialog.cxx index fbd93dc7d..b5c1e5106 100644 --- a/src/gui/StellaSettingsDialog.cxx +++ b/src/gui/StellaSettingsDialog.cxx @@ -15,6 +15,7 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include "OSystem.hxx" #include "Console.hxx" #include "EventHandler.hxx" #include "Launcher.hxx" @@ -88,6 +89,11 @@ StellaSettingsDialog::StellaSettingsDialog(OSystem& osystem, DialogContainer& pa addToFocusList(wid); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +StellaSettingsDialog::~StellaSettingsDialog() +{ +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void StellaSettingsDialog::addUIOptions(WidgetArray& wid, int& xpos, int& ypos) { diff --git a/src/gui/StellaSettingsDialog.hxx b/src/gui/StellaSettingsDialog.hxx index 791db381c..6f7cfe8a8 100644 --- a/src/gui/StellaSettingsDialog.hxx +++ b/src/gui/StellaSettingsDialog.hxx @@ -23,7 +23,6 @@ class PopUpWidget; #include "Props.hxx" #include "Menu.hxx" #include "Dialog.hxx" -#include "MessageBox.hxx" #if defined(RETRON77) #include "R77HelpDialog.hxx" @@ -33,6 +32,7 @@ class PopUpWidget; namespace GUI { class Font; + class MessageBox; } class StellaSettingsDialog : public Dialog @@ -40,7 +40,7 @@ class StellaSettingsDialog : public Dialog public: StellaSettingsDialog(OSystem& osystem, DialogContainer& parent, int max_w, int max_h, Menu::AppMode mode); - virtual ~StellaSettingsDialog() = default; + virtual ~StellaSettingsDialog(); private: void loadConfig() override; diff --git a/src/gui/Widget.hxx b/src/gui/Widget.hxx index c2a0b6b65..b20b8b159 100644 --- a/src/gui/Widget.hxx +++ b/src/gui/Widget.hxx @@ -23,14 +23,12 @@ class Dialog; -namespace GUI { - class Font; -} - #include #include "bspf.hxx" #include "Event.hxx" +#include "EventHandlerConstants.hxx" +#include "FrameBufferConstants.hxx" #include "StellaKeys.hxx" #include "GuiObject.hxx" #include "Font.hxx" diff --git a/src/libretro/SoundLIBRETRO.hxx b/src/libretro/SoundLIBRETRO.hxx index 9709e4b3d..aa98780e1 100644 --- a/src/libretro/SoundLIBRETRO.hxx +++ b/src/libretro/SoundLIBRETRO.hxx @@ -27,7 +27,6 @@ class AudioSettings; #include "bspf.hxx" #include "Sound.hxx" -#include "AudioQueue.hxx" /** This class implements the sound API for LIBRTRO. diff --git a/src/libretro/StellaLIBRETRO.cxx b/src/libretro/StellaLIBRETRO.cxx index e86709490..0759f9349 100644 --- a/src/libretro/StellaLIBRETRO.cxx +++ b/src/libretro/StellaLIBRETRO.cxx @@ -23,6 +23,7 @@ #include "AtariNTSC.hxx" #include "PaletteHandler.hxx" #include "AudioSettings.hxx" +#include "PaletteHandler.hxx" #include "Serializer.hxx" #include "StateManager.hxx" #include "Switches.hxx" From f4086e4bf49daab93d323dadcb538c1b7221c011 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Tue, 12 May 2020 14:00:08 -0230 Subject: [PATCH 210/377] libretro: Remove redundant code. --- src/libretro/StellaLIBRETRO.cxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libretro/StellaLIBRETRO.cxx b/src/libretro/StellaLIBRETRO.cxx index 0759f9349..d670c45a9 100644 --- a/src/libretro/StellaLIBRETRO.cxx +++ b/src/libretro/StellaLIBRETRO.cxx @@ -23,14 +23,12 @@ #include "AtariNTSC.hxx" #include "PaletteHandler.hxx" #include "AudioSettings.hxx" -#include "PaletteHandler.hxx" #include "Serializer.hxx" #include "StateManager.hxx" #include "Switches.hxx" #include "TIA.hxx" #include "TIASurface.hxx" - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - StellaLIBRETRO::StellaLIBRETRO() { From 16f36b98763dcbe0599ce15b6782a939e96dfd8f Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 13 May 2020 09:25:22 +0200 Subject: [PATCH 211/377] update default keys and doc for palette adjustments --- docs/index.html | 132 +++++++++++++++++--------------- src/common/PKeyboardHandler.cxx | 16 ++-- 2 files changed, 78 insertions(+), 70 deletions(-) diff --git a/docs/index.html b/docs/index.html index b2da54d33..246b84390 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1336,6 +1336,52 @@ +

      Palettes (can be remapped, only active in TIA mode)

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      FunctionKey (Standard)Key (macOS)
      Select previous palette (Standard/Z26/User/Custom)Shift-Control + pShift-Control + p
      Select next palette (Standard/Z26/User/Custom)Control + pControl + p
      Select previous palette attributeShift-Alt + 9Shift-Cmd + 9
      Select next palette attributeAlt + 9Cmd + 9
      Decrease selected palette attributeShift-Alt + 0Shift-Cmd + 0
      Increase selected palette attributeAlt + 0Cmd + 0
      +

      TV effects (can be remapped, only active in TIA mode)

      @@ -1345,54 +1391,34 @@ - + + + + + + - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - + + @@ -1403,25 +1429,25 @@ - - + + - - + + - - + + - - + + @@ -1614,24 +1640,6 @@ - - - - - - - - - - - - - - - - - - diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index 9384d3232..e30bff52f 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -481,15 +481,15 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo {Event::NextAttribute, KBDK_2, MOD3}, {Event::DecreaseAttribute, KBDK_3, KBDM_SHIFT | MOD3}, {Event::IncreaseAttribute, KBDK_3, MOD3}, - {Event::PreviousPaletteAttribute, KBDK_4, KBDM_SHIFT | MOD3}, - {Event::NextPaletteAttribute, KBDK_4, MOD3}, - {Event::PaletteAttributeDecrease, KBDK_5, KBDM_SHIFT | MOD3}, - {Event::PaletteAttributeIncrease, KBDK_5, MOD3}, - {Event::PhosphorDecrease, KBDK_9, KBDM_SHIFT | MOD3}, - {Event::PhosphorIncrease, KBDK_9, MOD3}, + {Event::PhosphorDecrease, KBDK_4, KBDM_SHIFT | MOD3}, + {Event::PhosphorIncrease, KBDK_4, MOD3}, {Event::TogglePhosphor, KBDK_P, MOD3}, - {Event::ScanlinesDecrease, KBDK_0, KBDM_SHIFT | MOD3}, - {Event::ScanlinesIncrease, KBDK_0, MOD3}, + {Event::ScanlinesDecrease, KBDK_5, KBDM_SHIFT | MOD3}, + {Event::ScanlinesIncrease, KBDK_5, MOD3}, + {Event::PreviousPaletteAttribute, KBDK_9, KBDM_SHIFT | MOD3}, + {Event::NextPaletteAttribute, KBDK_9, MOD3}, + {Event::PaletteAttributeDecrease, KBDK_0, KBDM_SHIFT | MOD3}, + {Event::PaletteAttributeIncrease, KBDK_0, MOD3}, {Event::ToggleColorLoss, KBDK_L, KBDM_CTRL}, {Event::PaletteDecrease, KBDK_P, KBDM_SHIFT | KBDM_CTRL}, {Event::PaletteIncrease, KBDK_P, KBDM_CTRL}, From b8cd71d75aef9efab56f5b066dde3c3035403288 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 13 May 2020 09:32:11 +0200 Subject: [PATCH 212/377] added UI messages with gauge bars for variable values (partially addresses #631) --- src/common/PaletteHandler.cxx | 19 ++-- src/common/SoundSDL2.cxx | 12 +-- src/common/tv_filters/NTSCFilter.cxx | 34 ++----- src/common/tv_filters/NTSCFilter.hxx | 3 +- src/emucore/Console.cxx | 109 ++++++---------------- src/emucore/Console.hxx | 16 ++-- src/emucore/EventHandler.cxx | 38 ++++---- src/emucore/FrameBuffer.cxx | 130 ++++++++++++++++++++++----- src/emucore/FrameBuffer.hxx | 29 ++++-- src/emucore/TIASurface.cxx | 14 +-- src/gui/CommandDialog.cxx | 2 +- src/gui/MinUICommandDialog.cxx | 2 +- 12 files changed, 211 insertions(+), 197 deletions(-) diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index 70867d116..b0e4eea2d 100644 --- a/src/common/PaletteHandler.cxx +++ b/src/common/PaletteHandler.cxx @@ -144,11 +144,10 @@ void PaletteHandler::changeAdjustable(bool increase) *myAdjustables[myCurrentAdjustable].value = scaleFrom100(newVal); - ostringstream buf; - buf << "Custom '" << myAdjustables[myCurrentAdjustable].name - << "' set to " << newVal << "%"; - - myOSystem.frameBuffer().showMessage(buf.str()); + ostringstream msg, val; + msg << "Palette " << myAdjustables[myCurrentAdjustable].name; + val << newVal << "%"; + myOSystem.frameBuffer().showMessage(msg.str(), val.str(), newVal); setPalette(); } } @@ -179,11 +178,11 @@ void PaletteHandler::changeColorPhaseShift(bool increase) generateCustomPalette(timing); setPalette(SETTING_CUSTOM); - ostringstream ss; - ss << "Color phase shift at " - << std::fixed << std::setprecision(1) << newPhase << DEGREE; - - myOSystem.frameBuffer().showMessage(ss.str()); + ostringstream val; + val << std::fixed << std::setprecision(1) << newPhase << DEGREE; + myOSystem.frameBuffer().showMessage("Palette phase shift", val.str(), newPhase, + (isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT) - MAX_SHIFT, + (isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT) + MAX_SHIFT); } } diff --git a/src/common/SoundSDL2.cxx b/src/common/SoundSDL2.cxx index 671e5f83c..c32189e95 100644 --- a/src/common/SoundSDL2.cxx +++ b/src/common/SoundSDL2.cxx @@ -217,7 +217,6 @@ void SoundSDL2::setVolume(uInt32 percent) void SoundSDL2::adjustVolume(Int8 direction) { ostringstream strval; - string message; Int32 percent = myVolume; @@ -225,9 +224,7 @@ void SoundSDL2::adjustVolume(Int8 direction) percent -= 2; else if(direction == 1) percent += 2; - - if((percent < 0) || (percent > 100)) - return; + percent = BSPF::clamp(percent, 0, 100); setVolume(percent); @@ -241,11 +238,8 @@ void SoundSDL2::adjustVolume(Int8 direction) } // Now show an onscreen message - strval << percent; - message = "Volume set to "; - message += strval.str(); - - myOSystem.frameBuffer().showMessage(message); + strval << percent << "%"; + myOSystem.frameBuffer().showMessage("Volume", strval.str(), percent); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/tv_filters/NTSCFilter.cxx b/src/common/tv_filters/NTSCFilter.cxx index 5a275fbf2..d742cc674 100644 --- a/src/common/tv_filters/NTSCFilter.cxx +++ b/src/common/tv_filters/NTSCFilter.cxx @@ -112,40 +112,24 @@ string NTSCFilter::setPreviousAdjustable() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string NTSCFilter::increaseAdjustable() +void NTSCFilter::changeAdjustable(bool increase, string& text, string& valueText, Int32& value) { //if(myPreset != Preset::CUSTOM) // return "'Custom' TV mode not selected"; - uInt32 newval = scaleTo100(*ourCustomAdjustables[myCurrentAdjustable].value); - newval += 2; if(newval > 100) newval = 100; - *ourCustomAdjustables[myCurrentAdjustable].value = scaleFrom100(newval); + value = scaleTo100(*ourCustomAdjustables[myCurrentAdjustable].value); + value = BSPF::clamp(value + (increase ? 2 : -2), 0, 100); - ostringstream buf; - buf << "Custom '" << ourCustomAdjustables[myCurrentAdjustable].type - << "' set to " << newval << "%"; + *ourCustomAdjustables[myCurrentAdjustable].value = scaleFrom100(value); setPreset(myPreset); - return buf.str(); -} -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string NTSCFilter::decreaseAdjustable() -{ - //if(myPreset != Preset::CUSTOM) - // return "'Custom' TV mode not selected"; + ostringstream msg, val; + msg << "Custom " << ourCustomAdjustables[myCurrentAdjustable].type; + val << value << "%"; - uInt32 newval = scaleTo100(*ourCustomAdjustables[myCurrentAdjustable].value); - if(newval < 2) newval = 0; - else newval -= 2; - *ourCustomAdjustables[myCurrentAdjustable].value = scaleFrom100(newval); - - ostringstream buf; - buf << "Custom '" << ourCustomAdjustables[myCurrentAdjustable].type - << "' set to " << newval << "%"; - - setPreset(myPreset); - return buf.str(); + text = msg.str(); + valueText = val.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/tv_filters/NTSCFilter.hxx b/src/common/tv_filters/NTSCFilter.hxx index f7e897916..c4fe30f15 100644 --- a/src/common/tv_filters/NTSCFilter.hxx +++ b/src/common/tv_filters/NTSCFilter.hxx @@ -92,8 +92,7 @@ class NTSCFilter // only 4 combinations are necessary string setNextAdjustable(); string setPreviousAdjustable(); - string increaseAdjustable(); - string decreaseAdjustable(); + void changeAdjustable(bool increase, string& text, string& valueText, Int32& value); // Load and save NTSC-related settings void loadConfig(const Settings& settings); diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index dda0c9fdd..33b7520be 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -349,14 +349,14 @@ bool Console::load(Serializer& in) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::toggleFormat(int direction) +void Console::selectFormat(bool next) { string saveformat, message; uInt32 format = myCurrentFormat; - if(direction == 1) + if(next) format = (myCurrentFormat + 1) % 7; - else if(direction == -1) + else format = myCurrentFormat > 0 ? (myCurrentFormat - 1) : 6; setFormat(format); @@ -521,39 +521,20 @@ void Console::togglePhosphor() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::changePhosphor(int direction) +void Console::changePhosphor(bool increase) { int blend = BSPF::stringToInt(myProperties.get(PropType::Display_PPBlend)); - if(direction == +1) // increase blend - { - if(blend >= 100) - { - myOSystem.frameBuffer().showMessage("Phosphor blend at maximum"); - myOSystem.frameBuffer().tiaSurface().enablePhosphor(true, 100); - return; - } - else - blend = std::min(blend+2, 100); - } - else if(direction == -1) // decrease blend - { - if(blend <= 2) - { - myOSystem.frameBuffer().showMessage("Phosphor blend at minimum"); - myOSystem.frameBuffer().tiaSurface().enablePhosphor(true, 0); - return; - } - else - blend = std::max(blend-2, 0); - } - else - return; + if(increase) // increase blend + blend += 2; + else // decrease blend + blend -= 2; + blend = BSPF::clamp(blend, 0, 100); ostringstream val; val << blend; myProperties.set(PropType::Display_PPBlend, val.str()); - myOSystem.frameBuffer().showMessage("Phosphor blend " + val.str()); + myOSystem.frameBuffer().showMessage("Phosphor blend", val.str() + "%", blend); myOSystem.frameBuffer().tiaSurface().enablePhosphor(true, blend); } @@ -631,45 +612,25 @@ void Console::fry() const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::changeVerticalCenter(int direction) +void Console::changeVerticalCenter(bool increase) { Int32 vcenter = myTIA->vcenter(); - if(direction == +1) // increase vcenter - { - if(vcenter >= myTIA->maxVcenter()) - { - myOSystem.frameBuffer().showMessage("V-Center at maximum"); - return; - } + if(increase) // increase vcenter ++vcenter; - } - else if(direction == -1) // decrease vcenter - { - if (vcenter <= myTIA->minVcenter()) - { - myOSystem.frameBuffer().showMessage("V-Center at minimum"); - return; - } + else // decrease vcenter --vcenter; - } - else - return; + vcenter = BSPF::clamp(vcenter, myTIA->minVcenter(), myTIA->maxVcenter()); - ostringstream ss; + ostringstream ss, val; ss << vcenter; myProperties.set(PropType::Display_VCenter, ss.str()); if (vcenter != myTIA->vcenter()) myTIA->setVcenter(vcenter); - ss.str(""); - ss << "V-Center "; - if (!vcenter) - ss << "default"; - else - ss << (vcenter > 0 ? "+" : "") << vcenter << "px"; - - myOSystem.frameBuffer().showMessage(ss.str()); + val << (vcenter ? vcenter > 0 ? "+" : "" : " ") << vcenter << "px"; + myOSystem.frameBuffer().showMessage("V-Center", val.str(), vcenter, + myTIA->minVcenter(), myTIA->maxVcenter()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -682,30 +643,15 @@ void Console::updateVcenter(Int32 vcenter) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::changeScanlineAdjust(int direction) +void Console::changeScanlineAdjust(bool increase) { Int32 newAdjustVSize = myTIA->adjustVSize(); - if (direction != -1 && direction != +1) return; - - if(direction == +1) // increase scanline adjustment - { - if (newAdjustVSize >= 5) - { - myOSystem.frameBuffer().showMessage("V-Size at maximum"); - return; - } + if(increase) // increase scanline adjustment newAdjustVSize++; - } - else if(direction == -1) // decrease scanline adjustment - { - if (newAdjustVSize <= -5) - { - myOSystem.frameBuffer().showMessage("V-Size at minimum"); - return; - } + else // decrease scanline adjustment newAdjustVSize--; - } + newAdjustVSize = BSPF::clamp(newAdjustVSize, -5, 5); if (newAdjustVSize != myTIA->adjustVSize()) { myTIA->setAdjustVSize(newAdjustVSize); @@ -713,15 +659,10 @@ void Console::changeScanlineAdjust(int direction) initializeVideo(); } - ostringstream ss; + ostringstream val; - ss << "V-Size "; - if (!newAdjustVSize) - ss << "default"; - else - ss << (newAdjustVSize > 0 ? "+" : "") << newAdjustVSize << "%"; - - myOSystem.frameBuffer().showMessage(ss.str()); + val << (newAdjustVSize ? newAdjustVSize > 0 ? "+" : "" : " ") << newAdjustVSize << "%"; + myOSystem.frameBuffer().showMessage("V-Size", val.str(), newAdjustVSize, -5, 5); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Console.hxx b/src/emucore/Console.hxx index ac26415d7..685297b55 100644 --- a/src/emucore/Console.hxx +++ b/src/emucore/Console.hxx @@ -189,9 +189,9 @@ class Console : public Serializable, public ConsoleIO /** Toggle between NTSC/PAL/SECAM (and variants) display format. - @param direction +1 indicates increase, -1 indicates decrease. + @param next Select next if true, else previous */ - void toggleFormat(int direction = 1); + void selectFormat(bool next = true); /** Set NTSC/PAL/SECAM (and variants) display format. @@ -222,9 +222,9 @@ class Console : public Serializable, public ConsoleIO /** Change the "Display.PPBlend" variable. - @param direction +1 indicates increase, -1 indicates decrease. + @param increase Increase if true, else decrease */ - void changePhosphor(int direction); + void changePhosphor(bool increase = true); /** Toggles the PAL color-loss effect. @@ -257,18 +257,18 @@ class Console : public Serializable, public ConsoleIO /** Change the "Display.VCenter" variable. - @param direction +1 indicates increase, -1 indicates decrease. + @param increase Increase if true, else decrease */ - void changeVerticalCenter(int direction); + void changeVerticalCenter(bool increase = true); /** Change the "TIA scanline adjust" variable. Note that there are currently two of these (NTSC and PAL). The currently active mode will determine which one is used. - @param direction +1 indicates increase, -1 indicates decrease. + @param increase Increase if true, else decrease */ - void changeScanlineAdjust(int direction); + void changeScanlineAdjust(bool increase = true); /** Returns the current framerate. diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 362625909..82fd4280c 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -413,27 +413,27 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::VidmodeDecrease: - if(pressed) myOSystem.frameBuffer().changeVidMode(-1); + if(pressed) myOSystem.frameBuffer().selectVidMode(false); return; case Event::VidmodeIncrease: - if(pressed) myOSystem.frameBuffer().changeVidMode(+1); + if(pressed) myOSystem.frameBuffer().selectVidMode(true); return; case Event::VCenterDecrease: - if (pressed) myOSystem.console().changeVerticalCenter(-1); + if (pressed) myOSystem.console().changeVerticalCenter(false); return; case Event::VCenterIncrease: - if (pressed) myOSystem.console().changeVerticalCenter(+1); + if (pressed) myOSystem.console().changeVerticalCenter(true); return; case Event::ScanlineAdjustDecrease: - if (pressed) myOSystem.console().changeScanlineAdjust(-1); + if (pressed) myOSystem.console().changeScanlineAdjust(false); return; case Event::ScanlineAdjustIncrease: - if (pressed) myOSystem.console().changeScanlineAdjust(+1); + if (pressed) myOSystem.console().changeScanlineAdjust(true); return; case Event::PreviousPaletteAttribute: @@ -457,11 +457,11 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::OverscanDecrease: - if (pressed) myOSystem.frameBuffer().changeOverscan(-1); + if (pressed) myOSystem.frameBuffer().changeOverscan(false); return; case Event::OverscanIncrease: - if (pressed) myOSystem.frameBuffer().changeOverscan(1); + if (pressed) myOSystem.frameBuffer().changeOverscan(true); return; case Event::PreviousVideoMode: @@ -525,27 +525,33 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) case Event::DecreaseAttribute: if (pressed) { + string text, valueText; + Int32 newVal; + myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::CUSTOM); - myOSystem.frameBuffer().showMessage( - myOSystem.frameBuffer().tiaSurface().ntsc().decreaseAdjustable()); + myOSystem.frameBuffer().tiaSurface().ntsc().changeAdjustable(false, text, valueText, newVal); + myOSystem.frameBuffer().showMessage(text, valueText, newVal); } return; case Event::IncreaseAttribute: if (pressed) { + string text, valueText; + Int32 newVal; + myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::CUSTOM); - myOSystem.frameBuffer().showMessage( - myOSystem.frameBuffer().tiaSurface().ntsc().increaseAdjustable()); + myOSystem.frameBuffer().tiaSurface().ntsc().changeAdjustable(true, text, valueText, newVal); + myOSystem.frameBuffer().showMessage(text, valueText, newVal); } return; case Event::PhosphorDecrease: - if (pressed) myOSystem.console().changePhosphor(-1); + if (pressed) myOSystem.console().changePhosphor(false); return; case Event::PhosphorIncrease: - if (pressed) myOSystem.console().changePhosphor(1); + if (pressed) myOSystem.console().changePhosphor(true); return; case Event::TogglePhosphor: @@ -603,11 +609,11 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::FormatDecrease: - if (pressed) myOSystem.console().toggleFormat(-1); + if (pressed) myOSystem.console().selectFormat(false); return; case Event::FormatIncrease: - if (pressed) myOSystem.console().toggleFormat(1); + if (pressed) myOSystem.console().selectFormat(true); return; case Event::ToggleGrabMouse: diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 14f620373..254060054 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -309,7 +309,12 @@ FBInitStatus FrameBuffer::createDisplay(const string& title, BufferType type, } if(!myMsg.surface) - myMsg.surface = allocateSurface(font().getMaxCharWidth() * 56, font().getFontHeight() * 1.5); + { + const int fontWidth = font().getMaxCharWidth(), + HBORDER = fontWidth * 1.25 / 2.0; + myMsg.surface = allocateSurface(fontWidth * MESSAGE_WIDTH + HBORDER * 2, + font().getFontHeight() * 1.5); + } #endif // Print initial usage message, but only print it later if the status has changed @@ -500,19 +505,62 @@ void FrameBuffer::showMessage(const string& message, MessagePosition position, const int VBORDER = fontHeight / 4; const int HBORDER = fontWidth * 1.25 / 2.0; - // Precompute the message coordinates - myMsg.text = message; - myMsg.counter = uInt32(myOSystem.frameRate()) << 1; // Show message for 2 seconds - if(myMsg.counter == 0) myMsg.counter = 60; - myMsg.color = kBtnTextColor; + myMsg.counter = uInt32(myOSystem.frameRate()) * 2; // Show message for 2 seconds + if(myMsg.counter == 0) + myMsg.counter = 120; - myMsg.w = font().getStringWidth(myMsg.text) + HBORDER * 2; - myMsg.h = fontHeight + VBORDER * 2; + // Precompute the message coordinates + myMsg.text = message; + myMsg.color = kBtnTextColor; + myMsg.showGauge = false; + myMsg.w = font().getStringWidth(myMsg.text) + HBORDER * 2; + myMsg.h = fontHeight + VBORDER * 2; + myMsg.position = position; + myMsg.enabled = true; + + myMsg.surface->setSrcSize(myMsg.w, myMsg.h); + myMsg.surface->setDstSize(myMsg.w * hidpiScaleFactor(), myMsg.h * hidpiScaleFactor()); +#endif +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FrameBuffer::showMessage(const string& message, const string& valueText, + float value, float minValue, float maxValue) +{ +#ifdef GUI_SUPPORT + // Only show messages if they've been enabled + if(myMsg.surface == nullptr || !myOSystem.settings().getBool("uimessages")) + return; + + const int fontWidth = font().getMaxCharWidth(), + fontHeight = font().getFontHeight(); + const int VBORDER = fontHeight / 4; + const int HBORDER = fontWidth * 1.25 / 2.0; + + myMsg.counter = uInt32(myOSystem.frameRate()) * 5; // Show message for 5 seconds + if(myMsg.counter == 0) + myMsg.counter = 120; + + // Precompute the message coordinates + myMsg.text = message; + myMsg.color = kBtnTextColor; + myMsg.showGauge = true; + if(maxValue - minValue != 0) + myMsg.value = (value - minValue) / (maxValue - minValue) * 100.F; + else + myMsg.value = 100.F; + myMsg.valueText = valueText; + myMsg.w = std::min(fontWidth * MESSAGE_WIDTH, + font().getStringWidth(myMsg.text) + + fontWidth * (GAUGEBAR_WIDTH + 2) + + font().getStringWidth(myMsg.valueText)) + + HBORDER * 2; + myMsg.h = fontHeight + VBORDER * 2; + myMsg.position = MessagePosition::BottomCenter; + myMsg.enabled = true; myMsg.surface->setSrcSize(myMsg.w, myMsg.h); myMsg.surface->setDstSize(myMsg.w * hidpiScaleFactor(), myMsg.h * hidpiScaleFactor()); - myMsg.position = position; - myMsg.enabled = true; #endif } @@ -631,6 +679,7 @@ inline bool FrameBuffer::drawMessage() fontHeight = font().getFontHeight(); const int VBORDER = fontHeight / 4; const int HBORDER = fontWidth * 1.25 / 2.0; + constexpr int BORDER = 1; switch(myMsg.position) { @@ -681,10 +730,44 @@ inline bool FrameBuffer::drawMessage() } myMsg.surface->setDstPos(myMsg.x + myImageRect.x(), myMsg.y + myImageRect.y()); - myMsg.surface->fillRect(1, 1, myMsg.w - 2, myMsg.h - 2, kBtnColor); - myMsg.surface->frameRect(0, 0, myMsg.w, myMsg.h, kColor); + myMsg.surface->fillRect(0, 0, myMsg.w, myMsg.h, kColor); + myMsg.surface->fillRect(BORDER, BORDER, myMsg.w - BORDER * 2, myMsg.h - BORDER * 2, kBtnColor); myMsg.surface->drawString(font(), myMsg.text, HBORDER, VBORDER, myMsg.w, myMsg.color); + + if(myMsg.showGauge) + { + constexpr int NUM_TICKMARKS = 4; + // limit gauge bar width if texts are too long + const int swidth = std::min(fontWidth * GAUGEBAR_WIDTH, + fontWidth * (MESSAGE_WIDTH - 2) + - font().getStringWidth(myMsg.text) + - font().getStringWidth(myMsg.valueText)); + const int bwidth = swidth * myMsg.value / 100.F; + const int bheight = fontHeight >> 1; + const int x = HBORDER + font().getStringWidth(myMsg.text) + fontWidth; + // align bar with bottom of text + const int y = VBORDER + font().desc().ascent - bheight; + + // draw bar gauge + myMsg.surface->fillRect(x - BORDER, y, swidth + BORDER * 2, bheight, kSliderBGColor); + myMsg.surface->fillRect(x, y + BORDER, bwidth, bheight - BORDER * 2, kSliderColor); + // draw tickmark in the middle of the bar + for(int i = 1; i < NUM_TICKMARKS; ++i) + { + ColorId color; + int xt = x + swidth * i / NUM_TICKMARKS; + if(bwidth < xt - x) + color = kCheckColor; // kSliderColor; + else + color = kSliderBGColor; + myMsg.surface->vLine(xt, y + bheight / 2, y + bheight - 1, color); + } + // draw value text + myMsg.surface->drawString(font(), myMsg.valueText, + x + swidth + fontWidth, VBORDER, + myMsg.w, myMsg.color); + } myMsg.surface->render(); myMsg.counter--; #endif @@ -900,12 +983,12 @@ void FrameBuffer::toggleFullscreen() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBuffer::changeOverscan(int direction) +void FrameBuffer::changeOverscan(bool increase) { if (fullScreen()) { int oldOverscan = myOSystem.settings().getInt("tia.fs_overscan"); - int overscan = BSPF::clamp(oldOverscan + direction, 0, 10); + int overscan = BSPF::clamp(oldOverscan + (increase ? 1 : -1), 0, 10); if (overscan != oldOverscan) { @@ -914,14 +997,15 @@ void FrameBuffer::changeOverscan(int direction) // issue a complete framebuffer re-initialization myOSystem.createFrameBuffer(); } - ostringstream msg; - msg << "Overscan at " << overscan << "%"; - showMessage(msg.str()); + + ostringstream val; + val << (overscan ? overscan > 0 ? "+" : "" : " ") << overscan << "%"; + myOSystem.frameBuffer().showMessage("Overscan", val.str(), overscan, 0, 10); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool FrameBuffer::changeVidMode(int direction) +bool FrameBuffer::selectVidMode(bool next) { EventHandlerState state = myOSystem.eventHandler().state(); bool tiaMode = (state != EventHandlerState::DEBUGGER && @@ -931,12 +1015,10 @@ bool FrameBuffer::changeVidMode(int direction) if(!tiaMode) return false; - if(direction == +1) + if(next) myCurrentModeList->next(); - else if(direction == -1) - myCurrentModeList->previous(); else - return false; + myCurrentModeList->previous(); saveCurrentWindowPosition(); @@ -956,7 +1038,7 @@ bool FrameBuffer::changeVidMode(int direction) myTIASurface->initialize(myOSystem.console(), mode); resetSurfaces(); - showMessage(mode.description); + showMessage("Zoom", mode.description, mode.zoom, supportedTIAMinZoom(), myTIAMaxZoom); myOSystem.sound().mute(oldMuteState); if(fullScreen()) @@ -1077,7 +1159,7 @@ void FrameBuffer::setAvailableVidModes(uInt32 baseWidth, uInt32 baseHeight) for(float zoom = minZoom; zoom <= myTIAMaxZoom; zoom += ZOOM_STEPS) { ostringstream desc; - desc << "Zoom " << zoom << "x"; + desc << (zoom * 100) << "%"; VideoMode mode(baseWidth*zoom, baseHeight*zoom, baseWidth*zoom, baseHeight*zoom, VideoMode::Stretch::Fill, 1.0, desc.str(), zoom); diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index a73b01ffb..7a73b3d90 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -147,6 +147,17 @@ class FrameBuffer void showMessage(const string& message, MessagePosition position = MessagePosition::BottomCenter, bool force = false); + /** + Shows a message with a bar gauge onscreen. + + @param message The message to be shown + @param valueText The value of the bar gauge as text + @param value The bar gauge percentage + @param minValue The minimal value of the bar gauge + @param maxValue The maximal value of the bar gauge + */ + void showMessage(const string& message, const string& valueText, + float value, float minValue = 0.F, float maxValue = 100.F); /** Toggles showing or hiding framerate statistics. @@ -251,10 +262,10 @@ class FrameBuffer /** Changes the fullscreen overscan. - direction = -1 means less overscan - direction = +1 means more overscan + + @param increase Increase if true, else decrease */ - void changeOverscan(int direction); + void changeOverscan(bool increase = true); /** This method is called when the user wants to switch to the next @@ -264,9 +275,9 @@ class FrameBuffer direction = -1 means go to the next lower video mode direction = +1 means go to the next higher video mode - @param direction Described above + @param next Select next if true, else previous */ - bool changeVidMode(int direction); + bool selectVidMode(bool next = true); /** Sets the state of the cursor (hidden or grabbed) based on the @@ -502,6 +513,11 @@ class FrameBuffer OSystem& myOSystem; private: + // Maximum message width [chars] + static constexpr int MESSAGE_WIDTH = 56; + // Maximum gauge bar width [chars] + static constexpr int GAUGEBAR_WIDTH = 30; + /** Draw pending messages. @@ -648,6 +664,9 @@ class FrameBuffer ColorId color{kNone}; shared_ptr surface; bool enabled{false}; + bool showGauge{false}; + float value{0.0F}; + string valueText; }; Message myMsg; Message myStatsMsg; diff --git a/src/emucore/TIASurface.cxx b/src/emucore/TIASurface.cxx index 8ff9f3e17..53060a97e 100644 --- a/src/emucore/TIASurface.cxx +++ b/src/emucore/TIASurface.cxx @@ -231,21 +231,11 @@ void TIASurface::setScanlineIntensity(int amount) ostringstream buf; uInt32 intensity = enableScanlines(amount); - if(intensity == 0) - buf << "Scanlines disabled"; - else - { - buf << "Scanline intensity at "; - if(intensity < 100) - buf << intensity << "%"; - else - buf << "maximum"; - } myOSystem.settings().setValue("tv.scanlines", intensity); - enableNTSC(ntscEnabled()); - myFB.showMessage(buf.str()); + buf << intensity << "%"; + myFB.showMessage("Scanline intensity", buf.str(), intensity); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/gui/CommandDialog.cxx b/src/gui/CommandDialog.cxx index 5790f7193..e4c5f610a 100644 --- a/src/gui/CommandDialog.cxx +++ b/src/gui/CommandDialog.cxx @@ -199,7 +199,7 @@ void CommandDialog::handleCommand(CommandSender* sender, int cmd, // Column 3 case kFormatCmd: - instance().console().toggleFormat(); + instance().console().selectFormat(); updateTVFormat(); break; diff --git a/src/gui/MinUICommandDialog.cxx b/src/gui/MinUICommandDialog.cxx index b93b95890..080316005 100644 --- a/src/gui/MinUICommandDialog.cxx +++ b/src/gui/MinUICommandDialog.cxx @@ -217,7 +217,7 @@ void MinUICommandDialog::handleCommand(CommandSender* sender, int cmd, // Column 3 case kFormatCmd: - instance().console().toggleFormat(); + instance().console().selectFormat(); updateTVFormat(); break; From 986ff0993566e0eecb4b8ca4018395a77a8a81a0 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 13 May 2020 10:56:34 +0200 Subject: [PATCH 213/377] fix #635 (<=2K ROMs rewind broken) --- src/emucore/CartEnhanced.cxx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index 0bd964890..496a4d051 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -40,7 +40,10 @@ void CartridgeEnhanced::install(System& system) // calculate bank switching and RAM sizes and masks myBankSize = 1 << myBankShift; // e.g. = 2 ^ 12 = 4K = 0x1000 myBankMask = myBankSize - 1; // e.g. = 0x0FFF - myBankSegs = 1 << (MAX_BANK_SHIFT - myBankShift); // e.g. = 1 + // Either the bankswitching supports multiple segments + // 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; myRamMask = ramSize - 1; // e.g. = 0xFFFF (doesn't matter for RAM size 0) myWriteOffset = myRamWpHigh ? ramSize : 0; // e.g. = 0x0000 From 60f144d9d4a17573f487cbd0bce46b59ec38a381 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 13 May 2020 13:33:17 +0200 Subject: [PATCH 214/377] increase maximum iterations and performance of RunToPC command --- src/debugger/Debugger.cxx | 8 +++++--- src/debugger/Debugger.hxx | 2 +- src/debugger/DebuggerParser.cxx | 24 +++++++++++++++++------- src/debugger/gui/RomWidget.cxx | 3 ++- 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/debugger/Debugger.cxx b/src/debugger/Debugger.cxx index b46570a6a..cdb039491 100644 --- a/src/debugger/Debugger.cxx +++ b/src/debugger/Debugger.cxx @@ -293,9 +293,10 @@ void Debugger::loadAllStates() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int Debugger::step() +int Debugger::step(bool save) { - saveOldState(); + if(save) + saveOldState(); uInt64 startCycle = mySystem.cycles(); @@ -303,7 +304,8 @@ int Debugger::step() myOSystem.console().tia().updateScanlineByStep().flushLineCache(); lockSystem(); - addState("step"); + if(save) + addState("step"); return int(mySystem.cycles() - startCycle); } diff --git a/src/debugger/Debugger.hxx b/src/debugger/Debugger.hxx index d063f2e90..6083d556a 100644 --- a/src/debugger/Debugger.hxx +++ b/src/debugger/Debugger.hxx @@ -306,7 +306,7 @@ class Debugger : public DialogContainer */ void setQuitState(); - int step(); + int step(bool save = true); int trace(); void nextScanline(int lines); void nextFrame(int frames); diff --git a/src/debugger/DebuggerParser.cxx b/src/debugger/DebuggerParser.cxx index d6be07b68..37632be39 100644 --- a/src/debugger/DebuggerParser.cxx +++ b/src/debugger/DebuggerParser.cxx @@ -1744,7 +1744,7 @@ void DebuggerParser::executeRunTo() bool done = false; do { - debugger.step(); + debugger.step(false); // Update romlist to point to current PC int pcline = cartdbg.addressToLine(debugger.cpuDebug().pc()); @@ -1778,22 +1778,32 @@ void DebuggerParser::executeRunToPc() uInt32 count = 0; bool done = false; + constexpr uInt32 max_iterations = 1000000; + // Create a progress dialog box to show the progress searching through the + // disassembly, since this may be a time-consuming operation + ostringstream buf; + buf << "RunTo PC searching through " << max_iterations << " instructions"; + ProgressDialog progress(debugger.baseDialog(), debugger.lfont(), buf.str()); + progress.setRange(0, max_iterations, 5); + do { - debugger.step(); + debugger.step(false); // Update romlist to point to current PC int pcline = cartdbg.addressToLine(debugger.cpuDebug().pc()); done = (pcline >= 0) && (list[pcline].address == args[0]); - } while(!done && ++count < list.size()); + progress.setProgress(count); + } while(!done && ++count < max_iterations/*list.size()*/); + progress.close(); if(done) commandResult - << "set PC to " << Base::HEX4 << args[0] << " in " - << dec << count << " disassembled instructions"; + << "Set PC to $" << Base::HEX4 << args[0] << " in " + << dec << count << " instructions"; else commandResult - << "PC " << Base::HEX4 << args[0] << " not reached or found in " - << dec << count << " disassembled instructions"; + << "PC $" << Base::HEX4 << args[0] << " not reached or found in " + << dec << count << " instructions"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/debugger/gui/RomWidget.cxx b/src/debugger/gui/RomWidget.cxx index bf459d8f7..010ae5f0b 100644 --- a/src/debugger/gui/RomWidget.cxx +++ b/src/debugger/gui/RomWidget.cxx @@ -200,7 +200,8 @@ void RomWidget::runtoPC(int disasm_line) { ostringstream command; command << "runtopc #" << list[disasm_line].address; - instance().debugger().run(command.str()); + string msg = instance().debugger().run(command.str()); + instance().frameBuffer().showMessage(msg); } } From 06a1477019aeb105ef83b1ce9bc00cb9e03996a4 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 13 May 2020 16:00:20 +0200 Subject: [PATCH 215/377] make sure that debugger command 'stepwhile' doesn't run forever. --- src/debugger/DebuggerParser.cxx | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/debugger/DebuggerParser.cxx b/src/debugger/DebuggerParser.cxx index 37632be39..49692ef8a 100644 --- a/src/debugger/DebuggerParser.cxx +++ b/src/debugger/DebuggerParser.cxx @@ -1941,9 +1941,23 @@ void DebuggerParser::executeStepwhile() } Expression* expr = YaccParser::getResult(); int ncycles = 0; + uInt32 count = 0; + constexpr uInt32 max_iterations = 1000000; + + // Create a progress dialog box to show the progress searching through the + // disassembly, since this may be a time-consuming operation + ostringstream buf; + buf << "stepwhile running through " << max_iterations << " disassembled instructions"; + ProgressDialog progress(debugger.baseDialog(), debugger.lfont(), buf.str()); + progress.setRange(0, max_iterations, 5); + do { - ncycles += debugger.step(); - } while (expr->evaluate()); + ncycles += debugger.step(false); + + progress.setProgress(count); + } while (expr->evaluate() && ++count < max_iterations); + + progress.close(); commandResult << "executed " << ncycles << " cycles"; } From 076c401c1bc363ef7ba7cd40092bd6750f5c0932 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 13 May 2020 20:26:19 +0200 Subject: [PATCH 216/377] added gauge bars display when selecting settings too --- src/common/PaletteHandler.cxx | 47 +++++++++------- src/common/PaletteHandler.hxx | 5 ++ src/common/tv_filters/NTSCFilter.cxx | 82 +++++++++++++--------------- src/common/tv_filters/NTSCFilter.hxx | 5 +- src/emucore/EventHandler.cxx | 58 ++++++-------------- src/emucore/TIASurface.cxx | 23 ++++++++ src/emucore/TIASurface.hxx | 10 ++++ 7 files changed, 121 insertions(+), 109 deletions(-) diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index b0e4eea2d..f040fe8e5 100644 --- a/src/common/PaletteHandler.cxx +++ b/src/common/PaletteHandler.cxx @@ -91,6 +91,31 @@ void PaletteHandler::cyclePalette(bool next) setPalette(palette); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::showAdjustableMessage() +{ + const bool isPhaseShift = myAdjustables[myCurrentAdjustable].value == nullptr; + ostringstream msg, buf; + + msg << "Palette " << myAdjustables[myCurrentAdjustable].name; + if(isPhaseShift) + { + const ConsoleTiming timing = myOSystem.console().timing(); + const bool isNTSC = timing == ConsoleTiming::ntsc; + const float value = myOSystem.console().timing() == ConsoleTiming::pal ? myPhasePAL : myPhaseNTSC; + buf << std::fixed << std::setprecision(1) << value << DEGREE; + myOSystem.frameBuffer().showMessage("Palette phase shift", buf.str(), value, + (isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT) - MAX_SHIFT, + (isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT) + MAX_SHIFT); + } + else + { + const int value = scaleTo100(*myAdjustables[myCurrentAdjustable].value); + buf << value << "%"; + myOSystem.frameBuffer().showMessage(msg.str(), buf.str(), value); + } +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaletteHandler::cycleAdjustable(bool next) { @@ -115,16 +140,7 @@ void PaletteHandler::cycleAdjustable(bool next) // skip phase shift when 'Custom' palette is not selected } while(isPhaseShift && !isCustomPalette); - ostringstream buf; - buf << "Palette adjustable '" << myAdjustables[myCurrentAdjustable].name - << "' selected ("; - if(isPhaseShift) - buf << (myOSystem.console().timing() == ConsoleTiming::pal ? myPhasePAL : myPhaseNTSC) - << DEGREE << ")"; - else - buf << scaleTo100(*myAdjustables[myCurrentAdjustable].value) << "%)"; - - myOSystem.frameBuffer().showMessage(buf.str()); + showAdjustableMessage(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -144,10 +160,7 @@ void PaletteHandler::changeAdjustable(bool increase) *myAdjustables[myCurrentAdjustable].value = scaleFrom100(newVal); - ostringstream msg, val; - msg << "Palette " << myAdjustables[myCurrentAdjustable].name; - val << newVal << "%"; - myOSystem.frameBuffer().showMessage(msg.str(), val.str(), newVal); + showAdjustableMessage(); setPalette(); } } @@ -178,11 +191,7 @@ void PaletteHandler::changeColorPhaseShift(bool increase) generateCustomPalette(timing); setPalette(SETTING_CUSTOM); - ostringstream val; - val << std::fixed << std::setprecision(1) << newPhase << DEGREE; - myOSystem.frameBuffer().showMessage("Palette phase shift", val.str(), newPhase, - (isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT) - MAX_SHIFT, - (isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT) + MAX_SHIFT); + showAdjustableMessage(); } } diff --git a/src/common/PaletteHandler.hxx b/src/common/PaletteHandler.hxx index 3a8c5c9e3..e8e083a8a 100644 --- a/src/common/PaletteHandler.hxx +++ b/src/common/PaletteHandler.hxx @@ -128,6 +128,11 @@ class PaletteHandler */ string toPaletteName(PaletteType type) const; + /** + Display current adjustable with bar gauge message + */ + void showAdjustableMessage(); + /** Change the "phase shift" variable. Note that there are two of these (NTSC and PAL). The currently diff --git a/src/common/tv_filters/NTSCFilter.cxx b/src/common/tv_filters/NTSCFilter.cxx index d742cc674..2d0ffaa6e 100644 --- a/src/common/tv_filters/NTSCFilter.cxx +++ b/src/common/tv_filters/NTSCFilter.cxx @@ -72,61 +72,53 @@ string NTSCFilter::getPreset() const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string NTSCFilter::setNextAdjustable() +void NTSCFilter::selectAdjustable(bool next, string& text, string& valueText, Int32& value) { - //if(myPreset != Preset::CUSTOM) - // return "'Custom' TV mode not selected"; + if(next) + { + #ifdef BLARGG_PALETTE + myCurrentAdjustable = (myCurrentAdjustable + 1) % 10; + #else + myCurrentAdjustable = (myCurrentAdjustable + 1) % 5; + #endif + } + else + { + #ifdef BLARGG_PALETTE + if(myCurrentAdjustable == 0) myCurrentAdjustable = 9; + #else + if(myCurrentAdjustable == 0) myCurrentAdjustable = 4; + #endif + else --myCurrentAdjustable; + } -#ifdef BLARGG_PALETTE - myCurrentAdjustable = (myCurrentAdjustable + 1) % 10; -#else - myCurrentAdjustable = (myCurrentAdjustable + 1) % 5; -#endif - - ostringstream buf; - buf << "Custom adjustable '" << ourCustomAdjustables[myCurrentAdjustable].type - << "' selected (" - << scaleTo100(*ourCustomAdjustables[myCurrentAdjustable].value) << "%)"; - - return buf.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string NTSCFilter::setPreviousAdjustable() -{ - //if(myPreset != Preset::CUSTOM) - // return "'Custom' TV mode not selected"; - -#ifdef BLARGG_PALETTE - if(myCurrentAdjustable == 0) myCurrentAdjustable = 9; -#else - if(myCurrentAdjustable == 0) myCurrentAdjustable = 4; -#endif - else --myCurrentAdjustable; - ostringstream buf; - buf << "Custom adjustable '" << ourCustomAdjustables[myCurrentAdjustable].type - << "' selected (" - << scaleTo100(*ourCustomAdjustables[myCurrentAdjustable].value) << "%)"; - - return buf.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void NTSCFilter::changeAdjustable(bool increase, string& text, string& valueText, Int32& value) -{ - //if(myPreset != Preset::CUSTOM) - // return "'Custom' TV mode not selected"; + ostringstream msg, val; value = scaleTo100(*ourCustomAdjustables[myCurrentAdjustable].value); - value = BSPF::clamp(value + (increase ? 2 : -2), 0, 100); + msg << "Custom " << ourCustomAdjustables[myCurrentAdjustable].type; + val << value << "%"; - *ourCustomAdjustables[myCurrentAdjustable].value = scaleFrom100(value); + text = msg.str(); + valueText = val.str(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void NTSCFilter::changeAdjustable(bool increase, string& text, string& valueText, Int32& newValue) +{ + //if(myPreset != Preset::CUSTOM) + // return "'Custom' TV mode not selected"; + + newValue = scaleTo100(*ourCustomAdjustables[myCurrentAdjustable].value); + newValue = BSPF::clamp(newValue + (increase ? 2 : -2), 0, 100); + + *ourCustomAdjustables[myCurrentAdjustable].value = scaleFrom100(newValue); setPreset(myPreset); ostringstream msg, val; + msg << "Custom " << ourCustomAdjustables[myCurrentAdjustable].type; - val << value << "%"; + val << newValue << "%"; text = msg.str(); valueText = val.str(); diff --git a/src/common/tv_filters/NTSCFilter.hxx b/src/common/tv_filters/NTSCFilter.hxx index c4fe30f15..6ccdcd155 100644 --- a/src/common/tv_filters/NTSCFilter.hxx +++ b/src/common/tv_filters/NTSCFilter.hxx @@ -90,9 +90,8 @@ class NTSCFilter // Changes are made this way since otherwise 20 key-combinations // would be needed to dynamically change each setting, and now // only 4 combinations are necessary - string setNextAdjustable(); - string setPreviousAdjustable(); - void changeAdjustable(bool increase, string& text, string& valueText, Int32& value); + void selectAdjustable(bool next, string& text, string& valueText, Int32& value); + void changeAdjustable(bool increase, string& text, string& valueText, Int32& newValue); // Load and save NTSC-related settings void loadConfig(const Settings& settings); diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 82fd4280c..d83a44aa0 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -496,6 +496,22 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::CUSTOM); return; + case Event::PreviousAttribute: + if (pressed) myOSystem.frameBuffer().tiaSurface().setNTSCAdjustable(false); + return; + + case Event::NextAttribute: + if (pressed) myOSystem.frameBuffer().tiaSurface().setNTSCAdjustable(true); + return; + + case Event::DecreaseAttribute: + if(pressed) myOSystem.frameBuffer().tiaSurface().changeNTSCAdjustable(false); + return; + + case Event::IncreaseAttribute: + if(pressed) myOSystem.frameBuffer().tiaSurface().changeNTSCAdjustable(true); + return; + case Event::ScanlinesDecrease: if (pressed) myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(-2); return; @@ -504,48 +520,6 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) if (pressed) myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(+2); return; - case Event::PreviousAttribute: - if (pressed) - { - myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::CUSTOM); - myOSystem.frameBuffer().showMessage( - myOSystem.frameBuffer().tiaSurface().ntsc().setPreviousAdjustable()); - } - return; - - case Event::NextAttribute: - if (pressed) - { - myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::CUSTOM); - myOSystem.frameBuffer().showMessage( - myOSystem.frameBuffer().tiaSurface().ntsc().setNextAdjustable()); - } - return; - - case Event::DecreaseAttribute: - if (pressed) - { - string text, valueText; - Int32 newVal; - - myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::CUSTOM); - myOSystem.frameBuffer().tiaSurface().ntsc().changeAdjustable(false, text, valueText, newVal); - myOSystem.frameBuffer().showMessage(text, valueText, newVal); - } - return; - - case Event::IncreaseAttribute: - if (pressed) - { - string text, valueText; - Int32 newVal; - - myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::CUSTOM); - myOSystem.frameBuffer().tiaSurface().ntsc().changeAdjustable(true, text, valueText, newVal); - myOSystem.frameBuffer().showMessage(text, valueText, newVal); - } - return; - case Event::PhosphorDecrease: if (pressed) myOSystem.console().changePhosphor(false); return; diff --git a/src/emucore/TIASurface.cxx b/src/emucore/TIASurface.cxx index 53060a97e..307863e8e 100644 --- a/src/emucore/TIASurface.cxx +++ b/src/emucore/TIASurface.cxx @@ -225,6 +225,29 @@ void TIASurface::changeNTSC(bool next, bool show) setNTSC(PRESETS[preset], show); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIASurface::setNTSCAdjustable(bool next) +{ + string text, valueText; + Int32 value; + + setNTSC(NTSCFilter::Preset::CUSTOM); + ntsc().selectAdjustable(next, text, valueText, value); + myOSystem.frameBuffer().showMessage(text, valueText, value); + +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIASurface::changeNTSCAdjustable(bool increase) +{ + string text, valueText; + Int32 newValue; + + setNTSC(NTSCFilter::Preset::CUSTOM); + ntsc().changeAdjustable(increase, text, valueText, newValue); + myOSystem.frameBuffer().showMessage(text, valueText, newValue); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIASurface::setScanlineIntensity(int amount) { diff --git a/src/emucore/TIASurface.hxx b/src/emucore/TIASurface.hxx index b2c00f912..90aeacb14 100644 --- a/src/emucore/TIASurface.hxx +++ b/src/emucore/TIASurface.hxx @@ -94,6 +94,16 @@ class TIASurface */ void changeNTSC(bool next, bool show = true); + /** + Switch to next/previous NTSC filtering adjustable. + */ + void setNTSCAdjustable(bool next = true); + + /** + Increase/decrease current NTSC filtering adjustable. + */ + void changeNTSCAdjustable(bool increase = true); + /** Retrieve palette handler. */ From d08eb6262e2e9165f415d9ff33fa1cbeabca95bb Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 14 May 2020 11:12:56 +0200 Subject: [PATCH 217/377] a little bit of polishing --- src/common/PKeyboardHandler.cxx | 4 +-- src/common/SoundSDL2.cxx | 5 ++- src/emucore/CartEnhanced.cxx | 32 +++++++++---------- src/emucore/Console.cxx | 11 +++++-- src/emucore/Console.hxx | 2 +- src/emucore/Event.hxx | 2 +- src/emucore/EventHandler.cxx | 55 ++++++++++++++------------------- src/emucore/FrameBuffer.cxx | 5 +++ src/emucore/TIASurface.cxx | 5 ++- 9 files changed, 66 insertions(+), 55 deletions(-) diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index e30bff52f..fc2c78722 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -460,8 +460,8 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo {Event::VidmodeIncrease, KBDK_EQUALS, MOD3}, {Event::VCenterDecrease, KBDK_PAGEUP, MOD3}, {Event::VCenterIncrease, KBDK_PAGEDOWN, MOD3}, - {Event::ScanlineAdjustDecrease, KBDK_PAGEDOWN, KBDM_SHIFT | MOD3}, - {Event::ScanlineAdjustIncrease, KBDK_PAGEUP, KBDM_SHIFT | MOD3}, + {Event::VSizeAdjustDecrease, KBDK_PAGEDOWN, KBDM_SHIFT | MOD3}, + {Event::VSizeAdjustIncrease, KBDK_PAGEUP, KBDM_SHIFT | MOD3}, {Event::VolumeDecrease, KBDK_LEFTBRACKET, MOD3}, {Event::VolumeIncrease, KBDK_RIGHTBRACKET, MOD3}, {Event::SoundToggle, KBDK_RIGHTBRACKET, KBDM_CTRL}, diff --git a/src/common/SoundSDL2.cxx b/src/common/SoundSDL2.cxx index c32189e95..85489abb5 100644 --- a/src/common/SoundSDL2.cxx +++ b/src/common/SoundSDL2.cxx @@ -238,7 +238,10 @@ void SoundSDL2::adjustVolume(Int8 direction) } // Now show an onscreen message - strval << percent << "%"; + if(percent) + strval << percent << "%"; + else + strval << "Off"; myOSystem.frameBuffer().showMessage("Volume", strval.str(), percent); } diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index 496a4d051..27fa425b5 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -35,7 +35,7 @@ CartridgeEnhanced::CartridgeEnhanced(const ByteBuffer& image, size_t size, void CartridgeEnhanced::install(System& system) { // limit banked RAM size to the size of one RAM bank - uInt32 ramSize = myRamBankCount > 0 ? 1 << (myBankShift - 1) : uInt32(myRamSize); + const uInt32 ramSize = myRamBankCount > 0 ? 1 << (myBankShift - 1) : uInt32(myRamSize); // calculate bank switching and RAM sizes and masks myBankSize = 1 << myBankShift; // e.g. = 2 ^ 12 = 4K = 0x1000 @@ -71,7 +71,7 @@ void CartridgeEnhanced::install(System& system) access.type = System::PageAccessType::WRITE; for(uInt16 addr = ROM_OFFSET + myWriteOffset; addr < ROM_OFFSET + myWriteOffset + myRamSize; addr += System::PAGE_SIZE) { - uInt16 offset = addr & myRamMask; + const uInt16 offset = addr & myRamMask; access.directPokeBase = &myRAM[offset]; access.romAccessBase = &myRomAccessBase[myWriteOffset + offset]; @@ -85,7 +85,7 @@ void CartridgeEnhanced::install(System& system) access.directPokeBase = nullptr; for(uInt16 addr = ROM_OFFSET + myReadOffset; addr < ROM_OFFSET + myReadOffset + myRamSize; addr += System::PAGE_SIZE) { - uInt16 offset = addr & myRamMask; + const uInt16 offset = addr & myRamMask; access.directPeekBase = &myRAM[offset]; access.romAccessBase = &myRomAccessBase[myReadOffset + offset]; @@ -117,7 +117,7 @@ void CartridgeEnhanced::reset() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeEnhanced::peek(uInt16 address) { - uInt16 peekAddress = address; + const uInt16 peekAddress = address; // hotspots in TIA range are reacting to pokes only if (hotspot() >= 0x80) @@ -157,7 +157,7 @@ bool CartridgeEnhanced::poke(uInt16 address, uInt8 value) if(myRamSize > 0) { // Code should never get here (System::PageAccess::directPoke() handles this) - uInt16 pokeAddress = address; + const uInt16 pokeAddress = address; if(isRamBank(address)) { @@ -193,20 +193,20 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) { if(bankLocked()) return false; - uInt16 segmentOffset = segment << myBankShift; + const uInt16 segmentOffset = segment << myBankShift; if(myRamBankCount == 0 || bank < romBankCount()) { // Setup ROM bank - uInt16 romBank = bank % romBankCount(); + const uInt16 romBank = bank % romBankCount(); // Remember what bank is in this segment - uInt32 bankOffset = myCurrentSegOffset[segment] = romBank << myBankShift; - uInt16 hotspot = this->hotspot(); + const uInt32 bankOffset = myCurrentSegOffset[segment] = romBank << myBankShift; + const uInt16 hotspot = this->hotspot(); uInt16 hotSpotAddr; // Skip extra RAM; if existing it is only mapped into first segment - uInt16 fromAddr = (ROM_OFFSET + segmentOffset + (segment == 0 ? myRomOffset : 0)) & ~System::PAGE_MASK; + const uInt16 fromAddr = (ROM_OFFSET + segmentOffset + (segment == 0 ? myRomOffset : 0)) & ~System::PAGE_MASK; // for ROMs < 4_KB, the whole address space will be mapped. - uInt16 toAddr = (ROM_OFFSET + segmentOffset + (mySize < 4_KB ? 4_KB : myBankSize)) & ~System::PAGE_MASK; + const uInt16 toAddr = (ROM_OFFSET + segmentOffset + (mySize < 4_KB ? 4_KB : myBankSize)) & ~System::PAGE_MASK; if(hotspot & 0x1000) hotSpotAddr = (hotspot & ~System::PAGE_MASK); @@ -217,7 +217,7 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) // Setup the page access methods for the current bank for(uInt16 addr = fromAddr; addr < toAddr; addr += System::PAGE_SIZE) { - uInt32 offset = bankOffset + (addr & myBankMask); + const uInt32 offset = bankOffset + (addr & myBankMask); if(myDirectPeek && addr != hotSpotAddr) access.directPeekBase = &myImage[offset]; @@ -232,9 +232,9 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) else { // Setup RAM bank - uInt16 ramBank = (bank - romBankCount()) % myRamBankCount; + const uInt16 ramBank = (bank - romBankCount()) % myRamBankCount; // The RAM banks follow the ROM banks and are half the size of a ROM bank - uInt32 bankOffset = uInt32(mySize) + (ramBank << (myBankShift - 1)); + const uInt32 bankOffset = uInt32(mySize) + (ramBank << (myBankShift - 1)); // Remember what bank is in this segment myCurrentSegOffset[segment] = uInt32(mySize) + (ramBank << myBankShift); @@ -246,7 +246,7 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) for(uInt16 addr = fromAddr; addr < toAddr; addr += System::PAGE_SIZE) { - uInt32 offset = bankOffset + (addr & myRamMask); + const uInt32 offset = bankOffset + (addr & myRamMask); access.directPokeBase = &myRAM[offset - mySize]; access.romAccessBase = &myRomAccessBase[offset]; @@ -263,7 +263,7 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) for(uInt16 addr = fromAddr; addr < toAddr; addr += System::PAGE_SIZE) { - uInt32 offset = bankOffset + (addr & myRamMask); + const uInt32 offset = bankOffset + (addr & myRamMask); access.directPeekBase = &myRAM[offset - mySize]; access.romAccessBase = &myRomAccessBase[offset]; diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 33b7520be..5af3d1077 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -534,7 +534,14 @@ void Console::changePhosphor(bool increase) ostringstream val; val << blend; myProperties.set(PropType::Display_PPBlend, val.str()); - myOSystem.frameBuffer().showMessage("Phosphor blend", val.str() + "%", blend); + if(blend) + val << "%"; + else + { + val.str(""); + val << "Off"; + } + myOSystem.frameBuffer().showMessage("Phosphor blend", val.str(), blend); myOSystem.frameBuffer().tiaSurface().enablePhosphor(true, blend); } @@ -643,7 +650,7 @@ void Console::updateVcenter(Int32 vcenter) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::changeScanlineAdjust(bool increase) +void Console::changeVSizeAdjust(bool increase) { Int32 newAdjustVSize = myTIA->adjustVSize(); diff --git a/src/emucore/Console.hxx b/src/emucore/Console.hxx index 685297b55..15173b48d 100644 --- a/src/emucore/Console.hxx +++ b/src/emucore/Console.hxx @@ -268,7 +268,7 @@ class Console : public Serializable, public ConsoleIO @param increase Increase if true, else decrease */ - void changeScanlineAdjust(bool increase = true); + void changeVSizeAdjust(bool increase = true); /** Returns the current framerate. diff --git a/src/emucore/Event.hxx b/src/emucore/Event.hxx index fba15b6fb..0c84225ed 100644 --- a/src/emucore/Event.hxx +++ b/src/emucore/Event.hxx @@ -104,7 +104,7 @@ class Event PreviousPaletteAttribute, NextPaletteAttribute, PaletteAttributeDecrease, PaletteAttributeIncrease, ToggleFullScreen, VidmodeDecrease, VidmodeIncrease, - VCenterDecrease, VCenterIncrease, ScanlineAdjustDecrease, ScanlineAdjustIncrease, + VCenterDecrease, VCenterIncrease, VSizeAdjustDecrease, VSizeAdjustIncrease, OverscanDecrease, OverscanIncrease, VidmodeStd, VidmodeRGB, VidmodeSVideo, VidModeComposite, VidModeBad, VidModeCustom, diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index d83a44aa0..2dbc5e217 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -345,7 +345,7 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) { // Take care of special events that aren't part of the emulation core // or need to be preprocessed before passing them on - bool pressed = (value != 0); + const bool pressed = (value != 0); switch(event) { @@ -428,12 +428,12 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) if (pressed) myOSystem.console().changeVerticalCenter(true); return; - case Event::ScanlineAdjustDecrease: - if (pressed) myOSystem.console().changeScanlineAdjust(false); + case Event::VSizeAdjustDecrease: + if (pressed) myOSystem.console().changeVSizeAdjust(false); return; - case Event::ScanlineAdjustIncrease: - if (pressed) myOSystem.console().changeScanlineAdjust(true); + case Event::VSizeAdjustIncrease: + if (pressed) myOSystem.console().changeVSizeAdjust(true); return; case Event::PreviousPaletteAttribute: @@ -592,14 +592,7 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) case Event::ToggleGrabMouse: if (pressed && !repeated && !myOSystem.frameBuffer().fullScreen()) - { - bool oldState = myOSystem.frameBuffer().grabMouseEnabled(); myOSystem.frameBuffer().toggleGrabMouse(); - bool newState = myOSystem.frameBuffer().grabMouseEnabled(); - myOSystem.frameBuffer().showMessage(oldState != newState ? myOSystem.frameBuffer().grabMouseEnabled() - ? "Grab mouse enabled" : "Grab mouse disabled" - : "Grab mouse not allowed while cursor shown"); - } return; case Event::ToggleP0Collision: @@ -760,7 +753,7 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) if (myOSystem.settings().getBool("confirmexit")) { StringList msg; - string saveOnExit = myOSystem.settings().getString("saveonexit"); + const string saveOnExit = myOSystem.settings().getString("saveonexit"); bool activeTM = myOSystem.settings().getBool( myOSystem.settings().getBool("dev.settings") ? "dev.timemachine" : "plr.timemachine"); @@ -1085,12 +1078,12 @@ void EventHandler::setActionMappings(EventMode mode) // Fill the EmulActionList with the current key and joystick mappings for(auto& item: ourEmulActionList) { - Event::Type event = item.event; + const Event::Type event = item.event; item.key = "None"; string key = myPKeyHandler->getMappingDesc(event, mode); #ifdef JOYSTICK_SUPPORT - string joydesc = myPJoyHandler->getMappingDesc(event, mode); + const string joydesc = myPJoyHandler->getMappingDesc(event, mode); if(joydesc != "") { if(key != "") @@ -1107,12 +1100,12 @@ void EventHandler::setActionMappings(EventMode mode) // Fill the MenuActionList with the current key and joystick mappings for(auto& item: ourMenuActionList) { - Event::Type event = item.event; + const Event::Type event = item.event; item.key = "None"; string key = myPKeyHandler->getMappingDesc(event, mode); #ifdef JOYSTICK_SUPPORT - string joydesc = myPJoyHandler->getMappingDesc(event, mode); + const string joydesc = myPJoyHandler->getMappingDesc(event, mode); if(joydesc != "") { if(key != "") @@ -1138,7 +1131,7 @@ void EventHandler::setComboMap() string list = myOSystem.settings().getString("combomap"); replace(list.begin(), list.end(), ':', ' '); istringstream buf(list); - Int32 version = myOSystem.settings().getInt("event_ver"); + const Int32 version = myOSystem.settings().getInt("event_ver"); // Erase the 'combo' array auto ERASE_ALL = [&]() { @@ -1200,7 +1193,7 @@ void EventHandler::removePhysicalJoystickFromDatabase(const string& name) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EventHandler::addKeyMapping(Event::Type event, EventMode mode, StellaKey key, StellaMod mod) { - bool mapped = myPKeyHandler->addMapping(event, mode, key, mod); + const bool mapped = myPKeyHandler->addMapping(event, mode, key, mod); if(mapped) setActionMappings(mode); @@ -1213,7 +1206,7 @@ bool EventHandler::addJoyMapping(Event::Type event, EventMode mode, bool updateMenus) { #ifdef JOYSTICK_SUPPORT - bool mapped = myPJoyHandler->addJoyMapping(event, mode, stick, button, axis, adir); + const bool mapped = myPJoyHandler->addJoyMapping(event, mode, stick, button, axis, adir); if (mapped && updateMenus) setActionMappings(mode); @@ -1411,7 +1404,7 @@ VariantList EventHandler::getComboList(EventMode /**/) const VarList::push_back(l, "None", "-1"); for(uInt32 i = 0; i < ourEmulActionList.size(); ++i) { - Event::Type event = EventHandler::ourEmulActionList[i].event; + const Event::Type event = EventHandler::ourEmulActionList[i].event; // exclude combos events if(!(event >= Event::Combo1 && event <= Event::Combo16)) { @@ -1433,7 +1426,7 @@ StringList EventHandler::getComboListForEvent(Event::Type event) const int combo = event - Event::Combo1; for(uInt32 i = 0; i < EVENTS_PER_COMBO; ++i) { - Event::Type e = myComboTable[combo][i]; + const Event::Type e = myComboTable[combo][i]; for(uInt32 j = 0; j < ourEmulActionList.size(); ++j) { if(EventHandler::ourEmulActionList[j].event == e) @@ -1457,7 +1450,7 @@ void EventHandler::setComboListForEvent(Event::Type event, const StringList& eve if(event >= Event::Combo1 && event <= Event::Combo16) { assert(events.size() == 8); - int combo = event - Event::Combo1; + const int combo = event - Event::Combo1; for(uInt32 i = 0; i < 8; ++i) { uInt32 idx = BSPF::stringToInt(events[i]); @@ -1544,7 +1537,7 @@ int EventHandler::getActionListIndex(int idx, Event::Group group) const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Event::Type EventHandler::eventAtIndex(int idx, Event::Group group) const { - int index = getActionListIndex(idx, group); + const int index = getActionListIndex(idx, group); if(group == Event::Group::Menu) { @@ -1565,7 +1558,7 @@ Event::Type EventHandler::eventAtIndex(int idx, Event::Group group) const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string EventHandler::actionAtIndex(int idx, Event::Group group) const { - int index = getActionListIndex(idx, group); + const int index = getActionListIndex(idx, group); if(group == Event::Group::Menu) { @@ -1586,7 +1579,7 @@ string EventHandler::actionAtIndex(int idx, Event::Group group) const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string EventHandler::keyAtIndex(int idx, Event::Group group) const { - int index = getActionListIndex(idx, group); + const int index = getActionListIndex(idx, group); if(group == Event::Group::Menu) { @@ -1797,8 +1790,8 @@ void EventHandler::setState(EventHandlerState state) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::exitEmulation(bool checkLauncher) { - string saveOnExit = myOSystem.settings().getString("saveonexit"); - bool activeTM = myOSystem.settings().getBool( + const string saveOnExit = myOSystem.settings().getString("saveonexit"); + const bool activeTM = myOSystem.settings().getBool( myOSystem.settings().getBool("dev.settings") ? "dev.timemachine" : "plr.timemachine"); @@ -1924,8 +1917,8 @@ EventHandler::EmulActionList EventHandler::ourEmulActionList = { { { Event::OverscanIncrease, "Increase overscan in fullscreen mode", "" }, { Event::VidmodeDecrease, "Previous zoom level", "" }, { Event::VidmodeIncrease, "Next zoom level", "" }, - { Event::ScanlineAdjustDecrease, "Decrease vertical display size", "" }, - { Event::ScanlineAdjustIncrease, "Increase vertical display size", "" }, + { Event::VSizeAdjustDecrease, "Decrease vertical display size", "" }, + { Event::VSizeAdjustIncrease, "Increase vertical display size", "" }, { Event::VCenterDecrease, "Move display up", "" }, { Event::VCenterIncrease, "Move display down", "" }, { Event::FormatDecrease, "Decrease display format", "" }, @@ -2064,7 +2057,7 @@ const Event::EventSet EventHandler::AudioVideoEvents = { Event::PhosphorDecrease, Event::PhosphorIncrease, Event::TogglePhosphor, Event::FormatDecrease, Event::FormatIncrease, Event::VCenterDecrease, Event::VCenterIncrease, - Event::ScanlineAdjustDecrease, Event::ScanlineAdjustIncrease, + Event::VSizeAdjustDecrease, Event::VSizeAdjustIncrease, Event::OverscanDecrease, Event::OverscanIncrease, Event::PaletteDecrease, Event::PaletteIncrease, Event::PreviousVideoMode, Event::NextVideoMode, diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 254060054..cd7e2e57c 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -1106,9 +1106,14 @@ void FrameBuffer::enableGrabMouse(bool enable) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::toggleGrabMouse() { + const bool oldState = myGrabMouse; + myGrabMouse = !myGrabMouse; setCursorState(); myOSystem.settings().setValue("grabmouse", myGrabMouse); + myOSystem.frameBuffer().showMessage(oldState != myGrabMouse ? myGrabMouse + ? "Grab mouse enabled" : "Grab mouse disabled" + : "Grab mouse not allowed while cursor shown"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/TIASurface.cxx b/src/emucore/TIASurface.cxx index 307863e8e..98adb4bd4 100644 --- a/src/emucore/TIASurface.cxx +++ b/src/emucore/TIASurface.cxx @@ -257,7 +257,10 @@ void TIASurface::setScanlineIntensity(int amount) myOSystem.settings().setValue("tv.scanlines", intensity); enableNTSC(ntscEnabled()); - buf << intensity << "%"; + if(intensity) + buf << intensity << "%"; + else + buf << "Off"; myFB.showMessage("Scanline intensity", buf.str(), intensity); } From 521edb5adee52e613d38f9ffc04dab763ce9d5e8 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 14 May 2020 21:18:55 +0200 Subject: [PATCH 218/377] added global hotkeys (pageup/down) for current displayed setting (or volume) --- docs/index.html | 18 +++++ src/common/PKeyboardHandler.cxx | 3 + src/common/PaletteHandler.cxx | 12 ++- src/common/PaletteHandler.hxx | 9 ++- src/common/SoundNull.hxx | 6 +- src/common/SoundSDL2.cxx | 31 +++++--- src/common/SoundSDL2.hxx | 8 +- src/common/StateManager.cxx | 17 ++-- src/common/StateManager.hxx | 6 +- src/common/bspf.hxx | 3 + src/emucore/Console.cxx | 17 ++-- src/emucore/Console.hxx | 10 +-- src/emucore/Event.hxx | 1 + src/emucore/EventHandler.cxx | 137 +++++++++++++++++++++++--------- src/emucore/EventHandler.hxx | 4 +- src/emucore/FrameBuffer.cxx | 36 ++++++--- src/emucore/FrameBuffer.hxx | 16 ++-- src/emucore/Sound.hxx | 6 +- src/emucore/TIASurface.cxx | 16 ++-- src/emucore/TIASurface.hxx | 8 +- src/libretro/SoundLIBRETRO.hxx | 6 +- 21 files changed, 252 insertions(+), 118 deletions(-) diff --git a/docs/index.html b/docs/index.html index 246b84390..5c5204863 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1767,6 +1767,24 @@ + + + + + + + + + + + + + + +
      Key (macOS)
      Disable TV effectsSelect previous TV effects presetShift-Alt + 1Shift-Cmd + 1
      Select next TV effects preset Alt + 1 Cmd + 1
      Select 'RGB' presetSelect previous 'Custom' mode attribute (*)Shift-Alt + 2Shift-Cmd + 2
      Select next 'Custom' mode attribute (*) Alt + 2 Cmd + 2
      Select 'S-Video' presetAlt + 3Cmd + 3
      Select 'Composite' presetAlt + 4Cmd + 4
      Select 'Badly adjusted' presetAlt + 5Cmd + 5
      Select 'Custom' presetAlt + 6Cmd + 6
      Select previous 'Custom' mode attribute (*)Shift-Alt + 7Shift-Cmd + 7
      Select next 'Custom' mode attribute (*)Alt + 7Cmd + 7
      Decrease 'Custom' selected attribute value (*)Shift-Alt + 8Shift-Cmd + 8Shift-Alt + 3Shift-Cmd + 3
      Increase 'Custom' selected attribute value (*)Alt + 8Cmd + 8Alt + 3Cmd + 3
      Decrease 'phosphor' blendShift-Alt + 9Shift-Cmd + 9Shift-Alt + 4Shift-Cmd + 4
      Increase 'phosphor' blendAlt + 9Cmd + 9Alt + 4Cmd + 4
      Decrease scanline intensityShift-Alt + 0Shift-Cmd + 0Shift-Alt + 5Shift-Cmd + 5
      Increase scanline intensityAlt + 0Cmd + 0Alt + 5Cmd + 5
      Control + f
      Switch palette (Standard/Z26/User/Custom)Control + pControl + p
      Decrease 'Custom' palette's phase shiftShift-Control + 9Shift-Control + 9
      Increase 'Custom' palette's phase shiftControl + 9Control + 9
      Toggle display interpolation Control + iAlt + Up arrow Cmd + Up arrow
      Decrease current setting (*)PageDownPageDown
      Increase current setting (*) + PageUpPageUp
      + (*) Note: These keys allow easy changing of the current displayed selection (e.g. volume (default), + phosphor, zoom...) without having to use the original keys.

      UI keys in Text Editing areas (cannot be remapped)

      diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index fc2c78722..95cef05e8 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -493,11 +493,14 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo {Event::ToggleColorLoss, KBDK_L, KBDM_CTRL}, {Event::PaletteDecrease, KBDK_P, KBDM_SHIFT | KBDM_CTRL}, {Event::PaletteIncrease, KBDK_P, KBDM_CTRL}, + {Event::SettingDecrease, KBDK_PAGEDOWN}, + {Event::SettingIncrease, KBDK_PAGEUP}, {Event::ToggleInter, KBDK_I, KBDM_CTRL}, {Event::ToggleTurbo, KBDK_T, KBDM_CTRL}, {Event::ToggleJitter, KBDK_J, MOD3}, {Event::ToggleFrameStats, KBDK_L, MOD3}, {Event::ToggleTimeMachine, KBDK_T, MOD3}, + #ifdef PNG_SUPPORT {Event::ToggleContSnapshots, KBDK_S, MOD3}, {Event::ToggleContSnapshotsFrame, KBDK_S, KBDM_SHIFT | MOD3}, diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index f040fe8e5..2c04ccd3b 100644 --- a/src/common/PaletteHandler.cxx +++ b/src/common/PaletteHandler.cxx @@ -55,7 +55,7 @@ string PaletteHandler::toPaletteName(PaletteType type) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PaletteHandler::cyclePalette(bool next) +AdjustFunction PaletteHandler::cyclePalette(bool next) { const string MESSAGES[PaletteType::NumTypes] = { "Standard Stella", "Z26", "User-defined", "Custom" @@ -89,6 +89,7 @@ void PaletteHandler::cyclePalette(bool next) myOSystem.frameBuffer().showMessage(message); setPalette(palette); + return std::bind(&PaletteHandler::cyclePalette, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -112,12 +113,13 @@ void PaletteHandler::showAdjustableMessage() { const int value = scaleTo100(*myAdjustables[myCurrentAdjustable].value); buf << value << "%"; - myOSystem.frameBuffer().showMessage(msg.str(), buf.str(), value); + myOSystem.frameBuffer().showMessage( + msg.str(), buf.str(), value); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PaletteHandler::cycleAdjustable(bool next) +AdjustFunction PaletteHandler::cycleAdjustable(bool next) { const bool isCustomPalette = SETTING_CUSTOM == myOSystem.settings().getString("palette"); bool isPhaseShift; @@ -141,10 +143,11 @@ void PaletteHandler::cycleAdjustable(bool next) } while(isPhaseShift && !isCustomPalette); showAdjustableMessage(); + return std::bind(&PaletteHandler::changeAdjustable, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PaletteHandler::changeAdjustable(bool increase) +AdjustFunction PaletteHandler::changeAdjustable(bool increase) { if(myAdjustables[myCurrentAdjustable].value == nullptr) changeColorPhaseShift(increase); @@ -163,6 +166,7 @@ void PaletteHandler::changeAdjustable(bool increase) showAdjustableMessage(); setPalette(); } + return std::bind(&PaletteHandler::changeAdjustable, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/PaletteHandler.hxx b/src/common/PaletteHandler.hxx index e8e083a8a..7a4b8676d 100644 --- a/src/common/PaletteHandler.hxx +++ b/src/common/PaletteHandler.hxx @@ -21,6 +21,7 @@ #include "bspf.hxx" #include "OSystem.hxx" #include "ConsoleTiming.hxx" +#include "EventHandlerConstants.hxx" class PaletteHandler { @@ -51,21 +52,21 @@ class PaletteHandler @param next Select next palette, else previous one */ - void cyclePalette(bool next = true); + AdjustFunction cyclePalette(bool next = true); /* Cycle through each palette adjustable. @param next Select next adjustable, else previous one */ - void cycleAdjustable(bool next = true); + AdjustFunction cycleAdjustable(bool next = true); /* Increase or decrease current palette adjustable. @param increase Increase adjustable if true, else decrease */ - void changeAdjustable(bool increase = true); + AdjustFunction changeAdjustable(bool increase = true); // Load adjustables from settings void loadConfig(const Settings& settings); @@ -129,7 +130,7 @@ class PaletteHandler string toPaletteName(PaletteType type) const; /** - Display current adjustable with bar gauge message + Display current adjustable with gauge bar message */ void showAdjustableMessage(); diff --git a/src/common/SoundNull.hxx b/src/common/SoundNull.hxx index f2aafbff8..ef07090a3 100644 --- a/src/common/SoundNull.hxx +++ b/src/common/SoundNull.hxx @@ -97,10 +97,10 @@ class SoundNull : public Sound /** Adjusts the volume of the sound device based on the given direction. - @param direction Increase or decrease the current volume by a predefined - amount based on the direction (1 = increase, -1 =decrease) + @param increase Increase or decrease the current volume by a predefined + amount */ - void adjustVolume(Int8 direction) override { } + AdjustFunction adjustVolume(bool increase) override { return nullptr; } /** This method is called to provide information about the sound device. diff --git a/src/common/SoundSDL2.cxx b/src/common/SoundSDL2.cxx index 85489abb5..234e4aae7 100644 --- a/src/common/SoundSDL2.cxx +++ b/src/common/SoundSDL2.cxx @@ -186,16 +186,31 @@ bool SoundSDL2::mute(bool state) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool SoundSDL2::toggleMute() { - bool enabled = myAudioSettings.enabled(); + bool enabled = !myAudioSettings.enabled(); - setEnabled(!enabled); + setEnabled(enabled); myOSystem.console().initializeAudio(); string message = "Sound "; - message += !enabled ? "unmuted" : "muted"; + message += enabled ? "unmuted" : "muted"; myOSystem.frameBuffer().showMessage(message); + //ostringstream strval; + //uInt32 volume; + //// Now show an onscreen message + //if(enabled) + //{ + // volume = myVolume; + // strval << volume << "%"; + //} + //else + //{ + // volume = 0; + // strval << "Muted"; + //} + //myOSystem.frameBuffer().showMessage("Volume", strval.str(), volume); + return enabled; } @@ -214,17 +229,12 @@ void SoundSDL2::setVolume(uInt32 percent) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void SoundSDL2::adjustVolume(Int8 direction) +AdjustFunction SoundSDL2::adjustVolume(bool increase) { ostringstream strval; - Int32 percent = myVolume; - if(direction == -1) - percent -= 2; - else if(direction == 1) - percent += 2; - percent = BSPF::clamp(percent, 0, 100); + percent = BSPF::clamp(percent += increase ? 2 : -2, 0, 100); setVolume(percent); @@ -243,6 +253,7 @@ void SoundSDL2::adjustVolume(Int8 direction) else strval << "Off"; myOSystem.frameBuffer().showMessage("Volume", strval.str(), percent); + return std::bind(&SoundSDL2::adjustVolume, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/SoundSDL2.hxx b/src/common/SoundSDL2.hxx index 613e6980d..bea035dd3 100644 --- a/src/common/SoundSDL2.hxx +++ b/src/common/SoundSDL2.hxx @@ -98,10 +98,10 @@ class SoundSDL2 : public Sound /** Adjusts the volume of the sound device based on the given direction. - @param direction Increase or decrease the current volume by a predefined - amount based on the direction (1 = increase, -1 = decrease) - */ - void adjustVolume(Int8 direction) override; + @param increase Increase or decrease the current volume by a predefined + amount + */ + AdjustFunction adjustVolume(bool increase) override; /** This method is called to provide information about the sound device. diff --git a/src/common/StateManager.cxx b/src/common/StateManager.cxx index 667665054..016b7a97a 100644 --- a/src/common/StateManager.cxx +++ b/src/common/StateManager.cxx @@ -198,7 +198,7 @@ void StateManager::update() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void StateManager::loadState(int slot) +AdjustFunction StateManager::loadState(int slot) { if(myOSystem.hasConsole()) { @@ -216,7 +216,7 @@ void StateManager::loadState(int slot) buf.str(""); buf << "Can't open/load from state file " << slot; myOSystem.frameBuffer().showMessage(buf.str()); - return; + return nullptr; } // First test if we have a valid header @@ -241,10 +241,11 @@ void StateManager::loadState(int slot) myOSystem.frameBuffer().showMessage(buf.str()); } + return std::bind(&StateManager::changeState, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void StateManager::saveState(int slot) +AdjustFunction StateManager::saveState(int slot) { if(myOSystem.hasConsole()) { @@ -262,7 +263,7 @@ void StateManager::saveState(int slot) buf.str(""); buf << "Can't open/save to state file " << slot; myOSystem.frameBuffer().showMessage(buf.str()); - return; + return nullptr; } try @@ -275,7 +276,7 @@ void StateManager::saveState(int slot) { buf << "Error saving state " << slot; myOSystem.frameBuffer().showMessage(buf.str()); - return; + return nullptr; } // Do a complete state save using the Console @@ -294,12 +295,13 @@ void StateManager::saveState(int slot) myOSystem.frameBuffer().showMessage(buf.str()); } + return std::bind(&StateManager::changeState, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void StateManager::changeState(int direction) +AdjustFunction StateManager::changeState(bool next) { - myCurrentSlot += direction; + myCurrentSlot += next ? 1 : -1; if (myCurrentSlot < 0) myCurrentSlot = 9; else @@ -309,6 +311,7 @@ void StateManager::changeState(int direction) ostringstream buf; buf << "Changed to slot " << myCurrentSlot; myOSystem.frameBuffer().showMessage(buf.str()); + return std::bind(&StateManager::changeState, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/StateManager.hxx b/src/common/StateManager.hxx index 09de785fb..3739b8c31 100644 --- a/src/common/StateManager.hxx +++ b/src/common/StateManager.hxx @@ -104,19 +104,19 @@ class StateManager @param slot The state 'slot' to load state from */ - void loadState(int slot = -1); + AdjustFunction loadState(int slot = -1); /** Save the current state from the system. @param slot The state 'slot' to save into */ - void saveState(int slot = -1); + AdjustFunction saveState(int slot = -1); /** Switches to the next higher or lower state slot (circular queue style). */ - void changeState(int direction); + AdjustFunction changeState(bool next); /** Toggles auto slot mode. diff --git a/src/common/bspf.hxx b/src/common/bspf.hxx index 1484b21ed..cfb801045 100644 --- a/src/common/bspf.hxx +++ b/src/common/bspf.hxx @@ -43,6 +43,7 @@ using uInt64 = uint64_t; #include #include #include +#include #include #include #include @@ -86,6 +87,8 @@ using StringList = std::vector; using ByteBuffer = std::unique_ptr; // NOLINT 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) { diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 5af3d1077..be5643e81 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -349,7 +349,7 @@ bool Console::load(Serializer& in) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::selectFormat(bool next) +AdjustFunction Console::selectFormat(bool next) { string saveformat, message; uInt32 format = myCurrentFormat; @@ -360,6 +360,7 @@ void Console::selectFormat(bool next) format = myCurrentFormat > 0 ? (myCurrentFormat - 1) : 6; setFormat(format); + return std::bind(&Console::selectFormat, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -504,7 +505,7 @@ void Console::toggleTurbo() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::togglePhosphor() +AdjustFunction Console::togglePhosphor() { if(myOSystem.frameBuffer().tiaSurface().phosphorEnabled()) { @@ -518,10 +519,11 @@ void Console::togglePhosphor() myOSystem.frameBuffer().tiaSurface().enablePhosphor(true); myOSystem.frameBuffer().showMessage("Phosphor effect enabled"); } + return std::bind(&Console::changePhosphor, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::changePhosphor(bool increase) +AdjustFunction Console::changePhosphor(bool increase) { int blend = BSPF::stringToInt(myProperties.get(PropType::Display_PPBlend)); @@ -530,6 +532,7 @@ void Console::changePhosphor(bool increase) else // decrease blend blend -= 2; blend = BSPF::clamp(blend, 0, 100); + myOSystem.frameBuffer().tiaSurface().enablePhosphor(true, blend); ostringstream val; val << blend; @@ -542,7 +545,7 @@ void Console::changePhosphor(bool increase) val << "Off"; } myOSystem.frameBuffer().showMessage("Phosphor blend", val.str(), blend); - myOSystem.frameBuffer().tiaSurface().enablePhosphor(true, blend); + return std::bind(&Console::changePhosphor, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -619,7 +622,7 @@ void Console::fry() const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::changeVerticalCenter(bool increase) +AdjustFunction Console::changeVerticalCenter(bool increase) { Int32 vcenter = myTIA->vcenter(); @@ -638,6 +641,7 @@ void Console::changeVerticalCenter(bool increase) val << (vcenter ? vcenter > 0 ? "+" : "" : " ") << vcenter << "px"; myOSystem.frameBuffer().showMessage("V-Center", val.str(), vcenter, myTIA->minVcenter(), myTIA->maxVcenter()); + return std::bind(&Console::changeVerticalCenter, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -650,7 +654,7 @@ void Console::updateVcenter(Int32 vcenter) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::changeVSizeAdjust(bool increase) +AdjustFunction Console::changeVSizeAdjust(bool increase) { Int32 newAdjustVSize = myTIA->adjustVSize(); @@ -670,6 +674,7 @@ void Console::changeVSizeAdjust(bool increase) val << (newAdjustVSize ? newAdjustVSize > 0 ? "+" : "" : " ") << newAdjustVSize << "%"; myOSystem.frameBuffer().showMessage("V-Size", val.str(), newAdjustVSize, -5, 5); + return std::bind(&Console::changeVSizeAdjust, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Console.hxx b/src/emucore/Console.hxx index 15173b48d..8c48575ad 100644 --- a/src/emucore/Console.hxx +++ b/src/emucore/Console.hxx @@ -191,7 +191,7 @@ class Console : public Serializable, public ConsoleIO @param next Select next if true, else previous */ - void selectFormat(bool next = true); + AdjustFunction selectFormat(bool next = true); /** Set NTSC/PAL/SECAM (and variants) display format. @@ -217,14 +217,14 @@ class Console : public Serializable, public ConsoleIO /** Toggles phosphor effect. */ - void togglePhosphor(); + AdjustFunction togglePhosphor(); /** Change the "Display.PPBlend" variable. @param increase Increase if true, else decrease */ - void changePhosphor(bool increase = true); + AdjustFunction changePhosphor(bool increase = true); /** Toggles the PAL color-loss effect. @@ -259,7 +259,7 @@ class Console : public Serializable, public ConsoleIO @param increase Increase if true, else decrease */ - void changeVerticalCenter(bool increase = true); + AdjustFunction changeVerticalCenter(bool increase = true); /** Change the "TIA scanline adjust" variable. @@ -268,7 +268,7 @@ class Console : public Serializable, public ConsoleIO @param increase Increase if true, else decrease */ - void changeVSizeAdjust(bool increase = true); + AdjustFunction changeVSizeAdjust(bool increase = true); /** Returns the current framerate. diff --git a/src/emucore/Event.hxx b/src/emucore/Event.hxx index 0c84225ed..2102b57f6 100644 --- a/src/emucore/Event.hxx +++ b/src/emucore/Event.hxx @@ -122,6 +122,7 @@ class Event ToggleFrameStats, ToggleSAPortOrder, ExitGame, // add new events from here to avoid that user remapped events get overwritten + SettingDecrease, SettingIncrease, LastType }; diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 2dbc5e217..883d2b744 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -63,6 +63,8 @@ #include "ScrollBarWidget.hxx" #endif +using namespace std::placeholders; + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EventHandler::EventHandler(OSystem& osystem) : myOSystem(osystem) @@ -347,8 +349,32 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) // or need to be preprocessed before passing them on const bool pressed = (value != 0); + // The global settings keys react as long as the setting message from the previous event is + // still displayed. When no message is displayed, volume adjustment will be the default event. + if(!myOSystem.frameBuffer().messageShown() || myAdjustFunction == nullptr) + myAdjustFunction = std::bind(&Sound::adjustVolume, &myOSystem.sound(), std::placeholders::_1); + + // Assume no adjust function will be pressed + const AdjustFunction oldAdjustFunction = myAdjustFunction; + if(pressed) + myAdjustFunction = nullptr; + switch(event) { + //////////////////////////////////////////////////////////////////////// + // Allow adjusting several (mostly repeated) settings using the same two hotkeys + case Event::SettingDecrease: + if(pressed && oldAdjustFunction != nullptr) + oldAdjustFunction(false); + myAdjustFunction = oldAdjustFunction; + return; + + case Event::SettingIncrease: + if(pressed && oldAdjustFunction != nullptr) + oldAdjustFunction(true); + myAdjustFunction = oldAdjustFunction; + return; + //////////////////////////////////////////////////////////////////////// // If enabled, make sure 'impossible' joystick directions aren't allowed case Event::JoystickZeroUp: @@ -401,55 +427,68 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::VolumeDecrease: - if(pressed) myOSystem.sound().adjustVolume(-1); + if(pressed) + myAdjustFunction = myOSystem.sound().adjustVolume(false); return; case Event::VolumeIncrease: - if(pressed) myOSystem.sound().adjustVolume(+1); + if(pressed) + myAdjustFunction = myOSystem.sound().adjustVolume(true); return; case Event::SoundToggle: - if(pressed && !repeated) myOSystem.sound().toggleMute(); + if(pressed && !repeated) + myOSystem.sound().toggleMute(); return; case Event::VidmodeDecrease: - if(pressed) myOSystem.frameBuffer().selectVidMode(false); + if(pressed) + myAdjustFunction = myOSystem.frameBuffer().selectVidMode(false); return; case Event::VidmodeIncrease: - if(pressed) myOSystem.frameBuffer().selectVidMode(true); + if(pressed) + myAdjustFunction = myOSystem.frameBuffer().selectVidMode(true); return; case Event::VCenterDecrease: - if (pressed) myOSystem.console().changeVerticalCenter(false); + if (pressed) + myAdjustFunction = myOSystem.console().changeVerticalCenter(false); return; case Event::VCenterIncrease: - if (pressed) myOSystem.console().changeVerticalCenter(true); + if (pressed) + myAdjustFunction = myOSystem.console().changeVerticalCenter(true); return; case Event::VSizeAdjustDecrease: - if (pressed) myOSystem.console().changeVSizeAdjust(false); + if (pressed) + myAdjustFunction = myOSystem.console().changeVSizeAdjust(false); return; case Event::VSizeAdjustIncrease: - if (pressed) myOSystem.console().changeVSizeAdjust(true); + if (pressed) + myAdjustFunction = myOSystem.console().changeVSizeAdjust(true); return; case Event::PreviousPaletteAttribute: - if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().cycleAdjustable(false); + if(pressed) + myAdjustFunction = myOSystem.frameBuffer().tiaSurface().paletteHandler().cycleAdjustable(false); return; case Event::NextPaletteAttribute: - if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().cycleAdjustable(true); + if(pressed) + myAdjustFunction = myOSystem.frameBuffer().tiaSurface().paletteHandler().cycleAdjustable(true); return; case Event::PaletteAttributeDecrease: - if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().changeAdjustable(false); + if(pressed) + myAdjustFunction = myOSystem.frameBuffer().tiaSurface().paletteHandler().changeAdjustable(false); return; case Event::PaletteAttributeIncrease: - if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().changeAdjustable(true); + if(pressed) + myAdjustFunction = myOSystem.frameBuffer().tiaSurface().paletteHandler().changeAdjustable(true); return; case Event::ToggleFullScreen: @@ -457,19 +496,23 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::OverscanDecrease: - if (pressed) myOSystem.frameBuffer().changeOverscan(false); + if (pressed) + myAdjustFunction = myOSystem.frameBuffer().changeOverscan(false); return; case Event::OverscanIncrease: - if (pressed) myOSystem.frameBuffer().changeOverscan(true); + if (pressed) + myAdjustFunction = myOSystem.frameBuffer().changeOverscan(true); return; case Event::PreviousVideoMode: - if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().changeNTSC(false); + if (pressed && !repeated) + myAdjustFunction = myOSystem.frameBuffer().tiaSurface().changeNTSC(false); return; case Event::NextVideoMode: - if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().changeNTSC(true); + if (pressed && !repeated) + myAdjustFunction = myOSystem.frameBuffer().tiaSurface().changeNTSC(true); return; case Event::VidmodeStd: @@ -497,39 +540,48 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::PreviousAttribute: - if (pressed) myOSystem.frameBuffer().tiaSurface().setNTSCAdjustable(false); + if(pressed) + myAdjustFunction = myOSystem.frameBuffer().tiaSurface().setNTSCAdjustable(false); return; case Event::NextAttribute: - if (pressed) myOSystem.frameBuffer().tiaSurface().setNTSCAdjustable(true); + if (pressed) + myAdjustFunction = myOSystem.frameBuffer().tiaSurface().setNTSCAdjustable(true); return; case Event::DecreaseAttribute: - if(pressed) myOSystem.frameBuffer().tiaSurface().changeNTSCAdjustable(false); + if(pressed) + myAdjustFunction = myOSystem.frameBuffer().tiaSurface().changeNTSCAdjustable(false); return; case Event::IncreaseAttribute: - if(pressed) myOSystem.frameBuffer().tiaSurface().changeNTSCAdjustable(true); + if(pressed) + myAdjustFunction = myOSystem.frameBuffer().tiaSurface().changeNTSCAdjustable(true); return; case Event::ScanlinesDecrease: - if (pressed) myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(-2); + if (pressed) + myAdjustFunction = myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(false); return; case Event::ScanlinesIncrease: - if (pressed) myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(+2); + if (pressed) + myAdjustFunction = myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(true); return; case Event::PhosphorDecrease: - if (pressed) myOSystem.console().changePhosphor(false); + if (pressed) + myAdjustFunction = myOSystem.console().changePhosphor(false); return; case Event::PhosphorIncrease: - if (pressed) myOSystem.console().changePhosphor(true); + if (pressed) + myAdjustFunction = myOSystem.console().changePhosphor(true); return; case Event::TogglePhosphor: - if (pressed && !repeated) myOSystem.console().togglePhosphor(); + if(pressed && !repeated) + myAdjustFunction = myOSystem.console().togglePhosphor(); return; case Event::ToggleColorLoss: @@ -537,11 +589,13 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::PaletteDecrease: - if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().paletteHandler().cyclePalette(false); + if (pressed && !repeated) + myAdjustFunction = myOSystem.frameBuffer().tiaSurface().paletteHandler().cyclePalette(false); return; case Event::PaletteIncrease: - if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().paletteHandler().cyclePalette(true); + if (pressed && !repeated) + myAdjustFunction = myOSystem.frameBuffer().tiaSurface().paletteHandler().cyclePalette(true); return; case Event::ToggleInter: @@ -583,11 +637,13 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::FormatDecrease: - if (pressed) myOSystem.console().selectFormat(false); + if (pressed && !repeated) + myAdjustFunction = myOSystem.console().selectFormat(false); return; case Event::FormatIncrease: - if (pressed) myOSystem.console().selectFormat(true); + if (pressed && !repeated) + myAdjustFunction = myOSystem.console().selectFormat(true); return; case Event::ToggleGrabMouse: @@ -656,7 +712,8 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::SaveState: - if(pressed && !repeated) myOSystem.state().saveState(); + if(pressed && !repeated) + myAdjustFunction = myOSystem.state().saveState(); return; case Event::SaveAllStates: @@ -664,12 +721,14 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) myOSystem.frameBuffer().showMessage(myOSystem.state().rewindManager().saveAllStates()); return; - case Event::NextState: - if(pressed) myOSystem.state().changeState(1); + case Event::PreviousState: + if (pressed) + myAdjustFunction = myOSystem.state().changeState(false); return; - case Event::PreviousState: - if (pressed) myOSystem.state().changeState(-1); + case Event::NextState: + if(pressed) + myAdjustFunction = myOSystem.state().changeState(true); return; case Event::ToggleAutoSlot: @@ -677,7 +736,8 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::LoadState: - if(pressed && !repeated) myOSystem.state().loadState(); + if(pressed && !repeated) + myAdjustFunction = myOSystem.state().loadState(); return; case Event::LoadAllStates: @@ -1950,6 +2010,10 @@ EventHandler::EmulActionList EventHandler::ourEmulActionList = { { { Event::PhosphorIncrease, "Increase 'phosphor' blend", "" }, { Event::ScanlinesDecrease, "Decrease scanlines", "" }, { Event::ScanlinesIncrease, "Increase scanlines", "" }, + + { Event::SettingDecrease, "Decrease current setting", "" }, + { Event::SettingIncrease, "Increase current setting", "" }, + // Developer keys: { Event::ToggleFrameStats, "Toggle frame stats", "" }, { Event::ToggleP0Bit, "Toggle TIA Player0 object", "" }, @@ -2044,6 +2108,7 @@ const Event::EventSet EventHandler::MiscEvents = { // Event::MouseButtonLeftValue, Event::MouseButtonRightValue, Event::HandleMouseControl, Event::ToggleGrabMouse, Event::ToggleSAPortOrder, + Event::SettingDecrease, Event::SettingIncrease }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx index 6d19b685b..4b7e91af1 100644 --- a/src/emucore/EventHandler.hxx +++ b/src/emucore/EventHandler.hxx @@ -425,6 +425,8 @@ class EventHandler string key; }; + AdjustFunction myAdjustFunction{nullptr}; + // Global Event object Event myEvent; @@ -468,7 +470,7 @@ class EventHandler #else PNG_SIZE = 0, #endif - EMUL_ACTIONLIST_SIZE = 152 + PNG_SIZE + COMBO_SIZE, + EMUL_ACTIONLIST_SIZE = 154 + PNG_SIZE + COMBO_SIZE, MENU_ACTIONLIST_SIZE = 18 ; diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index cd7e2e57c..dd88c3020 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -533,11 +533,11 @@ 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; - myMsg.counter = uInt32(myOSystem.frameRate()) * 5; // Show message for 5 seconds + myMsg.counter = uInt32(myOSystem.frameRate()) * 3; // Show message for 3 seconds if(myMsg.counter == 0) myMsg.counter = 120; @@ -551,10 +551,10 @@ void FrameBuffer::showMessage(const string& message, const string& valueText, myMsg.value = 100.F; myMsg.valueText = valueText; myMsg.w = std::min(fontWidth * MESSAGE_WIDTH, - font().getStringWidth(myMsg.text) - + fontWidth * (GAUGEBAR_WIDTH + 2) - + font().getStringWidth(myMsg.valueText)) - + HBORDER * 2; + font().getStringWidth(myMsg.text) + + fontWidth * (GAUGEBAR_WIDTH + 2) + + font().getStringWidth(myMsg.valueText)) + + HBORDER * 2; myMsg.h = fontHeight + VBORDER * 2; myMsg.position = MessagePosition::BottomCenter; myMsg.enabled = true; @@ -564,6 +564,16 @@ void FrameBuffer::showMessage(const string& message, const string& valueText, #endif } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool FrameBuffer::messageShown() +{ +#ifdef GUI_SUPPORT + return myMsg.enabled; +#else + return false; +#endif +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::drawFrameStats(float framesPerSecond) { @@ -662,6 +672,7 @@ inline bool FrameBuffer::drawMessage() #ifdef GUI_SUPPORT // Either erase the entire message (when time is reached), // or show again this frame + cerr << myMsg.counter << endl; if(myMsg.counter == 0) { myMsg.enabled = false; @@ -749,7 +760,7 @@ inline bool FrameBuffer::drawMessage() // align bar with bottom of text const int y = VBORDER + font().desc().ascent - bheight; - // draw bar gauge + // draw gauge bar myMsg.surface->fillRect(x - BORDER, y, swidth + BORDER * 2, bheight, kSliderBGColor); myMsg.surface->fillRect(x, y + BORDER, bwidth, bheight - BORDER * 2, kSliderColor); // draw tickmark in the middle of the bar @@ -983,7 +994,7 @@ void FrameBuffer::toggleFullscreen() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBuffer::changeOverscan(bool increase) +AdjustFunction FrameBuffer::changeOverscan(bool increase) { if (fullScreen()) { @@ -1002,10 +1013,11 @@ void FrameBuffer::changeOverscan(bool increase) val << (overscan ? overscan > 0 ? "+" : "" : " ") << overscan << "%"; myOSystem.frameBuffer().showMessage("Overscan", val.str(), overscan, 0, 10); } + return std::bind(&FrameBuffer::changeOverscan, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool FrameBuffer::selectVidMode(bool next) +AdjustFunction FrameBuffer::selectVidMode(bool next) { EventHandlerState state = myOSystem.eventHandler().state(); bool tiaMode = (state != EventHandlerState::DEBUGGER && @@ -1013,7 +1025,7 @@ bool FrameBuffer::selectVidMode(bool next) // Only applicable when in TIA/emulation mode if(!tiaMode) - return false; + return nullptr; if(next) myCurrentModeList->next(); @@ -1047,11 +1059,11 @@ bool FrameBuffer::selectVidMode(bool next) else myOSystem.settings().setValue("tia.zoom", mode.zoom); - return true; + return std::bind(&FrameBuffer::selectVidMode, this, std::placeholders::_1); } myOSystem.sound().mute(oldMuteState); - return false; + return nullptr; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index 7a73b3d90..4dd55f7f5 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -148,17 +148,19 @@ class FrameBuffer MessagePosition position = MessagePosition::BottomCenter, bool force = false); /** - Shows a message with a bar gauge onscreen. + Shows a message with a gauge bar onscreen. @param message The message to be shown - @param valueText The value of the bar gauge as text - @param value The bar gauge percentage - @param minValue The minimal value of the bar gauge - @param maxValue The maximal value of the bar gauge + @param valueText The value of the gauge bar as text + @param value The gauge bar percentage + @param minValue The minimal value of the gauge bar + @param maxValue The maximal value of the gauge bar */ void showMessage(const string& message, const string& valueText, float value, float minValue = 0.F, float maxValue = 100.F); + bool messageShown(); + /** Toggles showing or hiding framerate statistics. */ @@ -265,7 +267,7 @@ class FrameBuffer @param increase Increase if true, else decrease */ - void changeOverscan(bool increase = true); + AdjustFunction changeOverscan(bool increase = true); /** This method is called when the user wants to switch to the next @@ -277,7 +279,7 @@ class FrameBuffer @param next Select next if true, else previous */ - bool selectVidMode(bool next = true); + AdjustFunction selectVidMode(bool next = true); /** Sets the state of the cursor (hidden or grabbed) based on the diff --git a/src/emucore/Sound.hxx b/src/emucore/Sound.hxx index f74705489..a03223f71 100644 --- a/src/emucore/Sound.hxx +++ b/src/emucore/Sound.hxx @@ -88,10 +88,10 @@ class Sound /** Adjusts the volume of the sound device based on the given direction. - @param direction Increase or decrease the current volume by a predefined - amount based on the direction (1 = increase, -1 =decrease) + @param increase Increase or decrease the current volume by a predefined + amount */ - virtual void adjustVolume(Int8 direction) = 0; + virtual AdjustFunction adjustVolume(bool increase) = 0; /** This method is called to provide information about the sound device. diff --git a/src/emucore/TIASurface.cxx b/src/emucore/TIASurface.cxx index 98adb4bd4..88a41415c 100644 --- a/src/emucore/TIASurface.cxx +++ b/src/emucore/TIASurface.cxx @@ -200,7 +200,7 @@ void TIASurface::setNTSC(NTSCFilter::Preset preset, bool show) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIASurface::changeNTSC(bool next, bool show) +AdjustFunction TIASurface::changeNTSC(bool next) { constexpr NTSCFilter::Preset PRESETS[] = { NTSCFilter::Preset::OFF, NTSCFilter::Preset::RGB, NTSCFilter::Preset::SVIDEO, @@ -222,11 +222,12 @@ void TIASurface::changeNTSC(bool next, bool show) else preset--; } - setNTSC(PRESETS[preset], show); + setNTSC(PRESETS[preset], true); + return std::bind(&TIASurface::changeNTSC, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIASurface::setNTSCAdjustable(bool next) +AdjustFunction TIASurface::setNTSCAdjustable(bool next) { string text, valueText; Int32 value; @@ -234,11 +235,12 @@ void TIASurface::setNTSCAdjustable(bool next) setNTSC(NTSCFilter::Preset::CUSTOM); ntsc().selectAdjustable(next, text, valueText, value); myOSystem.frameBuffer().showMessage(text, valueText, value); + return std::bind(&TIASurface::changeNTSCAdjustable, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIASurface::changeNTSCAdjustable(bool increase) +AdjustFunction TIASurface::changeNTSCAdjustable(bool increase) { string text, valueText; Int32 newValue; @@ -246,13 +248,14 @@ void TIASurface::changeNTSCAdjustable(bool increase) setNTSC(NTSCFilter::Preset::CUSTOM); ntsc().changeAdjustable(increase, text, valueText, newValue); myOSystem.frameBuffer().showMessage(text, valueText, newValue); + return std::bind(&TIASurface::changeNTSCAdjustable, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIASurface::setScanlineIntensity(int amount) +AdjustFunction TIASurface::setScanlineIntensity(bool increase) { ostringstream buf; - uInt32 intensity = enableScanlines(amount); + uInt32 intensity = enableScanlines(increase ? 2 : -2); myOSystem.settings().setValue("tv.scanlines", intensity); enableNTSC(ntscEnabled()); @@ -262,6 +265,7 @@ void TIASurface::setScanlineIntensity(int amount) else buf << "Off"; myFB.showMessage("Scanline intensity", buf.str(), intensity); + return std::bind(&TIASurface::setScanlineIntensity, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/TIASurface.hxx b/src/emucore/TIASurface.hxx index 90aeacb14..ecb1de752 100644 --- a/src/emucore/TIASurface.hxx +++ b/src/emucore/TIASurface.hxx @@ -92,17 +92,17 @@ class TIASurface /** Switch to next/previous NTSC filtering effect. */ - void changeNTSC(bool next, bool show = true); + AdjustFunction changeNTSC(bool next); /** Switch to next/previous NTSC filtering adjustable. */ - void setNTSCAdjustable(bool next = true); + AdjustFunction setNTSCAdjustable(bool next = true); /** Increase/decrease current NTSC filtering adjustable. */ - void changeNTSCAdjustable(bool increase = true); + AdjustFunction changeNTSCAdjustable(bool increase = true); /** Retrieve palette handler. @@ -112,7 +112,7 @@ class TIASurface /** Increase/decrease current scanline intensity by given relative amount. */ - void setScanlineIntensity(int relative); + AdjustFunction setScanlineIntensity(bool increase); /** Change scanline intensity and interpolation. diff --git a/src/libretro/SoundLIBRETRO.hxx b/src/libretro/SoundLIBRETRO.hxx index aa98780e1..f69d71a14 100644 --- a/src/libretro/SoundLIBRETRO.hxx +++ b/src/libretro/SoundLIBRETRO.hxx @@ -95,10 +95,10 @@ class SoundLIBRETRO : public Sound /** Adjusts the volume of the sound device based on the given direction. - @param direction Increase or decrease the current volume by a predefined - amount based on the direction (1 = increase, -1 = decrease) + @param increase Increase or decrease the current volume by a predefined + amount */ - void adjustVolume(Int8 direction) override { } + void adjustVolume(bool increase) override { return nullptr; } /** This method is called to provide information about the sound device. From f5917d1f985d4bca780e14d7e7b6772fbd20d1fe Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Thu, 14 May 2020 21:03:25 -0230 Subject: [PATCH 219/377] libretro: Fix sound code for latest refactoring. --- src/libretro/SoundLIBRETRO.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libretro/SoundLIBRETRO.hxx b/src/libretro/SoundLIBRETRO.hxx index f69d71a14..68bf9fa16 100644 --- a/src/libretro/SoundLIBRETRO.hxx +++ b/src/libretro/SoundLIBRETRO.hxx @@ -98,7 +98,7 @@ class SoundLIBRETRO : public Sound @param increase Increase or decrease the current volume by a predefined amount */ - void adjustVolume(bool increase) override { return nullptr; } + AdjustFunction adjustVolume(bool increase) override { return AdjustFunction{}; } /** This method is called to provide information about the sound device. From c8c3a7cd816fcdb063391bbc4a23f97b5c4c5d1f Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Fri, 15 May 2020 09:33:39 -0230 Subject: [PATCH 220/377] libretro: Return nullptr when necessary. --- src/libretro/SoundLIBRETRO.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libretro/SoundLIBRETRO.hxx b/src/libretro/SoundLIBRETRO.hxx index 68bf9fa16..ad5966a9c 100644 --- a/src/libretro/SoundLIBRETRO.hxx +++ b/src/libretro/SoundLIBRETRO.hxx @@ -98,7 +98,7 @@ class SoundLIBRETRO : public Sound @param increase Increase or decrease the current volume by a predefined amount */ - AdjustFunction adjustVolume(bool increase) override { return AdjustFunction{}; } + AdjustFunction adjustVolume(bool increase) override { return nullptr; } /** This method is called to provide information about the sound device. From 2e4bc095457179c5257fb7f97c4f3d3de92d68ac Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Fri, 15 May 2020 15:25:27 -0230 Subject: [PATCH 221/377] Partially revert previous commit: fix ROM launcher not showing properties in certain cases. --- src/emucore/OSystem.cxx | 31 ++----------------------------- src/emucore/PropsSet.cxx | 31 +++++++++++++++++++++++++++++++ src/emucore/PropsSet.hxx | 17 ++++++++++++++++- src/gui/RomInfoWidget.cxx | 5 +++++ 4 files changed, 54 insertions(+), 30 deletions(-) diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index 8d60f6fb1..9c84b4165 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -648,35 +648,8 @@ ByteBuffer OSystem::openROM(const FilesystemNode& rom, string& md5, size_t& size if(md5 == "") md5 = MD5::hash(image, size); - // Handle ROM properties, do some error checking - // Only add to the database when necessary - bool toInsert = false; - - // First, does this ROM have a per-ROM properties entry? - // If so, load it into the database - FilesystemNode propsNode(rom.getPathWithExt(".pro")); - if(propsNode.exists() && propsNode.isFile()) - { - Logger::info("Loading per-ROM properties: " + propsNode.getShortPath()); - myPropSet->load(propsNode.getPath(), false); - } - - // Next, make sure we have a valid md5 and name - Properties props; - if(!myPropSet->getMD5(md5, props)) - { - props.set(PropType::Cart_MD5, md5); - toInsert = true; - } - if(toInsert || props.get(PropType::Cart_Name) == EmptyString) - { - props.set(PropType::Cart_Name, rom.getNameWithExt("")); - toInsert = true; - } - - // Finally, insert properties if any info was missing - if(toInsert) - myPropSet->insert(props, false); + // Make sure to load a per-ROM properties entry, if one exists + myPropSet->loadPerROM(rom, md5); return image; } diff --git a/src/emucore/PropsSet.cxx b/src/emucore/PropsSet.cxx index a13a9c759..a74a999e7 100644 --- a/src/emucore/PropsSet.cxx +++ b/src/emucore/PropsSet.cxx @@ -156,6 +156,37 @@ void PropertiesSet::insert(const Properties& properties, bool save) } } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PropertiesSet::loadPerROM(const FilesystemNode& rom, const string& md5) +{ + // Handle ROM properties, do some error checking + // Only add to the database when necessary + bool toInsert = false; + + // First, does this ROM have a per-ROM properties entry? + // If so, load it into the database + FilesystemNode propsNode(rom.getPathWithExt(".pro")); + if(propsNode.exists() && propsNode.isFile()) + load(propsNode.getPath(), false); + + // Next, make sure we have a valid md5 and name + Properties props; + if(!getMD5(md5, props)) + { + props.set(PropType::Cart_MD5, md5); + toInsert = true; + } + if(toInsert || props.get(PropType::Cart_Name) == EmptyString) + { + props.set(PropType::Cart_Name, rom.getNameWithExt("")); + toInsert = true; + } + + // Finally, insert properties if any info was missing + if(toInsert) + insert(props, false); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PropertiesSet::print() const { diff --git a/src/emucore/PropsSet.hxx b/src/emucore/PropsSet.hxx index 71924749a..f5a763ef8 100644 --- a/src/emucore/PropsSet.hxx +++ b/src/emucore/PropsSet.hxx @@ -42,7 +42,7 @@ class PropertiesSet /** Trivial constructor. */ - PropertiesSet() = default; + PropertiesSet() = default; /** Load properties from the specified file, and create an internal @@ -90,6 +90,21 @@ class PropertiesSet */ void insert(const Properties& properties, bool save = true); + /** + Load properties for a specific ROM from a per-ROM properties file, + if it exists. In any event, also do some error checking, like making + sure that the properties have a valid name, etc. + + NOTE: This method is meant to be called only when starting Stella + and loading a ROM for the first time. Currently, that means + only from the ROM launcher or when actually opening the ROM. + *** FOR ALL OTHER CASES, USE getMD5() *** + + @param rom The node representing the rom file + @param md5 The md5 of the property to get + */ + void loadPerROM(const FilesystemNode& rom, const string& md5); + /** Prints the contents of the PropertiesSet as a flat file. */ diff --git a/src/gui/RomInfoWidget.cxx b/src/gui/RomInfoWidget.cxx index 8b1852528..3cfa43185 100644 --- a/src/gui/RomInfoWidget.cxx +++ b/src/gui/RomInfoWidget.cxx @@ -48,6 +48,11 @@ RomInfoWidget::RomInfoWidget(GuiObject* boss, const GUI::Font& font, void RomInfoWidget::setProperties(const FilesystemNode& node, const string& md5) { myHaveProperties = true; + + // Make sure to load a per-ROM properties entry, if one exists + instance().propSet().loadPerROM(node, md5); + + // And now get the properties for this ROM instance().propSet().getMD5(md5, myProperties); // Decide whether the information should be shown immediately From 8e8db77e49dd5e5ea6c029f04aba9b73601ad97b Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Fri, 15 May 2020 19:22:36 -0230 Subject: [PATCH 222/377] Very small optimization for const char* instead of strings. --- src/common/FrameBufferSDL2.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index 4d013a35d..93a12615d 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -144,11 +144,11 @@ void FrameBufferSDL2::queryHardware(vector& fullscreenRes, struct RenderName { - string sdlName; - string stellaName; + const char* const sdlName; + const char* const stellaName; }; // Create name map for all currently known SDL renderers - static const std::array RENDERER_NAMES = {{ + static constexpr std::array RENDERER_NAMES = {{ { "direct3d", "Direct3D" }, { "metal", "Metal" }, { "opengl", "OpenGL" }, From 9e7940af95d843b2202020d3973afc7f7745abf7 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 16 May 2020 09:50:16 +0200 Subject: [PATCH 223/377] added four global hotkeys which allow selecting and changing several adjustable settings (addresses #631) --- src/common/PKeyboardHandler.cxx | 4 + src/common/PaletteHandler.cxx | 77 ++---- src/common/PaletteHandler.hxx | 33 ++- src/common/SoundNull.hxx | 5 +- src/common/SoundSDL2.cxx | 5 +- src/common/SoundSDL2.hxx | 5 +- src/common/StateManager.cxx | 26 +- src/common/StateManager.hxx | 8 +- src/common/bspf.hxx | 6 +- src/common/tv_filters/NTSCFilter.cxx | 34 ++- src/common/tv_filters/NTSCFilter.hxx | 16 +- src/emucore/Console.cxx | 46 +--- src/emucore/Console.hxx | 20 +- src/emucore/Event.hxx | 2 +- src/emucore/EventHandler.cxx | 373 ++++++++++++++++++++++----- src/emucore/EventHandler.hxx | 49 +++- src/emucore/FrameBuffer.cxx | 36 +-- src/emucore/FrameBuffer.hxx | 8 +- src/emucore/Sound.hxx | 5 +- src/emucore/TIASurface.cxx | 42 +-- src/emucore/TIASurface.hxx | 29 ++- src/libretro/SoundLIBRETRO.hxx | 5 +- 22 files changed, 563 insertions(+), 271 deletions(-) diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index 95cef05e8..c09cd48fb 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -493,8 +493,12 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo {Event::ToggleColorLoss, KBDK_L, KBDM_CTRL}, {Event::PaletteDecrease, KBDK_P, KBDM_SHIFT | KBDM_CTRL}, {Event::PaletteIncrease, KBDK_P, KBDM_CTRL}, + + {Event::PreviousSetting, KBDK_END}, + {Event::NextSetting, KBDK_HOME}, {Event::SettingDecrease, KBDK_PAGEDOWN}, {Event::SettingIncrease, KBDK_PAGEUP}, + {Event::ToggleInter, KBDK_I, KBDM_CTRL}, {Event::ToggleTurbo, KBDK_T, KBDM_CTRL}, {Event::ToggleJitter, KBDK_J, MOD3}, diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index 2c04ccd3b..d2a2a7768 100644 --- a/src/common/PaletteHandler.cxx +++ b/src/common/PaletteHandler.cxx @@ -55,33 +55,16 @@ string PaletteHandler::toPaletteName(PaletteType type) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction PaletteHandler::cyclePalette(bool next) +void PaletteHandler::cyclePalette(int direction) { const string MESSAGES[PaletteType::NumTypes] = { "Standard Stella", "Z26", "User-defined", "Custom" }; int type = toPaletteType(myOSystem.settings().getString("palette")); - if(next) - { - if(type == PaletteType::MaxType) - type = PaletteType::Standard; - else - type++; - // If we have no user-defined palette, we will skip it - if(type == PaletteType::User && !myUserPaletteDefined) - type++; - } - else - { - if(type == PaletteType::MinType) - type = PaletteType::MaxType; - else - type--; - // If we have no user-defined palette, we will skip it - if(type == PaletteType::User && !myUserPaletteDefined) - type--; - } + do { + type = BSPF::clampw(type + direction, int(PaletteType::MinType), int(PaletteType::MaxType)); + } while(type == PaletteType::User && !myUserPaletteDefined); const string palette = toPaletteName(PaletteType(type)); const string message = MESSAGES[type] + " palette"; @@ -89,7 +72,6 @@ AdjustFunction PaletteHandler::cyclePalette(bool next) myOSystem.frameBuffer().showMessage(message); setPalette(palette); - return std::bind(&PaletteHandler::cyclePalette, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -119,58 +101,55 @@ void PaletteHandler::showAdjustableMessage() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction PaletteHandler::cycleAdjustable(bool next) +void PaletteHandler::cycleAdjustable(int direction) { const bool isCustomPalette = SETTING_CUSTOM == myOSystem.settings().getString("palette"); bool isPhaseShift; do { - if(next) - { - myCurrentAdjustable++; - myCurrentAdjustable %= NUM_ADJUSTABLES; - } - else - { - if(myCurrentAdjustable == 0) - myCurrentAdjustable = NUM_ADJUSTABLES - 1; - else - myCurrentAdjustable--; - } + myCurrentAdjustable = BSPF::clampw(int(myCurrentAdjustable + direction), 0, NUM_ADJUSTABLES - 1); isPhaseShift = myAdjustables[myCurrentAdjustable].value == nullptr; - // skip phase shift when 'Custom' palette is not selected + if(!direction && isPhaseShift && !isCustomPalette) + myCurrentAdjustable++; } while(isPhaseShift && !isCustomPalette); showAdjustableMessage(); - return std::bind(&PaletteHandler::changeAdjustable, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction PaletteHandler::changeAdjustable(bool increase) +void PaletteHandler::changeAdjustable(int adjustable, int direction) +{ + const bool isCustomPalette = SETTING_CUSTOM == myOSystem.settings().getString("palette"); + const bool isPhaseShift = myAdjustables[adjustable].value == nullptr; + + myCurrentAdjustable = adjustable; + if(isPhaseShift && !isCustomPalette) + myCurrentAdjustable++; + + changeCurrentAdjustable(direction); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::changeCurrentAdjustable(int direction) { if(myAdjustables[myCurrentAdjustable].value == nullptr) - changeColorPhaseShift(increase); + changeColorPhaseShift(direction); else { int newVal = scaleTo100(*myAdjustables[myCurrentAdjustable].value); - if(increase) - newVal += 2; // += 2% - else - newVal -= 2; // -= 2% - newVal = BSPF::clamp(newVal, 0, 100); + newVal = BSPF::clamp(newVal + direction * 2, 0, 100); *myAdjustables[myCurrentAdjustable].value = scaleFrom100(newVal); showAdjustableMessage(); setPalette(); } - return std::bind(&PaletteHandler::changeAdjustable, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PaletteHandler::changeColorPhaseShift(bool increase) +void PaletteHandler::changeColorPhaseShift(int direction) { const ConsoleTiming timing = myOSystem.console().timing(); @@ -181,11 +160,7 @@ void PaletteHandler::changeColorPhaseShift(bool increase) const float shift = isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT; float newPhase = isNTSC ? myPhaseNTSC : myPhasePAL; - if(increase) // increase color phase shift - newPhase += 0.3F; - else // decrease color phase shift - newPhase -= 0.3F; - newPhase = BSPF::clamp(newPhase, shift - MAX_SHIFT, shift + MAX_SHIFT); + newPhase = BSPF::clamp(newPhase + direction * 0.3F, shift - MAX_SHIFT, shift + MAX_SHIFT); if(isNTSC) myPhaseNTSC = newPhase; diff --git a/src/common/PaletteHandler.hxx b/src/common/PaletteHandler.hxx index 7a4b8676d..817c5fb5e 100644 --- a/src/common/PaletteHandler.hxx +++ b/src/common/PaletteHandler.hxx @@ -37,6 +37,15 @@ class PaletteHandler static constexpr float DEF_PAL_SHIFT = 31.3F; // ~= 360 / 11.5 static constexpr float MAX_SHIFT = 4.5F; + enum Adjustables { + PHASE_SHIFT, + HUE, + SATURATION, + CONTRAST, + BRIGHTNESS, + GAMMA + }; + // Externally used adjustment parameters struct Adjustable { float phaseNtsc{0.F}, phasePal{0.F}; @@ -50,23 +59,31 @@ class PaletteHandler /** Cycle through available palettes. - @param next Select next palette, else previous one + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction cyclePalette(bool next = true); + void cyclePalette(int direction = +1); /* Cycle through each palette adjustable. - @param next Select next adjustable, else previous one + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction cycleAdjustable(bool next = true); + void cycleAdjustable(int direction = +1); + + /* + Increase or decrease given palette adjustable. + + @param adjustable The adjustable to change + @param direction +1 indicates increase, -1 indicates decrease. + */ + void changeAdjustable(int adjustable, int direction); /* Increase or decrease current palette adjustable. - @param increase Increase adjustable if true, else decrease + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction changeAdjustable(bool increase = true); + void changeCurrentAdjustable(int direction = +1); // Load adjustables from settings void loadConfig(const Settings& settings); @@ -139,9 +156,9 @@ class PaletteHandler Note that there are two of these (NTSC and PAL). The currently active mode will determine which one is used. - @param increase Increase if true, else decrease + @param direction +1 indicates increase, -1 indicates decrease. */ - void changeColorPhaseShift(bool increase = true); + void changeColorPhaseShift(int direction = +1); /** Generates a custom palette, based on user defined phase shifts. diff --git a/src/common/SoundNull.hxx b/src/common/SoundNull.hxx index ef07090a3..8974e9834 100644 --- a/src/common/SoundNull.hxx +++ b/src/common/SoundNull.hxx @@ -97,10 +97,9 @@ class SoundNull : public Sound /** Adjusts the volume of the sound device based on the given direction. - @param increase Increase or decrease the current volume by a predefined - amount + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction adjustVolume(bool increase) override { return nullptr; } + void adjustVolume(int direction = 1) override { } /** This method is called to provide information about the sound device. diff --git a/src/common/SoundSDL2.cxx b/src/common/SoundSDL2.cxx index 234e4aae7..928ebbc44 100644 --- a/src/common/SoundSDL2.cxx +++ b/src/common/SoundSDL2.cxx @@ -229,12 +229,12 @@ void SoundSDL2::setVolume(uInt32 percent) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction SoundSDL2::adjustVolume(bool increase) +void SoundSDL2::adjustVolume(int direction) { ostringstream strval; Int32 percent = myVolume; - percent = BSPF::clamp(percent += increase ? 2 : -2, 0, 100); + percent = BSPF::clamp(percent + direction * 2, 0, 100); setVolume(percent); @@ -253,7 +253,6 @@ AdjustFunction SoundSDL2::adjustVolume(bool increase) else strval << "Off"; myOSystem.frameBuffer().showMessage("Volume", strval.str(), percent); - return std::bind(&SoundSDL2::adjustVolume, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/SoundSDL2.hxx b/src/common/SoundSDL2.hxx index bea035dd3..398f1fa92 100644 --- a/src/common/SoundSDL2.hxx +++ b/src/common/SoundSDL2.hxx @@ -98,10 +98,9 @@ class SoundSDL2 : public Sound /** Adjusts the volume of the sound device based on the given direction. - @param increase Increase or decrease the current volume by a predefined - amount + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction adjustVolume(bool increase) override; + void adjustVolume(int direction = 1) override; /** This method is called to provide information about the sound device. diff --git a/src/common/StateManager.cxx b/src/common/StateManager.cxx index 016b7a97a..a4add0889 100644 --- a/src/common/StateManager.cxx +++ b/src/common/StateManager.cxx @@ -198,7 +198,7 @@ void StateManager::update() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction StateManager::loadState(int slot) +void StateManager::loadState(int slot) { if(myOSystem.hasConsole()) { @@ -216,7 +216,7 @@ AdjustFunction StateManager::loadState(int slot) buf.str(""); buf << "Can't open/load from state file " << slot; myOSystem.frameBuffer().showMessage(buf.str()); - return nullptr; + return; } // First test if we have a valid header @@ -241,11 +241,10 @@ AdjustFunction StateManager::loadState(int slot) myOSystem.frameBuffer().showMessage(buf.str()); } - return std::bind(&StateManager::changeState, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction StateManager::saveState(int slot) +void StateManager::saveState(int slot) { if(myOSystem.hasConsole()) { @@ -263,7 +262,7 @@ AdjustFunction StateManager::saveState(int slot) buf.str(""); buf << "Can't open/save to state file " << slot; myOSystem.frameBuffer().showMessage(buf.str()); - return nullptr; + return; } try @@ -276,7 +275,7 @@ AdjustFunction StateManager::saveState(int slot) { buf << "Error saving state " << slot; myOSystem.frameBuffer().showMessage(buf.str()); - return nullptr; + return; } // Do a complete state save using the Console @@ -295,23 +294,20 @@ AdjustFunction StateManager::saveState(int slot) myOSystem.frameBuffer().showMessage(buf.str()); } - return std::bind(&StateManager::changeState, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction StateManager::changeState(bool next) +void StateManager::changeState(int direction) { - myCurrentSlot += next ? 1 : -1; - if (myCurrentSlot < 0) - myCurrentSlot = 9; - else - myCurrentSlot %= 10; + myCurrentSlot = BSPF::clampw(myCurrentSlot + direction, 0, 9); // Print appropriate message ostringstream buf; - buf << "Changed to slot " << myCurrentSlot; + if(direction) + buf << "Changed to state slot " << myCurrentSlot; + else + buf << "State slot " << myCurrentSlot; myOSystem.frameBuffer().showMessage(buf.str()); - return std::bind(&StateManager::changeState, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/StateManager.hxx b/src/common/StateManager.hxx index 3739b8c31..3da98499c 100644 --- a/src/common/StateManager.hxx +++ b/src/common/StateManager.hxx @@ -104,19 +104,21 @@ class StateManager @param slot The state 'slot' to load state from */ - AdjustFunction loadState(int slot = -1); + void loadState(int slot = -1); /** Save the current state from the system. @param slot The state 'slot' to save into */ - AdjustFunction saveState(int slot = -1); + void saveState(int slot = -1); /** Switches to the next higher or lower state slot (circular queue style). + + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction changeState(bool next); + void changeState(int direction = +1); /** Toggles auto slot mode. diff --git a/src/common/bspf.hxx b/src/common/bspf.hxx index cfb801045..f21a99a4c 100644 --- a/src/common/bspf.hxx +++ b/src/common/bspf.hxx @@ -87,7 +87,7 @@ using StringList = std::vector; using ByteBuffer = std::unique_ptr; // NOLINT using DWordBuffer = std::unique_ptr; // NOLINT -using AdjustFunction = std::function; +using AdjustFunction = std::function; // We use KB a lot; let's make a literal for it constexpr uInt32 operator "" _KB(unsigned long long size) @@ -136,6 +136,10 @@ namespace BSPF { if(val < lower || val > upper) val = setVal; } + template inline T clampw(T val, T lower, T upper) + { + return (val < lower) ? upper : (val > upper) ? lower : val; + } // Convert string to given case inline const string& toUpperCase(string& s) diff --git a/src/common/tv_filters/NTSCFilter.cxx b/src/common/tv_filters/NTSCFilter.cxx index 2d0ffaa6e..9764f1ac3 100644 --- a/src/common/tv_filters/NTSCFilter.cxx +++ b/src/common/tv_filters/NTSCFilter.cxx @@ -62,9 +62,9 @@ string NTSCFilter::getPreset() const { switch(myPreset) { - case Preset::COMPOSITE: return "COMPOSITE"; - case Preset::SVIDEO: return "S-VIDEO"; case Preset::RGB: return "RGB"; + case Preset::SVIDEO: return "S-VIDEO"; + case Preset::COMPOSITE: return "COMPOSITE"; case Preset::BAD: return "BAD ADJUST"; case Preset::CUSTOM: return "CUSTOM"; default: return "Disabled"; @@ -72,9 +72,10 @@ string NTSCFilter::getPreset() const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void NTSCFilter::selectAdjustable(bool next, string& text, string& valueText, Int32& value) +void NTSCFilter::selectAdjustable(int direction, + string& text, string& valueText, Int32& value) { - if(next) + if(direction == +1) { #ifdef BLARGG_PALETTE myCurrentAdjustable = (myCurrentAdjustable + 1) % 10; @@ -82,7 +83,7 @@ void NTSCFilter::selectAdjustable(bool next, string& text, string& valueText, In myCurrentAdjustable = (myCurrentAdjustable + 1) % 5; #endif } - else + else if(direction == -1) { #ifdef BLARGG_PALETTE if(myCurrentAdjustable == 0) myCurrentAdjustable = 9; @@ -103,13 +104,22 @@ void NTSCFilter::selectAdjustable(bool next, string& text, string& valueText, In } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void NTSCFilter::changeAdjustable(bool increase, string& text, string& valueText, Int32& newValue) +void NTSCFilter::changeAdjustable(int adjustable, int direction, + string& text, string& valueText, Int32& newValue) +{ + myCurrentAdjustable = adjustable; + changeCurrentAdjustable(direction, text, valueText, newValue); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void NTSCFilter::changeCurrentAdjustable(int direction, + string& text, string& valueText, Int32& newValue) { //if(myPreset != Preset::CUSTOM) // return "'Custom' TV mode not selected"; newValue = scaleTo100(*ourCustomAdjustables[myCurrentAdjustable].value); - newValue = BSPF::clamp(newValue + (increase ? 2 : -2), 0, 100); + newValue = BSPF::clamp(newValue + direction * 2, 0, 100); *ourCustomAdjustables[myCurrentAdjustable].value = scaleFrom100(newValue); @@ -166,12 +176,12 @@ void NTSCFilter::getAdjustables(Adjustable& adjustable, Preset preset) const { switch(preset) { - case Preset::COMPOSITE: - convertToAdjustable(adjustable, AtariNTSC::TV_Composite); break; - case Preset::SVIDEO: - convertToAdjustable(adjustable, AtariNTSC::TV_SVideo); break; case Preset::RGB: convertToAdjustable(adjustable, AtariNTSC::TV_RGB); break; + case Preset::SVIDEO: + convertToAdjustable(adjustable, AtariNTSC::TV_SVideo); break; + case Preset::COMPOSITE: + convertToAdjustable(adjustable, AtariNTSC::TV_Composite); break; case Preset::BAD: convertToAdjustable(adjustable, AtariNTSC::TV_Bad); break; case Preset::CUSTOM: @@ -228,7 +238,7 @@ const std::array NTSCFilter::ourCustomAdjustables { "saturation", &myCustomSetup.saturation }, { "gamma", &myCustomSetup.gamma }, #else -const std::array NTSCFilter::ourCustomAdjustables = { { +const std::array NTSCFilter::ourCustomAdjustables = { { #endif { "sharpness", &myCustomSetup.sharpness }, { "resolution", &myCustomSetup.resolution }, diff --git a/src/common/tv_filters/NTSCFilter.hxx b/src/common/tv_filters/NTSCFilter.hxx index 6ccdcd155..b4b3aa713 100644 --- a/src/common/tv_filters/NTSCFilter.hxx +++ b/src/common/tv_filters/NTSCFilter.hxx @@ -47,6 +47,14 @@ class NTSCFilter BAD, CUSTOM }; + enum class Adjustables { + SHARPNESS, + RESOLUTION, + ARTIFACTS, + FRINGING, + BLEEDING, + NUM_ADJUSTABLES + }; /* Normally used in conjunction with custom mode, contains all aspects currently adjustable in NTSC TV emulation. */ @@ -90,8 +98,12 @@ class NTSCFilter // Changes are made this way since otherwise 20 key-combinations // would be needed to dynamically change each setting, and now // only 4 combinations are necessary - void selectAdjustable(bool next, string& text, string& valueText, Int32& value); - void changeAdjustable(bool increase, string& text, string& valueText, Int32& newValue); + void selectAdjustable(int direction, + string& text, string& valueText, Int32& value); + void changeAdjustable(int adjustable, int direction, + string& text, string& valueText, Int32& newValue); + void changeCurrentAdjustable(int direction, + string& text, string& valueText, Int32& newValue); // Load and save NTSC-related settings void loadConfig(const Settings& settings); diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index be5643e81..1d5bb5e6c 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -349,24 +349,20 @@ bool Console::load(Serializer& in) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction Console::selectFormat(bool next) +void Console::selectFormat(int direction) { string saveformat, message; - uInt32 format = myCurrentFormat; + Int32 format = myCurrentFormat; - if(next) - format = (myCurrentFormat + 1) % 7; - else - format = myCurrentFormat > 0 ? (myCurrentFormat - 1) : 6; + format = BSPF::clampw(format + direction, 0, 6); - setFormat(format); - return std::bind(&Console::selectFormat, this, std::placeholders::_1); + setFormat(format, true); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::setFormat(uInt32 format) +void Console::setFormat(uInt32 format, bool force) { - if(myCurrentFormat == format) + if(!force && myCurrentFormat == format) return; string saveformat, message; @@ -505,7 +501,7 @@ void Console::toggleTurbo() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction Console::togglePhosphor() +void Console::togglePhosphor() { if(myOSystem.frameBuffer().tiaSurface().phosphorEnabled()) { @@ -519,19 +515,14 @@ AdjustFunction Console::togglePhosphor() myOSystem.frameBuffer().tiaSurface().enablePhosphor(true); myOSystem.frameBuffer().showMessage("Phosphor effect enabled"); } - return std::bind(&Console::changePhosphor, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction Console::changePhosphor(bool increase) +void Console::changePhosphor(int direction) { int blend = BSPF::stringToInt(myProperties.get(PropType::Display_PPBlend)); - if(increase) // increase blend - blend += 2; - else // decrease blend - blend -= 2; - blend = BSPF::clamp(blend, 0, 100); + blend = BSPF::clamp(blend + direction * 2, 0, 100); myOSystem.frameBuffer().tiaSurface().enablePhosphor(true, blend); ostringstream val; @@ -545,7 +536,6 @@ AdjustFunction Console::changePhosphor(bool increase) val << "Off"; } myOSystem.frameBuffer().showMessage("Phosphor blend", val.str(), blend); - return std::bind(&Console::changePhosphor, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -622,15 +612,11 @@ void Console::fry() const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction Console::changeVerticalCenter(bool increase) +void Console::changeVerticalCenter(int direction) { Int32 vcenter = myTIA->vcenter(); - if(increase) // increase vcenter - ++vcenter; - else // decrease vcenter - --vcenter; - vcenter = BSPF::clamp(vcenter, myTIA->minVcenter(), myTIA->maxVcenter()); + vcenter = BSPF::clamp(vcenter + direction, myTIA->minVcenter(), myTIA->maxVcenter()); ostringstream ss, val; ss << vcenter; @@ -641,7 +627,6 @@ AdjustFunction Console::changeVerticalCenter(bool increase) val << (vcenter ? vcenter > 0 ? "+" : "" : " ") << vcenter << "px"; myOSystem.frameBuffer().showMessage("V-Center", val.str(), vcenter, myTIA->minVcenter(), myTIA->maxVcenter()); - return std::bind(&Console::changeVerticalCenter, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -654,15 +639,11 @@ void Console::updateVcenter(Int32 vcenter) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction Console::changeVSizeAdjust(bool increase) +void Console::changeVSizeAdjust(int direction) { Int32 newAdjustVSize = myTIA->adjustVSize(); - if(increase) // increase scanline adjustment - newAdjustVSize++; - else // decrease scanline adjustment - newAdjustVSize--; - newAdjustVSize = BSPF::clamp(newAdjustVSize, -5, 5); + newAdjustVSize = BSPF::clamp(newAdjustVSize + direction, -5, 5); if (newAdjustVSize != myTIA->adjustVSize()) { myTIA->setAdjustVSize(newAdjustVSize); @@ -674,7 +655,6 @@ AdjustFunction Console::changeVSizeAdjust(bool increase) val << (newAdjustVSize ? newAdjustVSize > 0 ? "+" : "" : " ") << newAdjustVSize << "%"; myOSystem.frameBuffer().showMessage("V-Size", val.str(), newAdjustVSize, -5, 5); - return std::bind(&Console::changeVSizeAdjust, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Console.hxx b/src/emucore/Console.hxx index 8c48575ad..bcf4d2cf2 100644 --- a/src/emucore/Console.hxx +++ b/src/emucore/Console.hxx @@ -189,14 +189,14 @@ class Console : public Serializable, public ConsoleIO /** Toggle between NTSC/PAL/SECAM (and variants) display format. - @param next Select next if true, else previous + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction selectFormat(bool next = true); + void selectFormat(int direction = +1); /** Set NTSC/PAL/SECAM (and variants) display format. */ - void setFormat(uInt32 format); + void setFormat(uInt32 format, bool force = false); /** Get NTSC/PAL/SECAM (and variants) display format name @@ -217,14 +217,14 @@ class Console : public Serializable, public ConsoleIO /** Toggles phosphor effect. */ - AdjustFunction togglePhosphor(); + void togglePhosphor(); /** Change the "Display.PPBlend" variable. - @param increase Increase if true, else decrease + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction changePhosphor(bool increase = true); + void changePhosphor(int direction = +1); /** Toggles the PAL color-loss effect. @@ -257,18 +257,18 @@ class Console : public Serializable, public ConsoleIO /** Change the "Display.VCenter" variable. - @param increase Increase if true, else decrease + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction changeVerticalCenter(bool increase = true); + void changeVerticalCenter(int direction = +1); /** Change the "TIA scanline adjust" variable. Note that there are currently two of these (NTSC and PAL). The currently active mode will determine which one is used. - @param increase Increase if true, else decrease + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction changeVSizeAdjust(bool increase = true); + void changeVSizeAdjust(int direction = +1); /** Returns the current framerate. diff --git a/src/emucore/Event.hxx b/src/emucore/Event.hxx index 2102b57f6..fa8a4d04d 100644 --- a/src/emucore/Event.hxx +++ b/src/emucore/Event.hxx @@ -122,7 +122,7 @@ class Event ToggleFrameStats, ToggleSAPortOrder, ExitGame, // add new events from here to avoid that user remapped events get overwritten - SettingDecrease, SettingIncrease, + SettingDecrease, SettingIncrease, PreviousSetting, NextSetting, LastType }; diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 883d2b744..303f8061f 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -342,6 +342,78 @@ void EventHandler::handleSystemEvent(SystemEvent e, int, int) } } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +AdjustFunction EventHandler::cycleAdjustSetting(int direction) +{ + const bool isFullScreen = myOSystem.frameBuffer().fullScreen(); + const bool isCustomPalette = + myOSystem.settings().getString("palette") == PaletteHandler::SETTING_CUSTOM; + const bool isCustomFilter = + myOSystem.settings().getInt("tv.filter") == int(NTSCFilter::Preset::CUSTOM); + + do + { + myAdjustSetting = + AdjustSetting(BSPF::clampw(int(myAdjustSetting) + direction, 0, int(AdjustSetting::MAX_ADJ))); + // skip currently non-relevant adjustments + } while((myAdjustSetting == AdjustSetting::OVERSCAN && !isFullScreen) + || (myAdjustSetting == AdjustSetting::PALETTE_PHASE && !isCustomPalette) + || (myAdjustSetting >= AdjustSetting::NTSC_SHARPNESS + && myAdjustSetting <= AdjustSetting::NTSC_BLEEDING + && !isCustomFilter)); + + return getAdjustSetting(myAdjustSetting); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +AdjustFunction EventHandler::getAdjustSetting(AdjustSetting setting) +{ + // MUST have the same order as AdjustSetting + const AdjustFunction ADJUST_FUNCTIONS[int(AdjustSetting::NUM_ADJ)] = + { + std::bind(&Sound::adjustVolume, &myOSystem.sound(), _1), + std::bind(&FrameBuffer::selectVidMode, &myOSystem.frameBuffer(), _1), + std::bind(&FrameBuffer::changeOverscan, &myOSystem.frameBuffer(), _1), + std::bind(&Console::selectFormat, &myOSystem.console(), _1), + std::bind(&Console::changeVerticalCenter, &myOSystem.console(), _1), + std::bind(&Console::changeVSizeAdjust, &myOSystem.console(), _1), + // Palette adjustables + std::bind(&PaletteHandler::cyclePalette, &myOSystem.frameBuffer().tiaSurface().paletteHandler(), _1), + std::bind(&PaletteHandler::changeAdjustable, &myOSystem.frameBuffer().tiaSurface().paletteHandler(), + PaletteHandler::PHASE_SHIFT, _1), + std::bind(&PaletteHandler::changeAdjustable, &myOSystem.frameBuffer().tiaSurface().paletteHandler(), + PaletteHandler::HUE, _1), + std::bind(&PaletteHandler::changeAdjustable, &myOSystem.frameBuffer().tiaSurface().paletteHandler(), + PaletteHandler::SATURATION, _1), + std::bind(&PaletteHandler::changeAdjustable, &myOSystem.frameBuffer().tiaSurface().paletteHandler(), + PaletteHandler::CONTRAST, _1), + std::bind(&PaletteHandler::changeAdjustable, &myOSystem.frameBuffer().tiaSurface().paletteHandler(), + PaletteHandler::BRIGHTNESS, _1), + std::bind(&PaletteHandler::changeAdjustable, &myOSystem.frameBuffer().tiaSurface().paletteHandler(), + PaletteHandler::GAMMA, _1), + // NTSC filter adjustables + std::bind(&TIASurface::changeNTSC, &myOSystem.frameBuffer().tiaSurface(), _1), + std::bind(&TIASurface::changeNTSCAdjustable, &myOSystem.frameBuffer().tiaSurface(), + int(NTSCFilter::Adjustables::SHARPNESS), _1), + std::bind(&TIASurface::changeNTSCAdjustable, &myOSystem.frameBuffer().tiaSurface(), + int(NTSCFilter::Adjustables::RESOLUTION), _1), + std::bind(&TIASurface::changeNTSCAdjustable, &myOSystem.frameBuffer().tiaSurface(), + int(NTSCFilter::Adjustables::ARTIFACTS), _1), + std::bind(&TIASurface::changeNTSCAdjustable, &myOSystem.frameBuffer().tiaSurface(), + int(NTSCFilter::Adjustables::FRINGING), _1), + std::bind(&TIASurface::changeNTSCAdjustable, &myOSystem.frameBuffer().tiaSurface(), + int(NTSCFilter::Adjustables::BLEEDING), _1), + std::bind(&Console::changePhosphor, &myOSystem.console(), _1), + std::bind(&TIASurface::setScanlineIntensity, &myOSystem.frameBuffer().tiaSurface(), _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), + std::bind(&TIASurface::changeCurrentNTSCAdjustable, &myOSystem.frameBuffer().tiaSurface(), _1), + }; + + return ADJUST_FUNCTIONS[int(setting)]; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) { @@ -349,30 +421,61 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) // or need to be preprocessed before passing them on const bool pressed = (value != 0); - // The global settings keys react as long as the setting message from the previous event is - // still displayed. When no message is displayed, volume adjustment will be the default event. - if(!myOSystem.frameBuffer().messageShown() || myAdjustFunction == nullptr) - myAdjustFunction = std::bind(&Sound::adjustVolume, &myOSystem.sound(), std::placeholders::_1); - - // Assume no adjust function will be pressed - const AdjustFunction oldAdjustFunction = myAdjustFunction; + // The global settings keys change settings or values as long as the setting + // message from the previous settings event is still displayed. + // Therefore, do not change global settings/values or direct values if + // a) the setting message is no longer shown + // b) other keys have been pressed + if(!myOSystem.frameBuffer().messageShown()) + { + myAdjustActive = false; + myAdjustDirect = AdjustSetting::NONE; + } + const bool adjustActive = myAdjustActive; + const AdjustSetting adjustDirect = myAdjustDirect; if(pressed) - myAdjustFunction = nullptr; + { + myAdjustActive = false; + myAdjustDirect = AdjustSetting::NONE; + } switch(event) { //////////////////////////////////////////////////////////////////////// - // Allow adjusting several (mostly repeated) settings using the same two hotkeys - case Event::SettingDecrease: - if(pressed && oldAdjustFunction != nullptr) - oldAdjustFunction(false); - myAdjustFunction = oldAdjustFunction; - return; + // Allow adjusting several (mostly repeated) settings using the same four hotkeys + case Event::PreviousSetting: + case Event::NextSetting: + if(pressed && !repeated) + { + const int direction = event == Event::PreviousSetting ? -1 : +1; + // Get (and display) the previous|next adjustment function, + // but do not change its value + cycleAdjustSetting(adjustActive ? direction : 0)(0); + myAdjustActive = true; + } + break; + + case Event::SettingDecrease: case Event::SettingIncrease: - if(pressed && oldAdjustFunction != nullptr) - oldAdjustFunction(true); - myAdjustFunction = oldAdjustFunction; + if(pressed) + { + const int direction = event == Event::SettingDecrease ? -1 : +1; + + // if a "direct only" hotkey was pressed last, use this one + if(adjustDirect != AdjustSetting::NONE) + { + myAdjustDirect = adjustDirect; + getAdjustSetting(myAdjustDirect)(direction); + } + else + { + // Get (and display) the current adjustment function, + // but only change its value if the function was already active before + getAdjustSetting(myAdjustSetting)(adjustActive ? direction : 0); + myAdjustActive = true; + } + } return; //////////////////////////////////////////////////////////////////////// @@ -419,76 +522,124 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) //////////////////////////////////////////////////////////////////////// case Event::Fry: - if (!repeated) myFryingFlag = pressed; + if(!repeated) myFryingFlag = pressed; return; case Event::ReloadConsole: - if (pressed && !repeated) myOSystem.reloadConsole(); + if(pressed && !repeated) myOSystem.reloadConsole(); return; case Event::VolumeDecrease: if(pressed) - myAdjustFunction = myOSystem.sound().adjustVolume(false); + { + myOSystem.sound().adjustVolume(-1); + myAdjustSetting = AdjustSetting::VOLUME; + myAdjustActive = true; + } return; case Event::VolumeIncrease: if(pressed) - myAdjustFunction = myOSystem.sound().adjustVolume(true); + { + myOSystem.sound().adjustVolume(+1); + myAdjustSetting = AdjustSetting::VOLUME; + myAdjustActive = true; + } return; case Event::SoundToggle: if(pressed && !repeated) + { myOSystem.sound().toggleMute(); + myAdjustSetting = AdjustSetting::VOLUME; + myAdjustActive = true; + } return; case Event::VidmodeDecrease: if(pressed) - myAdjustFunction = myOSystem.frameBuffer().selectVidMode(false); + { + myOSystem.frameBuffer().selectVidMode(-1); + myAdjustSetting = AdjustSetting::ZOOM; + myAdjustActive = true; + } return; case Event::VidmodeIncrease: if(pressed) - myAdjustFunction = myOSystem.frameBuffer().selectVidMode(true); + { + myOSystem.frameBuffer().selectVidMode(+1); + myAdjustSetting = AdjustSetting::ZOOM; + myAdjustActive = true; + } return; case Event::VCenterDecrease: - if (pressed) - myAdjustFunction = myOSystem.console().changeVerticalCenter(false); + if(pressed) + { + myOSystem.console().changeVerticalCenter(-1); + myAdjustSetting = AdjustSetting::VCENTER; + myAdjustActive = true; + } return; case Event::VCenterIncrease: - if (pressed) - myAdjustFunction = myOSystem.console().changeVerticalCenter(true); + if(pressed) + { + myOSystem.console().changeVerticalCenter(+1); + myAdjustSetting = AdjustSetting::VCENTER; + myAdjustActive = true; + } return; case Event::VSizeAdjustDecrease: - if (pressed) - myAdjustFunction = myOSystem.console().changeVSizeAdjust(false); + if(pressed) + { + myOSystem.console().changeVSizeAdjust(-1); + myAdjustSetting = AdjustSetting::VSIZE; + myAdjustActive = true; + } return; case Event::VSizeAdjustIncrease: - if (pressed) - myAdjustFunction = myOSystem.console().changeVSizeAdjust(true); + if(pressed) + { + myOSystem.console().changeVSizeAdjust(+1); + myAdjustSetting = AdjustSetting::VSIZE; + myAdjustActive = true; + } return; case Event::PreviousPaletteAttribute: if(pressed) - myAdjustFunction = myOSystem.frameBuffer().tiaSurface().paletteHandler().cycleAdjustable(false); + { + myOSystem.frameBuffer().tiaSurface().paletteHandler().cycleAdjustable(-1); + myAdjustDirect = AdjustSetting::PALETTE_CHANGE_ATTRIBUTE; + } return; case Event::NextPaletteAttribute: if(pressed) - myAdjustFunction = myOSystem.frameBuffer().tiaSurface().paletteHandler().cycleAdjustable(true); + { + myOSystem.frameBuffer().tiaSurface().paletteHandler().cycleAdjustable(+1); + myAdjustDirect = AdjustSetting::PALETTE_CHANGE_ATTRIBUTE; + } return; case Event::PaletteAttributeDecrease: if(pressed) - myAdjustFunction = myOSystem.frameBuffer().tiaSurface().paletteHandler().changeAdjustable(false); + { + myOSystem.frameBuffer().tiaSurface().paletteHandler().changeCurrentAdjustable(-1); + myAdjustDirect = AdjustSetting::PALETTE_CHANGE_ATTRIBUTE; + } return; case Event::PaletteAttributeIncrease: if(pressed) - myAdjustFunction = myOSystem.frameBuffer().tiaSurface().paletteHandler().changeAdjustable(true); + { + myOSystem.frameBuffer().tiaSurface().paletteHandler().changeCurrentAdjustable(+1); + myAdjustDirect = AdjustSetting::PALETTE_CHANGE_ATTRIBUTE; + } return; case Event::ToggleFullScreen: @@ -496,23 +647,39 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::OverscanDecrease: - if (pressed) - myAdjustFunction = myOSystem.frameBuffer().changeOverscan(false); + if(pressed) + { + myOSystem.frameBuffer().changeOverscan(-1); + myAdjustSetting = AdjustSetting::OVERSCAN; + myAdjustActive = true; + } return; case Event::OverscanIncrease: - if (pressed) - myAdjustFunction = myOSystem.frameBuffer().changeOverscan(true); + if(pressed) + { + myOSystem.frameBuffer().changeOverscan(+1); + myAdjustSetting = AdjustSetting::OVERSCAN; + myAdjustActive = true; + } return; case Event::PreviousVideoMode: - if (pressed && !repeated) - myAdjustFunction = myOSystem.frameBuffer().tiaSurface().changeNTSC(false); + if(pressed && !repeated) + { + myOSystem.frameBuffer().tiaSurface().changeNTSC(-1); + myAdjustSetting = AdjustSetting::NTSC_PRESET; + myAdjustActive = true; + } return; case Event::NextVideoMode: - if (pressed && !repeated) - myAdjustFunction = myOSystem.frameBuffer().tiaSurface().changeNTSC(true); + if(pressed && !repeated) + { + myOSystem.frameBuffer().tiaSurface().changeNTSC(+1); + myAdjustSetting = AdjustSetting::NTSC_PRESET; + myAdjustActive = true; + } return; case Event::VidmodeStd: @@ -541,47 +708,80 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) case Event::PreviousAttribute: if(pressed) - myAdjustFunction = myOSystem.frameBuffer().tiaSurface().setNTSCAdjustable(false); + { + myOSystem.frameBuffer().tiaSurface().setNTSCAdjustable(-1); + myAdjustDirect = AdjustSetting::NTSC_CHANGE_ATTRIBUTE; + } return; case Event::NextAttribute: - if (pressed) - myAdjustFunction = myOSystem.frameBuffer().tiaSurface().setNTSCAdjustable(true); + if(pressed) + { + myOSystem.frameBuffer().tiaSurface().setNTSCAdjustable(+1); + myAdjustDirect = AdjustSetting::NTSC_CHANGE_ATTRIBUTE; + } return; case Event::DecreaseAttribute: if(pressed) - myAdjustFunction = myOSystem.frameBuffer().tiaSurface().changeNTSCAdjustable(false); + { + myOSystem.frameBuffer().tiaSurface().changeCurrentNTSCAdjustable(-1); + myAdjustDirect = AdjustSetting::NTSC_CHANGE_ATTRIBUTE; + } return; case Event::IncreaseAttribute: if(pressed) - myAdjustFunction = myOSystem.frameBuffer().tiaSurface().changeNTSCAdjustable(true); + { + myOSystem.frameBuffer().tiaSurface().changeCurrentNTSCAdjustable(+1); + myAdjustDirect = AdjustSetting::NTSC_CHANGE_ATTRIBUTE; + } return; case Event::ScanlinesDecrease: - if (pressed) - myAdjustFunction = myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(false); + if(pressed) + { + myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(-1); + myAdjustSetting = AdjustSetting::SCANLINES; + myAdjustActive = true; + + } return; case Event::ScanlinesIncrease: - if (pressed) - myAdjustFunction = myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(true); + if(pressed) + { + myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(+1); + myAdjustSetting = AdjustSetting::SCANLINES; + myAdjustActive = true; + } return; case Event::PhosphorDecrease: - if (pressed) - myAdjustFunction = myOSystem.console().changePhosphor(false); + if(pressed) + { + myOSystem.console().changePhosphor(-1); + myAdjustSetting = AdjustSetting::PHOSPHOR; + myAdjustActive = true; + } return; case Event::PhosphorIncrease: - if (pressed) - myAdjustFunction = myOSystem.console().changePhosphor(true); + if(pressed) + { + myOSystem.console().changePhosphor(+1); + myAdjustSetting = AdjustSetting::PHOSPHOR; + myAdjustActive = true; + } return; case Event::TogglePhosphor: if(pressed && !repeated) - myAdjustFunction = myOSystem.console().togglePhosphor(); + { + myOSystem.console().togglePhosphor(); + myAdjustSetting = AdjustSetting::PHOSPHOR; + myAdjustActive = true; + } return; case Event::ToggleColorLoss: @@ -589,13 +789,21 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::PaletteDecrease: - if (pressed && !repeated) - myAdjustFunction = myOSystem.frameBuffer().tiaSurface().paletteHandler().cyclePalette(false); + if(pressed && !repeated) + { + myOSystem.frameBuffer().tiaSurface().paletteHandler().cyclePalette(-1); + myAdjustSetting = AdjustSetting::PALETTE; + myAdjustActive = true; + } return; case Event::PaletteIncrease: - if (pressed && !repeated) - myAdjustFunction = myOSystem.frameBuffer().tiaSurface().paletteHandler().cyclePalette(true); + if(pressed && !repeated) + { + myOSystem.frameBuffer().tiaSurface().paletteHandler().cyclePalette(+1); + myAdjustSetting = AdjustSetting::PALETTE; + myAdjustActive = true; + } return; case Event::ToggleInter: @@ -637,13 +845,21 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::FormatDecrease: - if (pressed && !repeated) - myAdjustFunction = myOSystem.console().selectFormat(false); + if(pressed && !repeated) + { + myOSystem.console().selectFormat(-1); + myAdjustSetting = AdjustSetting::TVFORMAT; + myAdjustActive = true; + } return; case Event::FormatIncrease: - if (pressed && !repeated) - myAdjustFunction = myOSystem.console().selectFormat(true); + if(pressed && !repeated) + { + myOSystem.console().selectFormat(+1); + myAdjustSetting = AdjustSetting::TVFORMAT; + myAdjustActive = true; + } return; case Event::ToggleGrabMouse: @@ -713,7 +929,10 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) case Event::SaveState: if(pressed && !repeated) - myAdjustFunction = myOSystem.state().saveState(); + { + myOSystem.state().saveState(); + myAdjustDirect = AdjustSetting::STATE; + } return; case Event::SaveAllStates: @@ -722,13 +941,19 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::PreviousState: - if (pressed) - myAdjustFunction = myOSystem.state().changeState(false); + if(pressed) + { + myOSystem.state().changeState(-1); + myAdjustDirect = AdjustSetting::STATE; + } return; case Event::NextState: if(pressed) - myAdjustFunction = myOSystem.state().changeState(true); + { + myOSystem.state().changeState(+1); + myAdjustDirect = AdjustSetting::STATE; + } return; case Event::ToggleAutoSlot: @@ -737,7 +962,10 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) case Event::LoadState: if(pressed && !repeated) - myAdjustFunction = myOSystem.state().loadState(); + { + myOSystem.state().loadState(); + myAdjustDirect = AdjustSetting::STATE; + } return; case Event::LoadAllStates: @@ -2011,6 +2239,8 @@ EventHandler::EmulActionList EventHandler::ourEmulActionList = { { { Event::ScanlinesDecrease, "Decrease scanlines", "" }, { Event::ScanlinesIncrease, "Increase scanlines", "" }, + { Event::PreviousSetting, "Select previous setting", "" }, + { Event::NextSetting, "Select next setting", "" }, { Event::SettingDecrease, "Decrease current setting", "" }, { Event::SettingIncrease, "Increase current setting", "" }, @@ -2108,7 +2338,8 @@ const Event::EventSet EventHandler::MiscEvents = { // Event::MouseButtonLeftValue, Event::MouseButtonRightValue, Event::HandleMouseControl, Event::ToggleGrabMouse, Event::ToggleSAPortOrder, - Event::SettingDecrease, Event::SettingIncrease + Event::SettingDecrease, Event::SettingIncrease, + Event::PreviousSetting, Event::NextSetting, }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx index 4b7e91af1..6051a9961 100644 --- a/src/emucore/EventHandler.hxx +++ b/src/emucore/EventHandler.hxx @@ -391,6 +391,41 @@ class EventHandler */ void removePhysicalJoystick(int index); + private: + enum class AdjustSetting + { + NONE = -1, + VOLUME, + ZOOM, + OVERSCAN, + TVFORMAT, + VCENTER, + VSIZE, + // Palette adjustables + PALETTE, + PALETTE_PHASE, + PALETTE_HUE, + PALETTE_SATURATION, + PALETTE_CONTRAST, + PALETTE_BRIGHTNESS, + PALETTE_GAMMA, + // NTSC filter adjustables + NTSC_PRESET, + NTSC_SHARPNESS, + NTSC_RESOLUTION, + NTSC_ARTIFACTS, + NTSC_FRINGING, + NTSC_BLEEDING, + PHOSPHOR, + SCANLINES, + MAX_ADJ = SCANLINES, + // Only used via direct hotkeys + STATE, + PALETTE_CHANGE_ATTRIBUTE, + NTSC_CHANGE_ATTRIBUTE, + NUM_ADJ + }; + private: // Define event groups static const Event::EventSet MiscEvents; @@ -417,6 +452,11 @@ class EventHandler int getEmulActionListIndex(int idx, const Event::EventSet& events) const; int getActionListIndex(int idx, Event::Group group) const; + // The following two methods are used for adjusting several settings using global hotkeys + // They return the function used to adjust the currenly selected setting + AdjustFunction cycleAdjustSetting(int direction); + AdjustFunction getAdjustSetting(AdjustSetting setting); + private: // Structure used for action menu items struct ActionList { @@ -425,7 +465,12 @@ class EventHandler string key; }; - AdjustFunction myAdjustFunction{nullptr}; + // 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 direct hotkey setting (0 if none) + AdjustSetting myAdjustDirect{AdjustSetting::NONE}; // Global Event object Event myEvent; @@ -470,7 +515,7 @@ class EventHandler #else PNG_SIZE = 0, #endif - EMUL_ACTIONLIST_SIZE = 154 + PNG_SIZE + COMBO_SIZE, + EMUL_ACTIONLIST_SIZE = 156 + PNG_SIZE + COMBO_SIZE, MENU_ACTIONLIST_SIZE = 18 ; diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index dd88c3020..c49f592a2 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -537,7 +537,7 @@ void FrameBuffer::showMessage(const string& message, const string& valueText, const int VBORDER = fontHeight / 4; const int HBORDER = fontWidth * 1.25 / 2.0; - myMsg.counter = uInt32(myOSystem.frameRate()) * 3; // Show message for 3 seconds + myMsg.counter = uInt32(myOSystem.frameRate()) * 2; // Show message for 2 seconds if(myMsg.counter == 0) myMsg.counter = 120; @@ -672,7 +672,6 @@ inline bool FrameBuffer::drawMessage() #ifdef GUI_SUPPORT // Either erase the entire message (when time is reached), // or show again this frame - cerr << myMsg.counter << endl; if(myMsg.counter == 0) { myMsg.enabled = false; @@ -760,7 +759,7 @@ inline bool FrameBuffer::drawMessage() // align bar with bottom of text const int y = VBORDER + font().desc().ascent - bheight; - // draw gauge bar + // draw gauge bar myMsg.surface->fillRect(x - BORDER, y, swidth + BORDER * 2, bheight, kSliderBGColor); myMsg.surface->fillRect(x, y + BORDER, bwidth, bheight - BORDER * 2, kSliderColor); // draw tickmark in the middle of the bar @@ -994,12 +993,12 @@ void FrameBuffer::toggleFullscreen() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction FrameBuffer::changeOverscan(bool increase) +void FrameBuffer::changeOverscan(int direction) { if (fullScreen()) { int oldOverscan = myOSystem.settings().getInt("tia.fs_overscan"); - int overscan = BSPF::clamp(oldOverscan + (increase ? 1 : -1), 0, 10); + int overscan = BSPF::clamp(oldOverscan + direction, 0, 10); if (overscan != oldOverscan) { @@ -1010,14 +1009,16 @@ AdjustFunction FrameBuffer::changeOverscan(bool increase) } ostringstream val; - val << (overscan ? overscan > 0 ? "+" : "" : " ") << overscan << "%"; + if(overscan) + val << (overscan > 0 ? "+" : "" ) << overscan << "%"; + else + val << "Off"; myOSystem.frameBuffer().showMessage("Overscan", val.str(), overscan, 0, 10); } - return std::bind(&FrameBuffer::changeOverscan, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction FrameBuffer::selectVidMode(bool next) +void FrameBuffer::selectVidMode(int direction) { EventHandlerState state = myOSystem.eventHandler().state(); bool tiaMode = (state != EventHandlerState::DEBUGGER && @@ -1025,11 +1026,11 @@ AdjustFunction FrameBuffer::selectVidMode(bool next) // Only applicable when in TIA/emulation mode if(!tiaMode) - return nullptr; + return; - if(next) + if(direction == +1) myCurrentModeList->next(); - else + else if(direction == -1) myCurrentModeList->previous(); saveCurrentWindowPosition(); @@ -1050,7 +1051,10 @@ AdjustFunction FrameBuffer::selectVidMode(bool next) myTIASurface->initialize(myOSystem.console(), mode); resetSurfaces(); - showMessage("Zoom", mode.description, mode.zoom, supportedTIAMinZoom(), myTIAMaxZoom); + if(fullScreen()) + showMessage(mode.description); + else + showMessage("Zoom", mode.description, mode.zoom, supportedTIAMinZoom(), myTIAMaxZoom); myOSystem.sound().mute(oldMuteState); if(fullScreen()) @@ -1059,11 +1063,9 @@ AdjustFunction FrameBuffer::selectVidMode(bool next) else myOSystem.settings().setValue("tia.zoom", mode.zoom); - return std::bind(&FrameBuffer::selectVidMode, this, std::placeholders::_1); + return; } myOSystem.sound().mute(oldMuteState); - - return nullptr; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1196,12 +1198,12 @@ void FrameBuffer::setAvailableVidModes(uInt32 baseWidth, uInt32 baseHeight) VideoMode mode1(baseWidth * myTIAMaxZoom, baseHeight * myTIAMaxZoom, myFullscreenDisplays[i].w, myFullscreenDisplays[i].h, VideoMode::Stretch::Preserve, overscan, - "Preserve aspect, no stretch", myTIAMaxZoom, i); + "Fullscreen: Preserve aspect, no stretch", myTIAMaxZoom, i); myFullscreenModeLists[i].add(mode1); VideoMode mode2(baseWidth * myTIAMaxZoom, baseHeight * myTIAMaxZoom, myFullscreenDisplays[i].w, myFullscreenDisplays[i].h, VideoMode::Stretch::Fill, overscan, - "Ignore aspect, full stretch", myTIAMaxZoom, i); + "Fullscreen: Ignore aspect, full stretch", myTIAMaxZoom, i); myFullscreenModeLists[i].add(mode2); } } diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index 4dd55f7f5..52f6eeae7 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -265,9 +265,9 @@ class FrameBuffer /** Changes the fullscreen overscan. - @param increase Increase if true, else decrease + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction changeOverscan(bool increase = true); + void changeOverscan(int direction = +1); /** This method is called when the user wants to switch to the next @@ -277,9 +277,9 @@ class FrameBuffer direction = -1 means go to the next lower video mode direction = +1 means go to the next higher video mode - @param next Select next if true, else previous + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction selectVidMode(bool next = true); + void selectVidMode(int direction = +1); /** Sets the state of the cursor (hidden or grabbed) based on the diff --git a/src/emucore/Sound.hxx b/src/emucore/Sound.hxx index a03223f71..4e1fda0d5 100644 --- a/src/emucore/Sound.hxx +++ b/src/emucore/Sound.hxx @@ -88,10 +88,9 @@ class Sound /** Adjusts the volume of the sound device based on the given direction. - @param increase Increase or decrease the current volume by a predefined - amount + @param direction +1 indicates increase, -1 indicates decrease. */ - virtual AdjustFunction adjustVolume(bool increase) = 0; + virtual void adjustVolume(int direction = 1) = 0; /** This method is called to provide information about the sound device. diff --git a/src/emucore/TIASurface.cxx b/src/emucore/TIASurface.cxx index 88a41415c..afaad7855 100644 --- a/src/emucore/TIASurface.cxx +++ b/src/emucore/TIASurface.cxx @@ -200,7 +200,7 @@ void TIASurface::setNTSC(NTSCFilter::Preset preset, bool show) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction TIASurface::changeNTSC(bool next) +void TIASurface::changeNTSC(int direction) { constexpr NTSCFilter::Preset PRESETS[] = { NTSCFilter::Preset::OFF, NTSCFilter::Preset::RGB, NTSCFilter::Preset::SVIDEO, @@ -208,14 +208,14 @@ AdjustFunction TIASurface::changeNTSC(bool next) }; int preset = myOSystem.settings().getInt("tv.filter"); - if(next) + if(direction == +1) { if(preset == int(NTSCFilter::Preset::CUSTOM)) preset = int(NTSCFilter::Preset::OFF); else preset++; } - else + else if (direction == -1) { if(preset == int(NTSCFilter::Preset::OFF)) preset = int(NTSCFilter::Preset::CUSTOM); @@ -223,39 +223,46 @@ AdjustFunction TIASurface::changeNTSC(bool next) preset--; } setNTSC(PRESETS[preset], true); - return std::bind(&TIASurface::changeNTSC, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction TIASurface::setNTSCAdjustable(bool next) +void TIASurface::setNTSCAdjustable(int direction) { string text, valueText; Int32 value; setNTSC(NTSCFilter::Preset::CUSTOM); - ntsc().selectAdjustable(next, text, valueText, value); + ntsc().selectAdjustable(direction, text, valueText, value); myOSystem.frameBuffer().showMessage(text, valueText, value); - return std::bind(&TIASurface::changeNTSCAdjustable, this, std::placeholders::_1); - } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction TIASurface::changeNTSCAdjustable(bool increase) +void TIASurface::changeNTSCAdjustable(int adjustable, int direction) { string text, valueText; Int32 newValue; setNTSC(NTSCFilter::Preset::CUSTOM); - ntsc().changeAdjustable(increase, text, valueText, newValue); + ntsc().changeAdjustable(adjustable, direction, text, valueText, newValue); myOSystem.frameBuffer().showMessage(text, valueText, newValue); - return std::bind(&TIASurface::changeNTSCAdjustable, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction TIASurface::setScanlineIntensity(bool increase) +void TIASurface::changeCurrentNTSCAdjustable(int direction) +{ + string text, valueText; + Int32 newValue; + + setNTSC(NTSCFilter::Preset::CUSTOM); + ntsc().changeCurrentAdjustable(direction, text, valueText, newValue); + myOSystem.frameBuffer().showMessage(text, valueText, newValue); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIASurface::setScanlineIntensity(int direction) { ostringstream buf; - uInt32 intensity = enableScanlines(increase ? 2 : -2); + uInt32 intensity = enableScanlines(direction * 2); myOSystem.settings().setValue("tv.scanlines", intensity); enableNTSC(ntscEnabled()); @@ -265,18 +272,15 @@ AdjustFunction TIASurface::setScanlineIntensity(bool increase) else buf << "Off"; myFB.showMessage("Scanline intensity", buf.str(), intensity); - return std::bind(&TIASurface::setScanlineIntensity, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 TIASurface::enableScanlines(int relative, int absolute) +uInt32 TIASurface::enableScanlines(int change) { FBSurface::Attributes& attr = mySLineSurface->attributes(); - if(relative == 0) attr.blendalpha = absolute; - else attr.blendalpha += relative; - attr.blendalpha = std::max(0, Int32(attr.blendalpha)); - attr.blendalpha = std::min(100U, attr.blendalpha); + attr.blendalpha += change; + attr.blendalpha = BSPF::clamp(Int32(attr.blendalpha), 0, 100); mySLineSurface->applyAttributes(); return attr.blendalpha; diff --git a/src/emucore/TIASurface.hxx b/src/emucore/TIASurface.hxx index ecb1de752..826ff75d9 100644 --- a/src/emucore/TIASurface.hxx +++ b/src/emucore/TIASurface.hxx @@ -91,18 +91,32 @@ class TIASurface /** Switch to next/previous NTSC filtering effect. + + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction changeNTSC(bool next); + void changeNTSC(int direction = +1); /** Switch to next/previous NTSC filtering adjustable. + + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction setNTSCAdjustable(bool next = true); + void setNTSCAdjustable(int direction = +1); + + /** + Increase/decrease given NTSC filtering adjustable. + + @param adjustable The adjustable to change + @param direction +1 indicates increase, -1 indicates decrease. + */ + void changeNTSCAdjustable(int adjustable, int direction); /** Increase/decrease current NTSC filtering adjustable. + + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction changeNTSCAdjustable(bool increase = true); + void changeCurrentNTSCAdjustable(int direction = +1); /** Retrieve palette handler. @@ -111,17 +125,18 @@ class TIASurface /** Increase/decrease current scanline intensity by given relative amount. + + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction setScanlineIntensity(bool increase); + void setScanlineIntensity(int direction = +1); /** Change scanline intensity and interpolation. - @param relative If non-zero, change current intensity by - 'relative' amount, otherwise set to 'absolute' + @param change change current intensity by 'change' @return New current intensity */ - uInt32 enableScanlines(int relative, int absolute = 50); + uInt32 enableScanlines(int change); /** Enable/disable/query phosphor effect. diff --git a/src/libretro/SoundLIBRETRO.hxx b/src/libretro/SoundLIBRETRO.hxx index ad5966a9c..f99c8f341 100644 --- a/src/libretro/SoundLIBRETRO.hxx +++ b/src/libretro/SoundLIBRETRO.hxx @@ -95,10 +95,9 @@ class SoundLIBRETRO : public Sound /** Adjusts the volume of the sound device based on the given direction. - @param increase Increase or decrease the current volume by a predefined - amount + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction adjustVolume(bool increase) override { return nullptr; } + void adjustVolume(int direction = +1) override { } /** This method is called to provide information about the sound device. From 15dbea7d742b300cdcf1f0960b36292915bbba8f Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 16 May 2020 13:00:38 +0200 Subject: [PATCH 224/377] added two more methods to global hotkeys updated and restructured hotkey documentation --- Changes.txt | 11 +- docs/index.html | 290 ++++++++++++++++++-------------- src/common/PKeyboardHandler.cxx | 5 + src/emucore/Console.cxx | 9 +- src/emucore/Console.hxx | 2 +- src/emucore/EventHandler.cxx | 38 +++-- src/emucore/EventHandler.hxx | 4 +- src/emucore/FrameBuffer.cxx | 8 +- src/emucore/FrameBuffer.hxx | 2 +- 9 files changed, 219 insertions(+), 150 deletions(-) diff --git a/Changes.txt b/Changes.txt index 83f2abc26..557157f25 100644 --- a/Changes.txt +++ b/Changes.txt @@ -22,6 +22,11 @@ * Added 'Custom' palette, generated from user controlled phase shifts. + * 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 + * Added 'Turbo' mode, runs the game as fast as the computer allows. * Added that paddle centering (per ROM) and sensitivity can be adjusted @@ -39,6 +44,9 @@ * Added displaying last write address in the debugger. + * Added debugger pseudo-register '_scanend', which gives the number of + scanlines at the end of the last frame. + * Added detection of color and audio data in DiStella. * Restored 'cfg' directory for Distella config files. @@ -47,9 +55,6 @@ * Removed unused CV+ and DASH bank switching types. - * Added debugger pseudo-register '_scanend', which gives the number of - scanlines at the end of the last frame. - -Have fun! diff --git a/docs/index.html b/docs/index.html index 5c5204863..3bf9ee26a 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1336,8 +1336,100 @@ -

      Palettes (can be remapped, only active in TIA mode)

      +

      Audio & Video Keys (can be remapped)

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      FunctionKey (Standard)Key (macOS)
      Toggle soundControl + ]Control + ]
      Decrease volumeAlt + [Cmd + [
      Increase volumeAlt + ]Cmd + ]
      Switch to next larger zoom level in windowed mode, +
      toggle stretching in fullscreen mode
      Alt + =Cmd + =
      Switch to next smaller zoom level in windowed mode, +
      toggle stretching in fullscreen mode
      Alt + -Cmd + -
      Toggle windowed/fullscreen modeAlt + EnterCmd + Enter
      Decrease overscan in fullscreen modeShift + PageDownShift-Fn + Down arrow
      Increase overscan in fullscreen modeShift + PageUpShift-Fn + Up arrow
      Move display down (uses "Display.VCenter")Alt + PageDownCmd-Fn + Down arrow
      Move display up (uses "Display.VCenter")Alt + PageUpCmd-Fn + Up arrow
      Decrease vertical display sizeShift-Alt + PageUpShift-Cmd-Fn + Up arrow
      Increase vertical display sizeShift-Alt + PageDownShift-Cmd-Fn + Down arrow
      Switch to previous display format (NTSC/PAL/SECAM etc.)Shift-Control + fShift-Control + f
      Switch to next display format (NTSC/PAL/SECAM etc.)Control + fControl + f
      Toggle display interpolationControl + iControl + i
      + These settings can also be changed using Global Audio & Video Keys
      +
      + +

      Palettes Keys (can be remapped)

      @@ -1346,43 +1438,48 @@ - + - + - + - + - + - + + + +
      Function
      Select previous palette (Standard/Z26/User/Custom)Select previous palette (Standard/z26/User/Custom) Shift-Control + p Shift-Control + p
      Select next palette (Standard/Z26/User/Custom)Select next palette (Standard/z26/User/Custom) Control + p Control + p
      Select previous palette attributeSelect previous palette attribute Shift-Alt + 9 Shift-Cmd + 9
      Select next palette attributeSelect next palette attribute Alt + 9 Cmd + 9
      Decrease selected palette attributeDecrease selected palette attribute Shift-Alt + 0 Shift-Cmd + 0
      Increase selected palette attributeIncrease selected palette attribute Alt + 0 Cmd + 0
      + These settings can also be changed using Global Audio & Video Keys
      +
      -

      TV effects (can be remapped, only active in TIA mode)

      +

      TV effects Keys (can be remapped)

      @@ -1391,73 +1488,112 @@ - + - + - + - + - + - + - - - + - - + - - + - + - + These settings can also be changed using Global Audio & Video Keys + + + +
      Key (macOS)
      Select previous TV effects presetSelect previous TV effects preset Shift-Alt + 1 Shift-Cmd + 1
      Select next TV effects presetSelect next TV effects preset Alt + 1 Cmd + 1
      Select previous 'Custom' mode attribute (*)Select previous 'Custom' mode attribute (*) Shift-Alt + 2 Shift-Cmd + 2
      Select next 'Custom' mode attribute (*)Select next 'Custom' mode attribute (*) Alt + 2 Cmd + 2
      Decrease 'Custom' selected attribute value (*)Decrease 'Custom' selected attribute value (*) Shift-Alt + 3 Shift-Cmd + 3
      Increase 'Custom' selected attribute value (*)Increase 'Custom' selected attribute value (*) Alt + 3 Cmd + 3
      Toggle 'phosphor' mode Alt + p Cmd + p
      Decrease 'phosphor' blendDecrease 'phosphor' blend Shift-Alt + 4 Shift-Cmd + 4
      Increase 'phosphor' blendIncrease 'phosphor' blend Alt + 4 Cmd + 4
      Decrease scanline intensityDecrease scanline intensity Shift-Alt + 5 Shift-Cmd + 5
      Increase scanline intensityIncrease scanline intensity Alt + 5 Cmd + 5
      - Items marked as (*) will also switch to 'Custom' preset mode
      + Items marked as (*) will also switch to 'Custom' mode
      +

      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 in TIA mode (can be remapped)

      +

      Developer Keys (can be remapped)

      @@ -1575,7 +1711,7 @@
      -

      Other Keys (can be remapped)

      +

      Other Emulation Keys (can be remapped)

      @@ -1583,93 +1719,11 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1767,27 +1821,9 @@ - - - - - - - - - - - - - - -
      Key (Standard) Key (macOS)
      Switch to next larger zoom level in windowed mode, -
      toggle stretching in fullscreen mode
      Alt + =Cmd + =
      Switch to next smaller zoom level in windowed mode, -
      toggle stretching in fullscreen mode
      Alt + -Cmd + -
      Toggle fullscreen/windowed modeAlt + EnterCmd + Enter
      Decrease overscan in fullscreen modeShift + PageDownShift + PageDown
      Increase overscan in fullscreen modeShift + PageUpShift + PageUp
      Move display up (uses "Display.VCenter")Alt + PageUpCmd + PageUp
      Move display down (uses "Display.VCenter")Alt + PageDownCmd + PageDown
      Switch display format in decreasing order (NTSC/PAL/SECAM etc.)Shift-Control + fShift-Control + f
      Switch display format in increasing order (NTSC/PAL/SECAM etc.)Control + fControl + f
      Toggle display interpolationControl + iControl + i
      Toggle 'Turbo' mode Control + t Control + t
      Toggle sound on/offControl + ]Control + ]
      Decrease volumeAlt + [Cmd + [
      Increase volumeAlt + ]Cmd + ]
      Switch mouse between controller emulation modes
      (see Game Properties - Controller)
      Control + 0Alt + Up arrow Cmd + Up arrow
      Decrease current setting (*)PageDownPageDown
      Increase current setting (*) - PageUpPageUp
      - (*) Note: These keys allow easy changing of the current displayed selection (e.g. volume (default), - phosphor, zoom...) without having to use the original keys.
      -

      UI keys in Text Editing areas (cannot be remapped)

      +

      UI Keys in Text Editing areas (cannot be remapped)

      diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index c09cd48fb..cf4a31831 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -494,8 +494,13 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo {Event::PaletteDecrease, KBDK_P, KBDM_SHIFT | KBDM_CTRL}, {Event::PaletteIncrease, KBDK_P, KBDM_CTRL}, +#ifndef BSPF_MACOS {Event::PreviousSetting, KBDK_END}, {Event::NextSetting, KBDK_HOME}, +#else + {Event::PreviousSetting, KBDK_HOME}, + {Event::NextSetting, KBDK_END}, +#endif {Event::SettingDecrease, KBDK_PAGEDOWN}, {Event::SettingIncrease, KBDK_PAGEUP}, diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 1d5bb5e6c..59c5cad32 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -468,17 +468,20 @@ void Console::enableColorLoss(bool state) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::toggleInter() +void Console::toggleInter(bool toggle) { bool enabled = myOSystem.settings().getBool("tia.inter"); - myOSystem.settings().setValue("tia.inter", !enabled); + if(toggle) + enabled = !enabled; + + myOSystem.settings().setValue("tia.inter", enabled); // ... and apply potential setting changes to the TIA surface myOSystem.frameBuffer().tiaSurface().updateSurfaceSettings(); ostringstream ss; - ss << "Interpolation " << (!enabled ? "enabled" : "disabled"); + ss << "Interpolation " << (enabled ? "enabled" : "disabled"); myOSystem.frameBuffer().showMessage(ss.str()); } diff --git a/src/emucore/Console.hxx b/src/emucore/Console.hxx index bcf4d2cf2..d13588b07 100644 --- a/src/emucore/Console.hxx +++ b/src/emucore/Console.hxx @@ -206,7 +206,7 @@ class Console : public Serializable, public ConsoleIO /** Toggle interpolation on/off */ - void toggleInter(); + void toggleInter(bool toggle = true); /** Toggle turbo mode on/off diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 303f8061f..00f73f2be 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -368,11 +368,14 @@ AdjustFunction EventHandler::cycleAdjustSetting(int direction) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - AdjustFunction EventHandler::getAdjustSetting(AdjustSetting setting) { - // MUST have the same order as AdjustSetting + // Notes: + // - All methods MUST show a message + // - This array MUST have the same order as AdjustSetting const AdjustFunction ADJUST_FUNCTIONS[int(AdjustSetting::NUM_ADJ)] = { std::bind(&Sound::adjustVolume, &myOSystem.sound(), _1), std::bind(&FrameBuffer::selectVidMode, &myOSystem.frameBuffer(), _1), + std::bind(&FrameBuffer::toggleFullscreen, &myOSystem.frameBuffer(), _1), std::bind(&FrameBuffer::changeOverscan, &myOSystem.frameBuffer(), _1), std::bind(&Console::selectFormat, &myOSystem.console(), _1), std::bind(&Console::changeVerticalCenter, &myOSystem.console(), _1), @@ -405,6 +408,7 @@ AdjustFunction EventHandler::getAdjustSetting(AdjustSetting setting) int(NTSCFilter::Adjustables::BLEEDING), _1), std::bind(&Console::changePhosphor, &myOSystem.console(), _1), std::bind(&TIASurface::setScanlineIntensity, &myOSystem.frameBuffer().tiaSurface(), _1), + std::bind(&Console::toggleInter, &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), @@ -643,7 +647,12 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::ToggleFullScreen: - if (pressed && !repeated) myOSystem.frameBuffer().toggleFullscreen(); + if(pressed && !repeated) + { + myOSystem.frameBuffer().toggleFullscreen(); + myAdjustSetting = AdjustSetting::FULLSCREEN; + myAdjustActive = true; + } return; case Event::OverscanDecrease: @@ -807,7 +816,12 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::ToggleInter: - if (pressed && !repeated) myOSystem.console().toggleInter(); + if(pressed && !repeated) + { + myOSystem.console().toggleInter(); + myAdjustSetting = AdjustSetting::INTERPOLATION; + myAdjustActive = true; + } return; case Event::ToggleTurbo: @@ -2338,8 +2352,6 @@ const Event::EventSet EventHandler::MiscEvents = { // Event::MouseButtonLeftValue, Event::MouseButtonRightValue, Event::HandleMouseControl, Event::ToggleGrabMouse, Event::ToggleSAPortOrder, - Event::SettingDecrease, Event::SettingIncrease, - Event::PreviousSetting, Event::NextSetting, }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -2347,19 +2359,21 @@ const Event::EventSet EventHandler::AudioVideoEvents = { Event::VolumeDecrease, Event::VolumeIncrease, Event::SoundToggle, Event::VidmodeDecrease, Event::VidmodeIncrease, Event::ToggleFullScreen, - Event::VidmodeStd, Event::VidmodeRGB, Event::VidmodeSVideo, Event::VidModeComposite, Event::VidModeBad, Event::VidModeCustom, - Event::PreviousAttribute, Event::NextAttribute, Event::DecreaseAttribute, Event::IncreaseAttribute, - Event::ScanlinesDecrease, Event::ScanlinesIncrease, - Event::PhosphorDecrease, Event::PhosphorIncrease, Event::TogglePhosphor, + Event::OverscanDecrease, Event::OverscanIncrease, Event::FormatDecrease, Event::FormatIncrease, Event::VCenterDecrease, Event::VCenterIncrease, Event::VSizeAdjustDecrease, Event::VSizeAdjustIncrease, - Event::OverscanDecrease, Event::OverscanIncrease, Event::PaletteDecrease, Event::PaletteIncrease, - Event::PreviousVideoMode, Event::NextVideoMode, Event::PreviousPaletteAttribute, Event::NextPaletteAttribute, Event::PaletteAttributeDecrease, Event::PaletteAttributeIncrease, - Event::ToggleInter + Event::VidmodeStd, Event::VidmodeRGB, Event::VidmodeSVideo, Event::VidModeComposite, Event::VidModeBad, Event::VidModeCustom, + Event::PreviousVideoMode, Event::NextVideoMode, + Event::PreviousAttribute, Event::NextAttribute, Event::DecreaseAttribute, Event::IncreaseAttribute, + 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 6051a9961..0ab40c7cd 100644 --- a/src/emucore/EventHandler.hxx +++ b/src/emucore/EventHandler.hxx @@ -397,6 +397,7 @@ class EventHandler NONE = -1, VOLUME, ZOOM, + FULLSCREEN, OVERSCAN, TVFORMAT, VCENTER, @@ -418,7 +419,8 @@ class EventHandler NTSC_BLEEDING, PHOSPHOR, SCANLINES, - MAX_ADJ = SCANLINES, + INTERPOLATION, + MAX_ADJ = INTERPOLATION, // Only used via direct hotkeys STATE, PALETTE_CHANGE_ATTRIBUTE, diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index c49f592a2..4599a3860 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -987,9 +987,13 @@ void FrameBuffer::setFullscreen(bool enable) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBuffer::toggleFullscreen() +void FrameBuffer::toggleFullscreen(bool toggle) { - setFullscreen(!fullScreen()); + const bool isFullscreen = toggle ? !fullScreen() : fullScreen(); + + setFullscreen(isFullscreen); + + showMessage(string("Fullscreen ") + (isFullscreen ? "enabled" : "disabled")); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index 52f6eeae7..3912f38cd 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -260,7 +260,7 @@ class FrameBuffer /** Toggles between fullscreen and window mode. */ - void toggleFullscreen(); + void toggleFullscreen(bool toggle = true); /** Changes the fullscreen overscan. From 41573ca65d6eaaee921d4e8df53149e58f06bcc3 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 16 May 2020 16:42:12 +0200 Subject: [PATCH 225/377] Revert "removed audio dialog screenshot" This reverts commit a0505a9739839fb9f394291401c4e825258d8917. --- docs/graphics/options_audio.png | Bin 0 -> 3879 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/graphics/options_audio.png diff --git a/docs/graphics/options_audio.png b/docs/graphics/options_audio.png new file mode 100644 index 0000000000000000000000000000000000000000..f37f07c6f33333eb2756b43a5e6fddaf2e48ad85 GIT binary patch literal 3879 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 literal 0 HcmV?d00001 From 429232780ed476acbe445cd8de81ae009eae7702 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sat, 16 May 2020 18:41:32 -0230 Subject: [PATCH 226/377] Revert "Very small optimization for const char* instead of strings." This reverts commit 8e8db77e49dd5e5ea6c029f04aba9b73601ad97b. --- src/common/FrameBufferSDL2.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index 93a12615d..4d013a35d 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -144,11 +144,11 @@ void FrameBufferSDL2::queryHardware(vector& fullscreenRes, struct RenderName { - const char* const sdlName; - const char* const stellaName; + string sdlName; + string stellaName; }; // Create name map for all currently known SDL renderers - static constexpr std::array RENDERER_NAMES = {{ + static const std::array RENDERER_NAMES = {{ { "direct3d", "Direct3D" }, { "metal", "Metal" }, { "opengl", "OpenGL" }, From b1ea775ac35e0c96aabaa39146e0be72088db95b Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 16 May 2020 23:47:15 +0200 Subject: [PATCH 227/377] minor fix, make sure that a message is displayed when switching TV format --- src/common/PaletteHandler.hxx | 2 +- src/emucore/Console.cxx | 2 +- src/emucore/EventHandler.cxx | 3 +++ src/gui/VideoAudioDialog.cxx | 4 ++-- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/common/PaletteHandler.hxx b/src/common/PaletteHandler.hxx index 817c5fb5e..bd102d9f0 100644 --- a/src/common/PaletteHandler.hxx +++ b/src/common/PaletteHandler.hxx @@ -74,7 +74,7 @@ class PaletteHandler Increase or decrease given palette adjustable. @param adjustable The adjustable to change - @param direction +1 indicates increase, -1 indicates decrease. + @param direction +1 indicates increase, -1 indicates decrease. */ void changeAdjustable(int adjustable, int direction); diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 59c5cad32..1e796a0bd 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -373,7 +373,7 @@ void Console::setFormat(uInt32 format, bool force) { case 0: // auto-detect { - if (myFormatAutodetected) return; + if (!force && myFormatAutodetected) return; myDisplayFormat = formatFromFilename(); if (myDisplayFormat == "AUTO") diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 00f73f2be..fa87be91d 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -456,6 +456,9 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) // Get (and display) the previous|next adjustment function, // but do not change its value cycleAdjustSetting(adjustActive ? direction : 0)(0); + // Fallback message when no message is displayed by method + //if(!myOSystem.frameBuffer().messageShown()) + // myOSystem.frameBuffer().showMessage("Message " + std::to_string(int(myAdjustSetting))); myAdjustActive = true; } break; diff --git a/src/gui/VideoAudioDialog.cxx b/src/gui/VideoAudioDialog.cxx index 5d569014a..48fdcc8de 100644 --- a/src/gui/VideoAudioDialog.cxx +++ b/src/gui/VideoAudioDialog.cxx @@ -311,11 +311,11 @@ void VideoAudioDialog::addTVEffectsTab() CREATE_CUSTOM_SLIDERS(ScanIntense, "Intensity", kScanlinesChanged) // Create buttons in 2nd column - xpos = myTVSharp->getRight() + fontWidth * 2; + int cloneWidth = _font.getStringWidth("Clone Bad Adjust") + fontWidth * 2.5; + xpos = _w - HBORDER - 2 * 2 - cloneWidth; ypos = VBORDER - VGAP / 2; // Adjustable presets - int cloneWidth = _font.getStringWidth("Clone Bad Adjust") + fontWidth * 2.5; #define CREATE_CLONE_BUTTON(obj, desc) \ myClone ## obj = \ new ButtonWidget(myTab, _font, xpos, ypos, cloneWidth, buttonHeight,\ From 5fa9936aab36aa16290ce80b217db0333fe05cfd Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 18 May 2020 12:26:05 +0200 Subject: [PATCH 228/377] added optional refresh rate adaption in fullscreen mode --- src/common/FrameBufferSDL2.cxx | 65 ++++++++++++++++++++++++++++++++++ src/common/FrameBufferSDL2.hxx | 8 +++++ src/emucore/FrameBuffer.hxx | 8 +++++ src/emucore/Settings.cxx | 1 + src/gui/VideoAudioDialog.cxx | 12 +++++++ src/gui/VideoAudioDialog.hxx | 1 + 6 files changed, 95 insertions(+) diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index 4d013a35d..a1a9c5bbd 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -340,9 +340,74 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) if(SDL_GetRendererInfo(myRenderer, &renderinfo) >= 0) myOSystem.settings().setValue("video", renderinfo.name); + adaptRefreshRate(); + return true; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool FrameBufferSDL2::adaptRefreshRate() +{ + const bool adapt = myOSystem.settings().getBool("tia.refresh"); + + // adapt only in emulation (and debugger?) and fullscreen mode + // TODO: adapt while creating new window + if(adapt && fullScreen() + && (myBufferType == BufferType::Emulator/* || myBufferType == BufferType::Debugger*/)) + { + SDL_DisplayMode sdlMode; + + if(SDL_GetWindowDisplayMode(myWindow, &sdlMode) != 0) + { + Logger::error("Display mode could not be retrieved"); + return false; + } + + const int currentRefreshRate = sdlMode.refresh_rate; + const string format = myOSystem.console().getFormatString(); + const bool isNtsc = format == "NTSC" || format == "PAL60" || format == "SECAM60"; + + sdlMode.refresh_rate = isNtsc ? 60 : 50; // TODO: check for multiples e.g. 120/100 too + + if(currentRefreshRate != sdlMode.refresh_rate) + { + const int display = SDL_GetWindowDisplayIndex(myWindow); + SDL_DisplayMode closestSdlMode; + + if(SDL_GetClosestDisplayMode(display, &sdlMode, &closestSdlMode) == NULL) + { + Logger::error("Closest display mode could not be retrieved"); + return false; + } + // Note: Modes are scanned with size being first priority, + // therefore the size will never change. + // Only change if the display supports a better refresh rate + if(currentRefreshRate != closestSdlMode.refresh_rate) + { + // Switch to new mode + if(SDL_SetWindowDisplayMode(myWindow, &closestSdlMode) != 0) + { + Logger::error("Display refresh rate change failed"); + return false; + } + // Any change only works in real fullscreen mode! + if(SDL_SetWindowFullscreen(myWindow, SDL_WINDOW_FULLSCREEN) != 0) + { + Logger::error("Display fullscreen change failed"); + return false; + } + ostringstream msg; + + msg << "Display refresh rate changed from " << currentRefreshRate << "Hz to " + << closestSdlMode.refresh_rate << "Hz"; + Logger::info(msg.str()); + return true; + } + } + } + return false; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferSDL2::setTitle(const string& title) { diff --git a/src/common/FrameBufferSDL2.hxx b/src/common/FrameBufferSDL2.hxx index d2825037c..0d74d100b 100644 --- a/src/common/FrameBufferSDL2.hxx +++ b/src/common/FrameBufferSDL2.hxx @@ -181,6 +181,14 @@ class FrameBufferSDL2 : public FrameBuffer */ bool setVideoMode(const string& title, const VideoMode& mode) override; + + /** + Adapt display refresh rate to game refresh rate in (real) fullscreen mode + + @return True if the refresh rate was changed + */ + bool adaptRefreshRate(); + /** This method is called to create a surface with the given attributes. diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index 3912f38cd..e19fcc335 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, @@ -439,6 +446,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 diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index f5e120408..bbcc0c4bd 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -54,6 +54,7 @@ Settings::Settings() setPermanent("tia.fs_stretch", "false"); setPermanent("tia.fs_overscan", "0"); setPermanent("tia.vsizeadjust", 0); + setPermanent("tia.refresh", "false"); setPermanent("tia.dbgcolors", "roygpb"); // Palette options setPermanent("palette", PaletteHandler::SETTING_STANDARD); diff --git a/src/gui/VideoAudioDialog.cxx b/src/gui/VideoAudioDialog.cxx index 48fdcc8de..74b326f7c 100644 --- a/src/gui/VideoAudioDialog.cxx +++ b/src/gui/VideoAudioDialog.cxx @@ -166,9 +166,14 @@ void VideoAudioDialog::addDisplayTab() myTVOverscan->setMinValue(0); myTVOverscan->setMaxValue(10); myTVOverscan->setTickmarkIntervals(2); wid.push_back(myTVOverscan); + + // Adapt refresh rate ypos += lineHeight + VGAP; + myRefreshAdjust = new CheckboxWidget(myTab, _font, xpos + INDENT, ypos + 1, "Adapt refresh rate"); + wid.push_back(myRefreshAdjust); // 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 +181,7 @@ void VideoAudioDialog::addDisplayTab() myVSizeAdjust->setTickmarkIntervals(2); wid.push_back(myVSizeAdjust); + // Add items for tab 0 addToFocusList(wid, myTab, tabID); } @@ -486,6 +492,8 @@ void VideoAudioDialog::loadConfig() myUseStretch->setState(instance().settings().getBool("tia.fs_stretch")); // Fullscreen overscan setting myTVOverscan->setValue(instance().settings().getInt("tia.fs_overscan")); + // Adapt refresh rate + myRefreshAdjust->setState(instance().settings().getBool("tia.refresh")); handleFullScreenChange(); // Aspect ratio setting (NTSC and PAL) @@ -597,6 +605,8 @@ void VideoAudioDialog::saveConfig() instance().settings().setValue("tia.fs_stretch", myUseStretch->getState()); // Fullscreen overscan instance().settings().setValue("tia.fs_overscan", myTVOverscan->getValueLabel()); + // Adapt refresh rate + instance().settings().setValue("tia.refresh", myRefreshAdjust->getState()); // TIA zoom levels instance().settings().setValue("tia.zoom", myTIAZoom->getValue() / 100.0); @@ -709,6 +719,7 @@ void VideoAudioDialog::setDefaults() //myFullScreenMode->setSelectedIndex(0); myUseStretch->setState(false); myTVOverscan->setValue(0); + myRefreshAdjust->setState(false); myTIAZoom->setValue(300); myVSizeAdjust->setValue(0); @@ -834,6 +845,7 @@ void VideoAudioDialog::handleFullScreenChange() bool enable = myFullscreen->getState(); myUseStretch->setEnabled(enable); myTVOverscan->setEnabled(enable); + myRefreshAdjust->setEnabled(enable); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/gui/VideoAudioDialog.hxx b/src/gui/VideoAudioDialog.hxx index f46740ae6..6764bc556 100644 --- a/src/gui/VideoAudioDialog.hxx +++ b/src/gui/VideoAudioDialog.hxx @@ -74,6 +74,7 @@ class VideoAudioDialog : public Dialog //PopUpWidget* myFullScreenMode; CheckboxWidget* myUseStretch{nullptr}; SliderWidget* myTVOverscan{nullptr}; + CheckboxWidget* myRefreshAdjust{nullptr}; SliderWidget* myTIAZoom{nullptr}; SliderWidget* myVSizeAdjust{nullptr}; From 2bf7421d1b206c81e91e355dfee999103b5a8d13 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 18 May 2020 21:13:18 +0200 Subject: [PATCH 229/377] improved refresh rate code --- src/common/FrameBufferSDL2.cxx | 130 +++++++++++++++++++-------------- src/common/FrameBufferSDL2.hxx | 16 +++- src/emucore/FrameBuffer.cxx | 10 ++- src/emucore/FrameBuffer.hxx | 5 ++ src/emucore/Settings.cxx | 3 +- src/gui/VideoAudioDialog.cxx | 28 +++---- src/gui/VideoAudioDialog.hxx | 3 +- 7 files changed, 115 insertions(+), 80 deletions(-) diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index a1a9c5bbd..37d2e5499 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -218,6 +218,10 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) if(SDL_WasInit(SDL_INIT_VIDEO) == 0) return false; + const bool fullScreen = mode.fsIndex != -1; + const bool shouldAdapt = fullScreen && myOSystem.settings().getBool("tia.fs_refresh") + && refreshRate() != gameRefreshRate(); + // TODO: On multiple displays, switching from centered mode, does not respect // current window's display (which many not be centered anymore) @@ -261,8 +265,11 @@ 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; + + SDL_DisplayMode adaptedSdlMode; + const bool adaptRefresh = shouldAdapt && adaptRefreshRate(displayIndex, adaptedSdlMode); + const uInt32 flags = SDL_WINDOW_ALLOW_HIGHDPI + | (fullScreen ? adaptRefresh ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP : 0); // macOS seems to have issues with destroying the window, and wants to // keep the same handle @@ -278,12 +285,14 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) 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 + || shouldAdapt) { SDL_DestroyWindow(myWindow); myWindow = nullptr; } } + if(myWindow) { // Even though window size stayed the same, the title may have changed @@ -312,8 +321,24 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) Logger::error(msg); return false; } + setWindowIcon(); } + if(adaptRefresh) + { + // Switch to mode for adapted refresh rate + if(SDL_SetWindowDisplayMode(myWindow, &adaptedSdlMode) != 0) + { + Logger::error("Display refresh rate change failed"); + } + else + { + ostringstream msg; + + msg << "Display refresh rate changed to " << adaptedSdlMode.refresh_rate << "Hz"; + Logger::info(msg.str()); + } + } uInt32 renderFlags = SDL_RENDERER_ACCELERATED; if(myOSystem.settings().getBool("vsync") @@ -340,70 +365,35 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) if(SDL_GetRendererInfo(myRenderer, &renderinfo) >= 0) myOSystem.settings().setValue("video", renderinfo.name); - adaptRefreshRate(); - return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool FrameBufferSDL2::adaptRefreshRate() +bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& closestSdlMode) { - const bool adapt = myOSystem.settings().getBool("tia.refresh"); + SDL_DisplayMode sdlMode; - // adapt only in emulation (and debugger?) and fullscreen mode - // TODO: adapt while creating new window - if(adapt && fullScreen() - && (myBufferType == BufferType::Emulator/* || myBufferType == BufferType::Debugger*/)) + if(SDL_GetCurrentDisplayMode(displayIndex, &sdlMode) != 0) { - SDL_DisplayMode sdlMode; + Logger::error("Display mode could not be retrieved"); + return false; + } - if(SDL_GetWindowDisplayMode(myWindow, &sdlMode) != 0) + const int currentRefreshRate = sdlMode.refresh_rate; + + sdlMode.refresh_rate = gameRefreshRate(); + + if(currentRefreshRate != sdlMode.refresh_rate) + { + // Note: Modes are scanned with size being first priority, + // therefore the size will never change. + if(SDL_GetClosestDisplayMode(displayIndex, &sdlMode, &closestSdlMode) == NULL) { - Logger::error("Display mode could not be retrieved"); + Logger::error("Closest display mode could not be retrieved"); return false; } - - const int currentRefreshRate = sdlMode.refresh_rate; - const string format = myOSystem.console().getFormatString(); - const bool isNtsc = format == "NTSC" || format == "PAL60" || format == "SECAM60"; - - sdlMode.refresh_rate = isNtsc ? 60 : 50; // TODO: check for multiples e.g. 120/100 too - - if(currentRefreshRate != sdlMode.refresh_rate) - { - const int display = SDL_GetWindowDisplayIndex(myWindow); - SDL_DisplayMode closestSdlMode; - - if(SDL_GetClosestDisplayMode(display, &sdlMode, &closestSdlMode) == NULL) - { - Logger::error("Closest display mode could not be retrieved"); - return false; - } - // Note: Modes are scanned with size being first priority, - // therefore the size will never change. - // Only change if the display supports a better refresh rate - if(currentRefreshRate != closestSdlMode.refresh_rate) - { - // Switch to new mode - if(SDL_SetWindowDisplayMode(myWindow, &closestSdlMode) != 0) - { - Logger::error("Display refresh rate change failed"); - return false; - } - // Any change only works in real fullscreen mode! - if(SDL_SetWindowFullscreen(myWindow, SDL_WINDOW_FULLSCREEN) != 0) - { - Logger::error("Display fullscreen change failed"); - return false; - } - ostringstream msg; - - msg << "Display refresh rate changed from " << currentRefreshRate << "Hz to " - << closestSdlMode.refresh_rate << "Hz"; - Logger::info(msg.str()); - return true; - } - } + // Only change if the display supports a better refresh rate + return currentRefreshRate != closestSdlMode.refresh_rate; } return false; } @@ -469,6 +459,34 @@ 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 != NULL) + 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; // TODO: check for multiples e.g. 120/100 too + } + return 60; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferSDL2::renderToScreen() { diff --git a/src/common/FrameBufferSDL2.hxx b/src/common/FrameBufferSDL2.hxx index 0d74d100b..f0d69bc96 100644 --- a/src/common/FrameBufferSDL2.hxx +++ b/src/common/FrameBufferSDL2.hxx @@ -183,11 +183,11 @@ class FrameBufferSDL2 : public FrameBuffer /** - Adapt display refresh rate to game refresh rate in (real) fullscreen mode + Checks if the display refresh rate should be adapted to game refresh rate in (real) fullscreen mode - @return True if the refresh rate was changed + @return True if the refresh rate should be changed */ - bool adaptRefreshRate(); + bool adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& closestSdlMode); /** This method is called to create a surface with the given attributes. @@ -241,6 +241,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/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 4599a3860..2d495c101 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -993,7 +993,15 @@ void FrameBuffer::toggleFullscreen(bool toggle) setFullscreen(isFullscreen); - showMessage(string("Fullscreen ") + (isFullscreen ? "enabled" : "disabled")); + ostringstream msg; + + msg << "Fullscreen "; + if(isFullscreen) + msg << "enabled (" << refreshRate() << " Hz)"; + else + msg << "disabled"; + + showMessage(msg.str()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index e19fcc335..945cbb780 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -518,6 +518,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; diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index bbcc0c4bd..dca79717d 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -52,9 +52,9 @@ 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.refresh", "false"); setPermanent("tia.dbgcolors", "roygpb"); // Palette options setPermanent("palette", PaletteHandler::SETTING_STANDARD); @@ -442,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\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" diff --git a/src/gui/VideoAudioDialog.cxx b/src/gui/VideoAudioDialog.cxx index 74b326f7c..46203783a 100644 --- a/src/gui/VideoAudioDialog.cxx +++ b/src/gui/VideoAudioDialog.cxx @@ -149,29 +149,23 @@ 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); + + // Adapt refresh rate ypos += lineHeight + VGAP; + myRefreshAdapt = new CheckboxWidget(myTab, _font, xpos + INDENT, ypos + 1, "Adapt display refresh rate"); + wid.push_back(myRefreshAdapt); // 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); - // Adapt refresh rate - ypos += lineHeight + VGAP; - myRefreshAdjust = new CheckboxWidget(myTab, _font, xpos + INDENT, ypos + 1, "Adapt refresh rate"); - wid.push_back(myRefreshAdjust); - // Vertical size ypos += lineHeight + VGAP; myVSizeAdjust = @@ -490,10 +484,10 @@ void VideoAudioDialog::loadConfig() myFullScreenMode->setSelected(mode);*/ // Fullscreen stretch setting myUseStretch->setState(instance().settings().getBool("tia.fs_stretch")); + // Adapt refresh rate + myRefreshAdapt->setState(instance().settings().getBool("tia.fs_refresh")); // Fullscreen overscan setting myTVOverscan->setValue(instance().settings().getInt("tia.fs_overscan")); - // Adapt refresh rate - myRefreshAdjust->setState(instance().settings().getBool("tia.refresh")); handleFullScreenChange(); // Aspect ratio setting (NTSC and PAL) @@ -603,10 +597,10 @@ void VideoAudioDialog::saveConfig() instance().settings().setValue("fullscreen", myFullscreen->getState()); // Fullscreen stretch setting instance().settings().setValue("tia.fs_stretch", myUseStretch->getState()); + // Adapt refresh rate + instance().settings().setValue("tia.fs_refresh", myRefreshAdapt->getState()); // Fullscreen overscan instance().settings().setValue("tia.fs_overscan", myTVOverscan->getValueLabel()); - // Adapt refresh rate - instance().settings().setValue("tia.refresh", myRefreshAdjust->getState()); // TIA zoom levels instance().settings().setValue("tia.zoom", myTIAZoom->getValue() / 100.0); @@ -718,8 +712,8 @@ void VideoAudioDialog::setDefaults() myFullscreen->setState(false); //myFullScreenMode->setSelectedIndex(0); myUseStretch->setState(false); + myRefreshAdapt->setState(false); myTVOverscan->setValue(0); - myRefreshAdjust->setState(false); myTIAZoom->setValue(300); myVSizeAdjust->setValue(0); @@ -844,8 +838,8 @@ void VideoAudioDialog::handleFullScreenChange() { bool enable = myFullscreen->getState(); myUseStretch->setEnabled(enable); + myRefreshAdapt->setEnabled(enable); myTVOverscan->setEnabled(enable); - myRefreshAdjust->setEnabled(enable); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/gui/VideoAudioDialog.hxx b/src/gui/VideoAudioDialog.hxx index 6764bc556..0961f776e 100644 --- a/src/gui/VideoAudioDialog.hxx +++ b/src/gui/VideoAudioDialog.hxx @@ -71,10 +71,9 @@ class VideoAudioDialog : public Dialog PopUpWidget* myRenderer{nullptr}; CheckboxWidget* myTIAInterpolate{nullptr}; CheckboxWidget* myFullscreen{nullptr}; - //PopUpWidget* myFullScreenMode; CheckboxWidget* myUseStretch{nullptr}; SliderWidget* myTVOverscan{nullptr}; - CheckboxWidget* myRefreshAdjust{nullptr}; + CheckboxWidget* myRefreshAdapt{nullptr}; SliderWidget* myTIAZoom{nullptr}; SliderWidget* myVSizeAdjust{nullptr}; From 41d217e17d32853f129689d13313eb11da62c289 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 19 May 2020 08:53:11 +0200 Subject: [PATCH 230/377] fix window position saving when switching from/to fullscreen mode suppress fullscreen UI message outside emulation mode --- src/common/FrameBufferSDL2.cxx | 2 +- src/emucore/FrameBuffer.cxx | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index 37d2e5499..8a943332c 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -482,7 +482,7 @@ int FrameBufferSDL2::gameRefreshRate() const const string format = myOSystem.console().getFormatString(); const bool isNtsc = format == "NTSC" || format == "PAL60" || format == "SECAM60"; - return isNtsc ? 60 : 50; // TODO: check for multiples e.g. 120/100 too + return isNtsc ? 75 : 50; // TODO: check for multiples e.g. 120/100 too } return 60; } diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 2d495c101..88f62517f 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -959,6 +959,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' @@ -993,15 +994,18 @@ void FrameBuffer::toggleFullscreen(bool toggle) setFullscreen(isFullscreen); - ostringstream msg; + if(myBufferType == BufferType::Emulator) + { + ostringstream msg; - msg << "Fullscreen "; - if(isFullscreen) - msg << "enabled (" << refreshRate() << " Hz)"; - else - msg << "disabled"; + msg << "Fullscreen "; + if(isFullscreen) + msg << "enabled (" << refreshRate() << " Hz)"; + else + msg << "disabled"; - showMessage(msg.str()); + showMessage(msg.str()); + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From cde78a779669a34a201baf92daaf05135e1ccd7b Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 19 May 2020 10:19:48 +0200 Subject: [PATCH 231/377] oops --- src/common/FrameBufferSDL2.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index 8a943332c..37d2e5499 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -482,7 +482,7 @@ int FrameBufferSDL2::gameRefreshRate() const const string format = myOSystem.console().getFormatString(); const bool isNtsc = format == "NTSC" || format == "PAL60" || format == "SECAM60"; - return isNtsc ? 75 : 50; // TODO: check for multiples e.g. 120/100 too + return isNtsc ? 60 : 50; // TODO: check for multiples e.g. 120/100 too } return 60; } From 5aca14c2481b8e27d55162e3eca656cc56c163cf Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 19 May 2020 12:33:01 +0200 Subject: [PATCH 232/377] try to create renderer only when required (needs testing) --- src/common/FrameBufferSDL2.cxx | 92 +++++++++++++++++++++++++++------- src/common/FrameBufferSDL2.hxx | 8 +++ 2 files changed, 82 insertions(+), 18 deletions(-) diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index 37d2e5499..c977405fa 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -221,6 +221,7 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) const bool fullScreen = mode.fsIndex != -1; const bool shouldAdapt = fullScreen && myOSystem.settings().getBool("tia.fs_refresh") && refreshRate() != gameRefreshRate(); + bool forceCreateRenderer = false; // TODO: On multiple displays, switching from centered mode, does not respect // current window's display (which many not be centered anymore) @@ -230,12 +231,12 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) // 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; - } + //// Always recreate renderer (some systems need this) + //if(myRenderer) + //{ + // SDL_DestroyRenderer(myRenderer); + // myRenderer = nullptr; + //} int posX, posY; @@ -313,6 +314,7 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) #endif else { + forceCreateRenderer = true; myWindow = SDL_CreateWindow(title.c_str(), posX, posY, mode.screen.w, mode.screen.h, flags); if(myWindow == nullptr) @@ -340,24 +342,78 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) } } + return createRenderer(forceCreateRenderer); + + //uInt32 renderFlags = SDL_RENDERER_ACCELERATED; + //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); + + //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); + + //return true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +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 " << 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(); @@ -482,7 +538,7 @@ int FrameBufferSDL2::gameRefreshRate() const const string format = myOSystem.console().getFormatString(); const bool isNtsc = format == "NTSC" || format == "PAL60" || format == "SECAM60"; - return isNtsc ? 60 : 50; // TODO: check for multiples e.g. 120/100 too + return isNtsc ? 75 : 50; // TODO: check for multiples e.g. 120/100 too } return 60; } diff --git a/src/common/FrameBufferSDL2.hxx b/src/common/FrameBufferSDL2.hxx index f0d69bc96..1799b5c6f 100644 --- a/src/common/FrameBufferSDL2.hxx +++ b/src/common/FrameBufferSDL2.hxx @@ -181,6 +181,14 @@ class FrameBufferSDL2 : public FrameBuffer */ bool setVideoMode(const string& title, const VideoMode& mode) override; + /** + 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); /** Checks if the display refresh rate should be adapted to game refresh rate in (real) fullscreen mode From 1a5f4aedc4d12af5d4dd8100d9d7c2cd2bfc674d Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 19 May 2020 19:37:06 +0200 Subject: [PATCH 233/377] added avoiding switching refresh rate when going back to launcher improved error logging messages --- src/common/FrameBufferSDL2.cxx | 55 +++++++--------------------------- 1 file changed, 10 insertions(+), 45 deletions(-) diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index c977405fa..691e96510 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -220,24 +220,14 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) const bool fullScreen = mode.fsIndex != -1; const bool shouldAdapt = fullScreen && myOSystem.settings().getBool("tia.fs_refresh") - && refreshRate() != gameRefreshRate(); + && gameRefreshRate() && refreshRate() != gameRefreshRate(); bool forceCreateRenderer = false; - // TODO: On multiple displays, switching from centered mode, does not respect - // current window's display (which many not be centered anymore) - // 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"); @@ -282,7 +272,7 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) // 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); @@ -331,7 +321,7 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) // Switch to mode for adapted refresh rate if(SDL_SetWindowDisplayMode(myWindow, &adaptedSdlMode) != 0) { - Logger::error("Display refresh rate change failed"); + Logger::error("ERROR: Display refresh rate change failed"); } else { @@ -343,33 +333,6 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) } return createRenderer(forceCreateRenderer); - - //uInt32 renderFlags = SDL_RENDERER_ACCELERATED; - //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); - - //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); - - //return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -396,7 +359,7 @@ bool FrameBufferSDL2::createRenderer(bool force) if(recreate) { - cerr << "Create new renderer " << int(myBufferType) << endl; + //cerr << "Create new renderer " << int(myBufferType) << endl; if(myRenderer) SDL_DestroyRenderer(myRenderer); @@ -418,6 +381,7 @@ bool FrameBufferSDL2::createRenderer(bool force) clear(); SDL_RendererInfo renderinfo; + if(SDL_GetRendererInfo(myRenderer, &renderinfo) >= 0) myOSystem.settings().setValue("video", renderinfo.name); @@ -431,7 +395,7 @@ bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& clos if(SDL_GetCurrentDisplayMode(displayIndex, &sdlMode) != 0) { - Logger::error("Display mode could not be retrieved"); + Logger::error("ERROR: Display mode could not be retrieved"); return false; } @@ -445,11 +409,12 @@ bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& clos // therefore the size will never change. if(SDL_GetClosestDisplayMode(displayIndex, &sdlMode, &closestSdlMode) == NULL) { - Logger::error("Closest display mode could not be retrieved"); + Logger::error("ERROR: Closest display mode could not be retrieved"); return false; } // Only change if the display supports a better refresh rate return currentRefreshRate != closestSdlMode.refresh_rate; + // TODO: check for multiples e.g. 120/100 too } return false; } @@ -538,9 +503,9 @@ int FrameBufferSDL2::gameRefreshRate() const const string format = myOSystem.console().getFormatString(); const bool isNtsc = format == "NTSC" || format == "PAL60" || format == "SECAM60"; - return isNtsc ? 75 : 50; // TODO: check for multiples e.g. 120/100 too + return isNtsc ? 60 : 50; // TODO: check for multiples e.g. 120/100 too } - return 60; + return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 842b40e5436b76a9604dee74e037e485f71e6d05 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 20 May 2020 10:19:31 +0200 Subject: [PATCH 234/377] added refresh rate adapt for integer factors of the game's refresh rate --- src/common/FrameBufferSDL2.cxx | 90 +++++++++++++++++++++------------- src/common/FrameBufferSDL2.hxx | 17 ++++--- 2 files changed, 65 insertions(+), 42 deletions(-) diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index 691e96510..72484c468 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -220,7 +220,7 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) const bool fullScreen = mode.fsIndex != -1; const bool shouldAdapt = fullScreen && myOSystem.settings().getBool("tia.fs_refresh") - && gameRefreshRate() && refreshRate() != gameRefreshRate(); + && gameRefreshRate() && refreshRate() % gameRefreshRate() != 0; bool forceCreateRenderer = false; // Get windowed window's last display @@ -277,7 +277,7 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) SDL_GetWindowSize(myWindow, &w, &h); if(d != displayIndex || uInt32(w) != mode.screen.w || uInt32(h) != mode.screen.h - || shouldAdapt) + || adaptRefresh) { SDL_DestroyWindow(myWindow); myWindow = nullptr; @@ -335,6 +335,57 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) 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(); + float factor = float(currentRefreshRate) / wantedRefreshRate; + 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) == NULL) + { + Logger::error("ERROR: Closest display mode could not be retrieved"); + return adapt; + } + factor = float(closestSdlMode.refresh_rate) / sdlMode.refresh_rate; + 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) { @@ -359,7 +410,7 @@ bool FrameBufferSDL2::createRenderer(bool force) if(recreate) { - //cerr << "Create new renderer " << int(myBufferType) << endl; + cerr << "Create new renderer " << int(myBufferType) << endl; if(myRenderer) SDL_DestroyRenderer(myRenderer); @@ -388,37 +439,6 @@ bool FrameBufferSDL2::createRenderer(bool force) return true; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& closestSdlMode) -{ - 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; - - sdlMode.refresh_rate = gameRefreshRate(); - - if(currentRefreshRate != sdlMode.refresh_rate) - { - // Note: Modes are scanned with size being first priority, - // therefore the size will never change. - if(SDL_GetClosestDisplayMode(displayIndex, &sdlMode, &closestSdlMode) == NULL) - { - Logger::error("ERROR: Closest display mode could not be retrieved"); - return false; - } - // Only change if the display supports a better refresh rate - return currentRefreshRate != closestSdlMode.refresh_rate; - // TODO: check for multiples e.g. 120/100 too - } - return false; -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferSDL2::setTitle(const string& title) { @@ -503,7 +523,7 @@ int FrameBufferSDL2::gameRefreshRate() const const string format = myOSystem.console().getFormatString(); const bool isNtsc = format == "NTSC" || format == "PAL60" || format == "SECAM60"; - return isNtsc ? 60 : 50; // TODO: check for multiples e.g. 120/100 too + return isNtsc ? 60 : 50; } return 0; } diff --git a/src/common/FrameBufferSDL2.hxx b/src/common/FrameBufferSDL2.hxx index 1799b5c6f..08005f85a 100644 --- a/src/common/FrameBufferSDL2.hxx +++ b/src/common/FrameBufferSDL2.hxx @@ -181,6 +181,16 @@ 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 + @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 @@ -190,13 +200,6 @@ class FrameBufferSDL2 : public FrameBuffer */ bool createRenderer(bool force); - /** - Checks if the display refresh rate should be adapted to game refresh rate in (real) fullscreen mode - - @return True if the refresh rate should be changed - */ - bool adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& closestSdlMode); - /** This method is called to create a surface with the given attributes. From 294b4a44657f744b6a8256dc6fb93f73f02a9918 Mon Sep 17 00:00:00 2001 From: Stephen Kitt Date: Thu, 21 May 2020 23:00:23 +0200 Subject: [PATCH 235/377] Remove extra quote for audio presets The list of presets includes an extra quote in "low quality, medium lag"; this patch removes it. Signed-off-by: Stephen Kitt --- docs/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.html b/docs/index.html index 3bf9ee26a..e5d859ba0 100644 --- a/docs/index.html +++ b/docs/index.html @@ -2155,7 +2155,7 @@ From 0920518d29d601d81cc98bad4616b510357c9930 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Thu, 21 May 2020 22:15:13 -0230 Subject: [PATCH 236/377] Fix compilation in Xcode. --- src/common/FrameBufferSDL2.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index 72484c468..0d5813168 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" From 9ea920524bf7de4f66ac11f4239f0c5cbaee7e45 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Fri, 22 May 2020 09:05:48 +0200 Subject: [PATCH 237/377] more compact available video modes logging --- src/common/FrameBufferSDL2.cxx | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index 0d5813168..6070abbce 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -101,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 @@ -329,7 +342,7 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) { ostringstream msg; - msg << "Display refresh rate changed to " << adaptedSdlMode.refresh_rate << "Hz"; + msg << "Display refresh rate changed to " << adaptedSdlMode.refresh_rate << " Hz"; Logger::info(msg.str()); } } @@ -412,7 +425,7 @@ bool FrameBufferSDL2::createRenderer(bool force) if(recreate) { - cerr << "Create new renderer " << int(myBufferType) << endl; + cerr << "Create new renderer for buffer type #" << int(myBufferType) << endl; if(myRenderer) SDL_DestroyRenderer(myRenderer); From f426f160a96e0d25801b04bac570df1cab084180 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Fri, 22 May 2020 15:07:20 -0230 Subject: [PATCH 238/377] Fix minor warnings from clang. --- src/common/FrameBufferSDL2.cxx | 6 ++++-- src/common/FrameBufferSDL2.hxx | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index 6070abbce..a912b8ad3 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -376,7 +376,7 @@ bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adap SDL_DisplayMode closestSdlMode; sdlMode.refresh_rate = wantedRefreshRate * m; - if(SDL_GetClosestDisplayMode(displayIndex, &sdlMode, &closestSdlMode) == NULL) + if(SDL_GetClosestDisplayMode(displayIndex, &sdlMode, &closestSdlMode) == nullptr) { Logger::error("ERROR: Closest display mode could not be retrieved"); return adapt; @@ -515,6 +515,7 @@ bool FrameBufferSDL2::fullScreen() const #endif } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int FrameBufferSDL2::refreshRate() const { ASSERT_MAIN_THREAD; @@ -525,8 +526,9 @@ int FrameBufferSDL2::refreshRate() const if(SDL_GetCurrentDisplayMode(displayIndex, &sdlMode) == 0) return sdlMode.refresh_rate; - if (myWindow != NULL) + if(myWindow != nullptr) Logger::error("Could not retrieve current display mode"); + return 0; } diff --git a/src/common/FrameBufferSDL2.hxx b/src/common/FrameBufferSDL2.hxx index 08005f85a..7904ed0ee 100644 --- a/src/common/FrameBufferSDL2.hxx +++ b/src/common/FrameBufferSDL2.hxx @@ -184,8 +184,8 @@ class FrameBufferSDL2 : public FrameBuffer /** 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 - @adaptedSdlMode The best matching mode if the refresh rate should be changed + @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 */ From de9277e98e4181dcf9f6d52ef85b5d326f96ea8c Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 23 May 2020 12:29:31 +0200 Subject: [PATCH 239/377] handle rounded refresh rates like 59.94 Hz disable refresh adjust option for macOS --- src/common/FrameBufferSDL2.cxx | 91 ++++++++++++++++++++++++++++++++-- src/common/FrameBufferSDL2.hxx | 2 + src/gui/VideoAudioDialog.cxx | 10 ++++ src/gui/VideoAudioDialog.hxx | 2 + 4 files changed, 100 insertions(+), 5 deletions(-) diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index a912b8ad3..9bb0dae57 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -234,8 +234,6 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) return false; const bool fullScreen = mode.fsIndex != -1; - const bool shouldAdapt = fullScreen && myOSystem.settings().getBool("tia.fs_refresh") - && gameRefreshRate() && refreshRate() % gameRefreshRate() != 0; bool forceCreateRenderer = false; // Get windowed window's last display @@ -272,8 +270,17 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) posY = BSPF::clamp(posY, y0 + 50, y1 - 50); } +#ifndef BSPF_MACOS + // macOS does not allow to change the display refresh rate 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); @@ -331,6 +338,7 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) setWindowIcon(); } +#ifndef BSPF_MACOS if(adaptRefresh) { // Switch to mode for adapted refresh rate @@ -346,10 +354,11 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) Logger::info(msg.str()); } } - +#endif return createRenderer(forceCreateRenderer); } +#ifndef BSPF_MACOS // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adaptedSdlMode) { @@ -363,7 +372,10 @@ bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adap const int currentRefreshRate = sdlMode.refresh_rate; const int wantedRefreshRate = gameRefreshRate(); - float factor = float(currentRefreshRate) / wantedRefreshRate; + // 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; @@ -382,6 +394,8 @@ bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adap return adapt; } factor = float(closestSdlMode.refresh_rate) / sdlMode.refresh_rate; + 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) { @@ -399,7 +413,74 @@ bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adap // Only change if the display supports a better refresh rate return adapt; + +#if 0 + // Adapting resfresh rate and display size + const bool hiDpi = myOSystem.settings().getBool("hidpi"); + const float mult = float(font().getFontHeight()) / getFontDesc("medium").height * hiDpi ? 2 : 1; + const Int32 minWidth = FBMinimum::Width * mult; + const Int32 minHeight = FBMinimum::Height * mult; + SDL_DisplayMode sdlMode; + + if(SDL_GetCurrentDisplayMode(displayIndex, &sdlMode) != 0) + { + Logger::error("ERROR: Display mode could not be retrieved"); + return false; + } + + const int numModes = SDL_GetNumDisplayModes(displayIndex); + if(numModes < 0) + { + Logger::error("ERROR: Number of display modes 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) + 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; + + for(int mode = 0; mode < numModes; ++mode) + { + // Note: Display modes returned are sorted by width, height,... refresh_rate + if(SDL_GetDisplayMode(displayIndex, mode, &sdlMode) != 0) + { + Logger::error("ERROR: Display modes could not be retrieved"); + return false; + } + // skip too small modes + if(sdlMode.w < minWidth || sdlMode.h < minHeight) + continue; + + cerr << sdlMode.w << "x" << sdlMode.h << " " << sdlMode.refresh_rate << " Hz" << endl; + + factor = std::min(float(sdlMode.refresh_rate) / wantedRefreshRate, + float(sdlMode.refresh_rate) / (wantedRefreshRate - 1)); + const float diff = std::abs(factor - std::round(factor)) / factor; + if(diff < bestDiff) + { + bestDiff = diff; + adaptedSdlMode = sdlMode; + 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; +#endif } +#endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameBufferSDL2::createRenderer(bool force) @@ -540,7 +621,7 @@ int FrameBufferSDL2::gameRefreshRate() const const string format = myOSystem.console().getFormatString(); const bool isNtsc = format == "NTSC" || format == "PAL60" || format == "SECAM60"; - return isNtsc ? 60 : 50; + return isNtsc ? 60 : 50; // The code will take care of 59/49 Hz } return 0; } diff --git a/src/common/FrameBufferSDL2.hxx b/src/common/FrameBufferSDL2.hxx index 7904ed0ee..282cf2100 100644 --- a/src/common/FrameBufferSDL2.hxx +++ b/src/common/FrameBufferSDL2.hxx @@ -181,6 +181,7 @@ class FrameBufferSDL2 : public FrameBuffer */ bool setVideoMode(const string& title, const VideoMode& mode) override; + #ifndef BSPF_MACOS /** Checks if the display refresh rate should be adapted to game refresh rate in (real) fullscreen mode @@ -190,6 +191,7 @@ class FrameBufferSDL2 : public FrameBuffer @return True if the refresh rate should be changed */ bool adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adaptedSdlMode); + #endif /** Create a new renderer if required diff --git a/src/gui/VideoAudioDialog.cxx b/src/gui/VideoAudioDialog.cxx index 46203783a..edce71e10 100644 --- a/src/gui/VideoAudioDialog.cxx +++ b/src/gui/VideoAudioDialog.cxx @@ -153,10 +153,12 @@ void VideoAudioDialog::addDisplayTab() myUseStretch = new CheckboxWidget(myTab, _font, xpos + INDENT, ypos + 1, "Stretch"); wid.push_back(myUseStretch); +#ifndef BSPF_MACOS // Adapt refresh rate ypos += lineHeight + VGAP; myRefreshAdapt = new CheckboxWidget(myTab, _font, xpos + INDENT, ypos + 1, "Adapt display refresh rate"); wid.push_back(myRefreshAdapt); +#endif // FS overscan ypos += lineHeight + VGAP; @@ -484,8 +486,10 @@ void VideoAudioDialog::loadConfig() myFullScreenMode->setSelected(mode);*/ // Fullscreen stretch setting myUseStretch->setState(instance().settings().getBool("tia.fs_stretch")); +#ifndef BSPF_MACOS // Adapt refresh rate myRefreshAdapt->setState(instance().settings().getBool("tia.fs_refresh")); +#endif // Fullscreen overscan setting myTVOverscan->setValue(instance().settings().getInt("tia.fs_overscan")); handleFullScreenChange(); @@ -597,8 +601,10 @@ void VideoAudioDialog::saveConfig() instance().settings().setValue("fullscreen", myFullscreen->getState()); // Fullscreen stretch setting instance().settings().setValue("tia.fs_stretch", myUseStretch->getState()); +#ifndef BSPF_MACOS // Adapt refresh rate instance().settings().setValue("tia.fs_refresh", myRefreshAdapt->getState()); +#endif // Fullscreen overscan instance().settings().setValue("tia.fs_overscan", myTVOverscan->getValueLabel()); @@ -712,7 +718,9 @@ void VideoAudioDialog::setDefaults() myFullscreen->setState(false); //myFullScreenMode->setSelectedIndex(0); myUseStretch->setState(false); + #ifndef BSPF_MACOS myRefreshAdapt->setState(false); + #endif myTVOverscan->setValue(0); myTIAZoom->setValue(300); myVSizeAdjust->setValue(0); @@ -838,7 +846,9 @@ void VideoAudioDialog::handleFullScreenChange() { bool enable = myFullscreen->getState(); myUseStretch->setEnabled(enable); +#ifndef BSPF_MACOS myRefreshAdapt->setEnabled(enable); +#endif myTVOverscan->setEnabled(enable); } diff --git a/src/gui/VideoAudioDialog.hxx b/src/gui/VideoAudioDialog.hxx index 0961f776e..c20b39438 100644 --- a/src/gui/VideoAudioDialog.hxx +++ b/src/gui/VideoAudioDialog.hxx @@ -73,7 +73,9 @@ class VideoAudioDialog : public Dialog CheckboxWidget* myFullscreen{nullptr}; CheckboxWidget* myUseStretch{nullptr}; SliderWidget* myTVOverscan{nullptr}; + #ifndef BSPF_MACOS CheckboxWidget* myRefreshAdapt{nullptr}; + #endif SliderWidget* myTIAZoom{nullptr}; SliderWidget* myVSizeAdjust{nullptr}; From c4aa9b2a56bacbd74bbd3a67ffcc243272ee997a Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 23 May 2020 20:50:14 +0200 Subject: [PATCH 240/377] updated doc for fullscreen refresh rate adaption removed debug output --- Changes.txt | 2 ++ docs/graphics/options_video.png | Bin 2744 -> 3001 bytes docs/index.html | 15 +++++++++++---- src/common/FrameBufferSDL2.cxx | 15 +++++++-------- src/emucore/Settings.cxx | 2 +- 5 files changed, 21 insertions(+), 13 deletions(-) diff --git a/Changes.txt b/Changes.txt index 557157f25..616ec22f7 100644 --- a/Changes.txt +++ b/Changes.txt @@ -37,6 +37,8 @@ * 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 diff --git a/docs/graphics/options_video.png b/docs/graphics/options_video.png index deb857ca4984e0d5815c693b739e4628a3b1b429..58654148ab3e6db654681c658c828eade4523b08 100644 GIT binary patch delta 2885 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 + + + + + @@ -2943,13 +2949,14 @@
      KeyEditor Function
      -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'.
      -tia.fs_refresh <1|0>
      While in fullscreen mode, adapt the display's refresh rate to the game's frame rate + to minimize judder.
      -tia.fs_overscan <0 - 10>
      Add overscan to TIA image while in fullscreen mode
      - - + + - + + - +
      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.-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
      diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index 9bb0dae57..612000943 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -393,7 +393,6 @@ bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adap Logger::error("ERROR: Closest display mode could not be retrieved"); return adapt; } - factor = float(closestSdlMode.refresh_rate) / sdlMode.refresh_rate; 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; @@ -404,12 +403,12 @@ bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adap adapt = true; } } - cerr << "refresh rate adapt "; - if(adapt) - cerr << "required (" << currentRefreshRate << " Hz -> " << adaptedSdlMode.refresh_rate << " Hz)"; - else - cerr << "not required/possible"; - cerr << endl; + //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; @@ -506,7 +505,7 @@ bool FrameBufferSDL2::createRenderer(bool force) if(recreate) { - cerr << "Create new renderer for buffer type #" << int(myBufferType) << endl; + //cerr << "Create new renderer for buffer type #" << int(myBufferType) << endl; if(myRenderer) SDL_DestroyRenderer(myRenderer); diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index dca79717d..790c784bb 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -442,7 +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\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" From ac9143ef08ace05655f08769e0f432cfdafef305 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sat, 23 May 2020 17:15:42 -0230 Subject: [PATCH 241/377] Add 'ADAPTABLE_REFRESH_SUPPORT', and enable it on non-Mac systems. Cleaned up some dead code. Made MacOS toggle from windowed to fullscreen work the same as all other systems. --- src/common/FrameBufferSDL2.cxx | 96 ++-------------------------------- src/common/FrameBufferSDL2.hxx | 2 - src/common/bspf.hxx | 6 +++ src/gui/VideoAudioDialog.cxx | 24 +++------ src/gui/VideoAudioDialog.hxx | 2 - 5 files changed, 18 insertions(+), 112 deletions(-) diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index 612000943..d930b2fc0 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -270,8 +270,7 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) posY = BSPF::clamp(posY, y0 + 50, y1 - 50); } -#ifndef BSPF_MACOS - // macOS does not allow to change the display refresh rate +#ifdef ADAPTABLE_REFRESH_SUPPORT SDL_DisplayMode adaptedSdlMode; const bool shouldAdapt = fullScreen && myOSystem.settings().getBool("tia.fs_refresh") && gameRefreshRate() @@ -284,12 +283,6 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) const uInt32 flags = SDL_WINDOW_ALLOW_HIGHDPI | (fullScreen ? adaptRefresh ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP : 0); - // 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 // 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) @@ -312,18 +305,6 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) 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; @@ -338,7 +319,8 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) setWindowIcon(); } -#ifndef BSPF_MACOS + +#ifdef ADAPTABLE_REFRESH_SUPPORT if(adaptRefresh) { // Switch to mode for adapted refresh rate @@ -355,10 +337,10 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) } } #endif + return createRenderer(forceCreateRenderer); } -#ifndef BSPF_MACOS // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adaptedSdlMode) { @@ -412,74 +394,7 @@ bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adap // Only change if the display supports a better refresh rate return adapt; - -#if 0 - // Adapting resfresh rate and display size - const bool hiDpi = myOSystem.settings().getBool("hidpi"); - const float mult = float(font().getFontHeight()) / getFontDesc("medium").height * hiDpi ? 2 : 1; - const Int32 minWidth = FBMinimum::Width * mult; - const Int32 minHeight = FBMinimum::Height * mult; - SDL_DisplayMode sdlMode; - - if(SDL_GetCurrentDisplayMode(displayIndex, &sdlMode) != 0) - { - Logger::error("ERROR: Display mode could not be retrieved"); - return false; - } - - const int numModes = SDL_GetNumDisplayModes(displayIndex); - if(numModes < 0) - { - Logger::error("ERROR: Number of display modes 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) - 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; - - for(int mode = 0; mode < numModes; ++mode) - { - // Note: Display modes returned are sorted by width, height,... refresh_rate - if(SDL_GetDisplayMode(displayIndex, mode, &sdlMode) != 0) - { - Logger::error("ERROR: Display modes could not be retrieved"); - return false; - } - // skip too small modes - if(sdlMode.w < minWidth || sdlMode.h < minHeight) - continue; - - cerr << sdlMode.w << "x" << sdlMode.h << " " << sdlMode.refresh_rate << " Hz" << endl; - - factor = std::min(float(sdlMode.refresh_rate) / wantedRefreshRate, - float(sdlMode.refresh_rate) / (wantedRefreshRate - 1)); - const float diff = std::abs(factor - std::round(factor)) / factor; - if(diff < bestDiff) - { - bestDiff = diff; - adaptedSdlMode = sdlMode; - 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; -#endif } -#endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameBufferSDL2::createRenderer(bool force) @@ -637,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 282cf2100..7904ed0ee 100644 --- a/src/common/FrameBufferSDL2.hxx +++ b/src/common/FrameBufferSDL2.hxx @@ -181,7 +181,6 @@ class FrameBufferSDL2 : public FrameBuffer */ bool setVideoMode(const string& title, const VideoMode& mode) override; - #ifndef BSPF_MACOS /** Checks if the display refresh rate should be adapted to game refresh rate in (real) fullscreen mode @@ -191,7 +190,6 @@ class FrameBufferSDL2 : public FrameBuffer @return True if the refresh rate should be changed */ bool adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adaptedSdlMode); - #endif /** Create a new renderer if required diff --git a/src/common/bspf.hxx b/src/common/bspf.hxx index f21a99a4c..3fc1aaf6c 100644 --- a/src/common/bspf.hxx +++ b/src/common/bspf.hxx @@ -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; diff --git a/src/gui/VideoAudioDialog.cxx b/src/gui/VideoAudioDialog.cxx index edce71e10..c51685fcf 100644 --- a/src/gui/VideoAudioDialog.cxx +++ b/src/gui/VideoAudioDialog.cxx @@ -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); @@ -153,11 +145,13 @@ void VideoAudioDialog::addDisplayTab() myUseStretch = new CheckboxWidget(myTab, _font, xpos + INDENT, ypos + 1, "Stretch"); wid.push_back(myUseStretch); -#ifndef BSPF_MACOS +#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 @@ -482,11 +476,9 @@ 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")); -#ifndef BSPF_MACOS +#ifdef ADAPTABLE_REFRESH_SUPPORT // Adapt refresh rate myRefreshAdapt->setState(instance().settings().getBool("tia.fs_refresh")); #endif @@ -601,7 +593,7 @@ void VideoAudioDialog::saveConfig() instance().settings().setValue("fullscreen", myFullscreen->getState()); // Fullscreen stretch setting instance().settings().setValue("tia.fs_stretch", myUseStretch->getState()); -#ifndef BSPF_MACOS +#ifdef ADAPTABLE_REFRESH_SUPPORT // Adapt refresh rate instance().settings().setValue("tia.fs_refresh", myRefreshAdapt->getState()); #endif @@ -621,7 +613,6 @@ void VideoAudioDialog::saveConfig() // Note: Palette values are saved directly when changed! - ///////////////////////////////////////////////////////////////////////////// // TV Effects tab // TV Mode @@ -716,9 +707,8 @@ void VideoAudioDialog::setDefaults() myTIAInterpolate->setState(false); // screen size myFullscreen->setState(false); - //myFullScreenMode->setSelectedIndex(0); myUseStretch->setState(false); - #ifndef BSPF_MACOS + #ifdef ADAPTABLE_REFRESH_SUPPORT myRefreshAdapt->setState(false); #endif myTVOverscan->setValue(0); @@ -846,7 +836,7 @@ void VideoAudioDialog::handleFullScreenChange() { bool enable = myFullscreen->getState(); myUseStretch->setEnabled(enable); -#ifndef BSPF_MACOS +#ifdef ADAPTABLE_REFRESH_SUPPORT myRefreshAdapt->setEnabled(enable); #endif myTVOverscan->setEnabled(enable); diff --git a/src/gui/VideoAudioDialog.hxx b/src/gui/VideoAudioDialog.hxx index c20b39438..0961f776e 100644 --- a/src/gui/VideoAudioDialog.hxx +++ b/src/gui/VideoAudioDialog.hxx @@ -73,9 +73,7 @@ class VideoAudioDialog : public Dialog CheckboxWidget* myFullscreen{nullptr}; CheckboxWidget* myUseStretch{nullptr}; SliderWidget* myTVOverscan{nullptr}; - #ifndef BSPF_MACOS CheckboxWidget* myRefreshAdapt{nullptr}; - #endif SliderWidget* myTIAZoom{nullptr}; SliderWidget* myVSizeAdjust{nullptr}; From 449bfb38d95ac79710bd8d226b882f5ac820bdf1 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 24 May 2020 10:03:53 +0200 Subject: [PATCH 242/377] updated doc (adapting refresh not available for macOS) added event and hotkey for adapting refresh rate fixed endless loop in global hotkeys --- docs/index.html | 15 ++++++++++--- src/common/PKeyboardHandler.cxx | 1 + src/emucore/Event.hxx | 1 + src/emucore/EventHandler.cxx | 37 +++++++++++++++++++++++++++------ src/emucore/EventHandler.hxx | 10 ++++++++- src/emucore/FrameBuffer.cxx | 29 ++++++++++++++++++++++++++ src/emucore/FrameBuffer.hxx | 7 +++++++ 7 files changed, 90 insertions(+), 10 deletions(-) diff --git a/docs/index.html b/docs/index.html index 85ddf5b74..d97a89022 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1377,6 +1377,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 @@ -2191,7 +2198,7 @@
      -audio.dpc_pitch <10000 - 30000>
      - Set the pitch o f Pitfall II music. + Set the pitch of Pitfall II music. @@ -2221,7 +2228,8 @@
      -tia.fs_refresh <1|0>
      While in fullscreen mode, adapt the display's refresh rate to the game's frame rate - to minimize judder. + to minimize judder.
      + Note: Not available for macOS. @@ -2954,7 +2962,8 @@ FullscreenSelf-explanatory - Note that colors may slightly change. This depends on the OS and renderer used.-fullscreen 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.-tia.fs_refresh + 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 the TIA image-tia.vsizeadjust diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index cf4a31831..81b25cd6e 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -467,6 +467,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}, diff --git a/src/emucore/Event.hxx b/src/emucore/Event.hxx index fa8a4d04d..ddac653f3 100644 --- a/src/emucore/Event.hxx +++ b/src/emucore/Event.hxx @@ -123,6 +123,7 @@ class Event ToggleFrameStats, ToggleSAPortOrder, ExitGame, // add new events from here to avoid that user remapped events get overwritten SettingDecrease, SettingIncrease, PreviousSetting, NextSetting, + ToggleAdaptRefresh, LastType }; diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index fa87be91d..3817232c6 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -350,17 +350,25 @@ AdjustFunction EventHandler::cycleAdjustSetting(int direction) myOSystem.settings().getString("palette") == PaletteHandler::SETTING_CUSTOM; const bool isCustomFilter = myOSystem.settings().getInt("tv.filter") == int(NTSCFilter::Preset::CUSTOM); + bool repeat; do { myAdjustSetting = AdjustSetting(BSPF::clampw(int(myAdjustSetting) + direction, 0, int(AdjustSetting::MAX_ADJ))); // skip currently non-relevant adjustments - } while((myAdjustSetting == AdjustSetting::OVERSCAN && !isFullScreen) - || (myAdjustSetting == AdjustSetting::PALETTE_PHASE && !isCustomPalette) - || (myAdjustSetting >= AdjustSetting::NTSC_SHARPNESS - && myAdjustSetting <= AdjustSetting::NTSC_BLEEDING - && !isCustomFilter)); + 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); + // avoid endless loop + if(repeat && !direction) + direction = 1; + } while(repeat); return getAdjustSetting(myAdjustSetting); } @@ -376,6 +384,9 @@ AdjustFunction EventHandler::getAdjustSetting(AdjustSetting setting) 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), @@ -658,6 +669,17 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) } 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) { @@ -2218,6 +2240,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", "" }, @@ -2361,7 +2386,7 @@ const Event::EventSet EventHandler::MiscEvents = { 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, diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx index 0ab40c7cd..7d9dd235e 100644 --- a/src/emucore/EventHandler.hxx +++ b/src/emucore/EventHandler.hxx @@ -398,6 +398,9 @@ class EventHandler VOLUME, ZOOM, FULLSCREEN, + #ifdef ADAPTABLE_REFRESH_SUPPORT + ADAPT_REFRESH, + #endif OVERSCAN, TVFORMAT, VCENTER, @@ -517,7 +520,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 = 156 + PNG_SIZE + COMBO_SIZE + REFRESH_SIZE, MENU_ACTIONLIST_SIZE = 18 ; diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 88f62517f..4812e22f6 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -1008,6 +1008,35 @@ void FrameBuffer::toggleFullscreen(bool toggle) } } +#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) { diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index 945cbb780..a86743911 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -269,6 +269,13 @@ class FrameBuffer */ void toggleFullscreen(bool toggle = true); + #ifdef ADAPTABLE_REFRESH_SUPPORT + /** + Toggles between adapt fullscreen refresh rate on and off. + */ + void FrameBuffer::toggleAdaptRefresh(bool toggle = true); + #endif + /** Changes the fullscreen overscan. From 894ab903ac5f02f1ac3748fe35feaa71ccbffa98 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sun, 24 May 2020 13:10:59 -0230 Subject: [PATCH 243/377] Fix compile error. --- src/emucore/FrameBuffer.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index a86743911..b09d492f1 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -273,7 +273,7 @@ class FrameBuffer /** Toggles between adapt fullscreen refresh rate on and off. */ - void FrameBuffer::toggleAdaptRefresh(bool toggle = true); + void toggleAdaptRefresh(bool toggle = true); #endif /** From 26887e314ee93b8acc7478b6f87665bd21ec4a17 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sun, 24 May 2020 16:08:24 -0230 Subject: [PATCH 244/377] Shorten error messages in ROM launcher, to fix overflow of buffer width. --- src/emucore/OSystem.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index 9c84b4165..2bb3746d4 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -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(); } From c41c0cf805bf330361e2c3ae8bdf87b4aaf8d493 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sun, 24 May 2020 18:57:45 -0230 Subject: [PATCH 245/377] Unify Cartridge::bank() and CartEnhanced::bank(). Otherwise, gcc complains of methods mirroring another with the same name. --- src/emucore/Cart.hxx | 8 ++++++-- src/emucore/CartAR.cxx | 2 +- src/emucore/CartAR.hxx | 7 +++++-- src/emucore/CartBUS.cxx | 2 +- src/emucore/CartBUS.hxx | 7 +++++-- src/emucore/CartCDF.cxx | 2 +- src/emucore/CartCDF.hxx | 7 +++++-- src/emucore/CartCM.cxx | 2 +- src/emucore/CartCM.hxx | 7 +++++-- src/emucore/CartCTY.cxx | 2 +- src/emucore/CartCTY.hxx | 7 +++++-- src/emucore/CartDPCPlus.cxx | 2 +- src/emucore/CartDPCPlus.hxx | 7 +++++-- src/emucore/CartEnhanced.hxx | 11 +---------- src/emucore/CartMDM.cxx | 2 +- src/emucore/CartMDM.hxx | 7 +++++-- src/emucore/CartMNetwork.cxx | 2 +- src/emucore/CartMNetwork.hxx | 7 +++++-- 18 files changed, 55 insertions(+), 36 deletions(-) diff --git a/src/emucore/Cart.hxx b/src/emucore/Cart.hxx index b04a95f10..cfd19497c 100644 --- a/src/emucore/Cart.hxx +++ b/src/emucore/Cart.hxx @@ -169,8 +169,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 +202,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 diff --git a/src/emucore/CartAR.cxx b/src/emucore/CartAR.cxx index a0eea7486..08f803e0b 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)); diff --git a/src/emucore/CartAR.hxx b/src/emucore/CartAR.hxx index 0bc74a291..349de38f1 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. diff --git a/src/emucore/CartBUS.cxx b/src/emucore/CartBUS.cxx index e2eb9b74a..62000118b 100644 --- a/src/emucore/CartBUS.cxx +++ b/src/emucore/CartBUS.cxx @@ -429,7 +429,7 @@ bool CartridgeBUS::poke(uInt16 address, uInt8 value) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeBUS::bank(uInt16 bank) +bool CartridgeBUS::bank(uInt16 bank, uInt16) { if(bankLocked()) return false; diff --git a/src/emucore/CartBUS.hxx b/src/emucore/CartBUS.hxx index 3ab40f7ec..58e4eea48 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. diff --git a/src/emucore/CartCDF.cxx b/src/emucore/CartCDF.cxx index 6f9a5f4f7..09e0da3e3 100644 --- a/src/emucore/CartCDF.cxx +++ b/src/emucore/CartCDF.cxx @@ -402,7 +402,7 @@ bool CartridgeCDF::poke(uInt16 address, uInt8 value) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeCDF::bank(uInt16 bank) +bool CartridgeCDF::bank(uInt16 bank, uInt16) { if(bankLocked()) return false; diff --git a/src/emucore/CartCDF.hxx b/src/emucore/CartCDF.hxx index 14b1eda26..62c1721ca 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. diff --git a/src/emucore/CartCM.cxx b/src/emucore/CartCM.cxx index 40ec603e5..b5dfc5197 100644 --- a/src/emucore/CartCM.cxx +++ b/src/emucore/CartCM.cxx @@ -98,7 +98,7 @@ uInt8 CartridgeCM::column() const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeCM::bank(uInt16 bank) +bool CartridgeCM::bank(uInt16 bank, uInt16) { if(bankLocked()) return false; diff --git a/src/emucore/CartCM.hxx b/src/emucore/CartCM.hxx index bf8b2586e..36fa13fa8 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. diff --git a/src/emucore/CartCTY.cxx b/src/emucore/CartCTY.cxx index 822473081..dbb5d13e2 100644 --- a/src/emucore/CartCTY.cxx +++ b/src/emucore/CartCTY.cxx @@ -229,7 +229,7 @@ bool CartridgeCTY::poke(uInt16 address, uInt8 value) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeCTY::bank(uInt16 bank) +bool CartridgeCTY::bank(uInt16 bank, uInt16) { if(bankLocked()) return false; diff --git a/src/emucore/CartCTY.hxx b/src/emucore/CartCTY.hxx index fdd6c1e19..1cd682446 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. diff --git a/src/emucore/CartDPCPlus.cxx b/src/emucore/CartDPCPlus.cxx index b71f5a8c0..7a0a7f4c6 100644 --- a/src/emucore/CartDPCPlus.cxx +++ b/src/emucore/CartDPCPlus.cxx @@ -591,7 +591,7 @@ bool CartridgeDPCPlus::poke(uInt16 address, uInt8 value) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeDPCPlus::bank(uInt16 bank) +bool CartridgeDPCPlus::bank(uInt16 bank, uInt16) { if(bankLocked()) return false; diff --git a/src/emucore/CartDPCPlus.hxx b/src/emucore/CartDPCPlus.hxx index 9617d6545..bbbf68197 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. diff --git a/src/emucore/CartEnhanced.hxx b/src/emucore/CartEnhanced.hxx index 743a4b50e..3c2e2c80d 100644 --- a/src/emucore/CartEnhanced.hxx +++ b/src/emucore/CartEnhanced.hxx @@ -70,16 +70,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. diff --git a/src/emucore/CartMDM.cxx b/src/emucore/CartMDM.cxx index decb634ec..2734b2793 100644 --- a/src/emucore/CartMDM.cxx +++ b/src/emucore/CartMDM.cxx @@ -88,7 +88,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..fe17ae628 100644 --- a/src/emucore/CartMDM.hxx +++ b/src/emucore/CartMDM.hxx @@ -73,9 +73,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..84cf8dac8 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; diff --git a/src/emucore/CartMNetwork.hxx b/src/emucore/CartMNetwork.hxx index 95cd24b56..7b4fdb729 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. From cb847c94b1e635b9b49243a9282edd5de854caf7 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 24 May 2020 23:45:46 +0200 Subject: [PATCH 246/377] Revert "Merge branch 'master' of https://github.com/stella-emu/stella" This reverts commit 3f9ef8026b1b8e8a44b7ce0d17f54f5540f26fc6, reversing changes made to 191684b6d2cf906904cf4573c5dd30fce8404873. --- src/emucore/Bankswitch.cxx | 4 +++ src/emucore/Bankswitch.hxx | 16 ++++++------ src/emucore/Cart.hxx | 8 ++---- src/emucore/CartAR.cxx | 2 +- src/emucore/CartAR.hxx | 7 ++--- src/emucore/CartBUS.cxx | 2 +- src/emucore/CartBUS.hxx | 7 ++--- src/emucore/CartCDF.cxx | 2 +- src/emucore/CartCDF.hxx | 7 ++--- src/emucore/CartCM.cxx | 2 +- src/emucore/CartCM.hxx | 7 ++--- src/emucore/CartCTY.cxx | 2 +- src/emucore/CartCTY.hxx | 7 ++--- src/emucore/CartDPCPlus.cxx | 2 +- src/emucore/CartDPCPlus.hxx | 7 ++--- src/emucore/CartDetector.cxx | 16 ++++++++++++ src/emucore/CartDetector.hxx | 5 ++++ src/emucore/CartEnhanced.hxx | 11 +++++++- src/emucore/CartMDM.cxx | 2 +- src/emucore/CartMDM.hxx | 7 ++--- src/emucore/CartMNetwork.cxx | 2 +- src/emucore/CartMNetwork.hxx | 7 ++--- src/emucore/EventHandler.cxx | 42 +++++++++++++++++++++++++----- src/emucore/OSystem.cxx | 2 +- src/windows/Stella.vcxproj | 4 +++ src/windows/Stella.vcxproj.filters | 12 +++++++++ 26 files changed, 122 insertions(+), 70 deletions(-) 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.hxx b/src/emucore/Cart.hxx index cfd19497c..b04a95f10 100644 --- a/src/emucore/Cart.hxx +++ b/src/emucore/Cart.hxx @@ -169,13 +169,8 @@ 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 bank, uInt16 segment = 0) { return false; } + virtual bool bank(uInt16) { return false; } /** Get the current bank for the provided address. Carts which have only @@ -202,6 +197,7 @@ 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 diff --git a/src/emucore/CartAR.cxx b/src/emucore/CartAR.cxx index 08f803e0b..a0eea7486 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, uInt16) +bool CartridgeAR::bank(uInt16 bank) { if(!bankLocked()) return bankConfiguration(uInt8(bank)); diff --git a/src/emucore/CartAR.hxx b/src/emucore/CartAR.hxx index 349de38f1..0bc74a291 100644 --- a/src/emucore/CartAR.hxx +++ b/src/emucore/CartAR.hxx @@ -73,12 +73,9 @@ 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 segment The segment the bank should be using - - @return true, if bank has changed + @param bank The bank that should be installed in the system */ - bool bank(uInt16 bank, uInt16 segment = 0) override; + bool bank(uInt16 bank) override; /** Get the current bank. diff --git a/src/emucore/CartBUS.cxx b/src/emucore/CartBUS.cxx index 62000118b..e2eb9b74a 100644 --- a/src/emucore/CartBUS.cxx +++ b/src/emucore/CartBUS.cxx @@ -429,7 +429,7 @@ bool CartridgeBUS::poke(uInt16 address, uInt8 value) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeBUS::bank(uInt16 bank, uInt16) +bool CartridgeBUS::bank(uInt16 bank) { if(bankLocked()) return false; diff --git a/src/emucore/CartBUS.hxx b/src/emucore/CartBUS.hxx index 58e4eea48..3ab40f7ec 100644 --- a/src/emucore/CartBUS.hxx +++ b/src/emucore/CartBUS.hxx @@ -84,12 +84,9 @@ 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 segment The segment the bank should be using - - @return true, if bank has changed + @param bank The bank that should be installed in the system */ - bool bank(uInt16 bank, uInt16 segment = 0) override; + bool bank(uInt16 bank) override; /** Get the current bank. diff --git a/src/emucore/CartCDF.cxx b/src/emucore/CartCDF.cxx index 09e0da3e3..6f9a5f4f7 100644 --- a/src/emucore/CartCDF.cxx +++ b/src/emucore/CartCDF.cxx @@ -402,7 +402,7 @@ bool CartridgeCDF::poke(uInt16 address, uInt8 value) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeCDF::bank(uInt16 bank, uInt16) +bool CartridgeCDF::bank(uInt16 bank) { if(bankLocked()) return false; diff --git a/src/emucore/CartCDF.hxx b/src/emucore/CartCDF.hxx index 62c1721ca..14b1eda26 100644 --- a/src/emucore/CartCDF.hxx +++ b/src/emucore/CartCDF.hxx @@ -90,12 +90,9 @@ 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 segment The segment the bank should be using - - @return true, if bank has changed + @param bank The bank that should be installed in the system */ - bool bank(uInt16 bank, uInt16 segment = 0) override; + bool bank(uInt16 bank) override; /** Get the current bank. diff --git a/src/emucore/CartCM.cxx b/src/emucore/CartCM.cxx index b5dfc5197..40ec603e5 100644 --- a/src/emucore/CartCM.cxx +++ b/src/emucore/CartCM.cxx @@ -98,7 +98,7 @@ uInt8 CartridgeCM::column() const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeCM::bank(uInt16 bank, uInt16) +bool CartridgeCM::bank(uInt16 bank) { if(bankLocked()) return false; diff --git a/src/emucore/CartCM.hxx b/src/emucore/CartCM.hxx index 36fa13fa8..bf8b2586e 100644 --- a/src/emucore/CartCM.hxx +++ b/src/emucore/CartCM.hxx @@ -141,12 +141,9 @@ 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 segment The segment the bank should be using - - @return true, if bank has changed + @param bank The bank that should be installed in the system */ - bool bank(uInt16 bank, uInt16 segment = 0) override; + bool bank(uInt16 bank) override; /** Get the current bank. diff --git a/src/emucore/CartCTY.cxx b/src/emucore/CartCTY.cxx index dbb5d13e2..822473081 100644 --- a/src/emucore/CartCTY.cxx +++ b/src/emucore/CartCTY.cxx @@ -229,7 +229,7 @@ bool CartridgeCTY::poke(uInt16 address, uInt8 value) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeCTY::bank(uInt16 bank, uInt16) +bool CartridgeCTY::bank(uInt16 bank) { if(bankLocked()) return false; diff --git a/src/emucore/CartCTY.hxx b/src/emucore/CartCTY.hxx index 1cd682446..fdd6c1e19 100644 --- a/src/emucore/CartCTY.hxx +++ b/src/emucore/CartCTY.hxx @@ -139,12 +139,9 @@ 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 segment The segment the bank should be using - - @return true, if bank has changed + @param bank The bank that should be installed in the system */ - bool bank(uInt16 bank, uInt16 segment = 0) override; + bool bank(uInt16 bank) override; /** Get the current bank. diff --git a/src/emucore/CartDPCPlus.cxx b/src/emucore/CartDPCPlus.cxx index 7a0a7f4c6..b71f5a8c0 100644 --- a/src/emucore/CartDPCPlus.cxx +++ b/src/emucore/CartDPCPlus.cxx @@ -591,7 +591,7 @@ bool CartridgeDPCPlus::poke(uInt16 address, uInt8 value) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeDPCPlus::bank(uInt16 bank, uInt16) +bool CartridgeDPCPlus::bank(uInt16 bank) { if(bankLocked()) return false; diff --git a/src/emucore/CartDPCPlus.hxx b/src/emucore/CartDPCPlus.hxx index bbbf68197..9617d6545 100644 --- a/src/emucore/CartDPCPlus.hxx +++ b/src/emucore/CartDPCPlus.hxx @@ -86,12 +86,9 @@ 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 segment The segment the bank should be using - - @return true, if bank has changed + @param bank The bank that should be installed in the system */ - bool bank(uInt16 bank, uInt16 segment = 0) override; + bool bank(uInt16 bank) override; /** Get the current bank. diff --git a/src/emucore/CartDetector.cxx b/src/emucore/CartDetector.cxx index 976d56579..2ff85803d 100644 --- a/src/emucore/CartDetector.cxx +++ b/src/emucore/CartDetector.cxx @@ -56,6 +56,7 @@ #include "CartFE.hxx" #include "CartMDM.hxx" #include "CartSB.hxx" +#include "CartTVBoy.hxx" #include "CartUA.hxx" #include "CartWD.hxx" #include "CartX07.hxx" @@ -328,6 +329,8 @@ CartDetector::createFromImage(const ByteBuffer& image, size_t size, Bankswitch:: 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); @@ -524,6 +527,11 @@ 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 // what else can we do? { if(isProbably3EX(image, size)) @@ -1000,6 +1008,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..11ff7ac1f 100644 --- a/src/emucore/CartDetector.hxx +++ b/src/emucore/CartDetector.hxx @@ -247,6 +247,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/CartEnhanced.hxx b/src/emucore/CartEnhanced.hxx index 3c2e2c80d..743a4b50e 100644 --- a/src/emucore/CartEnhanced.hxx +++ b/src/emucore/CartEnhanced.hxx @@ -70,7 +70,16 @@ class CartridgeEnhanced : public Cartridge @return true, if bank has changed */ - bool bank(uInt16 bank, uInt16 segment = 0) override; + 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); } /** Get the current bank. diff --git a/src/emucore/CartMDM.cxx b/src/emucore/CartMDM.cxx index 2734b2793..decb634ec 100644 --- a/src/emucore/CartMDM.cxx +++ b/src/emucore/CartMDM.cxx @@ -88,7 +88,7 @@ bool CartridgeMDM::poke(uInt16 address, uInt8 value) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeMDM::bank(uInt16 bank, uInt16) +bool CartridgeMDM::bank(uInt16 bank) { if(bankLocked() || myBankingDisabled) return false; diff --git a/src/emucore/CartMDM.hxx b/src/emucore/CartMDM.hxx index fe17ae628..4b0786e42 100644 --- a/src/emucore/CartMDM.hxx +++ b/src/emucore/CartMDM.hxx @@ -73,12 +73,9 @@ 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 segment The segment the bank should be using - - @return true, if bank has changed + @param bank The bank that should be installed in the system */ - bool bank(uInt16 bank, uInt16 segment = 0) override; + bool bank(uInt16 bank) 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 84cf8dac8..c6542b2b8 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, uInt16) +bool CartridgeMNetwork::bank(uInt16 bank) { if(bankLocked()) return false; diff --git a/src/emucore/CartMNetwork.hxx b/src/emucore/CartMNetwork.hxx index 7b4fdb729..95cd24b56 100644 --- a/src/emucore/CartMNetwork.hxx +++ b/src/emucore/CartMNetwork.hxx @@ -94,12 +94,9 @@ 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 segment The segment the bank should be using - - @return true, if bank has changed + @param bank The bank that should be installed in the system */ - bool bank(uInt16 bank, uInt16 segment = 0) override; + bool bank(uInt16 bank) override; /** Get the current bank. diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 3817232c6..2f26abc99 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -717,27 +717,57 @@ 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); + if(pressed && !repeated) + { + myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::CUSTOM); + myAdjustSetting = AdjustSetting::NTSC_PRESET; + myAdjustActive = true; + } return; case Event::PreviousAttribute: diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index 2bb3746d4..9c84b4165 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -414,7 +414,7 @@ string OSystem::createConsole(const FilesystemNode& rom, const string& md5sum, } catch(const runtime_error& e) { - buf << "ERROR: " << e.what(); + buf << "ERROR: Couldn't create console (" << e.what() << ")"; Logger::error(buf.str()); return buf.str(); } diff --git a/src/windows/Stella.vcxproj b/src/windows/Stella.vcxproj index 6fef5d589..a4a2365a7 100644 --- a/src/windows/Stella.vcxproj +++ b/src/windows/Stella.vcxproj @@ -523,6 +523,7 @@ true + true @@ -729,6 +730,7 @@ + @@ -1532,6 +1534,7 @@ true + true @@ -1747,6 +1750,7 @@ + diff --git a/src/windows/Stella.vcxproj.filters b/src/windows/Stella.vcxproj.filters index 0e4f58929..2a740137e 100644 --- a/src/windows/Stella.vcxproj.filters +++ b/src/windows/Stella.vcxproj.filters @@ -1005,6 +1005,12 @@ Source Files\gui + + Source Files\emucore + + + Source Files\debugger + @@ -2063,6 +2069,12 @@ Header Files\gui + + Header Files\emucore + + + Header Files\debugger + From 548e8b70187b4f114f7c8b23c1d388b56c3c061a Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 24 May 2020 23:50:36 +0200 Subject: [PATCH 247/377] Added TV Boy bankswitching --- src/debugger/gui/CartTVBoyWidget.cxx | 41 ++++++++++ src/debugger/gui/CartTVBoyWidget.hxx | 48 ++++++++++++ src/debugger/gui/module.mk | 1 + src/emucore/CartTVBoy.cxx | 87 +++++++++++++++++++++ src/emucore/CartTVBoy.hxx | 113 +++++++++++++++++++++++++++ src/emucore/module.mk | 1 + 6 files changed, 291 insertions(+) create mode 100644 src/debugger/gui/CartTVBoyWidget.cxx create mode 100644 src/debugger/gui/CartTVBoyWidget.hxx create mode 100644 src/emucore/CartTVBoy.cxx create mode 100644 src/emucore/CartTVBoy.hxx diff --git a/src/debugger/gui/CartTVBoyWidget.cxx b/src/debugger/gui/CartTVBoyWidget.cxx new file mode 100644 index 000000000..43fff60f7 --- /dev/null +++ b/src/debugger/gui/CartTVBoyWidget.cxx @@ -0,0 +1,41 @@ +//============================================================================ +// +// 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 "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) +{ + initialize(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartridgeTVBoyWidget::description() +{ + ostringstream info; + + info << "TV Boy, " << myCart.romBankCount() << " 4K banks\n" + << "Hotspots are from $" << Common::Base::HEX2 << 0x1800 << " to $" + << Common::Base::HEX2 << (0x1800 + myCart.romBankCount() - 1) << "\n"; + info << "Startup bank = #" << std::dec << myCart.startBank(); + + return info.str(); +} diff --git a/src/debugger/gui/CartTVBoyWidget.hxx b/src/debugger/gui/CartTVBoyWidget.hxx new file mode 100644 index 000000000..7303750a7 --- /dev/null +++ b/src/debugger/gui/CartTVBoyWidget.hxx @@ -0,0 +1,48 @@ +//============================================================================ +// +// 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; + +#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; + +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/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/CartTVBoy.cxx b/src/emucore/CartTVBoy.cxx new file mode 100644 index 000000000..8ce3c4549 --- /dev/null +++ b/src/emucore/CartTVBoy.cxx @@ -0,0 +1,87 @@ +//============================================================================ +// +// 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) + : CartridgeEnhanced(image, size, md5, settings) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +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) +{ + 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..670a358ff --- /dev/null +++ b/src/emucore/CartTVBoy.hxx @@ -0,0 +1,113 @@ +//============================================================================ +// +// 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 CartridgeMDMWidget; + + 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) + */ + CartridgeTVBoy(const ByteBuffer& image, size_t size, const string& md5, + const Settings& settings); + virtual ~CartridgeTVBoy() = default; + + public: + /** + Install pages for the specified bank in the system. + + @param bank The bank that should be installed in the system + */ + bool bank(uInt16 bank) 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/module.mk b/src/emucore/module.mk index e0dd4f96f..cccda359c 100644 --- a/src/emucore/module.mk +++ b/src/emucore/module.mk @@ -47,6 +47,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 \ From 57f5b3c5e4982620619ccbed488489479b74cd9d Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sun, 24 May 2020 19:33:21 -0230 Subject: [PATCH 248/377] Unify Cartridge::bank() and CartEnhanced::bank() (take 2). Otherwise, gcc complains of methods mirroring another with the same name. --- src/emucore/Cart.hxx | 9 ++++++--- src/emucore/CartAR.cxx | 2 +- src/emucore/CartAR.hxx | 7 +++++-- src/emucore/CartBUS.cxx | 2 +- src/emucore/CartBUS.hxx | 7 +++++-- src/emucore/CartCDF.cxx | 2 +- src/emucore/CartCDF.hxx | 7 +++++-- src/emucore/CartCM.cxx | 2 +- src/emucore/CartCM.hxx | 7 +++++-- src/emucore/CartCTY.cxx | 2 +- src/emucore/CartCTY.hxx | 7 +++++-- src/emucore/CartDPCPlus.cxx | 2 +- src/emucore/CartDPCPlus.hxx | 7 +++++-- src/emucore/CartEnhanced.hxx | 11 +---------- src/emucore/CartMDM.cxx | 2 +- src/emucore/CartMDM.hxx | 7 +++++-- src/emucore/CartMNetwork.cxx | 2 +- src/emucore/CartMNetwork.hxx | 7 +++++-- src/emucore/CartTVBoy.cxx | 2 +- src/emucore/CartTVBoy.hxx | 7 +++++-- 20 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/emucore/Cart.hxx b/src/emucore/Cart.hxx index b04a95f10..0e70f4bf7 100644 --- a/src/emucore/Cart.hxx +++ b/src/emucore/Cart.hxx @@ -140,7 +140,6 @@ class Cartridge : public Device */ uInt16 getIllegalRAMWriteAccess() const { return myRamWriteAccess; } - /** Query the access counters @@ -169,8 +168,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 +201,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 diff --git a/src/emucore/CartAR.cxx b/src/emucore/CartAR.cxx index a0eea7486..08f803e0b 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)); diff --git a/src/emucore/CartAR.hxx b/src/emucore/CartAR.hxx index 0bc74a291..349de38f1 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. diff --git a/src/emucore/CartBUS.cxx b/src/emucore/CartBUS.cxx index e2eb9b74a..62000118b 100644 --- a/src/emucore/CartBUS.cxx +++ b/src/emucore/CartBUS.cxx @@ -429,7 +429,7 @@ bool CartridgeBUS::poke(uInt16 address, uInt8 value) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeBUS::bank(uInt16 bank) +bool CartridgeBUS::bank(uInt16 bank, uInt16) { if(bankLocked()) return false; diff --git a/src/emucore/CartBUS.hxx b/src/emucore/CartBUS.hxx index 3ab40f7ec..58e4eea48 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. diff --git a/src/emucore/CartCDF.cxx b/src/emucore/CartCDF.cxx index 6f9a5f4f7..09e0da3e3 100644 --- a/src/emucore/CartCDF.cxx +++ b/src/emucore/CartCDF.cxx @@ -402,7 +402,7 @@ bool CartridgeCDF::poke(uInt16 address, uInt8 value) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeCDF::bank(uInt16 bank) +bool CartridgeCDF::bank(uInt16 bank, uInt16) { if(bankLocked()) return false; diff --git a/src/emucore/CartCDF.hxx b/src/emucore/CartCDF.hxx index 14b1eda26..62c1721ca 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. diff --git a/src/emucore/CartCM.cxx b/src/emucore/CartCM.cxx index 40ec603e5..b5dfc5197 100644 --- a/src/emucore/CartCM.cxx +++ b/src/emucore/CartCM.cxx @@ -98,7 +98,7 @@ uInt8 CartridgeCM::column() const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeCM::bank(uInt16 bank) +bool CartridgeCM::bank(uInt16 bank, uInt16) { if(bankLocked()) return false; diff --git a/src/emucore/CartCM.hxx b/src/emucore/CartCM.hxx index bf8b2586e..36fa13fa8 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. diff --git a/src/emucore/CartCTY.cxx b/src/emucore/CartCTY.cxx index 822473081..dbb5d13e2 100644 --- a/src/emucore/CartCTY.cxx +++ b/src/emucore/CartCTY.cxx @@ -229,7 +229,7 @@ bool CartridgeCTY::poke(uInt16 address, uInt8 value) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeCTY::bank(uInt16 bank) +bool CartridgeCTY::bank(uInt16 bank, uInt16) { if(bankLocked()) return false; diff --git a/src/emucore/CartCTY.hxx b/src/emucore/CartCTY.hxx index fdd6c1e19..1cd682446 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. diff --git a/src/emucore/CartDPCPlus.cxx b/src/emucore/CartDPCPlus.cxx index b71f5a8c0..7a0a7f4c6 100644 --- a/src/emucore/CartDPCPlus.cxx +++ b/src/emucore/CartDPCPlus.cxx @@ -591,7 +591,7 @@ bool CartridgeDPCPlus::poke(uInt16 address, uInt8 value) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeDPCPlus::bank(uInt16 bank) +bool CartridgeDPCPlus::bank(uInt16 bank, uInt16) { if(bankLocked()) return false; diff --git a/src/emucore/CartDPCPlus.hxx b/src/emucore/CartDPCPlus.hxx index 9617d6545..bbbf68197 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. diff --git a/src/emucore/CartEnhanced.hxx b/src/emucore/CartEnhanced.hxx index 743a4b50e..3c2e2c80d 100644 --- a/src/emucore/CartEnhanced.hxx +++ b/src/emucore/CartEnhanced.hxx @@ -70,16 +70,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. diff --git a/src/emucore/CartMDM.cxx b/src/emucore/CartMDM.cxx index decb634ec..2734b2793 100644 --- a/src/emucore/CartMDM.cxx +++ b/src/emucore/CartMDM.cxx @@ -88,7 +88,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..fe17ae628 100644 --- a/src/emucore/CartMDM.hxx +++ b/src/emucore/CartMDM.hxx @@ -73,9 +73,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..84cf8dac8 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; diff --git a/src/emucore/CartMNetwork.hxx b/src/emucore/CartMNetwork.hxx index 95cd24b56..7b4fdb729 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. diff --git a/src/emucore/CartTVBoy.cxx b/src/emucore/CartTVBoy.cxx index 8ce3c4549..b60c374c4 100644 --- a/src/emucore/CartTVBoy.cxx +++ b/src/emucore/CartTVBoy.cxx @@ -38,7 +38,7 @@ bool CartridgeTVBoy::checkSwitchBank(uInt16 address, uInt8) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeTVBoy::bank(uInt16 bank) +bool CartridgeTVBoy::bank(uInt16 bank, uInt16) { if(myBankingDisabled) return false; diff --git a/src/emucore/CartTVBoy.hxx b/src/emucore/CartTVBoy.hxx index 670a358ff..584029a5a 100644 --- a/src/emucore/CartTVBoy.hxx +++ b/src/emucore/CartTVBoy.hxx @@ -53,9 +53,12 @@ class CartridgeTVBoy : 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. From 1cfa4f1d0a7c8273a6b664c23d86681554bfb06b Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sun, 24 May 2020 19:40:43 -0230 Subject: [PATCH 249/377] libretro: Add TVBoy cart class. --- src/libretro/Makefile.common | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libretro/Makefile.common b/src/libretro/Makefile.common index 5fafdd855..66de31b4d 100644 --- a/src/libretro/Makefile.common +++ b/src/libretro/Makefile.common @@ -81,6 +81,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 \ From a7b1928465317273cbeff9278911201c392be8bd Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 25 May 2020 00:14:32 +0200 Subject: [PATCH 250/377] updated VS project file --- src/windows/Stella.vcxproj | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/windows/Stella.vcxproj b/src/windows/Stella.vcxproj index a4a2365a7..97117b637 100644 --- a/src/windows/Stella.vcxproj +++ b/src/windows/Stella.vcxproj @@ -523,7 +523,6 @@ true - true @@ -663,6 +662,9 @@ true + + true + true @@ -1534,7 +1536,6 @@ true - true @@ -1674,6 +1675,9 @@ true + + true + true From d4ad7728e2bddc05b6b91c3e62c0c74d0182c7ec Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sun, 24 May 2020 19:47:30 -0230 Subject: [PATCH 251/377] Updated Xcode project for TVBoy class. --- src/macos/stella.xcodeproj/project.pbxproj | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/macos/stella.xcodeproj/project.pbxproj b/src/macos/stella.xcodeproj/project.pbxproj index d59aac510..0c2019a93 100644 --- a/src/macos/stella.xcodeproj/project.pbxproj +++ b/src/macos/stella.xcodeproj/project.pbxproj @@ -407,6 +407,10 @@ 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 */; }; 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 +704,8 @@ isa = PBXBuildRule; compilerSpec = com.apple.compilers.llvm.clang.1_0; fileType = sourcecode.c; + inputFiles = ( + ); isEditable = 1; outputFiles = ( ); @@ -709,6 +715,8 @@ isa = PBXBuildRule; compilerSpec = com.apple.compilers.llvm.clang.1_0; fileType = sourcecode.asm; + inputFiles = ( + ); isEditable = 1; outputFiles = ( ); @@ -718,6 +726,8 @@ isa = PBXBuildRule; compilerSpec = com.apple.compilers.llvm.clang.1_0; fileType = sourcecode.cpp; + inputFiles = ( + ); isEditable = 1; outputFiles = ( ); @@ -1146,6 +1156,10 @@ 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 = ""; }; 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 +1657,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 */, @@ -1902,6 +1918,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 +2380,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 */, @@ -2696,6 +2715,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 +2853,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 */, @@ -3068,6 +3089,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 */, From 78b11d146aa315a3edb5788fdb923eb155075d1d Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sun, 24 May 2020 20:11:36 -0230 Subject: [PATCH 252/377] Fix paddle autodetect in a ROM; it actually uses joysticks. --- src/emucore/DefProps.hxx | 2 +- src/emucore/stella.pro | 41 +++++++++++++++++++++------------------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/emucore/DefProps.hxx b/src/emucore/DefProps.hxx index fc0fe6155..e6cb3185d 100644 --- a/src/emucore/DefProps.hxx +++ b/src/emucore/DefProps.hxx @@ -3357,7 +3357,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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, diff --git a/src/emucore/stella.pro b/src/emucore/stella.pro index 8b783bba4..db9e694c8 100644 --- a/src/emucore/stella.pro +++ b/src/emucore/stella.pro @@ -7084,6 +7084,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" @@ -10223,6 +10233,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)" @@ -20241,6 +20261,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" @@ -21354,22 +21376,3 @@ "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" -"" From 6d383b353657b9152a47c5da27671afca56b61f7 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 25 May 2020 08:36:20 +0200 Subject: [PATCH 253/377] updated docs for TV Boy bankswitching --- Changes.txt | 2 +- docs/index.html | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Changes.txt b/Changes.txt index 616ec22f7..3d7a18ef4 100644 --- a/Changes.txt +++ b/Changes.txt @@ -53,7 +53,7 @@ * 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. diff --git a/docs/index.html b/docs/index.html index 81185180d..98bf31b72 100644 --- a/docs/index.html +++ b/docs/index.html @@ -4035,6 +4035,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 From 7c283a0ac46257616eb6821acf5b80c99f68715b Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 25 May 2020 08:55:05 +0200 Subject: [PATCH 254/377] enhanced TVBoy widget --- src/debugger/gui/CartTVBoyWidget.cxx | 46 +++++++++++++++++++++++++--- src/debugger/gui/CartTVBoyWidget.hxx | 46 ++++++++++++++++++---------- src/emucore/CartTVBoy.hxx | 2 +- 3 files changed, 73 insertions(+), 21 deletions(-) diff --git a/src/debugger/gui/CartTVBoyWidget.cxx b/src/debugger/gui/CartTVBoyWidget.cxx index 43fff60f7..5012642ba 100644 --- a/src/debugger/gui/CartTVBoyWidget.cxx +++ b/src/debugger/gui/CartTVBoyWidget.cxx @@ -16,13 +16,15 @@ //============================================================================ #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) + : CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart), + myCartTVBoy(cart) { initialize(); } @@ -33,9 +35,45 @@ string CartridgeTVBoyWidget::description() ostringstream info; info << "TV Boy, " << myCart.romBankCount() << " 4K banks\n" - << "Hotspots are from $" << Common::Base::HEX2 << 0x1800 << " to $" - << Common::Base::HEX2 << (0x1800 + myCart.romBankCount() - 1) << "\n"; - info << "Startup bank = #" << std::dec << myCart.startBank(); + << "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 index 7303750a7..e1c2780e6 100644 --- a/src/debugger/gui/CartTVBoyWidget.hxx +++ b/src/debugger/gui/CartTVBoyWidget.hxx @@ -19,30 +19,44 @@ #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; + 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"; } + private: + string manufacturer() override { return "Akor"; } - string description() override; + string description() 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; + 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/emucore/CartTVBoy.hxx b/src/emucore/CartTVBoy.hxx index 584029a5a..90072a08d 100644 --- a/src/emucore/CartTVBoy.hxx +++ b/src/emucore/CartTVBoy.hxx @@ -34,7 +34,7 @@ */ class CartridgeTVBoy : public CartridgeEnhanced { - friend class CartridgeMDMWidget; + friend class CartridgeTVBoyWidget; public: /** From 72b5a484f0131429615bfc8f088aab5681aa2a9d Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 25 May 2020 09:19:51 +0200 Subject: [PATCH 255/377] disable scanlines by default add default pause key for macOS --- docs/index.html | 2 +- src/common/PKeyboardHandler.cxx | 4 ++++ src/emucore/Settings.cxx | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/index.html b/docs/index.html index 98bf31b72..cb5855c2b 100644 --- a/docs/index.html +++ b/docs/index.html @@ -775,7 +775,7 @@ Pause/resume emulation Pause -   + Shift-Cmd + p diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index 81b25cd6e..5f97b90a1 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -443,7 +443,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}, diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index 790c784bb..e6d81abdd 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -69,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"); From 47e258f638c0f43738a13a63f59af919b7d989ec Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 25 May 2020 13:58:53 +0200 Subject: [PATCH 256/377] fix cart detection for 512K ROMs add new event & hotkey for selecting previous multicart ROM --- docs/index.html | 8 +++++++- src/common/PKeyboardHandler.cxx | 1 + src/emucore/CartDetector.cxx | 19 +++++++++++++++---- src/emucore/Event.hxx | 2 +- src/emucore/EventHandler.cxx | 9 +++++++-- src/emucore/EventHandler.hxx | 2 +- src/emucore/OSystem.cxx | 6 ++++-- src/emucore/OSystem.hxx | 4 +++- 8 files changed, 39 insertions(+), 12 deletions(-) diff --git a/docs/index.html b/docs/index.html index cb5855c2b..368d16530 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1749,9 +1749,15 @@ Control + 1 + + Load previous game in ROM (multicart ROM, TIA mode) + Shift-Control + r + Shift-Control + r + + Reload current ROM (singlecart ROM, TIA mode)
      - Load next game in ROM (multicart ROM, TIA mode) + Load next game in ROM (multicart ROM, TIA mode) Control + r Control + r diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index 5f97b90a1..4408081d7 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -459,6 +459,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}, diff --git a/src/emucore/CartDetector.cxx b/src/emucore/CartDetector.cxx index 2ff85803d..6b48e3469 100644 --- a/src/emucore/CartDetector.cxx +++ b/src/emucore/CartDetector.cxx @@ -218,6 +218,14 @@ CartDetector::createFromMultiCart(const ByteBuffer& image, size_t& size, { // 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()); @@ -228,9 +236,6 @@ CartDetector::createFromMultiCart(const ByteBuffer& image, size_t& size, 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; @@ -529,7 +534,13 @@ Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t si } else if(size == 512_KB) { - if(isProbablyTVBoy(image, size)) + 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 if(isProbablyTVBoy(image, size)) type = Bankswitch::Type::_TVBOY; } else // what else can we do? diff --git a/src/emucore/Event.hxx b/src/emucore/Event.hxx index ddac653f3..9a6c16352 100644 --- a/src/emucore/Event.hxx +++ b/src/emucore/Event.hxx @@ -123,7 +123,7 @@ class Event ToggleFrameStats, ToggleSAPortOrder, ExitGame, // add new events from here to avoid that user remapped events get overwritten SettingDecrease, SettingIncrease, PreviousSetting, NextSetting, - ToggleAdaptRefresh, + ToggleAdaptRefresh, PreviousMultiCartRom, LastType }; diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 2f26abc99..23a9c98ee 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -544,7 +544,11 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::ReloadConsole: - if(pressed && !repeated) myOSystem.reloadConsole(); + if(pressed && !repeated) myOSystem.reloadConsole(true); + return; + + case Event::PreviousMultiCartRom: + if(pressed && !repeated) myOSystem.reloadConsole(false); return; case Event::VolumeDecrease: @@ -2172,6 +2176,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", "" }, @@ -2409,7 +2414,7 @@ const Event::EventSet EventHandler::MiscEvents = { // Event::MouseAxisXMove, Event::MouseAxisYMove, // Event::MouseButtonLeftValue, Event::MouseButtonRightValue, Event::HandleMouseControl, Event::ToggleGrabMouse, - Event::ToggleSAPortOrder, + Event::ToggleSAPortOrder, Event::PreviousMultiCartRom }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx index 7d9dd235e..5d82e31b8 100644 --- a/src/emucore/EventHandler.hxx +++ b/src/emucore/EventHandler.hxx @@ -525,7 +525,7 @@ class EventHandler #else REFRESH_SIZE = 0, #endif - EMUL_ACTIONLIST_SIZE = 156 + PNG_SIZE + COMBO_SIZE + REFRESH_SIZE, + EMUL_ACTIONLIST_SIZE = 157 + PNG_SIZE + COMBO_SIZE + REFRESH_SIZE, MENU_ACTIONLIST_SIZE = 18 ; diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index 9c84b4165..0ebefebf1 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -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 @@ -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; } 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. From c7012528e693d8fcfeb8f72096c027f54f3de6b9 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 25 May 2020 18:32:13 +0200 Subject: [PATCH 257/377] reorder 512K bankswitching detection --- src/emucore/CartDetector.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/emucore/CartDetector.cxx b/src/emucore/CartDetector.cxx index 6b48e3469..eff02eed4 100644 --- a/src/emucore/CartDetector.cxx +++ b/src/emucore/CartDetector.cxx @@ -534,14 +534,14 @@ Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t si } else if(size == 512_KB) { - if(isProbably3EX(image, size)) + 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 if(isProbablyTVBoy(image, size)) - type = Bankswitch::Type::_TVBOY; } else // what else can we do? { From 3946b2f4e1014d130f3ff0b58eaeda1813597873 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Mon, 25 May 2020 14:06:05 -0230 Subject: [PATCH 258/377] Add TVBoy properties to database. --- src/emucore/DefProps.hxx | 4 +++- src/emucore/stella.pro | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/emucore/DefProps.hxx b/src/emucore/DefProps.hxx index e6cb3185d..333121515 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 = 3516; 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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, diff --git a/src/emucore/stella.pro b/src/emucore/stella.pro index db9e694c8..c487a6bae 100644 --- a/src/emucore/stella.pro +++ b/src/emucore/stella.pro @@ -21376,3 +21376,18 @@ "Cart.Name" "Spitfire Attack (1983) (Milton Bradley) [h1]" "" +"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" "65a6f1255fe22468a8bf84ff28a4d289" +"Cart.Manufacturer" "Akor" +"Cart.Name" "Super TV Boy (1995) (Akor)" +"Cart.Note" "Includes 127 games" +"Controller.Left" "JOYSTICK" +"Controller.Right" "JOYSTICK" +"" From e8640e21338e531798e0b4fa7f3470435f4cd03c Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Mon, 25 May 2020 14:14:57 -0230 Subject: [PATCH 259/377] libretro: Allow ROMs that are max size for Stella (instead of requiring 1 byte less). --- src/libretro/libretro.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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); From 96959a7c7d086e53109adbe64ce2b2cb9b4fd1ff Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Mon, 25 May 2020 17:32:01 -0230 Subject: [PATCH 260/377] Move 'max rom size' into a const method, and make use of it elsewhere in the code. --- src/common/bspf.hxx | 7 +++++-- src/emucore/Cart.cxx | 2 +- src/emucore/FSNode.cxx | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/common/bspf.hxx b/src/common/bspf.hxx index 3fc1aaf6c..844f12804 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(""); @@ -128,6 +128,9 @@ namespace BSPF static const string ARCH = "NOARCH"; #endif + // Maximum size of a ROM that Stella can support + inline constexpr size_t romMaxSize() { return 512_KB; } + // Make 2D-arrays using std::array less verbose template using array2D = std::array, ROW>; diff --git a/src/emucore/Cart.cxx b/src/emucore/Cart.cxx index 7639101ff..f86c81f8c 100644 --- a/src/emucore/Cart.cxx +++ b/src/emucore/Cart.cxx @@ -83,7 +83,7 @@ uInt16 Cartridge::bankSize(uInt16 bank) const getImage(size); - return std::min(uInt32(size) / romBankCount(), 4_KB); // assuming that each bank has the same size + return std::min(size / romBankCount(), 4_KB); // assuming that each bank has the same size } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/FSNode.cxx b/src/emucore/FSNode.cxx index 64af7212e..acdad37ca 100644 --- a/src/emucore/FSNode.cxx +++ b/src/emucore/FSNode.cxx @@ -236,7 +236,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(BSPF::romMaxSize()); ifstream in(getPath(), std::ios::binary); if (in) { @@ -247,7 +247,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, BSPF::romMaxSize()); in.read(reinterpret_cast(image.get()), size); } else From eb6c633c13e9179d4a6ff0930abf95fa003abdb1 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Mon, 25 May 2020 18:37:35 -0230 Subject: [PATCH 261/377] libretro: Use ROM size from core, update formatting and add const. --- src/libretro/FSNodeLIBRETRO.cxx | 3 +- src/libretro/StellaLIBRETRO.cxx | 87 ++++++++++++++++----------------- src/libretro/StellaLIBRETRO.hxx | 84 ++++++++++++++++++------------- 3 files changed, 96 insertions(+), 78 deletions(-) diff --git a/src/libretro/FSNodeLIBRETRO.cxx b/src/libretro/FSNodeLIBRETRO.cxx index c2ee02b97..8c242391b 100644 --- a/src/libretro/FSNodeLIBRETRO.cxx +++ b/src/libretro/FSNodeLIBRETRO.cxx @@ -15,6 +15,7 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include "bspf.hxx" #include "FSNodeLIBRETRO.hxx" #ifdef _WIN32 @@ -92,7 +93,7 @@ AbstractFSNodePtr FilesystemNodeLIBRETRO::getParent() const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - size_t FilesystemNodeLIBRETRO::read(ByteBuffer& image) const { - image = make_unique(512 * 1024); + image = make_unique(BSPF::romMaxSize()); extern uInt32 libretro_read_rom(void* data); return libretro_read_rom(image.get()); 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..01c2cbaf7 100644 --- a/src/libretro/StellaLIBRETRO.hxx +++ b/src/libretro/StellaLIBRETRO.hxx @@ -32,7 +32,6 @@ #include "TIA.hxx" #include "TIASurface.hxx" - /** This class wraps Stella core for easier libretro maintenance */ @@ -52,46 +51,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 BSPF::romMaxSize(); } 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 +113,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 +121,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 +155,7 @@ class StellaLIBRETRO unique_ptr myOSystem; uInt32 system_ready; - unique_ptr rom_image; + ByteBuffer rom_image; uInt32 rom_size; string rom_path; From d11bac4afbcad62e5710f692c80a4592cef39c82 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 26 May 2020 10:33:16 +0200 Subject: [PATCH 262/377] added two more TV Boy dumps and their properties --- src/emucore/DefProps.hxx | 4 +++- src/emucore/stella.pro | 48 ++++++++++++++++++++++++++-------------- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/src/emucore/DefProps.hxx b/src/emucore/DefProps.hxx index 333121515..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 = 3516; +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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -3148,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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -3422,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/stella.pro b/src/emucore/stella.pro index c487a6bae..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)" @@ -8536,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" @@ -18974,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)" @@ -20633,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" @@ -21375,19 +21407,3 @@ "Cart.MD5" "ffebb0070689b9d322687edd9c0a2bae" "Cart.Name" "Spitfire Attack (1983) (Milton Bradley) [h1]" "" - -"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" "65a6f1255fe22468a8bf84ff28a4d289" -"Cart.Manufacturer" "Akor" -"Cart.Name" "Super TV Boy (1995) (Akor)" -"Cart.Note" "Includes 127 games" -"Controller.Left" "JOYSTICK" -"Controller.Right" "JOYSTICK" -"" From cf54e2b833897941ddf65aa98186f825b5be29a8 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 26 May 2020 15:30:32 +0200 Subject: [PATCH 263/377] fixed #645 --- src/debugger/gui/Cart3EPlusWidget.cxx | 90 ++++++++++++++------------- src/debugger/gui/Cart3EPlusWidget.hxx | 9 +-- 2 files changed, 51 insertions(+), 48 deletions(-) diff --git a/src/debugger/gui/Cart3EPlusWidget.cxx b/src/debugger/gui/Cart3EPlusWidget.cxx index 8e7cdf063..a0d97ad2b 100644 --- a/src/debugger/gui/Cart3EPlusWidget.cxx +++ b/src/debugger/gui/Cart3EPlusWidget.cxx @@ -39,7 +39,7 @@ string Cartridge3EPlusWidget::description() 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" @@ -61,6 +61,7 @@ void Cartridge3EPlusWidget::bankSelect(int& ypos) { size_t size; const uInt8* 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 From 91c49bd222e4d905e1f4fbf279d73ec6e3674c05 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Tue, 26 May 2020 14:55:40 -0230 Subject: [PATCH 264/377] Add support for loading grayscale PNG. Fixes #644. If I'd known it would be that easy, I'd have done it long ago. --- Changes.txt | 2 ++ src/common/PNGLibrary.cxx | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Changes.txt b/Changes.txt index 3d7a18ef4..df70e30c0 100644 --- a/Changes.txt +++ b/Changes.txt @@ -57,6 +57,8 @@ * Removed unused CV+ and DASH bank switching types. + * Added support for loading grayscale PNG images in the ROM launcher. + -Have fun! 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) { From 3d06fb02581d8994422eebc3205b980baa0fb405 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 27 May 2020 10:14:16 +0200 Subject: [PATCH 265/377] added analog input filtering in UI (fixes #578) --- Changes.txt | 2 ++ src/common/PJoystickHandler.cxx | 37 +++++++++++++++++++-------------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/Changes.txt b/Changes.txt index df70e30c0..681118cc5 100644 --- a/Changes.txt +++ b/Changes.txt @@ -33,6 +33,8 @@ * Added that mouse sensitivity for Driving controller can be adjusted + * Added paddle filtering in UI to avoid unwanted navigation events + * Added selectable dialog fonts * Added separate positioning of launcher, emulator and debugger 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 } } From 1518d6fc5d99075f39a0c6f3f6a35451bbf992e9 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 28 May 2020 18:19:26 +0200 Subject: [PATCH 266/377] minor doc update --- docs/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.html b/docs/index.html index 368d16530..f0687880f 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1965,7 +1965,7 @@ N/A N/A N/A - N/A + voice (2600-daptor II) SaveKey From 5137b3a82ad938d5a449a6660264e52c94c7efd5 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Fri, 29 May 2020 16:30:50 -0230 Subject: [PATCH 267/377] Updated changelog, removing highscore stuff until 6.3. --- Changes.txt | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/Changes.txt b/Changes.txt index 681118cc5..887b8071b 100644 --- a/Changes.txt +++ b/Changes.txt @@ -14,34 +14,30 @@ 6.1.2 to 6.2: (??? ??, 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 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 paddle filtering in UI to avoid unwanted navigation events + * Added paddle filtering in UI to avoid unwanted navigation events. - * Added selectable dialog fonts + * Added selectable dialog fonts. - * Added separate positioning of launcher, emulator and debugger + * Added separate positioning of launcher, emulator and debugger. - * Added optional display to game refresh rate adaption in fullscreen mode + * Added optional display to game refresh rate adaption in fullscreen mode. - * Added option which lets default ROM path follow launcher navigation + * Added option which lets default ROM path follow launcher navigation. * Added debugger 'saveaccess' function, which saves memory access counts to a CSV file. From bedc04aaf43319a1a965cb1e632e04154aa16be2 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sat, 30 May 2020 17:21:06 -0230 Subject: [PATCH 268/377] Split logic for cart creation from CartDetector into new CartCreator class. Besides simplifying the class, this allows the code to be more easily integrated into HarmonyCart. --- src/emucore/CartCreator.cxx | 348 ++++++++++++++++++++++++++++++++ src/emucore/CartCreator.hxx | 96 +++++++++ src/emucore/CartDetector.cxx | 326 ------------------------------ src/emucore/CartDetector.hxx | 53 ----- src/emucore/OSystem.cxx | 4 +- src/emucore/ProfilingRunner.cxx | 5 +- src/emucore/module.mk | 1 + 7 files changed, 450 insertions(+), 383 deletions(-) create mode 100644 src/emucore/CartCreator.cxx create mode 100644 src/emucore/CartCreator.hxx 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/CartDetector.cxx b/src/emucore/CartDetector.cxx index eff02eed4..22ad4be9b 100644 --- a/src/emucore/CartDetector.cxx +++ b/src/emucore/CartDetector.cxx @@ -16,336 +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 "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" -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -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"); - - // 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 -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::_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 - } -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t size) { diff --git a/src/emucore/CartDetector.hxx b/src/emucore/CartDetector.hxx index 11ff7ac1f..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 diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index 0ebefebf1..7ef0c2b4a 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" @@ -571,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/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/module.mk b/src/emucore/module.mk index cccda359c..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 \ From c6c2d9e1623542da0c4550abaa810dd3341c89b8 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sat, 30 May 2020 17:24:07 -0230 Subject: [PATCH 269/377] libretro: Add CartCreator class. --- src/libretro/Makefile.common | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libretro/Makefile.common b/src/libretro/Makefile.common index 66de31b4d..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 \ From 88914c493bf76dee17d2029b4576714a31212fe1 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sat, 30 May 2020 17:34:44 -0230 Subject: [PATCH 270/377] Add CartCreator to VS project, and fix a few warnings. --- src/common/ZipHandler.hxx | 2 +- src/emucore/Cart.cxx | 4 ++-- src/emucore/CartDetector.cxx | 2 +- src/emucore/MT24LC256.hxx | 6 +++--- src/windows/Stella.vcxproj | 2 ++ src/windows/Stella.vcxproj.filters | 14 ++++++++++---- 6 files changed, 19 insertions(+), 11 deletions(-) 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/emucore/Cart.cxx b/src/emucore/Cart.cxx index f86c81f8c..958b915df 100644 --- a/src/emucore/Cart.cxx +++ b/src/emucore/Cart.cxx @@ -80,10 +80,10 @@ bool Cartridge::bankChanged() uInt16 Cartridge::bankSize(uInt16 bank) const { size_t size; - getImage(size); - return std::min(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/CartDetector.cxx b/src/emucore/CartDetector.cxx index 22ad4be9b..0ecc6e82e 100644 --- a/src/emucore/CartDetector.cxx +++ b/src/emucore/CartDetector.cxx @@ -629,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; 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/windows/Stella.vcxproj b/src/windows/Stella.vcxproj index 97117b637..33abbe73e 100644 --- a/src/windows/Stella.vcxproj +++ b/src/windows/Stella.vcxproj @@ -717,6 +717,7 @@ + @@ -1739,6 +1740,7 @@ + diff --git a/src/windows/Stella.vcxproj.filters b/src/windows/Stella.vcxproj.filters index 2a740137e..ded397f71 100644 --- a/src/windows/Stella.vcxproj.filters +++ b/src/windows/Stella.vcxproj.filters @@ -1008,8 +1008,11 @@ Source Files\emucore - - Source Files\debugger + + Source Files + + + Source Files\emucore
      @@ -2072,8 +2075,11 @@ Header Files\emucore - - Header Files\debugger + + Header Files + + + Header Files\emucore From 7c263c4199a3da449941982e9bfb47c46eb4e3ab Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sat, 30 May 2020 17:47:41 -0230 Subject: [PATCH 271/377] Update Xcode project for CartCreator class. --- src/macos/stella.xcodeproj/project.pbxproj | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/macos/stella.xcodeproj/project.pbxproj b/src/macos/stella.xcodeproj/project.pbxproj index 0c2019a93..f8c0789ce 100644 --- a/src/macos/stella.xcodeproj/project.pbxproj +++ b/src/macos/stella.xcodeproj/project.pbxproj @@ -411,6 +411,8 @@ 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 */; }; @@ -1160,6 +1162,8 @@ 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 = ""; }; @@ -1864,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 */, @@ -2582,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 */, @@ -2914,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 */, From f78d880a450a7051567a13da0a688e1da88ffbe4 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sat, 30 May 2020 22:03:10 -0230 Subject: [PATCH 272/377] Some small API changes for FSNode::getChildren(); it should only include the parent if requested. --- src/emucore/FSNode.cxx | 5 +++-- src/emucore/FSNode.hxx | 3 ++- src/unix/FSNodePOSIX.cxx | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/emucore/FSNode.cxx b/src/emucore/FSNode.cxx index acdad37ca..0d9e53ad1 100644 --- a/src/emucore/FSNode.cxx +++ b/src/emucore/FSNode.cxx @@ -47,7 +47,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 +84,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(" [..]"); 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/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 From 32db1cc2df133ae9f69adff1d7e1539ad79cef0d Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 2 Jun 2020 18:28:38 +0200 Subject: [PATCH 273/377] Save old state for "RunTo" and "RunToPC" debugger commands (fixes #650) --- src/debugger/DebuggerParser.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/debugger/DebuggerParser.cxx b/src/debugger/DebuggerParser.cxx index 49692ef8a..253131314 100644 --- a/src/debugger/DebuggerParser.cxx +++ b/src/debugger/DebuggerParser.cxx @@ -1733,6 +1733,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 +1778,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; From ea17bfd60468768c640bc79eda09a786789d9f86 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Tue, 2 Jun 2020 15:49:20 -0230 Subject: [PATCH 274/377] Updated version number for upcoming release. --- Announce.txt | 22 +++++++++++----------- Changes.txt | 2 +- debian/changelog | 7 +++++++ docs/debugger.html | 2 +- docs/index_r77.html | 2 +- src/common/StateManager.hxx | 2 +- src/common/Version.hxx | 2 +- src/macos/Info-Stella.plist | 4 ++-- src/unix/stella.spec | 5 ++++- src/windows/stella.rc | 8 ++++---- 10 files changed, 33 insertions(+), 23 deletions(-) diff --git a/Announce.txt b/Announce.txt index 18f636c79..6b85d8d00 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 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 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-win32.exe (32-bit EXE installer) + Stella-6.2-x64.exe (64-bit EXE installer) + Stella-6.2-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-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_i386.deb + stella_6.2-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-2.i386.rpm + stella-6.2-2.x86_64.rpm * Source code distribution for all platforms : - stella-6.1-src.tar.xz + stella-6.2-src.tar.xz Distribution Site diff --git a/Changes.txt b/Changes.txt index 887b8071b..fceea0039 100644 --- a/Changes.txt +++ b/Changes.txt @@ -12,7 +12,7 @@ Release History =========================================================================== -6.1.2 to 6.2: (??? ??, 2020) +6.1.2 to 6.2: (June 7, 2020) * Added interactive palette to Video & Audio settings. diff --git a/debian/changelog b/debian/changelog index 81ab67bce..6b4dff642 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +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..7f2cabec5 100644 --- a/docs/debugger.html +++ b/docs/debugger.html @@ -15,7 +15,7 @@
      Stella
      -

      Release 6.1

      +

      Release 6.2

      Integrated Debugger

      (a work in progress)


      diff --git a/docs/index_r77.html b/docs/index_r77.html index 710f5e561..33e767c7e 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

      Quick Navigation Guide


      diff --git a/src/common/StateManager.hxx b/src/common/StateManager.hxx index 3da98499c..a69a48cd5 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 "06020000state" class OSystem; class RewindManager; diff --git a/src/common/Version.hxx b/src/common/Version.hxx index 09c706540..65aa59489 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_VERSION "6.2_beta1" #define STELLA_BUILD "5741" #endif diff --git a/src/macos/Info-Stella.plist b/src/macos/Info-Stella.plist index 8f37a40c3..386e378fc 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 CFBundleName Stella CFBundlePackageType @@ -53,7 +53,7 @@ CFBundleSignature StLa CFBundleVersion - 6.1 + 6.2 LSApplicationCategoryType public.app-category.games LSMinimumSystemVersionByArchitecture diff --git a/src/unix/stella.spec b/src/unix/stella.spec index 796217ea6..264b4da7e 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 %define rel 1 %define enable_sound 1 @@ -100,6 +100,9 @@ rm -rf $RPM_BUILD_DIR/%{name}-%{version} %_datadir/icons/large/%{name}.png %changelog +* 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.rc b/src/windows/stella.rc index d6fcd5ce3..7facd2292 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,0,0 + PRODUCTVERSION 6,2,0,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" 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" END END BLOCK "VarFileInfo" From 1daf02b82772f8eef330c8351601f7d944258682 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 2 Jun 2020 21:42:25 +0200 Subject: [PATCH 275/377] improved keyboard detection (JamLoopy demo) --- src/emucore/ControllerDetector.cxx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/emucore/ControllerDetector.cxx b/src/emucore/ControllerDetector.cxx index 023302d81..6609340df 100644 --- a/src/emucore/ControllerDetector.cxx +++ b/src/emucore/ControllerDetector.cxx @@ -314,13 +314,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 +330,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; From 8c9cbc87cbca62ec475a3023f257e6e57c6d8ca9 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 3 Jun 2020 12:22:30 +0200 Subject: [PATCH 276/377] updated doc --- docs/index.html | 87 ++++++++++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 40 deletions(-) diff --git a/docs/index.html b/docs/index.html index f0687880f..abe4e09db 100644 --- a/docs/index.html +++ b/docs/index.html @@ -70,7 +70,7 @@


      -
      February 1999 - ??? 2020
      +
      February 1999 - June 2020
      The Stella Team
      Stella Homepage
      @@ -2342,9 +2342,10 @@ -
      -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. @@ -2357,6 +2358,41 @@ 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. @@ -2364,24 +2400,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. @@ -2397,27 +2415,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. @@ -2588,11 +2600,6 @@ 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 From 73ac91b624e523a9d28ebb1a248b61c18523984e Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 4 Jun 2020 09:55:13 +0200 Subject: [PATCH 277/377] fix #648 (focus problem in debugger) --- src/debugger/DebuggerParser.cxx | 2 ++ src/debugger/gui/DebuggerDialog.cxx | 1 + 2 files changed, 3 insertions(+) diff --git a/src/debugger/DebuggerParser.cxx b/src/debugger/DebuggerParser.cxx index 253131314..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); } 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; From badb41c4edb53965e11f25425fd1dcaf44ced736 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sun, 24 May 2020 16:08:24 -0230 Subject: [PATCH 278/377] Shorten error messages in ROM launcher, to fix overflow of buffer width. --- src/emucore/OSystem.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index 7ef0c2b4a..0d1364790 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -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(); } From bc8211b4436b03ab264f20ab4185c16a30a0ed18 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Fri, 5 Jun 2020 18:04:08 +0200 Subject: [PATCH 279/377] take care of odd ROM sizes (fixes #653) --- src/emucore/CartEnhanced.cxx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index 27fa425b5..4d22deb39 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -278,7 +278,7 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeEnhanced::getBank(uInt16 address) const { - return myCurrentSegOffset[(address & ROM_MASK) >> myBankShift] >> myBankShift; + return myCurrentSegOffset[std::min((address & ROM_MASK) >> myBankShift, romBankCount() - 1)] >> myBankShift; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -290,7 +290,8 @@ uInt16 CartridgeEnhanced::getSegmentBank(uInt16 segment) const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeEnhanced::romBankCount() const { - return uInt16(mySize >> myBankShift); + // take care of too small ROMs + return uInt16(mySize + ((1 << myBankShift) - 1)) >> myBankShift; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 76a8468a66b03eb61085cc87bc9fe0d41723aa25 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sat, 6 Jun 2020 15:01:14 -0230 Subject: [PATCH 280/377] Final commit before branching for 6.2 release. --- src/common/Version.hxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/Version.hxx b/src/common/Version.hxx index 65aa59489..3f020344f 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_beta1" -#define STELLA_BUILD "5741" +#define STELLA_VERSION "6.2" +#define STELLA_BUILD "5995" #endif From 1476d460e5dbc8afa30f77b691ae05f1b35007a5 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sat, 6 Jun 2020 16:37:13 -0230 Subject: [PATCH 281/377] And as usual, some last minute updates. --- src/common/Version.hxx | 2 +- src/debugger/gui/CartEnhancedWidget.cxx | 2 +- src/emucore/CartEnhanced.cxx | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/common/Version.hxx b/src/common/Version.hxx index 3f020344f..569ef060e 100644 --- a/src/common/Version.hxx +++ b/src/common/Version.hxx @@ -19,6 +19,6 @@ #define VERSION_HXX #define STELLA_VERSION "6.2" -#define STELLA_BUILD "5995" +#define STELLA_BUILD "5996" #endif diff --git a/src/debugger/gui/CartEnhancedWidget.cxx b/src/debugger/gui/CartEnhancedWidget.cxx index 0bf38f529..af110cb0d 100644 --- a/src/debugger/gui/CartEnhancedWidget.cxx +++ b/src/debugger/gui/CartEnhancedWidget.cxx @@ -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/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index 4d22deb39..def9c8072 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -44,7 +44,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 @@ -315,7 +315,7 @@ bool CartridgeEnhanced::patch(uInt16 address, uInt8 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 From bfe33e25b71a681e416ef7118cd0fd3af929d7d5 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 7 Jun 2020 08:22:07 +0200 Subject: [PATCH 282/377] fix ROMs >= 64K (partially addresses #654) --- src/emucore/CartEnhanced.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index 4d22deb39..ccd2d0e1a 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -291,7 +291,7 @@ uInt16 CartridgeEnhanced::getSegmentBank(uInt16 segment) const uInt16 CartridgeEnhanced::romBankCount() const { // take care of too small ROMs - return uInt16(mySize + ((1 << myBankShift) - 1)) >> myBankShift; + return uInt16((mySize + ((1 << myBankShift) - 1)) >> myBankShift); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From dbc0baf9f075343fd5ce70cbbb9826491e8c88f6 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sun, 7 Jun 2020 14:49:27 -0230 Subject: [PATCH 283/377] Fix some common errors causing crashes when ROM sizes aren't what we expect (fixes #654). --- src/common/bspf.hxx | 9 +++++ src/emucore/Cart0840.cxx | 2 +- src/emucore/Cart2K.cxx | 34 +--------------- src/emucore/Cart3E.cxx | 2 +- src/emucore/Cart3F.cxx | 2 +- src/emucore/Cart4K.cxx | 2 +- src/emucore/CartBF.cxx | 2 +- src/emucore/CartCV.cxx | 10 ++--- src/emucore/CartDF.cxx | 2 +- src/emucore/CartE0.cxx | 2 +- src/emucore/CartEF.cxx | 2 +- src/emucore/CartEnhanced.cxx | 78 ++++++++++++++++++++++++++++++++---- src/emucore/CartEnhanced.hxx | 5 ++- src/emucore/CartF0.cxx | 2 +- src/emucore/CartF4.cxx | 2 +- src/emucore/CartF6.cxx | 2 +- src/emucore/CartF8.cxx | 2 +- src/emucore/CartFA.cxx | 2 +- src/emucore/CartFC.cxx | 2 +- src/emucore/CartFE.cxx | 2 +- src/emucore/CartMDM.cxx | 2 +- src/emucore/CartSB.cxx | 2 +- src/emucore/CartTVBoy.cxx | 2 +- src/emucore/CartUA.cxx | 2 +- src/emucore/CartWD.cxx | 4 +- src/emucore/CartX07.cxx | 2 +- 26 files changed, 109 insertions(+), 71 deletions(-) diff --git a/src/common/bspf.hxx b/src/common/bspf.hxx index 844f12804..24fe8d0a7 100644 --- a/src/common/bspf.hxx +++ b/src/common/bspf.hxx @@ -131,6 +131,15 @@ namespace BSPF // Maximum size of a ROM that Stella can support inline constexpr size_t romMaxSize() { return 512_KB; } + // 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; + } + // Make 2D-arrays using std::array less verbose template using array2D = std::array, ROW>; diff --git a/src/emucore/Cart0840.cxx b/src/emucore/Cart0840.cxx index e071f61a2..894b8eed7 100644 --- a/src/emucore/Cart0840.cxx +++ b/src/emucore/Cart0840.cxx @@ -21,7 +21,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge0840::Cartridge0840(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, md5, settings) + : CartridgeEnhanced(image, size, 8_KB, md5, settings) { } diff --git a/src/emucore/Cart2K.cxx b/src/emucore/Cart2K.cxx index f4d4ef7bd..c70cc373f 100644 --- a/src/emucore/Cart2K.cxx +++ b/src/emucore/Cart2K.cxx @@ -21,38 +21,6 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge2K::Cartridge2K(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, md5, settings) + : CartridgeEnhanced(image, size, 2_KB, md5, settings) { - // Size can be a maximum of 2K - if(size > 2_KB) - size = 2_KB; - - // Set image size to closest power-of-two for the given size - mySize = 1; myBankShift = 0; - while(mySize < size) - { - mySize <<= 1; - 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 - { - // 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; - } } diff --git a/src/emucore/Cart3E.cxx b/src/emucore/Cart3E.cxx index be69d105d..263c8b2e9 100644 --- a/src/emucore/Cart3E.cxx +++ b/src/emucore/Cart3E.cxx @@ -22,7 +22,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge3E::Cartridge3E(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, md5, settings) + : CartridgeEnhanced(image, size, BSPF::nextPowerOfTwo(size), md5, settings) { myBankShift = BANK_SHIFT; myRamSize = RAM_SIZE; diff --git a/src/emucore/Cart3F.cxx b/src/emucore/Cart3F.cxx index 21b21b9c7..20d9cef1d 100644 --- a/src/emucore/Cart3F.cxx +++ b/src/emucore/Cart3F.cxx @@ -22,7 +22,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge3F::Cartridge3F(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, md5, settings) + : CartridgeEnhanced(image, size, BSPF::nextPowerOfTwo(size), md5, settings) { myBankShift = BANK_SHIFT; } diff --git a/src/emucore/Cart4K.cxx b/src/emucore/Cart4K.cxx index 9e684afad..0a3e27bdc 100644 --- a/src/emucore/Cart4K.cxx +++ b/src/emucore/Cart4K.cxx @@ -21,6 +21,6 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge4K::Cartridge4K(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, md5, settings) + : CartridgeEnhanced(image, size, 4_KB, md5, settings) { } diff --git a/src/emucore/CartBF.cxx b/src/emucore/CartBF.cxx index ce3c53198..065b657dc 100644 --- a/src/emucore/CartBF.cxx +++ b/src/emucore/CartBF.cxx @@ -21,7 +21,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeBF::CartridgeBF(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, md5, settings) + : CartridgeEnhanced(image, size, 256_KB, md5, settings) { } diff --git a/src/emucore/CartCV.cxx b/src/emucore/CartCV.cxx index 8d7ac9d89..8e8e6504e 100644 --- a/src/emucore/CartCV.cxx +++ b/src/emucore/CartCV.cxx @@ -21,23 +21,19 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeCV::CartridgeCV(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, md5, settings) + : CartridgeEnhanced(image, size, 2_KB, md5, settings) { 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/CartDF.cxx b/src/emucore/CartDF.cxx index 0f4d9a1ca..f95ebcc93 100644 --- a/src/emucore/CartDF.cxx +++ b/src/emucore/CartDF.cxx @@ -21,7 +21,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeDF::CartridgeDF(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, md5, settings) + : CartridgeEnhanced(image, size, 128_KB, md5, settings) { } diff --git a/src/emucore/CartE0.cxx b/src/emucore/CartE0.cxx index 07afae5a2..7a10c3e34 100644 --- a/src/emucore/CartE0.cxx +++ b/src/emucore/CartE0.cxx @@ -21,7 +21,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeE0::CartridgeE0(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, md5, settings) + : CartridgeEnhanced(image, size, 8_KB, md5, settings) { myBankShift = BANK_SHIFT; } diff --git a/src/emucore/CartEF.cxx b/src/emucore/CartEF.cxx index 039f4aa5c..175b42263 100644 --- a/src/emucore/CartEF.cxx +++ b/src/emucore/CartEF.cxx @@ -21,7 +21,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeEF::CartridgeEF(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, md5, settings) + : CartridgeEnhanced(image, size, 64_KB, md5, settings) { } diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index c7378670a..363ffcd59 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -15,20 +15,84 @@ // 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) + size_t bsSize, const string& md5, + const Settings& settings) + : 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 + if(size != bsSize) + { + // Is the ROM too large? If so, we cap it + if(size > bsSize) + { + ostringstream buf; + buf << "ROM larger than expected (" << size << " > " << bsSize << "), truncating\n"; + Logger::info(buf.str()); - // Copy the ROM image into my buffer - std::copy_n(image.get(), mySize, myImage.get()); + size = bsSize; + } + + // Set image size to closest power-of-two for the given size + // This only applies for sizes less than the standard bank size + if(size < 4_KB) + { + mySize = 1; myBankShift = 0; + while(mySize < size) + { + mySize <<= 1; + myBankShift++; + } + } + else + mySize = size; + + // Initialize ROM with all 0's, to fill areas that the ROM may not cover + size_t bufSize = std::max(mySize, System::PAGE_SIZE); + myImage = make_unique(bufSize); + std::fill_n(myImage.get(), bufSize, 0); + + // 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) + { + if(size < mySize) + { + ostringstream buf; + buf << "ROM smaller than expected (" << mySize << " > " << size + << "), appending " << (mySize - size) << " bytes\n"; + Logger::info(buf.str()); + } + + // TODO: should we mirror here too?? + // Directly copy the ROM image into the buffer + std::copy_n(image.get(), mySize, myImage.get()); + } + else + { + // 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; + } + } + else + { + mySize = size; + + // Allocate array for the ROM image + myImage = make_unique(mySize); + + // Copy the ROM image into my buffer + std::copy_n(image.get(), mySize, myImage.get()); + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartEnhanced.hxx b/src/emucore/CartEnhanced.hxx index 3c2e2c80d..be0ac95de 100644 --- a/src/emucore/CartEnhanced.hxx +++ b/src/emucore/CartEnhanced.hxx @@ -42,10 +42,11 @@ class CartridgeEnhanced : public Cartridge @param image Pointer to the ROM image @param size The size of the ROM image @param md5 The md5sum of the ROM image + @param bsSize The size specified by the bankswitching scheme @param settings A reference to the various settings (read-only) */ - CartridgeEnhanced(const ByteBuffer& image, size_t size, const string& md5, - const Settings& settings); + CartridgeEnhanced(const ByteBuffer& image, size_t size, size_t bsSize, + const string& md5, const Settings& settings); virtual ~CartridgeEnhanced() = default; public: diff --git a/src/emucore/CartF0.cxx b/src/emucore/CartF0.cxx index 8747c57f3..f21bba07e 100644 --- a/src/emucore/CartF0.cxx +++ b/src/emucore/CartF0.cxx @@ -20,7 +20,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF0::CartridgeF0(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, md5, settings) + : CartridgeEnhanced(image, size, 64_KB, md5, settings) { } diff --git a/src/emucore/CartF4.cxx b/src/emucore/CartF4.cxx index 6a8cd6e00..609fd0b03 100644 --- a/src/emucore/CartF4.cxx +++ b/src/emucore/CartF4.cxx @@ -20,7 +20,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF4::CartridgeF4(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, md5, settings) + : CartridgeEnhanced(image, size, 32_KB, md5, settings) { } diff --git a/src/emucore/CartF6.cxx b/src/emucore/CartF6.cxx index 50e993e26..572909952 100644 --- a/src/emucore/CartF6.cxx +++ b/src/emucore/CartF6.cxx @@ -20,7 +20,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF6::CartridgeF6(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, md5, settings) + : CartridgeEnhanced(image, size, 16_KB, md5, settings) { } diff --git a/src/emucore/CartF8.cxx b/src/emucore/CartF8.cxx index 5d898091c..7ea1216a5 100644 --- a/src/emucore/CartF8.cxx +++ b/src/emucore/CartF8.cxx @@ -20,7 +20,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF8::CartridgeF8(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, md5, settings) + : CartridgeEnhanced(image, size, 8_KB, md5, settings) { } diff --git a/src/emucore/CartFA.cxx b/src/emucore/CartFA.cxx index 082e403f7..bc82dec84 100644 --- a/src/emucore/CartFA.cxx +++ b/src/emucore/CartFA.cxx @@ -21,7 +21,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeFA::CartridgeFA(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, md5, settings) + : CartridgeEnhanced(image, size, 12_KB, md5, settings) { myRamSize = RAM_SIZE; } diff --git a/src/emucore/CartFC.cxx b/src/emucore/CartFC.cxx index c415ba1af..9b945c666 100644 --- a/src/emucore/CartFC.cxx +++ b/src/emucore/CartFC.cxx @@ -21,7 +21,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeFC::CartridgeFC(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, md5, settings) + : CartridgeEnhanced(image, size, BSPF::nextPowerOfTwo(size), md5, settings) { } diff --git a/src/emucore/CartFE.cxx b/src/emucore/CartFE.cxx index 7c3debda3..a9602e88a 100644 --- a/src/emucore/CartFE.cxx +++ b/src/emucore/CartFE.cxx @@ -22,7 +22,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeFE::CartridgeFE(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, md5, settings) + : CartridgeEnhanced(image, size, 8_KB, md5, settings) { myDirectPeek = false; } diff --git a/src/emucore/CartMDM.cxx b/src/emucore/CartMDM.cxx index 2734b2793..022bc1bdb 100644 --- a/src/emucore/CartMDM.cxx +++ b/src/emucore/CartMDM.cxx @@ -21,7 +21,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeMDM::CartridgeMDM(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, md5, settings) + : CartridgeEnhanced(image, size, BSPF::nextPowerOfTwo(size), md5, settings) { } diff --git a/src/emucore/CartSB.cxx b/src/emucore/CartSB.cxx index 5caa01be7..8ad55f28d 100644 --- a/src/emucore/CartSB.cxx +++ b/src/emucore/CartSB.cxx @@ -21,7 +21,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeSB::CartridgeSB(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, md5, settings) + : CartridgeEnhanced(image, size, BSPF::nextPowerOfTwo(size), md5, settings) { } diff --git a/src/emucore/CartTVBoy.cxx b/src/emucore/CartTVBoy.cxx index b60c374c4..0626da0aa 100644 --- a/src/emucore/CartTVBoy.cxx +++ b/src/emucore/CartTVBoy.cxx @@ -21,7 +21,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeTVBoy::CartridgeTVBoy(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, md5, settings) + : CartridgeEnhanced(image, size, 512_KB, md5, settings) { } diff --git a/src/emucore/CartUA.cxx b/src/emucore/CartUA.cxx index 74ccc3773..23caa5091 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, 8_KB, md5, settings), mySwappedHotspots(swapHotspots) { } diff --git a/src/emucore/CartWD.cxx b/src/emucore/CartWD.cxx index 11ebc653e..f9c7463f3 100644 --- a/src/emucore/CartWD.cxx +++ b/src/emucore/CartWD.cxx @@ -23,10 +23,10 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeWD::CartridgeWD(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, md5, settings) + : CartridgeEnhanced(image, size, 8_KB, md5, settings) { // 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/CartX07.cxx b/src/emucore/CartX07.cxx index ac40b6ac6..e28869920 100644 --- a/src/emucore/CartX07.cxx +++ b/src/emucore/CartX07.cxx @@ -23,7 +23,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeX07::CartridgeX07(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, md5, settings) + : CartridgeEnhanced(image, size, 64_KB, md5, settings) { } From fec22a56c58a6ab2bc0681ffd225659078d745fc Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sun, 7 Jun 2020 15:34:38 -0230 Subject: [PATCH 284/377] Update warning message when truncating ROMs in the ROM buffer. --- src/common/Version.hxx | 2 +- src/emucore/CartEnhanced.cxx | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/common/Version.hxx b/src/common/Version.hxx index 569ef060e..ec5610431 100644 --- a/src/common/Version.hxx +++ b/src/common/Version.hxx @@ -19,6 +19,6 @@ #define VERSION_HXX #define STELLA_VERSION "6.2" -#define STELLA_BUILD "5996" +#define STELLA_BUILD "6000" #endif diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index 363ffcd59..c809cfab6 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -33,7 +33,8 @@ CartridgeEnhanced::CartridgeEnhanced(const ByteBuffer& image, size_t size, if(size > bsSize) { ostringstream buf; - buf << "ROM larger than expected (" << size << " > " << bsSize << "), truncating\n"; + buf << "ROM larger than expected (" << size << " > " << bsSize + << "), truncating " << (size - bsSize) << " bytes\n"; Logger::info(buf.str()); size = bsSize; From 081682e2b57f2fed37427230499eb46a6d79ebf3 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sun, 7 Jun 2020 17:40:42 -0230 Subject: [PATCH 285/377] And it never ends. Fix broken support for 2K ROMs. --- src/common/Version.hxx | 2 +- src/emucore/CartEnhanced.cxx | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/common/Version.hxx b/src/common/Version.hxx index ec5610431..e19349fae 100644 --- a/src/common/Version.hxx +++ b/src/common/Version.hxx @@ -19,6 +19,6 @@ #define VERSION_HXX #define STELLA_VERSION "6.2" -#define STELLA_BUILD "6000" +#define STELLA_BUILD "6001" #endif diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index c809cfab6..5295364f1 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -87,6 +87,8 @@ CartridgeEnhanced::CartridgeEnhanced(const ByteBuffer& image, size_t size, else { mySize = size; + if(mySize < 4_KB) + myBankShift = 11; // Allocate array for the ROM image myImage = make_unique(mySize); From 082b8dd9dccfbb50d33e57ea31b8bf8e963eb065 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sun, 7 Jun 2020 18:34:10 -0230 Subject: [PATCH 286/377] A small reprieve for gcc6 users. Fixed codebase so it compiles in g++6 again. Note that we're moving to gcc7 fairly soon, so this won't be for long. Bumped version number. --- src/common/PaletteHandler.hxx | 4 ++-- src/common/Version.hxx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/common/PaletteHandler.hxx b/src/common/PaletteHandler.hxx index bd102d9f0..3de835d7d 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 * (x + 1.F)); } /** Convert palette settings name to enumeration. diff --git a/src/common/Version.hxx b/src/common/Version.hxx index e19349fae..2c770f57f 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" +#define STELLA_VERSION "6.2.1_pre" #define STELLA_BUILD "6001" #endif From 77aafee4cc8305c0b4f58f899625b1e125a8cbbb Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sun, 7 Jun 2020 20:16:34 -0230 Subject: [PATCH 287/377] Updated changelog; I forgot something for the 6.2 release. --- Changes.txt | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Changes.txt b/Changes.txt index fceea0039..aeb71411b 100644 --- a/Changes.txt +++ b/Changes.txt @@ -12,6 +12,16 @@ Release History =========================================================================== +6.2 to 6.2.1: (XXX xx, 2020) + + * 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] + +-Have fun! + + 6.1.2 to 6.2: (June 7, 2020) * Added interactive palette to Video & Audio settings. @@ -57,8 +67,6 @@ * Added support for loading grayscale PNG images in the ROM launcher. --Have fun! - 6.1.1 to 6.1.2: (April 25, 2020) From 632d19a301d1b551c748b909ce938078fbc668c8 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 8 Jun 2020 15:27:08 +0200 Subject: [PATCH 288/377] make NTSC custom phase shift not affect Yellow anymore (fixes #656) --- src/common/PaletteHandler.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index d2a2a7768..0483b6bb9 100644 --- a/src/common/PaletteHandler.cxx +++ b/src/common/PaletteHandler.cxx @@ -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++) From d57479fa2b197df5712586799244e6b291d01ced Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Mon, 8 Jun 2020 10:59:11 -0230 Subject: [PATCH 289/377] Updated documentation with changes to properties key names. --- docs/index.html | 52 ++++++++++++++++++++++---------------------- src/tools/PropSet.pm | 44 ++++++++++++++++++------------------- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/docs/index.html b/docs/index.html index abe4e09db..69e1aff77 100644 --- a/docs/index.html +++ b/docs/index.html @@ -549,7 +549,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 @@ -2732,7 +2732,7 @@

      -bs <type>
      - Set "Cartridge.Type" property. See the Game Properties section + Set "Cart.Type" property. See the Game Properties section for valid types. @@ -2743,27 +2743,27 @@
      -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. @@ -3962,24 +3962,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

      @@ -3993,7 +3993,7 @@ Ms Pac-Man (Stella extended codes): - + - + @@ -4100,7 +4100,7 @@ Ms Pac-Man (Stella extended codes): - + @@ -4081,7 +4081,7 @@ Ms Pac-Man (Stella extended codes): 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 From 5423bc17187ced08a6884f48fd436823a5dd2085 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 11 Jun 2020 17:30:27 +0200 Subject: [PATCH 303/377] changed all adjustable steps to 1% updated changes --- Changes.txt | 4 +++- src/common/PaletteHandler.cxx | 2 +- src/common/tv_filters/NTSCFilter.cxx | 2 +- src/gui/VideoAudioDialog.cxx | 3 +-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Changes.txt b/Changes.txt index 507bfc84f..48c78a4b6 100644 --- a/Changes.txt +++ b/Changes.txt @@ -23,7 +23,9 @@ * Make NTSC custom phase shift not affect Yellow anymore. - * Allow changing palette adjustables in 1% steps again. + * Allow changing custom palette and TV effects adjustables in 1% steps again. + + * Fixed custom palette and TV effects adjustable slider rounding issue. * Fixed some bugs in 3E+ scheme when using non-standard ROM sizes. diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index 0483b6bb9..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); diff --git a/src/common/tv_filters/NTSCFilter.cxx b/src/common/tv_filters/NTSCFilter.cxx index 8e7e899c9..5a61dd140 100644 --- a/src/common/tv_filters/NTSCFilter.cxx +++ b/src/common/tv_filters/NTSCFilter.cxx @@ -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/gui/VideoAudioDialog.cxx b/src/gui/VideoAudioDialog.cxx index 7fcc65cf8..23e7692cc 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; @@ -233,7 +233,6 @@ void VideoAudioDialog::addPaletteTab() CREATE_CUSTOM_SLIDERS(Contrast, "Contrast ", kPaletteUpdated) CREATE_CUSTOM_SLIDERS(Bright, "Brightness ", kPaletteUpdated) CREATE_CUSTOM_SLIDERS(Gamma, "Gamma ", kPaletteUpdated) - myTVHue->setStepValue(1); // The resulting palette xpos = myPhaseShiftNtsc->getRight() + fontWidth * 2; From f2cddf2de6ca935cd9d34de795c8701da86862a3 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 11 Jun 2020 17:36:35 +0200 Subject: [PATCH 304/377] updated snapshot snapshot :) --- docs/graphics/launcher_options_snapshots.png | Bin 3586 -> 3034 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/graphics/launcher_options_snapshots.png b/docs/graphics/launcher_options_snapshots.png index 0d2b2e8d6ad728ab3caefd16fb1bbd2c6fcaba40..a833f8bb327b74e26b2fab74d400a9067c22808f 100644 GIT binary patch literal 3034 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 Date: Thu, 11 Jun 2020 19:04:39 -0230 Subject: [PATCH 305/377] Handle creation of 2K/Sub2K and all other cart types separately. This simplifies the logic in both cases, and fixes a few corner cases. --- src/emucore/Cart2K.cxx | 24 ++++++++++ src/emucore/CartEnhanced.cxx | 91 +++++++++--------------------------- 2 files changed, 47 insertions(+), 68 deletions(-) diff --git a/src/emucore/Cart2K.cxx b/src/emucore/Cart2K.cxx index ee0974549..3324e60df 100644 --- a/src/emucore/Cart2K.cxx +++ b/src/emucore/Cart2K.cxx @@ -24,4 +24,28 @@ Cartridge2K::Cartridge2K(const ByteBuffer& image, size_t size, 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 + size = std::min(size, bsSize); + + // Set image size to closest power-of-two for the given size + mySize = 1; myBankShift = 0; + while(mySize < size) + { + mySize <<= 1; + myBankShift++; + } + + // 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) + { + // 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; + } } diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index 574dacca8..6cc3b0ca6 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -27,78 +27,33 @@ CartridgeEnhanced::CartridgeEnhanced(const ByteBuffer& image, size_t size, { // ROMs are not always at the 'legal' size for their associated // bankswitching scheme; here we deal with the differing sizes - if(size != bsSize) + + // Is the ROM too large? If so, we cap it + if(size > bsSize) { - // 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()); - - size = bsSize; - } - - // Set image size to closest power-of-two for the given size - // This only applies for sizes less than the standard bank size - if(size < 4_KB) - { - mySize = 1; myBankShift = 0; - while(mySize < size) - { - mySize <<= 1; - myBankShift++; - } - } - else - // Make sure to use size defined by the bankswitching scheme - mySize = std::max(size, bsSize); - - // Initialize ROM with all 0's, to fill areas that the ROM may not cover - size_t bufSize = std::max(mySize, System::PAGE_SIZE); - myImage = make_unique(bufSize); - std::fill_n(myImage.get(), bufSize, 0); - - // 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) - { - if(size < mySize) - { - ostringstream buf; - buf << "ROM smaller than expected (" << mySize << " > " << size - << "), appending " << (mySize - size) << " bytes\n"; - Logger::info(buf.str()); - } - - // TODO: should we mirror here too?? - // 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()); - } - else - { - // 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; - } + ostringstream buf; + buf << "ROM larger than expected (" << size << " > " << bsSize + << "), truncating " << (size - bsSize) << " bytes\n"; + Logger::info(buf.str()); } - else + else if(size < mySize) { - mySize = size; - if(mySize < 4_KB) - myBankShift = 11; - - // Allocate array for the ROM image - myImage = make_unique(mySize); - - // Copy the ROM image into my buffer - std::copy_n(image.get(), mySize, myImage.get()); + 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()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From aba80851afd541a0ef232633230b407a6adb9c9c Mon Sep 17 00:00:00 2001 From: thrust26 Date: Fri, 12 Jun 2020 12:48:15 +0200 Subject: [PATCH 306/377] fix #663 (illegal segment access) --- src/emucore/CartEnhanced.cxx | 26 ++++++++++++++++++-------- src/emucore/CartEnhanced.hxx | 17 +++++++++++++++++ 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index 6cc3b0ca6..83947db63 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -155,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; @@ -168,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)]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -190,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; } @@ -300,10 +298,22 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) return myBankChanged = true; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt16 CartridgeEnhanced::romAddressSegmentOffset(uInt16 address) const +{ + return myCurrentSegOffset[((address & ROM_MASK) >> myBankShift) % myBankSegs]; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +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; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -335,7 +345,7 @@ 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 { @@ -347,7 +357,7 @@ 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; diff --git a/src/emucore/CartEnhanced.hxx b/src/emucore/CartEnhanced.hxx index e15fb8ba1..c50f88aa6 100644 --- a/src/emucore/CartEnhanced.hxx +++ b/src/emucore/CartEnhanced.hxx @@ -256,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; @@ -268,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; From c6a9775e25348d8e838840a83f11e445ddb89199 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Fri, 12 Jun 2020 09:24:15 -0230 Subject: [PATCH 307/377] Attempt to gain a little speed on frequently used functions. --- src/emucore/CartEnhanced.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index 83947db63..28b8b026c 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -299,13 +299,13 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeEnhanced::romAddressSegmentOffset(uInt16 address) const +inline uInt16 CartridgeEnhanced::romAddressSegmentOffset(uInt16 address) const { return myCurrentSegOffset[((address & ROM_MASK) >> myBankShift) % myBankSegs]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeEnhanced::ramAddressSegmentOffset(uInt16 address) const +inline uInt16 CartridgeEnhanced::ramAddressSegmentOffset(uInt16 address) const { return uInt16(myCurrentSegOffset[((address & ROM_MASK) >> myBankShift) % myBankSegs] - mySize) >> 1; } From 1519f50f79a98f2bb82e11fae21e4d907d50c3e8 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Fri, 12 Jun 2020 10:54:25 -0230 Subject: [PATCH 308/377] Eliminate magic number. --- src/emucore/Cart2K.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/emucore/Cart2K.cxx b/src/emucore/Cart2K.cxx index 3324e60df..d204d93ed 100644 --- a/src/emucore/Cart2K.cxx +++ b/src/emucore/Cart2K.cxx @@ -46,6 +46,6 @@ Cartridge2K::Cartridge2K(const ByteBuffer& image, size_t size, 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; } } From 8b8eb035b1a8f75780debc5b3ab508c2aaef765a Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Mon, 15 Jun 2020 23:35:20 +0200 Subject: [PATCH 309/377] Fix ROM dir for profiling. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 2cb7fe15fce8c64a2e856461273373a920b89ccb Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Tue, 16 Jun 2020 14:44:44 -0230 Subject: [PATCH 310/377] Fix reading from TIA registers when D6 is not used. Also fix randomization with 'tiadriven' to always fully randomize, with no relationship to what was on the data bus (fixes #664). --- Changes.txt | 6 ++++- src/emucore/System.hxx | 22 ----------------- src/emucore/tia/TIA.cxx | 52 +++++++++++++++++++---------------------- 3 files changed, 29 insertions(+), 51 deletions(-) diff --git a/Changes.txt b/Changes.txt index 48c78a4b6..3e2c16150 100644 --- a/Changes.txt +++ b/Changes.txt @@ -23,7 +23,11 @@ * Make NTSC custom phase shift not affect Yellow anymore. - * Allow changing custom palette and TV effects adjustables in 1% steps again. + * Allow changing custom palette and TV effects adjustables in 1% steps + again. + + * 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. diff --git a/src/emucore/System.hxx b/src/emucore/System.hxx index dab87b28a..b0660fec7 100644 --- a/src/emucore/System.hxx +++ b/src/emucore/System.hxx @@ -168,28 +168,6 @@ class System : public Serializable */ uInt8 getDataBusState() const { return myDataBusState; } - /** - Get the current state of the data bus in the system, taking into - account that certain bits are in Z-state (undriven). In those - cases, the bits are floating, but will usually be the same as the - last data bus value (the 'usually' is emulated by randomly driving - certain bits high). - - However, some CMOS EPROM chips always drive Z-state bits high. - This is emulated by hmask, which specifies to push a specific - Z-state bit high. - - @param zmask The bits which are in Z-state - @param hmask The bits which should always be driven high - @return The data bus state - */ - uInt8 getDataBusState(uInt8 zmask, uInt8 hmask = 0x00) const - { - // For the pins that are floating, randomly decide which are high or low - // Otherwise, they're specifically driven high - return (myDataBusState | (randGenerator().next() | hmask)) & zmask; - } - /** Get the byte at the specified address. No masking of the address occurs before it's sent to the device mapped at diff --git a/src/emucore/tia/TIA.cxx b/src/emucore/tia/TIA.cxx index 656524eae..6d3461c4c 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); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 9f048706afb9efd6f7de3fdbc419378606dcbf91 Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Wed, 17 Jun 2020 00:20:26 +0200 Subject: [PATCH 311/377] Fix reads and writes during timer wrap. Fixes #606 . --- src/emucore/M6532.cxx | 18 ++++++++---------- src/emucore/M6532.hxx | 3 +-- 2 files changed, 9 insertions(+), 12 deletions(-) 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. From 1893a8f434d4563da6fe665edf21d7d7d381a84f Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 17 Jun 2020 22:42:54 +0200 Subject: [PATCH 312/377] fixed crash in Audio & Video dialog when opened from debugger --- Changes.txt | 4 ++++ src/gui/VideoAudioDialog.cxx | 29 +++++++++++++---------------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/Changes.txt b/Changes.txt index 3e2c16150..6178d2d3e 100644 --- a/Changes.txt +++ b/Changes.txt @@ -33,6 +33,10 @@ * Fixed some bugs in 3E+ scheme when using non-standard ROM sizes. + * Fixed custom palette and TV effects adjustable slider rounding issue. + + * Fixed crash in Audio & Video dialog when opened from debugger. + * Updated documentation for changes in ROM properties key names. * The codebase now compiles under gcc6 again. Future versions will diff --git a/src/gui/VideoAudioDialog.cxx b/src/gui/VideoAudioDialog.cxx index 23e7692cc..e87cbe221 100644 --- a/src/gui/VideoAudioDialog.cxx +++ b/src/gui/VideoAudioDialog.cxx @@ -1005,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); } } } From 8ca5684b67647998b79ec69dc43d8a03011c113a Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 18 Jun 2020 07:22:47 +0200 Subject: [PATCH 313/377] simple fix for #667 (minimized window) --- src/gui/EmulationDialog.cxx | 1 + 1 file changed, 1 insertion(+) 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()); } From ef12cb49cc8502368806e4b1645ac9b29831a643 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Thu, 18 Jun 2020 12:06:29 -0230 Subject: [PATCH 314/377] Updated changelog, and bumped state number for recent changes in M6532 class. --- Changes.txt | 24 +++++++++++++++--------- src/common/StateManager.hxx | 2 +- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/Changes.txt b/Changes.txt index 6178d2d3e..490d98b82 100644 --- a/Changes.txt +++ b/Changes.txt @@ -16,15 +16,10 @@ * Fixed Pitfall II ROM not working correctly. - * 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] + * Fixed crashes when using some combinations of bankswitching schemes on + incorrect ROMs, or when using invalid ROM file sizes, etc. - * Make NTSC custom phase shift not affect Yellow anymore. - - * Allow changing custom palette and TV effects adjustables in 1% steps - again. + * 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. @@ -35,7 +30,18 @@ * Fixed custom palette and TV effects adjustable slider rounding issue. - * Fixed crash in Audio & Video dialog when opened from debugger. + * 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. + + * 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] + + * Allow changing custom palette and TV effects adjustables in 1% steps + again. * Updated documentation for changes in ROM properties key names. diff --git a/src/common/StateManager.hxx b/src/common/StateManager.hxx index a69a48cd5..83f3d7acc 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 "06020000state" +#define STATE_HEADER "06020090state" class OSystem; class RewindManager; From 5d0084307bcb28e7215a3dd3569324bdb2cec5f4 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Thu, 18 Jun 2020 21:48:51 -0230 Subject: [PATCH 315/377] Fix TIA images saved in '1x' mode to not use TV effects (fixes #643). --- Changes.txt | 3 +++ src/debugger/gui/TiaOutputWidget.cxx | 2 +- src/emucore/TIASurface.cxx | 15 +-------------- src/emucore/TIASurface.hxx | 12 ++++++++---- 4 files changed, 13 insertions(+), 19 deletions(-) diff --git a/Changes.txt b/Changes.txt index 490d98b82..2a5efe3b6 100644 --- a/Changes.txt +++ b/Changes.txt @@ -35,6 +35,9 @@ * 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. + * 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 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/emucore/TIASurface.cxx b/src/emucore/TIASurface.cxx index afaad7855..781ca203a 100644 --- a/src/emucore/TIASurface.cxx +++ b/src/emucore/TIASurface.cxx @@ -148,32 +148,19 @@ const FBSurface& TIASurface::baseSurface(Common::Rect& rect) const uInt32 tiaw = myTIA->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 From 7c91e2d60bd9188317268c6a6336075f8709d1ba Mon Sep 17 00:00:00 2001 From: thrust26 Date: Fri, 19 Jun 2020 22:31:29 +0200 Subject: [PATCH 316/377] fix missing key mapping when event version has changed --- src/common/PKeyboardHandler.cxx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index 4408081d7..4ff5191fb 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); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 6048fa9bc5df257f91b02114f0a1045070a55ba2 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Fri, 19 Jun 2020 19:55:27 -0230 Subject: [PATCH 317/377] Make sure long messages overlaid on framebuffer don't overflow display surface. --- src/emucore/FrameBuffer.cxx | 7 ++++--- src/emucore/FrameBuffer.hxx | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 4812e22f6..97af29fcf 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; diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index b09d492f1..0a55a0f89 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -166,7 +166,7 @@ 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. From 06db9b4f4a85d0044c6816d61154d86ffb75505f Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Fri, 19 Jun 2020 20:02:00 -0230 Subject: [PATCH 318/377] Remove superfluous 'deltax' parameter in drawString; I have no idea what it was doing there. --- src/emucore/FBSurface.cxx | 9 ++++----- src/emucore/FBSurface.hxx | 6 ++---- src/emucore/FrameBuffer.cxx | 6 +++--- src/gui/Widget.cxx | 2 +- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/emucore/FBSurface.cxx b/src/emucore/FBSurface.cxx index c489fc703..4b882346f 100644 --- a/src/emucore/FBSurface.cxx +++ b/src/emucore/FBSurface.cxx @@ -329,7 +329,7 @@ bool FBSurface::isWhiteSpace(const char s) const int FBSurface::drawString(const GUI::Font& font, const string& s, int x, int y, int w, int h, ColorId color, TextAlign align, - int deltax, bool useEllipsis, ColorId shadowColor) + bool useEllipsis, ColorId shadowColor) { int lines = 1; @@ -355,13 +355,13 @@ int FBSurface::drawString(const GUI::Font& font, const string& s, //str += inStr[i]; } wrapString(inStr, i, leftStr, rightStr); - drawString(font, leftStr, x, y, w, color, align, deltax, false, shadowColor); + drawString(font, leftStr, x, y, w, color, align, false, shadowColor); h -= font.getFontHeight(); y += font.getFontHeight(); inStr = rightStr; lines++; } - drawString(font, inStr, x, y, w, color, align, deltax, useEllipsis, shadowColor); + drawString(font, inStr, x, y, w, color, align, useEllipsis, shadowColor); #endif return lines; } @@ -370,7 +370,7 @@ int FBSurface::drawString(const GUI::Font& font, const string& s, void FBSurface::drawString(const GUI::Font& font, const string& s, int x, int y, int w, ColorId color, TextAlign align, - int deltax, bool useEllipsis, ColorId shadowColor) + bool useEllipsis, ColorId shadowColor) { #ifdef GUI_SUPPORT const string ELLIPSIS = "\x1d"; // "..." @@ -410,7 +410,6 @@ void FBSurface::drawString(const GUI::Font& font, const string& s, else if(align == TextAlign::Right) x = x + w - width; - x += deltax; for(i = 0; i < str.size(); ++i) { w = font.getCharWidth(str[i]); diff --git a/src/emucore/FBSurface.hxx b/src/emucore/FBSurface.hxx index 48632404d..4be99dc42 100644 --- a/src/emucore/FBSurface.hxx +++ b/src/emucore/FBSurface.hxx @@ -218,7 +218,6 @@ class FBSurface @param h The height of the string area (for multi line strings) @param color The color of the text @param align The alignment of the text in the string width area - @param deltax FIXME @param useEllipsis Whether to use '...' when the string is too long @return Number of lines drawn */ @@ -226,7 +225,7 @@ class FBSurface virtual int drawString( const GUI::Font& font, const string& s, int x, int y, int w, int h, ColorId color, TextAlign align = TextAlign::Left, - int deltax = 0, bool useEllipsis = true, ColorId shadowColor = kNone); + bool useEllipsis = true, ColorId shadowColor = kNone); /** This method should be called to draw the specified string. @@ -238,13 +237,12 @@ class FBSurface @param w The width of the string area @param color The color of the text @param align The alignment of the text in the string width area - @param deltax FIXME @param useEllipsis Whether to use '...' when the string is too long */ virtual void drawString( const GUI::Font& font, const string& s, int x, int y, int w, ColorId color, TextAlign align = TextAlign::Left, - int deltax = 0, bool useEllipsis = true, ColorId shadowColor = kNone); + bool useEllipsis = true, ColorId shadowColor = kNone); ////////////////////////////////////////////////////////////////////////// // Note: The following methods are FBSurface-specific, and must be diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 97af29fcf..2a53d2c8f 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -600,7 +600,7 @@ void FrameBuffer::drawFrameStats(float framesPerSecond) << info.DisplayFormat; myStatsMsg.surface->drawString(f, ss.str(), xPos, yPos, - myStatsMsg.w, color, TextAlign::Left, 0, true, kBGColor); + myStatsMsg.w, color, TextAlign::Left, true, kBGColor); yPos += dy; ss.str(""); @@ -615,7 +615,7 @@ void FrameBuffer::drawFrameStats(float framesPerSecond) << "% speed"; myStatsMsg.surface->drawString(f, ss.str(), xPos, yPos, - myStatsMsg.w, myStatsMsg.color, TextAlign::Left, 0, true, kBGColor); + myStatsMsg.w, myStatsMsg.color, TextAlign::Left, true, kBGColor); yPos += dy; ss.str(""); @@ -624,7 +624,7 @@ void FrameBuffer::drawFrameStats(float framesPerSecond) if (myOSystem.settings().getBool("dev.settings")) ss << "| Developer"; myStatsMsg.surface->drawString(f, ss.str(), xPos, yPos, - myStatsMsg.w, myStatsMsg.color, TextAlign::Left, 0, true, kBGColor); + myStatsMsg.w, myStatsMsg.color, TextAlign::Left, true, kBGColor); myStatsMsg.surface->setDstPos(myImageRect.x() + 10, myImageRect.y() + 8); myStatsMsg.surface->setDstSize(myStatsMsg.w * hidpiScaleFactor(), diff --git a/src/gui/Widget.cxx b/src/gui/Widget.cxx index ed6ba2f02..132bbd7b9 100644 --- a/src/gui/Widget.cxx +++ b/src/gui/Widget.cxx @@ -344,7 +344,7 @@ void StaticTextWidget::drawWidget(bool hilite) FBSurface& s = _boss->dialog().surface(); bool onTop = _boss->dialog().isOnTop(); s.drawString(_font, _label, _x, _y, _w, - isEnabled() && onTop ? _textcolor : kColor, _align, 0, true, _shadowcolor); + isEnabled() && onTop ? _textcolor : kColor, _align, true, _shadowcolor); setDirty(); } From 1bfcac8a6e348f2539750c0f19b3ebc3879b3fc0 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Fri, 19 Jun 2020 20:07:07 -0230 Subject: [PATCH 319/377] Added 'Save' button to GameInfoDialog, to save current properties to a separate .pro file. --- Changes.txt | 4 ++++ src/gui/Dialog.cxx | 28 ++++++++++++++++++++++++++ src/gui/Dialog.hxx | 9 +++++++++ src/gui/GameInfoDialog.cxx | 41 +++++++++++++++++++++++++++++++++----- src/gui/GameInfoDialog.hxx | 6 ++++++ 5 files changed, 83 insertions(+), 5 deletions(-) diff --git a/Changes.txt b/Changes.txt index 2a5efe3b6..9fa3661e9 100644 --- a/Changes.txt +++ b/Changes.txt @@ -43,6 +43,10 @@ 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. 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/GameInfoDialog.cxx b/src/gui/GameInfoDialog.cxx index fd646c6ed..2348e047d 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 @@ -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 From 464111c39d0fff553e70e67cca5e5a478ae2bc13 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Fri, 19 Jun 2020 20:20:56 -0230 Subject: [PATCH 320/377] Updated various files for 6.2.1 release. --- Announce.txt | 22 +++++++++++----------- Changes.txt | 6 +++--- debian/changelog | 7 +++++++ docs/debugger.html | 2 +- docs/index.html | 2 +- docs/index_r77.html | 2 +- src/common/StateManager.hxx | 2 +- src/common/Version.hxx | 4 ++-- src/macos/Info-Stella.plist | 4 ++-- src/unix/stella.spec | 5 ++++- src/windows/stella.rc | 8 ++++---- 11 files changed, 37 insertions(+), 27 deletions(-) diff --git a/Announce.txt b/Announce.txt index 6b85d8d00..2262f7975 100644 --- a/Announce.txt +++ b/Announce.txt @@ -9,7 +9,7 @@ SSSS ttt eeeee llll llll aaaaa =========================================================================== - Release 6.2 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.2 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.2-win32.exe (32-bit EXE installer) - Stella-6.2-x64.exe (64-bit EXE installer) - Stella-6.2-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.2-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.2-1_i386.deb - stella_6.2-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.2-2.i386.rpm - stella-6.2-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.2-src.tar.xz + stella-6.2.1-src.tar.xz Distribution Site diff --git a/Changes.txt b/Changes.txt index 9fa3661e9..749085128 100644 --- a/Changes.txt +++ b/Changes.txt @@ -12,7 +12,7 @@ Release History =========================================================================== -6.2 to 6.2.1: (XXX xx, 2020) +6.2 to 6.2.1: (June 20, 2020) * Fixed Pitfall II ROM not working correctly. @@ -28,8 +28,6 @@ * Fixed some bugs in 3E+ scheme when using non-standard ROM sizes. - * Fixed custom palette and TV effects adjustable slider rounding issue. - * Fixed crash in Audio & Video dialog when opened from debugger, and the debugger window sometimes being resized when using the Options dialog. @@ -38,6 +36,8 @@ * 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 diff --git a/debian/changelog b/debian/changelog index 6b4dff642..75c7267b6 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +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 diff --git a/docs/debugger.html b/docs/debugger.html index 7f2cabec5..306885c34 100644 --- a/docs/debugger.html +++ b/docs/debugger.html @@ -15,7 +15,7 @@
      Stella
      -

      Release 6.2

      +

      Release 6.2.1

      Integrated Debugger

      (a work in progress)


      diff --git a/docs/index.html b/docs/index.html index 85d019040..5b711a86d 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

      diff --git a/docs/index_r77.html b/docs/index_r77.html index 33e767c7e..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.2
      +
      Release 6.2.1

      Quick Navigation Guide


      diff --git a/src/common/StateManager.hxx b/src/common/StateManager.hxx index 83f3d7acc..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 "06020090state" +#define STATE_HEADER "06020100state" class OSystem; class RewindManager; diff --git a/src/common/Version.hxx b/src/common/Version.hxx index 2c770f57f..b0e339035 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.1_pre" -#define STELLA_BUILD "6001" +#define STELLA_VERSION "6.2.1" +#define STELLA_BUILD "6039" #endif diff --git a/src/macos/Info-Stella.plist b/src/macos/Info-Stella.plist index 386e378fc..d9eb7520e 100644 --- a/src/macos/Info-Stella.plist +++ b/src/macos/Info-Stella.plist @@ -45,7 +45,7 @@ CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion - 6.2 + 6.2.1 CFBundleName Stella CFBundlePackageType @@ -53,7 +53,7 @@ CFBundleSignature StLa CFBundleVersion - 6.2 + 6.2.1 LSApplicationCategoryType public.app-category.games LSMinimumSystemVersionByArchitecture diff --git a/src/unix/stella.spec b/src/unix/stella.spec index 264b4da7e..c54cf259a 100644 --- a/src/unix/stella.spec +++ b/src/unix/stella.spec @@ -1,5 +1,5 @@ %define name stella -%define version 6.2 +%define version 6.2.1 %define rel 1 %define enable_sound 1 @@ -100,6 +100,9 @@ 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 diff --git a/src/windows/stella.rc b/src/windows/stella.rc index 7facd2292..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,2,0,0 - PRODUCTVERSION 6,2,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.2" + 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.2" + VALUE "ProductVersion", "6.2.1" END END BLOCK "VarFileInfo" From 386d591e0846e6e826b551910e9396afb953d41a Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Fri, 19 Jun 2020 20:25:00 -0230 Subject: [PATCH 321/377] Revert "Remove superfluous 'deltax' parameter in drawString; I have no idea what it was doing there." This reverts commit 06db9b4f4a85d0044c6816d61154d86ffb75505f. And as soon as I committed it, I suspected it would cause problems :( --- src/emucore/FBSurface.cxx | 9 +++++---- src/emucore/FBSurface.hxx | 6 ++++-- src/emucore/FrameBuffer.cxx | 6 +++--- src/gui/Widget.cxx | 2 +- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/emucore/FBSurface.cxx b/src/emucore/FBSurface.cxx index 4b882346f..c489fc703 100644 --- a/src/emucore/FBSurface.cxx +++ b/src/emucore/FBSurface.cxx @@ -329,7 +329,7 @@ bool FBSurface::isWhiteSpace(const char s) const int FBSurface::drawString(const GUI::Font& font, const string& s, int x, int y, int w, int h, ColorId color, TextAlign align, - bool useEllipsis, ColorId shadowColor) + int deltax, bool useEllipsis, ColorId shadowColor) { int lines = 1; @@ -355,13 +355,13 @@ int FBSurface::drawString(const GUI::Font& font, const string& s, //str += inStr[i]; } wrapString(inStr, i, leftStr, rightStr); - drawString(font, leftStr, x, y, w, color, align, false, shadowColor); + drawString(font, leftStr, x, y, w, color, align, deltax, false, shadowColor); h -= font.getFontHeight(); y += font.getFontHeight(); inStr = rightStr; lines++; } - drawString(font, inStr, x, y, w, color, align, useEllipsis, shadowColor); + drawString(font, inStr, x, y, w, color, align, deltax, useEllipsis, shadowColor); #endif return lines; } @@ -370,7 +370,7 @@ int FBSurface::drawString(const GUI::Font& font, const string& s, void FBSurface::drawString(const GUI::Font& font, const string& s, int x, int y, int w, ColorId color, TextAlign align, - bool useEllipsis, ColorId shadowColor) + int deltax, bool useEllipsis, ColorId shadowColor) { #ifdef GUI_SUPPORT const string ELLIPSIS = "\x1d"; // "..." @@ -410,6 +410,7 @@ void FBSurface::drawString(const GUI::Font& font, const string& s, else if(align == TextAlign::Right) x = x + w - width; + x += deltax; for(i = 0; i < str.size(); ++i) { w = font.getCharWidth(str[i]); diff --git a/src/emucore/FBSurface.hxx b/src/emucore/FBSurface.hxx index 4be99dc42..48632404d 100644 --- a/src/emucore/FBSurface.hxx +++ b/src/emucore/FBSurface.hxx @@ -218,6 +218,7 @@ class FBSurface @param h The height of the string area (for multi line strings) @param color The color of the text @param align The alignment of the text in the string width area + @param deltax FIXME @param useEllipsis Whether to use '...' when the string is too long @return Number of lines drawn */ @@ -225,7 +226,7 @@ class FBSurface virtual int drawString( const GUI::Font& font, const string& s, int x, int y, int w, int h, ColorId color, TextAlign align = TextAlign::Left, - bool useEllipsis = true, ColorId shadowColor = kNone); + int deltax = 0, bool useEllipsis = true, ColorId shadowColor = kNone); /** This method should be called to draw the specified string. @@ -237,12 +238,13 @@ class FBSurface @param w The width of the string area @param color The color of the text @param align The alignment of the text in the string width area + @param deltax FIXME @param useEllipsis Whether to use '...' when the string is too long */ virtual void drawString( const GUI::Font& font, const string& s, int x, int y, int w, ColorId color, TextAlign align = TextAlign::Left, - bool useEllipsis = true, ColorId shadowColor = kNone); + int deltax = 0, bool useEllipsis = true, ColorId shadowColor = kNone); ////////////////////////////////////////////////////////////////////////// // Note: The following methods are FBSurface-specific, and must be diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 2a53d2c8f..97af29fcf 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -600,7 +600,7 @@ void FrameBuffer::drawFrameStats(float framesPerSecond) << info.DisplayFormat; myStatsMsg.surface->drawString(f, ss.str(), xPos, yPos, - myStatsMsg.w, color, TextAlign::Left, true, kBGColor); + myStatsMsg.w, color, TextAlign::Left, 0, true, kBGColor); yPos += dy; ss.str(""); @@ -615,7 +615,7 @@ void FrameBuffer::drawFrameStats(float framesPerSecond) << "% speed"; myStatsMsg.surface->drawString(f, ss.str(), xPos, yPos, - myStatsMsg.w, myStatsMsg.color, TextAlign::Left, true, kBGColor); + myStatsMsg.w, myStatsMsg.color, TextAlign::Left, 0, true, kBGColor); yPos += dy; ss.str(""); @@ -624,7 +624,7 @@ void FrameBuffer::drawFrameStats(float framesPerSecond) if (myOSystem.settings().getBool("dev.settings")) ss << "| Developer"; myStatsMsg.surface->drawString(f, ss.str(), xPos, yPos, - myStatsMsg.w, myStatsMsg.color, TextAlign::Left, true, kBGColor); + myStatsMsg.w, myStatsMsg.color, TextAlign::Left, 0, true, kBGColor); myStatsMsg.surface->setDstPos(myImageRect.x() + 10, myImageRect.y() + 8); myStatsMsg.surface->setDstSize(myStatsMsg.w * hidpiScaleFactor(), diff --git a/src/gui/Widget.cxx b/src/gui/Widget.cxx index 132bbd7b9..ed6ba2f02 100644 --- a/src/gui/Widget.cxx +++ b/src/gui/Widget.cxx @@ -344,7 +344,7 @@ void StaticTextWidget::drawWidget(bool hilite) FBSurface& s = _boss->dialog().surface(); bool onTop = _boss->dialog().isOnTop(); s.drawString(_font, _label, _x, _y, _w, - isEnabled() && onTop ? _textcolor : kColor, _align, true, _shadowcolor); + isEnabled() && onTop ? _textcolor : kColor, _align, 0, true, _shadowcolor); setDirty(); } From 1cbdb810a9e3d68447e07444f98554c499eeb0d4 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 20 Jun 2020 08:37:50 +0200 Subject: [PATCH 322/377] updated screenshots --- docs/graphics/options_gameinfo_cartridge.png | Bin 5210 -> 3168 bytes docs/graphics/options_gameinfo_console.png | Bin 4558 -> 2540 bytes docs/graphics/options_gameinfo_controller.png | Bin 4057 -> 4139 bytes docs/graphics/options_gameinfo_emulation.png | Bin 3393 -> 3476 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/graphics/options_gameinfo_cartridge.png b/docs/graphics/options_gameinfo_cartridge.png index ea09b98420e16a559dc4ccbe566fac9f2a17e7ee..b90761623b49600452ce6424dffe64eee68f17ec 100644 GIT binary patch literal 3168 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%0Db?EX1Q5of?%G2Uitol#9NfLfM(Mo}L zW8v40+>qEY>CDdM0rj3<%F(;!`z3s}J{-YxKEhqqWj0boquenj`;=uif%Cet87Y!} zLlR+9y``n5GA8OK99-{+IMx_Xq7@!~Q_*sW3ffsm1F^^P;hlCdxI_$sTbZatmxD@l-{jsZp8AIu#0rBz8Rb?D}M} zgJaw>v$mw$X*eW}r_$jLk6UF8_VIIn<{}5(wZ@iqlZ%S~}`F&XV#7~KeBqzC6qsmopM_te} zT+X_|QCKs*T@Z(EWwT zP&_LyRxpeOB>K>9+U>Z5zO|DJJ*WdsugHW*690q0@Y)~KwHmUA0wZJsn3k!B5f7aA zy}k%l7#Gy-SbVCN*AlPHZGAPWfW~w^o0?)*D{5V3I+{VvbjR}bhpU^%-C1^~U z^gn}UMnm06OwGZiomHTFk(xy+^wBWp{CIN@ZwJVqw8V@#BxS8&~kg*Z3pKW)JXJT&Dg zwQ!4}U8v`fHHvU%7U(6@acASbm4Iq*>q_w!9w{$aA`vyyz-7nSLCSf9Np+jDd86p! zG0G7uY7uJi8Lu_Qc4KU^BWTlysTZyX*Db%!TVY^vMLKHwrl0k1*N6XSyx|2N zQV0~*#nV3$#@RX_lYR&3z2*N-#At&y;JH1o>W!FAuUo-P%Z*`W1bZ331=;QC&{?PB z>uRBSru-oy1HF_(C234;BLOv!O!|13k-n?iKy+JWN?+V9Q}D%%rGL2$u4u5d7s|!U zAXQDu#{kpAJLiGft=rF*Y($M+;wJPi0+!h5T+4B|DvhBgZOl(26+^moF`@od5YIcG z*HfOp9uxFj9wjAdH4|)2`YA5ZXv_A4akYS8QE6lh4&kL87vZG^L+%-|U6Q>p~%c6z6ipF~e zF@5|*&bXvqQr2SVqVGx)z!qLiFa46D7J$+IjS>39lGD!fo3$iVDrg2OeyPa3bg|GJ zZob`UnPatXBl3a{G~$;1{+rRzS)(nkUvP+w_6$;1F?V#g5i@XX$3fKM7*^q{Mv@&E zaqM?IElu(2)9&m;WvZ>XeL~660nQM>c@YUb)T6m*H>zHU=EPx65%R6XU2p57MhI~7 z4-Og=4Gz<&Lvzn9+dgQQCo6%XXN+j6kDRV+76fFMRX}0fKBtiPj7F=G9MRy4V^V@F z1mr_+BgwD>^{{xDOZE=SA8W`z($?MmP=)W_gbU!>V`n<5JMjxs`j+PnYv;=%NeP*F z>3;u6^xq5>Bq78J5j&oS!=-34D1xMC z4{PUUO!2(5DVoGlWgF7-EBmJiQ#75`Ru#%V&@>C$RETkvm8wFr)3l)3?V>(R=6Av) zQq^n!?-CD434aGh+5iWV95`Ev&%ODj8UA5{KMnEk`~R{74-kiZVM;jg)?ZcKf66-! zyTcBSj$UVMT{u%n+^&1b3e}#pXA162$riL$$IuffIs}R@fx?ap6I`UKEc!4YI@#<$ zQAM6^hW+J@;FmE+IuCg&?wuRj>N*`Ri4L+W>&1ft8(*LQKuWfh>6QzDi-v9d~ z=9@$^Zcf+^{>PLq7Z|v3L>Q*5I6DRmB)1uhFoyAJf-u+mUjmy7x?e2${KzX4@}2qC za6%mqt1Nhb`LSKVcwUvqR9^g;c`8mi{hW|5X8YFcZ#=w8%3F;`&w4J(B*6CG7%Wq_ zI|Efd_;5#CYS*krlM>SztD;@ktly^?vV#W)n(s47?a4l_U5|bhMh5?6FfXt4FqjH~ zaTks(`}`<%7V^QX`13?3Tx$_RV@`e2MnqTcT=$a^Pau74%aik+8GY}Z!+vUCtk4at~vnrpZ^iIGi4-57>{;YGH0)u#OH8IR@k( z2LcI{SqL~v2VPmEdhFc<`3k{3>95VQTC$%H7bfW!m}zeLzu_vHRx5Qy9Eq64Xa9=Z TnU?(dm&ZWwrf#jaL)3o(-PS+I diff --git a/docs/graphics/options_gameinfo_console.png b/docs/graphics/options_gameinfo_console.png index 49577140c0a3b9038165da3df9efaf9005361709..e3aee16e58a7ec8a47ed7d3c318120ad6ba2b3a8 100644 GIT binary patch literal 2540 zcmd5;`#%#38z0fd-LW_-oOH^iIxeG~8Fi54S}vP2mslYS?ZS=19eBNK)^AEhw=kt7?&-eTM^xU81tB%&PQb(i!0D!E` z<%`Y$fY`i9JtX#t7}XCct|B8A?rd!Vs2x7GC;}2Fa|d$(pgvt%h?Epz{j2t_Rw5f1 z7+7tj&<6mFAv9 z31h2VvXk{R7Tz0d=vZiBb}YQ5L&ZVz_eqJrf(Wy@)BY~JtGNh2u=ll6FAyz_Y22v2 zq02n8>jAV#x}>IE;hncZuB%wJA|J&5#4PvQ?qzHH-Dg0^JMMqZNRB}+Wk8+Z7kTIzGsa<&#Q6#$g3KGGy^u{SNZa9g0xJrn2~_#` zBG~mO7gVgKib5WFZK8~|oLapCwI)zGgF&4>)8jhiWf_4Q?Ep{}U8Izuejjq!nzH~T zVw1GiG>pNb5ZX;0zCEU?3k+2NN1 zOfv=$=8*2!>WK>7Z87OnSsXpA8Xz^jN53UGLBtQ>?b>80tLQ9P|I~2JU;*r5kh8!7 z#YKi8>pI1|h!D(hcvX(7&vWw*xz;5~_8SU+V$~}YB%fD$-Z}9nUtU8U- zv&t~Kxj-=<7-0a{7vv~;`0_B;7WD`%$K%-?b*K6^x$m~IGwlMD(;cmI5A62YkV)&8 zksl#6dQ>UCl_BD~`TAF~ALF;2tCL+Hs>RL!sAgCc0unxX{+PS!$w_5Fn$sY5cupZO z>OtH#mc;A;s&8ib?5A8;-t?|j_839)e7`6Vu?HEZ5*+_^lS&+{V|ehdh>fGmRf6~1 z0v3ygqco=!w6#gEU?p)UFtwlZ)MS@`n_t{rJy%y@8PE*38BJu~AT z&2<*oPTR&_%h(n?^NabWoI`;@2j{UT8(8{5IeFU5xo@^a_BFD*Fw~pshobW^n!M$U za8gA9|3iXFc_7KaHz9!pla3oIU$o^N`wSbvQT-OCAYtA1MuWp%oE+nL2rVb_1%-?K z8nWBuc)n_O@0Bss?OfAsk5q6f>v?~EHy;KM@Wr*Pg#;Hwr45<6jq8U;fYz4YoAqM& zH&H)a(VD)XccNN0z4*r>|Blnc;M?fy7R^TJoY#2p>Ce+c**&8xko(95}~r>$(2kulEb^3A?jl%q>B$& z`&%(u`RB_fw=sO#Sq-Q!K9T74uSQ)<^tJ5+K($W|n**5fa|hYR`ekbM+OK~5AiO`9 zzyKNw=xJ6RlqJL9q8hFDSlzX!U7m;w$)`P-!#AWkhIoyAEtut+6|o~+W?9AP4&~4W z#@6?A6xA`7np3liAYbx^hC(IGLR|u{3f^en8IX*G${H-Ot9+(6a%wtE-JBlNIfZ8T zf*EEg-AN~nCi?GKL9`AOHMwX*-2C}_=CB8skkU7_mXIl2s~B?7k8NIe&Mq*NcYN>T5#@$Bt4-2N(awg z30|-qi@qMQ%VR|7QTDo4caZLhlcD009^z0`>kfhpx7f$Ih2)##g!vcGW@*gEztAG$ zZ{k#A@OHb=E}h4W;-cz`u63oj zUyjIXDB9w;?>A#`6a63MP_fo4tWfFXASGZR;YNR9CA-&!yg!gBE!FyLXZN0cO#76bkQzpt`sU!Emd<)=&OV2S!bXw#*s2xQ*hdVQqPnTvW)?Te zgl{OfMGLxyPL;SO&BQeR-MQ6?XMgTS2Rosfm5}hHnbsHnYNS?J!J^cgO8m3;|FdoWKjgWdVaUcay>Sks8UbRMQNkZ!?Z01q z5GxG2rW4y^q&K*K0*5#xIx+t(dh46y$By262l91wypt5e4t)Q;Y^)qF)>`;H_%|Zb B^^O1l literal 4558 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 R1b#1D%iZTKYR!BS{|h@BQN{oO delta 3916 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 diff --git a/docs/graphics/options_gameinfo_emulation.png b/docs/graphics/options_gameinfo_emulation.png index 0db133505a7fcf9f69c2b8867945958514ff9747..221a08fa5b818b9a3e6556753530d25c9dc42de1 100644 GIT binary patch delta 3357 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 Kq4>Pl!~X(1l;5rZ delta 3292 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 From 6999f69aa2175d0292f05810bc884967810f6b21 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sat, 20 Jun 2020 12:33:07 -0230 Subject: [PATCH 323/377] Last minute update to docs before the 6.2.1 release. --- docs/index.html | 12 +++++++++++- src/common/Version.hxx | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/docs/index.html b/docs/index.html index 5b711a86d..4683365a3 100644 --- a/docs/index.html +++ b/docs/index.html @@ -4290,7 +4290,17 @@ 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 @@ -4058,7 +4058,7 @@ Ms Pac-Man (Stella extended codes):
      Cartridge.StartBank:Cart.StartBank: Indicates which bank to use for reading the reset vector.
      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 @@ -4119,19 +4119,19 @@ Ms Pac-Man (Stella extended codes): - + - + - + @@ -4232,14 +4232,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.
      - + - + - + - + - + - + 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", From 53cd413221a3b9e105a9ad4e942357d46019e2e1 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 8 Jun 2020 15:34:10 +0200 Subject: [PATCH 290/377] allow changing TV hue in 1% steps update palette display when defaulting --- src/gui/VideoAudioDialog.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/VideoAudioDialog.cxx b/src/gui/VideoAudioDialog.cxx index c51685fcf..7fcc65cf8 100644 --- a/src/gui/VideoAudioDialog.cxx +++ b/src/gui/VideoAudioDialog.cxx @@ -233,6 +233,7 @@ void VideoAudioDialog::addPaletteTab() CREATE_CUSTOM_SLIDERS(Contrast, "Contrast ", kPaletteUpdated) CREATE_CUSTOM_SLIDERS(Bright, "Brightness ", kPaletteUpdated) CREATE_CUSTOM_SLIDERS(Gamma, "Gamma ", kPaletteUpdated) + myTVHue->setStepValue(1); // The resulting palette xpos = myPhaseShiftNtsc->getRight() + fontWidth * 2; @@ -729,6 +730,7 @@ void VideoAudioDialog::setDefaults() myTVBright->setValue(50); myTVGamma->setValue(50); handlePaletteChange(); + handlePaletteUpdate(); break; case 2: // TV effects From e0403d93a3ecf18b60d4ab919c5e9b3d7402daa4 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 9 Jun 2020 08:27:14 +0200 Subject: [PATCH 291/377] fixed palette/tv-effects slider rounding issue --- src/common/PaletteHandler.hxx | 2 +- src/common/tv_filters/NTSCFilter.cxx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/common/PaletteHandler.hxx b/src/common/PaletteHandler.hxx index 3de835d7d..ed46da516 100644 --- a/src/common/PaletteHandler.hxx +++ b/src/common/PaletteHandler.hxx @@ -126,7 +126,7 @@ class PaletteHandler Convert adjustables from/to 100% scale */ static constexpr float scaleFrom100(float x) { return (x / 50.F) - 1.F; } - static constexpr uInt32 scaleTo100(float x) { return uInt32(50 * (x + 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/tv_filters/NTSCFilter.cxx b/src/common/tv_filters/NTSCFilter.cxx index 9764f1ac3..8e7e899c9 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) From 1223e160b9d1edc179474f22d3055a89422fd39d Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Tue, 9 Jun 2020 11:19:49 -0230 Subject: [PATCH 292/377] Make sure to use correct 'virtual' size of ROM when creating the internal buffer. --- src/emucore/CartEnhanced.cxx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index 5295364f1..c462cbcc8 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -52,7 +52,8 @@ CartridgeEnhanced::CartridgeEnhanced(const ByteBuffer& image, size_t size, } } else - mySize = size; + // Make sure to use size defined by the bankswitching scheme + mySize = std::max(size, bsSize); // Initialize ROM with all 0's, to fill areas that the ROM may not cover size_t bufSize = std::max(mySize, System::PAGE_SIZE); @@ -73,7 +74,9 @@ CartridgeEnhanced::CartridgeEnhanced(const ByteBuffer& image, size_t size, // TODO: should we mirror here too?? // Directly copy the ROM image into the buffer - std::copy_n(image.get(), mySize, myImage.get()); + // 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()); } else { From fb3438aac705534ddfb64e6adbf056511530301f Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Tue, 9 Jun 2020 12:32:14 -0230 Subject: [PATCH 293/377] Make sure 3E+ ROMs are always internally sized as a multiple 1024 bytes. --- src/common/bspf.hxx | 6 ++++++ src/emucore/Cart3E.cxx | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/common/bspf.hxx b/src/common/bspf.hxx index 24fe8d0a7..a887bf80a 100644 --- a/src/common/bspf.hxx +++ b/src/common/bspf.hxx @@ -140,6 +140,12 @@ namespace BSPF 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/emucore/Cart3E.cxx b/src/emucore/Cart3E.cxx index 263c8b2e9..b03175477 100644 --- a/src/emucore/Cart3E.cxx +++ b/src/emucore/Cart3E.cxx @@ -22,7 +22,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge3E::Cartridge3E(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, BSPF::nextPowerOfTwo(size), md5, settings) + : CartridgeEnhanced(image, size, BSPF::nextMultipleOf(size, 1_KB), md5, settings) { myBankShift = BANK_SHIFT; myRamSize = RAM_SIZE; From 4f581d67ac905b5c26e3ed167a385a645a4bd91a Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Tue, 9 Jun 2020 15:56:31 -0230 Subject: [PATCH 294/377] Fixed interaction with ideal ROM size between 3E and 3E+. --- src/emucore/Cart3E.cxx | 9 ++++++++- src/emucore/Cart3E.hxx | 17 ++++++++++++++++- src/emucore/Cart3EPlus.cxx | 2 +- src/emucore/CartEnhanced.hxx | 2 +- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/emucore/Cart3E.cxx b/src/emucore/Cart3E.cxx index b03175477..a79e79167 100644 --- a/src/emucore/Cart3E.cxx +++ b/src/emucore/Cart3E.cxx @@ -22,7 +22,14 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge3E::Cartridge3E(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, BSPF::nextMultipleOf(size, 1_KB), md5, settings) + : Cartridge3E(image, size, BSPF::nextMultipleOf(size, 2_KB), md5, settings) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Cartridge3E::Cartridge3E(const ByteBuffer& image, size_t size, size_t bsSize, + const string& md5, const Settings& settings) + : CartridgeEnhanced(image, size, bsSize, md5, settings) { myBankShift = BANK_SHIFT; myRamSize = RAM_SIZE; diff --git a/src/emucore/Cart3E.hxx b/src/emucore/Cart3E.hxx index f2ead51f5..96fc7b28b 100644 --- a/src/emucore/Cart3E.hxx +++ b/src/emucore/Cart3E.hxx @@ -65,7 +65,7 @@ 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 @@ -76,6 +76,21 @@ class Cartridge3E : public CartridgeEnhanced const Settings& settings); virtual ~Cartridge3E() = default; + protected: + /** + Create a new cartridge using the specified image and size. + This is an alternate version of the constructor, meant to be used + only by classes inheriting from this class. + + @param image Pointer to the ROM image + @param size The size of the ROM image + @param bsSize The size specified by the bankswitching scheme + @param md5 The md5sum of the ROM image + @param settings A reference to the various settings (read-only) + */ + Cartridge3E(const ByteBuffer& image, size_t size, size_t bsSize, + const string& md5, const Settings& settings); + public: /** diff --git a/src/emucore/Cart3EPlus.cxx b/src/emucore/Cart3EPlus.cxx index 6c9fe7c2a..6d5ce7d4c 100644 --- a/src/emucore/Cart3EPlus.cxx +++ b/src/emucore/Cart3EPlus.cxx @@ -22,7 +22,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge3EPlus::Cartridge3EPlus(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge3E(image, size, md5, settings) + : Cartridge3E(image, size, BSPF::nextMultipleOf(size, 1_KB), md5, settings) { myBankShift = BANK_SHIFT; myRamSize = RAM_SIZE; diff --git a/src/emucore/CartEnhanced.hxx b/src/emucore/CartEnhanced.hxx index be0ac95de..cd398be11 100644 --- a/src/emucore/CartEnhanced.hxx +++ b/src/emucore/CartEnhanced.hxx @@ -41,8 +41,8 @@ class CartridgeEnhanced : public Cartridge @param image Pointer to the ROM image @param size The size of the ROM image - @param md5 The md5sum of the ROM image @param bsSize The size specified by the bankswitching scheme + @param md5 The md5sum of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeEnhanced(const ByteBuffer& image, size_t size, size_t bsSize, From 754cb5d4c669d53421f3b45c2a56f2c19d7eaa21 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 9 Jun 2020 20:43:37 +0200 Subject: [PATCH 295/377] Revert "take care of odd ROM sizes (fixes #653)" This reverts commit bc8211b4436b03ab264f20ab4185c16a30a0ed18. --- src/emucore/CartEnhanced.cxx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index c462cbcc8..00c7334ed 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -348,7 +348,7 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeEnhanced::getBank(uInt16 address) const { - return myCurrentSegOffset[std::min((address & ROM_MASK) >> myBankShift, romBankCount() - 1)] >> myBankShift; + return myCurrentSegOffset[(address & ROM_MASK) >> myBankShift] >> myBankShift; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -360,8 +360,7 @@ uInt16 CartridgeEnhanced::getSegmentBank(uInt16 segment) const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeEnhanced::romBankCount() const { - // take care of too small ROMs - return uInt16((mySize + ((1 << myBankShift) - 1)) >> myBankShift); + return uInt16(mySize >> myBankShift); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 46e7830c2b940be57d2842d6361a433975db47fb Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Tue, 9 Jun 2020 16:45:53 -0230 Subject: [PATCH 296/377] Remove focus from description in debugger CartRAM widget. --- src/debugger/gui/CartRamWidget.cxx | 1 - 1 file changed, 1 deletion(-) 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; From f68e10a1560d7664e781ddf6c59ba33ff36b469e Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Tue, 9 Jun 2020 19:00:35 -0230 Subject: [PATCH 297/377] Updated changelog and minimum compiler requirements in the docs. --- Changes.txt | 11 +++++++++++ docs/index.html | 3 +-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Changes.txt b/Changes.txt index aeb71411b..27eb65a84 100644 --- a/Changes.txt +++ b/Changes.txt @@ -19,6 +19,17 @@ apply the properties to the ROM. [NOTE: this was present in 6.2, but was mistakenly left out of the changelog] + * Make NTSC custom phase shift not affect Yellow anymore. + + * Allow changing palette adjustables in 1% steps again. + + * Fixed some bugs in 3E+ scheme when using non-standard ROM sizes. + + * Updated documentation for changes in ROM properties key names. + + * The codebase now compiles under gcc6 again. Future versions will + require gcc7, though. + -Have fun! diff --git a/docs/index.html b/docs/index.html index 69e1aff77..41be21bac 100644 --- a/docs/index.html +++ b/docs/index.html @@ -355,12 +355,11 @@

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

        -
      • Linux Kernel 3.x
      • i386 or x86_64 class machine, with 32 or 64-bit distribution
      • OpenGL capable video card
      • Other architectures (MIPS, PPC, PPC64, etc.) have been confirmed to work, but aren't as well tested as i386/x86_64
      • -
      • GNU g++ v/5 or Clang v/3.5 (with C++14 support) and the make utility are required for compiling the Stella source code
      • +
      • GNU g++ v/6 or Clang v/3.9 (with C++14 support) and the make utility are required for compiling the Stella source code

      From 2783c1cabe9f7287fc3807e9d78d2505b48d8209 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Wed, 10 Jun 2020 11:39:55 -0230 Subject: [PATCH 298/377] Make first 3 segments of 3E+ point to random banks, according to the documentation (fixes #660). --- src/debugger/gui/Cart3EPlusWidget.cxx | 2 +- src/emucore/Cart3EPlus.cxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/debugger/gui/Cart3EPlusWidget.cxx b/src/debugger/gui/Cart3EPlusWidget.cxx index a0d97ad2b..163dc23fd 100644 --- a/src/debugger/gui/Cart3EPlusWidget.cxx +++ b/src/debugger/gui/Cart3EPlusWidget.cxx @@ -46,7 +46,7 @@ string Cartridge3EPlusWidget::description() "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]; diff --git a/src/emucore/Cart3EPlus.cxx b/src/emucore/Cart3EPlus.cxx index 6d5ce7d4c..818d48c1f 100644 --- a/src/emucore/Cart3EPlus.cxx +++ b/src/emucore/Cart3EPlus.cxx @@ -34,7 +34,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); From e8fd51453c6755c006f408f1e2f3c8786726561b Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Wed, 10 Jun 2020 16:59:27 -0230 Subject: [PATCH 299/377] Fix Pitfall II not working (fixes #661). Note that I've refactored all the constructors to prevent this issue from happening again. It already happened with 3E+/3E, and now DPC/F8. Also, FA2/FA looked suspicious. --- Changes.txt | 2 ++ src/emucore/Cart0840.cxx | 5 +++-- src/emucore/Cart0840.hxx | 3 ++- src/emucore/Cart2K.cxx | 5 +++-- src/emucore/Cart2K.hxx | 3 ++- src/emucore/Cart3E.cxx | 13 ++++--------- src/emucore/Cart3E.hxx | 19 +++---------------- src/emucore/Cart3EPlus.cxx | 6 ++++-- src/emucore/Cart3EPlus.hxx | 4 +++- src/emucore/Cart3F.cxx | 6 ++++-- src/emucore/Cart3F.hxx | 4 +++- src/emucore/Cart4K.cxx | 5 +++-- src/emucore/Cart4K.hxx | 3 ++- src/emucore/Cart4KSC.cxx | 5 +++-- src/emucore/Cart4KSC.hxx | 3 ++- src/emucore/CartBF.cxx | 5 +++-- src/emucore/CartBF.hxx | 3 ++- src/emucore/CartBFSC.cxx | 5 +++-- src/emucore/CartBFSC.hxx | 3 ++- src/emucore/CartCV.cxx | 5 +++-- src/emucore/CartCV.hxx | 3 ++- src/emucore/CartDF.cxx | 5 +++-- src/emucore/CartDF.hxx | 3 ++- src/emucore/CartDFSC.cxx | 5 +++-- src/emucore/CartDFSC.hxx | 3 ++- src/emucore/CartDPC.cxx | 5 +++-- src/emucore/CartDPC.hxx | 3 ++- src/emucore/CartE0.cxx | 5 +++-- src/emucore/CartE0.hxx | 3 ++- src/emucore/CartEF.cxx | 5 +++-- src/emucore/CartEF.hxx | 3 ++- src/emucore/CartEFSC.cxx | 5 +++-- src/emucore/CartEFSC.hxx | 3 ++- src/emucore/CartEnhanced.cxx | 4 ++-- src/emucore/CartEnhanced.hxx | 7 ++++--- src/emucore/CartF0.cxx | 5 +++-- src/emucore/CartF0.hxx | 3 ++- src/emucore/CartF4.cxx | 5 +++-- src/emucore/CartF4.hxx | 3 ++- src/emucore/CartF4SC.cxx | 7 ++++--- src/emucore/CartF4SC.hxx | 3 ++- src/emucore/CartF6.cxx | 5 +++-- src/emucore/CartF6.hxx | 3 ++- src/emucore/CartF6SC.cxx | 7 ++++--- src/emucore/CartF6SC.hxx | 3 ++- src/emucore/CartF8.cxx | 5 +++-- src/emucore/CartF8.hxx | 3 ++- src/emucore/CartF8SC.cxx | 5 +++-- src/emucore/CartF8SC.hxx | 3 ++- src/emucore/CartFA.cxx | 5 +++-- src/emucore/CartFA.hxx | 3 ++- src/emucore/CartFA2.cxx | 5 +++-- src/emucore/CartFA2.hxx | 3 ++- src/emucore/CartFC.cxx | 6 ++++-- src/emucore/CartFC.hxx | 4 +++- src/emucore/CartFE.cxx | 5 +++-- src/emucore/CartFE.hxx | 3 ++- src/emucore/CartMDM.cxx | 6 ++++-- src/emucore/CartMDM.hxx | 4 +++- src/emucore/CartSB.cxx | 6 ++++-- src/emucore/CartSB.hxx | 4 +++- src/emucore/CartTVBoy.cxx | 5 +++-- src/emucore/CartTVBoy.hxx | 3 ++- src/emucore/CartUA.cxx | 2 +- src/emucore/CartWD.cxx | 5 +++-- src/emucore/CartWD.hxx | 3 ++- src/emucore/CartX07.cxx | 5 +++-- src/emucore/CartX07.hxx | 3 ++- 68 files changed, 183 insertions(+), 126 deletions(-) diff --git a/Changes.txt b/Changes.txt index 27eb65a84..507bfc84f 100644 --- a/Changes.txt +++ b/Changes.txt @@ -14,6 +14,8 @@ 6.2 to 6.2.1: (XXX xx, 2020) + * Fixed Pitfall II ROM not working correctly. + * 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 diff --git a/src/emucore/Cart0840.cxx b/src/emucore/Cart0840.cxx index 894b8eed7..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, 8_KB, 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 c70cc373f..ee0974549 100644 --- a/src/emucore/Cart2K.cxx +++ b/src/emucore/Cart2K.cxx @@ -20,7 +20,8 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge2K::Cartridge2K(const ByteBuffer& image, size_t size, - const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, 2_KB, md5, settings) + const string& md5, const Settings& settings, + size_t bsSize) + : CartridgeEnhanced(image, size, md5, settings, bsSize) { } 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 a79e79167..e3d049eea 100644 --- a/src/emucore/Cart3E.cxx +++ b/src/emucore/Cart3E.cxx @@ -21,15 +21,10 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge3E::Cartridge3E(const ByteBuffer& image, size_t size, - const string& md5, const Settings& settings) - : Cartridge3E(image, size, BSPF::nextMultipleOf(size, 2_KB), md5, settings) -{ -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Cartridge3E::Cartridge3E(const ByteBuffer& image, size_t size, size_t bsSize, - const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, bsSize, 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 96fc7b28b..60e50613a 100644 --- a/src/emucore/Cart3E.hxx +++ b/src/emucore/Cart3E.hxx @@ -71,26 +71,13 @@ class Cartridge3E : 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) */ Cartridge3E(const ByteBuffer& image, size_t size, const string& md5, - const Settings& settings); + const Settings& settings, size_t bsSize = 0); virtual ~Cartridge3E() = default; - protected: - /** - Create a new cartridge using the specified image and size. - This is an alternate version of the constructor, meant to be used - only by classes inheriting from this class. - - @param image Pointer to the ROM image - @param size The size of the ROM image - @param bsSize The size specified by the bankswitching scheme - @param md5 The md5sum of the ROM image - @param settings A reference to the various settings (read-only) - */ - Cartridge3E(const ByteBuffer& image, size_t size, size_t bsSize, - const string& md5, const Settings& settings); - public: /** diff --git a/src/emucore/Cart3EPlus.cxx b/src/emucore/Cart3EPlus.cxx index 818d48c1f..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, BSPF::nextMultipleOf(size, 1_KB), 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; diff --git a/src/emucore/Cart3EPlus.hxx b/src/emucore/Cart3EPlus.hxx index fe6a0a263..9abd5cb09 100644 --- a/src/emucore/Cart3EPlus.hxx +++ b/src/emucore/Cart3EPlus.hxx @@ -100,9 +100,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 20d9cef1d..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, BSPF::nextPowerOfTwo(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/Cart4K.cxx b/src/emucore/Cart4K.cxx index 0a3e27bdc..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, 4_KB, 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/CartBF.cxx b/src/emucore/CartBF.cxx index 065b657dc..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, 256_KB, 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/CartCV.cxx b/src/emucore/CartCV.cxx index 8e8e6504e..8fe746f1a 100644 --- a/src/emucore/CartCV.cxx +++ b/src/emucore/CartCV.cxx @@ -20,8 +20,9 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeCV::CartridgeCV(const ByteBuffer& image, size_t size, - const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, 2_KB, md5, settings) + const string& md5, const Settings& settings, + size_t bsSize) + : CartridgeEnhanced(image, size, md5, settings, bsSize) { myBankShift = BANK_SHIFT; myRamSize = RAM_SIZE; 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/CartDF.cxx b/src/emucore/CartDF.cxx index f95ebcc93..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, 128_KB, 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/CartE0.cxx b/src/emucore/CartE0.cxx index 7a10c3e34..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, 8_KB, 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 175b42263..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, 64_KB, 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 00c7334ed..574dacca8 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -21,8 +21,8 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeEnhanced::CartridgeEnhanced(const ByteBuffer& image, size_t size, - size_t bsSize, const string& md5, - const Settings& settings) + const string& md5, const Settings& settings, + size_t bsSize) : Cartridge(settings, md5) { // ROMs are not always at the 'legal' size for their associated diff --git a/src/emucore/CartEnhanced.hxx b/src/emucore/CartEnhanced.hxx index cd398be11..e15fb8ba1 100644 --- a/src/emucore/CartEnhanced.hxx +++ b/src/emucore/CartEnhanced.hxx @@ -41,12 +41,13 @@ class CartridgeEnhanced : public Cartridge @param image Pointer to the ROM image @param size The size of the ROM image - @param bsSize The size specified by the bankswitching scheme @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, size_t bsSize, - 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: diff --git a/src/emucore/CartF0.cxx b/src/emucore/CartF0.cxx index f21bba07e..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, 64_KB, 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 609fd0b03..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, 32_KB, 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 572909952..0e4bcf678 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, 16_KB, md5, settings) + const string& md5, const Settings& settings, + size_t bsSize) + : CartridgeEnhanced(image, size, md5, settings, bsSize) { } 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 7ea1216a5..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, 8_KB, 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 bc82dec84..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, 12_KB, 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 9b945c666..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, BSPF::nextPowerOfTwo(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 a9602e88a..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, 8_KB, 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 022bc1bdb..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, BSPF::nextPowerOfTwo(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/CartMDM.hxx b/src/emucore/CartMDM.hxx index fe17ae628..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: diff --git a/src/emucore/CartSB.cxx b/src/emucore/CartSB.cxx index 8ad55f28d..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, BSPF::nextPowerOfTwo(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 index 0626da0aa..50d66cb57 100644 --- a/src/emucore/CartTVBoy.cxx +++ b/src/emucore/CartTVBoy.cxx @@ -20,8 +20,9 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeTVBoy::CartridgeTVBoy(const ByteBuffer& image, size_t size, - const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, 512_KB, md5, settings) + const string& md5, const Settings& settings, + size_t bsSize) + : CartridgeEnhanced(image, size, md5, settings, bsSize) { } diff --git a/src/emucore/CartTVBoy.hxx b/src/emucore/CartTVBoy.hxx index 90072a08d..d1787e55b 100644 --- a/src/emucore/CartTVBoy.hxx +++ b/src/emucore/CartTVBoy.hxx @@ -44,9 +44,10 @@ class CartridgeTVBoy : 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 */ CartridgeTVBoy(const ByteBuffer& image, size_t size, const string& md5, - const Settings& settings); + const Settings& settings, size_t bsSize = 512_KB); virtual ~CartridgeTVBoy() = default; public: diff --git a/src/emucore/CartUA.cxx b/src/emucore/CartUA.cxx index 23caa5091..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, 8_KB, md5, settings), + : CartridgeEnhanced(image, size, md5, settings, 8_KB), mySwappedHotspots(swapHotspots) { } diff --git a/src/emucore/CartWD.cxx b/src/emucore/CartWD.cxx index f9c7463f3..d985abd00 100644 --- a/src/emucore/CartWD.cxx +++ b/src/emucore/CartWD.cxx @@ -22,8 +22,9 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeWD::CartridgeWD(const ByteBuffer& image, size_t size, - const string& md5, const Settings& settings) - : CartridgeEnhanced(image, size, 8_KB, 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(size == 8_KB + 3) 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 e28869920..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, 64_KB, 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: From 45b11cea538678e153bb737b5b5a2dd7b32e96d2 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 11 Jun 2020 16:20:10 +0200 Subject: [PATCH 300/377] Fixed #662 (3E+ initialization description) --- src/emucore/Cart3EPlus.hxx | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/emucore/Cart3EPlus.hxx b/src/emucore/Cart3EPlus.hxx index 9abd5cb09..ab8696372 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,11 +94,9 @@ 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, size_t bsSize = 0); + const Settings& settings); virtual ~Cartridge3EPlus() = default; public: From 041429ccfb690006e655d27956a6a187e8e96b80 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Thu, 11 Jun 2020 12:02:50 -0230 Subject: [PATCH 301/377] Fix compile error from last commit. --- src/emucore/Cart3EPlus.hxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/emucore/Cart3EPlus.hxx b/src/emucore/Cart3EPlus.hxx index ab8696372..2ba54d313 100644 --- a/src/emucore/Cart3EPlus.hxx +++ b/src/emucore/Cart3EPlus.hxx @@ -94,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: From 5560fb8976e01bc7c838c5e8904e52e9ffbd24ff Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Thu, 11 Jun 2020 12:18:30 -0230 Subject: [PATCH 302/377] Updated docs: modified text for saving "pixel-exact" images, and Cart.VCenter range. --- docs/index.html | 6 +++--- src/gui/SnapshotDialog.cxx | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/index.html b/docs/index.html index 41be21bac..85d019040 100644 --- a/docs/index.html +++ b/docs/index.html @@ -3172,9 +3172,9 @@

      - + - +
      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 @@ -4250,22 +4250,22 @@ 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.
      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
      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.
      _BASEDIR_/stella.pro
      -

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

      +

      The buttons at the bottom of the dialog 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.
      • +
      +

      Note that for any changes made here, Stella will require a restart for the + changes to take effect.


      Palette Support

      diff --git a/src/common/Version.hxx b/src/common/Version.hxx index b0e339035..9c070d208 100644 --- a/src/common/Version.hxx +++ b/src/common/Version.hxx @@ -19,6 +19,6 @@ #define VERSION_HXX #define STELLA_VERSION "6.2.1" -#define STELLA_BUILD "6039" +#define STELLA_BUILD "6041" #endif From 538eecc5d6cf703cb157fe38b6a16fbf2f1bff6d Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 20 Jun 2020 18:01:12 +0200 Subject: [PATCH 324/377] minor wording fix --- docs/index.html | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/index.html b/docs/index.html index 4683365a3..276fbae1b 100644 --- a/docs/index.html +++ b/docs/index.html @@ -4270,6 +4270,16 @@ Ms Pac-Man (Stella extended codes): +

      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:

      @@ -4290,17 +4300,7 @@ Ms Pac-Man (Stella extended codes):
      _BASEDIR_/stella.pro
      -

      The buttons at the bottom of the dialog 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.
      • -
      -

      Note that for any changes made here, Stella will require a restart for the - changes to take effect.

      +

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


      Palette Support

      From ad930ef34b6ced126c708e2a105836504c41623f Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 21 Jun 2020 15:58:58 +0200 Subject: [PATCH 325/377] Added new interface palette 'Dark' --- Changes.txt | 5 +++++ src/emucore/FrameBuffer.cxx | 14 ++++++++++++++ src/emucore/FrameBuffer.hxx | 3 ++- src/emucore/Settings.cxx | 3 ++- src/gui/UIDialog.cxx | 1 + 5 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Changes.txt b/Changes.txt index 749085128..65b7dbec1 100644 --- a/Changes.txt +++ b/Changes.txt @@ -12,6 +12,11 @@ Release History =========================================================================== +6.2.1 to 6.3 (XXXX XX, 2020) + + * Added new interface palette 'Dark'. (TODO: DOC) + + 6.2 to 6.2.1: (June 20, 2020) * Fixed Pitfall II ROM not working correctly. diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 97af29fcf..f2c3fc8f6 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -862,6 +862,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(); @@ -1553,3 +1554,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 0a55a0f89..544c8c6c1 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -714,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/Settings.cxx b/src/emucore/Settings.cxx index e6d81abdd..0c5073d45 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -524,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 Date: Wed, 1 Jul 2020 23:51:49 +0200 Subject: [PATCH 326/377] allow breakpoints in data areas (fixes #668) --- src/debugger/gui/RomWidget.cxx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) 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)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 33e57a83caa991e20b522eabf7448fa230312227 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 2 Jul 2020 09:33:16 +0200 Subject: [PATCH 327/377] suppress fullscreen mode switches in Time Machine mode (fixes #670) --- src/emucore/FrameBuffer.cxx | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index f2c3fc8f6..6ae234fa0 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -992,21 +992,33 @@ void FrameBuffer::setFullscreen(bool enable) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::toggleFullscreen(bool toggle) { - const bool isFullscreen = toggle ? !fullScreen() : fullScreen(); - - setFullscreen(isFullscreen); - - if(myBufferType == BufferType::Emulator) + switch (myOSystem.eventHandler().state()) { - ostringstream msg; + case EventHandlerState::LAUNCHER: + case EventHandlerState::EMULATION: + case EventHandlerState::PAUSE: + case EventHandlerState::DEBUGGER: + { + const bool isFullscreen = toggle ? !fullScreen() : fullScreen(); - msg << "Fullscreen "; - if(isFullscreen) - msg << "enabled (" << refreshRate() << " Hz)"; - else - msg << "disabled"; + setFullscreen(isFullscreen); - showMessage(msg.str()); + if (myBufferType != BufferType::Launcher) + { + ostringstream msg; + + msg << "Fullscreen "; + if (isFullscreen) + msg << "enabled (" << refreshRate() << " Hz)"; + else + msg << "disabled"; + + showMessage(msg.str()); + } + break; + } + default: + break; } } From 379dfe4ac374974c2dd85fb63d322caa09a0e4d5 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Thu, 2 Jul 2020 17:28:48 -0230 Subject: [PATCH 328/377] Refactor Cart::getImage, always return a ByteBuffer. Most classes did this already, but some didn't. So we standardize on this, and eliminate raw pointers. --- src/debugger/gui/Cart3EPlusWidget.cxx | 4 +-- src/debugger/gui/Cart3EWidget.cxx | 2 +- src/debugger/gui/Cart3FWidget.cxx | 2 +- src/debugger/gui/CartEnhancedWidget.cxx | 2 +- src/emucore/Cart.cxx | 6 ++-- src/emucore/Cart.hxx | 4 +-- src/emucore/Cart4A50.cxx | 9 +++--- src/emucore/Cart4A50.hxx | 6 ++-- src/emucore/CartAR.cxx | 4 +-- src/emucore/CartAR.hxx | 4 +-- src/emucore/CartBUS.cxx | 19 ++++++------ src/emucore/CartBUS.hxx | 6 ++-- src/emucore/CartCDF.cxx | 20 +++++++------ src/emucore/CartCDF.hxx | 6 ++-- src/emucore/CartCM.cxx | 13 ++++---- src/emucore/CartCM.hxx | 6 ++-- src/emucore/CartCTY.cxx | 17 ++++++----- src/emucore/CartCTY.hxx | 6 ++-- src/emucore/CartDPCPlus.cxx | 21 ++++++------- src/emucore/CartDPCPlus.hxx | 6 ++-- src/emucore/CartEnhanced.cxx | 4 +-- src/emucore/CartEnhanced.hxx | 4 +-- src/emucore/CartF6.cxx | 1 - src/emucore/CartMNetwork.cxx | 4 +-- src/emucore/CartMNetwork.hxx | 4 +-- src/emucore/Console.cxx | 2 +- src/emucore/ControllerDetector.cxx | 31 ++++++++++--------- src/emucore/ControllerDetector.hxx | 40 ++++++++++++++----------- src/gui/GameInfoDialog.cxx | 4 +-- src/gui/RomInfoWidget.cxx | 4 +-- src/gui/StellaSettingsDialog.cxx | 4 +-- 31 files changed, 139 insertions(+), 126 deletions(-) diff --git a/src/debugger/gui/Cart3EPlusWidget.cxx b/src/debugger/gui/Cart3EPlusWidget.cxx index 163dc23fd..cd0fda251 100644 --- a/src/debugger/gui/Cart3EPlusWidget.cxx +++ b/src/debugger/gui/Cart3EPlusWidget.cxx @@ -35,7 +35,7 @@ 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(); @@ -60,7 +60,7 @@ 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; 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 af110cb0d..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) { diff --git a/src/emucore/Cart.cxx b/src/emucore/Cart.cxx index 958b915df..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; } diff --git a/src/emucore/Cart.hxx b/src/emucore/Cart.hxx index 0e70f4bf7..8ccd10d79 100644 --- a/src/emucore/Cart.hxx +++ b/src/emucore/Cart.hxx @@ -229,9 +229,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/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/CartAR.cxx b/src/emucore/CartAR.cxx index 08f803e0b..cc58d60be 100644 --- a/src/emucore/CartAR.cxx +++ b/src/emucore/CartAR.cxx @@ -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 349de38f1..0b4369f31 100644 --- a/src/emucore/CartAR.hxx +++ b/src/emucore/CartAR.hxx @@ -105,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/CartBUS.cxx b/src/emucore/CartBUS.cxx index 62000118b..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); @@ -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 58e4eea48..2e21b5f24 100644 --- a/src/emucore/CartBUS.hxx +++ b/src/emucore/CartBUS.hxx @@ -116,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. @@ -214,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 09e0da3e3..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); @@ -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 62c1721ca..99374de2b 100644 --- a/src/emucore/CartCDF.hxx +++ b/src/emucore/CartCDF.hxx @@ -122,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. @@ -214,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 b5dfc5197..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); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -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 36fa13fa8..3a58889b4 100644 --- a/src/emucore/CartCM.hxx +++ b/src/emucore/CartCM.hxx @@ -173,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. @@ -246,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 dbb5d13e2..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(); @@ -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 1cd682446..5af3ceff4 100644 --- a/src/emucore/CartCTY.hxx +++ b/src/emucore/CartCTY.hxx @@ -171,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. @@ -263,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/CartDPCPlus.cxx b/src/emucore/CartDPCPlus.cxx index 7a0a7f4c6..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); @@ -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 bbbf68197..04a1b0de4 100644 --- a/src/emucore/CartDPCPlus.hxx +++ b/src/emucore/CartDPCPlus.hxx @@ -118,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. @@ -203,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/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index 28b8b026c..633104cf3 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -364,10 +364,10 @@ bool CartridgeEnhanced::patch(uInt16 address, uInt8 value) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -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 c50f88aa6..e99afc917 100644 --- a/src/emucore/CartEnhanced.hxx +++ b/src/emucore/CartEnhanced.hxx @@ -120,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. diff --git a/src/emucore/CartF6.cxx b/src/emucore/CartF6.cxx index 0e4bcf678..7b120d0b0 100644 --- a/src/emucore/CartF6.cxx +++ b/src/emucore/CartF6.cxx @@ -37,4 +37,3 @@ bool CartridgeF6::checkSwitchBank(uInt16 address, uInt8) } return false; } - diff --git a/src/emucore/CartMNetwork.cxx b/src/emucore/CartMNetwork.cxx index 84cf8dac8..78c68e6a0 100644 --- a/src/emucore/CartMNetwork.cxx +++ b/src/emucore/CartMNetwork.cxx @@ -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 7b4fdb729..9b17a4b67 100644 --- a/src/emucore/CartMNetwork.hxx +++ b/src/emucore/CartMNetwork.hxx @@ -126,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/Console.cxx b/src/emucore/Console.cxx index 1e796a0bd..e6afa0aa4 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -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 diff --git a/src/emucore/ControllerDetector.cxx b/src/emucore/ControllerDetector.cxx index 6609340df..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) @@ -383,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) @@ -440,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) @@ -549,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; @@ -568,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; @@ -587,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; @@ -607,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 @@ -652,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/gui/GameInfoDialog.cxx b/src/gui/GameInfoDialog.cxx index 2348e047d..ff1fca0c6 100644 --- a/src/gui/GameInfoDialog.cxx +++ b/src/gui/GameInfoDialog.cxx @@ -707,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"; } @@ -722,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"; } 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/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"; } From 8f2f13b0dccb18045a746b211f106c065c08e4b1 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 2 Jul 2020 23:33:13 +0200 Subject: [PATCH 329/377] Added global hot keys for debug options --- Changes.txt | 1 + docs/index.html | 99 +++++++------ src/common/PKeyboardHandler.cxx | 4 + src/emucore/Console.cxx | 47 +++--- src/emucore/Console.hxx | 40 ++--- src/emucore/Event.hxx | 3 +- src/emucore/EventHandler.cxx | 250 +++++++++++++++++++++++++++----- src/emucore/EventHandler.hxx | 41 +++++- src/emucore/FrameBuffer.cxx | 8 +- src/emucore/FrameBuffer.hxx | 2 +- src/emucore/tia/TIA.cxx | 27 +++- src/emucore/tia/TIA.hxx | 12 +- 12 files changed, 393 insertions(+), 141 deletions(-) diff --git a/Changes.txt b/Changes.txt index 65b7dbec1..cc1ca3b3b 100644 --- a/Changes.txt +++ b/Changes.txt @@ -16,6 +16,7 @@ * Added new interface palette 'Dark'. (TODO: DOC) + * Extended global hotkeys for debug options. 6.2 to 6.2.1: (June 20, 2020) diff --git a/docs/index.html b/docs/index.html index 276fbae1b..bc3f46f29 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1430,7 +1430,7 @@
      - These settings can also be changed using Global Audio & Video Keys
      + These settings can also be changed using Global Keys @@ -1480,7 +1480,7 @@
      - These settings can also be changed using Global Audio & Video Keys
      + These settings can also be changed using Global Keys @@ -1550,7 +1550,7 @@
      - These settings can also be changed using Global Audio & Video Keys
      + These settings can also be changed using Global Keys @@ -1559,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)

      @@ -1715,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)

      diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index 4ff5191fb..59beffdac 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -505,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/emucore/Console.cxx b/src/emucore/Console.cxx index e6afa0aa4..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)) @@ -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/Event.hxx b/src/emucore/Event.hxx index 9a6c16352..f666e19bc 100644 --- a/src/emucore/Event.hxx +++ b/src/emucore/Event.hxx @@ -121,9 +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 23a9c98ee..53b1eee7a 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,21 +360,38 @@ AdjustFunction EventHandler::cycleAdjustSetting(int direction) myOSystem.settings().getString("palette") == PaletteHandler::SETTING_CUSTOM; const bool isCustomFilter = myOSystem.settings().getInt("tv.filter") == int(NTSCFilter::Preset::CUSTOM); - bool repeat; + 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 - 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); + 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); + 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; @@ -381,6 +408,7 @@ 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), @@ -424,6 +452,25 @@ AdjustFunction EventHandler::getAdjustSetting(AdjustSetting setting) std::bind(&StateManager::changeState, &myOSystem.state(), _1), std::bind(&PaletteHandler::changeCurrentAdjustable, &myOSystem.frameBuffer().tiaSurface().paletteHandler(), _1), std::bind(&TIASurface::changeCurrentNTSCAdjustable, &myOSystem.frameBuffer().tiaSurface(), _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), }; return ADJUST_FUNCTIONS[int(setting)]; @@ -446,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; @@ -457,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: @@ -481,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 @@ -853,7 +932,12 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::ToggleColorLoss: - if (pressed && !repeated) myOSystem.console().toggleColorLoss(); + if (pressed && !repeated) + { + myOSystem.console().toggleColorLoss(); + myAdjustSetting = AdjustSetting::COLOR_LOSS; + myAdjustActive = true; + } return; case Event::PaletteDecrease: @@ -888,11 +972,21 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::ToggleJitter: - if (pressed && !repeated) myOSystem.console().toggleJitter(); + if (pressed && !repeated) + { + myOSystem.console().toggleJitter(); + myAdjustSetting = AdjustSetting::JITTER; + myAdjustActive = true; + } return; case Event::ToggleFrameStats: - if (pressed) myOSystem.frameBuffer().toggleFrameStats(); + if (pressed && !repeated) + { + myOSystem.frameBuffer().toggleFrameStats(); + myAdjustSetting = AdjustSetting::STATS; + myAdjustActive = true; + } return; case Event::ToggleTimeMachine: @@ -941,63 +1035,138 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) 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::SaveState: @@ -2316,6 +2485,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", "" }, @@ -2414,7 +2585,10 @@ const Event::EventSet EventHandler::MiscEvents = { // Event::MouseAxisXMove, Event::MouseAxisYMove, // Event::MouseButtonLeftValue, Event::MouseButtonRightValue, Event::HandleMouseControl, Event::ToggleGrabMouse, - Event::ToggleSAPortOrder, Event::PreviousMultiCartRom + Event::ToggleSAPortOrder, Event::PreviousMultiCartRom, + Event::PreviousSettingGroup, Event::NextSettingGroup, + Event::PreviousSetting, Event::NextSetting, + Event::SettingDecrease, Event::SettingIncrease, }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -2435,8 +2609,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 5d82e31b8..324b1fb5d 100644 --- a/src/emucore/EventHandler.hxx +++ b/src/emucore/EventHandler.hxx @@ -420,15 +420,45 @@ class EventHandler NTSC_ARTIFACTS, NTSC_FRINGING, NTSC_BLEEDING, + // Other TV effects adjustables PHOSPHOR, SCANLINES, INTERPOLATION, - MAX_ADJ = INTERPOLATION, // Only used via direct hotkeys STATE, PALETTE_CHANGE_ATTRIBUTE, NTSC_CHANGE_ATTRIBUTE, - NUM_ADJ + // Debug + 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, + // 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: @@ -459,6 +489,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); @@ -470,10 +501,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}; @@ -525,7 +556,7 @@ class EventHandler #else REFRESH_SIZE = 0, #endif - EMUL_ACTIONLIST_SIZE = 157 + PNG_SIZE + COMBO_SIZE + REFRESH_SIZE, + EMUL_ACTIONLIST_SIZE = 159 + PNG_SIZE + COMBO_SIZE + REFRESH_SIZE, MENU_ACTIONLIST_SIZE = 18 ; diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 6ae234fa0..2f4626968 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -634,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")); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index 544c8c6c1..58d61dfd3 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -171,7 +171,7 @@ class FrameBuffer /** Toggles showing or hiding framerate statistics. */ - void toggleFrameStats(); + void toggleFrameStats(bool toggle = true); /** Shows a message containing frame statistics for the current frame. diff --git a/src/emucore/tia/TIA.cxx b/src/emucore/tia/TIA.cxx index 6d3461c4c..b3a48c335 100644 --- a/src/emucore/tia/TIA.cxx +++ b/src/emucore/tia/TIA.cxx @@ -1029,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; @@ -1047,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; } @@ -1068,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; @@ -1086,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; } @@ -1207,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. From 279b68cb84cee9875a3334075069ebe8ed2b6479 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Fri, 3 Jul 2020 18:17:11 +0200 Subject: [PATCH 330/377] reordered and grouped event handling --- src/emucore/EventHandler.cxx | 420 ++++++++++++++++++----------------- src/emucore/EventHandler.hxx | 13 +- 2 files changed, 222 insertions(+), 211 deletions(-) diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 53b1eee7a..536b33e65 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -448,10 +448,6 @@ 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), - // 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), - std::bind(&TIASurface::changeCurrentNTSCAdjustable, &myOSystem.frameBuffer().tiaSurface(), _1), // Debug settings std::bind(&FrameBuffer::toggleFrameStats, &myOSystem.frameBuffer(), _1), std::bind(&Console::toggleP0Bit, &myOSystem.console(), _1), @@ -471,6 +467,10 @@ AdjustFunction EventHandler::getAdjustSetting(AdjustSetting setting) 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), + std::bind(&TIASurface::changeCurrentNTSCAdjustable, &myOSystem.frameBuffer().tiaSurface(), _1), }; return ADJUST_FUNCTIONS[int(setting)]; @@ -616,20 +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(true); - return; - - case Event::PreviousMultiCartRom: - if(pressed && !repeated) myOSystem.reloadConsole(false); - return; + /////////////////////////////////////////////////////////////////////////// + // Audio & Video events (with global hotkeys) case Event::VolumeDecrease: if(pressed) { @@ -675,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) { @@ -711,72 +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; - #ifdef ADAPTABLE_REFRESH_SUPPORT - case Event::ToggleAdaptRefresh: - if(pressed && !repeated) + case Event::PaletteIncrease: + 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; + myOSystem.frameBuffer().tiaSurface().paletteHandler().cyclePalette(+1); + myAdjustSetting = AdjustSetting::PALETTE; myAdjustActive = true; } return; @@ -852,58 +845,6 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) myAdjustActive = true; } 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; - - 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; - myAdjustActive = true; - } - return; - case Event::PhosphorDecrease: if(pressed) { @@ -931,29 +872,20 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) } return; - case Event::ToggleColorLoss: - if (pressed && !repeated) + case Event::ScanlinesDecrease: + if (pressed) { - myOSystem.console().toggleColorLoss(); - myAdjustSetting = AdjustSetting::COLOR_LOSS; + myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(-1); + myAdjustSetting = AdjustSetting::SCANLINES; myAdjustActive = true; } return; - case Event::PaletteDecrease: - if(pressed && !repeated) + case Event::ScanlinesIncrease: + if (pressed) { - myOSystem.frameBuffer().tiaSurface().paletteHandler().cyclePalette(-1); - myAdjustSetting = AdjustSetting::PALETTE; - myAdjustActive = true; - } - return; - - case Event::PaletteIncrease: - if(pressed && !repeated) - { - myOSystem.frameBuffer().tiaSurface().paletteHandler().cyclePalette(+1); - myAdjustSetting = AdjustSetting::PALETTE; + myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(+1); + myAdjustSetting = AdjustSetting::SCANLINES; myAdjustActive = true; } return; @@ -967,19 +899,75 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) } return; - case Event::ToggleTurbo: - if (pressed && !repeated) myOSystem.console().toggleTurbo(); - return; - - case Event::ToggleJitter: - if (pressed && !repeated) + /////////////////////////////////////////////////////////////////////////// + // Direct key Audio & Video events + case Event::PreviousPaletteAttribute: + if (pressed) { - myOSystem.console().toggleJitter(); - myAdjustSetting = AdjustSetting::JITTER; - myAdjustActive = true; + 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::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 && !repeated) { @@ -989,51 +977,6 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) } 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) - { - 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::ToggleGrabMouse: - if (pressed && !repeated && !myOSystem.frameBuffer().fullScreen()) - myOSystem.frameBuffer().toggleGrabMouse(); - return; - case Event::ToggleP0Collision: if (pressed && !repeated) { @@ -1169,8 +1112,29 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) } 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; @@ -1183,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; @@ -1191,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; @@ -1203,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; @@ -1251,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; @@ -1363,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() @@ -1488,6 +1497,7 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) myOSystem.console().switches().update(); } return; + //////////////////////////////////////////////////////////////////////// case Event::NoType: // Ignore unmapped events diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx index 324b1fb5d..0ff428998 100644 --- a/src/emucore/EventHandler.hxx +++ b/src/emucore/EventHandler.hxx @@ -395,6 +395,7 @@ class EventHandler enum class AdjustSetting { NONE = -1, + // *** Audio & Video group *** VOLUME, ZOOM, FULLSCREEN, @@ -424,11 +425,7 @@ class EventHandler PHOSPHOR, SCANLINES, INTERPOLATION, - // Only used via direct hotkeys - STATE, - PALETTE_CHANGE_ATTRIBUTE, - NTSC_CHANGE_ATTRIBUTE, - // Debug + // *** Debug group *** STATS, P0_ENAM, P1_ENAM, @@ -447,7 +444,11 @@ class EventHandler FIXED_COL, COLOR_LOSS, JITTER, - // Ranges + // *** Only used via direct hotkeys *** + STATE, + PALETTE_CHANGE_ATTRIBUTE, + NTSC_CHANGE_ATTRIBUTE, + // *** Ranges *** NUM_ADJ, START_AV_ADJ = VOLUME, END_AV_ADJ = INTERPOLATION, From f6f7f064b1fe108400b2e8de5fd08ae19d9cd5b6 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Fri, 3 Jul 2020 14:46:57 -0230 Subject: [PATCH 331/377] Moved 'max ROM size' function to more appropriate place. --- src/common/bspf.hxx | 3 --- src/emucore/Cart.hxx | 3 +++ src/emucore/FSNode.cxx | 5 +++-- src/libretro/FSNodeLIBRETRO.cxx | 3 ++- src/libretro/StellaLIBRETRO.hxx | 3 ++- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/common/bspf.hxx b/src/common/bspf.hxx index a887bf80a..5201ef2ff 100644 --- a/src/common/bspf.hxx +++ b/src/common/bspf.hxx @@ -128,9 +128,6 @@ namespace BSPF static const string ARCH = "NOARCH"; #endif - // Maximum size of a ROM that Stella can support - inline constexpr size_t romMaxSize() { return 512_KB; } - // 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; diff --git a/src/emucore/Cart.hxx b/src/emucore/Cart.hxx index 8ccd10d79..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 diff --git a/src/emucore/FSNode.cxx b/src/emucore/FSNode.cxx index 0d9e53ad1..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" @@ -237,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(BSPF::romMaxSize()); + image = make_unique(Cartridge::maxSize()); ifstream in(getPath(), std::ios::binary); if (in) { @@ -248,7 +249,7 @@ size_t FilesystemNode::read(ByteBuffer& image) const if (length == 0) throw runtime_error("Zero-byte file"); - size = std::min(length, BSPF::romMaxSize()); + size = std::min(length, Cartridge::maxSize()); in.read(reinterpret_cast(image.get()), size); } else diff --git a/src/libretro/FSNodeLIBRETRO.cxx b/src/libretro/FSNodeLIBRETRO.cxx index 8c242391b..f3670f0a2 100644 --- a/src/libretro/FSNodeLIBRETRO.cxx +++ b/src/libretro/FSNodeLIBRETRO.cxx @@ -16,6 +16,7 @@ //============================================================================ #include "bspf.hxx" +#include "Cart.hxx" #include "FSNodeLIBRETRO.hxx" #ifdef _WIN32 @@ -93,7 +94,7 @@ AbstractFSNodePtr FilesystemNodeLIBRETRO::getParent() const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - size_t FilesystemNodeLIBRETRO::read(ByteBuffer& image) const { - image = make_unique(BSPF::romMaxSize()); + image = make_unique(Cartridge::maxSize()); extern uInt32 libretro_read_rom(void* data); return libretro_read_rom(image.get()); diff --git a/src/libretro/StellaLIBRETRO.hxx b/src/libretro/StellaLIBRETRO.hxx index 01c2cbaf7..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" @@ -59,7 +60,7 @@ class StellaLIBRETRO void* getROM() const { return rom_image.get(); } uInt32 getROMSize() const { return rom_size; } - constexpr uInt32 getROMMax() const { return BSPF::romMaxSize(); } + constexpr uInt32 getROMMax() const { return Cartridge::maxSize(); } uInt8* getRAM() { return system_ram; } constexpr uInt32 getRAMSize() const { return 128; } From b2eb5c9aff3d5e80ae0dc2d0563f425a49ee1a43 Mon Sep 17 00:00:00 2001 From: Thomas Jentzsch Date: Sat, 4 Jul 2020 10:31:16 +0200 Subject: [PATCH 332/377] added numpad keys as defaults for global hotkeys --- src/emucore/EventHandler.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 536b33e65..b979a18c6 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -506,7 +506,8 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) switch(event) { //////////////////////////////////////////////////////////////////////// - // Allow adjusting several (mostly repeated) settings using the same four hotkeys + // Allow adjusting several (mostly repeated) settings using the same six hotkeys + case Event::PreviousSettingGroup: case Event::NextSettingGroup: if (pressed && !repeated) From 1ad3b286b6666b84c4bd4cf93de79f5d5af479fc Mon Sep 17 00:00:00 2001 From: Thomas Jentzsch Date: Sat, 4 Jul 2020 10:31:42 +0200 Subject: [PATCH 333/377] added numpad keys as defaults for global hotkeys --- src/common/PKeyboardHandler.cxx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index 59beffdac..a24ea1d54 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -508,13 +508,20 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo {Event::PreviousSettingGroup, KBDK_END, KBDM_CTRL}, {Event::NextSettingGroup, KBDK_HOME, KBDM_CTRL}, #else + // HOME & END keys are swapped on Mac keyboards {Event::PreviousSetting, KBDK_HOME}, {Event::NextSetting, KBDK_END}, {Event::PreviousSettingGroup, KBDK_HOME, KBDM_CTRL}, {Event::NextSettingGroup, KBDK_END, KBDM_CTRL}, #endif + {Event::PreviousSetting, KBDK_KP_1}, + {Event::NextSetting, KBDK_KP_7}, + {Event::PreviousSettingGroup, KBDK_KP_1, KBDM_CTRL}, + {Event::NextSettingGroup, KBDK_KP_7, KBDM_CTRL}, {Event::SettingDecrease, KBDK_PAGEDOWN}, + {Event::SettingDecrease, KBDK_KP_3}, {Event::SettingIncrease, KBDK_PAGEUP}, + {Event::SettingIncrease, KBDK_KP_9}, {Event::ToggleInter, KBDK_I, KBDM_CTRL}, {Event::ToggleTurbo, KBDK_T, KBDM_CTRL}, From 2549188d3f0022a21a48e6d48e09bf00e10ab7ea Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Mon, 13 Jul 2020 18:54:52 -0230 Subject: [PATCH 334/377] Add ability to use .pro file stored in a ZIP file (containing the ROM, with the same name). --- Changes.txt | 9 +++++++-- src/common/FSNodeZIP.cxx | 13 +++++++++++++ src/common/FSNodeZIP.hxx | 1 + src/emucore/FSNode.cxx | 42 ++++++++++++++++++++++++++++++++++++---- src/emucore/FSNode.hxx | 22 +++++++++++++++++++++ src/emucore/OSystem.cxx | 6 +++--- src/emucore/OSystem.hxx | 2 +- src/emucore/PropsSet.cxx | 25 ++++++++++++++++-------- src/emucore/PropsSet.hxx | 8 ++++---- 9 files changed, 106 insertions(+), 22 deletions(-) diff --git a/Changes.txt b/Changes.txt index cc1ca3b3b..76bc53cc4 100644 --- a/Changes.txt +++ b/Changes.txt @@ -18,6 +18,13 @@ * Extended global hotkeys for debug options. + * Added ability to load per-ROM properties file from a ZIP file containing + the ROM. This allows to distribute ROM and properties in one file, + which Stella can use directly. + +-Have fun! + + 6.2 to 6.2.1: (June 20, 2020) * Fixed Pitfall II ROM not working correctly. @@ -61,8 +68,6 @@ * The codebase now compiles under gcc6 again. Future versions will require gcc7, though. --Have fun! - 6.1.2 to 6.2: (June 7, 2020) diff --git a/src/common/FSNodeZIP.cxx b/src/common/FSNodeZIP.cxx index c5ace0f95..50e84ab3f 100644 --- a/src/common/FSNodeZIP.cxx +++ b/src/common/FSNodeZIP.cxx @@ -184,6 +184,19 @@ size_t FilesystemNodeZIP::read(ByteBuffer& image) const return found ? uInt32(myZipHandler->decompress(image)) : 0; // TODO: 64bit } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +size_t FilesystemNodeZIP::read(stringstream& image) const +{ + // For now, we just read into a buffer and store in the stream + // TODO: maybe there's a more efficient way to do this? + ByteBuffer buffer; + size_t size = read(buffer); + if(size > 0) + image.write(reinterpret_cast(buffer.get()), size); + + return size; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - AbstractFSNodePtr FilesystemNodeZIP::getParent() const { diff --git a/src/common/FSNodeZIP.hxx b/src/common/FSNodeZIP.hxx index 2a46afb4b..b2ae18f43 100644 --- a/src/common/FSNodeZIP.hxx +++ b/src/common/FSNodeZIP.hxx @@ -63,6 +63,7 @@ class FilesystemNodeZIP : public AbstractFSNode AbstractFSNodePtr getParent() const override; size_t read(ByteBuffer& image) const override; + size_t read(stringstream& image) const override; private: FilesystemNodeZIP(const string& zipfile, const string& virtualpath, diff --git a/src/emucore/FSNode.cxx b/src/emucore/FSNode.cxx index e9da05b03..633eb6eaf 100644 --- a/src/emucore/FSNode.cxx +++ b/src/emucore/FSNode.cxx @@ -225,7 +225,7 @@ bool FilesystemNode::rename(const string& newfile) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -size_t FilesystemNode::read(ByteBuffer& image) const +size_t FilesystemNode::read(ByteBuffer& buffer) const { size_t size = 0; @@ -234,11 +234,11 @@ size_t FilesystemNode::read(ByteBuffer& image) const throw runtime_error("File not found/readable"); // First let the private subclass attempt to open the file - if (_realNode && (size = _realNode->read(image)) > 0) + if (_realNode && (size = _realNode->read(buffer)) > 0) return size; // Otherwise, the default behaviour is to read from a normal C++ ifstream - image = make_unique(Cartridge::maxSize()); + buffer = make_unique(Cartridge::maxSize()); ifstream in(getPath(), std::ios::binary); if (in) { @@ -250,7 +250,41 @@ size_t FilesystemNode::read(ByteBuffer& image) const throw runtime_error("Zero-byte file"); size = std::min(length, Cartridge::maxSize()); - in.read(reinterpret_cast(image.get()), size); + in.read(reinterpret_cast(buffer.get()), size); + } + else + throw runtime_error("File open/read error"); + + return size; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +size_t FilesystemNode::read(stringstream& buffer) const +{ + size_t size = 0; + + // File must actually exist + if (!(exists() && isReadable())) + throw runtime_error("File not found/readable"); + + // First let the private subclass attempt to open the file + if (_realNode && (size = _realNode->read(buffer)) > 0) + return size; + + // Otherwise, the default behaviour is to read from a normal C++ ifstream + // and convert to a stringstream + ifstream in(getPath(), std::ios::binary); + if (in) + { + in.seekg(0, std::ios::end); + std::streampos length = in.tellg(); + in.seekg(0, std::ios::beg); + + if (length == 0) + throw runtime_error("Zero-byte file"); + + size = std::min(length, Cartridge::maxSize()); + buffer << in.rdbuf(); } else throw runtime_error("File open/read error"); diff --git a/src/emucore/FSNode.hxx b/src/emucore/FSNode.hxx index 16360cafe..66a80ead1 100644 --- a/src/emucore/FSNode.hxx +++ b/src/emucore/FSNode.hxx @@ -241,6 +241,17 @@ class FilesystemNode */ size_t read(ByteBuffer& buffer) const; + /** + * Read data (text format) into the given stream. + * + * @param buffer The buffer stream to contain the data. + * + * @return The number of bytes read (0 in the case of failure) + * This method can throw exceptions, and should be used inside + * a try-catch block. + */ + size_t read(stringstream& buffer) const; + /** * The following methods are almost exactly the same as the various * getXXXX() methods above. Internally, they call the respective methods @@ -400,6 +411,17 @@ class AbstractFSNode * a try-catch block. */ virtual size_t read(ByteBuffer& buffer) const { return 0; } + + /** + * Read data (text format) into the given steam. + * + * @param buffer The buffer stream to containing the data + * + * @return The number of bytes read (0 in the case of failure) + * This method can throw exceptions, and should be used inside + * a try-catch block. + */ + virtual size_t read(stringstream& buffer) const { return 0; } }; #endif diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index 0d1364790..8a5a16965 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -132,7 +132,7 @@ bool OSystem::create() << FilesystemNode(myConfigFile).getShortPath() << "'" << endl; buf << "Game properties: '" - << FilesystemNode(myPropertiesFile).getShortPath() << "'" << endl + << myPropertiesFile.getShortPath() << "'" << endl << "Cheat file: '" << FilesystemNode(myCheatFile).getShortPath() << "'" << endl << "Palette file: '" @@ -251,7 +251,7 @@ void OSystem::saveConfig() Logger::debug("Saving config options ..."); mySettings->save(); - if(myPropSet && myPropSet->save(myPropertiesFile)) + if(myPropSet && myPropSet->save(myPropertiesFile.getPath())) Logger::debug("Saving properties set ..."); } @@ -286,7 +286,7 @@ void OSystem::setConfigPaths() myCheatFile = FilesystemNode(myBaseDir + "stella.cht").getPath(); myPaletteFile = FilesystemNode(myBaseDir + "stella.pal").getPath(); - myPropertiesFile = FilesystemNode(myBaseDir + "stella.pro").getPath(); + myPropertiesFile = FilesystemNode(myBaseDir + "stella.pro"); #if 0 // Debug code diff --git a/src/emucore/OSystem.hxx b/src/emucore/OSystem.hxx index 4958efead..baebd3375 100644 --- a/src/emucore/OSystem.hxx +++ b/src/emucore/OSystem.hxx @@ -545,7 +545,7 @@ class OSystem string myCheatFile; string myConfigFile; string myPaletteFile; - string myPropertiesFile; + FilesystemNode myPropertiesFile; FilesystemNode myRomFile; string myRomMD5; diff --git a/src/emucore/PropsSet.cxx b/src/emucore/PropsSet.cxx index a74a999e7..ce5a34840 100644 --- a/src/emucore/PropsSet.cxx +++ b/src/emucore/PropsSet.cxx @@ -24,13 +24,21 @@ #include "PropsSet.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PropertiesSet::load(const string& filename, bool save) +void PropertiesSet::load(const FilesystemNode& file, bool save) { - ifstream in(filename); - - Properties prop; - while(in >> prop) - insert(prop, save); + try + { + stringstream in; + if(file.exists() && file.read(in) > 0) + { + Properties prop; + while(in >> prop) + insert(prop, save); + } + } + catch(...) + { + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -166,8 +174,9 @@ void PropertiesSet::loadPerROM(const FilesystemNode& rom, const string& md5) // First, does this ROM have a per-ROM properties entry? // If so, load it into the database FilesystemNode propsNode(rom.getPathWithExt(".pro")); - if(propsNode.exists() && propsNode.isFile()) - load(propsNode.getPath(), false); + + if(propsNode.exists()) + load(propsNode, false); // Next, make sure we have a valid md5 and name Properties props; diff --git a/src/emucore/PropsSet.hxx b/src/emucore/PropsSet.hxx index f5a763ef8..6ecd993b3 100644 --- a/src/emucore/PropsSet.hxx +++ b/src/emucore/PropsSet.hxx @@ -48,11 +48,11 @@ class PropertiesSet Load properties from the specified file, and create an internal searchable list. - @param filename Full pathname of input file to use - @param save Indicates whether the properties should be saved - when the program exits + @param file The node representing the input file to use + @param save Indicates whether the properties should be saved + when the program exits */ - void load(const string& filename, bool save = true); + void load(const FilesystemNode& file, bool save = true); /** Save properties to the specified file. From cc3fe461a3aa7ee198bae2d835667ea8ecec781a Mon Sep 17 00:00:00 2001 From: Thomas Jentzsch Date: Thu, 16 Jul 2020 17:25:33 +0200 Subject: [PATCH 335/377] Prevent enabling phosphor when cycling through global options (fixes #672) --- src/emucore/Console.cxx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 1f828ee94..be2907fe9 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -525,8 +525,11 @@ void Console::changePhosphor(int direction) { int blend = BSPF::stringToInt(myProperties.get(PropType::Display_PPBlend)); - blend = BSPF::clamp(blend + direction * 2, 0, 100); - myOSystem.frameBuffer().tiaSurface().enablePhosphor(true, blend); + if(direction) + { + blend = BSPF::clamp(blend + direction * 2, 0, 100); + myOSystem.frameBuffer().tiaSurface().enablePhosphor(true, blend); + } ostringstream val; val << blend; From 33d2e5a7aca1d35d4d1418ac942fe63a97bef559 Mon Sep 17 00:00:00 2001 From: Thomas Jentzsch Date: Thu, 16 Jul 2020 19:35:36 +0200 Subject: [PATCH 336/377] minor hotkey fix (avoids mapping clash) --- src/common/PKeyboardHandler.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index a24ea1d54..884ee594a 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -519,9 +519,9 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo {Event::PreviousSettingGroup, KBDK_KP_1, KBDM_CTRL}, {Event::NextSettingGroup, KBDK_KP_7, KBDM_CTRL}, {Event::SettingDecrease, KBDK_PAGEDOWN}, - {Event::SettingDecrease, KBDK_KP_3}, + {Event::SettingDecrease, KBDK_KP_3, KBDM_CTRL}, {Event::SettingIncrease, KBDK_PAGEUP}, - {Event::SettingIncrease, KBDK_KP_9}, + {Event::SettingIncrease, KBDK_KP_9, KBDM_CTRL}, {Event::ToggleInter, KBDK_I, KBDM_CTRL}, {Event::ToggleTurbo, KBDK_T, KBDM_CTRL}, From 8b5c13feb4cf7e3d51cb7807daa69d67a0317a63 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Thu, 16 Jul 2020 21:20:50 -0230 Subject: [PATCH 337/377] Begin the process of converting all file open/close operations to be done in FSNode. This will eventually allow ZIP files (and any other compression scheme we use in the future) to read and write as if they were normal files. Basically an implementation of a mini-VFS. --- src/common/FSNodeZIP.cxx | 16 +++++++- src/common/FSNodeZIP.hxx | 2 + src/debugger/CartDebug.cxx | 3 +- src/emucore/Cart.cxx | 22 ++++++---- src/emucore/Cart.hxx | 5 ++- src/emucore/FSNode.cxx | 84 +++++++++++++++++++++++++++++--------- src/emucore/FSNode.hxx | 83 ++++++++++++++++++++++++------------- src/emucore/OSystem.cxx | 2 +- src/emucore/PropsSet.cxx | 34 +++++++++------ src/emucore/PropsSet.hxx | 4 +- 10 files changed, 179 insertions(+), 76 deletions(-) diff --git a/src/common/FSNodeZIP.cxx b/src/common/FSNodeZIP.cxx index 50e84ab3f..c49f8359f 100644 --- a/src/common/FSNodeZIP.cxx +++ b/src/common/FSNodeZIP.cxx @@ -181,7 +181,7 @@ size_t FilesystemNodeZIP::read(ByteBuffer& image) const while(myZipHandler->hasNext() && !found) found = myZipHandler->next() == _virtualPath; - return found ? uInt32(myZipHandler->decompress(image)) : 0; // TODO: 64bit + return found ? myZipHandler->decompress(image) : 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -197,6 +197,20 @@ size_t FilesystemNodeZIP::read(stringstream& image) const return size; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +size_t FilesystemNodeZIP::write(const ByteBuffer& buffer, size_t size) const +{ + // TODO: Not yet implemented + throw runtime_error("ZIP file not writable"); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +size_t FilesystemNodeZIP::write(const stringstream& buffer) const +{ + // TODO: Not yet implemented + throw runtime_error("ZIP file not writable"); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - AbstractFSNodePtr FilesystemNodeZIP::getParent() const { diff --git a/src/common/FSNodeZIP.hxx b/src/common/FSNodeZIP.hxx index b2ae18f43..de8904315 100644 --- a/src/common/FSNodeZIP.hxx +++ b/src/common/FSNodeZIP.hxx @@ -64,6 +64,8 @@ class FilesystemNodeZIP : public AbstractFSNode size_t read(ByteBuffer& image) const override; size_t read(stringstream& image) const override; + size_t write(const ByteBuffer& buffer, size_t size) const override; + size_t write(const stringstream& buffer) const override; private: FilesystemNodeZIP(const string& zipfile, const string& virtualpath, diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index 3198eb9ea..228e7b5d0 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -1347,8 +1347,7 @@ string CartDebug::saveRom() const string& rom = myConsole.properties().get(PropType::Cart_Name) + ".a26"; FilesystemNode node(myOSystem.defaultSaveDir() + rom); - ofstream out(node.getPath(), std::ios::binary); - if(out && myConsole.cartridge().saveROM(out)) + if(myConsole.cartridge().saveROM(node)) return "saved ROM as " + node.getShortPath(); else return DebuggerParser::red("failed to save ROM"); diff --git a/src/emucore/Cart.cxx b/src/emucore/Cart.cxx index 045d4c784..d4b5c5c22 100644 --- a/src/emucore/Cart.cxx +++ b/src/emucore/Cart.cxx @@ -15,6 +15,7 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include "FSNode.hxx" #include "Settings.hxx" #include "System.hxx" #include "MD5.hxx" @@ -52,19 +53,24 @@ void Cartridge::setAbout(const string& about, const string& type, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Cartridge::saveROM(ofstream& out) const +bool Cartridge::saveROM(const FilesystemNode& out) const { - size_t size = 0; - - const ByteBuffer& image = getImage(size); - if(size == 0) + try + { + size_t size = 0; + const ByteBuffer& image = getImage(size); + if(size == 0) + { + cerr << "save not supported" << endl; + return false; + } + out.write(image, size); + } + catch(...) { - cerr << "save not supported" << endl; return false; } - out.write(reinterpret_cast(image.get()), size); - return true; } diff --git a/src/emucore/Cart.hxx b/src/emucore/Cart.hxx index 8a2e4656e..008135a73 100644 --- a/src/emucore/Cart.hxx +++ b/src/emucore/Cart.hxx @@ -20,6 +20,7 @@ class Cartridge; class Properties; +class FilesystemNode; class CartDebugWidget; class CartRamWidget; class GuiObject; @@ -72,9 +73,9 @@ class Cartridge : public Device /** Save the internal (patched) ROM image. - @param out The output file stream to save the image + @param out The output file to save the image */ - bool saveROM(ofstream& out) const; + bool saveROM(const FilesystemNode& out) const; /** Lock/unlock bankswitching capability. The debugger will lock diff --git a/src/emucore/FSNode.cxx b/src/emucore/FSNode.cxx index 633eb6eaf..590705d03 100644 --- a/src/emucore/FSNode.cxx +++ b/src/emucore/FSNode.cxx @@ -13,12 +13,8 @@ // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. -// -// Based on code from ScummVM - Scumm Interpreter -// Copyright (C) 2002-2004 The ScummVM project //============================================================================ -#include "Cart.hxx" #include "FSNodeFactory.hxx" #include "FSNode.hxx" @@ -227,49 +223,48 @@ bool FilesystemNode::rename(const string& newfile) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - size_t FilesystemNode::read(ByteBuffer& buffer) const { - size_t size = 0; + size_t sizeRead = 0; // File must actually exist if (!(exists() && isReadable())) throw runtime_error("File not found/readable"); // First let the private subclass attempt to open the file - if (_realNode && (size = _realNode->read(buffer)) > 0) - return size; + if (_realNode && (sizeRead = _realNode->read(buffer)) > 0) + return sizeRead; // Otherwise, the default behaviour is to read from a normal C++ ifstream - buffer = make_unique(Cartridge::maxSize()); ifstream in(getPath(), std::ios::binary); if (in) { in.seekg(0, std::ios::end); - std::streampos length = in.tellg(); + sizeRead = static_cast(in.tellg()); in.seekg(0, std::ios::beg); - if (length == 0) + if (sizeRead == 0) throw runtime_error("Zero-byte file"); - size = std::min(length, Cartridge::maxSize()); - in.read(reinterpret_cast(buffer.get()), size); + buffer = make_unique(sizeRead); + in.read(reinterpret_cast(buffer.get()), sizeRead); } else throw runtime_error("File open/read error"); - return size; + return sizeRead; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - size_t FilesystemNode::read(stringstream& buffer) const { - size_t size = 0; + size_t sizeRead = 0; // File must actually exist if (!(exists() && isReadable())) throw runtime_error("File not found/readable"); // First let the private subclass attempt to open the file - if (_realNode && (size = _realNode->read(buffer)) > 0) - return size; + if (_realNode && (sizeRead = _realNode->read(buffer)) > 0) + return sizeRead; // Otherwise, the default behaviour is to read from a normal C++ ifstream // and convert to a stringstream @@ -277,17 +272,66 @@ size_t FilesystemNode::read(stringstream& buffer) const if (in) { in.seekg(0, std::ios::end); - std::streampos length = in.tellg(); + sizeRead = static_cast(in.tellg()); in.seekg(0, std::ios::beg); - if (length == 0) + if (sizeRead == 0) throw runtime_error("Zero-byte file"); - size = std::min(length, Cartridge::maxSize()); buffer << in.rdbuf(); } else throw runtime_error("File open/read error"); - return size; + return sizeRead; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +size_t FilesystemNode::write(const ByteBuffer& buffer, size_t size) const +{ + size_t sizeWritten = 0; + + // First let the private subclass attempt to open the file + if (_realNode && (sizeWritten = _realNode->write(buffer, size)) > 0) + return sizeWritten; + + // Otherwise, the default behaviour is to write to a normal C++ ofstream + ofstream out(getPath(), std::ios::binary); + if (out) + { + out.write(reinterpret_cast(buffer.get()), size); + + out.seekp(0, std::ios::end); + sizeWritten = static_cast(out.tellp()); + out.seekp(0, std::ios::beg); + } + else + throw runtime_error("File open/write error"); + + return sizeWritten; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +size_t FilesystemNode::write(const stringstream& buffer) const +{ + size_t sizeWritten = 0; + + // First let the private subclass attempt to open the file + if (_realNode && (sizeWritten = _realNode->write(buffer)) > 0) + return sizeWritten; + + // Otherwise, the default behaviour is to write to a normal C++ ofstream + ofstream out(getPath(), std::ios::binary); + if (out) + { + out << buffer.rdbuf(); + + out.seekp(0, std::ios::end); + sizeWritten = static_cast(out.tellp()); + out.seekp(0, std::ios::beg); + } + else + throw runtime_error("File open/write error"); + + return sizeWritten; } diff --git a/src/emucore/FSNode.hxx b/src/emucore/FSNode.hxx index 66a80ead1..f965eaa10 100644 --- a/src/emucore/FSNode.hxx +++ b/src/emucore/FSNode.hxx @@ -13,42 +13,24 @@ // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. -// -// Based on code from ScummVM - Scumm Interpreter -// Copyright (C) 2002-2004 The ScummVM project //============================================================================ #ifndef FS_NODE_HXX #define FS_NODE_HXX +#include + #include "bspf.hxx" /* * The API described in this header is meant to allow for file system browsing in a - * portable fashions. To this ends, multiple or single roots have to be supported + * portable fashion. To this end, multiple or single roots have to be supported * (compare Unix with a single root, Windows with multiple roots C:, D:, ...). * * To this end, we abstract away from paths; implementations can be based on - * paths (and it's left to them whether / or \ or : is the path separator :-); - * but it is also possible to use inodes or vrefs (MacOS 9) or anything else. - * - * You may ask now: "isn't this cheating? Why do we go through all this when we use - * a path in the end anyway?!?". - * Well, for once as long as we don't provide our own file open/read/write API, we - * still have to use fopen(). Since all our targets already support fopen(), it should - * be possible to get a fopen() compatible string for any file system node. - * - * Secondly, with this abstraction layer, we still avoid a lot of complications based on - * differences in FS roots, different path separators, or even systems with no real - * paths (MacOS 9 doesn't even have the notion of a "current directory"). - * And if we ever want to support devices with no FS in the classical sense (Palm...), - * we can build upon this. + * paths (and it's left to them whether / or \ or : is the path separator :-). */ -#include - -#include "bspf.hxx" - class FilesystemNode; class AbstractFSNode; using AbstractFSNodePtr = shared_ptr; @@ -233,7 +215,7 @@ class FilesystemNode /** * Read data (binary format) into the given buffer. * - * @param buffer The buffer to contain the data. + * @param buffer The buffer to contain the data (allocated in this method). * * @return The number of bytes read (0 in the case of failure) * This method can throw exceptions, and should be used inside @@ -252,6 +234,29 @@ class FilesystemNode */ size_t read(stringstream& buffer) const; + /** + * Write data (binary format) from the given buffer. + * + * @param buffer The buffer that contains the data. + * @param size The size of the buffer. + * + * @return The number of bytes written (0 in the case of failure) + * This method can throw exceptions, and should be used inside + * a try-catch block. + */ + size_t write(const ByteBuffer& buffer, size_t size) const; + + /** + * Write data (text format) from the given stream. + * + * @param buffer The buffer stream that contains the data. + * + * @return The number of bytes written (0 in the case of failure) + * This method can throw exceptions, and should be used inside + * a try-catch block. + */ + size_t write(const stringstream& buffer) const; + /** * The following methods are almost exactly the same as the various * getXXXX() methods above. Internally, they call the respective methods @@ -403,9 +408,8 @@ class AbstractFSNode /** * Read data (binary format) into the given buffer. * - * @param buffer The buffer to containing the data - * This will be allocated by the method, and must be - * freed by the caller. + * @param buffer The buffer to contain the data (allocated in this method). + * * @return The number of bytes read (0 in the case of failure) * This method can throw exceptions, and should be used inside * a try-catch block. @@ -413,15 +417,38 @@ class AbstractFSNode virtual size_t read(ByteBuffer& buffer) const { return 0; } /** - * Read data (text format) into the given steam. + * Read data (text format) into the given stream. * - * @param buffer The buffer stream to containing the data + * @param buffer The buffer stream to contain the data. * * @return The number of bytes read (0 in the case of failure) * This method can throw exceptions, and should be used inside * a try-catch block. */ virtual size_t read(stringstream& buffer) const { return 0; } + + /** + * Write data (binary format) from the given buffer. + * + * @param buffer The buffer that contains the data. + * @param size The size of the buffer. + * + * @return The number of bytes written (0 in the case of failure) + * This method can throw exceptions, and should be used inside + * a try-catch block. + */ + virtual size_t write(const ByteBuffer& buffer, size_t size) const { return 0; } + + /** + * Write data (text format) from the given stream. + * + * @param buffer The buffer stream that contains the data. + * + * @return The number of bytes written (0 in the case of failure) + * This method can throw exceptions, and should be used inside + * a try-catch block. + */ + virtual size_t write(const stringstream& buffer) const { return 0; } }; #endif diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index 8a5a16965..f6f13f05e 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -251,7 +251,7 @@ void OSystem::saveConfig() Logger::debug("Saving config options ..."); mySettings->save(); - if(myPropSet && myPropSet->save(myPropertiesFile.getPath())) + if(myPropSet && myPropSet->save(myPropertiesFile)) Logger::debug("Saving properties set ..."); } diff --git a/src/emucore/PropsSet.cxx b/src/emucore/PropsSet.cxx index ce5a34840..65bae06bd 100644 --- a/src/emucore/PropsSet.cxx +++ b/src/emucore/PropsSet.cxx @@ -19,6 +19,7 @@ #include "bspf.hxx" #include "FSNode.hxx" +#include "Logger.hxx" #include "DefProps.hxx" #include "Props.hxx" #include "PropsSet.hxx" @@ -42,22 +43,31 @@ void PropertiesSet::load(const FilesystemNode& file, bool save) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool PropertiesSet::save(const string& filename) const +bool PropertiesSet::save(const FilesystemNode& file) const { - // Only save properties when it won't create an empty file - FilesystemNode props(filename); - if(!props.exists() && myExternalProps.size() == 0) - return false; + try + { + // Only save properties when it won't create an empty file + if(!file.exists() && myExternalProps.size() == 0) + return false; - ofstream out(filename); - if(!out) - return false; + // Only save those entries in the external list + stringstream out; + for(const auto& i: myExternalProps) + out << i.second; - // Only save those entries in the external list - for(const auto& i: myExternalProps) - out << i.second; + file.write(out); + return true; + } + catch(const runtime_error& e) + { + Logger::error(e.what()); + } + catch(...) + { + } - return true; + return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/PropsSet.hxx b/src/emucore/PropsSet.hxx index 6ecd993b3..387b79bda 100644 --- a/src/emucore/PropsSet.hxx +++ b/src/emucore/PropsSet.hxx @@ -57,14 +57,14 @@ class PropertiesSet /** Save properties to the specified file. - @param filename Full pathname of output file to use + @param file The node representing the output file to use @return True on success, false on failure or save not needed Failure occurs if file couldn't be opened for writing, or if the file doesn't exist and a zero-byte file would be created */ - bool save(const string& filename) const; + bool save(const FilesystemNode& file) const; /** Get the property from the set with the given MD5. From 63ca43a35effc0a147bb9c89d793b1b8170c3a70 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sat, 18 Jul 2020 15:26:42 -0230 Subject: [PATCH 338/377] Converted CartDebug to use new FSNode I/O. This means we can load from sym/list files stored in a ZIP file. --- src/debugger/CartDebug.cxx | 185 ++++++++++++++++-------------- src/debugger/CartDebug.hxx | 3 - src/debugger/gui/PromptWidget.cxx | 8 +- 3 files changed, 102 insertions(+), 94 deletions(-) diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index 228e7b5d0..bf55f35a9 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -734,19 +734,20 @@ string CartDebug::loadListFile() // The default naming/location for list files is the ROM dir based on the // actual ROM filename - if(myListFile == "") - { - FilesystemNode lst(myOSystem.romFile().getPathWithExt(".lst")); - if(lst.isFile() && lst.isReadable()) - myListFile = lst.getPath(); - else - return DebuggerParser::red("list file \'" + lst.getShortPath() + "\' not found"); - } + FilesystemNode lst(myOSystem.romFile().getPathWithExt(".lst")); + if(!lst.isReadable()) + return DebuggerParser::red("list file \'" + lst.getShortPath() + "\' not found"); - FilesystemNode node(myListFile); - ifstream in(node.getPath()); - if(!in.is_open()) - return DebuggerParser::red("list file '" + node.getShortPath() + "' not readable"); + stringstream in; + try + { + if(lst.read(in) == 0) + return DebuggerParser::red("list file '" + lst.getShortPath() + "' not readable"); + } + catch(...) + { + return DebuggerParser::red("list file '" + lst.getShortPath() + "' not readable"); + } while(!in.eof()) { @@ -785,7 +786,7 @@ string CartDebug::loadListFile() } myDebugger.rom().invalidate(); - return "list file '" + node.getShortPath() + "' loaded OK"; + return "list file '" + lst.getShortPath() + "' loaded OK"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -794,23 +795,24 @@ string CartDebug::loadSymbolFile() // The default naming/location for symbol files is the ROM dir based on the // actual ROM filename - if(mySymbolFile == "") - { - FilesystemNode sym(myOSystem.romFile().getPathWithExt(".sym")); - if(sym.isFile() && sym.isReadable()) - mySymbolFile = sym.getPath(); - else - return DebuggerParser::red("symbol file \'" + sym.getShortPath() + "\' not found"); - } - - FilesystemNode node(mySymbolFile); - ifstream in(node.getPath()); - if(!in.is_open()) - return DebuggerParser::red("symbol file '" + node.getShortPath() + "' not readable"); + FilesystemNode sym(myOSystem.romFile().getPathWithExt(".sym")); + if(!sym.isReadable()) + return DebuggerParser::red("symbol file \'" + sym.getShortPath() + "\' not found"); myUserAddresses.clear(); myUserLabels.clear(); + stringstream in; + try + { + if(sym.read(in) == 0) + return DebuggerParser::red("symbol file '" + sym.getShortPath() + "' not readable"); + } + catch(...) + { + return DebuggerParser::red("symbol file '" + sym.getShortPath() + "' not readable"); + } + while(!in.eof()) { string label; @@ -845,7 +847,7 @@ string CartDebug::loadSymbolFile() } myDebugger.rom().invalidate(); - return "symbol file '" + node.getShortPath() + "' loaded OK"; + return "symbol file '" + sym.getShortPath() + "' loaded OK"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -854,20 +856,21 @@ string CartDebug::loadConfigFile() // The default naming/location for config files is the CFG dir and based // on the actual ROM filename - if(myCfgFile == "") - { - FilesystemNode romNode(myOSystem.romFile().getPathWithExt(".cfg")); - FilesystemNode cfg(myOSystem.cfgDir() + romNode.getName()); - if(cfg.isFile() && cfg.isReadable()) - myCfgFile = cfg.getPath(); - else - return DebuggerParser::red("config file \'" + cfg.getShortPath() + "\' not found"); - } + FilesystemNode romNode(myOSystem.romFile().getPathWithExt(".cfg")); + FilesystemNode cfg(myOSystem.cfgDir() + romNode.getName()); + if(!cfg.isReadable()) + return DebuggerParser::red("config file \'" + cfg.getShortPath() + "\' not found"); - FilesystemNode node(myCfgFile); - ifstream in(node.getPath()); - if(!in.is_open()) - return "Unable to load directives from " + node.getPath(); + stringstream in; + try + { + if(cfg.read(in) == 0) + return "Unable to load directives from " + cfg.getPath(); + } + catch(...) + { + return "Unable to load directives from " + cfg.getPath(); + } // Erase all previous directives for(auto& bi: myBankInfo) @@ -965,7 +968,7 @@ string CartDebug::loadConfigFile() stringstream retVal; if(myConsole.cartridge().romBankCount() > 1) retVal << DebuggerParser::red("config file for multi-bank ROM not fully supported\n"); - retVal << "config file '" << node.getShortPath() << "' loaded OK"; + retVal << "config file '" << cfg.getShortPath() << "' loaded OK"; return retVal.str(); } @@ -976,25 +979,11 @@ string CartDebug::saveConfigFile() // The default naming/location for config files is the CFG dir and based // on the actual ROM filename - if(myCfgFile == "") - { - FilesystemNode romNode(myOSystem.romFile().getPathWithExt(".cfg")); - FilesystemNode cfg(myOSystem.cfgDir() + romNode.getName()); - if(cfg.getParent().isWritable()) - myCfgFile = cfg.getPath(); - else - return DebuggerParser::red("config file \'" + cfg.getShortPath() + "\' not writable"); - } - const string& name = myConsole.properties().get(PropType::Cart_Name); const string& md5 = myConsole.properties().get(PropType::Cart_MD5); - FilesystemNode cfg(myCfgFile); - ofstream out(cfg.getPath()); - if(!out.is_open()) - return "Unable to save directives to " + cfg.getShortPath(); - // Store all bank information + stringstream out; out << "// Stella.pro: \"" << name << "\"" << endl << "// MD5: " << md5 << endl << endl; @@ -1005,9 +994,25 @@ string CartDebug::saveConfigFile() } stringstream retVal; - if(myConsole.cartridge().romBankCount() > 1) - retVal << DebuggerParser::red("config file for multi-bank ROM not fully supported\n"); - retVal << "config file '" << cfg.getShortPath() << "' saved OK"; + try + { + FilesystemNode romNode(myOSystem.romFile().getPathWithExt(".cfg")); + FilesystemNode cfg(myOSystem.cfgDir() + romNode.getName()); + if(!cfg.getParent().isWritable()) + return DebuggerParser::red("config file \'" + cfg.getShortPath() + "\' not writable"); + + size_t size = cfg.write(out); + if(size == 0) + return "Unable to save directives to " + cfg.getShortPath(); + + if(myConsole.cartridge().romBankCount() > 1) + retVal << DebuggerParser::red("config file for multi-bank ROM not fully supported\n"); + retVal << "config file '" << cfg.getShortPath() << "' saved OK"; + } + catch(const runtime_error& e) + { + retVal << e.what(); + } return retVal.str(); } @@ -1033,19 +1038,6 @@ string CartDebug::saveDisassembly() bool isNTSC = myConsole.timing() == ConsoleTiming::ntsc; bool isPAL = myConsole.timing() == ConsoleTiming::pal; - if(myDisasmFile == "") - { - const string& propsname = - myConsole.properties().get(PropType::Cart_Name) + ".asm"; - - myDisasmFile = FilesystemNode(myOSystem.defaultSaveDir() + propsname).getPath(); - } - - FilesystemNode node(myDisasmFile); - ofstream out(node.getPath()); - if(!out.is_open()) - return "Unable to save disassembly to " + node.getShortPath(); - #define ALIGN(x) setfill(' ') << left << setw(x) // We can't print the header to the disassembly until it's actually @@ -1094,7 +1086,6 @@ string CartDebug::saveDisassembly() buf << " / 0.." << romBankCount - 1; buf << "\n;***********************************************************\n\n"; - // Disassemble bank disasm.list.clear(); DiStella distella(*this, disasm.list, info, settings, @@ -1183,6 +1174,7 @@ string CartDebug::saveDisassembly() // Some boilerplate, similar to what DiStella adds auto timeinfo = BSPF::localTime(); + stringstream out; out << "; Disassembly of " << myOSystem.romFile().getShortPath() << "\n" << "; Disassembled " << std::put_time(&timeinfo, "%c\n") << "; Using Stella " << STELLA_VERSION << "\n;\n" @@ -1335,9 +1327,24 @@ string CartDebug::saveDisassembly() out << buf.str(); stringstream retVal; - if(myConsole.cartridge().romBankCount() > 1) - retVal << DebuggerParser::red("disassembly for multi-bank ROM not fully supported\n"); - retVal << "saved " << node.getShortPath() << " OK"; + try + { + const string& propsname = + myConsole.properties().get(PropType::Cart_Name) + ".asm"; + FilesystemNode node(myOSystem.defaultSaveDir() + propsname); + + size_t size = node.write(out); + if(size == 0) + return "Unable to save disassembly to " + node.getShortPath(); + + if(myConsole.cartridge().romBankCount() > 1) + retVal << DebuggerParser::red("disassembly for multi-bank ROM not fully supported\n"); + retVal << "saved " << node.getShortPath() << " OK"; + } + catch(const runtime_error& e) + { + retVal << e.what(); + } return retVal.str(); } @@ -1356,19 +1363,25 @@ string CartDebug::saveRom() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartDebug::saveAccessFile() { - const string& rom = myConsole.properties().get(PropType::Cart_Name) + ".csv"; - FilesystemNode node(myOSystem.defaultSaveDir() + rom); - ofstream out(node.getPath()); + stringstream out; + out << myConsole.tia().getAccessCounters(); + out << myConsole.riot().getAccessCounters(); + out << myConsole.cartridge().getAccessCounters(); - if(out) + try { - out << myConsole.tia().getAccessCounters(); - out << myConsole.riot().getAccessCounters(); - out << myConsole.cartridge().getAccessCounters(); - return "saved access counters as " + node.getShortPath(); + const string& rom = myConsole.properties().get(PropType::Cart_Name) + ".csv"; + FilesystemNode node(myOSystem.defaultSaveDir() + rom); + + size_t size = node.write(out); + if(size > 0) + return "saved access counters as " + node.getShortPath(); } - else - return DebuggerParser::red("failed to save access counters file"); + catch(const runtime_error& e) + { + return e.what(); + } + return DebuggerParser::red("failed to save access counters file"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/debugger/CartDebug.hxx b/src/debugger/CartDebug.hxx index 486eedd79..10e5be562 100644 --- a/src/debugger/CartDebug.hxx +++ b/src/debugger/CartDebug.hxx @@ -342,9 +342,6 @@ class CartDebug : public DebuggerSystem // The maximum length of all labels currently defined uInt16 myLabelLength{8}; // longest pre-defined label - // Filenames to use for various I/O (currently these are hardcoded) - string myListFile, mySymbolFile, myCfgFile, myDisasmFile; - /// Table of instruction mnemonics static std::array ourTIAMnemonicR; // read mode static std::array ourTIAMnemonicW; // write mode diff --git a/src/debugger/gui/PromptWidget.cxx b/src/debugger/gui/PromptWidget.cxx index eb27f5258..7a1cd56f2 100644 --- a/src/debugger/gui/PromptWidget.cxx +++ b/src/debugger/gui/PromptWidget.cxx @@ -909,10 +909,7 @@ void PromptWidget::scrollToCurrent() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool PromptWidget::saveBuffer(const FilesystemNode& file) { - ofstream out(file.getPath()); - if(!out.is_open()) - return false; - + stringstream out; for(int start = 0; start < _promptStartPos; start += _lineWidth) { int end = start + _lineWidth - 1; @@ -930,7 +927,8 @@ bool PromptWidget::saveBuffer(const FilesystemNode& file) out << endl; } - return true; + try { return file.write(out) > 0; } + catch(...) { return false; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From f4db583d7f9208338387fc0a5a7605d445ee94b9 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 22 Jul 2020 10:29:23 +0200 Subject: [PATCH 339/377] support F12 (snapshot) in TM UI too (implements #679) --- src/gui/TimeMachineDialog.cxx | 9 +++++++++ src/gui/TimeMachineDialog.hxx | 5 +++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/gui/TimeMachineDialog.cxx b/src/gui/TimeMachineDialog.cxx index e84c50223..b8fc3a088 100644 --- a/src/gui/TimeMachineDialog.cxx +++ b/src/gui/TimeMachineDialog.cxx @@ -25,6 +25,7 @@ #include "StateManager.hxx" #include "RewindManager.hxx" #include "TimeLineWidget.hxx" +#include "TIASurface.hxx" #include "Console.hxx" #include "TIA.hxx" @@ -297,6 +298,8 @@ void TimeMachineDialog::handleKeyDown(StellaKey key, StellaMod mod, bool repeate // The following 'Alt' shortcuts duplicate the shortcuts in EventHandler // It is best to keep them the same, so changes in EventHandler mean we // need to update the logic here too + // Note: The hotkeys can be remapped in emulation mode, but this will not + // affect the fixed hotkeys here. if(StellaModTest::isAlt(mod)) { switch(key) @@ -323,6 +326,8 @@ void TimeMachineDialog::handleKeyDown(StellaKey key, StellaMod mod, bool repeate } else if(key == KBDK_SPACE || key == KBDK_ESCAPE) handleCommand(nullptr, kPlay, 0, 0); + else if (key == KBDK_F12) + handleCommand(nullptr, kSnapShot, 0, 0); else Dialog::handleKeyDown(key, mod); } @@ -383,6 +388,10 @@ void TimeMachineDialog::handleCommand(CommandSender* sender, int cmd, initBar(); break; + case kSnapShot: + instance().frameBuffer().tiaSurface().saveSnapShot(); + break; + default: Dialog::handleCommand(sender, cmd, data, 0); } diff --git a/src/gui/TimeMachineDialog.hxx b/src/gui/TimeMachineDialog.hxx index 4d94f006f..45c9dfa06 100644 --- a/src/gui/TimeMachineDialog.hxx +++ b/src/gui/TimeMachineDialog.hxx @@ -65,8 +65,9 @@ class TimeMachineDialog : public Dialog kUnwindAll = 'TMua', kUnwind10 = 'TMu1', kUnwind1 = 'TMun', - kSaveAll = 'TMsv', - kLoadAll = 'TMld', + kSaveAll = 'TMsv', + kLoadAll = 'TMld', + kSnapShot = 'TMsn', }; TimeLineWidget* myTimeline{nullptr}; From 16fe6ffcb252d2adae4bd38c45ee8a8bf17288a4 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 22 Jul 2020 12:03:31 +0200 Subject: [PATCH 340/377] use mapped keys instead of fixed keys in TM UI (resolves #679) --- src/gui/TimeMachineDialog.cxx | 66 ++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/src/gui/TimeMachineDialog.cxx b/src/gui/TimeMachineDialog.cxx index b8fc3a088..f157c67a8 100644 --- a/src/gui/TimeMachineDialog.cxx +++ b/src/gui/TimeMachineDialog.cxx @@ -295,41 +295,51 @@ void TimeMachineDialog::loadConfig() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TimeMachineDialog::handleKeyDown(StellaKey key, StellaMod mod, bool repeated) { - // The following 'Alt' shortcuts duplicate the shortcuts in EventHandler - // It is best to keep them the same, so changes in EventHandler mean we - // need to update the logic here too - // Note: The hotkeys can be remapped in emulation mode, but this will not - // affect the fixed hotkeys here. - if(StellaModTest::isAlt(mod)) + // The following shortcuts duplicate the shortcuts in EventHandler + + Event::Type event = instance().eventHandler().eventForKey(EventMode::kEmulationMode, key, mod); + + switch (event) { - switch(key) - { - case KBDK_LEFT: // Alt-left(-shift) rewinds 1(10) states - handleCommand(nullptr, StellaModTest::isShift(mod) ? kRewind10 : kRewind1, 0, 0); - break; + case Event::Rewind1Menu: + handleCommand(nullptr, kRewind1, 0, 0); + break; - case KBDK_RIGHT: // Alt-right(-shift) unwinds 1(10) states - handleCommand(nullptr, StellaModTest::isShift(mod) ? kUnwind10 : kUnwind1, 0, 0); - break; + case Event::Rewind10Menu: + handleCommand(nullptr, kRewind10, 0, 0); + break; - case KBDK_DOWN: // Alt-down rewinds to start of list - handleCommand(nullptr, kRewindAll, 0, 0); - break; + case Event::RewindAllMenu: + handleCommand(nullptr, kRewindAll, 0, 0); + break; - case KBDK_UP: // Alt-up rewinds to end of list - handleCommand(nullptr, kUnwindAll, 0, 0); - break; + case Event::Unwind1Menu: + handleCommand(nullptr, kUnwind1, 0, 0); + break; - default: + case Event::Unwind10Menu: + handleCommand(nullptr, kUnwind10, 0, 0); + break; + + case Event::UnwindAllMenu: + handleCommand(nullptr, kUnwindAll, 0, 0); + break; + + case Event::TakeSnapshot: + if (!repeated) + handleCommand(nullptr, kSnapShot, 0, 0); + break; + + case Event::ExitMode: + handleCommand(nullptr, kPlay, 0, 0); + break; + + default: + if (key == KBDK_SPACE) + handleCommand(nullptr, kPlay, 0, 0); + else Dialog::handleKeyDown(key, mod); - } } - else if(key == KBDK_SPACE || key == KBDK_ESCAPE) - handleCommand(nullptr, kPlay, 0, 0); - else if (key == KBDK_F12) - handleCommand(nullptr, kSnapShot, 0, 0); - else - Dialog::handleKeyDown(key, mod); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 32f872729c75a145a4697634f3e460173e392294 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 22 Jul 2020 12:11:23 +0200 Subject: [PATCH 341/377] updated doc and changes --- Changes.txt | 2 ++ docs/index.html | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Changes.txt b/Changes.txt index 76bc53cc4..eb4f0a16e 100644 --- a/Changes.txt +++ b/Changes.txt @@ -18,6 +18,8 @@ * Extended global hotkeys for debug options. + * Allow taking snapshots from within Time Machine dialog + * Added ability to load per-ROM properties file from a ZIP file containing the ROM. This allows to distribute ROM and properties in one file, which Stella can use directly. diff --git a/docs/index.html b/docs/index.html index bc3f46f29..9ccde3bd6 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1814,8 +1814,8 @@ - - + + From 2e6bb5aa5727c3e053a7c78731e4e5423ba7debe Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 23 Jul 2020 12:39:22 +0200 Subject: [PATCH 342/377] started adding playback mode (see #678) --- src/common/PKeyboardHandler.cxx | 2 + src/common/RewindManager.cxx | 6 +- src/emucore/Event.hxx | 1 + src/emucore/EventHandler.cxx | 43 +++++++++++-- src/emucore/EventHandler.hxx | 3 +- src/emucore/EventHandlerConstants.hxx | 1 + src/emucore/FrameBuffer.cxx | 40 ++++++++++++ src/emucore/OSystem.cxx | 1 + src/gui/TimeMachineDialog.cxx | 87 ++++++++++++++++++++------- src/gui/TimeMachineDialog.hxx | 7 ++- 10 files changed, 160 insertions(+), 31 deletions(-) diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index 884ee594a..f5d39b20a 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -416,6 +416,7 @@ void PhysicalKeyboardHandler::handleEvent(StellaKey key, StellaMod mod, bool pre { case EventHandlerState::EMULATION: case EventHandlerState::PAUSE: + case EventHandlerState::PLAYBACK: myHandler.handleEvent(myKeyMap.get(EventMode::kEmulationMode, key, mod), pressed, repeated); break; @@ -563,6 +564,7 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo {Event::Unwind1Menu, KBDK_RIGHT, MOD3}, {Event::Unwind10Menu, KBDK_RIGHT, KBDM_SHIFT | MOD3}, {Event::UnwindAllMenu, KBDK_UP, MOD3}, + {Event::TogglePlayBackMode, KBDK_SPACE, KBDM_SHIFT}, #if defined(RETRON77) {Event::ConsoleColorToggle, KBDK_F4}, // back ("COLOR","B/W") diff --git a/src/common/RewindManager.cxx b/src/common/RewindManager.cxx index 6bafbeeaa..70fa481d7 100644 --- a/src/common/RewindManager.cxx +++ b/src/common/RewindManager.cxx @@ -181,7 +181,8 @@ uInt32 RewindManager::rewindStates(uInt32 numStates) else message = "Rewind not possible"; - if(myOSystem.eventHandler().state() != EventHandlerState::TIMEMACHINE) + if(myOSystem.eventHandler().state() != EventHandlerState::TIMEMACHINE + && myOSystem.eventHandler().state() != EventHandlerState::PLAYBACK) myOSystem.frameBuffer().showMessage(message); return i; } @@ -215,7 +216,8 @@ uInt32 RewindManager::unwindStates(uInt32 numStates) else message = "Unwind not possible"; - if(myOSystem.eventHandler().state() != EventHandlerState::TIMEMACHINE) + if(myOSystem.eventHandler().state() != EventHandlerState::TIMEMACHINE + && myOSystem.eventHandler().state() != EventHandlerState::PLAYBACK) myOSystem.frameBuffer().showMessage(message); return i; } diff --git a/src/emucore/Event.hxx b/src/emucore/Event.hxx index f666e19bc..010007c72 100644 --- a/src/emucore/Event.hxx +++ b/src/emucore/Event.hxx @@ -125,6 +125,7 @@ class Event ToggleAdaptRefresh, PreviousMultiCartRom, // add new events from here to avoid that user remapped events get overwritten PreviousSettingGroup, NextSettingGroup, + TogglePlayBackMode, LastType }; diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index b979a18c6..5dbd2ca2f 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -1283,6 +1283,10 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) if (pressed && !repeated) changeStateByEvent(Event::TimeMachineMode); return; + case EventHandlerState::PLAYBACK: + if (pressed && !repeated) changeStateByEvent(Event::TogglePlayBackMode); + return; + // this event is called when exiting a ROM from the debugger, so it acts like pressing ESC in emulation case EventHandlerState::EMULATION: case EventHandlerState::DEBUGGER: @@ -1556,7 +1560,7 @@ bool EventHandler::changeStateByEvent(Event::Type type) switch(type) { case Event::TogglePauseMode: - if(myState == EventHandlerState::EMULATION) + if(myState == EventHandlerState::EMULATION || myState == EventHandlerState::PLAYBACK) setState(EventHandlerState::PAUSE); else if(myState == EventHandlerState::PAUSE) setState(EventHandlerState::EMULATION); @@ -1565,14 +1569,16 @@ bool EventHandler::changeStateByEvent(Event::Type type) break; case Event::OptionsMenuMode: - if (myState == EventHandlerState::EMULATION || myState == EventHandlerState::PAUSE) + if (myState == EventHandlerState::EMULATION || myState == EventHandlerState::PAUSE + || myState == EventHandlerState::PLAYBACK) enterMenuMode(EventHandlerState::OPTIONSMENU); else handled = false; break; case Event::CmdMenuMode: - if(myState == EventHandlerState::EMULATION || myState == EventHandlerState::PAUSE) + if(myState == EventHandlerState::EMULATION || myState == EventHandlerState::PAUSE + || myState == EventHandlerState::PLAYBACK) enterMenuMode(EventHandlerState::CMDMENU); else if(myState == EventHandlerState::CMDMENU && !myOSystem.settings().getBool("minimal_ui")) // The extra check for "minimal_ui" allows mapping e.g. right joystick fire @@ -1583,7 +1589,8 @@ bool EventHandler::changeStateByEvent(Event::Type type) break; case Event::TimeMachineMode: - if(myState == EventHandlerState::EMULATION || myState == EventHandlerState::PAUSE) + if(myState == EventHandlerState::EMULATION || myState == EventHandlerState::PAUSE + || myState == EventHandlerState::PLAYBACK) enterTimeMachineMenuMode(0, false); else if(myState == EventHandlerState::TIMEMACHINE) leaveMenuMode(); @@ -1591,10 +1598,24 @@ bool EventHandler::changeStateByEvent(Event::Type type) handled = false; break; + case Event::TogglePlayBackMode: + if (myState == EventHandlerState::EMULATION || myState == EventHandlerState::PAUSE + || myState == EventHandlerState::TIMEMACHINE) + enterPlayBackMode(); + else if (myState == EventHandlerState::PLAYBACK) + #ifdef GUI_SUPPORT + enterMenuMode(EventHandlerState::TIMEMACHINE); + #else + setState(EventHandlerState::PAUSE); + #endif + else + handled = false; + break; + case Event::DebuggerMode: #ifdef DEBUGGER_SUPPORT if(myState == EventHandlerState::EMULATION || myState == EventHandlerState::PAUSE - || myState == EventHandlerState::TIMEMACHINE) + || myState == EventHandlerState::TIMEMACHINE || myState == EventHandlerState::PLAYBACK) enterDebugMode(); else if(myState == EventHandlerState::DEBUGGER && myOSystem.debugger().canExit()) leaveDebugMode(); @@ -2248,6 +2269,15 @@ void EventHandler::enterTimeMachineMenuMode(uInt32 numWinds, bool unwind) #endif } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void EventHandler::enterPlayBackMode() +{ +#ifdef GUI_SUPPORT + setState(EventHandlerState::PLAYBACK); + myOSystem.sound().mute(true); // sound does not work in playback mode +#endif +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::setState(EventHandlerState state) { @@ -2263,6 +2293,7 @@ void EventHandler::setState(EventHandlerState state) switch(myState) { case EventHandlerState::EMULATION: + case EventHandlerState::PLAYBACK: myOSystem.sound().mute(false); enableTextEvents(false); break; @@ -2541,6 +2572,7 @@ EventHandler::EmulActionList EventHandler::ourEmulActionList = { { { Event::Unwind1Menu, "Unwind one state & enter TM UI", "" }, { Event::Unwind10Menu, "Unwind 10 states & enter TM UI", "" }, { Event::UnwindAllMenu, "Unwind all states & enter TM UI", "" }, + { Event::TogglePlayBackMode, "Toggle 'Time Machine' playback mode", "" }, { Event::Combo1, "Combo 1", "" }, { Event::Combo2, "Combo 2", "" }, @@ -2628,6 +2660,7 @@ const Event::EventSet EventHandler::StateEvents = { Event::TimeMachineMode, Event::RewindPause, Event::UnwindPause, Event::ToggleTimeMachine, Event::Rewind1Menu, Event::Rewind10Menu, Event::RewindAllMenu, Event::Unwind1Menu, Event::Unwind10Menu, Event::UnwindAllMenu, + Event::TogglePlayBackMode, Event::SaveAllStates, Event::LoadAllStates, Event::ToggleAutoSlot, }; diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx index 0ff428998..3f780b150 100644 --- a/src/emucore/EventHandler.hxx +++ b/src/emucore/EventHandler.hxx @@ -136,6 +136,7 @@ class EventHandler bool enterDebugMode(); void leaveDebugMode(); void enterTimeMachineMenuMode(uInt32 numWinds, bool unwind); + void enterPlayBackMode(); /** Send an event directly to the event handler. @@ -557,7 +558,7 @@ class EventHandler #else REFRESH_SIZE = 0, #endif - EMUL_ACTIONLIST_SIZE = 159 + PNG_SIZE + COMBO_SIZE + REFRESH_SIZE, + EMUL_ACTIONLIST_SIZE = 160 + PNG_SIZE + COMBO_SIZE + REFRESH_SIZE, MENU_ACTIONLIST_SIZE = 18 ; diff --git a/src/emucore/EventHandlerConstants.hxx b/src/emucore/EventHandlerConstants.hxx index 8f11ecab6..0009af3d3 100644 --- a/src/emucore/EventHandlerConstants.hxx +++ b/src/emucore/EventHandlerConstants.hxx @@ -22,6 +22,7 @@ enum class EventHandlerState { EMULATION, TIMEMACHINE, + PLAYBACK, PAUSE, LAUNCHER, OPTIONSMENU, diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 2f4626968..d35ebd36f 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -29,6 +29,8 @@ #include "FBSurface.hxx" #include "TIASurface.hxx" #include "FrameBuffer.hxx" +#include "StateManager.hxx" +#include "RewindManager.hxx" #ifdef DEBUGGER_SUPPORT #include "Debugger.hxx" @@ -422,6 +424,44 @@ void FrameBuffer::update(bool force) break; // EventHandlerState::TIMEMACHINE } + case EventHandlerState::PLAYBACK: + { + static Int32 frames = 0; + RewindManager& r = myOSystem.state().rewindManager(); + bool success = true; + Int64 frameCycles = 76 * std::max(myOSystem.console().tia().scanlinesLastFrame(), 240); + + if(--frames <= 0) + { + r.unwindStates(1); + // get time between current and next state + uInt64 startCycles = r.getCurrentCycles(); + success = r.unwindStates(1); + // display larger state gaps faster + frames = std::sqrt((myOSystem.console().tia().cycles() - startCycles) / frameCycles); + + if(success) + r.rewindStates(1); + } + + force = force || success; + if (force) + myTIASurface->render(); + + // Stop playback mode at the end of the state buffer + // and switch to Time Machine or Pause mode + if (!success) + { + frames = 0; + #ifdef GUI_SUPPORT + myOSystem.eventHandler().enterMenuMode(EventHandlerState::TIMEMACHINE); + #else + myOSystem.eventHandler().changeStateByEvent(Event::TogglePauseMode); + #endif + } + break; // EventHandlerState::PLAYBACK + } + case EventHandlerState::LAUNCHER: { force = force || myOSystem.launcher().needsRedraw(); diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index f6f13f05e..47a7a6c95 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -343,6 +343,7 @@ FBInitStatus OSystem::createFrameBuffer() case EventHandlerState::OPTIONSMENU: case EventHandlerState::CMDMENU: case EventHandlerState::TIMEMACHINE: + case EventHandlerState::PLAYBACK: #endif if((fbstatus = myConsole->initializeVideo()) != FBInitStatus::Success) return fbstatus; diff --git a/src/gui/TimeMachineDialog.cxx b/src/gui/TimeMachineDialog.cxx index f157c67a8..2ed5295f5 100644 --- a/src/gui/TimeMachineDialog.cxx +++ b/src/gui/TimeMachineDialog.cxx @@ -69,22 +69,23 @@ static constexpr std::array STOP = { 0b11111111111111, 0b11111111111111 }; -static constexpr std::array PLAY = { - 0b11000000000000, - 0b11110000000000, - 0b11111100000000, - 0b11111111000000, - 0b11111111110000, - 0b11111111111100, - 0b11111111111111, - 0b11111111111111, - 0b11111111111100, - 0b11111111110000, - 0b11111111000000, - 0b11111100000000, - 0b11110000000000, - 0b11000000000000 +static constexpr std::array EXIT = { + 0b01100000000110, + 0b11110000001111, + 0b11111000011111, + 0b01111100111110, + 0b00111111111100, + 0b00011111111000, + 0b00001111110000, + 0b00001111110000, + 0b00011111111000, + 0b00111111111100, + 0b01111100111110, + 0b11111000011111, + 0b11110000001111, + 0b01100000000110 }; + static constexpr std::array REWIND_ALL = { 0, 0b11000011000011, @@ -117,6 +118,22 @@ static constexpr std::array REWIND_1 = { 0b00000110001110, 0 }; +static constexpr std::array PLAYBACK = { + 0b11000000000000, + 0b11110000000000, + 0b11111100000000, + 0b11111111000000, + 0b11111111110000, + 0b11111111111100, + 0b11111111111111, + 0b11111111111111, + 0b11111111111100, + 0b11111111110000, + 0b11111111000000, + 0b11111100000000, + 0b11110000000000, + 0b11000000000000 +}; static constexpr std::array UNWIND_1 = { 0, 0b01110001100000, @@ -235,8 +252,8 @@ TimeMachineDialog::TimeMachineDialog(OSystem& osystem, DialogContainer& parent, STOP.data(), BUTTON_W, BUTTON_H, kToggle); xpos += buttonWidth + BUTTON_GAP; - myPlayWidget = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, - PLAY.data(), BUTTON_W, BUTTON_H, kPlay); + myExitWidget = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, + EXIT.data(), BUTTON_W, BUTTON_H, kExit); xpos += buttonWidth + BUTTON_GAP * 4; myRewindAllWidget = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, @@ -247,6 +264,10 @@ TimeMachineDialog::TimeMachineDialog(OSystem& osystem, DialogContainer& parent, REWIND_1.data(), BUTTON_W, BUTTON_H, kRewind1, true); xpos += buttonWidth + BUTTON_GAP; + myPlayBackWidget = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, + PLAYBACK.data(), BUTTON_W, BUTTON_H, kPlayBack); + xpos += buttonWidth + BUTTON_GAP; + myUnwind1Widget = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, UNWIND_1.data(), BUTTON_W, BUTTON_H, kUnwind1, true); xpos += buttonWidth + BUTTON_GAP; @@ -331,14 +352,33 @@ void TimeMachineDialog::handleKeyDown(StellaKey key, StellaMod mod, bool repeate break; case Event::ExitMode: - handleCommand(nullptr, kPlay, 0, 0); + handleCommand(nullptr, kExit, 0, 0); + break; + + default: + Dialog::handleKeyDown(key, mod); + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TimeMachineDialog::handleKeyUp(StellaKey key, StellaMod mod) +{ + // The following shortcuts duplicate the shortcuts in EventHandler + // Note: mode switches must happen in key UP + + Event::Type event = instance().eventHandler().eventForKey(EventMode::kEmulationMode, key, mod); + + switch (event) + { + case Event::TogglePlayBackMode: + handleCommand(nullptr, kPlayBack, 0, 0); break; default: if (key == KBDK_SPACE) - handleCommand(nullptr, kPlay, 0, 0); + handleCommand(nullptr, kPlayBack, 0, 0); else - Dialog::handleKeyDown(key, mod); + Dialog::handleKeyUp(key, mod); } } @@ -361,7 +401,7 @@ void TimeMachineDialog::handleCommand(CommandSender* sender, int cmd, handleToggle(); break; - case kPlay: + case kExit: instance().eventHandler().leaveMenuMode(); break; @@ -377,6 +417,10 @@ void TimeMachineDialog::handleCommand(CommandSender* sender, int cmd, handleWinds(-1000); break; + case kPlayBack: + instance().eventHandler().enterPlayBackMode(); + break; + case kUnwind1: handleWinds(1); break; @@ -479,6 +523,7 @@ void TimeMachineDialog::handleWinds(Int32 numWinds) // Enable/disable buttons myRewindAllWidget->setEnabled(!r.atFirst()); myRewind1Widget->setEnabled(!r.atFirst()); + myPlayBackWidget->setEnabled(!r.atLast()); myUnwindAllWidget->setEnabled(!r.atLast()); myUnwind1Widget->setEnabled(!r.atLast()); mySaveAllWidget->setEnabled(r.getLastIdx() != 0); diff --git a/src/gui/TimeMachineDialog.hxx b/src/gui/TimeMachineDialog.hxx index 45c9dfa06..283249514 100644 --- a/src/gui/TimeMachineDialog.hxx +++ b/src/gui/TimeMachineDialog.hxx @@ -38,6 +38,7 @@ class TimeMachineDialog : public Dialog private: void loadConfig() override; void handleKeyDown(StellaKey key, StellaMod mod, bool repeated) override; + void handleKeyUp(StellaKey key, StellaMod mod) override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; /** initialize timeline bar */ @@ -58,7 +59,8 @@ class TimeMachineDialog : public Dialog { kTimeline = 'TMtl', kToggle = 'TMtg', - kPlay = 'TMpl', + kExit = 'TMex', + kPlayBack = 'TMpb', kRewindAll = 'TMra', kRewind10 = 'TMr1', kRewind1 = 'TMre', @@ -73,7 +75,8 @@ class TimeMachineDialog : public Dialog TimeLineWidget* myTimeline{nullptr}; ButtonWidget* myToggleWidget{nullptr}; - ButtonWidget* myPlayWidget{nullptr}; + ButtonWidget* myExitWidget{ nullptr }; + ButtonWidget* myPlayBackWidget{nullptr}; ButtonWidget* myRewindAllWidget{nullptr}; ButtonWidget* myRewind1Widget{nullptr}; ButtonWidget* myUnwind1Widget{nullptr}; From 81fdbf4091347f55dab55310f30e34a9df700ebd Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 23 Jul 2020 14:28:52 +0200 Subject: [PATCH 343/377] removed GZIP from doc and rephrased ZIP text --- docs/index.html | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/index.html b/docs/index.html index 9ccde3bd6..554f2cdbd 100644 --- a/docs/index.html +++ b/docs/index.html @@ -302,7 +302,7 @@
    14. Supports using ROM filename extensions to force specific bankswitching schemes
    15. Supports using ROM filename to force specific display formats
    16. Supports Supercharger single-load and multi-load games
    17. -
    18. Supports ROMs stored in ZIP and GZIP format, as well as the usual raw A26/BIN/ROM formats
    19. +
    20. Supports the usual raw A26/BIN/ROM formats, also when stored in ZIP files
    21. Supports property file for setting the properties associated with games
    22. Supports the NTSC, PAL and SECAM television standards in 50Hz and 60Hz mode
    23. Supports autodetection of display format for 50Hz vs. 60Hz modes
    24. @@ -535,12 +535,12 @@

      Supported File formats

      -

      Stella supports ROMs ending with extensions .a26, .bin, .rom, .gz, and .zip. - For the last two compressed formats (GZIP and ZIP, respectively), Stella will - automatically decompress the archive, and use the first ROM image it finds in - it (ie, the first one ending in a valid extension). If a ZIP archive contains - many such files, Stella will display a virtual filesystem of the contents - of the archive.

      +

      Stella supports ROMs ending with extensions .a26, .bin, .rom, and .zip. + For the ZIP archive format, Stella will look into the archive and if it + contains only one ROM image file, Stella will automatically load it. If an + archive contains many such files, Stella will display a virtual + filesystem with the contents of the archive. This can be then browsed + like a normal directory.

      Other extensions are also possible, namely to force a specific bankswitch scheme. Normally, the bankswitching scheme for a ROM is determined automatically, From 54733946a4676ae6fc3ef3bca03627053727d62c Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 23 Jul 2020 21:12:33 +0200 Subject: [PATCH 344/377] Two minor fixes --- src/emucore/OSystem.cxx | 2 +- src/gui/TimeMachineDialog.cxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index 47a7a6c95..f7ae17060 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -343,8 +343,8 @@ FBInitStatus OSystem::createFrameBuffer() case EventHandlerState::OPTIONSMENU: case EventHandlerState::CMDMENU: case EventHandlerState::TIMEMACHINE: - case EventHandlerState::PLAYBACK: #endif + case EventHandlerState::PLAYBACK: if((fbstatus = myConsole->initializeVideo()) != FBInitStatus::Success) return fbstatus; break; diff --git a/src/gui/TimeMachineDialog.cxx b/src/gui/TimeMachineDialog.cxx index 2ed5295f5..3b591a62d 100644 --- a/src/gui/TimeMachineDialog.cxx +++ b/src/gui/TimeMachineDialog.cxx @@ -356,7 +356,7 @@ void TimeMachineDialog::handleKeyDown(StellaKey key, StellaMod mod, bool repeate break; default: - Dialog::handleKeyDown(key, mod); + Dialog::handleKeyDown(key, mod, repeated); } } From d954b495b7c746cac4a869fb9647acd8adb66dcf Mon Sep 17 00:00:00 2001 From: thrust26 Date: Fri, 24 Jul 2020 11:09:01 +0200 Subject: [PATCH 345/377] enhanced debugger option "Re-disassemble" into "Disassemble @ current line" (resolves #652) --- Changes.txt | 2 + docs/debugger.html | 8 +-- docs/graphics/debugger_main.png | Bin 63592 -> 63710 bytes docs/graphics/debugger_romcmenu.png | Bin 10000 -> 8710 bytes docs/graphics/resources/debugger_main.pdn | Bin 204733 -> 205235 bytes src/debugger/CartDebug.cxx | 15 +++-- src/debugger/CartDebug.hxx | 31 +++++++++- src/debugger/gui/RomListSettings.cxx | 6 +- src/debugger/gui/RomWidget.cxx | 66 ++++++++++++++-------- src/debugger/gui/RomWidget.hxx | 2 + 10 files changed, 93 insertions(+), 37 deletions(-) diff --git a/Changes.txt b/Changes.txt index eb4f0a16e..6d3b5b2f1 100644 --- a/Changes.txt +++ b/Changes.txt @@ -24,6 +24,8 @@ the ROM. This allows to distribute ROM and properties in one file, which Stella can use directly. + * Replaced "Re-disassemble" with "Disassemble @ current line" in debugger + -Have fun! diff --git a/docs/debugger.html b/docs/debugger.html index 306885c34..781d05bf5 100644 --- a/docs/debugger.html +++ b/docs/debugger.html @@ -1496,13 +1496,13 @@ anywhere in the listing:

      The following options are available:

      • Set PC @ current line: Set the Program Counter to the address of the -disassembly line where the mouse was clicked (highlighted in yellow).
      • +disassembly line where the mouse was clicked.
      • RunTo PC @ current line: Single-step through code until the Program Counter -matches the address of the disassembly line where the mouse was clicked (highlighted in yellow)
      • +matches the address of the disassembly line where the mouse was clicked. -
      • Re-disassemble: Self-explanatory; force the current bank to be -disassembled, regardless of whether anything has changed.
      • +
      • Disassemble @ current line: Disassemble from the disassembly line where the mouse was clicked. +This allows to fill gaps in the disassembly and is most useful for bankswitched ROMs.
      • Show tentative code: Allow Distella to do a static analysis/disassembly.
      • diff --git a/docs/graphics/debugger_main.png b/docs/graphics/debugger_main.png index b11c02f96ee70dbfeeb48475345636e3abbcebac..c59f1a345eb08d8f3c1ec6394ba8aac369391964 100644 GIT binary patch delta 53911 zcmb5Wby!s2*ET+YN`s)3v=Y*w2uKUkEip)UN=nxOVL(bcq;V(#2?6PFXpja$y1Tpi zox#sH-sgJW>%D&Shu1JOXPln6Qd2X4*U>tmBJ>YlPeLkKFnr_3MGak!w z8jjT0O_{|tPV^)v(FywdIplgSV=$;pn|h1j+OG*cpNCgB-<4qD39j|AB|{&Rwz->6 zggciKZ24A7L_{v0RnEx?#XnZ?*oOefo7KCu&<54$#O>&~1a}|pyx2J#Ub#8mh=AfKq)^#}V< ecr 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 z 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 F{}15ryRiTO diff --git a/docs/graphics/debugger_romcmenu.png b/docs/graphics/debugger_romcmenu.png index d6a78172e4a6770105b682fdb7074f5d91bb508e..f6cd561a337f329249a6a6af8e89375319bc8e38 100644 GIT binary patch literal 8710 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 diff --git a/docs/graphics/resources/debugger_main.pdn b/docs/graphics/resources/debugger_main.pdn index de1d1e3578ed75594e3e8072526d29f1f25ac7e6..6c864a2a40776eee62e1066b9a59fb3816f6ec39 100644 GIT binary patch delta 56868 zcmW)oH2syw98eDs@4pIO<-H#vUXL=k#}nC@;@p z%iEqD|6-~QOKy&5xFE><$h85t`gx0gaU4Gm2zFSJq42OT#xW>*`CYYlkdj0q(=)Zr z#q`@Jg8t4vY|XfSJjyWO&}V%AJp&ZU;tCVJ?*(vXRMv9bMx(=I8g~KneWziG#(_1E zdc3gY%v=zJk}+PKvEdd=&=sFOfD7%nCJwZ29BeJlFEQqg?4BKRmk?iWLY-M97z`bU ze-gxwJ%0^Zp54s${%Zzxr@XcCHVRYp@{%ZKF-C>^szL)8}w#L_Ip5nFwvFBUgubSPIqXh6fA%T4~mb zx+Z7dVfu$G-t_1jaqLWlwA4F3?>Cwauog6^ogc}j7AuWvV#N4JHw|q5d(+Y9hz>E% za*jNVwT=((s}XOuB}YS96y++`ezIBH4E`S zk4qSHDUw-?8%4fG&uF}4%0^Xb-eO)t%v#dS8U%kmE%2hEW-2G)JI z_FY<`7ET0D4Eq;lusj)S)3s)gxuapxS7<}~R!LkjK#R`$Y~duKbWVMqzZhBWI4zpM zyIPmS@{sl=Q_Q8NsAue1gAT)T3h9}*%xb9?8c}PTlzYa+v&!GP{QOkeTc49$bO_J) zdvk_mT{`g{I#9Qt5!w~FxmihG_Yc&&(5_YNAIfu^W36+S+?+>0R_%%Z;+>gS1r{)xy%yaO)EgQDAs zuX3Y`GNxhil>?T#-e8|)?5l~0H%=nY;W$4MhBo`JyeC=No6meNJ&Q2YyXn=s$i6O? zuHz!Pge+Pb^o*W;hgG=K_Ak^bi2ZR)C%lh=`dk81d?bQ{f0f3SZvFxr^t`RkTirfo zha!#5He$-wout^w`(dHfUk+y<6ehWQ`%AQC|5P#i?=J}bT>Ey8^(&TswavTir&!Bo z+)g;ZQz_`*LnRs8@+Dl53_8l2#`1A#f1Y^^%<0`uB0g zj-8%hlwN!x$p(#j>%fT_A^Zj6`%)=y?R$cy$8)o*w}IvU^y}6jSsK#ihjuO!r!7?~ zan;`!VFU9Z#23*%6)QDl@I~k`VUNtz6jm|{{KzmowPTrz6TiL2J50Sp_R@4RFnrOi zwzNNqqsqn5emi@qkD3rbForSy9 z>B}><;oN$LMxJUG)FX;YUm1M})hi3cOMO;+G44{{NQYg%(0eA=UhXvFv(h%@Ia*gh zZvwOalDnj^h3T)4hqta>;AHl5-;?ISu5u8;)%V_(~D`l_Fpo23Q%xOD}}Jr5M$ z4{0XU1|?U>L1WmvJjH^um2BW&hZn5;`ZH>DiamV6YtraKLj<}YF(G)I@k8c2{gYTw zbjpdG?}Yhsy|1se?@e$rA&E0%K0hRGw*)0(VMYyCOUW`7jC&C(n1=4hMudAG@13x5JkidB`?dn4e0`4| z7)--&wiNa32;&0sn!OHNYH;v-fbm=y2aYpU!q#;n)Sy2%u9;P_gF&N{Z${hn4^iv| z>1d3~)v4V=(l-*u>0n*wvqAguG>(_Y+qCl^KGo0qLCrg$(T~BY1md*Yp4Lpy55!i4 zDq^O0xW7Nz`=Q8sU??J&IPPJ}11Y+6LSeM}lUCvWtrs0W_PI}_*~B&-<&9o>7#>>& z1d34kTy%z;5JIFl(sIhS6CZ|qOv1g_gggSDIfcaAhoBX0^!>oAr}*w;;rP=BTc5|- z_gyd1ItxyB3PE2paJ+uF2S>z>_>(}%t&PCf$@Wq?WcBpu%{XDzug_nG<~OlP9RHbdL2ItgbJGnh&ratGsl3N~Qz*^xidc+Q^KufPCSSN-(J5W-xOyQ1XvH?7TgU`%DkW41 zHaYky>hApMybrx!ug@gqR=y)n`a&Rd`D8o);!N}LJF4n0F#$gO%m`;xw6cz)ilP3?L@ z|84H7KuT=t8X?j&3@PH_>s`rg-(<IVv*U`%F1tcQNV{k2n3>r1gt-}8`8SQ*+^^qtN5+D`}!gb*ZkF+#@Tpx zsaZ1}Kd2ijil-e9jX#R0pdy5q>R3G6F;-=nGXn#+Me-|O{`!nM;maoNMRh^p)%v2+ zqlbnEg7@a%i>NF*{ZM+j@B{YAEj_%~^W`6G&H{&E!Y!b;%1{^mx0yMG zTBJXzZC0DX$-Omnaii?{uCGG98ncI{^3O-RS{KdZ6xjocw@=}q#hf=|7WNm_S~rPf z_-;juuoKt5rwjYXvOp>htTEdmvX=SugK!8YPpK7$*Ypt@SyJ-RHy%sg;s=7&IfWRDVx{vl_nn$~)?n zLOwWIRlQi)@k$mNf{#HH#A22(eB{E1GYHzS#dW}Gb?dP-k=v=K0zBP9PfCG)#r}w{ z;)6x2X4@a$QY~Fy5wr(ZF?JUAjg$pTWpG7gDCyN3g|ts=7PLzp4}dWld$;qKwos z1C<@J&hO+HlwGMW>?@G_APc19jcUyd#su`#vrwBc)VL}fD9)Pm@`k*5MhkRFe7x~V zlt$kWFwfu%iSw{b2NY^61_ z>{(C`W$_qX7VFY4m-%mTYXtDl?-4Kc*MpWUxUAl-U>3@WDV4f1b#wT?FZp(2l3P8#;o_zK4a(CjofqlqD74;?8=w74mt0b`rzrdRIsd*Z zIEieHy47ajACWbS%xu2M}X15Z@B zI9{f!gkZ4j2^O1zFl6Q4?x)R^2IsAue)WWu**%Z3o=$@$K3$G4wIA_mNG;q0&?nXL za(tY(gn$#jO4i>fh@TYvBoPP$cwWxL7@W^l%N=CaD7L6)c17O1+$iVgmRh*jg<6Zp zhSk&L&=`ZzsQe@#rgZ)6E}Ntz|P7VA3J)${<zrf|lb2|S67ZD3H$0@kg$PBXFX7bsn__l! z6VrP`b$RS;=npK5zPoA}80f_*qNP?y-b{GKVFim+ZX1~pE@JDp;|thZVr+h`mIC{9 zIdaa|87i!-&2>F@#cW~HiRAk;R{YWmsPfMS2#lb3VIuszaOW77@DF~@8Mkqm@eUQb z--D#7%BzjpfzH+MPsLv<&*l(V8DvYW+(GtB55cGEDte}ODNl&+ha*-lePDETZhAcM zJIc@j6;bV7@rMK3Ds1GaHByYh#2++l_>{;422(hrfyO^;Y2>b!hA)Ko+-su-2FF0N z8A!m*q3zuJ-C6k*U3c8f4h$A$Ko4mC!rmzcWTo;F=&20JDVyel1p1bOHrhM(A$3+Z z><7-{fOc?qdjOqj$B^3RiW>M^(CEy)$hqR?ztf6k@Y$G}&Dvu{jp0~>ZvlNFVZra@ z6^Tz9zBxYNKffto;B_fG*VQn=RZv=4RGqPPc4K~oSHXq{rDMJ@W8o|o1O>0TVl~?(pWDa%`2`0ZlPT7JVa43kL9IMX6PQ98rftyu%vsef$n2^%T2rj#T?_Fi|X3vuKytge3+c^;x}dZU?ulg0Y(ia-g%u*2hW z|1jqGui$roO%luuoT)79EVos%^FE@a=!&=ly3_r@ZKkV)_T59_Idq-Qsc%EV0u9bw z4aTz7aKSIt{P%o8_pJ~96~+i;=FKCY7`jr7aPqX>#a^Myz=4W3aw!nZ0e7VNs|@S; zgZe4T!Zh?IBV9?*@F_LFF59=A9ni{7?I@#9q3|N>d5rRed4R`x%84daF>IM+A$U{| z8y}NE=sss(hDq0S=!Z-eqr1RKjZDTAiEQ65r*a{jY_kB8H(z~5ibmSy94OU z0=tpaxm)V8wxD8s@fsh&xYY1p&#l$i(Q6Id1D;l-3e;8N>Llo(sR>bTf%$d#+2h_^ z<3K>YnFy`bF6hnteI7a((r*8*?)+P|HCOO^R|fT8ye-eIcNC&>KPQ(c7loNy(#)Ib zNFvZ60$E^VlRj-RX1vOE17>^0uH2u#QEpQ+jcxC(&5zFai9j+wA=F!oM1=-QAZYHx zgcYTU;dgQ-gXW5qa}jV5l}8f4dy_zo#gF)bWO|eyT~2(|q=UuEsH+w&hHJ zWmy(_i;UqD9MFOSc^XXSav}^B7z6*)_oc!AiihbU1_IJ0gM{a}vD>^CUO!kJ2p zK?pv$MN((71m6r$?khX&aQq!I5PQ*TCNHj0^-z;~hNrn}(`l8H*M6(ir%&R$S{qJ0 z#h;s^AK7`0Gg6)XoGS0N+?foTAkz(ck$XxlgyRYGSkK6Bxtyc3sVyd;jctAf- zN$%Y1lKw6uGx6b;I7D3si95m>MV=qG8obTy7=B?P!D#e-dl_l=WY)iKwyz17hq$&f zAJt68eSAlqd>F+s|4PtiBj>TL;dctq_WNG6oNE`SyP~hpf9k|+YmYplN#Ywqsw3+! zHxQ-WOBA@nR*dR(dKk&aCx~6%@75g$e)5zba3Kh0E;zMme;5rdx`&h>3A1oAsk=Ax zktJ<3$~TcVz#l8K)4n<CfQwXCRT! zXn-ygcg9T!)kXtye8H0aRwB*$66{EBro5@^$X^_1z)aSXas$k6DO}CVG=7{~NujY} z({$1u1qjJw4Q=m3up&XcA|jMbSiCgp!LKOGVREe=OJ)SP@!vn;Saq`lk79~ReE`b0 zy4kux1+|?OB2Sn(H6EzuTZK+7H2Jc!diQM;R9`9QBL!Ay3>Px{U)UmvB ze(K%;xs(tRFtFj^CZXp{k|RU>ok5ckT0BNRaPoN7WO9feZvB7=1ySw9b9E6W*qogk z5;vauY={^f0eO1FY5%-Br{5{*CwBsOh1f(h?tpnaeYa4Qx}}+?|+Ro_Svf zM{>;aPvO7=krz%J1%g|(A*+gZ=}b^_-O~q2gG^J!3=b-sGaDOd!B?|>7Z@`nLiF36 zb{Z6A@{A+o2>MFmN5j==&Oj+B(o!ek(nT&o?BhQk)>i5b=_S?r(63##U z%922zi>t=TW(_)^Y0R`m^XbH02MHd}VP#I>Ayoq;o5+6Mt%!EL4H znfeZ&dK~*cOXw+@dHvA_iW3xt7u$KlTuH$ng;Fww;SnNK{Y z=3aMf#gF-rLUb@?mkFxyZMMv_(RA2RcjJ74$Xv6xltGVyqyYy-QcuAwZ8uQuR{e`o ziae4(z)#t0|bUW zq3Q8!jpL<@NBbOD%k>~xWhtM1+=UPH+fnfJqb{?MWqD~X4_ctE|5yk1IJX3)dR6-$ z<&m|FV2S3Lm@_Q0waM2LS+5&tPVnf(eE?oGd3)S)Ch&;;t(-GI*RDJXRDDCx<^Zeb zegn#0)h*QN88SzKl1?$#!^dL`_f5jMysT+fN>vNQGecMxSL*q z9^&&!xLQhQs411CF~-y#FaLyGj(URN%l$xk@lrIqggaR6ynZ z;wXyDb6+7Fz`bPLyd)F*&Vb%KmJjdK|UdFfJHM#HU1_Hf78J^Rp z$q4Yf6I>oW=f6>vBvHT(!UK-S@Au|>{Gb!*BZddh16@eDpa?e5?35oON>2N6>|EpD z))%~k_Ano6KiAjc2zBFISb^RZvm2Fksw}4W-Moepu)XlI9mTAcsgjQ`Qn)eK87rC* z7zO>SQf_qMd8TYi*Q?V2Ad?F?+>?%!2G)wlg%S6y=0-rc<^+38aE17|+2Sen`eOS# zA@iFJ z>mj~*POC;bSI8)^@<&r;(oLh`0M2B{arEB*{E6&HEfaw7Sw2lAlsl|v`<>!P2PA3; z(@cy50y038aEPA+hNh)eWjB2{C05Fz+gOo57Gy>ZS9z^%VjN{$>j34+XZP9Iff)tWzS zyJzn32q1yZ*QuBA4IBbNZmkl*8tisv(ID!f=h+RlQ6N7w?H)!dmUAttby*o&f+#YG9%HT|<2X6tAn;L5WLHvWSB z_fti4Z=mNdTEC#|H!k-nzAqe~ZN9lmjtt35h`99xrajP$4airhO#0eL`(E*Slzl6$ zA1ylg+=D0JrU7>|;}YPke0^1d`2_#uIrY@l#mlC;JDkQifcQe%Eoj^~;96!*>dEE^*nWWfHaWdG#v z(dA6ok*h9SbceRS?j50w^iu`%5$*~&L+H0Vfp5ciE?u=fUJNRKIX_Kk^T5jJdkC6N zO~nv<0nAB10q-njK}@eV{E=iqvM#uG7>d2_6M7-*9QZ3+C%5+lfkq4E%60mX46?u-6Gk7ga($;dA zRbz}AIUqL>tosP6dWP(UiGvJe$RxdQ&_%O=G{Q5u-?hKpJe=bOmbQR6nv->iR_Q_k zHk3>Ouip3M&ED6+Q_1@_fjlURzrmwZR0*t+PtyaUaU~5M6tBMvw0^#> zV9RJfZ`z+hcf6a^84M4{yc?wxq#o>?gCh{Mo(tEBMO% zFj_dOjiN0T?C6i6;C!LaYqiSu$1`DUDJS-P| z_nkoV^^)Q4d85T)0#6X!ziAm7Lc(R}_0~B92cjzMfiO}UUa|OnzEavQkfkGQz=y4K zq&B(wMIOFT?0;TF76A=Qzo7kcc%gI4?#X~fWAKA*!Z|eoEB0Se60Z8W_aSG4PtYXb zVwuq==@oJO!+GE+eq@=UT_b6I5f)^42qRRcOIEK|CZ<*D?hOz8`jqa5IRvpY?nAdK#TW&lg=Awu#FA zNBcwlEXb&5-`X4+k~JzxN0|?Jiz3fe3)xD(H<`^kwFS$5Qu@ad_V?G0k#wd+x%)nF z073I8m_L@>9J6t+u?IU$y-uY0UAZ>G<;o?V@)7G5%n1 z%9>!h+r1`E?S^ZRqljYr7eGVr!Ol8o(1*}?jaVT#+&Aj$2hb#fbK{}B{K1zh?8!+F zNXEdWNwL`Chbm0?d>PHF(>9e4Ew$&VPaP7?$1g_rdTmL}8B2DHRD zfi`83+K{~d08E-+7ePyu)G$zT3;kCCJ`&6ZjZo_rDRO9;Zutgjz**+*m+mV*8)myP zKn2gy`pvET$z~_s^O^?&XxMn@0`(W9n>h2Ea8MFcVMo4OLmvPZ4>b;!^_OsD2{M63 z9XudK$pJ~<{63cX8#k`!{%{Z}th1f~`7OC2ksqc&N25Ji$+*I&z46hZp}hODkRwRI zfT(ri)F8+PTI``X>-Y4a=^tTue0*GeyV?Q6cEO-~kg&2Sy_AO}1DS<)y|Dze32416 zo2h{g@L?%{FoVCcg=}Csr&IL{N))i&aS4v4bYNESQSaGvPkDaj=~Hm}u}PLb`mG#l zi~+$P=EBz@$Z>W6QAUX@kE3gxhhnIngBcit{TCIR@au+hKjduQvI3%{Dfm!6QaaWv zu+usE51ZZ~IyH)FgXruGMYs0?f(u`+tlws8de9&uUz*3Qg6Ffqifroo^LBo=T^zVl z7)cKnBa z*P2rd5ah~Aj(Pz`2v{H>0)r8f3{*JXH&~{1_+4+C1v;!gTRvW8A$zpy`V8q7%rA7q z*m9OOCc^Z)BM9H)*i)ZLpn#nF%l1O1>UT|Y ze&==2C8qg`Aw4b!Qfw-h$lX)u$IfsI4r&Hqk&)yjepoDM4080~fnrk!fwIo`ME4iF zPvlQnLM4;b{eC_^UN`g8+#JLOKvK09IE7)im8A0iS&Hb6^gmb}v@;Kytd1hw9K^wM z%mJ@$A&D5ZeD7w+_A8eSjx9(iP)@V(SYLH17 z?@XlXT<2a`f=*7d1uF;+BpdaNBivS_?#hTs*!lTaWOCOa;n!6o$Qea^h^l#OpU-Z+ zeOmtv8CJ4!3=%i9`Bi}bwu9U-aR3KYEd7|c4Fq3E`s(CsWwrMwPx3&JT;XE*3b=Cs zUU9uevJjb(t)14|gP98F%7z8t7l-kE^mk^N@%)6!=uzNQ&)o#RVLg3!`L2t3@&g4W zW%oN(3#2s{wcHi?dW7#N1b{%-waN_$pffCNb;3*B_x>ip(q4F_RVF(ilEiJgwA+{d z_&;e*7J0JK!w#UH0UtsL>Sn;<};EK+`+!q z-XL~Z&+j$fzrV6CZ}oTOv|tP2fY38ciZBOb9(Hm9WU{dFt8}&E0!fp~NMa5SkVg8L z1C0s@HHz4>22`;9Q?*ek7j4tmz&8(^OJB;_cW;-=KI{k??4CF}Mv6kUh?VT}QHKqh zS)`FiUQZ8P?KZ{%*7*<$0w@K{7W{_nbG*af45H{C6>mHaljK92b(;en@QJwER+7&P z1d7b^X#SW1G;UAW!TDe^pi&+Sgdf+!5d>T+R&*T5FTklgFKruNM!2x2YuUqN3hMk` zn&HEiSdRja7-XOahS6seWGP`2z)fSMatDa>8s=Ljhlu-QLo0x9BZM>dL3c$N+Y|eT z(o@zyAZlLbr9%40u>!y!-lcUT=%;P%mtF~+S^m^KU-)zEDv7cv;@$GXwdJBaa}ddu z&Ua@i2KC03yA{aAoQVwb9e7IQ?;a~TxAesP&C&yUMSHXPCGifZNKWu2Pt5Du0ZC?=a5mSnq7lH=9F~5 zUq1ga9<$6knHFA+s{YmI2YYYy2+N+qGU?uM#V4lxjR8(6cng2S0)mvl@jEh!K7qyZ zcJH3%K9>BvKeh(q6BM=A|M_&~kC9w$LAG$<$ZrO~<&PRI!q4%!w62PO_yY`E9Kdq- zxIo3!VM6jLQJ>wF-dQ$`Kb*4Q5mgiP!(B3Y!@BIZe=wEqZQ)$=4B!gI7RMJU^X|>% z0{wZn?&+KN)^|BHF-Ve%SVPuU_yxD<`{-wF;$&9WJ}|)lwADS@588j)MP$a6{N56P z_G#9>?+XOAcQl{FP}S6VeqyZ~PAcZ@K!yHxm%2U_SQIs~BFh_{0c^86y);}g33^FF)nhDMfeKZ zO6@&8Z>9#oWRlWn#j@Aa-0N(G*B?&}Uj|Mh5oeAKB8_ zdGNeG)C*0&Iml7EF9;kl<2?uBBLaLfAd}Oo7Qx#v}syb4C&)$q_E!~MF{Q@K2 zfA#`=1HJQWtfve(a$M^V8jN`m&efr3mIh=&+@l+c%)pk~>Oz5hu)dYqRoDV7qqcYe zG^_Z}GVSxj3>TveVZ5rY<%y!+0(=OD9X`4E0&I;S*!`TASh&31X~~2k6e-{${sC6I&b86#8{~fF!SjZY@F1c_ofxp{=7!` zz4*)SjAupd=dgqXWcanm5%&`mPGDrRJ%v#~IT2K*wBa~){>e-?m@1fD2%vI0lSgX6 z%~_cjBikpyF7Uq}=5SXbQXfUkP{^I@2mZyE@bD(TK9qo_No~lFDuOU~caqT`XNr{9 zks|h3;)ndU=e|jD64{glhEl+Qfs@gJ#eS!=!O2agi0Qg&m8f;IwxZ`0aXO5pD1H6= zbJzfI23r{f^HTppjj()0=I_A(a8p3`9mXA?%4!(nBng<>?~IYh?hl#0?RNK7g(~p# z-#oG2kSU{JvVu2XY8PZ&~523u0!<) z5qkDbdwJ{5K%jHHB8RQ(g&cLTX|qpBxwg?4o)KEXWjp*^p$h<8yr^2PjggygGHY^5}dbI=YSbOAp5ym#&(2z0dufi+jWW8^aqXf8gD3!Z&8*-MPD|N>4 z1q8{jKu!itQ6w5RE&yK|BxL@(%ox7Q?$)0EAVz-K#48Qb~O(= za=NL_rhR24-lYw0nP4gcnW!gT(b=KRSJqt?2b4*06S5)9nNBDPyz!jQy?Ga4H}vh` z4`qb}LJoCrAubJ);v*1kg3GZ`Y5a9xD;WAHn11xnGWzp@5B*k8rQ%lyL<8{!40Qxr zbzEq&##jwNhAR@H97mT7eH};ZV~x_}_{1JlQ#q&kVIjx|HnkLbuC-QUqa-}0$}jh+ z9%rchNcwWHZku#_DkMStvCqb#o9?p^?pS$WqEmJHCl13WjP@%|N*EyhV?r~_Ktl1J zBMTP@{wdMiP~{AYaOo*FF$QwzQvU+EgLyyhYy{U=*zp$UjP)c!8_3QuHD}~32jX8# zKrWFBlG$-yz5bvj0S@UNUBY88Qpc(K>&KVesuqynA!dFxy)Na>d-h}w%o4Fyl?pn| zi!Gn?wbNFi?2w4MRj#<2s1jlo2S9JrLvIR+()HdTmY2W1Nh?Jko(UVEh)Rf-n5{G{ zGB5it9X@rXv5>7R7hk#1CobWi&+w4L6mVVP8A#m#XY}n?+^$QApxUDy=D-XuEa%fH zKX_AUIz-IEiLyMB@-D9x;@v6U;NEH|mxEdmY=5y(n{0%3HYoX&kPAC8pbagA|B1hV zlYn7C-M7j>_X~)P`}1gZbT;`u=sR!F|DGIpwswO-Fu2V@^0i_%9kg@$obBt45ip3g z*g#ES9&cn2EQ*GX8c4@M4Zw)UTp3&mhBowA74yh<{of{fwD22QTXg@Vvpr4OSWGOB zhp+keJpd*|0r}Eg5>cF zTxeWSmIYTEzY^1i9`hHd2Yn>_;rG}|<3GbL^|M^afeN|_#3J_B3eWW~bE`LgTHSsf z0XTdFap1z5&nM>Z7Z~%btU1>JNcGGR8d{Y9M%7v|)k?7pFhK>9 zC+IyuG3c~Mp5@0(g#qk_b|d%yu6k;jp9l~Q_1ur9>D-n!4*`ZC_y!N@gIqLMSn*dg z^iu`*@&aXa_Cd(DLcIITK!zv7wwWG4!j;IhTw09KZJmx5hx@l1_6vjt+|9dJnE zUylv2{8bLQAh1}{;yOWN6C_QsuiO=c$3P00NT`0trOKl#NwDY>P)L7GEDD7H7Vjbh z1@ezf4dB;!nx$?z5f7}FuRnMRfMb`EH=?^dPE zE+->r_yY6>2^>-D*Z7ln10a7l}(Z? z^)uEdsy;c`vP3W3?JIxGTP*$7AXfszrGs9}2jvbjh7aEj%zs1TVe1pD$$*B3{n05G?o=2XqTmXSttY($F6A4cal`88L7jfmwzJZUVy{i*_S!7SC} zB2uL><+yZb6hnK}zJVg8I}0Ff2Sld80pD^e$Y>~bIFPf*FOWp|`4MJ$4akVpd+l%u zg50qUM%a99`W>s>vYC&P5hu#jrYnCe6&YZ1zoa2%&S|@E93AGWELY&Nx>qlrvN(L%pvf-2!t_>&0eqYz;-+QPuU%A55g+4f`J*KP0vdfFq9XR zzwxi%zAQP|0C#>~hbRee;;#~R?UWGul8^C#EbX8`Eo!QxJD{n4;jf-V-KyZda^Stx znjJmfT}Rbz5jN&p{!hYz2ZMT*O*ziEewC0RjC(wcW~Ti(;=x=8=bJma-lP&>6c6B6 zegY$Y+2~;MFzRmu`Mq5B8HelF6**G1FLkwpFRgZZ z_HW_+vFZDD$9?QLK7%hbyz>m0#<#%?%#%w@3@E0i69hO3<(vWOovpzjo%t01V;!#( z9IXp%90~xO>bvLds(RH6F(OBnkrG^3b*7x|k4p^z03V=y3@|lV*TAieN^9b+grLhkc@!X@!nKAG z2{B+nl?R=FTV=YN55*>ADs7`(JowGc`~ZNHTY#BQWoU6uT4RW+oza&6EFS##3IVe* zG5_V$fZXl*q)1+NUot9$<4@GhB7QdoBs}Kp-<2LFocwdtw?|hTIub+cvZ=&^oHq!n z7bS^J-YfbE^clx5kQa!j2zHDgAB%4|tO#q?a~gglIo|o$hNIs<`hrJDkK3GD*8n)0 zUzAhkLY6g<^_BBH0FL>wwF!VVCy+W}d2oe^)DQ66LTt7+_T-hemt>lc8 zcj9URMW#|H>k~oz&jZduCCU~U;{tWSnSO)_=Fpf-#{NVz0wbClW|JefeqFdQ8W`cF z3jxqjax}&+|WU0<+?!{>5->t(cQ&l!#3W;7`L18QJy$AVyh}XE> z`6`$wvw^yLQhqi>=;1n;9aqyT5_V^=11c0iniaIA5$%ZU!h1G{FrEB}egy_R2q-H+ z*xkV|1~JOl1eui$3i+~vOeqL*uF>{4&=e7Qdk*ZcnXnSFgTnDn6;sB>`w1!2F5vz! z%O`#TO+alCP%d|tIbfW6Y=P_Vp~uWrH;|M?RN%<2V)TO>-UXM`==rq`T0`KhMNH48 zR&mqSl58l5Q~5zlmZE+OpZj`vFwdc6eBC5&wLujBxR*Ga8y zye%PGkjmJc(`M(-2T;I}dn8Ff^A>_7~>zQQRB> zeim9F{|2~q{me~r+@9I#)f40>V2^a5IcY>1#uu`PzGn;_${SgpEA9|yA(pi}IbFtk z^M!UqUaQiyNx7H5q3&q*4!QiWHEz|lY@I5FZX_xE#1xlzRte0&aP}nw10ip`>t6nI ztQzqECoj2bk*)3+r*@cdxLoFIP4aYu$ehhNN3kmvr%r2Cen=8oi^48%)i{~n|4gJp_|srnS2eX_u6r&lEo0C* zJvMmjQa$YloT3UN7mG}IVJdm2J$L}6#k&4m6|r;oiBgq+Z%xj>yXV*qzK85%Z2# z!9(9```WG6(`3o59Unb84u@RTBUQI*7X}$iZU5Zo{itV0L&Kj-O@uFn*b|-s;fWy? z1PG7e)gLP6j!RQ52ol^T{qgq;iQxm8)BhKeJNnzARL+Bs&v(%r`GU1zWqdZeT6U#j zsYp-e_$DzFAFNlN*gZNttIs$W**qx!LYW|lHPoJ=n~6URVZMGw%x(+y;RNk(+XFm&b&h^~_RV(M!^r$75ii+nUm;9gLr<+3{ukI!3STH7GR z<~I|DgY(imdLdH=Pr)DTBgu3Z*sdxs8!fgWmFjDN@xF;rEPv@ulRA-l3}wq&qMpcx z8_zzg**J}DnFrHoJv^N_&>@&1t&oWy?@9T;2FJSC`L|` zy*75D9E%X)B_d~vou#UYie1JFVQbANbuQyZw+vygJwLrNna=Ob_?tGZkJ8~?gZoMzRu-xn~p*GXuI;QG>LH<+V~gfdAhXU)F?J-q90u^ zlew+)T@Gpfe853V7A!V-8a3v^L%e(9=r_#Inz|$2ZOM53n}0=g5?_~};prJ0jel{M z0I3ndc0Er+qMFmN!TTrW5mq%Lc5sk60S>Nk z0{Bew!9+POtn~1V?(tp*%zE-}dD>;9#8=a_!r$)k z7#Z>Kj>dZD)U_r(Q@-StHvMymDZ!i(p^~bcx1q@)zrQuO4&4m|a5=-E-8nJ5j({;d9lj)0+uT&ucMo!#2p} z(aQEAOp7X{P#iSa-Zy@lXf9XCE3HyI zMPO4f8+h$J zv~X!;z#7=u@6tFVrx~XPNX&l$fLYunJrlv5iGmKNCKkCRHfpV#z{cE}M%WLZIycr> z)FF#=PnFe*!%{=7)KBC0<3G0bmmMsTaiSWsWirup?bSbKE(qfj&Q~7#L5xxGwof9& z$Lvyz@9FNR-&W6-|8!24{i{=k@5vG8JtoYymJ(-}oPq-z%?kpDkPWt!J+&w1xsK`y zUYhb~O!rQa^H=;#3Iu;uBAf3zwU9BA z^wu+YSO0bDKA6&}*^Z7%(Ny5FA*A%Hiv zT5i8#iM`*==o%``FYf)@U8-2udu-z1W0|Nap7fk^b=NE_5m;G~rY(*Brcp(#&gFwJ zEWwadZ%b8MPw(idq!m(DX%vkqMm)2Mn)VS1f9WE`D=^1ic)w5dRv=62dy%p}kmDV3 zNba|jA6!VLk>&VT{)>BcQMe>i96F3o&C{N&tsGI+E zf5& zD^Xxf&{2)xvER$W&969cepq(o`{^Z4X39QxbkO}ZP^M-gymxO%%kk;UL-o{m z-Y9Z9lCt;i#e2I}VGA0kL_|;pS5Nrf*8%RBg&o2xLx}k?vZ{*n4s9zcHb#9puXHZE zkJSu%i5L`IFKS7t1n2gM@RFKvfi+roiZNfq+mf36gM za^@$lA(y^|t8*+s%ql8It~m&%bFAqz7)+f;-OSgX65AE_Q1Sn#C*^qag%Hjs*foX} zL$`m^$P@Ed7{6C|c`5giv_t;0!-FzRu~f!z+g&B`kVclTW8K)X*Gb|wjQh?r7e^7? zBZ~4PRvstwkSKn~r@E#t{cNM)c#7t@XtM5EG(Fi3bi=1hHMGyG<-U+kj$~PWxVa;N zwDKq3Nq@w_OxuI)asZj_4$2N79$H9#*%uQC7Xt2r6C!SPhPQooxP{%m7|{D)IK)n{23;9ta{rKJw)<-R@Qz}PRB?)=Tai+SpuUr7XxS&XM8 z!QhiPm5c(5X~yECxQ&~529j+uT97B`^>uJdgkdczsFh%I7zNwx)SBd9S6)`zyzURI zQwJBLj6yiIMR$56N44|ASK2rXCWaftIY-F?Gp3)%SmaMi3zw?avUz&Km8E#%0^(WQ z_A;=5PdA$5*j-Ruqo6V(<3y*6&>@Yh-CAv0ERFq28Gq?0?)Z0$FYZCRskLx7cE{*r z-n9P1LBf$fBa5uDD{x=Ni)FFIPJQ0u4D1iGE06!e09>t{cd&siggO%JMH@F#WLJw% z-z{T(czI^lyYqQA$Mdj81lNBBdwjM-<`QD~9H2IR`9H$PFunQaFj^S#*@W!UT^Hvi zg`>s9#1tg!KmOYlOu#peSmwbcGgt6$>HEE#%0eW(?A*zsrIkqlI${Culsc-QSz=~^I(gsA@w<~q`Zpn;agFE`D2Xgi zq=ZBe86p{v!H9(b58P2PYGxtIwlH_1Y_kKEq!6|w!tBX#Qz*u_0;e$0@sxMqW?!0Vw# z;%2;x1NVb1t;x141$W|~TVSft*nTL5M?K{H^ZtHoYWO|E$ezn!I2D0K7lswy%n24{ zZBkA<9jSVH?R(tMY z?&5$t=VERi2%UKF;&&CsTP zcQicWQvcz^8lD%ptF!}u$Nbc6*n>gdhr@yT1_iJATyY`9hgV0wFYVH!ryp67(!Iqg z{hjz=_9ycB(;jKyk#~su;rZR14X}v^ikG=3tr!YCqV=%~Gll6bOYrLeqEeh>@mFypj=Qdn%aliL;gh^6hp{ACmvJ%xOEG#^7+ z@p&7N)TBFRu*BMY5wwBcdz5eD*0$8+;Gd(L(x20h+51%7`N54J$${Wl%D?Uaa&{>4 zia8-!0N0nZTp%K*cdN^gxtFoIbY?x>Q$os}&v{7e9=pfi0(3OfzQ*-OSNvln=jWb% z9)|f7y?%g!In+#XdIvjQ=Uut%GQ4smC9sv+yZ*vjk~8Qh{yKZa?JZxJeY(>f=73Fb zYBr2WK`fgv>=5sOnG}AnWh8ZcbFJePQj8t^SxtYEqxsb$LO>LWe!O;gBDw3;PSn$s^0!+p zKYyRV+!;?kYsqwXiGsm9DYi=*m=Nk^NdIN8{vuTUW7uqCU9aU?ZNJQsGcLt#B4VaJ zzR%N%IFZw;dEvf2rCOQiO6ynT#yI0`ydFQyq!6cV6~-51M{W>vR4~5j$(?Nc!}$zi z8GpMbWiSmk*)>Zea6m(CM`5Pg`cI}(NsLsoHf-d-?D?5TqcS;p;|5=|F8ZQtxgXeM!T8zv;&qQ+aO_r-n$~ z>`UjGV)B)cxR(TCrm78pRienh3q&z^YaP!|?mX-=Uwqyw`x2$jXG|gFNj85o_vzAr z22hs^#G0+&(b$pCnJzMKVri&m&#fgC1@8bdbH#!5dz+6F?Py**^|!$zSw326M!gR& zHhfIY`#7rn<@?tP^g;Hjr)#7&lZwzaW4(Xqi6e^{KC#vD9MKeTnA-??{uxH>BRF#z zFZ2jc%0lE?FQ%|n0pS5JI4+#)Z`nXdmqVt3;RMG9=mkSJ_0ZFE9XXMJg6oWjNB9!( z*jN6*7jIU$T7vcbfj=BuU&($fb7Z$P-hJ)%(Blw7eYw}^)DjQjs!P{h1xkCoW-8I= zAxX3eWH($kn)xw2=GSiXi|YE6Hm#}n!vgS$e#VRs%v*mAv5#I3s3m_12Kj$jq0!^UnM*7t(jbfe(8m8jVz7ySBdwJ>E>?z zIsD$+04wjU`bWd^|726PX3YoOfuf}neIY9aq}Zcpx5^Y z++{@XeXIjI_KV#7_mLRVeWXkCpARzE0_`<)j&j>miC3?~Gy4^P!QL{B8fw$Rfjv^( ze&7Q%e&wCnFk*I56klU^u=w>cHVJ?KR&%){_Py~N-&c5S5ZkBbn>01+qYYyr9rtM} zrbnC;zv=>+=ID1*Dy}$wS1%j_KHpO?GPo`OY{Wb_mj-{!sg{X3z8op-6`x7p(T3&I z_6P~sfIehX+IEus?t%gkox>gxV8af5x&alvK5olTGkUl!Lj7E7flZ04vtNzRIWms> z*OfZKY_7Lk#^b+ZF0a7uzA`3Bt7aI?^H6_F?au~sqI;}d`eVtIvj9`96=uC*p?tw^ zV?CGgJJnHkJ}a1DetwV5@z&qNy3C;aANmjBHwmuPepQn2LB?RUNm#GHUhnQsVF8V` z9gTpErt5S619$e4{~ke0B>jG1uG1*q{yL+pXDM?iqCqIw{RFAa(yMm5kHA_!o5#r- zte4M3{AGu!TQOQ^F;|GU@!4`1EpNJFIy|No0_YUO!>8FG_gq>tN30ymh8*ZoE4t@& zhi-3xBlMz}m@S`;vTDb=-H(qy@^#c6zT>B z-+Mgw9m(B#G}M$TvTC_bIaVIGUeJ0H4W7`THGz-%DV# zyt$>m0yoky;ty&vXAbg{#XS6JM|OH$s=#)J1LTJpgM%Ace5n)D&^fe4g)H_nX_{+Fdu!J@7Aj8$vkNug| z?b52i(a_$a9v#nlw(M$`7yUvyQzm#qpX~Ldg_i&Ef-WksVr+WnAlwGh+g0a9MB4x4 zrY`5oT&O_xN^aoN=6Pt# z)$X5baYqjQX6m4h@YSn5&0Xeo^ZxkCZG7?1JK+&Xho?Ow1E?ZP}Gu} z_sT^LnEUx7=V(7Twlzu#LIsKT%?f3$jI8 z<_Ly^we9!1TKk=QR~qdq|9cQI|6;~m0!W@pc?in5h#rlPUj3ZQQDOc3A`WDcyauUw zUlf2vPv_FD4t4MWH5ubMgSCmkII0J<012tgO%5Ue}Z5x>4_ zkUN2WCRgGzAh4n|6b{Y&_+?s5#opoi-IRW{m+kwGn7FFs-8wX)_6pzWsCzu^#k4FW zK)+r^<&k82OeW;Z3O;g~05c{^uAa$D@+aw^--V0IEAc)iSLLLA9Cui1AIugf6i@9f z{MlaC6W>GqlPK+eJXE`icAh8P9*#5Zc`;^N|K0`t3_Gskv(B_WH+Mnkx+2#n#tev4 zkgzP7s;o5XH=|wFCDo(7*|@*G|84^iN!lRvE)l&x-wWHUpDQCye&7_xuH$+qyMMR9gfZ=T;8qVO^p+!43%X$Gfbz<&yI62ZjTEus6cT@GO{6r*f^zg zMYN2$zn(r3ljH>WNjqrkpVtje?lPsf?uyu60Dj!RPfNb|;vO!i7jb+sX8Ti5F9mUv zZ}j~-)oqB)jUB6(sAYc3zVcWgTy`DANai?)FZI2A%J4CKJqzA(ZD7RD*(pFp-U~-ahTiQ-D7U5`f2k7of4n6e7a_{EKCs#y(V_TaApx9_;lp zwETNKf#yp#mM!7qCH>kuAGce?OIkl54ofEY`y~z66PUrZkqykj^$_J035C1oy9F`D zzmsJjbvdZq_`1|a0qgRnkq?JC~1A0r8J2cN=jdUwIS2~ zOWJ!c0oILarjR^)U_!k=_yE-pcB~ zOf;H|+C%$AYDySqj5jW-pT*91r==B$W`Gu>rKoSF9~o;OPAu*<75sr3`q=x@1?PiM zOyGfs4aWYtQiS~q-R2t5aW| z?8G`R{~xXXX*M5iX$8iJI&?fa@TubmP1%}ZxYhW3YD(=5i@%4f=K!W%8O{I1KG)#C z3z^?@w^C1oEax`{{~p-E18ZqXy34y8-#-POzUJFm>YeRAL8lWvN-IsSIEVs0^uL55wNOPX5_mGQaH}VfHJyoXMl|+ZwuJsP zK?zRpJZClOzk^*T=-&fklAAqy&6BNyaEl6(6oX6`-M^d>!A%esDAw@a(Qd;AVa+uQz5g0%{DVxz?3`8^S&AEOO1;e=&xefDy6!^j3ML7 zeO`R*nL`MBc@^AeE&w_PY3JSVfEt~E4B|jM4*BE`kKJkK9-(G|;zib#n6+>JLf&M% zRMEHf_}iGd83jx^$(SiJO#_smUJ0Lnf8gMmk4o=m%&z|NMbdS|>5aM(3`_wRqI=kc zgMRp(lNKr4qIi6$U7H;ODNZIgHTl`!)$2RvV`p5ISNIX-T| zpZVS*a(M|(Z^JOovK8qfYH~kBUm51sueB{vj0Hqt_2QPo)U3SNhPaZy@4e?0+P?zC zOLiXvYeF53gjpSP+JB}?y^vq})u&h@?j9LZIKLUWxnvZn*O9 z5&n$KpBbIbITlW_{_??iznGf>47pRAPz89BRX$j{FAnM@((6?_V-vpYTDbj2N*9kH56hYd(~9fRo@3 zod)I?Y_j^S$m|?{=pLNaQ#c?7e&v&U2dtHIJ1QmN`nG?p47Ipebt<-SyJ4%UA4Sc0 z>9k&mtJLb8nnT0)gz9;A)N{A3-HuLZvy4hr^lgkPT<_!lvBB6(us|}ew!M_2MIKJi zBL)q6w`7+`mh8tVD3MFu4>HXNH2Me(+iO}1@KMGgyS zR+B$NAb!;y>Az$Ep)0DsuGl&ac=WWS^nVY@M<7W!_2gM<5bb%8un`yY^-E+1=^mYO z0)T+X`CE|YA4*6T&c#;ff%h1G8L`WHna$ZRk1UAw;At)&`iZm}i0hoE%0<_^JRr2U zZoD?a(byNKrV6rkCYb*EyfcaZ7sT^-M?+MWx!aW9=6yZ&-0qtJYddlR6Iu89lK7^F zL%9E~dBNGsNh02>TM^{nS$k!SfsEYZZSpEgrEk8eOaIv7zFKB?eFPK_7p#zt_YD;T zb?%SThtVM5f+TnxMK(y?$)ji#GRKTgUhEzS!KW~t4BOII+_MqQh zAdMJAAK^QG5=T6!t#)kMbLw9+|KVkMdP7=FP54htP_LW_uZp95C>nf-&;0CM-hp%C zj=k{N(J=~qZq1*46ps|jF=WKL$q}Cqi06RQVAfIJwq^Ir@`x|6%H90CbGF(JJH;D-DYkejsJ&K-CRKyq-`aPa<+ z)joAh)gP%1;TVJrgUY` zy98NE){4)$`RBV@LwLaNloSJ{v_~XO0GYSe&#g-Ue|>!GC%cvOT0393ko#*y8Kh@0 z+d9Bzu16@(TK_^9p?+cRpIjH{ZKhzGw&l|8nD9P)1?!Al%E;cl^<->hVJK2UQD>}w zFW3xdI$Ql$LPl6s~WIc6XJ&WdqdOLy8E3|Vu)0fJnR|3za{z)F1G@7Z>L`Paz@3gr=W+Z8o} zR#eKa*uWpsQ;fV{l{Re<;H-yp4yjDGmdbzgnE4YZ9LXR(OCV<#wEo85r+zT?rwCUE z&$9)RA78tNbE!LX{lOC;&K>0%B#NxbZbYV6_6UzXL1%B;#4p3p~R7C#hyOuDF zKpA-=_zB4wqM?twGUnYKtQuCzdHi~PARkg~4{v*n@=d!Al}V-_o?k9ytlSVOD3FB4 z0X_tIPIi-tLl~ZSO9l?~KT8oPG8Uk0d{4rLS!f7r(yf$K*G%bmLn^Yq6Uhg+tisC) zH{y{$FTj8A#HG9%=U6nqdTGdJ383CEh(W8IxSDpB#*e+W`ymF2E;8y9y|*r_Lb;P` z&!6PwN#&~Y=zs6OnWf_3#fVQ%1nrld50bEVI2T&rBPJkxw0xnF>FiNNR&^mm2%Uf? zsev%x{T8zXeY0%BL-!yJ==tx&a#jqElV%X}k0-9r5r46ha%&_85P%*}=(PN>(YRPp z^I;U-_-|U4qsHC!B_@tsTgI!9CK*G{3YnFz{O zA=TZF`{AO=xtq%#(pMw*2H^TK=f^wA^VQvEtM*&fPm%lDpFP{`veEdFlrbC!?ZS75 zKaU?lauvgi9$Q6B&7i`|^{^v>$}pVm=qVxas?k40!d5|! z9K%w~JG+a1e|Sni^rm`2)aCJ*625Q{j)fIoFNbD(bi0%l&u{$SmbJrh${0s4_>ebd zb@wgWYwSi|3G+B`2p;Ut7TOekKZfi`bNOi5gSv)c3(#ZN!7zWh`RZT#h9p{i5|62h z=HNji(gPn|DcN9McjE6;cJZa~rD;hztwK{KAHOw#d=BCuHx`xnndQTnjWEpBE@blO zk$~_&UH|yHQJ9v6hvQYyYFHF#1j{}XD}PUeXPjw^;oS|j4S&jp`dT#2LWGX5sD{lp z%&azosR3?Vj@%T3siCj>tp zHadtr4*V%`D?9IValTacz3ldUld%ttC5!Xht|DC?{z65UJAuCB!lT1-*A zsr-KI6V}S5+oug_dWh&qXnlmSP)~lWpWO;jtGYlT&FLbMeaCj_R$JL0i3Sb=MSoQ} z^On$`WuW)7~J$yej|1r+U!sDd>Ok!<~R^9|C$E>GUFLBT(w1 z?waw}MRn19l2t4kz%;;8agUmH)xrNwM4Qi+^5Ug%x0eprlL1R(&btzy`#{xWYfza~{EyU13PJQ^* zbW9mTelII>`m+EprS93E+vG8-?%W->M<6iX9_QO`x9=V>vlY6S&?vHb?nzj$o%;_K z?8Cn&5oF)X8<4yl8%ly?uJuNS{2{z)6e^IUb@st)!bv#)EGy`Awhz4|` zYHA=N#%6*wFZRDaxFX=YKY6x$6dL<_w9!1-Dc|^X`2bbD(y94;c0aZ^^%AXxVS3{w z%qOBKavp!vWjtn2zF~};L7))qB=%5-$picP!g%~0EAmWmRC^I5b2INnB72-5?6e3N z@Lmh$`rnB+Jf+~k{2M7{ORa-@AGn*BrJ@E@wb_lwU^}j#eP#=+?MecVO|N@iKD*qAHkgD; z$LYS0Q%16b~Bl7Cf? z-G?n=lB`a?IL$&%a^$QaZY{2ulMB)r` zk}q^BT+lnJ3aG-ct2xNo<;JDKeE#>Al#^3U|A0dI+v9cf!NPo2vZ(>!zz?YKEi`{} z)E3OIwP~j3rc&Z7jj#8u2sNvF3U3@T@X&T~>ixN|<4TUa9E8BZ=z2CP@jO z<_AxsHRbN-_Eb7VQrm1vExUo4QkYKKs*(Zmb?0*~+LQij(bs!=Skcq;hugS3UT9=B za4pskKZS+DDaYAtW`Sg)oRWtsuVZ%1{0R)$d!O>XP8vEy)UUp(uRZwh-V4_5wm)S$ z6ykkJ=;ML;B0H4hYP>Kqq#VBJLqp!Wyh;u#{&*3k*N&ixNd29=Bs)Ljoqt`PpHs^& zALB?rXvz#e$e%yqdB+nD56<{^ztY^je;m>d5t?q4hP^Z%Pq)o`dP4f0;xrdiDmcEH z_dc4Am8rf|dqGW%LeAH90=;IvdhD=`@r5FvLUOyY@P?2X)4g#<&VhSp;)COfqoaz- z5L%|zoIVsJJVyS78T2RB|Bn3e*D3*opwmeue-sd?x^+jvpI_;V3;^|RdOBVcnzmG+ zo;&_{i2KI0>DGTV1vVVDm?YDkipd9|2`EonC zdg4~%S*l~>Wp65T+?|n8X+G~6bMv+hapg)!f$TwV=mnAZlsJ_tl+mM|b6L9Y<8oD>^c3EZ#TK~pw!{X8a5{xAAqM6%6*~Fc8OVkaOM&iTdj~aDb!${uDb93 zZ1k~}RvU$ z{|p0+ai-7fa3MQ?bVoBf?576@%OE`n3oVa43W% zSB~e`&yZo^KW8XMcFNe^g5y9qNqxTW`9D*xZwd;Lg%>+tz)`ccoM;+layo(C`n~93b?53EY|z41#wtETFtL+3}sr(+nge&FMK~%O;i_O zHqN^pp(R*1l3GFWOk;=5Lgxu+Eo!2Y~iA-&4*B@FVZGNWKj; z;=r|2bRBajuYb4hHyGsE6;WMETrqm&ZUMdVpAvZee;nyT3@@t_RNtd|6iKyIx;{W# z!a^&$DF!gHu#sl|dw_p#@oU&m*-zU`Xb!+(a&S%dlWhm7}OrT2>J%IW;a z&GW`qr!XdV$&KT14LKj}GD+1fK31rf!ST{aGlXRH5Up5?+6NwD-Xi_{wb}JI`+mEK z-{6BZEO(xc6z?Cd6Q+yu@0zwAKB;UU34lJ0TJY`G;3P>q?f10MX1I&JfgS!fxX}+F zm0(RmO1-FvyX!H`=eeAeolbnDw|2c9UD*kajXa_ho=2_W{Dhf%1=U2q+?*q+6h#Ax z(pVh3T$@taS1otcee|Jm_nmY0CKcZ8tNQr?6%nlct)*3MxfW!!H>N-NoXQ+~fm0nH zt@n^)PNK)w%pLyz+jdrCPoIM;{%rDDUr{q2EYtVEEHR5(-o{c4-S9-qL4{DaS**va zshtu2MmjX%{Y`rCS=yW$UK{jSy-N^YW?fb{F1A92=DrIuS0FJ z-*$Ezeohv!a0{e-ica$vKT$V_9%Qpdzx(*2Y2IX< z_dp|)nWS7JSI!n=DL;YHDfAoqtI5Ck4LWj0mx~(i|0311-}EZD*V0q$s|Sp>siMEL zv^;t>KP|jFVI=#6637PE%c$r3^4ViUUL;V8>3F9n_O$%lyapos<(8Hys1~c=hl}Rj zzFuoe?UXLXrMNaa0_DhTw3X<5zg@-60MlIml51*G0EUPA!N2d4%&E94(eLsgi6@!&6 z=5jEoH`p^1Cq@0|x-7*=YPWBOy3Xy-oweln`QCHW2ryUd(3kq}etsX=`wi$Yy6th= zD4Wy2n+Vy-ck2BZ;lC&cI=Jow(8hEjEBaTBih7y3@U z8fW1ADowsFZnv?i{vI-F@gAVsmh=uyOw*lCu5?W=XcUcoFaJsVW4NC%^m~oz!VUrw z4>QI&SN5ra12+zA)f)_gPlfuroBBkAK_7aDGr0iWS zo)$MW5TH~0*`5@!=clW2c;zsG1Q@KPT>pIiPH5wGy?a3o7$dR#d!L{lxZ0OOsH?|E zmP=wXzpj3ot#?KU|J}+1{>cru>IA=kF`OKKN00A96OU*&oDRQ|o4if@+b0V_|6tSU4)JaRcSrY&b061R+-3=orI(12cz{i@N;jJo8{L{?pk^-Tf*N zQ*6h()PrFedB@;Mpq(v4rfGSc-JA6EG@#-<CWT#BOrMh(jsT?gL=tsyH2vx>-tkH<%m;l5rQ`4wCX?-#`NN zxB@XnA2yQ2-gh{(U}i64uzp)ww33{E56$%c(6^TSPPerGnm)u*93Eng&WI0I?WkXL z&9@igv9}^oG2fMh4A9qjAEjszyFtK=mXBZs{Ws2E>U@u`thDBIv>+3kO3 z=qDiP^n;l#&SG$tLU|zLXab;%>+X+!*{6|jxqs7VXjp5POC%&E;H$~DGDD`+LRxBv z%0aQ+{-}4U`&a@1j?&2F*1OnZhQn#65&ZV3Af6(O?A)zvLkq9KlS+&~^6_nO>c89c z-Wp`XM@a0(?J*xiKL#iKopKb0DvO#}>g+=N+8i52)(|ZGrprX!?74lv_OJPfltt|r zx@rdgy8EHfimWhAQ5OG*l7~}>%Ur_t6QQ9HCcxgqm`SpWG>HMW`Szz#W3BqXW$~2q*N+^vn2ekE<6?o93i^Z7S zCfPLPKRGb(?`JBK?PqC%eJoPIU#}YEOJSt?%~Bp*Ls`rGmfv#?#d2~V%=Xlx{SG;? z8Z_Ta1n;h0XX@koGGw5Hh zwkU5@i4)^S*&R3Cx%yej3U~Qw`@`5(6v}y{5~wHmKIyXF+%4evy3tcO1qw!$pZg%y-B3{gewRqnSFt4 zg#c!RGwb=UE2HV|u&{2;?c4(hzAsYwDdW)C1#hJ~l1$K)V zVX=D&-0-cEGs?n!#b_#osY1K_SV4J1AcP@<2%bSV$^I_gdsf7Y6!Jn7=wJPDSa02uEM&v-2)Rk3lnVdk)>1!8HcgtplQc6>2RWC?NtZFJ@^v zHZSB8Ng0E^cFBHKO;!@mJ_W@ts}@vYw!fRa{QbzU{!2MpZLb%p_+U4k);vYk@{iGF zjqX4?P!D@&6|uSQ40pRcsdI)(n?v1afRBD!0*!W$Lw)G2+pQ0|@8>{0A2i}btxvd)uo-4@#14V1%OE1|F?VUC8qe=(o;6D=PB zmS;{i?J0(fLnk<(mI9+s9;wQoj`aFot3F#o)u={(F_T>3^-gdz@3{x%WM~ zYxSvZt?kx|f>;l`Edg^rAp@?QR?f-FIRU|Btz;!xIiFUN5n^{AkKiCy@K6DTQWXa1 zfPi2J>~8Cz90mji0ReYKK!;(fFpM$<-d|>{yM3NN-uKXKwUxJ1YMx4g>=@O%SdGKv2}P4pg;nJT zzMFpyQ;L@5UP(nDuyt+Z96*8mERjop6s|^N>Dvt8&d#sg#p&caEbxIUp3AGLYbB=_H)u=Z*>2wT0I4>eHmPpj)F@TIX9h)6z~Ie(dlc(_z8>M9ChE~18C6{s#U*q1Sid`_5=2pU}7=EB{{xd{oUhlvQS3QNRp zXTkz}Ua7#t(Zxfs0Gel%j(Rj-1U$~ddIe#*AIdOi#0pJcUDDjD+3JGk*2Wgc%`uut zufA%vL8~tbUf)D^myiqk(^ohec=&uzz zH4rozl`B{@MTl4;S`KihlCL}f5^$|^!w+0JV zT&*HvR1gsr4xUp9ovN6pOl36sObxl=WHsy0g{;^fQoLGFK>M{G#brXGmkF$eQjHM7 z9yv-X&C)d3szF7zpau;fBuwjy5qU{Vt8+-f4T8@)gcshgFRjOAL6RD}#x zQ>`SAA|T14=!EV9kpo?M5u1>sG{pp3XQ+^ES0E4^(o%2HM;Zw4ah~TCKSq=;PaMeay3D`)X>Qc31OVercJyg zE=wTZ&0uRC)}Z4lS238gWF>)1qSsigb*r?POBmTG%o)%gUF0dH2VSpq#z1-0cVkrLIPq_ z_#tWBYytZ-Q!*#Yg(FU#8TOq{RobM6pM}=MCoHCX)}5d&wBE9`A(Thmgq@ZF z25&CL6iRhf%K0l$8Va;lI%cUW#i?dOIxEsB*`mP@fA)MJOQ_{>d6cjvb)^Jnj>TyS z;q=II1z$|;O9E6$>8Sui8dS079!9CH)n#U778buoqaLvcs>ZG=>`5tu5b?J?i#@v? z&j;+Y6po0=S%?sDvnl#bR%xiNi6@ngASh3V8wh9~-oc zaV;#TTrwG_FlM2g5mPEJog}QqAm%VrA@#5Tb@DQGE(rs%j8GPawIX_#Jcgv%ql!0b z4wx(ZJg6eX3a~XMp|X=BTCl@pH&l>W^dw6|?i=(t)Le~Kr%S~wM3K4x^sc2O2t_u7 zE!!mL1}i2lr->v1&64=3j8f$F$TU$0YNUoz#i%C~G^GvHscPK`sj=1`<(zp-#K~A1 zB%HEXXrLmg6jO7W-LBSjQ+Dz7qejDJ9a=_8R zaBk9F#4%x2SaUoxYCLJzcw4HE_0n8lXdsc-6f z2nqDSw5BXZZd^-Jdm6; zC<@79S-CBo%19$A&KFTQlinZ$j2u+^;}q)Njj!$L0NC^yFgp_72oP&En!I*rc+q8wstCrs~xnuO08>7{C885l!&Q`P zSYuq9YowHk6a&X~lGE{af{ZHc5rA?e$%H}55MEXXi4LE6ZGMUOTEi09iT49lE>WqZ2v1#5} zO_nMZsx(s8t2-Sf zEGh+toLpqAS4s_u2xvjDb(%HGh|NJ&6;?5N95K!Tj6%;a!FcU)JXPfATm*NQGLw#2 zM9qca_U#S=w+g#!qR0TkVPQ$H8I=$hGBh+PG$cO(P|ZvuMdge&OuRD#~HEt5uOTA^Y5lwM~k z2?8G2OKZGUr?jES%7tz=Bh7m4PQS!~`l?o9*GX-zNLVVf$_U1l2(rkxRM8qJ@R(V# zzZNK{p)#aV({Y-bk+IEDs+j=Cu~j`X%8?~iBJ>zT(^6yPyt@!7m{K}2myT(@4&(`H zU|dfMX;6bwK_=ier}HJW<@nSL#K$rR zjoJ%rMl!qG43bQm| z$tU0+;thu!;EcIU8V6j3Ik(hU^3s5FYSV&BCR3~zl3dO0tGLX(JfIYdJtPBoSjinP z<}9v~C|#=)JZZGrb5?8F-ta?QB_x6PXJw(B!2z#pbI9!%2jaP~ufj>KX*Ze&!3ER> zWx}-6Sdx@v(Sk$}O6D?QQf;U}3L}YT0>VJ_>4?@9(#X-25%)yULneibl#9}( z%U0Oglz3br?1R+hgifO)OehEi3qBbxB+9?MCT$>tVV5CR6DJ)yQ#kK8LrIv|Ci7H| zp?HHiY$yqMnXRfw=fMedq%sKqy$wwaKzI|DI&goXItl8lgjpLXqhAw^&ThSj&~u7< zGRb=EIae|VRsm2OK@|-(VX~Z^7Yg>I6|{g4tgIWz%{tPHJi;GGH|+3t1|T z?n0#dkaSV%z(z+3C<$qJ*c=JSl;wstnw^$2OJAB5`uU`?l3XXuY4zmOk zNX8N}t}DTGNkl7sE>Ea#WdL5S8PhR29dKY>Fd4lj23> zVXLX64nZy`jc_c0r||8|Ae#$sUyILz30$vv+$NVPKnZ|GF{r9pUn$E9(n6)0^Jy^+ zqV=%EK?>?bi1s4sWUj+soJ$%3>d7cn8b9wu|EohU^$|ss_en`v9uBHVcrVxGT30<0 zkHi8R!dc}@r2=G@;JOlSjYb(ld90E)7llE{qM}tJz)->*FVFC-m!i$aGB3ty(Q=Uh z4u3k{8*tdlJj9^B61v<2K?{t9Wtfa{oj$UIRZ33HI;zF$9gHZ&@7IGpBc9j(m z%ybnlv={2iMuW>=P#Ylph7)ATA=E}<#y|yx9KAK3s|VCJgVvOehGKH5R**m-XoQPO z(Hb^5Q0=s(O%N@ogoUEpzyvEOXTVT6<(D|=WF^!nM1+w4nwl_h_}r)sDo%rms?kJM zoCIEwDAN=?e2_D+vS0$#$-LJIlQLyetr4N+goyyTse*Nwo!6li1MLtYO&C1cki!Tb zfhN!CC3ZkZM9GR7xl_uobx}=x72$VTweCbFu5vW$7-Y#@j4N8o1Rc`K>w!q3QmLo~ z!I;za_s-#Mm6FbxZY$7S@B8-%i zaLV!_BwnmVzs2Ors#0lvoe#vkaNjEm6j6tjmU#7nhE$lY231BT5KWrF>8^VHPE(;+ z(xyWqWlEBz2`VTf(gl?SD0C%hVr3PtS)L`mUbMYJav=)_R92-XsB+f9f%G`*dh8kF zLMC9Bm=m&8&ZiGmOL)Lo2yLy*`=mxHUhxM~c63r!3hIOf{CSnm?gD2`2w9Te04Z%e zt1_d1LKlZAp2DIx>Af1OupTaXoIbj!VEI^Frtq0j&DLsIpbbqmKsKFnxY&`Lkp%GB zlq>{e5+k7_2-rqJaO_eTgcMa&=~#7GU1^@Mo2-Zx<&45eH{uGHE3I(K+^BrO+k+8N zRTQC+*(#&i%$c=9N+=K;tk71ZWh$bU(km#E&zK`g2(gI~IlhG;WxP)y^)S$u%3?}1 zCb7#D#p=V zYIm7XPYNG(A|QiR6U2WW!Iz{dnqS|^iM zc%xOC<-$35)}sgnPzOQBs(jP3#g7f5Ql++3NmJ6`Fhna2We!4ryC_v-8OmS*%`az7 zRuk~?ONn{5=0^vdM=nbg}bp{EWRf__-E}n#W2aKwum15E* z4Er@yh0KfeE}bk2=05OU0*_o(OCbh|5>iJlNCEraq}o-byp~1Fi?NZWNK+|cwjoa+ zti?ca$zs!PHET%?dg#>_OUB8ivsD84)g){wHJ}^i>UknzGsU>%h)r;=r9E%lr983~j+hJ?Afo zs}^y@6E&PN?qq59sSlk)8RvQXOC3Qo(0w?FJMJ~|f(OH{JYpekXM9t+wh(U3hRaWe3j%T*p3 zQLIy=fu(U$Xh$eT8G=!{rNjt{h$>lUD@tb><3#5Mx(|&`GO-!ndLao{A!K=tHlC2# zGZyF?>b7#)6?S<|EDY1!DEkLUAFsnB%dJA!3yC~J(g9E#OmEF>`cgW&D4gM(TGs$(m|-~sTJKKjjEKiM=2(ujw%A_ zny)NFuT)+rgEL^=Qm2Cvdo`d^^G=oBPHCkXsaIoQ-L{M%sU)@aQba|P*&<~HqnBuy zIaA2X`jrvC(W!->ZBByHKExs^6ZT9QL*1lg?Y!AW#Wl3d&iFlgBIGu+4O0U6KqKAy?-Jzb3Au*{Ue!K#XUDzl<2W6Ew-C1rZpW6%h7%G(io#_6Vjy zMDeUwXRUsmmLUgQOz5#mp#gPpMV?Y(zMCY8yieoMrZhf>Sz4({N|LO_B+cZ4Vvuu{ zVlC@%a~Tz^#|?;ZbOeB)nW7M|BSp+hsB}f4N^f-dv!JvK)UvY55ztWJTw#n0HH_NW z2>H!Gg-|hqGh29nTw4w1O`d47=4XU4mWQ`QSzHcP&=v> z)EsN((SKqU~(n<8#F@7PGk;snXgLYO4Zx zN;mJM!1ebOS#4P1GDk~kdzxYy4O=gg3O_v9OD?%Jrpllz8w6jUU4*ix3fU1CP1#ZR zH@F)mu|2`@0vq_9#$XzT-jzrs1t11#ED5quaRR<$Ww0n@s|qRs-v&i3$S5TeE9bB$ z{pD2Jm;hYE9%G_4K}8pe)wSr5^5-3y5~-vi=1%cdg0MuS(vmb~kSHa>pfaZdgVa<= z%jkj<`U8R<58X50L+y$3nVJm70?q+T9Xi$)uA&6!23^F8F=0Y z&829Z&3O}un%xGlx^cOEdAdlslF%zjt%0Ztt(Fc$v%gSD!4T0FMwvy5P7YGb5eZPc zHA+3#kQWWrH1t||K%qIi#9I#2XT+#HErt?W@L^P^s({36v_Q8n zGc=nRQ0-}mm5kkBaCoA!VxB_BAfiJLCoF{6I2+H^Xo+4g6~fzEq=cWX%~Ez)!j+OK z=!1W>mM22IFjEVca~X*;SaJ)60)tkNNymdVe_5As0ytbmxT&|Qq=3_E;IHN5WfbFd zv-v1WA7Zt*ENRq{&~T=KIRO|B^&@XQt*Zp9D!{=Ru^P7QdWF{8zp2`DNW zv!-cs3oeEtRn0mYa3~MyxRfVnguMgwqZu>0lAK<>*<=N4$(IubW*7#u-Sg{n~oMAQGC~ZpzJMLK;<21-S=mWT1M=;qR6tv=&=T z?DA*ShO!sZDz^-KQn9(g7$K4_hJAJ|6D?&7DK#LRiUI=^7e}&cGZ0(oaM9^&6(%ob zk{Usvh^?BNNaLaEae0%j5J(-cT}>xtQISSMfXKrnppTYlBtcqA;4!E*rTp+fWkm!- zYyDg;qRJ~&mOw@xCeu1k!;OAh5L84mI7jFFseqOU*klQxS)0vzgE0Ao(S-n{Ri8Q| zwIGl*X)Qr*zyQU3-dTwNIUO(Lt!`P&B66WM3vN{TDk2~WT7fIcTo$Trdsc_$ck~KJ z!7wC!iWrREVvN0#Ht0d=j5GxGnyMBp%it?*;uVC7R#~eY6dZD~NvAGm7(iGpx}sPN zAJYspR9;;%kxEA#e7^32&jvOmI(WsQeS%7f)lEE`UFfDOS*zHo)WIRgRECKK5Y#Ao z>Ybe3VJ-NIwALqqagbLiDT6;3Bci5sS*lcnqbZ@XY}Lnl#X!RfcuKCVBj@JTiwIXU zpDE3jX-k?(tIZxdfPTkdT40BiJFQN6l88V;u?SCA(CI{zxtdv_a_Mart(i05ZmqiHl{{vcyqwR_iI7*RHnl zNHxKgCIi)bL_kUjCCsn_P;F5(m$sUt6%A$68A32ab0o3_==!7>B7~KO?WW18Ga2KQ zMT+{RG@1>>U0GJIv3Zh3LDCZ8I0K3NKfq#&6pKofmCb7-v;)a9rPpY&)GAcWA}FMF zECY{Eok|YdVO|z;uvM!7CJzp2R;LiMA*U%~v3U8oC7ptsxIPM5s8OYF_V%b)G65)w zOjgZ^1t48;I+3PX9|Y>mp+N-Y5S3({ykYg{6-BFviRA&z(iE~4V}v8JHirz+3v6mt zT-Dulgp3-k@NpDMf&wCD(&?3XWQ=687_4goU`&;5l#>%mZE1~`%xP&DBC|RKAGu&a z=StOJZsS*Lb6%x0Rz=Sh&01tCpEihH0{pL)=w)yUC_Ukh5azVjR<}#BK`2CAI&`Ly zR@6~sDzmJ{kSz8+5JbAARDv;zLn>9Yz!*d>yUYa|S-#Aq>s6FAvPE-3OQUT;K&g#Rw#Y87ld>{oE-ke?|k}DlW$gag10iK33D-e!JwLL?UKA)f{ zFx9dk8VJE%CQ-%b2(wHham3(I3*>$vhirzRp+&4E6(Y|m5F_h@oP)+dK!RZ>WVVt! zSw`Zsl7;Fg&1#!=nl^19?$h8B8sM5KHYX`N%OoH+HP8{>t8*}*DpZXbJ*0SPG=60j zT3?h9=QO;=Pm(fG(vgJpqD=WpxD&amJ>k(etd!d6E;-XutDb|j1j>d0DRNuHA${2% zu9}P@nSwXU&_g0M5n*KGbwNtOhvQo8DmZOSqVomma=lnZMiqVO+8WETD$-xodiC%< zCWv?eDyd{Cp|**NDzU|{^rMVzkV`b~u-RP6R7?%RRS>yVCJz2oHf6*@CW{h}CFeuS z1lUz_2~y!i8Y^5LjRg>C>rJsR^0ROrbHhVhsIyp9>Kw}omFTCog(#6uD=&di3w5~3 zP>NfmwBH@oWEo>9S#|!ym91z!dKG|86wyc;1$tQT#(3<3jdaRr)4ST*q zrNRr#ZVB|LZZDtE!95fGc~dx_&5lKNu}q_<_ts}JkN`Du;d$=qbR2q z{Q)a8^w5h24q9xOZ$6wZOHL>bl9&BZ_=%OR0vt3;eOYtT`~Lo5~($eEb2WZ=k{ z6C4#UmyIR;2`a!x#4*3jh#m!zrXrVSOo0Z7ju7imCzaKc;;g+KO;zoLgMuW6fFXfOTc)(U#eptyPgoBB0+lYK zprDXID#e?H4Li#_2%xHR*v6(*Br7g4T1g1}os<`ms7@)Vie-Mc4=&r0$CD@M3V@|nT<oKz6|;{n=R)45 z3s#NxRFw%qL18HK28ER`SDOW)l29bHrlF{U%+BsJ+frd;Dr$2k(Tqb#JRY?{QA50n zj91*Ibo&da>HDA#DHkoQibZ%28%O-nm|b4EzQFzJ$X0;0oZ&!&^>_BSw6xqluBC;VyME^%?zs9Y z<*)kxc+Z_x8%wm_d53W7RfAWqT=^3Jefzt3;rH&2Rui#%OJP?0E7_l%S4n>L$e#jN zNq=?hPm!yfzasuT?tB0Hr_B5F(SNz>s`bftHR~GJ-#UKobvRB-%ePwkj}j}-ymQmH zKiagg<0lOB*Sm+WV@^KthwHb0N3whSFFM}7`@ykR#SeaG65aCgxax!Rp5phs@;&9x z%$qzDyyeC2i{BpqW!dtoWySle-_H(q&ARlrbNzxX^`Wyzh3#AY)7R_oTY72e@U`O~ z%DuU`@1S|(r-zQWUTl2P(KYAj;ei_(!++U!_R8f0*(+bp{iJVs$B|7#7Y|)p(qG&- z>)^3>_VjZ192uLB&1(5*FnN%lbnwX?mo_CkjyK+z{Vum+c!73R+glTd7f5i^jmYToT>b2D89I^_~oIumbU-pQ0GC$a!+^HP;f>6 zFUXDW>^SzpWXbMj?Yo{)zjprO6H|@$UjQz@OX` zxHMVYet>>!J-7Y+o!Vpu?5^>(#+_Amatd*!Z|Lm0_b`8O{N7CP2{1~IbhUI_+k_Y953Sj^=#p&5hKaZ^ z&s%UkPIuXRuROL>e2==fSG9fey}jMO_fN7%#;7C;KQGW5RTA|}o`u0!$JgL}mc+T#_L-XWE-u(Hl&W%epC(E;U zl}6ujXLsc0LdO?Fp9FS3xH0cOH^uj^!oO|N+9mYS9&+xj-0H(OZ=T)W8XI1AdxPt# z2M-_an?g=G?!SDf*J<3rmv0O`eXUQU3-W3Nl%^FshF|j*z?;f z>Dv$dW#Fbo7ow|*?|-r0aA9;(S(~4BG`jk=p++z{v}M!40#di@C!yXm3$7oWe6n{# z+sSm-{MP>v4{yGX?z*%4>cWxtmMuT_)-(GSc0W5Z;dXZ}8k)HJ?AqpAy55*_Y{`a3 z+lRv!RLa%E>jpQUrPh**x2t{g6^5w?=iIw-)wMTbPCWk6dt-VRe?4D&LkF{axB3P{ z2R{wIb+B{OR3+7IUwdw1_mcG7xjqFzxLy< z8`htXp6J|n@r4&>_MB#JnLp;@7iRh`f7hZ*-(K*|gk6l4qviRh#$Mm@j`Xp2KJ#Og z-EaNoBt8kWw1~es_){1JNB*e3_{`7d>6hKo+So+AK3pBw<@?sdtD5gUI9R`Yc_6M{ zR8M~vO|GgJ5AN9S8{GfP1t$V6q9x6%@LuN{x6nQPz^~t$`P+>vU%h?azfS57O+EPL z;IYH?U+?XU%{SC7`i{)$8+>Lgx4Ztr;g!ce9F%PEwhlh{8>6~c^2-UkmY)ddwl2d(Q1SCja2h>66dR^S&{4QvX4Ac=bUGTj*e~%()PH_u}gR`k2Pw zKW9v_AegyuWsO^E?Y3>XDQB=GJ4q$_|fT zP5p{$y=Z@BtYB@gy7#W-^FQC-x%AN4)c7TrtUudZ|4=_>6;|q>%?|7vJxtd&|C^q5 zbGWYCf1mv4bLzi%cGk4Z)#2fTvyL||fAQ6+O~S2LF7FTJH^&}|w!?|lc3bPx?kDd} zwlC}yzWWMUxi$Lx*sjiH=Vzt2W%@VG6b@c)9Uu>8S0DVPfAv4z_LUDDzx45uYPl&(L>H^-8;+oYUx?(7m#M?!4Iz!;H3``)?oD zea{iyt!pP0INEd_53=ENz_I)z6QgQym^`8#p@k z^7(yk?$4jRm|y$Ov7r{rHsR^}9ywP%e`QNgOw=~CkD7Adg%?w=pLla<>Z&(d|GK@m zdg!+43KIt}{PVQKXU)3&*FW~Joi(R6yzi$=KfL_a zQU2B5CtGqq7GGPtsrjs5NI&pub1EwN=4E!Y-ty_rEngj{vJ|H z=-y)g=R2{Z+*mJHwd@x+XFeuW&)~2Bzt8(`0t#n_BR)hlWUsy z>Gf;x`eq&a`m7uOb=szHLXAhq&Mlt5hq`61PF&CY(lzw?i zQ4gE#!>clni5|UbljzZ_x6im${JoYte(){g#MbMkyz(zza?kyrU*n$l zh)wbCb`${ZikxZQGSEhk9QK4=-=JVeL& z&W9(BzA&_6{@~|deKk$6^Pb4=7kcOT<-=`5(mf+@Sas9IK-*?QckjQ-mp0fT!8m2H zpTB9tPYV-A-up%9mH9UPI;j#V2T@M+SCf?n=aLQfDe*fqhHb0OWV>S8qK2x4o z9}-Hsle>=XUbnngEN`6q`McLHU-$Ae!_USZSU*ijjefi2BU62*MLB)D_x(*zgg$?+2}oh&H+P2!(>c;N93`n7%E895zhgL!=4MBxWJ7R3fTL*4tQoLZyq-CH}_+CAZ` zj+w;hWjXs{_h;`;FvP}najDIG?^r=(Dm6T=b7SvRU*q4tK8$8OcjCVIa>*;N{Vl>w z-M8hj<%JGGk1Uzq+qdQ4r{0Wj9$fu?_k`NDt4_AAUczqPl zTi%{nnE3KzU;n<)(LL~sgCnoFWBK}lj`_#0oIjU+d+x~ie0t&7>p#GZZfW3rzW(w5 z?WY3=)VZ;P2)2D7M{`MYv?ULg4SblJEqVIObVl7h1qicJr7k0j%KXf6d zr`qo9ZhlBh?tALqa^I8BckgZW?{-O+4j&!zHc$9|Uqf&ruz}uv?9$3l_nqH*%Kz4y zC8y3b2UJh*`0~vwPI;wE*Ndrv2NpfF(LAlu%8hSs$nZXXN2j^4Y`yi4W&8H8d-T|) zK0L8@M+T;Z-q|^IXvyrAW89Kc)Y9ihXWP2>o}u-XhwER=d+l#8|HiUj(|%yfw60*! znPRqa^xPux-o7XQZFFW#RQuAGe`jt#aNln$SGLX^c$yv;{dc~n)BMGr_{hXv_ujMg z;EB7jFZdh%&P(it&iZcd&tq5dYbK4X1%SL+=h?$Kl9UPFTeG8b3FZM zp>*TUwiBC&&K&ZpNALLB%p+sD;l_G)_VUv+?cA%c-%~vOsdHR^&uhakE!OwnKGYmj zt;6p1XPaXxF=_NNKd_j-YV*iqv)$Z&O$rM<7KyKadimJ2+av$#{d&#&4*q}UAJ)7N z_ok1C{`LO7^PUb%Jdd6>UNxEAw#D2~Sj^%=+h_2sGG5AC04TwrK<;DfHC z8KJV}qujv2z@}N-uKexv<%@ksuFc)pw(Uo~bI6x2wILnyFt?}k;d{n4m!6fSi4U5Z z*YM?)#_p@v=tq8B*30_7{(TU?|DU5{bn?w2&FHutcl|AmSDNEPv}0!X4ZQu#$c^_-zWH~*X}-m|u>G2epEg${&kFh~%m4ba;JChl zQ>T<|bkCfbOMhPI*?Vcn%zZo6YkwPUta|AeqlY>)PVhy;I`fm-rFlyhv?_|N{wdD| z*^v`^`_1K(eJf6V@tq0fj@2hm?`&7kB@g>YziF(}(K|3M^VDidtbfDmuE)<1?_AdP zB>Q`g_4OZZJJI#|V10Vu+17oFHXAOe>%Uz+@WkGsbGMJaclVc5eB2+Om@+?GUT{~p z?()n=xUsSK%3#ki?x{29LQ6j#vv1v!uBCm4<}aH4nR;looc+D>Y^k~QudM&i_5;!@ zapmL3o@(&cno?R`TzVv8fvz=M8{yyJ{ zV|TKH9pgBzv80QB>YL-O{Gju~JL4M%?q62CB%2fKelIoQu3gKM-IM#eUhG=4NY1YI zj^0mPiR|1@XV09*Ss!UHdm5j0*$2ADALv}SJHqtr{w&bS^^Sb{gtzGQ>@{rKTAI0}?%y1F?3jH7q+rprgRzgQmmPVarz2)td~GxBzG_tlF= zzv=t``=FXI?)t#{|I5psEKU38U2T2?SmID-1x(O7{dvVBh_|6I_#Yh-nKS3UpjhDu2*RN7Vm+RqT&O= zqJE9L+}I{Kd+NZ*INs^nK)0HU)!z2QpA0|K zMz1@W9P^{rwWl9yUCf;SkUTr<)Ztf0rjg~5_M1Mvw)M)*mmtBWpV)d~-;3>mQ`^hy z&T^%t(%rK!ytvjddZrV`acgHWrNvxaU#@Px zLq2KfrWZJFYj58hJ2&t*EEt^EaaUj0g3Tvajf^^6p%;g19owH@a{1Xqe++e>-!0y< z?S+A-cFJcxHToTHn(RBtZ{2utfA6WZWODC~{gaAowwEu=sidvv8>iM!oqwQymVD`& zD_>uQSLoU4JG;h3`a^9G+`ZhbJGtY{wM#aK*6us}<%O9$Qjc^E?Js15+}0nC-pKlW zzPU>VZu;WO%UAuL*@zt2NW_OV>091^SpANSu71?~r^Ayyk8U4X{nkCHG&X*{?d{GL zP?1G7H<#}ixeDm{C~T3cyib>`?P)bH!vv3BU`c=whW_fGq8_|o2i zGkXWIfX$>Ujqj#L*N%0X?k7vD4%98B+2pau+V$6rp5UrV#}e_v-FuGh{&I$T{OG^2 zeSrni`fBz^Z6SNP`^gX6PK@b)>Z{8Gy_3%isY%!YEze=jEpXr6DIe* zS$w3G4xMV-zq|c(pl#CH6@wdQEa&e%`SUdu{KlKw@cLaBhUcjUZcb#E zcQaGh-qbA`nSb{$Jl1|-*{K;n$$kIpD>>OWfBEqZzfh0f__+1IedE8r?+qswtpDR- zw0c}0_s~C{*!fb&{Jss}tV}PPv)%Qt25-m8^xTe59&6h+?c(Cu+|dPXTN>lqe%sa` zJpS2`X35A9#+CE^=97*Ov|HD{zKQ%a@Y3SZfA-$z>v`UM*O4PLZEqIpO$Wyw z`tiEHCuZ_}hxc9zOyb6V&fnUr8a;Taqt^CJXw7X$*Wc9j&atfmy+j|`c;%rBm-li#TvvS{{*+68>hSPG{in=Be?4%xtvG+Oqpvmnz^V&#_MW_a zW%$f-8d1XUAM0)RF268V^yH%lny1@x|Dr|h2mW$~O&>e5t+Ik19C=PWt*8I;Ks-QW zHEOi9Fj$U8ABuPq{$OM^dK!cB&XFO$4r|*;+;;!XvWX^5J+BW()#Y6Otkx=dq zJTG-4Yuo?dgEh9hj&z>w-lQ51-ge8#I(di1(tYvGnX66*{#qV+A}}w!LZ^>hIJlQv zFL4rz2p_3s)|7LS+&Xkjl&yVlzd++elCDLtM4z_WFzn`^t_|W9y zr?;=UzxklNW5eS`)&u=b0+I3F1W>tB~66yH+d)lNI+2t1=>WYm7axWjVBHEh&Pow9-(dX5~ vTYvO_d4L$dzK8$a;kJ3&FR#`$cO%U-(B0QQ|Htw2)*tNJWE;FXH{t&QLy|>L delta 53685 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, boss->parent()), CommandSender(boss) { - const int buttonWidth = font.getStringWidth("RunTo PC @ current line") + 20, + const int buttonWidth = font.getStringWidth("Disassemble @ current line") + 20, buttonHeight = font.getLineHeight() + 4; int xpos = 8, ypos = 8; WidgetArray wid; @@ -52,7 +52,7 @@ RomListSettings::RomListSettings(GuiObject* boss, const GUI::Font& font) ypos += buttonHeight + 4; ButtonWidget* disasm = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, - "Re-disassemble", RomListWidget::kDisassembleCmd); + "Disassemble @ current line", RomListWidget::kDisassembleCmd); wid.push_back(disasm); // Settings for Distella @@ -151,7 +151,7 @@ void RomListSettings::handleCommand(CommandSender* sender, int cmd, int data, in } case RomListWidget::kDisassembleCmd: { - sendCommand(cmd, -1, -1); + sendCommand(cmd, _item, -1); break; } case RomListWidget::kTentativeCodeCmd: diff --git a/src/debugger/gui/RomWidget.cxx b/src/debugger/gui/RomWidget.cxx index 52b2e81b8..9b387d69f 100644 --- a/src/debugger/gui/RomWidget.cxx +++ b/src/debugger/gui/RomWidget.cxx @@ -113,7 +113,8 @@ void RomWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) break; case RomListWidget::kDisassembleCmd: - invalidate(); + // 'data' is the line in the disassemblylist to be accessed + disassemble(data); break; case RomListWidget::kTentativeCodeCmd: @@ -165,29 +166,25 @@ 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 = - debugger.cartDebug().disassembly().list; + const uInt16 address = getAddress(disasm_line); - if(disasm_line >= int(list.size())) return; + if (address != 0) + { + Debugger& debugger = instance().debugger(); - const uInt16 address = list[disasm_line].address; - - if(address != 0) debugger.toggleBreakPoint(address, debugger.cartDebug().getBank(address)); + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomWidget::setPC(int disasm_line) { - const CartDebug::DisassemblyList& list = - instance().debugger().cartDebug().disassembly().list; - if(disasm_line >= int(list.size())) return; + const uInt16 address = getAddress(disasm_line); - if(list[disasm_line].address != 0) + if(address != 0) { ostringstream command; - command << "pc #" << list[disasm_line].address; + command << "pc #" << address; instance().debugger().run(command.str()); } } @@ -195,28 +192,39 @@ void RomWidget::setPC(int disasm_line) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomWidget::runtoPC(int disasm_line) { - const CartDebug::DisassemblyList& list = - instance().debugger().cartDebug().disassembly().list; - if(disasm_line >= int(list.size())) return; + const uInt16 address = getAddress(disasm_line); - if(list[disasm_line].address != 0) + if(address != 0) { ostringstream command; - command << "runtopc #" << list[disasm_line].address; + command << "runtopc #" << address; string msg = instance().debugger().run(command.str()); instance().frameBuffer().showMessage(msg); } } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void RomWidget::disassemble(int disasm_line) +{ + const uInt16 address = getAddress(disasm_line); + + if(address != 0) + { + CartDebug& cart = instance().debugger().cartDebug(); + + cart.disassembleAddr(address, true); + invalidate(); + scrollTo(cart.addressToLine(address)); // the line might have been changed + } +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomWidget::patchROM(int disasm_line, const string& bytes, Common::Base::Fmt base) { - const CartDebug::DisassemblyList& list = - instance().debugger().cartDebug().disassembly().list; - if(disasm_line >= int(list.size())) return; + const uInt16 address = getAddress(disasm_line); - if(list[disasm_line].address != 0) + if(address != 0) { ostringstream command; @@ -225,7 +233,7 @@ void RomWidget::patchROM(int disasm_line, const string& bytes, Common::Base::Fmt oldbase = Common::Base::format(); Common::Base::setFormat(base); - command << "rom #" << list[disasm_line].address << " " << bytes; + command << "rom #" << address << " " << bytes; instance().debugger().run(command.str()); // Restore previous base @@ -233,6 +241,18 @@ void RomWidget::patchROM(int disasm_line, const string& bytes, } } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt16 RomWidget::getAddress(int disasm_line) +{ + const CartDebug::DisassemblyList& list = + instance().debugger().cartDebug().disassembly().list; + + if (disasm_line < int(list.size()) && list[disasm_line].address != 0) + return list[disasm_line].address; + else + return 0; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomWidget::scrollTo(int line) { diff --git a/src/debugger/gui/RomWidget.hxx b/src/debugger/gui/RomWidget.hxx index 9c794a9f1..8dc4aabee 100644 --- a/src/debugger/gui/RomWidget.hxx +++ b/src/debugger/gui/RomWidget.hxx @@ -51,8 +51,10 @@ class RomWidget : public Widget, public CommandSender void toggleBreak(int disasm_line); void setPC(int disasm_line); void runtoPC(int disasm_line); + void disassemble(int disasm_line); void patchROM(int disasm_line, const string& bytes, Common::Base::Fmt base); + uInt16 getAddress(int disasm_line); private: RomListWidget* myRomList{nullptr}; From 9667c843f087aa9e4a63ecc70a060faf18b6bb64 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 25 Jul 2020 10:19:07 +0200 Subject: [PATCH 346/377] added autofire (resolves #676) --- Changes.txt | 2 + docs/graphics/eventmapping_devsports.png | Bin 7375 -> 4523 bytes docs/index.html | 6 ++ src/common/PKeyboardHandler.cxx | 3 + src/emucore/Booster.cxx | 7 +- src/emucore/Console.cxx | 28 ++++++- src/emucore/Console.hxx | 5 ++ src/emucore/Control.cxx | 11 +++ src/emucore/Control.hxx | 53 +++++++++++++ src/emucore/Driving.cxx | 18 +++-- src/emucore/Event.hxx | 1 + src/emucore/EventHandler.cxx | 12 +++ src/emucore/EventHandler.hxx | 2 +- src/emucore/Genesis.cxx | 7 +- src/emucore/Joystick.cxx | 9 ++- src/emucore/Lightgun.cxx | 10 ++- src/emucore/Paddles.cxx | 40 ++++++---- src/emucore/Paddles.hxx | 4 - src/emucore/PointingDevice.cxx | 5 +- src/emucore/Settings.cxx | 2 + src/gui/InputDialog.cxx | 95 ++++++++++++++++------- src/gui/InputDialog.hxx | 3 + 22 files changed, 247 insertions(+), 76 deletions(-) diff --git a/Changes.txt b/Changes.txt index 6d3b5b2f1..3e0571978 100644 --- a/Changes.txt +++ b/Changes.txt @@ -14,6 +14,8 @@ 6.2.1 to 6.3 (XXXX XX, 2020) + * Added autofire. + * Added new interface palette 'Dark'. (TODO: DOC) * Extended global hotkeys for debug options. diff --git a/docs/graphics/eventmapping_devsports.png b/docs/graphics/eventmapping_devsports.png index ab187595e2a69043ebf460087983ea00bc21a024..55dc205c6cfd3511ad3d0f5ae5abf9e4aab3c14d 100644 GIT binary patch literal 4523 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 diff --git a/docs/index.html b/docs/index.html index 554f2cdbd..a12d7e457 100644 --- a/docs/index.html +++ b/docs/index.html @@ -2379,6 +2379,11 @@ faster movement.
      + + + + + + diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index f5d39b20a..6d726f3fc 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -534,6 +534,9 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo {Event::ToggleContSnapshots, KBDK_S, MOD3}, {Event::ToggleContSnapshotsFrame, KBDK_S, KBDM_SHIFT | MOD3}, #endif + + {Event::DecreaseAutoFire, KBDK_A, KBDM_SHIFT | KBDM_CTRL}, + {Event::IncreaseAutoFire, KBDK_A, KBDM_CTRL }, {Event::HandleMouseControl, KBDK_0, KBDM_CTRL}, {Event::ToggleGrabMouse, KBDK_G, KBDM_CTRL}, {Event::ToggleSAPortOrder, KBDK_1, KBDM_CTRL}, diff --git a/src/emucore/Booster.cxx b/src/emucore/Booster.cxx index fddd51c21..96d328b8a 100644 --- a/src/emucore/Booster.cxx +++ b/src/emucore/Booster.cxx @@ -59,7 +59,7 @@ void BoosterGrip::update() setPin(DigitalPin::Two, myEvent.get(myDownEvent) == 0); setPin(DigitalPin::Three, myEvent.get(myLeftEvent) == 0); setPin(DigitalPin::Four, myEvent.get(myRightEvent) == 0); - setPin(DigitalPin::Six, myEvent.get(myFireEvent) == 0); + bool firePressed = myEvent.get(myFireEvent) != 0; // The CBS Booster-grip has two more buttons on it. These buttons are // connected to the inputs usually used by paddles. @@ -120,11 +120,12 @@ void BoosterGrip::update() } } // Get mouse button state - if(myEvent.get(Event::MouseButtonLeftValue)) - setPin(DigitalPin::Six, false); + firePressed = firePressed + || myEvent.get(Event::MouseButtonLeftValue); if(myEvent.get(Event::MouseButtonRightValue)) setPin(AnalogPin::Nine, MIN_RESISTANCE); } + setPin(DigitalPin::Six, !getAutoFireState(firePressed)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index be2907fe9..dd9146ac9 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -434,7 +434,7 @@ void Console::setFormat(uInt32 format, bool force) setTIAProperties(); initializeVideo(); // takes care of refreshing the screen - initializeAudio(); // ensure that audio synthesis is set up to match emulation speed + initializeAudio(); // ensure that audio synthesis is set up to match emulation rate myOSystem.resetFps(); // Reset FPS measurement myOSystem.frameBuffer().showMessage(message); @@ -492,7 +492,7 @@ void Console::toggleTurbo() myOSystem.settings().setValue("turbo", !enabled); - // update speed + // update rate initializeAudio(); // update VSync @@ -870,6 +870,30 @@ unique_ptr Console::getControllerPort(const Controller::Type type, return controller; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Console::changeAutoFireRate(int direction) +{ + const Int32 scanlines = std::max(tia().scanlinesLastFrame(), 240); + const bool isNTSC = scanlines <= 287; + + int rate = myOSystem.settings().getInt("autofirerate"); + + rate = BSPF::clamp(rate + direction, 0, isNTSC ? 30 : 25); + + myOSystem.settings().setValue("autofirerate", rate); + Controller::setAutoFireRate(rate); + + ostringstream val; + + if(rate) + val << rate << " Hz"; + else + { + val << "Off"; + } + myOSystem.frameBuffer().showMessage("Autofire rate", val.str(), rate, 0, isNTSC ? 30 : 25); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - float Console::getFramerate() const { diff --git a/src/emucore/Console.hxx b/src/emucore/Console.hxx index 1cc37fc0b..86595da9f 100644 --- a/src/emucore/Console.hxx +++ b/src/emucore/Console.hxx @@ -318,6 +318,11 @@ class Console : public Serializable, public ConsoleIO */ void setTIAProperties(); + /** + Change the autofire speed for all controllers + */ + void changeAutoFireRate(int direction = +1); + private: /** * Define console timing based on current display format diff --git a/src/emucore/Control.cxx b/src/emucore/Control.cxx index 0584626de..813063c04 100644 --- a/src/emucore/Control.cxx +++ b/src/emucore/Control.cxx @@ -147,3 +147,14 @@ Controller::Type Controller::getType(const string& propName) return Type::Unknown; } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Controller::setAutoFireRate(int rate, bool isNTSC) +{ + rate = BSPF::clamp(rate, 0, isNTSC ? 30 : 25); + AUTO_FIRE_RATE = 32 * 1024 * rate / (isNTSC ? 60 : 50); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int Controller::AUTO_FIRE_RATE = 0; + diff --git a/src/emucore/Control.hxx b/src/emucore/Control.hxx index a670f39f6..aa7e2aed3 100644 --- a/src/emucore/Control.hxx +++ b/src/emucore/Control.hxx @@ -272,6 +272,14 @@ class Controller : public Serializable */ static Type getType(const string& propName); + /** + Sets the auto fire rate. 0 disables auto fire. + + @param speed Auto fire rate (0..30/25) in Hz + @param isNTSC NTSC or PAL frame rate + */ + static void setAutoFireRate(int rate, bool isNTSC = true); + public: /// Constant which represents maximum resistance for analog pins static constexpr Int32 MAX_RESISTANCE = 0x7FFFFFFF; @@ -310,6 +318,44 @@ class Controller : public Serializable setPin(AnalogPin::Nine, MAX_RESISTANCE); } + /** + Checks for the next auto fire event. + + @param pressed True if the fire button is current pressed + @return The result of the auto fire event check + */ + inline bool getAutoFireState(bool pressed) + { + if(AUTO_FIRE_RATE && pressed) + { + myFireDelay -= AUTO_FIRE_RATE; + if(myFireDelay <= 0) + myFireDelay += 32 * 1024; + return myFireDelay > 16 * 1024; + } + myFireDelay = 0; + return pressed; + } + + /** + Checks for the next auto fire event for paddle 1. + + @param pressed True if the fire button is current pressed + @return The result of the auto fire event check + */ + inline bool getAutoFireStateP1(bool pressed) + { + if(AUTO_FIRE_RATE && pressed) + { + myFireDelayP1 -= AUTO_FIRE_RATE; + if(myFireDelayP1 <= 0) + myFireDelayP1 += 32 * 1024; + return myFireDelayP1 > 16 * 1024; + } + myFireDelayP1 = 0; + return pressed; + } + protected: /// Specifies which jack the controller is plugged in const Jack myJack; @@ -326,6 +372,13 @@ class Controller : public Serializable /// The callback that is dispatched whenver an analog pin has changed onAnalogPinUpdateCallback myOnAnalogPinUpdateCallback{nullptr}; + /// Defines the speed of the auto fire + static int AUTO_FIRE_RATE; + + /// Delay[frames] until the next fire event + int myFireDelay{0}; + int myFireDelayP1{0}; // required for paddles only + private: /// The boolean value on each digital pin std::array myDigitalPinState{true, true, true, true, true}; diff --git a/src/emucore/Driving.cxx b/src/emucore/Driving.cxx index 83f27e336..bd08a03e0 100644 --- a/src/emucore/Driving.cxx +++ b/src/emucore/Driving.cxx @@ -50,7 +50,8 @@ Driving::Driving(Jack jack, const Event& event, const System& system) void Driving::update() { // Digital events (from keyboard or joystick hats & buttons) - setPin(DigitalPin::Six, myEvent.get(myFireEvent) == 0); + bool firePressed = myEvent.get(myFireEvent) != 0; + int d_axis = myEvent.get(myXAxisValue); if(myEvent.get(myCCWEvent) != 0 || d_axis < -16384) --myCounter; else if(myEvent.get(myCWEvent) != 0 || d_axis > 16384) ++myCounter; @@ -61,9 +62,9 @@ void Driving::update() int m_axis = myEvent.get(Event::MouseAxisXMove); if(m_axis < -2) --myCounter; else if(m_axis > 2) ++myCounter; - if(myEvent.get(Event::MouseButtonLeftValue) || - myEvent.get(Event::MouseButtonRightValue)) - setPin(DigitalPin::Six, false); + firePressed = firePressed + || myEvent.get(Event::MouseButtonLeftValue) + || myEvent.get(Event::MouseButtonRightValue); } else { @@ -74,18 +75,19 @@ void Driving::update() int m_axis = myEvent.get(Event::MouseAxisXMove); if(m_axis < -2) --myCounter; else if(m_axis > 2) ++myCounter; - if(myEvent.get(Event::MouseButtonLeftValue)) - setPin(DigitalPin::Six, false); + firePressed = firePressed + || myEvent.get(Event::MouseButtonLeftValue); } if(myControlIDY > -1) { int m_axis = myEvent.get(Event::MouseAxisYMove); if(m_axis < -2) --myCounter; else if(m_axis > 2) ++myCounter; - if(myEvent.get(Event::MouseButtonRightValue)) - setPin(DigitalPin::Six, false); + firePressed = firePressed + || myEvent.get(Event::MouseButtonRightValue); } } + setPin(DigitalPin::Six, !getAutoFireState(firePressed)); // Only consider the lower-most bits (corresponding to pins 1 & 2) myGrayIndex = Int32(myCounter * SENSITIVITY / 4.0F) & 0b11; diff --git a/src/emucore/Event.hxx b/src/emucore/Event.hxx index 010007c72..b9a301e7f 100644 --- a/src/emucore/Event.hxx +++ b/src/emucore/Event.hxx @@ -126,6 +126,7 @@ class Event // add new events from here to avoid that user remapped events get overwritten PreviousSettingGroup, NextSettingGroup, TogglePlayBackMode, + DecreaseAutoFire, IncreaseAutoFire, LastType }; diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 5dbd2ca2f..6e6f38b50 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -102,6 +102,7 @@ void EventHandler::initialize() Paddles::setMouseSensitivity(myOSystem.settings().getInt("msense")); PointingDevice::setSensitivity(myOSystem.settings().getInt("tsense")); Driving::setSensitivity(myOSystem.settings().getInt("dcsense")); + Controller::setAutoFireRate(myOSystem.settings().getInt("autofirerate")); #ifdef GUI_SUPPORT // Set quick select delay when typing characters in listwidgets @@ -1249,6 +1250,14 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; #endif + case Event::DecreaseAutoFire: + if(pressed) myOSystem.console().changeAutoFireRate(-1); + return; + + case Event::IncreaseAutoFire: + if(pressed) myOSystem.console().changeAutoFireRate(+1); + return; + case Event::HandleMouseControl: if (pressed && !repeated) handleMouseControl(); return; @@ -2558,6 +2567,8 @@ EventHandler::EmulActionList EventHandler::ourEmulActionList = { { { Event::VolumeDecrease, "Decrease volume", "" }, { Event::VolumeIncrease, "Increase volume", "" }, + { Event::DecreaseAutoFire, "Decrease auto fire speed", "" }, + { Event::IncreaseAutoFire, "Increase auto fire speed", "" }, { Event::HandleMouseControl, "Switch mouse emulation modes", "" }, { Event::ToggleGrabMouse, "Toggle grab mouse", "" }, { Event::ToggleSAPortOrder, "Swap Stelladaptor port ordering", "" }, @@ -2627,6 +2638,7 @@ const Event::EventSet EventHandler::MiscEvents = { Event::TakeSnapshot, Event::ToggleContSnapshots, Event::ToggleContSnapshotsFrame, // Event::MouseAxisXMove, Event::MouseAxisYMove, // Event::MouseButtonLeftValue, Event::MouseButtonRightValue, + Event::DecreaseAutoFire, Event::IncreaseAutoFire, Event::HandleMouseControl, Event::ToggleGrabMouse, Event::ToggleSAPortOrder, Event::PreviousMultiCartRom, Event::PreviousSettingGroup, Event::NextSettingGroup, diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx index 3f780b150..055d56d64 100644 --- a/src/emucore/EventHandler.hxx +++ b/src/emucore/EventHandler.hxx @@ -558,7 +558,7 @@ class EventHandler #else REFRESH_SIZE = 0, #endif - EMUL_ACTIONLIST_SIZE = 160 + PNG_SIZE + COMBO_SIZE + REFRESH_SIZE, + EMUL_ACTIONLIST_SIZE = 162 + PNG_SIZE + COMBO_SIZE + REFRESH_SIZE, MENU_ACTIONLIST_SIZE = 18 ; diff --git a/src/emucore/Genesis.cxx b/src/emucore/Genesis.cxx index 488f04980..0b1ef7a2f 100644 --- a/src/emucore/Genesis.cxx +++ b/src/emucore/Genesis.cxx @@ -53,7 +53,7 @@ void Genesis::update() setPin(DigitalPin::Two, myEvent.get(myDownEvent) == 0); setPin(DigitalPin::Three, myEvent.get(myLeftEvent) == 0); setPin(DigitalPin::Four, myEvent.get(myRightEvent) == 0); - setPin(DigitalPin::Six, myEvent.get(myFire1Event) == 0); + bool firePressed = myEvent.get(myFire1Event) != 0; // The Genesis has one more button (C) that can be read by the 2600 // However, it seems to work opposite to the BoosterGrip controller, @@ -88,11 +88,12 @@ void Genesis::update() } } // Get mouse button state - if(myEvent.get(Event::MouseButtonLeftValue)) - setPin(DigitalPin::Six, false); + firePressed = firePressed + || myEvent.get(Event::MouseButtonLeftValue); if(myEvent.get(Event::MouseButtonRightValue)) setPin(AnalogPin::Five, MAX_RESISTANCE); } + setPin(DigitalPin::Six, !getAutoFireState(firePressed)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Joystick.cxx b/src/emucore/Joystick.cxx index f9ee75545..ea0d71300 100644 --- a/src/emucore/Joystick.cxx +++ b/src/emucore/Joystick.cxx @@ -52,7 +52,7 @@ void Joystick::update() setPin(DigitalPin::Two, myEvent.get(myDownEvent) == 0); setPin(DigitalPin::Three, myEvent.get(myLeftEvent) == 0); setPin(DigitalPin::Four, myEvent.get(myRightEvent) == 0); - setPin(DigitalPin::Six, myEvent.get(myFireEvent) == 0); + bool firePressed = myEvent.get(myFireEvent) != 0; // Axis events (usually generated by the Stelladaptor) int xaxis = myEvent.get(myXAxisValue); @@ -102,10 +102,11 @@ void Joystick::update() } } // Get mouse button state - if(myEvent.get(Event::MouseButtonLeftValue) || - myEvent.get(Event::MouseButtonRightValue)) - setPin(DigitalPin::Six, false); + firePressed = firePressed + || myEvent.get(Event::MouseButtonLeftValue) + || myEvent.get(Event::MouseButtonRightValue); } + setPin(DigitalPin::Six, !getAutoFireState(firePressed)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Lightgun.cxx b/src/emucore/Lightgun.cxx index 1c6c82ba7..3ae39d8e5 100644 --- a/src/emucore/Lightgun.cxx +++ b/src/emucore/Lightgun.cxx @@ -116,10 +116,12 @@ bool Lightgun::read(DigitalPin pin) void Lightgun::update() { // Digital events (from keyboard or joystick hats & buttons) - setPin(DigitalPin::One, myEvent.get(Event::JoystickZeroFire) == 0); + bool firePressed = myEvent.get(Event::JoystickZeroFire) != 0; // We allow left and right mouse buttons for fire button - if(myEvent.get(Event::MouseButtonLeftValue) || - myEvent.get(Event::MouseButtonRightValue)) - setPin(DigitalPin::One, false); + firePressed = firePressed + || myEvent.get(Event::MouseButtonLeftValue) + || myEvent.get(Event::MouseButtonRightValue); + + setPin(DigitalPin::One, !getAutoFireState(firePressed)); } diff --git a/src/emucore/Paddles.cxx b/src/emucore/Paddles.cxx index 31ba8875d..a7f72ce1d 100644 --- a/src/emucore/Paddles.cxx +++ b/src/emucore/Paddles.cxx @@ -186,8 +186,8 @@ void Paddles::update() setPin(DigitalPin::Four, true); // Digital events (from keyboard or joystick hats & buttons) - setPin(DigitalPin::Three, myEvent.get(myP1FireEvent) == 0); - setPin(DigitalPin::Four, myEvent.get(myP0FireEvent) == 0); + bool firePressedP0 = myEvent.get(myP0FireEvent) != 0; + bool firePressedP1 = myEvent.get(myP1FireEvent) != 0; // Paddle movement is a very difficult thing to accurately emulate, // since it originally came from an analog device that had very @@ -269,9 +269,14 @@ void Paddles::update() myCharge[myMPaddleID] = BSPF::clamp(myCharge[myMPaddleID] - (myEvent.get(myAxisMouseMotion) * MOUSE_SENSITIVITY), TRIGMIN, TRIGRANGE); - if(myEvent.get(Event::MouseButtonLeftValue) || - myEvent.get(Event::MouseButtonRightValue)) - setPin(ourButtonPin[myMPaddleID], false); + if(myMPaddleID == 0) + firePressedP0 = firePressedP0 + || myEvent.get(Event::MouseButtonLeftValue) + || myEvent.get(Event::MouseButtonRightValue); + else + firePressedP1 = firePressedP1 + || myEvent.get(Event::MouseButtonLeftValue) + || myEvent.get(Event::MouseButtonRightValue); } else { @@ -282,18 +287,30 @@ void Paddles::update() myCharge[myMPaddleIDX] = BSPF::clamp(myCharge[myMPaddleIDX] - (myEvent.get(Event::MouseAxisXMove) * MOUSE_SENSITIVITY), TRIGMIN, TRIGRANGE); - if(myEvent.get(Event::MouseButtonLeftValue)) - setPin(ourButtonPin[myMPaddleIDX], false); + + if(myMPaddleIDX == 0) + firePressedP0 = firePressedP0 + || myEvent.get(Event::MouseButtonLeftValue); + else + firePressedP1 = firePressedP1 + || myEvent.get(Event::MouseButtonLeftValue); } if(myMPaddleIDY > -1) { myCharge[myMPaddleIDY] = BSPF::clamp(myCharge[myMPaddleIDY] - (myEvent.get(Event::MouseAxisYMove) * MOUSE_SENSITIVITY), TRIGMIN, TRIGRANGE); - if(myEvent.get(Event::MouseButtonRightValue)) - setPin(ourButtonPin[myMPaddleIDY], false); + + if(myMPaddleIDY == 0) + firePressedP0 = firePressedP0 + || myEvent.get(Event::MouseButtonRightValue); + else + firePressedP1 = firePressedP1 + || myEvent.get(Event::MouseButtonRightValue); } } + setPin(DigitalPin::Four, !getAutoFireState(firePressedP0)); + setPin(DigitalPin::Three, !getAutoFireStateP1(firePressedP1)); // Finally, consider digital input, where movement happens // until a digital event is released @@ -449,8 +466,3 @@ int Paddles::DIGITAL_DISTANCE = -1; int Paddles::MOUSE_SENSITIVITY = -1; int Paddles::DEJITTER_BASE = 0; int Paddles::DEJITTER_DIFF = 0; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const std::array Paddles::ourButtonPin = { - DigitalPin::Four, DigitalPin::Three -}; diff --git a/src/emucore/Paddles.hxx b/src/emucore/Paddles.hxx index 57acda958..bb8144b21 100644 --- a/src/emucore/Paddles.hxx +++ b/src/emucore/Paddles.hxx @@ -190,10 +190,6 @@ class Paddles : public Controller static int DEJITTER_BASE, DEJITTER_DIFF; static int MOUSE_SENSITIVITY; - // Lookup table for associating paddle buttons with controller pins - // Yes, this is hideously complex - static const std::array ourButtonPin; - private: // Following constructors and assignment operators not supported Paddles() = delete; diff --git a/src/emucore/PointingDevice.cxx b/src/emucore/PointingDevice.cxx index 4d91d010c..05cf7c031 100644 --- a/src/emucore/PointingDevice.cxx +++ b/src/emucore/PointingDevice.cxx @@ -92,9 +92,8 @@ void PointingDevice::update() setPin(DigitalPin::Six, myEvent.get(Event::JoystickZeroFire) == 0); // We allow left and right mouse buttons for fire button - if(myEvent.get(Event::MouseButtonLeftValue) || - myEvent.get(Event::MouseButtonRightValue)) - setPin(DigitalPin::Six, false); + setPin(DigitalPin::Six, !getAutoFireState( + myEvent.get(Event::MouseButtonLeftValue) || myEvent.get(Event::MouseButtonRightValue))); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index 0c5073d45..0ccc7ebd5 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -100,6 +100,7 @@ Settings::Settings() setPermanent("combomap", ""); setPermanent("joydeadzone", "13"); setPermanent("joyallow4", "false"); + setPermanent("autofirerate", "0"); setPermanent("usemouse", "analog"); setPermanent("grabmouse", "true"); setPermanent("cursor", "2"); @@ -481,6 +482,7 @@ void Settings::usage() const << " -tsense <1-20> Sensitivity of mouse emulated trackball movement\n" << " -dcsense <1-20> Sensitivity of digital emulated driving controller\n" << " movement\n" + << " -autofirerate <0-30> Set fire button's autofire rate (0 means off)\n" << " -saport How to assign virtual ports to multiple\n" << " Stelladaptor/2600-daptors\n" << " -modcombo <1|0> Enable modifer key combos\n" diff --git a/src/gui/InputDialog.cxx b/src/gui/InputDialog.cxx index 3cced561b..4e792348c 100644 --- a/src/gui/InputDialog.cxx +++ b/src/gui/InputDialog.cxx @@ -134,7 +134,7 @@ void InputDialog::addDevicePortTab() xpos += fontWidth * 2; // Add analog paddle sensitivity - ypos += lineHeight + VGAP; + ypos += lineHeight; myPaddleSpeed = new SliderWidget(myTab, _font, xpos, ypos - 1, 13 * fontWidth, lineHeight, "Sensitivity", lwidth - fontWidth * 2, kPSpeedChanged, 4 * fontWidth, "%"); @@ -172,6 +172,14 @@ void InputDialog::addDevicePortTab() myDPaddleSpeed->setTickmarkIntervals(4); wid.push_back(myDPaddleSpeed); + ypos += lineHeight + VGAP * 4; + myAutoFireRate = new SliderWidget(myTab, _font, HBORDER, ypos - 1, 13 * fontWidth, lineHeight, + "Autofire rate", + lwidth, kAutoFireChanged, 5 * fontWidth, "Hz"); + myAutoFireRate->setMinValue(0); myAutoFireRate->setMaxValue(30); + myAutoFireRate->setTickmarkIntervals(6); + wid.push_back(myAutoFireRate); + // Add 'allow all 4 directions' for joystick ypos += lineHeight + VGAP * 4; myAllowAll4 = new CheckboxWidget(myTab, _font, HBORDER, ypos, @@ -315,38 +323,43 @@ void InputDialog::addMouseTab() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputDialog::loadConfig() { + Settings& settings = instance().settings(); + // Left & right ports - mySAPort->setState(instance().settings().getString("saport") == "rl"); + mySAPort->setState(settings.getString("saport") == "rl"); // Use mouse as a controller myMouseControl->setSelected( - instance().settings().getString("usemouse"), "analog"); + settings.getString("usemouse"), "analog"); handleMouseControlState(); // Mouse cursor state - myCursorState->setSelected(instance().settings().getString("cursor"), "2"); + myCursorState->setSelected(settings.getString("cursor"), "2"); handleCursorState(); // Joystick deadzone - myDeadzone->setValue(instance().settings().getInt("joydeadzone")); + myDeadzone->setValue(settings.getInt("joydeadzone")); // Paddle speed (analog) - myPaddleSpeed->setValue(instance().settings().getInt("psense")); + myPaddleSpeed->setValue(settings.getInt("psense")); // Paddle dejitter (analog) - myDejitterBase->setValue(instance().settings().getInt("dejitter.base")); - myDejitterDiff->setValue(instance().settings().getInt("dejitter.diff")); + myDejitterBase->setValue(settings.getInt("dejitter.base")); + myDejitterDiff->setValue(settings.getInt("dejitter.diff")); // Paddle speed (digital and mouse) - myDPaddleSpeed->setValue(instance().settings().getInt("dsense")); - myMPaddleSpeed->setValue(instance().settings().getInt("msense")); + myDPaddleSpeed->setValue(settings.getInt("dsense")); + myMPaddleSpeed->setValue(settings.getInt("msense")); // Trackball speed - myTrackBallSpeed->setValue(instance().settings().getInt("tsense")); + myTrackBallSpeed->setValue(settings.getInt("tsense")); // Driving controller speed - myDrivingSpeed->setValue(instance().settings().getInt("dcsense")); + myDrivingSpeed->setValue(settings.getInt("dcsense")); + + // Autofire rate + myAutoFireRate->setValue(settings.getInt("autofirerate")); // AtariVox serial port - myAVoxPort->setText(instance().settings().getString("avoxport")); + myAVoxPort->setText(settings.getString("avoxport")); // EEPROM erase (only enable in emulation mode and for valid controllers) if(instance().hasConsole()) @@ -361,13 +374,13 @@ void InputDialog::loadConfig() myEraseEEPROMButton->setEnabled(false); // Allow all 4 joystick directions - myAllowAll4->setState(instance().settings().getBool("joyallow4")); + myAllowAll4->setState(settings.getBool("joyallow4")); // Grab mouse - myGrabMouse->setState(instance().settings().getBool("grabmouse")); + myGrabMouse->setState(settings.getBool("grabmouse")); // Enable/disable modifier key-combos - myModCombo->setState(instance().settings().getBool("modcombo")); + myModCombo->setState(settings.getBool("modcombo")); myTab->loadConfig(); } @@ -375,70 +388,77 @@ void InputDialog::loadConfig() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputDialog::saveConfig() { + Settings& settings = instance().settings(); + // Left & right ports instance().eventHandler().mapStelladaptors(mySAPort->getState() ? "rl": "lr"); // Use mouse as a controller const string& usemouse = myMouseControl->getSelectedTag().toString(); - instance().settings().setValue("usemouse", usemouse); + settings.setValue("usemouse", usemouse); instance().eventHandler().setMouseControllerMode(usemouse); // Joystick deadzone int deadzone = myDeadzone->getValue(); - instance().settings().setValue("joydeadzone", deadzone); + settings.setValue("joydeadzone", deadzone); Joystick::setDeadZone(deadzone); // Paddle speed (analog) int sensitivity = myPaddleSpeed->getValue(); - instance().settings().setValue("psense", sensitivity); + settings.setValue("psense", sensitivity); Paddles::setAnalogSensitivity(sensitivity); // Paddle speed (digital and mouse) int dejitter = myDejitterBase->getValue(); - instance().settings().setValue("dejitter.base", dejitter); + settings.setValue("dejitter.base", dejitter); Paddles::setDejitterBase(dejitter); dejitter = myDejitterDiff->getValue(); - instance().settings().setValue("dejitter.diff", dejitter); + settings.setValue("dejitter.diff", dejitter); Paddles::setDejitterDiff(dejitter); sensitivity = myDPaddleSpeed->getValue(); - instance().settings().setValue("dsense", sensitivity); + settings.setValue("dsense", sensitivity); Paddles::setDigitalSensitivity(sensitivity); sensitivity = myMPaddleSpeed->getValue(); - instance().settings().setValue("msense", sensitivity); + settings.setValue("msense", sensitivity); Paddles::setMouseSensitivity(sensitivity); // Trackball speed sensitivity = myTrackBallSpeed->getValue(); - instance().settings().setValue("tsense", sensitivity); + settings.setValue("tsense", sensitivity); PointingDevice::setSensitivity(sensitivity); // Driving controller speed sensitivity = myDrivingSpeed->getValue(); - instance().settings().setValue("dcsense", sensitivity); + settings.setValue("dcsense", sensitivity); Driving::setSensitivity(sensitivity); + // Autofire rate + int rate = myAutoFireRate->getValue(); + settings.setValue("autofirerate", rate); + Controller::setAutoFireRate(rate); + // AtariVox serial port - instance().settings().setValue("avoxport", myAVoxPort->getText()); + settings.setValue("avoxport", myAVoxPort->getText()); // Allow all 4 joystick directions bool allowall4 = myAllowAll4->getState(); - instance().settings().setValue("joyallow4", allowall4); + settings.setValue("joyallow4", allowall4); instance().eventHandler().allowAllDirections(allowall4); // Grab mouse and hide cursor const string& cursor = myCursorState->getSelectedTag().toString(); - instance().settings().setValue("cursor", cursor); + settings.setValue("cursor", cursor); // only allow grab mouse if cursor is hidden in emulation int state = myCursorState->getSelected(); bool enableGrab = state != 1 && state != 3; bool grab = enableGrab ? myGrabMouse->getState() : false; - instance().settings().setValue("grabmouse", grab); + settings.setValue("grabmouse", grab); instance().frameBuffer().enableGrabMouse(grab); // Enable/disable modifier key-combos - instance().settings().setValue("modcombo", myModCombo->getState()); + settings.setValue("modcombo", myModCombo->getState()); instance().eventHandler().saveKeyMapping(); instance().eventHandler().saveJoyMapping(); @@ -477,6 +497,8 @@ void InputDialog::setDefaults() myDejitterBase->setValue(0); myDejitterDiff->setValue(0); #endif + // Autofire rate + myAutoFireRate->setValue(0); // AtariVox serial port myAVoxPort->setText(""); @@ -659,6 +681,10 @@ void InputDialog::handleCommand(CommandSender* sender, int cmd, myTrackBallSpeed->setValueLabel(myTrackBallSpeed->getValue() * 10); break; + case kAutoFireChanged: + updateAutoFireRate(); + break; + case kDBButtonPressed: if(!myJoyDialog) { @@ -726,6 +752,15 @@ void InputDialog::updateDejitterReaction() myDejitterDiff->setValueLabel(strength ? std::to_string(strength) : "Off"); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void InputDialog::updateAutoFireRate() +{ + int rate = myAutoFireRate->getValue(); + + myAutoFireRate->setValueLabel(rate ? std::to_string(rate) : "Off"); + myAutoFireRate->setValueUnit(rate ? " Hz" : ""); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputDialog::handleMouseControlState() { diff --git a/src/gui/InputDialog.hxx b/src/gui/InputDialog.hxx index 48e1629a3..6893d2c43 100644 --- a/src/gui/InputDialog.hxx +++ b/src/gui/InputDialog.hxx @@ -66,6 +66,7 @@ class InputDialog : public Dialog void handleCursorState(); void updateDejitterAveraging(); void updateDejitterReaction(); + void updateAutoFireRate(); void eraseEEPROM(); private: @@ -75,6 +76,7 @@ class InputDialog : public Dialog kDejitterAvChanged = 'JAch', kDejitterReChanged = 'JRch', kDPSpeedChanged = 'PDch', + kAutoFireChanged = 'AFch', kTBSpeedChanged = 'TBch', kDCSpeedChanged = 'DCch', kDBButtonPressed = 'DBbp', @@ -99,6 +101,7 @@ class InputDialog : public Dialog SliderWidget* myDejitterBase{nullptr}; SliderWidget* myDejitterDiff{nullptr}; SliderWidget* myDPaddleSpeed{nullptr}; + SliderWidget* myAutoFireRate{nullptr}; CheckboxWidget* myAllowAll4{nullptr}; CheckboxWidget* myModCombo{nullptr}; From d047e9b5040fde75436b533b393f23ab53eec375 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 25 Jul 2020 14:54:37 +0200 Subject: [PATCH 347/377] added missing hotkey doc for autofire --- docs/index.html | 73 +++++++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/docs/index.html b/docs/index.html index a12d7e457..82fe5364b 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1740,17 +1740,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - @@ -1762,44 +1798,11 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1811,13 +1814,11 @@ - - From 2f6b57b0b45320b475ff2b6ad5799e9885a9c091 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sat, 25 Jul 2020 11:28:41 -0230 Subject: [PATCH 348/377] Fix documentation warning from clang. --- src/emucore/Control.hxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/emucore/Control.hxx b/src/emucore/Control.hxx index aa7e2aed3..128912dcd 100644 --- a/src/emucore/Control.hxx +++ b/src/emucore/Control.hxx @@ -275,8 +275,8 @@ class Controller : public Serializable /** Sets the auto fire rate. 0 disables auto fire. - @param speed Auto fire rate (0..30/25) in Hz - @param isNTSC NTSC or PAL frame rate + @param rate Auto fire rate (0..30/25) in Hz + @param isNTSC NTSC or PAL frame rate */ static void setAutoFireRate(int rate, bool isNTSC = true); From 5f2811f2c4a87393f448232b946fe12f7b51c378 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sat, 25 Jul 2020 12:57:12 -0230 Subject: [PATCH 349/377] Almost all file I/O now goes through FilesystemNode::read/write, instead of raw C++ fstreams. This allows data to be stored in a ZIP archive and for Stella to use it as if it were a normal file. Still TODO is add ZIP write support. --- Changes.txt | 11 +- src/cheat/CheatManager.cxx | 16 +-- src/common/PNGLibrary.cxx | 16 +-- src/common/PNGLibrary.hxx | 2 +- src/common/PaletteHandler.cxx | 28 ++-- src/common/bspf.hxx | 2 - .../KeyValueRepositoryConfigfile.cxx | 33 +++-- .../KeyValueRepositoryConfigfile.hxx | 5 +- src/debugger/CartDebug.cxx | 43 +++--- src/debugger/Debugger.cxx | 4 +- src/debugger/DebuggerParser.cxx | 29 ++-- src/emucore/AtariVox.cxx | 2 +- src/emucore/AtariVox.hxx | 3 +- src/emucore/Console.cxx | 8 +- src/emucore/EventHandler.cxx | 6 +- src/emucore/FSNode.cxx | 50 +++++-- src/emucore/FSNode.hxx | 9 +- src/emucore/MT24LC256.cxx | 29 ++-- src/emucore/MT24LC256.hxx | 13 +- src/emucore/OSystem.cxx | 135 ++++++++++-------- src/emucore/OSystem.hxx | 64 +++------ src/emucore/SaveKey.cxx | 4 +- src/emucore/SaveKey.hxx | 6 +- src/gui/GameInfoDialog.cxx | 15 +- src/gui/LoggerDialog.cxx | 15 +- src/gui/RomInfoWidget.cxx | 2 +- src/gui/SnapshotDialog.cxx | 2 +- src/gui/UIDialog.cxx | 2 +- 28 files changed, 301 insertions(+), 253 deletions(-) diff --git a/Changes.txt b/Changes.txt index 3e0571978..32969710a 100644 --- a/Changes.txt +++ b/Changes.txt @@ -22,9 +22,14 @@ * Allow taking snapshots from within Time Machine dialog - * Added ability to load per-ROM properties file from a ZIP file containing - the ROM. This allows to distribute ROM and properties in one file, - which Stella can use directly. + * Added ability to access most files that Stella uses from within a ZIP + file. This includes the following: + - Per-ROM properties file (so one can distribute a ROM and its + associated properties). + - Debugger symbol (.sym) and list (.lst) files, etc. + - Several others, as we extend the support. + Basically, you are now able to put many files that Stella uses inside + one ZIP file, and distribute just that file. * Replaced "Re-disassemble" with "Disassemble @ current line" in debugger diff --git a/src/cheat/CheatManager.cxx b/src/cheat/CheatManager.cxx index e106279c6..3f4db3fb4 100644 --- a/src/cheat/CheatManager.cxx +++ b/src/cheat/CheatManager.cxx @@ -213,10 +213,9 @@ void CheatManager::enable(const string& code, bool enable) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheatManager::loadCheatDatabase() { - const string& cheatfile = myOSystem.cheatFile(); - ifstream in(cheatfile); - if(!in) - return; + stringstream in; + try { myOSystem.cheatFile().read(in); } + catch(...) { return; } string line, md5, cheat; string::size_type one, two, three, four; @@ -253,13 +252,12 @@ void CheatManager::saveCheatDatabase() if(!myListIsDirty) return; - const string& cheatfile = myOSystem.cheatFile(); - ofstream out(cheatfile); - if(!out) - return; - + stringstream out; for(const auto& iter: myCheatMap) out << "\"" << iter.first << "\" " << "\"" << iter.second << "\"" << endl; + + try { myOSystem.cheatFile().write(out); } + catch(...) { return; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/PNGLibrary.cxx b/src/common/PNGLibrary.cxx index 23dd798d6..ae7d3390f 100644 --- a/src/common/PNGLibrary.cxx +++ b/src/common/PNGLibrary.cxx @@ -52,7 +52,7 @@ void PNGLibrary::loadImage(const string& filename, FBSurface& surface) throw runtime_error(s); }; - ifstream in(filename, std::ios_base::binary); + std::ifstream in(filename, std::ios_base::binary); if(!in.is_open()) loadImageERROR("No snapshot found"); @@ -125,7 +125,7 @@ void PNGLibrary::loadImage(const string& filename, FBSurface& surface) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PNGLibrary::saveImage(const string& filename, const VariantList& comments) { - ofstream out(filename, std::ios_base::binary); + std::ofstream out(filename, std::ios_base::binary); if(!out.is_open()) throw runtime_error("ERROR: Couldn't create snapshot file"); @@ -156,7 +156,7 @@ void PNGLibrary::saveImage(const string& filename, const VariantList& comments) void PNGLibrary::saveImage(const string& filename, const FBSurface& surface, const Common::Rect& rect, const VariantList& comments) { - ofstream out(filename, std::ios_base::binary); + std::ofstream out(filename, std::ios_base::binary); if(!out.is_open()) throw runtime_error("ERROR: Couldn't create snapshot file"); @@ -182,7 +182,7 @@ void PNGLibrary::saveImage(const string& filename, const FBSurface& surface, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PNGLibrary::saveImageToDisk(ofstream& out, const vector& rows, +void PNGLibrary::saveImageToDisk(std::ofstream& out, const vector& rows, png_uint_32 width, png_uint_32 height, const VariantList& comments) { png_structp png_ptr = nullptr; @@ -297,7 +297,7 @@ void PNGLibrary::takeSnapshot(uInt32 number) // Figure out the correct snapshot name string filename; bool showmessage = number == 0; - string sspath = myOSystem.snapshotSaveDir() + + string sspath = myOSystem.snapshotSaveDir().getPath() + (myOSystem.settings().getString("snapname") != "int" ? myOSystem.romFile().getNameWithExt("") : myOSystem.console().properties().get(PropType::Cart_Name)); @@ -456,21 +456,21 @@ void PNGLibrary::writeComments(png_structp png_ptr, png_infop info_ptr, // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PNGLibrary::png_read_data(png_structp ctx, png_bytep area, png_size_t size) { - (static_cast(png_get_io_ptr(ctx)))->read( + (static_cast(png_get_io_ptr(ctx)))->read( reinterpret_cast(area), size); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PNGLibrary::png_write_data(png_structp ctx, png_bytep area, png_size_t size) { - (static_cast(png_get_io_ptr(ctx)))->write( + (static_cast(png_get_io_ptr(ctx)))->write( reinterpret_cast(area), size); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PNGLibrary::png_io_flush(png_structp ctx) { - (static_cast(png_get_io_ptr(ctx)))->flush(); + (static_cast(png_get_io_ptr(ctx)))->flush(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/PNGLibrary.hxx b/src/common/PNGLibrary.hxx index fe177ad83..04876d85b 100644 --- a/src/common/PNGLibrary.hxx +++ b/src/common/PNGLibrary.hxx @@ -165,7 +165,7 @@ class PNGLibrary @param height The height of the PNG image @param comments The text comments to add to the PNG image */ - void saveImageToDisk(ofstream& out, const vector& rows, + void saveImageToDisk(std::ofstream& out, const vector& rows, png_uint_32 width, png_uint_32 height, const VariantList& comments); diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index ec0d7691b..030ff4d9e 100644 --- a/src/common/PaletteHandler.cxx +++ b/src/common/PaletteHandler.cxx @@ -85,11 +85,13 @@ void PaletteHandler::showAdjustableMessage() { const ConsoleTiming timing = myOSystem.console().timing(); const bool isNTSC = timing == ConsoleTiming::ntsc; - const float value = myOSystem.console().timing() == ConsoleTiming::pal ? myPhasePAL : myPhaseNTSC; + const float value = + myOSystem.console().timing() == ConsoleTiming::pal ? myPhasePAL : myPhaseNTSC; buf << std::fixed << std::setprecision(1) << value << DEGREE; - myOSystem.frameBuffer().showMessage("Palette phase shift", buf.str(), value, - (isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT) - MAX_SHIFT, - (isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT) + MAX_SHIFT); + myOSystem.frameBuffer().showMessage( + "Palette phase shift", buf.str(), value, + (isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT) - MAX_SHIFT, + (isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT) + MAX_SHIFT); } else { @@ -328,29 +330,25 @@ void PaletteHandler::loadUserPalette() if (!myOSystem.checkUserPalette(true)) return; - const string& palette = myOSystem.paletteFile(); - ifstream in(palette, std::ios::binary); + ByteBuffer in; + try { myOSystem.paletteFile().read(in); } + catch(...) { return; } - // Now that we have valid data, create the user-defined palettes - std::array pixbuf; // Temporary buffer for one 24-bit pixel - - for(int i = 0; i < 128; i++) // NTSC palette + uInt8* pixbuf = in.get(); + for(int i = 0; i < 128; i++, pixbuf += 3) // NTSC palette { - in.read(reinterpret_cast(pixbuf.data()), 3); const uInt32 pixel = (int(pixbuf[0]) << 16) + (int(pixbuf[1]) << 8) + int(pixbuf[2]); ourUserNTSCPalette[(i<<1)] = pixel; } - for(int i = 0; i < 128; i++) // PAL palette + for(int i = 0; i < 128; i++, pixbuf += 3) // PAL palette { - in.read(reinterpret_cast(pixbuf.data()), 3); const uInt32 pixel = (int(pixbuf[0]) << 16) + (int(pixbuf[1]) << 8) + int(pixbuf[2]); ourUserPALPalette[(i<<1)] = pixel; } std::array secam; // All 8 24-bit pixels, plus 8 colorloss pixels - for(int i = 0; i < 8; i++) // SECAM palette + for(int i = 0; i < 8; i++, pixbuf += 3) // SECAM palette { - in.read(reinterpret_cast(pixbuf.data()), 3); const uInt32 pixel = (int(pixbuf[0]) << 16) + (int(pixbuf[1]) << 8) + int(pixbuf[2]); secam[(i<<1)] = pixel; secam[(i<<1)+1] = 0; diff --git a/src/common/bspf.hxx b/src/common/bspf.hxx index 5201ef2ff..b23f6475b 100644 --- a/src/common/bspf.hxx +++ b/src/common/bspf.hxx @@ -64,8 +64,6 @@ using std::istream; using std::ostream; using std::fstream; using std::iostream; -using std::ifstream; -using std::ofstream; using std::ostringstream; using std::istringstream; using std::stringstream; diff --git a/src/common/repository/KeyValueRepositoryConfigfile.cxx b/src/common/repository/KeyValueRepositoryConfigfile.cxx index fe0efdf64..44a840b81 100644 --- a/src/common/repository/KeyValueRepositoryConfigfile.cxx +++ b/src/common/repository/KeyValueRepositoryConfigfile.cxx @@ -28,8 +28,8 @@ namespace { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -KeyValueRepositoryConfigfile::KeyValueRepositoryConfigfile(const string& filename) - : myFilename(filename) +KeyValueRepositoryConfigfile::KeyValueRepositoryConfigfile(const FilesystemNode& file) + : myFile(file) { } @@ -41,10 +41,14 @@ std::map KeyValueRepositoryConfigfile::load() string line, key, value; string::size_type equalPos, garbage; - ifstream in(myFilename); - if(!in || !in.is_open()) { - Logger::error("ERROR: Couldn't load from settings file " + myFilename); - + stringstream in; + try + { + myFile.read(in); + } + catch(...) + { + Logger::error("ERROR: Couldn't load from settings file " + myFile.getShortPath()); return values; } @@ -79,13 +83,7 @@ std::map KeyValueRepositoryConfigfile::load() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void KeyValueRepositoryConfigfile::save(const std::map& values) { - ofstream out(myFilename); - if(!out || !out.is_open()) { - Logger::error("ERROR: Couldn't save to settings file " + myFilename); - - return; - } - + stringstream out; out << "; Stella configuration file" << endl << ";" << endl << "; Lines starting with ';' are comments and are ignored." << endl @@ -104,4 +102,13 @@ void KeyValueRepositoryConfigfile::save(const std::map& values) // Write out each of the key and value pairs for(const auto& pair: values) out << pair.first << " = " << pair.second << endl; + + try + { + myFile.write(out); + } + catch(...) + { + Logger::error("ERROR: Couldn't save to settings file " + myFile.getShortPath()); + } } diff --git a/src/common/repository/KeyValueRepositoryConfigfile.hxx b/src/common/repository/KeyValueRepositoryConfigfile.hxx index 4e29166f5..e1aecda07 100644 --- a/src/common/repository/KeyValueRepositoryConfigfile.hxx +++ b/src/common/repository/KeyValueRepositoryConfigfile.hxx @@ -18,13 +18,14 @@ #ifndef KEY_VALUE_REPOSITORY_CONFIGFILE_HXX #define KEY_VALUE_REPOSITORY_CONFIGFILE_HXX +#include "FSNode.hxx" #include "KeyValueRepository.hxx" class KeyValueRepositoryConfigfile : public KeyValueRepository { public: - explicit KeyValueRepositoryConfigfile(const string& filename); + explicit KeyValueRepositoryConfigfile(const FilesystemNode& file); std::map load() override; @@ -34,7 +35,7 @@ class KeyValueRepositoryConfigfile : public KeyValueRepository private: - const string& myFilename; + FilesystemNode myFile; }; #endif // KEY_VALUE_REPOSITORY_CONFIGFILE_HXX diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index b89215d6b..d62b16b66 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -747,7 +747,7 @@ string CartDebug::loadListFile() try { if(lst.read(in) == 0) - return DebuggerParser::red("list file '" + lst.getShortPath() + "' not readable"); + return DebuggerParser::red("list file '" + lst.getShortPath() + "' not found"); } catch(...) { @@ -811,7 +811,7 @@ string CartDebug::loadSymbolFile() try { if(sym.read(in) == 0) - return DebuggerParser::red("symbol file '" + sym.getShortPath() + "' not readable"); + return DebuggerParser::red("symbol file '" + sym.getShortPath() + "' not found"); } catch(...) { @@ -862,15 +862,14 @@ string CartDebug::loadConfigFile() // on the actual ROM filename FilesystemNode romNode(myOSystem.romFile().getPathWithExt(".cfg")); - FilesystemNode cfg(myOSystem.cfgDir() + romNode.getName()); + FilesystemNode cfg = myOSystem.cfgDir(); cfg /= romNode.getName(); if(!cfg.isReadable()) return DebuggerParser::red("config file \'" + cfg.getShortPath() + "\' not found"); stringstream in; try { - if(cfg.read(in) == 0) - return "Unable to load directives from " + cfg.getPath(); + cfg.read(in); } catch(...) { @@ -1002,12 +1001,11 @@ string CartDebug::saveConfigFile() try { FilesystemNode romNode(myOSystem.romFile().getPathWithExt(".cfg")); - FilesystemNode cfg(myOSystem.cfgDir() + romNode.getName()); + FilesystemNode cfg = myOSystem.cfgDir(); cfg /= romNode.getName(); if(!cfg.getParent().isWritable()) return DebuggerParser::red("config file \'" + cfg.getShortPath() + "\' not writable"); - size_t size = cfg.write(out); - if(size == 0) + if(cfg.write(out) == 0) return "Unable to save directives to " + cfg.getShortPath(); if(myConsole.cartridge().romBankCount() > 1) @@ -1016,7 +1014,7 @@ string CartDebug::saveConfigFile() } catch(const runtime_error& e) { - retVal << e.what(); + retVal << "Unable to save directives: " << e.what(); } return retVal.str(); } @@ -1331,24 +1329,21 @@ string CartDebug::saveDisassembly() // And finally, output the disassembly out << buf.str(); + const string& propsname = + myConsole.properties().get(PropType::Cart_Name) + ".asm"; + FilesystemNode node(myOSystem.defaultSaveDir().getPath() + propsname); stringstream retVal; try { - const string& propsname = - myConsole.properties().get(PropType::Cart_Name) + ".asm"; - FilesystemNode node(myOSystem.defaultSaveDir() + propsname); - - size_t size = node.write(out); - if(size == 0) - return "Unable to save disassembly to " + node.getShortPath(); + node.write(out); if(myConsole.cartridge().romBankCount() > 1) retVal << DebuggerParser::red("disassembly for multi-bank ROM not fully supported\n"); retVal << "saved " << node.getShortPath() << " OK"; } - catch(const runtime_error& e) + catch(...) { - retVal << e.what(); + retVal << "Unable to save disassembly to " << node.getShortPath(); } return retVal.str(); } @@ -1358,7 +1353,7 @@ string CartDebug::saveRom() { const string& rom = myConsole.properties().get(PropType::Cart_Name) + ".a26"; - FilesystemNode node(myOSystem.defaultSaveDir() + rom); + FilesystemNode node(myOSystem.defaultSaveDir().getPath() + rom); if(myConsole.cartridge().saveROM(node)) return "saved ROM as " + node.getShortPath(); else @@ -1376,15 +1371,13 @@ string CartDebug::saveAccessFile() try { const string& rom = myConsole.properties().get(PropType::Cart_Name) + ".csv"; - FilesystemNode node(myOSystem.defaultSaveDir() + rom); + FilesystemNode node(myOSystem.defaultSaveDir().getPath() + rom); - size_t size = node.write(out); - if(size > 0) - return "saved access counters as " + node.getShortPath(); + node.write(out); + return "saved access counters as " + node.getShortPath(); } - catch(const runtime_error& e) + catch(...) { - return e.what(); } return DebuggerParser::red("failed to save access counters file"); } diff --git a/src/debugger/Debugger.cxx b/src/debugger/Debugger.cxx index cdb039491..315a45c3b 100644 --- a/src/debugger/Debugger.cxx +++ b/src/debugger/Debugger.cxx @@ -167,7 +167,7 @@ string Debugger::autoExec(StringList* history) ostringstream buf; // autoexec.script is always run - FilesystemNode autoexec(myOSystem.baseDir() + "autoexec.script"); + FilesystemNode autoexec(myOSystem.baseDir().getPath() + "autoexec.script"); buf << "autoExec():" << endl << myParser->exec(autoexec, history) << endl; @@ -304,7 +304,7 @@ int Debugger::step(bool save) myOSystem.console().tia().updateScanlineByStep().flushLineCache(); lockSystem(); - if(save) + if(save) addState("step"); return int(mySystem.cycles() - startCycle); } diff --git a/src/debugger/DebuggerParser.cxx b/src/debugger/DebuggerParser.cxx index 9e3c0745b..73f09268f 100644 --- a/src/debugger/DebuggerParser.cxx +++ b/src/debugger/DebuggerParser.cxx @@ -132,9 +132,9 @@ string DebuggerParser::exec(const FilesystemNode& file, StringList* history) { if(file.exists()) { - ifstream in(file.getPath()); - if(!in.is_open()) - return red("script file \'" + file.getShortPath() + "\' not found"); + stringstream in; + try { file.read(in); } + catch(...) { return red("script file \'" + file.getShortPath() + "\' not found"); } ostringstream buf; int count = 0; @@ -633,11 +633,7 @@ string DebuggerParser::saveScriptFile(string file) if(file.find_last_of('.') == string::npos) file += ".script"; - FilesystemNode node(debugger.myOSystem.defaultSaveDir() + file); - ofstream out(node.getPath()); - if(!out.is_open()) - return "Unable to save script to " + node.getShortPath(); - + stringstream out; Debugger::FunctionDefMap funcs = debugger.getFunctionDefMap(); for(const auto& f: funcs) if (!debugger.isBuiltinFunction(f.first)) @@ -678,6 +674,16 @@ string DebuggerParser::saveScriptFile(string file) out << endl; } + FilesystemNode node(debugger.myOSystem.defaultSaveDir().getPath() + file); + try + { + node.write(out); + } + catch(...) + { + return "Unable to save script to " + node.getShortPath(); + } + return "saved " + node.getShortPath() + " OK"; } @@ -1140,7 +1146,7 @@ void DebuggerParser::executeDump() file << ".dump"; FilesystemNode node(file.str()); // cout << "dump " << args[0] << "-" << args[1] << " to " << file.str() << endl; - ofstream ofs(node.getPath(), ofstream::out | ofstream::app); + std::ofstream ofs(node.getPath(), std::ofstream::out | std::ofstream::app); if(!ofs.is_open()) { outputCommandError("Unable to append dump to file " + node.getShortPath(), myCommand); @@ -1221,9 +1227,8 @@ void DebuggerParser::executeExec() if(file.find_last_of('.') == string::npos) file += ".script"; FilesystemNode node(file); - if (!node.exists()) { - node = FilesystemNode(debugger.myOSystem.defaultSaveDir() + file); - } + if (!node.exists()) + node = FilesystemNode(debugger.myOSystem.defaultSaveDir().getPath() + file); if (argCount == 2) { execPrefix = argStrings[1]; diff --git a/src/emucore/AtariVox.cxx b/src/emucore/AtariVox.cxx index 700789352..9cb60012f 100644 --- a/src/emucore/AtariVox.cxx +++ b/src/emucore/AtariVox.cxx @@ -22,7 +22,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - AtariVox::AtariVox(Jack jack, const Event& event, const System& system, - const string& portname, const string& eepromfile, + const string& portname, const FilesystemNode& eepromfile, const onMessageCallback& callback) : SaveKey(jack, event, system, eepromfile, callback, Controller::Type::AtariVox) { diff --git a/src/emucore/AtariVox.hxx b/src/emucore/AtariVox.hxx index e0c2e72c7..92b5f053d 100644 --- a/src/emucore/AtariVox.hxx +++ b/src/emucore/AtariVox.hxx @@ -20,6 +20,7 @@ class OSystem; class SerialPort; +class FilesystemNode; #include "Control.hxx" #include "SaveKey.hxx" @@ -47,7 +48,7 @@ class AtariVox : public SaveKey @param callback Called to pass messages back to the parent controller */ AtariVox(Jack jack, const Event& event, const System& system, - const string& portname, const string& eepromfile, + const string& portname, const FilesystemNode& eepromfile, const onMessageCallback& callback); virtual ~AtariVox(); diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index dd9146ac9..b8d6231a6 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -192,7 +192,7 @@ Console::Console(OSystem& osystem, unique_ptr& cart, myConsoleInfo.BankSwitch = myCart->about(); // Some carts have an associated nvram file - myCart->setNVRamFile(myOSystem.nvramDir(), myConsoleInfo.CartName); + myCart->setNVRamFile(myOSystem.nvramDir().getPath(), myConsoleInfo.CartName); // Let the other devices know about the new console mySystem->consoleChanged(myConsoleTiming); @@ -824,7 +824,8 @@ unique_ptr Console::getControllerPort(const Controller::Type type, case Controller::Type::AtariVox: { - const string& nvramfile = myOSystem.nvramDir() + "atarivox_eeprom.dat"; + FilesystemNode nvramfile = myOSystem.nvramDir(); + nvramfile /= "atarivox_eeprom.dat"; Controller::onMessageCallback callback = [&os = myOSystem](const string& msg) { bool devSettings = os.settings().getBool("dev.settings"); if(os.settings().getBool(devSettings ? "dev.eepromaccess" : "plr.eepromaccess")) @@ -836,7 +837,8 @@ unique_ptr Console::getControllerPort(const Controller::Type type, } case Controller::Type::SaveKey: { - const string& nvramfile = myOSystem.nvramDir() + "savekey_eeprom.dat"; + FilesystemNode nvramfile = myOSystem.nvramDir(); + nvramfile /= "savekey_eeprom.dat"; Controller::onMessageCallback callback = [&os = myOSystem](const string& msg) { bool devSettings = os.settings().getBool("dev.settings"); if(os.settings().getBool(devSettings ? "dev.eepromaccess" : "plr.eepromaccess")) diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 6e6f38b50..24159b369 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -334,8 +334,9 @@ void EventHandler::handleSystemEvent(SystemEvent e, int, int) #endif #if 0 case SystemEvent::WINDOW_MINIMIZED: - if(myState == EventHandlerState::EMULATION) enterMenuMode(EventHandlerState::OPTIONSMENU); - break; + if(myState == EventHandlerState::EMULATION) + enterMenuMode(EventHandlerState::OPTIONSMENU); + break; #endif default: // handle other events as testing requires // cerr << "handleSystemEvent: " << e << endl; @@ -343,7 +344,6 @@ void EventHandler::handleSystemEvent(SystemEvent e, int, int) } } - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EventHandler::AdjustGroup EventHandler::getAdjustGroup() { diff --git a/src/emucore/FSNode.cxx b/src/emucore/FSNode.cxx index 590705d03..a24ab8850 100644 --- a/src/emucore/FSNode.cxx +++ b/src/emucore/FSNode.cxx @@ -25,15 +25,49 @@ FilesystemNode::FilesystemNode(const AbstractFSNodePtr& realNode) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -FilesystemNode::FilesystemNode(const string& p) +FilesystemNode::FilesystemNode(const string& path) { + setPath(path); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FilesystemNode::setPath(const string& path) +{ + // Only create a new object when necessary + if (path == getPath()) + return; + // Is this potentially a ZIP archive? #if defined(ZIP_SUPPORT) - if (BSPF::containsIgnoreCase(p, ".zip")) - _realNode = FilesystemNodeFactory::create(p, FilesystemNodeFactory::Type::ZIP); + if (BSPF::containsIgnoreCase(path, ".zip")) + _realNode = FilesystemNodeFactory::create(path, FilesystemNodeFactory::Type::ZIP); else #endif - _realNode = FilesystemNodeFactory::create(p, FilesystemNodeFactory::Type::SYSTEM); + _realNode = FilesystemNodeFactory::create(path, FilesystemNodeFactory::Type::SYSTEM); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +FilesystemNode& FilesystemNode::operator/=(const string& path) +{ + // This part could probably be put in a virtual function, but it seems like + // a waste since almost every system uses the same separator, except Windows +#ifdef BSPF_WINDOWS + #define PATH_SEPARATOR '\\' +#else + #define PATH_SEPARATOR '/' +#endif + + if (path != EmptyString) + { + string newPath = getPath(); + if (newPath != EmptyString && newPath[newPath.length()-1] != PATH_SEPARATOR) + newPath += PATH_SEPARATOR; + newPath += path; + setPath(newPath); + } + + return *this; +#undef PATH_SEPARATOR } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -234,7 +268,7 @@ size_t FilesystemNode::read(ByteBuffer& buffer) const return sizeRead; // Otherwise, the default behaviour is to read from a normal C++ ifstream - ifstream in(getPath(), std::ios::binary); + std::ifstream in(getPath(), std::ios::binary); if (in) { in.seekg(0, std::ios::end); @@ -268,7 +302,7 @@ size_t FilesystemNode::read(stringstream& buffer) const // Otherwise, the default behaviour is to read from a normal C++ ifstream // and convert to a stringstream - ifstream in(getPath(), std::ios::binary); + std::ifstream in(getPath(), std::ios::binary); if (in) { in.seekg(0, std::ios::end); @@ -296,7 +330,7 @@ size_t FilesystemNode::write(const ByteBuffer& buffer, size_t size) const return sizeWritten; // Otherwise, the default behaviour is to write to a normal C++ ofstream - ofstream out(getPath(), std::ios::binary); + std::ofstream out(getPath(), std::ios::binary); if (out) { out.write(reinterpret_cast(buffer.get()), size); @@ -321,7 +355,7 @@ size_t FilesystemNode::write(const stringstream& buffer) const return sizeWritten; // Otherwise, the default behaviour is to write to a normal C++ ofstream - ofstream out(getPath(), std::ios::binary); + std::ofstream out(getPath(), std::ios::binary); if (out) { out << buffer.rdbuf(); diff --git a/src/emucore/FSNode.hxx b/src/emucore/FSNode.hxx index f965eaa10..cf76f9ac1 100644 --- a/src/emucore/FSNode.hxx +++ b/src/emucore/FSNode.hxx @@ -84,13 +84,19 @@ class FilesystemNode /** * Compare the name of this node to the name of another, testing for - * equality, + * equality. */ inline bool operator==(const FilesystemNode& node) const { return BSPF::compareIgnoreCase(getName(), node.getName()) == 0; } + /** + * Append the given path to the node, adding a directory separator + * when necessary. Modelled on the C++17 fs::path API. + */ + FilesystemNode& operator/=(const string& path); + /** * By default, the output operator simply outputs the fully-qualified * pathname of the node. @@ -269,6 +275,7 @@ class FilesystemNode private: AbstractFSNodePtr _realNode; explicit FilesystemNode(const AbstractFSNodePtr& realNode); + void setPath(const string& path); }; diff --git a/src/emucore/MT24LC256.cxx b/src/emucore/MT24LC256.cxx index 93dace04b..b99f2ec2a 100644 --- a/src/emucore/MT24LC256.cxx +++ b/src/emucore/MT24LC256.cxx @@ -43,27 +43,23 @@ */ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -MT24LC256::MT24LC256(const string& filename, const System& system, +MT24LC256::MT24LC256(const FilesystemNode& eepromfile, const System& system, const Controller::onMessageCallback& callback) : mySystem(system), myCallback(callback), - myDataFile(filename) + myDataFile(eepromfile) { // Load the data from an external file (if it exists) - ifstream in(myDataFile, std::ios_base::binary); - if(in.is_open()) + try { // Get length of file; it must be 32768 - in.seekg(0, std::ios::end); - if(uInt32(in.tellg()) == FLASH_SIZE) - { - in.seekg(0, std::ios::beg); - in.read(reinterpret_cast(myData.data()), myData.size()); + if(myDataFile.read(myData) == FLASH_SIZE) myDataFileExists = true; - } } - else + catch(...) + { myDataFileExists = false; + } // Then initialize the I2C state jpee_init(); @@ -77,9 +73,8 @@ MT24LC256::~MT24LC256() // Save EEPROM data to external file only when necessary if(!myDataFileExists || myDataChanged) { - ofstream out(myDataFile, std::ios_base::binary); - if(out.is_open()) - out.write(reinterpret_cast(myData.data()), myData.size()); + try { myDataFile.write(myData, FLASH_SIZE); } + catch(...) { } } } @@ -139,7 +134,7 @@ void MT24LC256::eraseAll() // Work around a bug in XCode 11.2 with -O0 and -O1 const uInt8 initialValue = INITIAL_VALUE; - myData.fill(initialValue); + std::fill_n(myData.get(), FLASH_SIZE, initialValue); myDataChanged = true; } @@ -153,7 +148,7 @@ void MT24LC256::eraseCurrent() { if(myPageHit[page]) { - std::fill_n(myData.begin() + page * PAGE_SIZE, PAGE_SIZE, initialValue); + std::fill_n(myData.get() + page * PAGE_SIZE, PAGE_SIZE, initialValue); myDataChanged = true; } } @@ -182,7 +177,7 @@ void MT24LC256::jpee_init() jpee_smallmode = 0; jpee_logmode = -1; if(!myDataFileExists) - myData.fill(initialValue); + std::fill_n(myData.get(), FLASH_SIZE, initialValue); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/MT24LC256.hxx b/src/emucore/MT24LC256.hxx index 94b894b21..6f51dea26 100644 --- a/src/emucore/MT24LC256.hxx +++ b/src/emucore/MT24LC256.hxx @@ -21,6 +21,7 @@ class System; #include "Control.hxx" +#include "FSNode.hxx" #include "bspf.hxx" /** @@ -36,11 +37,11 @@ class MT24LC256 /** Create a new 24LC256 with its data stored in the given file - @param filename Data file containing the EEPROM data - @param system The system using the controller of this device - @param callback Called to pass messages back to the parent controller + @param eepromfile Data file containing the EEPROM data + @param system The system using the controller of this device + @param callback Called to pass messages back to the parent controller */ - MT24LC256(const string& filename, const System& system, + MT24LC256(const FilesystemNode& eepromfile, const System& system, const Controller::onMessageCallback& callback); ~MT24LC256(); @@ -92,7 +93,7 @@ class MT24LC256 Controller::onMessageCallback myCallback; // The EEPROM data - std::array myData; + ByteBuffer myData; // Track which pages are used std::array myPageHit; @@ -110,7 +111,7 @@ class MT24LC256 uInt64 myCyclesWhenSDASet{0}, myCyclesWhenSCLSet{0}; // The file containing the EEPROM data - string myDataFile; + FilesystemNode myDataFile; // Indicates if a valid EEPROM data file exists/was successfully loaded bool myDataFileExists{false}; diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index f7ae17060..057e5739b 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -121,22 +121,22 @@ bool OSystem::create() << " Features: " << myFeatures << endl << " " << myBuildInfo << endl << endl << "Base directory: '" - << FilesystemNode(myBaseDir).getShortPath() << "'" << endl + << myBaseDir.getShortPath() << "'" << endl << "State directory: '" - << FilesystemNode(myStateDir).getShortPath() << "'" << endl + << myStateDir.getShortPath() << "'" << endl << "NVRam directory: '" - << FilesystemNode(myNVRamDir).getShortPath() << "'" << endl; + << myNVRamDir.getShortPath() << "'" << endl; - if(!myConfigFile.empty()) + if(myConfigFile.getPath() != EmptyString) buf << "Configuration file: '" - << FilesystemNode(myConfigFile).getShortPath() << "'" << endl; + << myConfigFile.getShortPath() << "'" << endl; buf << "Game properties: '" << myPropertiesFile.getShortPath() << "'" << endl << "Cheat file: '" - << FilesystemNode(myCheatFile).getShortPath() << "'" << endl + << myCheatFile.getShortPath() << "'" << endl << "Palette file: '" - << FilesystemNode(myPaletteFile).getShortPath() << "'" << endl; + << myPaletteFile.getShortPath() << "'" << endl; Logger::info(buf.str()); // NOTE: The framebuffer MUST be created before any other object!!! @@ -193,30 +193,27 @@ void OSystem::loadConfig(const Settings::Options& options) { // Get base directory and config file from derived class // It will decide whether it can override its default location - getBaseDirAndConfig(myBaseDir, myConfigFile, - myDefaultSaveDir, myDefaultLoadDir, - ourOverrideBaseDirWithApp, ourOverrideBaseDir); + string baseDir, cfgFile, defSaveDir, defLoadDir; + getBaseDirAndConfig(baseDir, cfgFile, defSaveDir, defLoadDir, + ourOverrideBaseDirWithApp, ourOverrideBaseDir); // Get fully-qualified pathnames, and make directories when needed - FilesystemNode node(myBaseDir); - if(!node.isDirectory()) - node.makeDir(); - myBaseDir = node.getPath(); - if(!myConfigFile.empty()) - myConfigFile = FilesystemNode(myConfigFile).getPath(); + myBaseDir = FilesystemNode(baseDir); + if(!myBaseDir.isDirectory()) + myBaseDir.makeDir(); + if(!cfgFile.empty()) + myConfigFile = FilesystemNode(cfgFile); - FilesystemNode save(myDefaultSaveDir); - if(!save.isDirectory()) - save.makeDir(); - myDefaultSaveDir = save.getShortPath(); + myDefaultSaveDir = FilesystemNode(defSaveDir); + if(!myDefaultSaveDir.isDirectory()) + myDefaultSaveDir.makeDir(); - FilesystemNode load(myDefaultLoadDir); - if(!load.isDirectory()) - load.makeDir(); - myDefaultLoadDir = load.getShortPath(); + myDefaultLoadDir = FilesystemNode(defLoadDir); + if(!myDefaultLoadDir.isDirectory()) + myDefaultLoadDir.makeDir(); #ifdef SQLITE_SUPPORT - mySettingsDb = make_shared(myBaseDir, "settings"); + mySettingsDb = make_shared(myBaseDir.getPath(), "settings"); if(!mySettingsDb->initialize()) mySettingsDb.reset(); #endif @@ -259,38 +256,48 @@ void OSystem::saveConfig() void OSystem::setConfigPaths() { // Make sure all required directories actually exist - auto buildDirIfRequired = [](string& path, const string& pathToBuild) + auto buildDirIfRequired = [](FilesystemNode& path, + const FilesystemNode& initialPath, + const string& pathToAppend = EmptyString) { - FilesystemNode node(pathToBuild); - if(!node.isDirectory()) - node.makeDir(); - - path = node.getPath(); + path = initialPath; + if(pathToAppend != EmptyString) + path /= pathToAppend; + if(!path.isDirectory()) + path.makeDir(); }; - buildDirIfRequired(myStateDir, myBaseDir + "state"); - buildDirIfRequired(myNVRamDir, myBaseDir + "nvram"); + buildDirIfRequired(myStateDir, myBaseDir, "state"); + buildDirIfRequired(myNVRamDir, myBaseDir, "nvram"); #ifdef DEBUGGER_SUPPORT - buildDirIfRequired(myCfgDir, myBaseDir + "cfg"); + buildDirIfRequired(myCfgDir, myBaseDir, "cfg"); #endif #ifdef PNG_SUPPORT - mySnapshotSaveDir = mySettings->getString("snapsavedir"); - if(mySnapshotSaveDir == "") mySnapshotSaveDir = defaultSaveDir(); - buildDirIfRequired(mySnapshotSaveDir, mySnapshotSaveDir); + const string& ssSaveDir = mySettings->getString("snapsavedir"); + if(ssSaveDir == EmptyString) + mySnapshotSaveDir = defaultSaveDir(); + else + mySnapshotSaveDir = FilesystemNode(ssSaveDir); + if(!mySnapshotSaveDir.isDirectory()) + mySnapshotSaveDir.makeDir(); - mySnapshotLoadDir = mySettings->getString("snaploaddir"); - if(mySnapshotLoadDir == "") mySnapshotLoadDir = defaultLoadDir(); - buildDirIfRequired(mySnapshotLoadDir, mySnapshotLoadDir); + const string& ssLoadDir = mySettings->getString("snaploaddir"); + if(ssLoadDir == EmptyString) + mySnapshotLoadDir = defaultLoadDir(); + else + mySnapshotLoadDir = FilesystemNode(ssLoadDir); + if(!mySnapshotLoadDir.isDirectory()) + mySnapshotLoadDir.makeDir(); #endif - myCheatFile = FilesystemNode(myBaseDir + "stella.cht").getPath(); - myPaletteFile = FilesystemNode(myBaseDir + "stella.pal").getPath(); - myPropertiesFile = FilesystemNode(myBaseDir + "stella.pro"); + myCheatFile = myBaseDir; myCheatFile /= "stella.cht"; + myPaletteFile = myBaseDir; myPaletteFile /= "stella.pal"; + myPropertiesFile = myBaseDir; myPropertiesFile /= "stella.pro"; #if 0 // Debug code - auto dbgPath = [](const string& desc, const string& location) + auto dbgPath = [](const string& desc, const FilesystemNode& location) { cerr << desc << ": " << location << endl; }; @@ -310,21 +317,24 @@ void OSystem::setConfigPaths() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool OSystem::checkUserPalette(bool outputError) const { - const string& palette = paletteFile(); - ifstream in(palette, std::ios::binary); - if (!in) - return false; - - // Make sure the contains enough data for the NTSC, PAL and SECAM palettes - // This means 128 colours each for NTSC and PAL, at 3 bytes per pixel - // and 8 colours for SECAM at 3 bytes per pixel - in.seekg(0, std::ios::end); - std::streampos length = in.tellg(); - in.seekg(0, std::ios::beg); - if (length < 128 * 3 * 2 + 8 * 3) + try + { + ByteBuffer palette; + size_t size = paletteFile().read(palette); + + // Make sure the contains enough data for the NTSC, PAL and SECAM palettes + // This means 128 colours each for NTSC and PAL, at 3 bytes per pixel + // and 8 colours for SECAM at 3 bytes per pixel + if(size != 128 * 3 * 2 + 8 * 3) + { + if(outputError) + cerr << "ERROR: invalid palette file " << paletteFile() << endl; + + return false; + } + } + catch(...) { - if (outputError) - cerr << "ERROR: invalid palette file " << palette << endl; return false; } return true; @@ -457,8 +467,11 @@ string OSystem::createConsole(const FilesystemNode& rom, const string& md5sum, myConsole->cartridge().detectedType() + ", loading ROM" + id); } buf << "Game console created:" << endl - << " ROM file: " << myRomFile.getShortPath() << endl << endl - << getROMInfo(*myConsole); + << " ROM file: " << myRomFile.getShortPath() << endl; + FilesystemNode propsFile(myRomFile.getPathWithExt(".pro")); + if(propsFile.exists()) + buf << " PRO file: " << propsFile.getShortPath() << endl; + buf << endl << getROMInfo(*myConsole); Logger::info(buf.str()); myFrameBuffer->setCursorState(); @@ -821,7 +834,7 @@ shared_ptr OSystem::createSettingsRepository() ? shared_ptr(mySettingsDb, &mySettingsDb->settingsRepository()) : make_shared(); #else - if (myConfigFile.empty()) + if (myConfigFile.getPath() == EmptyString) return make_shared(); return make_shared(myConfigFile); diff --git a/src/emucore/OSystem.hxx b/src/emucore/OSystem.hxx index baebd3375..4fb6287e8 100644 --- a/src/emucore/OSystem.hxx +++ b/src/emucore/OSystem.hxx @@ -246,53 +246,48 @@ class OSystem void setConfigPaths(); /** - Return the default full/complete directory name for storing data. + Return the default full/complete path name for storing data. */ - const string& baseDir() const { return myBaseDir; } + const FilesystemNode& baseDir() const { return myBaseDir; } /** - Return the full/complete directory name for storing state files. + Return the full/complete path name for storing state files. */ - const string& stateDir() const { return myStateDir; } + const FilesystemNode& stateDir() const { return myStateDir; } /** - Return the full/complete directory name for storing nvram + Return the full/complete path name for storing nvram (flash/EEPROM) files. */ - const string& nvramDir() const { return myNVRamDir; } + const FilesystemNode& nvramDir() const { return myNVRamDir; } #ifdef CHEATCODE_SUPPORT /** - This method should be called to get the full path of the cheat file. - - @return String representing the full path of the cheat filename. + Return the full/complete path name of the cheat file. */ - const string& cheatFile() const { return myCheatFile; } + const FilesystemNode& cheatFile() const { return myCheatFile; } #endif #ifdef DEBUGGER_SUPPORT /** - Return the full/complete directory name for storing Distella cfg files. + Return the full/complete path name for storing Distella cfg files. */ - const string& cfgDir() const { return myCfgDir; } + const FilesystemNode& cfgDir() const { return myCfgDir; } #endif #ifdef PNG_SUPPORT /** - Return the full/complete directory name for saving and loading + Return the full/complete path name for saving and loading PNG snapshots. */ - const string& snapshotSaveDir() const { return mySnapshotSaveDir; } - const string& snapshotLoadDir() const { return mySnapshotLoadDir; } + const FilesystemNode& snapshotSaveDir() const { return mySnapshotSaveDir; } + const FilesystemNode& snapshotLoadDir() const { return mySnapshotLoadDir; } #endif /** - This method should be called to get the full path of the - (optional) palette file. - - @return String representing the full path of the properties filename. + Return the full/complete path name of the (optional) palette file. */ - const string& paletteFile() const { return myPaletteFile; } + const FilesystemNode& paletteFile() const { return myPaletteFile; } /** Checks if a valid a user-defined palette file exists. @@ -300,10 +295,7 @@ class OSystem bool checkUserPalette(bool outputError = false) const; /** - This method should be called to get the full path of the currently - loaded ROM. - - @return FSNode object representing the ROM file. + Return the full/complete path name of the currently loaded ROM. */ const FilesystemNode& romFile() const { return myRomFile; } @@ -311,8 +303,8 @@ class OSystem The default locations for saving and loading various files that don't already have a specific location. */ - const string& defaultSaveDir() const { return myDefaultSaveDir; } - const string& defaultLoadDir() const { return myDefaultLoadDir; } + const FilesystemNode& defaultSaveDir() const { return myDefaultSaveDir; } + const FilesystemNode& defaultLoadDir() const { return myDefaultLoadDir; } /** Open the given ROM and return an array containing its contents. @@ -533,22 +525,10 @@ class OSystem bool myQuitLoop{false}; private: - string myBaseDir; - string myStateDir; - string mySnapshotSaveDir; - string mySnapshotLoadDir; - string myNVRamDir; - string myCfgDir; - string myDefaultSaveDir; - string myDefaultLoadDir; - - string myCheatFile; - string myConfigFile; - string myPaletteFile; - FilesystemNode myPropertiesFile; - - FilesystemNode myRomFile; - string myRomMD5; + FilesystemNode myBaseDir, myStateDir, mySnapshotSaveDir, mySnapshotLoadDir, + myNVRamDir, myCfgDir, myDefaultSaveDir, myDefaultLoadDir; + FilesystemNode myCheatFile, myConfigFile, myPaletteFile, myPropertiesFile; + FilesystemNode myRomFile; string myRomMD5; string myFeatures; string myBuildInfo; diff --git a/src/emucore/SaveKey.cxx b/src/emucore/SaveKey.cxx index b0ca56f89..dcab2b8b3 100644 --- a/src/emucore/SaveKey.cxx +++ b/src/emucore/SaveKey.cxx @@ -22,7 +22,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SaveKey::SaveKey(Jack jack, const Event& event, const System& system, - const string& eepromfile, const onMessageCallback& callback, + const FilesystemNode& eepromfile, const onMessageCallback& callback, Type type) : Controller(jack, event, system, type), myEEPROM(make_unique(eepromfile, system, callback)) @@ -33,7 +33,7 @@ SaveKey::SaveKey(Jack jack, const Event& event, const System& system, // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SaveKey::SaveKey(Jack jack, const Event& event, const System& system, - const string& eepromfile, const onMessageCallback& callback) + const FilesystemNode& eepromfile, const onMessageCallback& callback) : SaveKey(jack, event, system, eepromfile, callback, Controller::Type::SaveKey) { } diff --git a/src/emucore/SaveKey.hxx b/src/emucore/SaveKey.hxx index 70ea96e5e..ce5c3e347 100644 --- a/src/emucore/SaveKey.hxx +++ b/src/emucore/SaveKey.hxx @@ -20,6 +20,7 @@ class MT24LC256; class OSystem; +class FilesystemNode; #include "Control.hxx" @@ -45,7 +46,7 @@ class SaveKey : public Controller @param callback Called to pass messages back to the parent controller */ SaveKey(Jack jack, const Event& event, const System& system, - const string& eepromfile, const onMessageCallback& callback); + const FilesystemNode& eepromfile, const onMessageCallback& callback); virtual ~SaveKey(); protected: @@ -54,7 +55,8 @@ class SaveKey : public Controller that inherit from SaveKey (currently, AtariVox) */ SaveKey(Jack jack, const Event& event, const System& system, - const string& eepromfile, const onMessageCallback& callback, Type type); + const FilesystemNode& eepromfile, + const onMessageCallback& callback, Type type); public: using Controller::read; diff --git a/src/gui/GameInfoDialog.cxx b/src/gui/GameInfoDialog.cxx index ff1fca0c6..6017c65d3 100644 --- a/src/gui/GameInfoDialog.cxx +++ b/src/gui/GameInfoDialog.cxx @@ -809,17 +809,22 @@ void GameInfoDialog::eraseEEPROM() void GameInfoDialog::saveCurrentPropertiesToDisk() { saveProperties(); + stringstream out; + out << myGameProperties; - FilesystemNode propfile(instance().defaultSaveDir() + myGameFile.getNameWithExt(".pro")); - ofstream out(propfile.getPath()); - if(out) + try { - out << myGameProperties; + FilesystemNode propfile = instance().defaultSaveDir(); + propfile /= myGameFile.getNameWithExt(".pro"); + + propfile.write(out); instance().frameBuffer().showMessage("Properties saved to " + propfile.getShortPath()); } - else + catch(...) + { instance().frameBuffer().showMessage("Error saving properties"); + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/gui/LoggerDialog.cxx b/src/gui/LoggerDialog.cxx index f9b05911b..ce60d20b7 100644 --- a/src/gui/LoggerDialog.cxx +++ b/src/gui/LoggerDialog.cxx @@ -116,15 +116,18 @@ void LoggerDialog::saveConfig() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LoggerDialog::saveLogFile() { - ostringstream path; - path << instance().defaultSaveDir() << "stella.log"; - FilesystemNode node(path.str()); + FilesystemNode node = instance().defaultSaveDir(); + node /= "stella.log"; - ofstream out(node.getPath()); - if(out.is_open()) + try { + stringstream out; out << Logger::instance().logMessages(); - instance().frameBuffer().showMessage("Saving log file to " + path.str()); + instance().frameBuffer().showMessage("Saving log file to " + node.getShortPath()); + } + catch(...) + { + instance().frameBuffer().showMessage("Error savin log file to " + node.getShortPath()); } } diff --git a/src/gui/RomInfoWidget.cxx b/src/gui/RomInfoWidget.cxx index b90a45fb2..7e29d19e4 100644 --- a/src/gui/RomInfoWidget.cxx +++ b/src/gui/RomInfoWidget.cxx @@ -104,7 +104,7 @@ void RomInfoWidget::parseProperties(const FilesystemNode& node) #ifdef PNG_SUPPORT // Get a valid filename representing a snapshot file for this rom - const string& filename = instance().snapshotLoadDir() + + const string& filename = instance().snapshotLoadDir().getPath() + myProperties.get(PropType::Cart_Name) + ".png"; // Read the PNG file diff --git a/src/gui/SnapshotDialog.cxx b/src/gui/SnapshotDialog.cxx index e7f5795ed..792d7af7f 100644 --- a/src/gui/SnapshotDialog.cxx +++ b/src/gui/SnapshotDialog.cxx @@ -131,7 +131,7 @@ void SnapshotDialog::saveConfig() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SnapshotDialog::setDefaults() { - mySnapSavePath->setText(instance().defaultSaveDir()); + mySnapSavePath->setText(instance().defaultSaveDir().getShortPath()); mySnapInterval->setValue(2); mySnapName->setState(false); mySnapSingle->setState(false); diff --git a/src/gui/UIDialog.cxx b/src/gui/UIDialog.cxx index 598dd0756..72e70ecae 100644 --- a/src/gui/UIDialog.cxx +++ b/src/gui/UIDialog.cxx @@ -507,7 +507,7 @@ void UIDialog::setDefaults() myLauncherHeightSlider->setValue(h); myLauncherFontPopup->setSelected("medium", ""); myRomViewerSize->setValue(35); - mySnapLoadPath->setText(instance().defaultLoadDir()); + mySnapLoadPath->setText(instance().defaultLoadDir().getShortPath()); myLauncherExitWidget->setState(false); break; } From ac1a4b8d6893f568d469981d73e318be86fa867b Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sat, 25 Jul 2020 16:37:52 -0230 Subject: [PATCH 350/377] Fixed snapshots being cut off in fullscreen mode (fixes #674). --- Changes.txt | 3 +++ src/common/Rect.hxx | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Changes.txt b/Changes.txt index 32969710a..0a1179454 100644 --- a/Changes.txt +++ b/Changes.txt @@ -14,6 +14,9 @@ 6.2.1 to 6.3 (XXXX XX, 2020) + * Fix bug when taking fullscreen snapshots; the dimensions were sometimes + cut off. + * Added autofire. * Added new interface palette 'Dark'. (TODO: DOC) diff --git a/src/common/Rect.hxx b/src/common/Rect.hxx index 155151457..5243740f2 100644 --- a/src/common/Rect.hxx +++ b/src/common/Rect.hxx @@ -111,7 +111,8 @@ struct Rect Rect() {} explicit Rect(const Size& s) : bottom(s.h), right(s.w) { assert(valid()); } Rect(uInt32 w, uInt32 h) : bottom(h), right(w) { assert(valid()); } - Rect(const Point& p, uInt32 w, uInt32 h) : top(p.y), left(p.x), bottom(h), right(w) { assert(valid()); } + Rect(const Point& p, uInt32 w, uInt32 h) + : top(p.y), left(p.x), bottom(p.y + h), right(p.x + w) { assert(valid()); } Rect(uInt32 x1, uInt32 y1, uInt32 x2, uInt32 y2) : top(y1), left(x1), bottom(y2), right(x2) { assert(valid()); } uInt32 x() const { return left; } From 1a7ee589824542659d3f215810b2e6369d283f99 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sat, 25 Jul 2020 17:53:53 -0230 Subject: [PATCH 351/377] Fix bug with accessing files as text using binary I/O. This doesn't seem to matter for Linux and macOS, but breaks Windows CRLF endings. --- src/emucore/FSNode.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/emucore/FSNode.cxx b/src/emucore/FSNode.cxx index a24ab8850..f2e5e477a 100644 --- a/src/emucore/FSNode.cxx +++ b/src/emucore/FSNode.cxx @@ -302,7 +302,7 @@ size_t FilesystemNode::read(stringstream& buffer) const // Otherwise, the default behaviour is to read from a normal C++ ifstream // and convert to a stringstream - std::ifstream in(getPath(), std::ios::binary); + std::ifstream in(getPath()); if (in) { in.seekg(0, std::ios::end); @@ -355,7 +355,7 @@ size_t FilesystemNode::write(const stringstream& buffer) const return sizeWritten; // Otherwise, the default behaviour is to write to a normal C++ ofstream - std::ofstream out(getPath(), std::ios::binary); + std::ofstream out(getPath()); if (out) { out << buffer.rdbuf(); From 709e1ccb5a3c80bebe0527f7cd108b50803c035a Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 26 Jul 2020 09:31:58 +0200 Subject: [PATCH 352/377] added docs for TM playback --- Changes.txt | 8 +++++--- docs/graphics/timemachine.png | Bin 2197 -> 2564 bytes docs/index.html | 10 ++++++++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Changes.txt b/Changes.txt index 0a1179454..c9b902582 100644 --- a/Changes.txt +++ b/Changes.txt @@ -14,15 +14,14 @@ 6.2.1 to 6.3 (XXXX XX, 2020) - * Fix bug when taking fullscreen snapshots; the dimensions were sometimes - cut off. - * Added autofire. * Added new interface palette 'Dark'. (TODO: DOC) * Extended global hotkeys for debug options. + * Added option to playback a game using the Time Machine + * Allow taking snapshots from within Time Machine dialog * Added ability to access most files that Stella uses from within a ZIP @@ -36,6 +35,9 @@ * Replaced "Re-disassemble" with "Disassemble @ current line" in debugger + * Fix bug when taking fullscreen snapshots; the dimensions were sometimes + cut off. + -Have fun! diff --git a/docs/graphics/timemachine.png b/docs/graphics/timemachine.png index 269005fe83a8894fc8c060e69660e2f700f30add..fc2237abf333c1d6119098c1927cdb7c618708ac 100644 GIT binary patch delta 2519 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 b)z$w21iG}S^1OLf00000NkvXXu0mjf_!2Mc diff --git a/docs/index.html b/docs/index.html index 82fe5364b..49e4c50bc 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1819,6 +1819,11 @@ + + + + + @@ -2027,12 +2032,13 @@

      Bottom row (left to right)

      Enter/Exit the Time Machine dialogt to enter, t/Escape/Space to exitt to enter, t/Escape/Space to exitShift + t to enter, Shift + t/Escape/Space to exit and continue with emulationShift + t to enter, Shift + t/Escape/Space to exit and continue with emulation
      -autofirerate <0 - 30>
      Automatic trigger rate of the fire buttons in Hz (0 = disabled)
      -joyallow4 <1|0>
      Allow all 4 directions on a joystick to be pressed @@ -3302,6 +3307,7 @@
      Analog paddle) Dejitter averagingStrength of paddle input averaging, suppresses mouse jitter-dejitter.base
      (Analog paddle) Dejitter reactionStrength of paddle reaction to fast paddle movements, suppresses mouse jitter-dejitter.diff
      Digital paddle sensitivitySensitivity used when emulating a paddle using a digital device-dsense
      Autofire rateAutomatic trigger rate of the fire buttons in Hz-autofirerate
      Allow all 4 directions ...Allow all 4 joystick directions to be pressed simultaneously-joyallow4
      Use modifier key combosEnable using modifier keys in keyboard actions-modcombo
      Swap Stelladaptor portsSwap the order of the detected Stelladaptors/2600-daptors (see Advanced Configuration - Stelladaptor/2600-daptor Support)-saport
      Key (Standard) Key (macOS)
      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 + rControl + r
      Reload ROM listing (ROM launcher mode)Control + rControl + r
      Emulate 'frying' effect (TIA mode)BackspaceBackspace
      Go to parent directory (UI mode)BackspaceBackspace
      Toggle 'Turbo' mode Control + t Control + t
      Decrease autofire rateShift-Control + aShift-Control + a
      Increase autofire rateControl + aControl + a
      Switch mouse between controller emulation modes
      (see Game Properties - Controller)
      Control + 0 Control + 0
      Toggle grab mouse Control + gControl + 1 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 + rControl + r
      Reload ROM listing (ROM launcher mode)Control + rControl + r
      Emulate 'frying' effect (TIA mode)BackspaceBackspace
      Go to parent directory (UI mode)BackspaceBackspace
      Save continuous PNG snapshots
      (per interval defined in Snapshot Settings)
      Alt + s Cmd + s
      Save continuous PNG snapshots (every frame) Shift-Alt + sAlt + t Cmd + t
      Enter/Exit the Time Machine dialog Shift + t to enter, Shift + t/Escape/Space to exit and continue with emulation Shift + t to enter, Shift + t/Escape/Space to exit and continue with emulation
      Rewind by one state (enters the Time Machine dialog) Alt + Left arrowShift + t to enter, Shift + t/Escape/Space to exit and continue with emulation Shift + t to enter, Shift + t/Escape/Space to exit and continue with emulation
      Playback the Time Machine from current state (without sound).Shift + SpaceShift + Space
      Rewind by one state (enters the Time Machine dialog) Alt + Left arrow
      - - + + From fd02e13d555906650846cc9c5b6db57024f976e9 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 26 Jul 2020 10:52:38 +0200 Subject: [PATCH 353/377] added emulation speed hotkeys --- docs/index.html | 12 +++++- src/common/PKeyboardHandler.cxx | 2 + src/emucore/Console.cxx | 67 ++++++++++++++++++++++++++++++++- src/emucore/Console.hxx | 6 +++ src/emucore/Event.hxx | 1 + src/emucore/EventHandler.cxx | 14 ++++++- src/emucore/EventHandler.hxx | 2 +- 7 files changed, 98 insertions(+), 6 deletions(-) diff --git a/docs/index.html b/docs/index.html index 49e4c50bc..38b3da174 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1767,7 +1767,17 @@ - + + + + + + + + + + + diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index 6d726f3fc..7532a1632 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -525,6 +525,8 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo {Event::SettingIncrease, KBDK_KP_9, KBDM_CTRL}, {Event::ToggleInter, KBDK_I, KBDM_CTRL}, + {Event::DecreaseSpeed, KBDK_S, KBDM_SHIFT | KBDM_CTRL}, + {Event::IncreaseSpeed, KBDK_S, KBDM_CTRL }, {Event::ToggleTurbo, KBDK_T, KBDM_CTRL}, {Event::ToggleJitter, KBDK_J, MOD3}, {Event::ToggleFrameStats, KBDK_L, MOD3}, diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index b8d6231a6..9cb5c5087 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -73,6 +73,45 @@ #include "Console.hxx" +namespace { + // Emulation speed is a positive float that multiplies the framerate. However, the UI controls + // adjust speed in terms of a speedup factor (1/10, 1/9 .. 1/2, 1, 2, 3, .., 10). The following + // mapping and formatting functions implement this conversion. The speedup factor is represented + // by an integer value between -900 and 900 (0 means no speedup). + + constexpr int MAX_SPEED = 900; + constexpr int MIN_SPEED = -900; + constexpr int SPEED_STEP = 10; + + int mapSpeed(float speed) + { + speed = std::abs(speed); + + return BSPF::clamp( + static_cast(round(100 * (speed >= 1 ? speed - 1 : -1 / speed + 1))), + MIN_SPEED, MAX_SPEED + ); + } + + float unmapSpeed(int speed) + { + float f_speed = static_cast(speed) / 100; + + return speed < 0 ? -1 / (f_speed - 1) : 1 + f_speed; + } + + string formatSpeed(int speed) { + stringstream ss; + + ss + << std::setw(3) << std::fixed << std::setprecision(0) + << (unmapSpeed(speed) * 100); + + return ss.str(); + } +} + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Console::Console(OSystem& osystem, unique_ptr& cart, const Properties& props, AudioSettings& audioSettings) @@ -503,6 +542,31 @@ void Console::toggleTurbo() myOSystem.frameBuffer().showMessage(ss.str()); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Console::changeSpeed(int direction) +{ + int speed = mapSpeed(myOSystem.settings().getFloat("speed")); + bool turbo = myOSystem.settings().getBool("turbo"); + + speed = BSPF::clamp(speed + direction * SPEED_STEP, MIN_SPEED, MAX_SPEED); + myOSystem.settings().setValue("speed", unmapSpeed(speed)); + + // update rate + initializeAudio(); + + if(turbo) + { + myOSystem.settings().setValue("turbo", false); + // update VSync + initializeVideo(); + } + + ostringstream val; + + val << formatSpeed(speed) << "%"; + myOSystem.frameBuffer().showMessage("Emulation speed", val.str(), speed, MIN_SPEED, MAX_SPEED); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::togglePhosphor() { @@ -890,9 +954,8 @@ void Console::changeAutoFireRate(int direction) if(rate) val << rate << " Hz"; else - { val << "Off"; - } + myOSystem.frameBuffer().showMessage("Autofire rate", val.str(), rate, 0, isNTSC ? 30 : 25); } diff --git a/src/emucore/Console.hxx b/src/emucore/Console.hxx index 86595da9f..366e606a0 100644 --- a/src/emucore/Console.hxx +++ b/src/emucore/Console.hxx @@ -213,6 +213,12 @@ class Console : public Serializable, public ConsoleIO */ void toggleTurbo(); + /** + Change emulation speed + + @param direction +1 indicates increase, -1 indicates decrease. + */ + void changeSpeed(int direction = +1); /** Toggles phosphor effect. diff --git a/src/emucore/Event.hxx b/src/emucore/Event.hxx index b9a301e7f..52808d77a 100644 --- a/src/emucore/Event.hxx +++ b/src/emucore/Event.hxx @@ -127,6 +127,7 @@ class Event PreviousSettingGroup, NextSettingGroup, TogglePlayBackMode, DecreaseAutoFire, IncreaseAutoFire, + DecreaseSpeed, IncreaseSpeed, LastType }; diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 24159b369..75a38b97c 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -1220,6 +1220,14 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) /////////////////////////////////////////////////////////////////////////// // Misc events + case Event::DecreaseSpeed: + if(pressed) myOSystem.console().changeSpeed(-1); + return; + + case Event::IncreaseSpeed: + if(pressed) myOSystem.console().changeSpeed(+1); + return; + case Event::ToggleTurbo: if (pressed && !repeated) myOSystem.console().toggleTurbo(); return; @@ -2403,7 +2411,9 @@ EventHandler::EmulActionList EventHandler::ourEmulActionList = { { { Event::TogglePauseMode, "Toggle Pause mode", "" }, { Event::StartPauseMode, "Start Pause mode", "" }, { Event::Fry, "Fry cartridge", "" }, - { Event::ToggleTurbo, "Toggle Turbo mode", "" }, + { Event::DecreaseSpeed, "Decrease emulation speed", "" }, + { Event::IncreaseSpeed, "Increase emulation speed", "" }, + { Event::ToggleTurbo, "Toggle 'Turbo' mode", "" }, { Event::DebuggerMode, "Toggle Debugger mode", "" }, { Event::ConsoleSelect, "Select", "" }, @@ -2634,7 +2644,7 @@ EventHandler::MenuActionList EventHandler::ourMenuActionList = { { const Event::EventSet EventHandler::MiscEvents = { Event::Quit, Event::ReloadConsole, Event::Fry, Event::StartPauseMode, Event::TogglePauseMode, Event::OptionsMenuMode, Event::CmdMenuMode, Event::ExitMode, - Event::ToggleTurbo, + Event::ToggleTurbo, Event::DecreaseSpeed, Event::IncreaseSpeed, Event::TakeSnapshot, Event::ToggleContSnapshots, Event::ToggleContSnapshotsFrame, // Event::MouseAxisXMove, Event::MouseAxisYMove, // Event::MouseButtonLeftValue, Event::MouseButtonRightValue, diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx index 055d56d64..93e167282 100644 --- a/src/emucore/EventHandler.hxx +++ b/src/emucore/EventHandler.hxx @@ -558,7 +558,7 @@ class EventHandler #else REFRESH_SIZE = 0, #endif - EMUL_ACTIONLIST_SIZE = 162 + PNG_SIZE + COMBO_SIZE + REFRESH_SIZE, + EMUL_ACTIONLIST_SIZE = 164 + PNG_SIZE + COMBO_SIZE + REFRESH_SIZE, MENU_ACTIONLIST_SIZE = 18 ; From 829710b6378a096edc9589f4e78db5093a742a9f Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 26 Jul 2020 10:59:08 +0200 Subject: [PATCH 354/377] added emulation speed change to 'direct only' hotkeys --- src/emucore/EventHandler.cxx | 13 +++++++++++-- src/emucore/EventHandler.hxx | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 75a38b97c..ed72579a6 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -472,6 +472,7 @@ AdjustFunction EventHandler::getAdjustSetting(AdjustSetting setting) std::bind(&StateManager::changeState, &myOSystem.state(), _1), std::bind(&PaletteHandler::changeCurrentAdjustable, &myOSystem.frameBuffer().tiaSurface().paletteHandler(), _1), std::bind(&TIASurface::changeCurrentNTSCAdjustable, &myOSystem.frameBuffer().tiaSurface(), _1), + std::bind(&Console::changeSpeed, &myOSystem.console(), _1), }; return ADJUST_FUNCTIONS[int(setting)]; @@ -1221,11 +1222,19 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) // Misc events case Event::DecreaseSpeed: - if(pressed) myOSystem.console().changeSpeed(-1); + if(pressed) + { + myOSystem.console().changeSpeed(-1); + myAdjustDirect = AdjustSetting::CHANGE_SPEED; + } return; case Event::IncreaseSpeed: - if(pressed) myOSystem.console().changeSpeed(+1); + if(pressed) + { + myOSystem.console().changeSpeed(+1); + myAdjustDirect = AdjustSetting::CHANGE_SPEED; + } return; case Event::ToggleTurbo: diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx index 93e167282..4c7954c40 100644 --- a/src/emucore/EventHandler.hxx +++ b/src/emucore/EventHandler.hxx @@ -449,6 +449,7 @@ class EventHandler STATE, PALETTE_CHANGE_ATTRIBUTE, NTSC_CHANGE_ATTRIBUTE, + CHANGE_SPEED, // *** Ranges *** NUM_ADJ, START_AV_ADJ = VOLUME, From f9fcd11267150ffc226e570e75eb4f53cc25f7f6 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 26 Jul 2020 18:29:50 +0200 Subject: [PATCH 355/377] minor doc update --- docs/index.html | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/index.html b/docs/index.html index 38b3da174..04829b57e 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1826,11 +1826,16 @@ - - + + - + + + + + + From 069f98194b2595ce602093c7ba6ffee3555d2daf Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 26 Jul 2020 21:41:17 +0200 Subject: [PATCH 356/377] Fixed popup widget text limits --- src/gui/PopUpWidget.cxx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gui/PopUpWidget.cxx b/src/gui/PopUpWidget.cxx index 589c34660..3f4474fea 100644 --- a/src/gui/PopUpWidget.cxx +++ b/src/gui/PopUpWidget.cxx @@ -260,8 +260,9 @@ void PopUpWidget::drawWidget(bool hilite) // Draw the selected entry, if any const string& name = myMenu->getSelectedName(); - TextAlign align = (_font.getStringWidth(name) > w - 6) ? + w -= dropDownWidth(_font); + TextAlign align = (_font.getStringWidth(name) > w) ? TextAlign::Right : TextAlign::Left; - s.drawString(_font, name, x + _textOfs, _y + myTextY, w - 6, + s.drawString(_font, name, x + _textOfs, _y + myTextY, w, !(isEnabled() && onTop) ? kColor : _changed ? kDbgChangedTextColor : kTextColor, align); } From 9ad484f62d5af06414018521e01d751099ba2a4e Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Sun, 26 Jul 2020 21:56:46 +0200 Subject: [PATCH 357/377] Remove misleading comment. --- src/emucore/FrameBuffer.cxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index d35ebd36f..80b1d67e1 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -507,8 +507,6 @@ void FrameBuffer::update(bool force) void FrameBuffer::updateInEmulationMode(float framesPerSecond) { // Update method that is specifically tailored to emulation mode - // Typically called from a thread, so it needs to be separate from - // the normal update() method // // We don't worry about selective rendering here; the rendering // always happens at the full framerate From 3785f2b7910fc8ecf57a311bb1122fdff5e751ec Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Mon, 27 Jul 2020 00:42:53 -0230 Subject: [PATCH 358/377] AtariVox controller was mistakenly reported as SaveKey in the logs. --- src/emucore/AtariVox.hxx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/emucore/AtariVox.hxx b/src/emucore/AtariVox.hxx index 92b5f053d..3251234ed 100644 --- a/src/emucore/AtariVox.hxx +++ b/src/emucore/AtariVox.hxx @@ -79,6 +79,11 @@ class AtariVox : public SaveKey */ void update() override { } + /** + Returns the name of this controller. + */ + string name() const override { return "AtariVox"; } + /** Notification method invoked by the system after its reset method has been called. It may be necessary to override this method for From cb75f794dbb47bef183062f03c9b960b3f9455da Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 27 Jul 2020 09:01:54 +0200 Subject: [PATCH 359/377] fixed missing log file saving --- src/gui/LoggerDialog.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/LoggerDialog.cxx b/src/gui/LoggerDialog.cxx index ce60d20b7..bf53d80a0 100644 --- a/src/gui/LoggerDialog.cxx +++ b/src/gui/LoggerDialog.cxx @@ -124,10 +124,11 @@ void LoggerDialog::saveLogFile() stringstream out; out << Logger::instance().logMessages(); instance().frameBuffer().showMessage("Saving log file to " + node.getShortPath()); + node.write(out); } catch(...) { - instance().frameBuffer().showMessage("Error savin log file to " + node.getShortPath()); + instance().frameBuffer().showMessage("Error saving log file to " + node.getShortPath()); } } From 543ddf2ffedf9b52ba82e04833ea89dac0c7bfaf Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 27 Jul 2020 09:43:31 +0200 Subject: [PATCH 360/377] added option to select audio device (resolves #682) --- Changes.txt | 8 ++++--- docs/graphics/options_audio.png | Bin 3879 -> 4108 bytes docs/index.html | 10 +++++++-- src/common/AudioSettings.cxx | 14 +++++++++++++ src/common/AudioSettings.hxx | 6 ++++++ src/common/FrameBufferSDL2.cxx | 2 +- src/common/SoundNull.hxx | 7 +++++++ src/common/SoundSDL2.cxx | 36 ++++++++++++++++++++++++++++++-- src/common/SoundSDL2.hxx | 9 ++++++++ src/emucore/Settings.cxx | 2 ++ src/emucore/Sound.hxx | 18 ++++++++++++++++ src/gui/VideoAudioDialog.cxx | 20 +++++++++++++++++- src/gui/VideoAudioDialog.hxx | 2 ++ 13 files changed, 125 insertions(+), 9 deletions(-) diff --git a/Changes.txt b/Changes.txt index c9b902582..3db21a9ea 100644 --- a/Changes.txt +++ b/Changes.txt @@ -20,9 +20,9 @@ * Extended global hotkeys for debug options. - * Added option to playback a game using the Time Machine + * Added option to playback a game using the Time Machine. - * Allow taking snapshots from within Time Machine dialog + * Allow taking snapshots from within Time Machine dialog. * Added ability to access most files that Stella uses from within a ZIP file. This includes the following: @@ -33,7 +33,9 @@ Basically, you are now able to put many files that Stella uses inside one ZIP file, and distribute just that file. - * Replaced "Re-disassemble" with "Disassemble @ current line" in debugger + * Added option to select the audio device. + + * Replaced "Re-disassemble" with "Disassemble @ current line" in debugger. * Fix bug when taking fullscreen snapshots; the dimensions were sometimes cut off. diff --git a/docs/graphics/options_audio.png b/docs/graphics/options_audio.png index f37f07c6f33333eb2756b43a5e6fddaf2e48ad85..e46d77b87f9813ce9b3abc88ba21ded4ed05f6e1 100644 GIT binary patch delta 4015 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 IJUZe30E-gU_y7O^ delta 3784 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 O3Rqj&p02U*i2WC2PkKiH diff --git a/docs/index.html b/docs/index.html index 04829b57e..555895e6a 100644 --- a/docs/index.html +++ b/docs/index.html @@ -2201,6 +2201,11 @@ + + + + + - + + - +
      ItemDescription
      Current timeShows the time of the currently selected status, +
      Current timeShows the time of the currently selected state, relative to the first one
      'Start/Stop' buttonStarts or stops the Time Machine
      'Continue' buttonExits the dialog and continues emulation
      'Exit' buttonExits the dialog and continues emulation, starting at current state
      'Rewind All' buttonNavigates back to the begin of the timeline
      'Rewind One' buttonNavigates back by one state
      'Playback' buttonStarts playback, starting at the current state (with sound disabled)
      'Unwind One' buttonNavigates forward by one state
      'Unwind All' buttonNavigates forward to the end of the timeline
      'Save All' buttonSaves all Time Machine states to disk
      Backspace
      Toggle 'Turbo' modeDecrease emulation speed (disables 'Turbo' mode)Shift-Control + sShift-Control + s
      Increase emulation speed (disables 'Turbo' mode)Control + sControl + s
      Toggle 'Turbo' mode (maximum emulation speed) Control + t Control + t
      Enter/Exit the Time Machine dialogShift + t to enter, Shift + t/Escape/Space to exit and continue with emulationShift + t to enter, Shift + t/Escape/Space to exit and continue with emulationShift + t to enter, Shift + t/Escape to exit and continue with emulationShift + t to enter, Shift + t/Escape to exit and continue with emulation
      Playback the Time Machine from current state (without sound).Playback the Time Machine from current state (without sound, from the TM dialog only)ShiftShift
      Start/Stop playback (exist/enters the Time Machine dialog) Shift + Space Shift + Space
      Set the volume.
      -audio.device <number>
      Set the audio device (0 = default).
      -audio.preset <1 - 5>
      Set an audio preset. Numbers in sequence represent presets for @@ -3084,7 +3089,8 @@
      ItemBrief descriptionFor more information,
      see CommandLine
      Enable audioSelf-explanatory-audio.enabled
      VolumeSelf-explanatory-audio.volume
      ModeSelect an audio preset or choose 'custom' for manual configuration-audio.preset
      DeviceUse the specified audio device.-audio.device
      ModeSelect an audio preset or choose 'Custom' for manual configuration.-audio.preset
      Fragment sizeThe number of samples in a single fragment processed by the audio driver. Smaller values mean less latency, but may lead to dropouts (depending on OS and hardware).-audio.fragment_size
      Sample rate Output samples per second. Higher values reduce artifacts from resampling and decrease latency, @@ -3097,7 +3103,7 @@ some games (notably Quadrun). -audio.resampling_quality
      HeadroomNumber of frames to buffer before playback starts. Higher values increase latency, but reduce the potential for dropouts.-audio.headroom
      Buffer sizeMaximum size of the audio buffer. Higher values increase maximum latency, but reduce the potential for dropouts-audio.buffer_size
      Buffer sizeMaximum size of the audio buffer. Higher values increase maximum latency, but reduce the potential for dropouts.-audio.buffer_size
      Stereo for all ROMsEnable stereo mode for all ROMs.-audio.stereo
      Pitfall II music pitchDefines the pitch of Pitfall II music (which may vary between carts).-audio.dpc_pitch
      diff --git a/src/common/AudioSettings.cxx b/src/common/AudioSettings.cxx index 2881c4cfa..640ba9527 100644 --- a/src/common/AudioSettings.cxx +++ b/src/common/AudioSettings.cxx @@ -154,6 +154,12 @@ uInt32 AudioSettings::volume() const return lboundInt(mySettings.getInt(SETTING_VOLUME), 0); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt32 AudioSettings::device() const +{ + return mySettings.getInt(SETTING_DEVICE); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool AudioSettings::enabled() const { @@ -285,6 +291,14 @@ void AudioSettings::setVolume(uInt32 volume) normalize(mySettings); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void AudioSettings::setDevice(uInt32 device) +{ + if(!myIsPersistent) return; + + mySettings.setValue(SETTING_DEVICE, device); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AudioSettings::setEnabled(bool isEnabled) { diff --git a/src/common/AudioSettings.hxx b/src/common/AudioSettings.hxx index 95104c74f..d319671c3 100644 --- a/src/common/AudioSettings.hxx +++ b/src/common/AudioSettings.hxx @@ -48,6 +48,7 @@ class AudioSettings static constexpr const char* SETTING_RESAMPLING_QUALITY = "audio.resampling_quality"; static constexpr const char* SETTING_STEREO = "audio.stereo"; static constexpr const char* SETTING_VOLUME = "audio.volume"; + static constexpr const char* SETTING_DEVICE = "audio.device"; static constexpr const char* SETTING_ENABLED = "audio.enabled"; static constexpr const char* SETTING_DPC_PITCH = "audio.dpc_pitch"; @@ -59,6 +60,7 @@ class AudioSettings static constexpr ResamplingQuality DEFAULT_RESAMPLING_QUALITY = ResamplingQuality::lanczos_2; static constexpr bool DEFAULT_STEREO = false; static constexpr uInt32 DEFAULT_VOLUME = 80; + static constexpr uInt32 DEFAULT_DEVICE = 0; static constexpr bool DEFAULT_ENABLED = true; static constexpr uInt32 DEFAULT_DPC_PITCH = 20000; @@ -87,6 +89,8 @@ class AudioSettings uInt32 volume() const; + uInt32 device() const; + bool enabled() const; uInt32 dpcPitch() const; @@ -109,6 +113,8 @@ class AudioSettings void setVolume(uInt32 volume); + void setDevice(uInt32 device); + void setEnabled(bool isEnabled); void setPersistent(bool isPersistent); diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index d930b2fc0..24b038d01 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -118,7 +118,7 @@ void FrameBufferSDL2::queryHardware(vector& fullscreenRes, Logger::debug(s.str()); s.str(""); lastRes = res.str(); - s << lastRes << ": "; + s << " " << lastRes << ": "; } s << mode.refresh_rate << "Hz"; if(mode.w == display.w && mode.h == display.h && mode.refresh_rate == display.refresh_rate) diff --git a/src/common/SoundNull.hxx b/src/common/SoundNull.hxx index 8974e9834..6bd9db54d 100644 --- a/src/common/SoundNull.hxx +++ b/src/common/SoundNull.hxx @@ -101,6 +101,13 @@ class SoundNull : public Sound */ void adjustVolume(int direction = 1) override { } + /** + Sets the audio device. + + @param device The number of the device to select (0 = default). + */ + void setDevice(uInt32 device) override { }; + /** This method is called to provide information about the sound device. */ diff --git a/src/common/SoundSDL2.cxx b/src/common/SoundSDL2.cxx index 928ebbc44..01c2a81ba 100644 --- a/src/common/SoundSDL2.cxx +++ b/src/common/SoundSDL2.cxx @@ -56,6 +56,9 @@ SoundSDL2::SoundSDL2(OSystem& osystem, AudioSettings& audioSettings) return; } + queryHardware(myDevices); + + SDL_zero(myHardwareSpec); if(!openDevice()) return; @@ -76,6 +79,29 @@ SoundSDL2::~SoundSDL2() SDL_QuitSubSystem(SDL_INIT_AUDIO); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void SoundSDL2::queryHardware(VariantList& devices) +{ + ASSERT_MAIN_THREAD; + + int numDevices = SDL_GetNumAudioDevices(0); + + // log the available audio devices + ostringstream s; + s << "Supported audio devices (" << numDevices << "):"; + Logger::debug(s.str()); + + VarList::push_back(devices, "Default", 0); + for(int i = 0; i < numDevices; ++i) { + ostringstream ss; + + ss << " " << i + 1 << ": " << SDL_GetAudioDeviceName(i, 0); + Logger::debug(ss.str()); + + VarList::push_back(devices, SDL_GetAudioDeviceName(i, 0), i + 1); + } +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool SoundSDL2::openDevice() { @@ -91,7 +117,11 @@ bool SoundSDL2::openDevice() if(myIsInitializedFlag) SDL_CloseAudioDevice(myDevice); - myDevice = SDL_OpenAudioDevice(nullptr, 0, &desired, &myHardwareSpec, + + myDeviceId = BSPF::clamp(myAudioSettings.device(), 0u, uInt32(myDevices.size() - 1)); + const char* device = myDeviceId ? myDevices.at(myDeviceId).first.c_str() : nullptr; + + myDevice = SDL_OpenAudioDevice(device, 0, &desired, &myHardwareSpec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); if(myDevice == 0) @@ -126,7 +156,8 @@ void SoundSDL2::open(shared_ptr audioQueue, // Do we need to re-open the sound device? // Only do this when absolutely necessary if(myAudioSettings.sampleRate() != uInt32(myHardwareSpec.freq) || - myAudioSettings.fragmentSize() != uInt32(myHardwareSpec.samples)) + myAudioSettings.fragmentSize() != uInt32(myHardwareSpec.samples) || + myAudioSettings.device() != myDeviceId) openDevice(); myEmulationTiming = emulationTiming; @@ -261,6 +292,7 @@ string SoundSDL2::about() const ostringstream buf; buf << "Sound enabled:" << endl << " Volume: " << myVolume << "%" << endl + << " Device: " << myDevices.at(myDeviceId).first << endl << " Channels: " << uInt32(myHardwareSpec.channels) << (myAudioQueue->isStereo() ? " (Stereo)" : " (Mono)") << endl << " Preset: "; diff --git a/src/common/SoundSDL2.hxx b/src/common/SoundSDL2.hxx index 398f1fa92..5a7cd330b 100644 --- a/src/common/SoundSDL2.hxx +++ b/src/common/SoundSDL2.hxx @@ -108,6 +108,13 @@ class SoundSDL2 : public Sound string about() const override; protected: + /** + This method is called to query the audio devices. + + @param devices List of device names + */ + void queryHardware(VariantList& devices); + /** Invoked by the sound callback to process the next sound fragment. The stream is 16-bits (even though the callback is 8-bits), since @@ -139,6 +146,8 @@ class SoundSDL2 : public Sound // Audio specification structure SDL_AudioSpec myHardwareSpec; + uInt32 myDeviceId{0}; + SDL_AudioDeviceID myDevice{0}; shared_ptr myAudioQueue; diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index 0ccc7ebd5..d3c388d64 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -80,6 +80,7 @@ Settings::Settings() // Sound options setPermanent(AudioSettings::SETTING_ENABLED, AudioSettings::DEFAULT_ENABLED); setPermanent(AudioSettings::SETTING_VOLUME, AudioSettings::DEFAULT_VOLUME); + setPermanent(AudioSettings::SETTING_DEVICE, AudioSettings::DEFAULT_DEVICE); setPermanent(AudioSettings::SETTING_PRESET, static_cast(AudioSettings::DEFAULT_PRESET)); setPermanent(AudioSettings::SETTING_FRAGMENT_SIZE, AudioSettings::DEFAULT_FRAGMENT_SIZE); setPermanent(AudioSettings::SETTING_SAMPLE_RATE, AudioSettings::DEFAULT_SAMPLE_RATE); @@ -426,6 +427,7 @@ void Settings::usage() const #ifdef SOUND_SUPPORT << " -audio.enabled <1|0> Enable audio\n" << " -audio.volume <0-100> Volume\n" + << " -audio.device ID of the audio device (0 = default)\n" << " -audio.preset <1-5> Audio preset (or 1 for custom)\n" << " -audio.sample_rate Output sample rate (44100|48000|96000)\n" << " -audio.fragment_size Fragment size (128|256|512|1024|\n" diff --git a/src/emucore/Sound.hxx b/src/emucore/Sound.hxx index 4e1fda0d5..880c47f00 100644 --- a/src/emucore/Sound.hxx +++ b/src/emucore/Sound.hxx @@ -97,10 +97,28 @@ class Sound */ virtual string about() const = 0; + /** + Get the supported devices for the audio hardware. + + @return An array of supported devices + */ + const VariantList& supportedDevices() const {return myDevices;} + + protected: + /** + This method is called to query the audio devices. + + @param devices List of device names + */ + virtual void queryHardware(VariantList& devices) = 0; + protected: // The OSystem for this sound object OSystem& myOSystem; + // Supported device + VariantList myDevices; + private: // Following constructors and assignment operators not supported Sound() = delete; diff --git a/src/gui/VideoAudioDialog.cxx b/src/gui/VideoAudioDialog.cxx index e87cbe221..edb40c7bb 100644 --- a/src/gui/VideoAudioDialog.cxx +++ b/src/gui/VideoAudioDialog.cxx @@ -68,7 +68,7 @@ VideoAudioDialog::VideoAudioDialog(OSystem& osystem, DialogContainer& parent, // Set real dimensions setSize(44 * fontWidth + HBORDER * 2 + PopUpWidget::dropDownWidth(font) * 2, - _th + VGAP * 6 + lineHeight + 10 * (lineHeight + VGAP) + buttonHeight + VBORDER * 3, + _th + VGAP * 3 + lineHeight + 11 * (lineHeight + VGAP) + buttonHeight + VBORDER * 3, max_w, max_h); // The tab widget @@ -365,6 +365,14 @@ void VideoAudioDialog::addAudioTab() wid.push_back(myVolumeSlider); ypos += lineHeight + VGAP; + // Device + myDevicePopup = new PopUpWidget(myTab, _font, xpos, ypos, + _w - xpos - lwidth - HBORDER - PopUpWidget::dropDownWidth(_font) - 2, lineHeight, + instance().sound().supportedDevices(), + "Device", lwidth, kDeviceChanged); + wid.push_back(myDevicePopup); + ypos += lineHeight + VGAP; + // Mode items.clear(); VarList::push_back(items, "Low quality, medium lag", static_cast(AudioSettings::Preset::lowQualityMediumLag)); @@ -542,6 +550,11 @@ void VideoAudioDialog::loadConfig() // Volume myVolumeSlider->setValue(audioSettings.volume()); + // Device + uInt32 deviceId = BSPF::clamp(audioSettings.device(), 0u, + uInt32(instance().sound().supportedDevices().size() - 1)); + myDevicePopup->setSelected(deviceId); + // Stereo myStereoSoundCheckbox->setState(audioSettings.stereo()); @@ -666,6 +679,9 @@ void VideoAudioDialog::saveConfig() audioSettings.setVolume(myVolumeSlider->getValue()); instance().sound().setVolume(myVolumeSlider->getValue()); + // Device + audioSettings.setDevice(myDevicePopup->getSelected()); + // Stereo audioSettings.setStereo(myStereoSoundCheckbox->getState()); @@ -754,6 +770,7 @@ void VideoAudioDialog::setDefaults() case 3: // Audio mySoundEnableCheckbox->setState(AudioSettings::DEFAULT_ENABLED); myVolumeSlider->setValue(AudioSettings::DEFAULT_VOLUME); + myDevicePopup->setSelected(AudioSettings::DEFAULT_DEVICE); myStereoSoundCheckbox->setState(AudioSettings::DEFAULT_STEREO); myDpcPitch->setValue(AudioSettings::DEFAULT_DPC_PITCH); myModePopup->setSelected(static_cast(AudioSettings::DEFAULT_PRESET)); @@ -1061,6 +1078,7 @@ void VideoAudioDialog::updateEnabledState() bool userMode = preset == AudioSettings::Preset::custom; myVolumeSlider->setEnabled(active); + myDevicePopup->setEnabled(active); myStereoSoundCheckbox->setEnabled(active); myModePopup->setEnabled(active); // enable only for Pitfall II cart diff --git a/src/gui/VideoAudioDialog.hxx b/src/gui/VideoAudioDialog.hxx index 0961f776e..ef0f850a8 100644 --- a/src/gui/VideoAudioDialog.hxx +++ b/src/gui/VideoAudioDialog.hxx @@ -115,6 +115,7 @@ class VideoAudioDialog : public Dialog // Audio CheckboxWidget* mySoundEnableCheckbox{nullptr}; SliderWidget* myVolumeSlider{nullptr}; + PopUpWidget* myDevicePopup{nullptr}; CheckboxWidget* myStereoSoundCheckbox{nullptr}; PopUpWidget* myModePopup{nullptr}; PopUpWidget* myFragsizePopup{nullptr}; @@ -149,6 +150,7 @@ class VideoAudioDialog : public Dialog kScanlinesChanged = 'VDsc', kSoundEnableChanged = 'ADse', + kDeviceChanged = 'ADdc', kModeChanged = 'ADmc', kHeadroomChanged = 'ADhc', kBufferSizeChanged = 'ADbc' From 9b620435defe9efbdccd14da96264eef07e42f9f Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Mon, 27 Jul 2020 10:45:41 -0230 Subject: [PATCH 361/377] Fix warnings from clang. --- src/common/SoundSDL2.hxx | 2 +- src/emucore/OSystem.cxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/SoundSDL2.hxx b/src/common/SoundSDL2.hxx index 5a7cd330b..586e90ff8 100644 --- a/src/common/SoundSDL2.hxx +++ b/src/common/SoundSDL2.hxx @@ -113,7 +113,7 @@ class SoundSDL2 : public Sound @param devices List of device names */ - void queryHardware(VariantList& devices); + void queryHardware(VariantList& devices) override; /** Invoked by the sound callback to process the next sound fragment. diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index 057e5739b..6c5caa8d9 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -470,7 +470,7 @@ string OSystem::createConsole(const FilesystemNode& rom, const string& md5sum, << " ROM file: " << myRomFile.getShortPath() << endl; FilesystemNode propsFile(myRomFile.getPathWithExt(".pro")); if(propsFile.exists()) - buf << " PRO file: " << propsFile.getShortPath() << endl; + buf << " PRO file: " << propsFile.getShortPath() << endl; buf << endl << getROMInfo(*myConsole); Logger::info(buf.str()); From c23ddea71127a9b6bf132a090e75ab42139ff8d9 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Mon, 27 Jul 2020 10:53:43 -0230 Subject: [PATCH 362/377] libretro: Fix compile error with recent sound code changes. --- src/common/SoundSDL2.cxx | 1 - src/libretro/SoundLIBRETRO.cxx | 5 +++++ src/libretro/SoundLIBRETRO.hxx | 9 ++++++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/common/SoundSDL2.cxx b/src/common/SoundSDL2.cxx index 01c2a81ba..af99d3f2c 100644 --- a/src/common/SoundSDL2.cxx +++ b/src/common/SoundSDL2.cxx @@ -58,7 +58,6 @@ SoundSDL2::SoundSDL2(OSystem& osystem, AudioSettings& audioSettings) queryHardware(myDevices); - SDL_zero(myHardwareSpec); if(!openDevice()) return; diff --git a/src/libretro/SoundLIBRETRO.cxx b/src/libretro/SoundLIBRETRO.cxx index 8d424b1fa..eef9c7dd5 100644 --- a/src/libretro/SoundLIBRETRO.cxx +++ b/src/libretro/SoundLIBRETRO.cxx @@ -120,4 +120,9 @@ void SoundLIBRETRO::dequeue(Int16* stream, uInt32* samples) *samples = outIndex / 2; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void SoundLIBRETRO::queryHardware(VariantList& devices) +{ +} + #endif // SOUND_SUPPORT diff --git a/src/libretro/SoundLIBRETRO.hxx b/src/libretro/SoundLIBRETRO.hxx index f99c8f341..7f68c0127 100644 --- a/src/libretro/SoundLIBRETRO.hxx +++ b/src/libretro/SoundLIBRETRO.hxx @@ -104,7 +104,6 @@ class SoundLIBRETRO : public Sound */ string about() const override { return ""; } - public: /** Empties the playback buffer. @@ -113,6 +112,14 @@ class SoundLIBRETRO : public Sound */ void dequeue(Int16* stream, uInt32* samples); + protected: + /** + This method is called to query the audio devices. + + @param devices List of device names + */ + void queryHardware(VariantList& devices) override; + private: // Indicates if the sound device was successfully initialized bool myIsInitializedFlag; From 68d977b49b10dfe88898f56aa82f17f48e9bc95d Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Mon, 27 Jul 2020 13:41:54 -0230 Subject: [PATCH 363/377] I guess we're far enough along to move the version number. --- src/common/Version.hxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/Version.hxx b/src/common/Version.hxx index 9c070d208..22801ca3a 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.1" -#define STELLA_BUILD "6041" +#define STELLA_VERSION "6.3_pre" +#define STELLA_BUILD "6091" #endif From b6638540c751494440c355bd20d9b488d953da96 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Mon, 27 Jul 2020 23:27:21 -0230 Subject: [PATCH 364/377] Make FSNodeZIP::exists() actually inspect the ZIP contents, and not just the ZIP file itself. This fixes issues with checking for a .pro file in a ZIP file always being true, even if there isn't one. --- src/common/FSNodeZIP.cxx | 15 +++++++++++++++ src/common/FSNodeZIP.hxx | 2 +- src/emucore/PropsSet.cxx | 1 - 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/common/FSNodeZIP.cxx b/src/common/FSNodeZIP.cxx index c49f8359f..7bd88efc0 100644 --- a/src/common/FSNodeZIP.cxx +++ b/src/common/FSNodeZIP.cxx @@ -126,6 +126,21 @@ void FilesystemNodeZIP::setFlags(const string& zipfile, _error = zip_error::NOT_READABLE; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool FilesystemNodeZIP::exists() const +{ + if(_realNode && _realNode->exists()) + { + // We need to inspect the actual path, not just the ZIP file itself + myZipHandler->open(_zipFile); + while(myZipHandler->hasNext()) + if(BSPF::startsWithIgnoreCase(myZipHandler->next(), _virtualPath)) + return true; + } + + return false; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FilesystemNodeZIP::getChildren(AbstractFSList& myList, ListMode mode) const { diff --git a/src/common/FSNodeZIP.hxx b/src/common/FSNodeZIP.hxx index de8904315..079d3c546 100644 --- a/src/common/FSNodeZIP.hxx +++ b/src/common/FSNodeZIP.hxx @@ -42,7 +42,7 @@ class FilesystemNodeZIP : public AbstractFSNode */ explicit FilesystemNodeZIP(const string& path); - bool exists() const override { return _realNode && _realNode->exists(); } + bool exists() const override; const string& getName() const override { return _name; } void setName(const string& name) override { _name = name; } const string& getPath() const override { return _path; } diff --git a/src/emucore/PropsSet.cxx b/src/emucore/PropsSet.cxx index 65bae06bd..db6cfc1fe 100644 --- a/src/emucore/PropsSet.cxx +++ b/src/emucore/PropsSet.cxx @@ -184,7 +184,6 @@ void PropertiesSet::loadPerROM(const FilesystemNode& rom, const string& md5) // First, does this ROM have a per-ROM properties entry? // If so, load it into the database FilesystemNode propsNode(rom.getPathWithExt(".pro")); - if(propsNode.exists()) load(propsNode, false); From cbc5f1be0dc135305e772e9dd559c1214166e70d Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 28 Jul 2020 09:40:44 +0200 Subject: [PATCH 365/377] added option to display detected settings info when a ROM is loaded (resolves #684) --- Changes.txt | 2 ++ docs/graphics/options_developer.png | Bin 5061 -> 5233 bytes docs/graphics/options_developer_emulation.png | Bin 4977 -> 5162 bytes docs/index.html | 4 ++++ src/emucore/OSystem.cxx | 16 ++++++++++++++-- src/emucore/Settings.cxx | 4 ++++ src/gui/DeveloperDialog.cxx | 14 +++++++++++++- src/gui/DeveloperDialog.hxx | 2 ++ 8 files changed, 39 insertions(+), 3 deletions(-) diff --git a/Changes.txt b/Changes.txt index 3db21a9ea..7b2d6d87a 100644 --- a/Changes.txt +++ b/Changes.txt @@ -35,6 +35,8 @@ * Added option to select the audio device. + * Added option to display detected settings info when a ROM is loaded. + * Replaced "Re-disassemble" with "Disassemble @ current line" in debugger. * Fix bug when taking fullscreen snapshots; the dimensions were sometimes diff --git a/docs/graphics/options_developer.png b/docs/graphics/options_developer.png index 8d345f9aaf7ea1cf40feb1eb308a87d4f6baf08b..f405818b125986916aefddafde831575283648b7 100644 GIT binary patch literal 5233 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 literal 5061 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 diff --git a/docs/graphics/options_developer_emulation.png b/docs/graphics/options_developer_emulation.png index 6b8009f35c4bd7b45800c7c188c5b18f546610cd..977893402c447cccf3e95ae39201c6e85b701b66 100644 GIT binary patch literal 5162 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 NQ`=apO7nii{{SP5XoUa( literal 4977 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 B;NSoN diff --git a/docs/index.html b/docs/index.html index 555895e6a..d0bac0933 100644 --- a/docs/index.html +++ b/docs/index.html @@ -2893,6 +2893,9 @@
      -<plr.|dev.>stats <1|0>
      Overlay console info on the TIA image during emulation. + +
      -<plr.|dev.>detectedinfo <1|0>
      + Display detected settings info when a ROM is loaded.
      -<plr.|dev.>console <2600|7800>
      Select console for B/W and Pause key handling and RAM initialization. @@ -3606,6 +3609,7 @@ ItemBrief descriptionFor more information,
      see CommandLine Player/Developer settingsSelects the active settings set-dev.settings Console info overlayOverlay console info on the TIA image during emulation.-plr.stats
      -dev.stats + Detected settings infoDisplay detected settings when a ROM is loaded.-plr.detectedinfo
      -dev.detectedinfo ConsoleSelect the console type, this affects Color/B&W/Pause key emulation and zero-page RAM initialization-plr.console
      -dev.console Random startup bankRandomize the startup bank (only for selected bankswitch types)-plr.bankrandom
      -dev.bankrandom Randomize zero-page ...When loading a ROM, randomize all RAM content instead of initializing with all zeroes (for 'Console' = 'Atari 2600' only)-plr.ramrandom
      -dev.ramrandom diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index 6c5caa8d9..88d546ba2 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -451,8 +451,8 @@ string OSystem::createConsole(const FilesystemNode& rom, const string& md5sum, myConsole->initializeAudio(); string saveOnExit = settings().getString("saveonexit"); - bool activeTM = settings().getBool( - settings().getBool("dev.settings") ? "dev.timemachine" : "plr.timemachine"); + bool devSettings = settings().getBool("dev.settings"); + bool activeTM = settings().getBool(devSettings ? "dev.timemachine" : "plr.timemachine"); if (saveOnExit == "all" && activeTM) myEventHandler->handleEvent(Event::LoadAllStates); @@ -483,7 +483,19 @@ string OSystem::createConsole(const FilesystemNode& rom, const string& md5sum, if(mySettings->getBool("debug")) myEventHandler->enterDebugMode(); #endif + + if(!showmessage && + settings().getBool(devSettings ? "dev.detectedinfo" : "plr.detectedinfo")) + { + ostringstream msg; + + msg << myConsole->leftController().name() << "/" << myConsole->rightController().name() + << " - " << myConsole->cartridge().detectedType() + << " - " << myConsole->getFormatString(); + myFrameBuffer->showMessage(msg.str()); + } } + return EmptyString; } diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index d3c388d64..0ec82b9da 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -198,6 +198,7 @@ Settings::Settings() setPermanent("plr.tm.uncompressed", 60); setPermanent("plr.tm.interval", "30f"); // = 0.5 seconds setPermanent("plr.tm.horizon", "10m"); // = ~10 minutes + setPermanent("plr.detectedinfo", "false"); setPermanent("plr.eepromaccess", "false"); // Developer settings @@ -227,6 +228,7 @@ Settings::Settings() setPermanent("dev.tm.horizon", "30s"); // = ~30 seconds // Thumb ARM emulation options setPermanent("dev.thumb.trapfatal", "true"); + setPermanent("dev.detectedinfo", "true"); setPermanent("dev.eepromaccess", "true"); } @@ -616,6 +618,7 @@ void Settings::usage() const << " mode\n" << endl << " -plr.stats <1|0> Overlay console info during emulation\n" + << " -plr.detectedinfo <1|0> Enable initial detected settings info\n" << " -plr.console <2600|7800> Select console for B/W and Pause key\n" << " handling and RAM initialization\n" << " -plr.bankrandom <1|0> Randomize the startup bank on reset\n" @@ -631,6 +634,7 @@ void Settings::usage() const << endl << " The same parameters but for developer settings mode\n" << " -dev.stats <1|0> Overlay console info during emulation\n" + << " -dev.detectedinfo <1|0> Enable initial detected settings info\n" << " -dev.console <2600|7800> Select console for B/W and Pause key\n" << " handling and RAM initialization\n" << " -dev.bankrandom <1|0> Randomize the startup bank on reset\n" diff --git a/src/gui/DeveloperDialog.cxx b/src/gui/DeveloperDialog.cxx index 288fb6a40..336c5e1e8 100644 --- a/src/gui/DeveloperDialog.cxx +++ b/src/gui/DeveloperDialog.cxx @@ -111,8 +111,15 @@ void DeveloperDialog::addEmulationTab(const GUI::Font& font) wid.push_back(r); ypos += lineHeight + VGAP * 1; - myFrameStatsWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 1, ypos + 1, "Console info overlay"); + myFrameStatsWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 1, ypos + 1, + "Console info overlay"); wid.push_back(myFrameStatsWidget); + + + myDetectedInfoWidget = new CheckboxWidget(myTab, font, + myFrameStatsWidget->getRight() + fontWidth * 2.5, ypos + 1, + "Detected settings info"); + wid.push_back(myDetectedInfoWidget); ypos += lineHeight + VGAP; // 2600/7800 mode @@ -611,6 +618,7 @@ void DeveloperDialog::loadSettings(SettingsSet set) const string& prefix = devSettings ? "dev." : "plr."; myFrameStats[set] = instance().settings().getBool(prefix + "stats"); + myDetectedInfo[set] = instance().settings().getBool(prefix + "detectedinfo"); myConsole[set] = instance().settings().getString(prefix + "console") == "7800" ? 1 : 0; // Randomization myRandomBank[set] = instance().settings().getBool(prefix + "bankrandom"); @@ -662,6 +670,7 @@ void DeveloperDialog::saveSettings(SettingsSet set) const string& prefix = devSettings ? "dev." : "plr."; instance().settings().setValue(prefix + "stats", myFrameStats[set]); + instance().settings().setValue(prefix + "detectedinfo", myDetectedInfo[set]); instance().settings().setValue(prefix + "console", myConsole[set] == 1 ? "7800" : "2600"); if(instance().hasConsole()) instance().eventHandler().set7800Mode(); @@ -724,6 +733,7 @@ void DeveloperDialog::saveSettings(SettingsSet set) void DeveloperDialog::getWidgetStates(SettingsSet set) { myFrameStats[set] = myFrameStatsWidget->getState(); + myDetectedInfo[set] = myDetectedInfoWidget->getState(); myConsole[set] = myConsoleWidget->getSelected() == 1; // Randomization myRandomBank[set] = myRandomBankWidget->getState(); @@ -775,6 +785,7 @@ void DeveloperDialog::getWidgetStates(SettingsSet set) void DeveloperDialog::setWidgetStates(SettingsSet set) { myFrameStatsWidget->setState(myFrameStats[set]); + myDetectedInfoWidget->setState(myDetectedInfo[set]); myConsoleWidget->setSelectedIndex(myConsole[set]); // Randomization myRandomBankWidget->setState(myRandomBank[set]); @@ -955,6 +966,7 @@ void DeveloperDialog::setDefaults() { case 0: // Emulation myFrameStats[set] = devSettings ? true : false; + myDetectedInfo[set] = devSettings ? true : false; myConsole[set] = 0; // Randomization myRandomBank[set] = devSettings ? true : false; diff --git a/src/gui/DeveloperDialog.hxx b/src/gui/DeveloperDialog.hxx index 8bd84ab91..8dd2dc4e2 100644 --- a/src/gui/DeveloperDialog.hxx +++ b/src/gui/DeveloperDialog.hxx @@ -90,6 +90,7 @@ class DeveloperDialog : public Dialog // Emulator widgets RadioButtonGroup* mySettingsGroupEmulation{nullptr}; CheckboxWidget* myFrameStatsWidget{nullptr}; + CheckboxWidget* myDetectedInfoWidget{nullptr}; PopUpWidget* myConsoleWidget{nullptr}; StaticTextWidget* myLoadingROMLabel{nullptr}; CheckboxWidget* myRandomBankWidget{nullptr}; @@ -148,6 +149,7 @@ class DeveloperDialog : public Dialog bool mySettings; // Emulator sets std::array myFrameStats; + std::array myDetectedInfo; std::array myConsole; std::array myRandomBank; std::array myRandomizeRAM; From b355e0056132e651f3f66e52966aaf5be829056b Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 28 Jul 2020 23:47:13 +0200 Subject: [PATCH 366/377] added static What's New" popup (see #581) (to get things going :-) --- Changes.txt | 12 +++---- src/emucore/Settings.cxx | 1 + src/gui/Dialog.cxx | 22 ++++++++++++ src/gui/Dialog.hxx | 9 +++-- src/gui/LauncherDialog.cxx | 17 +++++++++ src/gui/LauncherDialog.hxx | 4 +++ src/gui/Stella12x24tFont.hxx | 40 ++++++++++----------- src/gui/Stella14x28tFont.hxx | 56 +++++++++++++++--------------- src/gui/Stella16x32tFont.hxx | 56 +++++++++++++++--------------- src/gui/StellaLargeFont.hxx | 32 ++++++++--------- src/gui/module.mk | 1 + src/windows/Stella.vcxproj | 2 ++ src/windows/Stella.vcxproj.filters | 6 ++++ 13 files changed, 158 insertions(+), 100 deletions(-) diff --git a/Changes.txt b/Changes.txt index 7b2d6d87a..f19fabcfb 100644 --- a/Changes.txt +++ b/Changes.txt @@ -16,16 +16,16 @@ * Added autofire. - * Added new interface palette 'Dark'. (TODO: DOC) + * Added new UI theme 'Dark'. (TODO: DOC) * Extended global hotkeys for debug options. * Added option to playback a game using the Time Machine. - * Allow taking snapshots from within Time Machine dialog. + * Allow taking snapshots from within the Time Machine dialog. - * Added ability to access most files that Stella uses from within a ZIP - file. This includes the following: + * Added the ability to access most files that Stella uses from within a + ZIP file. This includes the following: - Per-ROM properties file (so one can distribute a ROM and its associated properties). - Debugger symbol (.sym) and list (.lst) files, etc. @@ -39,8 +39,8 @@ * Replaced "Re-disassemble" with "Disassemble @ current line" in debugger. - * Fix bug when taking fullscreen snapshots; the dimensions were sometimes - cut off. + * Fixed bug when taking fullscreen snapshots; the dimensions were + sometimes cut off. -Have fun! diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index 0ec82b9da..5cf836954 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -38,6 +38,7 @@ Settings::Settings() // If no version is recorded with the persisted settings, we set it to zero setPermanent(SETTINGS_VERSION_KEY, 0); + setPermanent("stella.version", "6.2.1"); // Video-related options setPermanent("video", ""); diff --git a/src/gui/Dialog.cxx b/src/gui/Dialog.cxx index e455a976c..85c95349f 100644 --- a/src/gui/Dialog.cxx +++ b/src/gui/Dialog.cxx @@ -767,6 +767,28 @@ Widget* Dialog::findWidget(int x, int y) const return Widget::findWidgetInChain(_firstWidget, x, y); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Dialog::addOKBGroup(WidgetArray& wid, const GUI::Font& font, + const string& okText, int buttonWidth) +{ + 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; + + buttonWidth = fontWidth * 6 + BTN_BORDER; + buttonWidth = std::max(buttonWidth, font.getStringWidth(okText) + BTN_BORDER); + + _w = std::max(HBORDER * 2 + buttonWidth * 2 + BUTTON_GAP, _w); + + addOKWidget(new ButtonWidget(this, font, (_w - buttonWidth) / 2, + _h - buttonHeight - VBORDER, buttonWidth, buttonHeight, okText, GuiObject::kCloseCmd)); + wid.push_back(_okWidget); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::addOKCancelBGroup(WidgetArray& wid, const GUI::Font& font, const string& okText, const string& cancelText, diff --git a/src/gui/Dialog.hxx b/src/gui/Dialog.hxx index 0dc5e7118..3c0242e9c 100644 --- a/src/gui/Dialog.hxx +++ b/src/gui/Dialog.hxx @@ -146,6 +146,11 @@ class Dialog : public GuiObject Widget* findWidget(int x, int y) const; // Find the widget at pos x,y if any + + void addOKBGroup(WidgetArray& wid, const GUI::Font& font, + const string& okText = "OK", + int buttonWidth = 0); + void addOKCancelBGroup(WidgetArray& wid, const GUI::Font& font, const string& okText = "OK", const string& cancelText = "Cancel", @@ -158,7 +163,7 @@ 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 + // NOTE: This method, and the three 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, @@ -167,7 +172,7 @@ class Dialog : public GuiObject const string& defaultsText = "Defaults", bool focusOKButton = true); - void processCancelWithoutWidget(bool state) { _processCancel = state; } + void processCancelWithoutWidget(bool state = true) { _processCancel = state; } virtual void processCancel() { close(); } /** Define the size (allowed) for the dialog. */ diff --git a/src/gui/LauncherDialog.cxx b/src/gui/LauncherDialog.cxx index 3e9936cdf..40a05ad53 100644 --- a/src/gui/LauncherDialog.cxx +++ b/src/gui/LauncherDialog.cxx @@ -28,6 +28,7 @@ #include "OptionsDialog.hxx" #include "GlobalPropsDialog.hxx" #include "StellaSettingsDialog.hxx" +#include "WhatsNewDialog.hxx" #include "MessageBox.hxx" #include "OSystem.hxx" #include "FrameBuffer.hxx" @@ -287,6 +288,14 @@ void LauncherDialog::loadConfig() const string& tmpromdir = instance().settings().getString("tmpromdir"); const string& romdir = tmpromdir != "" ? tmpromdir : instance().settings().getString("romdir"); + const string& version = instance().settings().getString("stella.version"); + + // Show "What's New" message when a new version of Stella is run for the first time + if(version != STELLA_VERSION) + { + openWhatsNew(); + instance().settings().setValue("stella.version", STELLA_VERSION); + } // Assume that if the list is empty, this is the first time that loadConfig() // has been called (and we should reload the list) @@ -675,3 +684,11 @@ void LauncherDialog::openSettings() myOptionsDialog->open(); } } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void LauncherDialog::openWhatsNew() +{ + if(myWhatsNewDialog == nullptr) + myWhatsNewDialog = make_unique(instance(), parent(), _font, _w, _h); + myWhatsNewDialog->open(); +} diff --git a/src/gui/LauncherDialog.hxx b/src/gui/LauncherDialog.hxx index faeea2598..35472aad2 100644 --- a/src/gui/LauncherDialog.hxx +++ b/src/gui/LauncherDialog.hxx @@ -26,6 +26,7 @@ class BrowserDialog; class OptionsDialog; class GlobalPropsDialog; class StellaSettingsDialog; +class WhatsNewDialog; class OSystem; class Properties; class EditTextWidget; @@ -122,6 +123,7 @@ class LauncherDialog : public Dialog void showOnlyROMs(bool state); void setDefaultDir(); void openSettings(); + void openWhatsNew(); private: unique_ptr myOptionsDialog; @@ -129,6 +131,8 @@ class LauncherDialog : public Dialog unique_ptr myMenu; unique_ptr myGlobalProps; unique_ptr myRomDir; + unique_ptr myWhatsNewDialog; + unique_ptr myWhatsNewMsg; // automatically sized font for ROM info viewer unique_ptr myROMInfoFont; diff --git a/src/gui/Stella12x24tFont.hxx b/src/gui/Stella12x24tFont.hxx index e1e3e07d7..4ed48528c 100644 --- a/src/gui/Stella12x24tFont.hxx +++ b/src/gui/Stella12x24tFont.hxx @@ -222,16 +222,16 @@ static const uInt16 stella12x24t_font_bits[] = { // NOLINT : too complicated to | | | | | | - | | - | | - | | - | | - | | - | | - | | - | | - | | - | | + | **** | + | ******** | + | ******** | + | ********** | + | ********** | + | ********** | + | ********** | + | ******** | + | ******** | + | **** | | | | | | | @@ -248,16 +248,16 @@ static const uInt16 stella12x24t_font_bits[] = { // NOLINT : too complicated to 0x0000, 0x0000, 0x0000, -0x0000, -0x0000, -0x0000, -0x0000, -0x0000, -0x0000, -0x0000, -0x0000, -0x0000, -0x0000, +0b0000111100000000, +0b0011111110000000, +0b0011111110000000, +0b0111111111000000, +0b0111111111000000, +0b0111111111000000, +0b0111111111000000, +0b0011111110000000, +0b0011111110000000, +0b0000111100000000, 0x0000, 0x0000, 0x0000, diff --git a/src/gui/Stella14x28tFont.hxx b/src/gui/Stella14x28tFont.hxx index 8b1e262a5..52ad7dda6 100644 --- a/src/gui/Stella14x28tFont.hxx +++ b/src/gui/Stella14x28tFont.hxx @@ -247,20 +247,20 @@ static const uInt16 stella14x28t_font_bits[] = { // NOLINT : too complicated to | | | | | | - | | - | | - | | - | | - | | - | | - | | - | | - | | - | | - | | - | | - | | - | | + | **** | + | ******** | + | ********** | + | ********** | + | ************ | + | ************ | + | ************ | + | ************ | + | ************ | + | ************ | + | ********** | + | ********** | + | ******** | + | **** | | | | | | | @@ -277,20 +277,20 @@ static const uInt16 stella14x28t_font_bits[] = { // NOLINT : too complicated to 0x0000, 0x0000, 0x0000, -0x0000, -0x0000, -0x0000, -0x0000, -0x0000, -0x0000, -0x0000, -0x0000, -0x0000, -0x0000, -0x0000, -0x0000, -0x0000, -0x0000, +0b0000011110000000, +0b0001111111100000, +0b0011111111110000, +0b0011111111110000, +0b0111111111111000, +0b0111111111111000, +0b0111111111111000, +0b0111111111111000, +0b0111111111111000, +0b0111111111111000, +0b0011111111110000, +0b0011111111110000, +0b0001111111100000, +0b0000011110000000, 0x0000, 0x0000, 0x0000, diff --git a/src/gui/Stella16x32tFont.hxx b/src/gui/Stella16x32tFont.hxx index 63708f473..6f15c3293 100644 --- a/src/gui/Stella16x32tFont.hxx +++ b/src/gui/Stella16x32tFont.hxx @@ -272,20 +272,20 @@ static const uInt16 stella16x32t_font_bits[] = { // NOLINT : too complicated to | | | | | | - | | - | | - | | - | | - | | - | | - | | - | | - | | - | | - | | - | | - | | - | | + | ***** | + | ********* | + | *********** | + | *********** | + | ************* | + | ************* | + | ************* | + | ************* | + | ************* | + | ************* | + | *********** | + | *********** | + | ********* | + | ***** | | | | | | | @@ -306,20 +306,20 @@ static const uInt16 stella16x32t_font_bits[] = { // NOLINT : too complicated to 0x0000, 0x0000, 0x0000, -0x0000, -0x0000, -0x0000, -0x0000, -0x0000, -0x0000, -0x0000, -0x0000, -0x0000, -0x0000, -0x0000, -0x0000, -0x0000, -0x0000, +0b0000011111000000, +0b0001111111110000, +0b0011111111111000, +0b0011111111111000, +0b0111111111111100, +0b0111111111111100, +0b0111111111111100, +0b0111111111111100, +0b0111111111111100, +0b0111111111111100, +0b0011111111111000, +0b0011111111111000, +0b0001111111110000, +0b0000011111000000, 0x0000, 0x0000, 0x0000, diff --git a/src/gui/StellaLargeFont.hxx b/src/gui/StellaLargeFont.hxx index 3c04ffa44..f8a2f5a42 100644 --- a/src/gui/StellaLargeFont.hxx +++ b/src/gui/StellaLargeFont.hxx @@ -202,14 +202,14 @@ static const uInt16 stellaLarge_font_bits[] = { // NOLINT : too complicated to | | | | | | - | | - | | - | | - | | - | | - | | - | | - | | + | **** | + | ****** | + | ******** | + | ******** | + | ******** | + | ******** | + | ****** | + | **** | | | | | | | @@ -224,14 +224,14 @@ static const uInt16 stellaLarge_font_bits[] = { // NOLINT : too complicated to 0x0000, 0x0000, 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0000, + 0b0001111000000000, + 0b0011111100000000, + 0b0111111110000000, + 0b0111111110000000, + 0b0111111110000000, + 0b0111111110000000, + 0b0011111100000000, + 0b0001111000000000, 0x0000, 0x0000, 0x0000, diff --git a/src/gui/module.mk b/src/gui/module.mk index 1447b8195..4b52d3996 100644 --- a/src/gui/module.mk +++ b/src/gui/module.mk @@ -50,6 +50,7 @@ MODULE_OBJS := \ src/gui/TimeMachine.o \ src/gui/UIDialog.o \ src/gui/VideoAudioDialog.o \ + src/gui/WhatsNewDialog.o \ src/gui/Widget.o MODULE_DIRS += \ diff --git a/src/windows/Stella.vcxproj b/src/windows/Stella.vcxproj index 33abbe73e..c6ba9d7ff 100644 --- a/src/windows/Stella.vcxproj +++ b/src/windows/Stella.vcxproj @@ -777,6 +777,7 @@ + @@ -1818,6 +1819,7 @@ + diff --git a/src/windows/Stella.vcxproj.filters b/src/windows/Stella.vcxproj.filters index ded397f71..215e9eeab 100644 --- a/src/windows/Stella.vcxproj.filters +++ b/src/windows/Stella.vcxproj.filters @@ -1014,6 +1014,9 @@ Source Files\emucore + + Source Files\gui +
      @@ -2081,6 +2084,9 @@ Header Files\emucore + + Header Files\gui + From 7d130521f899f5a9d0847a799e620d7a8a68d7c2 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 29 Jul 2020 07:46:22 +0200 Subject: [PATCH 367/377] added missing files --- src/gui/WhatsNewDialog.cxx | 88 ++++++++++++++++++++++++++++++++++++++ src/gui/WhatsNewDialog.hxx | 41 ++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 src/gui/WhatsNewDialog.cxx create mode 100644 src/gui/WhatsNewDialog.hxx diff --git a/src/gui/WhatsNewDialog.cxx b/src/gui/WhatsNewDialog.cxx new file mode 100644 index 000000000..9f0e6b690 --- /dev/null +++ b/src/gui/WhatsNewDialog.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 "Version.hxx" + +#include "WhatsNewDialog.hxx" + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +WhatsNewDialog::WhatsNewDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, + int max_w, int max_h) + : Dialog(osystem, parent, font, "What's New in Stella " + string(STELLA_VERSION) + "?") +{ + const int lineHeight = _font.getLineHeight(), + fontHeight = _font.getFontHeight(), + fontWidth = _font.getMaxCharWidth(), + buttonHeight = _font.getLineHeight() * 1.25; + const int VGAP = fontHeight / 4; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + int ypos = _th + VBORDER; + + + // Set preliminary dimensions + setSize(64 * fontWidth + HBORDER * 2, max_h, + max_w, max_h); + + add(ypos, "added autofire"); + add(ypos, "added new UI theme 'Dark'"); + add(ypos, "extended global hotkeys for debug options"); + add(ypos, "added option to playback a game using the Time Machine"); + add(ypos, "allow taking snapshots from within the Time Machine dialog"); + add(ypos, "added the ability to access most files that Stella uses from within a ZIP file"); + add(ypos, "added option to select the audio device"); + add(ypos, "added option to display detected settings info when a ROM is loaded"); + add(ypos, "replaced 'Re-disassemble' with 'Disassemble @ current line' in debugger"); + add(ypos, "fixed bug when taking fullscreen snapshots; the dimensions were sometimes cut"); + + // Set needed dimensions + setSize(64 * fontWidth + HBORDER * 2, + ypos + VGAP + buttonHeight + VBORDER, + max_w, max_h); + + WidgetArray wid; + addOKBGroup(wid, _font); + addBGroupToFocusList(wid); + + // We don't have a close/cancel button, but we still want the cancel + // event to be processed + processCancelWithoutWidget(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void WhatsNewDialog::add(int& ypos, const string& text) +{ + const int lineHeight = _font.getLineHeight(), + fontHeight = _font.getFontHeight(), + fontWidth = _font.getMaxCharWidth(), + HBORDER = fontWidth * 1.25; + const string DOT = "\x1f"; + string txt = DOT + " " + text; + + // automatically wrap too long texts + while(txt.length() > 64) + { + int i = 64; + + while(--i && txt[i] != ' '); + new StaticTextWidget(this, _font, HBORDER, ypos, txt.substr(0, i)); + txt = " " + txt.substr(i); + ypos += fontHeight; + } + new StaticTextWidget(this, _font, HBORDER, ypos, txt); + ypos += lineHeight; +} diff --git a/src/gui/WhatsNewDialog.hxx b/src/gui/WhatsNewDialog.hxx new file mode 100644 index 000000000..9ca7505e5 --- /dev/null +++ b/src/gui/WhatsNewDialog.hxx @@ -0,0 +1,41 @@ +//============================================================================ +// +// 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 WHATSNEW_DIALOG_HXX +#define WHATSNEW_DIALOG_HXX + +#include "Dialog.hxx" + +class WhatsNewDialog : public Dialog +{ + public: + // These must be accessible from dialogs created by this class + enum { + kLoadROMCmd = 'STRT', // load currently selected ROM + kRomDirChosenCmd = 'romc' // rom dir chosen + }; + + public: + WhatsNewDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, + int max_w, int max_h); + virtual ~WhatsNewDialog() = default; + + private: + void add(int& ypos, const string& text); +}; + +#endif From 2e5812ee2da870a69f444dda581fc31010ab2375 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 29 Jul 2020 10:56:48 +0200 Subject: [PATCH 368/377] fixed #686 (launcher losing navigation) --- src/gui/LauncherDialog.cxx | 16 ++++++++++++---- src/gui/UIDialog.cxx | 7 +++++-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/gui/LauncherDialog.cxx b/src/gui/LauncherDialog.cxx index 40a05ad53..3f6ddcec8 100644 --- a/src/gui/LauncherDialog.cxx +++ b/src/gui/LauncherDialog.cxx @@ -626,11 +626,17 @@ void LauncherDialog::handleCommand(CommandSender* sender, int cmd, case kRomDirChosenCmd: { - FilesystemNode node(instance().settings().getString("romdir")); - if(!(node.exists() && node.isDirectory())) - node = FilesystemNode("~"); + string romDir = instance().settings().getString("romdir"); - myList->setDirectory(node); + if(myList->currentDir().getPath() != romDir) + { + FilesystemNode node(romDir); + + if(!(node.exists() && node.isDirectory())) + node = FilesystemNode("~"); + + myList->setDirectory(node); + } break; } @@ -668,6 +674,8 @@ void LauncherDialog::setDefaultDir() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LauncherDialog::openSettings() { + saveConfig(); + // Create an options dialog, similar to the in-game one if (instance().settings().getBool("basic_settings")) { diff --git a/src/gui/UIDialog.cxx b/src/gui/UIDialog.cxx index 72e70ecae..1b64d73f2 100644 --- a/src/gui/UIDialog.cxx +++ b/src/gui/UIDialog.cxx @@ -522,12 +522,15 @@ void UIDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) switch(cmd) { case GuiObject::kOKCmd: + { + bool inform = myIsGlobal && + myRomPath->getText() != instance().settings().getString("romdir"); saveConfig(); close(); - if(myIsGlobal) // Let the boss know romdir has changed + if(inform) // Let the boss know romdir has changed sendCommand(LauncherDialog::kRomDirChosenCmd, 0, 0); break; - + } case GuiObject::kDefaultsCmd: setDefaults(); break; From e151a9cc9f376a6836af949a06d9d996f2e1501d Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 29 Jul 2020 10:57:44 +0200 Subject: [PATCH 369/377] removed magic number in WhatsNewDialog --- src/gui/WhatsNewDialog.cxx | 12 +++++++----- src/gui/WhatsNewDialog.hxx | 7 ------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/gui/WhatsNewDialog.cxx b/src/gui/WhatsNewDialog.cxx index 9f0e6b690..cda4b4b5c 100644 --- a/src/gui/WhatsNewDialog.cxx +++ b/src/gui/WhatsNewDialog.cxx @@ -19,6 +19,8 @@ #include "WhatsNewDialog.hxx" +constexpr int MAX_CHARS = 64; // maximum number of chars per line + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - WhatsNewDialog::WhatsNewDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, int max_w, int max_h) @@ -35,7 +37,7 @@ WhatsNewDialog::WhatsNewDialog(OSystem& osystem, DialogContainer& parent, const // Set preliminary dimensions - setSize(64 * fontWidth + HBORDER * 2, max_h, + setSize(MAX_CHARS * fontWidth + HBORDER * 2, max_h, max_w, max_h); add(ypos, "added autofire"); @@ -50,7 +52,7 @@ WhatsNewDialog::WhatsNewDialog(OSystem& osystem, DialogContainer& parent, const add(ypos, "fixed bug when taking fullscreen snapshots; the dimensions were sometimes cut"); // Set needed dimensions - setSize(64 * fontWidth + HBORDER * 2, + setSize(MAX_CHARS * fontWidth + HBORDER * 2, ypos + VGAP + buttonHeight + VBORDER, max_w, max_h); @@ -70,13 +72,13 @@ void WhatsNewDialog::add(int& ypos, const string& text) fontHeight = _font.getFontHeight(), fontWidth = _font.getMaxCharWidth(), HBORDER = fontWidth * 1.25; - const string DOT = "\x1f"; + const string DOT = "\x1f"; string txt = DOT + " " + text; // automatically wrap too long texts - while(txt.length() > 64) + while(txt.length() > MAX_CHARS) { - int i = 64; + int i = MAX_CHARS; while(--i && txt[i] != ' '); new StaticTextWidget(this, _font, HBORDER, ypos, txt.substr(0, i)); diff --git a/src/gui/WhatsNewDialog.hxx b/src/gui/WhatsNewDialog.hxx index 9ca7505e5..d90edbd15 100644 --- a/src/gui/WhatsNewDialog.hxx +++ b/src/gui/WhatsNewDialog.hxx @@ -22,13 +22,6 @@ class WhatsNewDialog : public Dialog { - public: - // These must be accessible from dialogs created by this class - enum { - kLoadROMCmd = 'STRT', // load currently selected ROM - kRomDirChosenCmd = 'romc' // rom dir chosen - }; - public: WhatsNewDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, int max_w, int max_h); From ea90ec84aa8da070ee371f543b9c4bd7967c1fd5 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 29 Jul 2020 15:52:50 +0200 Subject: [PATCH 370/377] added 'What's New' button to 'About' dialog --- src/gui/AboutDialog.cxx | 17 ++++++++++++++++- src/gui/AboutDialog.hxx | 8 ++++++++ src/gui/LauncherDialog.hxx | 1 - 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/gui/AboutDialog.cxx b/src/gui/AboutDialog.cxx index 8393e2009..bca95061c 100644 --- a/src/gui/AboutDialog.cxx +++ b/src/gui/AboutDialog.cxx @@ -20,6 +20,8 @@ #include "Version.hxx" #include "Widget.hxx" #include "Font.hxx" +#include "WhatsNewDialog.hxx" + #include "AboutDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -64,11 +66,17 @@ AboutDialog::AboutDialog(OSystem& osystem, DialogContainer& parent, wid.push_back(b); addCancelWidget(b); - xpos = HBORDER; ypos = _th + VBORDER; + xpos = HBORDER; ypos = _th + VBORDER + (buttonHeight - fontHeight) / 2; myTitle = new StaticTextWidget(this, font, xpos, ypos, _w - xpos * 2, fontHeight, "", TextAlign::Center); myTitle->setTextColor(kTextColorEm); + int bwidth = font.getStringWidth("What's New" + ELLIPSIS) + fontWidth * 2.5; + myWhatsNewButton = + new ButtonWidget(this, font, _w - HBORDER - bwidth, ypos - (buttonHeight - fontHeight) / 2, + bwidth, buttonHeight, "What's New" + ELLIPSIS, kWhatsNew); + wid.push_back(myWhatsNewButton); + xpos = HBORDER * 2; ypos += lineHeight + VGAP * 2; for(int i = 0; i < myLinesPerPage; i++) { @@ -258,6 +266,13 @@ void AboutDialog::handleCommand(CommandSender* sender, int cmd, int data, int id displayInfo(); break; + case kWhatsNew: + if(myWhatsNewDialog == nullptr) + myWhatsNewDialog = make_unique(instance(), parent(), _font, + 640 * 0.95, 480 * 0.95); + myWhatsNewDialog->open(); + break; + default: Dialog::handleCommand(sender, cmd, data, 0); } diff --git a/src/gui/AboutDialog.hxx b/src/gui/AboutDialog.hxx index 8dc8bc0bf..ecba48d41 100644 --- a/src/gui/AboutDialog.hxx +++ b/src/gui/AboutDialog.hxx @@ -23,6 +23,7 @@ class DialogContainer; class CommandSender; class ButtonWidget; class StaticTextWidget; +class WhatsNewDialog; #include "Dialog.hxx" @@ -41,6 +42,7 @@ class AboutDialog : public Dialog void loadConfig() override { displayInfo(); } private: + ButtonWidget* myWhatsNewButton{nullptr}; ButtonWidget* myNextButton{nullptr}; ButtonWidget* myPrevButton{nullptr}; @@ -52,6 +54,12 @@ class AboutDialog : public Dialog int myNumPages{4}; int myLinesPerPage{13}; + unique_ptr myWhatsNewDialog; + + enum { + kWhatsNew = 'ADWN' + }; + private: // Following constructors and assignment operators not supported AboutDialog() = delete; diff --git a/src/gui/LauncherDialog.hxx b/src/gui/LauncherDialog.hxx index 35472aad2..0f1f1cda2 100644 --- a/src/gui/LauncherDialog.hxx +++ b/src/gui/LauncherDialog.hxx @@ -132,7 +132,6 @@ class LauncherDialog : public Dialog unique_ptr myGlobalProps; unique_ptr myRomDir; unique_ptr myWhatsNewDialog; - unique_ptr myWhatsNewMsg; // automatically sized font for ROM info viewer unique_ptr myROMInfoFont; From af6f7a5ef4abbcaf8df7428aa8931cfb6f35f4c4 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Wed, 29 Jul 2020 13:19:43 -0230 Subject: [PATCH 371/377] Fix compile errors in gcc/clang. --- src/gui/AboutDialog.cxx | 5 +++++ src/gui/AboutDialog.hxx | 2 +- src/gui/WhatsNewDialog.cxx | 3 +-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/gui/AboutDialog.cxx b/src/gui/AboutDialog.cxx index bca95061c..db088d923 100644 --- a/src/gui/AboutDialog.cxx +++ b/src/gui/AboutDialog.cxx @@ -89,6 +89,11 @@ AboutDialog::AboutDialog(OSystem& osystem, DialogContainer& parent, addToFocusList(wid); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +AboutDialog::~AboutDialog() +{ +} + // The following commands can be put at the start of a line (all subject to change): // \C, \L, \R -- set center/left/right alignment // \c0 - \c5 -- set a custom color: diff --git a/src/gui/AboutDialog.hxx b/src/gui/AboutDialog.hxx index ecba48d41..fd3ad0a4c 100644 --- a/src/gui/AboutDialog.hxx +++ b/src/gui/AboutDialog.hxx @@ -32,7 +32,7 @@ class AboutDialog : public Dialog public: AboutDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font); - virtual ~AboutDialog() = default; + virtual ~AboutDialog(); private: void handleCommand(CommandSender* sender, int cmd, int data, int id) override; diff --git a/src/gui/WhatsNewDialog.cxx b/src/gui/WhatsNewDialog.cxx index cda4b4b5c..bb2414a1d 100644 --- a/src/gui/WhatsNewDialog.cxx +++ b/src/gui/WhatsNewDialog.cxx @@ -26,8 +26,7 @@ WhatsNewDialog::WhatsNewDialog(OSystem& osystem, DialogContainer& parent, const int max_w, int max_h) : Dialog(osystem, parent, font, "What's New in Stella " + string(STELLA_VERSION) + "?") { - const int lineHeight = _font.getLineHeight(), - fontHeight = _font.getFontHeight(), + const int fontHeight = _font.getFontHeight(), fontWidth = _font.getMaxCharWidth(), buttonHeight = _font.getLineHeight() * 1.25; const int VGAP = fontHeight / 4; From ef16e3f902e13ada47421a3ef286d953c9a7d275 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Thu, 30 Jul 2020 13:33:22 -0230 Subject: [PATCH 372/377] Tie CTS signal from the serial port to the appropriate AVox pin. Still TODO is actually implement this in the platform-specific serial code. --- src/emucore/AtariVox.cxx | 5 +++-- src/emucore/SerialPort.hxx | 8 ++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/emucore/AtariVox.cxx b/src/emucore/AtariVox.cxx index 9cb60012f..b80f6de4b 100644 --- a/src/emucore/AtariVox.cxx +++ b/src/emucore/AtariVox.cxx @@ -51,8 +51,9 @@ bool AtariVox::read(DigitalPin pin) { // Pin 2: SpeakJet READY case DigitalPin::Two: - // For now, we just assume the device is always ready - return setPin(pin, true); + { + return setPin(pin, mySerialPort->isCTS()); + } default: return SaveKey::read(pin); diff --git a/src/emucore/SerialPort.hxx b/src/emucore/SerialPort.hxx index aa08acbe8..f2ac5bf68 100644 --- a/src/emucore/SerialPort.hxx +++ b/src/emucore/SerialPort.hxx @@ -58,6 +58,14 @@ class SerialPort */ virtual bool writeByte(uInt8 data) { return false; } + /** + Test for 'Clear To Send' enabled. By default, assume it's always + OK to send more data. + + @return True if CTS signal enabled, else false + */ + virtual bool isCTS() { return true; } + private: // Following constructors and assignment operators not supported SerialPort(const SerialPort&) = delete; From 5c4391bee8492f6db0c8684ab773e8298e564a79 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Thu, 30 Jul 2020 13:35:16 -0230 Subject: [PATCH 373/377] Forgot comment in last commit. --- src/emucore/AtariVox.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/emucore/AtariVox.cxx b/src/emucore/AtariVox.cxx index b80f6de4b..994b494cf 100644 --- a/src/emucore/AtariVox.cxx +++ b/src/emucore/AtariVox.cxx @@ -50,6 +50,7 @@ bool AtariVox::read(DigitalPin pin) switch(pin) { // Pin 2: SpeakJet READY + // CTS enabled means the SpeakJet can accept more data case DigitalPin::Two: { return setPin(pin, mySerialPort->isCTS()); From 6d7ead166030e71d71e6d5479fee6dd29833614d Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Thu, 30 Jul 2020 16:26:45 -0230 Subject: [PATCH 374/377] Add missing files to Xcode project. --- src/macos/stella.xcodeproj/project.pbxproj | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/macos/stella.xcodeproj/project.pbxproj b/src/macos/stella.xcodeproj/project.pbxproj index f8c0789ce..44732af79 100644 --- a/src/macos/stella.xcodeproj/project.pbxproj +++ b/src/macos/stella.xcodeproj/project.pbxproj @@ -222,6 +222,8 @@ DC1B2EC81E50036100F62837 /* TrakBall.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC1B2EC21E50036100F62837 /* TrakBall.hxx */; }; DC1BC6662066B4390076F74A /* PKeyboardHandler.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC1BC6642066B4390076F74A /* PKeyboardHandler.cxx */; }; DC1BC6672066B4390076F74A /* PKeyboardHandler.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC1BC6652066B4390076F74A /* PKeyboardHandler.hxx */; }; + DC1E474E24D34F3B0047E61A /* WhatsNewDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC1E474C24D34F3A0047E61A /* WhatsNewDialog.cxx */; }; + DC1E474F24D34F3B0047E61A /* WhatsNewDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC1E474D24D34F3A0047E61A /* WhatsNewDialog.hxx */; }; DC21E5BF21CA903E007D0E1A /* OSystemMACOS.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC21E5B921CA903E007D0E1A /* OSystemMACOS.cxx */; }; DC21E5C021CA903E007D0E1A /* OSystemMACOS.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC21E5BA21CA903E007D0E1A /* OSystemMACOS.hxx */; }; DC21E5C121CA903E007D0E1A /* SerialPortMACOS.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC21E5BB21CA903E007D0E1A /* SerialPortMACOS.cxx */; }; @@ -973,6 +975,8 @@ DC1B2EC21E50036100F62837 /* TrakBall.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TrakBall.hxx; sourceTree = ""; }; DC1BC6642066B4390076F74A /* PKeyboardHandler.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PKeyboardHandler.cxx; sourceTree = ""; }; DC1BC6652066B4390076F74A /* PKeyboardHandler.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PKeyboardHandler.hxx; sourceTree = ""; }; + DC1E474C24D34F3A0047E61A /* WhatsNewDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WhatsNewDialog.cxx; sourceTree = ""; }; + DC1E474D24D34F3A0047E61A /* WhatsNewDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = WhatsNewDialog.hxx; sourceTree = ""; }; DC21E5B921CA903E007D0E1A /* OSystemMACOS.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OSystemMACOS.cxx; sourceTree = SOURCE_ROOT; }; DC21E5BA21CA903E007D0E1A /* OSystemMACOS.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = OSystemMACOS.hxx; sourceTree = SOURCE_ROOT; }; DC21E5BB21CA903E007D0E1A /* SerialPortMACOS.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SerialPortMACOS.cxx; sourceTree = SOURCE_ROOT; }; @@ -2133,6 +2137,8 @@ DC8078E70B4BD697005E9305 /* UIDialog.hxx */, DC3C9BC72469C93D00CF2D47 /* VideoAudioDialog.cxx */, DC3C9BC92469C93D00CF2D47 /* VideoAudioDialog.hxx */, + DC1E474C24D34F3A0047E61A /* WhatsNewDialog.cxx */, + DC1E474D24D34F3A0047E61A /* WhatsNewDialog.hxx */, 2DDBEAD4084578BF00812C11 /* Widget.cxx */, 2DDBEAD5084578BF00812C11 /* Widget.hxx */, ); @@ -2509,6 +2515,7 @@ 2D91745209BA90380026E9FF /* CommandDialog.hxx in Headers */, 2D91745309BA90380026E9FF /* CommandMenu.hxx in Headers */, E0306E111F93E916003DDD52 /* JitterEmulation.hxx in Headers */, + DC1E474F24D34F3B0047E61A /* WhatsNewDialog.hxx in Headers */, 2D91745509BA90380026E9FF /* CpuWidget.hxx in Headers */, 2D91745609BA90380026E9FF /* DataGridOpsWidget.hxx in Headers */, 2D91745709BA90380026E9FF /* DataGridWidget.hxx in Headers */, @@ -2911,6 +2918,7 @@ CFE3F60D1E84A9A200A8204E /* CartCDFWidget.cxx in Sources */, 2D9174B709BA90380026E9FF /* OptionsDialog.cxx in Sources */, 2D9174B809BA90380026E9FF /* PopUpWidget.cxx in Sources */, + DC1E474E24D34F3B0047E61A /* WhatsNewDialog.cxx in Sources */, DCBDDE9A1D6A5F0E009DF1E9 /* Cart3EPlusWidget.cxx in Sources */, DCE9158B201543B900960CC0 /* TimeLineWidget.cxx in Sources */, DCE5CDE31BA10024005CD08A /* RiotRamWidget.cxx in Sources */, From 0491cbb999b94d76d0fcd7d0bcece0c9ee661395 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 30 Jul 2020 22:19:12 +0200 Subject: [PATCH 375/377] refined texts for WhatsNewDialog --- Changes.txt | 4 ++-- src/gui/WhatsNewDialog.cxx | 26 ++++++++++++++++++-------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/Changes.txt b/Changes.txt index f19fabcfb..9db31b627 100644 --- a/Changes.txt +++ b/Changes.txt @@ -14,9 +14,9 @@ 6.2.1 to 6.3 (XXXX XX, 2020) - * Added autofire. + * Added adjustable autofire. - * Added new UI theme 'Dark'. (TODO: DOC) + * Added 'Dark' UI theme. (TODO: DOC) * Extended global hotkeys for debug options. diff --git a/src/gui/WhatsNewDialog.cxx b/src/gui/WhatsNewDialog.cxx index bb2414a1d..7f6c15084 100644 --- a/src/gui/WhatsNewDialog.cxx +++ b/src/gui/WhatsNewDialog.cxx @@ -24,7 +24,11 @@ constexpr int MAX_CHARS = 64; // maximum number of chars per line // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - WhatsNewDialog::WhatsNewDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, int max_w, int max_h) +#if defined(RETRON77) + : Dialog(osystem, parent, font, "What's New in Stella " + string(STELLA_VERSION) + " for RetroN 77?") +#else : Dialog(osystem, parent, font, "What's New in Stella " + string(STELLA_VERSION) + "?") +#endif { const int fontHeight = _font.getFontHeight(), fontWidth = _font.getMaxCharWidth(), @@ -39,20 +43,26 @@ WhatsNewDialog::WhatsNewDialog(OSystem& osystem, DialogContainer& parent, const setSize(MAX_CHARS * fontWidth + HBORDER * 2, max_h, max_w, max_h); - add(ypos, "added autofire"); - add(ypos, "added new UI theme 'Dark'"); - add(ypos, "extended global hotkeys for debug options"); +#if defined(RETRON77) + add(ypos, "added adjustable autofire (see 'Advanced Settings')"); + add(ypos, "added new UI theme 'Dark' (see 'Advanced Settings')"); +#else + add(ypos, "added adjustable autofire"); + add(ypos, "added 'Dark' UI theme"); + //add(ypos, "extended global hotkeys for debug options"); add(ypos, "added option to playback a game using the Time Machine"); - add(ypos, "allow taking snapshots from within the Time Machine dialog"); + //add(ypos, "allow taking snapshots from within the Time Machine dialog"); add(ypos, "added the ability to access most files that Stella uses from within a ZIP file"); add(ypos, "added option to select the audio device"); - add(ypos, "added option to display detected settings info when a ROM is loaded"); - add(ypos, "replaced 'Re-disassemble' with 'Disassemble @ current line' in debugger"); - add(ypos, "fixed bug when taking fullscreen snapshots; the dimensions were sometimes cut"); + //add(ypos, "added option to display detected settings info when a ROM is loaded"); + //add(ypos, "replaced 'Re-disassemble' with 'Disassemble @ current line' in debugger"); + //add(ypos, "fixed bug when taking fullscreen snapshots; the dimensions were sometimes cut"); + add(ypos, ELLIPSIS + " (for a complete list see 'docs/Changes.txt')"); +#endif // Set needed dimensions setSize(MAX_CHARS * fontWidth + HBORDER * 2, - ypos + VGAP + buttonHeight + VBORDER, + ypos + VGAP * 2 + buttonHeight + VBORDER, max_w, max_h); WidgetArray wid; From cd06ae69eb43405659c65b081da1b00df0e892d4 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Thu, 30 Jul 2020 17:50:34 -0230 Subject: [PATCH 376/377] Add SerialPort::isCTS() to all ports, and connect it to AtariVox. --- src/emucore/AtariVox.cxx | 5 +++-- src/macos/SerialPortMACOS.cxx | 12 ++++++++++++ src/macos/SerialPortMACOS.hxx | 7 +++++++ src/unix/SerialPortUNIX.cxx | 15 +++++++++++++++ src/unix/SerialPortUNIX.hxx | 7 +++++++ src/windows/SerialPortWINDOWS.cxx | 12 ++++++++++++ src/windows/SerialPortWINDOWS.hxx | 8 ++++++++ src/windows/Stella.vcxproj | 1 + src/windows/Stella.vcxproj.filters | 3 +++ 9 files changed, 68 insertions(+), 2 deletions(-) diff --git a/src/emucore/AtariVox.cxx b/src/emucore/AtariVox.cxx index 994b494cf..fd75024e4 100644 --- a/src/emucore/AtariVox.cxx +++ b/src/emucore/AtariVox.cxx @@ -50,10 +50,11 @@ bool AtariVox::read(DigitalPin pin) switch(pin) { // Pin 2: SpeakJet READY - // CTS enabled means the SpeakJet can accept more data + // CTS (Clear To Send) is connected inverted + // So CTS = 0 means the buffer is full, which pulls pin 2 high case DigitalPin::Two: { - return setPin(pin, mySerialPort->isCTS()); + return setPin(pin, !mySerialPort->isCTS()); } default: diff --git a/src/macos/SerialPortMACOS.cxx b/src/macos/SerialPortMACOS.cxx index 90235e0a8..9745eceff 100644 --- a/src/macos/SerialPortMACOS.cxx +++ b/src/macos/SerialPortMACOS.cxx @@ -73,3 +73,15 @@ bool SerialPortMACOS::writeByte(uInt8 data) } return false; } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool SerialPortMACOS::isCTS() +{ + if(myHandle) + { + int status = 0; + ioctl(myHandle, TIOCMGET, &status); + return status & TIOCM_CTS; + } + return false; +} diff --git a/src/macos/SerialPortMACOS.hxx b/src/macos/SerialPortMACOS.hxx index 0c83e5045..3d71d5135 100644 --- a/src/macos/SerialPortMACOS.hxx +++ b/src/macos/SerialPortMACOS.hxx @@ -48,6 +48,13 @@ class SerialPortMACOS : public SerialPort */ bool writeByte(uInt8 data) override; + /** + Test for 'Clear To Send' enabled. + + @return True if CTS signal enabled, else false + */ + bool isCTS() override; + private: // File descriptor for serial connection int myHandle{0}; diff --git a/src/unix/SerialPortUNIX.cxx b/src/unix/SerialPortUNIX.cxx index f114e18fe..1105d2092 100644 --- a/src/unix/SerialPortUNIX.cxx +++ b/src/unix/SerialPortUNIX.cxx @@ -49,6 +49,9 @@ bool SerialPortUNIX::openPort(const string& device) if(myHandle <= 0) return false; + // Open the device in nonblocking mode + fcntl(myHandle, F_SETFL, FNDELAY); + struct termios termios; memset(&termios, 0, sizeof(struct termios)); @@ -71,3 +74,15 @@ bool SerialPortUNIX::writeByte(uInt8 data) } return false; } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool SerialPortUNIX::isCTS() +{ + if(myHandle) + { + int status = 0; + ioctl(myHandle, TIOCMGET, &status); + return status & TIOCM_CTS; + } + return false; +} diff --git a/src/unix/SerialPortUNIX.hxx b/src/unix/SerialPortUNIX.hxx index b46d0a64a..7a675298e 100644 --- a/src/unix/SerialPortUNIX.hxx +++ b/src/unix/SerialPortUNIX.hxx @@ -48,6 +48,13 @@ class SerialPortUNIX : public SerialPort */ bool writeByte(uInt8 data) override; + /** + Test for 'Clear To Send' enabled. + + @return True if CTS signal enabled, else false + */ + bool isCTS() override; + private: // File descriptor for serial connection int myHandle{0}; diff --git a/src/windows/SerialPortWINDOWS.cxx b/src/windows/SerialPortWINDOWS.cxx index 51ed73247..91b6c0bb3 100644 --- a/src/windows/SerialPortWINDOWS.cxx +++ b/src/windows/SerialPortWINDOWS.cxx @@ -79,3 +79,15 @@ bool SerialPortWINDOWS::writeByte(uInt8 data) } return false; } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool SerialPortWINDOWS::isCTS() +{ + if(myHandle) + { + DWORD modemStat; + GetCommModemStatus(myHandle, &modemStat); + return modemStat & MS_CTS_ON; + } + return false; +} diff --git a/src/windows/SerialPortWINDOWS.hxx b/src/windows/SerialPortWINDOWS.hxx index 8c0ed789c..3f8513573 100644 --- a/src/windows/SerialPortWINDOWS.hxx +++ b/src/windows/SerialPortWINDOWS.hxx @@ -47,6 +47,14 @@ class SerialPortWINDOWS : public SerialPort */ bool writeByte(uInt8 data) override; + /** + Test for 'Clear To Send' enabled. By default, assume it's always + OK to send more data. + + @return True if CTS signal enabled, else false + */ + bool isCTS() override; + private: // Handle to serial port HANDLE myHandle{0}; diff --git a/src/windows/Stella.vcxproj b/src/windows/Stella.vcxproj index c6ba9d7ff..52a8c4327 100644 --- a/src/windows/Stella.vcxproj +++ b/src/windows/Stella.vcxproj @@ -1774,6 +1774,7 @@ + diff --git a/src/windows/Stella.vcxproj.filters b/src/windows/Stella.vcxproj.filters index 215e9eeab..5875efb8c 100644 --- a/src/windows/Stella.vcxproj.filters +++ b/src/windows/Stella.vcxproj.filters @@ -2087,6 +2087,9 @@ Header Files\gui + + Header Files\emucore + From c29933ed90ef33dc24229806b55d1f8afb92fc47 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Fri, 31 Jul 2020 08:55:16 +0200 Subject: [PATCH 377/377] minor change in Inputdialog (AtariVox) --- docs/graphics/eventmapping_devsports.png | Bin 4523 -> 4530 bytes docs/index.html | 2 +- src/gui/InputDialog.cxx | 4 ++-- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/graphics/eventmapping_devsports.png b/docs/graphics/eventmapping_devsports.png index 55dc205c6cfd3511ad3d0f5ae5abf9e4aab3c14d..9b3da3ebc870cf8e21a8bc31d7ae4720bfbdadeb 100644 GIT binary patch literal 4530 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 literal 4523 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 nteCbx{?|8Swap Stelladaptor portsSwap the order of the detected Stelladaptors/2600-daptors (see Advanced Configuration - Stelladaptor/2600-daptor Support)-saport Joystick databaseShow all joysticks that Stella knows about, with the option to remove them  Erase EEPROMErase the whole AtariVox/SaveKey flash memory  - AVox serial portDescribed in further detail in Advanced Configuration - AtariVox/SaveKey Support -avoxport + AtariVox serial portDescribed in further detail in Advanced Configuration - AtariVox/SaveKey Support -avoxport diff --git a/src/gui/InputDialog.cxx b/src/gui/InputDialog.cxx index 4e792348c..727c9a874 100644 --- a/src/gui/InputDialog.cxx +++ b/src/gui/InputDialog.cxx @@ -221,9 +221,9 @@ void InputDialog::addDevicePortTab() // Add AtariVox serial port ypos += lineHeight + VGAP * 3; - lwidth = _font.getStringWidth("AVox serial port "); + lwidth = _font.getStringWidth("AtariVox serial port "); fwidth = _w - HBORDER * 2 - 2 - lwidth; - new StaticTextWidget(myTab, _font, HBORDER, ypos + 2, "AVox serial port "); + new StaticTextWidget(myTab, _font, HBORDER, ypos + 2, "AtariVox serial port "); myAVoxPort = new EditTextWidget(myTab, _font, HBORDER + lwidth, ypos, fwidth, fontHeight); wid.push_back(myAVoxPort);