* somewhat proper event scheduler

* support for timers
* fixes, additions, shit
This commit is contained in:
StapleButter 2016-12-05 17:08:24 +01:00
parent a14c01208a
commit 343797f47d
12 changed files with 488 additions and 75 deletions

43
ARM.cpp
View File

@ -38,6 +38,8 @@ ARM::~ARM()
void ARM::Reset() void ARM::Reset()
{ {
Cycles = 0;
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
R[i] = 0; R[i] = 0;
@ -49,22 +51,25 @@ void ARM::Reset()
JumpTo(ExceptionBase); JumpTo(ExceptionBase);
} }
void ARM::JumpTo(u32 addr) void ARM::JumpTo(u32 addr, bool restorecpsr)
{ {
// pipeline shit if (restorecpsr)
//printf("jump from %08X to %08X\n", R[15] - ((CPSR&0x20)?4:8), addr);
if (addr&1)
{ {
addr &= ~1; RestoreCPSR();
if (CPSR & 0x20) addr |= 0x1;
else addr &= ~0x1;
}
if (addr & 0x1)
{
addr &= ~0x1;
NextInstr = Read16(addr); NextInstr = Read16(addr);
R[15] = addr+2; R[15] = addr+2;
CPSR |= 0x20; CPSR |= 0x20;
} }
else else
{ {
addr &= ~3; addr &= ~0x3;
NextInstr = Read32(addr); NextInstr = Read32(addr);
R[15] = addr+4; R[15] = addr+4;
CPSR &= ~0x20; CPSR &= ~0x20;
@ -191,49 +196,57 @@ void ARM::TriggerIRQ()
UpdateMode(oldcpsr, CPSR); UpdateMode(oldcpsr, CPSR);
R_IRQ[2] = oldcpsr; R_IRQ[2] = oldcpsr;
R[14] = R[15];// - (oldcpsr & 0x20 ? 0 : 4); R[14] = R[15] + (oldcpsr & 0x20 ? 2 : 0);
JumpTo(ExceptionBase + 0x18); JumpTo(ExceptionBase + 0x18);
} }
s32 ARM::Execute(s32 cycles) s32 ARM::Execute(s32 cycles)
{ {
while (cycles > 0) s32 cyclesrun = 0;
while (cyclesrun < cycles)
{ {
if (CPSR & 0x20) // THUMB if (CPSR & 0x20) // THUMB
{ {
// prefetch // prefetch
CurInstr = NextInstr; CurInstr = NextInstr;
NextInstr = Read16(R[15]); NextInstr = Read16(R[15]);
//cyclesrun += MemWaitstate(0, R[15]);
R[15] += 2; R[15] += 2;
Cycles = cyclesrun;
// actually execute // actually execute
u32 icode = (CurInstr >> 6); u32 icode = (CurInstr >> 6);
cycles -= ARMInterpreter::THUMBInstrTable[icode](this); cyclesrun += ARMInterpreter::THUMBInstrTable[icode](this);
} }
else else
{ {
// prefetch // prefetch
CurInstr = NextInstr; CurInstr = NextInstr;
NextInstr = Read32(R[15]); NextInstr = Read32(R[15]);
//cyclesrun += MemWaitstate(1, R[15]);
R[15] += 4; R[15] += 4;
Cycles = cyclesrun;
// actually execute // actually execute
if (CheckCondition(CurInstr >> 28)) if (CheckCondition(CurInstr >> 28))
{ {
u32 icode = ((CurInstr >> 4) & 0xF) | ((CurInstr >> 16) & 0xFF0); u32 icode = ((CurInstr >> 4) & 0xF) | ((CurInstr >> 16) & 0xFF0);
cycles -= ARMInterpreter::ARMInstrTable[icode](this); cyclesrun += ARMInterpreter::ARMInstrTable[icode](this);
} }
else if ((CurInstr & 0xFE000000) == 0xFA000000) else if ((CurInstr & 0xFE000000) == 0xFA000000)
{ {
cycles -= ARMInterpreter::A_BLX_IMM(this); cyclesrun += ARMInterpreter::A_BLX_IMM(this);
} }
else else
{ {
// not executing it. oh well // not executing it. oh well
cycles -= 1; // 1S. todo: check cyclesrun += 1; // 1S. todo: check
} }
} }
} }
return cycles; return cyclesrun;
} }

4
ARM.h
View File

@ -21,7 +21,7 @@ public:
void Reset(); void Reset();
void JumpTo(u32 addr); void JumpTo(u32 addr, bool restorecpsr = false);
void RestoreCPSR(); void RestoreCPSR();
s32 Execute(s32 cycles); s32 Execute(s32 cycles);
@ -145,6 +145,8 @@ public:
u32 Num; u32 Num;
s32 Cycles;
u32 R[16]; // heh u32 R[16]; // heh
u32 CPSR; u32 CPSR;
u32 R_FIQ[8]; // holding SPSR too u32 R_FIQ[8]; // holding SPSR too

View File

@ -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) #define INSTRFUNC_PROTO(x) s32 (*x)(ARM* cpu)
#include "ARM_InstrTable.h" #include "ARM_InstrTable.h"
#undef INSTRFUNC_PROTO #undef INSTRFUNC_PROTO

View File

@ -268,8 +268,7 @@ s32 A_##x##_REG_ROR_REG(ARM* cpu) \
!res); \ !res); \
if (((cpu->CurInstr>>12) & 0xF) == 15) \ if (((cpu->CurInstr>>12) & 0xF) == 15) \
{ \ { \
cpu->JumpTo(res); \ cpu->JumpTo(res, true); \
cpu->RestoreCPSR(); \
return C_S(2) + C_I(c) + C_N(1); \ return C_S(2) + C_I(c) + C_N(1); \
} \ } \
else \ else \
@ -302,8 +301,7 @@ A_IMPLEMENT_ALU_OP(AND)
!res); \ !res); \
if (((cpu->CurInstr>>12) & 0xF) == 15) \ if (((cpu->CurInstr>>12) & 0xF) == 15) \
{ \ { \
cpu->JumpTo(res); \ cpu->JumpTo(res, true); \
cpu->RestoreCPSR(); \
return C_S(2) + C_I(c) + C_N(1); \ return C_S(2) + C_I(c) + C_N(1); \
} \ } \
else \ else \
@ -338,8 +336,7 @@ A_IMPLEMENT_ALU_OP(EOR)
OVERFLOW_SUB(a, b, res)); \ OVERFLOW_SUB(a, b, res)); \
if (((cpu->CurInstr>>12) & 0xF) == 15) \ if (((cpu->CurInstr>>12) & 0xF) == 15) \
{ \ { \
cpu->JumpTo(res); \ cpu->JumpTo(res, true); \
cpu->RestoreCPSR(); \
return C_S(2) + C_I(c) + C_N(1); \ return C_S(2) + C_I(c) + C_N(1); \
} \ } \
else \ else \
@ -374,8 +371,7 @@ A_IMPLEMENT_ALU_OP(SUB)
OVERFLOW_SUB(b, a, res)); \ OVERFLOW_SUB(b, a, res)); \
if (((cpu->CurInstr>>12) & 0xF) == 15) \ if (((cpu->CurInstr>>12) & 0xF) == 15) \
{ \ { \
cpu->JumpTo(res); \ cpu->JumpTo(res, true); \
cpu->RestoreCPSR(); \
return C_S(2) + C_I(c) + C_N(1); \ return C_S(2) + C_I(c) + C_N(1); \
} \ } \
else \ else \
@ -410,8 +406,7 @@ A_IMPLEMENT_ALU_OP(RSB)
OVERFLOW_ADD(a, b, res)); \ OVERFLOW_ADD(a, b, res)); \
if (((cpu->CurInstr>>12) & 0xF) == 15) \ if (((cpu->CurInstr>>12) & 0xF) == 15) \
{ \ { \
cpu->JumpTo(res); \ cpu->JumpTo(res, true); \
cpu->RestoreCPSR(); \
return C_S(2) + C_I(c) + C_N(1); \ return C_S(2) + C_I(c) + C_N(1); \
} \ } \
else \ else \
@ -448,8 +443,7 @@ A_IMPLEMENT_ALU_OP(ADD)
OVERFLOW_ADD(a, b, res_tmp) | OVERFLOW_ADD(res_tmp, carry, res)); \ OVERFLOW_ADD(a, b, res_tmp) | OVERFLOW_ADD(res_tmp, carry, res)); \
if (((cpu->CurInstr>>12) & 0xF) == 15) \ if (((cpu->CurInstr>>12) & 0xF) == 15) \
{ \ { \
cpu->JumpTo(res); \ cpu->JumpTo(res, true); \
cpu->RestoreCPSR(); \
return C_S(2) + C_I(c) + C_N(1); \ return C_S(2) + C_I(c) + C_N(1); \
} \ } \
else \ else \
@ -486,8 +480,7 @@ A_IMPLEMENT_ALU_OP(ADC)
OVERFLOW_SUB(a, b, res_tmp) | OVERFLOW_SUB(res_tmp, carry, res)); \ OVERFLOW_SUB(a, b, res_tmp) | OVERFLOW_SUB(res_tmp, carry, res)); \
if (((cpu->CurInstr>>12) & 0xF) == 15) \ if (((cpu->CurInstr>>12) & 0xF) == 15) \
{ \ { \
cpu->JumpTo(res); \ cpu->JumpTo(res, true); \
cpu->RestoreCPSR(); \
return C_S(2) + C_I(c) + C_N(1); \ return C_S(2) + C_I(c) + C_N(1); \
} \ } \
else \ else \
@ -524,8 +517,7 @@ A_IMPLEMENT_ALU_OP(SBC)
OVERFLOW_SUB(b, a, res_tmp) | OVERFLOW_SUB(res_tmp, carry, res)); \ OVERFLOW_SUB(b, a, res_tmp) | OVERFLOW_SUB(res_tmp, carry, res)); \
if (((cpu->CurInstr>>12) & 0xF) == 15) \ if (((cpu->CurInstr>>12) & 0xF) == 15) \
{ \ { \
cpu->JumpTo(res); \ cpu->JumpTo(res, true); \
cpu->RestoreCPSR(); \
return C_S(2) + C_I(c) + C_N(1); \ return C_S(2) + C_I(c) + C_N(1); \
} \ } \
else \ else \
@ -602,8 +594,7 @@ A_IMPLEMENT_ALU_TEST(CMN)
!res); \ !res); \
if (((cpu->CurInstr>>12) & 0xF) == 15) \ if (((cpu->CurInstr>>12) & 0xF) == 15) \
{ \ { \
cpu->JumpTo(res); \ cpu->JumpTo(res, true); \
cpu->RestoreCPSR(); \
return C_S(2) + C_I(c) + C_N(1); \ return C_S(2) + C_I(c) + C_N(1); \
} \ } \
else \ else \
@ -632,8 +623,7 @@ A_IMPLEMENT_ALU_OP(ORR)
!b); \ !b); \
if (((cpu->CurInstr>>12) & 0xF) == 15) \ if (((cpu->CurInstr>>12) & 0xF) == 15) \
{ \ { \
cpu->JumpTo(b); \ cpu->JumpTo(b, true); \
cpu->RestoreCPSR(); \
return C_S(2) + C_I(c) + C_N(1); \ return C_S(2) + C_I(c) + C_N(1); \
} \ } \
else \ else \
@ -666,8 +656,7 @@ A_IMPLEMENT_ALU_OP(MOV)
!res); \ !res); \
if (((cpu->CurInstr>>12) & 0xF) == 15) \ if (((cpu->CurInstr>>12) & 0xF) == 15) \
{ \ { \
cpu->JumpTo(res); \ cpu->JumpTo(res, true); \
cpu->RestoreCPSR(); \
return C_S(2) + C_I(c) + C_N(1); \ return C_S(2) + C_I(c) + C_N(1); \
} \ } \
else \ else \
@ -698,8 +687,7 @@ A_IMPLEMENT_ALU_OP(BIC)
!b); \ !b); \
if (((cpu->CurInstr>>12) & 0xF) == 15) \ if (((cpu->CurInstr>>12) & 0xF) == 15) \
{ \ { \
cpu->JumpTo(b); \ cpu->JumpTo(b, true); \
cpu->RestoreCPSR(); \
return C_S(2) + C_I(c) + C_N(1); \ return C_S(2) + C_I(c) + C_N(1); \
} \ } \
else \ else \
@ -1057,7 +1045,7 @@ s32 T_ADD_HIREG(ARM* cpu)
if (rd == 15) if (rd == 15)
{ {
cpu->JumpTo(a + b); cpu->JumpTo((a + b) | 1);
return C_S(2) + C_N(1); return C_S(2) + C_N(1);
} }
else else
@ -1090,7 +1078,7 @@ s32 T_MOV_HIREG(ARM* cpu)
if (rd == 15) if (rd == 15)
{ {
cpu->JumpTo(cpu->R[rs]); cpu->JumpTo(cpu->R[rs] | 1);
return C_S(2) + C_N(1); return C_S(2) + C_N(1);
} }
else else
@ -1103,7 +1091,7 @@ s32 T_MOV_HIREG(ARM* cpu)
s32 T_ADD_PCREL(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); val += ((cpu->CurInstr & 0xFF) << 2);
cpu->R[(cpu->CurInstr >> 8) & 0x7] = val; cpu->R[(cpu->CurInstr >> 8) & 0x7] = val;
return C_S(1); return C_S(1);

