Commit 343797f4 authored by StapleButter's avatar StapleButter
Browse files

* somewhat proper event scheduler

* support for timers
* fixes, additions, shit
parent a14c0120
......@@ -38,6 +38,8 @@ ARM::~ARM()
void ARM::Reset()
{
Cycles = 0;
for (int i = 0; i < 16; i++)
R[i] = 0;
......@@ -49,22 +51,25 @@ void ARM::Reset()
JumpTo(ExceptionBase);
}
void ARM::JumpTo(u32 addr)
void ARM::JumpTo(u32 addr, bool restorecpsr)
{
// pipeline shit
//printf("jump from %08X to %08X\n", R[15] - ((CPSR&0x20)?4:8), addr);
if (restorecpsr)
{
RestoreCPSR();
if (CPSR & 0x20) addr |= 0x1;
else addr &= ~0x1;
}
if (addr&1)
if (addr & 0x1)
{
addr &= ~1;
addr &= ~0x1;
NextInstr = Read16(addr);
R[15] = addr+2;
CPSR |= 0x20;
}
else
{
addr &= ~3;
addr &= ~0x3;
NextInstr = Read32(addr);
R[15] = addr+4;
CPSR &= ~0x20;
......@@ -191,49 +196,57 @@ void ARM::TriggerIRQ()
UpdateMode(oldcpsr, CPSR);
R_IRQ[2] = oldcpsr;
R[14] = R[15];// - (oldcpsr & 0x20 ? 0 : 4);
R[14] = R[15] + (oldcpsr & 0x20 ? 2 : 0);
JumpTo(ExceptionBase + 0x18);
}
s32 ARM::Execute(s32 cycles)
{
while (cycles > 0)
s32 cyclesrun = 0;
while (cyclesrun < cycles)
{
if (CPSR & 0x20) // THUMB
{
// prefetch
CurInstr = NextInstr;
NextInstr = Read16(R[15]);
//cyclesrun += MemWaitstate(0, R[15]);
R[15] += 2;
Cycles = cyclesrun;
// actually execute
u32 icode = (CurInstr >> 6);
cycles -= ARMInterpreter::THUMBInstrTable[icode](this);
cyclesrun += ARMInterpreter::THUMBInstrTable[icode](this);
}
else
{
// prefetch
CurInstr = NextInstr;
NextInstr = Read32(R[15]);
//cyclesrun += MemWaitstate(1, R[15]);
R[15] += 4;
Cycles = cyclesrun;
// actually execute
if (CheckCondition(CurInstr >> 28))
{
u32 icode = ((CurInstr >> 4) & 0xF) | ((CurInstr >> 16) & 0xFF0);
cycles -= ARMInterpreter::ARMInstrTable[icode](this);
cyclesrun += ARMInterpreter::ARMInstrTable[icode](this);
}
else if ((CurInstr & 0xFE000000) == 0xFA000000)
{
cycles -= ARMInterpreter::A_BLX_IMM(this);
cyclesrun += ARMInterpreter::A_BLX_IMM(this);
}
else
{
// not executing it. oh well
cycles -= 1; // 1S. todo: check
cyclesrun += 1; // 1S. todo: check
}
}
}
return cycles;
return cyclesrun;
}
......@@ -21,7 +21,7 @@ public:
void Reset();
void JumpTo(u32 addr);
void JumpTo(u32 addr, bool restorecpsr = false);
void RestoreCPSR();
s32 Execute(s32 cycles);
......@@ -145,6 +145,8 @@ public:
u32 Num;
s32 Cycles;
u32 R[16]; // heh
u32 CPSR;
u32 R_FIQ[8]; // holding SPSR too
......
......@@ -172,6 +172,24 @@ s32 A_MRC(ARM* cpu)
s32 T_SVC(ARM* cpu)
{
u32 oldcpsr = cpu->CPSR;
cpu->CPSR &= ~0xFF;
cpu->CPSR |= 0xD3;
cpu->UpdateMode(oldcpsr, cpu->CPSR);
cpu->R_SVC[2] = oldcpsr;
cpu->R[14] = cpu->R[15] - 2;
cpu->JumpTo(cpu->ExceptionBase + 0x08);
printf("SWI %02X\n", (cpu->CurInstr & 0xFF));
return C_S(2) + C_N(1);
}
#define INSTRFUNC_PROTO(x) s32 (*x)(ARM* cpu)
#include "ARM_InstrTable.h"
#undef INSTRFUNC_PROTO
......
......@@ -268,8 +268,7 @@ s32 A_##x##_REG_ROR_REG(ARM* cpu) \
!res); \
if (((cpu->CurInstr>>12) & 0xF) == 15) \
{ \
cpu->JumpTo(res); \
cpu->RestoreCPSR(); \
cpu->JumpTo(res, true); \
return C_S(2) + C_I(c) + C_N(1); \
} \
else \
......@@ -302,8 +301,7 @@ A_IMPLEMENT_ALU_OP(AND)
!res); \
if (((cpu->CurInstr>>12) & 0xF) == 15) \
{ \
cpu->JumpTo(res); \
cpu->RestoreCPSR(); \
cpu->JumpTo(res, true); \
return C_S(2) + C_I(c) + C_N(1); \
} \
else \
......@@ -338,8 +336,7 @@ A_IMPLEMENT_ALU_OP(EOR)
OVERFLOW_SUB(a, b, res)); \
if (((cpu->CurInstr>>12) & 0xF) == 15) \
{ \
cpu->JumpTo(res); \
cpu->RestoreCPSR(); \
cpu->JumpTo(res, true); \
return C_S(2) + C_I(c) + C_N(1); \
} \
else \
......@@ -374,8 +371,7 @@ A_IMPLEMENT_ALU_OP(SUB)
OVERFLOW_SUB(b, a, res)); \
if (((cpu->CurInstr>>12) & 0xF) == 15) \
{ \
cpu->JumpTo(res); \
cpu->RestoreCPSR(); \
cpu->JumpTo(res, true); \
return C_S(2) + C_I(c) + C_N(1); \
} \
else \
......@@ -410,8 +406,7 @@ A_IMPLEMENT_ALU_OP(RSB)
OVERFLOW_ADD(a, b, res)); \
if (((cpu->CurInstr>>12) & 0xF) == 15) \
{ \
cpu->JumpTo(res); \
cpu->RestoreCPSR(); \
cpu->JumpTo(res, true); \
return C_S(2) + C_I(c) + C_N(1); \
} \
else \
......@@ -448,8 +443,7 @@ A_IMPLEMENT_ALU_OP(ADD)
OVERFLOW_ADD(a, b, res_tmp) | OVERFLOW_ADD(res_tmp, carry, res)); \
if (((cpu->CurInstr>>12) & 0xF) == 15) \
{ \
cpu->JumpTo(res); \
cpu->RestoreCPSR(); \
cpu->JumpTo(res, true); \
return C_S(2) + C_I(c) + C_N(1); \
} \
else \
......@@ -486,8 +480,7 @@ A_IMPLEMENT_ALU_OP(ADC)
OVERFLOW_SUB(a, b, res_tmp) | OVERFLOW_SUB(res_tmp, carry, res)); \
if (((cpu->CurInstr>>12) & 0xF) == 15) \
{ \
cpu->JumpTo(res); \
cpu->RestoreCPSR(); \
cpu->JumpTo(res, true); \
return C_S(2) + C_I(c) + C_N(1); \
} \
else \
......@@ -524,8 +517,7 @@ A_IMPLEMENT_ALU_OP(SBC)
OVERFLOW_SUB(b, a, res_tmp) | OVERFLOW_SUB(res_tmp, carry, res)); \
if (((cpu->CurInstr>>12) & 0xF) == 15) \
{ \
cpu->JumpTo(res); \
cpu->RestoreCPSR(); \
cpu->JumpTo(res, true); \
return C_S(2) + C_I(c) + C_N(1); \
} \
else \
......@@ -602,8 +594,7 @@ A_IMPLEMENT_ALU_TEST(CMN)
!res); \
if (((cpu->CurInstr>>12) & 0xF) == 15) \
{ \
cpu->JumpTo(res); \
cpu->RestoreCPSR(); \
cpu->JumpTo(res, true); \
return C_S(2) + C_I(c) + C_N(1); \
} \
else \
......@@ -632,8 +623,7 @@ A_IMPLEMENT_ALU_OP(ORR)
!b); \
if (((cpu->CurInstr>>12) & 0xF) == 15) \
{ \
cpu->JumpTo(b); \
cpu->RestoreCPSR(); \
cpu->JumpTo(b, true); \
return C_S(2) + C_I(c) + C_N(1); \
} \
else \
......@@ -666,8 +656,7 @@ A_IMPLEMENT_ALU_OP(MOV)
!res); \
if (((cpu->CurInstr>>12) & 0xF) == 15) \
{ \
cpu->JumpTo(res); \
cpu->RestoreCPSR(); \
cpu->JumpTo(res, true); \
return C_S(2) + C_I(c) + C_N(1); \
} \
else \
......@@ -698,8 +687,7 @@ A_IMPLEMENT_ALU_OP(BIC)
!b); \
if (((cpu->CurInstr>>12) & 0xF) == 15) \
{ \
cpu->JumpTo(b); \
cpu->RestoreCPSR(); \
cpu->JumpTo(b, true); \
return C_S(2) + C_I(c) + C_N(1); \
} \
else \
......@@ -1057,7 +1045,7 @@ s32 T_ADD_HIREG(ARM* cpu)
if (rd == 15)
{
cpu->JumpTo(a + b);
cpu->JumpTo((a + b) | 1);
return C_S(2) + C_N(1);
}
else
......@@ -1090,7 +1078,7 @@ s32 T_MOV_HIREG(ARM* cpu)
if (rd == 15)
{
cpu->JumpTo(cpu->R[rs]);
cpu->JumpTo(cpu->R[rs] | 1);
return C_S(2) + C_N(1);
}
else
......@@ -1103,7 +1091,7 @@ s32 T_MOV_HIREG(ARM* cpu)
s32 T_ADD_PCREL(ARM* cpu)
{
u32 val = cpu->R[15] = ~2;
u32 val = cpu->R[15] & ~2;
val += ((cpu->CurInstr & 0xFF) << 2);
cpu->R[(cpu->CurInstr >> 8) & 0x7] = val;
return C_S(1);
......
......@@ -196,7 +196,7 @@ A_IMPLEMENT_WB_LDRSTR(LDRB)
#define A_STRH \
offset += cpu->R[(cpu->CurInstr>>16) & 0xF]; \
cpu->Write16(offset, cpu->R[(cpu->CurInstr>>12) & 0xF]); \
if (cpu->CurInstr & (1<<24)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; \
if (cpu->CurInstr & (1<<21)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; \
return C_N(2) + cpu->MemWaitstate(2, offset);
#define A_STRH_POST \
......@@ -225,7 +225,7 @@ A_IMPLEMENT_WB_LDRSTR(LDRB)
#define A_STRD \
offset += cpu->R[(cpu->CurInstr>>16) & 0xF]; \
if (cpu->CurInstr & (1<<24)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; \
if (cpu->CurInstr & (1<<21)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; \
u32 r = (cpu->CurInstr>>12) & 0xF; \
cpu->Write32(offset , cpu->R[r ]); \
cpu->Write32(offset+4, cpu->R[r+1]); \
......@@ -242,7 +242,7 @@ A_IMPLEMENT_WB_LDRSTR(LDRB)
#define A_LDRH \
offset += cpu->R[(cpu->CurInstr>>16) & 0xF]; \
cpu->R[(cpu->CurInstr>>12) & 0xF] = cpu->Read16(offset); \
if (cpu->CurInstr & (1<<24)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; \
if (cpu->CurInstr & (1<<21)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; \
return C_N(2) + cpu->MemWaitstate(2, offset);
#define A_LDRH_POST \
......@@ -254,7 +254,7 @@ A_IMPLEMENT_WB_LDRSTR(LDRB)
#define A_LDRSB \
offset += cpu->R[(cpu->CurInstr>>16) & 0xF]; \
cpu->R[(cpu->CurInstr>>12) & 0xF] = (s32)(s8)cpu->Read8(offset); \
if (cpu->CurInstr & (1<<24)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; \
if (cpu->CurInstr & (1<<21)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; \
return C_N(2) + cpu->MemWaitstate(3, offset);
#define A_LDRSB_POST \
......@@ -266,7 +266,7 @@ A_IMPLEMENT_WB_LDRSTR(LDRB)
#define A_LDRSH \
offset += cpu->R[(cpu->CurInstr>>16) & 0xF]; \
cpu->R[(cpu->CurInstr>>12) & 0xF] = (s32)(s16)cpu->Read16(offset); \
if (cpu->CurInstr & (1<<24)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; \
if (cpu->CurInstr & (1<<21)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; \
return C_N(2) + cpu->MemWaitstate(2, offset);
#define A_LDRSH_POST \
......@@ -310,6 +310,33 @@ A_IMPLEMENT_HD_LDRSTR(LDRSH)
s32 A_SWP(ARM* cpu)
{
u32 base = cpu->R[(cpu->CurInstr >> 16) & 0xF];
u32 val = cpu->Read32(base);
cpu->R[(cpu->CurInstr >> 12) & 0xF] = ROR(val, 8*(base&0x3));
cpu->Write32(base, cpu->R[cpu->CurInstr & 0xF]);
// the 1S is a code cycle. TODO
return C_S(1) + C_N(2) + C_I(1) + 2*cpu->MemWaitstate(3, base);
}
s32 A_SWPB(ARM* cpu)
{
u32 base = cpu->R[(cpu->CurInstr >> 16) & 0xF];
cpu->R[(cpu->CurInstr >> 12) & 0xF] = cpu->Read8(base);
cpu->Write8(base, cpu->R[cpu->CurInstr & 0xF]);
// the 1S is a code cycle. TODO
return C_S(1) + C_N(2) + C_I(1) + 2*cpu->MemWaitstate(3, base);
}
s32 A_LDM(ARM* cpu)
{
u32 base = cpu->R[(cpu->CurInstr >> 16) & 0xF];
......@@ -359,8 +386,7 @@ s32 A_LDM(ARM* cpu)
if (cpu->Num == 1)
pc &= ~0x1;
cpu->JumpTo(pc);
if (cpu->CurInstr & (1<<22)) cpu->RestoreCPSR();
cpu->JumpTo(pc, cpu->CurInstr & (1<<22));
}
if ((cpu->CurInstr & (1<<22)) && !(cpu->CurInstr & (1<<15)))
......
......@@ -40,6 +40,9 @@ A_PROTO_HD_LDRSTR(LDRSH)
s32 A_LDM(ARM* cpu);
s32 A_STM(ARM* cpu);
s32 A_SWP(ARM* cpu);
s32 A_SWPB(ARM* cpu);
s32 T_LDR_PCREL(ARM* cpu);
......
......@@ -102,7 +102,7 @@ INSTRFUNC_PROTO(ARMInstrTable[4096]) =
// 0001 0000 0000
A_MRS, A_UNK, A_UNK, A_UNK,
A_UNK, A_UNK, A_UNK, A_UNK,
A_UNK, A_UNK, A_UNK, A_STRH_REG,
A_UNK, A_SWP, A_UNK, A_STRH_REG,
A_UNK, A_LDRD_REG, A_UNK, A_STRD_REG,
// 0001 0001 0000
......@@ -126,7 +126,7 @@ INSTRFUNC_PROTO(ARMInstrTable[4096]) =
// 0001 0100 0000
A_MRS, A_UNK, A_UNK, A_UNK,
A_UNK, A_UNK, A_UNK, A_UNK,
A_UNK, A_UNK, A_UNK, A_STRH_IMM,
A_UNK, A_SWPB, A_UNK, A_STRH_IMM,
A_UNK, A_LDRD_IMM, A_UNK, A_STRD_IMM,
// 0001 0101 0000
......@@ -1910,7 +1910,7 @@ INSTRFUNC_PROTO(THUMBInstrTable[1024]) =
T_BCOND, T_BCOND, T_BCOND, T_BCOND,
T_BCOND, T_BCOND, T_BCOND, T_BCOND,
T_UNK, T_UNK, T_UNK, T_UNK,
T_UNK, T_UNK, T_UNK, T_UNK,
T_SVC, T_SVC, T_SVC, T_SVC,
// 1110 0000 00
T_B, T_B, T_B, T_B,
......
......@@ -23,7 +23,7 @@ void UpdateDTCMSetting()
if (Control & (1<<16))
{
NDS::ARM9DTCMBase = DTCMSetting & 0xFFFFF000;
NDS::ARM9DTCMSize = 256 << (DTCMSetting & 0x3E);
NDS::ARM9DTCMSize = 0x200 << ((DTCMSetting >> 1) & 0x1F);
printf("DTCM enabled at %08X, size %X\n", NDS::ARM9DTCMBase, NDS::ARM9DTCMSize);
}
else
......@@ -38,8 +38,8 @@ void UpdateITCMSetting()
{
if (Control & (1<<18))
{
NDS::ARM9ITCMSize = 256 << (DTCMSetting & 0x3E);
printf("ITCM enabled at %08X, size %X\n", 0, NDS::ARM9DTCMSize);
NDS::ARM9ITCMSize = 0x200 << ((ITCMSetting >> 1) & 0x1F);
printf("ITCM enabled at %08X, size %X\n", 0, NDS::ARM9ITCMSize);
}
else
{
......
......@@ -9,10 +9,17 @@
namespace NDS
{
SchedEvent SchedBuffer[SCHED_BUF_LEN];
SchedEvent* SchedQueue;
bool NeedReschedule;
ARM* ARM9;
ARM* ARM7;
s32 ARM9Cycles, ARM7Cycles;
s32 CompensatedCycles;
s32 SchedCycles;
u8 ARM9BIOS[0x1000];
u8 ARM7BIOS[0x4000];
......@@ -37,8 +44,12 @@ u32 ARM9DTCMBase, ARM9DTCMSize;
u32 IME[2];
u32 IE[2], IF[2];
Timer Timers[8];
u16 IPCSync9, IPCSync7;
u16 _soundbias; // temp
bool Running;
......@@ -103,10 +114,18 @@ void Reset()
ARM7->Reset();
CP15::Reset();
memset(Timers, 0, 8*sizeof(Timer));
SPI::Reset();
memset(SchedBuffer, 0, sizeof(SchedEvent)*SCHED_BUF_LEN);
SchedQueue = NULL;
ARM9Cycles = 0;
ARM7Cycles = 0;
SchedCycles = 0;
_soundbias = 0;
Running = true; // hax
}
......@@ -116,15 +135,142 @@ void RunFrame()
{
s32 framecycles = 560190<<1;
// very gross and temp. loop
const s32 maxcycles = 16;
while (Running && framecycles>0)
{
ARM9Cycles = ARM9->Execute(32 + ARM9Cycles);
ARM7Cycles = ARM7->Execute(16 + ARM7Cycles);
//ARM9Cycles = ARM9->Execute(32 + ARM9Cycles);
//ARM7Cycles = ARM7->Execute(16 + ARM7Cycles);
//framecycles -= 32;
s32 cyclestorun = maxcycles;
// TODO: scheduler integration here
CompensatedCycles = ARM9Cycles;
s32 c9 = ARM9->Execute(cyclestorun - ARM9Cycles);
ARM9Cycles = c9 - cyclestorun;
c9 -= CompensatedCycles;
s32 c7 = ARM7->Execute((c9 - ARM7Cycles) >> 1) << 1;
ARM7Cycles = c7 - c9;
RunEvents(c9);
framecycles -= cyclestorun;
}
}
SchedEvent* ScheduleEvent(s32 Delay, void (*Func)(u32), u32 Param)
{
// find a free entry
u32 entry = -1;
for (int i = 0; i < SCHED_BUF_LEN; i++)
{
if (SchedBuffer[i].Func == NULL)
{
entry = i;
break;
}
}
if (entry == -1)
{
printf("!! SCHEDULER BUFFER FULL\n");
return NULL;
}
SchedEvent* evt = &SchedBuffer[entry];
evt->Func = Func;
evt->Param = Param;
SchedEvent* cur = SchedQueue;
SchedEvent* prev = NULL;
for (;;)
{
if (cur == NULL) break;
if (cur->Delay > Delay) break;
Delay -= cur->Delay;
prev = cur;
cur = cur->NextEvent;
}
// so, we found it. we insert our event before 'cur'.
evt->Delay = Delay;
if (cur == NULL)
{
if (prev == NULL)
{
// list empty
SchedQueue = evt;
evt->PrevEvent = NULL;
evt->NextEvent = NULL;
}
else
{
// inserting at the end of the list
evt->PrevEvent = prev;
evt->NextEvent = NULL;
prev->NextEvent = evt;
}
}
else
{
evt->NextEvent = cur;
evt->PrevEvent = cur->PrevEvent;
framecycles -= 32;
if (evt->PrevEvent)
evt->PrevEvent->NextEvent = evt;
cur->PrevEvent = evt;
cur->Delay -= evt->Delay;
}
return evt;
}
void CancelEvent(SchedEvent* event)
{
event->Func = NULL;
// unlink
if (event->PrevEvent)
event->PrevEvent->NextEvent = event->NextEvent;
else
SchedQueue = event->NextEvent;
if (event->NextEvent)
event->NextEvent->PrevEvent = event->PrevEvent;
}
void RunEvents(s32 cycles)
{
SchedCycles += cycles;
SchedEvent* evt = SchedQueue;
while (evt && evt->Delay <= SchedCycles)
{
evt->Func(evt->Param);
evt->Func = NULL;
SchedCycles -= evt->Delay;
evt = evt->NextEvent;
}
SchedQueue = evt;
if (evt) evt->PrevEvent = NULL;
}
void CompensateARM7()
{
s32 c9 = ARM9->Cycles - CompensatedCycles;
CompensatedCycles = ARM9->Cycles;
s32 c7 = ARM7->Execute((c9 - ARM7Cycles) >> 1) << 1;
ARM7Cycles = c7 - c9;
RunEvents(c9);
}
......@@ -182,6 +328,73 @@ void TriggerIRQ(u32 cpu, u32 irq)
const s32 TimerPrescaler[4] = {2, 128, 512, 2048};
void TimerIncrement(u32 param)
{
Timer* timer = &Timers[param];
u32 tid = param & 0x3;
u32 cpu = param >> 2;