From c3220e0532ea0bc280e36648bea64078c7f3f257 Mon Sep 17 00:00:00 2001 From: Thomas Jentzsch Date: Thu, 1 Jul 2021 15:40:49 +0200 Subject: [PATCH] added emulation of merged I-S cycles improved ARM timers fixed MAMCR register emulation --- src/emucore/Thumbulator.cxx | 149 +++++++++++++++++++++++++----------- src/emucore/Thumbulator.hxx | 17 ++-- 2 files changed, 114 insertions(+), 52 deletions(-) diff --git a/src/emucore/Thumbulator.cxx b/src/emucore/Thumbulator.cxx index c6473e5fe..96e72b74a 100644 --- a/src/emucore/Thumbulator.cxx +++ b/src/emucore/Thumbulator.cxx @@ -53,6 +53,7 @@ using Common::Base; #endif #ifdef THUMB_CYCLE_COUNT + #define MERGE_I_S #define INC_S_CYCLES(addr, accessType) \ if(_countCycles) \ incSCycles(addr, accessType) @@ -68,7 +69,7 @@ using Common::Base; #define INC_CYCLES(m) \ _totalCycles += m #define FETCH_TYPE_N \ - _fetchCycleType = CycleType::N + _prefetchCycleType = CycleType::N #else #define INC_S_CYCLES(addr, accessType) #define INC_N_CYCLES(addr, accessType) @@ -168,13 +169,13 @@ void Thumbulator::updateTimer(uInt32 cycles) if(T0TCR & 1) // bit 0 controls timer on/off { T0TC += static_cast(cycles * timing_factor); - tim0Cycles = 0; + tim0Total = 0; } #endif if(T1TCR & 1) // bit 0 controls timer on/off { T1TC += static_cast(cycles * timing_factor); - tim1Cycles = 0; + tim1Total = 0; } } @@ -245,15 +246,22 @@ uInt32 Thumbulator::fetch16(uInt32 addr) uInt32 data; #ifdef THUMB_CYCLE_COUNT - if(_fetchCycleType == CycleType::S) + if(_prefetchCycleType == CycleType::S) { + #ifdef MERGE_I_S + //if(_countCycles && _lastCycleType == CycleType::I) + //{ + // --_totalCycles; + // _lastCycleType == CycleType::S; + //} + #endif INC_S_CYCLES(addr, AccessType::prefetch); } else { INC_N_CYCLES(addr, AccessType::prefetch); + _prefetchCycleType = CycleType::S; // default } - _fetchCycleType = CycleType::S; #endif switch(addr & 0xF0000000) @@ -308,18 +316,8 @@ void Thumbulator::write16(uInt32 addr, uInt32 data) ram[addr] = CONV_DATA(data); return; -#ifndef UNSAFE_OPTIMIZATIONS - case 0xE0000000: //MAMCR -#else default: -#endif - if(addr == 0xE01FC000) - { - DO_DBUG(statusMsg << "write16(" << Base::HEX8 << "MAMCR" << "," << Base::HEX8 << data << ") *" << endl); - if(!_lockMamcr) - mamcr = static_cast(data); - return; - } + break; } #ifndef UNSAFE_OPTIMIZATIONS fatalError("write16", addr, data, "abort"); @@ -355,23 +353,51 @@ void Thumbulator::write32(uInt32 addr, uInt32 data) #endif #ifdef TIMER_0 case 0xE0004004: // T0TCR - Timer 0 Control Register + #ifdef THUMB_CYCLE_COUNT + if((T0TCR ^ data) & 1) + { + // timer changed counter state + if(data & 1) + // timer switched to counting + tim0Start = _totalCycles; + else + // timer switched to disabled + tim0Total += _totalCycles - tim0Start; + } + #endif T0TCR = data; break; case 0xE0004008: // T0TC - Timer 0 Counter + #ifdef THUMB_CYCLE_COUNT + tim0Start = _totalCycles; + tim0Total = data / _armCyclesFactor; + #endif T0TC = data; - tim0Cycles = _totalCycles; break; #endif case 0xE0008004: // T1TCR - Timer 1 Control Register + #ifdef THUMB_CYCLE_COUNT + if((T1TCR ^ data) & 1) + { + // timer changed counter state + if(data & 1) + // timer switched to counting + tim1Start = _totalCycles; + else + // timer switched to disabled + tim1Total += _totalCycles - tim1Start; + } + #endif T1TCR = data; break; case 0xE0008008: // T1TC - Timer 1 Counter - T1TC = data; #ifdef THUMB_CYCLE_COUNT - tim1Cycles = _totalCycles; + tim1Start = _totalCycles; + tim1Total = data / _armCyclesFactor; #endif + T1TC = data; break; case 0xE000E010: @@ -398,6 +424,15 @@ void Thumbulator::write32(uInt32 addr, uInt32 data) systick_calibrate = data & 0x00FFFFFF; break; + #ifdef THUMB_CYCLE_COUNT + case 0xE01FC000: //MAMCR + DO_DBUG(statusMsg << "write32(" << Base::HEX8 << "MAMCR" << "," + << Base::HEX8 << data << ") *" << endl); + if(!_lockMamcr) + mamcr = static_cast(data); + break; + #endif + default: break; } @@ -501,16 +536,7 @@ uInt32 Thumbulator::read16(uInt32 addr) DO_DBUG(statusMsg << "read16(" << Base::HEX8 << addr << ")=" << Base::HEX4 << data << endl); return data; -#ifndef UNSAFE_OPTIMIZATIONS - case 0xE0000000: //MAMCR - if(addr == 0xE01FC000) -#else - default: -#endif - { - DO_DBUG(statusMsg << "read16(" << "MAMCR" << addr << ")=" << mamcr << " *"); - return static_cast(mamcr); - } + default: break; } #ifndef UNSAFE_OPTIMIZATIONS return fatalError("read16", addr, "abort"); @@ -543,6 +569,13 @@ uInt32 Thumbulator::read32(uInt32 addr) { switch(addr) { + #ifdef THUMB_CYCLE_COUNT + case 0xE01FC000: //MAMCR + DO_DBUG(statusMsg << "read32(" << "MAMCR" << addr << ")=" << mamcr << " *"); + data = static_cast(mamcr); + return data; + #endif + #ifdef TIMER_0 case 0xE0004004: // T0TCR - Timer 0 Control Register data = T0TCR; @@ -550,7 +583,12 @@ uInt32 Thumbulator::read32(uInt32 addr) case 0xE0004008: // T0TC - Timer 0 Counter #ifdef THUMB_CYCLE_COUNT - data = T0TC + (_totalCycles - tim0Cycles) * _armCyclesFactor; + if(T0TCR & 1) + // timer is counting + data = T0TC + (tim0Total + (_totalCycles - tim0Start)) * _armCyclesFactor; + else + // timer is disabled + data = T0TC + tim0Total * _armCyclesFactor; #else data = T0TC; #endif @@ -562,7 +600,12 @@ uInt32 Thumbulator::read32(uInt32 addr) case 0xE0008008: // T1TC - Timer 1 Counter #ifdef THUMB_CYCLE_COUNT - data = T1TC + (_totalCycles - tim1Cycles) * _armCyclesFactor; + if(T1TCR & 1) + // timer is counting + data = T1TC + (tim1Total + (_totalCycles - tim1Start)) * _armCyclesFactor; + else + // timer is disabled + data = T1TC + tim1Total * _armCyclesFactor; #else data = T1TC; #endif @@ -1771,10 +1814,10 @@ int Thumbulator::execute() sp += 4; } } + INC_I_CYCLES; // Note: destination PC not possible, see pop instead //there is a write back exception. if((inst & (1 << rn)) == 0) write_register(rn, sp); - INC_I_CYCLES; return 0; } @@ -1787,9 +1830,9 @@ int Thumbulator::execute() DO_DISS(statusMsg << "ldr r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX2 << rb << "]" << endl); rb = read_register(rn) + rb; rc = read32(rb); - write_register(rd, rc); INC_N_CYCLES(rb, AccessType::data); INC_I_CYCLES; + write_register(rd, rc); return 0; } @@ -1801,9 +1844,9 @@ int Thumbulator::execute() DO_DISS(statusMsg << "ldr r" << dec << rd << ",[r" << dec << rn << ",r" << dec << "]" << endl); rb = read_register(rn) + read_register(rm); rc = read32(rb); - write_register(rd, rc); INC_N_CYCLES(rb, AccessType::data); INC_I_CYCLES; + write_register(rd, rc); return 0; } @@ -1818,9 +1861,9 @@ int Thumbulator::execute() rb += ra; DO_DISS(statusMsg << ";@ 0x" << Base::HEX2 << rb << endl); rc = read32(rb); - write_register(rd, rc); INC_N_CYCLES(rb, AccessType::data); INC_I_CYCLES; + write_register(rd, rc); return 0; } @@ -1834,9 +1877,9 @@ int Thumbulator::execute() //ra&=~3; rb += ra; rc = read32(rb); - write_register(rd, rc); INC_N_CYCLES(rb, AccessType::data); INC_I_CYCLES; + write_register(rd, rc); return 0; } @@ -1859,9 +1902,9 @@ int Thumbulator::execute() else { } - write_register(rd, rc & 0xFF); INC_N_CYCLES(rb & (~1U), AccessType::data); INC_I_CYCLES; + write_register(rd, rc & 0xFF); return 0; } @@ -1881,9 +1924,9 @@ int Thumbulator::execute() { rc >>= 8; } - write_register(rd, rc & 0xFF); INC_N_CYCLES(rb & (~1U), AccessType::data); INC_I_CYCLES; + write_register(rd, rc & 0xFF); return 0; } @@ -1896,9 +1939,9 @@ int Thumbulator::execute() DO_DISS(statusMsg << "ldrh r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX2 << rb << "]" << endl); rb = read_register(rn) + rb; rc = read16(rb); - write_register(rd, rc & 0xFFFF); INC_N_CYCLES(rb, AccessType::data); INC_I_CYCLES; + write_register(rd, rc & 0xFFFF); return 0; } @@ -1935,9 +1978,9 @@ int Thumbulator::execute() rc &= 0xFF; if(rc & 0x80) rc |= ((~0U) << 8); - write_register(rd, rc); INC_N_CYCLES(rb & (~1U), AccessType::data); INC_I_CYCLES; + write_register(rd, rc); return 0; } @@ -1952,9 +1995,9 @@ int Thumbulator::execute() rc &= 0xFFFF; if(rc & 0x8000) rc |= ((~0U) << 16); - write_register(rd, rc); INC_N_CYCLES(rb, AccessType::data); INC_I_CYCLES; + write_register(rd, rc); return 0; } @@ -2233,6 +2276,7 @@ int Thumbulator::execute() sp += 4; } } + INC_I_CYCLES; // ??? (copied from ldmia) if(inst & 0x100) { rc = read32(sp); @@ -2249,7 +2293,6 @@ int Thumbulator::execute() sp += 4; } write_register(13, sp); - INC_I_CYCLES; // ??? (copied from stmia) return 0; } @@ -2322,8 +2365,7 @@ int Thumbulator::execute() } } write_register(13, sp); - INC_I_CYCLES; // ??? (copied from ldmia) - FETCH_TYPE_N; // ??? (copied from ldmia) + FETCH_TYPE_N; // ??? (copied from stmia) return 0; } @@ -2470,7 +2512,6 @@ int Thumbulator::execute() } } write_register(rn, sp); - INC_I_CYCLES; FETCH_TYPE_N; return 0; } @@ -3005,7 +3046,17 @@ void Thumbulator::incSCycles(uInt32 addr, AccessType accessType) cycles = _flashCycles; } } + +#ifdef MERGE_I_S + if(_lastCycleType[1] == CycleType::I) + --cycles; +#endif + incCycles(accessType, cycles); +#ifdef MERGE_I_S + _lastCycleType[1] = _lastCycleType[0]; + _lastCycleType[0] = CycleType::S; +#endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -3026,6 +3077,10 @@ void Thumbulator::incNCycles(uInt32 addr, AccessType accessType) cycles = _flashCycles; } incCycles(accessType, cycles); +#ifdef MERGE_I_S + _lastCycleType[1] = _lastCycleType[0]; + _lastCycleType[0] = CycleType::N; +#endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -3047,6 +3102,10 @@ void Thumbulator::incICycles(uInt32 m) } #endif _totalCycles += m; +#ifdef MERGE_I_S + _lastCycleType[1] = _lastCycleType[0]; + _lastCycleType[0] = CycleType::I; +#endif } #endif // THUMB_CYCLE_COUNT diff --git a/src/emucore/Thumbulator.hxx b/src/emucore/Thumbulator.hxx index c63cc9fef..4e1992ae3 100644 --- a/src/emucore/Thumbulator.hxx +++ b/src/emucore/Thumbulator.hxx @@ -283,13 +283,15 @@ class Thumbulator // 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 - uInt32 tim0Cycles{0}; + uInt32 T0TCR{0}; // Timer 0 Timer Control Register + uInt32 T0TC{0}; // Timer 0 Timer Counter + uInt32 tim0Start{0}; // _totalCycles when Timer 0 got started last time + uInt32 tim0Total{0}; // total cycles of Timer 0 #endif - uInt32 T1TCR{0}; // Timer 1 Timer Control Register - uInt32 T1TC{0}; // Timer 1 Timer Counter - uInt32 tim1Cycles{0}; + uInt32 T1TCR{0}; // Timer 1 Timer Control Register + uInt32 T1TC{0}; // Timer 1 Timer Counter + uInt32 tim1Start{0}; // _totalCycles when Timer 1 got started last time + uInt32 tim1Total{0}; // total cycles of Timer 1 double timing_factor{0.0}; #ifndef UNSAFE_OPTIMIZATIONS @@ -301,7 +303,8 @@ class Thumbulator #ifdef THUMB_CYCLE_COUNT double _armCyclesFactor{1.05}; - CycleType _fetchCycleType{CycleType::S}; + CycleType _prefetchCycleType{CycleType::S}; + CycleType _lastCycleType[2]{CycleType::S}; #ifdef EMULATE_PIPELINE uInt32 _fetchPipeline{0}; // reserve fetch cycles resulting from pipelining (execution stage) uInt32 _memory0Pipeline{0}, _memory1Pipeline{0};