Added emulation for frame 'jitter' based on inconsistent scanline

counts.  Thanks to Spiceware for the idea and implementation.

Tweaked 'MDM' autodetection; the identifying string can be in
either bank 0 or bank 1 (or both).


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@3199 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2015-09-11 22:46:13 +00:00
parent 20251f6a9f
commit a331fb228b
6 changed files with 61 additions and 9 deletions

View File

@ -23,6 +23,15 @@
now, this applies mainly to the various decimal and binary fields. now, this applies mainly to the various decimal and binary fields.
More widgets will be made editable in future releases. More widgets will be made editable in future releases.
* The TIA now emulates the jitter that occurs when scanline counts
are not consistent frame-over-frame. Also, the DPC+ scheme now
emulates jitter that can occur when using its Fractional Datafetchers
if the DFxFRACINC registers are not re-initialized every frame.
Special thanks to SpiceWare for this implementation.
* Tweaked 'MDM' scheme autodetection to detect that the identification
string can be in either bank 0 or bank 1.
* Changed 'hidecursor' commandline argument (and associated UI item) to * Changed 'hidecursor' commandline argument (and associated UI item) to
'cursor'. The new argument allows to set mouse cursor visibility 'cursor'. The new argument allows to set mouse cursor visibility
separately for both UI and emulation modes. separately for both UI and emulation modes.

View File

