diff --git a/src/emucore/CartARM.cxx b/src/emucore/CartARM.cxx index 99b587e98..4459bdc29 100644 --- a/src/emucore/CartARM.cxx +++ b/src/emucore/CartARM.cxx @@ -43,6 +43,24 @@ void CartridgeARM::setInitialState() enableCycleCount(devSettings); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void CartridgeARM::consoleChanged(ConsoleTiming timing) +{ + myThumbEmulator->setConsoleTiming(timing); + + constexpr double NTSC = 1193191.66666667; // NTSC 6507 clock rate + constexpr double PAL = 1182298; // PAL 6507 clock rate + constexpr double SECAM = 1187500; // SECAM 6507 clock rate + + switch(timing) + { + case ConsoleTiming::ntsc: myClockRate = NTSC; break; + case ConsoleTiming::pal: myClockRate = PAL; break; + case ConsoleTiming::secam: myClockRate = SECAM; break; + default: break; // satisfy compiler + } +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeARM::updateCycles(int cycles) { diff --git a/src/emucore/CartARM.hxx b/src/emucore/CartARM.hxx index bc7bb145e..5b176803c 100644 --- a/src/emucore/CartARM.hxx +++ b/src/emucore/CartARM.hxx @@ -35,6 +35,15 @@ class CartridgeARM : public Cartridge ~CartridgeARM() override = default; protected: + /** + Notification method invoked by the system when the console type + has changed. We need this to inform the Thumbulator that the + timing has changed. + + @param timing Enum representing the new console type + */ + void consoleChanged(ConsoleTiming timing) override; + /** Save the current state of this cart to the given Serializer. @@ -69,7 +78,7 @@ class CartridgeARM : public Cartridge void incCycles(bool enable); void cycleFactor(double factor); double cycleFactor() const { return myThumbEmulator->cycleFactor(); } - void setChipType(Thumbulator::ChipType armType) { myThumbEmulator->setChipType(armType); } + void setChipType(Thumbulator::ChipType chipType) { myThumbEmulator->setChipType(chipType); } void lockMamMode(bool lock) { myThumbEmulator->lockMamMode(lock); } void setMamMode(Thumbulator::MamModeType mamMode) { myThumbEmulator->setMamMode(mamMode); } Thumbulator::MamModeType mamMode() const { return myThumbEmulator->mamMode(); } @@ -80,6 +89,9 @@ class CartridgeARM : public Cartridge // ARM code increases 6507 cycles bool myIncCycles{false}; + + // Console clock rate + double myClockRate{1193191.66666667}; #ifdef DEBUGGER_SUPPORT Thumbulator::Stats myStats{0}; Thumbulator::Stats myPrevStats{0}; diff --git a/src/emucore/CartBUS.cxx b/src/emucore/CartBUS.cxx index 29a030e31..469264ccf 100644 --- a/src/emucore/CartBUS.cxx +++ b/src/emucore/CartBUS.cxx @@ -116,12 +116,6 @@ void CartridgeBUS::setInitialState() CartridgeARM::setInitialState(); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeBUS::consoleChanged(ConsoleTiming timing) -{ - myThumbEmulator->setConsoleTiming(timing); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBUS::install(System& system) { @@ -149,7 +143,7 @@ inline void CartridgeBUS::updateMusicModeDataFetchers() myAudioCycles = mySystem->cycles(); // Calculate the number of BUS OSC clocks since the last update - double clocks = ((20000.0 * cycles) / 1193191.66666667) + myFractionalClocks; + double clocks = ((20000.0 * cycles) / myClockRate) + myFractionalClocks; uInt32 wholeClocks = uInt32(clocks); myFractionalClocks = clocks - double(wholeClocks); @@ -172,7 +166,7 @@ inline void CartridgeBUS::callFunction(uInt8 value) uInt32 cycles = uInt32(mySystem->cycles() - myARMCycles); myARMCycles = mySystem->cycles(); - myThumbEmulator->run(cycles); + myThumbEmulator->run(cycles, value == 254); updateCycles(cycles); } catch(const runtime_error& e) { diff --git a/src/emucore/CartBUS.hxx b/src/emucore/CartBUS.hxx index 5cd26de3f..a6e00acab 100644 --- a/src/emucore/CartBUS.hxx +++ b/src/emucore/CartBUS.hxx @@ -64,15 +64,6 @@ class CartridgeBUS : public CartridgeARM */ void reset() override; - /** - Notification method invoked by the system when the console type - has changed. We need this to inform the Thumbulator that the - timing has changed. - - @param timing Enum representing the new console type - */ - void consoleChanged(ConsoleTiming timing) override; - /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. diff --git a/src/emucore/CartCDF.cxx b/src/emucore/CartCDF.cxx index fba117d9d..d93a3437f 100644 --- a/src/emucore/CartCDF.cxx +++ b/src/emucore/CartCDF.cxx @@ -149,12 +149,6 @@ void CartridgeCDF::setInitialState() CartridgeARM::setInitialState(); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeCDF::consoleChanged(ConsoleTiming timing) -{ - myThumbEmulator->setConsoleTiming(timing); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCDF::install(System& system) { @@ -177,7 +171,7 @@ inline void CartridgeCDF::updateMusicModeDataFetchers() myAudioCycles = mySystem->cycles(); // Calculate the number of CDF OSC clocks since the last update - double clocks = ((20000.0 * cycles) / 1193191.66666667) + myFractionalClocks; + double clocks = ((20000.0 * cycles) / myClockRate) + myFractionalClocks; uInt32 wholeClocks = uInt32(clocks); myFractionalClocks = clocks - double(wholeClocks); @@ -200,7 +194,7 @@ inline void CartridgeCDF::callFunction(uInt8 value) uInt32 cycles = uInt32(mySystem->cycles() - myARMCycles); myARMCycles = mySystem->cycles(); - myThumbEmulator->run(cycles); + myThumbEmulator->run(cycles, value == 254); updateCycles(cycles); } catch(const runtime_error& e) { diff --git a/src/emucore/CartCDF.hxx b/src/emucore/CartCDF.hxx index b5184c9a9..621873e9f 100644 --- a/src/emucore/CartCDF.hxx +++ b/src/emucore/CartCDF.hxx @@ -85,15 +85,6 @@ class CartridgeCDF : public CartridgeARM */ void reset() override; - /** - Notification method invoked by the system when the console type - has changed. We need this to inform the Thumbulator that the - timing has changed. - - @param timing Enum representing the new console type - */ - void consoleChanged(ConsoleTiming timing) override; - /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. diff --git a/src/emucore/CartCTY.cxx b/src/emucore/CartCTY.cxx index 94bf5b87f..61960ebf3 100644 --- a/src/emucore/CartCTY.cxx +++ b/src/emucore/CartCTY.cxx @@ -64,6 +64,22 @@ void CartridgeCTY::reset() bank(startBank()); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void CartridgeCTY::consoleChanged(ConsoleTiming timing) +{ + constexpr double NTSC = 1193191.66666667; // NTSC 6507 clock rate + constexpr double PAL = 1182298.0; // PAL 6507 clock rate + constexpr double SECAM = 1187500.0; // SECAM 6507 clock rate + + switch(timing) + { + case ConsoleTiming::ntsc: myClockRate = NTSC; break; + case ConsoleTiming::pal: myClockRate = PAL; break; + case ConsoleTiming::secam: myClockRate = SECAM; break; + default: break; // satisfy compiler + } +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCTY::install(System& system) { @@ -573,7 +589,7 @@ inline void CartridgeCTY::updateMusicModeDataFetchers() myAudioCycles = mySystem->cycles(); // Calculate the number of CTY OSC clocks since the last update - double clocks = ((20000.0 * cycles) / 1193191.66666667) + myFractionalClocks; + double clocks = ((20000.0 * cycles) / myClockRate) + myFractionalClocks; uInt32 wholeClocks = uInt32(clocks); myFractionalClocks = clocks - double(wholeClocks); diff --git a/src/emucore/CartCTY.hxx b/src/emucore/CartCTY.hxx index c13c93000..68cfeda66 100644 --- a/src/emucore/CartCTY.hxx +++ b/src/emucore/CartCTY.hxx @@ -128,6 +128,15 @@ class CartridgeCTY : public Cartridge */ void reset() override; + /** + Notification method invoked by the system when the console type + has changed. We need this to inform the Thumbulator that the + timing has changed. + + @param timing Enum representing the new console type + */ + void consoleChanged(ConsoleTiming timing) override; + /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @@ -271,6 +280,9 @@ class CartridgeCTY : public Cartridge // The 64 bytes of RAM accessible at $1000 - $1080 std::array myRAM; + // Console clock rate + double myClockRate{1193191.66666667}; + // Operation type (written to $1000, used by hotspot $1FF4) uInt8 myOperationType{0}; diff --git a/src/emucore/CartDPC.cxx b/src/emucore/CartDPC.cxx index 066b30b56..267c086f7 100644 --- a/src/emucore/CartDPC.cxx +++ b/src/emucore/CartDPC.cxx @@ -38,6 +38,22 @@ void CartridgeDPC::reset() myDpcPitch = mySettings.getInt(AudioSettings::SETTING_DPC_PITCH); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void CartridgeDPC::consoleChanged(ConsoleTiming timing) +{ + constexpr double NTSC = 1193191.66666667; // NTSC 6507 clock rate + constexpr double PAL = 1182298.0; // PAL 6507 clock rate + constexpr double SECAM = 1187500.0; // SECAM 6507 clock rate + + switch(timing) + { + case ConsoleTiming::ntsc: myClockRate = NTSC; break; + case ConsoleTiming::pal: myClockRate = PAL; break; + case ConsoleTiming::secam: myClockRate = SECAM; break; + default: break; // satisfy compiler + } +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDPC::install(System& system) { @@ -82,7 +98,7 @@ inline void CartridgeDPC::updateMusicModeDataFetchers() myAudioCycles = mySystem->cycles(); // Calculate the number of DPC OSC clocks since the last update - double clocks = ((myDpcPitch * cycles) / 1193191.66666667) + myFractionalClocks; + double clocks = ((myDpcPitch * cycles) / myClockRate) + myFractionalClocks; uInt32 wholeClocks = uInt32(clocks); myFractionalClocks = clocks - double(wholeClocks); diff --git a/src/emucore/CartDPC.hxx b/src/emucore/CartDPC.hxx index 19c4d79a7..0dd351f88 100644 --- a/src/emucore/CartDPC.hxx +++ b/src/emucore/CartDPC.hxx @@ -53,18 +53,28 @@ class CartridgeDPC : public CartridgeF8 ~CartridgeDPC() override = default; public: + /** + Reset device to its power-on state + */ + void reset() override; + + /** + Notification method invoked by the system when the console type + has changed. We need this to inform the Thumbulator that the + timing has changed. + + @param timing Enum representing the new console type + */ + + void consoleChanged(ConsoleTiming timing) 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; - /** - Reset device to its power-on state - */ - void reset() override; + void install(System& system) override; /** Patch the cartridge ROM. @@ -147,6 +157,9 @@ class CartridgeDPC : public CartridgeF8 void updateMusicModeDataFetchers(); private: + // Console clock rate + double myClockRate{1193191.66666667}; + // Pointer to the 2K display ROM image of the cartridge uInt8* myDisplayImage{nullptr}; diff --git a/src/emucore/CartDPCPlus.cxx b/src/emucore/CartDPCPlus.cxx index cf29d2ef0..d214c06e7 100644 --- a/src/emucore/CartDPCPlus.cxx +++ b/src/emucore/CartDPCPlus.cxx @@ -122,12 +122,6 @@ void CartridgeDPCPlus::setInitialState() CartridgeARM::setInitialState(); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeDPCPlus::consoleChanged(ConsoleTiming timing) -{ - myThumbEmulator->setConsoleTiming(timing); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDPCPlus::install(System& system) { @@ -167,7 +161,7 @@ inline void CartridgeDPCPlus::updateMusicModeDataFetchers() myAudioCycles = mySystem->cycles(); // Calculate the number of DPC+ OSC clocks since the last update - double clocks = ((20000.0 * cycles) / 1193191.66666667) + myFractionalClocks; + double clocks = ((20000.0 * cycles) / myClockRate) + myFractionalClocks; uInt32 wholeClocks = uInt32(clocks); myFractionalClocks = clocks - double(wholeClocks); @@ -205,7 +199,7 @@ inline void CartridgeDPCPlus::callFunction(uInt8 value) uInt32 cycles = uInt32(mySystem->cycles() - myARMCycles); myARMCycles = mySystem->cycles(); - myThumbEmulator->run(cycles); + myThumbEmulator->run(cycles, value == 254); updateCycles(cycles); } catch(const runtime_error& e) { diff --git a/src/emucore/CartDPCPlus.hxx b/src/emucore/CartDPCPlus.hxx index cd1d2f710..a52ba8338 100644 --- a/src/emucore/CartDPCPlus.hxx +++ b/src/emucore/CartDPCPlus.hxx @@ -65,15 +65,6 @@ class CartridgeDPCPlus : public CartridgeARM */ void reset() override; - /** - Notification method invoked by the system when the console type - has changed. We need this to inform the Thumbulator that the - timing has changed. - - @param timing Enum representing the new console type - */ - void consoleChanged(ConsoleTiming timing) override; - /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. diff --git a/src/emucore/Thumbulator.cxx b/src/emucore/Thumbulator.cxx index 63fca51b9..b9d618902 100644 --- a/src/emucore/Thumbulator.cxx +++ b/src/emucore/Thumbulator.cxx @@ -105,8 +105,9 @@ Thumbulator::Thumbulator(const uInt16* rom_ptr, uInt16* ram_ptr, uInt32 rom_size } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string Thumbulator::doRun(uInt32& cycles) +string Thumbulator::doRun(uInt32& cycles, bool irqDrivenAudio) { + _irqDrivenAudio = irqDrivenAudio; reset(); for(;;) { @@ -118,6 +119,12 @@ string Thumbulator::doRun(uInt32& cycles) } #ifdef THUMB_CYCLE_COUNT _totalCycles *= _armCyclesFactor; + + // assuming 10% per scanline is spend for audio updates + // (equals 5 cycles 6507 code + ~130-155 cycles ARM code) + if(_irqDrivenAudio) + _totalCycles *= 1.10; + //_totalCycles = 127148; // VB during Turbo start sequence cycles = _totalCycles / timing_factor; #else @@ -137,9 +144,9 @@ void Thumbulator::setConsoleTiming(ConsoleTiming timing) { // this sets how many ticks of the Harmony/Melody clock // will occur per tick of the 6507 clock - constexpr double NTSC = 1.193182; // NTSC 6507 clock rate - constexpr double PAL = 1.182298; // PAL 6507 clock rate - constexpr double SECAM = 1.187500; // SECAM 6507 clock rate + constexpr double NTSC = 1.19318166666667; // NTSC 6507 clock rate + constexpr double PAL = 1.182298; // PAL 6507 clock rate + constexpr double SECAM = 1.187500; // SECAM 6507 clock rate _consoleTiming = timing; switch(timing) @@ -169,10 +176,10 @@ void Thumbulator::updateTimer(uInt32 cycles) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string Thumbulator::run(uInt32& cycles) +string Thumbulator::run(uInt32& cycles, bool irqDrivenAudio) { updateTimer(cycles); - return doRun(cycles); + return doRun(cycles, irqDrivenAudio); } #ifndef UNSAFE_OPTIMIZATIONS @@ -1595,6 +1602,7 @@ int Thumbulator::execute() rc += 2; //rc &= ~1; write_register(15, rc); + //_totalCycles += 100; // just a wild guess return 0; } return 1; diff --git a/src/emucore/Thumbulator.hxx b/src/emucore/Thumbulator.hxx index 80e29c152..99a1fb926 100644 --- a/src/emucore/Thumbulator.hxx +++ b/src/emucore/Thumbulator.hxx @@ -104,8 +104,7 @@ class Thumbulator @return The results of any debugging output (if enabled), otherwise an empty string */ - string doRun(uInt32& cycles); - string run(uInt32& cycles); + string run(uInt32& cycles, bool irqDrivenAudio); void enableCycleCount(bool enable) { _countCycles = enable; } const Stats& stats() const { return _stats; } const uInt32 cycles() const { return _totalCycles; } @@ -207,6 +206,7 @@ class Thumbulator #endif private: + string doRun(uInt32& cycles, bool irqDrivenAudio); uInt32 read_register(uInt32 reg); void write_register(uInt32 reg, uInt32 data, bool isFlowBreak = true); uInt32 fetch16(uInt32 addr); @@ -268,6 +268,7 @@ class Thumbulator uInt32 _flashCycles{4}; uInt32 _flashBanks{1}; Stats _stats{0}; + bool _irqDrivenAudio{false}; uInt32 _totalCycles{0}; // For emulation of LPC2103's timer 1, used for NTSC/PAL/SECAM detection.