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.
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
'cursor'. The new argument allows to set mouse cursor visibility
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)
{
// 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' };
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
case 0x00:
myFractionalCounters[index] = (myFractionalCounters[index] & 0x0F0000) | ((uInt16)value << 8);
myFractionalCounters[index] = (myFractionalCounters[index] & 0x0F00FF) | ((uInt16)value << 8);
break;
// DFxFRACHI - fractional data pointer high byte

View File

@ -57,8 +57,10 @@ TIA::TIA(Console& console, Sound& sound, Settings& settings)
myFrameCounter(0),
myPALFrameCounter(0),
myBitsEnabled(true),
myCollisionsEnabled(true)
myCollisionsEnabled(true),
myNextFrameJitter(0),
myCurrentFrameJitter(0)
{
// Allocate buffers for two frame buffers
myCurrentFrameBuffer = new uInt8[160 * 320];
@ -141,6 +143,7 @@ void TIA::reset()
myFrameCounter = myPALFrameCounter = 0;
myScanlineCountForLastFrame = 0;
myNextFrameJitter = myCurrentFrameJitter = 0;
myP0Mask = &TIATables::PxMask[0][0][0];
myP1Mask = &TIATables::PxMask[0][0][0];
@ -653,6 +656,39 @@ inline void TIA::endFrame()
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'
if(myAutoFrameEnabled)
{

View File

@ -175,7 +175,7 @@ class TIA : public Device
@return Pointer to the current frame buffer
*/
uInt8* currentFrameBuffer() const
{ return myCurrentFrameBuffer + myFramePointerOffset; }
{ return myCurrentFrameBuffer + myFramePointerOffset + myCurrentFrameJitter; }
/**
Answers the previous frame buffer
@ -615,7 +615,14 @@ class TIA : public Device
// Whether TIA bits/collisions are currently enabled/disabled
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:
// Following constructors and assignment operators not supported
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; };
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>"; };
DCDAF4D818CA9AAB00D3865D /* 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 = "<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 = "<absolute>"; };
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; };
DCDE17F817724E5D00EB1AC6 /* SnapshotDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SnapshotDialog.cxx; path = ../gui/SnapshotDialog.cxx; sourceTree = SOURCE_ROOT; };