@ -894,9 +894,9 @@ bool Cartridge::isProbablyFE(const uInt8* image, uInt32 size)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge::isProbablyMDM(const uInt8* image, uInt32 size) bool Cartridge::isProbablyMDM(const uInt8* image, uInt32 size)
{ {
// MDM cart is identified key 'MDMC' in the first 4K of ROM // MDM cart is identified key 'MDMC' in the first 8K of ROM
uInt8 signature[] = { 'M', 'D', 'M', 'C' }; uInt8 signature[] = { 'M', 'D', 'M', 'C' };
return searchForBytes(image, 4096, signature, 4, 1); return searchForBytes(image, 8192, signature, 4, 1);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -412,7 +412,7 @@ bool CartridgeDPCPlus::poke(uInt16 address, uInt8 value)
{ {
//DFxFRACLOW - fractional data pointer low byte //DFxFRACLOW - fractional data pointer low byte
case 0x00: case 0x00:
myFractionalCounters[index] = (myFractionalCounters[index] & 0x0F0000) | ((uInt16)value << 8); myFractionalCounters[index] = (myFractionalCounters[index] & 0x0F00FF) | ((uInt16)value << 8);
break; break;
// DFxFRACHI - fractional data pointer high byte // DFxFRACHI - fractional data pointer high byte

View File

@ -57,7 +57,9 @@ TIA::TIA(Console& console, Sound& sound, Settings& settings)
myFrameCounter(0), myFrameCounter(0),
myPALFrameCounter(0), myPALFrameCounter(0),
myBitsEnabled(true), myBitsEnabled(true),
myCollisionsEnabled(true) myCollisionsEnabled(true),
myNextFrameJitter(0),
myCurrentFrameJitter(0)
{ {
// Allocate buffers for two frame buffers // Allocate buffers for two frame buffers
@ -141,6 +143,7 @@ void TIA::reset()
myFrameCounter = myPALFrameCounter = 0; myFrameCounter = myPALFrameCounter = 0;
myScanlineCountForLastFrame = 0; myScanlineCountForLastFrame = 0;
myNextFrameJitter = myCurrentFrameJitter = 0;
myP0Mask = &TIATables::PxMask[0][0][0]; myP0Mask = &TIATables::PxMask[0][0][0];
myP1Mask = &TIATables::PxMask[0][0][0]; myP1Mask = &TIATables::PxMask[0][0][0];
@ -653,6 +656,39 @@ inline void TIA::endFrame()
memset(myPreviousFrameBuffer + offset, 1, stride); memset(myPreviousFrameBuffer + offset, 1, stride);
} }
// Account for frame jitter, skipping the first few frames
if(myFrameCounter > 3)
{
// Set the jitter amount for the current frame
myCurrentFrameJitter = myNextFrameJitter * 160;
// Calculate the jitter amount for the next frame.
// Jitter amount of a frame depends upon the difference
// between the scanline counts of the prior two frames.
myNextFrameJitter = myScanlineCountForLastFrame - previousCount;
if(myNextFrameJitter < 0)
{
myNextFrameJitter = --myNextFrameJitter >> 1;
// Make sure currentFrameBuffer() doesn't return a pointer that
// results in memory being accessed outside of the 160*320 bytes
// allocated for the frame buffer
if(myNextFrameJitter < -myFrameYStart)
myNextFrameJitter = myFrameYStart;
}
else if(myNextFrameJitter > 0)
{
myNextFrameJitter = ++myNextFrameJitter >> 1;
// Make sure currentFrameBuffer() doesn't return a pointer that
// results in memory being accessed outside of the 160*320 bytes
// allocated for the frame buffer
if(myNextFrameJitter > 320 - myFrameYStart - myFrameHeight)
myNextFrameJitter = 320 - myFrameYStart - myFrameHeight;
}
}
// Recalculate framerate. attempting to auto-correct for scanline 'jumps' // Recalculate framerate. attempting to auto-correct for scanline 'jumps'
if(myAutoFrameEnabled) if(myAutoFrameEnabled)
{ {

View File

@ -175,7 +175,7 @@ class TIA : public Device
@return Pointer to the current frame buffer @return Pointer to the current frame buffer
*/ */
uInt8* currentFrameBuffer() const uInt8* currentFrameBuffer() const
{ return myCurrentFrameBuffer + myFramePointerOffset; } { return myCurrentFrameBuffer + myFramePointerOffset + myCurrentFrameJitter; }
/** /**
Answers the previous frame buffer Answers the previous frame buffer
@ -616,6 +616,13 @@ class TIA : public Device
// Whether TIA bits/collisions are currently enabled/disabled // Whether TIA bits/collisions are currently enabled/disabled
bool myBitsEnabled, myCollisionsEnabled; bool myBitsEnabled, myCollisionsEnabled;
// Derived from the difference between the scanline counts of the
// current and prior frames. If non-zero the next frame should jitter.
Int32 myNextFrameJitter;
// Jitter amount for the current frame
Int32 myCurrentFrameJitter;
private: private:
// Following constructors and assignment operators not supported // Following constructors and assignment operators not supported
TIA() = delete; TIA() = delete;

View File

@ -1032,8 +1032,8 @@
DCD6FC9211C28C6F005DA767 /* PNGLibrary.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = PNGLibrary.hxx; path = ../common/PNGLibrary.hxx; sourceTree = SOURCE_ROOT; }; DCD6FC9211C28C6F005DA767 /* PNGLibrary.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = PNGLibrary.hxx; path = ../common/PNGLibrary.hxx; sourceTree = SOURCE_ROOT; };
DCDA03AE1A2009BA00711920 /* CartWD.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartWD.cxx; path = ../emucore/CartWD.cxx; sourceTree = "<group>"; }; DCDA03AE1A2009BA00711920 /* CartWD.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartWD.cxx; path = ../emucore/CartWD.cxx; sourceTree = "<group>"; };
DCDA03AF1A2009BB00711920 /* CartWD.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartWD.hxx; path = ../emucore/CartWD.hxx; sourceTree = "<group>"; }; DCDA03AF1A2009BB00711920 /* CartWD.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartWD.hxx; path = ../emucore/CartWD.hxx; sourceTree = "<group>"; };
DCDAF4D818CA9AAB00D3865D /* SDL2.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL2.framework; path = ../../../../../../Library/Frameworks/SDL2.framework; sourceTree = "<group>"; }; DCDAF4D818CA9AAB00D3865D /* SDL2.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL2.framework; path = /Library/Frameworks/SDL2.framework; sourceTree = "<absolute>"; };
DCDAF4DA18CA9AF000D3865D /* SDL2.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL2.framework; path = ../../../../../../Library/Frameworks/SDL2.framework; sourceTree = "<group>"; }; DCDAF4DA18CA9AF000D3865D /* SDL2.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL2.framework; path = /Library/Frameworks/SDL2.framework; sourceTree = "<absolute>"; };
DCDE17F617724E5D00EB1AC6 /* ConfigPathDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ConfigPathDialog.cxx; path = ../gui/ConfigPathDialog.cxx; sourceTree = SOURCE_ROOT; }; DCDE17F617724E5D00EB1AC6 /* ConfigPathDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ConfigPathDialog.cxx; path = ../gui/ConfigPathDialog.cxx; sourceTree = SOURCE_ROOT; };
DCDE17F717724E5D00EB1AC6 /* ConfigPathDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ConfigPathDialog.hxx; path = ../gui/ConfigPathDialog.hxx; sourceTree = SOURCE_ROOT; }; DCDE17F717724E5D00EB1AC6 /* ConfigPathDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ConfigPathDialog.hxx; path = ../gui/ConfigPathDialog.hxx; sourceTree = SOURCE_ROOT; };
DCDE17F817724E5D00EB1AC6 /* SnapshotDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SnapshotDialog.cxx; path = ../gui/SnapshotDialog.cxx; sourceTree = SOURCE_ROOT; }; DCDE17F817724E5D00EB1AC6 /* SnapshotDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SnapshotDialog.cxx; path = ../gui/SnapshotDialog.cxx; sourceTree = SOURCE_ROOT; };