From f87aafb3e9cb682bb50c7e544aab4622dae4701a Mon Sep 17 00:00:00 2001 From: Thomas Jentzsch Date: Tue, 15 Jun 2021 17:31:08 +0200 Subject: [PATCH] switched ARM cycle counting to "real" cycles --- src/debugger/gui/CartARMWidget.cxx | 48 +++++------ src/debugger/gui/CartARMWidget.hxx | 4 +- src/emucore/CartARM.cxx | 5 +- src/emucore/Thumbulator.cxx | 124 +++++++++++++++++++++++++++-- src/emucore/Thumbulator.hxx | 10 ++- 5 files changed, 151 insertions(+), 40 deletions(-) diff --git a/src/debugger/gui/CartARMWidget.cxx b/src/debugger/gui/CartARMWidget.cxx index 602e02a62..2369a48c8 100644 --- a/src/debugger/gui/CartARMWidget.cxx +++ b/src/debugger/gui/CartARMWidget.cxx @@ -53,19 +53,19 @@ void CartridgeARMWidget::addCycleWidgets(int xpos, int ypos) addFocusWidget(myCycleFactor); ypos += myLineHeight + VGAP; - StaticTextWidget* s = new StaticTextWidget(_boss, _font, xpos, ypos + 1, "Mem. cycles "); + StaticTextWidget* s = new StaticTextWidget(_boss, _font, xpos, ypos + 1, "Cycles "); - myPrevThumbMemCycles = new EditTextWidget(_boss, _font, s->getRight(), ypos - 1, + myPrevThumbCycles = new EditTextWidget(_boss, _font, s->getRight(), ypos - 1, EditTextWidget::calcWidth(_font, 6), myLineHeight, ""); - myPrevThumbMemCycles->setEditable(false); - myPrevThumbMemCycles->setToolTip("Number of memory cycles of last but one ARM run."); + myPrevThumbCycles->setEditable(false); + myPrevThumbCycles->setToolTip("Number of approximated CPU cycles of last but one ARM run."); - myThumbMemCycles = new EditTextWidget(_boss, _font, myPrevThumbMemCycles->getRight() + _fontWidth / 2, ypos - 1, + myThumbCycles = new EditTextWidget(_boss, _font, myPrevThumbCycles->getRight() + _fontWidth / 2, ypos - 1, EditTextWidget::calcWidth(_font, 6), myLineHeight, ""); - myThumbMemCycles->setEditable(false); - myThumbMemCycles->setToolTip("Number of memory cycles of last ARM run."); + myThumbCycles->setEditable(false); + myThumbCycles->setToolTip("Number of approximated CPU cycles of last ARM run."); - s = new StaticTextWidget(_boss, _font, myThumbMemCycles->getRight() + _fontWidth * 2, ypos + 1, "Fetches "); + s = new StaticTextWidget(_boss, _font, myThumbCycles->getRight() + _fontWidth * 2, ypos + 1, "Fetches "); myPrevThumbFetches = new EditTextWidget(_boss, _font, s->getRight(), ypos - 1, EditTextWidget::calcWidth(_font, 6), myLineHeight, ""); myPrevThumbFetches->setEditable(false); @@ -79,12 +79,12 @@ void CartridgeARMWidget::addCycleWidgets(int xpos, int ypos) ypos += myLineHeight + VGAP; s = new StaticTextWidget(_boss, _font, xpos, ypos + 1, "Reads "); - myPrevThumbReads = new EditTextWidget(_boss, _font, myPrevThumbMemCycles->getLeft(), ypos - 1, + myPrevThumbReads = new EditTextWidget(_boss, _font, myPrevThumbCycles->getLeft(), ypos - 1, EditTextWidget::calcWidth(_font, 6), myLineHeight, ""); myPrevThumbReads->setEditable(false); myPrevThumbReads->setToolTip("Number of reads of last but one ARM run."); - myThumbReads = new EditTextWidget(_boss, _font, myThumbMemCycles->getLeft(), ypos - 1, + myThumbReads = new EditTextWidget(_boss, _font, myThumbCycles->getLeft(), ypos - 1, EditTextWidget::calcWidth(_font, 6), myLineHeight, ""); myThumbReads->setEditable(false); myThumbReads->setToolTip("Number of reads of last ARM run."); @@ -105,20 +105,18 @@ void CartridgeARMWidget::addCycleWidgets(int xpos, int ypos) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeARMWidget::saveOldState() { - myOldState.armStats.clear(); myOldState.armPrevStats.clear(); + myOldState.armStats.clear(); - myOldState.armStats.push_back(myCart.stats().fetches - + myCart.stats().reads + myCart.stats().writes); - myOldState.armStats.push_back(myCart.stats().fetches); - myOldState.armStats.push_back(myCart.stats().reads); - myOldState.armStats.push_back(myCart.stats().writes); - - myOldState.armPrevStats.push_back(myCart.prevStats().fetches - + myCart.prevStats().reads + myCart.prevStats().writes); + myOldState.armPrevStats.push_back(myCart.prevStats().cycles); myOldState.armPrevStats.push_back(myCart.prevStats().fetches); myOldState.armPrevStats.push_back(myCart.prevStats().reads); myOldState.armPrevStats.push_back(myCart.prevStats().writes); + + myOldState.armStats.push_back(myCart.stats().cycles); + myOldState.armStats.push_back(myCart.stats().fetches); + myOldState.armStats.push_back(myCart.stats().reads); + myOldState.armStats.push_back(myCart.stats().writes); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -131,10 +129,8 @@ void CartridgeARMWidget::loadConfig() bool isChanged; - isChanged = myCart.prevStats().fetches + myCart.prevStats().reads + myCart.prevStats().writes - != myOldState.armPrevStats[0]; - myPrevThumbMemCycles->setText(Common::Base::toString(myCart.prevStats().fetches - + myCart.prevStats().reads + myCart.prevStats().writes, + isChanged = myCart.prevStats().cycles != myOldState.armPrevStats[0]; + myPrevThumbCycles->setText(Common::Base::toString(myCart.prevStats().cycles, Common::Base::Fmt::_10_6), isChanged); isChanged = myCart.prevStats().fetches != myOldState.armPrevStats[1]; myPrevThumbFetches->setText(Common::Base::toString(myCart.prevStats().fetches, @@ -146,10 +142,8 @@ void CartridgeARMWidget::loadConfig() myPrevThumbWrites->setText(Common::Base::toString(myCart.prevStats().writes, Common::Base::Fmt::_10_6), isChanged); - isChanged = myCart.stats().fetches + myCart.stats().reads + myCart.stats().writes - != myOldState.armStats[0]; - myThumbMemCycles->setText(Common::Base::toString(myCart.stats().fetches - + myCart.stats().reads + myCart.stats().writes, + isChanged = myCart.stats().cycles != myOldState.armStats[0]; + myThumbCycles->setText(Common::Base::toString(myCart.stats().cycles, Common::Base::Fmt::_10_6), isChanged); isChanged = myCart.stats().fetches != myOldState.armStats[1]; myThumbFetches->setText(Common::Base::toString(myCart.stats().fetches, diff --git a/src/debugger/gui/CartARMWidget.hxx b/src/debugger/gui/CartARMWidget.hxx index e816ebff6..03a7c25a1 100644 --- a/src/debugger/gui/CartARMWidget.hxx +++ b/src/debugger/gui/CartARMWidget.hxx @@ -60,11 +60,11 @@ class CartridgeARMWidget : public CartDebugWidget CheckboxWidget* myIncCycles{nullptr}; SliderWidget* myCycleFactor{nullptr}; - EditTextWidget* myPrevThumbMemCycles{nullptr}; + EditTextWidget* myPrevThumbCycles{nullptr}; EditTextWidget* myPrevThumbFetches{nullptr}; EditTextWidget* myPrevThumbReads{nullptr}; EditTextWidget* myPrevThumbWrites{nullptr}; - EditTextWidget* myThumbMemCycles{nullptr}; + EditTextWidget* myThumbCycles{nullptr}; EditTextWidget* myThumbFetches{nullptr}; EditTextWidget* myThumbReads{nullptr}; EditTextWidget* myThumbWrites{nullptr}; diff --git a/src/emucore/CartARM.cxx b/src/emucore/CartARM.cxx index e657b724f..cd90e4cb5 100644 --- a/src/emucore/CartARM.cxx +++ b/src/emucore/CartARM.cxx @@ -31,10 +31,7 @@ CartridgeARM::CartridgeARM(const string& md5, const Settings& settings) void CartridgeARM::updateCycles(int cycles) { if(myIncCycles) - { - mySystem->incrementCycles(cycles); // * ~1.79 is the limit for ZEVIOUZ title screen (~88,000 cycles) - cerr << cycles << " "; - } + mySystem->incrementCycles(cycles); // * ~1.11 is the limit for ZEVIOUZ title screen (~142,000 cycles) myStats = myThumbEmulator->stats(); myPrevStats = myThumbEmulator->prevStats(); } diff --git a/src/emucore/Thumbulator.cxx b/src/emucore/Thumbulator.cxx index 1de50c29a..14c70bc11 100644 --- a/src/emucore/Thumbulator.cxx +++ b/src/emucore/Thumbulator.cxx @@ -96,7 +96,7 @@ string Thumbulator::doRun(uInt32& cycles) #endif } #ifndef NO_THUMB_STATS - cycles = uInt32((_stats.fetches + _stats.reads + _stats.writes) * arm_cycle_factor / timing_factor); + cycles = _stats.cycles * arm_cycle_factor / timing_factor; #else cycles = 0; #endif @@ -204,6 +204,7 @@ uInt32 Thumbulator::fetch16(uInt32 addr) { #ifndef NO_THUMB_STATS ++_stats.fetches; + ++_stats.cycles; #endif #ifndef UNSAFE_OPTIMIZATIONS @@ -562,7 +563,13 @@ void Thumbulator::write_register(uInt32 reg, uInt32 data) DO_DBUG(statusMsg << "write_register(" << dec << reg << "," << Base::HEX8 << data << ")" << endl); //#ifndef UNSAFE_OPTIMIZATIONS // this fails when combined with read_register UNSAFE_OPTIMIZATIONS - if(reg == 15) data &= ~1; + if(reg == 15) + { + data &= ~1; + #ifndef NO_THUMB_STATS + ++_stats.cycles; + #endif + } //#endif reg_norm[reg] = data; } @@ -622,7 +629,7 @@ void Thumbulator::do_vflag_bit(uInt32 x) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Thumbulator::Op Thumbulator::decodeInstructionWord(uint16_t inst) { - //ADC + //ADC add with carry if((inst & 0xFFC0) == 0x4140) return Op::adc; //ADD(1) small immediate two registers @@ -838,7 +845,7 @@ Thumbulator::Op Thumbulator::decodeInstructionWord(uint16_t inst) { //UXTB if((inst & 0xFFC0) == 0xB2C0) return Op::uxtb; - //UXTH + //UXTH Zero extend Halfword if((inst & 0xFFC0) == 0xB280) return Op::uxth; return Op::invalid; @@ -872,6 +879,9 @@ int Thumbulator::execute() decodedOp = decodedRom[(instructionPtr & ROMADDMASK) >> 1]; #endif +#ifdef COUNT_OPS + ++opCount[int(decodedOp)]; +#endif switch (decodedOp) { //ADC case Op::adc: { @@ -1028,6 +1038,9 @@ int Thumbulator::execute() //ASR(1) two register immediate case Op::asr1: { + #ifndef NO_THUMB_STATS + ++_stats.cycles; + #endif rd = (inst >> 0) & 0x07; rm = (inst >> 3) & 0x07; rb = (inst >> 6) & 0x1F; @@ -1062,6 +1075,9 @@ int Thumbulator::execute() //ASR(2) two register case Op::asr2: { + #ifndef NO_THUMB_STATS + ++_stats.cycles; + #endif rd = (inst >> 0) & 0x07; rs = (inst >> 3) & 0x07; DO_DISS(statusMsg << "asrs r" << dec << rd << ",r" << dec << rs << endl); @@ -1102,6 +1118,9 @@ int Thumbulator::execute() //B(1) conditional branch case Op::b1: { + #ifndef NO_THUMB_STATS + ++_stats.cycles; + #endif rb = (inst >> 0) & 0xFF; if(rb & 0x80) rb |= (~0U) << 8; @@ -1219,6 +1238,9 @@ int Thumbulator::execute() //B(2) unconditional branch case Op::b2: { + #ifndef NO_THUMB_STATS + ++_stats.cycles; + #endif rb = (inst >> 0) & 0x7FF; if(rb & (1 << 10)) rb |= (~0U) << 11; @@ -1255,6 +1277,9 @@ int Thumbulator::execute() //BL/BLX(1) case Op::blx1: { + #ifndef NO_THUMB_STATS + ++_stats.cycles; + #endif if((inst & 0x1800) == 0x1000) //H=b10 { DO_DISS(statusMsg << endl); @@ -1295,6 +1320,9 @@ int Thumbulator::execute() //BLX(2) case Op::blx2: { + #ifndef NO_THUMB_STATS + ++_stats.cycles; + #endif rm = (inst >> 3) & 0xF; DO_DISS(statusMsg << "blx r" << dec << rm << endl); rc = read_register(rm); @@ -1317,6 +1345,9 @@ int Thumbulator::execute() //BX case Op::bx: { + #ifndef NO_THUMB_STATS + ++_stats.cycles; + #endif rm = (inst >> 3) & 0xF; DO_DISS(statusMsg << "bx r" << dec << rm << endl); rc = read_register(rm); @@ -1648,6 +1679,9 @@ int Thumbulator::execute() //LDMIA case Op::ldmia: { + #ifndef NO_THUMB_STATS + ++_stats.cycles; + #endif rn = (inst >> 8) & 0x7; #if defined(THUMB_DISS) statusMsg << "ldmia r" << dec << rn << "!,{"; @@ -1667,6 +1701,9 @@ int Thumbulator::execute() { if(inst & rb) { + #ifndef NO_THUMB_STATS + ++_stats.cycles; + #endif write_register(ra, read32(sp)); sp += 4; } @@ -1680,6 +1717,9 @@ int Thumbulator::execute() //LDR(1) two register immediate case Op::ldr1: { + #ifndef NO_THUMB_STATS + _stats.cycles += 2; + #endif rd = (inst >> 0) & 0x07; rn = (inst >> 3) & 0x07; rb = (inst >> 6) & 0x1F; @@ -1693,6 +1733,9 @@ int Thumbulator::execute() //LDR(2) three register case Op::ldr2: { + #ifndef NO_THUMB_STATS + _stats.cycles += 2; + #endif rd = (inst >> 0) & 0x7; rn = (inst >> 3) & 0x7; rm = (inst >> 6) & 0x7; @@ -1705,6 +1748,9 @@ int Thumbulator::execute() //LDR(3) case Op::ldr3: { + #ifndef NO_THUMB_STATS + _stats.cycles += 2; + #endif rb = (inst >> 0) & 0xFF; rd = (inst >> 8) & 0x07; rb <<= 2; @@ -1720,6 +1766,9 @@ int Thumbulator::execute() //LDR(4) case Op::ldr4: { + #ifndef NO_THUMB_STATS + _stats.cycles += 2; + #endif rb = (inst >> 0) & 0xFF; rd = (inst >> 8) & 0x07; rb <<= 2; @@ -1734,6 +1783,9 @@ int Thumbulator::execute() //LDRB(1) case Op::ldrb1: { + #ifndef NO_THUMB_STATS + _stats.cycles += 2; + #endif rd = (inst >> 0) & 0x07; rn = (inst >> 3) & 0x07; rb = (inst >> 6) & 0x1F; @@ -1757,6 +1809,9 @@ int Thumbulator::execute() //LDRB(2) case Op::ldrb2: { + #ifndef NO_THUMB_STATS + _stats.cycles += 2; + #endif rd = (inst >> 0) & 0x7; rn = (inst >> 3) & 0x7; rm = (inst >> 6) & 0x7; @@ -1777,6 +1832,9 @@ int Thumbulator::execute() //LDRH(1) case Op::ldrh1: { + #ifndef NO_THUMB_STATS + _stats.cycles += 2; + #endif rd = (inst >> 0) & 0x07; rn = (inst >> 3) & 0x07; rb = (inst >> 6) & 0x1F; @@ -1790,6 +1848,9 @@ int Thumbulator::execute() //LDRH(2) case Op::ldrh2: { + #ifndef NO_THUMB_STATS + _stats.cycles += 2; + #endif rd = (inst >> 0) & 0x7; rn = (inst >> 3) & 0x7; rm = (inst >> 6) & 0x7; @@ -1802,6 +1863,9 @@ int Thumbulator::execute() //LDRSB case Op::ldrsb: { + #ifndef NO_THUMB_STATS + _stats.cycles += 2; + #endif rd = (inst >> 0) & 0x7; rn = (inst >> 3) & 0x7; rm = (inst >> 6) & 0x7; @@ -1825,6 +1889,9 @@ int Thumbulator::execute() //LDRSH case Op::ldrsh: { + #ifndef NO_THUMB_STATS + _stats.cycles += 2; + #endif rd = (inst >> 0) & 0x7; rn = (inst >> 3) & 0x7; rm = (inst >> 6) & 0x7; @@ -1840,6 +1907,9 @@ int Thumbulator::execute() //LSL(1) case Op::lsl1: { + #ifndef NO_THUMB_STATS + ++_stats.cycles; + #endif rd = (inst >> 0) & 0x07; rm = (inst >> 3) & 0x07; rb = (inst >> 6) & 0x1F; @@ -1865,6 +1935,9 @@ int Thumbulator::execute() //LSL(2) two register case Op::lsl2: { + #ifndef NO_THUMB_STATS + ++_stats.cycles; + #endif rd = (inst >> 0) & 0x07; rs = (inst >> 3) & 0x07; DO_DISS(statusMsg << "lsls r" << dec << rd << ",r" << dec << rs << endl); @@ -1897,6 +1970,9 @@ int Thumbulator::execute() //LSR(1) two register immediate case Op::lsr1: { + #ifndef NO_THUMB_STATS + ++_stats.cycles; + #endif rd = (inst >> 0) & 0x07; rm = (inst >> 3) & 0x07; rb = (inst >> 6) & 0x1F; @@ -1920,6 +1996,9 @@ int Thumbulator::execute() //LSR(2) two register case Op::lsr2: { + #ifndef NO_THUMB_STATS + ++_stats.cycles; + #endif rd = (inst >> 0) & 0x07; rs = (inst >> 3) & 0x07; DO_DISS(statusMsg << "lsrs r" << dec << rd << ",r" << dec << rs << endl); @@ -1999,6 +2078,9 @@ int Thumbulator::execute() //MUL case Op::mul: { + #ifndef NO_THUMB_STATS + _stats.cycles += 2; // asuming 16 bits TODO: check bits set + #endif rd = (inst >> 0) & 0x7; rm = (inst >> 3) & 0x7; DO_DISS(statusMsg << "muls r" << dec << rd << ",r" << dec << rm << endl); @@ -2193,6 +2275,9 @@ int Thumbulator::execute() //ROR case Op::ror: { + #ifndef NO_THUMB_STATS + ++_stats.cycles; + #endif rd = (inst >> 0) & 0x7; rs = (inst >> 3) & 0x7; DO_DISS(statusMsg << "rors r" << dec << rd << ",r" << dec << rs << endl); @@ -2278,6 +2363,9 @@ int Thumbulator::execute() { if(inst & rb) { + #ifndef NO_THUMB_STATS + ++_stats.cycles; + #endif write32(sp, read_register(ra)); sp += 4; } @@ -2288,6 +2376,9 @@ int Thumbulator::execute() //STR(1) case Op::str1: { + #ifndef NO_THUMB_STATS + ++_stats.cycles; + #endif rd = (inst >> 0) & 0x07; rn = (inst >> 3) & 0x07; rb = (inst >> 6) & 0x1F; @@ -2301,6 +2392,9 @@ int Thumbulator::execute() //STR(2) case Op::str2: { + #ifndef NO_THUMB_STATS + ++_stats.cycles; + #endif rd = (inst >> 0) & 0x7; rn = (inst >> 3) & 0x7; rm = (inst >> 6) & 0x7; @@ -2313,6 +2407,9 @@ int Thumbulator::execute() //STR(3) case Op::str3: { + #ifndef NO_THUMB_STATS + ++_stats.cycles; + #endif rb = (inst >> 0) & 0xFF; rd = (inst >> 8) & 0x07; rb <<= 2; @@ -2326,6 +2423,9 @@ int Thumbulator::execute() //STRB(1) case Op::strb1: { + #ifndef NO_THUMB_STATS + ++_stats.cycles; + #endif rd = (inst >> 0) & 0x07; rn = (inst >> 3) & 0x07; rb = (inst >> 6) & 0x1F; @@ -2353,6 +2453,9 @@ int Thumbulator::execute() //STRB(2) case Op::strb2: { + #ifndef NO_THUMB_STATS + ++_stats.cycles; + #endif rd = (inst >> 0) & 0x7; rn = (inst >> 3) & 0x7; rm = (inst >> 6) & 0x7; @@ -2380,6 +2483,9 @@ int Thumbulator::execute() //STRH(1) case Op::strh1: { + #ifndef NO_THUMB_STATS + ++_stats.cycles; + #endif rd = (inst >> 0) & 0x07; rn = (inst >> 3) & 0x07; rb = (inst >> 6) & 0x1F; @@ -2393,6 +2499,9 @@ int Thumbulator::execute() //STRH(2) case Op::strh2: { + #ifndef NO_THUMB_STATS + ++_stats.cycles; + #endif rd = (inst >> 0) & 0x7; rn = (inst >> 3) & 0x7; rm = (inst >> 6) & 0x7; @@ -2583,9 +2692,12 @@ int Thumbulator::reset() _prevStats.fetches = _stats.fetches; _prevStats.reads = _stats.reads; _prevStats.writes = _stats.writes; - _stats.fetches = _stats.reads = _stats.writes = 0; + _prevStats.cycles = _stats.cycles; + _stats.fetches = _stats.reads = _stats.writes = _stats.cycles = 0; +#endif +#ifdef COUNT_OPS + //memset(opCount, 0, sizeof(opCount)); #endif - return 0; } diff --git a/src/emucore/Thumbulator.hxx b/src/emucore/Thumbulator.hxx index a57db3764..201d6c8aa 100644 --- a/src/emucore/Thumbulator.hxx +++ b/src/emucore/Thumbulator.hxx @@ -47,6 +47,7 @@ class Cartridge; #define CPSR_V (1u<<28) //#define TIMER_0 // enable timer 0 support +//#define COUNT_OPS class Thumbulator { @@ -65,6 +66,7 @@ class Thumbulator struct Stats { #ifndef NO_THUMB_STATS uInt32 fetches{0}, reads{0}, writes{0}; + uInt32 cycles{0}; #endif }; @@ -166,7 +168,8 @@ class Thumbulator sxth, tst, uxtb, - uxth + uxth, + numOps }; private: @@ -219,8 +222,10 @@ class Thumbulator #ifndef UNSAFE_OPTIMIZATIONS uInt32 instructions{0}; #endif + #ifndef NO_THUMB_STATS Stats _stats; Stats _prevStats; + #endif // For emulation of LPC2103's timer 1, used for NTSC/PAL/SECAM detection. // Register names from documentation: @@ -241,6 +246,9 @@ class Thumbulator #ifndef NO_THUMB_STATS static double arm_cycle_factor; #endif +#ifdef COUNT_OPS + uInt32 opCount[size_t(Op::numOps)]{0}; +#endif ConfigureFor configuration;