make timers not suck. fixes issues (Worms2 intro FMV plays at the right speed, aging cart tests get further...)
This commit is contained in:
parent
f38bc94011
commit
a56bf5c76c
|
@ -40,7 +40,6 @@ TODO LIST
|
|||
IMMEDIATE TODO LIST (prior release 1.0)
|
||||
|
||||
* UI
|
||||
* make timers suck less
|
||||
|
||||
|
||||
TODO LIST FOR LATER
|
||||
|
|
25
src/ARM.cpp
25
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)
|
||||
|
|
13
src/DMA.cpp
13
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--;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
130
src/NDS.cpp
130
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<<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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue