switched ARM cycle counting to "real" cycles

This commit is contained in:
Thomas Jentzsch 2021-06-15 17:31:08 +02:00
parent fc9490deca
commit f87aafb3e9
5 changed files with 151 additions and 40 deletions

View File

@ -53,19 +53,19 @@ void CartridgeARMWidget::addCycleWidgets(int xpos, int ypos)
addFocusWidget(myCycleFactor); addFocusWidget(myCycleFactor);
ypos += myLineHeight + VGAP; 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, ""); EditTextWidget::calcWidth(_font, 6), myLineHeight, "");
myPrevThumbMemCycles->setEditable(false); myPrevThumbCycles->setEditable(false);
myPrevThumbMemCycles->setToolTip("Number of memory cycles of last but one ARM run."); 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, ""); EditTextWidget::calcWidth(_font, 6), myLineHeight, "");
myThumbMemCycles->setEditable(false); myThumbCycles->setEditable(false);
myThumbMemCycles->setToolTip("Number of memory cycles of last ARM run."); 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, myPrevThumbFetches = new EditTextWidget(_boss, _font, s->getRight(), ypos - 1,
EditTextWidget::calcWidth(_font, 6), myLineHeight, ""); EditTextWidget::calcWidth(_font, 6), myLineHeight, "");
myPrevThumbFetches->setEditable(false); myPrevThumbFetches->setEditable(false);
@ -79,12 +79,12 @@ void CartridgeARMWidget::addCycleWidgets(int xpos, int ypos)
ypos += myLineHeight + VGAP; ypos += myLineHeight + VGAP;
s = new StaticTextWidget(_boss, _font, xpos, ypos + 1, "Reads "); 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, ""); EditTextWidget::calcWidth(_font, 6), myLineHeight, "");
myPrevThumbReads->setEditable(false); myPrevThumbReads->setEditable(false);
myPrevThumbReads->setToolTip("Number of reads of last but one ARM run."); 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, ""); EditTextWidget::calcWidth(_font, 6), myLineHeight, "");
myThumbReads->setEditable(false); myThumbReads->setEditable(false);
myThumbReads->setToolTip("Number of reads of last ARM run."); myThumbReads->setToolTip("Number of reads of last ARM run.");
@ -105,20 +105,18 @@ void CartridgeARMWidget::addCycleWidgets(int xpos, int ypos)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeARMWidget::saveOldState() void CartridgeARMWidget::saveOldState()
{ {
myOldState.armStats.clear();
myOldState.armPrevStats.clear(); myOldState.armPrevStats.clear();
myOldState.armStats.clear();
myOldState.armStats.push_back(myCart.stats().fetches myOldState.armPrevStats.push_back(myCart.prevStats().cycles);
+ 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().fetches); myOldState.armPrevStats.push_back(myCart.prevStats().fetches);
myOldState.armPrevStats.push_back(myCart.prevStats().reads); myOldState.armPrevStats.push_back(myCart.prevStats().reads);
myOldState.armPrevStats.push_back(myCart.prevStats().writes); 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; bool isChanged;
isChanged = myCart.prevStats().fetches + myCart.prevStats().reads + myCart.prevStats().writes isChanged = myCart.prevStats().cycles != myOldState.armPrevStats[0];
!= myOldState.armPrevStats[0]; myPrevThumbCycles->setText(Common::Base::toString(myCart.prevStats().cycles,
myPrevThumbMemCycles->setText(Common::Base::toString(myCart.prevStats().fetches
+ myCart.prevStats().reads + myCart.prevStats().writes,
Common::Base::Fmt::_10_6), isChanged); Common::Base::Fmt::_10_6), isChanged);
isChanged = myCart.prevStats().fetches != myOldState.armPrevStats[1]; isChanged = myCart.prevStats().fetches != myOldState.armPrevStats[1];
myPrevThumbFetches->setText(Common::Base::toString(myCart.prevStats().fetches, myPrevThumbFetches->setText(Common::Base::toString(myCart.prevStats().fetches,
@ -146,10 +142,8 @@ void CartridgeARMWidget::loadConfig()
myPrevThumbWrites->setText(Common::Base::toString(myCart.prevStats().writes, myPrevThumbWrites->setText(Common::Base::toString(myCart.prevStats().writes,
Common::Base::Fmt::_10_6), isChanged); Common::Base::Fmt::_10_6), isChanged);
isChanged = myCart.stats().fetches + myCart.stats().reads + myCart.stats().writes isChanged = myCart.stats().cycles != myOldState.armStats[0];
!= myOldState.armStats[0]; myThumbCycles->setText(Common::Base::toString(myCart.stats().cycles,
myThumbMemCycles->setText(Common::Base::toString(myCart.stats().fetches
+ myCart.stats().reads + myCart.stats().writes,
Common::Base::Fmt::_10_6), isChanged); Common::Base::Fmt::_10_6), isChanged);
isChanged = myCart.stats().fetches != myOldState.armStats[1]; isChanged = myCart.stats().fetches != myOldState.armStats[1];
myThumbFetches->setText(Common::Base::toString(myCart.stats().fetches, myThumbFetches->setText(Common::Base::toString(myCart.stats().fetches,

View File

@ -60,11 +60,11 @@ class CartridgeARMWidget : public CartDebugWidget
CheckboxWidget* myIncCycles{nullptr}; CheckboxWidget* myIncCycles{nullptr};
SliderWidget* myCycleFactor{nullptr}; SliderWidget* myCycleFactor{nullptr};
EditTextWidget* myPrevThumbMemCycles{nullptr}; EditTextWidget* myPrevThumbCycles{nullptr};
EditTextWidget* myPrevThumbFetches{nullptr}; EditTextWidget* myPrevThumbFetches{nullptr};
EditTextWidget* myPrevThumbReads{nullptr}; EditTextWidget* myPrevThumbReads{nullptr};
EditTextWidget* myPrevThumbWrites{nullptr}; EditTextWidget* myPrevThumbWrites{nullptr};
EditTextWidget* myThumbMemCycles{nullptr}; EditTextWidget* myThumbCycles{nullptr};
EditTextWidget* myThumbFetches{nullptr}; EditTextWidget* myThumbFetches{nullptr};
EditTextWidget* myThumbReads{nullptr}; EditTextWidget* myThumbReads{nullptr};
EditTextWidget* myThumbWrites{nullptr}; EditTextWidget* myThumbWrites{nullptr};

View File

@ -31,10 +31,7 @@ CartridgeARM::CartridgeARM(const string& md5, const Settings& settings)
void CartridgeARM::updateCycles(int cycles) void CartridgeARM::updateCycles(int cycles)
{ {
if(myIncCycles) if(myIncCycles)
{ mySystem->incrementCycles(cycles); // * ~1.11 is the limit for ZEVIOUZ title screen (~142,000 cycles)
mySystem->incrementCycles(cycles); // * ~1.79 is the limit for ZEVIOUZ title screen (~88,000 cycles)
cerr << cycles << " ";
}
myStats = myThumbEmulator->stats(); myStats = myThumbEmulator->stats();
myPrevStats = myThumbEmulator->prevStats(); myPrevStats = myThumbEmulator->prevStats();
} }

View File

@ -96,7 +96,7 @@ string Thumbulator::doRun(uInt32& cycles)
#endif #endif
} }
#ifndef NO_THUMB_STATS #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 #else
cycles = 0; cycles = 0;
#endif #endif
@ -204,6 +204,7 @@ uInt32 Thumbulator::fetch16(uInt32 addr)
{ {
#ifndef NO_THUMB_STATS #ifndef NO_THUMB_STATS
++_stats.fetches; ++_stats.fetches;
++_stats.cycles;
#endif #endif
#ifndef UNSAFE_OPTIMIZATIONS #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); DO_DBUG(statusMsg << "write_register(" << dec << reg << "," << Base::HEX8 << data << ")" << endl);
//#ifndef UNSAFE_OPTIMIZATIONS // this fails when combined with read_register UNSAFE_OPTIMIZATIONS //#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 //#endif
reg_norm[reg] = data; reg_norm[reg] = data;
} }
@ -622,7 +629,7 @@ void Thumbulator::do_vflag_bit(uInt32 x)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Thumbulator::Op Thumbulator::decodeInstructionWord(uint16_t inst) { Thumbulator::Op Thumbulator::decodeInstructionWord(uint16_t inst) {
//ADC //ADC add with carry
if((inst & 0xFFC0) == 0x4140) return Op::adc; if((inst & 0xFFC0) == 0x4140) return Op::adc;
//ADD(1) small immediate two registers //ADD(1) small immediate two registers
@ -838,7 +845,7 @@ Thumbulator::Op Thumbulator::decodeInstructionWord(uint16_t inst) {
//UXTB //UXTB
if((inst & 0xFFC0) == 0xB2C0) return Op::uxtb; if((inst & 0xFFC0) == 0xB2C0) return Op::uxtb;
//UXTH //UXTH Zero extend Halfword
if((inst & 0xFFC0) == 0xB280) return Op::uxth; if((inst & 0xFFC0) == 0xB280) return Op::uxth;
return Op::invalid; return Op::invalid;
@ -872,6 +879,9 @@ int Thumbulator::execute()
decodedOp = decodedRom[(instructionPtr & ROMADDMASK) >> 1]; decodedOp = decodedRom[(instructionPtr & ROMADDMASK) >> 1];
#endif #endif
#ifdef COUNT_OPS
++opCount[int(decodedOp)];
#endif
switch (decodedOp) { switch (decodedOp) {
//ADC //ADC
case Op::adc: { case Op::adc: {
@ -1028,6 +1038,9 @@ int Thumbulator::execute()
//ASR(1) two register immediate //ASR(1) two register immediate
case Op::asr1: { case Op::asr1: {
#ifndef NO_THUMB_STATS
++_stats.cycles;
#endif
rd = (inst >> 0) & 0x07; rd = (inst >> 0) & 0x07;
rm = (inst >> 3) & 0x07; rm = (inst >> 3) & 0x07;
rb = (inst >> 6) & 0x1F; rb = (inst >> 6) & 0x1F;
@ -1062,6 +1075,9 @@ int Thumbulator::execute()
//ASR(2) two register //ASR(2) two register
case Op::asr2: { case Op::asr2: {
#ifndef NO_THUMB_STATS
++_stats.cycles;
#endif
rd = (inst >> 0) & 0x07; rd = (inst >> 0) & 0x07;
rs = (inst >> 3) & 0x07; rs = (inst >> 3) & 0x07;
DO_DISS(statusMsg << "asrs r" << dec << rd << ",r" << dec << rs << endl); DO_DISS(statusMsg << "asrs r" << dec << rd << ",r" << dec << rs << endl);
@ -1102,6 +1118,9 @@ int Thumbulator::execute()
//B(1) conditional branch //B(1) conditional branch
case Op::b1: { case Op::b1: {
#ifndef NO_THUMB_STATS
++_stats.cycles;
#endif
rb = (inst >> 0) & 0xFF; rb = (inst >> 0) & 0xFF;
if(rb & 0x80) if(rb & 0x80)
rb |= (~0U) << 8; rb |= (~0U) << 8;
@ -1219,6 +1238,9 @@ int Thumbulator::execute()
//B(2) unconditional branch //B(2) unconditional branch
case Op::b2: { case Op::b2: {
#ifndef NO_THUMB_STATS
++_stats.cycles;
#endif
rb = (inst >> 0) & 0x7FF; rb = (inst >> 0) & 0x7FF;
if(rb & (1 << 10)) if(rb & (1 << 10))
rb |= (~0U) << 11; rb |= (~0U) << 11;
@ -1255,6 +1277,9 @@ int Thumbulator::execute()
//BL/BLX(1) //BL/BLX(1)
case Op::blx1: { case Op::blx1: {
#ifndef NO_THUMB_STATS
++_stats.cycles;
#endif
if((inst & 0x1800) == 0x1000) //H=b10 if((inst & 0x1800) == 0x1000) //H=b10
{ {
DO_DISS(statusMsg << endl); DO_DISS(statusMsg << endl);
@ -1295,6 +1320,9 @@ int Thumbulator::execute()
//BLX(2) //BLX(2)
case Op::blx2: { case Op::blx2: {
#ifndef NO_THUMB_STATS
++_stats.cycles;
#endif
rm = (inst >> 3) & 0xF; rm = (inst >> 3) & 0xF;
DO_DISS(statusMsg << "blx r" << dec << rm << endl); DO_DISS(statusMsg << "blx r" << dec << rm << endl);
rc = read_register(rm); rc = read_register(rm);
@ -1317,6 +1345,9 @@ int Thumbulator::execute()
//BX //BX
case Op::bx: { case Op::bx: {
#ifndef NO_THUMB_STATS
++_stats.cycles;
#endif
rm = (inst >> 3) & 0xF; rm = (inst >> 3) & 0xF;
DO_DISS(statusMsg << "bx r" << dec << rm << endl); DO_DISS(statusMsg << "bx r" << dec << rm << endl);
rc = read_register(rm); rc = read_register(rm);
@ -1648,6 +1679,9 @@ int Thumbulator::execute()
//LDMIA //LDMIA
case Op::ldmia: { case Op::ldmia: {
#ifndef NO_THUMB_STATS
++_stats.cycles;
#endif
rn = (inst >> 8) & 0x7; rn = (inst >> 8) & 0x7;
#if defined(THUMB_DISS) #if defined(THUMB_DISS)
statusMsg << "ldmia r" << dec << rn << "!,{"; statusMsg << "ldmia r" << dec << rn << "!,{";
@ -1667,6 +1701,9 @@ int Thumbulator::execute()
{ {
if(inst & rb) if(inst & rb)
{ {
#ifndef NO_THUMB_STATS
++_stats.cycles;
#endif
write_register(ra, read32(sp)); write_register(ra, read32(sp));
sp += 4; sp += 4;
} }
@ -1680,6 +1717,9 @@ int Thumbulator::execute()
//LDR(1) two register immediate //LDR(1) two register immediate
case Op::ldr1: { case Op::ldr1: {
#ifndef NO_THUMB_STATS
_stats.cycles += 2;
#endif
rd = (inst >> 0) & 0x07; rd = (inst >> 0) & 0x07;
rn = (inst >> 3) & 0x07; rn = (inst >> 3) & 0x07;
rb = (inst >> 6) & 0x1F; rb = (inst >> 6) & 0x1F;
@ -1693,6 +1733,9 @@ int Thumbulator::execute()
//LDR(2) three register //LDR(2) three register
case Op::ldr2: { case Op::ldr2: {
#ifndef NO_THUMB_STATS
_stats.cycles += 2;
#endif
rd = (inst >> 0) & 0x7; rd = (inst >> 0) & 0x7;
rn = (inst >> 3) & 0x7; rn = (inst >> 3) & 0x7;
rm = (inst >> 6) & 0x7; rm = (inst >> 6) & 0x7;
@ -1705,6 +1748,9 @@ int Thumbulator::execute()
//LDR(3) //LDR(3)
case Op::ldr3: { case Op::ldr3: {
#ifndef NO_THUMB_STATS
_stats.cycles += 2;
#endif
rb = (inst >> 0) & 0xFF; rb = (inst >> 0) & 0xFF;
rd = (inst >> 8) & 0x07; rd = (inst >> 8) & 0x07;
rb <<= 2; rb <<= 2;
@ -1720,6 +1766,9 @@ int Thumbulator::execute()
//LDR(4) //LDR(4)
case Op::ldr4: { case Op::ldr4: {
#ifndef NO_THUMB_STATS
_stats.cycles += 2;
#endif
rb = (inst >> 0) & 0xFF; rb = (inst >> 0) & 0xFF;
rd = (inst >> 8) & 0x07; rd = (inst >> 8) & 0x07;
rb <<= 2; rb <<= 2;
@ -1734,6 +1783,9 @@ int Thumbulator::execute()
//LDRB(1) //LDRB(1)
case Op::ldrb1: { case Op::ldrb1: {
#ifndef NO_THUMB_STATS
_stats.cycles += 2;
#endif
rd = (inst >> 0) & 0x07; rd = (inst >> 0) & 0x07;
rn = (inst >> 3) & 0x07; rn = (inst >> 3) & 0x07;
rb = (inst >> 6) & 0x1F; rb = (inst >> 6) & 0x1F;
@ -1757,6 +1809,9 @@ int Thumbulator::execute()
//LDRB(2) //LDRB(2)
case Op::ldrb2: { case Op::ldrb2: {
#ifndef NO_THUMB_STATS
_stats.cycles += 2;
#endif
rd = (inst >> 0) & 0x7; rd = (inst >> 0) & 0x7;
rn = (inst >> 3) & 0x7; rn = (inst >> 3) & 0x7;
rm = (inst >> 6) & 0x7; rm = (inst >> 6) & 0x7;
@ -1777,6 +1832,9 @@ int Thumbulator::execute()
//LDRH(1) //LDRH(1)
case Op::ldrh1: { case Op::ldrh1: {
#ifndef NO_THUMB_STATS
_stats.cycles += 2;
#endif
rd = (inst >> 0) & 0x07; rd = (inst >> 0) & 0x07;
rn = (inst >> 3) & 0x07; rn = (inst >> 3) & 0x07;
rb = (inst >> 6) & 0x1F; rb = (inst >> 6) & 0x1F;
@ -1790,6 +1848,9 @@ int Thumbulator::execute()
//LDRH(2) //LDRH(2)
case Op::ldrh2: { case Op::ldrh2: {
#ifndef NO_THUMB_STATS
_stats.cycles += 2;
#endif
rd = (inst >> 0) & 0x7; rd = (inst >> 0) & 0x7;
rn = (inst >> 3) & 0x7; rn = (inst >> 3) & 0x7;
rm = (inst >> 6) & 0x7; rm = (inst >> 6) & 0x7;
@ -1802,6 +1863,9 @@ int Thumbulator::execute()
//LDRSB //LDRSB
case Op::ldrsb: { case Op::ldrsb: {
#ifndef NO_THUMB_STATS
_stats.cycles += 2;
#endif
rd = (inst >> 0) & 0x7; rd = (inst >> 0) & 0x7;
rn = (inst >> 3) & 0x7; rn = (inst >> 3) & 0x7;
rm = (inst >> 6) & 0x7; rm = (inst >> 6) & 0x7;
@ -1825,6 +1889,9 @@ int Thumbulator::execute()
//LDRSH //LDRSH
case Op::ldrsh: { case Op::ldrsh: {
#ifndef NO_THUMB_STATS
_stats.cycles += 2;
#endif
rd = (inst >> 0) & 0x7; rd = (inst >> 0) & 0x7;
rn = (inst >> 3) & 0x7; rn = (inst >> 3) & 0x7;
rm = (inst >> 6) & 0x7; rm = (inst >> 6) & 0x7;
@ -1840,6 +1907,9 @@ int Thumbulator::execute()
//LSL(1) //LSL(1)
case Op::lsl1: { case Op::lsl1: {
#ifndef NO_THUMB_STATS
++_stats.cycles;
#endif
rd = (inst >> 0) & 0x07; rd = (inst >> 0) & 0x07;
rm = (inst >> 3) & 0x07; rm = (inst >> 3) & 0x07;
rb = (inst >> 6) & 0x1F; rb = (inst >> 6) & 0x1F;
@ -1865,6 +1935,9 @@ int Thumbulator::execute()
//LSL(2) two register //LSL(2) two register
case Op::lsl2: { case Op::lsl2: {
#ifndef NO_THUMB_STATS
++_stats.cycles;
#endif
rd = (inst >> 0) & 0x07; rd = (inst >> 0) & 0x07;
rs = (inst >> 3) & 0x07; rs = (inst >> 3) & 0x07;
DO_DISS(statusMsg << "lsls r" << dec << rd << ",r" << dec << rs << endl); DO_DISS(statusMsg << "lsls r" << dec << rd << ",r" << dec << rs << endl);
@ -1897,6 +1970,9 @@ int Thumbulator::execute()
//LSR(1) two register immediate //LSR(1) two register immediate
case Op::lsr1: { case Op::lsr1: {
#ifndef NO_THUMB_STATS
++_stats.cycles;
#endif
rd = (inst >> 0) & 0x07; rd = (inst >> 0) & 0x07;
rm = (inst >> 3) & 0x07; rm = (inst >> 3) & 0x07;
rb = (inst >> 6) & 0x1F; rb = (inst >> 6) & 0x1F;
@ -1920,6 +1996,9 @@ int Thumbulator::execute()
//LSR(2) two register //LSR(2) two register
case Op::lsr2: { case Op::lsr2: {
#ifndef NO_THUMB_STATS
++_stats.cycles;
#endif
rd = (inst >> 0) & 0x07; rd = (inst >> 0) & 0x07;
rs = (inst >> 3) & 0x07; rs = (inst >> 3) & 0x07;
DO_DISS(statusMsg << "lsrs r" << dec << rd << ",r" << dec << rs << endl); DO_DISS(statusMsg << "lsrs r" << dec << rd << ",r" << dec << rs << endl);
@ -1999,6 +2078,9 @@ int Thumbulator::execute()
//MUL //MUL
case Op::mul: { case Op::mul: {
#ifndef NO_THUMB_STATS
_stats.cycles += 2; // asuming 16 bits TODO: check bits set
#endif
rd = (inst >> 0) & 0x7; rd = (inst >> 0) & 0x7;
rm = (inst >> 3) & 0x7; rm = (inst >> 3) & 0x7;
DO_DISS(statusMsg << "muls r" << dec << rd << ",r" << dec << rm << endl); DO_DISS(statusMsg << "muls r" << dec << rd << ",r" << dec << rm << endl);
@ -2193,6 +2275,9 @@ int Thumbulator::execute()
//ROR //ROR
case Op::ror: { case Op::ror: {
#ifndef NO_THUMB_STATS
++_stats.cycles;
#endif
rd = (inst >> 0) & 0x7; rd = (inst >> 0) & 0x7;
rs = (inst >> 3) & 0x7; rs = (inst >> 3) & 0x7;
DO_DISS(statusMsg << "rors r" << dec << rd << ",r" << dec << rs << endl); DO_DISS(statusMsg << "rors r" << dec << rd << ",r" << dec << rs << endl);
@ -2278,6 +2363,9 @@ int Thumbulator::execute()
{ {
if(inst & rb) if(inst & rb)
{ {
#ifndef NO_THUMB_STATS
++_stats.cycles;
#endif
write32(sp, read_register(ra)); write32(sp, read_register(ra));
sp += 4; sp += 4;
} }
@ -2288,6 +2376,9 @@ int Thumbulator::execute()
//STR(1) //STR(1)
case Op::str1: { case Op::str1: {
#ifndef NO_THUMB_STATS
++_stats.cycles;
#endif
rd = (inst >> 0) & 0x07; rd = (inst >> 0) & 0x07;
rn = (inst >> 3) & 0x07; rn = (inst >> 3) & 0x07;
rb = (inst >> 6) & 0x1F; rb = (inst >> 6) & 0x1F;
@ -2301,6 +2392,9 @@ int Thumbulator::execute()
//STR(2) //STR(2)
case Op::str2: { case Op::str2: {
#ifndef NO_THUMB_STATS
++_stats.cycles;
#endif
rd = (inst >> 0) & 0x7; rd = (inst >> 0) & 0x7;
rn = (inst >> 3) & 0x7; rn = (inst >> 3) & 0x7;
rm = (inst >> 6) & 0x7; rm = (inst >> 6) & 0x7;
@ -2313,6 +2407,9 @@ int Thumbulator::execute()
//STR(3) //STR(3)
case Op::str3: { case Op::str3: {
#ifndef NO_THUMB_STATS
++_stats.cycles;
#endif
rb = (inst >> 0) & 0xFF; rb = (inst >> 0) & 0xFF;
rd = (inst >> 8) & 0x07; rd = (inst >> 8) & 0x07;
rb <<= 2; rb <<= 2;
@ -2326,6 +2423,9 @@ int Thumbulator::execute()
//STRB(1) //STRB(1)
case Op::strb1: { case Op::strb1: {
#ifndef NO_THUMB_STATS
++_stats.cycles;
#endif
rd = (inst >> 0) & 0x07; rd = (inst >> 0) & 0x07;
rn = (inst >> 3) & 0x07; rn = (inst >> 3) & 0x07;
rb = (inst >> 6) & 0x1F; rb = (inst >> 6) & 0x1F;
@ -2353,6 +2453,9 @@ int Thumbulator::execute()
//STRB(2) //STRB(2)
case Op::strb2: { case Op::strb2: {
#ifndef NO_THUMB_STATS
++_stats.cycles;
#endif
rd = (inst >> 0) & 0x7; rd = (inst >> 0) & 0x7;
rn = (inst >> 3) & 0x7; rn = (inst >> 3) & 0x7;
rm = (inst >> 6) & 0x7; rm = (inst >> 6) & 0x7;
@ -2380,6 +2483,9 @@ int Thumbulator::execute()
//STRH(1) //STRH(1)
case Op::strh1: { case Op::strh1: {
#ifndef NO_THUMB_STATS
++_stats.cycles;
#endif
rd = (inst >> 0) & 0x07; rd = (inst >> 0) & 0x07;
rn = (inst >> 3) & 0x07; rn = (inst >> 3) & 0x07;
rb = (inst >> 6) & 0x1F; rb = (inst >> 6) & 0x1F;
@ -2393,6 +2499,9 @@ int Thumbulator::execute()
//STRH(2) //STRH(2)
case Op::strh2: { case Op::strh2: {
#ifndef NO_THUMB_STATS
++_stats.cycles;
#endif
rd = (inst >> 0) & 0x7; rd = (inst >> 0) & 0x7;
rn = (inst >> 3) & 0x7; rn = (inst >> 3) & 0x7;
rm = (inst >> 6) & 0x7; rm = (inst >> 6) & 0x7;
@ -2583,9 +2692,12 @@ int Thumbulator::reset()
_prevStats.fetches = _stats.fetches; _prevStats.fetches = _stats.fetches;
_prevStats.reads = _stats.reads; _prevStats.reads = _stats.reads;
_prevStats.writes = _stats.writes; _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 #endif
return 0; return 0;
} }

View File

@ -47,6 +47,7 @@ class Cartridge;
#define CPSR_V (1u<<28) #define CPSR_V (1u<<28)
//#define TIMER_0 // enable timer 0 support //#define TIMER_0 // enable timer 0 support
//#define COUNT_OPS
class Thumbulator class Thumbulator
{ {
@ -65,6 +66,7 @@ class Thumbulator
struct Stats { struct Stats {
#ifndef NO_THUMB_STATS #ifndef NO_THUMB_STATS
uInt32 fetches{0}, reads{0}, writes{0}; uInt32 fetches{0}, reads{0}, writes{0};
uInt32 cycles{0};
#endif #endif
}; };
@ -166,7 +168,8 @@ class Thumbulator
sxth, sxth,
tst, tst,
uxtb, uxtb,
uxth uxth,
numOps
}; };
private: private:
@ -219,8 +222,10 @@ class Thumbulator
#ifndef UNSAFE_OPTIMIZATIONS #ifndef UNSAFE_OPTIMIZATIONS
uInt32 instructions{0}; uInt32 instructions{0};
#endif #endif
#ifndef NO_THUMB_STATS
Stats _stats; Stats _stats;
Stats _prevStats; Stats _prevStats;
#endif
// For emulation of LPC2103's timer 1, used for NTSC/PAL/SECAM detection. // For emulation of LPC2103's timer 1, used for NTSC/PAL/SECAM detection.
// Register names from documentation: // Register names from documentation:
@ -241,6 +246,9 @@ class Thumbulator
#ifndef NO_THUMB_STATS #ifndef NO_THUMB_STATS
static double arm_cycle_factor; static double arm_cycle_factor;
#endif #endif
#ifdef COUNT_OPS
uInt32 opCount[size_t(Op::numOps)]{0};
#endif
ConfigureFor configuration; ConfigureFor configuration;