View File

@ -196,7 +196,7 @@ A_IMPLEMENT_WB_LDRSTR(LDRB)
#define A_STRH \ #define A_STRH \
offset += cpu->R[(cpu->CurInstr>>16) & 0xF]; \ offset += cpu->R[(cpu->CurInstr>>16) & 0xF]; \
cpu->Write16(offset, cpu->R[(cpu->CurInstr>>12) & 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); return C_N(2) + cpu->MemWaitstate(2, offset);
#define A_STRH_POST \ #define A_STRH_POST \
@ -225,7 +225,7 @@ A_IMPLEMENT_WB_LDRSTR(LDRB)
#define A_STRD \ #define A_STRD \
offset += cpu->R[(cpu->CurInstr>>16) & 0xF]; \ 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; \ u32 r = (cpu->CurInstr>>12) & 0xF; \
cpu->Write32(offset , cpu->R[r ]); \ cpu->Write32(offset , cpu->R[r ]); \
cpu->Write32(offset+4, cpu->R[r+1]); \ cpu->Write32(offset+4, cpu->R[r+1]); \
@ -242,7 +242,7 @@ A_IMPLEMENT_WB_LDRSTR(LDRB)
#define A_LDRH \ #define A_LDRH \
offset += cpu->R[(cpu->CurInstr>>16) & 0xF]; \ offset += cpu->R[(cpu->CurInstr>>16) & 0xF]; \
cpu->R[(cpu->CurInstr>>12) & 0xF] = cpu->Read16(offset); \ 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); return C_N(2) + cpu->MemWaitstate(2, offset);
#define A_LDRH_POST \ #define A_LDRH_POST \
@ -254,7 +254,7 @@ A_IMPLEMENT_WB_LDRSTR(LDRB)
#define A_LDRSB \ #define A_LDRSB \
offset += cpu->R[(cpu->CurInstr>>16) & 0xF]; \ offset += cpu->R[(cpu->CurInstr>>16) & 0xF]; \
cpu->R[(cpu->CurInstr>>12) & 0xF] = (s32)(s8)cpu->Read8(offset); \ 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); return C_N(2) + cpu->MemWaitstate(3, offset);
#define A_LDRSB_POST \ #define A_LDRSB_POST \
@ -266,7 +266,7 @@ A_IMPLEMENT_WB_LDRSTR(LDRB)
#define A_LDRSH \ #define A_LDRSH \
offset += cpu->R[(cpu->CurInstr>>16) & 0xF]; \ offset += cpu->R[(cpu->CurInstr>>16) & 0xF]; \
cpu->R[(cpu->CurInstr>>12) & 0xF] = (s32)(s16)cpu->Read16(offset); \ 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); return C_N(2) + cpu->MemWaitstate(2, offset);
#define A_LDRSH_POST \ #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) s32 A_LDM(ARM* cpu)
{ {
u32 base = cpu->R[(cpu->CurInstr >> 16) & 0xF]; u32 base = cpu->R[(cpu->CurInstr >> 16) & 0xF];
@ -359,8 +386,7 @@ s32 A_LDM(ARM* cpu)
if (cpu->Num == 1) if (cpu->Num == 1)
pc &= ~0x1; pc &= ~0x1;
cpu->JumpTo(pc); cpu->JumpTo(pc, cpu->CurInstr & (1<<22));
if (cpu->CurInstr & (1<<22)) cpu->RestoreCPSR();
} }
if ((cpu->CurInstr & (1<<22)) && !(cpu->CurInstr & (1<<15))) if ((cpu->CurInstr & (1<<22)) && !(cpu->CurInstr & (1<<15)))

