diff --git a/Changes.txt b/Changes.txt index ffaa92033..a3a10218a 100644 --- a/Changes.txt +++ b/Changes.txt @@ -18,10 +18,19 @@ scanlines; the output is now blanked as on a real TV. Special thanks to Omegamatrix of AtariAge for test ROMs in this area. + * Modified hotkey for "Change console palette" (Control-f) to also + change the display properties of the TIA. This allows you to switch + between NTSC/PAL/SECAM (and variants) modes dynamically. Related to + this, added Shift-Control-f key to step backwards through the + available modes. + * Fixed several bugs in DPC+ bankswitching scheme, including ability to load and save state files. As well, ROMs now work correctly after console format autodetection. + * Note: because of the TIA changes, the state file format has changed + again, and old state files will not work with this release. + -Have fun! diff --git a/docs/index.html b/docs/index.html index 469f678c7..e79304110 100644 --- a/docs/index.html +++ b/docs/index.html @@ -10,7 +10,7 @@

A multi-platform Atari 2600 VCS emulator

-

Release 3.7

+

Release 3.7.1



User's Guide

@@ -1553,11 +1553,17 @@ - Toggle display palette (NTSC/PAL/SECAM) + Toggle console type in increasing order (NTSC/PAL/SECAM, etc)) Control + f Control + f + + Toggle console type in decreasing order (NTSC/PAL/SECAM, etc)) + Shift-Control + f + Shift-Control + f + + Save current properties to a new properties file Control + s diff --git a/src/common/Version.hxx b/src/common/Version.hxx index 891730b39..5f044908b 100644 --- a/src/common/Version.hxx +++ b/src/common/Version.hxx @@ -22,7 +22,7 @@ #include -#define STELLA_VERSION "3.8_svn" +#define STELLA_VERSION "3.7.1_pre" #define STELLA_BUILD atoi("$Rev$" + 6) #endif diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 36edeb58d..881388cc1 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -77,6 +77,7 @@ Console::Console(OSystem* osystem, Cartridge* cart, const Properties& props) myCMHandler(0), myDisplayFormat("NTSC"), myFramerate(60.0), + myCurrentFormat(0), myUserPaletteDefined(false) { // Load user-defined palette for this ROM @@ -118,24 +119,17 @@ Console::Console(OSystem* osystem, Cartridge* cart, const Properties& props) // We turn off the SuperCharger progress bars, otherwise the SC BIOS // will take over 250 frames! // The 'fastscbios' option must be changed before the system is reset - - // The algorithm used is as follows: - // Run for 60 frames; if there's a frame that has more than 287 - // scanlines, count it as PAL - // If at least 25 PAL frames are found, then the format is PAL, else NTSC bool fastscbios = myOSystem->settings().getBool("fastscbios"); myOSystem->settings().setBool("fastscbios", true); mySystem->reset(true); // autodetect in reset enabled - int palCount = 0; for(int i = 0; i < 60; ++i) - { myTIA->update(); - if(myTIA->scanlines() >= 287) - ++palCount; - } - myDisplayFormat = (palCount >= 25) ? "PAL" : "NTSC"; + myDisplayFormat = myTIA->isPAL() ? "PAL" : "NTSC"; if(myProperties.get(Display_Format) == "AUTO-DETECT") + { autodetected = "*"; + myCurrentFormat = 0; + } // Don't forget to reset the SC progress bars again myOSystem->settings().setBool("fastscbios", fastscbios); @@ -145,48 +139,15 @@ Console::Console(OSystem* osystem, Cartridge* cart, const Properties& props) // Set up the correct properties used when toggling format // Note that this can be overridden if a format is forced // For example, if a PAL ROM is forced to be NTSC, it will use NTSC-like - // properties (60Hz, 262 scanlines, etc) and cycle between NTSC-like modes + // properties (60Hz, 262 scanlines, etc), but likely result in flicker // The TIA will self-adjust the framerate if necessary - - // TODO - query these values directly from the TIA if value is 'AUTO' - uInt32 ystart = atoi(myProperties.get(Display_YStart).c_str()); - if(ystart > 64) ystart = 64; - uInt32 height = atoi(myProperties.get(Display_Height).c_str()); - if(height < 210) height = 210; - else if(height > 256) height = 256; - - if(myDisplayFormat == "NTSC" || myDisplayFormat == "PAL60" || - myDisplayFormat == "SECAM60") - { - // Assume we've got ~262 scanlines (NTSC-like format) - myFramerate = 60.0; - myConsoleInfo.InitialFrameRate = "60"; - } - else - { - // Assume we've got ~312 scanlines (PAL-like format) - myFramerate = 50.0; - myConsoleInfo.InitialFrameRate = "50"; - - // PAL ROMs normally need at least 250 lines - height = BSPF_max(height, 250u); - } - - // Make sure these values fit within the bounds of the desktop - // If not, attempt to center vertically - if(height <= myOSystem->desktopHeight()) - { - myTIA->setYStart(ystart); - myTIA->setHeight(height); - } - else - { - ystart += height - myOSystem->desktopHeight(); - ystart = BSPF_min(ystart, 64u); - height = myOSystem->desktopHeight(); - myTIA->setYStart(ystart); - myTIA->setHeight(height); - } + setTIAProperties(); + if(myDisplayFormat == "NTSC") myCurrentFormat = 1; + else if(myDisplayFormat == "PAL") myCurrentFormat = 2; + else if(myDisplayFormat == "SECAM") myCurrentFormat = 3; + else if(myDisplayFormat == "NTSC50") myCurrentFormat = 4; + else if(myDisplayFormat == "PAL60") myCurrentFormat = 5; + else if(myDisplayFormat == "SECAM60") myCurrentFormat = 6; // Add the real controllers for this system // This must be done before the debugger is initialized @@ -275,54 +236,56 @@ bool Console::load(Serializer& in) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::toggleFormat() +void Console::toggleFormat(int direction) { - string format, message; + string saveformat, message; - if(myDisplayFormat.compare(0, 4, "NTSC") == 0) - { - if(myFramerate > 55.0) - { - format = "PAL60"; - message = "PAL palette (PAL60)"; - } - else - { - format = "PAL"; - message = "PAL palette (PAL)"; - } - } - else if(myDisplayFormat.compare(0, 3, "PAL") == 0) - { - if(myFramerate > 55.0) - { - format = "SECAM"; - message = "SECAM palette (SECAM60)"; - } - else - { - format = "SECAM"; - message = "SECAM palette (SECAM)"; - } - } - else if(myDisplayFormat.compare(0, 5, "SECAM") == 0) - { - if(myFramerate > 55.0) - { - format = "NTSC"; - message = "NTSC palette (NTSC)"; - } - else - { - format = "NTSC50"; - message = "NTSC palette (NTSC50)"; - } - } + if(direction == 1) + myCurrentFormat = (myCurrentFormat + 1) % 7; + else if(direction == -1) + myCurrentFormat = myCurrentFormat > 0 ? (myCurrentFormat - 1) : 6; + + switch(myCurrentFormat) + { + case 0: // auto-detect + myTIA->update(); + myDisplayFormat = myTIA->isPAL() ? "PAL" : "NTSC"; + message = "Auto-detect mode: " + myDisplayFormat; + saveformat = "AUTO-DETECT"; + break; + case 1: + saveformat = myDisplayFormat = "NTSC"; + message = "NTSC mode"; + break; + case 2: + saveformat = myDisplayFormat = "PAL"; + message = "PAL mode"; + break; + case 3: + saveformat = myDisplayFormat = "SECAM"; + message = "SECAM mode"; + break; + case 4: + saveformat = myDisplayFormat = "NTSC50"; + message = "NTSC50 mode"; + break; + case 5: + saveformat = myDisplayFormat = "PAL60"; + message = "PAL60 mode"; + break; + case 6: + saveformat = myDisplayFormat = "SECAM60"; + message = "SECAM60 mode"; + break; + } + myProperties.set(Display_Format, saveformat); - myDisplayFormat = format; - myProperties.set(Display_Format, myDisplayFormat); - myOSystem->frameBuffer().showMessage(message); setPalette(myOSystem->settings().getString("palette")); + setTIAProperties(); + myTIA->frameReset(); + initializeVideo(); // takes care of refreshing the screen + + myOSystem->frameBuffer().showMessage(message); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -605,6 +568,50 @@ void Console::changeHeight(int direction) myProperties.set(Display_Height, val.str()); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Console::setTIAProperties() +{ + // TODO - query these values directly from the TIA if value is 'AUTO' + uInt32 ystart = atoi(myProperties.get(Display_YStart).c_str()); + if(ystart > 64) ystart = 64; + uInt32 height = atoi(myProperties.get(Display_Height).c_str()); + if(height < 210) height = 210; + else if(height > 256) height = 256; + + if(myDisplayFormat == "NTSC" || myDisplayFormat == "PAL60" || + myDisplayFormat == "SECAM60") + { + // Assume we've got ~262 scanlines (NTSC-like format) + myFramerate = 60.0; + myConsoleInfo.InitialFrameRate = "60"; + } + else + { + // Assume we've got ~312 scanlines (PAL-like format) + myFramerate = 50.0; + myConsoleInfo.InitialFrameRate = "50"; + + // PAL ROMs normally need at least 250 lines + height = BSPF_max(height, 250u); + } + + // Make sure these values fit within the bounds of the desktop + // If not, attempt to center vertically + if(height <= myOSystem->desktopHeight()) + { + myTIA->setYStart(ystart); + myTIA->setHeight(height); + } + else + { + ystart += height - myOSystem->desktopHeight(); + ystart = BSPF_min(ystart, 64u); + height = myOSystem->desktopHeight(); + myTIA->setYStart(ystart); + myTIA->setHeight(height); + } +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::setControllers(const string& rommd5) { diff --git a/src/emucore/Console.hxx b/src/emucore/Console.hxx index e420fdfb2..587107866 100644 --- a/src/emucore/Console.hxx +++ b/src/emucore/Console.hxx @@ -182,8 +182,10 @@ class Console : public Serializable public: /** Toggle between NTSC/PAL/SECAM (and variants) display format. + + @param direction +1 indicates increase, -1 indicates decrease. */ - void toggleFormat(); + void toggleFormat(int direction = 1); /** Toggle between the available palettes. @@ -285,6 +287,12 @@ class Console : public Serializable void toggleFixedColors() const; private: + /** + Sets various properties of the TIA (YStart, Height, etc) based on + the current display format. + */ + void setTIAProperties(); + /** Adds the left and right controllers to the console. */ @@ -350,6 +358,9 @@ class Console : public Serializable // The currently defined display framerate float myFramerate; + // Display format currently in use + uInt32 myCurrentFormat; + // Indicates whether an external palette was found and // successfully loaded bool myUserPaletteDefined; diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index ba72c2a3d..698f24119 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -576,8 +576,8 @@ void EventHandler::poll(uInt64 time) toggleSAPortOrder(); break; - case KBDK_f: // Ctrl-f toggles NTSC/PAL mode - myOSystem->console().toggleFormat(); + case KBDK_f: // (Shift) Ctrl-f toggles NTSC/PAL/SECAM mode + myOSystem->console().toggleFormat(mod & KMOD_SHIFT ? -1 : 1); break; case KBDK_g: // Ctrl-g (un)grabs mouse diff --git a/src/emucore/StateManager.cxx b/src/emucore/StateManager.cxx index dfbab3ae0..2b61889c3 100644 --- a/src/emucore/StateManager.cxx +++ b/src/emucore/StateManager.cxx @@ -30,7 +30,7 @@ #include "StateManager.hxx" -#define STATE_HEADER "03070000state" +#define STATE_HEADER "03070100state" #define MOVIE_HEADER "03030000movie" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/TIA.cxx b/src/emucore/TIA.cxx index 8a900bcad..32c8cba29 100644 --- a/src/emucore/TIA.cxx +++ b/src/emucore/TIA.cxx @@ -54,6 +54,7 @@ TIA::TIA(Console& console, Sound& sound, Settings& settings) myPartialFrameFlag(false), myAutoFrameEnabled(false), myFrameCounter(0), + myPALFrameCounter(0), myBitsEnabled(true), myCollisionsEnabled(true) @@ -137,8 +138,35 @@ void TIA::reset() // Should undriven pins be randomly driven high or low? myTIAPinsDriven = mySettings.getBool("tiadriven"); - myFrameCounter = 0; + myFrameCounter = myPALFrameCounter = 0; myScanlineCountForLastFrame = 0; + + myCurrentP0Mask = &TIATables::PxMask[0][0][0][0]; + myCurrentP1Mask = &TIATables::PxMask[0][0][0][0]; + myCurrentM0Mask = &TIATables::MxMask[0][0][0][0]; + myCurrentM1Mask = &TIATables::MxMask[0][0][0][0]; + myCurrentBLMask = &TIATables::BLMask[0][0][0]; + myCurrentPFMask = TIATables::PFMask[0]; + + // Recalculate the size of the display + toggleFixedColors(0); + frameReset(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIA::frameReset() +{ + // Clear frame buffers + clearBuffers(); + + // Reset pixel pointer and drawing flag + myFramePointer = myCurrentFrameBuffer; + + // Calculate color clock offsets for starting and stopping frame drawing + // Note that although we always start drawing at scanline zero, the + // framebuffer that is exposed outside the class actually starts at 'ystart' + myFramePointerOffset = 160 * myFrameYStart; + myAutoFrameEnabled = (mySettings.getInt("framerate") <= 0); myFramerate = myConsole.getFramerate(); @@ -169,32 +197,6 @@ void TIA::reset() myMaximumNumberOfScanlines = 342; } - myCurrentP0Mask = &TIATables::PxMask[0][0][0][0]; - myCurrentP1Mask = &TIATables::PxMask[0][0][0][0]; - myCurrentM0Mask = &TIATables::MxMask[0][0][0][0]; - myCurrentM1Mask = &TIATables::MxMask[0][0][0][0]; - myCurrentBLMask = &TIATables::BLMask[0][0][0]; - myCurrentPFMask = TIATables::PFMask[0]; - - // Recalculate the size of the display - toggleFixedColors(0); - frameReset(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::frameReset() -{ - // Clear frame buffers - clearBuffers(); - - // Reset pixel pointer and drawing flag - myFramePointer = myCurrentFrameBuffer; - - // Calculate color clock offsets for starting and stopping frame drawing - // Note that although we always start drawing at scanline zero, the - // framebuffer that is exposed outside the class actually starts at 'ystart' - myFramePointerOffset = 160 * myFrameYStart; - // NTSC screens will process at least 262 scanlines, // while PAL will have at least 312 // In any event, at most 320 lines can be processed @@ -350,6 +352,7 @@ bool TIA::save(Serializer& out) const out.putBool(myHMOVEBlankEnabled); out.putInt(myFrameCounter); + out.putInt(myPALFrameCounter); // Save the sound sample stuff ... mySound.save(out); @@ -452,7 +455,8 @@ bool TIA::load(Serializer& in) myPreviousHMOVEPos = (Int32) in.getInt(); myHMOVEBlankEnabled = in.getBool(); - myFrameCounter = (Int32) in.getInt(); + myFrameCounter = in.getInt(); + myPALFrameCounter = in.getInt(); // Load the sound sample stuff ... mySound.load(in); @@ -603,6 +607,8 @@ inline void TIA::endFrame() // Stats counters myFrameCounter++; + if(myScanlineCountForLastFrame >= 287) + myPALFrameCounter++; // Recalculate framerate. attempting to auto-correct for scanline 'jumps' if(myFrameCounter % 8 == 0 && myAutoFrameEnabled && diff --git a/src/emucore/TIA.hxx b/src/emucore/TIA.hxx index ef30a94f8..113e723ac 100644 --- a/src/emucore/TIA.hxx +++ b/src/emucore/TIA.hxx @@ -216,6 +216,13 @@ class TIA : public Device void enableColorLoss(bool mode) { myColorLossEnabled = myFramerate <= 55 ? mode : false; } + /** + Answers whether this TIA runs at NTSC or PAL scanrates, + based on how many frames of out the total count are PAL frames. + */ + bool isPAL() + { return float(myPALFrameCounter) / myFrameCounter >= (25.0/60.0); } + /** Answers the current color clock we've gotten to on this scanline. @@ -605,8 +612,11 @@ class TIA : public Device // Automatic framerate correction based on number of scanlines bool myAutoFrameEnabled; - // Number of frames displayed by this TIA - int myFrameCounter; + // Number of total frames displayed by this TIA + uInt32 myFrameCounter; + + // Number of PAL frames displayed by this TIA + uInt32 myPALFrameCounter; // The framerate currently in use by the Console float myFramerate;