From 0c511805c79bcc04a55f85bdbf2a6303babdd956 Mon Sep 17 00:00:00 2001 From: Thomas Jentzsch Date: Sun, 13 Jun 2021 12:18:44 +0200 Subject: [PATCH] added command line options to include (coarse) ARM cycles into system cycles --- docs/index.html | 10 +++++++++ src/emucore/CartBUS.cxx | 9 ++++++-- src/emucore/CartBUS.hxx | 3 +++ src/emucore/CartCDF.cxx | 9 ++++++-- src/emucore/CartCDF.hxx | 3 +++ src/emucore/CartDPCPlus.cxx | 9 ++++++-- src/emucore/CartDPCPlus.hxx | 3 +++ src/emucore/Settings.cxx | 8 ++++++-- src/emucore/Thumbulator.cxx | 41 +++++++++++++++++++++++++++++++++---- src/emucore/Thumbulator.hxx | 19 ++++++++++++++--- 10 files changed, 99 insertions(+), 15 deletions(-) diff --git a/docs/index.html b/docs/index.html index 3a0f1f7c3..932adb4c0 100644 --- a/docs/index.html +++ b/docs/index.html @@ -3541,6 +3541,16 @@ fatal errors are simply logged, and emulation continues. Do not use this unless you know exactly what you're doing, as it changes the behaviour as compared to real hardware. + +
-dev.thumb.incycles <1|0>
+ When enabled, ARM emulation cycles are added to system cycles. This + allows detecting timer overruns.
+ Note: The ARM emulation cycles are only a coarse approximation. + + +
-dev.thumb.cyclefactor <float>
+ Adjust ARM emulation cycles by a factor (1.25 = default). +
-<plr.|dev.>eepromaccess <1|0>
When enabled, each read or write access to the AtariVox/SaveKey EEPROM is diff --git a/src/emucore/CartBUS.cxx b/src/emucore/CartBUS.cxx index 960b05bff..b236b0c14 100644 --- a/src/emucore/CartBUS.cxx +++ b/src/emucore/CartBUS.cxx @@ -72,9 +72,12 @@ CartridgeBUS::CartridgeBUS(const ByteBuffer& image, size_t size, 0x00000808, 0x40001FDC, devSettings ? settings.getBool("dev.thumb.trapfatal") : false, + devSettings ? settings.getFloat("dev.thumb.cyclefactor") : 1.0, Thumbulator::ConfigureFor::BUS, this); + myIncCycles = devSettings ? settings.getBool("dev.thumb.inccycles") : false, + setInitialState(); } @@ -167,10 +170,12 @@ inline void CartridgeBUS::callFunction(uInt8 value) // time for Stella as ARM code "runs in zero 6507 cycles". case 255: // call without IRQ driven audio try { - Int32 cycles = Int32(mySystem->cycles() - myARMCycles); - myARMCycles = mySystem->cycles(); + uInt32 cycles = uInt32(mySystem->cycles() - myARMCycles); + myARMCycles = mySystem->cycles(); myThumbEmulator->run(cycles); + if(myIncCycles) + mySystem->incrementCycles(cycles); } catch(const runtime_error& e) { if(!mySystem->autodetectMode()) diff --git a/src/emucore/CartBUS.hxx b/src/emucore/CartBUS.hxx index 585d977dc..3ce835d55 100644 --- a/src/emucore/CartBUS.hxx +++ b/src/emucore/CartBUS.hxx @@ -299,6 +299,9 @@ class CartridgeBUS : public Cartridge uInt8 myFastJumpActive{false}; + // ARM code increases 6507 cycles + bool myIncCycles{false}; + private: // Following constructors and assignment operators not supported CartridgeBUS() = delete; diff --git a/src/emucore/CartCDF.cxx b/src/emucore/CartCDF.cxx index 56a48164d..3a97368af 100644 --- a/src/emucore/CartCDF.cxx +++ b/src/emucore/CartCDF.cxx @@ -108,9 +108,12 @@ CartridgeCDF::CartridgeCDF(const ByteBuffer& image, size_t size, static_cast(mySize), cBase, cStart, cStack, devSettings ? settings.getBool("dev.thumb.trapfatal") : false, + devSettings ? settings.getFloat("dev.thumb.cyclefactor") : 1.0, thumulatorConfiguration(myCDFSubtype), this); + myIncCycles = devSettings ? settings.getBool("dev.thumb.inccycles") : false, + setInitialState(); } @@ -195,10 +198,12 @@ inline void CartridgeCDF::callFunction(uInt8 value) // time for Stella as ARM code "runs in zero 6507 cycles". case 255: // call without IRQ driven audio try { - Int32 cycles = Int32(mySystem->cycles() - myARMCycles); - myARMCycles = mySystem->cycles(); + uInt32 cycles = uInt32(mySystem->cycles() - myARMCycles); + myARMCycles = mySystem->cycles(); myThumbEmulator->run(cycles); + if(myIncCycles) + mySystem->incrementCycles(cycles); // * ~1.79 is the limit for ZEVIOUZ title screen } catch(const runtime_error& e) { if(!mySystem->autodetectMode()) diff --git a/src/emucore/CartCDF.hxx b/src/emucore/CartCDF.hxx index 2510ecf66..9d51d73d4 100644 --- a/src/emucore/CartCDF.hxx +++ b/src/emucore/CartCDF.hxx @@ -369,6 +369,9 @@ class CartridgeCDF : public Cartridge // CDF subtype CDFSubtype myCDFSubtype{CDFSubtype::CDF0}; + // ARM code increases 6507 cycles + bool myIncCycles{false}; + private: // Following constructors and assignment operators not supported CartridgeCDF() = delete; diff --git a/src/emucore/CartDPCPlus.cxx b/src/emucore/CartDPCPlus.cxx index 19ed1c808..4f801cece 100644 --- a/src/emucore/CartDPCPlus.cxx +++ b/src/emucore/CartDPCPlus.cxx @@ -58,6 +58,7 @@ CartridgeDPCPlus::CartridgeDPCPlus(const ByteBuffer& image, size_t size, 0x00000C08, 0x40001FDC, devSettings ? settings.getBool("dev.thumb.trapfatal") : false, + devSettings ? settings.getFloat("dev.thumb.cyclefactor") : 1.0, Thumbulator::ConfigureFor::DPCplus, this); @@ -77,6 +78,8 @@ CartridgeDPCPlus::CartridgeDPCPlus(const ByteBuffer& image, size_t size, myDriverMD5 == "8dd73b44fd11c488326ce507cbeb19d1" ) myFractionalLowMask = 0x0F0000; + myIncCycles = devSettings ? settings.getBool("dev.thumb.inccycles") : false, + setInitialState(); } @@ -200,10 +203,12 @@ inline void CartridgeDPCPlus::callFunction(uInt8 value) // time for Stella as ARM code "runs in zero 6507 cycles". case 255: // call without IRQ driven audio try { - Int32 cycles = Int32(mySystem->cycles() - myARMCycles); - myARMCycles = mySystem->cycles(); + uInt32 cycles = uInt32(mySystem->cycles() - myARMCycles); + myARMCycles = mySystem->cycles(); myThumbEmulator->run(cycles); + if(myIncCycles) + mySystem->incrementCycles(cycles); } catch(const runtime_error& e) { if(!mySystem->autodetectMode()) diff --git a/src/emucore/CartDPCPlus.hxx b/src/emucore/CartDPCPlus.hxx index c87ca79f1..caf86342c 100644 --- a/src/emucore/CartDPCPlus.hxx +++ b/src/emucore/CartDPCPlus.hxx @@ -312,6 +312,9 @@ class CartridgeDPCPlus : public Cartridge // For current versions, this is 0x0F00FF; older versions need 0x0F0000 uInt32 myFractionalLowMask{0x0F00FF}; + // ARM code increases 6507 cycles + bool myIncCycles{false}; + private: // Following constructors and assignment operators not supported CartridgeDPCPlus() = delete; diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index 9f0cc5055..38bef3d5a 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -242,10 +242,12 @@ Settings::Settings() setPermanent("dev.tm.uncompressed", 600); setPermanent("dev.tm.interval", "1f"); // = 1 frame setPermanent("dev.tm.horizon", "30s"); // = ~30 seconds - // Thumb ARM emulation options - setPermanent("dev.thumb.trapfatal", "true"); setPermanent("dev.detectedinfo", "true"); setPermanent("dev.eepromaccess", "true"); + // Thumb ARM emulation options + setPermanent("dev.thumb.trapfatal", "true"); + setPermanent("dev.thumb.inccycles", "true"); + setPermanent("dev.thumb.cyclefactor", "1.25"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -683,6 +685,8 @@ void Settings::usage() const #endif << " -dev.thumb.trapfatal <1|0> Determines whether errors in ARM emulation\n" << " throw an exception\n" + << " -dev.thumb.inccycles <1|0> Determines whether ARM emulation cycles\n" + << " increase system cycles\n" << " -dev.eepromaccess <1|0> Enable messages for AtariVox/SaveKey access\n" << " messages\n" << " -dev.tia.type 500000"); #endif } +#ifndef NO_THUMB_STATS + cycles = uInt32((_stats.fetches + _stats.reads + _stats.writes) * arm_cycle_factor / timing_factor); +#else + cycles = 0; +#endif #if defined(THUMB_DISS) || defined(THUMB_DBUG) dump_counters(); cout << statusMsg.str() << endl; @@ -119,15 +130,19 @@ void Thumbulator::setConsoleTiming(ConsoleTiming timing) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Thumbulator::updateTimer(uInt32 cycles) { +#ifdef TIMER_0 + if(T0TCR & 1) // bit 0 controls timer on/off + T0TC += uInt32(cycles * timing_factor); +#endif if (T1TCR & 1) // bit 0 controls timer on/off T1TC += uInt32(cycles * timing_factor); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string Thumbulator::run(uInt32 cycles) +string Thumbulator::run(uInt32& cycles) { updateTimer(cycles); - return run(); + return doRun(cycles); } #ifndef UNSAFE_OPTIMIZATIONS @@ -289,7 +304,15 @@ void Thumbulator::write32(uInt32 addr, uInt32 data) DO_DISS(statusMsg << "uart: [" << char(data&0xFF) << "]" << endl); break; #endif +#ifdef TIMER_0 + case 0xE0004004: // T0TCR - Timer 0 Control Register + T0TCR = data; + break; + case 0xE0004008: // T0TC - Timer 0 Counter + T0TC = data; + break; +#endif case 0xE0008004: // T1TCR - Timer 1 Control Register T1TCR = data; break; @@ -467,6 +490,15 @@ uInt32 Thumbulator::read32(uInt32 addr) { switch(addr) { + #ifdef TIMER_0 + case 0xE0004004: // T0TCR - Timer 0 Control Register + data = T0TCR; + return data; + + case 0xE0004008: // T0TC - Timer 0 Counter + data = T0TC; + break; + #endif case 0xE0008004: // T1TCR - Timer 1 Control Register data = T1TCR; return data; @@ -2560,4 +2592,5 @@ int Thumbulator::reset() #ifndef UNSAFE_OPTIMIZATIONS // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Thumbulator::trapOnFatal = true; +double Thumbulator::arm_cycle_factor = 1.25; #endif diff --git a/src/emucore/Thumbulator.hxx b/src/emucore/Thumbulator.hxx index bb7640677..e7a82923f 100644 --- a/src/emucore/Thumbulator.hxx +++ b/src/emucore/Thumbulator.hxx @@ -46,6 +46,8 @@ class Cartridge; #define CPSR_C (1u<<29) #define CPSR_V (1u<<28) +//#define TIMER_0 // enable timer 0 support + class Thumbulator { public: @@ -68,7 +70,8 @@ class Thumbulator Thumbulator(const uInt16* rom_ptr, uInt16* ram_ptr, uInt32 rom_size, const uInt32 c_base, const uInt32 c_start, const uInt32 c_stack, - bool traponfatal, Thumbulator::ConfigureFor configurefor, + bool traponfatal, double cyclefactor, + Thumbulator::ConfigureFor configurefor, Cartridge* cartridge); /** @@ -79,8 +82,8 @@ class Thumbulator @return The results of any debugging output (if enabled), otherwise an empty string */ - string run(); - string run(uInt32 cycles); + string doRun(uInt32& cycles); + string run(uInt32& cycles); const Stats& stats() const { return _stats; } const Stats& prevStats() const { return _prevStats; } @@ -99,6 +102,9 @@ class Thumbulator */ static void trapFatalErrors(bool enable) { trapOnFatal = enable; } #endif +#ifndef NO_THUMB_STATS + static void cycleFactor(double factor) { arm_cycle_factor = factor; } +#endif /** Inform the Thumbulator class about the console currently in use, @@ -215,6 +221,10 @@ class Thumbulator // For emulation of LPC2103's timer 1, used for NTSC/PAL/SECAM detection. // Register names from documentation: // http://www.nxp.com/documents/user_manual/UM10161.pdf + #ifdef TIMER_0 + uInt32 T0TCR{0}; // Timer 0 Timer Control Register + uInt32 T0TC{0}; // Timer 0 Timer Counter + #endif uInt32 T1TCR{0}; // Timer 1 Timer Control Register uInt32 T1TC{0}; // Timer 1 Timer Counter double timing_factor{0.0}; @@ -224,6 +234,9 @@ class Thumbulator static bool trapOnFatal; #endif +#ifndef NO_THUMB_STATS + static double arm_cycle_factor; +#endif ConfigureFor configuration;