diff --git a/src/emucore/QuadTari.cxx b/src/emucore/QuadTari.cxx index ca7d3b81f..e249c7f14 100644 --- a/src/emucore/QuadTari.cxx +++ b/src/emucore/QuadTari.cxx @@ -61,8 +61,17 @@ bool QuadTari::read(DigitalPin pin) // can switch the controller multiple times per frame // (we can't just read 60 times per second in the ::update() method) - // If bit 7 of VBlank is not set, read first, else second controller - if(!(mySystem.tia().registerValue(VBLANK) & 0x80)) + constexpr int MIN_CYCLES = 30 * 76; // minimal cycles required for stable input switch (TODO: define cycles) + bool readFirst; + + if(mySystem.tia().dumpPortsCycles() < MIN_CYCLES) + // Random controller if read too soon after dump ports changed + readFirst = mySystem.randGenerator().next() % 2; + else + // If bit 7 of VBlank is not set, read first, else second controller + readFirst = !(mySystem.tia().registerValue(VBLANK) & 0x80); + + if(readFirst) return myFirstController->read(pin); else return mySecondController->read(pin); diff --git a/src/emucore/tia/TIA.cxx b/src/emucore/tia/TIA.cxx index 7e4cdbf04..78a44fc55 100644 --- a/src/emucore/tia/TIA.cxx +++ b/src/emucore/tia/TIA.cxx @@ -523,6 +523,7 @@ bool TIA::poke(uInt16 address, uInt8 value) for (PaddleReader& paddleReader : myPaddleReaders) paddleReader.vblank(value, myTimestamp); + updateDumpPorts(value); myDelayQueue.push(VBLANK, value, Delay::vblank); @@ -1981,6 +1982,24 @@ void TIA::toggleCollBLPF() myCollisionMask ^= (CollisionMask::ball & CollisionMask::playfield); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIA::updateDumpPorts(uInt8 value) +{ + bool newIsDumped = value & 0x80; + + if(myArePortsDumped != newIsDumped) + { + myArePortsDumped = newIsDumped; + myDumpPortsTimestamp = myTimestamp; + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Int64 TIA::dumpPortsCycles() +{ + return (myTimestamp - myDumpPortsTimestamp) / 3; +} + #ifdef DEBUGGER_SUPPORT // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::createAccessArrays() diff --git a/src/emucore/tia/TIA.hxx b/src/emucore/tia/TIA.hxx index ada06a042..18609f087 100644 --- a/src/emucore/tia/TIA.hxx +++ b/src/emucore/tia/TIA.hxx @@ -334,6 +334,13 @@ class TIA : public Device return uInt32(mySystem->cycles() - myCyclesAtFrameStart); } + /** + * Get the CPU cycles since the last dump ports change. + * + * @return The number of CPU cycles since the last dump ports change + */ + Int64 dumpPortsCycles(); + /** Answers whether the TIA is currently in being rendered (we're in between the start and end of drawing a frame). @@ -695,6 +702,13 @@ class TIA : public Device */ void applyDeveloperSettings(); + /** + * Updates the dump ports state with the time of change. + * + * @param value The value to be stored at VBLANK + */ + void updateDumpPorts(uInt8 value); + #ifdef DEBUGGER_SUPPORT void createAccessArrays(); @@ -894,6 +908,16 @@ class TIA : public Device */ uInt64 myTimestamp{0}; + /** + * The number of CPU clocks since the last dump ports state change. + */ + uInt64 myDumpPortsTimestamp{0}; + + /** + * The current dump ports state. + */ + bool myArePortsDumped{false}; + /** * The "shadow registers" track the last written register value for the * debugger.