View File

@ -40,6 +40,9 @@ A_PROTO_HD_LDRSTR(LDRSH)
s32 A_LDM(ARM* cpu); s32 A_LDM(ARM* cpu);
s32 A_STM(ARM* cpu); s32 A_STM(ARM* cpu);
s32 A_SWP(ARM* cpu);
s32 A_SWPB(ARM* cpu);
s32 T_LDR_PCREL(ARM* cpu); s32 T_LDR_PCREL(ARM* cpu);

View File

@ -102,7 +102,7 @@ INSTRFUNC_PROTO(ARMInstrTable[4096]) =
// 0001 0000 0000 // 0001 0000 0000
A_MRS, A_UNK, A_UNK, A_UNK, A_MRS, A_UNK, A_UNK, A_UNK,
A_UNK, 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, A_UNK, A_LDRD_REG, A_UNK, A_STRD_REG,
// 0001 0001 0000 // 0001 0001 0000
@ -126,7 +126,7 @@ INSTRFUNC_PROTO(ARMInstrTable[4096]) =
// 0001 0100 0000 // 0001 0100 0000
A_MRS, A_UNK, A_UNK, A_UNK, A_MRS, A_UNK, A_UNK, A_UNK,
A_UNK, 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, A_UNK, A_LDRD_IMM, A_UNK, A_STRD_IMM,
// 0001 0101 0000 // 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_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_UNK, T_UNK, T_UNK, T_UNK, T_SVC, T_SVC, T_SVC, T_SVC,
// 1110 0000 00 // 1110 0000 00
T_B, T_B, T_B, T_B, T_B, T_B, T_B, T_B,

