mirror of https://github.com/stella-emu/stella.git
intermediate Thumb cycle count commit
This commit is contained in:
parent
f8c52ec24b
commit
c73261b716
|
@ -251,7 +251,11 @@ void CartridgeARMWidget::handleMamLock()
|
||||||
void CartridgeARMWidget::handleMamMode()
|
void CartridgeARMWidget::handleMamMode()
|
||||||
{
|
{
|
||||||
// override MAM mode set by ROM
|
// override MAM mode set by ROM
|
||||||
Int32 mode = myMamMode->getSelectedTag().toInt();
|
Int32 mode = myMamMode->getSelected();
|
||||||
|
|
||||||
|
string name = myMamMode->getSelectedName();
|
||||||
|
myMamMode->setSelectedName(name + "XXX");
|
||||||
|
|
||||||
|
|
||||||
instance().settings().setValue("dev.thumb.mammode", mode);
|
instance().settings().setValue("dev.thumb.mammode", mode);
|
||||||
myCart.setMamMode(static_cast<Thumbulator::MamModeType>(mode));
|
myCart.setMamMode(static_cast<Thumbulator::MamModeType>(mode));
|
||||||
|
|
|
@ -66,17 +66,50 @@ using Common::Base;
|
||||||
#define INC_I_CYCLES_M(m) \
|
#define INC_I_CYCLES_M(m) \
|
||||||
if(_countCycles) \
|
if(_countCycles) \
|
||||||
incICycles(m)
|
incICycles(m)
|
||||||
#define INC_CYCLES(m) \
|
|
||||||
|
#define INC_SHIFT_CYCLES \
|
||||||
|
INC_I_CYCLES; \
|
||||||
|
//FETCH_TYPE(CycleType::S, AccessType::data)
|
||||||
|
|
||||||
|
#define INC_LDR_CYCLES \
|
||||||
|
INC_N_CYCLES(rb, AccessType::data); \
|
||||||
|
INC_I_CYCLES; \
|
||||||
|
//FETCH_TYPE(CycleType::N, AccessType::data); \
|
||||||
|
//FETCH_TYPE_N;
|
||||||
|
#define INC_LDRB_CYCLES \
|
||||||
|
INC_N_CYCLES(rb & (~1U), AccessType::data); \
|
||||||
|
INC_I_CYCLES; \
|
||||||
|
//FETCH_TYPE(CycleType::N, AccessType::data); \
|
||||||
|
//FETCH_TYPE_N;
|
||||||
|
|
||||||
|
#define INC_STR_CYCLES \
|
||||||
|
INC_N_CYCLES(rb, AccessType::data); \
|
||||||
|
FETCH_TYPE_N; \
|
||||||
|
//INC_N_CYCLES(rb, AccessType::data);
|
||||||
|
#define INC_STRB_CYCLES \
|
||||||
|
INC_N_CYCLES(rb & (~1U), AccessType::data); \
|
||||||
|
FETCH_TYPE_N; \
|
||||||
|
//INC_N_CYCLES(rb & (~1U), AccessType::data);
|
||||||
|
|
||||||
|
#define FETCH_TYPE(cycleType, accessType) \
|
||||||
|
_prefetchCycleType[_pipeIdx] = cycleType; \
|
||||||
|
_prefetchAccessType[_pipeIdx] = accessType
|
||||||
|
#define FETCH_TYPE_N \
|
||||||
|
_prefetchCycleType[_pipeIdx] = CycleType::N
|
||||||
|
|
||||||
|
// ARM cycles
|
||||||
|
#define INC_ARM_CYCLES(m) \
|
||||||
_totalCycles += m
|
_totalCycles += m
|
||||||
#define FETCH_TYPE_N \
|
|
||||||
_prefetchCycleType = 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 INC_LDR_CYCLES
|
||||||
|
#define INC_LDRB_CYCLES
|
||||||
#define FETCH_TYPE_N
|
#define FETCH_TYPE_N
|
||||||
|
// ARM cycles
|
||||||
|
#define INC_ARM_CYCLES(m)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -246,22 +279,35 @@ uInt32 Thumbulator::fetch16(uInt32 addr)
|
||||||
uInt32 data;
|
uInt32 data;
|
||||||
|
|
||||||
#ifdef THUMB_CYCLE_COUNT
|
#ifdef THUMB_CYCLE_COUNT
|
||||||
if(_prefetchCycleType == CycleType::S)
|
_pipeIdx = (++_pipeIdx) % 3;
|
||||||
|
|
||||||
|
#ifdef MERGE_I_S
|
||||||
|
if(_lastCycleType[2] == CycleType::I)
|
||||||
|
//if(_lastCycleType[_pipeIdx] == CycleType::I)
|
||||||
|
--_totalCycles;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(_prefetchCycleType[_pipeIdx] == CycleType::S)
|
||||||
{
|
{
|
||||||
#ifdef MERGE_I_S
|
//#ifdef MERGE_I_S
|
||||||
//if(_countCycles && _lastCycleType == CycleType::I)
|
// //if(_lastCycleType[2] == CycleType::I)
|
||||||
//{
|
// if(_lastCycleType[_pipeIdx] == CycleType::I)
|
||||||
// --_totalCycles;
|
// {
|
||||||
// _lastCycleType == CycleType::S;
|
// --_totalCycles;
|
||||||
//}
|
// INC_S_CYCLES(addr, AccessType::prefetch); // N?
|
||||||
#endif
|
// }
|
||||||
INC_S_CYCLES(addr, AccessType::prefetch);
|
// else
|
||||||
|
//#endif
|
||||||
|
INC_S_CYCLES(addr, AccessType::prefetch);
|
||||||
|
//INC_S_CYCLES(addr, _prefetchAccessType[_pipeIdx]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
INC_N_CYCLES(addr, AccessType::prefetch);
|
INC_N_CYCLES(addr, AccessType::prefetch); // or ::data ?
|
||||||
_prefetchCycleType = CycleType::S; // default
|
//INC_N_CYCLES(addr, _prefetchAccessType[_pipeIdx]);
|
||||||
}
|
}
|
||||||
|
_prefetchCycleType[_pipeIdx] = CycleType::S; // default
|
||||||
|
//_prefetchAccessType[_pipeIdx] = AccessType::prefetch; // default
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
switch(addr & 0xF0000000)
|
switch(addr & 0xF0000000)
|
||||||
|
@ -691,9 +737,14 @@ void Thumbulator::write_register(uInt32 reg, uInt32 data, bool isFlowBreak)
|
||||||
data &= ~1;
|
data &= ~1;
|
||||||
if(isFlowBreak)
|
if(isFlowBreak)
|
||||||
{
|
{
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.taken;
|
||||||
|
#endif
|
||||||
// dummy fetch + fill the pipeline
|
// dummy fetch + fill the pipeline
|
||||||
INC_N_CYCLES(reg_norm[15] - 2, AccessType::prefetch);
|
//INC_N_CYCLES(reg_norm[15] - 2, AccessType::prefetch);
|
||||||
INC_S_CYCLES(data - 2, AccessType::branch);
|
//INC_S_CYCLES(data - 2, AccessType::branch);
|
||||||
|
INC_N_CYCLES(reg_norm[15] + 4, AccessType::prefetch);
|
||||||
|
INC_S_CYCLES(data, AccessType::branch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//#endif
|
//#endif
|
||||||
|
@ -1192,7 +1243,7 @@ int Thumbulator::execute()
|
||||||
write_register(rd, rc);
|
write_register(rd, rc);
|
||||||
do_nflag(rc);
|
do_nflag(rc);
|
||||||
do_zflag(rc);
|
do_zflag(rc);
|
||||||
INC_I_CYCLES;
|
INC_SHIFT_CYCLES;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1233,12 +1284,15 @@ int Thumbulator::execute()
|
||||||
write_register(rd, rc);
|
write_register(rd, rc);
|
||||||
do_nflag(rc);
|
do_nflag(rc);
|
||||||
do_zflag(rc);
|
do_zflag(rc);
|
||||||
INC_I_CYCLES;
|
INC_SHIFT_CYCLES;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//B(1) conditional branch
|
//B(1) conditional branch
|
||||||
case Op::b1: {
|
case Op::b1: {
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.branches;
|
||||||
|
#endif
|
||||||
rb = inst & 0xFF;
|
rb = inst & 0xFF;
|
||||||
if(rb & 0x80)
|
if(rb & 0x80)
|
||||||
rb |= (~0U) << 8;
|
rb |= (~0U) << 8;
|
||||||
|
@ -1357,6 +1411,9 @@ int Thumbulator::execute()
|
||||||
|
|
||||||
//B(2) unconditional branch
|
//B(2) unconditional branch
|
||||||
case Op::b2: {
|
case Op::b2: {
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.branches;
|
||||||
|
#endif
|
||||||
rb = (inst >> 0) & 0x7FF;
|
rb = (inst >> 0) & 0x7FF;
|
||||||
if(rb & (1 << 10))
|
if(rb & (1 << 10))
|
||||||
rb |= (~0U) << 11;
|
rb |= (~0U) << 11;
|
||||||
|
@ -1628,36 +1685,36 @@ int Thumbulator::execute()
|
||||||
{
|
{
|
||||||
myCartridge->thumbCallback(0, read_register(2), read_register(3));
|
myCartridge->thumbCallback(0, read_register(2), read_register(3));
|
||||||
// approximated cycles
|
// approximated cycles
|
||||||
INC_CYCLES(_flashCycles + 1); // this instruction
|
INC_ARM_CYCLES(_flashCycles + 1); // this instruction
|
||||||
INC_CYCLES(6); // ARM code NoteStore
|
INC_ARM_CYCLES(6); // ARM code NoteStore
|
||||||
INC_CYCLES(2 + _flashCycles + 2); // ARM code ReturnC
|
INC_ARM_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
|
// approximated cycles
|
||||||
INC_CYCLES(_flashCycles + 1); // this instruction
|
INC_ARM_CYCLES(_flashCycles + 1); // this instruction
|
||||||
INC_CYCLES(6 + _flashCycles + 2); // ARM code ResetWaveStore
|
INC_ARM_CYCLES(6 + _flashCycles + 2); // ARM code ResetWaveStore
|
||||||
INC_CYCLES(2 + _flashCycles + 2); // ARM code ReturnC
|
INC_ARM_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
|
// approximated cycles
|
||||||
INC_CYCLES(_flashCycles + 1); // this instruction
|
INC_ARM_CYCLES(_flashCycles + 1); // this instruction
|
||||||
INC_CYCLES(6 + _flashCycles + 2); // ARM code WavePtrFetch
|
INC_ARM_CYCLES(6 + _flashCycles + 2); // ARM code WavePtrFetch
|
||||||
INC_CYCLES(2 + _flashCycles + 2); // ARM code ReturnC
|
INC_ARM_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
|
// approximated cycles
|
||||||
INC_CYCLES(_flashCycles + 1); // this instruction
|
INC_ARM_CYCLES(_flashCycles + 1); // this instruction
|
||||||
INC_CYCLES(18 + _flashCycles * 3 + 2); // ARM code WaveSizeStore
|
INC_ARM_CYCLES(18 + _flashCycles * 3 + 2); // ARM code WaveSizeStore
|
||||||
INC_CYCLES(2 + _flashCycles + 2); // ARM code ReturnC
|
INC_ARM_CYCLES(2 + _flashCycles + 2); // ARM code ReturnC
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
else if (pc == 0x0000083a)
|
else if (pc == 0x0000083a)
|
||||||
|
@ -1850,9 +1907,8 @@ int Thumbulator::execute()
|
||||||
DO_DISS(statusMsg << "ldr r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX2 << rb << "]" << endl);
|
DO_DISS(statusMsg << "ldr r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX2 << rb << "]" << endl);
|
||||||
rb = read_register(rn) + rb;
|
rb = read_register(rn) + rb;
|
||||||
rc = read32(rb);
|
rc = read32(rb);
|
||||||
INC_N_CYCLES(rb, AccessType::data);
|
|
||||||
INC_I_CYCLES;
|
|
||||||
write_register(rd, rc);
|
write_register(rd, rc);
|
||||||
|
INC_LDR_CYCLES;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1864,9 +1920,8 @@ int Thumbulator::execute()
|
||||||
DO_DISS(statusMsg << "ldr r" << dec << rd << ",[r" << dec << rn << ",r" << dec << "]" << endl);
|
DO_DISS(statusMsg << "ldr r" << dec << rd << ",[r" << dec << rn << ",r" << dec << "]" << endl);
|
||||||
rb = read_register(rn) + read_register(rm);
|
rb = read_register(rn) + read_register(rm);
|
||||||
rc = read32(rb);
|
rc = read32(rb);
|
||||||
INC_N_CYCLES(rb, AccessType::data);
|
|
||||||
INC_I_CYCLES;
|
|
||||||
write_register(rd, rc);
|
write_register(rd, rc);
|
||||||
|
INC_LDR_CYCLES;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1881,9 +1936,8 @@ int Thumbulator::execute()
|
||||||
rb += ra;
|
rb += ra;
|
||||||
DO_DISS(statusMsg << ";@ 0x" << Base::HEX2 << rb << endl);
|
DO_DISS(statusMsg << ";@ 0x" << Base::HEX2 << rb << endl);
|
||||||
rc = read32(rb);
|
rc = read32(rb);
|
||||||
INC_N_CYCLES(rb, AccessType::data);
|
|
||||||
INC_I_CYCLES;
|
|
||||||
write_register(rd, rc);
|
write_register(rd, rc);
|
||||||
|
INC_LDR_CYCLES;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1897,9 +1951,8 @@ int Thumbulator::execute()
|
||||||
//ra&=~3;
|
//ra&=~3;
|
||||||
rb += ra;
|
rb += ra;
|
||||||
rc = read32(rb);
|
rc = read32(rb);
|
||||||
INC_N_CYCLES(rb, AccessType::data);
|
|
||||||
INC_I_CYCLES;
|
|
||||||
write_register(rd, rc);
|
write_register(rd, rc);
|
||||||
|
INC_LDR_CYCLES;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1922,9 +1975,8 @@ int Thumbulator::execute()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
INC_N_CYCLES(rb & (~1U), AccessType::data);
|
|
||||||
INC_I_CYCLES;
|
|
||||||
write_register(rd, rc & 0xFF);
|
write_register(rd, rc & 0xFF);
|
||||||
|
INC_LDRB_CYCLES;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1944,9 +1996,8 @@ int Thumbulator::execute()
|
||||||
{
|
{
|
||||||
rc >>= 8;
|
rc >>= 8;
|
||||||
}
|
}
|
||||||
INC_N_CYCLES(rb & (~1U), AccessType::data);
|
|
||||||
INC_I_CYCLES;
|
|
||||||
write_register(rd, rc & 0xFF);
|
write_register(rd, rc & 0xFF);
|
||||||
|
INC_LDRB_CYCLES;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1959,9 +2010,8 @@ int Thumbulator::execute()
|
||||||
DO_DISS(statusMsg << "ldrh r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX2 << rb << "]" << endl);
|
DO_DISS(statusMsg << "ldrh r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX2 << rb << "]" << endl);
|
||||||
rb = read_register(rn) + rb;
|
rb = read_register(rn) + rb;
|
||||||
rc = read16(rb);
|
rc = read16(rb);
|
||||||
INC_N_CYCLES(rb, AccessType::data);
|
|
||||||
INC_I_CYCLES;
|
|
||||||
write_register(rd, rc & 0xFFFF);
|
write_register(rd, rc & 0xFFFF);
|
||||||
|
INC_LDR_CYCLES;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1974,8 +2024,7 @@ int Thumbulator::execute()
|
||||||
rb = read_register(rn) + read_register(rm);
|
rb = read_register(rn) + read_register(rm);
|
||||||
rc = read16(rb);
|
rc = read16(rb);
|
||||||
write_register(rd, rc & 0xFFFF);
|
write_register(rd, rc & 0xFFFF);
|
||||||
INC_N_CYCLES(rb, AccessType::data);
|
INC_LDR_CYCLES;
|
||||||
INC_I_CYCLES;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1998,9 +2047,8 @@ int Thumbulator::execute()
|
||||||
rc &= 0xFF;
|
rc &= 0xFF;
|
||||||
if(rc & 0x80)
|
if(rc & 0x80)
|
||||||
rc |= ((~0U) << 8);
|
rc |= ((~0U) << 8);
|
||||||
INC_N_CYCLES(rb & (~1U), AccessType::data);
|
|
||||||
INC_I_CYCLES;
|
|
||||||
write_register(rd, rc);
|
write_register(rd, rc);
|
||||||
|
INC_LDRB_CYCLES;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2015,9 +2063,8 @@ int Thumbulator::execute()
|
||||||
rc &= 0xFFFF;
|
rc &= 0xFFFF;
|
||||||
if(rc & 0x8000)
|
if(rc & 0x8000)
|
||||||
rc |= ((~0U) << 16);
|
rc |= ((~0U) << 16);
|
||||||
INC_N_CYCLES(rb, AccessType::data);
|
|
||||||
INC_I_CYCLES;
|
|
||||||
write_register(rd, rc);
|
write_register(rd, rc);
|
||||||
|
INC_LDR_CYCLES;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2043,7 +2090,7 @@ int Thumbulator::execute()
|
||||||
write_register(rd, rc);
|
write_register(rd, rc);
|
||||||
do_nflag(rc);
|
do_nflag(rc);
|
||||||
do_zflag(rc);
|
do_zflag(rc);
|
||||||
INC_I_CYCLES;
|
INC_SHIFT_CYCLES;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2076,7 +2123,7 @@ int Thumbulator::execute()
|
||||||
write_register(rd, rc);
|
write_register(rd, rc);
|
||||||
do_nflag(rc);
|
do_nflag(rc);
|
||||||
do_zflag(rc);
|
do_zflag(rc);
|
||||||
INC_I_CYCLES;
|
INC_SHIFT_CYCLES;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2100,7 +2147,7 @@ int Thumbulator::execute()
|
||||||
write_register(rd, rc);
|
write_register(rd, rc);
|
||||||
do_nflag(rc);
|
do_nflag(rc);
|
||||||
do_zflag(rc);
|
do_zflag(rc);
|
||||||
INC_I_CYCLES;
|
INC_SHIFT_CYCLES;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2133,7 +2180,7 @@ int Thumbulator::execute()
|
||||||
write_register(rd, rc);
|
write_register(rd, rc);
|
||||||
do_nflag(rc);
|
do_nflag(rc);
|
||||||
do_zflag(rc);
|
do_zflag(rc);
|
||||||
INC_I_CYCLES;
|
INC_SHIFT_CYCLES;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2460,7 +2507,7 @@ int Thumbulator::execute()
|
||||||
write_register(rd, rc);
|
write_register(rd, rc);
|
||||||
do_nflag(rc);
|
do_nflag(rc);
|
||||||
do_zflag(rc);
|
do_zflag(rc);
|
||||||
INC_I_CYCLES;
|
INC_SHIFT_CYCLES;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2546,8 +2593,7 @@ int Thumbulator::execute()
|
||||||
rb = read_register(rn) + rb;
|
rb = read_register(rn) + rb;
|
||||||
rc = read_register(rd);
|
rc = read_register(rd);
|
||||||
write32(rb, rc);
|
write32(rb, rc);
|
||||||
INC_N_CYCLES(rb, AccessType::data);
|
INC_STR_CYCLES;
|
||||||
FETCH_TYPE_N;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2560,8 +2606,7 @@ int Thumbulator::execute()
|
||||||
rb = read_register(rn) + read_register(rm);
|
rb = read_register(rn) + read_register(rm);
|
||||||
rc = read_register(rd);
|
rc = read_register(rd);
|
||||||
write32(rb, rc);
|
write32(rb, rc);
|
||||||
INC_N_CYCLES(rb, AccessType::data);
|
INC_STR_CYCLES;
|
||||||
FETCH_TYPE_N;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2575,8 +2620,7 @@ int Thumbulator::execute()
|
||||||
//fprintf(stderr,"0x%08X\n",rb);
|
//fprintf(stderr,"0x%08X\n",rb);
|
||||||
rc = read_register(rd);
|
rc = read_register(rd);
|
||||||
write32(rb, rc);
|
write32(rb, rc);
|
||||||
INC_N_CYCLES(rb, AccessType::data);
|
INC_STR_CYCLES;
|
||||||
FETCH_TYPE_N;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2604,8 +2648,7 @@ int Thumbulator::execute()
|
||||||
ra |= rc & 0x00FF;
|
ra |= rc & 0x00FF;
|
||||||
}
|
}
|
||||||
write16(rb & (~1U), ra & 0xFFFF);
|
write16(rb & (~1U), ra & 0xFFFF);
|
||||||
INC_N_CYCLES(rb, AccessType::data);
|
INC_STRB_CYCLES;
|
||||||
FETCH_TYPE_N;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2633,8 +2676,7 @@ int Thumbulator::execute()
|
||||||
ra |= rc & 0x00FF;
|
ra |= rc & 0x00FF;
|
||||||
}
|
}
|
||||||
write16(rb & (~1U), ra & 0xFFFF);
|
write16(rb & (~1U), ra & 0xFFFF);
|
||||||
INC_N_CYCLES(rb, AccessType::data);
|
INC_STRB_CYCLES;
|
||||||
FETCH_TYPE_N;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2648,8 +2690,7 @@ int Thumbulator::execute()
|
||||||
rb = read_register(rn) + rb;
|
rb = read_register(rn) + rb;
|
||||||
rc= read_register(rd);
|
rc= read_register(rd);
|
||||||
write16(rb, rc & 0xFFFF);
|
write16(rb, rc & 0xFFFF);
|
||||||
INC_N_CYCLES(rb, AccessType::data);
|
INC_STR_CYCLES;
|
||||||
FETCH_TYPE_N;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2662,8 +2703,7 @@ int Thumbulator::execute()
|
||||||
rb = read_register(rn) + read_register(rm);
|
rb = read_register(rn) + read_register(rm);
|
||||||
rc = read_register(rd);
|
rc = read_register(rd);
|
||||||
write16(rb, rc & 0xFFFF);
|
write16(rb, rc & 0xFFFF);
|
||||||
INC_N_CYCLES(rb, AccessType::data);
|
INC_STR_CYCLES;
|
||||||
FETCH_TYPE_N;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2848,7 +2888,12 @@ int Thumbulator::reset()
|
||||||
statusMsg.str("");
|
statusMsg.str("");
|
||||||
#endif
|
#endif
|
||||||
#ifdef THUMB_STATS
|
#ifdef THUMB_STATS
|
||||||
_stats.reads = _stats.writes = 0;
|
_stats.reads = _stats.writes
|
||||||
|
= _stats.nCylces = _stats.sCylces = _stats.iCylces
|
||||||
|
= _stats.branches = _stats.taken
|
||||||
|
= _stats.mamPrefetchHits = _stats.mamPrefetchMisses
|
||||||
|
= _stats.mamBranchHits = _stats.mamBranchMisses
|
||||||
|
= _stats.mamDataHits = _stats.mamDataMisses = 0;
|
||||||
#endif
|
#endif
|
||||||
#ifdef THUMB_CYCLE_COUNT
|
#ifdef THUMB_CYCLE_COUNT
|
||||||
_totalCycles = 0;
|
_totalCycles = 0;
|
||||||
|
@ -2899,7 +2944,7 @@ Thumbulator::ChipPropsType Thumbulator::setChipType(ChipType type)
|
||||||
- If a branch target cannot be found in the two buffers a new line of 128 bits is read from
|
- If a branch target cannot be found in the two buffers a new line of 128 bits is read from
|
||||||
memory and put into the branch trail buffer. This causes wait states.
|
memory and put into the branch trail buffer. This causes wait states.
|
||||||
|
|
||||||
Data access in only checking and updating the data buffer.
|
Data access is only checking and updating the data buffer.
|
||||||
|
|
||||||
The function returns true in case of a buffer hit.
|
The function returns true in case of a buffer hit.
|
||||||
*/
|
*/
|
||||||
|
@ -2915,25 +2960,44 @@ bool Thumbulator::isMamBuffered(uInt32 addr, AccessType accessType)
|
||||||
case AccessType::prefetch:
|
case AccessType::prefetch:
|
||||||
if(addr != _prefetchBufferAddr[0] && addr != _branchBufferAddr[0])
|
if(addr != _prefetchBufferAddr[0] && addr != _branchBufferAddr[0])
|
||||||
{
|
{
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.mamPrefetchMisses;
|
||||||
|
#endif
|
||||||
_prefetchBufferAddr[0] = addr;
|
_prefetchBufferAddr[0] = addr;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.mamPrefetchHits;
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AccessType::branch:
|
case AccessType::branch:
|
||||||
if(addr != _prefetchBufferAddr[0] && addr != _branchBufferAddr[0])
|
if(addr != _prefetchBufferAddr[0] && addr != _branchBufferAddr[0])
|
||||||
{
|
{
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.mamBranchMisses;
|
||||||
|
#endif
|
||||||
_branchBufferAddr[0] = addr;
|
_branchBufferAddr[0] = addr;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.mamBranchHits;
|
||||||
|
#endif
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: // AccessType::data
|
default: // AccessType::data
|
||||||
if(addr != _dataBufferAddr)
|
if(addr != _dataBufferAddr)
|
||||||
{
|
{
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.mamDataMisses;
|
||||||
|
#endif
|
||||||
_dataBufferAddr = addr;
|
_dataBufferAddr = addr;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.mamDataHits;
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -2951,27 +3015,45 @@ bool Thumbulator::isMamBuffered(uInt32 addr, AccessType accessType)
|
||||||
_prefetchBufferAddr[bank ^ 1] = addr + 0x80;
|
_prefetchBufferAddr[bank ^ 1] = addr + 0x80;
|
||||||
if(addr != _prefetchBufferAddr[bank] && addr != _branchBufferAddr[bank])
|
if(addr != _prefetchBufferAddr[bank] && addr != _branchBufferAddr[bank])
|
||||||
{
|
{
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.mamPrefetchMisses;
|
||||||
|
#endif
|
||||||
_prefetchBufferAddr[bank] = addr;
|
_prefetchBufferAddr[bank] = addr;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.mamPrefetchHits;
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AccessType::branch:
|
case AccessType::branch:
|
||||||
if(addr != _prefetchBufferAddr[bank] && addr != _branchBufferAddr[bank])
|
if(addr != _prefetchBufferAddr[bank] && addr != _branchBufferAddr[bank])
|
||||||
{
|
{
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.mamBranchMisses;
|
||||||
|
#endif
|
||||||
// load both branch trail buffers at once
|
// load both branch trail buffers at once
|
||||||
_branchBufferAddr[bank] = addr;
|
_branchBufferAddr[bank] = addr;
|
||||||
_branchBufferAddr[bank ^ 1] = addr + 0x80;
|
_branchBufferAddr[bank ^ 1] = addr + 0x80;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.mamBranchHits;
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: // AccessType::data
|
default: // AccessType::data
|
||||||
if(addr != _dataBufferAddr)
|
if(addr != _dataBufferAddr)
|
||||||
{
|
{
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.mamDataMisses;
|
||||||
|
#endif
|
||||||
_dataBufferAddr = addr;
|
_dataBufferAddr = addr;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.mamDataHits;
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -3057,14 +3139,22 @@ void Thumbulator::incCycles(AccessType accessType, uInt32 cycles)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Thumbulator::incSCycles(uInt32 addr, AccessType accessType)
|
void Thumbulator::incSCycles(uInt32 addr, AccessType accessType)
|
||||||
{
|
{
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.sCylces;
|
||||||
|
#endif
|
||||||
|
|
||||||
uInt32 cycles;
|
uInt32 cycles;
|
||||||
|
|
||||||
|
|
||||||
if(addr & 0xC0000000) // RAM, peripherals
|
if(addr & 0xC0000000) // RAM, peripherals
|
||||||
cycles = 1;
|
cycles = 1;
|
||||||
else // Flash
|
else // Flash
|
||||||
{
|
{
|
||||||
if(mamcr == MamModeType::mode0)
|
if(mamcr == MamModeType::mode0 ||
|
||||||
|
(mamcr == MamModeType::mode1 && accessType == AccessType::data))
|
||||||
|
{
|
||||||
cycles = _flashCycles; // 3|4
|
cycles = _flashCycles; // 3|4
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(isMamBuffered(addr, accessType) || mamcr == MamModeType::modeX)
|
if(isMamBuffered(addr, accessType) || mamcr == MamModeType::modeX)
|
||||||
|
@ -3075,27 +3165,48 @@ void Thumbulator::incSCycles(uInt32 addr, AccessType accessType)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MERGE_I_S
|
#ifdef MERGE_I_S
|
||||||
if(accessType != AccessType::prefetch)
|
//if(accessType != AccessType::prefetch)
|
||||||
{
|
//{
|
||||||
if(_lastCycleType[0] == CycleType::I)
|
// if(_lastCycleType[0] == CycleType::I)
|
||||||
{
|
// {
|
||||||
_lastCycleType[0] = CycleType::S; // merge cannot be used twice!
|
// _lastCycleType[0] = CycleType::S; // merge cannot be used twice!
|
||||||
--cycles;
|
// --cycles;
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
else if(_lastCycleType[2] == CycleType::I)
|
//else if(_lastCycleType[2] == CycleType::I)
|
||||||
--cycles;
|
// --cycles;
|
||||||
|
|
||||||
|
//if(accessType == AccessType::prefetch &&
|
||||||
|
// _lastCycleType[_pipeIdx] == CycleType::I)
|
||||||
|
// --cycles;
|
||||||
|
|
||||||
|
|
||||||
_lastCycleType[2] = _lastCycleType[1];
|
_lastCycleType[2] = _lastCycleType[1];
|
||||||
_lastCycleType[1] = _lastCycleType[0];
|
_lastCycleType[1] = _lastCycleType[0];
|
||||||
_lastCycleType[0] = CycleType::S;
|
_lastCycleType[0] = CycleType::S;
|
||||||
|
//_lastCycleType[_pipeIdx] = CycleType::S;
|
||||||
#endif
|
#endif
|
||||||
incCycles(accessType, cycles);
|
incCycles(accessType, cycles);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef MERGE_I_S
|
||||||
|
if(accessType == AccessType::branch)
|
||||||
|
{
|
||||||
|
if(_lastCycleType[1] == CycleType::I || _lastCycleType[2] == CycleType::I)
|
||||||
|
_lastCycleType[1] = _lastCycleType[2] = CycleType::S;
|
||||||
|
//if(_lastCycleType[_pipeIdx ^ 1] == CycleType::I || _lastCycleType[_pipeIdx ^ 2] == CycleType::I)
|
||||||
|
// _lastCycleType[_pipeIdx ^ 1] = _lastCycleType[_pipeIdx ^ 2] = CycleType::S;
|
||||||
|
}
|
||||||
|
#endif // MERGE_I_S
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Thumbulator::incNCycles(uInt32 addr, AccessType accessType)
|
void Thumbulator::incNCycles(uInt32 addr, AccessType accessType)
|
||||||
{
|
{
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.nCylces;
|
||||||
|
#endif
|
||||||
|
|
||||||
uInt32 cycles;
|
uInt32 cycles;
|
||||||
|
|
||||||
if(addr & 0xC0000000) // RAM, peripherals
|
if(addr & 0xC0000000) // RAM, peripherals
|
||||||
|
@ -3114,6 +3225,7 @@ void Thumbulator::incNCycles(uInt32 addr, AccessType accessType)
|
||||||
_lastCycleType[2] = _lastCycleType[1];
|
_lastCycleType[2] = _lastCycleType[1];
|
||||||
_lastCycleType[1] = _lastCycleType[0];
|
_lastCycleType[1] = _lastCycleType[0];
|
||||||
_lastCycleType[0] = CycleType::N;
|
_lastCycleType[0] = CycleType::N;
|
||||||
|
//_lastCycleType[_pipeIdx] = CycleType::N;
|
||||||
#endif
|
#endif
|
||||||
incCycles(accessType, cycles);
|
incCycles(accessType, cycles);
|
||||||
}
|
}
|
||||||
|
@ -3121,6 +3233,10 @@ void Thumbulator::incNCycles(uInt32 addr, AccessType accessType)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Thumbulator::incICycles(uInt32 m)
|
void Thumbulator::incICycles(uInt32 m)
|
||||||
{
|
{
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.iCylces;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef EMULATE_PIPELINE
|
#ifdef EMULATE_PIPELINE
|
||||||
_fetchPipeline += m;
|
_fetchPipeline += m;
|
||||||
//if(_memory0Pipeline)
|
//if(_memory0Pipeline)
|
||||||
|
@ -3140,6 +3256,7 @@ void Thumbulator::incICycles(uInt32 m)
|
||||||
_lastCycleType[2] = _lastCycleType[1];
|
_lastCycleType[2] = _lastCycleType[1];
|
||||||
_lastCycleType[1] = _lastCycleType[0];
|
_lastCycleType[1] = _lastCycleType[0];
|
||||||
_lastCycleType[0] = CycleType::I;
|
_lastCycleType[0] = CycleType::I;
|
||||||
|
//_lastCycleType[_pipeIdx] = CycleType::I;
|
||||||
#endif
|
#endif
|
||||||
_totalCycles += m;
|
_totalCycles += m;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ class Cartridge;
|
||||||
#ifdef DEBUGGER_SUPPORT
|
#ifdef DEBUGGER_SUPPORT
|
||||||
#define THUMB_CYCLE_COUNT
|
#define THUMB_CYCLE_COUNT
|
||||||
//#define COUNT_OPS
|
//#define COUNT_OPS
|
||||||
//#define THUMB_STATS
|
#define THUMB_STATS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef THUMB_CYCLE_COUNT
|
#ifdef THUMB_CYCLE_COUNT
|
||||||
|
@ -88,6 +88,11 @@ class Thumbulator
|
||||||
uInt32 instructions{0};
|
uInt32 instructions{0};
|
||||||
#ifdef THUMB_STATS
|
#ifdef THUMB_STATS
|
||||||
uInt32 reads{0}, writes{0};
|
uInt32 reads{0}, writes{0};
|
||||||
|
uInt32 nCylces{0}, sCylces{0}, iCylces{0};
|
||||||
|
uInt32 branches{0}, taken{0};
|
||||||
|
uInt32 mamPrefetchHits{0}, mamPrefetchMisses{0};
|
||||||
|
uInt32 mamBranchHits{0}, mamBranchMisses{0};
|
||||||
|
uInt32 mamDataHits{0}, mamDataMisses{0};
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -303,8 +308,10 @@ class Thumbulator
|
||||||
|
|
||||||
#ifdef THUMB_CYCLE_COUNT
|
#ifdef THUMB_CYCLE_COUNT
|
||||||
double _armCyclesFactor{1.05};
|
double _armCyclesFactor{1.05};
|
||||||
CycleType _prefetchCycleType{CycleType::S};
|
uInt32 _pipeIdx{0};
|
||||||
|
CycleType _prefetchCycleType[3]{CycleType::S};
|
||||||
CycleType _lastCycleType[3]{CycleType::S};
|
CycleType _lastCycleType[3]{CycleType::S};
|
||||||
|
AccessType _prefetchAccessType[3]{AccessType::data};
|
||||||
#ifdef EMULATE_PIPELINE
|
#ifdef EMULATE_PIPELINE
|
||||||
uInt32 _fetchPipeline{0}; // reserve fetch cycles resulting from pipelining (execution stage)
|
uInt32 _fetchPipeline{0}; // reserve fetch cycles resulting from pipelining (execution stage)
|
||||||
uInt32 _memory0Pipeline{0}, _memory1Pipeline{0};
|
uInt32 _memory0Pipeline{0}, _memory1Pipeline{0};
|
||||||
|
|
Loading…
Reference in New Issue