added more chips types for ARM cycle count

added missing cycle counts for push and pop
added music update cycles to ARM cycle count for CDFJ
fixed stmia cycle counts
This commit is contained in:
Thomas Jentzsch 2021-06-27 09:44:42 +02:00
parent 287ab8b742
commit 6175176a6a
4 changed files with 123 additions and 53 deletions

View File

@ -89,8 +89,10 @@ void CartridgeARMWidget::addCycleWidgets(int xpos, int ypos)
- PopUpWidget::dropDownWidth(_font); - PopUpWidget::dropDownWidth(_font);
items.clear(); items.clear();
VarList::push_back(items, "LPC2101/2/3", static_cast<uInt32>(Thumbulator::ChipType::LPC2103)); VarList::push_back(items, "LPC2101" + ELLIPSIS + "3", static_cast<uInt32>(Thumbulator::ChipType::LPC2101));
VarList::push_back(items, "LPC2104/5/6", static_cast<uInt32>(Thumbulator::ChipType::LPC2104)); VarList::push_back(items, "LPC2104" + ELLIPSIS + "6 OC", static_cast<uInt32>(Thumbulator::ChipType::LPC2104_OC));
VarList::push_back(items, "LPC2104" + ELLIPSIS + "6", static_cast<uInt32>(Thumbulator::ChipType::LPC2104));
VarList::push_back(items, "LPC213x", static_cast<uInt32>(Thumbulator::ChipType::LPC213x));
myChipType = new PopUpWidget(_boss, _font, xpos, ypos, pwidth, myLineHeight, items, myChipType = new PopUpWidget(_boss, _font, xpos, ypos, pwidth, myLineHeight, items,
"Chip ", 0, kChipChanged); "Chip ", 0, kChipChanged);
myChipType->setToolTip("Select emulated ARM chip."); myChipType->setToolTip("Select emulated ARM chip.");
@ -221,8 +223,19 @@ void CartridgeARMWidget::handleChipType()
} }
myChipType->setEnabled(devSettings); myChipType->setEnabled(devSettings);
Thumbulator::ChipPropsType chipProps = myCart.setChipType(static_cast<Thumbulator::ChipType>(myChipType->getSelectedTag().toInt()));
myCart.setChipType(static_cast<Thumbulator::ChipType>(myChipType->getSelectedTag().toInt())); // update tooltip with currently selecte chip's properties
string tip = myChipType->getToolTip(Common::Point(0, 0));
ostringstream buf;
tip = tip.substr(0, 25);
buf << tip << "\nCurrent:\n"
<< chipProps.MHz << " MHz, "
<< chipProps.flashBanks << " flash bank"
<< (chipProps.flashBanks > 1 ? "s" : "") << ", "
<< chipProps.flashCycles - 1 << " wait states";
myChipType->setToolTip(buf.str());
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -78,7 +78,9 @@ class CartridgeARM : public Cartridge
void incCycles(bool enable); void incCycles(bool enable);
void cycleFactor(double factor); void cycleFactor(double factor);
double cycleFactor() const { return myThumbEmulator->cycleFactor(); } double cycleFactor() const { return myThumbEmulator->cycleFactor(); }
void setChipType(Thumbulator::ChipType chipType) { myThumbEmulator->setChipType(chipType); } Thumbulator::ChipPropsType setChipType(Thumbulator::ChipType chipType) {
return myThumbEmulator->setChipType(chipType);
}
void lockMamMode(bool lock) { myThumbEmulator->lockMamMode(lock); } void lockMamMode(bool lock) { myThumbEmulator->lockMamMode(lock); }
void setMamMode(Thumbulator::MamModeType mamMode) { myThumbEmulator->setMamMode(mamMode); } void setMamMode(Thumbulator::MamModeType mamMode) { myThumbEmulator->setMamMode(mamMode); }
Thumbulator::MamModeType mamMode() const { return myThumbEmulator->mamMode(); } Thumbulator::MamModeType mamMode() const { return myThumbEmulator->mamMode(); }

View File

