added command line options to include (coarse) ARM cycles into system cycles

This commit is contained in:
Thomas Jentzsch 2021-06-13 12:18:44 +02:00
parent c02fc531aa
commit 0c511805c7
10 changed files with 99 additions and 15 deletions

View File

@ -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.</td>
</tr><tr>
<td><pre>-dev.thumb.incycles &lt;1|0&gt;</pre></td>
<td>When enabled, ARM emulation cycles are added to system cycles. This
allows detecting timer overruns.</br>
Note: The ARM emulation cycles are only a coarse approximation.
</td>
</tr><tr>
<td><pre>-dev.thumb.cyclefactor &lt;float&gt;</pre></td>
<td>Adjust ARM emulation cycles by a factor (1.25 = default).
</td>
</tr><tr>
<td><pre>-&lt;plr.|dev.&gt;eepromaccess &lt;1|0&gt;</pre></td>
<td>When enabled, each read or write access to the AtariVox/SaveKey EEPROM is

View File

@ -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())

View File

@ -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;

View File

@ -108,9 +108,12 @@ CartridgeCDF::CartridgeCDF(const ByteBuffer& image, size_t size,
static_cast<uInt32>(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())

View File

@ -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;

View File

@ -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())

View File

@ -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;

View File

@ -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 <standard|custom| Selects a TIA type\n"

View File

@ -52,10 +52,13 @@ using Common::Base;
#define CONV_RAMROM(d) (d)
#endif
#define CYCLE_FACTOR 1.25 // coarse ARM cycle multiplier
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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)
: rom{rom_ptr},
romSize{rom_size},
@ -73,12 +76,15 @@ Thumbulator::Thumbulator(const uInt16* rom_ptr, uInt16* ram_ptr, uInt32 rom_size
setConsoleTiming(ConsoleTiming::ntsc);
#ifndef UNSAFE_OPTIMIZATIONS
trapFatalErrors(traponfatal);
#endif
#ifndef NO_THUMB_STATS
cycleFactor(cyclefactor);
#endif
reset();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string Thumbulator::run()
string Thumbulator::doRun(uInt32& cycles)
{
reset();
for(;;)
@ -89,6 +95,11 @@ string Thumbulator::run()
throw runtime_error("instructions > 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

View File

@ -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;