make timers not suck. fixes issues (Worms2 intro FMV plays at the right speed, aging cart tests get further...)

This commit is contained in:
StapleButter 2017-03-20 17:39:42 +01:00
parent f38bc94011
commit a56bf5c76c
7 changed files with 95 additions and 89 deletions

View File

@ -40,7 +40,6 @@ TODO LIST
IMMEDIATE TODO LIST (prior release 1.0)
* UI
* make timers suck less
TODO LIST FOR LATER

View File

@ -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)

View File

@ -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--;

View File

@ -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);
}

View File

@ -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<<i)))
@ -382,9 +371,6 @@ void RunFrame()
if (cycles > 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);
}
}

View File

@ -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);

View File

@ -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)
{