@ -65,13 +65,16 @@ using Common::Base;
#define INC_I_CYCLES_M(m) \ #define INC_I_CYCLES_M(m) \
if(_countCycles) \ if(_countCycles) \
incICycles(m) incICycles(m)
#define FETCH_TYPE_N \ #define INC_CYCLES(m) \
_totalCycles += m
#define FETCH_TYPE_N \
_fetchCycleType = CycleType::N _fetchCycleType = CycleType::N
#else #else
#define INC_S_CYCLES(addr, accessType) #define INC_S_CYCLES(addr, accessType)
#define INC_N_CYCLES(addr, accessType) #define INC_N_CYCLES(addr, accessType)
#define INC_I_CYCLES #define INC_I_CYCLES
#define INC_I_CYCLES_M(m) #define INC_I_CYCLES_M(m)
#define INC_CYCLES(m)
#define FETCH_TYPE_N #define FETCH_TYPE_N
#endif #endif
@ -1516,7 +1519,7 @@ int Thumbulator::execute()
} }
else if (pc == 0x0000083a) else if (pc == 0x0000083a)
{ {
// exiting Custom ARM code, returning to BUS Driver control // exiting Custom ARM code, returning to CDF Driver control
} }
else else
{ {
@ -1560,26 +1563,42 @@ int Thumbulator::execute()
if (pc == CDF1_SetNote) if (pc == CDF1_SetNote)
{ {
myCartridge->thumbCallback(0, read_register(2), read_register(3)); myCartridge->thumbCallback(0, read_register(2), read_register(3));
// approximated cycles
INC_CYCLES(_flashCycles + 1); // this instruction
INC_CYCLES(6); // ARM code NoteStore
INC_CYCLES(2 + _flashCycles + 2); // ARM code ReturnC
handled = true; handled = true;
} }
else if (pc == CDF1_ResetWave) else if (pc == CDF1_ResetWave)
{ {
myCartridge->thumbCallback(1, read_register(2), 0); myCartridge->thumbCallback(1, read_register(2), 0);
// approximated cycles
INC_CYCLES(_flashCycles + 1); // this instruction
INC_CYCLES(6 + _flashCycles + 2); // ARM code ResetWaveStore
INC_CYCLES(2 + _flashCycles + 2); // ARM code ReturnC
handled = true; handled = true;
} }
else if (pc == CDF1_GetWavePtr) else if (pc == CDF1_GetWavePtr)
{ {
write_register(2, myCartridge->thumbCallback(2, read_register(2), 0)); write_register(2, myCartridge->thumbCallback(2, read_register(2), 0));
// approximated cycles
INC_CYCLES(_flashCycles + 1); // this instruction
INC_CYCLES(6 + _flashCycles + 2); // ARM code WavePtrFetch
INC_CYCLES(2 + _flashCycles + 2); // ARM code ReturnC
handled = true; handled = true;
} }
else if (pc == CDF1_SetWaveSize) else if (pc == CDF1_SetWaveSize)
{ {
myCartridge->thumbCallback(3, read_register(2), read_register(3)); myCartridge->thumbCallback(3, read_register(2), read_register(3));
// approximated cycles
INC_CYCLES(_flashCycles + 1); // this instruction
INC_CYCLES(18 + _flashCycles * 3 + 2); // ARM code WaveSizeStore
INC_CYCLES(2 + _flashCycles + 2); // ARM code ReturnC
handled = true; handled = true;
} }
else if (pc == 0x0000083a) else if (pc == 0x0000083a)
{ {
// exiting Custom ARM code, returning to BUS Driver control // exiting Custom ARM code, returning to CDFJ Driver control
} }
else else
{ {
@ -2195,6 +2214,7 @@ int Thumbulator::execute()
} }
statusMsg << "}" << endl; statusMsg << "}" << endl;
#endif #endif
bool first = true;
sp = read_register(13); sp = read_register(13);
for(ra = 0, rb = 0x01; rb; rb = (rb << 1) & 0xFF, ++ra) for(ra = 0, rb = 0x01; rb; rb = (rb << 1) & 0xFF, ++ra)
@ -2202,19 +2222,29 @@ int Thumbulator::execute()
if(inst & rb) if(inst & rb)
{ {
write_register(ra, read32(sp)); write_register(ra, read32(sp));
//INC_S_CYCLES(sp, AccessType::data); // TODO if(first)
{
INC_N_CYCLES(sp, AccessType::data);
first = false;
}
else
INC_S_CYCLES(sp, AccessType::data);
sp += 4; sp += 4;
} }
} }
if(inst & 0x100) if(inst & 0x100)
{ {
rc = read32(sp); rc = read32(sp);
if(first)
INC_N_CYCLES(sp, AccessType::data);
else
INC_S_CYCLES(sp, AccessType::data);
rc += 2; rc += 2;
write_register(15, rc); write_register(15, rc);
//INC_S_CYCLES(sp, AccessType::data); // TODO
sp += 4; sp += 4;
} }
write_register(13, sp); write_register(13, sp);
INC_I_CYCLES; // ??? (copied from stmia)
return 0; return 0;
} }
@ -2251,13 +2281,21 @@ int Thumbulator::execute()
if(inst & 0x100) ++rc; if(inst & 0x100) ++rc;
rc <<= 2; rc <<= 2;
sp -= rc; sp -= rc;
bool first = true;
rd = sp; rd = sp;
for(ra = 0, rb = 0x01; rb; rb = (rb << 1) & 0xFF, ++ra) for(ra = 0, rb = 0x01; rb; rb = (rb << 1) & 0xFF, ++ra)
{ {
if(inst & rb) if(inst & rb)
{ {
write32(rd, read_register(ra)); write32(rd, read_register(ra));
//INC_S_CYCLES(rd, AccessType::data); // TODO if(first)
{
INC_N_CYCLES(rd, AccessType::data);
first = false;
}
else
INC_S_CYCLES(rd, AccessType::data);
rd += 4; rd += 4;
} }
} }
@ -2265,13 +2303,18 @@ int Thumbulator::execute()
{ {
rc = read_register(14); rc = read_register(14);
write32(rd, rc); write32(rd, rc);
//INC_S_CYCLES(rd, AccessType::data); // TODO if(first)
INC_N_CYCLES(rd, AccessType::data);
else
INC_S_CYCLES(rd, AccessType::data);
if((rc & 1) == 0) if((rc & 1) == 0)
{ {
// FIXME fprintf(stderr,"push {lr} with an ARM address pc 0x%08X popped 0x%08X\n",pc,rc); // FIXME fprintf(stderr,"push {lr} with an ARM address pc 0x%08X popped 0x%08X\n",pc,rc);
} }
} }
write_register(13, sp); write_register(13, sp);
INC_I_CYCLES; // ??? (copied from ldmia)
FETCH_TYPE_N; // ??? (copied from ldmia)
return 0; return 0;
} }
@ -2409,11 +2452,11 @@ int Thumbulator::execute()
write32(sp, read_register(ra)); write32(sp, read_register(ra));
if(first) if(first)
{ {
INC_N_CYCLES(rb, AccessType::data); INC_N_CYCLES(sp, AccessType::data);
first = false; first = false;
} }
else else
INC_S_CYCLES(rb, AccessType::data); INC_S_CYCLES(sp, AccessType::data);
sp += 4; sp += 4;
} }
} }
@ -2750,16 +2793,20 @@ int Thumbulator::reset()
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Thumbulator::setChipType(ChipType type) Thumbulator::ChipPropsType Thumbulator::setChipType(ChipType type)
{ {
ChipPropsType props = ChipProps[static_cast<uInt32>(type)];
_chipType = type; _chipType = type;
_MHz = ChipProps[static_cast<uInt32>(_chipType)].MHz; _MHz = props.MHz;
#ifdef THUMB_CYCLE_COUNT #ifdef THUMB_CYCLE_COUNT
_flashCycles = ChipProps[static_cast<uInt32>(_chipType)].flashCycles; _flashCycles = props.flashCycles;
_flashBanks = ChipProps[static_cast<uInt32>(_chipType)].flashBanks; _flashBanks = props.flashBanks;
#endif #endif
setConsoleTiming(_consoleTiming); setConsoleTiming(_consoleTiming);
return props;
} }
#ifdef THUMB_CYCLE_COUNT #ifdef THUMB_CYCLE_COUNT
@ -2866,12 +2913,11 @@ void Thumbulator::incCycles(AccessType accessType, uInt32 cycles)
{ {
#ifdef EMULATE_PIPELINE #ifdef EMULATE_PIPELINE
// simulate the pipeline effects // simulate the pipeline effects
//if(_memory0Pipeline)
if(_memory0Pipeline) //{
{ // --_memory0Pipeline; // == 0
--_memory0Pipeline; // == 0 // ++_fetchPipeline;
++_fetchPipeline; //}
}
if(_memory1Pipeline) if(_memory1Pipeline)
{ {
--_memory1Pipeline; --_memory1Pipeline;
@ -2896,20 +2942,26 @@ void Thumbulator::incCycles(AccessType accessType, uInt32 cycles)
// Reduce cycles by pipelined cycles // Reduce cycles by pipelined cycles
// Cart (Turbo start sequence): 1F0AC // Cart (Turbo start sequence): 1F0AC
// None: 1FF2E @ 90% (22989 @ 100%) // None: 1FF2E @ 90% (22989 @ 100%)
#if 0 #if 1
// Version 1: 1ECFC @ 90% (223C3 @ 100%) // Version 1: 1ECFC @ 90% (223C3 @ 100%)
if(cycles == _flashCycles)
{
if(!_memory1Pipeline) // there must be no pending memory access
{
uInt32 newCycles = std::max(1, Int32(cycles - _fetchPipeline)); uInt32 newCycles = std::max(1, Int32(cycles - _fetchPipeline));
_fetchPipeline -= (cycles - newCycles); _fetchPipeline -= (cycles - newCycles);
cycles = newCycles; cycles = newCycles;
}
}
#endif #endif
#if 1 #if 0
// Version 2: 1ED23 @ 90% (223EF @ 100%) // Version 2: 1ED23 @ 90% (223EF @ 100%)
// considers that partial fetches are not allowed // considers that partial fetches are not allowed
if(cycles == _flashCycles) if(cycles == _flashCycles)
{ {
_memory0Pipeline = _memory1Pipeline = 0; //_memory0Pipeline = _memory1Pipeline = 0;
if(_fetchPipeline >= _flashCycles) if(!_memory1Pipeline && _fetchPipeline >= _flashCycles)
{ {
_fetchPipeline -= (_flashCycles - 1); _fetchPipeline -= (_flashCycles - 1);
cycles = 1; cycles = 1;
@ -2935,7 +2987,7 @@ void Thumbulator::incSCycles(uInt32 addr, AccessType accessType)
else // Flash else // Flash
{ {
if(mamcr == MamModeType::mode0) if(mamcr == MamModeType::mode0)
cycles = _flashCycles; // 4 cycles = _flashCycles; // 3|4
else else
{ {
if(isMamBuffered(addr, accessType) || mamcr == MamModeType::modeX) if(isMamBuffered(addr, accessType) || mamcr == MamModeType::modeX)
@ -2957,7 +3009,7 @@ void Thumbulator::incNCycles(uInt32 addr, AccessType accessType)
else // Flash else // Flash
{ {
if(mamcr < MamModeType::mode2) if(mamcr < MamModeType::mode2)
cycles = _flashCycles; // 4 cycles = _flashCycles; // 3|4
else else
if(isMamBuffered(addr, accessType) || mamcr == MamModeType::modeX) if(isMamBuffered(addr, accessType) || mamcr == MamModeType::modeX)
cycles = 1; cycles = 1;
@ -2972,11 +3024,13 @@ void Thumbulator::incICycles(uInt32 m)
{ {
#ifdef EMULATE_PIPELINE #ifdef EMULATE_PIPELINE
_fetchPipeline += m; _fetchPipeline += m;
if(_memory0Pipeline) //if(_memory0Pipeline)
{ //{
--_memory0Pipeline; // == 0 // --_memory0Pipeline; // == 0
++_fetchPipeline; // ++_fetchPipeline;
} //}
// TODO: m!
if(_memory1Pipeline) if(_memory1Pipeline)
{ {
--_memory1Pipeline; --_memory1Pipeline;

View File

@ -52,7 +52,7 @@ class Cartridge;
#endif #endif
#ifdef THUMB_CYCLE_COUNT #ifdef THUMB_CYCLE_COUNT
//#define EMULATE_PIPELINE // enable coarse ARM pipeline emulation //#define EMULATE_PIPELINE // enable coarse ARM pipeline emulation (TODO)
#define TIMER_0 // enable timer 0 support (e.g. for measuring cycle count) #define TIMER_0 // enable timer 0 support (e.g. for measuring cycle count)
#endif #endif
@ -70,9 +70,10 @@ class Thumbulator
DPCplus // cartridges of type DPC+ DPCplus // cartridges of type DPC+
}; };
enum class ChipType { enum class ChipType {
LPC2103, // Harmony LPC2101, // Harmony (includes LPC2103)
LPC2104, // Encore (includes LPC2105) LPC2104_OC, // Dev cart overclocked (includes LPC2105)
LPC2132, // future use LPC2104, // Dev cart (includes LPC2105)
LPC213x, // future use (includes LPC2132)
numTypes numTypes
}; };
enum class MamModeType { enum class MamModeType {
@ -108,7 +109,7 @@ class Thumbulator
void enableCycleCount(bool enable) { _countCycles = enable; } void enableCycleCount(bool enable) { _countCycles = enable; }
const Stats& stats() const { return _stats; } const Stats& stats() const { return _stats; }
uInt32 cycles() const { return _totalCycles; } uInt32 cycles() const { return _totalCycles; }
void setChipType(ChipType type); ChipPropsType setChipType(ChipType type);
void setMamMode(MamModeType mode) { mamcr = mode; } void setMamMode(MamModeType mode) { mamcr = mode; }
void lockMamMode(bool lock) { _lockMamcr = lock; } void lockMamMode(bool lock) { _lockMamcr = lock; }
MamModeType mamMode() const { return static_cast<MamModeType>(mamcr); } MamModeType mamMode() const { return static_cast<MamModeType>(mamcr); }
@ -204,6 +205,13 @@ class Thumbulator
prefetch, branch, data prefetch, branch, data
}; };
#endif #endif
const std::array<ChipPropsType, uInt32(ChipType::numTypes)> ChipProps =
{{
{ 70.0, 4, 1 }, // LPC2101_02_03
{ 70.0, 4, 2 }, // LPC2104_05_06 Overclocked
{ 60.0, 3, 2 }, // LPC2104_05_06
{ 60.0, 3, 1 }, // LPC2132..
}};
private: private:
string doRun(uInt32& cycles, bool irqDrivenAudio); string doRun(uInt32& cycles, bool irqDrivenAudio);
@ -262,7 +270,7 @@ class Thumbulator
MamModeType mamcr{MamModeType::mode0}; MamModeType mamcr{MamModeType::mode0};
bool handler_mode{false}; bool handler_mode{false};
uInt32 systick_ctrl{0}, systick_reload{0}, systick_count{0}, systick_calibrate{0}; uInt32 systick_ctrl{0}, systick_reload{0}, systick_count{0}, systick_calibrate{0};
ChipType _chipType{ChipType::LPC2103}; ChipType _chipType{ChipType::LPC2101};
ConsoleTiming _consoleTiming{ConsoleTiming::ntsc}; ConsoleTiming _consoleTiming{ConsoleTiming::ntsc};
double _MHz{70.0}; double _MHz{70.0};
uInt32 _flashCycles{4}; uInt32 _flashCycles{4};
@ -288,13 +296,6 @@ class Thumbulator
ostringstream statusMsg; ostringstream statusMsg;
bool trapOnFatal{true}; bool trapOnFatal{true};
#endif #endif
const std::array<ChipPropsType, uInt32(ChipType::numTypes)> ChipProps =
{{
{ 70.0, 4, 1 }, // LPC2101_02_03
{ 60.0, 3, 2 }, // LPC2104_05_06
{ 60.0, 3, 1 }, // LPC2132..
}};
bool _countCycles{false}; bool _countCycles{false};
bool _lockMamcr{false}; bool _lockMamcr{false};