View File

@ -23,7 +23,7 @@ void UpdateDTCMSetting()
if (Control & (1<<16)) if (Control & (1<<16))
{ {
NDS::ARM9DTCMBase = DTCMSetting & 0xFFFFF000; 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); printf("DTCM enabled at %08X, size %X\n", NDS::ARM9DTCMBase, NDS::ARM9DTCMSize);
} }
else else
@ -38,8 +38,8 @@ void UpdateITCMSetting()
{ {
if (Control & (1<<18)) if (Control & (1<<18))
{ {
NDS::ARM9ITCMSize = 256 << (DTCMSetting & 0x3E); NDS::ARM9ITCMSize = 0x200 << ((ITCMSetting >> 1) & 0x1F);
printf("ITCM enabled at %08X, size %X\n", 0, NDS::ARM9DTCMSize); printf("ITCM enabled at %08X, size %X\n", 0, NDS::ARM9ITCMSize);
} }
else else
{ {

342
NDS.cpp
View File

@ -9,10 +9,17 @@
namespace NDS namespace NDS
{ {
SchedEvent SchedBuffer[SCHED_BUF_LEN];
SchedEvent* SchedQueue;
bool NeedReschedule;
ARM* ARM9; ARM* ARM9;
ARM* ARM7; ARM* ARM7;
s32 ARM9Cycles, ARM7Cycles; s32 ARM9Cycles, ARM7Cycles;
s32 CompensatedCycles;
s32 SchedCycles;
u8 ARM9BIOS[0x1000]; u8 ARM9BIOS[0x1000];
u8 ARM7BIOS[0x4000]; u8 ARM7BIOS[0x4000];
@ -37,8 +44,12 @@ u32 ARM9DTCMBase, ARM9DTCMSize;
u32 IME[2]; u32 IME[2];
u32 IE[2], IF[2]; u32 IE[2], IF[2];
Timer Timers[8];
u16 IPCSync9, IPCSync7; u16 IPCSync9, IPCSync7;
u16 _soundbias; // temp
bool Running; bool Running;
@ -103,10 +114,18 @@ void Reset()
ARM7->Reset(); ARM7->Reset();
CP15::Reset(); CP15::Reset();
memset(Timers, 0, 8*sizeof(Timer));
SPI::Reset(); SPI::Reset();
memset(SchedBuffer, 0, sizeof(SchedEvent)*SCHED_BUF_LEN);
SchedQueue = NULL;
ARM9Cycles = 0; ARM9Cycles = 0;
ARM7Cycles = 0; ARM7Cycles = 0;
SchedCycles = 0;
_soundbias = 0;
Running = true; // hax Running = true; // hax
} }
@ -116,17 +135,144 @@ void RunFrame()
{ {
s32 framecycles = 560190<<1; s32 framecycles = 560190<<1;
// very gross and temp. loop const s32 maxcycles = 16;
while (Running && framecycles>0) while (Running && framecycles>0)
{ {
ARM9Cycles = ARM9->Execute(32 + ARM9Cycles); //ARM9Cycles = ARM9->Execute(32 + ARM9Cycles);
ARM7Cycles = ARM7->Execute(16 + ARM7Cycles); //ARM7Cycles = ARM7->Execute(16 + ARM7Cycles);
framecycles -= 32; //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;
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);
}
void Halt() void Halt()
{ {
@ -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;
for (;;)
{
timer->Counter++;
if (param==7)printf("timer%d increment %04X %04X %04X\n", param, timer->Control, timer->Counter, timer->Reload);
if (tid == (param&0x3))
timer->Event = ScheduleEvent(TimerPrescaler[timer->Control&0x3], TimerIncrement, param);
if (timer->Counter == 0)
{
timer->Counter = timer->Reload;
if (timer->Control & (1<<6))
TriggerIRQ(cpu, IRQ_Timer0 + tid);
// cascade
if (tid == 3)
break;
timer++;
if ((timer->Control & 0x84) != 0x84)
break;
tid++;
continue;
}
break;
}
}
void TimerStart(u32 id, u16 cnt)
{
Timer* timer = &Timers[id];
u16 curstart = timer->Control & (1<<7);
u16 newstart = cnt & (1<<7);
printf("timer%d start: %04X %04X\n", id, timer->Control, cnt);
timer->Control = cnt;
if ((!curstart) && newstart)
{
// start the timer, if it's not a cascading timer
if (!(cnt & (1<<2)))
{
timer->Counter = timer->Reload;
timer->Event = ScheduleEvent(TimerPrescaler[cnt&0x3], TimerIncrement, id);
}
else
timer->Event = NULL;
}
else if (curstart && !newstart)
{
if (timer->Event)
CancelEvent(timer->Event);
}
}
u8 ARM9Read8(u32 addr) u8 ARM9Read8(u32 addr)
{ {
if ((addr & 0xFFFFF000) == 0xFFFF0000) if ((addr & 0xFFFFF000) == 0xFFFF0000)
@ -245,6 +458,15 @@ u16 ARM9Read16(u32 addr)
case 0x04000000: case 0x04000000:
switch (addr) switch (addr)
{ {
case 0x04000100: return Timers[0].Counter;
case 0x04000102: return Timers[0].Control;
case 0x04000104: return Timers[1].Counter;
case 0x04000106: return Timers[1].Control;
case 0x04000108: return Timers[2].Counter;
case 0x0400010A: return Timers[2].Control;
case 0x0400010C: return Timers[3].Counter;
case 0x0400010E: return Timers[3].Control;
case 0x04000180: return IPCSync9; case 0x04000180: return IPCSync9;
} }
} }
@ -268,6 +490,20 @@ u32 ARM9Read32(u32 addr)
return *(u32*)&ARM9DTCM[(addr - ARM9DTCMBase) & 0x3FFF]; return *(u32*)&ARM9DTCM[(addr - ARM9DTCMBase) & 0x3FFF];
} }
if (addr >= 0xFFFF1000)
{
Halt();
/*FILE* f = fopen("ram.bin", "wb");
fwrite(MainRAM, 0x400000, 1, f);
fclose(f);
fopen("wram.bin", "wb");
fwrite(ARM7WRAM, 0x10000, 1, f);
fclose(f);
fopen("swram.bin", "wb");
fwrite(ARM7WRAM, 0x8000, 1, f);
fclose(f);*/
}
switch (addr & 0xFF000000) switch (addr & 0xFF000000)
{ {
case 0x02000000: case 0x02000000:
@ -280,13 +516,18 @@ u32 ARM9Read32(u32 addr)
case 0x04000000: case 0x04000000:
switch (addr) switch (addr)
{ {
case 0x04000100: return Timers[0].Counter | (Timers[0].Control << 16);
case 0x04000104: return Timers[1].Counter | (Timers[1].Control << 16);
case 0x04000108: return Timers[2].Counter | (Timers[2].Control << 16);
case 0x0400010C: return Timers[3].Counter | (Timers[3].Control << 16);
case 0x04000208: return IME[0]; case 0x04000208: return IME[0];
case 0x04000210: return IE[0]; case 0x04000210: return IE[0];
case 0x04000214: return IF[0]; case 0x04000214: return IF[0];
} }
} }
printf("unknown arm9 read32 %08X | %08X\n", addr, ARM9->R[15]); printf("unknown arm9 read32 %08X | %08X %08X %08X\n", addr, ARM9->R[15], ARM9->R[12], ARM9Read32(0x027FF820));
return 0; return 0;
} }
@ -352,6 +593,15 @@ void ARM9Write16(u32 addr, u16 val)
case 0x04000000: case 0x04000000:
switch (addr) switch (addr)
{ {
case 0x04000100: Timers[0].Reload = val; return;
case 0x04000102: TimerStart(0, val); return;
case 0x04000104: Timers[1].Reload = val; return;
case 0x04000106: TimerStart(1, val); return;
case 0x04000108: Timers[2].Reload = val; return;
case 0x0400010A: TimerStart(2, val); return;
case 0x0400010C: Timers[3].Reload = val; return;
case 0x0400010E: TimerStart(3, val); return;
case 0x04000180: case 0x04000180:
IPCSync7 &= 0xFFF0; IPCSync7 &= 0xFFF0;
IPCSync7 |= ((val & 0x0F00) >> 8); IPCSync7 |= ((val & 0x0F00) >> 8);
@ -361,6 +611,7 @@ void ARM9Write16(u32 addr, u16 val)
{ {
TriggerIRQ(1, IRQ_IPCSync); TriggerIRQ(1, IRQ_IPCSync);
} }
CompensateARM7();
return; return;
} }
} }
@ -394,6 +645,23 @@ void ARM9Write32(u32 addr, u32 val)
case 0x04000000: case 0x04000000:
switch (addr) switch (addr)
{ {
case 0x04000100:
Timers[0].Reload = val & 0xFFFF;
TimerStart(0, val>>16);
return;
case 0x04000104:
Timers[1].Reload = val & 0xFFFF;
TimerStart(1, val>>16);
return;
case 0x04000108:
Timers[2].Reload = val & 0xFFFF;
TimerStart(2, val>>16);
return;
case 0x0400010C:
Timers[3].Reload = val & 0xFFFF;
TimerStart(3, val>>16);
return;
case 0x04000208: IME[0] = val; return; case 0x04000208: IME[0] = val; return;
case 0x04000210: IE[0] = val; return; case 0x04000210: IE[0] = val; return;
case 0x04000214: IF[0] &= ~val; return; case 0x04000214: IF[0] &= ~val; return;
@ -462,14 +730,25 @@ u16 ARM7Read16(u32 addr)
case 0x04000000: case 0x04000000:
switch (addr) switch (addr)
{ {
case 0x04000100: return Timers[4].Counter;
case 0x04000102: return Timers[4].Control;
case 0x04000104: return Timers[5].Counter;
case 0x04000106: return Timers[5].Control;
case 0x04000108: return Timers[6].Counter;
case 0x0400010A: return Timers[6].Control;
case 0x0400010C: return Timers[7].Counter;
case 0x0400010E: return Timers[7].Control;
case 0x04000180: return IPCSync7; case 0x04000180: return IPCSync7;
case 0x040001C0: return SPI::ReadCnt(); case 0x040001C0: return SPI::ReadCnt();
case 0x040001C2: return SPI::ReadData(); case 0x040001C2: return SPI::ReadData();
case 0x04000504: return _soundbias;
} }
} }
printf("unknown arm7 read16 %08X\n", addr); printf("unknown arm7 read16 %08X %08X\n", addr, ARM7->R[15]);
return 0; return 0;
} }
@ -495,6 +774,11 @@ u32 ARM7Read32(u32 addr)
case 0x04000000: case 0x04000000:
switch (addr) switch (addr)
{ {
case 0x04000100: return Timers[4].Counter | (Timers[4].Control << 16);
case 0x04000104: return Timers[5].Counter | (Timers[5].Control << 16);
case 0x04000108: return Timers[6].Counter | (Timers[6].Control << 16);
case 0x0400010C: return Timers[7].Counter | (Timers[7].Control << 16);
case 0x040001A4: case 0x040001A4:
return 0x00800000; // hax return 0x00800000; // hax
@ -507,6 +791,7 @@ u32 ARM7Read32(u32 addr)
} }
} }
if ((addr&0xFF000000) == 0xEA000000) Halt(); if ((addr&0xFF000000) == 0xEA000000) Halt();
printf("unknown arm7 read32 %08X | %08X\n", addr, ARM7->R[15]); printf("unknown arm7 read32 %08X | %08X\n", addr, ARM7->R[15]);
return 0; return 0;
} }
@ -545,6 +830,19 @@ void ARM7Write8(u32 addr, u8 val)
} }
} }
if (addr==0xA20)
{
/*FILE* f = fopen("ram.bin", "wb");
fwrite(MainRAM, 0x400000, 1, f);
fclose(f);
fopen("wram.bin", "wb");
fwrite(ARM7WRAM, 0x10000, 1, f);
fclose(f);
fopen("swram.bin", "wb");
fwrite(ARM7WRAM, 0x8000, 1, f);
fclose(f);*/
}
printf("unknown arm7 write8 %08X %02X | %08X | %08X %08X %08X %08X\n", addr, val, ARM7->R[15], IME[1], IE[1], ARM7->R[0], ARM7->R[1]); printf("unknown arm7 write8 %08X %02X | %08X | %08X %08X %08X %08X\n", addr, val, ARM7->R[15], IME[1], IE[1], ARM7->R[0], ARM7->R[1]);
} }
@ -568,6 +866,15 @@ void ARM7Write16(u32 addr, u16 val)
case 0x04000000: case 0x04000000:
switch (addr) switch (addr)
{ {
case 0x04000100: Timers[4].Reload = val; return;
case 0x04000102: TimerStart(4, val); return;
case 0x04000104: Timers[5].Reload = val; return;
case 0x04000106: TimerStart(5, val); return;
case 0x04000108: Timers[6].Reload = val; return;
case 0x0400010A: TimerStart(6, val); return;
case 0x0400010C: Timers[7].Reload = val; return;
case 0x0400010E: TimerStart(7, val); return;
case 0x04000180: case 0x04000180:
IPCSync9 &= 0xFFF0; IPCSync9 &= 0xFFF0;
IPCSync9 |= ((val & 0x0F00) >> 8); IPCSync9 |= ((val & 0x0F00) >> 8);
@ -586,6 +893,10 @@ void ARM7Write16(u32 addr, u16 val)
case 0x040001C2: case 0x040001C2:
SPI::WriteData(val & 0xFF); SPI::WriteData(val & 0xFF);
return; return;
case 0x04000504:
_soundbias = val & 0x3FF;
return;
} }
} }
@ -612,13 +923,30 @@ void ARM7Write32(u32 addr, u32 val)
case 0x04000000: case 0x04000000:
switch (addr) switch (addr)
{ {
case 0x04000100:
Timers[4].Reload = val & 0xFFFF;
TimerStart(4, val>>16);
return;
case 0x04000104:
Timers[5].Reload = val & 0xFFFF;
TimerStart(5, val>>16);
return;
case 0x04000108:
Timers[6].Reload = val & 0xFFFF;
TimerStart(6, val>>16);
return;
case 0x0400010C:
Timers[7].Reload = val & 0xFFFF;
TimerStart(7, val>>16);
return;
case 0x04000208: IME[1] = val; return; case 0x04000208: IME[1] = val; return;
case 0x04000210: IE[1] = val; return; case 0x04000210: IE[1] = val; return;
case 0x04000214: IF[1] &= ~val; printf("IRQ ack %08X\n", val);return; case 0x04000214: IF[1] &= ~val; printf("IRQ ack %08X\n", val);return;
} }
} }
printf("unknown arm7 write32 %08X %08X | %08X\n", addr, val, ARM7->R[15]); printf("unknown arm7 write32 %08X %08X | %08X %08X\n", addr, val, ARM7->R[15], ARM7->CurInstr);
} }
} }

