From a56bf5c76cbbb002a6ef93729513f2178edb7c96 Mon Sep 17 00:00:00 2001 From: StapleButter Date: Mon, 20 Mar 2017 17:39:42 +0100 Subject: [PATCH] make timers not suck. fixes issues (Worms2 intro FMV plays at the right speed, aging cart tests get further...) --- README.md | 1 - src/ARM.cpp | 25 ++++------ src/DMA.cpp | 13 +++-- src/GPU.cpp | 3 ++ src/NDS.cpp | 130 +++++++++++++++++++++++------------------------- src/NDS.h | 6 ++- src/NDSCart.cpp | 6 +++ 7 files changed, 95 insertions(+), 89 deletions(-) diff --git a/README.md b/README.md index 5cdfb288..c50a8849 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,6 @@ TODO LIST IMMEDIATE TODO LIST (prior release 1.0) * UI - * make timers suck less TODO LIST FOR LATER diff --git a/src/ARM.cpp b/src/ARM.cpp index 536c78ce..382f56ed 100644 --- a/src/ARM.cpp +++ b/src/ARM.cpp @@ -20,7 +20,6 @@ #include "NDS.h" #include "ARM.h" #include "ARMInterpreter.h" -#include "GPU3D.h" u32 ARM::ConditionTable[16] = @@ -328,20 +327,19 @@ s32 ARM::Execute() else { Cycles = CyclesToRun; - GPU3D::Run(CyclesToRun >> 1); + + if (Num == 0) NDS::RunTimingCriticalDevices(0, CyclesToRun >> 1); + else NDS::RunTimingCriticalDevices(1, CyclesToRun); + return Cycles; } } Cycles = 0; s32 lastcycles = 0; - u32 addr = R[15] - (CPSR&0x20 ? 4:8); - u32 cpsr = CPSR; while (Cycles < CyclesToRun) { - //if(Num==1)printf("%08X %08X\n", R[15] - (CPSR&0x20 ? 4:8), NextInstr); - if (CPSR & 0x20) // THUMB { // prefetch @@ -376,15 +374,18 @@ s32 ARM::Execute() //if (R[15]==0x037F9364) printf("R8=%08X R9=%08X\n", R[8], R[9]); - // gross hack - // TODO, though: move timer code here too? - // quick testing shows that moving this to the NDS loop doesn't really slow things down if (Num==0) { s32 diff = Cycles - lastcycles; - GPU3D::Run(diff >> 1); + NDS::RunTimingCriticalDevices(0, diff >> 1); lastcycles = Cycles - (diff&1); } + else + { + s32 diff = Cycles - lastcycles; + NDS::RunTimingCriticalDevices(1, diff); + lastcycles = Cycles; + } // TODO optimize this shit!!! if (Halted) @@ -398,10 +399,6 @@ s32 ARM::Execute() if (NDS::IME[Num]&1) TriggerIRQ(); } - - // temp. debug cruft - addr = R[15] - (CPSR&0x20 ? 4:8); - cpsr = CPSR; } if (Halted == 2) diff --git a/src/DMA.cpp b/src/DMA.cpp index b3e4f2f6..5a7ca1c1 100644 --- a/src/DMA.cpp +++ b/src/DMA.cpp @@ -26,7 +26,6 @@ // NOTES ON DMA SHIT // // * could use optimized code paths for common types of DMA transfers. for example, VRAM -// * needs to eventually be made more accurate anyway. DMA isn't instant. DMA::DMA(u32 cpu, u32 num) @@ -154,7 +153,7 @@ void DMA::WriteCnt(u32 val) else if (StartMode == 0x07) GPU3D::CheckFIFODMA(); - if ((StartMode&7)!=0x00 && (StartMode&7)!=0x1 && StartMode!=2 && StartMode!=0x05 && StartMode!=0x12 && StartMode!=0x07) + if (StartMode==0x04 || StartMode==0x06 || StartMode==0x13) printf("UNIMPLEMENTED ARM%d DMA%d START MODE %02X\n", CPU?7:9, Num, StartMode); } } @@ -215,7 +214,10 @@ s32 DMA::Run(s32 cycles) { writefn(CurDstAddr, readfn(CurSrcAddr)); - cycles -= (Waitstates[0][(CurSrcAddr >> 24) & 0xF] + Waitstates[0][(CurDstAddr >> 24) & 0xF]); + s32 c = (Waitstates[0][(CurSrcAddr >> 24) & 0xF] + Waitstates[0][(CurDstAddr >> 24) & 0xF]); + cycles -= c; + NDS::RunTimingCriticalDevices(CPU, c); + CurSrcAddr += SrcAddrInc<<1; CurDstAddr += DstAddrInc<<1; IterCount--; @@ -231,7 +233,10 @@ s32 DMA::Run(s32 cycles) { writefn(CurDstAddr, readfn(CurSrcAddr)); - cycles -= (Waitstates[1][(CurSrcAddr >> 24) & 0xF] + Waitstates[1][(CurDstAddr >> 24) & 0xF]); + s32 c = (Waitstates[1][(CurSrcAddr >> 24) & 0xF] + Waitstates[1][(CurDstAddr >> 24) & 0xF]); + cycles -= c; + NDS::RunTimingCriticalDevices(CPU, c); + CurSrcAddr += SrcAddrInc<<2; CurDstAddr += DstAddrInc<<2; IterCount--; diff --git a/src/GPU.cpp b/src/GPU.cpp index 28c5d243..aaef43f9 100644 --- a/src/GPU.cpp +++ b/src/GPU.cpp @@ -716,6 +716,9 @@ void StartScanline(u32 line) //NDS::ScheduleEvent(NDS::Event_LCD, true, LINE_CYCLES, StartScanline, line+1); } + // checkme + if (line == 0) NDS::CheckDMAs(0, 0x03); + NDS::ScheduleEvent(NDS::Event_LCD, true, HBLANK_CYCLES, StartHBlank, line); } diff --git a/src/NDS.cpp b/src/NDS.cpp index 52a1de0a..3ab543e0 100644 --- a/src/NDS.cpp +++ b/src/NDS.cpp @@ -333,17 +333,6 @@ void CalcIterationCycles() void RunSystem(s32 cycles) { - for (int i = 0; i < 8; i++) - { - if ((Timers[i].Cnt & 0x84) == 0x80) - Timers[i].Counter += (ARM9->Cycles >> 1) << Timers[i].CycleShift; - } - for (int i = 4; i < 8; i++) - { - if ((Timers[i].Cnt & 0x84) == 0x80) - Timers[i].Counter += ARM7->Cycles << Timers[i].CycleShift; - } - for (int i = 0; i < Event_MAX; i++) { if (!(SchedListMask & (1< 0) cycles = DMAs[2]->Run(cycles); if (cycles > 0) cycles = DMAs[3]->Run(cycles); ndscyclestorun = CurIterationCycles - cycles; - - // TODO: run other timing critical shit, like timers - GPU3D::Run(ndscyclestorun); } else { @@ -567,6 +553,66 @@ void ResumeCPU(u32 cpu, u32 mask) +void HandleTimerOverflow(u32 tid) +{ + Timer* timer = &Timers[tid]; + + timer->Counter += timer->Reload << 16; + if (timer->Cnt & (1<<6)) + SetIRQ(tid >> 2, IRQ_Timer0 + (tid & 0x3)); + + if ((tid & 0x3) == 3) + return; + + for (;;) + { + tid++; + + timer = &Timers[tid]; + + if ((timer->Cnt & 0x84) != 0x84) + break; + + timer->Counter += 0x10000; + if (timer->Counter >> 16) + break; + + timer->Counter = timer->Reload << 16; + if (timer->Cnt & (1<<6)) + SetIRQ(tid >> 2, IRQ_Timer0 + (tid & 0x3)); + + if ((tid & 0x3) == 3) + break; + } +} + +void RunTimer(u32 tid, s32 cycles) +{ + Timer* timer = &Timers[tid]; + if ((timer->Cnt & 0x84) != 0x80) + return; + + u32 oldcount = timer->Counter; + timer->Counter += (cycles << timer->CycleShift); + if (timer->Counter < oldcount) + HandleTimerOverflow(tid); +} + +void RunTimingCriticalDevices(u32 cpu, s32 cycles) +{ + RunTimer((cpu<<2)+0, cycles); + RunTimer((cpu<<2)+1, cycles); + RunTimer((cpu<<2)+2, cycles); + RunTimer((cpu<<2)+3, cycles); + + if (cpu == 0) + { + GPU3D::Run(cycles); + } +} + + + void CheckDMAs(u32 cpu, u32 mode) { cpu <<= 2; @@ -578,58 +624,16 @@ void CheckDMAs(u32 cpu, u32 mode) -//const s32 TimerPrescaler[4] = {1, 64, 256, 1024}; + const s32 TimerPrescaler[4] = {0, 6, 8, 10}; u16 TimerGetCounter(u32 timer) { u32 ret = Timers[timer].Counter; - if ((Timers[timer].Cnt & 0x84) == 0x80) - { - u32 c = (timer & 0x4) ? ARM7->Cycles : (ARM9->Cycles>>1); - ret += (c << Timers[timer].CycleShift); - } - return ret >> 16; } -void TimerOverflow(u32 param) -{ - Timer* timer = &Timers[param]; - timer->Counter = 0; - - u32 tid = param & 0x3; - u32 cpu = param >> 2; - - for (;;) - { - if (tid == (param&0x3)) - ScheduleEvent(Event_Timer9_0 + param, true, (0x10000 - timer->Reload) << TimerPrescaler[timer->Cnt & 0x03], TimerOverflow, param); - //timer->Event = ScheduleEvent(TimerPrescaler[timer->Control&0x3], TimerIncrement, param); - - if (timer->Counter == 0) - { - timer->Counter = timer->Reload << 16; - - if (timer->Cnt & (1<<6)) - SetIRQ(cpu, IRQ_Timer0 + tid); - - // cascade - if (tid == 3) - break; - timer++; - if ((timer->Cnt & 0x84) != 0x84) - break; - timer->Counter += 0x10000; - tid++; - continue; - } - - break; - } -} - void TimerStart(u32 id, u16 cnt) { Timer* timer = &Timers[id]; @@ -637,21 +641,11 @@ void TimerStart(u32 id, u16 cnt) u16 newstart = cnt & (1<<7); timer->Cnt = cnt; + timer->CycleShift = 16 - TimerPrescaler[cnt & 0x03]; if ((!curstart) && newstart) { timer->Counter = timer->Reload << 16; - timer->CycleShift = 16 - TimerPrescaler[cnt & 0x03]; - - // start the timer, if it's not a cascading timer - if (!(cnt & (1<<2))) - ScheduleEvent(Event_Timer9_0 + id, false, (0x10000 - timer->Reload) << TimerPrescaler[cnt & 0x03], TimerOverflow, id); - else - CancelEvent(Event_Timer9_0 + id); - } - else if (curstart && (!newstart)) - { - CancelEvent(Event_Timer9_0 + id); } } diff --git a/src/NDS.h b/src/NDS.h index 976bd26b..28f777e6 100644 --- a/src/NDS.h +++ b/src/NDS.h @@ -40,14 +40,14 @@ enum { Event_LCD = 0, - Event_Timer9_0, + /*Event_Timer9_0, Event_Timer9_1, Event_Timer9_2, Event_Timer9_3, Event_Timer7_0, Event_Timer7_1, Event_Timer7_2, - Event_Timer7_3, + Event_Timer7_3,*/ Event_MAX }; @@ -149,6 +149,8 @@ void ResumeCPU(u32 cpu, u32 mask); void CheckDMAs(u32 cpu, u32 mode); +void RunTimingCriticalDevices(u32 cpu, s32 cycles); + u8 ARM9Read8(u32 addr); u16 ARM9Read16(u32 addr); u32 ARM9Read32(u32 addr); diff --git a/src/NDSCart.cpp b/src/NDSCart.cpp index 16e84353..29da046a 100644 --- a/src/NDSCart.cpp +++ b/src/NDSCart.cpp @@ -565,11 +565,15 @@ bool Init() { if (!NDSCart_SRAM::Init()) return false; + CartROM = NULL; + return true; } void DeInit() { + if (CartROM) delete[] CartROM; + NDSCart_SRAM::DeInit(); } @@ -606,6 +610,8 @@ bool LoadROM(const char* path, bool direct) // TODO: streaming mode? for really big ROMs or systems with limited RAM // for now we're lazy + if (CartROM) delete[] CartROM; + FILE* f = fopen(path, "rb"); if (!f) {