28
NDS.h
View File

@ -7,6 +7,18 @@
namespace NDS namespace NDS
{ {
#define SCHED_BUF_LEN 64
typedef struct _SchedEvent
{
u32 Delay;
void (*Func)(u32);
u32 Param;
struct _SchedEvent* PrevEvent;
struct _SchedEvent* NextEvent;
} SchedEvent;
enum enum
{ {
IRQ_VBlank = 0, IRQ_VBlank = 0,
@ -36,6 +48,15 @@ enum
IRQ_Wifi IRQ_Wifi
}; };
typedef struct
{
u16 Reload;
u16 Control;
u16 Counter;
SchedEvent* Event;
} Timer;
extern u32 ARM9ITCMSize; extern u32 ARM9ITCMSize;
extern u32 ARM9DTCMBase, ARM9DTCMSize; extern u32 ARM9DTCMBase, ARM9DTCMSize;
@ -44,6 +65,13 @@ void Reset();
void RunFrame(); void RunFrame();
SchedEvent* ScheduleEvent(s32 Delay, void (*Func)(u32), u32 Param);
void CancelEvent(SchedEvent* event);
void RunEvents(s32 cycles);
// DO NOT CALL FROM ARM7!!
void CompensateARM7();
void Halt(); void Halt();
void MapSharedWRAM(); void MapSharedWRAM();

View File

@ -13,4 +13,11 @@ LOVE MELONS
NO ASKING ROMZ!! ILLEGAL NO ASKING ROMZ!! ILLEGAL
license will eventually be GPL or some crap. don't steal the code and make money off of it or claim it as your own or be an asshole. license will eventually be GPL or some crap. don't steal the code and make money off of it or claim it as your own or be an asshole.
TODO LIST
* take code fetch waitstates into account when fetching instructions, and during branches (pipeline shit) (tricky, some code fetches are nonsequential)
*

View File

@ -3,12 +3,12 @@
<stdio.h> <stdio.h>
"NDS.h" "NDS.h"
1480786846 c:\documents\sources\melonds\nds.h 1480942921 c:\documents\sources\melonds\nds.h
"types.h" "types.h"
1463409689 c:\documents\sources\melonds\types.h 1463409689 c:\documents\sources\melonds\types.h
1480816263 source:c:\documents\sources\melonds\nds.cpp 1480953322 source:c:\documents\sources\melonds\nds.cpp
<stdio.h> <stdio.h>
<string.h> <string.h>
"NDS.h" "NDS.h"
@ -16,23 +16,23 @@
"CP15.h" "CP15.h"
"SPI.h" "SPI.h"
1480789789 source:c:\documents\sources\melonds\arm.cpp 1480953451 source:c:\documents\sources\melonds\arm.cpp
<stdio.h> <stdio.h>
"NDS.h" "NDS.h"
"ARM.h" "ARM.h"
"ARMInterpreter.h" "ARMInterpreter.h"
1480786942 c:\documents\sources\melonds\arm.h 1480951045 c:\documents\sources\melonds\arm.h
"types.h" "types.h"
"NDS.h" "NDS.h"
1480785229 c:\documents\sources\melonds\arm_instrtable.h 1480954012 c:\documents\sources\melonds\arm_instrtable.h
1480725698 c:\documents\sources\melonds\arminterpreter.h 1480725698 c:\documents\sources\melonds\arminterpreter.h
"types.h" "types.h"
"ARM.h" "ARM.h"
1480776855 source:c:\documents\sources\melonds\arminterpreter.cpp 1480952246 source:c:\documents\sources\melonds\arminterpreter.cpp
<stdio.h> <stdio.h>
"NDS.h" "NDS.h"
"CP15.h" "CP15.h"
@ -50,24 +50,24 @@
1480784137 c:\documents\sources\melonds\arminterpreter_alu.h 1480784137 c:\documents\sources\melonds\arminterpreter_alu.h
1480784110 source:c:\documents\sources\melonds\arminterpreter_alu.cpp 1480952092 source:c:\documents\sources\melonds\arminterpreter_alu.cpp
"ARM.h" "ARM.h"
1480785175 c:\documents\sources\melonds\arminterpreter_loadstore.h 1480953933 c:\documents\sources\melonds\arminterpreter_loadstore.h
1480785158 source:c:\documents\sources\melonds\arminterpreter_loadstore.cpp 1480951014 source:c:\documents\sources\melonds\arminterpreter_loadstore.cpp
<stdio.h> <stdio.h>
"ARM.h" "ARM.h"
1480776964 c:\documents\sources\melonds\cp15.h 1480776964 c:\documents\sources\melonds\cp15.h
1480777799 source:c:\documents\sources\melonds\cp15.cpp 1480950166 source:c:\documents\sources\melonds\cp15.cpp
<stdio.h> <stdio.h>
"NDS.h" "NDS.h"
1480814622 c:\documents\sources\melonds\spi.h 1480814622 c:\documents\sources\melonds\spi.h
1480816142 source:c:\documents\sources\melonds\spi.cpp 1480816963 source:c:\documents\sources\melonds\spi.cpp
<stdio.h> <stdio.h>
"NDS.h" "NDS.h"
"SPI.h" "SPI.h"